gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] [gnurl] branch master updated (131de33cb -> 054e207ac)


From: gnunet
Subject: [GNUnet-SVN] [gnurl] branch master updated (131de33cb -> 054e207ac)
Date: Tue, 05 Dec 2017 14:50:30 +0100

This is an automated email from the git hooks/post-receive script.

ng0 pushed a change to branch master
in repository gnurl.

    from 131de33cb README: Adjust to 7.56.1-2 changes.
     new 2de63ab17 travis: exit if any steps fail
     new 6746f8aa9 RELEASE-NOTES: clean slate towards 7.57.0
     new f6535791f curl_mime_filedata.3: fix typos
     new 7408570bf libcurl-tutorial.3: fix typo
     new 016c6a6ab libtest: Add required test libraries for lib1552 and lib1553
     new b9d25f9a6 timediff: return timediff_t from the time diff functions
     new f786d1f14 ftplistparser: free off temporary memory always
     new 1d72b5b89 ftplistparser: follow-up cleanup to remove PL_ERROR()
     new 5d543fe90 time: rename Curl_tvnow to Curl_now
     new 3340b456a multi: allow table handle sizes to be overridden
     new 7b11c5dbe wildcards: don't use with non-supported protocols
     new f0364f7e3 curl_fnmatch: return error on illegal wildcard pattern
     new 788d33357 timeval: make timediff_t also work on 32bit windows
     new 979d2877b transfer: Fix chunked-encoding upload bug
     new 9e76dbe05 curl_setup: Improve detection of CURL_WINDOWS_APP
     new fe03485e9 curl_setup.h: oops, shorten the too long line
     new 36bbbeb7c HELP-US: rename the subtitle too since the label is changed
     new 733190413 resolvers: only include anything if needed
     new 961c8667d setopt: fix CURLOPT_SSH_AUTH_TYPES option read
     new 9dfc541dd appveyor: add a win32 build
     new 0d85eed3d Curl_timeleft: change return type to timediff_t
     new cb361b4a5 ROADMAP.md: spelling fixes
     new 516d3b9ff ROADMAP: cleanup
     new 1d0c8dea9 TODO: support multiple Content-Encodings
     new 2b5b37cb9 auth: add support for RFC7616 - HTTP Digest access 
authentication
     new f20cbac97 auth: Added test cases for RFC7616
     new 58a9e770e RELEASE-NOTES: synced with f20cbac97
     new 1cb4f5d6e cmake: Export libcurl and curl targets to use by other cmake 
projects
     new 7ee59512f timeleft: made two more users of Curl_timeleft use timediff_t
     new f82f952d2 cli tool: in -F option arg, comma is a delimiter for files 
only
     new e240a546a cli tool: improve ";type=" handling in -F option arguments
     new d531f33ba timeval: use mach time on MacOS
     new 647f9aea6 INTERNALS: remove curlx_tv* functions no longer provided
     new f2003295a select: update comments
     new a7b99d58a curlx: the timeval functions are no longer provided as 
curlx_*
     new 89116e342 runtests.pl: Fixed typo in message
     new 6089aa53e mkhelp.pl: support reproducible build
     new 52d9a11c1 memdebug: use send/recv signature for curl_dosend/curl_dorecv
     new fa394c8c2 cookie: avoid NULL dereference
     new b8bd6dc11 url: fix CURLOPT_POSTFIELDSIZE arg value check to allow -1
     new cda89c8b5 include: remove conncache.h inclusion from where its not 
needed
     new 25cb41d35 CURLOPT_MAXREDIRS: allow -1 as a value
     new 591f5d18c tests: Fixed torture tests on tests 556 and 650
     new 544bfdebe http2: Fixed OOM handling in upgrade request
     new b51e0742b url: fix CURLOPT_DNS_CACHE_TIMEOUT arg value check to allow 
-1
     new 921bf1de5 CURLOPT_INFILESIZE: accept -1
     new 90abb74ff curl: pass through [] in URLs instead of calling globbing 
error
     new ee8016b3d curl: speed up handling of many URLs
     new d2146c598 RELEASE-NOTES: synced with ee8016b3d
     new 685ef1305 ntlm: avoid malloc(0) for zero length passwords
     new 462f3cac3 url: remove arg value check from CURLOPT_SSH_AUTH_TYPES
     new dbcced8e3 HTTP: support multiple Content-Encodings
     new 11bf1796c HTTP: implement Brotli content encoding
     new 609aa62f5 Makefile.m32: add brotli support
     new c675c4029 travis: add a job with brotli enabled
     new cc1f44360 Makefile.m32: allow to customize brotli libs
     new 3962a3cfc src/Makefile.m32: fix typo in brotli lib customization
     new cbb22cb76 url: remove unncessary NULL-check
     new 6e6bf6035 fnmatch: remove dead code
     new 19e66e536 content_encoding: do not write 0 length data
     new fa64b0fc4 content_encoding: fix inflate_stream for no bytes available
     new 63b8fbbbc curl_multi_fdset.3: emphasize curl_multi_timeout
     new 6b12beb25 connect: store IPv6 connection status after valid connection
     new e871ab56e imap: deal with commands case insensitively
     new 67c55a26d share: add support for sharing the connection cache
     new edd1f45c9 test1554: verify connection cache sharing
     new 3d1280866 examples: add shared-connection-cache
     new b78dce252 curl_share_setopt.3: document CURL_LOCK_DATA_CONNECT
     new 32828cc4f --interface: add support for Linux VRF
     new f405133ad RELEASE-NOTES: synced with 32828cc4f
     new 2671f5f7c cmake: Correctly include curl.rc in Windows builds (#2064)
     new 3619ee5fe curl_share_setopt: va_end was not called if conncache errors
     new 2e850dafa cmake: Add missing setmode check
     new aa7668b94 setopt: split out curl_easy_setopt() to its own file
     new dab7debe2 README.md: fixed layout
     new 9f78b0544 connect.c: remove executable bit on file
     new fa1512b2a SMB: fix uninitialized local variable
     new def2ca262 zlib/brotli: only include header files in modules needing 
them
     new de67c259d INTERNALS: we may use libidn2 now, not libidn
     new ae7369b6d URL: return error on malformed URLs with junk after IPv6 
bracket
     new 964d47e7f RELEASE-NOTES: synced with ae7369b6d
     new a9f669896 TODO: ignore private IP addresses in PASV response
     new d3ab7c5a2 openssl: fix too broad use of HAVE_OPAQUE_EVP_PKEY
     new 6ce984567 macOS: Fix missing connectx function with Xcode version 
older than 9.0
     new 715f1f53e resolve: allow IP address within [] brackets
     new 297516e12 examples/curlx: Fix code style
     new 2f81e48c0 BUGS: spellchecked
     new 46e852ce2 ntlm: remove unnecessary NULL-check to please scan-build
     new cec0734b4 Curl_llist_remove: fix potential NULL pointer deref
     new cd79b5319 mime: fix "Value stored to 'sz' is never read" scan-build 
error
     new 3d97e3744 openssl: fix "Value stored to 'rc' is never read" scan-build 
error
     new 786992c80 http2: fix "Value stored to 'hdbuf' is never read" 
scan-build error
     new 9474a5fe1 http2: fix "Value stored to 'end' is never read" scan-build 
error
     new 9554c3c6e Curl_open: fix OOM return error correctly
     new fa939220d url: reject ASCII control characters and space in host names
     new 914f4ed27 test1264: verify URL with space in host name being rejected
     new ed22d8654 examples/rtsp: clear RANGE again after use
     new 31f18d272 connect: improve the bind error message
     new 6b9dd0d40 RELEASE-NOTES: synced with 31f18d272
     new 9f691be3d make: fix "make distclean"
     new 979b012ee connect: add support for new TCP Fast Open API on Linux
     new d6ec96f7f metalink: fix memory-leak and NULL pointer dereference
     new 25634611f URL: update "file:" URL handling
     new d7c103746 test: add tests to ensure basic file: URLs
     new 3da4ebad3 test: add test for bad UNC/SMB path in file: URL
     new c79b2ca03 ssh: remove check for a NULL pointer (!)
     new 9b5e12a54 url: fix alignment of ssl_backend_data struct
     new 0b664ba96 wildcardmatch: fix heap buffer overflow in setcharset
     new 7f2a1df6f ntlm: avoid integer overflow for malloc size
     new d661b0afb global_init: ignore CURL_GLOBAL_SSL's absense
     new 59657f53f libcurl-share.3: the connection cache is shareable now
     new 014887c50 curl_ntlm_core.c: use the limits.h's SIZE_T_MAX if provided
     new cd276c3cc openssl: fix boringssl build again
     new d05b8ff1f THANKS: added contributors from 7.57.0 release
     new 62c07b574 RELEASE-NOTES: curl 7.57.0
     new 054e207ac Merge tag 'curl-7_57_0'

The 116 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .travis.yml                                   |   25 +
 CMake/curl-config.cmake                       |   59 +
 CMakeLists.txt                                |   29 +-
 Makefile.am                                   |   12 +-
 README.md                                     |    1 +
 RELEASE-NOTES                                 |  238 +-
 appveyor.yml                                  |    7 +-
 configure.ac                                  |   95 +
 docs/BUGS                                     |    8 +-
 docs/HELP-US.md                               |    2 +-
 docs/INTERNALS.md                             |   70 +-
 docs/Makefile.am                              |    3 +
 docs/RESOURCES                                |    2 +
 docs/ROADMAP.md                               |   94 +-
 docs/THANKS                                   |   23 +
 docs/TODO                                     |   36 +-
 docs/cmdline-opts/form.d                      |    5 +
 docs/cmdline-opts/interface.d                 |    4 +
 docs/cmdline-opts/resolve.d                   |    2 +
 docs/examples/Makefile.inc                    |    3 +-
 docs/examples/curlx.c                         |    3 +-
 docs/examples/rtsp.c                          |    3 +
 docs/examples/shared-connection-cache.c       |   85 +
 docs/libcurl/gnurl_global_init.3              |    3 +
 docs/libcurl/gnurl_mime_filedata.3            |    4 +-
 docs/libcurl/gnurl_multi_fdset.3              |    9 +-
 docs/libcurl/gnurl_share_setopt.3             |    9 +-
 docs/libcurl/gnurl_version_info.3             |    8 +
 docs/libcurl/libgnurl-share.3                 |    9 +-
 docs/libcurl/libgnurl-tutorial.3              |    2 +-
 docs/libcurl/opts/GNURLINFO_HTTPAUTH_AVAIL.3  |    3 +-
 docs/libcurl/opts/GNURLINFO_PROXYAUTH_AVAIL.3 |    3 +-
 docs/libcurl/opts/GNURLOPT_RESOLVE.3          |    4 +-
 docs/libcurl/symbols-in-versions              |    2 +
 include/gnurl/curl.h                          |   12 +-
 lib/CMakeLists.txt                            |   19 +-
 lib/Makefile.inc                              |    6 +-
 lib/Makefile.m32                              |   20 +-
 lib/asyn-ares.c                               |   24 +-
 lib/asyn-thread.c                             |    3 +-
 lib/conncache.c                               |  141 +-
 lib/conncache.h                               |   10 +-
 lib/connect.c                                 |  125 +-
 lib/connect.h                                 |    7 +-
 lib/content_encoding.c                        |  735 +++++-
 lib/content_encoding.h                        |   45 +-
 lib/cookie.c                                  |    2 +-
 lib/curl_config.h.cmake                       |    3 +
 lib/curl_fnmatch.c                            |   20 +-
 lib/curl_ntlm_core.c                          |   25 +-
 lib/curl_setup.h                              |    5 +-
 lib/{gopher.h => curl_sha256.h}               |   15 +-
 lib/curlx.h                                   |   12 +-
 lib/easy.c                                    |   87 +-
 lib/file.c                                    |    4 +-
 lib/ftp.c                                     |   23 +-
 lib/ftplistparser.c                           |  175 +-
 lib/hostasyn.c                                |   10 +-
 lib/hostip.c                                  |   17 +-
 lib/hostip4.c                                 |    9 +-
 lib/hostip6.c                                 |   10 +-
 lib/hostsyn.c                                 |   10 +-
 lib/http.c                                    |   69 +-
 lib/http2.c                                   |    9 +-
 lib/http_chunks.c                             |   42 +-
 lib/http_proxy.c                              |    2 +-
 lib/imap.c                                    |   22 +-
 lib/llist.c                                   |    6 +-
 lib/memdebug.c                                |   23 +-
 lib/memdebug.h                                |   13 +-
 lib/mime.c                                    |    2 -
 lib/multi.c                                   |  112 +-
 lib/multihandle.h                             |    4 -
 lib/pingpong.c                                |   12 +-
 lib/pingpong.h                                |    4 +-
 lib/progress.c                                |   28 +-
 lib/rand.c                                    |    2 +-
 lib/select.c                                  |   12 +-
 lib/sendf.c                                   |    6 +-
 lib/setopt.c                                  | 2554 ++++++++++++++++++++
 lib/{vtls/cyassl.h => setopt.h}               |   12 +-
 lib/sha256.c                                  |  262 +++
 lib/share.c                                   |    6 +-
 lib/share.h                                   |    5 +-
 lib/smb.c                                     |    2 +-
 lib/smtp.c                                    |    2 +-
 lib/socks.c                                   |    4 +-
 lib/speedcheck.c                              |    2 +-
 lib/ssh.c                                     |    8 +-
 lib/telnet.c                                  |    8 +-
 lib/tftp.c                                    |    4 +-
 lib/timeval.c                                 |   98 +-
 lib/timeval.h                                 |   27 +-
 lib/transfer.c                                |   64 +-
 lib/url.c                                     | 3069 +++----------------------
 lib/url.h                                     |   12 +-
 lib/urldata.h                                 |   48 +-
 lib/vauth/digest.c                            |  194 +-
 lib/vauth/digest.h                            |    6 +-
 lib/vauth/ntlm.c                              |    3 +-
 lib/version.c                                 |   48 +-
 lib/vtls/openssl.c                            |   22 +-
 packages/Symbian/group/libcurl.mmp            |    2 +-
 src/CMakeLists.txt                            |   15 +-
 src/Makefile.m32                              |   20 +-
 src/mkhelp.pl                                 |    2 -
 src/tool_cfgable.h                            |    1 +
 src/tool_formparse.c                          |   71 +-
 src/tool_getparam.c                           |   20 +-
 src/tool_help.c                               |    1 +
 src/tool_metalink.c                           |   27 +-
 src/tool_urlglob.c                            |    8 +-
 tests/data/Makefile.inc                       |   19 +-
 tests/data/test1034                           |   25 +-
 tests/data/test1035                           |   21 +-
 tests/data/test1133                           |   14 +-
 tests/data/{test1501 => test1162}             |   33 +-
 tests/data/{test1501 => test1163}             |   33 +-
 tests/data/{test1260 => test1263}             |    5 +-
 tests/data/{test20 => test1264}               |   12 +-
 tests/data/{test214 => test1290}              |   18 +-
 tests/data/test1291                           |   51 +
 tests/data/{test1317 => test1324}             |   10 +-
 tests/data/test1554                           |   77 +
 tests/data/{test1001 => test2058}             |   16 +-
 tests/data/{test1001 => test2059}             |   16 +-
 tests/data/{test1001 => test2060}             |   16 +-
 tests/data/{test64 => test2061}               |   14 +-
 tests/data/{test64 => test2062}               |   14 +-
 tests/data/{test64 => test2063}               |   14 +-
 tests/data/{test65 => test2064}               |   14 +-
 tests/data/{test65 => test2065}               |   14 +-
 tests/data/{test65 => test2066}               |   14 +-
 tests/data/{test1284 => test2067}             |   14 +-
 tests/data/{test1284 => test2068}             |   14 +-
 tests/data/{test1284 => test2069}             |   14 +-
 tests/data/{test200 => test2070}              |    6 +-
 tests/data/{test203 => test2071}              |    7 +-
 tests/data/{test1145 => test2072}             |    6 +-
 tests/data/test220                            |    5 +-
 tests/data/test221                            |    5 +-
 tests/data/test222                            |    5 +-
 tests/data/test223                            |    5 +-
 tests/data/test224                            |    5 +-
 tests/data/{test1123 => test230}              |   66 +-
 tests/data/{test222 => test314}               |   61 +-
 tests/data/test315                            |   91 +
 tests/libtest/Makefile.inc                    |    7 +-
 tests/libtest/lib1554.c                       |   81 +
 tests/libtest/lib501.c                        |    5 +-
 tests/libtest/lib556.c                        |    4 +-
 tests/libtest/lib650.c                        |   57 +-
 tests/runtests.pl                             |   16 +-
 tests/server/Makefile.inc                     |    2 -
 tests/server/util.c                           |  111 +-
 tests/server/util.h                           |    3 +-
 tests/unit/unit1323.c                         |    2 +-
 tests/unit/unit1399.c                         |    2 +-
 158 files changed, 6194 insertions(+), 4284 deletions(-)
 create mode 100644 CMake/curl-config.cmake
 create mode 100644 docs/examples/shared-connection-cache.c
 mode change 100755 => 100644 lib/connect.c
 copy lib/{gopher.h => curl_sha256.h} (76%)
 create mode 100644 lib/setopt.c
 copy lib/{vtls/cyassl.h => setopt.h} (83%)
 create mode 100644 lib/sha256.c
 copy tests/data/{test1501 => test1162} (58%)
 copy tests/data/{test1501 => test1163} (57%)
 copy tests/data/{test1260 => test1263} (64%)
 copy tests/data/{test20 => test1264} (71%)
 copy tests/data/{test214 => test1290} (71%)
 create mode 100644 tests/data/test1291
 copy tests/data/{test1317 => test1324} (77%)
 create mode 100644 tests/data/test1554
 copy tests/data/{test1001 => test2058} (72%)
 copy tests/data/{test1001 => test2059} (65%)
 copy tests/data/{test1001 => test2060} (71%)
 copy tests/data/{test64 => test2061} (74%)
 copy tests/data/{test64 => test2062} (73%)
 copy tests/data/{test64 => test2063} (66%)
 copy tests/data/{test65 => test2064} (74%)
 copy tests/data/{test65 => test2065} (73%)
 copy tests/data/{test65 => test2066} (66%)
 copy tests/data/{test1284 => test2067} (75%)
 copy tests/data/{test1284 => test2068} (74%)
 copy tests/data/{test1284 => test2069} (67%)
 copy tests/data/{test200 => test2070} (77%)
 copy tests/data/{test203 => test2071} (73%)
 copy tests/data/{test1145 => test2072} (70%)
 copy tests/data/{test1123 => test230} (73%)
 copy tests/data/{test222 => test314} (74%)
 create mode 100644 tests/data/test315
 create mode 100644 tests/libtest/lib1554.c

diff --git a/.travis.yml b/.travis.yml
index b7776c98d..8db95272f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -35,6 +35,10 @@ matrix:
           dist: trusty
           env: T=normal C=--enable-ares
         - os: linux
+          compiler: gcc
+          dist: trusty
+          env: T=normal BROTLI=yes
+        - os: linux
           compiler: clang
           dist: trusty
           env: T=debug
@@ -90,9 +94,25 @@ install:
 
 before_script:
     - ./buildconf
+    - |
+      # No brotli package available for Trusty. Download & compile from source.
+      # Cannot be done in the install script because cmake is needed.
+          if [ "$TRAVIS_OS_NAME" = linux -a "$BROTLI" ]; then
+          curl -L https://github.com/google/brotli/archive/v1.0.1.tar.gz |
+              tar xzf - &&
+              (
+                  cd brotli-1.0.1 &&
+                  cmake . -DCMAKE_INSTALL_PREFIX=/usr \
+                          -DCMAKE_INSTALL_LIBDIR=/usr/lib &&
+                  make &&
+                  sudo make install
+              )
+          fi
 
 script:
     - |
+        # Uncomment this when `coverage` runs on Trusty.
+        # set -eo pipefail
         if [ "$T" = "coverage" ]; then
              export CC="gcc-4.8"
              ./configure --enable-debug --disable-shared --enable-code-coverage
@@ -105,18 +125,21 @@ script:
              coveralls --gcov /usr/bin/gcov-4.8 --gcov-options '\-lp' -e src 
-i lib -e tests -e docs -b $PWD/lib
         fi
     - |
+        set -eo pipefail
         if [ "$T" = "debug" ]; then
              ./configure --enable-debug --enable-werror $C
              make && make examples
              make TFLAGS=-n test-nonflaky
         fi
     - |
+        set -eo pipefail
         if [ "$T" = "normal" ]; then
              ./configure --enable-warnings --enable-werror $C
              make && make examples
              make test-nonflaky
         fi
     - |
+        set -eo pipefail
         if [ "$T" = "cmake" ]; then
              mkdir build
              cd build
@@ -124,6 +147,7 @@ script:
              make
         fi
     - |
+        set -eo pipefail
         if [ "$T" = "distcheck" ]; then
             ./configure
             make
@@ -155,6 +179,7 @@ script:
              make)
         fi
     - |
+        set -eo pipefail
         if [ "$T" = "fuzzer" ]; then
           # Download the fuzzer to a temporary folder
           ./tests/fuzz/download_fuzzer.sh /tmp/curl_fuzzer
diff --git a/CMake/curl-config.cmake b/CMake/curl-config.cmake
new file mode 100644
index 000000000..119332cdd
--- /dev/null
+++ b/CMake/curl-config.cmake
@@ -0,0 +1,59 @@
+
+get_filename_component(_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
+
+if(NOT CURL_FIND_COMPONENTS)
+    set(CURL_FIND_COMPONENTS curl libcurl)
+    if(CURL_FIND_REQUIRED)
+        set(CURL_FIND_REQUIRED_curl TRUE)
+        set(CURL_FIND_REQUIRED_libcurl TRUE)
+    endif()
+endif()
+
+set(_curl_missing_components)
+foreach(_comp ${CURL_FIND_COMPONENTS})
+    if(EXISTS "${_DIR}/${_comp}-target.cmake")
+        include("${_DIR}/${_comp}-target.cmake")
+        set(CURL_${_comp}_FOUND TRUE)
+    else()
+        set(CURL_${_comp}_FOUND FALSE)
+        if(CURL_FIND_REQUIRED_${_comp})
+            set(CURL_FOUND FALSE)
+            list(APPEND _curl_missing_components ${_comp})
+        endif()
+    endif()
+endforeach()
+
+if(_curl_missing_components)
+    set(CURL_NOT_FOUND_MESSAGE "Following required components not found: " 
${_curl_missing_components})
+else()
+    if(TARGET CURL::libcurl)
+        string(TOUPPER "${CMAKE_BUILD_TYPE}" _curl_current_config)
+        if(NOT _curl_current_config)
+            set(_curl_current_config "NOCONFIG")
+        endif()
+        get_target_property(_curl_configurations CURL::libcurl 
IMPORTED_CONFIGURATIONS)
+        list(FIND _curl_configurations "${_curl_current_config}" _i)
+        if(_i LESS 0)
+            set(_curl_config "RELEASE")
+            list(FIND _curl_configurations "${_curl_current_config}" _i)
+            if(_i LESS 0)
+                set(_curl_config "NOCONFIG")
+                list(FIND _curl_configurations "${_curl_current_config}" _i)
+            endif()
+        endif()
+
+        if(_i LESS 0)
+            set(_curl_current_config "") # let CMake pick config at random
+        else()
+           set(_curl_current_config "_${_curl_current_config}")
+        endif()
+
+        get_target_property(CURL_INCLUDE_DIRS CURL::libcurl 
INTERFACE_INCLUDE_DIRECTORIES)
+        get_target_property(CURL_LIBRARIES CURL::libcurl 
"LOCATION${_curl_current_config}")
+        set(_curl_current_config)
+        set(_curl_configurations)
+        set(_i)
+    endif()
+endif()
+
+unset(_curl_missing_components)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 19099ff0a..569eefc90 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -38,7 +38,7 @@
 # To check:
 # (From Daniel Stenberg) The cmake build selected to run gcc with -fPIC on my 
box while the plain configure script did not.
 # (From Daniel Stenberg) The gcc command line use neither -g nor any -O 
options. As a developer, I also treasure our configure scripts's --enable-debug 
option that sets a long range of "picky" compiler options.
-cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
+cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR)
 set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake;${CMAKE_MODULE_PATH}")
 include(Utilities)
 include(Macros)
@@ -874,10 +874,12 @@ check_symbol_exists(ftruncate      "${CURL_INCLUDES}" 
HAVE_FTRUNCATE)
 check_symbol_exists(getprotobyname "${CURL_INCLUDES}" HAVE_GETPROTOBYNAME)
 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(fcntl          "${CURL_INCLUDES}" HAVE_FCNTL)
 check_symbol_exists(ioctl          "${CURL_INCLUDES}" HAVE_IOCTL)
 check_symbol_exists(setsockopt     "${CURL_INCLUDES}" HAVE_SETSOCKOPT)
+check_function_exists(mach_absolute_time HAVE_MACH_ABSOLUTE_TIME)
 
 # symbol exists in win32, but function does not.
 if(WIN32)
@@ -1130,6 +1132,12 @@ function(TRANSFORM_MAKEFILE_INC INPUT_FILE OUTPUT_FILE)
 
 endfunction()
 
+if(WIN32 AND NOT CYGWIN)
+    set(CURL_INSTALL_CMAKE_DIR CMake)
+else()
+    set(CURL_INSTALL_CMAKE_DIR lib/cmake/curl)
+endif()
+
 if(USE_MANUAL)
   add_subdirectory(docs)
 endif()
@@ -1280,6 +1288,25 @@ install(DIRECTORY 
"${CMAKE_CURRENT_SOURCE_DIR}/include/gnurl"
     DESTINATION include
     FILES_MATCHING PATTERN "*.h")
 
+
+include(CMakePackageConfigHelpers)
+write_basic_package_version_file(
+    "${PROJECT_BINARY_DIR}/curl-config-version.cmake"
+    VERSION ${CURL_VERSION}
+    COMPATIBILITY SameMajorVersion
+)
+
+configure_file(CMake/curl-config.cmake
+        "${PROJECT_BINARY_DIR}/curl-config.cmake"
+        COPYONLY
+)
+
+install(
+        FILES ${PROJECT_BINARY_DIR}/curl-config.cmake
+              ${PROJECT_BINARY_DIR}/curl-config-version.cmake
+        DESTINATION ${CURL_INSTALL_CMAKE_DIR}
+)
+
 # Workaround for MSVS10 to avoid the Dialog Hell
 # FIXME: This could be removed with future version of CMake.
 if(MSVC_VERSION EQUAL 1600)
diff --git a/Makefile.am b/Makefile.am
index d668ead22..aa4f44f80 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -30,7 +30,8 @@ CMAKE_DIST = CMakeLists.txt CMake/CMakeConfigurableFile.in    
  \
  CMake/Macros.cmake              \
  CMake/CurlSymbolHiding.cmake CMake/FindCARES.cmake             \
  CMake/FindLibSSH2.cmake CMake/FindNGHTTP2.cmake                \
- CMake/FindMbedTLS.cmake CMake/cmake_uninstall.cmake.in
+ CMake/FindMbedTLS.cmake CMake/cmake_uninstall.cmake.in         \
+ CMake/curl-config.cmake
 
 VC6_LIBTMPL = projects/Windows/VC6/lib/libcurl.tmpl
 VC6_LIBDSP = projects/Windows/VC6/lib/libcurl.dsp.dist
@@ -216,15 +217,6 @@ examples:
 check-docs:
        @(cd docs/libcurl; $(MAKE) check)
 
-# This is a hook to have 'make clean' also clean up the docs and the tests
-# dir. The extra check for the Makefiles being present is necessary because
-# 'make distcheck' will make clean first in these directories _before_ it runs
-# this hook.
-clean-local:
-       @(if test -f tests/Makefile; then cd tests; $(MAKE) clean; fi)
-       @(if test -f docs/Makefile; then cd docs; $(MAKE) clean; fi)
-
-#
 # Build source and binary rpms. For rpm-3.0 and above, the ~/.rpmmacros
 # must contain the following line:
 # %_topdir /home/loic/local/rpm
diff --git a/README.md b/README.md
index 4abb51bc2..a5992098f 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,5 @@
 ![curl logo](https://cdn.rawgit.com/curl/curl-www/master/logo/curl-logo.svg)
+
 [![CII Best 
Practices](https://bestpractices.coreinfrastructure.org/projects/63/badge)](https://bestpractices.coreinfrastructure.org/projects/63)
 [![Coverity 
passed](https://scan.coverity.com/projects/curl/badge.svg)](https://scan.coverity.com/projects/curl)
 [![Build 
Status](https://travis-ci.org/curl/curl.svg?branch=master)](https://travis-ci.org/curl/curl)
diff --git a/RELEASE-NOTES b/RELEASE-NOTES
index 7da35d2eb..bb52004c0 100644
--- a/RELEASE-NOTES
+++ b/RELEASE-NOTES
@@ -1,63 +1,88 @@
-Curl and libcurl 7.56.1
+Curl and libcurl 7.57.0
 
- Public curl releases:         170
+ Public curl releases:         171
  Command line options:         211
  curl_easy_setopt() options:   249
  Public functions in libcurl:  74
- Contributors:                 1626
+ Contributors:                 1649
+
+This release includes the following changes:
+
+ o auth: add support for RFC7616 - HTTP Digest access authentication [12]
+ o share: add support for sharing the connection cache [31]
+ o HTTP: implement Brotli content encoding [28]
 
 This release includes the following bugfixes:
 
- o imap: if a FETCH response has no size, don't call write callback [32]
- o ftp: UBsan fixup 'pointer index expression overflowed [1]
- o failf: skip the sprintf() if there are no consumers [2]
- o fuzzer: move to using external curl-fuzzer [3]
- o lib/Makefile.m32: allow customizing dll suffixes [4]
- o docs: fix typo in curl_mime_data_cb man page [5]
- o darwinssl: add support for TLSv1.3 [6]
- o build: fix --disable-crypto-auth [7]
- o lib/config-win32.h: let SMB/SMBS be enabled with OpenSSL/NSS [8]
- o openssl: fix build without HAVE_OPAQUE_EVP_PKEY [9]
- o strtoofft: Remove extraneous null check [10]
- o multi_cleanup: call DONE on handles that never got that [11]
- o tests: added flaky keyword to tests 587 and 644
- o pingpong: return error when trying to send without connection [12]
- o remove_handle: call multi_done() first, then clear dns cache pointer [13]
- o mime: be tolerant about setting twice the same header list in a part.
- o mime: improve unbinding top multipart from easy handle.
- o mime: avoid resetting a part's encoder when part's contents change.
- o mime: refuse to add subparts to one of their own descendants [14]
- o RTSP: avoid integer overflow on funny RTSP responses [15]
- o curl: don't pass semicolons when parsing Content-Disposition [16]
- o openssl: enable PKCS12 support for !BoringSSL [17]
- o FAQ: s/CURLOPT_PROGRESSFUNCTION/CURLOPT_XFERINFOFUNCTION
- o CURLOPT_NOPROGRESS.3: also refer to xferinfofunction
- o CURLOPT_XFERINFODATA.3: fix duplicate see also
- o test298: verify --ftp-method nowcwd with URL encoded path [18]
- o FTP: URL decode path for dir listing in nocwd mode [19]
- o smtp_done: fix memory leak on send failure [20]
- o ftpserver: support case insensitive commands
- o test950; verify SMTP with custom request
- o openssl: don't use old BORINGSSL_YYYYMM macros [21]
- o setopt: update current connection SSL verify params [22]
- o winbuild/BUILD.WINDOWS.txt: mention WITH_NGHTTP2
- o curl: reimplement stdin buffering in -F option [23]
- o mime: keep "text/plain" content type if user-specified [24]
- o mime: fix the content reader to handle >16K data properly [25]
- o configure: remove the C++ compiler check [26]
- o memdebug: trace send, recv and socket [27]
- o runtests: use valgrind for torture as well
- o ldap: silence clang warning [28]
- o makefile.m32: allow to override gcc, ar and ranlib [29]
- o setopt: avoid integer overflows when setting millsecond values [30]
- o setopt: range check most long options [31]
- o ftp: reject illegal IP/port in PASV 227 response [33]
- o mime: do not reuse previously computed multipart size [34]
- o vtls: change struct Curl_ssl `close' field name to `close_one'
- o os400: add missing symbols in config file
- o mime: limit bas64-encoded lines length to 76 characters
- o mk-ca-bundle: Remove URL for aurora [35]
- o mk-ca-bundle: Fix URL for NSS [36]
+ o CVE-2017-8816: NTLM buffer overflow via integer overflow [47]
+ o CVE-2017-8817: FTP wildcard out of bounds read [48]
+ o CVE-2017-8818: SSL out of buffer access [49]
+ o curl_mime_filedata.3: fix typos [1]
+ o libtest: Add required test libraries for lib1552 and lib1553 [2]
+ o fix time diffs for systems using unsigned time_t [3]
+ o ftplistparser: memory leak fix: free temporary memory always [4]
+ o multi: allow table handle sizes to be overridden [5]
+ o wildcards: don't use with non-supported protocols [6]
+ o curl_fnmatch: return error on illegal wildcard pattern [7]
+ o transfer: Fix chunked-encoding upload too early exit [8]
+ o curl_setup: Improve detection of CURL_WINDOWS_APP [9]
+ o resolvers: only include anything if needed [10]
+ o setopt: fix CURLOPT_SSH_AUTH_TYPES option read
+ o appveyor: add a win32 build
+ o Curl_timeleft: change return type to timediff_t [11]
+ o cmake: Export libcurl and curl targets to use by other cmake projects [13]
+ o curl: in -F option arg, comma is a delimiter for files only [14]
+ o curl: improved ";type=" handling in -F option arguments
+ o timeval: use mach_absolute_time() on MacOS [15]
+ o curlx: the timeval functions are no longer provided as curlx_* [16]
+ o mkhelp.pl: do not generate comment with current date [17]
+ o memdebug: use send/recv signature for curl_dosend/curl_dorecv [18]
+ o cookie: avoid NULL dereference [19]
+ o url: fix CURLOPT_POSTFIELDSIZE arg value check to allow -1 [20]
+ o include: remove conncache.h inclusion from where its not needed
+ o CURLOPT_MAXREDIRS: allow -1 as a value [21]
+ o tests: Fixed torture tests on tests 556 and 650
+ o http2: Fixed OOM handling in upgrade request
+ o url: fix CURLOPT_DNS_CACHE_TIMEOUT arg value check to allow -1
+ o CURLOPT_INFILESIZE: accept -1 [22]
+ o curl: pass through [] in URLs instead of calling globbing error [23]
+ o curl: speed up handling of many URLs [24]
+ o ntlm: avoid malloc(0) for zero length passwords [25]
+ o url: remove faulty arg value check from CURLOPT_SSH_AUTH_TYPES [26]
+ o HTTP: support multiple Content-Encodings [27]
+ o travis: add a job with brotli enabled
+ o url: remove unncessary NULL-check
+ o fnmatch: remove dead code
+ o connect: store IPv6 connection status after valid connection [29]
+ o imap: deal with commands case insensitively [30]
+ o --interface: add support for Linux VRF [32]
+ o content_encoding: fix inflate_stream for no bytes available [33]
+ o cmake: Correctly include curl.rc in Windows builds [34]
+ o cmake: Add missing setmode check [35]
+ o connect.c: remove executable bit on file [36]
+ o SMB: fix uninitialized local variable
+ o zlib/brotli: only include header files in modules needing them [37]
+ o URL: return error on malformed URLs with junk after IPv6 bracket [38]
+ o openssl: fix too broad use of HAVE_OPAQUE_EVP_PKEY [39]
+ o macOS: Fix missing connectx function with Xcode version older than 9.0 [40]
+ o --resolve: allow IP address within [] brackets [41]
+ o examples/curlx: Fix code style [42]
+ o ntlm: remove unnecessary NULL-check to please scan-build [43]
+ o Curl_llist_remove: fix potential NULL pointer deref [43]
+ o mime: fix "Value stored to 'sz' is never read" scan-build error [43]
+ o openssl: fix "Value stored to 'rc' is never read" scan-build error [43]
+ o http2: fix "Value stored to 'hdbuf' is never read" scan-build error [43]
+ o http2: fix "Value stored to 'end' is never read" scan-build error [43]
+ o Curl_open: fix OOM return error correctly [43]
+ o url: reject ASCII control characters and space in host names [44]
+ o examples/rtsp: clear RANGE again after use [45]
+ o connect: improve the bind error message [46]
+ o make: fix "make distclean" [50]
+ o connect: add support for new TCP Fast Open API on Linux [51]
+ o metalink: fix memory-leak and NULL pointer dereference [52]
+ o URL: update "file:" URL handling [53]
+ o ssh: remove check for a NULL pointer [54]
+ o global_init: ignore CURL_GLOBAL_SSL's absense [55]
 
 This release includes the following known bugs:
 
@@ -66,50 +91,73 @@ This release includes the following known bugs:
 This release would not have looked like this without help, code, reports and
 advice from friends like these:
 
-  Alexey Melnichuk, Artak Galoyan, Benbuck Nason, Brian Carpenter,
-  Christian Schmitz, Dan Fandrich, Daniel Stenberg, David Benjamin,
-  Felix Kaiser, Javier Sixto, Jeroen Ooms, Jon DeVree, Kristiyan Tsaklev,
-  Marcel Raad, Max Dymond, Nick Zitzmann, Patrick Monnerat, Viktor Szakáts,
-  Wyatt O'Day, Zenju on github, 0xd34db347
-  (21 contributors)
+  Alessandro Ghedini, Alex Malinovich, Alex Nichols, Alfonso Martone,
+  Andrew Lambert, arainchik on github, Brian Carpenter, cbartl on github,
+  Dan Fandrich, Daniel Bankhead, Daniel Stenberg, Dirk Feytons,
+  Dmitri Tikhonov, Evgeny Grin, Gisle Vanem, hsiao yi, Jakub Zakrzewski,
+  John Starks, Juro Bystricky, Kamil Dudka, Luca Boccassi, Marcel Raad,
+  Martin Storsjö, Matthew Kerwin, Max Dymond, Michael Felt, Michael Kaufmann,
+  moohoorama on github, omau on github, Orgad Shaneh, Patrick Monnerat,
+  Paul Howarth, Pavel Gushchin, Pavol Markovic, Per Lundberg, Peter Piekarski,
+  Petr Voytsik, Ray Satiro, Rob Cotrone, Viktor Szakáts, youngchopin on github,
+  (41 contributors)
 
         Thanks! (and sorry if I forgot to mention someone)
 
 References to bug reports and discussions on issues:
 
- [1] = https://curl.haxx.se/bug/?i=1939
- [2] = https://curl.haxx.se/bug/?i=1936
- [3] = https://curl.haxx.se/bug/?i=1923
- [4] = https://curl.haxx.se/bug/?i=1942
- [5] = https://curl.haxx.se/bug/?i=1946
- [6] = https://curl.haxx.se/bug/?i=1794
- [7] = https://curl.haxx.se/bug/?i=1945
- [8] = https://curl.haxx.se/bug/?i=1943
- [9] = https://curl.haxx.se/bug/?i=1955
- [10] = https://curl.haxx.se/bug/?i=1950
- [11] = https://curl.haxx.se/bug/?i=1954
- [12] = https://curl.haxx.se/bug/?i=1953
- [13] = https://curl.haxx.se/bug/?i=1960
- [14] = https://curl.haxx.se/bug/?i=1962
- [15] = https://curl.haxx.se/bug/?i=1969
- [16] = https://curl.haxx.se/bug/?i=1964
- [17] = https://curl.haxx.se/bug/?i=1948
- [18] = https://curl.haxx.se/bug/?i=1974
- [19] = https://curl.haxx.se/bug/?i=1974
- [20] = https://curl.haxx.se/bug/?i=1977
- [21] = https://curl.haxx.se/bug/?i=1979
- [22] = https://curl.haxx.se/bug/?i=1941
- [23] = https://curl.haxx.se/bug/?i=1985
- [24] = https://curl.haxx.se/bug/?i=1986
- [25] = https://curl.haxx.se/bug/?i=1988
- [26] = https://curl.haxx.se/bug/?i=1990
- [27] = https://curl.haxx.se/bug/?i=1980
- [28] = https://curl.haxx.se/bug/?i=1992
- [29] = https://curl.haxx.se/bug/?i=1993
- [30] = https://curl.haxx.se/bug/?i=1938
- [31] = https://curl.haxx.se/bug/?i=1938
- [32] = https://curl.haxx.se/docs/adv_20171023.html
- [33] = https://curl.haxx.se/bug/?i=1997
- [34] = https://curl.haxx.se/bug/?i=1999
- [35] = https://curl.haxx.se/bug/?i=1998
- [36] = https://curl.haxx.se/bug/?i=1998
+ [1] = https://curl.haxx.se/bug/?i=2008
+ [2] = https://curl.haxx.se/bug/?i=2006
+ [3] = https://curl.haxx.se/bug/?i=2004
+ [4] = https://curl.haxx.se/bug/?i=2013
+ [5] = https://curl.haxx.se/bug/?i=1982
+ [6] = https://curl.haxx.se/bug/?i=2016
+ [7] = https://curl.haxx.se/bug/?i=2015
+ [8] = https://curl.haxx.se/bug/?i=2001
+ [9] = https://curl.haxx.se/bug/?i=2025
+ [10] = https://curl.haxx.se/bug/?i=2023
+ [11] = https://curl.haxx.se/bug/?i=2021
+ [12] = https://curl.haxx.se/bug/?i=1934
+ [13] = https://curl.haxx.se/bug/?i=1879
+ [14] = https://curl.haxx.se/bug/?i=2022
+ [15] = https://curl.haxx.se/bug/?i=2033
+ [16] = https://curl.haxx.se/bug/?i=2034
+ [17] = https://curl.haxx.se/bug/?i=2026
+ [18] = https://curl.haxx.se/bug/?i=2031
+ [19] = https://curl.haxx.se/bug/?i=2032
+ [20] = https://curl.haxx.se/mail/lib-2017-11/0000.html
+ [21] = https://curl.haxx.se/bug/?i=2038
+ [22] = https://curl.haxx.se/bug/?i=2047
+ [23] = https://curl.haxx.se/bug/?i=2044
+ [24] = https://curl.haxx.se/bug/?i=1959
+ [25] = https://curl.haxx.se/bug/?i=2054
+ [26] = https://github.com/curl/curl/commit/f121575#commitcomment-25347120
+ [27] = https://curl.haxx.se/bug/?i=2002
+ [28] = https://curl.haxx.se/bug/?i=2045
+ [29] = https://curl.haxx.se/bug/?i=2053
+ [30] = https://curl.haxx.se/bug/?i=2061
+ [31] = https://curl.haxx.se/bug/?i=2043
+ [32] = https://curl.haxx.se/bug/?i=2024
+ [33] = https://curl.haxx.se/bug/?i=2060
+ [34] = https://curl.haxx.se/bug/?i=2064
+ [35] = https://curl.haxx.se/bug/?i=2067
+ [36] = https://curl.haxx.se/bug/?i=2071
+ [37] = https://curl.haxx.se/mail/lib-2017-11/0032.html
+ [38] = https://curl.haxx.se/bug/?i=2072
+ [39] = https://curl.haxx.se/bug/?i=2079
+ [40] = https://curl.haxx.se/bug/?i=2080
+ [41] = https://curl.haxx.se/bug/?i=2087
+ [42] = https://curl.haxx.se/bug/?i=2096
+ [43] = https://curl.haxx.se/bug/?i=2098
+ [44] = https://curl.haxx.se/bug/?i=2073
+ [45] = https://curl.haxx.se/bug/?i=2106
+ [46] = https://curl.haxx.se/bug/?i=2104
+ [47] = https://curl.haxx.se/docs/adv_2017-11e7.html
+ [48] = https://curl.haxx.se/docs/adv_2017-ae72.html
+ [49] = https://curl.haxx.se/docs/adv_2017-af0a.html
+ [50] = https://curl.haxx.se/bug/?i=2097
+ [51] = https://curl.haxx.se/bug/?i=2056
+ [52] = https://curl.haxx.se/bug/?i=2109
+ [53] = https://curl.haxx.se/bug/?i=2110
+ [54] = https://curl.haxx.se/bug/?i=2111
+ [55] = https://curl.haxx.se/bug/?i=2083
diff --git a/appveyor.yml b/appveyor.yml
index 3c60a4690..e2664b4cb 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -56,7 +56,12 @@ environment:
         OPENSSL: OFF
         TESTING: ON
         STATICLIB: ON
-
+      - PRJ_GEN: "Visual Studio 14 2015"
+        BDIR: msvc2015
+        PRJ_CFG: Release
+        OPENSSL: OFF
+        TESTING: ON
+        STATICLIB: ON
 
 build_script:
     - mkdir build.%BDIR%
diff --git a/configure.ac b/configure.ac
index e37237d42..eae012514 100755
--- a/configure.ac
+++ b/configure.ac
@@ -148,6 +148,7 @@ dnl initialize all the info variables
     curl_ssl_msg="no      
(--with-{ssl,gnutls,nss,polarssl,mbedtls,cyassl,axtls,winssl,darwinssl} )"
     curl_ssh_msg="no      (--with-libssh2)"
    curl_zlib_msg="no      (--with-zlib)"
+ curl_brotli_msg="no      (--with-brotli)"
     curl_gss_msg="no      (--with-gssapi)"
 curl_tls_srp_msg="no      (--enable-tls-srp)"
     curl_res_msg="default (--enable-ares / --enable-threaded-resolver)"
@@ -969,6 +970,94 @@ AM_CONDITIONAL(HAVE_LIBZ, test x"$AMFIXLIB" = x1)
 AC_SUBST(ZLIB_LIBS)
 
 dnl **********************************************************************
+dnl Check for the presence of BROTLI decoder libraries and headers
+dnl **********************************************************************
+
+dnl Brotli project home page: https://github.com/google/brotli
+
+dnl Default to compiler & linker defaults for BROTLI files & libraries.
+OPT_BROTLI=off
+AC_ARG_WITH(brotli,dnl
+AC_HELP_STRING([--with-brotli=PATH],[Where to look for brotli, PATH points to 
the BROTLI installation; when possible, set the PKG_CONFIG_PATH environment 
variable instead of using this option])
+AC_HELP_STRING([--without-brotli], [disable BROTLI]),
+  OPT_BROTLI=$withval)
+
+if test X"$OPT_BROTLI" != Xno; then
+  dnl backup the pre-brotli variables
+  CLEANLDFLAGS="$LDFLAGS"
+  CLEANCPPFLAGS="$CPPFLAGS"
+  CLEANLIBS="$LIBS"
+
+  case "$OPT_BROTLI" in
+  yes)
+    dnl --with-brotli (without path) used
+    CURL_CHECK_PKGCONFIG(libbrotlidec)
+
+    if test "$PKGCONFIG" != "no" ; then
+      LIB_BROTLI=`$PKGCONFIG --libs-only-l libbrotlidec`
+      LD_BROTLI=`$PKGCONFIG --libs-only-L libbrotlidec`
+      CPP_BROTLI=`$PKGCONFIG --cflags-only-I libbrotlidec`
+      version=`$PKGCONFIG --modversion libbrotlidec`
+      DIR_BROTLI=`echo $LD_BROTLI | $SED -e 's/-L//'`
+    fi
+
+    ;;
+  off)
+    dnl no --with-brotli option given, just check default places
+    ;;
+  *)
+    dnl use the given --with-brotli spot
+    PREFIX_BROTLI=$OPT_BROTLI
+    ;;
+  esac
+
+  dnl if given with a prefix, we set -L and -I based on that
+  if test -n "$PREFIX_BROTLI"; then
+    LIB_BROTLI="-lbrotlidec"
+    LD_BROTLI=-L${PREFIX_BROTLI}/lib$libsuff
+    CPP_BROTLI=-I${PREFIX_BROTLI}/include
+    DIR_BROTLI=${PREFIX_BROTLI}/lib$libsuff
+  fi
+
+  LDFLAGS="$LDFLAGS $LD_BROTLI"
+  CPPFLAGS="$CPPFLAGS $CPP_BROTLI"
+  LIBS="$LIB_BROTLI $LIBS"
+
+  AC_CHECK_LIB(brotlidec, BrotliDecoderDecompress)
+
+  AC_CHECK_HEADERS(brotli/decode.h,
+    curl_brotli_msg="enabled (libbrotlidec)"
+    HAVE_BROTLI=1
+    AC_DEFINE(HAVE_BROTLI, 1, [if BROTLI is in use])
+    AC_SUBST(HAVE_BROTLI, [1])
+  )
+
+  if test X"$OPT_BROTLI" != Xoff &&
+     test "$HAVE_BROTLI" != "1"; then
+    AC_MSG_ERROR([BROTLI libs and/or directories were not found where 
specified!])
+  fi
+
+  if test "$HAVE_BROTLI" = "1"; then
+    if test -n "$DIR_BROTLI"; then
+       dnl when the brotli shared libs were found in a path that the run-time
+       dnl linker doesn't search through, we need to add it to LD_LIBRARY_PATH
+       dnl to prevent further configure tests to fail due to this
+
+       if test "x$cross_compiling" != "xyes"; then
+         LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$DIR_BROTLI"
+         export LD_LIBRARY_PATH
+         AC_MSG_NOTICE([Added $DIR_BROTLI to LD_LIBRARY_PATH])
+       fi
+    fi
+  else
+    dnl no brotli, revert back to clean variables
+    LDFLAGS=$CLEANLDFLAGS
+    CPPFLAGS=$CLEANCPPFLAGS
+    LIBS=$CLEANLIBS
+  fi
+fi
+
+dnl **********************************************************************
 dnl Check for LDAP
 dnl **********************************************************************
 
@@ -2142,6 +2231,7 @@ AC_CHECK_HEADERS(
         net/if.h \
         netinet/in.h \
         sys/un.h \
+        linux/tcp.h \
         netinet/tcp.h \
         netdb.h \
         sys/sockio.h \
@@ -2341,6 +2431,7 @@ AC_CHECK_FUNCS([geteuid \
   getrlimit \
   gettimeofday \
   if_nametoindex \
+  mach_absolute_time \
   pipe \
   setlocale \
   setmode \
@@ -2740,6 +2831,9 @@ fi
 if test "x$HAVE_LIBZ" = "x1"; then
   SUPPORT_FEATURES="$SUPPORT_FEATURES libz"
 fi
+if test "x$HAVE_BROTLI" = "x1"; then
+  SUPPORT_FEATURES="$SUPPORT_FEATURES brotli"
+fi
 if test "x$USE_ARES" = "x1" -o "x$USE_THREADS_POSIX" = "x1" \
                             -o "x$USE_THREADS_WIN32" = "x1"; then
   SUPPORT_FEATURES="$SUPPORT_FEATURES AsynchDNS"
@@ -2957,6 +3051,7 @@ AC_MSG_NOTICE([Configured to build gnurl/libgnurl:
   SSL support:      ${curl_ssl_msg}
   SSH support:      ${curl_ssh_msg}
   zlib support:     ${curl_zlib_msg}
+  brotli support:   ${curl_brotli_msg}
   GSS-API support:  ${curl_gss_msg}
   TLS-SRP support:  ${curl_tls_srp_msg}
   resolver:         ${curl_res_msg}
diff --git a/docs/BUGS b/docs/BUGS
index 3c8fa9fcc..33f06cedc 100644
--- a/docs/BUGS
+++ b/docs/BUGS
@@ -63,7 +63,7 @@ BUGS
   Security related bugs or bugs that are suspected to have a security impact,
   should be reported by email to address@hidden so that they first can
   be dealt with away from the public to minimize the harm and impact it will
-  have on existing users out there who might be using the vulernable versions.
+  have on existing users out there who might be using the vulnerable versions.
 
   The curl project's process for handling security related issues is
   documented here:
@@ -186,7 +186,7 @@ BUGS
   include the version number of the curl you're using when you experience the
   issue. If that version number shows us that you're using an out-of-date
   curl, you should also try out a modern curl version to see if the problem
-  persists or how/if it has changed in apperance.
+  persists or how/if it has changed in appearance.
 
   Even if you cannot immediately upgrade your application/system to run the
   latest curl version, you can most often at least run a test version or
@@ -290,8 +290,8 @@ BUGS
   The issue and pull request trackers on https://github.com/curl/curl will
   only hold "active" entries (using a non-precise definition of what active
   actually is, but they're at least not completely dead). Those that are
-  abandonded or in other ways dormant will be closed and sometimes added to
+  abandoned or in other ways dormant will be closed and sometimes added to
   TODO and KNOWN_BUGS instead.
 
   This way, we only have "active" issues open on github. Irrelevant issues and
-  pull requests will not distract developes or casual visitors.
+  pull requests will not distract developers or casual visitors.
diff --git a/docs/HELP-US.md b/docs/HELP-US.md
index d37ad9480..aae2b9f59 100644
--- a/docs/HELP-US.md
+++ b/docs/HELP-US.md
@@ -15,7 +15,7 @@ found yourself or perhaps got annoyed at in the past. It can 
be a spelling
 error in an error text or a weirdly phrased section in a man page. Hunt it
 down and report the bug. Or make your first pull request with a fix for that.
 
-## PR-welcome
+## Help wanted
 
 In the issue tracker we occasionally mark bugs with [help
 wanted](https://github.com/curl/curl/labels/help%20wanted), as a sign that the
diff --git a/docs/INTERNALS.md b/docs/INTERNALS.md
index 2e273a9dc..459684ba2 100644
--- a/docs/INTERNALS.md
+++ b/docs/INTERNALS.md
@@ -82,7 +82,7 @@ Dependencies
  - zlib         1.1.4
  - libssh2      0.16
  - c-ares       1.6.0
- - libidn       0.4.1
+ - libidn2      2.0.0
  - cyassl       2.0.0
  - openldap     2.0
  - MIT Kerberos 1.2.4
@@ -612,20 +612,6 @@ curlx
    strtoll() (or equivalent) function exist on your platform. If `curl_off_t`
    is only a 32 bit number on your platform, this macro uses strtol().
 
-`curlx_tvnow()`
----------------
-   returns a struct timeval for the current time.
-
-`curlx_tvdiff()`
---------------
-   returns the difference between two timeval structs, in number of
-   milliseconds.
-
-`curlx_tvdiff_secs()`
----------------------
-   returns the same as `curlx_tvdiff` but with full usec resolution (as a
-   double)
-
 Future
 ------
 
@@ -656,29 +642,29 @@ Content Encoding
 ## About content encodings
 
  [HTTP/1.1][4] specifies that a client may request that a server encode its
- response. This is usually used to compress a response using one of a set of
- commonly available compression techniques. These schemes are 'deflate' (the
- zlib algorithm), 'gzip' and 'compress'. A client requests that the server
- perform an encoding by including an Accept-Encoding header in the request
- document. The value of the header should be one of the recognized tokens
- 'deflate', ... (there's a way to register new schemes/tokens, see sec 3.5 of
- the spec). A server MAY honor the client's encoding request. When a response
- is encoded, the server includes a Content-Encoding header in the
- response. The value of the Content-Encoding header indicates which scheme was
- used to encode the data.
-
- A client may tell a server that it can understand several different encoding
- schemes. In this case the server may choose any one of those and use it to
- encode the response (indicating which one using the Content-Encoding header).
+ response. This is usually used to compress a response using one (or more)
+ encodings from a set of commonly available compression techniques. These
+ schemes include 'deflate' (the zlib algorithm), 'gzip' 'br' (brotli) and
+ 'compress'. A client requests that the server perform an encoding by including
+ an Accept-Encoding header in the request document. The value of the header
+ should be one of the recognized tokens 'deflate', ... (there's a way to
+ register new schemes/tokens, see sec 3.5 of the spec). A server MAY honor
+ the client's encoding request. When a response is encoded, the server
+ includes a Content-Encoding header in the response. The value of the
+ Content-Encoding header indicates which encodings were used to encode the
+ data, in the order in which they were applied.
+
  It's also possible for a client to attach priorities to different schemes so
  that the server knows which it prefers. See sec 14.3 of RFC 2616 for more
- information on the Accept-Encoding header.
+ information on the Accept-Encoding header. See sec [3.1.2.2 of RFC 7231][15]
+ for more information on the Content-Encoding header.
 
 ## Supported content encodings
 
- The 'deflate' and 'gzip' content encoding are supported by libcurl. Both
- regular and chunked transfers work fine.  The zlib library is required for
- this feature.
+ The 'deflate', 'gzip' and 'br' content encodings are supported by libcurl.
+ Both regular and chunked transfers work fine.  The zlib library is required
+ for the 'deflate' and 'gzip' encodings, while the brotli decoding library is
+ for the 'br' encoding.
 
 ## The libcurl interface
 
@@ -688,14 +674,15 @@ Content Encoding
 
  where string is the intended value of the Accept-Encoding header.
 
- Currently, libcurl only understands how to process responses that use the
- "deflate" or "gzip" Content-Encoding, so the only values for
- [`CURLOPT_ACCEPT_ENCODING`][5] that will work (besides "identity," which does
- nothing) are "deflate" and "gzip" If a response is encoded using the
- "compress" or methods, libcurl will return an error indicating that the
- response could not be decoded.  If <string> is NULL no Accept-Encoding header
- is generated.  If <string> is a zero-length string, then an Accept-Encoding
- header containing all supported encodings will be generated.
+ Currently, libcurl does support multiple encodings but only
+ understands how to process responses that use the "deflate", "gzip" and/or
+ "br" content encodings, so the only values for [`CURLOPT_ACCEPT_ENCODING`][5]
+ that will work (besides "identity," which does nothing) are "deflate",
+ "gzip" and "br". If a response is encoded using the "compress" or methods,
+ libcurl will return an error indicating that the response could
+ not be decoded.  If <string> is NULL no Accept-Encoding header is generated.
+ If <string> is a zero-length string, then an Accept-Encoding header
+ containing all supported encodings will be generated.
 
  The [`CURLOPT_ACCEPT_ENCODING`][5] must be set to any non-NULL value for
  content to be automatically decoded.  If it is not set and the server still
@@ -1091,3 +1078,4 @@ for older and later versions as things don't change 
drastically that often.
 [12]: https://curl.haxx.se/libcurl/c/curl_multi_fdset.html
 [13]: https://curl.haxx.se/libcurl/c/curl_multi_add_handle.html
 [14]: https://curl.haxx.se/libcurl/c/curl_multi_info_read.html
+[15]: https://tools.ietf.org/html/rfc7231#section-3.1.2.2
diff --git a/docs/Makefile.am b/docs/Makefile.am
index 70da87ad5..2ce22b8e4 100644
--- a/docs/Makefile.am
+++ b/docs/Makefile.am
@@ -81,3 +81,6 @@ pdf: $(PDFPAGES)
        rm $$foo.ps; \
        echo "converted $< to $@")
 
+distclean:
+       rm -f $(CLEANFILES)
+
diff --git a/docs/RESOURCES b/docs/RESOURCES
index 1ad8aac31..2880b8fb0 100644
--- a/docs/RESOURCES
+++ b/docs/RESOURCES
@@ -81,3 +81,5 @@ This document lists documents and standards used by curl.
   RFC 4616 - PLAIN authentication
 
   RFC 4954 - SMTP Authentication
+
+  RFC 7932 - Brotli Compressed Data Format
diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md
index 1007ccb02..64989b1be 100644
--- a/docs/ROADMAP.md
+++ b/docs/ROADMAP.md
@@ -1,20 +1,14 @@
 curl the next few years - perhaps
 =================================
 
-Roadmap of things Daniel Stenberg and Steve Holme want to work on next. It is
-intended to serve as a guideline for others for information, feedback and
-possible participation.
+Roadmap of things Daniel Stenberg wants to work on next. It is intended to
+serve as a guideline for others for information, feedback and possible
+participation.
 
 QUIC
 ----
 
-The standardization process of QUIC has been taken to the IETF and can be
-followed on the [IETF QUIC Mailing
-list](https://www.ietf.org/mailman/listinfo/quic). I'd like us to get on the
-bandwagon. Ideally, this would be done with a separate library/project to
-handle the binary/framing layer in a similar fashion to how HTTP/2 is
-implemented. This, to allow other projects to benefit from the work and to
-thus broaden the interest and chance of others to participate.
+ See the [QUIC wiki page](https://github.com/curl/curl/wiki/QUIC).
 
 HTTP cookies
 ------------
@@ -34,85 +28,15 @@ SRV records
 
 How to find services for specific domains/hosts.
 
-curl_formadd()
---------------
-
-make sure there's an easy handle passed in to `curl_formadd()`,
-`curl_formget()` and `curl_formfree()` by adding replacement functions and
-deprecating the old ones to allow custom mallocs and more.
-
-Or perhaps even better: revamp the formpost API completely while we're at it
-and making something that is easier to use and understand:
-
- https://github.com/curl/curl/wiki/formpost-API-redesigned
-
-Third-party SASL
-----------------
-
-Add support for third-party SASL libraries such as Cyrus SASL.
-
-SASL authentication in LDAP
----------------------------
-
-...
-
-Simplify the SMTP email
------------------------
-
-Simplify the SMTP email interface so that programmers don't have to
-construct the body of an email that contains all the headers, alternative
-content, images and attachments - maintain raw interface so that
-programmers that want to do this can
-
-email capabilities
-------------------
-
-Allow the email protocols to return the capabilities before
-authenticating. This will allow an application to decide on the best
-authentication mechanism
-
-Win32 pthreads
---------------
-
-Allow Windows threading model to be replaced by Win32 pthreads port
-
-dynamic buffer size
--------------------
-
-Implement a dynamic buffer size to allow SFTP to use much larger buffers and
-possibly allow the size to be customizable by applications. Use less memory
-when handles are not in use?
-
-New stuff - curl
-----------------
-
-1. Embed a language interpreter (lua?). For that middle ground where curl
-   isn’t enough and a libcurl binding feels “too much”. Build-time conditional
-   of course.
-
-2. Simplify the SMTP command line so that the headers and multi-part content
-   don't have to be constructed before calling curl
-
 Improve
 -------
 
-1. build for windows (considered hard by many users)
-
-2. curl -h output (considered overwhelming to users)
+1. curl -h output (considered overwhelming to users).
 
-3. we have > 200 command line options, is there a way to redo things to
+2. We have > 200 command line options, is there a way to redo things to
    simplify or improve the situation as we are likely to keep adding
-   features/options in the future too
-
-4. authentication framework (consider merging HTTP and SASL authentication to
-   give one API for protocols to call)
+   features/options in the future too.
 
-5. Perform some of the clean up from the TODO document, removing old
+3. Perform some of the clean up from the TODO document, removing old
    definitions and such like that are currently earmarked to be removed years
-   ago
-
-Remove
-------
-
-1. makefile.vc files as there is no point in maintaining two sets of Windows
-   makefiles. Note: These are currently being used by the Windows autobuilds
+   ago.
diff --git a/docs/THANKS b/docs/THANKS
index 14a131938..f71a3f1b9 100644
--- a/docs/THANKS
+++ b/docs/THANKS
@@ -40,8 +40,10 @@ Alex Bligh
 Alex Chan
 Alex Fishman
 Alex Gruz
+Alex Malinovich
 Alex McLellan
 Alex Neblett
+Alex Nichols
 Alex Potapenko
 Alex Rousskov
 Alex Suykov
@@ -66,6 +68,7 @@ Alexey Simak
 Alexey Zakhlestin
 Alexis Carvalho
 Alexis La Goutte
+Alfonso Martone
 Alfred Gebert
 Allen Pulsifer
 Alona Rossen
@@ -104,6 +107,7 @@ Andrew Francis
 Andrew Fuller
 Andrew Krieger
 Andrew Kurushin
+Andrew Lambert
 Andrew Moise
 Andrew Robbins
 Andrew Wansink
@@ -307,6 +311,7 @@ Dan Nelson
 Dan Petitt
 Dan Torop
 Dan Zitter
+Daniel Bankhead
 Daniel Black
 Daniel Cater
 Daniel Egger
@@ -392,6 +397,7 @@ Dirk Eddelbuettel
 Dirk Feytons
 Dirk Manske
 Dmitri Shubin
+Dmitri Tikhonov
 Dmitriy Sergeyev
 Dmitry Bartsevich
 Dmitry Eremin-Solenikov
@@ -749,6 +755,7 @@ John Marino
 John Marshall
 John McGowan
 John P. McCaskey
+John Starks
 John Suprock
 John Wanghui
 John Wilkinson
@@ -796,6 +803,7 @@ Julien Nabet
 Julien Royer
 Jun-ichiro itojun Hagino
 Jurij Smakov
+Juro Bystricky
 Justin Clift
 Justin Ehlert
 Justin Fletcher
@@ -895,6 +903,7 @@ Loic Dachary
 Loren Kirkby
 Luan Cestari
 Luca Altea
+Luca Boccassi
 Lucas Adamski
 Lucas Pardue
 Ludek Finstrle
@@ -992,6 +1001,7 @@ Matteo Rocco
 Matthew Blain
 Matthew Clarke
 Matthew Hall
+Matthew Kerwin
 Matthias Bolte
 Maurice Barnum
 Mauro Iorio
@@ -1012,6 +1022,7 @@ Michael Calmer
 Michael Cronenworth
 Michael Curtis
 Michael Day
+Michael Felt
 Michael Goffioul
 Michael Jahn
 Michael Jerris
@@ -1156,14 +1167,17 @@ Paul Oliver
 Paul Querna
 Paul Saab
 Pavel Cenek
+Pavel Gushchin
 Pavel Orehov
 Pavel P
 Pavel Raiskup
 Pavel Rochnyak
+Pavol Markovic
 Pawel A. Gajda
 Pawel Kierski
 Pedro Larroy
 Pedro Neves
+Per Lundberg
 Per Malmberg
 Peter Bray
 Peter Forret
@@ -1177,6 +1191,7 @@ Peter Lamberg
 Peter Laser
 Peter O'Gorman
 Peter Pentchev
+Peter Piekarski
 Peter Silva
 Peter Su
 Peter Sylvester
@@ -1189,6 +1204,7 @@ Peteris Krumins
 Petr Bahula
 Petr Novak
 Petr Pisar
+Petr Voytsik
 Phil Blundell
 Phil Crump
 Phil Karn
@@ -1275,6 +1291,7 @@ Rick Jones
 Rick Richardson
 Ricki Hirner
 Rider Linden
+Rob Cotrone
 Rob Crittenden
 Rob Davies
 Rob Jones
@@ -1592,13 +1609,16 @@ Zenju on github
 Zmey Petroff
 Zvi Har'El
 afrind on github
+arainchik on github
 asavah on github
 baumanj on github
 bsammon on github
 canavan on github
+cbartl on github
 destman on github
 dkjjr89 on github
 eXeC64 on github
+hsiao yi
 imilli on github
 jonrumsey on github
 joshhe on github
@@ -1611,11 +1631,13 @@ madblobfish on github
 marc-groundctl on github
 mccormickt12 on github
 mkzero on github
+moohoorama on github
 neex on github
 neheb on github
 nk
 nopjmp on github
 olesteban on github
+omau on github
 ovidiu-benea on github
 paulharris on github
 silveja1 on github
@@ -1626,6 +1648,7 @@ tommink[at]post.pl
 vanillajonathan on github
 wmsch on github
 wyattoday on github
+youngchopin on github
 zelinchen on github
 İsmail Dönmez
 Štefan Kremeň
diff --git a/docs/TODO b/docs/TODO
index 264d559ad..4a0d4aed1 100644
--- a/docs/TODO
+++ b/docs/TODO
@@ -56,6 +56,7 @@
  4.5 ASCII support
  4.6 GSSAPI via Windows SSPI
  4.7 STAT for LIST without data connection
+ 4.8 Option to ignore private IP addresses in PASV response
 
  5. HTTP
  5.1 Better persistency for HTTP 1.0
@@ -64,9 +65,8 @@
  5.4 HTTP Digest using SHA-256
  5.5 auth= in URLs
  5.6 Refuse "downgrade" redirects
- 5.7 Brotli compression
- 5.8 QUIC
- 5.10 Leave secure cookies alone
+ 5.7 QUIC
+ 5.8 Leave secure cookies alone
 
  6. TELNET
  6.1 ditch stdin
@@ -449,17 +449,23 @@
 
 4.6 GSSAPI via Windows SSPI
 
-In addition to currently supporting the SASL GSSAPI mechanism (Kerberos V5)
-via third-party GSS-API libraries, such as Heimdal or MIT Kerberos, also add
-support for GSSAPI authentication via Windows SSPI.
+ In addition to currently supporting the SASL GSSAPI mechanism (Kerberos V5)
+ via third-party GSS-API libraries, such as Heimdal or MIT Kerberos, also add
+ support for GSSAPI authentication via Windows SSPI.
 
 4.7 STAT for LIST without data connection
 
-Some FTP servers allow STAT for listing directories instead of using LIST, and
-the response is then sent over the control connection instead of as the
-otherwise usedw data connection: http://www.nsftools.com/tips/RawFTP.htm#STAT
+ Some FTP servers allow STAT for listing directories instead of using LIST,
+ and the response is then sent over the control connection instead of as the
+ otherwise usedw data connection: http://www.nsftools.com/tips/RawFTP.htm#STAT
 
-This is not detailed in any FTP specification.
+ This is not detailed in any FTP specification.
+
+4.8 Option to ignore private IP addresses in PASV response
+
+ Some servers respond with and some other FTP client implementations can
+ ignore private (RFC 1918 style) IP addresses when received in PASV responses.
+ To consider for libcurl as well. See https://github.com/curl/curl/issues/1455
 
 5. HTTP
 
@@ -514,13 +520,7 @@ This is not detailed in any FTP specification.
  Consider a way to tell curl to refuse to "downgrade" protocol with a redirect
  and/or possibly a bit that refuses redirect to change protocol completely.
 
-5.7 Brotli compression
-
- Brotli compression performs better than gzip and is being implemented by
- browsers and servers widely. The algorithm: https://github.com/google/brotli
- The Firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=366559
-
-5.8 QUIC
+5.7 QUIC
 
  The standardization process of QUIC has been taken to the IETF and can be
  followed on the [IETF QUIC Mailing
@@ -530,7 +530,7 @@ This is not detailed in any FTP specification.
  implemented. This, to allow other projects to benefit from the work and to
  thus broaden the interest and chance of others to participate.
 
-5.10 Leave secure cookies alone
+5.8 Leave secure cookies alone
 
  Non-secure origins (HTTP sites) should not be allowed to set or modify
  cookies with the 'secure' property:
diff --git a/docs/cmdline-opts/form.d b/docs/cmdline-opts/form.d
index b3251bdb8..d95d0cc38 100644
--- a/docs/cmdline-opts/form.d
+++ b/docs/cmdline-opts/form.d
@@ -57,6 +57,11 @@ or
 Note that if a filename/path is quoted by double-quotes, any double-quote
 or backslash within the filename must be escaped by backslash.
 
+Quoting must also be applied to non-file data if it contains semicolons,
+leading/trailing spaces or leading double quotes:
+
+ curl -F 'colors="red; green; blue";type=text/x-myapp' example.com
+
 You can add custom headers to the field by setting headers=, like
 
   curl -F "submit=OK;headers=\\"X-submit-type: OK\\"" example.com
diff --git a/docs/cmdline-opts/interface.d b/docs/cmdline-opts/interface.d
index da84cd2b6..bd0817618 100644
--- a/docs/cmdline-opts/interface.d
+++ b/docs/cmdline-opts/interface.d
@@ -10,3 +10,7 @@ name, IP address or host name. An example could look like:
  curl --interface eth0:1 https://www.example.com/
 
 If this option is used several times, the last one will be used.
+
+On Linux it can be used to specify a VRF, but the binary needs to either
+have CAP_NET_RAW or to be ran as root. More information about Linux VRF:
+https://www.kernel.org/doc/Documentation/networking/vrf.txt
diff --git a/docs/cmdline-opts/resolve.d b/docs/cmdline-opts/resolve.d
index ba3967a14..91539b8e9 100644
--- a/docs/cmdline-opts/resolve.d
+++ b/docs/cmdline-opts/resolve.d
@@ -14,4 +14,6 @@ different ports.
 The provided address set by this option will be used even if --ipv4 or --ipv6
 is set to make curl use another IP version.
 
+Support for providing the IP address within [brackets] was added in 7.57.0.
+
 This option can be used many times to add many host names to resolve.
diff --git a/docs/examples/Makefile.inc b/docs/examples/Makefile.inc
index 71b804c75..075df9ea2 100644
--- a/docs/examples/Makefile.inc
+++ b/docs/examples/Makefile.inc
@@ -33,7 +33,8 @@ check_PROGRAMS = 10-at-a-time anyauthput cookie_interface 
debug fileupload \
   imap-search imap-create imap-delete imap-copy imap-noop imap-ssl         \
   imap-tls imap-multi url2file sftpget ftpsget postinmemory http2-download \
   http2-upload http2-serverpush getredirect ftpuploadfrommem               \
-  ftpuploadresume sslbackend postit2-formadd multi-formadd
+  ftpuploadresume sslbackend postit2-formadd multi-formadd                 \
+  shared-connection-cache
 
 # These examples require external dependencies that may not be commonly
 # available on POSIX systems, so don't bother attempting to compile them here.
diff --git a/docs/examples/curlx.c b/docs/examples/curlx.c
index 24579fa2a..714669b50 100644
--- a/docs/examples/curlx.c
+++ b/docs/examples/curlx.c
@@ -537,7 +537,7 @@ int main(int argc, char **argv)
              res = curl_easy_perform(p.curl));
   {
     int result = curl_easy_getinfo(p.curl, CURLINFO_CONTENT_TYPE, &response);
-    if(mimetypeaccept && p.verbose)
+    if(mimetypeaccept && p.verbose) {
       if(!strcmp(mimetypeaccept, response))
         BIO_printf(p.errorbio, "the response has a correct mimetype : %s\n",
                    response);
@@ -545,6 +545,7 @@ int main(int argc, char **argv)
         BIO_printf(p.errorbio, "the response doesn\'t have an acceptable "
                    "mime type, it is %s instead of %s\n",
                    response, mimetypeaccept);
+    }
   }
 
   /*** code d'erreur si accept mime ***, egalement code return HTTP != 200 ***/
diff --git a/docs/examples/rtsp.c b/docs/examples/rtsp.c
index fe3e74df9..ded3cae70 100644
--- a/docs/examples/rtsp.c
+++ b/docs/examples/rtsp.c
@@ -129,6 +129,9 @@ static void rtsp_play(CURL *curl, const char *uri, const 
char *range)
   my_curl_easy_setopt(curl, CURLOPT_RANGE, range);
   my_curl_easy_setopt(curl, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_PLAY);
   my_curl_easy_perform(curl);
+
+  /* switch off using range again */
+  my_curl_easy_setopt(curl, CURLOPT_RANGE, NULL);
 }
 
 
diff --git a/docs/examples/shared-connection-cache.c 
b/docs/examples/shared-connection-cache.c
new file mode 100644
index 000000000..a1aa0d674
--- /dev/null
+++ b/docs/examples/shared-connection-cache.c
@@ -0,0 +1,85 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <address@hidden>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+/* <DESC>
+ * Connection cache shared between easy handles with the share inteface
+ * </DESC>
+ */
+#include <stdio.h>
+#include <curl/curl.h>
+
+static void my_lock(CURL *handle, curl_lock_data data,
+                    curl_lock_access laccess, void *useptr)
+{
+  (void)handle;
+  (void)data;
+  (void)laccess;
+  (void)useptr;
+  fprintf(stderr, "-> Mutex lock\n");
+}
+
+static void my_unlock(CURL *handle, curl_lock_data data, void *useptr)
+{
+  (void)handle;
+  (void)data;
+  (void)useptr;
+  fprintf(stderr, "<- Mutex unlock\n");
+}
+
+int main(void)
+{
+  CURL *curl;
+  CURLcode res;
+  CURLSH *share;
+  int i;
+
+  share = curl_share_init();
+  curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT);
+
+  curl_share_setopt(share, CURLSHOPT_LOCKFUNC, my_lock);
+  curl_share_setopt(share, CURLSHOPT_UNLOCKFUNC, my_unlock);
+
+  /* Loop the transfer and cleanup the handle properly every lap. This will
+     still reuse connections since the pool is in the shared object! */
+
+  for(i = 0; i < 3; i++) {
+    curl = curl_easy_init();
+    if(curl) {
+      curl_easy_setopt(curl, CURLOPT_URL, "https://curl.haxx.se/";);
+
+      /* use the share object */
+      curl_easy_setopt(curl, CURLOPT_SHARE, share);
+
+      /* Perform the request, res will get the return code */
+      res = curl_easy_perform(curl);
+      /* Check for errors */
+      if(res != CURLE_OK)
+        fprintf(stderr, "curl_easy_perform() failed: %s\n",
+                curl_easy_strerror(res));
+
+      /* always cleanup */
+      curl_easy_cleanup(curl);
+    }
+  }
+
+  curl_share_cleanup(share);
+  return 0;
+}
diff --git a/docs/libcurl/gnurl_global_init.3 b/docs/libcurl/gnurl_global_init.3
index 2d32e6474..6ff5b774b 100644
--- a/docs/libcurl/gnurl_global_init.3
+++ b/docs/libcurl/gnurl_global_init.3
@@ -62,6 +62,9 @@ Initialize everything possible. This sets all known bits 
except
 \fBCURL_GLOBAL_ACK_EINTR\fP.
 
 .IP CURL_GLOBAL_SSL
+(This flag's presence or absense serves no meaning since 7.57.0. The
+description below is for older libcurl versions.)
+
 Initialize SSL.
 
 The implication here is that if this bit is not set, the initialization of the
diff --git a/docs/libcurl/gnurl_mime_filedata.3 
b/docs/libcurl/gnurl_mime_filedata.3
index f522d997f..ca235ad75 100644
--- a/docs/libcurl/gnurl_mime_filedata.3
+++ b/docs/libcurl/gnurl_mime_filedata.3
@@ -41,10 +41,10 @@ safely be reused after this call.
 
 As a side effect, the part's remote file name is set to the base name of the
 given \fIfilename\fP if it is a valid named file. This can be undone or
-overriden by a subsequent call to \fIcurl_mime_filename(3)\fP.
+overridden by a subsequent call to \fIcurl_mime_filename(3)\fP.
 
 The contents of the file is read during the file transfer in a streaming
-manner to allow huge files to get transfered without using much memory. It
+manner to allow huge files to get transferred without using much memory. It
 therefore requires that the file is kept intact during the entire request.
 
 If the file size cannot be determined before actually reading it (such as for
diff --git a/docs/libcurl/gnurl_multi_fdset.3 b/docs/libcurl/gnurl_multi_fdset.3
index a2a7b28b0..a098ed0e6 100644
--- a/docs/libcurl/gnurl_multi_fdset.3
+++ b/docs/libcurl/gnurl_multi_fdset.3
@@ -5,7 +5,7 @@
 .\" *                            | (__| |_| |  _ <| |___
 .\" *                             \___|\___/|_| \_\_____|
 .\" *
-.\" * Copyright (C) 1998 - 2014, Daniel Stenberg, <address@hidden>, et al.
+.\" * Copyright (C) 1998 - 2017, Daniel Stenberg, <address@hidden>, et al.
 .\" *
 .\" * This software is licensed as described in the file COPYING, which
 .\" * you should have received as part of this distribution. The terms
@@ -58,9 +58,10 @@ libcurl set. When libcurl returns -1 in \fImax_fd\fP, it is 
because libcurl
 currently does something that isn't possible for your application to monitor
 with a socket and unfortunately you can then not know exactly when the current
 action is completed using select(). You then need to wait a while before you
-proceed and call \fIcurl_multi_perform(3)\fP anyway. How long to wait? We
-suggest 100 milliseconds at least, but you may want to test it out in your own
-particular conditions to find a suitable value.
+proceed and call \fIcurl_multi_perform(3)\fP anyway. How long to wait? Unless
+\fIcurl_multi_timeout(3)\fP gives you a lower number, we suggest 100
+milliseconds or so, but you may want to test it out in your own particular
+conditions to find a suitable value.
 
 When doing select(), you should use \fIcurl_multi_timeout(3)\fP to figure out
 how long to wait for action. Call \fIcurl_multi_perform(3)\fP even if no
diff --git a/docs/libcurl/gnurl_share_setopt.3 
b/docs/libcurl/gnurl_share_setopt.3
index 9e06b9d38..57fb7d9e5 100644
--- a/docs/libcurl/gnurl_share_setopt.3
+++ b/docs/libcurl/gnurl_share_setopt.3
@@ -5,7 +5,7 @@
 .\" *                            | (__| |_| |  _ <| |___
 .\" *                             \___|\___/|_| \_\_____|
 .\" *
-.\" * Copyright (C) 1998 - 2011, Daniel Stenberg, <address@hidden>, et al.
+.\" * Copyright (C) 1998 - 2017, Daniel Stenberg, <address@hidden>, et al.
 .\" *
 .\" * This software is licensed as described in the file COPYING, which
 .\" * you should have received as part of this distribution. The terms
@@ -70,6 +70,13 @@ object. This will reduce the time spent in the SSL handshake 
when reconnecting
 to the same server. Note SSL session IDs are reused within the same easy handle
 by default. Note this symbol was added in 7.10.3 but was not implemented until
 7.23.0.
+.IP CURL_LOCK_DATA_CONNECT
+Put the connection cache in the share object and make all easy handles using
+this share object share the connection cache. Using this, you can for example
+do multi-threaded libcurl use with one handle in each thread, and yet have a
+shared pool of unused connections and this way get way better connection
+re-use than if you use one separate pool in each thread. Support for this was
+added in 7.57.0, but the symbol existed long before this.
 .RE
 .IP CURLSHOPT_UNSHARE
 This option does the opposite of \fICURLSHOPT_SHARE\fP. It specifies that
diff --git a/docs/libcurl/gnurl_version_info.3 
b/docs/libcurl/gnurl_version_info.3
index 35d7f4522..18d3bd2f5 100644
--- a/docs/libcurl/gnurl_version_info.3
+++ b/docs/libcurl/gnurl_version_info.3
@@ -72,6 +72,12 @@ typedef struct {
 
   const char *libssh_version; /* human readable string */
 
+  /* when 'age' is 4 or higher (7.57.0 or later), the members below also
+     exist  */
+  unsigned int brotli_ver_num; /* Numeric Brotli version
+                                  (MAJOR << 24) | (MINOR << 12) | PATCH */
+  const char *brotli_version; /* human readable string. */
+
 } curl_version_info_data;
 .fi
 
@@ -160,6 +166,8 @@ libcurl was built with support for HTTPS-proxy.
 libcurl was built with multiple SSL backends. For details, see
 \fIcurl_global_sslset(3)\fP.
 (Added in 7.56.0)
+.IP CURL_VERSION_BROTLI
+supports HTTP Brotli content encoding using libbrotlidec (Added in 7.57.0)
 .RE
 \fIssl_version\fP is an ASCII string for the OpenSSL version used. If libcurl
 has no SSL support, this is NULL.
diff --git a/docs/libcurl/libgnurl-share.3 b/docs/libcurl/libgnurl-share.3
index c7cd65548..26e43b8c8 100644
--- a/docs/libcurl/libgnurl-share.3
+++ b/docs/libcurl/libgnurl-share.3
@@ -5,7 +5,7 @@
 .\" *                            | (__| |_| |  _ <| |___
 .\" *                             \___|\___/|_| \_\_____|
 .\" *
-.\" * Copyright (C) 1998 - 2014, Daniel Stenberg, <address@hidden>, et al.
+.\" * Copyright (C) 1998 - 2017, Daniel Stenberg, <address@hidden>, et al.
 .\" *
 .\" * This software is licensed as described in the file COPYING, which
 .\" * you should have received as part of this distribution. The terms
@@ -34,10 +34,9 @@ The share interface was added to enable sharing of data 
between curl
 \&"handles".
 .SH "ONE SET OF DATA - MANY TRANSFERS"
 You can have multiple easy handles share data between them. Have them update
-and use the \fBsame\fP cookie database, DNS cache, TLS session cache! This
-way, each single transfer will take advantage from data updates made by the
-other transfer(s). The sharing interface, however, does not share active or
-persistent connections between different easy handles.
+and use the \fBsame\fP cookie database, DNS cache, TLS session cache and/or
+connection cache! This way, each single transfer will take advantage from data
+updates made by the other transfer(s).
 .SH "SHARE OBJECT"
 You create a shared object with \fIcurl_share_init(3)\fP. It returns a handle
 for a newly created one.
diff --git a/docs/libcurl/libgnurl-tutorial.3 b/docs/libcurl/libgnurl-tutorial.3
index 187d5ca0f..6b23057de 100644
--- a/docs/libcurl/libgnurl-tutorial.3
+++ b/docs/libcurl/libgnurl-tutorial.3
@@ -1222,7 +1222,7 @@ alternative and a file attachment encoded in base64:
 .nf
  curl_mime *message = curl_mime_init(easyhandle);
 
- /* The inline part is an alterative proposing the html and the text
+ /* The inline part is an alternative proposing the html and the text
     versions of the e-mail. */
  curl_mime *alt = curl_mime_init(easyhandle);
 
diff --git a/docs/libcurl/opts/GNURLINFO_HTTPAUTH_AVAIL.3 
b/docs/libcurl/opts/GNURLINFO_HTTPAUTH_AVAIL.3
index 4937086ae..235abd03e 100644
--- a/docs/libcurl/opts/GNURLINFO_HTTPAUTH_AVAIL.3
+++ b/docs/libcurl/opts/GNURLINFO_HTTPAUTH_AVAIL.3
@@ -62,7 +62,8 @@ if(curl) {
 }
 .fi
 .SH AVAILABILITY
-Added in 7.10.8
+Added RFC2617 in 7.10.8
+Added RFC7616 in 7.57.0
 .SH RETURN VALUE
 Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
 .SH "SEE ALSO"
diff --git a/docs/libcurl/opts/GNURLINFO_PROXYAUTH_AVAIL.3 
b/docs/libcurl/opts/GNURLINFO_PROXYAUTH_AVAIL.3
index ab404449c..429a8a25c 100644
--- a/docs/libcurl/opts/GNURLINFO_PROXYAUTH_AVAIL.3
+++ b/docs/libcurl/opts/GNURLINFO_PROXYAUTH_AVAIL.3
@@ -63,7 +63,8 @@ if(curl) {
 }
 .fi
 .SH AVAILABILITY
-Added in 7.10.8
+Added RFC2617 in 7.10.8
+Added RFC7616 in 7.57.0
 .SH RETURN VALUE
 Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
 .SH "SEE ALSO"
diff --git a/docs/libcurl/opts/GNURLOPT_RESOLVE.3 
b/docs/libcurl/opts/GNURLOPT_RESOLVE.3
index 13fe1ea12..e321f000f 100644
--- a/docs/libcurl/opts/GNURLOPT_RESOLVE.3
+++ b/docs/libcurl/opts/GNURLOPT_RESOLVE.3
@@ -5,7 +5,7 @@
 .\" *                            | (__| |_| |  _ <| |___
 .\" *                             \___|\___/|_| \_\_____|
 .\" *
-.\" * Copyright (C) 1998 - 2016, Daniel Stenberg, <address@hidden>, et al.
+.\" * Copyright (C) 1998 - 2017, Daniel Stenberg, <address@hidden>, et al.
 .\" *
 .\" * This software is licensed as described in the file COPYING, which
 .\" * you should have received as part of this distribution. The terms
@@ -55,6 +55,8 @@ Remove names from the DNS cache again, to stop providing 
these fake resolves,
 by including a string in the linked list that uses the format
 \&"-HOST:PORT". The host name must be prefixed with a dash, and the host name
 and port number must exactly match what was already added previously.
+
+Support for providing the ADDRESS within [brackets] was added in 7.57.0.
 .SH DEFAULT
 NULL
 .SH PROTOCOLS
diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions
index f912fb719..7878b227f 100644
--- a/docs/libcurl/symbols-in-versions
+++ b/docs/libcurl/symbols-in-versions
@@ -699,6 +699,7 @@ CURLUSESSL_ALL                  7.17.0
 CURLUSESSL_CONTROL              7.17.0
 CURLUSESSL_NONE                 7.17.0
 CURLUSESSL_TRY                  7.17.0
+CURLVERSION_FIFTH               7.57.0
 CURLVERSION_FIRST               7.10
 CURLVERSION_FOURTH              7.16.1
 CURLVERSION_NOW                 7.10
@@ -829,6 +830,7 @@ CURL_TIMECOND_NONE              7.9.7
 CURL_TLSAUTH_NONE               7.21.4
 CURL_TLSAUTH_SRP                7.21.4
 CURL_VERSION_ASYNCHDNS          7.10.7
+CURL_VERSION_BROTLI             7.57.0
 CURL_VERSION_CONV               7.15.4
 CURL_VERSION_CURLDEBUG          7.19.6
 CURL_VERSION_DEBUG              7.10.6
diff --git a/include/gnurl/curl.h b/include/gnurl/curl.h
index 7139a3311..9ad5c20df 100644
--- a/include/gnurl/curl.h
+++ b/include/gnurl/curl.h
@@ -2514,7 +2514,7 @@ typedef enum {
   CURLCLOSEPOLICY_LAST /* last, never use this */
 } curl_closepolicy;
 
-#define CURL_GLOBAL_SSL (1<<0)
+#define CURL_GLOBAL_SSL (1<<0) /* no purpose since since 7.57.0 */
 #define CURL_GLOBAL_WIN32 (1<<1)
 #define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32)
 #define CURL_GLOBAL_NOTHING 0
@@ -2592,6 +2592,7 @@ typedef enum {
   CURLVERSION_SECOND,
   CURLVERSION_THIRD,
   CURLVERSION_FOURTH,
+  CURLVERSION_FIFTH,
   CURLVERSION_LAST /* never actually use this */
 } CURLversion;
 
@@ -2600,7 +2601,7 @@ typedef enum {
    meant to be a built-in version number for what kind of struct the caller
    expects. If the struct ever changes, we redefine the NOW to another enum
    from above. */
-#define CURLVERSION_NOW CURLVERSION_FOURTH
+#define CURLVERSION_NOW CURLVERSION_FIFTH
 
 typedef struct {
   CURLversion age;          /* age of the returned struct */
@@ -2628,6 +2629,12 @@ typedef struct {
 
   const char *libssh_version; /* human readable string */
 
+  /* These fields were added in CURLVERSION_FIFTH */
+
+  unsigned int brotli_ver_num; /* Numeric Brotli version
+                                  (MAJOR << 24) | (MINOR << 12) | PATCH */
+  const char *brotli_version; /* human readable string. */
+
 } curl_version_info_data;
 
 #define CURL_VERSION_IPV6         (1<<0)  /* IPv6-enabled */
@@ -2658,6 +2665,7 @@ typedef struct {
                                              for cookie domain verification */
 #define CURL_VERSION_HTTPS_PROXY  (1<<21) /* HTTPS-proxy support built-in */
 #define CURL_VERSION_MULTI_SSL    (1<<22) /* Multiple SSL backends available */
+#define CURL_VERSION_BROTLI       (1<<23) /* Brotli features are present. */
 
  /*
  * NAME curl_version_info()
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index d6c996189..1fabdba90 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -108,7 +108,24 @@ if(WIN32)
   endif()
 endif()
 
+target_include_directories(${LIB_NAME} INTERFACE
+       $<INSTALL_INTERFACE:include>)
+
 install(TARGETS ${LIB_NAME}
+  EXPORT libcurl-target
   ARCHIVE DESTINATION lib
   LIBRARY DESTINATION lib
-  RUNTIME DESTINATION bin)
+  RUNTIME DESTINATION bin
+)
+
+export(TARGETS ${LIB_NAME}
+       APPEND FILE ${PROJECT_BINARY_DIR}/libcurl-target.cmake
+       NAMESPACE CURL::
+)
+
+install(EXPORT libcurl-target
+        FILE libcurl-target.cmake
+        NAMESPACE CURL::
+        DESTINATION ${CURL_INSTALL_CMAKE_DIR}
+)
+
diff --git a/lib/Makefile.inc b/lib/Makefile.inc
index 5c0b930cf..0a88b8eb8 100644
--- a/lib/Makefile.inc
+++ b/lib/Makefile.inc
@@ -5,7 +5,7 @@
 #                            | (__| |_| |  _ <| |___
 #                             \___|\___/|_| \_\_____|
 #
-# Copyright (C) 1998 - 2016, Daniel Stenberg, <address@hidden>, et al.
+# Copyright (C) 1998 - 2017, Daniel Stenberg, <address@hidden>, et al.
 #
 # This software is licensed as described in the file COPYING, which
 # you should have received as part of this distribution. The terms
@@ -54,7 +54,7 @@ LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c 
formdata.c   \
   http_ntlm.c curl_ntlm_wb.c curl_ntlm_core.c curl_sasl.c rand.c        \
   curl_multibyte.c hostcheck.c conncache.c pipeline.c dotdot.c          \
   x509asn1.c http2.c smb.c curl_endian.c curl_des.c system_win32.c      \
-  mime.c
+  mime.c sha256.c setopt.c
 
 LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \
   formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h if2ip.h         \
@@ -73,7 +73,7 @@ LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h 
progress.h \
   curl_sasl.h curl_multibyte.h hostcheck.h conncache.h                  \
   curl_setup_once.h multihandle.h setup-vms.h pipeline.h dotdot.h       \
   x509asn1.h http2.h sigpipe.h smb.h curl_endian.h curl_des.h           \
-  curl_printf.h system_win32.h rand.h mime.h
+  curl_printf.h system_win32.h rand.h mime.h curl_sha256.h setopt.h
 
 LIB_RCFILES = libcurl.rc
 
diff --git a/lib/Makefile.m32 b/lib/Makefile.m32
index 1389b8539..773187ad7 100644
--- a/lib/Makefile.m32
+++ b/lib/Makefile.m32
@@ -23,7 +23,8 @@
 ###########################################################################
 #
 ## Makefile for building libcurl.a with MingW (GCC-3.2 or later or LLVM/Clang)
-## and optionally OpenSSL (1.0.2a), libssh2 (1.5), zlib (1.2.8), librtmp (2.4)
+## and optionally OpenSSL (1.0.2a), libssh2 (1.5), zlib (1.2.8), librtmp (2.4),
+## brotli (1.0.1)
 ##
 ## Usage:   mingw32-make -f Makefile.m32 
CFG=-feature1[-feature2][-feature3][...]
 ## Example: mingw32-make -f Makefile.m32 CFG=-zlib-ssl-sspi-winidn
@@ -38,6 +39,10 @@
 ifndef ZLIB_PATH
 ZLIB_PATH = ../../zlib-1.2.8
 endif
+# Edit the path below to point to the base of your Brotli sources.
+ifndef BROTLI_PATH
+BROTLI_PATH = ../../brotli-1.0.1
+endif
 # Edit the path below to point to the base of your OpenSSL package.
 ifndef OPENSSL_PATH
 OPENSSL_PATH = ../../openssl-1.0.2a
@@ -175,6 +180,9 @@ endif
 ifeq ($(findstring -zlib,$(CFG)),-zlib)
 ZLIB = 1
 endif
+ifeq ($(findstring -brotli,$(CFG)),-brotli)
+BROTLI = 1
+endif
 ifeq ($(findstring -idn2,$(CFG)),-idn2)
 IDN2 = 1
 endif
@@ -280,6 +288,16 @@ ifdef ZLIB
   CFLAGS += -DHAVE_LIBZ -DHAVE_ZLIB_H
   DLL_LIBS += -L"$(ZLIB_PATH)" -lz
 endif
+ifdef BROTLI
+  INCLUDES += -I"$(BROTLI_PATH)/include"
+  CFLAGS += -DHAVE_BROTLI
+  DLL_LIBS += -L"$(BROTLI_PATH)/lib"
+  ifdef BROTLI_LIBS
+    DLL_LIBS += $(BROTLI_LIBS)
+  else
+    DLL_LIBS += -lbrotlidec
+  endif
+endif
 ifdef IDN2
   INCLUDES += -I"$(LIBIDN2_PATH)/include"
   CFLAGS += -DUSE_LIBIDN2
diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c
index 87e70b4d9..38ede999c 100644
--- a/lib/asyn-ares.c
+++ b/lib/asyn-ares.c
@@ -22,6 +22,14 @@
 
 #include "curl_setup.h"
 
+/***********************************************************************
+ * Only for ares-enabled builds
+ * And only for functions that fulfill the asynch resolver backend API
+ * as defined in asyn.h, nothing else belongs in this file!
+ **********************************************************************/
+
+#ifdef CURLRES_ARES
+
 #ifdef HAVE_LIMITS_H
 #include <limits.h>
 #endif
@@ -48,14 +56,6 @@
 #define in_addr_t unsigned long
 #endif
 
-/***********************************************************************
- * Only for ares-enabled builds
- * And only for functions that fulfill the asynch resolver backend API
- * as defined in asyn.h, nothing else belongs in this file!
- **********************************************************************/
-
-#ifdef CURLRES_ARES
-
 #include "urldata.h"
 #include "sendf.h"
 #include "hostip.h"
@@ -354,8 +354,8 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
 {
   CURLcode result = CURLE_OK;
   struct Curl_easy *data = conn->data;
-  long timeout;
-  struct curltime now = Curl_tvnow();
+  timediff_t timeout;
+  struct curltime now = Curl_now();
   struct Curl_dns_entry *temp_entry;
 
   if(entry)
@@ -400,8 +400,8 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
     if(Curl_pgrsUpdate(conn))
       result = CURLE_ABORTED_BY_CALLBACK;
     else {
-      struct curltime now2 = Curl_tvnow();
-      time_t timediff = Curl_tvdiff(now2, now); /* spent time */
+      struct curltime now2 = Curl_now();
+      timediff_t timediff = Curl_timediff(now2, now); /* spent time */
       if(timediff <= 0)
         timeout -= 1; /* always deduct at least 1 */
       else if(timediff > timeout)
diff --git a/lib/asyn-thread.c b/lib/asyn-thread.c
index a86772965..1ac3fc809 100644
--- a/lib/asyn-thread.c
+++ b/lib/asyn-thread.c
@@ -535,7 +535,8 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
   }
   else {
     /* poll for name lookup done with exponential backoff up to 250ms */
-    time_t elapsed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle);
+    timediff_t elapsed = Curl_timediff(Curl_now(),
+                                       data->progress.t_startsingle);
     if(elapsed < 0)
       elapsed = 0;
 
diff --git a/lib/conncache.c b/lib/conncache.c
index ad5ac41a8..24c2e6aa6 100644
--- a/lib/conncache.c
+++ b/lib/conncache.c
@@ -31,11 +31,21 @@
 #include "multiif.h"
 #include "sendf.h"
 #include "conncache.h"
+#include "share.h"
+#include "sigpipe.h"
+#include "connect.h"
+
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_memory.h"
 #include "memdebug.h"
 
+#define CONN_LOCK(x) if((x)->share)                                     \
+    Curl_share_lock((x), CURL_LOCK_DATA_CONNECT, CURL_LOCK_ACCESS_SINGLE)
+#define CONN_UNLOCK(x) if((x)->share)                   \
+    Curl_share_unlock((x), CURL_LOCK_DATA_CONNECT)
+
+
 static void conn_llist_dtor(void *user, void *element)
 {
   struct connectdata *data = element;
@@ -109,8 +119,23 @@ static void free_bundle_hash_entry(void *freethis)
 
 int Curl_conncache_init(struct conncache *connc, int size)
 {
-  return Curl_hash_init(&connc->hash, size, Curl_hash_str,
-                        Curl_str_key_compare, free_bundle_hash_entry);
+  int rc;
+
+  /* allocate a new easy handle to use when closing cached connections */
+  connc->closure_handle = curl_easy_init();
+  if(!connc->closure_handle)
+    return 1; /* bad */
+
+  rc = Curl_hash_init(&connc->hash, size, Curl_hash_str,
+                      Curl_str_key_compare, free_bundle_hash_entry);
+  if(rc) {
+    Curl_close(connc->closure_handle);
+    connc->closure_handle = NULL;
+  }
+  else
+    connc->closure_handle->state.conn_cache = connc;
+
+  return rc;
 }
 
 void Curl_conncache_destroy(struct conncache *connc)
@@ -149,7 +174,9 @@ struct connectbundle *Curl_conncache_find_bundle(struct 
connectdata *conn,
   if(connc) {
     char key[128];
     hashkey(conn, key, sizeof(key));
+    CONN_LOCK(conn->data);
     bundle = Curl_hash_pick(&connc->hash, key, strlen(key));
+    CONN_UNLOCK(conn->data);
   }
 
   return bundle;
@@ -206,7 +233,9 @@ CURLcode Curl_conncache_add_conn(struct conncache *connc,
       return result;
 
     hashkey(conn, key, sizeof(key));
+    CONN_LOCK(data);
     rc = conncache_add_bundle(data->state.conn_cache, key, new_bundle);
+    CONN_UNLOCK(data);
 
     if(!rc) {
       bundle_destroy(new_bundle);
@@ -215,12 +244,15 @@ CURLcode Curl_conncache_add_conn(struct conncache *connc,
     bundle = new_bundle;
   }
 
+  CONN_LOCK(data);
   result = bundle_add_conn(bundle, conn);
   if(result) {
     if(new_bundle)
       conncache_remove_bundle(data->state.conn_cache, new_bundle);
+    CONN_UNLOCK(data);
     return result;
   }
+  CONN_UNLOCK(data);
 
   conn->connection_id = connc->next_connection_id++;
   connc->num_connections++;
@@ -240,11 +272,11 @@ void Curl_conncache_remove_conn(struct conncache *connc,
   /* The bundle pointer can be NULL, since this function can be called
      due to a failed connection attempt, before being added to a bundle */
   if(bundle) {
+    CONN_LOCK(conn->data);
     bundle_remove_conn(bundle, conn);
-    if(bundle->num_connections == 0) {
+    if(bundle->num_connections == 0)
       conncache_remove_bundle(connc, bundle);
-    }
-
+    CONN_UNLOCK(conn->data);
     if(connc) {
       connc->num_connections--;
 
@@ -261,7 +293,8 @@ void Curl_conncache_remove_conn(struct conncache *connc,
 
    Return 0 from func() to continue the loop, return 1 to abort it.
  */
-void Curl_conncache_foreach(struct conncache *connc,
+void Curl_conncache_foreach(struct Curl_easy *data,
+                            struct conncache *connc,
                             void *param,
                             int (*func)(struct connectdata *conn, void *param))
 {
@@ -272,6 +305,7 @@ void Curl_conncache_foreach(struct conncache *connc,
   if(!connc)
     return;
 
+  CONN_LOCK(data);
   Curl_hash_start_iterate(&connc->hash, &iter);
 
   he = Curl_hash_next_element(&iter);
@@ -288,14 +322,21 @@ void Curl_conncache_foreach(struct conncache *connc,
       struct connectdata *conn = curr->ptr;
       curr = curr->next;
 
-      if(1 == func(conn, param))
+      if(1 == func(conn, param)) {
+        CONN_UNLOCK(data);
         return;
+      }
     }
   }
+  CONN_UNLOCK(data);
 }
 
 /* Return the first connection found in the cache. Used when closing all
-   connections */
+   connections.
+
+   NOTE: no locking is done here as this is presumably only done when cleaning
+   up a cache!
+*/
 struct connectdata *
 Curl_conncache_find_first_connection(struct conncache *connc)
 {
@@ -321,6 +362,90 @@ Curl_conncache_find_first_connection(struct conncache 
*connc)
   return NULL;
 }
 
+/*
+ * This function finds the connection in the connection
+ * cache that has been unused for the longest time.
+ *
+ * Returns the pointer to the oldest idle connection, or NULL if none was
+ * found.
+ */
+struct connectdata *
+Curl_conncache_oldest_idle(struct Curl_easy *data)
+{
+  struct conncache *bc = data->state.conn_cache;
+  struct curl_hash_iterator iter;
+  struct curl_llist_element *curr;
+  struct curl_hash_element *he;
+  timediff_t highscore =- 1;
+  timediff_t score;
+  struct curltime now;
+  struct connectdata *conn_candidate = NULL;
+  struct connectbundle *bundle;
+
+  now = Curl_now();
+
+  CONN_LOCK(data);
+  Curl_hash_start_iterate(&bc->hash, &iter);
+
+  he = Curl_hash_next_element(&iter);
+  while(he) {
+    struct connectdata *conn;
+
+    bundle = he->ptr;
+
+    curr = bundle->conn_list.head;
+    while(curr) {
+      conn = curr->ptr;
+
+      if(!conn->inuse) {
+        /* Set higher score for the age passed since the connection was used */
+        score = Curl_timediff(now, conn->now);
+
+        if(score > highscore) {
+          highscore = score;
+          conn_candidate = conn;
+        }
+      }
+      curr = curr->next;
+    }
+
+    he = Curl_hash_next_element(&iter);
+  }
+  CONN_UNLOCK(data);
+
+  return conn_candidate;
+}
+
+void Curl_conncache_close_all_connections(struct conncache *connc)
+{
+  struct connectdata *conn;
+
+  conn = Curl_conncache_find_first_connection(connc);
+  while(conn) {
+    SIGPIPE_VARIABLE(pipe_st);
+    conn->data = connc->closure_handle;
+
+    sigpipe_ignore(conn->data, &pipe_st);
+    conn->data->easy_conn = NULL; /* clear the easy handle's connection
+                                     pointer */
+    /* This will remove the connection from the cache */
+    connclose(conn, "kill all");
+    (void)Curl_disconnect(conn, FALSE);
+    sigpipe_restore(&pipe_st);
+
+    conn = Curl_conncache_find_first_connection(connc);
+  }
+
+  if(connc->closure_handle) {
+    SIGPIPE_VARIABLE(pipe_st);
+    sigpipe_ignore(connc->closure_handle, &pipe_st);
+
+    Curl_hostcache_clean(connc->closure_handle,
+                         connc->closure_handle->dns.hostcache);
+    Curl_close(connc->closure_handle);
+    sigpipe_restore(&pipe_st);
+  }
+}
 
 #if 0
 /* Useful for debugging the connection cache */
diff --git a/lib/conncache.h b/lib/conncache.h
index 14be4e8e7..0d97a6cef 100644
--- a/lib/conncache.h
+++ b/lib/conncache.h
@@ -28,6 +28,8 @@ struct conncache {
   size_t num_connections;
   long next_connection_id;
   struct curltime last_cleanup;
+  /* handle used for closing cached connections */
+  struct Curl_easy *closure_handle;
 };
 
 #define BUNDLE_NO_MULTIUSE -1
@@ -41,8 +43,8 @@ struct connectbundle {
   struct curl_llist conn_list;  /* The connectdata members of the bundle */
 };
 
+/* returns 1 on error, 0 is fine */
 int Curl_conncache_init(struct conncache *, int size);
-
 void Curl_conncache_destroy(struct conncache *connc);
 
 /* return the correct bundle, to a host or a proxy */
@@ -55,7 +57,8 @@ CURLcode Curl_conncache_add_conn(struct conncache *connc,
 void Curl_conncache_remove_conn(struct conncache *connc,
                                 struct connectdata *conn);
 
-void Curl_conncache_foreach(struct conncache *connc,
+void Curl_conncache_foreach(struct Curl_easy *data,
+                            struct conncache *connc,
                             void *param,
                             int (*func)(struct connectdata *conn,
                                         void *param));
@@ -63,6 +66,9 @@ void Curl_conncache_foreach(struct conncache *connc,
 struct connectdata *
 Curl_conncache_find_first_connection(struct conncache *connc);
 
+struct connectdata *
+Curl_conncache_oldest_idle(struct Curl_easy *data);
+void Curl_conncache_close_all_connections(struct conncache *connc);
 void Curl_conncache_print(struct conncache *connc);
 
 #endif /* HEADER_CURL_CONNCACHE_H */
diff --git a/lib/connect.c b/lib/connect.c
old mode 100755
new mode 100644
index b7d10af55..3edb71eb7
--- a/lib/connect.c
+++ b/lib/connect.c
@@ -28,8 +28,10 @@
 #ifdef HAVE_SYS_UN_H
 #include <sys/un.h> /* for sockaddr_un */
 #endif
-#ifdef HAVE_NETINET_TCP_H
-#include <netinet/tcp.h> /* for TCP_NODELAY */
+#ifdef HAVE_LINUX_TCP_H
+#include <linux/tcp.h>
+#elif defined(HAVE_NETINET_TCP_H)
+#include <netinet/tcp.h>
 #endif
 #ifdef HAVE_SYS_IOCTL_H
 #include <sys/ioctl.h>
@@ -179,12 +181,12 @@ singleipconnect(struct connectdata *conn,
  *
  * @unittest: 1303
  */
-time_t Curl_timeleft(struct Curl_easy *data,
-                     struct curltime *nowp,
-                     bool duringconnect)
+timediff_t Curl_timeleft(struct Curl_easy *data,
+                         struct curltime *nowp,
+                         bool duringconnect)
 {
   int timeout_set = 0;
-  time_t timeout_ms = duringconnect?DEFAULT_CONNECT_TIMEOUT:0;
+  timediff_t timeout_ms = duringconnect?DEFAULT_CONNECT_TIMEOUT:0;
   struct curltime now;
 
   /* if a timeout is set, use the most restrictive one */
@@ -218,17 +220,17 @@ time_t Curl_timeleft(struct Curl_easy *data,
   }
 
   if(!nowp) {
-    now = Curl_tvnow();
+    now = Curl_now();
     nowp = &now;
   }
 
   /* subtract elapsed time */
   if(duringconnect)
     /* since this most recent connect started */
-    timeout_ms -= Curl_tvdiff(*nowp, data->progress.t_startsingle);
+    timeout_ms -= Curl_timediff(*nowp, data->progress.t_startsingle);
   else
     /* since the entire operation started */
-    timeout_ms -= Curl_tvdiff(*nowp, data->progress.t_startop);
+    timeout_ms -= Curl_timediff(*nowp, data->progress.t_startop);
   if(!timeout_ms)
     /* avoid returning 0 as that means no timeout! */
     return -1;
@@ -285,6 +287,34 @@ static CURLcode bindlocal(struct connectdata *conn,
 
     /* interface */
     if(!is_host) {
+#ifdef SO_BINDTODEVICE
+      /* I am not sure any other OSs than Linux that provide this feature,
+       * and at the least I cannot test. --Ben
+       *
+       * This feature allows one to tightly bind 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.
+       *
+       * 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,
+                    dev, (curl_socklen_t)strlen(dev) + 1) == 0) {
+        /* This is typically "errno 1, error: Operation not permitted" if
+         * you're 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.
+         */
+        return CURLE_OK;
+      }
+#endif
+
       switch(Curl_if2ip(af, scope, conn->scope_id, dev,
                         myhost, sizeof(myhost))) {
         case IF2IP_NOT_FOUND:
@@ -305,30 +335,6 @@ static CURLcode bindlocal(struct connectdata *conn,
           infof(data, "Local Interface %s is ip %s using address family %i\n",
                 dev, myhost, af);
           done = 1;
-
-#ifdef SO_BINDTODEVICE
-          /* I am not sure any other OSs than Linux that provide this feature,
-           * and at the least I cannot test. --Ben
-           *
-           * This feature allows one to tightly bind 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.
-           */
-          if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
-                        dev, (curl_socklen_t)strlen(dev) + 1) != 0) {
-            error = SOCKERRNO;
-            infof(data, "SO_BINDTODEVICE %s failed with errno %d: %s;"
-                  " will do regular bind\n",
-                  dev, error, Curl_strerror(conn, error));
-            /* This is typically "errno 1, error: Operation not permitted" if
-               you're not running as root or another suitable privileged
-               user */
-          }
-#endif
           break;
       }
     }
@@ -408,6 +414,10 @@ static CURLcode bindlocal(struct connectdata *conn,
     }
 
     if(done < 1) {
+      /* errorbuf is set false so failf will overwrite any message already in
+         the error buffer, so the user receives this error message instead of a
+         generic resolve error. */
+      data->state.errorbuf = FALSE;
       failf(data, "Couldn't bind to '%s'", dev);
       return CURLE_INTERFACE_FAILED;
     }
@@ -721,7 +731,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
 {
   struct Curl_easy *data = conn->data;
   CURLcode result = CURLE_OK;
-  time_t allow;
+  timediff_t allow;
   int error = 0;
   struct curltime now;
   int rc;
@@ -737,7 +747,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
     return CURLE_OK;
   }
 
-  now = Curl_tvnow();
+  now = Curl_now();
 
   /* figure out how long time we have left to connect */
   allow = Curl_timeleft(data, &now, TRUE);
@@ -765,7 +775,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
 
     if(rc == 0) { /* no connection yet */
       error = 0;
-      if(curlx_tvdiff(now, conn->connecttime) >= conn->timeoutms_per_addr) {
+      if(Curl_timediff(now, conn->connecttime) >= conn->timeoutms_per_addr) {
         infof(data, "After %ldms connect time, move on!\n",
               conn->timeoutms_per_addr);
         error = ETIMEDOUT;
@@ -773,7 +783,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
 
       /* should we try another protocol family? */
       if(i == 0 && conn->tempaddr[1] == NULL &&
-         curlx_tvdiff(now, conn->connecttime) >= HAPPY_EYEBALLS_TIMEOUT) {
+         Curl_timediff(now, conn->connecttime) >= HAPPY_EYEBALLS_TIMEOUT) {
         trynextip(conn, sockindex, 1);
       }
     }
@@ -785,6 +795,9 @@ CURLcode Curl_is_connected(struct connectdata *conn,
         conn->sock[sockindex] = conn->tempsock[i];
         conn->ip_addr = conn->tempaddr[i];
         conn->tempsock[i] = CURL_SOCKET_BAD;
+#ifdef ENABLE_IPV6
+        conn->bits.ipv6 = (conn->ip_addr->ai_family == AF_INET6)?TRUE:FALSE;
+#endif
 
         /* close the other socket, if open */
         if(conn->tempsock[other] != CURL_SOCKET_BAD) {
@@ -978,6 +991,9 @@ static CURLcode singleipconnect(struct connectdata *conn,
   char ipaddress[MAX_IPADR_LEN];
   long port;
   bool is_tcp;
+#ifdef TCP_FASTOPEN_CONNECT
+  int optval = 1;
+#endif
 
   *sockp = CURL_SOCKET_BAD;
 
@@ -1051,17 +1067,19 @@ static CURLcode singleipconnect(struct connectdata 
*conn,
   /* set socket non-blocking */
   (void)curlx_nonblock(sockfd, TRUE);
 
-  conn->connecttime = Curl_tvnow();
+  conn->connecttime = Curl_now();
   if(conn->num_addr > 1)
     Curl_expire(data, conn->timeoutms_per_addr, EXPIRE_DNS_PER_NAME);
 
   /* Connect TCP sockets, bind UDP */
   if(!isconnected && (conn->socktype == SOCK_STREAM)) {
     if(conn->bits.tcp_fastopen) {
-#if defined(CONNECT_DATA_IDEMPOTENT) /* OS X */
-#ifdef HAVE_BUILTIN_AVAILABLE
+#if defined(CONNECT_DATA_IDEMPOTENT) /* Darwin */
+#  if defined(HAVE_BUILTIN_AVAILABLE)
+      /* while connectx function is available since macOS 10.11 / iOS 9,
+         it did not have the interface declared correctly until
+         Xcode 9 / macOS SDK 10.13 */
       if(__builtin_available(macOS 10.11, iOS 9.0, tvOS 9.0, watchOS 2.0, *)) {
-#endif /* HAVE_BUILTIN_AVAILABLE */
         sa_endpoints_t endpoints;
         endpoints.sae_srcif = 0;
         endpoints.sae_srcaddr = NULL;
@@ -1072,13 +1090,22 @@ static CURLcode singleipconnect(struct connectdata 
*conn,
         rc = connectx(sockfd, &endpoints, SAE_ASSOCID_ANY,
                       CONNECT_RESUME_ON_READ_WRITE | CONNECT_DATA_IDEMPOTENT,
                       NULL, 0, NULL, NULL);
-#ifdef HAVE_BUILTIN_AVAILABLE
       }
       else {
         rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
       }
-#endif /* HAVE_BUILTIN_AVAILABLE */
-#elif defined(MSG_FASTOPEN) /* Linux */
+#  else
+      rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
+#  endif /* HAVE_BUILTIN_AVAILABLE */
+#elif defined(TCP_FASTOPEN_CONNECT) /* Linux >= 4.11 */
+      if(setsockopt(sockfd, IPPROTO_TCP, TCP_FASTOPEN_CONNECT,
+                    (void *)&optval, sizeof(optval)) < 0)
+        infof(data, "Failed to enable TCP Fast Open on fd %d\n", sockfd);
+      else
+        infof(data, "TCP_FASTOPEN_CONNECT set\n");
+
+      rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
+#elif defined(MSG_FASTOPEN) /* old Linux */
       if(conn->given->flags & PROTOPT_SSL)
         rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
       else
@@ -1097,10 +1124,6 @@ static CURLcode singleipconnect(struct connectdata *conn,
     return CURLE_OK;
   }
 
-#ifdef ENABLE_IPV6
-  conn->bits.ipv6 = (addr.family == AF_INET6)?TRUE:FALSE;
-#endif
-
   if(-1 == rc) {
     switch(error) {
     case EINPROGRESS:
@@ -1145,10 +1168,10 @@ CURLcode Curl_connecthost(struct connectdata *conn,  /* 
context */
                           const struct Curl_dns_entry *remotehost)
 {
   struct Curl_easy *data = conn->data;
-  struct curltime before = Curl_tvnow();
+  struct curltime before = Curl_now();
   CURLcode result = CURLE_COULDNT_CONNECT;
 
-  time_t timeout_ms = Curl_timeleft(data, &before, TRUE);
+  timediff_t timeout_ms = Curl_timeleft(data, &before, TRUE);
 
   if(timeout_ms < 0) {
     /* a precaution, no need to continue if time already is up */
@@ -1225,7 +1248,7 @@ curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
     find.tofind = data->state.lastconnect;
     find.found = FALSE;
 
-    Curl_conncache_foreach(data->multi_easy?
+    Curl_conncache_foreach(data, data->multi_easy?
                            &data->multi_easy->conn_cache:
                            &data->multi->conn_cache, &find, conn_is_conn);
 
diff --git a/lib/connect.h b/lib/connect.h
index 3f05c3978..397448636 100644
--- a/lib/connect.h
+++ b/lib/connect.h
@@ -25,6 +25,7 @@
 
 #include "nonblock.h" /* for curlx_nonblock(), formerly Curl_nonblock() */
 #include "sockaddr.h"
+#include "timeval.h"
 
 CURLcode Curl_is_connected(struct connectdata *conn,
                            int sockindex,
@@ -35,9 +36,9 @@ CURLcode Curl_connecthost(struct connectdata *conn,
 
 /* generic function that returns how much time there's left to run, according
    to the timeouts set */
-time_t Curl_timeleft(struct Curl_easy *data,
-                     struct curltime *nowp,
-                     bool duringconnect);
+timediff_t Curl_timeleft(struct Curl_easy *data,
+                         struct curltime *nowp,
+                         bool duringconnect);
 
 #define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */
 #define HAPPY_EYEBALLS_TIMEOUT     200 /* milliseconds to wait between
diff --git a/lib/content_encoding.c b/lib/content_encoding.c
index b1a540f03..65e9ba2ec 100644
--- a/lib/content_encoding.c
+++ b/lib/content_encoding.c
@@ -22,22 +22,43 @@
 
 #include "curl_setup.h"
 
-#ifdef HAVE_LIBZ
-
 #include "urldata.h"
 #include <gnurl/curl.h>
+#include <stddef.h>
+
+#ifdef HAVE_ZLIB_H
+#include <zlib.h>
+#ifdef __SYMBIAN32__
+/* zlib pollutes the namespace with this definition */
+#undef WIN32
+#endif
+#endif
+
+#ifdef HAVE_BROTLI
+#include <brotli/decode.h>
+#endif
+
 #include "sendf.h"
+#include "http.h"
 #include "content_encoding.h"
 #include "strdup.h"
+#include "strcase.h"
 #include "curl_memory.h"
 #include "memdebug.h"
 
+#define CONTENT_ENCODING_DEFAULT  "identity"
+
+#ifndef CURL_DISABLE_HTTP
+
+#define DSIZ CURL_MAX_WRITE_SIZE /* buffer size for decompressed data */
+
+
+#ifdef HAVE_LIBZ
+
 /* Comment this out if zlib is always going to be at least ver. 1.2.0.4
    (doing so will reduce code size slightly). */
 #define OLD_ZLIB_SUPPORT 1
 
-#define DSIZ CURL_MAX_WRITE_SIZE /* buffer size for decompressed data */
-
 #define GZIP_MAGIC_0 0x1f
 #define GZIP_MAGIC_1 0x8b
 
@@ -49,6 +70,21 @@
 #define COMMENT      0x10 /* bit 4 set: file comment present */
 #define RESERVED     0xE0 /* bits 5..7: reserved */
 
+typedef enum {
+  ZLIB_UNINIT,          /* uninitialized */
+  ZLIB_INIT,            /* initialized */
+  ZLIB_GZIP_HEADER,     /* reading gzip header */
+  ZLIB_GZIP_INFLATING,  /* inflating gzip stream */
+  ZLIB_INIT_GZIP        /* initialized in transparent gzip mode */
+} zlibInitState;
+
+/* Writer parameters. */
+typedef struct {
+  zlibInitState zlib_init;    /* zlib init state */
+  z_stream z;                /* State structure for zlib. */
+}  zlib_params;
+
+
 static voidpf
 zalloc_cb(voidpf opaque, unsigned int items, unsigned int size)
 {
@@ -79,19 +115,27 @@ process_zlib_error(struct connectdata *conn, z_stream *z)
 }
 
 static CURLcode
-exit_zlib(z_stream *z, zlibInitState *zlib_init, CURLcode result)
+exit_zlib(struct connectdata *conn,
+          z_stream *z, zlibInitState *zlib_init, CURLcode result)
 {
-  inflateEnd(z);
-  *zlib_init = ZLIB_UNINIT;
+  if(*zlib_init == ZLIB_GZIP_HEADER)
+    Curl_safefree(z->next_in);
+
+  if(*zlib_init != ZLIB_UNINIT) {
+    if(inflateEnd(z) != Z_OK && result == CURLE_OK)
+      result = process_zlib_error(conn, z);
+    *zlib_init = ZLIB_UNINIT;
+  }
+
   return result;
 }
 
 static CURLcode
-inflate_stream(struct connectdata *conn,
-               struct SingleRequest *k)
+inflate_stream(struct connectdata *conn, contenc_writer *writer)
 {
+  zlib_params *zp = (zlib_params *) &writer->params;
   int allow_restart = 1;
-  z_stream *z = &k->z;          /* zlib state structure */
+  z_stream *z = &zp->z;         /* zlib state structure */
   uInt nread = z->avail_in;
   Bytef *orig_in = z->next_in;
   int status;                   /* zlib status */
@@ -102,44 +146,42 @@ inflate_stream(struct connectdata *conn,
      large to hold on the stack */
   decomp = malloc(DSIZ);
   if(decomp == NULL) {
-    return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY);
+    return exit_zlib(conn, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
   }
 
   /* because the buffer size is fixed, iteratively decompress and transfer to
      the client via client_write. */
   for(;;) {
+    if(z->avail_in == 0) {
+      free(decomp);
+      return result;
+    }
+
     /* (re)set buffer for decompressed output for every iteration */
-    z->next_out = (Bytef *)decomp;
+    z->next_out = (Bytef *) decomp;
     z->avail_out = DSIZ;
 
     status = inflate(z, Z_SYNC_FLUSH);
     if(status == Z_OK || status == Z_STREAM_END) {
       allow_restart = 0;
-      if((DSIZ - z->avail_out) && (!k->ignorebody)) {
-        result = Curl_client_write(conn, CLIENTWRITE_BODY, decomp,
+      result = Curl_unencode_write(conn, writer->downstream, decomp,
                                    DSIZ - z->avail_out);
-        /* if !CURLE_OK, clean up, return */
-        if(result) {
-          free(decomp);
-          return exit_zlib(z, &k->zlib_init, result);
-        }
+      /* if !CURLE_OK, clean up, return */
+      if(result) {
+        free(decomp);
+        return exit_zlib(conn, z, &zp->zlib_init, result);
       }
 
       /* Done? clean up, return */
       if(status == Z_STREAM_END) {
         free(decomp);
-        if(inflateEnd(z) == Z_OK)
-          return exit_zlib(z, &k->zlib_init, result);
-        return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
+        return exit_zlib(conn, z, &zp->zlib_init, result);
       }
 
       /* Done with these bytes, exit */
 
       /* status is always Z_OK at this point! */
-      if(z->avail_in == 0) {
-        free(decomp);
-        return result;
-      }
+      continue;
     }
     else if(allow_restart && status == Z_DATA_ERROR) {
       /* some servers seem to not generate zlib headers, so this is an attempt
@@ -148,7 +190,8 @@ inflate_stream(struct connectdata *conn,
       (void) inflateEnd(z);     /* don't care about the return code */
       if(inflateInit2(z, -MAX_WBITS) != Z_OK) {
         free(decomp);
-        return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
+        zp->zlib_init = ZLIB_UNINIT;  /* inflateEnd() already called. */
+        return exit_zlib(conn, z, &zp->zlib_init, process_zlib_error(conn, z));
       }
       z->next_in = orig_in;
       z->avail_in = nread;
@@ -157,36 +200,97 @@ inflate_stream(struct connectdata *conn,
     }
     else {                      /* Error; exit loop, handle below */
       free(decomp);
-      return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
+      return exit_zlib(conn, z, &zp->zlib_init, process_zlib_error(conn, z));
     }
   }
-  /* Will never get here */
+  /* UNREACHED */
 }
 
-CURLcode
-Curl_unencode_deflate_write(struct connectdata *conn,
-                            struct SingleRequest *k,
-                            ssize_t nread)
+
+/* Deflate handler. */
+static CURLcode deflate_init_writer(struct connectdata *conn,
+                                    contenc_writer *writer)
 {
-  z_stream *z = &k->z;          /* zlib state structure */
+  zlib_params *zp = (zlib_params *) &writer->params;
+  z_stream *z = &zp->z;     /* zlib state structure */
 
-  /* Initialize zlib? */
-  if(k->zlib_init == ZLIB_UNINIT) {
-    memset(z, 0, sizeof(z_stream));
-    z->zalloc = (alloc_func)zalloc_cb;
-    z->zfree = (free_func)zfree_cb;
+  if(!writer->downstream)
+    return CURLE_WRITE_ERROR;
 
-    if(inflateInit(z) != Z_OK)
-      return process_zlib_error(conn, z);
-    k->zlib_init = ZLIB_INIT;
-  }
+  /* Initialize zlib */
+  z->zalloc = (alloc_func) zalloc_cb;
+  z->zfree = (free_func) zfree_cb;
+
+  if(inflateInit(z) != Z_OK)
+    return process_zlib_error(conn, z);
+  zp->zlib_init = ZLIB_INIT;
+  return CURLE_OK;
+}
+
+static CURLcode deflate_unencode_write(struct connectdata *conn,
+                                       contenc_writer *writer,
+                                       const char *buf, size_t nbytes)
+{
+  zlib_params *zp = (zlib_params *) &writer->params;
+  z_stream *z = &zp->z;     /* zlib state structure */
 
   /* Set the compressed input when this function is called */
-  z->next_in = (Bytef *)k->str;
-  z->avail_in = (uInt)nread;
+  z->next_in = (Bytef *) buf;
+  z->avail_in = (uInt) nbytes;
 
   /* Now uncompress the data */
-  return inflate_stream(conn, k);
+  return inflate_stream(conn, writer);
+}
+
+static void deflate_close_writer(struct connectdata *conn,
+                                 contenc_writer *writer)
+{
+  zlib_params *zp = (zlib_params *) &writer->params;
+  z_stream *z = &zp->z;     /* zlib state structure */
+
+  exit_zlib(conn, z, &zp->zlib_init, CURLE_OK);
+}
+
+static const content_encoding deflate_encoding = {
+  "deflate",
+  NULL,
+  deflate_init_writer,
+  deflate_unencode_write,
+  deflate_close_writer,
+  sizeof(zlib_params)
+};
+
+
+/* Gzip handler. */
+static CURLcode gzip_init_writer(struct connectdata *conn,
+                                 contenc_writer *writer)
+{
+  zlib_params *zp = (zlib_params *) &writer->params;
+  z_stream *z = &zp->z;     /* zlib state structure */
+
+  if(!writer->downstream)
+    return CURLE_WRITE_ERROR;
+
+  /* Initialize zlib */
+  z->zalloc = (alloc_func) zalloc_cb;
+  z->zfree = (free_func) zfree_cb;
+
+  if(strcmp(zlibVersion(), "1.2.0.4") >= 0) {
+    /* zlib ver. >= 1.2.0.4 supports transparent gzip decompressing */
+    if(inflateInit2(z, MAX_WBITS + 32) != Z_OK) {
+      return process_zlib_error(conn, z);
+    }
+    zp->zlib_init = ZLIB_INIT_GZIP; /* Transparent gzip decompress state */
+  }
+  else {
+    /* we must parse the gzip header ourselves */
+    if(inflateInit2(z, -MAX_WBITS) != Z_OK) {
+      return process_zlib_error(conn, z);
+    }
+    zp->zlib_init = ZLIB_INIT;   /* Initial call state */
+  }
+
+  return CURLE_OK;
 }
 
 #ifdef OLD_ZLIB_SUPPORT
@@ -273,47 +377,25 @@ static enum {
 }
 #endif
 
-CURLcode
-Curl_unencode_gzip_write(struct connectdata *conn,
-                         struct SingleRequest *k,
-                         ssize_t nread)
+static CURLcode gzip_unencode_write(struct connectdata *conn,
+                                    contenc_writer *writer,
+                                    const char *buf, size_t nbytes)
 {
-  z_stream *z = &k->z;          /* zlib state structure */
-
-  /* Initialize zlib? */
-  if(k->zlib_init == ZLIB_UNINIT) {
-    memset(z, 0, sizeof(z_stream));
-    z->zalloc = (alloc_func)zalloc_cb;
-    z->zfree = (free_func)zfree_cb;
-
-    if(strcmp(zlibVersion(), "1.2.0.4") >= 0) {
-      /* zlib ver. >= 1.2.0.4 supports transparent gzip decompressing */
-      if(inflateInit2(z, MAX_WBITS + 32) != Z_OK) {
-        return process_zlib_error(conn, z);
-      }
-      k->zlib_init = ZLIB_INIT_GZIP; /* Transparent gzip decompress state */
-    }
-    else {
-      /* we must parse the gzip header ourselves */
-      if(inflateInit2(z, -MAX_WBITS) != Z_OK) {
-        return process_zlib_error(conn, z);
-      }
-      k->zlib_init = ZLIB_INIT;   /* Initial call state */
-    }
-  }
+  zlib_params *zp = (zlib_params *) &writer->params;
+  z_stream *z = &zp->z;     /* zlib state structure */
 
-  if(k->zlib_init == ZLIB_INIT_GZIP) {
+  if(zp->zlib_init == ZLIB_INIT_GZIP) {
     /* Let zlib handle the gzip decompression entirely */
-    z->next_in = (Bytef *)k->str;
-    z->avail_in = (uInt)nread;
+    z->next_in = (Bytef *) buf;
+    z->avail_in = (uInt) nbytes;
     /* Now uncompress the data */
-    return inflate_stream(conn, k);
+    return inflate_stream(conn, writer);
   }
 
 #ifndef OLD_ZLIB_SUPPORT
   /* Support for old zlib versions is compiled away and we are running with
      an old version, so return an error. */
-  return exit_zlib(z, &k->zlib_init, CURLE_WRITE_ERROR);
+  return exit_zlib(conn, z, &zp->zlib_init, CURLE_WRITE_ERROR);
 
 #else
   /* This next mess is to get around the potential case where there isn't
@@ -326,18 +408,18 @@ Curl_unencode_gzip_write(struct connectdata *conn,
    * can handle the gzip header themselves.
    */
 
-  switch(k->zlib_init) {
+  switch(zp->zlib_init) {
   /* Skip over gzip header? */
   case ZLIB_INIT:
   {
     /* Initial call state */
     ssize_t hlen;
 
-    switch(check_gzip_header((unsigned char *)k->str, nread, &hlen)) {
+    switch(check_gzip_header((unsigned char *) buf, nbytes, &hlen)) {
     case GZIP_OK:
-      z->next_in = (Bytef *)k->str + hlen;
-      z->avail_in = (uInt)(nread - hlen);
-      k->zlib_init = ZLIB_GZIP_INFLATING; /* Inflating stream state */
+      z->next_in = (Bytef *) buf + hlen;
+      z->avail_in = (uInt) (nbytes - hlen);
+      zp->zlib_init = ZLIB_GZIP_INFLATING; /* Inflating stream state */
       break;
 
     case GZIP_UNDERFLOW:
@@ -348,19 +430,19 @@ Curl_unencode_gzip_write(struct connectdata *conn,
        * the first place, and it's even more unlikely for a transfer to fail
        * immediately afterwards, it should seldom be a problem.
        */
-      z->avail_in = (uInt)nread;
+      z->avail_in = (uInt) nbytes;
       z->next_in = malloc(z->avail_in);
       if(z->next_in == NULL) {
-        return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY);
+        return exit_zlib(conn, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
       }
-      memcpy(z->next_in, k->str, z->avail_in);
-      k->zlib_init = ZLIB_GZIP_HEADER;   /* Need more gzip header data state */
+      memcpy(z->next_in, buf, z->avail_in);
+      zp->zlib_init = ZLIB_GZIP_HEADER;  /* Need more gzip header data state */
       /* We don't have any data to inflate yet */
       return CURLE_OK;
 
     case GZIP_BAD:
     default:
-      return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
+      return exit_zlib(conn, z, &zp->zlib_init, process_zlib_error(conn, z));
     }
 
   }
@@ -370,22 +452,22 @@ Curl_unencode_gzip_write(struct connectdata *conn,
   {
     /* Need more gzip header data state */
     ssize_t hlen;
-    z->avail_in += (uInt)nread;
+    z->avail_in += (uInt) nbytes;
     z->next_in = Curl_saferealloc(z->next_in, z->avail_in);
     if(z->next_in == NULL) {
-      return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY);
+      return exit_zlib(conn, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
     }
     /* Append the new block of data to the previous one */
-    memcpy(z->next_in + z->avail_in - nread, k->str, nread);
+    memcpy(z->next_in + z->avail_in - nbytes, buf, nbytes);
 
     switch(check_gzip_header(z->next_in, z->avail_in, &hlen)) {
     case GZIP_OK:
       /* This is the zlib stream data */
       free(z->next_in);
       /* Don't point into the malloced block since we just freed it */
-      z->next_in = (Bytef *)k->str + hlen + nread - z->avail_in;
-      z->avail_in = (uInt)(z->avail_in - hlen);
-      k->zlib_init = ZLIB_GZIP_INFLATING;   /* Inflating stream state */
+      z->next_in = (Bytef *) buf + hlen + nbytes - z->avail_in;
+      z->avail_in = (uInt) (z->avail_in - hlen);
+      zp->zlib_init = ZLIB_GZIP_INFLATING;   /* Inflating stream state */
       break;
 
     case GZIP_UNDERFLOW:
@@ -394,8 +476,7 @@ Curl_unencode_gzip_write(struct connectdata *conn,
 
     case GZIP_BAD:
     default:
-      free(z->next_in);
-      return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
+      return exit_zlib(conn, z, &zp->zlib_init, process_zlib_error(conn, z));
     }
 
   }
@@ -404,8 +485,8 @@ Curl_unencode_gzip_write(struct connectdata *conn,
   case ZLIB_GZIP_INFLATING:
   default:
     /* Inflating stream state */
-    z->next_in = (Bytef *)k->str;
-    z->avail_in = (uInt)nread;
+    z->next_in = (Bytef *) buf;
+    z->avail_in = (uInt) nbytes;
     break;
   }
 
@@ -415,17 +496,465 @@ Curl_unencode_gzip_write(struct connectdata *conn,
   }
 
   /* We've parsed the header, now uncompress the data */
-  return inflate_stream(conn, k);
+  return inflate_stream(conn, writer);
 #endif
 }
 
+static void gzip_close_writer(struct connectdata *conn,
+                              contenc_writer *writer)
+{
+  zlib_params *zp = (zlib_params *) &writer->params;
+  z_stream *z = &zp->z;     /* zlib state structure */
+
+  exit_zlib(conn, z, &zp->zlib_init, CURLE_OK);
+}
+
+static const content_encoding gzip_encoding = {
+  "gzip",
+  "x-gzip",
+  gzip_init_writer,
+  gzip_unencode_write,
+  gzip_close_writer,
+  sizeof(zlib_params)
+};
+
+#endif /* HAVE_LIBZ */
+
+
+#ifdef HAVE_BROTLI
+
+/* Writer parameters. */
+typedef struct {
+  BrotliDecoderState *br;    /* State structure for brotli. */
+}  brotli_params;
+
+
+static CURLcode brotli_map_error(BrotliDecoderErrorCode be)
+{
+  switch(be) {
+  case BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE:
+  case BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE:
+  case BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET:
+  case BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME:
+  case BROTLI_DECODER_ERROR_FORMAT_CL_SPACE:
+  case BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE:
+  case BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT:
+  case BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1:
+  case BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2:
+  case BROTLI_DECODER_ERROR_FORMAT_TRANSFORM:
+  case BROTLI_DECODER_ERROR_FORMAT_DICTIONARY:
+  case BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS:
+  case BROTLI_DECODER_ERROR_FORMAT_PADDING_1:
+  case BROTLI_DECODER_ERROR_FORMAT_PADDING_2:
+  case BROTLI_DECODER_ERROR_COMPOUND_DICTIONARY:
+  case BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET:
+  case BROTLI_DECODER_ERROR_INVALID_ARGUMENTS:
+    return CURLE_BAD_CONTENT_ENCODING;
+  case BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES:
+  case BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS:
+  case BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP:
+  case BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1:
+  case BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2:
+  case BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES:
+    return CURLE_OUT_OF_MEMORY;
+  default:
+    break;
+  }
+  return CURLE_WRITE_ERROR;
+}
+
+static CURLcode brotli_init_writer(struct connectdata *conn,
+                                   contenc_writer *writer)
+{
+  brotli_params *bp = (brotli_params *) &writer->params;
+
+  (void) conn;
+
+  if(!writer->downstream)
+    return CURLE_WRITE_ERROR;
+
+  bp->br = BrotliDecoderCreateInstance(NULL, NULL, NULL);
+  return bp->br? CURLE_OK: CURLE_OUT_OF_MEMORY;
+}
+
+static CURLcode brotli_unencode_write(struct connectdata *conn,
+                                      contenc_writer *writer,
+                                      const char *buf, size_t nbytes)
+{
+  brotli_params *bp = (brotli_params *) &writer->params;
+  const uint8_t *src = (const uint8_t *) buf;
+  char *decomp;
+  uint8_t *dst;
+  size_t dstleft;
+  CURLcode result = CURLE_OK;
+
+  if(!bp->br)
+    return CURLE_WRITE_ERROR;  /* Stream already ended. */
+
+  decomp = malloc(DSIZ);
+  if(!decomp)
+    return CURLE_OUT_OF_MEMORY;
+
+  while(nbytes && result == CURLE_OK) {
+    BrotliDecoderResult r;
+
+    dst = (uint8_t *) decomp;
+    dstleft = DSIZ;
+    r = BrotliDecoderDecompressStream(bp->br,
+                                      &nbytes, &src, &dstleft, &dst, NULL);
+    result = Curl_unencode_write(conn, writer->downstream,
+                                 decomp, DSIZ - dstleft);
+    if(result)
+      break;
+    switch(r) {
+    case BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT:
+    case BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT:
+      break;
+    case BROTLI_DECODER_RESULT_SUCCESS:
+      BrotliDecoderDestroyInstance(bp->br);
+      bp->br = NULL;
+      if(nbytes)
+        result = CURLE_WRITE_ERROR;
+      break;
+    default:
+      result = brotli_map_error(BrotliDecoderGetErrorCode(bp->br));
+      break;
+    }
+  }
+  free(decomp);
+  return result;
+}
+
+static void brotli_close_writer(struct connectdata *conn,
+                                contenc_writer *writer)
+{
+  brotli_params *bp = (brotli_params *) &writer->params;
+
+  (void) conn;
+
+  if(bp->br) {
+    BrotliDecoderDestroyInstance(bp->br);
+    bp->br = NULL;
+  }
+}
+
+static const content_encoding brotli_encoding = {
+  "br",
+  NULL,
+  brotli_init_writer,
+  brotli_unencode_write,
+  brotli_close_writer,
+  sizeof(brotli_params)
+};
+#endif
+
+
+/* Identity handler. */
+static CURLcode identity_init_writer(struct connectdata *conn,
+                                     contenc_writer *writer)
+{
+  (void) conn;
+  return writer->downstream? CURLE_OK: CURLE_WRITE_ERROR;
+}
+
+static CURLcode identity_unencode_write(struct connectdata *conn,
+                                        contenc_writer *writer,
+                                        const char *buf, size_t nbytes)
+{
+  return Curl_unencode_write(conn, writer->downstream, buf, nbytes);
+}
+
+static void identity_close_writer(struct connectdata *conn,
+                                  contenc_writer *writer)
+{
+  (void) conn;
+  (void) writer;
+}
+
+static const content_encoding identity_encoding = {
+  "identity",
+  NULL,
+  identity_init_writer,
+  identity_unencode_write,
+  identity_close_writer,
+  0
+};
+
+
+/* supported content encodings table. */
+static const content_encoding * const encodings[] = {
+  &identity_encoding,
+#ifdef HAVE_LIBZ
+  &deflate_encoding,
+  &gzip_encoding,
+#endif
+#ifdef HAVE_BROTLI
+  &brotli_encoding,
+#endif
+  NULL
+};
+
+
+/* Return a list of comma-separated names of supported encodings. */
+char *Curl_all_content_encodings(void)
+{
+  size_t len = 0;
+  const content_encoding * const *cep;
+  const content_encoding *ce;
+  char *ace;
+  char *p;
+
+  for(cep = encodings; *cep; cep++) {
+    ce = *cep;
+    if(!strcasecompare(ce->name, CONTENT_ENCODING_DEFAULT))
+      len += strlen(ce->name) + 2;
+  }
+
+  if(!len)
+    return strdup(CONTENT_ENCODING_DEFAULT);
+
+  ace = malloc(len);
+  if(ace) {
+    p = ace;
+    for(cep = encodings; *cep; cep++) {
+      ce = *cep;
+      if(!strcasecompare(ce->name, CONTENT_ENCODING_DEFAULT)) {
+        strcpy(p, ce->name);
+        p += strlen(p);
+        *p++ = ',';
+        *p++ = ' ';
+      }
+    }
+    p[-2] = '\0';
+  }
+
+  return ace;
+}
+
+
+/* Real client writer: no downstream. */
+static CURLcode client_init_writer(struct connectdata *conn,
+                                   contenc_writer *writer)
+{
+  (void) conn;
+  return writer->downstream? CURLE_WRITE_ERROR: CURLE_OK;
+}
+
+static CURLcode client_unencode_write(struct connectdata *conn,
+                                      contenc_writer *writer,
+                                      const char *buf, size_t nbytes)
+{
+  struct Curl_easy *data = conn->data;
+  struct SingleRequest *k = &data->req;
+
+  (void) writer;
+
+  if(!nbytes || k->ignorebody)
+    return CURLE_OK;
+
+  return Curl_client_write(conn, CLIENTWRITE_BODY, (char *) buf, nbytes);
+}
+
+static void client_close_writer(struct connectdata *conn,
+                                contenc_writer *writer)
+{
+  (void) conn;
+  (void) writer;
+}
+
+static const content_encoding client_encoding = {
+  NULL,
+  NULL,
+  client_init_writer,
+  client_unencode_write,
+  client_close_writer,
+  0
+};
+
+
+/* Deferred error dummy writer. */
+static CURLcode error_init_writer(struct connectdata *conn,
+                                  contenc_writer *writer)
+{
+  (void) conn;
+  return writer->downstream? CURLE_OK: CURLE_WRITE_ERROR;
+}
+
+static CURLcode error_unencode_write(struct connectdata *conn,
+                                     contenc_writer *writer,
+                                     const char *buf, size_t nbytes)
+{
+  char *all = Curl_all_content_encodings();
+
+  (void) writer;
+  (void) buf;
+  (void) nbytes;
+
+  if(!all)
+    return CURLE_OUT_OF_MEMORY;
+  failf(conn->data, "Unrecognized content encoding type. "
+                    "libcurl understands %s content encodings.", all);
+  free(all);
+  return CURLE_BAD_CONTENT_ENCODING;
+}
+
+static void error_close_writer(struct connectdata *conn,
+                               contenc_writer *writer)
+{
+  (void) conn;
+  (void) writer;
+}
+
+static const content_encoding error_encoding = {
+  NULL,
+  NULL,
+  error_init_writer,
+  error_unencode_write,
+  error_close_writer,
+  0
+};
+
+/* Create an unencoding writer stage using the given handler. */
+static contenc_writer *new_unencoding_writer(struct connectdata *conn,
+                                             const content_encoding *handler,
+                                             contenc_writer *downstream)
+{
+  size_t sz = offsetof(contenc_writer, params) + handler->paramsize;
+  contenc_writer *writer = (contenc_writer *) malloc(sz);
+
+  if(writer) {
+    memset(writer, 0, sz);
+    writer->handler = handler;
+    writer->downstream = downstream;
+    if(handler->init_writer(conn, writer)) {
+      free(writer);
+      writer = NULL;
+    }
+  }
+
+  return writer;
+}
+
+/* Write data using an unencoding writer stack. */
+CURLcode Curl_unencode_write(struct connectdata *conn, contenc_writer *writer,
+                             const char *buf, size_t nbytes)
+{
+  if(!nbytes)
+    return CURLE_OK;
+  return writer->handler->unencode_write(conn, writer, buf, nbytes);
+}
+
+/* Close and clean-up the connection's writer stack. */
 void Curl_unencode_cleanup(struct connectdata *conn)
 {
   struct Curl_easy *data = conn->data;
   struct SingleRequest *k = &data->req;
-  z_stream *z = &k->z;
-  if(k->zlib_init != ZLIB_UNINIT)
-    (void) exit_zlib(z, &k->zlib_init, CURLE_OK);
+  contenc_writer *writer = k->writer_stack;
+
+  while(writer) {
+    k->writer_stack = writer->downstream;
+    writer->handler->close_writer(conn, writer);
+    free(writer);
+    writer = k->writer_stack;
+  }
 }
 
-#endif /* HAVE_LIBZ */
+/* Find the content encoding by name. */
+static const content_encoding *find_encoding(const char *name, size_t len)
+{
+  const content_encoding * const *cep;
+  const content_encoding *ce;
+
+  for(cep = encodings; *cep; cep++) {
+    ce = *cep;
+    if((strncasecompare(name, ce->name, len) && !ce->name[len]) ||
+       (ce->alias && strncasecompare(name, ce->alias, len) && !ce->alias[len]))
+      return ce;
+  }
+  return NULL;
+}
+
+/* Set-up the unencoding stack from the Content-Encoding header value.
+ * See RFC 7231 section 3.1.2.2. */
+CURLcode Curl_build_unencoding_stack(struct connectdata *conn,
+                                     const char *enclist, int maybechunked)
+{
+  struct Curl_easy *data = conn->data;
+  struct SingleRequest *k = &data->req;
+
+  do {
+    const char *name;
+    size_t namelen;
+
+    /* Parse a single encoding name. */
+    while(ISSPACE(*enclist) || *enclist == ',')
+      enclist++;
+
+    name = enclist;
+
+    for(namelen = 0; *enclist && *enclist != ','; enclist++)
+      if(!ISSPACE(*enclist))
+        namelen = enclist - name + 1;
+
+    /* Special case: chunked encoding is handled at the reader level. */
+    if(maybechunked && namelen == 7 && strncasecompare(name, "chunked", 7)) {
+      k->chunk = TRUE;             /* chunks coming our way. */
+      Curl_httpchunk_init(conn);   /* init our chunky engine. */
+    }
+    else if(namelen) {
+      const content_encoding *encoding = find_encoding(name, namelen);
+      contenc_writer *writer;
+
+      if(!k->writer_stack) {
+        k->writer_stack = new_unencoding_writer(conn, &client_encoding, NULL);
+
+        if(!k->writer_stack)
+          return CURLE_OUT_OF_MEMORY;
+      }
+
+      if(!encoding)
+        encoding = &error_encoding;  /* Defer error at stack use. */
+
+      /* Stack the unencoding stage. */
+      writer = new_unencoding_writer(conn, encoding, k->writer_stack);
+      if(!writer)
+        return CURLE_OUT_OF_MEMORY;
+      k->writer_stack = writer;
+    }
+  } while(*enclist);
+
+  return CURLE_OK;
+}
+
+#else
+/* Stubs for builds without HTTP. */
+CURLcode Curl_build_unencoding_stack(struct connectdata *conn,
+                                     const char *enclist, int maybechunked)
+{
+  (void) conn;
+  (void) enclist;
+  (void) maybechunked;
+  return CURLE_NOT_BUILT_IN;
+}
+
+CURLcode Curl_unencode_write(struct connectdata *conn, contenc_writer *writer,
+                             const char *buf, size_t nbytes)
+{
+  (void) conn;
+  (void) writer;
+  (void) buf;
+  (void) nbytes;
+  return CURLE_NOT_BUILT_IN;
+}
+
+void Curl_unencode_cleanup(struct connectdata *conn)
+{
+  (void) conn;
+}
+
+char *Curl_all_content_encodings(void)
+{
+  return strdup(CONTENT_ENCODING_DEFAULT);  /* Satisfy caller. */
+}
+
+#endif /* CURL_DISABLE_HTTP */
diff --git a/lib/content_encoding.h b/lib/content_encoding.h
index 3fadd2899..4cd52be62 100644
--- a/lib/content_encoding.h
+++ b/lib/content_encoding.h
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2011, Daniel Stenberg, <address@hidden>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <address@hidden>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -23,26 +23,33 @@
  ***************************************************************************/
 #include "curl_setup.h"
 
-/*
- * Comma-separated list all supported Content-Encodings ('identity' is implied)
- */
-#ifdef HAVE_LIBZ
-#define ALL_CONTENT_ENCODINGS "deflate, gzip"
-/* force a cleanup */
-void Curl_unencode_cleanup(struct connectdata *conn);
-#else
-#define ALL_CONTENT_ENCODINGS "identity"
-#define Curl_unencode_cleanup(x) Curl_nop_stmt
-#endif
+/* Decoding writer. */
+typedef struct contenc_writer_s contenc_writer;
+typedef struct content_encoding_s content_encoding;
+
+struct contenc_writer_s {
+  const content_encoding *handler;  /* Encoding handler. */
+  contenc_writer *downstream;  /* Downstream writer. */
+  void *params;  /* Encoding-specific storage (variable length). */
+};
 
-CURLcode Curl_unencode_deflate_write(struct connectdata *conn,
-                                     struct SingleRequest *req,
-                                     ssize_t nread);
+/* Content encoding writer. */
+struct content_encoding_s {
+  const char *name;        /* Encoding name. */
+  const char *alias;       /* Encoding name alias. */
+  CURLcode (*init_writer)(struct connectdata *conn, contenc_writer *writer);
+  CURLcode (*unencode_write)(struct connectdata *conn, contenc_writer *writer,
+                             const char *buf, size_t nbytes);
+  void (*close_writer)(struct connectdata *conn, contenc_writer *writer);
+  size_t paramsize;
+};
 
-CURLcode
-Curl_unencode_gzip_write(struct connectdata *conn,
-                         struct SingleRequest *k,
-                         ssize_t nread);
 
+CURLcode Curl_build_unencoding_stack(struct connectdata *conn,
+                                     const char *enclist, int maybechunked);
+CURLcode Curl_unencode_write(struct connectdata *conn, contenc_writer *writer,
+                             const char *buf, size_t nbytes);
+void Curl_unencode_cleanup(struct connectdata *conn);
+char *Curl_all_content_encodings(void);
 
 #endif /* HEADER_CURL_CONTENT_ENCODING_H */
diff --git a/lib/cookie.c b/lib/cookie.c
index 271f6d49d..c7afc7ae3 100644
--- a/lib/cookie.c
+++ b/lib/cookie.c
@@ -309,7 +309,7 @@ static void remove_expired(struct CookieInfo *cookies)
   while(co) {
     nx = co->next;
     if(co->expires && co->expires < now) {
-      if(co == cookies->cookies) {
+      if(!pv) {
         cookies->cookies = co->next;
       }
       else {
diff --git a/lib/curl_config.h.cmake b/lib/curl_config.h.cmake
index c80484f65..e4d14c784 100644
--- a/lib/curl_config.h.cmake
+++ b/lib/curl_config.h.cmake
@@ -1000,3 +1000,6 @@
 
 /* the signed version of size_t */
 #cmakedefine ssize_t ${ssize_t}
+
+/* Define to 1 if you have the mach_absolute_time function. */
+#cmakedefine HAVE_MACH_ABSOLUTE_TIME 1
diff --git a/lib/curl_fnmatch.c b/lib/curl_fnmatch.c
index 6a7267d07..0e328fa44 100644
--- a/lib/curl_fnmatch.c
+++ b/lib/curl_fnmatch.c
@@ -133,6 +133,9 @@ static int setcharset(unsigned char **p, unsigned char 
*charset)
   unsigned char c;
   for(;;) {
     c = **p;
+    if(!c)
+      return SETCHARSET_FAIL;
+
     switch(state) {
     case CURLFNM_SCHS_DEFAULT:
       if(ISALNUM(c)) { /* ASCII value */
@@ -196,9 +199,6 @@ static int setcharset(unsigned char **p, unsigned char 
*charset)
         else
           return SETCHARSET_FAIL;
       }
-      else if(c == '\0') {
-        return SETCHARSET_FAIL;
-      }
       else {
         charset[c] = 1;
         (*p)++;
@@ -235,15 +235,10 @@ static int setcharset(unsigned char **p, unsigned char 
*charset)
         return SETCHARSET_FAIL;
       break;
     case CURLFNM_SCHS_MAYRANGE2:
-      if(c == '\\') {
-        c = *(++(*p));
-        if(!ISPRINT(c))
-          return SETCHARSET_FAIL;
-      }
       if(c == ']') {
         return SETCHARSET_OK;
       }
-      if(c == '\\') {
+      else if(c == '\\') {
         c = *(++(*p));
         if(ISPRINT(c)) {
           charset[c] = 1;
@@ -253,7 +248,7 @@ static int setcharset(unsigned char **p, unsigned char 
*charset)
         else
           return SETCHARSET_FAIL;
       }
-      if(c >= rangestart) {
+      else if(c >= rangestart) {
         if((ISLOWER(c) && ISLOWER(rangestart)) ||
            (ISDIGIT(c) && ISDIGIT(rangestart)) ||
            (ISUPPER(c) && ISUPPER(rangestart))) {
@@ -267,6 +262,8 @@ static int setcharset(unsigned char **p, unsigned char 
*charset)
         else
           return SETCHARSET_FAIL;
       }
+      else
+        return SETCHARSET_FAIL;
       break;
     case CURLFNM_SCHS_RIGHTBR:
       if(c == '[') {
@@ -277,9 +274,6 @@ static int setcharset(unsigned char **p, unsigned char 
*charset)
       else if(c == ']') {
         return SETCHARSET_OK;
       }
-      else if(c == '\0') {
-        return SETCHARSET_FAIL;
-      }
       else if(ISPRINT(c)) {
         charset[c] = 1;
         (*p)++;
diff --git a/lib/curl_ntlm_core.c b/lib/curl_ntlm_core.c
index 5154949e6..e8962769c 100644
--- a/lib/curl_ntlm_core.c
+++ b/lib/curl_ntlm_core.c
@@ -557,7 +557,7 @@ CURLcode Curl_ntlm_core_mk_nt_hash(struct Curl_easy *data,
                                    unsigned char *ntbuffer /* 21 bytes */)
 {
   size_t len = strlen(password);
-  unsigned char *pw = malloc(len * 2);
+  unsigned char *pw = len ? malloc(len * 2) : strdup("");
   CURLcode result;
   if(!pw)
     return CURLE_OUT_OF_MEMORY;
@@ -646,6 +646,15 @@ CURLcode Curl_hmac_md5(const unsigned char *key, unsigned 
int keylen,
   return CURLE_OK;
 }
 
+#ifndef SIZE_T_MAX
+/* some limits.h headers have this defined, some don't */
+#if defined(SIZEOF_SIZE_T) && (SIZEOF_SIZE_T > 4)
+#define SIZE_T_MAX 18446744073709551615U
+#else
+#define SIZE_T_MAX 4294967295U
+#endif
+#endif
+
 /* This creates the NTLMv2 hash by using NTLM hash as the key and Unicode
  * (uppercase UserName + Domain) as the data
  */
@@ -655,10 +664,20 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_hash(const char *user, 
size_t userlen,
                                        unsigned char *ntlmv2hash)
 {
   /* Unicode representation */
-  size_t identity_len = (userlen + domlen) * 2;
-  unsigned char *identity = malloc(identity_len);
+  size_t identity_len;
+  unsigned char *identity;
   CURLcode result = CURLE_OK;
 
+  /* we do the length checks below separately to avoid integer overflow risk
+     on extreme data lengths */
+  if((userlen > SIZE_T_MAX/2) ||
+     (domlen > SIZE_T_MAX/2) ||
+     ((userlen + domlen) > SIZE_T_MAX/2))
+    return CURLE_OUT_OF_MEMORY;
+
+  identity_len = (userlen + domlen) * 2;
+  identity = malloc(identity_len);
+
   if(!identity)
     return CURLE_OUT_OF_MEMORY;
 
diff --git a/lib/curl_setup.h b/lib/curl_setup.h
index db9571602..090ebf9cf 100644
--- a/lib/curl_setup.h
+++ b/lib/curl_setup.h
@@ -751,9 +751,10 @@ endings either CRLF or LF so 't' is appropriate.
 
 /* Detect Windows App environment which has a restricted access
  * to the Win32 APIs. */
-# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0602)
+# if (defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0602)) || \
+  defined(WINAPI_FAMILY)
 #  include <winapifamily.h>
-#  if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \
+#  if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) &&  \
      !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
 #    define CURL_WINDOWS_APP
 #  endif
diff --git a/lib/gopher.h b/lib/curl_sha256.h
similarity index 76%
copy from lib/gopher.h
copy to lib/curl_sha256.h
index 501c990a8..6db4b04db 100644
--- a/lib/gopher.h
+++ b/lib/curl_sha256.h
@@ -1,5 +1,5 @@
-#ifndef HEADER_CURL_GOPHER_H
-#define HEADER_CURL_GOPHER_H
+#ifndef HEADER_CURL_SHA256_H
+#define HEADER_CURL_SHA256_H
 /***************************************************************************
  *                                  _   _ ____  _
  *  Project                     ___| | | |  _ \| |
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2009, Daniel Stenberg, <address@hidden>, et al.
+ * Copyright (C) 1998 - 2010, Florin Petriuc, <address@hidden>
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -22,8 +22,11 @@
  *
  ***************************************************************************/
 
-#ifndef CURL_DISABLE_GOPHER
-extern const struct Curl_handler Curl_handler_gopher;
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+
+void Curl_sha256it(unsigned char *outbuffer,
+                const unsigned char *input);
+
 #endif
 
-#endif /* HEADER_CURL_GOPHER_H */
+#endif /* HEADER_CURL_SHA256_H */
diff --git a/lib/curlx.h b/lib/curlx.h
index a261e71f4..e589801c2 100644
--- a/lib/curlx.h
+++ b/lib/curlx.h
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <address@hidden>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <address@hidden>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -42,16 +42,6 @@
    curl_off_t number from a given string.
 */
 
-#include "timeval.h"
-/*
-  "timeval.h" sets up a 'struct timeval' even for platforms that otherwise
-  don't have one and has protos for these functions:
-
-  curlx_tvnow()
-  curlx_tvdiff()
-  curlx_tvdiff_secs()
-*/
-
 #include "nonblock.h"
 /* "nonblock.h" provides curlx_nonblock() */
 
diff --git a/lib/easy.c b/lib/easy.c
index 894787191..bed6ee5d0 100644
--- a/lib/easy.c
+++ b/lib/easy.c
@@ -68,10 +68,11 @@
 #include "amigaos.h"
 #include "non-ascii.h"
 #include "warnless.h"
-#include "conncache.h"
 #include "multiif.h"
 #include "sigpipe.h"
 #include "ssh.h"
+#include "setopt.h"
+
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_memory.h"
@@ -214,11 +215,10 @@ static CURLcode global_init(long flags, bool memoryfuncs)
 #endif
   }
 
-  if(flags & CURL_GLOBAL_SSL)
-    if(!Curl_ssl_init()) {
-      DEBUGF(fprintf(stderr, "Error: Curl_ssl_init failed\n"));
-      return CURLE_FAILED_INIT;
-    }
+  if(!Curl_ssl_init()) {
+    DEBUGF(fprintf(stderr, "Error: Curl_ssl_init failed\n"));
+    return CURLE_FAILED_INIT;
+  }
 
   if(flags & CURL_GLOBAL_WIN32)
     if(win32_init()) {
@@ -318,10 +318,7 @@ void curl_global_cleanup(void)
     return;
 
   Curl_global_host_cache_dtor();
-
-  if(init_flags & CURL_GLOBAL_SSL)
-    Curl_ssl_cleanup();
-
+  Curl_ssl_cleanup();
   Curl_resolver_global_cleanup();
 
   if(init_flags & CURL_GLOBAL_WIN32)
@@ -365,28 +362,6 @@ struct Curl_easy *curl_easy_init(void)
   return data;
 }
 
-/*
- * curl_easy_setopt() is the external interface for setting options on an
- * easy handle.
- */
-
-#undef curl_easy_setopt
-CURLcode curl_easy_setopt(struct Curl_easy *data, CURLoption tag, ...)
-{
-  va_list arg;
-  CURLcode result;
-
-  if(!data)
-    return CURLE_BAD_FUNCTION_ARGUMENT;
-
-  va_start(arg, tag);
-
-  result = Curl_setopt(data, tag, arg);
-
-  va_end(arg);
-  return result;
-}
-
 #ifdef CURLDEBUG
 
 struct socketmonitor {
@@ -586,12 +561,12 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, 
struct events *ev)
     }
 
     /* get the time stamp to use to figure out how long poll takes */
-    before = curlx_tvnow();
+    before = Curl_now();
 
     /* wait for activity or timeout */
     pollrc = Curl_poll(fds, numfds, (int)ev->ms);
 
-    after = curlx_tvnow();
+    after = Curl_now();
 
     ev->msbump = FALSE; /* reset here */
 
@@ -619,7 +594,7 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, 
struct events *ev)
         /* If nothing updated the timeout, we decrease it by the spent time.
          * If it was updated, it has the new timeout time stored already.
          */
-        time_t timediff = curlx_tvdiff(after, before);
+        timediff_t timediff = Curl_timediff(after, before);
         if(timediff > 0) {
           if(timediff > ev->ms)
             ev->ms = 0;
@@ -680,17 +655,17 @@ static CURLcode easy_transfer(struct Curl_multi *multi)
     int still_running = 0;
     int rc;
 
-    before = curlx_tvnow();
+    before = Curl_now();
     mcode = curl_multi_wait(multi, NULL, 0, 1000, &rc);
 
     if(!mcode) {
       if(!rc) {
-        struct curltime after = curlx_tvnow();
+        struct curltime after = Curl_now();
 
         /* If it returns without any filedescriptor instantly, we need to
            avoid busy-looping during periods where it has nothing particular
            to wait for */
-        if(curlx_tvdiff(after, before) <= 10) {
+        if(Curl_timediff(after, before) <= 10) {
           without_fds++;
           if(without_fds > 2) {
             int sleep_ms = without_fds < 10 ? (1 << (without_fds - 1)) : 1000;
@@ -861,6 +836,40 @@ CURLcode curl_easy_getinfo(struct Curl_easy *data, 
CURLINFO info, ...)
   return result;
 }
 
+static CURLcode dupset(struct Curl_easy *dst, struct Curl_easy *src)
+{
+  CURLcode result = CURLE_OK;
+  enum dupstring i;
+
+  /* Copy src->set into dst->set first, then deal with the strings
+     afterwards */
+  dst->set = src->set;
+
+  /* clear all string pointers first */
+  memset(dst->set.str, 0, STRING_LAST * sizeof(char *));
+
+  /* duplicate all strings */
+  for(i = (enum dupstring)0; i< STRING_LASTZEROTERMINATED; i++) {
+    result = Curl_setstropt(&dst->set.str[i], src->set.str[i]);
+    if(result)
+      return result;
+  }
+
+  /* duplicate memory areas pointed to */
+  i = STRING_COPYPOSTFIELDS;
+  if(src->set.postfieldsize && src->set.str[i]) {
+    /* postfieldsize is curl_off_t, Curl_memdup() takes a size_t ... */
+    dst->set.str[i] = Curl_memdup(src->set.str[i],
+                                  curlx_sotouz(src->set.postfieldsize));
+    if(!dst->set.str[i])
+      return CURLE_OUT_OF_MEMORY;
+    /* point to the new copy */
+    dst->set.postfields = dst->set.str[i];
+  }
+
+  return CURLE_OK;
+}
+
 /*
  * curl_easy_duphandle() is an external interface to allow duplication of a
  * given input easy handle. The returned handle will be a new working handle
@@ -888,7 +897,7 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy 
*data)
   outcurl->state.headersize = HEADERSIZE;
 
   /* copy all userdefined values */
-  if(Curl_dupset(outcurl, data))
+  if(dupset(outcurl, data))
     goto fail;
 
   /* the connection cache is setup on demand */
diff --git a/lib/file.c b/lib/file.c
index 25f8005af..be19c9fc2 100644
--- a/lib/file.c
+++ b/lib/file.c
@@ -404,7 +404,7 @@ static CURLcode file_upload(struct connectdata *conn)
     if(Curl_pgrsUpdate(conn))
       result = CURLE_ABORTED_BY_CALLBACK;
     else
-      result = Curl_speedcheck(data, Curl_tvnow());
+      result = Curl_speedcheck(data, Curl_now());
   }
   if(!result && Curl_pgrsUpdate(conn))
     result = CURLE_ABORTED_BY_CALLBACK;
@@ -589,7 +589,7 @@ static CURLcode file_do(struct connectdata *conn, bool 
*done)
     if(Curl_pgrsUpdate(conn))
       result = CURLE_ABORTED_BY_CALLBACK;
     else
-      result = Curl_speedcheck(data, Curl_tvnow());
+      result = Curl_speedcheck(data, Curl_now());
   }
   if(Curl_pgrsUpdate(conn))
     result = CURLE_ABORTED_BY_CALLBACK;
diff --git a/lib/ftp.c b/lib/ftp.c
index 0141a0dca..27d7f3311 100644
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -182,7 +182,8 @@ const struct Curl_handler Curl_handler_ftp = {
   PORT_FTP,                        /* defport */
   CURLPROTO_FTP,                   /* protocol */
   PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD |
-  PROTOPT_NOURLQUERY | PROTOPT_PROXY_AS_HTTP /* flags */
+  PROTOPT_NOURLQUERY | PROTOPT_PROXY_AS_HTTP |
+  PROTOPT_WILDCARD /* flags */
 };
 
 
@@ -210,7 +211,7 @@ const struct Curl_handler Curl_handler_ftps = {
   PORT_FTPS,                       /* defport */
   CURLPROTO_FTPS,                  /* protocol */
   PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION |
-  PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY /* flags */
+  PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY | PROTOPT_WILDCARD /* flags */
 };
 #endif
 
@@ -332,16 +333,16 @@ static CURLcode AcceptServerConnect(struct connectdata 
*conn)
  * Curl_pgrsTime(..., TIMER_STARTACCEPT);
  *
  */
-static time_t ftp_timeleft_accept(struct Curl_easy *data)
+static timediff_t ftp_timeleft_accept(struct Curl_easy *data)
 {
-  time_t timeout_ms = DEFAULT_ACCEPT_TIMEOUT;
-  time_t other;
+  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_tvnow();
+  now = Curl_now();
 
   /* check if the generic timeout possibly is set shorter */
   other =  Curl_timeleft(data, &now, FALSE);
@@ -351,7 +352,7 @@ static time_t ftp_timeleft_accept(struct Curl_easy *data)
     timeout_ms = other;
   else {
     /* subtract elapsed time */
-    timeout_ms -= Curl_tvdiff(now, data->progress.t_acceptdata);
+    timeout_ms -= Curl_timediff(now, data->progress.t_acceptdata);
     if(!timeout_ms)
       /* avoid returning 0 as that means no timeout! */
       return -1;
@@ -3177,7 +3178,7 @@ static CURLcode ftp_done(struct connectdata *conn, 
CURLcode status,
   /* now store a copy of the directory we are in */
   free(ftpc->prevpath);
 
-  if(data->set.wildcardmatch) {
+  if(data->state.wildcardmatch) {
     if(data->set.chunk_end && ftpc->file) {
       data->set.chunk_end(data->wildcard.customptr);
     }
@@ -3261,7 +3262,7 @@ static CURLcode ftp_done(struct connectdata *conn, 
CURLcode status,
     long old_time = pp->response_time;
 
     pp->response_time = 60*1000; /* give it only a minute for now */
-    pp->response = Curl_tvnow(); /* timeout relative now */
+    pp->response = Curl_now(); /* timeout relative now */
 
     result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
 
@@ -3381,7 +3382,7 @@ CURLcode ftp_sendquote(struct connectdata *conn, struct 
curl_slist *quote)
 
       PPSENDF(&conn->proto.ftpc.pp, "%s", cmd);
 
-      pp->response = Curl_tvnow(); /* timeout relative now */
+      pp->response = Curl_now(); /* timeout relative now */
 
       result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
       if(result)
@@ -3962,7 +3963,7 @@ static CURLcode ftp_do(struct connectdata *conn, bool 
*done)
   *done = FALSE; /* default to false */
   ftpc->wait_data_conn = FALSE; /* default to no such wait */
 
-  if(conn->data->set.wildcardmatch) {
+  if(conn->data->state.wildcardmatch) {
     result = wc_statemach(conn);
     if(conn->data->wildcard.state == CURLWC_SKIP ||
       conn->data->wildcard.state == CURLWC_DONE) {
diff --git a/lib/ftplistparser.c b/lib/ftplistparser.c
index ab6c50e82..ec3579ce3 100644
--- a/lib/ftplistparser.c
+++ b/lib/ftplistparser.c
@@ -264,16 +264,6 @@ static int ftp_pl_get_permission(const char *str)
   return permissions;
 }
 
-static void PL_ERROR(struct connectdata *conn, CURLcode err)
-{
-  struct ftp_wc_tmpdata *tmpdata = conn->data->wildcard.tmp;
-  struct ftp_parselist_data *parser = tmpdata->parser;
-  if(parser->file_data)
-    Curl_fileinfo_dtor(NULL, parser->file_data);
-  parser->file_data = NULL;
-  parser->error = err;
-}
-
 static CURLcode ftp_pl_insert_finfo(struct connectdata *conn,
                                     struct fileinfo *infop)
 {
@@ -338,6 +328,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t 
nmemb,
   struct curl_fileinfo *finfo;
   unsigned long i = 0;
   CURLcode result;
+  size_t retsize = bufflen;
 
   if(parser->error) { /* error in previous call */
     /* scenario:
@@ -346,7 +337,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t 
nmemb,
      * 3. (last) call => is skipped RIGHT HERE and the error is hadled later
      *    in wc_statemach()
      */
-    return bufflen;
+    goto fail;
   }
 
   if(parser->os_type == OS_TYPE_UNKNOWN && bufflen > 0) {
@@ -362,12 +353,12 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, 
size_t nmemb,
       parser->file_data = Curl_fileinfo_alloc();
       if(!parser->file_data) {
         parser->error = CURLE_OUT_OF_MEMORY;
-        return bufflen;
+        goto fail;
       }
       parser->file_data->info.b_data = malloc(FTP_BUFFER_ALLOCSIZE);
       if(!parser->file_data->info.b_data) {
-        PL_ERROR(conn, CURLE_OUT_OF_MEMORY);
-        return bufflen;
+        parser->error = CURLE_OUT_OF_MEMORY;
+        goto fail;
       }
       parser->file_data->info.b_size = FTP_BUFFER_ALLOCSIZE;
       parser->item_offset = 0;
@@ -390,8 +381,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t 
nmemb,
         Curl_fileinfo_dtor(NULL, parser->file_data);
         parser->file_data = NULL;
         parser->error = CURLE_OUT_OF_MEMORY;
-        PL_ERROR(conn, CURLE_OUT_OF_MEMORY);
-        return bufflen;
+        goto fail;
       }
     }
 
@@ -429,15 +419,15 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, 
size_t nmemb,
               while(ISDIGIT(*endptr))
                 endptr++;
               if(*endptr != 0) {
-                PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-                return bufflen;
+                parser->error = CURLE_FTP_BAD_FILE_LIST;
+                goto fail;
               }
               parser->state.UNIX.main = PL_UNIX_FILETYPE;
               finfo->b_used = 0;
             }
             else {
-              PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-              return bufflen;
+              parser->error = CURLE_FTP_BAD_FILE_LIST;
+              goto fail;
             }
           }
           break;
@@ -470,8 +460,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t 
nmemb,
           finfo->filetype = CURLFILETYPE_DOOR;
           break;
         default:
-          PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-          return bufflen;
+          parser->error = CURLE_FTP_BAD_FILE_LIST;
+          goto fail;
         }
         parser->state.UNIX.main = PL_UNIX_PERMISSION;
         parser->item_length = 0;
@@ -481,21 +471,21 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, 
size_t nmemb,
         parser->item_length++;
         if(parser->item_length <= 9) {
           if(!strchr("rwx-tTsS", c)) {
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            return bufflen;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
         }
         else if(parser->item_length == 10) {
           unsigned int perm;
           if(c != ' ') {
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            return bufflen;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
           finfo->b_data[10] = 0; /* terminate permissions */
           perm = ftp_pl_get_permission(finfo->b_data + parser->item_offset);
           if(perm & FTP_LP_MALFORMATED_PERM) {
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            return bufflen;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
           parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_PERM;
           parser->file_data->info.perm = perm;
@@ -516,8 +506,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t 
nmemb,
               parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_NUMBER;
             }
             else {
-              PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-              return bufflen;
+              parser->error = CURLE_FTP_BAD_FILE_LIST;
+              goto fail;
             }
           }
           break;
@@ -538,8 +528,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t 
nmemb,
             parser->state.UNIX.sub.user = PL_UNIX_USER_PRESPACE;
           }
           else if(c < '0' || c > '9') {
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            return bufflen;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
           break;
         }
@@ -598,8 +588,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t 
nmemb,
               parser->state.UNIX.sub.size = PL_UNIX_SIZE_NUMBER;
             }
             else {
-              PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-              return bufflen;
+              parser->error = CURLE_FTP_BAD_FILE_LIST;
+              goto fail;
             }
           }
           break;
@@ -623,8 +613,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t 
nmemb,
             }
           }
           else if(!ISDIGIT(c)) {
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            return bufflen;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
           break;
         }
@@ -639,8 +629,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t 
nmemb,
               parser->state.UNIX.sub.time = PL_UNIX_TIME_PART1;
             }
             else {
-              PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-              return bufflen;
+              parser->error = CURLE_FTP_BAD_FILE_LIST;
+              goto fail;
             }
           }
           break;
@@ -650,8 +640,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t 
nmemb,
             parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART2;
           }
           else if(!ISALNUM(c) && c != '.') {
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            return bufflen;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
           break;
         case PL_UNIX_TIME_PREPART2:
@@ -661,8 +651,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t 
nmemb,
               parser->state.UNIX.sub.time = PL_UNIX_TIME_PART2;
             }
             else {
-              PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-              return bufflen;
+              parser->error = CURLE_FTP_BAD_FILE_LIST;
+              goto fail;
             }
           }
           break;
@@ -672,8 +662,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t 
nmemb,
             parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART3;
           }
           else if(!ISALNUM(c) && c != '.') {
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            return bufflen;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
           break;
         case PL_UNIX_TIME_PREPART3:
@@ -683,8 +673,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t 
nmemb,
               parser->state.UNIX.sub.time = PL_UNIX_TIME_PART3;
             }
             else {
-              PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-              return bufflen;
+              parser->error = CURLE_FTP_BAD_FILE_LIST;
+              goto fail;
             }
           }
           break;
@@ -708,8 +698,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t 
nmemb,
             }
           }
           else if(!ISALNUM(c) && c != '.' && c != ':') {
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            return bufflen;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
           break;
         }
@@ -734,8 +724,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t 
nmemb,
             parser->state.UNIX.main = PL_UNIX_FILETYPE;
             result = ftp_pl_insert_finfo(conn, infop);
             if(result) {
-              PL_ERROR(conn, result);
-              return bufflen;
+              parser->error = result;
+              goto fail;
             }
           }
           break;
@@ -746,13 +736,13 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, 
size_t nmemb,
             parser->state.UNIX.main = PL_UNIX_FILETYPE;
             result = ftp_pl_insert_finfo(conn, infop);
             if(result) {
-              PL_ERROR(conn, result);
-              return bufflen;
+              parser->error = result;
+              goto fail;
             }
           }
           else {
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            return bufflen;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
           break;
         }
@@ -772,8 +762,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t 
nmemb,
             parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET1;
           }
           else if(c == '\r' || c == '\n') {
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            return bufflen;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
           break;
         case PL_UNIX_SYMLINK_PRETARGET1:
@@ -782,8 +772,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t 
nmemb,
             parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET2;
           }
           else if(c == '\r' || c == '\n') {
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            return bufflen;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
           else {
             parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
@@ -795,8 +785,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t 
nmemb,
             parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET3;
           }
           else if(c == '\r' || c == '\n') {
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            return bufflen;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
           else {
             parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
@@ -813,8 +803,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t 
nmemb,
             parser->item_offset = 0;
           }
           else if(c == '\r' || c == '\n') {
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            return bufflen;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
           else {
             parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
@@ -827,8 +817,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t 
nmemb,
             parser->item_length = 1;
           }
           else {
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            return bufflen;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
           break;
         case PL_UNIX_SYMLINK_TARGET:
@@ -841,8 +831,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t 
nmemb,
             parser->offsets.symlink_target = parser->item_offset;
             result = ftp_pl_insert_finfo(conn, infop);
             if(result) {
-              PL_ERROR(conn, result);
-              return bufflen;
+              parser->error = result;
+              goto fail;
             }
             parser->state.UNIX.main = PL_UNIX_FILETYPE;
           }
@@ -853,14 +843,14 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, 
size_t nmemb,
             parser->offsets.symlink_target = parser->item_offset;
             result = ftp_pl_insert_finfo(conn, infop);
             if(result) {
-              PL_ERROR(conn, result);
-              return bufflen;
+              parser->error = result;
+              goto fail;
             }
             parser->state.UNIX.main = PL_UNIX_FILETYPE;
           }
           else {
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            return bufflen;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
           break;
         }
@@ -873,8 +863,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t 
nmemb,
         parser->item_length++;
         if(parser->item_length < 9) {
           if(!strchr("0123456789-", c)) { /* only simple control */
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            return bufflen;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
         }
         else if(parser->item_length == 9) {
@@ -883,13 +873,13 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, 
size_t nmemb,
             parser->state.NT.sub.time = PL_WINNT_TIME_PRESPACE;
           }
           else {
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            return bufflen;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
         }
         else {
-          PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-          return bufflen;
+          parser->error = CURLE_FTP_BAD_FILE_LIST;
+          goto fail;
         }
         break;
       case PL_WINNT_TIME:
@@ -909,8 +899,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t 
nmemb,
             parser->item_length = 0;
           }
           else if(!strchr("APM0123456789:", c)) {
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            return bufflen;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
           break;
         }
@@ -940,8 +930,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t 
nmemb,
               if(curlx_strtoofft(finfo->b_data +
                                  parser->item_offset,
                                  &endptr, 10, &finfo->size)) {
-                PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-                return bufflen;
+                parser->error = CURLE_FTP_BAD_FILE_LIST;
+                goto fail;
               }
               /* correct file type */
               parser->file_data->info.filetype = CURLFILETYPE_FILE;
@@ -976,8 +966,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t 
nmemb,
             parser->offsets.filename = parser->item_offset;
             result = ftp_pl_insert_finfo(conn, infop);
             if(result) {
-              PL_ERROR(conn, result);
-              return bufflen;
+              parser->error = result;
+              goto fail;
             }
             parser->state.NT.main = PL_WINNT_DATE;
             parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
@@ -988,15 +978,15 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, 
size_t nmemb,
             parser->offsets.filename = parser->item_offset;
             result = ftp_pl_insert_finfo(conn, infop);
             if(result) {
-              PL_ERROR(conn, result);
-              return bufflen;
+              parser->error = result;
+              goto fail;
             }
             parser->state.NT.main = PL_WINNT_DATE;
             parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
           }
           else {
-            PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-            return bufflen;
+            parser->error = CURLE_FTP_BAD_FILE_LIST;
+            goto fail;
           }
           break;
         }
@@ -1004,13 +994,22 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, 
size_t nmemb,
       }
       break;
     default:
-      return bufflen + 1;
+      retsize = bufflen + 1;
+      goto fail;
     }
 
     i++;
   }
 
-  return bufflen;
+fail:
+
+  /* Clean up any allocated memory. */
+  if(parser->file_data) {
+    Curl_fileinfo_dtor(NULL, parser->file_data);
+    parser->file_data = NULL;
+  }
+
+  return retsize;
 }
 
 #endif /* CURL_DISABLE_FTP */
diff --git a/lib/hostasyn.c b/lib/hostasyn.c
index 28bdf7a48..7b6e8568a 100644
--- a/lib/hostasyn.c
+++ b/lib/hostasyn.c
@@ -22,6 +22,11 @@
 
 #include "curl_setup.h"
 
+/***********************************************************************
+ * Only for builds using asynchronous name resolves
+ **********************************************************************/
+#ifdef CURLRES_ASYNCH
+
 #ifdef HAVE_NETINET_IN_H
 #include <netinet/in.h>
 #endif
@@ -51,11 +56,6 @@
 /* The last #include file should be: */
 #include "memdebug.h"
 
-/***********************************************************************
- * Only for builds using asynchronous name resolves
- **********************************************************************/
-#ifdef CURLRES_ASYNCH
-
 /*
  * Curl_addrinfo_callback() gets called by ares, gethostbyname_thread()
  * or getaddrinfo_thread() when we got the name resolved (or not!).
diff --git a/lib/hostip.c b/lib/hostip.c
index 1a18a3ed7..7f010a037 100644
--- a/lib/hostip.c
+++ b/lib/hostip.c
@@ -688,8 +688,8 @@ clean_up:
      the time we spent until now! */
   if(prev_alarm) {
     /* there was an alarm() set before us, now put it back */
-    unsigned long elapsed_secs = (unsigned long) (Curl_tvdiff(Curl_tvnow(),
-                                   conn->created) / 1000);
+    timediff_t elapsed_secs = Curl_timediff(Curl_now(),
+                                            conn->created) / 1000;
 
     /* the alarm period is counted in even number of seconds */
     unsigned long alarm_set = prev_alarm - elapsed_secs;
@@ -778,7 +778,6 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
 {
   struct curl_slist *hostp;
   char hostname[256];
-  char address[256];
   int port;
 
   for(hostp = data->change.resolve; hostp; hostp = hostp->next) {
@@ -820,6 +819,8 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
       Curl_addrinfo *addr;
       char *entry_id;
       size_t entry_len;
+      char buffer[256];
+      char *address = &buffer[0];
 
       if(3 != sscanf(hostp->data, "%255[^:]:%d:%255s", hostname, &port,
                      address)) {
@@ -828,6 +829,16 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
         continue;
       }
 
+      /* allow IP(v6) address within [brackets] */
+      if(address[0] == '[') {
+        size_t alen = strlen(address);
+        if(address[alen-1] != ']')
+          /* it needs to also end with ] to be valid */
+          continue;
+        address[alen-1] = 0; /* zero terminate there */
+        address++; /* pass the open bracket */
+      }
+
       addr = Curl_str2addr(address, port);
       if(!addr) {
         infof(data, "Address in '%s' found illegal!\n", hostp->data);
diff --git a/lib/hostip4.c b/lib/hostip4.c
index 6a7c6e576..9d6f115ae 100644
--- a/lib/hostip4.c
+++ b/lib/hostip4.c
@@ -22,6 +22,11 @@
 
 #include "curl_setup.h"
 
+/***********************************************************************
+ * Only for plain IPv4 builds
+ **********************************************************************/
+#ifdef CURLRES_IPV4 /* plain IPv4 code coming up */
+
 #ifdef HAVE_NETINET_IN_H
 #include <netinet/in.h>
 #endif
@@ -53,10 +58,6 @@
 #include "curl_memory.h"
 #include "memdebug.h"
 
-/***********************************************************************
- * Only for plain IPv4 builds
- **********************************************************************/
-#ifdef CURLRES_IPV4 /* plain IPv4 code coming up */
 /*
  * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've
  * been set and returns TRUE if they are OK.
diff --git a/lib/hostip6.c b/lib/hostip6.c
index edeebec9e..7c9988f41 100644
--- a/lib/hostip6.c
+++ b/lib/hostip6.c
@@ -22,6 +22,11 @@
 
 #include "curl_setup.h"
 
+/***********************************************************************
+ * Only for IPv6-enabled builds
+ **********************************************************************/
+#ifdef CURLRES_IPV6
+
 #ifdef HAVE_NETINET_IN_H
 #include <netinet/in.h>
 #endif
@@ -54,11 +59,6 @@
 #include "curl_memory.h"
 #include "memdebug.h"
 
-/***********************************************************************
- * Only for IPv6-enabled builds
- **********************************************************************/
-#ifdef CURLRES_IPV6
-
 #if defined(CURLDEBUG) && defined(HAVE_GETNAMEINFO)
 /* These are strictly for memory tracing and are using the same style as the
  * family otherwise present in memdebug.c. I put these ones here since they
diff --git a/lib/hostsyn.c b/lib/hostsyn.c
index 1a95263c6..3de6746f5 100644
--- a/lib/hostsyn.c
+++ b/lib/hostsyn.c
@@ -22,6 +22,11 @@
 
 #include "curl_setup.h"
 
+/***********************************************************************
+ * Only for builds using synchronous name resolves
+ **********************************************************************/
+#ifdef CURLRES_SYNCH
+
 #ifdef HAVE_NETINET_IN_H
 #include <netinet/in.h>
 #endif
@@ -51,11 +56,6 @@
 /* The last #include file should be: */
 #include "memdebug.h"
 
-/***********************************************************************
- * Only for builds using synchronous name resolves
- **********************************************************************/
-#ifdef CURLRES_SYNCH
-
 /*
  * Function provided by the resolver backend to set DNS servers to use.
  */
diff --git a/lib/http.c b/lib/http.c
index 52f4c2b65..89bb498e7 100644
--- a/lib/http.c
+++ b/lib/http.c
@@ -73,7 +73,6 @@
 #include "http_proxy.h"
 #include "warnless.h"
 #include "non-ascii.h"
-#include "conncache.h"
 #include "pipeline.h"
 #include "http2.h"
 #include "connect.h"
@@ -3104,7 +3103,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy 
*data,
            !(conn->handler->protocol & CURLPROTO_RTSP) &&
            data->set.httpreq != HTTPREQ_HEAD) {
           /* On HTTP 1.1, when connection is not to get closed, but no
-             Content-Length nor Content-Encoding chunked have been
+             Content-Length nor Transfer-Encoding chunked have been
              received, according to RFC2616 section 4.4 point 5, we
              assume that the server will close the connection to
              signal the end of the document. */
@@ -3614,51 +3613,9 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy 
*data,
        * of chunks, and a chunk-data set to zero signals the
        * end-of-chunks. */
 
-      char *start;
-
-      /* Find the first non-space letter */
-      start = k->p + 18;
-
-      for(;;) {
-        /* skip whitespaces and commas */
-        while(*start && (ISSPACE(*start) || (*start == ',')))
-          start++;
-
-        if(checkprefix("chunked", start)) {
-          k->chunk = TRUE; /* chunks coming our way */
-
-          /* init our chunky engine */
-          Curl_httpchunk_init(conn);
-
-          start += 7;
-        }
-
-        if(k->auto_decoding)
-          /* TODO: we only support the first mentioned compression for now */
-          break;
-
-        if(checkprefix("identity", start)) {
-          k->auto_decoding = IDENTITY;
-          start += 8;
-        }
-        else if(checkprefix("deflate", start)) {
-          k->auto_decoding = DEFLATE;
-          start += 7;
-        }
-        else if(checkprefix("gzip", start)) {
-          k->auto_decoding = GZIP;
-          start += 4;
-        }
-        else if(checkprefix("x-gzip", start)) {
-          k->auto_decoding = GZIP;
-          start += 6;
-        }
-        else
-          /* unknown! */
-          break;
-
-      }
-
+      result = Curl_build_unencoding_stack(conn, k->p + 18, TRUE);
+      if(result)
+        return result;
     }
     else if(checkprefix("Content-Encoding:", k->p) &&
             data->set.str[STRING_ENCODING]) {
@@ -3669,21 +3626,9 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy 
*data,
        * 2616). zlib cannot handle compress.  However, errors are
        * handled further down when the response body is processed
        */
-      char *start;
-
-      /* Find the first non-space letter */
-      start = k->p + 17;
-      while(*start && ISSPACE(*start))
-        start++;
-
-      /* Record the content-encoding for later use */
-      if(checkprefix("identity", start))
-        k->auto_decoding = IDENTITY;
-      else if(checkprefix("deflate", start))
-        k->auto_decoding = DEFLATE;
-      else if(checkprefix("gzip", start)
-              || checkprefix("x-gzip", start))
-        k->auto_decoding = GZIP;
+      result = Curl_build_unencoding_stack(conn, k->p + 17, FALSE);
+      if(result)
+        return result;
     }
     else if(checkprefix("Content-Range:", k->p)) {
       /* Content-Range: bytes [num]-
diff --git a/lib/http2.c b/lib/http2.c
index 4c8d2e529..7ab626fb5 100644
--- a/lib/http2.c
+++ b/lib/http2.c
@@ -32,7 +32,6 @@
 #include "curl_base64.h"
 #include "strcase.h"
 #include "multiif.h"
-#include "conncache.h"
 #include "url.h"
 #include "connect.h"
 #include "strtoofft.h"
@@ -1184,14 +1183,17 @@ CURLcode Curl_http2_request_upgrade(Curl_send_buffer 
*req,
                                          httpc->local_settings_num);
   if(!binlen) {
     failf(conn->data, "nghttp2 unexpectedly failed on pack_settings_payload");
+    Curl_add_buffer_free(req);
     return CURLE_FAILED_INIT;
   }
   conn->proto.httpc.binlen = binlen;
 
   result = Curl_base64url_encode(conn->data, (const char *)binsettings, binlen,
                                  &base64, &blen);
-  if(result)
+  if(result) {
+    Curl_add_buffer_free(req);
     return result;
+  }
 
   result = Curl_add_bufferf(req,
                             "Connection: Upgrade, HTTP2-Settings\r\n"
@@ -1846,9 +1848,6 @@ static ssize_t http2_send(struct connectdata *conn, int 
sockindex,
     goto fail;
   }
 
-  hdbuf = end + 1;
-
-  end = line_end;
   nva[2].name = (unsigned char *)":scheme";
   nva[2].namelen = strlen((char *)nva[2].name);
   if(conn->handler->flags & PROTOPT_SSL)
diff --git a/lib/http_chunks.c b/lib/http_chunks.c
index 92d773112..161642969 100644
--- a/lib/http_chunks.c
+++ b/lib/http_chunks.c
@@ -187,49 +187,17 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
       piece = curlx_sotouz((ch->datasize >= length)?length:ch->datasize);
 
       /* Write the data portion available */
-#ifdef HAVE_LIBZ
-      switch(conn->data->set.http_ce_skip?
-             IDENTITY : data->req.auto_decoding) {
-      case IDENTITY:
-#endif
-        if(!k->ignorebody) {
-          if(!data->set.http_te_skip)
-            result = Curl_client_write(conn, CLIENTWRITE_BODY, datap,
-                                       piece);
-          else
-            result = CURLE_OK;
-        }
-#ifdef HAVE_LIBZ
-        break;
-
-      case DEFLATE:
-        /* update data->req.keep.str to point to the chunk data. */
-        data->req.str = datap;
-        result = Curl_unencode_deflate_write(conn, &data->req,
-                                             (ssize_t)piece);
-        break;
-
-      case GZIP:
-        /* update data->req.keep.str to point to the chunk data. */
-        data->req.str = datap;
-        result = Curl_unencode_gzip_write(conn, &data->req,
-                                          (ssize_t)piece);
-        break;
-
-      default:
-        failf(conn->data,
-              "Unrecognized content encoding type. "
-              "libcurl understands `identity', `deflate' and `gzip' "
-              "content encodings.");
-        return CHUNKE_BAD_ENCODING;
+      if(conn->data->set.http_ce_skip || !k->writer_stack) {
+        if(!k->ignorebody)
+          result = Curl_client_write(conn, CLIENTWRITE_BODY, datap, piece);
       }
-#endif
+      else
+        result = Curl_unencode_write(conn, k->writer_stack, datap, piece);
 
       if(result)
         return CHUNKE_WRITE_ERROR;
 
       *wrote += piece;
-
       ch->datasize -= piece; /* decrease amount left to expect */
       datap += piece;    /* move read pointer forward */
       length -= piece;   /* decrease space left in this round */
diff --git a/lib/http_proxy.c b/lib/http_proxy.c
index 26da33788..0fecfcf8a 100644
--- a/lib/http_proxy.c
+++ b/lib/http_proxy.c
@@ -188,7 +188,7 @@ static CURLcode CONNECT(struct connectdata *conn,
   CURLcode result;
   curl_socket_t tunnelsocket = conn->sock[sockindex];
   bool closeConnection = FALSE;
-  time_t check;
+  timediff_t check;
   struct http_connect_state *s = conn->connect_state;
 
 #define SELECT_OK      0
diff --git a/lib/imap.c b/lib/imap.c
index c059ff90c..5f3502606 100644
--- a/lib/imap.c
+++ b/lib/imap.c
@@ -275,15 +275,15 @@ static bool imap_endofresp(struct connectdata *conn, char 
*line, size_t len,
       case IMAP_LIST:
         if((!imap->custom && !imap_matchresp(line, len, "LIST")) ||
           (imap->custom && !imap_matchresp(line, len, imap->custom) &&
-           (strcmp(imap->custom, "STORE") ||
+           (!strcasecompare(imap->custom, "STORE") ||
             !imap_matchresp(line, len, "FETCH")) &&
-           strcmp(imap->custom, "SELECT") &&
-           strcmp(imap->custom, "EXAMINE") &&
-           strcmp(imap->custom, "SEARCH") &&
-           strcmp(imap->custom, "EXPUNGE") &&
-           strcmp(imap->custom, "LSUB") &&
-           strcmp(imap->custom, "UID") &&
-           strcmp(imap->custom, "NOOP")))
+           !strcasecompare(imap->custom, "SELECT") &&
+           !strcasecompare(imap->custom, "EXAMINE") &&
+           !strcasecompare(imap->custom, "SEARCH") &&
+           !strcasecompare(imap->custom, "EXPUNGE") &&
+           !strcasecompare(imap->custom, "LSUB") &&
+           !strcasecompare(imap->custom, "UID") &&
+           !strcasecompare(imap->custom, "NOOP")))
           return FALSE;
         break;
 
@@ -1053,7 +1053,7 @@ static CURLcode imap_state_select_resp(struct connectdata 
*conn, int imapcode,
   else if(imapcode == IMAP_RESP_OK) {
     /* Check if the UIDVALIDITY has been specified and matches */
     if(imap->uidvalidity && imapc->mailbox_uidvalidity &&
-       strcmp(imap->uidvalidity, imapc->mailbox_uidvalidity)) {
+       !strcasecompare(imap->uidvalidity, imapc->mailbox_uidvalidity)) {
       failf(conn->data, "Mailbox UIDVALIDITY has changed");
       result = CURLE_REMOTE_FILE_NOT_FOUND;
     }
@@ -1526,9 +1526,9 @@ static CURLcode imap_perform(struct connectdata *conn, 
bool *connected,
   /* Determine if the requested mailbox (with the same UIDVALIDITY if set)
      has already been selected on this connection */
   if(imap->mailbox && imapc->mailbox &&
-     !strcmp(imap->mailbox, imapc->mailbox) &&
+     strcasecompare(imap->mailbox, imapc->mailbox) &&
      (!imap->uidvalidity || !imapc->mailbox_uidvalidity ||
-      !strcmp(imap->uidvalidity, imapc->mailbox_uidvalidity)))
+      strcasecompare(imap->uidvalidity, imapc->mailbox_uidvalidity)))
     selected = TRUE;
 
   /* Start the first command in the DO phase */
diff --git a/lib/llist.c b/lib/llist.c
index 7fd6637d4..59174c86e 100644
--- a/lib/llist.c
+++ b/lib/llist.c
@@ -106,7 +106,11 @@ Curl_llist_remove(struct curl_llist *list, struct 
curl_llist_element *e,
       e->next->prev = NULL;
   }
   else {
-    e->prev->next = e->next;
+    if(!e->prev)
+      list->head = e->next;
+    else
+      e->prev->next = e->next;
+
     if(!e->next)
       list->tail = e->prev;
     else
diff --git a/lib/memdebug.c b/lib/memdebug.c
index c21fab59b..b033e3690 100644
--- a/lib/memdebug.c
+++ b/lib/memdebug.c
@@ -356,29 +356,32 @@ curl_socket_t curl_socket(int domain, int type, int 
protocol,
   return sockfd;
 }
 
-ssize_t curl_dosend(int sockfd, const void *buf, size_t len, int flags,
-                    int line, const char *source)
+SEND_TYPE_RETV curl_dosend(SEND_TYPE_ARG1 sockfd,
+                           SEND_QUAL_ARG2 SEND_TYPE_ARG2 buf,
+                           SEND_TYPE_ARG3 len, SEND_TYPE_ARG4 flags, int line,
+                           const char *source)
 {
-  ssize_t rc;
+  SEND_TYPE_RETV rc;
   if(countcheck("send", line, source))
     return -1;
   rc = send(sockfd, buf, len, flags);
   if(source)
-    curl_memlog("SEND %s:%d send(%zu) = %zd\n",
-                source, line, len, rc);
+    curl_memlog("SEND %s:%d send(%lu) = %ld\n",
+                source, line, (unsigned long)len, (long)rc);
   return rc;
 }
 
-ssize_t curl_dorecv(int sockfd, void *buf, size_t len, int flags,
-                    int line, const char *source)
+RECV_TYPE_RETV curl_dorecv(RECV_TYPE_ARG1 sockfd, RECV_TYPE_ARG2 buf,
+                           RECV_TYPE_ARG3 len, RECV_TYPE_ARG4 flags, int line,
+                           const char *source)
 {
-  ssize_t rc;
+  RECV_TYPE_RETV rc;
   if(countcheck("recv", line, source))
     return -1;
   rc = recv(sockfd, buf, len, flags);
   if(source)
-    curl_memlog("RECV %s:%d recv(%zu) = %zd\n",
-                source, line, len, rc);
+    curl_memlog("RECV %s:%d recv(%lu) = %ld\n",
+                source, line, (unsigned long)len, (long)rc);
   return rc;
 }
 
diff --git a/lib/memdebug.h b/lib/memdebug.h
index c6b9225f4..6fb8b6851 100644
--- a/lib/memdebug.h
+++ b/lib/memdebug.h
@@ -67,10 +67,15 @@ CURL_EXTERN int curl_socketpair(int domain, int type, int 
protocol,
 #endif
 
 /* send/receive sockets */
-CURL_EXTERN ssize_t curl_dosend(int sockfd, const void *buf, size_t len,
-                                int flags, int line, const char *source);
-CURL_EXTERN ssize_t curl_dorecv(int sockfd, void *buf, size_t len, int flags,
-                                int line, const char *source);
+CURL_EXTERN SEND_TYPE_RETV curl_dosend(SEND_TYPE_ARG1 sockfd,
+                                       SEND_QUAL_ARG2 SEND_TYPE_ARG2 buf,
+                                       SEND_TYPE_ARG3 len,
+                                       SEND_TYPE_ARG4 flags, int line,
+                                       const char *source);
+CURL_EXTERN RECV_TYPE_RETV curl_dorecv(RECV_TYPE_ARG1 sockfd,
+                                       RECV_TYPE_ARG2 buf, RECV_TYPE_ARG3 len,
+                                       RECV_TYPE_ARG4 flags, int line,
+                                       const char *source);
 
 /* FILE functions */
 CURL_EXTERN FILE *curl_fopen(const char *file, const char *mode, int line,
diff --git a/lib/mime.c b/lib/mime.c
index 8f67a1fca..53c67c47f 100644
--- a/lib/mime.c
+++ b/lib/mime.c
@@ -719,8 +719,6 @@ static size_t readback_bytes(mime_state *state,
 {
   size_t sz;
 
-  sz = numbytes - state->offset;
-
   if(numbytes > state->offset) {
     sz = numbytes - state->offset;
     bytes += state->offset;
diff --git a/lib/multi.c b/lib/multi.c
index 4b2628599..dbf8eae4e 100644
--- a/lib/multi.c
+++ b/lib/multi.c
@@ -59,7 +59,9 @@
 #define CURL_SOCKET_HASH_TABLE_SIZE 911
 #endif
 
+#ifndef CURL_CONNECTION_HASH_SIZE
 #define CURL_CONNECTION_HASH_SIZE 97
+#endif
 
 #define CURL_MULTI_HANDLE 0x000bab1e
 
@@ -324,14 +326,6 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* 
socket hash */
   Curl_llist_init(&multi->msglist, multi_freeamsg);
   Curl_llist_init(&multi->pending, multi_freeamsg);
 
-  /* allocate a new easy handle to use when closing cached connections */
-  multi->closure_handle = curl_easy_init();
-  if(!multi->closure_handle)
-    goto error;
-
-  multi->closure_handle->multi = multi;
-  multi->closure_handle->state.conn_cache = &multi->conn_cache;
-
   multi->max_pipeline_length = 5;
 
   /* -1 means it not set by user, use the default value */
@@ -343,8 +337,6 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* 
socket hash */
   Curl_hash_destroy(&multi->sockhash);
   Curl_hash_destroy(&multi->hostcache);
   Curl_conncache_destroy(&multi->conn_cache);
-  Curl_close(multi->closure_handle);
-  multi->closure_handle = NULL;
   Curl_llist_destroy(&multi->msglist, NULL);
   Curl_llist_destroy(&multi->pending, NULL);
 
@@ -405,8 +397,11 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
     data->dns.hostcachetype = HCACHE_MULTI;
   }
 
-  /* Point to the multi's connection cache */
-  data->state.conn_cache = &multi->conn_cache;
+  /* Point to the shared or multi handle connection cache */
+  if(data->share && (data->share->specifier & (1<< CURL_LOCK_DATA_CONNECT)))
+    data->state.conn_cache = &data->share->conn_cache;
+  else
+    data->state.conn_cache = &multi->conn_cache;
 
   /* This adds the new entry at the 'end' of the doubly-linked circular
      list of Curl_easy structs to try and maintain a FIFO queue so
@@ -460,8 +455,8 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
      state somewhat we clone the timeouts from each added handle so that the
      closure handle always has the same timeouts as the most recently added
      easy handle. */
-  multi->closure_handle->set.timeout = data->set.timeout;
-  multi->closure_handle->set.server_response_timeout =
+  data->state.conn_cache->closure_handle->set.timeout = data->set.timeout;
+  data->state.conn_cache->closure_handle->set.server_response_timeout =
     data->set.server_response_timeout;
 
   update_timer(multi);
@@ -502,7 +497,7 @@ ConnectionDone(struct Curl_easy *data, struct connectdata 
*conn)
      data->state.conn_cache->num_connections > maxconnects) {
     infof(data, "Connection cache is full, closing the oldest one.\n");
 
-    conn_candidate = Curl_oldest_idle_connection(data);
+    conn_candidate = Curl_conncache_oldest_idle(data);
 
     if(conn_candidate) {
       /* Set the connection's owner correctly */
@@ -1316,7 +1311,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
   struct SingleRequest *k;
   time_t timeout_ms;
   time_t recv_timeout_ms;
-  time_t send_timeout_ms;
+  timediff_t send_timeout_ms;
   int control;
 
   if(!GOOD_EASY_HANDLE(data))
@@ -1380,23 +1375,23 @@ static CURLMcode multi_runsingle(struct Curl_multi 
*multi,
         /* Handle timed out */
         if(data->mstate == CURLM_STATE_WAITRESOLVE)
           failf(data, "Resolving timed out after %ld milliseconds",
-                Curl_tvdiff(now, data->progress.t_startsingle));
+                Curl_timediff(now, data->progress.t_startsingle));
         else if(data->mstate == CURLM_STATE_WAITCONNECT)
           failf(data, "Connection timed out after %ld milliseconds",
-                Curl_tvdiff(now, data->progress.t_startsingle));
+                Curl_timediff(now, data->progress.t_startsingle));
         else {
           k = &data->req;
           if(k->size != -1) {
             failf(data, "Operation timed out after %ld milliseconds with %"
                   CURL_FORMAT_CURL_OFF_T " out of %"
                   CURL_FORMAT_CURL_OFF_T " bytes received",
-                  Curl_tvdiff(now, data->progress.t_startsingle),
+                  Curl_timediff(now, data->progress.t_startsingle),
                   k->bytecount, k->size);
           }
           else {
             failf(data, "Operation timed out after %ld milliseconds with %"
                   CURL_FORMAT_CURL_OFF_T " bytes received",
-                  Curl_tvdiff(now, data->progress.t_startsingle),
+                  Curl_timediff(now, data->progress.t_startsingle),
                   k->bytecount);
           }
         }
@@ -1661,7 +1656,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
         if(!result) {
           if(!dophase_done) {
             /* some steps needed for wildcard matching */
-            if(data->set.wildcardmatch) {
+            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 */
@@ -1813,7 +1808,13 @@ static CURLMcode multi_runsingle(struct Curl_multi 
*multi,
          (data->easy_conn->writesockfd != CURL_SOCKET_BAD))
         multistate(data, CURLM_STATE_WAITPERFORM);
       else
+      {
+        if(data->state.wildcardmatch &&
+           ((data->easy_conn->handler->flags & PROTOPT_WILDCARD) == 0)) {
+           data->wildcard.state = CURLWC_DONE;
+        }
         multistate(data, CURLM_STATE_DONE);
+      }
       rc = CURLM_CALL_MULTI_PERFORM;
       break;
 
@@ -2030,7 +2031,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
           data->easy_conn = NULL;
       }
 
-      if(data->set.wildcardmatch) {
+      if(data->state.wildcardmatch) {
         if(data->wildcard.state != CURLWC_DONE) {
           /* if a wildcard is set and we are not ending -> lets start again
              with CURLM_STATE_INIT */
@@ -2147,7 +2148,7 @@ CURLMcode curl_multi_perform(struct Curl_multi *multi, 
int *running_handles)
   struct Curl_easy *data;
   CURLMcode returncode = CURLM_OK;
   struct Curl_tree *t;
-  struct curltime now = Curl_tvnow();
+  struct curltime now = Curl_now();
 
   if(!GOOD_MULTI_HANDLE(multi))
     return CURLM_BAD_HANDLE;
@@ -2193,36 +2194,12 @@ CURLMcode curl_multi_perform(struct Curl_multi *multi, 
int *running_handles)
   return returncode;
 }
 
-static void close_all_connections(struct Curl_multi *multi)
-{
-  struct connectdata *conn;
-
-  conn = Curl_conncache_find_first_connection(&multi->conn_cache);
-  while(conn) {
-    SIGPIPE_VARIABLE(pipe_st);
-    conn->data = multi->closure_handle;
-
-    sigpipe_ignore(conn->data, &pipe_st);
-    conn->data->easy_conn = NULL; /* clear the easy handle's connection
-                                     pointer */
-    /* This will remove the connection from the cache */
-    connclose(conn, "kill all");
-    (void)Curl_disconnect(conn, FALSE);
-    sigpipe_restore(&pipe_st);
-
-    conn = Curl_conncache_find_first_connection(&multi->conn_cache);
-  }
-}
-
 CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
 {
   struct Curl_easy *data;
   struct Curl_easy *nextdata;
 
   if(GOOD_MULTI_HANDLE(multi)) {
-    bool restore_pipe = FALSE;
-    SIGPIPE_VARIABLE(pipe_st);
-
     multi->type = 0; /* not good anymore */
 
     /* Firsrt remove all remaining easy handles */
@@ -2247,18 +2224,7 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
     }
 
     /* Close all the connections in the connection cache */
-    close_all_connections(multi);
-
-    if(multi->closure_handle) {
-      sigpipe_ignore(multi->closure_handle, &pipe_st);
-      restore_pipe = TRUE;
-
-      multi->closure_handle->dns.hostcache = &multi->hostcache;
-      Curl_hostcache_clean(multi->closure_handle,
-                           multi->closure_handle->dns.hostcache);
-
-      Curl_close(multi->closure_handle);
-    }
+    Curl_conncache_close_all_connections(&multi->conn_cache);
 
     Curl_hash_destroy(&multi->sockhash);
     Curl_conncache_destroy(&multi->conn_cache);
@@ -2272,8 +2238,6 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
     Curl_pipeline_set_server_blacklist(NULL, &multi->pipelining_server_bl);
 
     free(multi);
-    if(restore_pipe)
-      sigpipe_restore(&pipe_st);
 
     return CURLM_OK;
   }
@@ -2514,9 +2478,9 @@ static CURLMcode add_next_timeout(struct curltime now,
      timeout in *tv */
   for(e = list->head; e;) {
     struct curl_llist_element *n = e->next;
-    time_t diff;
+    timediff_t diff;
     node = (struct time_node *)e->ptr;
-    diff = curlx_tvdiff(node->time, now);
+    diff = Curl_timediff(node->time, now);
     if(diff <= 0)
       /* remove outdated entry */
       Curl_llist_remove(list, e, NULL);
@@ -2553,7 +2517,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
   CURLMcode result = CURLM_OK;
   struct Curl_easy *data = NULL;
   struct Curl_tree *t;
-  struct curltime now = Curl_tvnow();
+  struct curltime now = Curl_now();
 
   if(checkall) {
     /* *perform() deals with running_handles on its own */
@@ -2629,8 +2593,8 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
 
       data = NULL; /* set data to NULL again to avoid calling
                       multi_runsingle() in case there's no need to */
-      now = Curl_tvnow(); /* get a newer time since the multi_runsingle() loop
-                             may have taken some time */
+      now = Curl_now(); /* get a newer time since the multi_runsingle() loop
+                           may have taken some time */
     }
   }
   else {
@@ -2783,15 +2747,15 @@ static CURLMcode multi_timeout(struct Curl_multi *multi,
 
   if(multi->timetree) {
     /* we have a tree of expire times */
-    struct curltime now = Curl_tvnow();
+    struct curltime now = Curl_now();
 
     /* splay the lowest to the bottom */
     multi->timetree = Curl_splay(tv_zero, multi->timetree);
 
     if(Curl_splaycomparekeys(multi->timetree->key, now) > 0) {
       /* some time left before expiration */
-      *timeout_ms = (long)curlx_tvdiff(multi->timetree->key, now);
-      if(!*timeout_ms)
+      timediff_t diff = Curl_timediff(multi->timetree->key, now);
+      if(diff <= 0)
         /*
          * Since we only provide millisecond resolution on the returned value
          * and the diff might be less than one millisecond here, we don't
@@ -2800,6 +2764,10 @@ static CURLMcode multi_timeout(struct Curl_multi *multi,
          * millisecond! instead we return 1 until the time is ripe.
          */
         *timeout_ms = 1;
+      else
+        /* this should be safe even on 64 bit archs, as we don't use that
+           overly long timeouts */
+        *timeout_ms = (long)diff;
     }
     else
       /* 0 means immediately */
@@ -2906,7 +2874,7 @@ multi_addtimeout(struct Curl_easy *data,
     /* find the correct spot in the list */
     for(e = timeoutlist->head; e; e = e->next) {
       struct time_node *check = (struct time_node *)e->ptr;
-      time_t diff = curlx_tvdiff(check->time, node->time);
+      timediff_t diff = Curl_timediff(check->time, node->time);
       if(diff > 0)
         break;
       prev = e;
@@ -2945,7 +2913,7 @@ void Curl_expire(struct Curl_easy *data, time_t milli, 
expire_id id)
 
   DEBUGASSERT(id < EXPIRE_LAST);
 
-  set = Curl_tvnow();
+  set = Curl_now();
   set.tv_sec += milli/1000;
   set.tv_usec += (unsigned int)(milli%1000)*1000;
 
@@ -2965,7 +2933,7 @@ void Curl_expire(struct Curl_easy *data, time_t milli, 
expire_id id)
     /* This means that the struct is added as a node in the splay tree.
        Compare if the new time is earlier, and only remove-old/add-new if it
        is. */
-    time_t diff = curlx_tvdiff(set, *nowp);
+    timediff_t diff = Curl_timediff(set, *nowp);
 
     if(diff > 0) {
       /* The current splay tree entry is sooner than this new expiry time.
diff --git a/lib/multihandle.h b/lib/multihandle.h
index 405753947..de9a7cf59 100644
--- a/lib/multihandle.h
+++ b/lib/multihandle.h
@@ -114,10 +114,6 @@ struct Curl_multi {
   /* Shared connection cache (bundles)*/
   struct conncache conn_cache;
 
-  /* This handle will be used for closing the cached connections in
-     curl_multi_cleanup() */
-  struct Curl_easy *closure_handle;
-
   long maxconnects; /* if >0, a fixed limit of the maximum number of entries
                        we're allowed to grow the connection cache to */
 
diff --git a/lib/pingpong.c b/lib/pingpong.c
index ef865ae54..438856a99 100644
--- a/lib/pingpong.c
+++ b/lib/pingpong.c
@@ -61,12 +61,12 @@ time_t Curl_pp_state_timeout(struct pingpong *pp)
   /* Without a requested timeout, we only wait 'response_time' seconds for the
      full response to arrive before we bail out */
   timeout_ms = response_time -
-    Curl_tvdiff(Curl_tvnow(), pp->response); /* spent time */
+    Curl_timediff(Curl_now(), pp->response); /* spent time */
 
   if(data->set.timeout) {
     /* if timeout is requested, find out how much remaining time we have */
     timeout2_ms = data->set.timeout - /* timeout time */
-      Curl_tvdiff(Curl_tvnow(), conn->now); /* spent time */
+      Curl_timediff(Curl_now(), conn->now); /* spent time */
 
     /* pick the lowest number */
     timeout_ms = CURLMIN(timeout_ms, timeout2_ms);
@@ -120,7 +120,7 @@ CURLcode Curl_pp_statemach(struct pingpong *pp, bool block)
     if(Curl_pgrsUpdate(conn))
       result = CURLE_ABORTED_BY_CALLBACK;
     else
-      result = Curl_speedcheck(data, Curl_tvnow());
+      result = Curl_speedcheck(data, Curl_now());
 
     if(result)
       return result;
@@ -143,7 +143,7 @@ void Curl_pp_init(struct pingpong *pp)
   pp->nread_resp = 0;
   pp->linestart_resp = conn->data->state.buffer;
   pp->pending_resp = TRUE;
-  pp->response = Curl_tvnow(); /* start response time-out now! */
+  pp->response = Curl_now(); /* start response time-out now! */
 }
 
 
@@ -235,7 +235,7 @@ CURLcode Curl_pp_vsendf(struct pingpong *pp,
     free(s);
     pp->sendthis = NULL;
     pp->sendleft = pp->sendsize = 0;
-    pp->response = Curl_tvnow();
+    pp->response = Curl_now();
   }
 
   return CURLE_OK;
@@ -499,7 +499,7 @@ CURLcode Curl_pp_flushsend(struct pingpong *pp)
     free(pp->sendthis);
     pp->sendthis = NULL;
     pp->sendleft = pp->sendsize = 0;
-    pp->response = Curl_tvnow();
+    pp->response = Curl_now();
   }
   return CURLE_OK;
 }
diff --git a/lib/pingpong.h b/lib/pingpong.h
index a2c8ff592..5ac8df876 100644
--- a/lib/pingpong.h
+++ b/lib/pingpong.h
@@ -58,8 +58,8 @@ struct pingpong {
                      server */
   size_t sendleft; /* number of bytes left to send from the sendthis buffer */
   size_t sendsize; /* total size of the sendthis buffer */
-  struct curltime response; /* set to Curl_tvnow() when a command has been sent
-                              off, used to time-out response reading */
+  struct curltime response; /* set to Curl_now() when a command has been sent
+                               off, used to time-out response reading */
   long response_time; /* When no timeout is given, this is the amount of
                          milliseconds we await for a server response. */
 
diff --git a/lib/progress.c b/lib/progress.c
index 00609d9ee..72c518a14 100644
--- a/lib/progress.c
+++ b/lib/progress.c
@@ -161,7 +161,7 @@ void Curl_pgrsResetTransferSizes(struct Curl_easy *data)
  */
 void Curl_pgrsTime(struct Curl_easy *data, timerid timer)
 {
-  struct curltime now = Curl_tvnow();
+  struct curltime now = Curl_now();
   time_t *delta = NULL;
 
   switch(timer) {
@@ -212,13 +212,13 @@ void Curl_pgrsTime(struct Curl_easy *data, timerid timer)
     /* this is the normal end-of-transfer thing */
     break;
   case TIMER_REDIRECT:
-    data->progress.t_redirect = Curl_tvdiff_us(now, data->progress.start);
+    data->progress.t_redirect = Curl_timediff_us(now, data->progress.start);
     break;
   }
   if(delta) {
-    time_t us = Curl_tvdiff_us(now, data->progress.t_startsingle);
-    if(!us)
-      us++; /* make sure at least one microsecond passed */
+    timediff_t us = Curl_timediff_us(now, data->progress.t_startsingle);
+    if(us < 1)
+      us = 1; /* make sure at least one microsecond passed */
     *delta += us;
   }
 }
@@ -226,7 +226,7 @@ void Curl_pgrsTime(struct Curl_easy *data, timerid timer)
 void Curl_pgrsStartNow(struct Curl_easy *data)
 {
   data->progress.speeder_c = 0; /* reset the progress meter display */
-  data->progress.start = Curl_tvnow();
+  data->progress.start = Curl_now();
   data->progress.is_t_startransfer_set = false;
   data->progress.ul_limit_start.tv_sec = 0;
   data->progress.ul_limit_start.tv_usec = 0;
@@ -274,7 +274,7 @@ long Curl_pgrsLimitWaitTime(curl_off_t cursize,
     return -1;
 
   minimum = (time_t) (CURL_OFF_T_C(1000) * size / limit);
-  actual = Curl_tvdiff(now, start);
+  actual = Curl_timediff(now, start);
 
   if(actual < minimum)
     /* this is a conversion on some systems (64bit time_t => 32bit long) */
@@ -285,7 +285,7 @@ long Curl_pgrsLimitWaitTime(curl_off_t cursize,
 
 void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size)
 {
-  struct curltime now = Curl_tvnow();
+  struct curltime now = Curl_now();
 
   data->progress.downloaded = size;
 
@@ -303,7 +303,7 @@ void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, 
curl_off_t size)
 
 void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size)
 {
-  struct curltime now = Curl_tvnow();
+  struct curltime now = Curl_now();
 
   data->progress.uploaded = size;
 
@@ -370,10 +370,10 @@ int Curl_pgrsUpdate(struct connectdata *conn)
   curl_off_t total_estimate;
   bool shownow = FALSE;
 
-  now = Curl_tvnow(); /* what time is it */
+  now = Curl_now(); /* what time is it */
 
   /* The time spent so far (from the start) */
-  data->progress.timespent = Curl_tvdiff_us(now, data->progress.start);
+  data->progress.timespent = Curl_timediff_us(now, data->progress.start);
   timespent = (curl_off_t)data->progress.timespent/1000000; /* seconds */
 
   /* The average download speed this far */
@@ -413,7 +413,7 @@ int Curl_pgrsUpdate(struct connectdata *conn)
 
     /* first of all, we don't do this if there's no counted seconds yet */
     if(countindex) {
-      time_t span_ms;
+      timediff_t span_ms;
 
       /* Get the index position to compare with the 'nowindex' position.
          Get the oldest entry possible. While we have less than CURR_TIME
@@ -422,8 +422,8 @@ int Curl_pgrsUpdate(struct connectdata *conn)
         data->progress.speeder_c%CURR_TIME:0;
 
       /* Figure out the exact time for the time span */
-      span_ms = Curl_tvdiff(now,
-                            data->progress.speeder_time[checkindex]);
+      span_ms = Curl_timediff(now,
+                              data->progress.speeder_time[checkindex]);
       if(0 == span_ms)
         span_ms = 1; /* at least one millisecond MUST have passed */
 
diff --git a/lib/rand.c b/lib/rand.c
index 69a8576dd..0d1e71200 100644
--- a/lib/rand.c
+++ b/lib/rand.c
@@ -86,7 +86,7 @@ static CURLcode randit(struct Curl_easy *data, unsigned int 
*rnd)
 #endif
 
   if(!seeded) {
-    struct curltime now = curlx_tvnow();
+    struct curltime now = Curl_now();
     infof(data, "WARNING: Using weak random seed\n");
     randseed += (unsigned int)now.tv_usec + (unsigned int)now.tv_sec;
     randseed = randseed * 1103515245 + 12345;
diff --git a/lib/select.c b/lib/select.c
index dd2a2c284..936cb5c6f 100644
--- a/lib/select.c
+++ b/lib/select.c
@@ -51,7 +51,7 @@
 #include "warnless.h"
 
 /* Convenience local macros */
-#define ELAPSED_MS()  (int)curlx_tvdiff(curlx_tvnow(), initial_tv)
+#define ELAPSED_MS() (int)Curl_timediff(Curl_now(), initial_tv)
 
 int Curl_ack_eintr = 0;
 #define ERROR_NOT_EINTR(error) (Curl_ack_eintr || error != EINTR)
@@ -96,7 +96,7 @@ int Curl_wait_ms(int timeout_ms)
   Sleep(timeout_ms);
 #else
   pending_ms = timeout_ms;
-  initial_tv = curlx_tvnow();
+  initial_tv = Curl_now();
   do {
 #if defined(HAVE_POLL_FINE)
     r = poll(NULL, 0, pending_ms);
@@ -177,14 +177,14 @@ int Curl_socket_check(curl_socket_t readfd0, /* two 
sockets to read from */
     return r;
   }
 
-  /* Avoid initial timestamp, avoid curlx_tvnow() call, when elapsed
+  /* Avoid initial timestamp, avoid Curl_now() call, when elapsed
      time in this function does not need to be measured. This happens
      when function is called with a zero timeout or a negative timeout
      value indicating a blocking call should be performed. */
 
   if(timeout_ms > 0) {
     pending_ms = (int)timeout_ms;
-    initial_tv = curlx_tvnow();
+    initial_tv = Curl_now();
   }
 
 #ifdef HAVE_POLL_FINE
@@ -418,14 +418,14 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, 
int timeout_ms)
     return r;
   }
 
-  /* Avoid initial timestamp, avoid curlx_tvnow() call, when elapsed
+  /* Avoid initial timestamp, avoid Curl_now() call, when elapsed
      time in this function does not need to be measured. This happens
      when function is called with a zero timeout or a negative timeout
      value indicating a blocking call should be performed. */
 
   if(timeout_ms > 0) {
     pending_ms = timeout_ms;
-    initial_tv = curlx_tvnow();
+    initial_tv = Curl_now();
   }
 
 #ifdef HAVE_POLL_FINE
diff --git a/lib/sendf.c b/lib/sendf.c
index 799f0ce13..939bb7dea 100644
--- a/lib/sendf.c
+++ b/lib/sendf.c
@@ -22,6 +22,10 @@
 
 #include "curl_setup.h"
 
+#ifdef HAVE_LINUX_TCP_H
+#include <linux/tcp.h>
+#endif
+
 #include <gnurl/curl.h>
 
 #include "urldata.h"
@@ -360,7 +364,7 @@ ssize_t Curl_send_plain(struct connectdata *conn, int num,
      available. */
   pre_receive_plain(conn, num);
 
-#ifdef MSG_FASTOPEN /* Linux */
+#if defined(MSG_FASTOPEN) && !defined(TCP_FASTOPEN_CONNECT) /* Linux */
   if(conn->bits.tcp_fastopen) {
     bytes_written = sendto(sockfd, mem, len, MSG_FASTOPEN,
                            conn->ip_addr->ai_addr, conn->ip_addr->ai_addrlen);
diff --git a/lib/setopt.c b/lib/setopt.c
new file mode 100644
index 000000000..70466bffb
--- /dev/null
+++ b/lib/setopt.c
@@ -0,0 +1,2554 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <address@hidden>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#ifdef HAVE_LINUX_TCP_H
+#include <linux/tcp.h>
+#endif
+
+#include "urldata.h"
+#include "url.h"
+#include "progress.h"
+#include "content_encoding.h"
+#include "strcase.h"
+#include "share.h"
+#include "vtls/vtls.h"
+#include "warnless.h"
+#include "sendf.h"
+#include "http2.h"
+#include "setopt.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+CURLcode Curl_setstropt(char **charp, const char *s)
+{
+  /* Release the previous storage at `charp' and replace by a dynamic storage
+     copy of `s'. Return CURLE_OK or CURLE_OUT_OF_MEMORY. */
+
+  Curl_safefree(*charp);
+
+  if(s) {
+    char *str = strdup(s);
+
+    if(!str)
+      return CURLE_OUT_OF_MEMORY;
+
+    *charp = str;
+  }
+
+  return CURLE_OK;
+}
+
+static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp)
+{
+  CURLcode result = CURLE_OK;
+  char *user = NULL;
+  char *passwd = NULL;
+
+  /* Parse the login details if specified. It not then we treat NULL as a hint
+     to clear the existing data */
+  if(option) {
+    result = Curl_parse_login_details(option, strlen(option),
+                                      (userp ? &user : NULL),
+                                      (passwdp ? &passwd : NULL),
+                                      NULL);
+  }
+
+  if(!result) {
+    /* Store the username part of option if required */
+    if(userp) {
+      if(!user && option && option[0] == ':') {
+        /* Allocate an empty string instead of returning NULL as user name */
+        user = strdup("");
+        if(!user)
+          result = CURLE_OUT_OF_MEMORY;
+      }
+
+      Curl_safefree(*userp);
+      *userp = user;
+    }
+
+    /* Store the password part of option if required */
+    if(passwdp) {
+      Curl_safefree(*passwdp);
+      *passwdp = passwd;
+    }
+  }
+
+  return result;
+}
+
+#define C_SSLVERSION_VALUE(x) (x & 0xffff)
+#define C_SSLVERSION_MAX_VALUE(x) (x & 0xffff0000)
+
+static CURLcode setopt(struct Curl_easy *data, CURLoption option,
+                       va_list param)
+{
+  char *argptr;
+  CURLcode result = CURLE_OK;
+  long arg;
+  curl_off_t bigsize;
+
+  switch(option) {
+  case CURLOPT_DNS_CACHE_TIMEOUT:
+    arg = va_arg(param, long);
+    if(arg < -1)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.dns_cache_timeout = arg;
+    break;
+  case CURLOPT_DNS_USE_GLOBAL_CACHE:
+    /* remember we want this enabled */
+    arg = va_arg(param, long);
+    data->set.global_dns_cache = (0 != arg) ? TRUE : FALSE;
+    break;
+  case CURLOPT_SSL_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_ORIG],
+                            va_arg(param, char *));
+    break;
+  case CURLOPT_PROXY_SSL_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 *));
+    break;
+
+  case CURLOPT_RANDOM_FILE:
+    /*
+     * This is the path name to a file that contains random data to seed
+     * the random SSL stuff with. The file is only used for reading.
+     */
+    result = Curl_setstropt(&data->set.str[STRING_SSL_RANDOM_FILE],
+                            va_arg(param, char *));
+    break;
+  case CURLOPT_EGDSOCKET:
+    /*
+     * The Entropy Gathering Daemon socket pathname
+     */
+    result = Curl_setstropt(&data->set.str[STRING_SSL_EGDSOCKET],
+                            va_arg(param, char *));
+    break;
+  case CURLOPT_MAXCONNECTS:
+    /*
+     * Set the absolute number of maximum simultaneous alive connection that
+     * libcurl is allowed to have.
+     */
+    arg = va_arg(param, long);
+    if(arg < 0)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.maxconnects = arg;
+    break;
+  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)) ? TRUE : FALSE;
+    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)) ? TRUE : FALSE;
+    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)) ? TRUE : FALSE;
+    break;
+  case CURLOPT_HEADER:
+    /*
+     * Set to include the header in the general data output stream.
+     */
+    data->set.include_header = (0 != va_arg(param, long)) ? TRUE : FALSE;
+    break;
+  case CURLOPT_NOPROGRESS:
+    /*
+     * Shut off the internal supported progress meter
+     */
+    data->set.hide_progress = (0 != va_arg(param, long)) ? TRUE : FALSE;
+    if(data->set.hide_progress)
+      data->progress.flags |= PGRS_HIDE;
+    else
+      data->progress.flags &= ~PGRS_HIDE;
+    break;
+  case CURLOPT_NOBODY:
+    /*
+     * Do not include the body part in the output data stream.
+     */
+    data->set.opt_no_body = (0 != va_arg(param, long)) ? TRUE : FALSE;
+    break;
+  case CURLOPT_FAILONERROR:
+    /*
+     * Don't output the >=400 error code HTML-page, but instead only
+     * return error.
+     */
+    data->set.http_fail_on_error = (0 != va_arg(param, long)) ? TRUE : FALSE;
+    break;
+  case CURLOPT_KEEP_SENDING_ON_ERROR:
+    data->set.http_keep_sending_on_error = (0 != va_arg(param, long)) ?
+      TRUE : FALSE;
+    break;
+  case CURLOPT_UPLOAD:
+  case CURLOPT_PUT:
+    /*
+     * We want to sent data to the remote host. If this is HTTP, that equals
+     * using the PUT request.
+     */
+    data->set.upload = (0 != va_arg(param, long)) ? TRUE : FALSE;
+    if(data->set.upload) {
+      /* If this is HTTP, PUT is what's needed to "upload" */
+      data->set.httpreq = HTTPREQ_PUT;
+      data->set.opt_no_body = FALSE; /* this is implied */
+    }
+    else
+      /* In HTTP, the opposite of upload is GET (unless NOBODY is true as
+         then this can be changed to HEAD later on) */
+      data->set.httpreq = 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)) ? TRUE : FALSE;
+    break;
+  case CURLOPT_FTP_CREATE_MISSING_DIRS:
+    /*
+     * An FTP option that modifies an upload to create missing directories on
+     * the server.
+     */
+    switch(va_arg(param, long)) {
+    case 0:
+      data->set.ftp_create_missing_dirs = 0;
+      break;
+    case 1:
+      data->set.ftp_create_missing_dirs = 1;
+      break;
+    case 2:
+      data->set.ftp_create_missing_dirs = 2;
+      break;
+    default:
+      /* reserve other values for future use */
+      result = CURLE_UNKNOWN_OPTION;
+      break;
+    }
+    break;
+  case CURLOPT_SERVER_RESPONSE_TIMEOUT:
+    /*
+     * Option that specifies how quickly an 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 = arg * 1000;
+    else
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    break;
+  case CURLOPT_TFTP_NO_OPTIONS:
+    /*
+     * Option that prevents libcurl from sending TFTP option requests to the
+     * server.
+     */
+    data->set.tftp_no_options = va_arg(param, long) != 0;
+    break;
+  case CURLOPT_TFTP_BLKSIZE:
+    /*
+     * TFTP option that specifies the block size to use for data transmission.
+     */
+    arg = va_arg(param, long);
+    if(arg < 0)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.tftp_blksize = arg;
+    break;
+  case CURLOPT_DIRLISTONLY:
+    /*
+     * An option that changes the command to one that asks for a list
+     * only, no file info details.
+     */
+    data->set.ftp_list_only = (0 != va_arg(param, long)) ? TRUE : FALSE;
+    break;
+  case CURLOPT_APPEND:
+    /*
+     * We want to upload and append to an existing file.
+     */
+    data->set.ftp_append = (0 != va_arg(param, long)) ? TRUE : FALSE;
+    break;
+  case CURLOPT_FTP_FILEMETHOD:
+    /*
+     * How do access files over FTP.
+     */
+    arg = va_arg(param, long);
+    if((arg < CURLFTPMETHOD_DEFAULT) || (arg > CURLFTPMETHOD_SINGLECWD))
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.ftp_filemethod = (curl_ftpfile)arg;
+    break;
+  case CURLOPT_NETRC:
+    /*
+     * Parse the $HOME/.netrc file
+     */
+    arg = va_arg(param, long);
+    if((arg < CURL_NETRC_IGNORED) || (arg > CURL_NETRC_REQUIRED))
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.use_netrc = (enum CURL_NETRC_OPTION)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;
+  case CURLOPT_TRANSFERTEXT:
+    /*
+     * This option was previously named 'FTPASCII'. Renamed to work with
+     * more protocols than merely FTP.
+     *
+     * Transfer using ASCII (instead of BINARY).
+     */
+    data->set.prefer_ascii = (0 != va_arg(param, long)) ? TRUE : FALSE;
+    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_LASTMOD))
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.timecondition = (curl_TimeCond)arg;
+    break;
+  case CURLOPT_TIMEVALUE:
+    /*
+     * 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);
+    break;
+  case CURLOPT_SSLVERSION:
+    /*
+     * Set explicit SSL version to try to connect with, as some SSL
+     * implementations are lame.
+     */
+#ifdef USE_SSL
+    arg = va_arg(param, long);
+    if((arg < CURL_SSLVERSION_DEFAULT) || (arg > CURL_SSLVERSION_TLSv1_3))
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.ssl.primary.version = C_SSLVERSION_VALUE(arg);
+    data->set.ssl.primary.version_max = C_SSLVERSION_MAX_VALUE(arg);
+#else
+    result = CURLE_UNKNOWN_OPTION;
+#endif
+    break;
+  case CURLOPT_PROXY_SSLVERSION:
+    /*
+     * Set explicit SSL version to try to connect with for proxy, as some SSL
+     * implementations are lame.
+     */
+#ifdef USE_SSL
+    arg = va_arg(param, long);
+    if((arg < CURL_SSLVERSION_DEFAULT) || (arg > CURL_SSLVERSION_TLSv1_3))
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.proxy_ssl.primary.version = C_SSLVERSION_VALUE(arg);
+    data->set.proxy_ssl.primary.version_max = C_SSLVERSION_MAX_VALUE(arg);
+#else
+    result = CURLE_UNKNOWN_OPTION;
+#endif
+    break;
+
+#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)) ? TRUE : FALSE;
+    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 don't send an Accept-Encoding header
+     * and ignore an received Content-Encoding header.
+     *
+     */
+    argptr = va_arg(param, char *);
+    if(argptr && !*argptr) {
+      argptr = Curl_all_content_encodings();
+      if(!argptr)
+        result = CURLE_OUT_OF_MEMORY;
+      else {
+        result = Curl_setstropt(&data->set.str[STRING_ENCODING], argptr);
+        free(argptr);
+      }
+    }
+    else
+      result = Curl_setstropt(&data->set.str[STRING_ENCODING], argptr);
+    break;
+
+  case CURLOPT_TRANSFER_ENCODING:
+    data->set.http_transfer_encoding = (0 != va_arg(param, long)) ?
+      TRUE : FALSE;
+    break;
+
+  case CURLOPT_FOLLOWLOCATION:
+    /*
+     * Follow Location: header hints on a HTTP-server.
+     */
+    data->set.http_follow_location = (0 != va_arg(param, long)) ? TRUE : FALSE;
+    break;
+
+  case CURLOPT_UNRESTRICTED_AUTH:
+    /*
+     * Send authentication (user+password) when following locations, even when
+     * hostname changed.
+     */
+    data->set.http_disable_hostname_check_before_authentication =
+      (0 != va_arg(param, long)) ? TRUE : FALSE;
+    break;
+
+  case CURLOPT_MAXREDIRS:
+    /*
+     * 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;
+    break;
+
+  case CURLOPT_POSTREDIR:
+    /*
+     * Set the behaviour of POST when redirecting
+     * CURL_REDIR_GET_ALL - POST is changed to GET after 301 and 302
+     * CURL_REDIR_POST_301 - POST is kept as POST after 301
+     * CURL_REDIR_POST_302 - POST is kept as POST after 302
+     * CURL_REDIR_POST_303 - POST is kept as POST after 303
+     * 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 */
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.keep_post = arg & CURL_REDIR_POST_ALL;
+    break;
+
+  case CURLOPT_POST:
+    /* Does this option serve a purpose anymore? Yes it does, when
+       CURLOPT_POSTFIELDS isn't used and the POST data is read off the
+       callback! */
+    if(va_arg(param, long)) {
+      data->set.httpreq = HTTPREQ_POST;
+      data->set.opt_no_body = FALSE; /* this is implied */
+    }
+    else
+      data->set.httpreq = HTTPREQ_GET;
+    break;
+
+  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 {
+        char *p;
+
+        (void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
+
+        /* Allocate even when size == 0. This satisfies the need of possible
+           later address compare to detect the COPYPOSTFIELDS mode, and
+           to mark that postfields is used rather than read function or
+           form data.
+        */
+        p = malloc((size_t)(data->set.postfieldsize?
+                            data->set.postfieldsize:1));
+
+        if(!p)
+          result = CURLE_OUT_OF_MEMORY;
+        else {
+          if(data->set.postfieldsize)
+            memcpy(p, argptr, (size_t)data->set.postfieldsize);
+
+          data->set.str[STRING_COPYPOSTFIELDS] = p;
+        }
+      }
+    }
+
+    data->set.postfields = data->set.str[STRING_COPYPOSTFIELDS];
+    data->set.httpreq = 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. */
+    (void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
+    data->set.httpreq = 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)
+      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. */
+      (void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
+      data->set.postfields = NULL;
+    }
+
+    data->set.postfieldsize = bigsize;
+    break;
+
+  case CURLOPT_POSTFIELDSIZE_LARGE:
+    /*
+     * The size of the POSTFIELD data to prevent libcurl to do strlen() to
+     * figure it out. Enables binary posts.
+     */
+    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. */
+      (void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
+      data->set.postfields = NULL;
+    }
+
+    data->set.postfieldsize = bigsize;
+    break;
+
+  case CURLOPT_HTTPPOST:
+    /*
+     * Set to make us do HTTP POST
+     */
+    data->set.httppost = va_arg(param, struct curl_httppost *);
+    data->set.httpreq = HTTPREQ_POST_FORM;
+    data->set.opt_no_body = FALSE; /* this is implied */
+    break;
+#endif   /* CURL_DISABLE_HTTP */
+
+  case CURLOPT_MIMEPOST:
+    /*
+     * Set to make us do MIME/form POST
+     */
+    result = Curl_mime_set_subparts(&data->set.mimepost,
+                                    va_arg(param, curl_mime *), FALSE);
+    if(!result) {
+      data->set.httpreq = HTTPREQ_POST_MIME;
+      data->set.opt_no_body = FALSE; /* this is implied */
+    }
+    break;
+
+  case CURLOPT_REFERER:
+    /*
+     * String to set in the HTTP Referer: field.
+     */
+    if(data->change.referer_alloc) {
+      Curl_safefree(data->change.referer);
+      data->change.referer_alloc = FALSE;
+    }
+    result = Curl_setstropt(&data->set.str[STRING_SET_REFERER],
+                            va_arg(param, char *));
+    data->change.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;
+
+  case CURLOPT_HTTPHEADER:
+    /*
+     * Set a list with HTTP headers to use (or replace internals with)
+     */
+    data->set.headers = va_arg(param, struct curl_slist *);
+    break;
+
+#ifndef CURL_DISABLE_HTTP
+  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;
+
+  case CURLOPT_HEADEROPT:
+    /*
+     * Set header option.
+     */
+    arg = va_arg(param, long);
+    data->set.sep_headers = (arg & CURLHEADER_SEPARATE)? TRUE: FALSE;
+    break;
+
+  case CURLOPT_HTTP200ALIASES:
+    /*
+     * Set a list of aliases for HTTP 200 in response header
+     */
+    data->set.http200aliases = va_arg(param, struct curl_slist *);
+    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;
+      /* append the cookie file name to the list of file names, and deal with
+         them later */
+      cl = curl_slist_append(data->change.cookielist, argptr);
+      if(!cl) {
+        curl_slist_free_all(data->change.cookielist);
+        data->change.cookielist = NULL;
+        return CURLE_OUT_OF_MEMORY;
+      }
+      data->change.cookielist = cl; /* store the list for later use */
+    }
+    break;
+
+  case CURLOPT_COOKIEJAR:
+    /*
+     * Set cookie file name to dump all cookies to when we're done.
+     */
+  {
+    struct CookieInfo *newcookies;
+    result = Curl_setstropt(&data->set.str[STRING_COOKIEJAR],
+                            va_arg(param, char *));
+
+    /*
+     * Activate the cookie parser. This may or may not already
+     * have been made.
+     */
+    newcookies = Curl_cookie_init(data, NULL, data->cookies,
+                                  data->set.cookiesession);
+    if(!newcookies)
+      result = CURLE_OUT_OF_MEMORY;
+    data->cookies = newcookies;
+  }
+  break;
+
+  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.
+     *
+     * In the original Netscape cookie spec, "session cookies" are cookies
+     * with no expire date set. RFC2109 describes the same action if no
+     * 'Max-Age' is set and RFC2965 includes the RFC2109 description and adds
+     * a 'Discard' action that can enforce the discard even for cookies that
+     * have a Max-Age.
+     *
+     * We run mostly with the original cookie spec, as hardly anyone implements
+     * anything else.
+     */
+    data->set.cookiesession = (0 != va_arg(param, long)) ? TRUE : FALSE;
+    break;
+
+  case CURLOPT_COOKIELIST:
+    argptr = va_arg(param, char *);
+
+    if(argptr == NULL)
+      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, 0);
+    }
+    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);
+
+      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, argptr + 11, NULL, NULL);
+
+        else
+          /* Netscape format line */
+          Curl_cookie_add(data, data->cookies, FALSE, argptr, NULL, NULL);
+
+        Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+        free(argptr);
+      }
+    }
+
+    break;
+#endif /* !CURL_DISABLE_COOKIES */
+
+  case CURLOPT_HTTPGET:
+    /*
+     * Set to force us do HTTP GET
+     */
+    if(va_arg(param, long)) {
+      data->set.httpreq = HTTPREQ_GET;
+      data->set.upload = FALSE; /* switch off upload */
+      data->set.opt_no_body = FALSE; /* this is implied */
+    }
+    break;
+
+  case CURLOPT_HTTP_VERSION:
+    /*
+     * 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);
+    if(arg < CURL_HTTP_VERSION_NONE)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+#ifndef USE_NGHTTP2
+    if(arg >= CURL_HTTP_VERSION_2)
+      return CURLE_UNSUPPORTED_PROTOCOL;
+#else
+    if(arg > CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE)
+      return CURLE_UNSUPPORTED_PROTOCOL;
+#endif
+    data->set.httpversion = arg;
+    break;
+
+  case CURLOPT_EXPECT_100_TIMEOUT_MS:
+    /*
+     * Time to wait for a response to a 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;
+
+#endif   /* CURL_DISABLE_HTTP */
+
+  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) ? TRUE : FALSE;
+
+    if(auth & CURLAUTH_DIGEST_IE) {
+      auth |= CURLAUTH_DIGEST; /* set standard digest bit */
+      auth &= ~CURLAUTH_DIGEST_IE; /* unset ie digest bit */
+    }
+
+    /* switch off bits we can't support */
+#ifndef USE_NTLM
+    auth &= ~CURLAUTH_NTLM;    /* no NTLM support */
+    auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */
+#elif !defined(NTLM_WB_ENABLED)
+    auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */
+#endif
+#ifndef USE_SPNEGO
+    auth &= ~CURLAUTH_NEGOTIATE; /* no Negotiate (SPNEGO) auth without
+                                    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 don't set
+       data->set.httpreq = HTTPREQ_CUSTOM;
+       here, we continue as if we were using the already set type
+       and this just changes the actual request keyword */
+    break;
+
+#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)) ?
+      TRUE : FALSE;
+    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 = 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) ? TRUE : FALSE;
+
+    if(auth & CURLAUTH_DIGEST_IE) {
+      auth |= CURLAUTH_DIGEST; /* set standard digest bit */
+      auth &= ~CURLAUTH_DIGEST_IE; /* unset ie digest bit */
+    }
+    /* switch off bits we can't support */
+#ifndef USE_NTLM
+    auth &= ~CURLAUTH_NTLM;    /* no NTLM support */
+    auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */
+#elif !defined(NTLM_WB_ENABLED)
+    auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */
+#endif
+#ifndef USE_SPNEGO
+    auth &= ~CURLAUTH_NEGOTIATE; /* no Negotiate (SPNEGO) auth without
+                                    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 don't 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 don't want
+     * to use the socks proxy.
+     */
+    result = Curl_setstropt(&data->set.str[STRING_PRE_PROXY],
+                            va_arg(param, char *));
+    break;
+
+  case CURLOPT_PROXYTYPE:
+    /*
+     * Set proxy type. HTTP/HTTP_1_0/SOCKS4/SOCKS4a/SOCKS5/SOCKS5_HOSTNAME
+     */
+    arg = va_arg(param, long);
+    if((arg < CURLPROXY_HTTP) || (arg > CURLPROXY_SOCKS5_HOSTNAME))
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.proxytype = (curl_proxytype)arg;
+    break;
+
+  case CURLOPT_PROXY_TRANSFER_MODE:
+    /*
+     * 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:
+      /* reserve other values for future use */
+      result = CURLE_UNKNOWN_OPTION;
+      break;
+    }
+    break;
+#endif   /* CURL_DISABLE_PROXY */
+
+  case CURLOPT_SOCKS5_AUTH:
+    data->set.socks5auth = va_arg(param, unsigned long);
+    if(data->set.socks5auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI))
+      result = CURLE_NOT_BUILT_IN;
+    break;
+#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)) ? TRUE : FALSE;
+    break;
+
+  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
+
+#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) ||     \
+  defined(USE_SPNEGO)
+  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;
+
+#endif
+
+  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;
+  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]) ? TRUE : FALSE;
+    break;
+
+  case CURLOPT_FTP_USE_EPRT:
+    data->set.ftp_use_eprt = (0 != va_arg(param, long)) ? TRUE : FALSE;
+    break;
+
+  case CURLOPT_FTP_USE_EPSV:
+    data->set.ftp_use_epsv = (0 != va_arg(param, long)) ? TRUE : FALSE;
+    break;
+
+  case CURLOPT_FTP_USE_PRET:
+    data->set.ftp_use_pret = (0 != va_arg(param, long)) ? TRUE : FALSE;
+    break;
+
+  case CURLOPT_FTP_SSL_CCC:
+    arg = va_arg(param, long);
+    if((arg < CURLFTPSSL_CCC_NONE) || (arg > CURLFTPSSL_CCC_ACTIVE))
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.ftp_ccc = (curl_ftpccc)arg;
+    break;
+
+  case CURLOPT_FTP_SKIP_PASV_IP:
+    /*
+     * 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)) ? TRUE : FALSE;
+    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 = va_arg(param, void *);
+    break;
+  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_URL:
+    /*
+     * The URL to fetch.
+     */
+    if(data->change.url_alloc) {
+      /* the already set URL is allocated, free it first! */
+      Curl_safefree(data->change.url);
+      data->change.url_alloc = FALSE;
+    }
+    result = Curl_setstropt(&data->set.str[STRING_SET_URL],
+                            va_arg(param, char *));
+    data->change.url = data->set.str[STRING_SET_URL];
+    break;
+  case CURLOPT_PORT:
+    /*
+     * The port number to use when getting the URL
+     */
+    arg = va_arg(param, long);
+    if((arg < 0) || (arg > 65535))
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.use_port = arg;
+    break;
+  case CURLOPT_TIMEOUT:
+    /*
+     * 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 = arg * 1000;
+    else
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    break;
+
+  case CURLOPT_TIMEOUT_MS:
+    arg = va_arg(param, long);
+    if(arg < 0)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.timeout = arg;
+    break;
+
+  case CURLOPT_CONNECTTIMEOUT:
+    /*
+     * 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 = arg * 1000;
+    else
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    break;
+
+  case CURLOPT_CONNECTTIMEOUT_MS:
+    arg = va_arg(param, long);
+    if(arg < 0)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.connecttimeout = arg;
+    break;
+
+  case CURLOPT_ACCEPTTIMEOUT_MS:
+    /*
+     * The maximum time you allow curl to wait for server connect
+     */
+    arg = va_arg(param, long);
+    if(arg < 0)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.accepttimeout = arg;
+    break;
+
+  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 user name 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_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;
+  case CURLOPT_RESOLVE:
+    /*
+     * List of NAME:[address] names to populate the DNS cache with
+     * Prefix the NAME with dash (-) to _remove_ the name from the cache.
+     *
+     * Names added with this API will remain in the cache until explicitly
+     * removed or the handle is cleaned up.
+     *
+     * This API can remove any name from the DNS cache, but only entries
+     * that aren't actually in use right now will be pruned immediately.
+     */
+    data->set.resolve = va_arg(param, struct curl_slist *);
+    data->change.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
+     */
+    result = setstropt_userpwd(va_arg(param, char *),
+                               &data->set.str[STRING_PROXYUSERNAME],
+                               &data->set.str[STRING_PROXYPASSWORD]);
+    break;
+  case CURLOPT_PROXYUSERNAME:
+    /*
+     * authentication user name 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'll 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) {
+      data->set.is_fwrite_set = 0;
+      /* When set to NULL, reset to our internal default function */
+      data->set.fwrite_func = (curl_write_callback)fwrite;
+    }
+    else
+      data->set.is_fwrite_set = 1;
+    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_CONV_FROM_NETWORK_FUNCTION:
+    /*
+     * "Convert from network encoding" callback
+     */
+    data->set.convfromnetwork = va_arg(param, curl_conv_callback);
+    break;
+  case CURLOPT_CONV_TO_NETWORK_FUNCTION:
+    /*
+     * "Convert to network encoding" callback
+     */
+    data->set.convtonetwork = va_arg(param, curl_conv_callback);
+    break;
+  case CURLOPT_CONV_FROM_UTF8_FUNCTION:
+    /*
+     * "Convert from UTF-8 encoding" callback
+     */
+    data->set.convfromutf8 = va_arg(param, curl_conv_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_IOCTLDATA:
+    /*
+     * I/O control data pointer. Might be NULL.
+     */
+    data->set.ioctl_client = va_arg(param, void *);
+    break;
+  case CURLOPT_SSLCERT:
+    /*
+     * String that holds file name of the SSL certificate to use
+     */
+    result = Curl_setstropt(&data->set.str[STRING_CERT_ORIG],
+                            va_arg(param, char *));
+    break;
+  case CURLOPT_PROXY_SSLCERT:
+    /*
+     * String that holds file name of the SSL certificate to use for proxy
+     */
+    result = Curl_setstropt(&data->set.str[STRING_CERT_PROXY],
+                            va_arg(param, char *));
+    break;
+  case CURLOPT_SSLCERTTYPE:
+    /*
+     * String that holds file type of the SSL certificate to use
+     */
+    result = Curl_setstropt(&data->set.str[STRING_CERT_TYPE_ORIG],
+                            va_arg(param, char *));
+    break;
+  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;
+  case CURLOPT_SSLKEY:
+    /*
+     * String that holds file name of the SSL key to use
+     */
+    result = Curl_setstropt(&data->set.str[STRING_KEY_ORIG],
+                            va_arg(param, char *));
+    break;
+  case CURLOPT_PROXY_SSLKEY:
+    /*
+     * String that holds file name of the SSL key to use for proxy
+     */
+    result = Curl_setstropt(&data->set.str[STRING_KEY_PROXY],
+                            va_arg(param, char *));
+    break;
+  case CURLOPT_SSLKEYTYPE:
+    /*
+     * String that holds file type of the SSL key to use
+     */
+    result = Curl_setstropt(&data->set.str[STRING_KEY_TYPE_ORIG],
+                            va_arg(param, char *));
+    break;
+  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;
+  case CURLOPT_KEYPASSWD:
+    /*
+     * String that holds the SSL or SSH private key password.
+     */
+    result = Curl_setstropt(&data->set.str[STRING_KEY_PASSWD_ORIG],
+                            va_arg(param, char *));
+    break;
+  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;
+  case CURLOPT_SSLENGINE:
+    /*
+     * String that holds the SSL crypto engine.
+     */
+    argptr = va_arg(param, char *);
+    if(argptr && argptr[0])
+      result = Curl_ssl_set_engine(data, argptr);
+    break;
+
+  case CURLOPT_SSLENGINE_DEFAULT:
+    /*
+     * flag to set engine as default.
+     */
+    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)) ? TRUE : FALSE;
+    break;
+
+  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 = Curl_setstropt(&data->set.str[STRING_DEVICE],
+                            va_arg(param, char *));
+    break;
+  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);
+    break;
+  case CURLOPT_LOCALPORTRANGE:
+    /*
+     * 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_sltosi(arg);
+    break;
+  case CURLOPT_KRBLEVEL:
+    /*
+     * A string that defines the kerberos security level.
+     */
+    result = Curl_setstropt(&data->set.str[STRING_KRB_LEVEL],
+                            va_arg(param, char *));
+    data->set.krb = (data->set.str[STRING_KRB_LEVEL]) ? TRUE : FALSE;
+    break;
+  case CURLOPT_GSSAPI_DELEGATION:
+    /*
+     * GSS-API credential delegation bitmask
+     */
+    arg = va_arg(param, long);
+    if(arg < CURLGSSAPI_DELEGATION_NONE)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.gssapi_delegation = arg;
+    break;
+  case CURLOPT_SSL_VERIFYPEER:
+    /*
+     * Enable peer SSL verifying.
+     */
+    data->set.ssl.primary.verifypeer = (0 != va_arg(param, long)) ?
+      TRUE : FALSE;
+
+    /* Update the current connection ssl_config. */
+    if(data->easy_conn) {
+      data->easy_conn->ssl_config.verifypeer =
+        data->set.ssl.primary.verifypeer;
+    }
+    break;
+  case CURLOPT_PROXY_SSL_VERIFYPEER:
+    /*
+     * Enable peer SSL verifying for proxy.
+     */
+    data->set.proxy_ssl.primary.verifypeer =
+      (0 != va_arg(param, long))?TRUE:FALSE;
+
+    /* Update the current connection proxy_ssl_config. */
+    if(data->easy_conn) {
+      data->easy_conn->proxy_ssl_config.verifypeer =
+        data->set.proxy_ssl.primary.verifypeer;
+    }
+    break;
+  case CURLOPT_SSL_VERIFYHOST:
+    /*
+     * Enable verification of the host name 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 wasn't and misused it. We thus ban
+       1 as a sensible input and we warn about its use. Then we only have the
+       2 action internally stored as TRUE. */
+
+    if(1 == arg) {
+      failf(data, "CURLOPT_SSL_VERIFYHOST no longer supports 1 as value!");
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    }
+
+    data->set.ssl.primary.verifyhost = (0 != arg) ? TRUE : FALSE;
+
+    /* Update the current connection ssl_config. */
+    if(data->easy_conn) {
+      data->easy_conn->ssl_config.verifyhost =
+        data->set.ssl.primary.verifyhost;
+    }
+    break;
+  case CURLOPT_PROXY_SSL_VERIFYHOST:
+    /*
+     * Enable verification of the host name in the peer certificate for proxy
+     */
+    arg = va_arg(param, long);
+
+    /* Obviously people are not reading documentation and too many thought
+       this argument took a boolean when it wasn't and misused it. We thus ban
+       1 as a sensible input and we warn about its use. Then we only have the
+       2 action internally stored as TRUE. */
+
+    if(1 == arg) {
+      failf(data, "CURLOPT_SSL_VERIFYHOST no longer supports 1 as value!");
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    }
+
+    data->set.proxy_ssl.primary.verifyhost = (0 != arg)?TRUE:FALSE;
+
+    /* Update the current connection proxy_ssl_config. */
+    if(data->easy_conn) {
+      data->easy_conn->proxy_ssl_config.verifyhost =
+        data->set.proxy_ssl.primary.verifyhost;
+    }
+    break;
+  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)) ?
+      TRUE : FALSE;
+
+    /* Update the current connection ssl_config. */
+    if(data->easy_conn) {
+      data->easy_conn->ssl_config.verifystatus =
+        data->set.ssl.primary.verifystatus;
+    }
+    break;
+  case CURLOPT_SSL_CTX_FUNCTION:
+    /*
+     * Set a SSL_CTX callback
+     */
+#ifdef USE_SSL
+    if(Curl_ssl->have_ssl_ctx)
+      data->set.ssl.fsslctx = va_arg(param, curl_ssl_ctx_callback);
+    else
+#endif
+      result = CURLE_NOT_BUILT_IN;
+    break;
+  case CURLOPT_SSL_CTX_DATA:
+    /*
+     * Set a SSL_CTX callback parameter pointer
+     */
+#ifdef USE_SSL
+    if(Curl_ssl->have_ssl_ctx)
+      data->set.ssl.fsslctxp = va_arg(param, void *);
+    else
+#endif
+      result = CURLE_NOT_BUILT_IN;
+    break;
+  case CURLOPT_SSL_FALSESTART:
+    /*
+     * Enable TLS false start.
+     */
+    if(!Curl_ssl_false_start()) {
+      result = CURLE_NOT_BUILT_IN;
+      break;
+    }
+
+    data->set.ssl.falsestart = (0 != va_arg(param, long)) ? TRUE : FALSE;
+    break;
+  case CURLOPT_CERTINFO:
+#ifdef USE_SSL
+    if(Curl_ssl->have_certinfo)
+      data->set.ssl.certinfo = (0 != va_arg(param, long)) ? TRUE : FALSE;
+    else
+#endif
+      result = CURLE_NOT_BUILT_IN;
+        break;
+  case CURLOPT_PINNEDPUBLICKEY:
+    /*
+     * Set pinned public key for SSL connection.
+     * Specify file name of the public key in DER format.
+     */
+#ifdef USE_SSL
+    if(Curl_ssl->have_pinnedpubkey)
+      result = Curl_setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG],
+                              va_arg(param, char *));
+    else
+#endif
+      result = CURLE_NOT_BUILT_IN;
+    break;
+  case CURLOPT_PROXY_PINNEDPUBLICKEY:
+    /*
+     * Set pinned public key for SSL connection.
+     * Specify file name of the public key in DER format.
+     */
+#ifdef USE_SSL
+    if(Curl_ssl->have_pinnedpubkey)
+      result = Curl_setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY],
+                              va_arg(param, char *));
+    else
+#endif
+      result = CURLE_NOT_BUILT_IN;
+    break;
+  case CURLOPT_CAINFO:
+    /*
+     * Set CA info for SSL connection. Specify file name of the CA certificate
+     */
+    result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE_ORIG],
+                            va_arg(param, char *));
+    break;
+  case CURLOPT_PROXY_CAINFO:
+    /*
+     * Set CA info SSL connection for proxy. Specify file name of the
+     * CA certificate
+     */
+    result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE_PROXY],
+                            va_arg(param, char *));
+    break;
+  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->have_ca_path)
+      /* This does not work on windows. */
+      result = Curl_setstropt(&data->set.str[STRING_SSL_CAPATH_ORIG],
+                              va_arg(param, char *));
+    else
+#endif
+      result = CURLE_NOT_BUILT_IN;
+    break;
+  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->have_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;
+  case CURLOPT_CRLFILE:
+    /*
+     * Set CRL file info for SSL connection. Specify file name of the CRL
+     * to check certificates revocation
+     */
+    result = Curl_setstropt(&data->set.str[STRING_SSL_CRLFILE_ORIG],
+                            va_arg(param, char *));
+    break;
+  case CURLOPT_PROXY_CRLFILE:
+    /*
+     * Set CRL file info for SSL connection for proxy. Specify file name of the
+     * CRL to check certificates revocation
+     */
+    result = Curl_setstropt(&data->set.str[STRING_SSL_CRLFILE_PROXY],
+                            va_arg(param, char *));
+    break;
+  case CURLOPT_ISSUERCERT:
+    /*
+     * Set Issuer certificate file
+     * to check certificates issuer
+     */
+    result = Curl_setstropt(&data->set.str[STRING_SSL_ISSUERCERT_ORIG],
+                            va_arg(param, char *));
+    break;
+  case CURLOPT_TELNETOPTIONS:
+    /*
+     * Set a linked list of telnet options
+     */
+    data->set.telnet_options = va_arg(param, struct curl_slist *);
+    break;
+
+  case CURLOPT_BUFFERSIZE:
+    /*
+     * The application kindly asks for a differently sized receive buffer.
+     * If it seems reasonable, we'll use it.
+     */
+    arg = va_arg(param, long);
+
+    if(arg > READBUFFER_MAX)
+      arg = READBUFFER_MAX;
+    else if(arg < 1)
+      arg = READBUFFER_SIZE;
+    else if(arg < READBUFFER_MIN)
+      arg = READBUFFER_MIN;
+
+    /* Resize if new size */
+    if(arg != data->set.buffer_size) {
+      char *newbuff = realloc(data->state.buffer, arg + 1);
+      if(!newbuff) {
+        DEBUGF(fprintf(stderr, "Error: realloc of buffer failed\n"));
+        result = CURLE_OUT_OF_MEMORY;
+      }
+      else
+        data->state.buffer = newbuff;
+    }
+    data->set.buffer_size = arg;
+
+    break;
+
+  case CURLOPT_NOSIGNAL:
+    /*
+     * 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)) ? TRUE : FALSE;
+    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
+
+      if(data->share->sslsession == data->state.session)
+        data->state.session = NULL;
+
+      data->share->dirty--;
+
+      Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
+      data->share = NULL;
+    }
+
+    /* 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 */
+      if(data->share->sslsession) {
+        data->set.general_ssl.max_ssl_sessions = data->share->max_ssl_sessions;
+        data->state.session = data->share->sslsession;
+      }
+      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;
+    break;
+
+#ifdef USE_SSL
+  case CURLOPT_USE_SSL:
+    /*
+     * Make transfers attempt to use SSL/TLS.
+     */
+    arg = va_arg(param, long);
+    if((arg < CURLUSESSL_NONE) || (arg > CURLUSESSL_ALL))
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.use_ssl = (curl_usessl)arg;
+    break;
+
+  case CURLOPT_SSL_OPTIONS:
+    arg = va_arg(param, long);
+    data->set.ssl.enable_beast = arg&CURLSSLOPT_ALLOW_BEAST?TRUE:FALSE;
+    data->set.ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE);
+    break;
+
+  case CURLOPT_PROXY_SSL_OPTIONS:
+    arg = va_arg(param, long);
+    data->set.proxy_ssl.enable_beast = arg&CURLSSLOPT_ALLOW_BEAST?TRUE:FALSE;
+    data->set.proxy_ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE);
+    break;
+
+#endif
+  case CURLOPT_FTPSSLAUTH:
+    /*
+     * Set a specific auth for FTP-SSL transfers.
+     */
+    arg = va_arg(param, long);
+    if((arg < CURLFTPAUTH_DEFAULT) || (arg > CURLFTPAUTH_TLS))
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.ftpsslauth = (curl_ftpauth)arg;
+    break;
+
+  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 = 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)) ? TRUE : FALSE;
+    break;
+
+  case CURLOPT_FTP_ACCOUNT:
+    result = Curl_setstropt(&data->set.str[STRING_FTP_ACCOUNT],
+                            va_arg(param, char *));
+    break;
+
+  case CURLOPT_IGNORE_CONTENT_LENGTH:
+    data->set.ignorecl = (0 != va_arg(param, long)) ? TRUE : FALSE;
+    break;
+
+  case CURLOPT_CONNECT_ONLY:
+    /*
+     * No data transfer, set up connection and let application use the socket
+     */
+    data->set.connect_only = (0 != va_arg(param, long)) ? TRUE : FALSE;
+    break;
+
+  case CURLOPT_FTP_ALTERNATIVE_TO_USER:
+    result = Curl_setstropt(&data->set.str[STRING_FTP_ALTERNATIVE_TO_USER],
+                            va_arg(param, char *));
+    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_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.sessionid = (0 != va_arg(param, long)) ?
+      TRUE : FALSE;
+    data->set.proxy_ssl.primary.sessionid = data->set.ssl.primary.sessionid;
+    break;
+
+#ifdef USE_LIBSSH2
+    /* we only include SSH options if explicitly built to support SSH */
+  case CURLOPT_SSH_AUTH_TYPES:
+    data->set.ssh_auth_types = va_arg(param, long);
+    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;
+#ifdef HAVE_LIBSSH2_KNOWNHOST_API
+  case CURLOPT_SSH_KNOWNHOSTS:
+    /*
+     * Store the file name to read known hosts from.
+     */
+    result = Curl_setstropt(&data->set.str[STRING_SSH_KNOWNHOSTS],
+                            va_arg(param, char *));
+    break;
+
+  case CURLOPT_SSH_KEYFUNCTION:
+    /* setting to NULL is fine since the ssh.c functions themselves will
+       then rever 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;
+#endif /* HAVE_LIBSSH2_KNOWNHOST_API */
+
+#endif /* USE_LIBSSH2 */
+
+  case CURLOPT_HTTP_TRANSFER_DECODING:
+    /*
+     * disable libcurl transfer encoding is used
+     */
+    data->set.http_te_skip = (0 == va_arg(param, long)) ? TRUE : FALSE;
+    break;
+
+  case CURLOPT_HTTP_CONTENT_DECODING:
+    /*
+     * raw data passed to the application when content encoding is used
+     */
+    data->set.http_ce_skip = (0 == va_arg(param, long)) ? TRUE : FALSE;
+    break;
+
+  case CURLOPT_NEW_FILE_PERMS:
+    /*
+     * 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 = arg;
+    break;
+
+  case CURLOPT_NEW_DIRECTORY_PERMS:
+    /*
+     * 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 = arg;
+    break;
+
+  case CURLOPT_ADDRESS_SCOPE:
+    /*
+     * We always get longs when passed plain numericals, but for this value we
+     * know that an unsigned int will always hold the value so we blindly
+     * typecast to this type
+     */
+    arg = va_arg(param, long);
+    if((arg < 0) || (arg > 0xf))
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.scope_id = curlx_sltoui(arg);
+    break;
+
+  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 = va_arg(param, long);
+    break;
+
+  case CURLOPT_REDIR_PROTOCOLS:
+    /* set the bitmask for the protocols that libcurl is allowed to follow to,
+       as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs
+       to be set in both bitmasks to be allowed to get redirected to. Defaults
+       to all protocols except FILE and SCP. */
+    data->set.redir_protocols = va_arg(param, long);
+    break;
+
+  case CURLOPT_DEFAULT_PROTOCOL:
+    /* Set the protocol to use when the URL doesn't include any protocol */
+    result = Curl_setstropt(&data->set.str[STRING_DEFAULT_PROTOCOL],
+                            va_arg(param, char *));
+    break;
+
+  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_SASL_IR:
+    /* Enable/disable SASL initial response */
+    data->set.sasl_ir = (0 != va_arg(param, long)) ? TRUE : FALSE;
+    break;
+
+  case CURLOPT_RTSP_REQUEST:
+  {
+    /*
+     * Set the RTSP request method (OPTIONS, SETUP, PLAY, etc...)
+     * Would this be better if the RTSPREQ_* were just moved into here?
+     */
+    long curl_rtspreq = va_arg(param, long);
+    Curl_RtspReq rtspreq = RTSPREQ_NONE;
+    switch(curl_rtspreq) {
+    case CURL_RTSPREQ_OPTIONS:
+      rtspreq = RTSPREQ_OPTIONS;
+      break;
+
+    case CURL_RTSPREQ_DESCRIBE:
+      rtspreq = RTSPREQ_DESCRIBE;
+      break;
+
+    case CURL_RTSPREQ_ANNOUNCE:
+      rtspreq = RTSPREQ_ANNOUNCE;
+      break;
+
+    case CURL_RTSPREQ_SETUP:
+      rtspreq = RTSPREQ_SETUP;
+      break;
+
+    case CURL_RTSPREQ_PLAY:
+      rtspreq = RTSPREQ_PLAY;
+      break;
+
+    case CURL_RTSPREQ_PAUSE:
+      rtspreq = RTSPREQ_PAUSE;
+      break;
+
+    case CURL_RTSPREQ_TEARDOWN:
+      rtspreq = RTSPREQ_TEARDOWN;
+      break;
+
+    case CURL_RTSPREQ_GET_PARAMETER:
+      rtspreq = RTSPREQ_GET_PARAMETER;
+      break;
+
+    case CURL_RTSPREQ_SET_PARAMETER:
+      rtspreq = RTSPREQ_SET_PARAMETER;
+      break;
+
+    case CURL_RTSPREQ_RECORD:
+      rtspreq = RTSPREQ_RECORD;
+      break;
+
+    case CURL_RTSPREQ_RECEIVE:
+      rtspreq = RTSPREQ_RECEIVE;
+      break;
+    default:
+      rtspreq = RTSPREQ_NONE;
+    }
+
+    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);
+    break;
+
+  case CURLOPT_RTSP_SERVER_CSEQ:
+    /* Same as the above, but for server-initiated requests */
+    data->state.rtsp_next_client_CSeq = va_arg(param, long);
+    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;
+
+  case CURLOPT_WILDCARDMATCH:
+    data->set.wildcard_enabled = (0 != va_arg(param, long)) ? TRUE : FALSE;
+    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->wildcard.customptr = va_arg(param, void *);
+    break;
+  case CURLOPT_FNMATCH_DATA:
+    data->set.fnmatch_data = va_arg(param, void *);
+    break;
+#ifdef USE_TLS_SRP
+  case CURLOPT_TLSAUTH_USERNAME:
+    result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_USERNAME_ORIG],
+                            va_arg(param, char *));
+    if(data->set.str[STRING_TLSAUTH_USERNAME_ORIG] && !data->set.ssl.authtype)
+      data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */
+    break;
+  case CURLOPT_PROXY_TLSAUTH_USERNAME:
+    result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_USERNAME_PROXY],
+                            va_arg(param, char *));
+    if(data->set.str[STRING_TLSAUTH_USERNAME_PROXY] &&
+       !data->set.proxy_ssl.authtype)
+      data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */
+    break;
+  case CURLOPT_TLSAUTH_PASSWORD:
+    result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_ORIG],
+                            va_arg(param, char *));
+    if(data->set.str[STRING_TLSAUTH_USERNAME_ORIG] && !data->set.ssl.authtype)
+      data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */
+    break;
+  case CURLOPT_PROXY_TLSAUTH_PASSWORD:
+    result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_PROXY],
+                            va_arg(param, char *));
+    if(data->set.str[STRING_TLSAUTH_USERNAME_PROXY] &&
+       !data->set.proxy_ssl.authtype)
+      data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */
+    break;
+  case CURLOPT_TLSAUTH_TYPE:
+    argptr = va_arg(param, char *);
+    if(!argptr ||
+       strncasecompare(argptr, "SRP", strlen("SRP")))
+      data->set.ssl.authtype = CURL_TLSAUTH_SRP;
+    else
+      data->set.ssl.authtype = CURL_TLSAUTH_NONE;
+    break;
+  case CURLOPT_PROXY_TLSAUTH_TYPE:
+    argptr = va_arg(param, char *);
+    if(!argptr ||
+       strncasecompare(argptr, "SRP", strlen("SRP")))
+      data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP;
+    else
+      data->set.proxy_ssl.authtype = CURL_TLSAUTH_NONE;
+    break;
+#endif
+  case CURLOPT_DNS_SERVERS:
+    result = Curl_set_dns_servers(data, va_arg(param, char *));
+    break;
+  case CURLOPT_DNS_INTERFACE:
+    result = Curl_set_dns_interface(data, va_arg(param, char *));
+    break;
+  case CURLOPT_DNS_LOCAL_IP4:
+    result = Curl_set_dns_local_ip4(data, va_arg(param, char *));
+    break;
+  case CURLOPT_DNS_LOCAL_IP6:
+    result = Curl_set_dns_local_ip6(data, va_arg(param, char *));
+    break;
+
+  case CURLOPT_TCP_KEEPALIVE:
+    data->set.tcp_keepalive = (0 != va_arg(param, long)) ? TRUE : FALSE;
+    break;
+  case CURLOPT_TCP_KEEPIDLE:
+    arg = va_arg(param, long);
+    if(arg < 0)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.tcp_keepidle = arg;
+    break;
+  case CURLOPT_TCP_KEEPINTVL:
+    arg = va_arg(param, long);
+    if(arg < 0)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    data->set.tcp_keepintvl = 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))?TRUE:FALSE;
+#else
+    result = CURLE_NOT_BUILT_IN;
+#endif
+    break;
+  case CURLOPT_SSL_ENABLE_NPN:
+    data->set.ssl_enable_npn = (0 != va_arg(param, long)) ? TRUE : FALSE;
+    break;
+  case CURLOPT_SSL_ENABLE_ALPN:
+    data->set.ssl_enable_alpn = (0 != va_arg(param, long)) ? TRUE : FALSE;
+    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)) ? TRUE : FALSE;
+    break;
+  case CURLOPT_PIPEWAIT:
+    data->set.pipewait = (0 != va_arg(param, long)) ? TRUE : FALSE;
+    break;
+  case CURLOPT_STREAM_WEIGHT:
+#ifndef USE_NGHTTP2
+    return CURLE_NOT_BUILT_IN;
+#else
+    arg = va_arg(param, long);
+    if((arg >= 1) && (arg <= 256))
+      data->set.stream_weight = (int)arg;
+    break;
+#endif
+  case CURLOPT_STREAM_DEPENDS:
+  case CURLOPT_STREAM_DEPENDS_E:
+  {
+#ifndef USE_NGHTTP2
+    return CURLE_NOT_BUILT_IN;
+#else
+    struct Curl_easy *dep = va_arg(param, struct Curl_easy *);
+    if(!dep || GOOD_EASY_HANDLE(dep)) {
+      if(data->set.stream_depends_on) {
+        Curl_http2_remove_child(data->set.stream_depends_on, data);
+      }
+      Curl_http2_add_child(dep, data, (option == CURLOPT_STREAM_DEPENDS_E));
+    }
+    break;
+#endif
+  }
+  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))?TRUE:FALSE;
+    break;
+  case CURLOPT_SSH_COMPRESSION:
+    data->set.ssh_compression = (0 != va_arg(param, long))?TRUE:FALSE;
+    break;
+  default:
+    /* unknown tag and its companion, just ignore: */
+    result = CURLE_UNKNOWN_OPTION;
+    break;
+  }
+
+  return result;
+}
+
+/*
+ * curl_easy_setopt() is the external interface for setting options on an
+ * easy handle.
+ */
+
+#undef curl_easy_setopt
+CURLcode curl_easy_setopt(struct Curl_easy *data, CURLoption tag, ...)
+{
+  va_list arg;
+  CURLcode result;
+
+  if(!data)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  va_start(arg, tag);
+
+  result = setopt(data, tag, arg);
+
+  va_end(arg);
+  return result;
+}
+
diff --git a/lib/vtls/cyassl.h b/lib/setopt.h
similarity index 83%
copy from lib/vtls/cyassl.h
copy to lib/setopt.h
index 01e11cc23..35769440f 100644
--- a/lib/vtls/cyassl.h
+++ b/lib/setopt.h
@@ -1,5 +1,5 @@
-#ifndef HEADER_CURL_CYASSL_H
-#define HEADER_CURL_CYASSL_H
+#ifndef HEADER_CURL_SETOPT_H
+#define HEADER_CURL_SETOPT_H
 /***************************************************************************
  *                                  _   _ ____  _
  *  Project                     ___| | | |  _ \| |
@@ -21,11 +21,7 @@
  * KIND, either express or implied.
  *
  ***************************************************************************/
-#include "curl_setup.h"
 
-#ifdef USE_CYASSL
+CURLcode Curl_setstropt(char **charp, const char *s);
 
-extern const struct Curl_ssl Curl_ssl_cyassl;
-
-#endif /* USE_CYASSL */
-#endif /* HEADER_CURL_CYASSL_H */
+#endif /* HEADER_CURL_SETOPT_H */
diff --git a/lib/sha256.c b/lib/sha256.c
new file mode 100644
index 000000000..cd81c0254
--- /dev/null
+++ b/lib/sha256.c
@@ -0,0 +1,262 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Florin Petriuc, <address@hidden>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+
+#include "warnless.h"
+#include "curl_sha256.h"
+
+#if defined(USE_OPENSSL)
+
+/* When OpenSSL is available we use the SHA256-function from OpenSSL */
+#include <openssl/sha.h>
+
+#else
+
+/* When no other crypto library is available we use this code segment */
+
+/* ===== start - public domain SHA256 implementation ===== */
+/* This is based on SHA256 implementation in LibTomCrypt that was released into
+ * public domain by Tom St Denis. */
+
+#define WPA_GET_BE32(a) ((((unsigned long)(a)[0]) << 24) | \
+                         (((unsigned long)(a)[1]) << 16) | \
+                         (((unsigned long)(a)[2]) <<  8) | \
+                          ((unsigned long)(a)[3]))
+#define WPA_PUT_BE32(a, val)                                        \
+do {                                                                \
+  (a)[0] = (unsigned char)((((unsigned long) (val)) >> 24) & 0xff); \
+  (a)[1] = (unsigned char)((((unsigned long) (val)) >> 16) & 0xff); \
+  (a)[2] = (unsigned char)((((unsigned long) (val)) >> 8) & 0xff);  \
+  (a)[3] = (unsigned char)(((unsigned long) (val)) & 0xff);         \
+} while(0)
+
+#ifdef HAVE_LONGLONG
+#define WPA_PUT_BE64(a, val)                                    \
+do {                                                            \
+  (a)[0] = (unsigned char)(((unsigned long long)(val)) >> 56);  \
+  (a)[1] = (unsigned char)(((unsigned long long)(val)) >> 48);  \
+  (a)[2] = (unsigned char)(((unsigned long long)(val)) >> 40);  \
+  (a)[3] = (unsigned char)(((unsigned long long)(val)) >> 32);  \
+  (a)[4] = (unsigned char)(((unsigned long long)(val)) >> 24);  \
+  (a)[5] = (unsigned char)(((unsigned long long)(val)) >> 16);  \
+  (a)[6] = (unsigned char)(((unsigned long long)(val)) >> 8);   \
+  (a)[7] = (unsigned char)(((unsigned long long)(val)) & 0xff); \
+} while(0)
+#else
+#define WPA_PUT_BE64(a, val)                                  \
+do {                                                          \
+  (a)[0] = (unsigned char)(((unsigned __int64)(val)) >> 56);  \
+  (a)[1] = (unsigned char)(((unsigned __int64)(val)) >> 48);  \
+  (a)[2] = (unsigned char)(((unsigned __int64)(val)) >> 40);  \
+  (a)[3] = (unsigned char)(((unsigned __int64)(val)) >> 32);  \
+  (a)[4] = (unsigned char)(((unsigned __int64)(val)) >> 24);  \
+  (a)[5] = (unsigned char)(((unsigned __int64)(val)) >> 16);  \
+  (a)[6] = (unsigned char)(((unsigned __int64)(val)) >> 8);   \
+  (a)[7] = (unsigned char)(((unsigned __int64)(val)) & 0xff); \
+} while(0)
+#endif
+
+typedef struct sha256_state {
+#ifdef HAVE_LONGLONG
+  unsigned long long length;
+#else
+  unsigned __int64 length;
+#endif
+  unsigned long state[8], curlen;
+  unsigned char buf[64];
+} SHA256_CTX;
+/* the K array */
+static const unsigned long K[64] = {
+  0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL,
+  0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL,
+  0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL,
+  0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
+  0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL,
+  0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL,
+  0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL,
+  0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
+  0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL,
+  0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL,
+  0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL,
+  0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
+  0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
+};
+/* Various logical functions */
+#define RORc(x, y) \
+(((((unsigned long)(x) & 0xFFFFFFFFUL) >> (unsigned long)((y) & 31)) | \
+   ((unsigned long)(x) << (unsigned long)(32 - ((y) & 31)))) & 0xFFFFFFFFUL)
+#define Ch(x,y,z)   (z ^ (x & (y ^ z)))
+#define Maj(x,y,z)  (((x | y) & z) | (x & y))
+#define S(x, n)     RORc((x), (n))
+#define R(x, n)     (((x)&0xFFFFFFFFUL)>>(n))
+#define Sigma0(x)   (S(x, 2) ^ S(x, 13) ^ S(x, 22))
+#define Sigma1(x)   (S(x, 6) ^ S(x, 11) ^ S(x, 25))
+#define Gamma0(x)   (S(x, 7) ^ S(x, 18) ^ R(x, 3))
+#define Gamma1(x)   (S(x, 17) ^ S(x, 19) ^ R(x, 10))
+#ifndef MIN
+#define MIN(x, y)   (((x) < (y)) ? (x) : (y))
+#endif
+/* compress 512-bits */
+static int sha256_compress(struct sha256_state *md,
+                           unsigned char *buf)
+{
+  unsigned long S[8], W[64], t0, t1;
+  unsigned long t;
+  int i;
+  /* copy state into S */
+  for(i = 0; i < 8; i++) {
+    S[i] = md->state[i];
+  }
+  /* copy the state into 512-bits into W[0..15] */
+  for(i = 0; i < 16; i++)
+    W[i] = WPA_GET_BE32(buf + (4 * i));
+  /* fill W[16..63] */
+  for(i = 16; i < 64; i++) {
+    W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) +
+      W[i - 16];
+  }
+  /* Compress */
+#define RND(a,b,c,d,e,f,g,h,i)                    \
+  t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
+  t1 = Sigma0(a) + Maj(a, b, c);                  \
+  d += t0;                                        \
+  h = t0 + t1;
+  for(i = 0; i < 64; ++i) {
+    RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i);
+    t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4];
+    S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t;
+  }
+  /* feedback */
+  for(i = 0; i < 8; i++) {
+    md->state[i] = md->state[i] + S[i];
+  }
+  return 0;
+}
+/* Initialize the hash state */
+static void SHA256_Init(struct sha256_state *md)
+{
+  md->curlen = 0;
+  md->length = 0;
+  md->state[0] = 0x6A09E667UL;
+  md->state[1] = 0xBB67AE85UL;
+  md->state[2] = 0x3C6EF372UL;
+  md->state[3] = 0xA54FF53AUL;
+  md->state[4] = 0x510E527FUL;
+  md->state[5] = 0x9B05688CUL;
+  md->state[6] = 0x1F83D9ABUL;
+  md->state[7] = 0x5BE0CD19UL;
+}
+/**
+   Process a block of memory though the hash
+   @param md     The hash state
+   @param in     The data to hash
+   @param inlen  The length of the data (octets)
+   @return CRYPT_OK if successful
+*/
+static int SHA256_Update(struct sha256_state *md,
+                         const unsigned char *in,
+                         unsigned long inlen)
+{
+  unsigned long n;
+#define block_size 64
+  if(md->curlen > sizeof(md->buf))
+    return -1;
+  while(inlen > 0) {
+    if(md->curlen == 0 && inlen >= block_size) {
+      if(sha256_compress(md, (unsigned char *)in) < 0)
+        return -1;
+      md->length += block_size * 8;
+      in += block_size;
+      inlen -= block_size;
+    }
+    else {
+      n = MIN(inlen, (block_size - md->curlen));
+      memcpy(md->buf + md->curlen, in, n);
+      md->curlen += n;
+      in += n;
+      inlen -= n;
+      if(md->curlen == block_size) {
+        if(sha256_compress(md, md->buf) < 0)
+          return -1;
+        md->length += 8 * block_size;
+        md->curlen = 0;
+      }
+    }
+  }
+  return 0;
+}
+/**
+   Terminate the hash to get the digest
+   @param md  The hash state
+   @param out [out] The destination of the hash (32 bytes)
+   @return CRYPT_OK if successful
+*/
+static int SHA256_Final(unsigned char *out,
+                        struct sha256_state *md)
+{
+  int i;
+  if(md->curlen >= sizeof(md->buf))
+    return -1;
+  /* increase the length of the message */
+  md->length += md->curlen * 8;
+  /* append the '1' bit */
+  md->buf[md->curlen++] = (unsigned char)0x80;
+  /* if the length is currently above 56 bytes we append zeros
+   * then compress.  Then we can fall back to padding zeros and length
+   * encoding like normal.
+   */
+  if(md->curlen > 56) {
+    while(md->curlen < 64) {
+      md->buf[md->curlen++] = (unsigned char)0;
+    }
+    sha256_compress(md, md->buf);
+    md->curlen = 0;
+  }
+  /* pad upto 56 bytes of zeroes */
+  while(md->curlen < 56) {
+    md->buf[md->curlen++] = (unsigned char)0;
+  }
+  /* store length */
+  WPA_PUT_BE64(md->buf + 56, md->length);
+  sha256_compress(md, md->buf);
+  /* copy output */
+  for(i = 0; i < 8; i++)
+    WPA_PUT_BE32(out + (4 * i), md->state[i]);
+  return 0;
+}
+/* ===== end - public domain SHA256 implementation ===== */
+
+#endif
+
+void Curl_sha256it(unsigned char *outbuffer, /* 32 unsigned chars */
+                   const unsigned char *input)
+{
+  SHA256_CTX ctx;
+  SHA256_Init(&ctx);
+  SHA256_Update(&ctx, input, curlx_uztoui(strlen((char *)input)));
+  SHA256_Final(outbuffer, &ctx);
+}
+
+#endif /* CURL_DISABLE_CRYPTO_AUTH */
diff --git a/lib/share.c b/lib/share.c
index 3b2f7fdfc..8653a4300 100644
--- a/lib/share.c
+++ b/lib/share.c
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <address@hidden>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <address@hidden>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -102,6 +102,8 @@ curl_share_setopt(struct Curl_share *share, CURLSHoption 
option, ...)
       break;
 
     case CURL_LOCK_DATA_CONNECT:     /* not supported (yet) */
+      if(Curl_conncache_init(&share->conn_cache, 103))
+        res = CURLSHE_NOMEM;
       break;
 
     default:
@@ -186,6 +188,8 @@ curl_share_cleanup(struct Curl_share *share)
     return CURLSHE_IN_USE;
   }
 
+  Curl_conncache_close_all_connections(&share->conn_cache);
+  Curl_conncache_destroy(&share->conn_cache);
   Curl_hash_destroy(&share->hostcache);
 
 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
diff --git a/lib/share.h b/lib/share.h
index 59a4a14f0..c0d0a5189 100644
--- a/lib/share.h
+++ b/lib/share.h
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <address@hidden>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <address@hidden>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -26,6 +26,7 @@
 #include <gnurl/curl.h>
 #include "cookie.h"
 #include "urldata.h"
+#include "conncache.h"
 
 /* SalfordC says "A structure member may not be volatile". Hence:
  */
@@ -43,7 +44,7 @@ struct Curl_share {
   curl_lock_function lockfunc;
   curl_unlock_function unlockfunc;
   void *clientdata;
-
+  struct conncache conn_cache;
   struct curl_hash hostcache;
 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
   struct CookieInfo *cookies;
diff --git a/lib/smb.c b/lib/smb.c
index 13dfd514b..efcfd2da2 100644
--- a/lib/smb.c
+++ b/lib/smb.c
@@ -648,7 +648,7 @@ static CURLcode smb_connection_state(struct connectdata 
*conn, bool *done)
   if(smbc->state == SMB_CONNECTING) {
 #ifdef USE_SSL
     if((conn->handler->flags & PROTOPT_SSL)) {
-      bool ssl_done;
+      bool ssl_done = FALSE;
       result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &ssl_done);
       if(result && result != CURLE_AGAIN)
         return result;
diff --git a/lib/smtp.c b/lib/smtp.c
index bd3fc2e10..76958603b 100644
--- a/lib/smtp.c
+++ b/lib/smtp.c
@@ -1233,7 +1233,7 @@ static CURLcode smtp_done(struct connectdata *conn, 
CURLcode status,
     }
     else {
       /* Successfully sent so adjust the response timeout relative to now */
-      pp->response = Curl_tvnow();
+      pp->response = Curl_now();
 
       free(eob);
     }
diff --git a/lib/socks.c b/lib/socks.c
index e64cb98d4..ac4270eac 100644
--- a/lib/socks.c
+++ b/lib/socks.c
@@ -57,7 +57,7 @@ int Curl_blockread_all(struct connectdata *conn, /* 
connection data */
   ssize_t nread;
   ssize_t allread = 0;
   int result;
-  time_t timeleft;
+  timediff_t timeleft;
   *n = 0;
   for(;;) {
     timeleft = Curl_timeleft(conn->data, NULL, TRUE);
@@ -382,7 +382,7 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
   CURLcode code;
   curl_socket_t sock = conn->sock[sockindex];
   struct Curl_easy *data = conn->data;
-  time_t timeout;
+  timediff_t timeout;
   bool socks5_resolve_local =
     (conn->socks_proxy.proxytype == CURLPROXY_SOCKS5) ? TRUE : FALSE;
   const size_t hostname_len = strlen(hostname);
diff --git a/lib/speedcheck.c b/lib/speedcheck.c
index 4d9eb12e9..86920a078 100644
--- a/lib/speedcheck.c
+++ b/lib/speedcheck.c
@@ -46,7 +46,7 @@ CURLcode Curl_speedcheck(struct Curl_easy *data,
         data->state.keeps_speed = now;
       else {
         /* how long has it been under the limit */
-        time_t howlong = Curl_tvdiff(now, data->state.keeps_speed);
+        timediff_t howlong = Curl_timediff(now, data->state.keeps_speed);
 
         if(howlong >= data->set.low_speed_time * 1000) {
           /* too long */
diff --git a/lib/ssh.c b/lib/ssh.c
index ae717f9cc..8cb00ab75 100644
--- a/lib/ssh.c
+++ b/lib/ssh.c
@@ -2347,8 +2347,8 @@ static CURLcode ssh_statemach_act(struct connectdata 
*conn, bool *block)
         }
         sshc->sftp_handle = NULL;
       }
-      if(sftp_scp)
-        Curl_safefree(sftp_scp->path);
+
+      Curl_safefree(sftp_scp->path);
 
       DEBUGF(infof(data, "SFTP DONE done\n"));
 
@@ -2833,8 +2833,8 @@ static CURLcode ssh_block_statemach(struct connectdata 
*conn,
 
   while((sshc->state != SSH_STOP) && !result) {
     bool block;
-    time_t left = 1000;
-    struct curltime now = Curl_tvnow();
+    timediff_t left = 1000;
+    struct curltime now = Curl_now();
 
     result = ssh_statemach_act(conn, &block);
     if(result)
diff --git a/lib/telnet.c b/lib/telnet.c
index 37458fa42..b3c9cd27f 100644
--- a/lib/telnet.c
+++ b/lib/telnet.c
@@ -1560,8 +1560,8 @@ static CURLcode telnet_do(struct connectdata *conn, bool 
*done)
     }
 
     if(data->set.timeout) {
-      now = Curl_tvnow();
-      if(Curl_tvdiff(now, conn->created) >= data->set.timeout) {
+      now = Curl_now();
+      if(Curl_timediff(now, conn->created) >= data->set.timeout) {
         failf(data, "Time-out");
         result = CURLE_OPERATION_TIMEDOUT;
         keepon = FALSE;
@@ -1678,8 +1678,8 @@ static CURLcode telnet_do(struct connectdata *conn, bool 
*done)
     } /* poll switch statement */
 
     if(data->set.timeout) {
-      now = Curl_tvnow();
-      if(Curl_tvdiff(now, conn->created) >= data->set.timeout) {
+      now = Curl_now();
+      if(Curl_timediff(now, conn->created) >= data->set.timeout) {
         failf(data, "Time-out");
         result = CURLE_OPERATION_TIMEDOUT;
         keepon = FALSE;
diff --git a/lib/tftp.c b/lib/tftp.c
index caa767127..5e624d3c4 100644
--- a/lib/tftp.c
+++ b/lib/tftp.c
@@ -200,7 +200,7 @@ const struct Curl_handler Curl_handler_tftp = {
 static CURLcode tftp_set_timeouts(tftp_state_data_t *state)
 {
   time_t maxtime, timeout;
-  time_t timeout_ms;
+  timediff_t timeout_ms;
   bool start = (state->state == TFTP_STATE_START) ? TRUE : FALSE;
 
   time(&state->start_time);
@@ -1293,7 +1293,7 @@ static CURLcode tftp_doing(struct connectdata *conn, bool 
*dophase_done)
     if(Curl_pgrsUpdate(conn))
       result = CURLE_ABORTED_BY_CALLBACK;
     else
-      result = Curl_speedcheck(conn->data, Curl_tvnow());
+      result = Curl_speedcheck(conn->data, Curl_now());
   }
   return result;
 }
diff --git a/lib/timeval.c b/lib/timeval.c
index d7207b3a2..66f923a8e 100644
--- a/lib/timeval.c
+++ b/lib/timeval.c
@@ -24,7 +24,7 @@
 
 #if defined(WIN32) && !defined(MSDOS)
 
-struct curltime curlx_tvnow(void)
+struct curltime Curl_now(void)
 {
   /*
   ** GetTickCount() is available on _all_ Windows versions from W95 up
@@ -48,7 +48,7 @@ struct curltime curlx_tvnow(void)
 
 #elif defined(HAVE_CLOCK_GETTIME_MONOTONIC)
 
-struct curltime curlx_tvnow(void)
+struct curltime Curl_now(void)
 {
   /*
   ** clock_gettime() is granted to be increased monotonically when the
@@ -84,9 +84,40 @@ struct curltime curlx_tvnow(void)
   return cnow;
 }
 
+#elif defined(HAVE_MACH_ABSOLUTE_TIME)
+
+#include <stdint.h>
+#include <mach/mach_time.h>
+
+struct curltime Curl_now(void)
+{
+  /*
+  ** Monotonic timer on Mac OS is provided by mach_absolute_time(), which
+  ** returns time in Mach "absolute time units," which are platform-dependent.
+  ** To convert to nanoseconds, one must use conversion factors specified by
+  ** mach_timebase_info().
+  */
+  static mach_timebase_info_data_t timebase;
+  struct curltime cnow;
+  uint64_t usecs;
+
+  if(0 == timebase.denom)
+    (void) mach_timebase_info(&timebase);
+
+  usecs = mach_absolute_time();
+  usecs *= timebase.numer;
+  usecs /= timebase.denom;
+  usecs /= 1000;
+
+  cnow.tv_sec = usecs / 1000000;
+  cnow.tv_usec = usecs % 1000000;
+
+  return cnow;
+}
+
 #elif defined(HAVE_GETTIMEOFDAY)
 
-struct curltime curlx_tvnow(void)
+struct curltime Curl_now(void)
 {
   /*
   ** gettimeofday() is not granted to be increased monotonically, due to
@@ -103,7 +134,7 @@ struct curltime curlx_tvnow(void)
 
 #else
 
-struct curltime curlx_tvnow(void)
+struct curltime Curl_now(void)
 {
   /*
   ** time() returns the value of time in seconds since the Epoch.
@@ -116,47 +147,40 @@ struct curltime curlx_tvnow(void)
 
 #endif
 
+#if SIZEOF_TIME_T < 8
+#define TIME_MAX INT_MAX
+#define TIME_MIN INT_MIN
+#else
+#define TIME_MAX 9223372036854775807LL
+#define TIME_MIN -9223372036854775807LL
+#endif
+
 /*
- * Make sure that the first argument is the more recent time, as otherwise
- * we'll get a weird negative time-diff back...
- *
- * Returns: the time difference in number of milliseconds. For large diffs it
- * returns 0x7fffffff on 32bit time_t systems.
+ * Returns: time difference in number of milliseconds. For too large diffs it
+ * returns max value.
  *
  * @unittest: 1323
  */
-time_t curlx_tvdiff(struct curltime newer, struct curltime older)
+timediff_t Curl_timediff(struct curltime newer, struct curltime older)
 {
-#if SIZEOF_TIME_T < 8
-  /* for 32bit time_t systems, add a precaution to avoid overflow for really
-     big time differences */
-  time_t diff = newer.tv_sec-older.tv_sec;
-  if(diff >= (0x7fffffff/1000))
-    return 0x7fffffff;
-#endif
-  return (newer.tv_sec-older.tv_sec)*1000+
-    (int)(newer.tv_usec-older.tv_usec)/1000;
+  timediff_t diff = newer.tv_sec-older.tv_sec;
+  if(diff >= (TIME_MAX/1000))
+    return TIME_MAX;
+  else if(diff <= (TIME_MIN/1000))
+    return TIME_MIN;
+  return diff * 1000 + (newer.tv_usec-older.tv_usec)/1000;
 }
 
 /*
- * Make sure that the first argument is the more recent time, as otherwise
- * we'll get a weird negative time-diff back...
- *
- * Returns: the time difference in number of microseconds. For too large diffs
- * it returns max value.
+ * Returns: time difference in number of microseconds. For too large diffs it
+ * returns max value.
  */
-time_t Curl_tvdiff_us(struct curltime newer, struct curltime older)
+timediff_t Curl_timediff_us(struct curltime newer, struct curltime older)
 {
-  time_t diff = newer.tv_sec-older.tv_sec;
-#if SIZEOF_TIME_T < 8
-  /* for 32bit time_t systems */
-  if(diff >= (0x7fffffff/1000000))
-    return 0x7fffffff;
-#else
-  /* for 64bit time_t systems */
-  if(diff >= (0x7fffffffffffffffLL/1000000))
-    return 0x7fffffffffffffffLL;
-#endif
-  return (newer.tv_sec-older.tv_sec)*1000000+
-    (int)(newer.tv_usec-older.tv_usec);
+  timediff_t diff = newer.tv_sec-older.tv_sec;
+  if(diff >= (TIME_MAX/1000000))
+    return TIME_MAX;
+  else if(diff <= (TIME_MIN/1000000))
+    return TIME_MIN;
+  return diff * 1000000 + newer.tv_usec-older.tv_usec;
 }
diff --git a/lib/timeval.h b/lib/timeval.h
index 1ee4b3044..fb3f680c4 100644
--- a/lib/timeval.h
+++ b/lib/timeval.h
@@ -22,19 +22,20 @@
  *
  ***************************************************************************/
 
-/*
- * CAUTION: this header is designed to work when included by the app-side
- * as well as the library. Do not mix with library internals!
- */
-
 #include "curl_setup.h"
 
+#if SIZEOF_TIME_T < 8
+typedef int timediff_t;
+#else
+typedef curl_off_t timediff_t;
+#endif
+
 struct curltime {
-  time_t       tv_sec;     /* seconds */
-  unsigned int tv_usec;    /* microseconds */
+  time_t tv_sec; /* seconds */
+  int tv_usec;   /* microseconds */
 };
 
-struct curltime curlx_tvnow(void);
+struct curltime Curl_now(void);
 
 /*
  * Make sure that the first argument (t1) is the more recent time and t2 is
@@ -42,7 +43,7 @@ struct curltime curlx_tvnow(void);
  *
  * Returns: the time difference in number of milliseconds.
  */
-time_t curlx_tvdiff(struct curltime t1, struct curltime t2);
+timediff_t Curl_timediff(struct curltime t1, struct curltime t2);
 
 /*
  * Make sure that the first argument (t1) is the more recent time and t2 is
@@ -50,12 +51,6 @@ time_t curlx_tvdiff(struct curltime t1, struct curltime t2);
  *
  * Returns: the time difference in number of microseconds.
  */
-time_t Curl_tvdiff_us(struct curltime newer, struct curltime older);
-
-/* These two defines below exist to provide the older API for library
-   internals only. */
-#define Curl_tvnow() curlx_tvnow()
-#define Curl_tvdiff(x,y) curlx_tvdiff(x,y)
+timediff_t Curl_timediff_us(struct curltime newer, struct curltime older);
 
 #endif /* HEADER_CURL_TIMEVAL_H */
-
diff --git a/lib/transfer.c b/lib/transfer.c
index 30e936407..a6db3f739 100644
--- a/lib/transfer.c
+++ b/lib/transfer.c
@@ -238,9 +238,11 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int 
bytes, int *nreadp)
     }
 #endif /* CURL_DOES_CONVERSIONS */
 
-    if((nread - hexlen) == 0)
+    if((nread - hexlen) == 0) {
       /* mark this as done once this chunk is transferred */
       data->req.upload_done = TRUE;
+      infof(data, "Signaling end of chunked upload via terminating chunk.\n");
+    }
 
     nread += (int)strlen(endofline_native); /* for the added end of line */
   }
@@ -490,7 +492,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
       Curl_pgrsTime(data, TIMER_STARTTRANSFER);
       if(k->exp100 > EXP100_SEND_DATA)
         /* set time stamp to compare with when waiting for the 100 */
-        k->start100 = Curl_tvnow();
+        k->start100 = Curl_now();
     }
 
     *didwhat |= KEEP_RECV;
@@ -777,48 +779,19 @@ static CURLcode readwrite_data(struct Curl_easy *data,
              in http_chunks.c.
              Make sure that ALL_CONTENT_ENCODINGS contains all the
              encodings handled here. */
-#ifdef HAVE_LIBZ
-          switch(conn->data->set.http_ce_skip ?
-                 IDENTITY : k->auto_decoding) {
-          case IDENTITY:
-#endif
-            /* This is the default when the server sends no
-               Content-Encoding header. See Curl_readwrite_init; the
-               memset() call initializes k->auto_decoding to zero. */
+          if(conn->data->set.http_ce_skip || !k->writer_stack) {
             if(!k->ignorebody) {
-
 #ifndef CURL_DISABLE_POP3
-              if(conn->handler->protocol&PROTO_FAMILY_POP3)
+              if(conn->handler->protocol & PROTO_FAMILY_POP3)
                 result = Curl_pop3_write(conn, k->str, nread);
               else
 #endif /* CURL_DISABLE_POP3 */
-
                 result = Curl_client_write(conn, CLIENTWRITE_BODY, k->str,
                                            nread);
             }
-#ifdef HAVE_LIBZ
-            break;
-
-          case DEFLATE:
-            /* Assume CLIENTWRITE_BODY; headers are not encoded. */
-            if(!k->ignorebody)
-              result = Curl_unencode_deflate_write(conn, k, nread);
-            break;
-
-          case GZIP:
-            /* Assume CLIENTWRITE_BODY; headers are not encoded. */
-            if(!k->ignorebody)
-              result = Curl_unencode_gzip_write(conn, k, nread);
-            break;
-
-          default:
-            failf(data, "Unrecognized content encoding type. "
-                  "libcurl understands `identity', `deflate' and `gzip' "
-                  "content encodings.");
-            result = CURLE_BAD_CONTENT_ENCODING;
-            break;
           }
-#endif
+          else
+            result = Curl_unencode_write(conn, k->writer_stack, k->str, nread);
         }
         k->badheader = HEADER_NORMAL; /* taken care of now */
 
@@ -925,7 +898,7 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
              go into the Expect: 100 state and await such a header */
           k->exp100 = EXP100_AWAITING_CONTINUE; /* wait for the header */
           k->keepon &= ~KEEP_SEND;         /* disable writing */
-          k->start100 = Curl_tvnow();       /* timeout count starts now */
+          k->start100 = Curl_now();       /* timeout count starts now */
           *didwhat &= ~KEEP_SEND;  /* we didn't write anything actually */
 
           /* set a timeout for the multi interface */
@@ -1046,7 +1019,8 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
 
     k->writebytecount += bytes_written;
 
-    if(k->writebytecount == data->state.infilesize) {
+    if((!k->upload_chunky || k->forbidchunk) &&
+       (k->writebytecount == data->state.infilesize)) {
       /* we have sent all data we were supposed to */
       k->upload_done = TRUE;
       infof(data, "We are completely uploaded and fine\n");
@@ -1150,7 +1124,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
       return result;
   }
 
-  k->now = Curl_tvnow();
+  k->now = Curl_now();
   if(didwhat) {
     /* Update read/write counters */
     if(k->bytecountp)
@@ -1174,7 +1148,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
 
       */
 
-      time_t ms = Curl_tvdiff(k->now, k->start100);
+      timediff_t ms = Curl_timediff(k->now, k->start100);
       if(ms >= data->set.expect_100_timeout) {
         /* we've waited long enough, continue anyway */
         k->exp100 = EXP100_SEND_DATA;
@@ -1198,13 +1172,14 @@ CURLcode Curl_readwrite(struct connectdata *conn,
         failf(data, "Operation timed out after %ld milliseconds with %"
               CURL_FORMAT_CURL_OFF_T " out of %"
               CURL_FORMAT_CURL_OFF_T " bytes received",
-              Curl_tvdiff(k->now, data->progress.t_startsingle), k->bytecount,
-              k->size);
+              Curl_timediff(k->now, data->progress.t_startsingle),
+              k->bytecount, k->size);
       }
       else {
         failf(data, "Operation timed out after %ld milliseconds with %"
               CURL_FORMAT_CURL_OFF_T " bytes received",
-              Curl_tvdiff(k->now, data->progress.t_startsingle), k->bytecount);
+              Curl_timediff(k->now, data->progress.t_startsingle),
+              k->bytecount);
       }
       return CURLE_OPERATION_TIMEDOUT;
     }
@@ -1343,6 +1318,7 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
   if(result)
     return result;
 
+  data->state.wildcardmatch = data->set.wildcard_enabled;
   data->set.followlocation = 0; /* reset the location-follow counter */
   data->state.this_is_a_follow = FALSE; /* reset this */
   data->state.errorbuf = FALSE; /* no error has occurred */
@@ -1400,7 +1376,7 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
     data->state.authhost.picked &= data->state.authhost.want;
     data->state.authproxy.picked &= data->state.authproxy.want;
 
-    if(data->set.wildcardmatch) {
+    if(data->state.wildcardmatch) {
       struct WildcardData *wc = &data->wildcard;
       if(wc->state < CURLWC_INIT) {
         result = Curl_wildcard_init(wc); /* init wildcard structures */
@@ -2049,7 +2025,7 @@ Curl_setup_transfer(
          (http->sending == HTTPSEND_BODY)) {
         /* wait with write until we either got 100-continue or a timeout */
         k->exp100 = EXP100_AWAITING_CONTINUE;
-        k->start100 = Curl_tvnow();
+        k->start100 = Curl_now();
 
         /* Set a timeout for the multi interface. Add the inaccuracy margin so
            that we don't fire slightly too early and get denied to run. */
diff --git a/lib/url.c b/lib/url.c
index c538ca096..47f69c9f1 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -120,6 +120,8 @@ bool curl_win32_idn_to_ascii(const char *in, char **out);
 #include "pipeline.h"
 #include "dotdot.h"
 #include "strdup.h"
+#include "setopt.h"
+
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_memory.h"
@@ -136,15 +138,8 @@ static CURLcode parse_url_login(struct Curl_easy *data,
                                 struct connectdata *conn,
                                 char **userptr, char **passwdptr,
                                 char **optionsptr);
-static CURLcode parse_login_details(const char *login, const size_t len,
-                                    char **userptr, char **passwdptr,
-                                    char **optionsptr);
 static unsigned int get_protocol_family(unsigned int protocol);
 
-#define READBUFFER_SIZE CURL_MAX_WRITE_SIZE
-#define READBUFFER_MAX  CURL_MAX_READ_SIZE
-#define READBUFFER_MIN  1024
-
 /* Some parts of the code (e.g. chunked encoding) assume this buffer has at
  * more than just a few bytes to play with. Don't let it become too small or
  * bad things will happen.
@@ -301,98 +296,6 @@ void Curl_freeset(struct Curl_easy *data)
   data->change.url = NULL;
 }
 
-static CURLcode setstropt(char **charp, const char *s)
-{
-  /* Release the previous storage at `charp' and replace by a dynamic storage
-     copy of `s'. Return CURLE_OK or CURLE_OUT_OF_MEMORY. */
-
-  Curl_safefree(*charp);
-
-  if(s) {
-    char *str = strdup(s);
-
-    if(!str)
-      return CURLE_OUT_OF_MEMORY;
-
-    *charp = str;
-  }
-
-  return CURLE_OK;
-}
-
-static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp)
-{
-  CURLcode result = CURLE_OK;
-  char *user = NULL;
-  char *passwd = NULL;
-
-  /* Parse the login details if specified. It not then we treat NULL as a hint
-     to clear the existing data */
-  if(option) {
-    result = parse_login_details(option, strlen(option),
-                                 (userp ? &user : NULL),
-                                 (passwdp ? &passwd : NULL),
-                                 NULL);
-  }
-
-  if(!result) {
-    /* Store the username part of option if required */
-    if(userp) {
-      if(!user && option && option[0] == ':') {
-        /* Allocate an empty string instead of returning NULL as user name */
-        user = strdup("");
-        if(!user)
-          result = CURLE_OUT_OF_MEMORY;
-      }
-
-      Curl_safefree(*userp);
-      *userp = user;
-    }
-
-    /* Store the password part of option if required */
-    if(passwdp) {
-      Curl_safefree(*passwdp);
-      *passwdp = passwd;
-    }
-  }
-
-  return result;
-}
-
-CURLcode Curl_dupset(struct Curl_easy *dst, struct Curl_easy *src)
-{
-  CURLcode result = CURLE_OK;
-  enum dupstring i;
-
-  /* Copy src->set into dst->set first, then deal with the strings
-     afterwards */
-  dst->set = src->set;
-
-  /* clear all string pointers first */
-  memset(dst->set.str, 0, STRING_LAST * sizeof(char *));
-
-  /* duplicate all strings */
-  for(i = (enum dupstring)0; i< STRING_LASTZEROTERMINATED; i++) {
-    result = setstropt(&dst->set.str[i], src->set.str[i]);
-    if(result)
-      return result;
-  }
-
-  /* duplicate memory areas pointed to */
-  i = STRING_COPYPOSTFIELDS;
-  if(src->set.postfieldsize && src->set.str[i]) {
-    /* postfieldsize is curl_off_t, Curl_memdup() takes a size_t ... */
-    dst->set.str[i] = Curl_memdup(src->set.str[i],
-                                  curlx_sotouz(src->set.postfieldsize));
-    if(!dst->set.str[i])
-      return CURLE_OUT_OF_MEMORY;
-    /* point to the new copy */
-    dst->set.postfields = dst->set.str[i];
-  }
-
-  return CURLE_OK;
-}
-
 /*
  * This is the internal function curl_easy_cleanup() calls. This should
  * cleanup and free all resources associated with this sessionhandle.
@@ -489,12 +392,8 @@ CURLcode Curl_close(struct Curl_easy *data)
     Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
   }
 
-  if(data->set.wildcardmatch) {
-    /* destruct wildcard structures if it is needed */
-    struct WildcardData *wc = &data->wildcard;
-    Curl_wildcard_dtor(wc);
-  }
-
+  /* destruct wildcard structures if it is needed */
+  Curl_wildcard_dtor(&data->wildcard);
   Curl_freeset(data);
   free(data);
   return CURLE_OK;
@@ -583,2550 +482,130 @@ CURLcode Curl_init_userdefined(struct UserDefined *set)
 
 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
   /*
-   * disallow unprotected protection negotiation NEC reference implementation
-   * seem not to follow rfc1961 section 4.3/4.4
-   */
-  set->socks5_gssapi_nec = FALSE;
-#endif
-
-  /* This is our preferred CA cert bundle/path since install time */
-#if defined(CURL_CA_BUNDLE)
-  result = setstropt(&set->str[STRING_SSL_CAFILE_ORIG], CURL_CA_BUNDLE);
-  if(result)
-    return result;
-
-  result = setstropt(&set->str[STRING_SSL_CAFILE_PROXY], CURL_CA_BUNDLE);
-  if(result)
-    return result;
-#endif
-#if defined(CURL_CA_PATH)
-  result = setstropt(&set->str[STRING_SSL_CAPATH_ORIG], CURL_CA_PATH);
-  if(result)
-    return result;
-
-  result = setstropt(&set->str[STRING_SSL_CAPATH_PROXY], CURL_CA_PATH);
-  if(result)
-    return result;
-#endif
-
-  set->wildcardmatch  = FALSE;
-  set->chunk_bgn      = ZERO_NULL;
-  set->chunk_end      = ZERO_NULL;
-
-  /* tcp keepalives are disabled by default, but provide reasonable values for
-   * the interval and idle times.
-   */
-  set->tcp_keepalive = FALSE;
-  set->tcp_keepintvl = 60;
-  set->tcp_keepidle = 60;
-  set->tcp_fastopen = FALSE;
-  set->tcp_nodelay = TRUE;
-
-  set->ssl_enable_npn = TRUE;
-  set->ssl_enable_alpn = TRUE;
-
-  set->expect_100_timeout = 1000L; /* Wait for a second by default. */
-  set->sep_headers = TRUE; /* separated header lists by default */
-  set->buffer_size = READBUFFER_SIZE;
-
-  Curl_http2_init_userset(set);
-  return result;
-}
-
-/**
- * Curl_open()
- *
- * @param curl is a pointer to a sessionhandle pointer that gets set by this
- * function.
- * @return CURLcode
- */
-
-CURLcode Curl_open(struct Curl_easy **curl)
-{
-  CURLcode result;
-  struct Curl_easy *data;
-
-  /* Very 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 */
-    DEBUGF(fprintf(stderr, "Error: calloc of Curl_easy failed\n"));
-    return CURLE_OUT_OF_MEMORY;
-  }
-
-  data->magic = CURLEASY_MAGIC_NUMBER;
-
-  result = Curl_resolver_init(&data->state.resolver);
-  if(result) {
-    DEBUGF(fprintf(stderr, "Error: resolver_init failed\n"));
-    free(data);
-    return result;
-  }
-
-  /* We do some initial setup here, all those fields that can't be just 0 */
-
-  data->state.buffer = malloc(READBUFFER_SIZE + 1);
-  if(!data->state.buffer) {
-    DEBUGF(fprintf(stderr, "Error: malloc of buffer failed\n"));
-    result = CURLE_OUT_OF_MEMORY;
-  }
-
-  Curl_mime_initpart(&data->set.mimepost, data);
-
-  data->state.headerbuff = malloc(HEADERSIZE);
-  if(!data->state.headerbuff) {
-    DEBUGF(fprintf(stderr, "Error: malloc of headerbuff failed\n"));
-    result = CURLE_OUT_OF_MEMORY;
-  }
-  else {
-    result = Curl_init_userdefined(&data->set);
-
-    data->state.headersize = HEADERSIZE;
-
-    Curl_convert_init(data);
-
-    Curl_initinfo(data);
-
-    /* most recent connection is not yet defined */
-    data->state.lastconnect = NULL;
-
-    data->progress.flags |= PGRS_HIDE;
-    data->state.current_speed = -1; /* init to negative == impossible */
-    data->set.fnmatch = ZERO_NULL;
-    data->set.maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */
-
-    Curl_http2_init_state(&data->state);
-  }
-
-  if(result) {
-    Curl_resolver_cleanup(data->state.resolver);
-    free(data->state.buffer);
-    free(data->state.headerbuff);
-    Curl_freeset(data);
-    free(data);
-    data = NULL;
-  }
-  else
-    *curl = data;
-
-  return result;
-}
-
-#define C_SSLVERSION_VALUE(x) (x & 0xffff)
-#define C_SSLVERSION_MAX_VALUE(x) (x & 0xffff0000)
-
-CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option,
-                     va_list param)
-{
-  char *argptr;
-  CURLcode result = CURLE_OK;
-  long arg;
-  curl_off_t bigsize;
-
-  switch(option) {
-  case CURLOPT_DNS_CACHE_TIMEOUT:
-    arg = va_arg(param, long);
-    if(arg < 0)
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    data->set.dns_cache_timeout = arg;
-    break;
-  case CURLOPT_DNS_USE_GLOBAL_CACHE:
-    /* remember we want this enabled */
-    arg = va_arg(param, long);
-    data->set.global_dns_cache = (0 != arg) ? TRUE : FALSE;
-    break;
-  case CURLOPT_SSL_CIPHER_LIST:
-    /* set a list of cipher we want to use in the SSL connection */
-    result = setstropt(&data->set.str[STRING_SSL_CIPHER_LIST_ORIG],
-                       va_arg(param, char *));
-    break;
-  case CURLOPT_PROXY_SSL_CIPHER_LIST:
-    /* set a list of cipher we want to use in the SSL connection for proxy */
-    result = setstropt(&data->set.str[STRING_SSL_CIPHER_LIST_PROXY],
-                       va_arg(param, char *));
-    break;
-
-  case CURLOPT_RANDOM_FILE:
-    /*
-     * This is the path name to a file that contains random data to seed
-     * the random SSL stuff with. The file is only used for reading.
-     */
-    result = setstropt(&data->set.str[STRING_SSL_RANDOM_FILE],
-                       va_arg(param, char *));
-    break;
-  case CURLOPT_EGDSOCKET:
-    /*
-     * The Entropy Gathering Daemon socket pathname
-     */
-    result = setstropt(&data->set.str[STRING_SSL_EGDSOCKET],
-                       va_arg(param, char *));
-    break;
-  case CURLOPT_MAXCONNECTS:
-    /*
-     * Set the absolute number of maximum simultaneous alive connection that
-     * libcurl is allowed to have.
-     */
-    arg = va_arg(param, long);
-    if(arg < 0)
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    data->set.maxconnects = arg;
-    break;
-  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)) ? TRUE : FALSE;
-    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)) ? TRUE : FALSE;
-    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)) ? TRUE : FALSE;
-    break;
-  case CURLOPT_HEADER:
-    /*
-     * Set to include the header in the general data output stream.
-     */
-    data->set.include_header = (0 != va_arg(param, long)) ? TRUE : FALSE;
-    break;
-  case CURLOPT_NOPROGRESS:
-    /*
-     * Shut off the internal supported progress meter
-     */
-    data->set.hide_progress = (0 != va_arg(param, long)) ? TRUE : FALSE;
-    if(data->set.hide_progress)
-      data->progress.flags |= PGRS_HIDE;
-    else
-      data->progress.flags &= ~PGRS_HIDE;
-    break;
-  case CURLOPT_NOBODY:
-    /*
-     * Do not include the body part in the output data stream.
-     */
-    data->set.opt_no_body = (0 != va_arg(param, long)) ? TRUE : FALSE;
-    break;
-  case CURLOPT_FAILONERROR:
-    /*
-     * Don't output the >=400 error code HTML-page, but instead only
-     * return error.
-     */
-    data->set.http_fail_on_error = (0 != va_arg(param, long)) ? TRUE : FALSE;
-    break;
-  case CURLOPT_KEEP_SENDING_ON_ERROR:
-    data->set.http_keep_sending_on_error = (0 != va_arg(param, long)) ?
-                                           TRUE : FALSE;
-    break;
-  case CURLOPT_UPLOAD:
-  case CURLOPT_PUT:
-    /*
-     * We want to sent data to the remote host. If this is HTTP, that equals
-     * using the PUT request.
-     */
-    data->set.upload = (0 != va_arg(param, long)) ? TRUE : FALSE;
-    if(data->set.upload) {
-      /* If this is HTTP, PUT is what's needed to "upload" */
-      data->set.httpreq = HTTPREQ_PUT;
-      data->set.opt_no_body = FALSE; /* this is implied */
-    }
-    else
-      /* In HTTP, the opposite of upload is GET (unless NOBODY is true as
-         then this can be changed to HEAD later on) */
-      data->set.httpreq = HTTPREQ_GET;
-    break;
-  case CURLOPT_REQUEST_TARGET:
-    result = 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)) ? TRUE : FALSE;
-    break;
-  case CURLOPT_FTP_CREATE_MISSING_DIRS:
-    /*
-     * An FTP option that modifies an upload to create missing directories on
-     * the server.
-     */
-    switch(va_arg(param, long)) {
-    case 0:
-      data->set.ftp_create_missing_dirs = 0;
-      break;
-    case 1:
-      data->set.ftp_create_missing_dirs = 1;
-      break;
-    case 2:
-      data->set.ftp_create_missing_dirs = 2;
-      break;
-    default:
-      /* reserve other values for future use */
-      result = CURLE_UNKNOWN_OPTION;
-      break;
-    }
-    break;
-  case CURLOPT_SERVER_RESPONSE_TIMEOUT:
-    /*
-     * Option that specifies how quickly an 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 = arg * 1000;
-    else
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    break;
-  case CURLOPT_TFTP_NO_OPTIONS:
-    /*
-     * Option that prevents libcurl from sending TFTP option requests to the
-     * server.
-     */
-    data->set.tftp_no_options = va_arg(param, long) != 0;
-    break;
-  case CURLOPT_TFTP_BLKSIZE:
-    /*
-     * TFTP option that specifies the block size to use for data transmission.
-     */
-    arg = va_arg(param, long);
-    if(arg < 0)
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    data->set.tftp_blksize = arg;
-    break;
-  case CURLOPT_DIRLISTONLY:
-    /*
-     * An option that changes the command to one that asks for a list
-     * only, no file info details.
-     */
-    data->set.ftp_list_only = (0 != va_arg(param, long)) ? TRUE : FALSE;
-    break;
-  case CURLOPT_APPEND:
-    /*
-     * We want to upload and append to an existing file.
-     */
-    data->set.ftp_append = (0 != va_arg(param, long)) ? TRUE : FALSE;
-    break;
-  case CURLOPT_FTP_FILEMETHOD:
-    /*
-     * How do access files over FTP.
-     */
-    arg = va_arg(param, long);
-    if((arg < CURLFTPMETHOD_DEFAULT) || (arg > CURLFTPMETHOD_SINGLECWD))
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    data->set.ftp_filemethod = (curl_ftpfile)arg;
-    break;
-  case CURLOPT_NETRC:
-    /*
-     * Parse the $HOME/.netrc file
-     */
-    arg = va_arg(param, long);
-    if((arg < CURL_NETRC_IGNORED) || (arg > CURL_NETRC_REQUIRED))
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    data->set.use_netrc = (enum CURL_NETRC_OPTION)arg;
-    break;
-  case CURLOPT_NETRC_FILE:
-    /*
-     * Use this file instead of the $HOME/.netrc file
-     */
-    result = setstropt(&data->set.str[STRING_NETRC_FILE],
-                       va_arg(param, char *));
-    break;
-  case CURLOPT_TRANSFERTEXT:
-    /*
-     * This option was previously named 'FTPASCII'. Renamed to work with
-     * more protocols than merely FTP.
-     *
-     * Transfer using ASCII (instead of BINARY).
-     */
-    data->set.prefer_ascii = (0 != va_arg(param, long)) ? TRUE : FALSE;
-    break;
-  case CURLOPT_TIMECONDITION:
-    /*
-     * Set HTTP time condition. This must be one of the defines in the
-     * gnurl/curl.h header file.
-     */
-    arg = va_arg(param, long);
-    if((arg < CURL_TIMECOND_NONE) || (arg > CURL_TIMECOND_LASTMOD))
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    data->set.timecondition = (curl_TimeCond)arg;
-    break;
-  case CURLOPT_TIMEVALUE:
-    /*
-     * 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);
-    break;
-  case CURLOPT_SSLVERSION:
-    /*
-     * Set explicit SSL version to try to connect with, as some SSL
-     * implementations are lame.
-     */
-#ifdef USE_SSL
-    arg = va_arg(param, long);
-    if((arg < CURL_SSLVERSION_DEFAULT) || (arg > CURL_SSLVERSION_TLSv1_3))
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    data->set.ssl.primary.version = C_SSLVERSION_VALUE(arg);
-    data->set.ssl.primary.version_max = C_SSLVERSION_MAX_VALUE(arg);
-#else
-    result = CURLE_UNKNOWN_OPTION;
-#endif
-    break;
-  case CURLOPT_PROXY_SSLVERSION:
-    /*
-     * Set explicit SSL version to try to connect with for proxy, as some SSL
-     * implementations are lame.
-     */
-#ifdef USE_SSL
-    arg = va_arg(param, long);
-    if((arg < CURL_SSLVERSION_DEFAULT) || (arg > CURL_SSLVERSION_TLSv1_3))
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    data->set.proxy_ssl.primary.version = C_SSLVERSION_VALUE(arg);
-    data->set.proxy_ssl.primary.version_max = C_SSLVERSION_MAX_VALUE(arg);
-#else
-    result = CURLE_UNKNOWN_OPTION;
-#endif
-    break;
-
-#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)) ? TRUE : FALSE;
-    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 don't send an Accept-Encoding header
-     * and ignore an received Content-Encoding header.
-     *
-     */
-    argptr = va_arg(param, char *);
-    result = setstropt(&data->set.str[STRING_ENCODING],
-                       (argptr && !*argptr)?
-                       ALL_CONTENT_ENCODINGS: argptr);
-    break;
-
-  case CURLOPT_TRANSFER_ENCODING:
-    data->set.http_transfer_encoding = (0 != va_arg(param, long)) ?
-                                       TRUE : FALSE;
-    break;
-
-  case CURLOPT_FOLLOWLOCATION:
-    /*
-     * Follow Location: header hints on a HTTP-server.
-     */
-    data->set.http_follow_location = (0 != va_arg(param, long)) ? TRUE : FALSE;
-    break;
-
-  case CURLOPT_UNRESTRICTED_AUTH:
-    /*
-     * Send authentication (user+password) when following locations, even when
-     * hostname changed.
-     */
-    data->set.http_disable_hostname_check_before_authentication =
-      (0 != va_arg(param, long)) ? TRUE : FALSE;
-    break;
-
-  case CURLOPT_MAXREDIRS:
-    /*
-     * 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 < 0)
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    data->set.maxredirs = arg;
-    break;
-
-  case CURLOPT_POSTREDIR:
-  {
-    /*
-     * Set the behaviour of POST when redirecting
-     * CURL_REDIR_GET_ALL - POST is changed to GET after 301 and 302
-     * CURL_REDIR_POST_301 - POST is kept as POST after 301
-     * CURL_REDIR_POST_302 - POST is kept as POST after 302
-     * CURL_REDIR_POST_303 - POST is kept as POST after 303
-     * 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 */
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    data->set.keep_post = arg & CURL_REDIR_POST_ALL;
-  }
-  break;
-
-  case CURLOPT_POST:
-    /* Does this option serve a purpose anymore? Yes it does, when
-       CURLOPT_POSTFIELDS isn't used and the POST data is read off the
-       callback! */
-    if(va_arg(param, long)) {
-      data->set.httpreq = HTTPREQ_POST;
-      data->set.opt_no_body = FALSE; /* this is implied */
-    }
-    else
-      data->set.httpreq = HTTPREQ_GET;
-    break;
-
-  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 = 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 {
-        char *p;
-
-        (void) setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
-
-        /* Allocate even when size == 0. This satisfies the need of possible
-           later address compare to detect the COPYPOSTFIELDS mode, and
-           to mark that postfields is used rather than read function or
-           form data.
-        */
-        p = malloc((size_t)(data->set.postfieldsize?
-                            data->set.postfieldsize:1));
-
-        if(!p)
-          result = CURLE_OUT_OF_MEMORY;
-        else {
-          if(data->set.postfieldsize)
-            memcpy(p, argptr, (size_t)data->set.postfieldsize);
-
-          data->set.str[STRING_COPYPOSTFIELDS] = p;
-        }
-      }
-    }
-
-    data->set.postfields = data->set.str[STRING_COPYPOSTFIELDS];
-    data->set.httpreq = 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. */
-    (void) setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
-    data->set.httpreq = 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 < 0)
-      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. */
-      (void) setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
-      data->set.postfields = NULL;
-    }
-
-    data->set.postfieldsize = bigsize;
-    break;
-
-  case CURLOPT_POSTFIELDSIZE_LARGE:
-    /*
-     * The size of the POSTFIELD data to prevent libcurl to do strlen() to
-     * figure it out. Enables binary posts.
-     */
-    bigsize = va_arg(param, curl_off_t);
-
-    if(data->set.postfieldsize < bigsize &&
-       data->set.postfields == data->set.str[STRING_COPYPOSTFIELDS]) {
-      /* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */
-      (void) setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
-      data->set.postfields = NULL;
-    }
-
-    data->set.postfieldsize = bigsize;
-    break;
-
-  case CURLOPT_HTTPPOST:
-    /*
-     * Set to make us do HTTP POST
-     */
-    data->set.httppost = va_arg(param, struct curl_httppost *);
-    data->set.httpreq = HTTPREQ_POST_FORM;
-    data->set.opt_no_body = FALSE; /* this is implied */
-    break;
-#endif   /* CURL_DISABLE_HTTP */
-
-  case CURLOPT_MIMEPOST:
-    /*
-     * Set to make us do MIME/form POST
-     */
-    result = Curl_mime_set_subparts(&data->set.mimepost,
-                                    va_arg(param, curl_mime *), FALSE);
-    if(!result) {
-      data->set.httpreq = HTTPREQ_POST_MIME;
-      data->set.opt_no_body = FALSE; /* this is implied */
-    }
-    break;
-
-  case CURLOPT_REFERER:
-    /*
-     * String to set in the HTTP Referer: field.
-     */
-    if(data->change.referer_alloc) {
-      Curl_safefree(data->change.referer);
-      data->change.referer_alloc = FALSE;
-    }
-    result = setstropt(&data->set.str[STRING_SET_REFERER],
-                       va_arg(param, char *));
-    data->change.referer = data->set.str[STRING_SET_REFERER];
-    break;
-
-  case CURLOPT_USERAGENT:
-    /*
-     * String to use in the HTTP User-Agent field
-     */
-    result = setstropt(&data->set.str[STRING_USERAGENT],
-                       va_arg(param, char *));
-    break;
-
-  case CURLOPT_HTTPHEADER:
-    /*
-     * Set a list with HTTP headers to use (or replace internals with)
-     */
-    data->set.headers = va_arg(param, struct curl_slist *);
-    break;
-
-#ifndef CURL_DISABLE_HTTP
-  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;
-
-  case CURLOPT_HEADEROPT:
-    /*
-     * Set header option.
-     */
-    arg = va_arg(param, long);
-    data->set.sep_headers = (arg & CURLHEADER_SEPARATE)? TRUE: FALSE;
-    break;
-
-  case CURLOPT_HTTP200ALIASES:
-    /*
-     * Set a list of aliases for HTTP 200 in response header
-     */
-    data->set.http200aliases = va_arg(param, struct curl_slist *);
-    break;
-
-#if !defined(CURL_DISABLE_COOKIES)
-  case CURLOPT_COOKIE:
-    /*
-     * Cookie string to send to the remote server in the request.
-     */
-    result = 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;
-      /* append the cookie file name to the list of file names, and deal with
-         them later */
-      cl = curl_slist_append(data->change.cookielist, argptr);
-      if(!cl) {
-        curl_slist_free_all(data->change.cookielist);
-        data->change.cookielist = NULL;
-        return CURLE_OUT_OF_MEMORY;
-      }
-      data->change.cookielist = cl; /* store the list for later use */
-    }
-    break;
-
-  case CURLOPT_COOKIEJAR:
-    /*
-     * Set cookie file name to dump all cookies to when we're done.
-     */
-  {
-    struct CookieInfo *newcookies;
-    result = setstropt(&data->set.str[STRING_COOKIEJAR],
-                       va_arg(param, char *));
-
-    /*
-     * Activate the cookie parser. This may or may not already
-     * have been made.
-     */
-    newcookies = Curl_cookie_init(data, NULL, data->cookies,
-                                  data->set.cookiesession);
-    if(!newcookies)
-      result = CURLE_OUT_OF_MEMORY;
-    data->cookies = newcookies;
-  }
-    break;
-
-  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.
-     *
-     * In the original Netscape cookie spec, "session cookies" are cookies
-     * with no expire date set. RFC2109 describes the same action if no
-     * 'Max-Age' is set and RFC2965 includes the RFC2109 description and adds
-     * a 'Discard' action that can enforce the discard even for cookies that
-     * have a Max-Age.
-     *
-     * We run mostly with the original cookie spec, as hardly anyone implements
-     * anything else.
-     */
-    data->set.cookiesession = (0 != va_arg(param, long)) ? TRUE : FALSE;
-    break;
-
-  case CURLOPT_COOKIELIST:
-    argptr = va_arg(param, char *);
-
-    if(argptr == NULL)
-      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, 0);
-    }
-    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);
-
-      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, argptr + 11, NULL, NULL);
-
-        else
-          /* Netscape format line */
-          Curl_cookie_add(data, data->cookies, FALSE, argptr, NULL, NULL);
-
-        Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
-        free(argptr);
-      }
-    }
-
-    break;
-#endif /* !CURL_DISABLE_COOKIES */
-
-  case CURLOPT_HTTPGET:
-    /*
-     * Set to force us do HTTP GET
-     */
-    if(va_arg(param, long)) {
-      data->set.httpreq = HTTPREQ_GET;
-      data->set.upload = FALSE; /* switch off upload */
-      data->set.opt_no_body = FALSE; /* this is implied */
-    }
-    break;
-
-  case CURLOPT_HTTP_VERSION:
-    /*
-     * This sets a requested HTTP version to be used. The value is one of
-     * the listed enums in gnurl/curl.h.
-     */
-    arg = va_arg(param, long);
-    if(arg < CURL_HTTP_VERSION_NONE)
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-#ifndef USE_NGHTTP2
-    if(arg >= CURL_HTTP_VERSION_2)
-      return CURLE_UNSUPPORTED_PROTOCOL;
-#else
-    if(arg > CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE)
-      return CURLE_UNSUPPORTED_PROTOCOL;
-#endif
-    data->set.httpversion = arg;
-    break;
-
-  case CURLOPT_EXPECT_100_TIMEOUT_MS:
-    /*
-     * Time to wait for a response to a 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;
-
-#endif   /* CURL_DISABLE_HTTP */
-
-  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) ? TRUE : FALSE;
-
-    if(auth & CURLAUTH_DIGEST_IE) {
-      auth |= CURLAUTH_DIGEST; /* set standard digest bit */
-      auth &= ~CURLAUTH_DIGEST_IE; /* unset ie digest bit */
-    }
-
-    /* switch off bits we can't support */
-#ifndef USE_NTLM
-    auth &= ~CURLAUTH_NTLM;    /* no NTLM support */
-    auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */
-#elif !defined(NTLM_WB_ENABLED)
-    auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */
-#endif
-#ifndef USE_SPNEGO
-    auth &= ~CURLAUTH_NEGOTIATE; /* no Negotiate (SPNEGO) auth without
-                                    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 = setstropt(&data->set.str[STRING_CUSTOMREQUEST],
-                       va_arg(param, char *));
-
-    /* we don't set
-       data->set.httpreq = HTTPREQ_CUSTOM;
-       here, we continue as if we were using the already set type
-       and this just changes the actual request keyword */
-    break;
-
-#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)) ?
-                                      TRUE : FALSE;
-    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 = 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) ? TRUE : FALSE;
-
-    if(auth & CURLAUTH_DIGEST_IE) {
-      auth |= CURLAUTH_DIGEST; /* set standard digest bit */
-      auth &= ~CURLAUTH_DIGEST_IE; /* unset ie digest bit */
-    }
-    /* switch off bits we can't support */
-#ifndef USE_NTLM
-    auth &= ~CURLAUTH_NTLM;    /* no NTLM support */
-    auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */
-#elif !defined(NTLM_WB_ENABLED)
-    auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */
-#endif
-#ifndef USE_SPNEGO
-    auth &= ~CURLAUTH_NEGOTIATE; /* no Negotiate (SPNEGO) auth without
-                                    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 don't 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 = 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 don't want
-     * to use the socks proxy.
-     */
-    result = setstropt(&data->set.str[STRING_PRE_PROXY],
-                       va_arg(param, char *));
-    break;
-
-  case CURLOPT_PROXYTYPE:
-    /*
-     * Set proxy type. HTTP/HTTP_1_0/SOCKS4/SOCKS4a/SOCKS5/SOCKS5_HOSTNAME
-     */
-    arg = va_arg(param, long);
-    if((arg < CURLPROXY_HTTP) || (arg > CURLPROXY_SOCKS5_HOSTNAME))
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    data->set.proxytype = (curl_proxytype)arg;
-    break;
-
-  case CURLOPT_PROXY_TRANSFER_MODE:
-    /*
-     * 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:
-      /* reserve other values for future use */
-      result = CURLE_UNKNOWN_OPTION;
-      break;
-    }
-    break;
-#endif   /* CURL_DISABLE_PROXY */
-
-  case CURLOPT_SOCKS5_AUTH:
-    data->set.socks5auth = va_arg(param, unsigned long);
-    if(data->set.socks5auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI))
-      result = CURLE_NOT_BUILT_IN;
-    break;
-#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)) ? TRUE : FALSE;
-    break;
-
-  case CURLOPT_SOCKS5_GSSAPI_SERVICE:
-  case CURLOPT_PROXY_SERVICE_NAME:
-    /*
-     * Set proxy authentication service name for Kerberos 5 and SPNEGO
-     */
-    result = setstropt(&data->set.str[STRING_PROXY_SERVICE_NAME],
-                       va_arg(param, char *));
-    break;
-#endif
-
-#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) || \
-    defined(USE_SPNEGO)
-  case CURLOPT_SERVICE_NAME:
-    /*
-     * Set authentication service name for DIGEST-MD5, Kerberos 5 and SPNEGO
-     */
-    result = setstropt(&data->set.str[STRING_SERVICE_NAME],
-                       va_arg(param, char *));
-    break;
-
-#endif
-
-  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;
-  case CURLOPT_FTPPORT:
-    /*
-     * Use FTP PORT, this also specifies which IP address to use
-     */
-    result = setstropt(&data->set.str[STRING_FTPPORT],
-                       va_arg(param, char *));
-    data->set.ftp_use_port = (data->set.str[STRING_FTPPORT]) ? TRUE : FALSE;
-    break;
-
-  case CURLOPT_FTP_USE_EPRT:
-    data->set.ftp_use_eprt = (0 != va_arg(param, long)) ? TRUE : FALSE;
-    break;
-
-  case CURLOPT_FTP_USE_EPSV:
-    data->set.ftp_use_epsv = (0 != va_arg(param, long)) ? TRUE : FALSE;
-    break;
-
-  case CURLOPT_FTP_USE_PRET:
-    data->set.ftp_use_pret = (0 != va_arg(param, long)) ? TRUE : FALSE;
-    break;
-
-  case CURLOPT_FTP_SSL_CCC:
-    arg = va_arg(param, long);
-    if((arg < CURLFTPSSL_CCC_NONE) || (arg > CURLFTPSSL_CCC_ACTIVE))
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    data->set.ftp_ccc = (curl_ftpccc)arg;
-    break;
-
-  case CURLOPT_FTP_SKIP_PASV_IP:
-    /*
-     * 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)) ? TRUE : FALSE;
-    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 = va_arg(param, void *);
-    break;
-  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 < 0)
-      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 < 0)
-      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_URL:
-    /*
-     * The URL to fetch.
-     */
-    if(data->change.url_alloc) {
-      /* the already set URL is allocated, free it first! */
-      Curl_safefree(data->change.url);
-      data->change.url_alloc = FALSE;
-    }
-    result = setstropt(&data->set.str[STRING_SET_URL],
-                       va_arg(param, char *));
-    data->change.url = data->set.str[STRING_SET_URL];
-    break;
-  case CURLOPT_PORT:
-    /*
-     * The port number to use when getting the URL
-     */
-    arg = va_arg(param, long);
-    if((arg < 0) || (arg > 65535))
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    data->set.use_port = arg;
-    break;
-  case CURLOPT_TIMEOUT:
-    /*
-     * 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 = arg * 1000;
-    else
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    break;
-
-  case CURLOPT_TIMEOUT_MS:
-    arg = va_arg(param, long);
-    if(arg < 0)
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    data->set.timeout = arg;
-    break;
-
-  case CURLOPT_CONNECTTIMEOUT:
-    /*
-     * 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 = arg * 1000;
-    else
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    break;
-
-  case CURLOPT_CONNECTTIMEOUT_MS:
-    arg = va_arg(param, long);
-    if(arg < 0)
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    data->set.connecttimeout = arg;
-    break;
-
-  case CURLOPT_ACCEPTTIMEOUT_MS:
-    /*
-     * The maximum time you allow curl to wait for server connect
-     */
-    arg = va_arg(param, long);
-    if(arg < 0)
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    data->set.accepttimeout = arg;
-    break;
-
-  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 user name to use in the operation
-     */
-    result = setstropt(&data->set.str[STRING_USERNAME],
-                       va_arg(param, char *));
-    break;
-
-  case CURLOPT_PASSWORD:
-    /*
-     * authentication password to use in the operation
-     */
-    result = setstropt(&data->set.str[STRING_PASSWORD],
-                       va_arg(param, char *));
-    break;
-
-  case CURLOPT_LOGIN_OPTIONS:
-    /*
-     * authentication options to use in the operation
-     */
-    result = 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 = setstropt(&data->set.str[STRING_BEARER],
-                       va_arg(param, char *));
-    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;
-  case CURLOPT_RESOLVE:
-    /*
-     * List of NAME:[address] names to populate the DNS cache with
-     * Prefix the NAME with dash (-) to _remove_ the name from the cache.
-     *
-     * Names added with this API will remain in the cache until explicitly
-     * removed or the handle is cleaned up.
-     *
-     * This API can remove any name from the DNS cache, but only entries
-     * that aren't actually in use right now will be pruned immediately.
-     */
-    data->set.resolve = va_arg(param, struct curl_slist *);
-    data->change.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
-     */
-    result = setstropt_userpwd(va_arg(param, char *),
-                               &data->set.str[STRING_PROXYUSERNAME],
-                               &data->set.str[STRING_PROXYPASSWORD]);
-    break;
-  case CURLOPT_PROXYUSERNAME:
-    /*
-     * authentication user name to use in the operation
-     */
-    result = setstropt(&data->set.str[STRING_PROXYUSERNAME],
-                       va_arg(param, char *));
-    break;
-  case CURLOPT_PROXYPASSWORD:
-    /*
-     * authentication password to use in the operation
-     */
-    result = setstropt(&data->set.str[STRING_PROXYPASSWORD],
-                       va_arg(param, char *));
-    break;
-  case CURLOPT_NOPROXY:
-    /*
-     * proxy exception list
-     */
-    result = 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 = 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'll 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) {
-      data->set.is_fwrite_set = 0;
-      /* When set to NULL, reset to our internal default function */
-      data->set.fwrite_func = (curl_write_callback)fwrite;
-    }
-    else
-      data->set.is_fwrite_set = 1;
-    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_CONV_FROM_NETWORK_FUNCTION:
-    /*
-     * "Convert from network encoding" callback
-     */
-    data->set.convfromnetwork = va_arg(param, curl_conv_callback);
-    break;
-  case CURLOPT_CONV_TO_NETWORK_FUNCTION:
-    /*
-     * "Convert to network encoding" callback
-     */
-    data->set.convtonetwork = va_arg(param, curl_conv_callback);
-    break;
-  case CURLOPT_CONV_FROM_UTF8_FUNCTION:
-    /*
-     * "Convert from UTF-8 encoding" callback
-     */
-    data->set.convfromutf8 = va_arg(param, curl_conv_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_IOCTLDATA:
-    /*
-     * I/O control data pointer. Might be NULL.
-     */
-    data->set.ioctl_client = va_arg(param, void *);
-    break;
-  case CURLOPT_SSLCERT:
-    /*
-     * String that holds file name of the SSL certificate to use
-     */
-    result = setstropt(&data->set.str[STRING_CERT_ORIG],
-                       va_arg(param, char *));
-    break;
-  case CURLOPT_PROXY_SSLCERT:
-    /*
-     * String that holds file name of the SSL certificate to use for proxy
-     */
-    result = setstropt(&data->set.str[STRING_CERT_PROXY],
-                       va_arg(param, char *));
-    break;
-  case CURLOPT_SSLCERTTYPE:
-    /*
-     * String that holds file type of the SSL certificate to use
-     */
-    result = setstropt(&data->set.str[STRING_CERT_TYPE_ORIG],
-                       va_arg(param, char *));
-    break;
-  case CURLOPT_PROXY_SSLCERTTYPE:
-    /*
-     * String that holds file type of the SSL certificate to use for proxy
-     */
-    result = setstropt(&data->set.str[STRING_CERT_TYPE_PROXY],
-                       va_arg(param, char *));
-    break;
-  case CURLOPT_SSLKEY:
-    /*
-     * String that holds file name of the SSL key to use
-     */
-    result = setstropt(&data->set.str[STRING_KEY_ORIG],
-                       va_arg(param, char *));
-    break;
-  case CURLOPT_PROXY_SSLKEY:
-    /*
-     * String that holds file name of the SSL key to use for proxy
-     */
-    result = setstropt(&data->set.str[STRING_KEY_PROXY],
-                       va_arg(param, char *));
-    break;
-  case CURLOPT_SSLKEYTYPE:
-    /*
-     * String that holds file type of the SSL key to use
-     */
-    result = setstropt(&data->set.str[STRING_KEY_TYPE_ORIG],
-                       va_arg(param, char *));
-    break;
-  case CURLOPT_PROXY_SSLKEYTYPE:
-    /*
-     * String that holds file type of the SSL key to use for proxy
-     */
-    result = setstropt(&data->set.str[STRING_KEY_TYPE_PROXY],
-                       va_arg(param, char *));
-    break;
-  case CURLOPT_KEYPASSWD:
-    /*
-     * String that holds the SSL or SSH private key password.
-     */
-    result = setstropt(&data->set.str[STRING_KEY_PASSWD_ORIG],
-                       va_arg(param, char *));
-    break;
-  case CURLOPT_PROXY_KEYPASSWD:
-    /*
-     * String that holds the SSL private key password for proxy.
-     */
-    result = setstropt(&data->set.str[STRING_KEY_PASSWD_PROXY],
-                       va_arg(param, char *));
-    break;
-  case CURLOPT_SSLENGINE:
-    /*
-     * String that holds the SSL crypto engine.
-     */
-    argptr = va_arg(param, char *);
-    if(argptr && argptr[0])
-      result = Curl_ssl_set_engine(data, argptr);
-    break;
-
-  case CURLOPT_SSLENGINE_DEFAULT:
-    /*
-     * flag to set engine as default.
-     */
-    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)) ? TRUE : FALSE;
-    break;
-
-  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(&data->set.str[STRING_DEVICE],
-                       va_arg(param, char *));
-    break;
-  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);
-    break;
-  case CURLOPT_LOCALPORTRANGE:
-    /*
-     * 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_sltosi(arg);
-    break;
-  case CURLOPT_KRBLEVEL:
-    /*
-     * A string that defines the kerberos security level.
-     */
-    result = setstropt(&data->set.str[STRING_KRB_LEVEL],
-                       va_arg(param, char *));
-    data->set.krb = (data->set.str[STRING_KRB_LEVEL]) ? TRUE : FALSE;
-    break;
-  case CURLOPT_GSSAPI_DELEGATION:
-    /*
-     * GSS-API credential delegation bitmask
-     */
-    arg = va_arg(param, long);
-    if(arg < CURLGSSAPI_DELEGATION_NONE)
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    data->set.gssapi_delegation = arg;
-    break;
-  case CURLOPT_SSL_VERIFYPEER:
-    /*
-     * Enable peer SSL verifying.
-     */
-    data->set.ssl.primary.verifypeer = (0 != va_arg(param, long)) ?
-                                       TRUE : FALSE;
-
-    /* Update the current connection ssl_config. */
-    if(data->easy_conn) {
-      data->easy_conn->ssl_config.verifypeer =
-        data->set.ssl.primary.verifypeer;
-    }
-    break;
-  case CURLOPT_PROXY_SSL_VERIFYPEER:
-    /*
-     * Enable peer SSL verifying for proxy.
-     */
-    data->set.proxy_ssl.primary.verifypeer =
-      (0 != va_arg(param, long))?TRUE:FALSE;
-
-    /* Update the current connection proxy_ssl_config. */
-    if(data->easy_conn) {
-      data->easy_conn->proxy_ssl_config.verifypeer =
-        data->set.proxy_ssl.primary.verifypeer;
-    }
-    break;
-  case CURLOPT_SSL_VERIFYHOST:
-    /*
-     * Enable verification of the host name 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 wasn't and misused it. We thus ban
-       1 as a sensible input and we warn about its use. Then we only have the
-       2 action internally stored as TRUE. */
-
-    if(1 == arg) {
-      failf(data, "CURLOPT_SSL_VERIFYHOST no longer supports 1 as value!");
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    }
-
-    data->set.ssl.primary.verifyhost = (0 != arg) ? TRUE : FALSE;
-
-    /* Update the current connection ssl_config. */
-    if(data->easy_conn) {
-      data->easy_conn->ssl_config.verifyhost =
-        data->set.ssl.primary.verifyhost;
-    }
-    break;
-  case CURLOPT_PROXY_SSL_VERIFYHOST:
-    /*
-     * Enable verification of the host name in the peer certificate for proxy
-     */
-    arg = va_arg(param, long);
-
-    /* Obviously people are not reading documentation and too many thought
-       this argument took a boolean when it wasn't and misused it. We thus ban
-       1 as a sensible input and we warn about its use. Then we only have the
-       2 action internally stored as TRUE. */
-
-    if(1 == arg) {
-      failf(data, "CURLOPT_SSL_VERIFYHOST no longer supports 1 as value!");
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    }
-
-    data->set.proxy_ssl.primary.verifyhost = (0 != arg)?TRUE:FALSE;
-
-    /* Update the current connection proxy_ssl_config. */
-    if(data->easy_conn) {
-      data->easy_conn->proxy_ssl_config.verifyhost =
-        data->set.proxy_ssl.primary.verifyhost;
-    }
-    break;
-  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)) ?
-                                         TRUE : FALSE;
-
-    /* Update the current connection ssl_config. */
-    if(data->easy_conn) {
-      data->easy_conn->ssl_config.verifystatus =
-        data->set.ssl.primary.verifystatus;
-    }
-    break;
-  case CURLOPT_SSL_CTX_FUNCTION:
-    /*
-     * Set a SSL_CTX callback
-     */
-#ifdef USE_SSL
-    if(Curl_ssl->have_ssl_ctx)
-      data->set.ssl.fsslctx = va_arg(param, curl_ssl_ctx_callback);
-    else
-#endif
-      result = CURLE_NOT_BUILT_IN;
-    break;
-  case CURLOPT_SSL_CTX_DATA:
-    /*
-     * Set a SSL_CTX callback parameter pointer
-     */
-#ifdef USE_SSL
-    if(Curl_ssl->have_ssl_ctx)
-      data->set.ssl.fsslctxp = va_arg(param, void *);
-    else
-#endif
-      result = CURLE_NOT_BUILT_IN;
-    break;
-  case CURLOPT_SSL_FALSESTART:
-    /*
-     * Enable TLS false start.
-     */
-    if(!Curl_ssl_false_start()) {
-      result = CURLE_NOT_BUILT_IN;
-      break;
-    }
-
-    data->set.ssl.falsestart = (0 != va_arg(param, long)) ? TRUE : FALSE;
-    break;
-  case CURLOPT_CERTINFO:
-#ifdef USE_SSL
-    if(Curl_ssl->have_certinfo)
-      data->set.ssl.certinfo = (0 != va_arg(param, long)) ? TRUE : FALSE;
-    else
-#endif
-      result = CURLE_NOT_BUILT_IN;
-    break;
-  case CURLOPT_PINNEDPUBLICKEY:
-    /*
-     * Set pinned public key for SSL connection.
-     * Specify file name of the public key in DER format.
-     */
-#ifdef USE_SSL
-    if(Curl_ssl->have_pinnedpubkey)
-      result = setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG],
-                         va_arg(param, char *));
-    else
-#endif
-      result = CURLE_NOT_BUILT_IN;
-    break;
-  case CURLOPT_PROXY_PINNEDPUBLICKEY:
-    /*
-     * Set pinned public key for SSL connection.
-     * Specify file name of the public key in DER format.
-     */
-#ifdef USE_SSL
-    if(Curl_ssl->have_pinnedpubkey)
-      result = setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY],
-                         va_arg(param, char *));
-    else
-#endif
-      result = CURLE_NOT_BUILT_IN;
-    break;
-  case CURLOPT_CAINFO:
-    /*
-     * Set CA info for SSL connection. Specify file name of the CA certificate
-     */
-    result = setstropt(&data->set.str[STRING_SSL_CAFILE_ORIG],
-                       va_arg(param, char *));
-    break;
-  case CURLOPT_PROXY_CAINFO:
-    /*
-     * Set CA info SSL connection for proxy. Specify file name of the
-     * CA certificate
-     */
-    result = setstropt(&data->set.str[STRING_SSL_CAFILE_PROXY],
-                       va_arg(param, char *));
-    break;
-  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->have_ca_path)
-      /* This does not work on windows. */
-      result = setstropt(&data->set.str[STRING_SSL_CAPATH_ORIG],
-                         va_arg(param, char *));
-    else
-#endif
-      result = CURLE_NOT_BUILT_IN;
-    break;
-  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->have_ca_path)
-      /* This does not work on windows. */
-      result = setstropt(&data->set.str[STRING_SSL_CAPATH_PROXY],
-                         va_arg(param, char *));
-    else
-#endif
-      result = CURLE_NOT_BUILT_IN;
-    break;
-  case CURLOPT_CRLFILE:
-    /*
-     * Set CRL file info for SSL connection. Specify file name of the CRL
-     * to check certificates revocation
-     */
-    result = setstropt(&data->set.str[STRING_SSL_CRLFILE_ORIG],
-                       va_arg(param, char *));
-    break;
-  case CURLOPT_PROXY_CRLFILE:
-    /*
-     * Set CRL file info for SSL connection for proxy. Specify file name of the
-     * CRL to check certificates revocation
-     */
-    result = setstropt(&data->set.str[STRING_SSL_CRLFILE_PROXY],
-                       va_arg(param, char *));
-    break;
-  case CURLOPT_ISSUERCERT:
-    /*
-     * Set Issuer certificate file
-     * to check certificates issuer
-     */
-    result = setstropt(&data->set.str[STRING_SSL_ISSUERCERT_ORIG],
-                       va_arg(param, char *));
-    break;
-  case CURLOPT_TELNETOPTIONS:
-    /*
-     * Set a linked list of telnet options
-     */
-    data->set.telnet_options = va_arg(param, struct curl_slist *);
-    break;
-
-  case CURLOPT_BUFFERSIZE:
-    /*
-     * The application kindly asks for a differently sized receive buffer.
-     * If it seems reasonable, we'll use it.
-     */
-    arg = va_arg(param, long);
-
-    if(arg > READBUFFER_MAX)
-      arg = READBUFFER_MAX;
-    else if(arg < 1)
-      arg = READBUFFER_SIZE;
-    else if(arg < READBUFFER_MIN)
-      arg = READBUFFER_MIN;
-
-    /* Resize if new size */
-    if(arg != data->set.buffer_size) {
-      char *newbuff = realloc(data->state.buffer, arg + 1);
-      if(!newbuff) {
-        DEBUGF(fprintf(stderr, "Error: realloc of buffer failed\n"));
-        result = CURLE_OUT_OF_MEMORY;
-      }
-      else
-        data->state.buffer = newbuff;
-    }
-    data->set.buffer_size = arg;
-
-    break;
-
-  case CURLOPT_NOSIGNAL:
-    /*
-     * 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)) ? TRUE : FALSE;
-    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
-
-      if(data->share->sslsession == data->state.session)
-        data->state.session = NULL;
-
-      data->share->dirty--;
-
-      Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
-      data->share = NULL;
-    }
-
-    /* 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 */
-      if(data->share->sslsession) {
-        data->set.general_ssl.max_ssl_sessions = data->share->max_ssl_sessions;
-        data->state.session = data->share->sslsession;
-      }
-      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;
-    break;
-
-#ifdef USE_SSL
-  case CURLOPT_USE_SSL:
-    /*
-     * Make transfers attempt to use SSL/TLS.
-     */
-    arg = va_arg(param, long);
-    if((arg < CURLUSESSL_NONE) || (arg > CURLUSESSL_ALL))
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    data->set.use_ssl = (curl_usessl)arg;
-    break;
-
-  case CURLOPT_SSL_OPTIONS:
-    arg = va_arg(param, long);
-    data->set.ssl.enable_beast = arg&CURLSSLOPT_ALLOW_BEAST?TRUE:FALSE;
-    data->set.ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE);
-    break;
-
-  case CURLOPT_PROXY_SSL_OPTIONS:
-    arg = va_arg(param, long);
-    data->set.proxy_ssl.enable_beast = arg&CURLSSLOPT_ALLOW_BEAST?TRUE:FALSE;
-    data->set.proxy_ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE);
-    break;
-
-#endif
-  case CURLOPT_FTPSSLAUTH:
-    /*
-     * Set a specific auth for FTP-SSL transfers.
-     */
-    arg = va_arg(param, long);
-    if((arg < CURLFTPAUTH_DEFAULT) || (arg > CURLFTPAUTH_TLS))
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    data->set.ftpsslauth = (curl_ftpauth)arg;
-    break;
-
-  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 = 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)) ? TRUE : FALSE;
-    break;
-
-  case CURLOPT_FTP_ACCOUNT:
-    result = setstropt(&data->set.str[STRING_FTP_ACCOUNT],
-                       va_arg(param, char *));
-    break;
-
-  case CURLOPT_IGNORE_CONTENT_LENGTH:
-    data->set.ignorecl = (0 != va_arg(param, long)) ? TRUE : FALSE;
-    break;
-
-  case CURLOPT_CONNECT_ONLY:
-    /*
-     * No data transfer, set up connection and let application use the socket
-     */
-    data->set.connect_only = (0 != va_arg(param, long)) ? TRUE : FALSE;
-    break;
-
-  case CURLOPT_FTP_ALTERNATIVE_TO_USER:
-    result = setstropt(&data->set.str[STRING_FTP_ALTERNATIVE_TO_USER],
-                       va_arg(param, char *));
-    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_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.sessionid = (0 != va_arg(param, long)) ?
-                                      TRUE : FALSE;
-    data->set.proxy_ssl.primary.sessionid = data->set.ssl.primary.sessionid;
-    break;
-
-#ifdef USE_LIBSSH2
-    /* we only include SSH options if explicitly built to support SSH */
-  case CURLOPT_SSH_AUTH_TYPES:
-    arg = va_arg(param, long);
-    if(arg < CURLSSH_AUTH_NONE)
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    data->set.ssh_auth_types = va_arg(param, long);
-    break;
-
-  case CURLOPT_SSH_PUBLIC_KEYFILE:
-    /*
-     * Use this file instead of the $HOME/.ssh/id_dsa.pub file
-     */
-    result = 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 = 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 = setstropt(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5],
-                       va_arg(param, char *));
-    break;
-#ifdef HAVE_LIBSSH2_KNOWNHOST_API
-  case CURLOPT_SSH_KNOWNHOSTS:
-    /*
-     * Store the file name to read known hosts from.
-     */
-    result = setstropt(&data->set.str[STRING_SSH_KNOWNHOSTS],
-                       va_arg(param, char *));
-    break;
-
-  case CURLOPT_SSH_KEYFUNCTION:
-    /* setting to NULL is fine since the ssh.c functions themselves will
-       then rever 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;
-#endif /* HAVE_LIBSSH2_KNOWNHOST_API */
-
-#endif /* USE_LIBSSH2 */
-
-  case CURLOPT_HTTP_TRANSFER_DECODING:
-    /*
-     * disable libcurl transfer encoding is used
-     */
-    data->set.http_te_skip = (0 == va_arg(param, long)) ? TRUE : FALSE;
-    break;
-
-  case CURLOPT_HTTP_CONTENT_DECODING:
-    /*
-     * raw data passed to the application when content encoding is used
-     */
-    data->set.http_ce_skip = (0 == va_arg(param, long)) ? TRUE : FALSE;
-    break;
-
-  case CURLOPT_NEW_FILE_PERMS:
-    /*
-     * 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 = arg;
-    break;
-
-  case CURLOPT_NEW_DIRECTORY_PERMS:
-    /*
-     * 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 = arg;
-    break;
-
-  case CURLOPT_ADDRESS_SCOPE:
-    /*
-     * We always get longs when passed plain numericals, but for this value we
-     * know that an unsigned int will always hold the value so we blindly
-     * typecast to this type
-     */
-    arg = va_arg(param, long);
-    if((arg < 0) || (arg > 0xf))
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    data->set.scope_id = curlx_sltoui(arg);
-    break;
-
-  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 = va_arg(param, long);
-    break;
-
-  case CURLOPT_REDIR_PROTOCOLS:
-    /* set the bitmask for the protocols that libcurl is allowed to follow to,
-       as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs
-       to be set in both bitmasks to be allowed to get redirected to. Defaults
-       to all protocols except FILE and SCP. */
-    data->set.redir_protocols = va_arg(param, long);
-    break;
-
-  case CURLOPT_DEFAULT_PROTOCOL:
-    /* Set the protocol to use when the URL doesn't include any protocol */
-    result = setstropt(&data->set.str[STRING_DEFAULT_PROTOCOL],
-                       va_arg(param, char *));
-    break;
-
-  case CURLOPT_MAIL_FROM:
-    /* Set the SMTP mail originator */
-    result = setstropt(&data->set.str[STRING_MAIL_FROM],
-                       va_arg(param, char *));
-    break;
-
-  case CURLOPT_MAIL_AUTH:
-    /* Set the SMTP auth originator */
-    result = 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_SASL_IR:
-    /* Enable/disable SASL initial response */
-    data->set.sasl_ir = (0 != va_arg(param, long)) ? TRUE : FALSE;
-    break;
-
-  case CURLOPT_RTSP_REQUEST:
-    {
-      /*
-       * Set the RTSP request method (OPTIONS, SETUP, PLAY, etc...)
-       * Would this be better if the RTSPREQ_* were just moved into here?
-       */
-      long curl_rtspreq = va_arg(param, long);
-      Curl_RtspReq rtspreq = RTSPREQ_NONE;
-      switch(curl_rtspreq) {
-        case CURL_RTSPREQ_OPTIONS:
-          rtspreq = RTSPREQ_OPTIONS;
-          break;
-
-        case CURL_RTSPREQ_DESCRIBE:
-          rtspreq = RTSPREQ_DESCRIBE;
-          break;
-
-        case CURL_RTSPREQ_ANNOUNCE:
-          rtspreq = RTSPREQ_ANNOUNCE;
-          break;
+   * disallow unprotected protection negotiation NEC reference implementation
+   * seem not to follow rfc1961 section 4.3/4.4
+   */
+  set->socks5_gssapi_nec = FALSE;
+#endif
 
-        case CURL_RTSPREQ_SETUP:
-          rtspreq = RTSPREQ_SETUP;
-          break;
+  /* This is our preferred CA cert bundle/path since install time */
+#if defined(CURL_CA_BUNDLE)
+  result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_ORIG], CURL_CA_BUNDLE);
+  if(result)
+    return result;
 
-        case CURL_RTSPREQ_PLAY:
-          rtspreq = RTSPREQ_PLAY;
-          break;
+  result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_PROXY], CURL_CA_BUNDLE);
+  if(result)
+    return result;
+#endif
+#if defined(CURL_CA_PATH)
+  result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_ORIG], CURL_CA_PATH);
+  if(result)
+    return result;
 
-        case CURL_RTSPREQ_PAUSE:
-          rtspreq = RTSPREQ_PAUSE;
-          break;
+  result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_PROXY], CURL_CA_PATH);
+  if(result)
+    return result;
+#endif
 
-        case CURL_RTSPREQ_TEARDOWN:
-          rtspreq = RTSPREQ_TEARDOWN;
-          break;
+  set->wildcard_enabled = FALSE;
+  set->chunk_bgn      = ZERO_NULL;
+  set->chunk_end      = ZERO_NULL;
 
-        case CURL_RTSPREQ_GET_PARAMETER:
-          rtspreq = RTSPREQ_GET_PARAMETER;
-          break;
+  /* tcp keepalives are disabled by default, but provide reasonable values for
+   * the interval and idle times.
+   */
+  set->tcp_keepalive = FALSE;
+  set->tcp_keepintvl = 60;
+  set->tcp_keepidle = 60;
+  set->tcp_fastopen = FALSE;
+  set->tcp_nodelay = TRUE;
 
-        case CURL_RTSPREQ_SET_PARAMETER:
-          rtspreq = RTSPREQ_SET_PARAMETER;
-          break;
+  set->ssl_enable_npn = TRUE;
+  set->ssl_enable_alpn = TRUE;
 
-        case CURL_RTSPREQ_RECORD:
-          rtspreq = RTSPREQ_RECORD;
-          break;
+  set->expect_100_timeout = 1000L; /* Wait for a second by default. */
+  set->sep_headers = TRUE; /* separated header lists by default */
+  set->buffer_size = READBUFFER_SIZE;
 
-        case CURL_RTSPREQ_RECEIVE:
-          rtspreq = RTSPREQ_RECEIVE;
-          break;
-        default:
-          rtspreq = RTSPREQ_NONE;
-      }
+  Curl_http2_init_userset(set);
+  return result;
+}
 
-      data->set.rtspreq = rtspreq;
-    break;
-    }
+/**
+ * Curl_open()
+ *
+ * @param curl is a pointer to a sessionhandle pointer that gets set by this
+ * function.
+ * @return CURLcode
+ */
 
+CURLcode Curl_open(struct Curl_easy **curl)
+{
+  CURLcode result;
+  struct Curl_easy *data;
 
-  case CURLOPT_RTSP_SESSION_ID:
-    /*
-     * Set the RTSP Session ID manually. Useful if the application is
-     * resuming a previously established RTSP session
-     */
-    result = setstropt(&data->set.str[STRING_RTSP_SESSION_ID],
-                       va_arg(param, char *));
-    break;
+  /* Very 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 */
+    DEBUGF(fprintf(stderr, "Error: calloc of Curl_easy failed\n"));
+    return CURLE_OUT_OF_MEMORY;
+  }
 
-  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 = setstropt(&data->set.str[STRING_RTSP_STREAM_URI],
-                       va_arg(param, char *));
-    break;
+  data->magic = CURLEASY_MAGIC_NUMBER;
 
-  case CURLOPT_RTSP_TRANSPORT:
-    /*
-     * The content of the Transport: header for the RTSP request
-     */
-    result = setstropt(&data->set.str[STRING_RTSP_TRANSPORT],
-                       va_arg(param, char *));
-    break;
+  result = Curl_resolver_init(&data->state.resolver);
+  if(result) {
+    DEBUGF(fprintf(stderr, "Error: resolver_init failed\n"));
+    free(data);
+    return result;
+  }
 
-  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);
-    break;
+  /* We do some initial setup here, all those fields that can't be just 0 */
 
-  case CURLOPT_RTSP_SERVER_CSEQ:
-    /* Same as the above, but for server-initiated requests */
-    data->state.rtsp_next_client_CSeq = va_arg(param, long);
-    break;
+  data->state.buffer = malloc(READBUFFER_SIZE + 1);
+  if(!data->state.buffer) {
+    DEBUGF(fprintf(stderr, "Error: malloc of buffer failed\n"));
+    result = CURLE_OUT_OF_MEMORY;
+  }
+  else {
+    Curl_mime_initpart(&data->set.mimepost, data);
 
-  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;
+    data->state.headerbuff = malloc(HEADERSIZE);
+    if(!data->state.headerbuff) {
+      DEBUGF(fprintf(stderr, "Error: malloc of headerbuff failed\n"));
+      result = CURLE_OUT_OF_MEMORY;
+    }
+    else {
+      result = Curl_init_userdefined(&data->set);
 
-  case CURLOPT_WILDCARDMATCH:
-    data->set.wildcardmatch = (0 != va_arg(param, long)) ? TRUE : FALSE;
-    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->wildcard.customptr = va_arg(param, void *);
-    break;
-  case CURLOPT_FNMATCH_DATA:
-    data->set.fnmatch_data = va_arg(param, void *);
-    break;
-#ifdef USE_TLS_SRP
-  case CURLOPT_TLSAUTH_USERNAME:
-    result = setstropt(&data->set.str[STRING_TLSAUTH_USERNAME_ORIG],
-                       va_arg(param, char *));
-    if(data->set.str[STRING_TLSAUTH_USERNAME_ORIG] && !data->set.ssl.authtype)
-      data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */
-    break;
-  case CURLOPT_PROXY_TLSAUTH_USERNAME:
-    result = setstropt(&data->set.str[STRING_TLSAUTH_USERNAME_PROXY],
-                       va_arg(param, char *));
-    if(data->set.str[STRING_TLSAUTH_USERNAME_PROXY] &&
-       !data->set.proxy_ssl.authtype)
-      data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */
-    break;
-  case CURLOPT_TLSAUTH_PASSWORD:
-    result = setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_ORIG],
-                       va_arg(param, char *));
-    if(data->set.str[STRING_TLSAUTH_USERNAME_ORIG] && !data->set.ssl.authtype)
-      data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */
-    break;
-  case CURLOPT_PROXY_TLSAUTH_PASSWORD:
-    result = setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_PROXY],
-                       va_arg(param, char *));
-    if(data->set.str[STRING_TLSAUTH_USERNAME_PROXY] &&
-       !data->set.proxy_ssl.authtype)
-      data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */
-    break;
-  case CURLOPT_TLSAUTH_TYPE:
-    argptr = va_arg(param, char *);
-    if(!argptr ||
-       strncasecompare(argptr, "SRP", strlen("SRP")))
-      data->set.ssl.authtype = CURL_TLSAUTH_SRP;
-    else
-      data->set.ssl.authtype = CURL_TLSAUTH_NONE;
-    break;
-  case CURLOPT_PROXY_TLSAUTH_TYPE:
-    argptr = va_arg(param, char *);
-    if(!argptr ||
-       strncasecompare(argptr, "SRP", strlen("SRP")))
-      data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP;
-    else
-      data->set.proxy_ssl.authtype = CURL_TLSAUTH_NONE;
-    break;
-#endif
-  case CURLOPT_DNS_SERVERS:
-    result = Curl_set_dns_servers(data, va_arg(param, char *));
-    break;
-  case CURLOPT_DNS_INTERFACE:
-    result = Curl_set_dns_interface(data, va_arg(param, char *));
-    break;
-  case CURLOPT_DNS_LOCAL_IP4:
-    result = Curl_set_dns_local_ip4(data, va_arg(param, char *));
-    break;
-  case CURLOPT_DNS_LOCAL_IP6:
-    result = Curl_set_dns_local_ip6(data, va_arg(param, char *));
-    break;
+      data->state.headersize = HEADERSIZE;
+      Curl_convert_init(data);
+      Curl_initinfo(data);
 
-  case CURLOPT_TCP_KEEPALIVE:
-    data->set.tcp_keepalive = (0 != va_arg(param, long)) ? TRUE : FALSE;
-    break;
-  case CURLOPT_TCP_KEEPIDLE:
-    arg = va_arg(param, long);
-    if(arg < 0)
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    data->set.tcp_keepidle = arg;
-    break;
-  case CURLOPT_TCP_KEEPINTVL:
-    arg = va_arg(param, long);
-    if(arg < 0)
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-    data->set.tcp_keepintvl = arg;
-    break;
-  case CURLOPT_TCP_FASTOPEN:
-#if defined(CONNECT_DATA_IDEMPOTENT) || defined(MSG_FASTOPEN)
-    data->set.tcp_fastopen = (0 != va_arg(param, long))?TRUE:FALSE;
-#else
-    result = CURLE_NOT_BUILT_IN;
-#endif
-    break;
-  case CURLOPT_SSL_ENABLE_NPN:
-    data->set.ssl_enable_npn = (0 != va_arg(param, long)) ? TRUE : FALSE;
-    break;
-  case CURLOPT_SSL_ENABLE_ALPN:
-    data->set.ssl_enable_alpn = (0 != va_arg(param, long)) ? TRUE : FALSE;
-    break;
+      /* most recent connection is not yet defined */
+      data->state.lastconnect = NULL;
 
-#ifdef USE_UNIX_SOCKETS
-  case CURLOPT_UNIX_SOCKET_PATH:
-    data->set.abstract_unix_socket = FALSE;
-    result = 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 = setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH],
-                       va_arg(param, char *));
-    break;
-#endif
+      data->progress.flags |= PGRS_HIDE;
+      data->state.current_speed = -1; /* init to negative == impossible */
+      data->set.fnmatch = ZERO_NULL;
+      data->set.maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */
 
-  case CURLOPT_PATH_AS_IS:
-    data->set.path_as_is = (0 != va_arg(param, long)) ? TRUE : FALSE;
-    break;
-  case CURLOPT_PIPEWAIT:
-    data->set.pipewait = (0 != va_arg(param, long)) ? TRUE : FALSE;
-    break;
-  case CURLOPT_STREAM_WEIGHT:
-#ifndef USE_NGHTTP2
-    return CURLE_NOT_BUILT_IN;
-#else
-    arg = va_arg(param, long);
-    if((arg >= 1) && (arg <= 256))
-      data->set.stream_weight = (int)arg;
-    break;
-#endif
-  case CURLOPT_STREAM_DEPENDS:
-  case CURLOPT_STREAM_DEPENDS_E:
-  {
-#ifndef USE_NGHTTP2
-    return CURLE_NOT_BUILT_IN;
-#else
-    struct Curl_easy *dep = va_arg(param, struct Curl_easy *);
-    if(!dep || GOOD_EASY_HANDLE(dep)) {
-      if(data->set.stream_depends_on) {
-        Curl_http2_remove_child(data->set.stream_depends_on, data);
-      }
-      Curl_http2_add_child(dep, data, (option == CURLOPT_STREAM_DEPENDS_E));
+      Curl_http2_init_state(&data->state);
     }
-    break;
-#endif
   }
-  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))?TRUE:FALSE;
-    break;
-  case CURLOPT_SSH_COMPRESSION:
-    data->set.ssh_compression = (0 != va_arg(param, long))?TRUE:FALSE;
-    break;
-  default:
-    /* unknown tag and its companion, just ignore: */
-    result = CURLE_UNKNOWN_OPTION;
-    break;
+
+  if(result) {
+    Curl_resolver_cleanup(data->state.resolver);
+    free(data->state.buffer);
+    free(data->state.headerbuff);
+    Curl_freeset(data);
+    free(data);
+    data = NULL;
   }
+  else
+    *curl = data;
 
   return result;
 }
@@ -3445,58 +924,6 @@ static void signalPipeClose(struct curl_llist *pipeline, 
bool pipe_broke)
   }
 }
 
-/*
- * This function finds the connection in the connection
- * cache that has been unused for the longest time.
- *
- * Returns the pointer to the oldest idle connection, or NULL if none was
- * found.
- */
-struct connectdata *
-Curl_oldest_idle_connection(struct Curl_easy *data)
-{
-  struct conncache *bc = data->state.conn_cache;
-  struct curl_hash_iterator iter;
-  struct curl_llist_element *curr;
-  struct curl_hash_element *he;
-  time_t highscore =- 1;
-  time_t score;
-  struct curltime now;
-  struct connectdata *conn_candidate = NULL;
-  struct connectbundle *bundle;
-
-  now = Curl_tvnow();
-
-  Curl_hash_start_iterate(&bc->hash, &iter);
-
-  he = Curl_hash_next_element(&iter);
-  while(he) {
-    struct connectdata *conn;
-
-    bundle = he->ptr;
-
-    curr = bundle->conn_list.head;
-    while(curr) {
-      conn = curr->ptr;
-
-      if(!conn->inuse) {
-        /* Set higher score for the age passed since the connection was used */
-        score = Curl_tvdiff(now, conn->now);
-
-        if(score > highscore) {
-          highscore = score;
-          conn_candidate = conn;
-        }
-      }
-      curr = curr->next;
-    }
-
-    he = Curl_hash_next_element(&iter);
-  }
-
-  return conn_candidate;
-}
-
 static bool
 proxy_info_matches(const struct proxy_info* data,
                    const struct proxy_info* needle)
@@ -3522,15 +949,15 @@ find_oldest_idle_connection_in_bundle(struct Curl_easy 
*data,
                                       struct connectbundle *bundle)
 {
   struct curl_llist_element *curr;
-  time_t highscore = -1;
-  time_t score;
+  timediff_t highscore = -1;
+  timediff_t score;
   struct curltime now;
   struct connectdata *conn_candidate = NULL;
   struct connectdata *conn;
 
   (void)data;
 
-  now = Curl_tvnow();
+  now = Curl_now();
 
   curr = bundle->conn_list.head;
   while(curr) {
@@ -3538,7 +965,7 @@ find_oldest_idle_connection_in_bundle(struct Curl_easy 
*data,
 
     if(!conn->inuse) {
       /* Set higher score for the age passed since the connection was used */
-      score = Curl_tvdiff(now, conn->now);
+      score = Curl_timediff(now, conn->now);
 
       if(score > highscore) {
         highscore = score;
@@ -3612,11 +1039,11 @@ static int call_disconnect_if_dead(struct connectdata 
*conn,
  */
 static void prune_dead_connections(struct Curl_easy *data)
 {
-  struct curltime now = Curl_tvnow();
-  time_t elapsed = Curl_tvdiff(now, data->state.conn_cache->last_cleanup);
+  struct curltime now = Curl_now();
+  time_t elapsed = Curl_timediff(now, data->state.conn_cache->last_cleanup);
 
   if(elapsed >= 1000L) {
-    Curl_conncache_foreach(data->state.conn_cache, data,
+    Curl_conncache_foreach(data, data->state.conn_cache, data,
                            call_disconnect_if_dead);
     data->state.conn_cache->last_cleanup = now;
   }
@@ -4260,7 +1687,7 @@ static bool is_ASCII_name(const char *hostname)
 /*
  * Perform any necessary IDN conversion of hostname
  */
-static void fix_hostname(struct connectdata *conn, struct hostname *host)
+static CURLcode fix_hostname(struct connectdata *conn, struct hostname *host)
 {
   size_t len;
   struct Curl_easy *data = conn->data;
@@ -4300,9 +1727,11 @@ static void fix_hostname(struct connectdata *conn, 
struct hostname *host)
         /* change the name pointer to point to the encoded hostname */
         host->name = host->encalloc;
       }
-      else
-        infof(data, "Failed to convert %s to ACE; %s\n", host->name,
+      else {
+        failf(data, "Failed to convert %s to ACE; %s\n", host->name,
               idn2_strerror(rc));
+        return CURLE_URL_MALFORMAT;
+      }
     }
 #elif defined(USE_WIN32_IDN)
     char *ace_hostname = NULL;
@@ -4312,12 +1741,24 @@ static void fix_hostname(struct connectdata *conn, 
struct hostname *host)
       /* change the name pointer to point to the encoded hostname */
       host->name = host->encalloc;
     }
-    else
-      infof(data, "Failed to convert %s to ACE;\n", host->name);
+    else {
+      failf(data, "Failed to convert %s to ACE;\n", host->name);
+      return CURLE_URL_MALFORMAT;
+    }
 #else
     infof(data, "IDN support not present, can't parse Unicode domains\n");
 #endif
   }
+  {
+    char *hostp;
+    for(hostp = host->name; *hostp; hostp++) {
+      if(*hostp <= 32) {
+        failf(data, "Host name '%s' contains bad letter", host->name);
+        return CURLE_URL_MALFORMAT;
+      }
+    }
+  }
+  return CURLE_OK;
 }
 
 /*
@@ -4352,15 +1793,41 @@ static void llist_dtor(void *user, void *element)
  */
 static struct connectdata *allocate_conn(struct Curl_easy *data)
 {
+  struct connectdata *conn;
+  size_t connsize = sizeof(struct connectdata);
+
 #ifdef USE_SSL
-#define SSL_EXTRA + 4 * Curl_ssl->sizeof_ssl_backend_data - sizeof(long long)
-#else
-#define SSL_EXTRA 0
+/* SSLBK_MAX_ALIGN: The max byte alignment a CPU would use */
+#define SSLBK_MAX_ALIGN 32
+  /* The SSL backend-specific data (ssl_backend_data) objects are allocated as
+     part of connectdata at the end. To ensure suitable alignment we will
+     assume a maximum of SSLBK_MAX_ALIGN for alignment. Since calloc returns a
+     pointer suitably aligned for any variable this will ensure the
+     ssl_backend_data array has proper alignment, even if that alignment turns
+     out to be less than SSLBK_MAX_ALIGN. */
+  size_t paddingsize = sizeof(struct connectdata) % SSLBK_MAX_ALIGN;
+  size_t alignsize = paddingsize ? (SSLBK_MAX_ALIGN - paddingsize) : 0;
+  size_t sslbksize = Curl_ssl->sizeof_ssl_backend_data;
+  connsize += alignsize + (4 * sslbksize);
 #endif
-  struct connectdata *conn = calloc(1, sizeof(struct connectdata) + SSL_EXTRA);
+
+  conn = calloc(1, connsize);
   if(!conn)
     return NULL;
 
+#ifdef USE_SSL
+  /* Point to the ssl_backend_data objects at the end of connectdata.
+     Note that these backend pointers can be swapped by vtls (eg ssl backend
+     data becomes proxy backend data). */
+  {
+    char *end = (char *)conn + connsize;
+    conn->ssl[0].backend = ((void *)(end - (4 * sslbksize)));
+    conn->ssl[1].backend = ((void *)(end - (3 * sslbksize)));
+    conn->proxy_ssl[0].backend = ((void *)(end - (2 * sslbksize)));
+    conn->proxy_ssl[1].backend = ((void *)(end - (1 * sslbksize)));
+  }
+#endif
+
   conn->handler = &Curl_handler_dummy;  /* Be sure we have a handler defined
                                            already from start to avoid NULL
                                            situations and checks */
@@ -4385,7 +1852,7 @@ static struct connectdata *allocate_conn(struct Curl_easy 
*data)
   connclose(conn, "Default to force-close");
 
   /* Store creation time to help future close decision making */
-  conn->created = Curl_tvnow();
+  conn->created = Curl_now();
 
   conn->data = data; /* Setup the association between this connection
                         and the Curl_easy */
@@ -4440,23 +1907,6 @@ static struct connectdata *allocate_conn(struct 
Curl_easy *data)
 
   conn->ip_version = data->set.ipver;
 
-#ifdef USE_SSL
-  /*
-   * To save on malloc()s, the SSL backend-specific data has been allocated
-   * at the end of the connectdata struct.
-   */
-  {
-    char *p = (char *)&conn->align_data__do_not_use;
-    conn->ssl[0].backend = (struct ssl_backend_data *)p;
-    conn->ssl[1].backend =
-      (struct ssl_backend_data *)(p + Curl_ssl->sizeof_ssl_backend_data);
-    conn->proxy_ssl[0].backend =
-      (struct ssl_backend_data *)(p + Curl_ssl->sizeof_ssl_backend_data * 2);
-    conn->proxy_ssl[1].backend =
-      (struct ssl_backend_data *)(p + Curl_ssl->sizeof_ssl_backend_data * 3);
-  }
-#endif
-
 #if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \
     defined(NTLM_WB_ENABLED)
   conn->ntlm_auth_hlpr_socket = CURL_SOCKET_BAD;
@@ -4598,6 +2048,14 @@ static CURLcode parseurlandfillconn(struct Curl_easy 
*data,
     ('A' <= str[0] && str[0] <= 'Z')) && \
    (str[1] == ':'))
 
+  /* MSDOS/Windows style drive prefix, optionally with
+   * a '|' instead of ':', followed by a slash or NUL */
+#define STARTS_WITH_URL_DRIVE_PREFIX(str) \
+  ((('a' <= (str)[0] && (str)[0] <= 'z') || \
+    ('A' <= (str)[0] && (str)[0] <= 'Z')) && \
+   ((str)[1] == ':' || (str)[1] == '|') && \
+   ((str)[2] == '/' || (str)[2] == 0))
+
   /* Don't mistake a drive letter for a scheme if the default protocol is file.
      curld --proto-default file c:/foo/bar.txt */
   if(STARTS_WITH_DRIVE_PREFIX(data->change.url) &&
@@ -4630,63 +2088,90 @@ static CURLcode parseurlandfillconn(struct Curl_easy 
*data,
       return CURLE_URL_MALFORMAT;
     }
 
-    if(url_has_scheme && path[0] == '/' && path[1] == '/') {
-      /* Allow omitted hostname (e.g. file:/<path>).  This is not strictly
-       * speaking a valid file: URL by RFC 1738, but treating file:/<path> as
-       * file://localhost/<path> is similar to how other schemes treat missing
-       * hostnames.  See RFC 1808. */
-
-      /* This cannot be done with strcpy() in a portable manner, since the
-         memory areas overlap! */
-      memmove(path, path + 2, strlen(path + 2) + 1);
+    if(url_has_scheme && path[0] == '/' && path[1] == '/' &&
+       path[2] == '/' && path[3] == '/') {
+      /* This appears to be a UNC string (usually indicating a SMB share).
+       * We don't do SMB in file: URLs. (TODO?)
+       */
+      failf(data, "SMB shares are not supported in file: URLs.");
+      return CURLE_URL_MALFORMAT;
     }
 
-    /*
-     * we deal with file://<host>/<path> differently since it supports no
-     * hostname other than "localhost" and "127.0.0.1", which is unique among
-     * the URL protocols specified in RFC 1738
+    /* Extra handling URLs with an authority component (i.e. that start with
+     * "file://")
+     *
+     * We allow omitted hostname (e.g. file:/<path>) -- valid according to
+     * RFC 8089, but not the (current) WHAT-WG URL spec.
      */
-    if(path[0] != '/' && !STARTS_WITH_DRIVE_PREFIX(path)) {
-      /* the URL includes a host name, it must match "localhost" or
-         "127.0.0.1" to be valid */
-      char *ptr;
-      if(!checkprefix("localhost/", path) &&
-         !checkprefix("127.0.0.1/", path)) {
-        failf(data, "Invalid file://hostname/, "
-                    "expected localhost or 127.0.0.1 or none");
-        return CURLE_URL_MALFORMAT;
-      }
-      ptr = &path[9]; /* now points to the slash after the host */
-
-      /* there was a host name and slash present
-
-         RFC1738 (section 3.1, page 5) says:
-
-         The rest of the locator consists of data specific to the scheme,
-         and is known as the "url-path". It supplies the details of how the
-         specified resource can be accessed. Note that the "/" between the
-         host (or port) and the url-path is NOT part of the url-path.
+    if(url_has_scheme && path[0] == '/' && path[1] == '/') {
+      /* swallow the two slashes */
+      char *ptr = &path[2];
 
-         As most agents use file://localhost/foo to get '/foo' although the
-         slash preceding foo is a separator and not a slash for the path,
-         a URL as file://localhost//foo must be valid as well, to refer to
-         the same file with an absolute path.
-      */
+      /*
+       * According to RFC 8089, a file: URL can be reliably dereferenced if:
+       *
+       *  o it has no/blank hostname, or
+       *
+       *  o the hostname matches "localhost" (case-insensitively), or
+       *
+       *  o the hostname is a FQDN that resolves to this machine.
+       *
+       * For brevity, we only consider URLs with empty, "localhost", or
+       * "127.0.0.1" hostnames as local.
+       *
+       * Additionally, there is an exception for URLs with a Windows drive
+       * letter in the authority (which was accidentally omitted from RFC 8089
+       * Appendix E, but believe me, it was meant to be there. --MK)
+       */
+      if(ptr[0] != '/' && !STARTS_WITH_URL_DRIVE_PREFIX(ptr)) {
+        /* the URL includes a host name, it must match "localhost" or
+           "127.0.0.1" to be valid */
+        if(!checkprefix("localhost/", ptr) &&
+           !checkprefix("127.0.0.1/", ptr)) {
+          failf(data, "Invalid file://hostname/, "
+                      "expected localhost or 127.0.0.1 or none");
+          return CURLE_URL_MALFORMAT;
+        }
+        ptr += 9; /* now points to the slash after the host */
+      }
 
-      if('/' == ptr[1])
-        /* if there was two slashes, we skip the first one as that is then
-           used truly as a separator */
+      /*
+       * RFC 8089, Appendix D, Section D.1, says:
+       *
+       * > In a POSIX file system, the root of the file system is represented
+       * > as a directory with a zero-length name, usually written as "/"; the
+       * > presence of this root in a file URI can be taken as given by the
+       * > initial slash in the "path-absolute" rule.
+       *
+       * i.e. the first slash is part of the path.
+       *
+       * However in RFC 1738 the "/" between the host (or port) and the
+       * URL-path was NOT part of the URL-path.  Any agent that followed the
+       * older spec strictly, and wanted to refer to a file with an absolute
+       * path, would have included a second slash.  So if there are two
+       * slashes, swallow one.
+       */
+      if('/' == ptr[1]) /* note: the only way ptr[0]!='/' is if ptr[1]==':' */
         ptr++;
 
-      /* This cannot be made with strcpy, as the memory chunks overlap! */
+      /* This cannot be done with strcpy, as the memory chunks overlap! */
       memmove(path, ptr, strlen(ptr) + 1);
     }
 
 #if !defined(MSDOS) && !defined(WIN32) && !defined(__CYGWIN__)
-    if(STARTS_WITH_DRIVE_PREFIX(path)) {
+    /* Don't allow Windows drive letters when not in Windows.
+     * This catches both "file:/c:" and "file:c:" */
+    if(('/' == path[0] && STARTS_WITH_URL_DRIVE_PREFIX(&path[1])) ||
+       STARTS_WITH_URL_DRIVE_PREFIX(path)) {
       failf(data, "File drive letters are only accepted in MSDOS/Windows.");
       return CURLE_URL_MALFORMAT;
     }
+#else
+    /* If the path starts with a slash and a drive letter, ditch the slash */
+    if('/' == path[0] && STARTS_WITH_URL_DRIVE_PREFIX(&path[1])) {
+      /* This cannot be done with strcpy, as the memory chunks overlap! */
+      memmove(path, &path[1], strlen(&path[1]) + 1);
+    }
 #endif
 
     protop = "file"; /* protocol string */
@@ -5298,8 +2783,8 @@ static CURLcode parse_proxy(struct Curl_easy *data,
   atsign = strchr(proxyptr, '@');
   if(atsign) {
     CURLcode result =
-      parse_login_details(proxyptr, atsign - proxyptr,
-                              &proxyuser, &proxypasswd, NULL);
+      Curl_parse_login_details(proxyptr, atsign - proxyptr,
+                               &proxyuser, &proxypasswd, NULL);
     if(result)
       return result;
     proxyptr = atsign + 1;
@@ -5690,10 +3175,11 @@ static CURLcode parse_url_login(struct Curl_easy *data,
 
   /* We could use the login information in the URL so extract it. Only parse
      options if the handler says we should. */
-  result = parse_login_details(login, ptr - login - 1,
-                               &userp, &passwdp,
-                               (conn->handler->flags & PROTOPT_URLOPTIONS)?
-                               &optionsp:NULL);
+  result =
+    Curl_parse_login_details(login, ptr - login - 1,
+                             &userp, &passwdp,
+                             (conn->handler->flags & PROTOPT_URLOPTIONS)?
+                             &optionsp:NULL);
   if(result)
     goto out;
 
@@ -5749,7 +3235,7 @@ static CURLcode parse_url_login(struct Curl_easy *data,
 }
 
 /*
- * parse_login_details()
+ * Curl_parse_login_details()
  *
  * This is used to parse a login string for user name, password and options in
  * the following formats:
@@ -5777,9 +3263,9 @@ static CURLcode parse_url_login(struct Curl_easy *data,
  *
  * Returns CURLE_OK on success.
  */
-static CURLcode parse_login_details(const char *login, const size_t len,
-                                    char **userp, char **passwdp,
-                                    char **optionsp)
+CURLcode Curl_parse_login_details(const char *login, const size_t len,
+                                  char **userp, char **passwdp,
+                                  char **optionsp)
 {
   CURLcode result = CURLE_OK;
   char *ubuf = NULL;
@@ -5908,7 +3394,13 @@ static CURLcode parse_remote_port(struct Curl_easy *data,
     portptr = strchr(conn->host.name, ']');
     if(portptr) {
       *portptr++ = '\0'; /* zero terminate, killing the bracket */
-      if(':' != *portptr)
+      if(*portptr) {
+        if (*portptr != ':') {
+          failf(data, "IPv6 closing bracket followed by '%c'", *portptr);
+          return CURLE_URL_MALFORMAT;
+        }
+      }
+      else
         portptr = NULL; /* no port number available */
     }
   }
@@ -6327,7 +3819,7 @@ static CURLcode resolve_server(struct Curl_easy *data,
                                bool *async)
 {
   CURLcode result = CURLE_OK;
-  time_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
+  timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
 
   /*************************************************************
    * Resolve the name of the server or proxy
@@ -6744,13 +4236,24 @@ static CURLcode create_conn(struct Curl_easy *data,
   /*************************************************************
    * IDN-fix the hostnames
    *************************************************************/
-  fix_hostname(conn, &conn->host);
-  if(conn->bits.conn_to_host)
-    fix_hostname(conn, &conn->conn_to_host);
-  if(conn->bits.httpproxy)
-    fix_hostname(conn, &conn->http_proxy.host);
-  if(conn->bits.socksproxy)
-    fix_hostname(conn, &conn->socks_proxy.host);
+  result = fix_hostname(conn, &conn->host);
+  if(result)
+    goto out;
+  if(conn->bits.conn_to_host) {
+    result = fix_hostname(conn, &conn->conn_to_host);
+    if(result)
+      goto out;
+  }
+  if(conn->bits.httpproxy) {
+    result = fix_hostname(conn, &conn->http_proxy.host);
+    if(result)
+      goto out;
+  }
+  if(conn->bits.socksproxy) {
+    result = fix_hostname(conn, &conn->socks_proxy.host);
+    if(result)
+      goto out;
+  }
 
   /*************************************************************
    * Check whether the host and the "connect to host" are equal.
@@ -6993,7 +4496,7 @@ static CURLcode create_conn(struct Curl_easy *data,
       struct connectdata *conn_candidate;
 
       /* The cache is full. Let's see if we can kill a connection. */
-      conn_candidate = Curl_oldest_idle_connection(data);
+      conn_candidate = Curl_conncache_oldest_idle(data);
 
       if(conn_candidate) {
         /* Set the connection's owner correctly, then kill it */
@@ -7128,7 +4631,7 @@ CURLcode Curl_setup_conn(struct connectdata *conn,
 
   /* set start time here for timeout purposes in the connect procedure, it
      is later set again for the progress meter purpose */
-  conn->now = Curl_tvnow();
+  conn->now = Curl_now();
 
   if(CURL_SOCKET_BAD == conn->sock[FIRSTSOCKET]) {
     conn->bits.tcpconnect[FIRSTSOCKET] = FALSE;
@@ -7145,7 +4648,7 @@ CURLcode Curl_setup_conn(struct connectdata *conn,
     Curl_verboseconnect(conn);
   }
 
-  conn->now = Curl_tvnow(); /* time this *after* the connect is done, we
+  conn->now = Curl_now(); /* time this *after* the connect is done, we
                                set this here perhaps a second time */
 
 #ifdef __EMX__
@@ -7218,13 +4721,17 @@ CURLcode Curl_init_do(struct Curl_easy *data, struct 
connectdata *conn)
 {
   struct SingleRequest *k = &data->req;
 
-  if(conn)
-    conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to
-                                 * use */
+  conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to
+                                 use */
 
   data->state.done = FALSE; /* *_done() is not called yet */
   data->state.expect100header = FALSE;
 
+  /* if the protocol used doesn't support wildcards, switch it off */
+  if(data->state.wildcardmatch &&
+     !(conn->handler->flags & PROTOPT_WILDCARD))
+    data->state.wildcardmatch = FALSE;
+
   if(data->set.opt_no_body)
     /* in HTTP lingo, no body means using the HEAD request... */
     data->set.httpreq = HTTPREQ_HEAD;
@@ -7236,7 +4743,7 @@ CURLcode Curl_init_do(struct Curl_easy *data, struct 
connectdata *conn)
        HTTP. */
     data->set.httpreq = HTTPREQ_GET;
 
-  k->start = Curl_tvnow(); /* start time */
+  k->start = Curl_now(); /* start time */
   k->now = k->start;   /* current time is now */
   k->header = TRUE; /* assume header */
 
diff --git a/lib/url.h b/lib/url.h
index f13c8e664..5dd04fdff 100644
--- a/lib/url.h
+++ b/lib/url.h
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <address@hidden>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <address@hidden>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -23,6 +23,10 @@
  ***************************************************************************/
 #include "curl_setup.h"
 
+#define READBUFFER_SIZE CURL_MAX_WRITE_SIZE
+#define READBUFFER_MAX  CURL_MAX_READ_SIZE
+#define READBUFFER_MIN  1024
+
 /*
  * Prototypes for library-wide functions provided by url.c
  */
@@ -51,14 +55,14 @@ int Curl_protocol_getsock(struct connectdata *conn,
 int Curl_doing_getsock(struct connectdata *conn,
                        curl_socket_t *socks,
                        int numsocks);
-
+CURLcode Curl_parse_login_details(const char *login, const size_t len,
+                                  char **userptr, char **passwdptr,
+                                  char **optionsptr);
 bool Curl_isPipeliningEnabled(const struct Curl_easy *handle);
 CURLcode Curl_addHandleToPipeline(struct Curl_easy *handle,
                                   struct curl_llist *pipeline);
 int Curl_removeHandleFromPipeline(struct Curl_easy *handle,
                                   struct curl_llist *pipeline);
-struct connectdata *
-Curl_oldest_idle_connection(struct Curl_easy *data);
 /* remove the specified connection from all (possible) pipelines and related
    queues */
 void Curl_getoff_all_pipelines(struct Curl_easy *data,
diff --git a/lib/urldata.h b/lib/urldata.h
index fc9549608..f008dd44e 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -88,14 +88,6 @@
 
 #include "timeval.h"
 
-#ifdef HAVE_ZLIB_H
-#include <zlib.h>               /* for content-encoding */
-#ifdef __SYMBIAN32__
-/* zlib pollutes the namespace with this definition */
-#undef WIN32
-#endif
-#endif
-
 #include <gnurl/curl.h>
 
 #include "http_chunks.h" /* for the structs and enum stuff */
@@ -287,6 +279,7 @@ struct digestdata {
   char *qop;
   char *algorithm;
   int nc; /* nounce count */
+  bool userhash;
 #endif
 };
 
@@ -464,16 +457,6 @@ struct hostname {
 #define KEEP_SENDBITS (KEEP_SEND | KEEP_SEND_HOLD | KEEP_SEND_PAUSE)
 
 
-#ifdef HAVE_LIBZ
-typedef enum {
-  ZLIB_UNINIT,          /* uninitialized */
-  ZLIB_INIT,            /* initialized */
-  ZLIB_GZIP_HEADER,     /* reading gzip header */
-  ZLIB_GZIP_INFLATING,  /* inflating gzip stream */
-  ZLIB_INIT_GZIP        /* initialized in transparent gzip mode */
-} zlibInitState;
-#endif
-
 #ifdef CURLRES_ASYNCH
 struct Curl_async {
   char *hostname;
@@ -561,18 +544,8 @@ struct SingleRequest {
   enum expect100 exp100;        /* expect 100 continue state */
   enum upgrade101 upgr101;      /* 101 upgrade state */
 
-  int auto_decoding;            /* What content encoding. sec 3.5, RFC2616. */
-
-#define IDENTITY 0              /* No encoding */
-#define DEFLATE 1               /* zlib deflate [RFC 1950 & 1951] */
-#define GZIP 2                  /* gzip algorithm [RFC 1952] */
-
-#ifdef HAVE_LIBZ
-  zlibInitState zlib_init;      /* possible zlib init state;
-                                   undefined if Content-Encoding header. */
-  z_stream z;                   /* State structure for zlib. */
-#endif
-
+  struct contenc_writer_s *writer_stack;  /* Content unencoding stack. */
+                                          /* See sec 3.5, RFC2616. */
   time_t timeofdoc;
   long bodywrites;
 
@@ -720,6 +693,7 @@ struct Curl_handler {
 #define PROTOPT_PROXY_AS_HTTP (1<<11) /* allow this non-HTTP scheme over a
                                          HTTP proxy as HTTP proxies may know
                                          this protocol and act as a gateway */
+#define PROTOPT_WILDCARD (1<<12) /* protocol supports wildcard matching */
 
 #define CONNCHECK_NONE 0                 /* No checks */
 #define CONNCHECK_ISDEAD (1<<0)          /* Check if the connection is dead. */
@@ -1031,16 +1005,6 @@ struct connectdata {
   char *unix_domain_socket;
   bool abstract_unix_socket;
 #endif
-
-#ifdef USE_SSL
-  /*
-   * To avoid multiple malloc() calls, the ssl_connect_data structures
-   * associated with a connectdata struct are allocated in the same block
-   * as the latter. This field forces alignment to an 8-byte boundary so
-   * that this all works.
-   */
-  long long *align_data__do_not_use;
-#endif
 };
 
 /* The end of connectdata. */
@@ -1309,7 +1273,7 @@ struct UrlState {
 
   /* set after initial USER failure, to prevent an authentication loop */
   bool ftp_trying_alternative;
-
+  bool wildcardmatch; /* enable wildcard matching */
   int httpversion;       /* the lowest HTTP version*10 reported by any server
                             involved in this request */
   bool expect100header;  /* TRUE if we added Expect: 100-continue */
@@ -1673,7 +1637,7 @@ struct UserDefined {
   /* Common RTSP header options */
   Curl_RtspReq rtspreq; /* RTSP request type */
   long rtspversion; /* like httpversion, for RTSP */
-  bool wildcardmatch; /* enable wildcard matching */
+  bool wildcard_enabled; /* enable wildcard matching */
   curl_chunk_bgn_callback chunk_bgn; /* called before part of transfer
                                         starts */
   curl_chunk_end_callback chunk_end; /* called after part transferring
diff --git a/lib/vauth/digest.c b/lib/vauth/digest.c
index 0ae736c83..8174cc8fe 100644
--- a/lib/vauth/digest.c
+++ b/lib/vauth/digest.c
@@ -19,6 +19,7 @@
  * KIND, either express or implied.
  *
  * RFC2831 DIGEST-MD5 authentication
+ * RFC7616 DIGEST-SHA256, DIGEST-SHA512-256 authentication
  *
  ***************************************************************************/
 
@@ -34,6 +35,7 @@
 #include "curl_base64.h"
 #include "curl_hmac.h"
 #include "curl_md5.h"
+#include "curl_sha256.h"
 #include "vtls/vtls.h"
 #include "warnless.h"
 #include "strtok.h"
@@ -144,6 +146,15 @@ static void auth_digest_md5_to_ascii(unsigned char 
*source, /* 16 bytes */
     snprintf((char *) &dest[i * 2], 3, "%02x", source[i]);
 }
 
+/* Convert sha256 chunk to RFC7616 -suitable ascii string*/
+static void auth_digest_sha256_to_ascii(unsigned char *source, /* 32 bytes */
+                                     unsigned char *dest) /* 65 bytes */
+{
+  int i;
+  for(i = 0; i < 32; i++)
+    snprintf((char *) &dest[i * 2], 3, "%02x", source[i]);
+}
+
 /* Perform quoted-string escaping as described in RFC2616 and its errata */
 static char *auth_digest_string_quoted(const char *source)
 {
@@ -602,9 +613,22 @@ CURLcode Curl_auth_decode_digest_http_message(const char 
*chlg,
           digest->algo = CURLDIGESTALGO_MD5SESS;
         else if(strcasecompare(content, "MD5"))
           digest->algo = CURLDIGESTALGO_MD5;
+        else if(strcasecompare(content, "SHA-256"))
+          digest->algo = CURLDIGESTALGO_SHA256;
+        else if(strcasecompare(content, "SHA-256-SESS"))
+          digest->algo = CURLDIGESTALGO_SHA256SESS;
+        else if(strcasecompare(content, "SHA-512-256"))
+          digest->algo = CURLDIGESTALGO_SHA512_256;
+        else if(strcasecompare(content, "SHA-512-256-SESS"))
+          digest->algo = CURLDIGESTALGO_SHA512_256SESS;
         else
           return CURLE_BAD_CONTENT_ENCODING;
       }
+      else if(strcasecompare(value, "userhash")) {
+        if(strcasecompare(content, "true")) {
+          digest->userhash = TRUE;
+        }
+      }
       else {
         /* Unknown specifier, ignore it! */
       }
@@ -635,7 +659,7 @@ CURLcode Curl_auth_decode_digest_http_message(const char 
*chlg,
 }
 
 /*
- * Curl_auth_create_digest_http_message()
+ * _Curl_auth_create_digest_http_message()
  *
  * This is used to generate a HTTP DIGEST response message ready for sending
  * to the recipient.
@@ -654,20 +678,24 @@ CURLcode Curl_auth_decode_digest_http_message(const char 
*chlg,
  *
  * Returns CURLE_OK on success.
  */
-CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
-                                              const char *userp,
-                                              const char *passwdp,
-                                              const unsigned char *request,
-                                              const unsigned char *uripath,
-                                              struct digestdata *digest,
-                                              char **outptr, size_t *outlen)
+static CURLcode _Curl_auth_create_digest_http_message(
+                  struct Curl_easy *data,
+                  const char *userp,
+                  const char *passwdp,
+                  const unsigned char *request,
+                  const unsigned char *uripath,
+                  struct digestdata *digest,
+                  char **outptr, size_t *outlen,
+                  void (*convert_to_ascii)(unsigned char *, unsigned char *),
+                  void (*hash)(unsigned char *, const unsigned char *))
 {
   CURLcode result;
-  unsigned char md5buf[16]; /* 16 bytes/128 bits */
-  unsigned char request_digest[33];
-  unsigned char *md5this;
-  unsigned char ha1[33];    /* 32 digits and 1 zero byte */
-  unsigned char ha2[33];    /* 32 digits and 1 zero byte */
+  unsigned char hashbuf[32]; /* 32 bytes/256 bits */
+  unsigned char request_digest[65];
+  unsigned char *hashthis;
+  unsigned char ha1[65];    /* 64 digits and 1 zero byte */
+  unsigned char ha2[65];    /* 64 digits and 1 zero byte */
+  char userh[65];
   char cnoncebuf[33];
   char *cnonce = NULL;
   size_t cnonce_sz = 0;
@@ -692,6 +720,17 @@ CURLcode Curl_auth_create_digest_http_message(struct 
Curl_easy *data,
     digest->cnonce = cnonce;
   }
 
+  if(digest->userhash) {
+    hashthis = (unsigned char *) aprintf("%s:%s", userp, digest->realm);
+    if(!hashthis)
+      return CURLE_OUT_OF_MEMORY;
+
+    CURL_OUTPUT_DIGEST_CONV(data, hashthis);
+    hash(hashbuf, hashthis);
+    free(hashthis);
+    convert_to_ascii(hashbuf, (unsigned char *)userh);
+  }
+
   /*
     If the algorithm is "MD5" or unspecified (which then defaults to MD5):
 
@@ -703,26 +742,29 @@ CURLcode Curl_auth_create_digest_http_message(struct 
Curl_easy *data,
            unq(nonce-value) ":" unq(cnonce-value)
   */
 
-  md5this = (unsigned char *)
-    aprintf("%s:%s:%s", userp, digest->realm, passwdp);
-  if(!md5this)
+  hashthis = (unsigned char *)
+    aprintf("%s:%s:%s", digest->userhash ? userh : userp,
+                                    digest->realm, passwdp);
+  if(!hashthis)
     return CURLE_OUT_OF_MEMORY;
 
-  CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */
-  Curl_md5it(md5buf, md5this);
-  free(md5this);
-  auth_digest_md5_to_ascii(md5buf, ha1);
+  CURL_OUTPUT_DIGEST_CONV(data, hashthis); /* convert on non-ASCII machines */
+  hash(hashbuf, hashthis);
+  free(hashthis);
+  convert_to_ascii(hashbuf, ha1);
 
-  if(digest->algo == CURLDIGESTALGO_MD5SESS) {
+  if(digest->algo == CURLDIGESTALGO_MD5SESS ||
+     digest->algo == CURLDIGESTALGO_SHA256SESS ||
+     digest->algo == CURLDIGESTALGO_SHA512_256SESS) {
     /* nonce and cnonce are OUTSIDE the hash */
     tmp = aprintf("%s:%s:%s", ha1, digest->nonce, digest->cnonce);
     if(!tmp)
       return CURLE_OUT_OF_MEMORY;
 
     CURL_OUTPUT_DIGEST_CONV(data, tmp); /* Convert on non-ASCII machines */
-    Curl_md5it(md5buf, (unsigned char *) tmp);
+    hash(hashbuf, (unsigned char *) tmp);
     free(tmp);
-    auth_digest_md5_to_ascii(md5buf, ha1);
+    convert_to_ascii(hashbuf, ha1);
   }
 
   /*
@@ -738,27 +780,32 @@ CURLcode Curl_auth_create_digest_http_message(struct 
Curl_easy *data,
     5.1.1 of RFC 2616)
   */
 
-  md5this = (unsigned char *) aprintf("%s:%s", request, uripath);
+  hashthis = (unsigned char *) aprintf("%s:%s", request, uripath);
 
   if(digest->qop && strcasecompare(digest->qop, "auth-int")) {
     /* We don't support auth-int for PUT or POST at the moment.
-       TODO: replace md5 of empty string with entity-body for PUT/POST */
-    unsigned char *md5this2 = (unsigned char *)
-      aprintf("%s:%s", md5this, "d41d8cd98f00b204e9800998ecf8427e");
-    free(md5this);
-    md5this = md5this2;
+       TODO: replace hash of empty string with entity-body for PUT/POST */
+    char hashed[65];
+    unsigned char *hashthis2;
+
+    hash(hashbuf, (const unsigned char *)"");
+    convert_to_ascii(hashbuf, (unsigned char *)hashed);
+
+    hashthis2 = (unsigned char *)aprintf("%s:%s", hashthis, hashed);
+    free(hashthis);
+    hashthis = hashthis2;
   }
 
-  if(!md5this)
+  if(!hashthis)
     return CURLE_OUT_OF_MEMORY;
 
-  CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */
-  Curl_md5it(md5buf, md5this);
-  free(md5this);
-  auth_digest_md5_to_ascii(md5buf, ha2);
+  CURL_OUTPUT_DIGEST_CONV(data, hashthis); /* convert on non-ASCII machines */
+  hash(hashbuf, hashthis);
+  free(hashthis);
+  convert_to_ascii(hashbuf, ha2);
 
   if(digest->qop) {
-    md5this = (unsigned char *) aprintf("%s:%s:%08x:%s:%s:%s",
+    hashthis = (unsigned char *) aprintf("%s:%s:%08x:%s:%s:%s",
                                         ha1,
                                         digest->nonce,
                                         digest->nc,
@@ -767,19 +814,19 @@ CURLcode Curl_auth_create_digest_http_message(struct 
Curl_easy *data,
                                         ha2);
   }
   else {
-    md5this = (unsigned char *) aprintf("%s:%s:%s",
+    hashthis = (unsigned char *) aprintf("%s:%s:%s",
                                         ha1,
                                         digest->nonce,
                                         ha2);
   }
 
-  if(!md5this)
+  if(!hashthis)
     return CURLE_OUT_OF_MEMORY;
 
-  CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */
-  Curl_md5it(md5buf, md5this);
-  free(md5this);
-  auth_digest_md5_to_ascii(md5buf, request_digest);
+  CURL_OUTPUT_DIGEST_CONV(data, hashthis); /* convert on non-ASCII machines */
+  hash(hashbuf, hashthis);
+  free(hashthis);
+  convert_to_ascii(hashbuf, request_digest);
 
   /* For test case 64 (snooped from a Mozilla 1.3a request)
 
@@ -794,7 +841,7 @@ CURLcode Curl_auth_create_digest_http_message(struct 
Curl_easy *data,
      characters.  algorithm and qop with standard values only contain web-safe
      characters.
   */
-  userp_quoted = auth_digest_string_quoted(userp);
+  userp_quoted = auth_digest_string_quoted(digest->userhash ? userh : userp);
   if(!userp_quoted)
     return CURLE_OUT_OF_MEMORY;
 
@@ -858,6 +905,16 @@ CURLcode Curl_auth_create_digest_http_message(struct 
Curl_easy *data,
     response = tmp;
   }
 
+  if(digest->userhash) {
+    /* Append the userhash */
+    tmp = aprintf("%s, userhash=true", response);
+    free(response);
+    if(!tmp)
+      return CURLE_OUT_OF_MEMORY;
+
+    response = tmp;
+  }
+
   /* Return the output */
   *outptr = response;
   *outlen = strlen(response);
@@ -866,6 +923,58 @@ CURLcode Curl_auth_create_digest_http_message(struct 
Curl_easy *data,
 }
 
 /*
+ * Curl_auth_create_digest_http_message()
+ *
+ * This is used to generate a HTTP DIGEST response message ready for sending
+ * to the recipient.
+ *
+ * Parameters:
+ *
+ * data    [in]     - The session handle.
+ * userp   [in]     - The user name.
+ * passdwp [in]     - The user's password.
+ * request [in]     - The HTTP request.
+ * uripath [in]     - The path of the HTTP uri.
+ * digest  [in/out] - The digest data struct being used and modified.
+ * outptr  [in/out] - The address where a pointer to newly allocated memory
+ *                    holding the result will be stored upon completion.
+ * outlen  [out]    - The length of the output message.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
+                                              const char *userp,
+                                              const char *passwdp,
+                                              const unsigned char *request,
+                                              const unsigned char *uripath,
+                                              struct digestdata *digest,
+                                              char **outptr, size_t *outlen)
+{
+  switch(digest->algo) {
+  case CURLDIGESTALGO_MD5:
+  case CURLDIGESTALGO_MD5SESS:
+    return _Curl_auth_create_digest_http_message(data, userp, passwdp,
+                                                 request, uripath, digest,
+                                                 outptr, outlen,
+                                                 auth_digest_md5_to_ascii,
+                                                 Curl_md5it);
+
+  case CURLDIGESTALGO_SHA256:
+  case CURLDIGESTALGO_SHA256SESS:
+  case CURLDIGESTALGO_SHA512_256:
+  case CURLDIGESTALGO_SHA512_256SESS:
+    return _Curl_auth_create_digest_http_message(data, userp, passwdp,
+                                                 request, uripath, digest,
+                                                 outptr, outlen,
+                                                 auth_digest_sha256_to_ascii,
+                                                 Curl_sha256it);
+
+  default:
+    return CURLE_UNSUPPORTED_PROTOCOL;
+  }
+}
+
+/*
  * Curl_auth_digest_cleanup()
  *
  * This is used to clean up the digest specific data.
@@ -887,6 +996,7 @@ void Curl_auth_digest_cleanup(struct digestdata *digest)
   digest->nc = 0;
   digest->algo = CURLDIGESTALGO_MD5; /* default algorithm */
   digest->stale = FALSE; /* default means normal, not stale */
+  digest->userhash = FALSE;
 }
 #endif  /* !USE_WINDOWS_SSPI */
 
diff --git a/lib/vauth/digest.h b/lib/vauth/digest.h
index d0ea27778..cb544da9b 100644
--- a/lib/vauth/digest.h
+++ b/lib/vauth/digest.h
@@ -31,7 +31,11 @@
 
 enum {
   CURLDIGESTALGO_MD5,
-  CURLDIGESTALGO_MD5SESS
+  CURLDIGESTALGO_MD5SESS,
+  CURLDIGESTALGO_SHA256,
+  CURLDIGESTALGO_SHA256SESS,
+  CURLDIGESTALGO_SHA512_256,
+  CURLDIGESTALGO_SHA512_256SESS
 };
 
 /* This is used to extract the realm from a challenge message */
diff --git a/lib/vauth/ntlm.c b/lib/vauth/ntlm.c
index 50d922208..1e0d4792e 100644
--- a/lib/vauth/ntlm.c
+++ b/lib/vauth/ntlm.c
@@ -543,8 +543,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct 
Curl_easy *data,
   else
     user = userp;
 
-  if(user)
-    userlen = strlen(user);
+  userlen = strlen(user);
 
   /* Get the machine's un-qualified host name as NTLM doesn't like the fully
      qualified domain name */
diff --git a/lib/version.c b/lib/version.c
index 33e5fee3c..f14d80b18 100644
--- a/lib/version.c
+++ b/lib/version.c
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <address@hidden>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <address@hidden>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -64,6 +64,18 @@
 #define CURL_LIBSSH2_VERSION LIBSSH2_VERSION
 #endif
 
+#ifdef HAVE_ZLIB_H
+#include <zlib.h>
+#ifdef __SYMBIAN32__
+/* zlib pollutes the namespace with this definition */
+#undef WIN32
+#endif
+#endif
+
+#ifdef HAVE_BROTLI
+#include <brotli/decode.h>
+#endif
+
 void Curl_version_init(void);
 
 /* For thread safety purposes this function is called by global_init so that
@@ -74,6 +86,18 @@ void Curl_version_init(void)
   curl_version_info(CURLVERSION_NOW);
 }
 
+#ifdef HAVE_BROTLI
+static size_t brotli_version(char *buf, size_t bufsz)
+{
+  uint32_t brotli_version = BrotliDecoderVersion();
+  unsigned int major = brotli_version >> 24;
+  unsigned int minor = (brotli_version & 0x00FFFFFF) >> 12;
+  unsigned int patch = brotli_version & 0x00000FFF;
+
+  return snprintf(buf, bufsz, "%u.%u.%u", major, minor, patch);
+}
+#endif
+
 char *curl_version(void)
 {
   static bool initialized;
@@ -105,6 +129,14 @@ char *curl_version(void)
   left -= len;
   ptr += len;
 #endif
+#ifdef HAVE_BROTLI
+  len = snprintf(ptr, left, "%s", " brotli/");
+  left -= len;
+  ptr += len;
+  len = brotli_version(ptr, left);
+  left -= len;
+  ptr += len;
+#endif
 #ifdef USE_ARES
   /* this function is only present in c-ares, not in the original ares */
   len = snprintf(ptr, left, " c-ares/%s", ares_version(NULL));
@@ -327,6 +359,9 @@ static curl_version_info_data version_info = {
 #if defined(CURL_WITH_MULTI_SSL)
   | CURL_VERSION_MULTI_SSL
 #endif
+#if defined(HAVE_BROTLI)
+  | CURL_VERSION_BROTLI
+#endif
   ,
   NULL, /* ssl_version */
   0,    /* ssl_version_num, this is kept at zero */
@@ -337,6 +372,8 @@ static curl_version_info_data version_info = {
   NULL, /* libidn version */
   0,    /* iconv version */
   NULL, /* ssh lib version */
+  0,    /* brotli_ver_num */
+  NULL, /* brotli version */
 };
 
 curl_version_info_data *curl_version_info(CURLversion stamp)
@@ -348,6 +385,9 @@ curl_version_info_data *curl_version_info(CURLversion stamp)
 #ifdef USE_SSL
   static char ssl_buffer[80];
 #endif
+#ifdef HAVE_BROTLI
+  static char brotli_buffer[80];
+#endif
 
   if(initialized)
     return &version_info;
@@ -396,6 +436,12 @@ curl_version_info_data *curl_version_info(CURLversion 
stamp)
   version_info.libssh_version = ssh_buffer;
 #endif
 
+#ifdef HAVE_BROTLI
+  version_info.brotli_ver_num = BrotliDecoderVersion();
+  brotli_version(brotli_buffer, sizeof brotli_buffer);
+  version_info.brotli_version = brotli_buffer;
+#endif
+
   (void)stamp; /* avoid compiler warnings, we don't use this */
 
   initialized = true;
diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c
index f94415222..7b04edfd6 100644
--- a/lib/vtls/openssl.c
+++ b/lib/vtls/openssl.c
@@ -446,14 +446,14 @@ static CURLcode Curl_ossl_seed(struct Curl_easy *data)
     size_t len = sizeof(randb);
     size_t i, i_max;
     for(i = 0, i_max = len / sizeof(struct curltime); i < i_max; ++i) {
-      struct curltime tv = curlx_tvnow();
+      struct curltime tv = Curl_now();
       Curl_wait_ms(1);
       tv.tv_sec *= i + 1;
       tv.tv_usec *= (unsigned int)i + 2;
-      tv.tv_sec ^= ((curlx_tvnow().tv_sec + curlx_tvnow().tv_usec) *
+      tv.tv_sec ^= ((Curl_now().tv_sec + Curl_now().tv_usec) *
                     (i + 3)) << 8;
-      tv.tv_usec ^= (unsigned int) ((curlx_tvnow().tv_sec +
-                                     curlx_tvnow().tv_usec) *
+      tv.tv_usec ^= (unsigned int) ((Curl_now().tv_sec +
+                                     Curl_now().tv_usec) *
                                     (i + 4)) << 16;
       memcpy(&randb[i * sizeof(struct curltime)], &tv,
              sizeof(struct curltime));
@@ -838,12 +838,18 @@ int cert_stuff(struct connectdata *conn,
       EVP_PKEY_free(pktmp);
     }
 
-#if !defined(OPENSSL_NO_RSA) && defined(HAVE_OPAQUE_EVP_PKEY)
+#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_IS_BORINGSSL)
     {
       /* If RSA is used, don't check the private key if its flags indicate
        * it doesn't support it. */
       EVP_PKEY *priv_key = SSL_get_privatekey(ssl);
-      if(EVP_PKEY_id(priv_key) == EVP_PKEY_RSA) {
+      int pktype;
+#ifdef HAVE_OPAQUE_EVP_PKEY
+      pktype = EVP_PKEY_id(priv_key);
+#else
+      pktype = priv_key->type;
+#endif
+      if(pktype == EVP_PKEY_RSA) {
         RSA *rsa = EVP_PKEY_get1_RSA(priv_key);
         if(RSA_flags(rsa) & RSA_METHOD_FLAG_NO_CHECK)
           check_privkey = FALSE;
@@ -3061,12 +3067,12 @@ static CURLcode servercert(struct connectdata *conn,
   ASN1_TIME_print(mem, X509_get0_notBefore(BACKEND->server_cert));
   len = BIO_get_mem_data(mem, (char **) &ptr);
   infof(data, " start date: %.*s\n", len, ptr);
-  rc = BIO_reset(mem);
+  (void)BIO_reset(mem);
 
   ASN1_TIME_print(mem, X509_get0_notAfter(BACKEND->server_cert));
   len = BIO_get_mem_data(mem, (char **) &ptr);
   infof(data, " expire date: %.*s\n", len, ptr);
-  rc = BIO_reset(mem);
+  (void)BIO_reset(mem);
 
   BIO_free(mem);
 
diff --git a/packages/Symbian/group/libcurl.mmp 
b/packages/Symbian/group/libcurl.mmp
index 81fd3b33f..bb99ec265 100644
--- a/packages/Symbian/group/libcurl.mmp
+++ b/packages/Symbian/group/libcurl.mmp
@@ -39,7 +39,7 @@ SOURCE \
   asyn-ares.c asyn-thread.c curl_gssapi.c http_ntlm.c curl_ntlm_wb.c   \
   curl_ntlm_core.c curl_sasl.c vtls/schannel.c curl_multibyte.c        \
   vtls/darwinssl.c conncache.c curl_sasl_sspi.c smb.c curl_endian.c    \
-  curl_des.c system_win32.c                                            \
+  curl_des.c system_win32.c sha256.c                                   \
   vauth/vauth.c vauth/cleartext.c vauth/cram.c vauth/digest.c          \
   vauth/digest_sspi.c vauth/krb5_gssapi.c vauth/krb5_sspi.c            \
   vauth/ntlm.c vauth/ntlm_sspi.c vauth/oauth2.c vauth/spnego_gssapi.c  \
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 6e50d82ad..506713015 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -40,7 +40,7 @@ transform_makefile_inc("Makefile.inc" 
"${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.
 include(${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake)
 
 if(MSVC)
-  list(APPEND CURL_SOURCE curl.rc)
+  list(APPEND CURL_FILES curl.rc)
 endif()
 
 # CURL_FILES comes from Makefile.inc
@@ -76,4 +76,15 @@ set_target_properties(${EXE_NAME} PROPERTIES
 
 #INCLUDE(ModuleInstall OPTIONAL)
 
-install(TARGETS ${EXE_NAME} DESTINATION bin)
+install(TARGETS ${EXE_NAME} EXPORT curl-target DESTINATION bin)
+export(TARGETS ${EXE_NAME}
+       APPEND FILE ${PROJECT_BINARY_DIR}/curl-target.cmake
+       NAMESPACE CURL::
+)
+
+install(EXPORT curl-target
+        FILE curl-target.cmake
+        NAMESPACE CURL::
+        DESTINATION ${CURL_INSTALL_CMAKE_DIR}
+)
+
diff --git a/src/Makefile.m32 b/src/Makefile.m32
index 21e3a6bc0..2dfa3ba22 100644
--- a/src/Makefile.m32
+++ b/src/Makefile.m32
@@ -23,7 +23,8 @@
 ###########################################################################
 #
 ## Makefile for building curl.exe with MingW (GCC-3.2 or later or LLVM/Clang)
-## and optionally OpenSSL (1.0.2a), libssh2 (1.5), zlib (1.2.8), librtmp (2.4)
+## and optionally OpenSSL (1.0.2a), libssh2 (1.5), zlib (1.2.8), librtmp (2.4),
+## brotli (1.0.1)
 ##
 ## Usage:   mingw32-make -f Makefile.m32 
CFG=-feature1[-feature2][-feature3][...]
 ## Example: mingw32-make -f Makefile.m32 CFG=-zlib-ssl-sspi-winidn
@@ -38,6 +39,10 @@
 ifndef ZLIB_PATH
 ZLIB_PATH = ../../zlib-1.2.8
 endif
+# Edit the path below to point to the base of your Brotli sources.
+ifndef BROTLI_PATH
+BROTLI_PATH = ../../brotli-1.0.1
+endif
 # Edit the path below to point to the base of your OpenSSL package.
 ifndef OPENSSL_PATH
 OPENSSL_PATH = ../../openssl-1.0.2a
@@ -184,6 +189,9 @@ endif
 ifeq ($(findstring -zlib,$(CFG)),-zlib)
 ZLIB = 1
 endif
+ifeq ($(findstring -brotli,$(CFG)),-brotli)
+BROTLI = 1
+endif
 ifeq ($(findstring -idn2,$(CFG)),-idn2)
 IDN2 = 1
 endif
@@ -294,6 +302,16 @@ ifdef ZLIB
   CFLAGS += -DHAVE_LIBZ -DHAVE_ZLIB_H
   curl_LDADD += -L"$(ZLIB_PATH)" -lz
 endif
+ifdef BROTLI
+  INCLUDES += -I"$(BROTLI_PATH)/include"
+  CFLAGS += -DHAVE_BROTLI
+  curl_LDADD += -L"$(BROTLI_PATH)/lib"
+  ifdef BROTLI_LIBS
+    curl_LDADD += $(BROTLI_LIBS)
+  else
+    curl_LDADD += -lbrotlidec
+  endif
+endif
 ifdef IDN2
   CFLAGS += -DUSE_LIBIDN2
   curl_LDADD += -L"$(LIBIDN2_PATH)/lib" -lidn2
diff --git a/src/mkhelp.pl b/src/mkhelp.pl
index 270daa20a..757f024ce 100755
--- a/src/mkhelp.pl
+++ b/src/mkhelp.pl
@@ -102,11 +102,9 @@ while(<READ>) {
 }
 close(READ);
 
-$now = localtime;
 print <<HEAD
 /*
  * NEVER EVER edit this manually, fix the mkhelp.pl script instead!
- * Generation time: $now
  */
 #ifdef USE_MANUAL
 #include "tool_hugehelp.h"
diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h
index 23943fe7b..ddfc9bfce 100644
--- a/src/tool_cfgable.h
+++ b/src/tool_cfgable.h
@@ -114,6 +114,7 @@ struct OperationConfig {
   struct getout *url_last;  /* point to the last/current node */
   struct getout *url_get;   /* point to the node to fill in URL */
   struct getout *url_out;   /* point to the node to fill in outfile */
+  struct getout *url_ul;    /* point to the node to fill in upload */
   char *cipher_list;
   char *proxy_cipher_list;
   char *cert;
diff --git a/src/tool_formparse.c b/src/tool_formparse.c
index b763d88a5..719e3413f 100644
--- a/src/tool_formparse.c
+++ b/src/tool_formparse.c
@@ -52,13 +52,12 @@ typedef struct {
  * after call get_parm_word, str either point to string end
  * or point to any of end chars.
  */
-static char *get_param_word(char **str, char **end_pos)
+static char *get_param_word(char **str, char **end_pos, char endchar)
 {
   char *ptr = *str;
   char *word_begin = NULL;
   char *ptr2;
   char *escape = NULL;
-  const char *end_chars = ";,";
 
   /* the first non-space char is here */
   word_begin = ptr;
@@ -88,7 +87,7 @@ static char *get_param_word(char **str, char **end_pos)
           while(ptr < *end_pos);
           *end_pos = ptr2;
         }
-        while(*ptr && NULL == strchr(end_chars, *ptr))
+        while(*ptr && *ptr != ';' && *ptr != endchar)
           ++ptr;
         *str = ptr;
         return word_begin + 1;
@@ -99,7 +98,7 @@ static char *get_param_word(char **str, char **end_pos)
     ptr = word_begin;
   }
 
-  while(*ptr && NULL == strchr(end_chars, *ptr))
+  while(*ptr && *ptr != ';' && *ptr != endchar)
     ++ptr;
   *str = *end_pos = ptr;
   return word_begin;
@@ -181,9 +180,10 @@ static int read_field_headers(struct OperationConfig 
*config,
   /* NOTREACHED */
 }
 
-static int get_param_part(struct OperationConfig *config, char **str,
-                          char **pdata, char **ptype, char **pfilename,
-                          char **pencoder, struct curl_slist **pheaders)
+static int get_param_part(struct OperationConfig *config, char endchar,
+                          char **str, char **pdata, char **ptype,
+                          char **pfilename, char **pencoder,
+                          struct curl_slist **pheaders)
 {
   char *p = *str;
   char *type = NULL;
@@ -208,7 +208,7 @@ static int get_param_part(struct OperationConfig *config, 
char **str,
   while(ISSPACE(*p))
     p++;
   tp = p;
-  *pdata = get_param_word(&p, &endpos);
+  *pdata = get_param_word(&p, &endpos, endchar);
   /* If not quoted, strip trailing spaces. */
   if(*pdata == tp)
     while(endpos > *pdata && ISSPACE(endpos[-1]))
@@ -233,12 +233,10 @@ static int get_param_part(struct OperationConfig *config, 
char **str,
       }
 
       /* now point beyond the content-type specifier */
-      endpos = type + strlen(type_major) + strlen(type_minor) + 1;
-      for(p = endpos; ISSPACE(*p); p++)
-        ;
-      while(*p && *p != ';' && *p != ',')
-        p++;
-      endct = p;
+      p = type + strlen(type_major) + strlen(type_minor) + 1;
+      for(endct = p; *p && *p != ';' && *p != endchar; p++)
+        if(!ISSPACE(*p))
+          endct = p + 1;
       sep = *p;
     }
     else if(checkprefix("filename=", p)) {
@@ -249,7 +247,7 @@ static int get_param_part(struct OperationConfig *config, 
char **str,
       for(p += 9; ISSPACE(*p); p++)
         ;
       tp = p;
-      filename = get_param_word(&p, &endpos);
+      filename = get_param_word(&p, &endpos, endchar);
       /* If not quoted, strip trailing spaces. */
       if(filename == tp)
         while(endpos > filename && ISSPACE(endpos[-1]))
@@ -272,7 +270,7 @@ static int get_param_part(struct OperationConfig *config, 
char **str,
           p++;
         } while(ISSPACE(*p));
         tp = p;
-        hdrfile = get_param_word(&p, &endpos);
+        hdrfile = get_param_word(&p, &endpos, endchar);
         /* If not quoted, strip trailing spaces. */
         if(hdrfile == tp)
           while(endpos > hdrfile && ISSPACE(endpos[-1]))
@@ -300,7 +298,7 @@ static int get_param_part(struct OperationConfig *config, 
char **str,
         while(ISSPACE(*p))
           p++;
         tp = p;
-        hdr = get_param_word(&p, &endpos);
+        hdr = get_param_word(&p, &endpos, endchar);
         /* If not quoted, strip trailing spaces. */
         if(hdr == tp)
           while(endpos > hdr && ISSPACE(endpos[-1]))
@@ -322,7 +320,7 @@ static int get_param_part(struct OperationConfig *config, 
char **str,
       for(p += 8; ISSPACE(*p); p++)
         ;
       tp = p;
-      encoder = get_param_word(&p, &endpos);
+      encoder = get_param_word(&p, &endpos, endchar);
       /* If not quoted, strip trailing spaces. */
       if(encoder == tp)
         while(endpos > encoder && ISSPACE(endpos[-1]))
@@ -330,29 +328,27 @@ static int get_param_part(struct OperationConfig *config, 
char **str,
       sep = *p;
       *endpos = '\0';
     }
+    else if(endct) {
+      /* This is part of content type. */
+      for(endct = p; *p && *p != ';' && *p != endchar; p++)
+        if(!ISSPACE(*p))
+          endct = p + 1;
+      sep = *p;
+    }
     else {
       /* unknown prefix, skip to next block */
-      char *unknown = get_param_word(&p, &endpos);
+      char *unknown = get_param_word(&p, &endpos, endchar);
 
       sep = *p;
-      if(endct)
-        endct = p;
-      else {
-        *endpos = '\0';
-         if(*unknown)
-           warnf(config->global, "skip unknown form field: %s\n", unknown);
-      }
+      *endpos = '\0';
+      if(*unknown)
+        warnf(config->global, "skip unknown form field: %s\n", unknown);
     }
   }
 
-  /* Terminate and strip content type. */
-  if(type) {
-    if(!endct)
-      endct = type + strlen(type);
-    while(endct > type && ISSPACE(endct[-1]))
-      endct--;
+  /* Terminate content type. */
+  if(endct)
     *endct = '\0';
-  }
 
   if(ptype)
     *ptype = type;
@@ -598,7 +594,8 @@ int formparse(struct OperationConfig *config,
       curl_mime *subparts;
 
       /* Starting a multipart. */
-      sep = get_param_part(config, &contp, &data, &type, NULL, NULL, &headers);
+      sep = get_param_part(config, '\0',
+                           &contp, &data, &type, NULL, NULL, &headers);
       if(sep < 0) {
         Curl_safefree(contents);
         return 3;
@@ -657,7 +654,7 @@ int formparse(struct OperationConfig *config,
         /* since this was a file, it may have a content-type specifier
            at the end too, or a filename. Or both. */
         ++contp;
-        sep = get_param_part(config, &contp,
+        sep = get_param_part(config, ',', &contp,
                              &data, &type, &filename, &encoder, &headers);
         if(sep < 0) {
           if(subparts != *mimecurrent)
@@ -767,7 +764,7 @@ int formparse(struct OperationConfig *config,
 
       if(*contp == '<' && !literal_value) {
         ++contp;
-        sep = get_param_part(config, &contp,
+        sep = get_param_part(config, '\0', &contp,
                              &data, &type, NULL, &encoder, &headers);
         if(sep < 0) {
           Curl_safefree(contents);
@@ -796,7 +793,7 @@ int formparse(struct OperationConfig *config,
         if(literal_value)
           data = contp;
         else {
-          sep = get_param_part(config, &contp,
+          sep = get_param_part(config, '\0', &contp,
                                &data, &type, &filename, &encoder, &headers);
           if(sep < 0) {
             Curl_safefree(contents);
diff --git a/src/tool_getparam.c b/src/tool_getparam.c
index b65c45732..12e3abd55 100644
--- a/src/tool_getparam.c
+++ b/src/tool_getparam.c
@@ -787,7 +787,7 @@ ParameterError getparameter(const char *flag, /* f or 
-long-flag */
           url = config->url_get;
         else
           /* there was no free node, create one! */
-          url = new_getout(config);
+          config->url_get = url = new_getout(config);
 
         if(!url)
           return PARAM_NO_MEM;
@@ -1787,7 +1787,7 @@ ParameterError getparameter(const char *flag, /* f or 
-long-flag */
         url = config->url_out;
       else
         /* there was no free node, create one! */
-        url = new_getout(config);
+        config->url_out = url = new_getout(config);
 
       if(!url)
         return PARAM_NO_MEM;
@@ -1912,23 +1912,23 @@ ParameterError getparameter(const char *flag, /* f or 
-long-flag */
       /* we are uploading */
     {
       struct getout *url;
-      if(!config->url_out)
-        config->url_out = config->url_list;
-      if(config->url_out) {
+      if(!config->url_ul)
+        config->url_ul = config->url_list;
+      if(config->url_ul) {
         /* there's a node here, if it already is filled-in continue to find
            an "empty" node */
-        while(config->url_out && (config->url_out->flags & GETOUT_UPLOAD))
-          config->url_out = config->url_out->next;
+        while(config->url_ul && (config->url_ul->flags & GETOUT_UPLOAD))
+          config->url_ul = config->url_ul->next;
       }
 
       /* now there might or might not be an available node to fill in! */
 
-      if(config->url_out)
+      if(config->url_ul)
         /* existing node */
-        url = config->url_out;
+        url = config->url_ul;
       else
         /* there was no free node, create one! */
-        url = new_getout(config);
+        config->url_ul = url = new_getout(config);
 
       if(!url)
         return PARAM_NO_MEM;
diff --git a/src/tool_help.c b/src/tool_help.c
index 486f65dc8..c6d329cdf 100644
--- a/src/tool_help.c
+++ b/src/tool_help.c
@@ -499,6 +499,7 @@ static const struct feat feats[] = {
   {"NTLM_WB",        CURL_VERSION_NTLM_WB},
   {"SSL",            CURL_VERSION_SSL},
   {"libz",           CURL_VERSION_LIBZ},
+  {"brotli",         CURL_VERSION_BROTLI},
   {"CharConv",       CURL_VERSION_CONV},
   {"TLS-SRP",        CURL_VERSION_TLSAUTH_SRP},
   {"HTTP2",          CURL_VERSION_HTTP2},
diff --git a/src/tool_metalink.c b/src/tool_metalink.c
index 270345547..bbbfc2a65 100644
--- a/src/tool_metalink.c
+++ b/src/tool_metalink.c
@@ -539,6 +539,7 @@ digest_context *Curl_digest_init(const digest_params 
*dparams)
   ctxt->digest_hash = dparams;
 
   if(dparams->digest_init(ctxt->digest_hashctx) != 1) {
+    free(ctxt->digest_hashctx);
     free(ctxt);
     return NULL;
   }
@@ -557,7 +558,8 @@ int Curl_digest_update(digest_context *context,
 
 int Curl_digest_final(digest_context *context, unsigned char *result)
 {
-  (*context->digest_hash->digest_final)(result, context->digest_hashctx);
+  if(result)
+    (*context->digest_hash->digest_final)(result, context->digest_hashctx);
 
   free(context->digest_hashctx);
   free(context);
@@ -622,6 +624,7 @@ static int check_hash(const char *filename,
   result = malloc(digest_def->dparams->digest_resultlen);
   if(!result) {
     close(fd);
+    Curl_digest_final(dctx, NULL);
     return -1;
   }
   while(1) {
@@ -690,6 +693,8 @@ static metalink_checksum 
*new_metalink_checksum_from_hex_digest
     chksum->digest_def = digest_def;
     chksum->digest = digest;
   }
+  else
+    free(digest);
   return chksum;
 }
 
@@ -781,8 +786,24 @@ static metalinkfile *new_metalinkfile(metalink_file_t 
*fileinfo)
          curl_strequal((*p)->type, "ftp") ||
          curl_strequal((*p)->type, "ftps")) {
         res = new_metalink_resource((*p)->url);
-        tail->next = res;
-        tail = res;
+        if(res) {
+          tail->next = res;
+          tail = res;
+        }
+        else {
+          tail = root.next;
+
+          /* clean up the linked list */
+          while(tail) {
+            res = tail->next;
+            free(tail->url);
+            free(tail);
+            tail = res;
+          }
+          free(f->filename);
+          free(f);
+          return NULL;
+        }
       }
     }
     f->resource = root.next;
diff --git a/src/tool_urlglob.c b/src/tool_urlglob.c
index df85d7129..f78d058cd 100644
--- a/src/tool_urlglob.c
+++ b/src/tool_urlglob.c
@@ -367,9 +367,11 @@ static CURLcode glob_parse(URLGlob *glob, char *pattern,
     size_t sublen = 0;
     while(*pattern && *pattern != '{') {
       if(*pattern == '[') {
-        /* Skip over potential IPv6 literals. */
-        size_t skip;
-        if(peek_ipv6(pattern, &skip)) {
+        /* skip over IPv6 literals and [] */
+        size_t skip = 0;
+        if(!peek_ipv6(pattern, &skip) && (pattern[1] == ']'))
+          skip = 2;
+        if(skip) {
           memcpy(buf, pattern, skip);
           buf += skip;
           pattern += skip;
diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc
index aa8a1d21e..dbeb5771e 100644
--- a/tests/data/Makefile.inc
+++ b/tests/data/Makefile.inc
@@ -45,7 +45,7 @@ test190 test191 test192 test193 test194 test195 test196 
test197 test198 \
 test199 test200 test201 test202 test203 test204 test205 test206 test207 \
 test208 test209 test210 test211 test212 test213 test214 test215 test216 \
 test217 test218 test219 test220 test221 test222 test223 test224 test225 \
-test226 test227 test228 test229         test231         test233 test234 \
+test226 test227 test228 test229 test230 test231         test233 test234 \
 test235 test236 test237 test238 test239 test240 test241 test242 test243 \
 test244 test245 test246 test247 test248 test249 test250 test251 test252 \
 test253 test254 test255 test256 test257 test258 test259 test260 test261 \
@@ -54,7 +54,7 @@ test271 test272 test273 test274 test275 test276 test277 
test278 test279 \
 test280 test281 test282 test283 test284 test285 test286 test287 test288 \
 test289 test290 test291 test292 test293 test294 test295 test296 test297 \
 test298 test299 test300 test301 test302 test303 test304 test305 test306 \
-test307 test308 test309 test310 test311 test312 test313                 \
+test307 test308 test309 test310 test311 test312 test313 test314 test315 \
                                 test320 test321 test322 test323 test324 \
 test325 \
 test350 test351 test352 test353 test354 \
@@ -125,7 +125,7 @@ test1136 test1137 test1138                   test1141 
test1142 test1143 \
 test1144 test1145 test1146 test1147 test1148 test1149 test1150 test1151 \
 test1152 test1153 \
 \
-test1160 test1161 \
+test1160 test1161 test1162 test1163 \
 test1200 test1201 test1202 test1203 test1204 test1205 test1206 test1207 \
 test1208 test1209 test1210 test1211 test1212 test1213 test1214 test1215 \
 test1216 test1217 test1218 test1219 \
@@ -134,15 +134,15 @@ test1228 test1229 test1230 test1231 test1232 test1233 
test1234 test1235 \
 test1236 test1237 test1238 test1239 test1240 test1241 test1242 test1243 \
 test1244 test1245 test1246 test1247 test1248 test1249 test1250 test1251 \
 test1252 test1253 test1254 test1255 test1256 test1257 test1258 test1259 \
-test1260 test1261 test1262 \
+test1260 test1261 test1262 test1263 test1264 \
 \
 test1280 test1281 test1282 test1283 test1284 test1285 test1286 test1287 \
-test1288 test1289 \
+test1288 test1289 test1290 test1291 \
 test1298 test1299 \
 test1300 test1301 test1302 test1303 test1304 test1305 test1306 test1307 \
 test1308 test1309 test1310 test1311 test1312 test1313 test1314 test1315 \
 test1316 test1317 test1318 test1319 test1320 test1321 test1322 test1323 \
-         test1325 test1326 test1327 test1328 test1329 test1330 test1331 \
+test1324 test1325 test1326 test1327 test1328 test1329 test1330 test1331 \
 test1332 test1333 test1334 test1335 test1336 test1337 test1338 test1339 \
 test1340 test1341 test1342 test1343 test1344 test1345 test1346 test1347 \
 test1348 test1349 test1350 test1351 test1352 test1353 test1354 test1355 \
@@ -170,7 +170,7 @@ test1520 test1521 \
 test1525 test1526 test1527 test1528 test1529 test1530 test1531 test1532 \
 test1533 test1534 test1535 test1536 test1537 test1538 \
 test1540 \
-test1550 test1551 test1552 test1553 \
+test1550 test1551 test1552 test1553 test1554 \
 test1600 test1601 test1602 test1603 test1604 test1605 test1606 \
 \
 test1700 test1701 test1702 \
@@ -186,4 +186,7 @@ test2024 test2025 test2026 test2027 test2028 test2029 
test2030 test2031 \
 test2032 test2033 test2034 test2035 test2036 test2037 test2038 test2039 \
 test2040 test2041 test2042 test2043 test2044 test2045 test2046 test2047 \
 test2048 test2049 test2050 test2051 test2052 test2053 test2054 test2055 \
-test2056 test2057
+test2056 test2057 test2058 test2059 test2060 test2061 test2062 test2063 \
+test2064 test2065 test2066 test2067 test2068 test2069 \
+\
+test2070 test2071 test2072
diff --git a/tests/data/test1034 b/tests/data/test1034
index 6c1beb671..beab0d3c0 100644
--- a/tests/data/test1034
+++ b/tests/data/test1034
@@ -13,24 +13,17 @@ config file
 #
 # Server-side
 <reply>
-<data>
-HTTP/1.0 503 Service Unavailable
-Date: Thu, 09 Nov 2010 14:49:00 GMT
-Server: test-server/fake swsclose
-Content-Type: text/html
-Funny-head: yesyes
-
-</data>
 </reply>
 
 #
 # Client-side
 <client>
 <server>
-http
+none
 </server>
 <features>
 idn
+http
 </features>
 <setenv>
 LC_ALL=
@@ -54,17 +47,9 @@ url = "http://invalid-utf8-
 </client>
 
 #
-# Verify data after the test has been "shot"
 <verify>
-<strip>
-^User-Agent:.*
-</strip>
-<protocol>
-GET http://invalid-utf8-�.local/page/1034 HTTP/1.1
-Host: invalid-utf8-�.local
-Accept: */*
-Proxy-Connection: Keep-Alive
-
-</protocol>
+<errorcode>
+3
+</errorcode>
 </verify>
 </testcase>
diff --git a/tests/data/test1035 b/tests/data/test1035
index 033a48a72..a316c51e1 100644
--- a/tests/data/test1035
+++ b/tests/data/test1035
@@ -12,24 +12,17 @@ FAILURE
 #
 # Server-side
 <reply>
-<data>
-HTTP/1.0 503 Service Unavailable
-Date: Thu, 09 Nov 2010 14:49:00 GMT
-Server: test-server/fake swsclose
-Content-Type: text/html
-Funny-head: yesyes
-
-</data>
 </reply>
 
 #
 # Client-side
 <client>
 <server>
-http
+none
 </server>
 <features>
 idn
+http
 </features>
 <setenv>
 LC_ALL=
@@ -52,12 +45,8 @@ 
http://too-long-IDN-name-cürl-rüles-la-la-la-dee-da-flooby-nooby.local/page/10
 <strip>
 ^User-Agent:.*
 </strip>
-<protocol>
-GET 
http://too-long-IDN-name-cürl-rüles-la-la-la-dee-da-flooby-nooby.local/page/1035
 HTTP/1.1
-Host: too-long-IDN-name-cürl-rüles-la-la-la-dee-da-flooby-nooby.local
-Accept: */*
-Proxy-Connection: Keep-Alive
-
-</protocol>
+<errorcode>
+3
+</errorcode>
 </verify>
 </testcase>
diff --git a/tests/data/test1133 b/tests/data/test1133
index 2238b9c07..b8ed56b2d 100644
--- a/tests/data/test1133
+++ b/tests/data/test1133
@@ -23,10 +23,10 @@ blablabla
 http
 </server>
  <name>
-HTTP RFC1867-type formposting with filename contains ',', ';', '"'
+HTTP RFC1867-type formposting with filename/data contains ',', ';', '"'
  </name>
  <command>
-http://%HOSTIP:%HTTPPORT/we/want/1133 -F 
"address@hidden"log/test1133,a\\\"nd;.txt\";type=mo/foo;filename=\"faker,and;.txt\""
 -F 'file2=@"log/test1133,a\"nd;.txt"' -F 
'file3=@"log/test1133,a\"nd;.txt";type=m/f,"log/test1133,a\"nd;.txt"'
+http://%HOSTIP:%HTTPPORT/we/want/1133 -F 
"address@hidden"log/test1133,a\\\"nd;.txt\";type=mo/foo;filename=\"faker,and;.txt\""
 -F 'file2=@"log/test1133,a\"nd;.txt"' -F 
'file3=@"log/test1133,a\"nd;.txt";type=m/f,"log/test1133,a\"nd;.txt"' -F 
a="{\"field1\":\"value1\",\"field2\":\"value2\"}" -F 'b=" 
\\value1;type=\"whatever\" "; type=text/foo; charset=utf-8 ; filename=param_b'
 </command>
 # We create this file before the command is invoked!
 <file name=log/test1133,a"nd;.txt>
@@ -47,7 +47,8 @@ POST /we/want/1133 HTTP/1.1
 User-Agent: curl/7.10.4 (i686-pc-linux-gnu) libcurl/7.10.4 OpenSSL/0.9.7a ipv6 
zlib/1.1.3
 Host: %HOSTIP:%HTTPPORT
 Accept: */*
-Content-Length: 969
+Content-Length: 1270
+Expect: 100-continue
 Content-Type: multipart/form-data; 
boundary=----------------------------24e78000bd32
 
 ------------------------------24e78000bd32
@@ -89,6 +90,13 @@ bar
 foo
 
 
+Content-Disposition: form-data; name="a"
+
+{"field1":"value1","field2":"value2"}
+Content-Disposition: form-data; name="b"; filename="param_b"
+Content-Type: text/foo; charset=utf-8
+
+ \value1;type="whatever" 
 ------------------------------24e78000bd32--
 </protocol>
 </verify>
diff --git a/tests/data/test1501 b/tests/data/test1162
similarity index 58%
copy from tests/data/test1501
copy to tests/data/test1162
index 8c7e13af7..73e4646e1 100644
--- a/tests/data/test1501
+++ b/tests/data/test1162
@@ -3,19 +3,18 @@
 <keywords>
 FTP
 RETR
-multi
 LIST
+wildcardmatch
+ftplistparser
+flaky
 </keywords>
 </info>
 
+#
 # Server-side
 <reply>
 <data>
 </data>
-<servercmd>
-DELAY LIST 2
-DELAY TYPE 2
-</servercmd>
 </reply>
 
 # Client-side
@@ -24,30 +23,30 @@ DELAY TYPE 2
 ftp
 </server>
 <tool>
-lib1501
+lib576
 </tool>
- <name>
-FTP with multi interface and slow LIST response 
- </name>
- <command>
-ftp://%HOSTIP:%FTPPORT/1501/
+<name>
+FTP wildcard with crazy pattern
+</name>
+<command>
+"ftp://%HOSTIP:%FTPPORT/fully_simulated/DOS/[*\\s-'tl"
 </command>
 </client>
-# Verify data after the test has been "shot"
 <verify>
-<errorcode>
-0
-</errorcode>
 <protocol>
 USER anonymous
 PASS address@hidden
 PWD
-CWD 1501
+CWD fully_simulated
+CWD DOS
 EPSV
 TYPE A
 LIST
 QUIT
 </protocol>
-
+# 78 == CURLE_REMOTE_FILE_NOT_FOUND
+<errorcode>
+78
+</errorcode>
 </verify>
 </testcase>
diff --git a/tests/data/test1501 b/tests/data/test1163
similarity index 57%
copy from tests/data/test1501
copy to tests/data/test1163
index 8c7e13af7..a109b511b 100644
--- a/tests/data/test1501
+++ b/tests/data/test1163
@@ -3,19 +3,18 @@
 <keywords>
 FTP
 RETR
-multi
 LIST
+wildcardmatch
+ftplistparser
+flaky
 </keywords>
 </info>
 
+#
 # Server-side
 <reply>
 <data>
 </data>
-<servercmd>
-DELAY LIST 2
-DELAY TYPE 2
-</servercmd>
 </reply>
 
 # Client-side
@@ -24,30 +23,30 @@ DELAY TYPE 2
 ftp
 </server>
 <tool>
-lib1501
+lib576
 </tool>
- <name>
-FTP with multi interface and slow LIST response 
- </name>
- <command>
-ftp://%HOSTIP:%FTPPORT/1501/
+<name>
+FTP wildcard with pattern ending with an open-bracket
+</name>
+<command>
+"ftp://%HOSTIP:%FTPPORT/fully_simulated/DOS/*[][";
 </command>
 </client>
-# Verify data after the test has been "shot"
 <verify>
-<errorcode>
-0
-</errorcode>
 <protocol>
 USER anonymous
 PASS address@hidden
 PWD
-CWD 1501
+CWD fully_simulated
+CWD DOS
 EPSV
 TYPE A
 LIST
 QUIT
 </protocol>
-
+# 78 == CURLE_REMOTE_FILE_NOT_FOUND
+<errorcode>
+78
+</errorcode>
 </verify>
 </testcase>
diff --git a/tests/data/test1260 b/tests/data/test1263
similarity index 64%
copy from tests/data/test1260
copy to tests/data/test1263
index 1d86ecd4e..7946916e2 100644
--- a/tests/data/test1260
+++ b/tests/data/test1263
@@ -1,3 +1,4 @@
+# similar to test 1260
 <testcase>
 <info>
 <keywords>
@@ -19,10 +20,10 @@ none
 http
 </features>
  <name>
-HTTP URL with rubbish after port number
+HTTP URL with rubbish after IPv6 bracket
  </name>
  <command>
--g "http://[%HOSTIP]:%HTTPPORT:80/we/want/1260"; 
"http://%HOSTIP:%HTTPPORT:80/we/want/1260"; 
"http://address@hidden:address@hidden";
+-g "http://[%HOSTIP]test:%HTTPPORT/we/want/1263"; 
"http://[%HOSTIP][%HOSTIP]:%HTTPPORT/we/want/1263"; 
"http://address@hidden::address@hidden";
 </command>
 </client>
 
diff --git a/tests/data/test20 b/tests/data/test1264
similarity index 71%
copy from tests/data/test20
copy to tests/data/test1264
index 57fa48dea..272db736c 100644
--- a/tests/data/test20
+++ b/tests/data/test1264
@@ -2,15 +2,12 @@
 <info>
 <keywords>
 HTTP
-FAILURE
-non-existing host
+HTTP GET
 </keywords>
 </info>
 
 # Server-side
 <reply>
-<data>
-</data>
 </reply>
 
 # Client-side
@@ -22,17 +19,18 @@ none
 http
 </features>
  <name>
-attempt connect to non-existing host name
+HTTP URL with space in host name
  </name>
  <command>
-non-existing-host.haxx.se.
+-g "http://127.0.0.1 www.example.com/we/want/1264"
 </command>
 </client>
 
 # Verify data after the test has been "shot"
 <verify>
+# CURLE_URL_MALFORMAT == 3
 <errorcode>
-6
+3
 </errorcode>
 </verify>
 </testcase>
diff --git a/tests/data/test214 b/tests/data/test1290
similarity index 71%
copy from tests/data/test214
copy to tests/data/test1290
index a9b8fcd07..e556303bf 100644
--- a/tests/data/test214
+++ b/tests/data/test1290
@@ -3,48 +3,46 @@
 <keywords>
 HTTP
 HTTP GET
+globbing
 </keywords>
 </info>
+
 #
 # Server-side
 <reply>
 <data>
 HTTP/1.1 200 OK
-Date: Thu, 09 Nov 2010 14:49:00 GMT
 Content-Length: 6
+Connection: close
 Content-Type: text/html
-Funny-head: yesyes
 
 -foo-
 </data>
 </reply>
 
-#
 # Client-side
 <client>
 <server>
 http
 </server>
- <name>
-HTTP URL with escaped { and }
- </name>
+<name>
+Verify URL globbing ignores []
+</name>
 <command>
-"http://%HOSTIP:%HTTPPORT/\{\}\/214";
+"http://%HOSTIP:%HTTPPORT/we/want/[]/page/1290";
 </command>
 </client>
 
-#
 # Verify data after the test has been "shot"
 <verify>
 <strip>
 ^User-Agent:.*
 </strip>
 <protocol>
-GET /{}\/214 HTTP/1.1
+GET /we/want/[]/page/1290 HTTP/1.1
 Host: %HOSTIP:%HTTPPORT
 Accept: */*
 
 </protocol>
-
 </verify>
 </testcase>
diff --git a/tests/data/test1291 b/tests/data/test1291
new file mode 100644
index 000000000..12d65f3d8
--- /dev/null
+++ b/tests/data/test1291
@@ -0,0 +1,51 @@
+# This test case is primarily meant to verify that parsing and adding the 100K
+# files is a swift operation.
+#
+<testcase>
+<info>
+<keywords>
+HTTP
+HTTP PUT
+</keywords>
+</info>
+
+#
+# Server-side
+<reply>
+<data>
+</data>
+</reply>
+
+# Client-side
+<client>
+<server>
+none
+</server>
+<name>
+Attempt to upload 100K files but fail immediately
+</name>
+<command>
+-K log/cmd1291 --fail-early
+</command>
+<file name="log/upload-this">
+XXXXXXXx
+</file>
+# generate the config file
+<precheck>
+perl -e 'for(1 .. 100000) { 
printf("upload-file=log/upload-this\nurl=htttttp://non-existing-host.haxx.se/upload/1291\n",
 $_);}' > log/cmd1291;
+</precheck>
+</client>
+
+# Verify data after the test has been "shot"
+<verify>
+<errorcode>
+1
+</errorcode>
+
+# we disable valgrind here since it takes 40+ seconds even on a fairly snappy
+# machine
+<valgrind>
+disable
+</valgrind>
+</verify>
+</testcase>
diff --git a/tests/data/test1317 b/tests/data/test1324
similarity index 77%
copy from tests/data/test1317
copy to tests/data/test1324
index d41886a5f..d7e663a0f 100644
--- a/tests/data/test1317
+++ b/tests/data/test1324
@@ -30,13 +30,13 @@ Funny-head: yesyes
 # Client-side
 <client>
 <server>
-http
+http-ipv6
 </server>
 <name>
-HTTP with --resolve
+HTTP with --resolve and [ipv6address]
 </name>
 <command>
---resolve example.com:%HTTPPORT:%HOSTIP http://example.com:%HTTPPORT/1317
+--resolve example.com:%HTTP6PORT:%HOST6IP http://example.com:%HTTP6PORT/1324
 </command>
 </client>
 
@@ -47,8 +47,8 @@ HTTP with --resolve
 ^User-Agent:.*
 </strip>
 <protocol>
-GET /1317 HTTP/1.1
-Host: example.com:%HTTPPORT
+GET /1324 HTTP/1.1
+Host: example.com:%HTTP6PORT
 Accept: */*
 
 </protocol>
diff --git a/tests/data/test1554 b/tests/data/test1554
new file mode 100644
index 000000000..8739b2c8a
--- /dev/null
+++ b/tests/data/test1554
@@ -0,0 +1,77 @@
+<testcase>
+<info>
+<keywords>
+HTTP
+HTTP GET
+shared connections
+</keywords>
+</info>
+
+# Server-side
+<reply>
+<data>
+HTTP/1.1 200 OK
+Date: Thu, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Content-Type: text/html
+Content-Length: 29
+
+run 1: foobar and so on fun!
+</data>
+<datacheck>
+-> Mutex lock
+<- Mutex unlock
+-> Mutex lock
+<- Mutex unlock
+-> Mutex lock
+<- Mutex unlock
+-> Mutex lock
+<- Mutex unlock
+-> Mutex lock
+<- Mutex unlock
+-> Mutex lock
+<- Mutex unlock
+-> Mutex lock
+<- Mutex unlock
+run 1: foobar and so on fun!
+-> Mutex lock
+<- Mutex unlock
+-> Mutex lock
+<- Mutex unlock
+-> Mutex lock
+<- Mutex unlock
+run 1: foobar and so on fun!
+-> Mutex lock
+<- Mutex unlock
+-> Mutex lock
+<- Mutex unlock
+-> Mutex lock
+<- Mutex unlock
+run 1: foobar and so on fun!
+-> Mutex lock
+<- Mutex unlock
+-> Mutex lock
+<- Mutex unlock
+</datacheck>
+</reply>
+
+# Client-side
+<client>
+<server>
+http
+</server>
+<name>
+HTTP with shared connection cache
+</name>
+<tool>
+lib1554
+</tool>
+<command>
+http://%HOSTIP:%HTTPPORT/1554
+</command>
+</client>
+
+# Verify data after the test has been "shot"
+<verify>
+</verify>
+</testcase>
diff --git a/tests/data/test1001 b/tests/data/test2058
similarity index 72%
copy from tests/data/test1001
copy to tests/data/test2058
index 91b13203e..0082503e0 100644
--- a/tests/data/test1001
+++ b/tests/data/test2058
@@ -21,7 +21,7 @@ X-Powered-By: ASP.NET
 
 HTTP/1.1 401 authentication please swsbounce
 Server: Microsoft-IIS/6.0
-WWW-Authenticate: Digest realm="testrealm", nonce="1053604144"
+WWW-Authenticate: Digest realm="testrealm", algorithm="SHA-256", 
nonce="1053604144"
 Content-Type: text/html; charset=iso-8859-1
 Content-Length: 0
 
@@ -43,7 +43,7 @@ X-Powered-By: ASP.NET
 
 HTTP/1.1 401 authentication please swsbounce
 Server: Microsoft-IIS/6.0
-WWW-Authenticate: Digest realm="testrealm", nonce="1053604144"
+WWW-Authenticate: Digest realm="testrealm", algorithm="SHA-256", 
nonce="1053604144"
 Content-Type: text/html; charset=iso-8859-1
 Content-Length: 0
 
@@ -68,12 +68,12 @@ http
 crypto
 </features>
  <name>
-HTTP POST --digest with PUT and resumed upload and modified method
+HTTP POST --digest with PUT, resumed upload, modified method and SHA-256
  </name>
  <command>
-http://%HOSTIP:%HTTPPORT/1001 -u auser:apasswd --digest -T log/1001 -x  
http://%HOSTIP:%HTTPPORT -C 2 -X GET
+http://%HOSTIP:%HTTPPORT/2058 -u auser:apasswd --digest -T log/2058 -x  
http://%HOSTIP:%HTTPPORT -C 2 -X GET
 </command>
-<file name="log/1001">
+<file name="log/2058">
 test
 </file>
 </client>
@@ -84,7 +84,7 @@ test
 ^User-Agent:.*
 </strip>
 <protocol>
-GET http://%HOSTIP:%HTTPPORT/1001 HTTP/1.1
+GET http://%HOSTIP:%HTTPPORT/2058 HTTP/1.1
 Host: %HOSTIP:%HTTPPORT
 Content-Range: bytes 2-4/5
 User-Agent: curl/7.12.1-CVS (i686-pc-linux-gnu) libcurl/7.12.1-CVS 
OpenSSL/0.9.6b ipv6 zlib/1.1.4 GSS libidn/0.4.6
@@ -92,9 +92,9 @@ Accept: */*
 Proxy-Connection: Keep-Alive
 Content-Length: 0
 
-GET http://%HOSTIP:%HTTPPORT/1001 HTTP/1.1
+GET http://%HOSTIP:%HTTPPORT/2058 HTTP/1.1
 Host: %HOSTIP:%HTTPPORT
-Authorization: Digest username="auser", realm="testrealm", nonce="1053604144", 
uri="/1001", response="6af4d89c952f4dd4cc215a6878dc499d"
+Authorization: Digest username="auser", realm="testrealm", nonce="1053604144", 
uri="/2058", 
response="fbed69f9f3fd304c8f1acb1a43eb32688b933c0e28055c16b926cbcec070aeed", 
algorithm="SHA-256"
 Content-Range: bytes 2-4/5
 Accept: */*
 Proxy-Connection: Keep-Alive
diff --git a/tests/data/test1001 b/tests/data/test2059
similarity index 65%
copy from tests/data/test1001
copy to tests/data/test2059
index 91b13203e..b74b0bdc1 100644
--- a/tests/data/test1001
+++ b/tests/data/test2059
@@ -21,7 +21,7 @@ X-Powered-By: ASP.NET
 
 HTTP/1.1 401 authentication please swsbounce
 Server: Microsoft-IIS/6.0
-WWW-Authenticate: Digest realm="testrealm", nonce="1053604144"
+WWW-Authenticate: Digest realm="testrealm", algorithm="SHA-512-256", 
nonce="1053604144", userhash=true
 Content-Type: text/html; charset=iso-8859-1
 Content-Length: 0
 
@@ -43,7 +43,7 @@ X-Powered-By: ASP.NET
 
 HTTP/1.1 401 authentication please swsbounce
 Server: Microsoft-IIS/6.0
-WWW-Authenticate: Digest realm="testrealm", nonce="1053604144"
+WWW-Authenticate: Digest realm="testrealm", algorithm="SHA-512-256", 
nonce="1053604144", userhash=true
 Content-Type: text/html; charset=iso-8859-1
 Content-Length: 0
 
@@ -68,12 +68,12 @@ http
 crypto
 </features>
  <name>
-HTTP POST --digest with PUT and resumed upload and modified method
+HTTP POST --digest with PUT, resumed upload, modified method, SHA-512-256 and 
userhash=true
  </name>
  <command>
-http://%HOSTIP:%HTTPPORT/1001 -u auser:apasswd --digest -T log/1001 -x  
http://%HOSTIP:%HTTPPORT -C 2 -X GET
+http://%HOSTIP:%HTTPPORT/2059 -u auser:apasswd --digest -T log/2059 -x  
http://%HOSTIP:%HTTPPORT -C 2 -X GET
 </command>
-<file name="log/1001">
+<file name="log/2059">
 test
 </file>
 </client>
@@ -84,7 +84,7 @@ test
 ^User-Agent:.*
 </strip>
 <protocol>
-GET http://%HOSTIP:%HTTPPORT/1001 HTTP/1.1
+GET http://%HOSTIP:%HTTPPORT/2059 HTTP/1.1
 Host: %HOSTIP:%HTTPPORT
 Content-Range: bytes 2-4/5
 User-Agent: curl/7.12.1-CVS (i686-pc-linux-gnu) libcurl/7.12.1-CVS 
OpenSSL/0.9.6b ipv6 zlib/1.1.4 GSS libidn/0.4.6
@@ -92,9 +92,9 @@ Accept: */*
 Proxy-Connection: Keep-Alive
 Content-Length: 0
 
-GET http://%HOSTIP:%HTTPPORT/1001 HTTP/1.1
+GET http://%HOSTIP:%HTTPPORT/2059 HTTP/1.1
 Host: %HOSTIP:%HTTPPORT
-Authorization: Digest username="auser", realm="testrealm", nonce="1053604144", 
uri="/1001", response="6af4d89c952f4dd4cc215a6878dc499d"
+Authorization: Digest 
username="fddc3bc7b753b73ab0848fd83cb20cbbca971258eb8d20c941dd5e0b010d66be", 
realm="testrealm", nonce="1053604144", uri="/2059", 
response="fc09be8192851e284e73e8b719b32a2f6f91cca0594e68713da8c49dc2c1656e", 
algorithm="SHA-512-256", userhash=true
 Content-Range: bytes 2-4/5
 Accept: */*
 Proxy-Connection: Keep-Alive
diff --git a/tests/data/test1001 b/tests/data/test2060
similarity index 71%
copy from tests/data/test1001
copy to tests/data/test2060
index 91b13203e..f323eb520 100644
--- a/tests/data/test1001
+++ b/tests/data/test2060
@@ -21,7 +21,7 @@ X-Powered-By: ASP.NET
 
 HTTP/1.1 401 authentication please swsbounce
 Server: Microsoft-IIS/6.0
-WWW-Authenticate: Digest realm="testrealm", nonce="1053604144"
+WWW-Authenticate: Digest realm="testrealm", algorithm="SHA-512-256", 
nonce="1053604144"
 Content-Type: text/html; charset=iso-8859-1
 Content-Length: 0
 
@@ -43,7 +43,7 @@ X-Powered-By: ASP.NET
 
 HTTP/1.1 401 authentication please swsbounce
 Server: Microsoft-IIS/6.0
-WWW-Authenticate: Digest realm="testrealm", nonce="1053604144"
+WWW-Authenticate: Digest realm="testrealm", algorithm="SHA-512-256", 
nonce="1053604144"
 Content-Type: text/html; charset=iso-8859-1
 Content-Length: 0
 
@@ -68,12 +68,12 @@ http
 crypto
 </features>
  <name>
-HTTP POST --digest with PUT and resumed upload and modified method
+HTTP POST --digest with PUT, resumed upload, modified method, SHA-512-256 and 
userhash=false
  </name>
  <command>
-http://%HOSTIP:%HTTPPORT/1001 -u auser:apasswd --digest -T log/1001 -x  
http://%HOSTIP:%HTTPPORT -C 2 -X GET
+http://%HOSTIP:%HTTPPORT/2060 -u auser:apasswd --digest -T log/2060 -x  
http://%HOSTIP:%HTTPPORT -C 2 -X GET
 </command>
-<file name="log/1001">
+<file name="log/2060">
 test
 </file>
 </client>
@@ -84,7 +84,7 @@ test
 ^User-Agent:.*
 </strip>
 <protocol>
-GET http://%HOSTIP:%HTTPPORT/1001 HTTP/1.1
+GET http://%HOSTIP:%HTTPPORT/2060 HTTP/1.1
 Host: %HOSTIP:%HTTPPORT
 Content-Range: bytes 2-4/5
 User-Agent: curl/7.12.1-CVS (i686-pc-linux-gnu) libcurl/7.12.1-CVS 
OpenSSL/0.9.6b ipv6 zlib/1.1.4 GSS libidn/0.4.6
@@ -92,9 +92,9 @@ Accept: */*
 Proxy-Connection: Keep-Alive
 Content-Length: 0
 
-GET http://%HOSTIP:%HTTPPORT/1001 HTTP/1.1
+GET http://%HOSTIP:%HTTPPORT/2060 HTTP/1.1
 Host: %HOSTIP:%HTTPPORT
-Authorization: Digest username="auser", realm="testrealm", nonce="1053604144", 
uri="/1001", response="6af4d89c952f4dd4cc215a6878dc499d"
+Authorization: Digest username="auser", realm="testrealm", nonce="1053604144", 
uri="/2060", 
response="3ce1e25ffa611bdbe90e2ab367b9602fa223db9f6de76ac667f0d6157e2178a6", 
algorithm="SHA-512-256"
 Content-Range: bytes 2-4/5
 Accept: */*
 Proxy-Connection: Keep-Alive
diff --git a/tests/data/test64 b/tests/data/test2061
similarity index 74%
copy from tests/data/test64
copy to tests/data/test2061
index 804a6fa80..af3758c97 100644
--- a/tests/data/test64
+++ b/tests/data/test2061
@@ -11,7 +11,7 @@ HTTP Digest auth
 <data>
 HTTP/1.1 401 Authorization Required swsclose
 Server: Apache/1.3.27 (Darwin) PHP/4.1.2
-WWW-Authenticate: Digest realm="testrealm", nonce="1053604145"
+WWW-Authenticate: Digest realm="testrealm", nonce="1053604145", 
algorithm="SHA-256"
 Content-Type: text/html; charset=iso-8859-1
 Content-Length: 26
 
@@ -32,7 +32,7 @@ This IS the real page!
 <datacheck>
 HTTP/1.1 401 Authorization Required swsclose
 Server: Apache/1.3.27 (Darwin) PHP/4.1.2
-WWW-Authenticate: Digest realm="testrealm", nonce="1053604145"
+WWW-Authenticate: Digest realm="testrealm", nonce="1053604145", 
algorithm="SHA-256"
 Content-Type: text/html; charset=iso-8859-1
 Content-Length: 26
 
@@ -56,10 +56,10 @@ http
 crypto
 </features>
  <name>
-HTTP with Digest authorization
+HTTP with RFC7616 SHA256 Digest authorization
  </name>
  <command>
-http://%HOSTIP:%HTTPPORT/64 -u testuser:testpass --digest
+http://%HOSTIP:%HTTPPORT/2061 -u testuser:testpass --digest
 </command>
 </client>
 
@@ -69,13 +69,13 @@ http://%HOSTIP:%HTTPPORT/64 -u testuser:testpass --digest
 ^User-Agent:.*
 </strip>
 <protocol>
-GET /64 HTTP/1.1
+GET /2061 HTTP/1.1
 Host: %HOSTIP:%HTTPPORT
 Accept: */*
 
-GET /64 HTTP/1.1
+GET /2061 HTTP/1.1
 Host: %HOSTIP:%HTTPPORT
-Authorization: Digest username="testuser", realm="testrealm", 
nonce="1053604145", uri="/64", response="c55f7f30d83d774a3d2dcacf725abaca"
+Authorization: Digest username="testuser", realm="testrealm", 
nonce="1053604145", uri="/2061", 
response="9dc55255f1a2537b838311674b621d45346b862a81631bb20e4ce356ef25062d", 
algorithm="SHA-256"
 User-Agent: curl/7.10.5 (i686-pc-linux-gnu) libcurl/7.10.5 OpenSSL/0.9.7a ipv6 
zlib/1.1.3
 Accept: */*
 
diff --git a/tests/data/test64 b/tests/data/test2062
similarity index 73%
copy from tests/data/test64
copy to tests/data/test2062
index 804a6fa80..d5ce6899f 100644
--- a/tests/data/test64
+++ b/tests/data/test2062
@@ -11,7 +11,7 @@ HTTP Digest auth
 <data>
 HTTP/1.1 401 Authorization Required swsclose
 Server: Apache/1.3.27 (Darwin) PHP/4.1.2
-WWW-Authenticate: Digest realm="testrealm", nonce="1053604145"
+WWW-Authenticate: Digest realm="testrealm", nonce="1053604145", 
algorithm="SHA-512-256"
 Content-Type: text/html; charset=iso-8859-1
 Content-Length: 26
 
@@ -32,7 +32,7 @@ This IS the real page!
 <datacheck>
 HTTP/1.1 401 Authorization Required swsclose
 Server: Apache/1.3.27 (Darwin) PHP/4.1.2
-WWW-Authenticate: Digest realm="testrealm", nonce="1053604145"
+WWW-Authenticate: Digest realm="testrealm", nonce="1053604145", 
algorithm="SHA-512-256"
 Content-Type: text/html; charset=iso-8859-1
 Content-Length: 26
 
@@ -56,10 +56,10 @@ http
 crypto
 </features>
  <name>
-HTTP with Digest authorization
+HTTP with RFC7616 SHA-512-256 Digest authorization and userhash=false
  </name>
  <command>
-http://%HOSTIP:%HTTPPORT/64 -u testuser:testpass --digest
+http://%HOSTIP:%HTTPPORT/2062 -u testuser:testpass --digest
 </command>
 </client>
 
@@ -69,13 +69,13 @@ http://%HOSTIP:%HTTPPORT/64 -u testuser:testpass --digest
 ^User-Agent:.*
 </strip>
 <protocol>
-GET /64 HTTP/1.1
+GET /2062 HTTP/1.1
 Host: %HOSTIP:%HTTPPORT
 Accept: */*
 
-GET /64 HTTP/1.1
+GET /2062 HTTP/1.1
 Host: %HOSTIP:%HTTPPORT
-Authorization: Digest username="testuser", realm="testrealm", 
nonce="1053604145", uri="/64", response="c55f7f30d83d774a3d2dcacf725abaca"
+Authorization: Digest username="testuser", realm="testrealm", 
nonce="1053604145", uri="/2062", 
response="2af735ec3508f4dff99248ffbbe9de9002bfd7cc770cfa2b026cb334042a54e3", 
algorithm="SHA-512-256"
 User-Agent: curl/7.10.5 (i686-pc-linux-gnu) libcurl/7.10.5 OpenSSL/0.9.7a ipv6 
zlib/1.1.3
 Accept: */*
 
diff --git a/tests/data/test64 b/tests/data/test2063
similarity index 66%
copy from tests/data/test64
copy to tests/data/test2063
index 804a6fa80..220fe4ebe 100644
--- a/tests/data/test64
+++ b/tests/data/test2063
@@ -11,7 +11,7 @@ HTTP Digest auth
 <data>
 HTTP/1.1 401 Authorization Required swsclose
 Server: Apache/1.3.27 (Darwin) PHP/4.1.2
-WWW-Authenticate: Digest realm="testrealm", nonce="1053604145"
+WWW-Authenticate: Digest realm="testrealm", nonce="1053604145", 
algorithm="SHA-512-256", userhash=true
 Content-Type: text/html; charset=iso-8859-1
 Content-Length: 26
 
@@ -32,7 +32,7 @@ This IS the real page!
 <datacheck>
 HTTP/1.1 401 Authorization Required swsclose
 Server: Apache/1.3.27 (Darwin) PHP/4.1.2
-WWW-Authenticate: Digest realm="testrealm", nonce="1053604145"
+WWW-Authenticate: Digest realm="testrealm", nonce="1053604145", 
algorithm="SHA-512-256", userhash=true
 Content-Type: text/html; charset=iso-8859-1
 Content-Length: 26
 
@@ -56,10 +56,10 @@ http
 crypto
 </features>
  <name>
-HTTP with Digest authorization
+HTTP with RFC7616 SHA-512-256 Digest authorization and userhash=true
  </name>
  <command>
-http://%HOSTIP:%HTTPPORT/64 -u testuser:testpass --digest
+http://%HOSTIP:%HTTPPORT/2063 -u testuser:testpass --digest
 </command>
 </client>
 
@@ -69,13 +69,13 @@ http://%HOSTIP:%HTTPPORT/64 -u testuser:testpass --digest
 ^User-Agent:.*
 </strip>
 <protocol>
-GET /64 HTTP/1.1
+GET /2063 HTTP/1.1
 Host: %HOSTIP:%HTTPPORT
 Accept: */*
 
-GET /64 HTTP/1.1
+GET /2063 HTTP/1.1
 Host: %HOSTIP:%HTTPPORT
-Authorization: Digest username="testuser", realm="testrealm", 
nonce="1053604145", uri="/64", response="c55f7f30d83d774a3d2dcacf725abaca"
+Authorization: Digest 
username="75af8a3500f771e58a52093a25e7905d6e428a511285c12ea1420c73078dfd61", 
realm="testrealm", nonce="1053604145", uri="/2063", 
response="43f7ab531dff687b5dc75617daa59d1fd67d648341d6d2655ca65ef5064cfb51", 
algorithm="SHA-512-256", userhash=true
 User-Agent: curl/7.10.5 (i686-pc-linux-gnu) libcurl/7.10.5 OpenSSL/0.9.7a ipv6 
zlib/1.1.3
 Accept: */*
 
diff --git a/tests/data/test65 b/tests/data/test2064
similarity index 74%
copy from tests/data/test65
copy to tests/data/test2064
index f0b974213..aa20c0bc0 100644
--- a/tests/data/test65
+++ b/tests/data/test2064
@@ -11,7 +11,7 @@ HTTP Digest auth
 <data>
 HTTP/1.1 401 Authorization Required
 Server: Apache/1.3.27 (Darwin) PHP/4.1.2
-WWW-Authenticate: Digest realm="testrealm", nonce="2053604145"
+WWW-Authenticate: Digest realm="testrealm", nonce="2053604145", 
algorithm="SHA-256"
 Content-Type: text/html; charset=iso-8859-1
 Content-Length: 26
 
@@ -32,7 +32,7 @@ This is not the real page either
 <datacheck>
 HTTP/1.1 401 Authorization Required
 Server: Apache/1.3.27 (Darwin) PHP/4.1.2
-WWW-Authenticate: Digest realm="testrealm", nonce="2053604145"
+WWW-Authenticate: Digest realm="testrealm", nonce="2053604145", 
algorithm="SHA-256"
 Content-Type: text/html; charset=iso-8859-1
 Content-Length: 26
 
@@ -56,10 +56,10 @@ http
 crypto
 </features>
  <name>
-HTTP with Digest authorization with bad password
+HTTP with RFC7616 Digest authorization with bad password and SHA256
  </name>
  <command>
-http://%HOSTIP:%HTTPPORT/65 -u testuser:test2pass --digest
+http://%HOSTIP:%HTTPPORT/2064 -u testuser:test2pass --digest
 </command>
 </client>
 
@@ -69,13 +69,13 @@ http://%HOSTIP:%HTTPPORT/65 -u testuser:test2pass --digest
 ^User-Agent:.*
 </strip>
 <protocol>
-GET /65 HTTP/1.1
+GET /2064 HTTP/1.1
 Host: %HOSTIP:%HTTPPORT
 Accept: */*
 
-GET /65 HTTP/1.1
+GET /2064 HTTP/1.1
 Host: %HOSTIP:%HTTPPORT
-Authorization: Digest username="testuser", realm="testrealm", 
nonce="2053604145", uri="/65", response="66d68d3251f1839576ba7c766cf9205b"
+Authorization: Digest username="testuser", realm="testrealm", 
nonce="2053604145", uri="/2064", 
response="a9c3ec1036068b336cbabefe9dfcad52ee8b89bc7c91ddbb5bb415c6acdf38a5", 
algorithm="SHA-256"
 User-Agent: curl/7.10.5 (i686-pc-linux-gnu) libcurl/7.10.5 OpenSSL/0.9.7a ipv6 
zlib/1.1.3
 Accept: */*
 
diff --git a/tests/data/test65 b/tests/data/test2065
similarity index 73%
copy from tests/data/test65
copy to tests/data/test2065
index f0b974213..d3afe0b13 100644
--- a/tests/data/test65
+++ b/tests/data/test2065
@@ -11,7 +11,7 @@ HTTP Digest auth
 <data>
 HTTP/1.1 401 Authorization Required
 Server: Apache/1.3.27 (Darwin) PHP/4.1.2
-WWW-Authenticate: Digest realm="testrealm", nonce="2053604145"
+WWW-Authenticate: Digest realm="testrealm", nonce="2053604145", 
algorithm="SHA-512-256"
 Content-Type: text/html; charset=iso-8859-1
 Content-Length: 26
 
@@ -32,7 +32,7 @@ This is not the real page either
 <datacheck>
 HTTP/1.1 401 Authorization Required
 Server: Apache/1.3.27 (Darwin) PHP/4.1.2
-WWW-Authenticate: Digest realm="testrealm", nonce="2053604145"
+WWW-Authenticate: Digest realm="testrealm", nonce="2053604145", 
algorithm="SHA-512-256"
 Content-Type: text/html; charset=iso-8859-1
 Content-Length: 26
 
@@ -56,10 +56,10 @@ http
 crypto
 </features>
  <name>
-HTTP with Digest authorization with bad password
+HTTP with RFC7616 Digest authorization with bad password, SHA-512-256 and 
userhash=false
  </name>
  <command>
-http://%HOSTIP:%HTTPPORT/65 -u testuser:test2pass --digest
+http://%HOSTIP:%HTTPPORT/2065 -u testuser:test2pass --digest
 </command>
 </client>
 
@@ -69,13 +69,13 @@ http://%HOSTIP:%HTTPPORT/65 -u testuser:test2pass --digest
 ^User-Agent:.*
 </strip>
 <protocol>
-GET /65 HTTP/1.1
+GET /2065 HTTP/1.1
 Host: %HOSTIP:%HTTPPORT
 Accept: */*
 
-GET /65 HTTP/1.1
+GET /2065 HTTP/1.1
 Host: %HOSTIP:%HTTPPORT
-Authorization: Digest username="testuser", realm="testrealm", 
nonce="2053604145", uri="/65", response="66d68d3251f1839576ba7c766cf9205b"
+Authorization: Digest username="testuser", realm="testrealm", 
nonce="2053604145", uri="/2065", 
response="5a5f20b0e601aeddc6f96422c2332d49ff431c49ab143b5f836ef76e9ac78f5e", 
algorithm="SHA-512-256"
 User-Agent: curl/7.10.5 (i686-pc-linux-gnu) libcurl/7.10.5 OpenSSL/0.9.7a ipv6 
zlib/1.1.3
 Accept: */*
 
diff --git a/tests/data/test65 b/tests/data/test2066
similarity index 66%
copy from tests/data/test65
copy to tests/data/test2066
index f0b974213..e6ec28a1e 100644
--- a/tests/data/test65
+++ b/tests/data/test2066
@@ -11,7 +11,7 @@ HTTP Digest auth
 <data>
 HTTP/1.1 401 Authorization Required
 Server: Apache/1.3.27 (Darwin) PHP/4.1.2
-WWW-Authenticate: Digest realm="testrealm", nonce="2053604145"
+WWW-Authenticate: Digest realm="testrealm", nonce="2053604145", 
algorithm="SHA-512-256", userhash=true
 Content-Type: text/html; charset=iso-8859-1
 Content-Length: 26
 
@@ -32,7 +32,7 @@ This is not the real page either
 <datacheck>
 HTTP/1.1 401 Authorization Required
 Server: Apache/1.3.27 (Darwin) PHP/4.1.2
-WWW-Authenticate: Digest realm="testrealm", nonce="2053604145"
+WWW-Authenticate: Digest realm="testrealm", nonce="2053604145", 
algorithm="SHA-512-256", userhash=true
 Content-Type: text/html; charset=iso-8859-1
 Content-Length: 26
 
@@ -56,10 +56,10 @@ http
 crypto
 </features>
  <name>
-HTTP with Digest authorization with bad password
+HTTP with RFC7616 Digest authorization with bad password, SHA-512-256 and 
userhash=true
  </name>
  <command>
-http://%HOSTIP:%HTTPPORT/65 -u testuser:test2pass --digest
+http://%HOSTIP:%HTTPPORT/2066 -u testuser:test2pass --digest
 </command>
 </client>
 
@@ -69,13 +69,13 @@ http://%HOSTIP:%HTTPPORT/65 -u testuser:test2pass --digest
 ^User-Agent:.*
 </strip>
 <protocol>
-GET /65 HTTP/1.1
+GET /2066 HTTP/1.1
 Host: %HOSTIP:%HTTPPORT
 Accept: */*
 
-GET /65 HTTP/1.1
+GET /2066 HTTP/1.1
 Host: %HOSTIP:%HTTPPORT
-Authorization: Digest username="testuser", realm="testrealm", 
nonce="2053604145", uri="/65", response="66d68d3251f1839576ba7c766cf9205b"
+Authorization: Digest 
username="75af8a3500f771e58a52093a25e7905d6e428a511285c12ea1420c73078dfd61", 
realm="testrealm", nonce="2053604145", uri="/2066", 
response="a2e2ae589f575fb132991d6f550ef14bf7ef697d2fef1242d2498f07eafc77dc", 
algorithm="SHA-512-256", userhash=true
 User-Agent: curl/7.10.5 (i686-pc-linux-gnu) libcurl/7.10.5 OpenSSL/0.9.7a ipv6 
zlib/1.1.3
 Accept: */*
 
diff --git a/tests/data/test1284 b/tests/data/test2067
similarity index 75%
copy from tests/data/test1284
copy to tests/data/test2067
index 8437a4082..faa7c57fa 100644
--- a/tests/data/test1284
+++ b/tests/data/test2067
@@ -12,7 +12,7 @@ HTTP Digest auth
 <data>
 HTTP/1.1 401 authentication please swsbounce
 Server: Microsoft-IIS/6.0
-WWW-Authenticate: Digest realm="testrealm", nonce="1053604144"
+WWW-Authenticate: Digest realm="testrealm", nonce="1053604144", 
algorithm="SHA-256"
 Content-Type: text/html; charset=iso-8859-1
 Content-Length: 0
 
@@ -29,7 +29,7 @@ ok
 <datacheck>
 HTTP/1.1 401 authentication please swsbounce
 Server: Microsoft-IIS/6.0
-WWW-Authenticate: Digest realm="testrealm", nonce="1053604144"
+WWW-Authenticate: Digest realm="testrealm", nonce="1053604144", 
algorithm="SHA-256"
 Content-Type: text/html; charset=iso-8859-1
 Content-Length: 0
 
@@ -54,13 +54,13 @@ http
 crypto
 </features>
 <name>
-HTTP POST --digest with user-specified Content-Length header
+HTTP POST --digest with SHA256 and user-specified Content-Length header
 </name>
 # This test is to ensure 'Content-Length: 0' is sent while negotiating auth
 # even when there is a user-specified Content-Length header.
 # https://github.com/curl/curl/pull/1242
 <command>
--H "Content-Length: 11" -u auser:apasswd --digest -d "junkelijunk" 
http://%HOSTIP:%HTTPPORT/1284
+-H "Content-Length: 11" -u auser:apasswd --digest -d "junkelijunk" 
http://%HOSTIP:%HTTPPORT/2067
 </command>
 </client>
 
@@ -70,15 +70,15 @@ HTTP POST --digest with user-specified Content-Length header
 ^User-Agent:.*
 </strip>
 <protocol nonewline="yes">
-POST /1284 HTTP/1.1
+POST /2067 HTTP/1.1
 Host: %HOSTIP:%HTTPPORT
 Accept: */*
 Content-Length: 0
 Content-Type: application/x-www-form-urlencoded
 
-POST /1284 HTTP/1.1
+POST /2067 HTTP/1.1
 Host: %HOSTIP:%HTTPPORT
-Authorization: Digest username="auser", realm="testrealm", nonce="1053604144", 
uri="/1284", response="5763079608de439072861a59ac733515"
+Authorization: Digest username="auser", realm="testrealm", nonce="1053604144", 
uri="/2067", 
response="67b97af219c92fa7e8685e5bebb8e74892f6c6792e911c52bd2dfbf0b49272eb", 
algorithm="SHA-256"
 Accept: */*
 Content-Length: 11
 Content-Type: application/x-www-form-urlencoded
diff --git a/tests/data/test1284 b/tests/data/test2068
similarity index 74%
copy from tests/data/test1284
copy to tests/data/test2068
index 8437a4082..43a50e626 100644
--- a/tests/data/test1284
+++ b/tests/data/test2068
@@ -12,7 +12,7 @@ HTTP Digest auth
 <data>
 HTTP/1.1 401 authentication please swsbounce
 Server: Microsoft-IIS/6.0
-WWW-Authenticate: Digest realm="testrealm", nonce="1053604144"
+WWW-Authenticate: Digest realm="testrealm", nonce="1053604144", 
algorithm="SHA-512-256"
 Content-Type: text/html; charset=iso-8859-1
 Content-Length: 0
 
@@ -29,7 +29,7 @@ ok
 <datacheck>
 HTTP/1.1 401 authentication please swsbounce
 Server: Microsoft-IIS/6.0
-WWW-Authenticate: Digest realm="testrealm", nonce="1053604144"
+WWW-Authenticate: Digest realm="testrealm", nonce="1053604144", 
algorithm="SHA-512-256"
 Content-Type: text/html; charset=iso-8859-1
 Content-Length: 0
 
@@ -54,13 +54,13 @@ http
 crypto
 </features>
 <name>
-HTTP POST --digest with user-specified Content-Length header
+HTTP POST --digest with SHA-512-256, userhash=false and user-specified 
Content-Length header
 </name>
 # This test is to ensure 'Content-Length: 0' is sent while negotiating auth
 # even when there is a user-specified Content-Length header.
 # https://github.com/curl/curl/pull/1242
 <command>
--H "Content-Length: 11" -u auser:apasswd --digest -d "junkelijunk" 
http://%HOSTIP:%HTTPPORT/1284
+-H "Content-Length: 11" -u auser:apasswd --digest -d "junkelijunk" 
http://%HOSTIP:%HTTPPORT/2068
 </command>
 </client>
 
@@ -70,15 +70,15 @@ HTTP POST --digest with user-specified Content-Length header
 ^User-Agent:.*
 </strip>
 <protocol nonewline="yes">
-POST /1284 HTTP/1.1
+POST /2068 HTTP/1.1
 Host: %HOSTIP:%HTTPPORT
 Accept: */*
 Content-Length: 0
 Content-Type: application/x-www-form-urlencoded
 
-POST /1284 HTTP/1.1
+POST /2068 HTTP/1.1
 Host: %HOSTIP:%HTTPPORT
-Authorization: Digest username="auser", realm="testrealm", nonce="1053604144", 
uri="/1284", response="5763079608de439072861a59ac733515"
+Authorization: Digest username="auser", realm="testrealm", nonce="1053604144", 
uri="/2068", 
response="4bc9c97a72f1856bcec9b0e1518c6b7ee28773f91357d56840bdc30bd89ca68f", 
algorithm="SHA-512-256"
 Accept: */*
 Content-Length: 11
 Content-Type: application/x-www-form-urlencoded
diff --git a/tests/data/test1284 b/tests/data/test2069
similarity index 67%
copy from tests/data/test1284
copy to tests/data/test2069
index 8437a4082..e8040a5e0 100644
--- a/tests/data/test1284
+++ b/tests/data/test2069
@@ -12,7 +12,7 @@ HTTP Digest auth
 <data>
 HTTP/1.1 401 authentication please swsbounce
 Server: Microsoft-IIS/6.0
-WWW-Authenticate: Digest realm="testrealm", nonce="1053604144"
+WWW-Authenticate: Digest realm="testrealm", nonce="1053604144", 
algorithm="SHA-512-256", userhash=true
 Content-Type: text/html; charset=iso-8859-1
 Content-Length: 0
 
@@ -29,7 +29,7 @@ ok
 <datacheck>
 HTTP/1.1 401 authentication please swsbounce
 Server: Microsoft-IIS/6.0
-WWW-Authenticate: Digest realm="testrealm", nonce="1053604144"
+WWW-Authenticate: Digest realm="testrealm", nonce="1053604144", 
algorithm="SHA-512-256", userhash=true
 Content-Type: text/html; charset=iso-8859-1
 Content-Length: 0
 
@@ -54,13 +54,13 @@ http
 crypto
 </features>
 <name>
-HTTP POST --digest with user-specified Content-Length header
+HTTP POST --digest with SHA-512-256, userhash=true and user-specified 
Content-Length header
 </name>
 # This test is to ensure 'Content-Length: 0' is sent while negotiating auth
 # even when there is a user-specified Content-Length header.
 # https://github.com/curl/curl/pull/1242
 <command>
--H "Content-Length: 11" -u auser:apasswd --digest -d "junkelijunk" 
http://%HOSTIP:%HTTPPORT/1284
+-H "Content-Length: 11" -u auser:apasswd --digest -d "junkelijunk" 
http://%HOSTIP:%HTTPPORT/2069
 </command>
 </client>
 
@@ -70,15 +70,15 @@ HTTP POST --digest with user-specified Content-Length header
 ^User-Agent:.*
 </strip>
 <protocol nonewline="yes">
-POST /1284 HTTP/1.1
+POST /2069 HTTP/1.1
 Host: %HOSTIP:%HTTPPORT
 Accept: */*
 Content-Length: 0
 Content-Type: application/x-www-form-urlencoded
 
-POST /1284 HTTP/1.1
+POST /2069 HTTP/1.1
 Host: %HOSTIP:%HTTPPORT
-Authorization: Digest username="auser", realm="testrealm", nonce="1053604144", 
uri="/1284", response="5763079608de439072861a59ac733515"
+Authorization: Digest 
username="fddc3bc7b753b73ab0848fd83cb20cbbca971258eb8d20c941dd5e0b010d66be", 
realm="testrealm", nonce="1053604144", uri="/2069", 
response="ff13d977110a471f30de75e747976e4de78d7a3d2425cd23ff46e67f4bc9ead7", 
algorithm="SHA-512-256", userhash=true
 Accept: */*
 Content-Length: 11
 Content-Type: application/x-www-form-urlencoded
diff --git a/tests/data/test200 b/tests/data/test2070
similarity index 77%
copy from tests/data/test200
copy to tests/data/test2070
index 8be1de0c7..bc3898ab3 100644
--- a/tests/data/test200
+++ b/tests/data/test2070
@@ -21,12 +21,12 @@ moo
 file
 </server>
  <name>
-basic file:// file
+basic file:// file with no authority
  </name>
  <command>
-file://localhost/%PWD/log/test200.txt
+file:%PWD/log/test2070.txt
 </command>
-<file name="log/test200.txt">
+<file name="log/test2070.txt">
 foo
    bar
 bar
diff --git a/tests/data/test203 b/tests/data/test2071
similarity index 73%
copy from tests/data/test203
copy to tests/data/test2071
index 366cc2cd0..997dfffeb 100644
--- a/tests/data/test203
+++ b/tests/data/test2071
@@ -5,7 +5,6 @@ FILE
 </keywords>
 </info>
 
-# Server-side
 <reply>
 <data>
 foo
@@ -22,12 +21,12 @@ moo
 file
 </server>
  <name>
-file:/path URL with a single slash
+basic file:// file with "127.0.0.1" hostname
  </name>
  <command>
-file:%PWD/log/test203.txt
+file://127.0.0.1/%PWD/log/test2070.txt
 </command>
-<file name="log/test203.txt">
+<file name="log/test2070.txt">
 foo
    bar
 bar
diff --git a/tests/data/test1145 b/tests/data/test2072
similarity index 70%
copy from tests/data/test1145
copy to tests/data/test2072
index 287bebfcc..2949c2502 100644
--- a/tests/data/test1145
+++ b/tests/data/test2072
@@ -14,12 +14,10 @@ FILE
 file
 </server>
 <name>
-file:// bad host
+file:// with SMB path
 </name>
-# This command should not succeed since we only accept
-# file:/// file://localhost/ file://127.0.0.1/
 <command>
-file://bad-host%PWD/log/test1145.txt
+file:////bad-host%PWD/log/test1145.txt
 </command>
 <file name="log/test1145.txt">
 foo
diff --git a/tests/data/test220 b/tests/data/test220
index 2fb0b8a6a..7fd264345 100644
--- a/tests/data/test220
+++ b/tests/data/test220
@@ -57,11 +57,14 @@ http://%HOSTIP:%HTTPPORT/220 --compressed
 <strip>
 ^User-Agent:.*
 </strip>
+<strippart>
+s/^Accept-Encoding: .*/Accept-Encoding: xxx/
+</strippart>
 <protocol>
 GET /220 HTTP/1.1
 Host: %HOSTIP:%HTTPPORT
 Accept: */*
-Accept-Encoding: deflate, gzip
+Accept-Encoding: xxx
 
 </protocol>
 </verify>
diff --git a/tests/data/test221 b/tests/data/test221
index 95edb4990..3a85439d0 100644
--- a/tests/data/test221
+++ b/tests/data/test221
@@ -57,11 +57,14 @@ http://%HOSTIP:%HTTPPORT/221 --compressed
 <strip>
 ^User-Agent:.*
 </strip>
+<strippart>
+s/^Accept-Encoding: .*/Accept-Encoding: xxx/
+</strippart>
 <protocol>
 GET /221 HTTP/1.1
 Host: %HOSTIP:%HTTPPORT
 Accept: */*
-Accept-Encoding: deflate, gzip
+Accept-Encoding: xxx
 
 </protocol>
 <errorcode>
diff --git a/tests/data/test222 b/tests/data/test222
index a4594869e..865266e07 100644
--- a/tests/data/test222
+++ b/tests/data/test222
@@ -188,11 +188,14 @@ http://%HOSTIP:%HTTPPORT/222 --compressed
 <strip>
 ^User-Agent:.*
 </strip>
+<strippart>
+s/^Accept-Encoding: .*/Accept-Encoding: xxx/
+</strippart>
 <protocol>
 GET /222 HTTP/1.1
 Host: %HOSTIP:%HTTPPORT
 Accept: */*
-Accept-Encoding: deflate, gzip
+Accept-Encoding: xxx
 
 </protocol>
 </verify>
diff --git a/tests/data/test223 b/tests/data/test223
index 196e78c80..884967e3f 100644
--- a/tests/data/test223
+++ b/tests/data/test223
@@ -78,11 +78,14 @@ http://%HOSTIP:%HTTPPORT/223 --compressed
 <strip>
 ^User-Agent:.*
 </strip>
+<strippart>
+s/^Accept-Encoding: .*/Accept-Encoding: xxx/
+</strippart>
 <protocol>
 GET /223 HTTP/1.1
 Host: %HOSTIP:%HTTPPORT
 Accept: */*
-Accept-Encoding: deflate, gzip
+Accept-Encoding: xxx
 
 </protocol>
 <errorcode>
diff --git a/tests/data/test224 b/tests/data/test224
index 1c8ad2380..a56046873 100644
--- a/tests/data/test224
+++ b/tests/data/test224
@@ -93,11 +93,14 @@ http://%HOSTIP:%HTTPPORT/224 --compressed
 <strip>
 ^User-Agent:.*
 </strip>
+<strippart>
+s/^Accept-Encoding: .*/Accept-Encoding: xxx/
+</strippart>
 <protocol>
 GET /224 HTTP/1.1
 Host: %HOSTIP:%HTTPPORT
 Accept: */*
-Accept-Encoding: deflate, gzip
+Accept-Encoding: xxx
 
 </protocol>
 </verify>
diff --git a/tests/data/test1123 b/tests/data/test230
similarity index 73%
copy from tests/data/test1123
copy to tests/data/test230
index bd441a995..2174434b3 100644
--- a/tests/data/test1123
+++ b/tests/data/test230
@@ -4,7 +4,6 @@
 HTTP
 HTTP GET
 compressed
-Transfer-Encoding
 </keywords>
 </info>
 #
@@ -15,30 +14,31 @@ 
SFRUUC8xLjEgMjAwIE9LDQpEYXRlOiBNb24sIDI5IE5vdiAyMDA0IDIxOjU2OjUzIEdNVA0KU2Vy
 dmVyOiBBcGFjaGUvMS4zLjMxIChEZWJpYW4gR05VL0xpbnV4KSBtb2RfZ3ppcC8xLjMuMjYuMWEg
 UEhQLzQuMy45LTEgbW9kX3NzbC8yLjguMjAgT3BlblNTTC8wLjkuN2QgbW9kX3BlcmwvMS4yOQ0K
 VmFyeTogQWNjZXB0LUVuY29kaW5nDQpDb250ZW50LVR5cGU6IHRleHQvaHRtbDsgY2hhcnNldD1J
-U08tODg1OS0xDQpUcmFuc2Zlci1FbmNvZGluZzogZGVmbGF0ZQ0KQ29udGVudC1MZW5ndGg6IDEz
-MDUNCg0KeJzcWNtu4zYQfTeQf2D91AK2brYTOXC0KHLZBM02wdoFuk8GLdE2G0kUSMq5PPTbO5Qo
-ibEcr3eDvgRIYnLmnMPhDEmTmXx6SmK0IVxQlp51XcvpIpKGLKLp6qx7M73r+/5o3He7n4LO5JeL
-u/PZt/tLlHH2DwllP6ZCAhBNv01nl19Qdy1ldmrbS07EOiFYWimR9gKHDySN7GXS1zzRd6yhFcmo
-C6JbWkEHocqm2k1vTqPAPXa9iW0YSkSEJZnjKCKAGI/9vuP3PRc5w1PHPfXGE9vwG4Q8Ux9R4DnO
-sO86fddHjnfqwc9AUyrEqzhSnJC5WDMugzDncR2OYW/jl3kcF3CE0wjFdNGmFhAdHhGhljpnSVJS
-UoIkY7UAx/wZLRlHYUxJKvuCRgT99fUWSY5TsYSKWjCLRshQ3hkMogLhcgSlWqlwVd8ljYk46uRC
-ddQY4jmV+MlCNxKJPMtAX6Dr2ey+V/yd9tAVtI86V0X74uZ81kOzy9s/L+Hz9uJ3gF3d3F72iuE/
-391fX36FNgzwSGKIqZTqZ0zInm7m0AoZe6BEFNooz2KGIxgCllqekKiZdQ9lWIhHxiPVhMjSPFkU
-9un09qgTEi7pkoZQVzD9QTj4mChDgWo8wQjFtCAbGXsknERHncVzlaQekmvyZsarslhHndkaqAjD
-74KmajMJSG2dapVgBpsOec5RJ8bpKscrIooYSLqhnKUJDCBAR5fQWBsbKnFM5fNchIyTYHTiD63R
-ycTesm+BM8JDkAwGlntsYCvzFhrm8wB7bWwgC5Ne1yzLY8ybsY5HY4hhCMt529MiVAO6A8t3XxFe
-h2I4ymCc0Su0EQ7HxbnhWyNnYuuO6ZmHLAddz6282vAKUw7iD2qMMYDIFyLkNJNwRIpgoE6H16YS
-BqVPw/Vc7eXggixxHsuJbRpLGNR/Xh1gGZQ92HloVielrdaLPbFbrEZszRLythAsYMpLFXV42iZD
-69YCjaZcvRwuB2CtpGiNyOLFO1wEwFpE0RqRF5odLgJgLaJojUi4hj1GYrY6XKqmaMFGopHlWXK4
-IIC1lKI1IhFZHC4CYC2iaI0IE0+HiwBYiyiaUS8RqfPyB2pWEqq6abqxzHMOaRMk0Ou36hqF2Ygf
-KMlGVMXYCENE3RwOV1FoLVMQG52Ecs744UolXmtpslnXhAVVraBZemIKhxyk4MvNzP4bncPpASmj
-eYJuS8fErhAar76n5JyTmNSZa5nn+v4WnFiuZ8EF6Q33G2x1rzo5dvxRi1hdsNocdS/afXHaBSzn
-Yu+azATOUQITXjM5l2v4qoactUwlEucSbjKiDqnsV93aoE9gnFISo6kkKXzDrya26WxRoEq76/7v
-Aq8ioopsIFt0zmIS3D2mhNe4wlRFapuhVr1qCasveE4TmmJpzk5yuCEUtYGC1p2W1/OO97kHe7n7
-nK7v7+W6e8eFpbE/6r1u93i4zz3eS/bHe73OXrc7+k7c3wlsf2SD1tjl/W67/LAmMngywUMMrqO1
-Tm18RvI5I2ddTkJ4HSibeknVi7LBmRvZUUPtcuwk6nsLuE+Gqhg7XTuZxuOsRd1+uL3FlVSqDQV2
-uLOjX/Vt6redWiW23mkN4u28seLehuP/L2nOT2dsOHhnxtT76uMnyvUGI/cdmXqBp9jHz9LAc4Yn
-78jSNaFJhOOPn6jhcDTw3pGosA9PffEzeTIs+qyv/ysUdP4DAAD//4IzEaNjAAAAAP//AwDdOI7R
+U08tODg1OS0xDQpDb250ZW50LUVuY29kaW5nOiBkZWZsYXRlLCBpZGVudGl0eSwgZ3ppcA0KQ29u
+dGVudC1MZW5ndGg6IDEzMjgNCg0KH4sIAPpl+lkAAwEZBeb6eJzcWNtu4zYQfTeQf2D91AK2brYT
+OXC0KHLZBM02wdoFuk8GLdE2G0kUSMq5PPTbO5QoibEcr3eDvgRIYnLmnMPhDEmTmXx6SmK0IVxQ
+lp51XcvpIpKGLKLp6qx7M73r+/5o3He7n4LO5JeLu/PZt/tLlHH2DwllP6ZCAhBNv01nl19Qdy1l
+dmrbS07EOiFYWimR9gKHDySN7GXS1zzRd6yhFcmoC6JbWkEHocqm2k1vTqPAPXa9iW0YSkSEJZnj
+KCKAGI/9vuP3PRc5w1PHPfXGE9vwG4Q8Ux9R4DnOsO86fddHjnfqwc9AUyrEqzhSnJC5WDMugzDn
+cR2OYW/jl3kcF3CE0wjFdNGmFhAdHhGhljpnSVJSUoIkY7UAx/wZLRlHYUxJKvuCRgT99fUWSY5T
+sYSKWjCLRshQ3hkMogLhcgSlWqlwVd8ljYk46uRCddQY4jmV+MlCNxKJPMtAX6Dr2ey+V/yd9tAV
+tI86V0X74uZ81kOzy9s/L+Hz9uJ3gF3d3F72iuE/391fX36FNgzwSGKIqZTqZ0zInm7m0AoZe6BE
+FNooz2KGIxgCllqekKiZdQ9lWIhHxiPVhMjSPFkU9un09qgTEi7pkoZQVzD9QTj4mChDgWo8wQjF
+tCAbGXsknERHncVzlaQekmvyZsarslhHndkaqAjD74KmajMJSG2dapVgBpsOec5RJ8bpKscrIooY
+SLqhnKUJDCBAR5fQWBsbKnFM5fNchIyTYHTiD63RycTesm+BM8JDkAwGlntsYCvzFhrm8wB7bWwg
+C5Ne1yzLY8ybsY5HY4hhCMt529MiVAO6A8t3XxFeh2I4ymCc0Su0EQ7HxbnhWyNnYuuO6ZmHLAdd
+z6282vAKUw7iD2qMMYDIFyLkNJNwRIpgoE6H16YSBqVPw/Vc7eXggixxHsuJbRpLGNR/Xh1gGZQ9
+2HloVielrdaLPbFbrEZszRLythAsYMpLFXV42iZD69YCjaZcvRwuB2CtpGiNyOLFO1wEwFpE0RqR
+F5odLgJgLaJojUi4hj1GYrY6XKqmaMFGopHlWXK4IIC1lKI1IhFZHC4CYC2iaI0IE0+HiwBYiyia
+US8RqfPyB2pWEqq6abqxzHMOaRMk0Ou36hqF2YgfKMlGVMXYCENE3RwOV1FoLVMQG52Ecs744Uol
+XmtpslnXhAVVraBZemIKhxyk4MvNzP4bncPpASmjeYJuS8fErhAar76n5JyTmNSZa5nn+v4WnFiu
+Z8EF6Q33G2x1rzo5dvxRi1hdsNocdS/afXHaBSznYu+azATOUQITXjM5l2v4qoactUwlEucSbjKi
+DqnsV93aoE9gnFISo6kkKXzDrya26WxRoEq76/7vAq8ioopsIFt0zmIS3D2mhNe4wlRFapuhVr1q
+CasveE4TmmJpzk5yuCEUtYGC1p2W1/OO97kHe7n7nK7v7+W6e8eFpbE/6r1u93i4zz3eS/bHe73O
+Xrc7+k7c3wlsf2SD1tjl/W67/LAmMngywUMMrqO1Tm18RvI5I2ddTkJ4HSibeknVi7LBmRvZUUPt
+cuwk6nsLuE+Gqhg7XTuZxuOsRd1+uL3FlVSqDQV2uLOjX/Vt6redWiW23mkN4u28seLehuP/L2nO
+T2dsOHhnxtT76uMnyvUGI/cdmXqBp9jHz9LAc4Yn78jSNaFJhOOPn6jhcDTw3pGosA9PffEzeTIs
++qyv/ysUdP4DAAD//4IzEaNjAAAAAP//AwDdOI7RbCh2MRkFAAA=
 </data>
 
 <datacheck>
@@ -47,8 +47,8 @@ Date: Mon, 29 Nov 2004 21:56:53 GMT
 Server: Apache/1.3.31 (Debian GNU/Linux) mod_gzip/1.3.26.1a PHP/4.3.9-1 
mod_ssl/2.8.20 OpenSSL/0.9.7d mod_perl/1.29
 Vary: Accept-Encoding
 Content-Type: text/html; charset=ISO-8859-1
-Transfer-Encoding: deflate
-Content-Length: 1305
+Content-Encoding: deflate, identity, gzip
+Content-Length: 1328
 
 <?xml version="1.0" encoding="ISO-8859-1"?>
 <!DOCTYPE project-listing SYSTEM 
"http://freshmeat.net/backend/fm-projects-0.4.dtd";>
@@ -176,10 +176,10 @@ libz
 http
 </server>
  <name>
-HTTP GET deflate transfer-encoded content
+HTTP GET multiply compressed content
  </name>
  <command>
-http://%HOSTIP:%HTTPPORT/1123 --tr-encoding
+http://%HOSTIP:%HTTPPORT/230 --compressed
 </command>
 </client>
 
@@ -189,12 +189,14 @@ http://%HOSTIP:%HTTPPORT/1123 --tr-encoding
 <strip>
 ^User-Agent:.*
 </strip>
+<strippart>
+s/^Accept-Encoding: .*/Accept-Encoding: xxx/
+</strippart>
 <protocol>
-GET /1123 HTTP/1.1
+GET /230 HTTP/1.1
 Host: %HOSTIP:%HTTPPORT
 Accept: */*
-Connection: TE
-TE: gzip
+Accept-Encoding: xxx
 
 </protocol>
 </verify>
diff --git a/tests/data/test222 b/tests/data/test314
similarity index 74%
copy from tests/data/test222
copy to tests/data/test314
index a4594869e..f4703cdeb 100644
--- a/tests/data/test222
+++ b/tests/data/test314
@@ -14,30 +14,26 @@ 
SFRUUC8xLjEgMjAwIE9LDQpEYXRlOiBNb24sIDI5IE5vdiAyMDA0IDIxOjU2OjUzIEdNVA0KU2Vy
 dmVyOiBBcGFjaGUvMS4zLjMxIChEZWJpYW4gR05VL0xpbnV4KSBtb2RfZ3ppcC8xLjMuMjYuMWEg
 UEhQLzQuMy45LTEgbW9kX3NzbC8yLjguMjAgT3BlblNTTC8wLjkuN2QgbW9kX3BlcmwvMS4yOQ0K
 VmFyeTogQWNjZXB0LUVuY29kaW5nDQpDb250ZW50LVR5cGU6IHRleHQvaHRtbDsgY2hhcnNldD1J
-U08tODg1OS0xDQpDb250ZW50LUVuY29kaW5nOiBkZWZsYXRlDQpDb250ZW50LUxlbmd0aDogMTMw
-NQ0KDQp4nNxY227jNhB9N5B/YP3UArZuthM5cLQoctkEzTbB2gW6TwYt0TYbSRRIyrk89Ns7lCiJ
-sRyvd4O+BEhicuacw+EMSZOZfHpKYrQhXFCWnnVdy+kikoYsounqrHszvev7/mjcd7ufgs7kl4u7
-89m3+0uUcfYPCWU/pkICEE2/TWeXX1B3LWV2attLTsQ6IVhaKZH2AocPJI3sZdLXPNF3rKEVyagL
-oltaQQehyqbaTW9Oo8A9dr2JbRhKRIQlmeMoIoAYj/2+4/c9FznDU8c99cYT2/AbhDxTH1HgOc6w
-7zp910eOd+rBz0BTKsSrOFKckLlYMy6DMOdxHY5hb+OXeRwXcITTCMV00aYWEB0eEaGWOmdJUlJS
-giRjtQDH/BktGUdhTEkq+4JGBP319RZJjlOxhIpaMItGyFDeGQyiAuFyBKVaqXBV3yWNiTjq5EJ1
-1BjiOZX4yUI3Eok8y0BfoOvZ7L5X/J320BW0jzpXRfvi5nzWQ7PL2z8v4fP24neAXd3cXvaK4T/f
-3V9ffoU2DPBIYoiplOpnTMiebubQChl7oEQU2ijPYoYjGAKWWp6QqJl1D2VYiEfGI9WEyNI8WRT2
-6fT2qBMSLumShlBXMP1BOPiYKEOBajzBCMW0IBsZeyScREedxXOVpB6Sa/JmxquyWEed2RqoCMPv
-gqZqMwlIbZ1qlWAGmw55zlEnxukqxysiihhIuqGcpQkMIEBHl9BYGxsqcUzl81yEjJNgdOIPrdHJ
-xN6yb4EzwkOQDAaWe2xgK/MWGubzAHttbCALk17XLMtjzJuxjkdjiGEIy3nb0yJUA7oDy3dfEV6H
-YjjKYJzRK7QRDsfFueFbI2di647pmYcsB13Prbza8ApTDuIPaowxgMgXIuQ0k3BEimCgTofXphIG
-pU/D9Vzt5eCCLHEey4ltGksY1H9eHWAZlD3YeWhWJ6Wt1os9sVusRmzNEvK2ECxgyksVdXjaJkPr
-1gKNply9HC4HYK2kaI3I4sU7XATAWkTRGpEXmh0uAmAtomiNSLiGPUZitjpcqqZowUaikeVZcrgg
-gLWUojUiEVkcLgJgLaJojQgTT4eLAFiLKJpRLxGp8/IHalYSqrppurHMcw5pEyTQ67fqGoXZiB8o
-yUZUxdgIQ0TdHA5XUWgtUxAbnYRyzvjhSiVea2myWdeEBVWtoFl6YgqHHKTgy83M/hudw+kBKaN5
-gm5Lx8SuEBqvvqfknJOY1Jlrmef6/hacWK5nwQXpDfcbbHWvOjl2/FGLWF2w2hx1L9p9cdoFLOdi
-75rMBM5RAhNeMzmXa/iqhpy1TCUS5xJuMqIOqexX3dqgT2CcUhKjqSQpfMOvJrbpbFGgSrvr/u8C
-ryKiimwgW3TOYhLcPaaE17jCVEVqm6FWvWoJqy94ThOaYmnOTnK4IRS1gYLWnZbX8473uQd7ufuc
-ru/v5bp7x4WlsT/qvW73eLjPPd5L9sd7vc5etzv6TtzfCWx/ZIPW2OX9brv8sCYyeDLBQwyuo7VO
-bXxG8jkjZ11OQngdKJt6SdWLssGZG9lRQ+1y7CTqewu4T4aqGDtdO5nG46xF3X64vcWVVKoNBXa4
-s6Nf9W3qt51aJbbeaQ3i7byx4t6G4/8vac5PZ2w4eGfG1Pvq4yfK9QYj9x2ZeoGn2MfP0sBzhifv
-yNI1oUmE44+fqOFwNPDekaiwD0998TN5Miz6rK//KxR0/gMAAP//gjMRo2MAAAAA//8DAN04jtE=
+U08tODg1OS0xDQpDb250ZW50LUVuY29kaW5nOiBicg0KQ29udGVudC1MZW5ndGg6IDEwNTYNCg0K
+G7ATAJwFdhtdgaQ8i+mZBoO/lwogPKuqHpeP38jV5TDITTB7/oJVCS69FFDKWDVtMk8y4SfMSu/a
+9vvLxWPweDCKePH/2y9VIkbF+EgCYSNs9v53J8QTIHT4ZucHCCRQiXRdT6XdE60KSlbIvobr5rJQ
+sRn7ipIjMVMq3Go+/UXtY2d0yP1qaaGSxCn8nZuUNGh74KOI7EEkgFl1tjYytkpc9mJJy9J+wTTI
++HroUQP2VR2DYkNoUECqgtOLlGcVEln4+eVzEWcrb8fNrcrVxLArJBpSd8FX8eZs8ebJUO7aBZ5e
+pHz6zel7lhLlfHoQIkGh34riaSVr7VTGDmmO6HjSCzKO27LybZ9I3CtMSD2Il4mB131Tlcbut1Bd
+zL4XU4DZYMLBN4jwVZEoHpjzHX+vQ3prnrNw4oB7OWOr/fBzjvfjDuO24WxwzPqPo+V6VNcthz1p
+fF1+sMK4yWY7He33m32EuQgQFSZ3a5Wu4FyQcAb45Z+wUxM5XCmX52YmdUR2YTs+W+bNw2EZSfMR
+cP3CinyJI/cTT+JubL3T4COkhz0Rffeoh/3E4c/6ugma1ubhokYecXp8HBwmeDL48d62H26u69DO
+yMhg1PFj+oVDWnK4K+L5AlRr0mpJLqoGHrzflMLQ6qL2oIo9hN6qCeZEEqXM+/KunVYpWVeTY+ht
+hA0y5p5RLLTTS4cehaJOpbFyAVxZOardIkJAVx0NshOZY4hDbts9BXsXzFEOgsFhrIQYgh04StZz
+llIRMVDptYlwGmpZCHHmVECdGiFIfEhkQ2INSwMCuuKpaycgSOO9hJA9UFKDBdzTiLJBP9oUVkKL
+bHjwicICCi3k0HcppcvQaW27AMI06kuQU4WUGizgnkaUDcZqCgsotMgG528UFlBo8SFpb05OAjJq
+2gEI0UgN93KS1OvAOYSLN5IaLOCeRnQpJXuLUwcm7urpg6lYxAk26uEoADdsRytHGkSWjOKP6T07
+wiceuNo7CXyu7ohtUZXoEWawRHGVkPDVJYqH+xa0DDRKSSgM4K3efLVPSTaUPvBGIZgnn2JBFFWa
+MsKZguUuUnz6qaSGqnmGAYiupdC1EFye58V4CLbWVjJU4NF2jrOUYR/Dv04zYwVQtQcFzgmK6H4N
+HAhmb0a6pQRKxZaZ+x2vCC7sCuIu4dNCATwqzk12ue6oEsxzYybLPNGJd084M43O9W8E+5/drd/F
+QVB2X4jlFlCuHuWeQxQo+w73Tb9swW692v3BlfQTP1ClWzuJ+RwuSb9m4V3QVa4MEL+0Xzc5FX9P
++YX1cgaL+6oMHw7L+IOjOt+n1BOloyqk35lLHX7RZmu8SckMnGP95XjWc4FRKP9x/iXrKaeCnut/
+zstyZdJS5FRmBT/wb5KK9YWBGnqPLO8isN2HS8gA
 </data>
 
 <datacheck>
@@ -46,8 +42,8 @@ Date: Mon, 29 Nov 2004 21:56:53 GMT
 Server: Apache/1.3.31 (Debian GNU/Linux) mod_gzip/1.3.26.1a PHP/4.3.9-1 
mod_ssl/2.8.20 OpenSSL/0.9.7d mod_perl/1.29
 Vary: Accept-Encoding
 Content-Type: text/html; charset=ISO-8859-1
-Content-Encoding: deflate
-Content-Length: 1305
+Content-Encoding: br
+Content-Length: 1056
 
 <?xml version="1.0" encoding="ISO-8859-1"?>
 <!DOCTYPE project-listing SYSTEM 
"http://freshmeat.net/backend/fm-projects-0.4.dtd";>
@@ -169,16 +165,16 @@ languages and environments.
 # Client-side
 <client>
 <features>
-libz
+brotli
 </features>
 <server>
 http
 </server>
  <name>
-HTTP GET deflate compressed content
+HTTP GET brotli compressed content
  </name>
  <command>
-http://%HOSTIP:%HTTPPORT/222 --compressed
+http://%HOSTIP:%HTTPPORT/314 --compressed
 </command>
 </client>
 
@@ -188,11 +184,14 @@ http://%HOSTIP:%HTTPPORT/222 --compressed
 <strip>
 ^User-Agent:.*
 </strip>
+<strippart>
+s/^Accept-Encoding: .*/Accept-Encoding: xxx/
+</strippart>
 <protocol>
-GET /222 HTTP/1.1
+GET /314 HTTP/1.1
 Host: %HOSTIP:%HTTPPORT
 Accept: */*
-Accept-Encoding: deflate, gzip
+Accept-Encoding: xxx
 
 </protocol>
 </verify>
diff --git a/tests/data/test315 b/tests/data/test315
new file mode 100644
index 000000000..c75d9ae7b
--- /dev/null
+++ b/tests/data/test315
@@ -0,0 +1,91 @@
+<testcase>
+<info>
+<keywords>
+HTTP
+HTTP GET
+compressed
+FAILURE
+</keywords>
+</info>
+#
+# Server-side
+<reply>
+# this brotli chunk has three bytes removed from the beginning
+<data base64="yes">
+SFRUUC8xLjEgMjAwIE9LDQpEYXRlOiBNb24sIDI5IE5vdiAyMDA0IDIxOjU2OjUzIEdNVA0KU2Vy
+dmVyOiBBcGFjaGUvMS4zLjMxIChEZWJpYW4gR05VL0xpbnV4KSBtb2RfZ3ppcC8xLjMuMjYuMWEg
+UEhQLzQuMy45LTEgbW9kX3NzbC8yLjguMjAgT3BlblNTTC8wLjkuN2QgbW9kX3BlcmwvMS4yOQ0K
+VmFyeTogQWNjZXB0LUVuY29kaW5nDQpDb250ZW50LVR5cGU6IHRleHQvaHRtbDsgY2hhcnNldD1J
+U08tODg1OS0xDQpDb250ZW50LUVuY29kaW5nOiBicg0KQ29udGVudC1MZW5ndGg6IDEwNTYNCg0K
+AJwFdhtdgaQ8i+mZBoO/lwogPKuqHpeP38jV5TDITTB7/oJVCS69FFDKWDVtMk8y4SfMSu/a9vvL
+xWPweDCKePH/2y9VIkbF+EgCYSNs9v53J8QTIHT4ZucHCCRQiXRdT6XdE60KSlbIvobr5rJQsRn7
+ipIjMVMq3Go+/UXtY2d0yP1qaaGSxCn8nZuUNGh74KOI7EEkgFl1tjYytkpc9mJJy9J+wTTI+Hro
+UQP2VR2DYkNoUECqgtOLlGcVEln4+eVzEWcrb8fNrcrVxLArJBpSd8FX8eZs8ebJUO7aBZ5epHz6
+zel7lhLlfHoQIkGh34riaSVr7VTGDmmO6HjSCzKO27LybZ9I3CtMSD2Il4mB131Tlcbut1BdzL4X
+U4DZYMLBN4jwVZEoHpjzHX+vQ3prnrNw4oB7OWOr/fBzjvfjDuO24WxwzPqPo+V6VNcthz1pfF1+
+sMK4yWY7He33m32EuQgQFSZ3a5Wu4FyQcAb45Z+wUxM5XCmX52YmdUR2YTs+W+bNw2EZSfMRcP3C
+inyJI/cTT+JubL3T4COkhz0Rffeoh/3E4c/6ugma1ubhokYecXp8HBwmeDL48d62H26u69DOyMhg
+1PFj+oVDWnK4K+L5AlRr0mpJLqoGHrzflMLQ6qL2oIo9hN6qCeZEEqXM+/KunVYpWVeTY+hthA0y
+5p5RLLTTS4cehaJOpbFyAVxZOardIkJAVx0NshOZY4hDbts9BXsXzFEOgsFhrIQYgh04StZzllIR
+MVDptYlwGmpZCHHmVECdGiFIfEhkQ2INSwMCuuKpaycgSOO9hJA9UFKDBdzTiLJBP9oUVkKLbHjw
+icICCi3k0HcppcvQaW27AMI06kuQU4WUGizgnkaUDcZqCgsotMgG528UFlBo8SFpb05OAjJq2gEI
+0UgN93KS1OvAOYSLN5IaLOCeRnQpJXuLUwcm7urpg6lYxAk26uEoADdsRytHGkSWjOKP6T07wice
+uNo7CXyu7ohtUZXoEWawRHGVkPDVJYqH+xa0DDRKSSgM4K3efLVPSTaUPvBGIZgnn2JBFFWaMsKZ
+guUuUnz6qaSGqnmGAYiupdC1EFye58V4CLbWVjJU4NF2jrOUYR/Dv04zYwVQtQcFzgmK6H4NHAhm
+b0a6pQRKxZaZ+x2vCC7sCuIu4dNCATwqzk12ue6oEsxzYybLPNGJd084M43O9W8E+5/drd/FQVB2
+X4jlFlCuHuWeQxQo+w73Tb9swW692v3BlfQTP1ClWzuJ+RwuSb9m4V3QVa4MEL+0Xzc5FX9P+YX1
+cgaL+6oMHw7L+IOjOt+n1BOloyqk35lLHX7RZmu8SckMnGP95XjWc4FRKP9x/iXrKaeCnut/zsty
+ZdJS5FRmBT/wb5KK9YWBGnqPLO8isN2HS8gA
+</data>
+
+<datacheck>
+HTTP/1.1 200 OK
+Date: Mon, 29 Nov 2004 21:56:53 GMT
+Server: Apache/1.3.31 (Debian GNU/Linux) mod_gzip/1.3.26.1a PHP/4.3.9-1 
mod_ssl/2.8.20 OpenSSL/0.9.7d mod_perl/1.29
+Vary: Accept-Encoding
+Content-Type: text/html; charset=ISO-8859-1
+Content-Encoding: br
+Content-Length: 1056
+
+</datacheck>
+
+</reply>
+
+#
+# Client-side
+<client>
+<features>
+brotli
+</features>
+<server>
+http
+</server>
+ <name>
+HTTP GET brotli compressed content with broken header
+ </name>
+ <command>
+http://%HOSTIP:%HTTPPORT/315 --compressed
+</command>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+<strip>
+^User-Agent:.*
+</strip>
+<strippart>
+s/^Accept-Encoding: .*/Accept-Encoding: xxx/
+</strippart>
+<protocol>
+GET /315 HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+Accept: */*
+Accept-Encoding: xxx
+
+</protocol>
+<errorcode>
+61
+</errorcode>
+</verify>
+</testcase>
diff --git a/tests/libtest/Makefile.inc b/tests/libtest/Makefile.inc
index 230416763..9e1ba28a9 100644
--- a/tests/libtest/Makefile.inc
+++ b/tests/libtest/Makefile.inc
@@ -27,7 +27,7 @@ noinst_PROGRAMS = chkhostname libauthretry libntlmconnect     
           \
  lib1525 lib1526 lib1527 lib1528 lib1529 lib1530 lib1531 lib1532 lib1533 \
  lib1534 lib1535 lib1536 lib1537 lib1538 \
  lib1540 \
- lib1550 lib1551 lib1552 lib1553 \
+ lib1550 lib1551 lib1552 lib1553 lib1554 \
  lib1900 \
  lib2033
 
@@ -464,11 +464,16 @@ lib1551_SOURCES = lib1551.c $(SUPPORTFILES)
 lib1551_CPPFLAGS = $(AM_CPPFLAGS)
 
 lib1552_SOURCES = lib1552.c $(SUPPORTFILES) $(TESTUTIL)
+lib1552_LDADD = $(TESTUTIL_LIBS)
 lib1552_CPPFLAGS = $(AM_CPPFLAGS)
 
 lib1553_SOURCES = lib1553.c $(SUPPORTFILES) $(TESTUTIL)
+lib1553_LDADD = $(TESTUTIL_LIBS)
 lib1553_CPPFLAGS = $(AM_CPPFLAGS)
 
+lib1554_SOURCES = lib1554.c $(SUPPORTFILES)
+lib1554_CPPFLAGS = $(AM_CPPFLAGS)
+
 lib1900_SOURCES = lib1900.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
 lib1900_LDADD = $(TESTUTIL_LIBS)
 lib1900_CPPFLAGS = $(AM_CPPFLAGS)
diff --git a/tests/libtest/lib1554.c b/tests/libtest/lib1554.c
new file mode 100644
index 000000000..aa4aeb732
--- /dev/null
+++ b/tests/libtest/lib1554.c
@@ -0,0 +1,81 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <address@hidden>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "test.h"
+#include "memdebug.h"
+
+static void my_lock(CURL *handle, curl_lock_data data,
+                    curl_lock_access laccess, void *useptr)
+{
+  (void)handle;
+  (void)data;
+  (void)laccess;
+  (void)useptr;
+  printf("-> Mutex lock\n");
+}
+
+static void my_unlock(CURL *handle, curl_lock_data data, void *useptr)
+{
+  (void)handle;
+  (void)data;
+  (void)useptr;
+  printf("<- Mutex unlock\n");
+}
+
+/* test function */
+int test(char *URL)
+{
+  CURL *curl;
+  CURLcode res;
+  CURLSH *share;
+  int i;
+
+  share = curl_share_init();
+  curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT);
+  curl_share_setopt(share, CURLSHOPT_LOCKFUNC, my_lock);
+  curl_share_setopt(share, CURLSHOPT_UNLOCKFUNC, my_unlock);
+
+  /* Loop the transfer and cleanup the handle properly every lap. This will
+     still reuse connections since the pool is in the shared object! */
+
+  for(i = 0; i < 3; i++) {
+    curl = curl_easy_init();
+    if(curl) {
+      curl_easy_setopt(curl, CURLOPT_URL, URL);
+
+      /* use the share object */
+      curl_easy_setopt(curl, CURLOPT_SHARE, share);
+
+      /* Perform the request, res will get the return code */
+      res = curl_easy_perform(curl);
+      /* Check for errors */
+      if(res != CURLE_OK)
+        fprintf(stderr, "curl_easy_perform() failed: %s\n",
+                curl_easy_strerror(res));
+
+      /* always cleanup */
+      curl_easy_cleanup(curl);
+    }
+  }
+
+  curl_share_cleanup(share);
+  return 0;
+}
diff --git a/tests/libtest/lib501.c b/tests/libtest/lib501.c
index 7a2341246..af65bd4d7 100644
--- a/tests/libtest/lib501.c
+++ b/tests/libtest/lib501.c
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <address@hidden>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <address@hidden>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -44,6 +44,9 @@ int test(char *URL)
 
   test_setopt(curl, CURLOPT_HEADER, 1L);
 
+  /* just verify that setting this to -1 is fine */
+  test_setopt(curl, CURLOPT_MAXREDIRS, -1L);
+
   res = curl_easy_perform(curl);
 
 test_cleanup:
diff --git a/tests/libtest/lib556.c b/tests/libtest/lib556.c
index f06c5299c..acb0f63d1 100644
--- a/tests/libtest/lib556.c
+++ b/tests/libtest/lib556.c
@@ -95,8 +95,8 @@ int test(char *URL)
       } while((res == CURLE_OK && iolen != 0) || (res == CURLE_AGAIN));
     }
 
-    if(res != CURLE_OK || iolen != 0)
-      return TEST_ERR_FAILURE;
+    if(iolen != 0)
+      res = TEST_ERR_FAILURE;
   }
 
 test_cleanup:
diff --git a/tests/libtest/lib650.c b/tests/libtest/lib650.c
index 60a2e9f1d..da1fd5672 100644
--- a/tests/libtest/lib650.c
+++ b/tests/libtest/lib650.c
@@ -33,7 +33,7 @@ static char data[] =
   "this is what we post to the silly web server";
 #endif
 
-static char name[] = "fieldname";
+static const char name[] = "fieldname";
 
 
 /* This test attempts to use all form API features that are not
@@ -53,10 +53,10 @@ static size_t count_chars(void *userp, const char *buf, 
size_t len)
 
 int test(char *URL)
 {
-  CURL *curl;
-  CURLcode res = CURLE_OK;
+  CURL *curl = NULL;
+  CURLcode res = TEST_ERR_MAJOR_BAD;
   CURLFORMcode formrc;
-  struct curl_slist *headers = NULL;
+  struct curl_slist *headers, *headers2 = NULL;
   struct curl_httppost *formpost = NULL;
   struct curl_httppost *lastptr = NULL;
   struct curl_forms formarray[3];
@@ -69,17 +69,30 @@ int test(char *URL)
   }
 
   /* Check proper name and data copying, as well as headers. */
-  headers = curl_slist_append(headers, "X-customheader-1: Header 1 data");
-  headers = curl_slist_append(headers, "X-customheader-2: Header 2 data");
-  headers = curl_slist_append(headers, "Content-Type: text/plain");
+  headers = curl_slist_append(NULL, "X-customheader-1: Header 1 data");
+  if(!headers) {
+    goto test_cleanup;
+  }
+  headers2 = curl_slist_append(headers, "X-customheader-2: Header 2 data");
+  if(!headers2) {
+    goto test_cleanup;
+  }
+  headers = headers2;
+  headers2 = curl_slist_append(headers, "Content-Type: text/plain");
+  if(!headers2) {
+    goto test_cleanup;
+  }
+  headers = headers2;
   formrc = curl_formadd(&formpost, &lastptr,
                         CURLFORM_COPYNAME, &name,
                         CURLFORM_COPYCONTENTS, &data,
                         CURLFORM_CONTENTHEADER, headers,
                         CURLFORM_END);
 
-  if(formrc)
+  if(formrc) {
     printf("curl_formadd(1) = %d\n", (int) formrc);
+    goto test_cleanup;
+  }
 
   /* Use a form array for the non-copy test. */
   formarray[0].option = CURLFORM_PTRCONTENTS;
@@ -96,8 +109,10 @@ int test(char *URL)
                         CURLFORM_FILENAME, "remotefile.txt",
                         CURLFORM_END);
 
-  if(formrc)
+  if(formrc) {
     printf("curl_formadd(2) = %d\n", (int) formrc);
+    goto test_cleanup;
+  }
 
   /* Now change in-memory data to affect CURLOPT_PTRCONTENTS value.
      Copied values (first field) must not be affected.
@@ -114,8 +129,10 @@ int test(char *URL)
                         CURLFORM_FILE, libtest_arg2,
                         CURLFORM_END);
 
-  if(formrc)
+  if(formrc) {
     printf("curl_formadd(3) = %d\n", (int) formrc);
+    goto test_cleanup;
+  }
 
   /* Check data from file content. */
   formrc = curl_formadd(&formpost,
@@ -124,8 +141,10 @@ int test(char *URL)
                         CURLFORM_FILECONTENT, libtest_arg2,
                         CURLFORM_END);
 
-  if(formrc)
+  if(formrc) {
     printf("curl_formadd(4) = %d\n", (int) formrc);
+    goto test_cleanup;
+  }
 
   /* Measure the current form length.
    * This is done before including stdin data because we want to reuse it
@@ -140,6 +159,10 @@ int test(char *URL)
                         CURLFORM_COPYNAME, "formlength",
                         CURLFORM_COPYCONTENTS, &flbuf,
                         CURLFORM_END);
+  if(formrc) {
+    printf("curl_formadd(5) = %d\n", (int) formrc);
+    goto test_cleanup;
+  }
 
   /* Check stdin (may be problematic on some platforms). */
   formrc = curl_formadd(&formpost,
@@ -147,17 +170,15 @@ int test(char *URL)
                         CURLFORM_COPYNAME, "standardinput",
                         CURLFORM_FILE, "-",
                         CURLFORM_END);
-
-  if(formrc)
-    printf("curl_formadd(5) = %d\n", (int) formrc);
+  if(formrc) {
+    printf("curl_formadd(6) = %d\n", (int) formrc);
+    goto test_cleanup;
+  }
 
   curl = curl_easy_init();
   if(!curl) {
     fprintf(stderr, "curl_easy_init() failed\n");
-    curl_slist_free_all(headers);
-    curl_formfree(formpost);
-    curl_global_cleanup();
-    return TEST_ERR_MAJOR_BAD;
+    goto test_cleanup;
   }
 
   /* First set the URL that is about to receive our POST. */
diff --git a/tests/runtests.pl b/tests/runtests.pl
index a886a28f9..827b759e3 100755
--- a/tests/runtests.pl
+++ b/tests/runtests.pl
@@ -217,6 +217,7 @@ my $gopher_ipv6;    # set if Gopher server has IPv6 support
 my $has_ipv6;       # set if libcurl is built with IPv6 support
 my $has_unix;       # set if libcurl is built with Unix sockets support
 my $has_libz;       # set if libcurl is built with libz support
+my $has_brotli;     # set if libcurl is built with brotli support
 my $has_getrlimit;  # set if system has getrlimit()
 my $has_ntlm;       # set if libcurl is built with NTLM support
 my $has_ntlm_wb;    # set if libcurl is built with NTLM delegation to winbind
@@ -601,7 +602,7 @@ sub torture {
             my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
                 localtime(time());
             my $now = sprintf("%02d:%02d:%02d ", $hour, $min, $sec);
-            logmsg "Fail funcion no: $limit at $now\r";
+            logmsg "Fail function no: $limit at $now\r";
         }
 
         # make the memory allocation function number $limit return failure
@@ -2880,6 +2881,9 @@ sub checksystem {
             if($feat =~ /libz/i) {
                 $has_libz = 1;
             }
+            if($feat =~ /brotli/i) {
+                $has_brotli = 1;
+            }
             if($feat =~ /NTLM/i) {
                 # NTLM enabled
                 $has_ntlm=1;
@@ -3396,6 +3400,11 @@ sub singletest {
                     next;
                 }
             }
+            elsif($1 eq "brotli") {
+                if($has_brotli) {
+                    next;
+                }
+            }
             elsif($1 eq "NTLM") {
                 if($has_ntlm) {
                     next;
@@ -3552,6 +3561,11 @@ sub singletest {
                         next;
                     }
                 }
+                elsif($1 eq "brotli") {
+                    if(!$has_brotli) {
+                        next;
+                    }
+                }
                 elsif($1 eq "NTLM") {
                     if(!$has_ntlm) {
                         next;
diff --git a/tests/server/Makefile.inc b/tests/server/Makefile.inc
index c3ea664b6..208aa0fc8 100644
--- a/tests/server/Makefile.inc
+++ b/tests/server/Makefile.inc
@@ -4,14 +4,12 @@ CURLX_SRCS = \
  ../../lib/mprintf.c \
  ../../lib/nonblock.c \
  ../../lib/strtoofft.c \
- ../../lib/timeval.c \
  ../../lib/warnless.c
 
 CURLX_HDRS = \
  ../../lib/curlx.h \
  ../../lib/nonblock.h \
  ../../lib/strtoofft.h \
- ../../lib/timeval.h \
  ../../lib/warnless.h
 
 USEFUL = \
diff --git a/tests/server/util.c b/tests/server/util.c
index 1bbd89a3c..fdbd71f0f 100644
--- a/tests/server/util.c
+++ b/tests/server/util.c
@@ -67,6 +67,8 @@ const struct in6_addr in6addr_any = {{ IN6ADDR_ANY_INIT }};
 #endif /* w32api < 3.6 */
 #endif /* ENABLE_IPV6 && __MINGW32__*/
 
+static struct timeval tvnow(void);
+
 /* This function returns a pointer to STATIC memory. It converts the given
  * binary lump to a hex formatted string usable for output in logs or
  * whatever.
@@ -100,7 +102,7 @@ void logmsg(const char *msg, ...)
   char buffer[2048 + 1];
   FILE *logfp;
   int error;
-  struct curltime tv;
+  struct timeval tv;
   time_t sec;
   struct tm *now;
   char timebuf[20];
@@ -112,7 +114,7 @@ void logmsg(const char *msg, ...)
     return;
   }
 
-  tv = curlx_tvnow();
+  tv = tvnow();
   if(!known_offset) {
     epoch_offset = time(NULL) - tv.tv_sec;
     known_offset = 1;
@@ -213,7 +215,7 @@ int wait_ms(int timeout_ms)
 #ifndef HAVE_POLL_FINE
   struct timeval pending_tv;
 #endif
-  struct curltime initial_tv;
+  struct timeval initial_tv;
   int pending_ms;
   int error;
 #endif
@@ -231,7 +233,7 @@ int wait_ms(int timeout_ms)
   Sleep(timeout_ms);
 #else
   pending_ms = timeout_ms;
-  initial_tv = curlx_tvnow();
+  initial_tv = tvnow();
   do {
 #if defined(HAVE_POLL_FINE)
     r = poll(NULL, 0, pending_ms);
@@ -245,7 +247,7 @@ int wait_ms(int timeout_ms)
     error = errno;
     if(error && (error != EINTR))
       break;
-    pending_ms = timeout_ms - (int)curlx_tvdiff(curlx_tvnow(), initial_tv);
+    pending_ms = timeout_ms - (int)timediff(tvnow(), initial_tv);
     if(pending_ms <= 0)
       break;
   } while(r == -1);
@@ -397,3 +399,102 @@ int strncasecompare(const char *first, const char 
*second, size_t max)
 
   return raw_toupper(*first) == raw_toupper(*second);
 }
+
+#if defined(WIN32) && !defined(MSDOS)
+
+static struct timeval tvnow(void)
+{
+  /*
+  ** GetTickCount() is available on _all_ Windows versions from W95 up
+  ** to nowadays. Returns milliseconds elapsed since last system boot,
+  ** increases monotonically and wraps once 49.7 days have elapsed.
+  **
+  ** GetTickCount64() is available on Windows version from Windows Vista
+  ** and Windows Server 2008 up to nowadays. The resolution of the
+  ** function is limited to the resolution of the system timer, which
+  ** is typically in the range of 10 milliseconds to 16 milliseconds.
+  */
+  struct timeval now;
+#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600)
+  ULONGLONG milliseconds = GetTickCount64();
+#else
+  DWORD milliseconds = GetTickCount();
+#endif
+  now.tv_sec = (long)(milliseconds / 1000);
+  now.tv_usec = (milliseconds % 1000) * 1000;
+  return now;
+}
+
+#elif defined(HAVE_CLOCK_GETTIME_MONOTONIC)
+
+static struct timeval tvnow(void)
+{
+  /*
+  ** clock_gettime() is granted to be increased monotonically when the
+  ** monotonic clock is queried. Time starting point is unspecified, it
+  ** could be the system start-up time, the Epoch, or something else,
+  ** in any case the time starting point does not change once that the
+  ** system has started up.
+  */
+  struct timeval now;
+  struct timespec tsnow;
+  if(0 == clock_gettime(CLOCK_MONOTONIC, &tsnow)) {
+    now.tv_sec = tsnow.tv_sec;
+    now.tv_usec = tsnow.tv_nsec / 1000;
+  }
+  /*
+  ** Even when the configure process has truly detected monotonic clock
+  ** availability, it might happen that it is not actually available at
+  ** run-time. When this occurs simply fallback to other time source.
+  */
+#ifdef HAVE_GETTIMEOFDAY
+  else
+    (void)gettimeofday(&now, NULL);
+#else
+  else {
+    now.tv_sec = (long)time(NULL);
+    now.tv_usec = 0;
+  }
+#endif
+  return now;
+}
+
+#elif defined(HAVE_GETTIMEOFDAY)
+
+static struct timeval tvnow(void)
+{
+  /*
+  ** gettimeofday() is not granted to be increased monotonically, due to
+  ** clock drifting and external source time synchronization it can jump
+  ** forward or backward in time.
+  */
+  struct timeval now;
+  (void)gettimeofday(&now, NULL);
+  return now;
+}
+
+#else
+
+static struct timeval tvnow(void)
+{
+  /*
+  ** time() returns the value of time in seconds since the Epoch.
+  */
+  struct timeval now;
+  now.tv_sec = (long)time(NULL);
+  now.tv_usec = 0;
+  return now;
+}
+
+#endif
+
+long timediff(struct timeval newer, struct timeval older)
+{
+  timediff_t diff = newer.tv_sec-older.tv_sec;
+  if(diff >= (LONG_MAX/1000))
+    return LONG_MAX;
+  else if(diff <= (LONG_MIN/1000))
+    return LONG_MIN;
+  return (long)(newer.tv_sec-older.tv_sec)*1000+
+    (long)(newer.tv_usec-older.tv_usec)/1000;
+}
diff --git a/tests/server/util.h b/tests/server/util.h
index a2a56badd..7b4ec1626 100644
--- a/tests/server/util.h
+++ b/tests/server/util.h
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <address@hidden>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <address@hidden>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -25,6 +25,7 @@
 
 char *data_to_hex(char *data, size_t len);
 void logmsg(const char *msg, ...);
+long timediff(struct timeval newer, struct timeval older);
 
 #define TEST_DATA_PATH "%s/data/test%ld"
 
diff --git a/tests/unit/unit1323.c b/tests/unit/unit1323.c
index 7bb4cca40..1adb27494 100644
--- a/tests/unit/unit1323.c
+++ b/tests/unit/unit1323.c
@@ -50,7 +50,7 @@ UNITTEST_START
   size_t i;
 
   for(i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) {
-    time_t result = curlx_tvdiff(tests[i].first, tests[i].second);
+    timediff_t result = Curl_timediff(tests[i].first, tests[i].second);
     if(result != tests[i].result) {
       printf("%d.%06u to %d.%06u got %d, but expected %d\n",
              tests[i].first.tv_sec,
diff --git a/tests/unit/unit1399.c b/tests/unit/unit1399.c
index 91fd3dae1..897a34319 100644
--- a/tests/unit/unit1399.c
+++ b/tests/unit/unit1399.c
@@ -80,7 +80,7 @@ static void expect_timer_seconds(struct Curl_easy *data, int 
seconds)
  * be 3 seconds. */
 UNITTEST_START
   struct Curl_easy data;
-  struct curltime now = Curl_tvnow();
+  struct curltime now = Curl_now();
 
   data.progress.t_nslookup = 0;
   data.progress.t_connect = 0;

-- 
To stop receiving notification emails like this one, please contact
address@hidden



reply via email to

[Prev in Thread] Current Thread [Next in Thread]