[Cmake-commits] CMake branch, next, updated. v3.6.1-1102-g13ce471

Brad King brad.king at kitware.com
Wed Aug 3 15:08:44 EDT 2016


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "CMake".

The branch, next has been updated
       via  13ce471eee787ca728646f4eec102f5ffc327efa (commit)
       via  f59ab43370dc9bff7e6480032c95505cdd00e3cd (commit)
       via  f53f4a8a2d215dac634effea575a27e000dfcb29 (commit)
       via  202adcfe056681109fe61569ecdb3bd69f0b4f97 (commit)
       via  e1c11352f231ae310339cd539ed59cb302bd4dbe (commit)
       via  a51c6c5394169f34480e7261ef666eb4bf898c67 (commit)
       via  7ec709d3d7cc988d4cf6dc2c49713d4c55f09542 (commit)
       via  3e9b03439f6fa16abf555f37016e0f45f2073b78 (commit)
      from  f07f592ef88d4db60780a737c78b2fc0aae3fec7 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=13ce471eee787ca728646f4eec102f5ffc327efa
commit 13ce471eee787ca728646f4eec102f5ffc327efa
Merge: f07f592 f59ab43
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Wed Aug 3 15:08:31 2016 -0400
Commit:     CMake Topic Stage <kwrobot at kitware.com>
CommitDate: Wed Aug 3 15:08:31 2016 -0400

    Merge topic 'update-curl' into next
    
    f59ab433 curl: Remove CMake-specific README
    f53f4a8a Merge branch 'upstream-curl' into update-curl
    202adcfe curl 2016-08-03 (f2cb3a01)
    e1c11352 curl: Update script to get curl 7.50.1
    a51c6c53 Merge branch 'upstream-curl' into update-curl
    7ec709d3 curl 2015-08-11 (1a7f66a3)
    3e9b0343 Add script to update curl from upstream


https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=f59ab43370dc9bff7e6480032c95505cdd00e3cd
commit f59ab43370dc9bff7e6480032c95505cdd00e3cd
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Wed Aug 3 14:31:05 2016 -0400
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Wed Aug 3 14:31:05 2016 -0400

    curl: Remove CMake-specific README
    
    We will now manage the curl source tree updates using
    the `Utilities/Scripts/update-curl.bash` script.  Drop
    the README that covered the old method.

diff --git a/Utilities/cmcurl/README-CMake.txt b/Utilities/cmcurl/README-CMake.txt
deleted file mode 100644
index 1e75672..0000000
--- a/Utilities/cmcurl/README-CMake.txt
+++ /dev/null
@@ -1,66 +0,0 @@
-The Utilities/cmcurl directory contains a reduced distribution
-of the curl source tree with only the library source code and
-CMake build system.  It is not a submodule; the actual content is part
-of our source tree and changes can be made and committed directly.
-
-We update from upstream using Git's "subtree" merge strategy.  A
-special branch contains commits of upstream curl snapshots and
-nothing else.  No Git ref points explicitly to the head of this
-branch, but it is merged into our history.
-
-Update curl from upstream as follows.  Create a local branch to
-explicitly reference the upstream snapshot branch head:
-
- git branch curl-upstream 70654261
-
-Use a temporary directory to checkout the branch:
-
- mkdir curl-tmp
- cd curl-tmp
- git init
- git pull .. curl-upstream
- rm -rf *
-
-Now place the (reduced) curl content in this directory.  See
-instructions shown by
-
- git log 70654261
-
-for help extracting the content from the upstream repo.  Then run
-the following commands to commit the new version.  Substitute the
-appropriate date and version number:
-
- git add --all
-
- GIT_AUTHOR_NAME='Curl Upstream' \
- GIT_AUTHOR_EMAIL='curl-library at cool.haxx.se' \
- GIT_AUTHOR_DATE='Tue Aug 11 20:13:01 2015 +0200' \
- git commit -m 'curl 7.44.0 (reduced)' &&
- git commit --amend
-
-Edit the commit message to describe the procedure used to obtain the
-content.  Then push the changes back up to the main local repository:
-
- git push .. HEAD:curl-upstream
- cd ..
- rm -rf curl-tmp
-
-Create a topic in the main repository on which to perform the update:
-
- git checkout -b update-curl master
-
-Merge the curl-upstream branch as a subtree:
-
- git merge -s recursive -X subtree=Utilities/cmcurl \
-           curl-upstream
-
-If there are conflicts, resolve them and commit.  Build and test the
-tree.  Commit any additional changes needed to succeed.
-
-Finally, run
-
- git rev-parse --short=8 curl-upstream
-
-to get the commit from which the curl-upstream branch must be started
-on the next update.  Edit the "git branch curl-upstream" line above to
-record it, and commit this file.

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=f53f4a8a2d215dac634effea575a27e000dfcb29
commit f53f4a8a2d215dac634effea575a27e000dfcb29
Merge: e1c1135 202adcf
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Wed Aug 3 14:26:53 2016 -0400
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Wed Aug 3 14:26:53 2016 -0400

    Merge branch 'upstream-curl' into update-curl
    
    * upstream-curl:
      curl 2016-08-03 (f2cb3a01)

diff --cc Utilities/cmcurl/CMakeLists.txt
index 39b70c0,0000000..9031181
mode 100644,000000..100644
--- a/Utilities/cmcurl/CMakeLists.txt
+++ b/Utilities/cmcurl/CMakeLists.txt
@@@ -1,1261 -1,0 +1,1267 @@@
 +# Set curl options as needed for CMake build
 +set(BUILD_CURL_EXE OFF CACHE INTERNAL "No curl exe")
- set(BUILD_CURL_TESTS OFF CACHE INTERNAL "No curl tests")
 +set(BUILD_DASHBOARD_REPORTS OFF CACHE INTERNAL "No curl dashboard reports")
 +set(BUILD_RELEASE_DEBUG_DIRS OFF CACHE INTERNAL "No curl release/debug dirs")
 +set(CMAKE_USE_GSSAPI OFF CACHE INTERNAL "Disable curl gssapi")
 +set(CMAKE_USE_LIBSSH2 OFF CACHE INTERNAL "Disable curl libssh2")
 +set(CMAKE_USE_OPENLDAP OFF CACHE INTERNAL "No curl OpenLDAP")
 +set(CURL_DISABLE_COOKIES OFF CACHE INTERNAL "Do not disable curl cookie support")
 +set(CURL_DISABLE_CRYPTO_AUTH OFF CACHE INTERNAL "Do not disable curl crypto auth")
 +set(CURL_DISABLE_DICT ON CACHE INTERNAL "Disable curl dict protocol?")
 +set(CURL_DISABLE_FILE OFF CACHE INTERNAL "Disable curl file protocol?")
 +set(CURL_DISABLE_FTP OFF CACHE INTERNAL "Disable curl ftp protocol?")
 +set(CURL_DISABLE_GOPHER ON CACHE INTERNAL "Disable curl gopher protocol?")
 +set(CURL_DISABLE_HTTP OFF CACHE INTERNAL "Disable curl http protocol?")
 +set(CURL_DISABLE_IMAP ON CACHE INTERNAL "Disable curl imap protocol?")
 +set(CURL_DISABLE_LDAP ON CACHE INTERNAL "Disable curl ldap protocol?")
 +set(CURL_DISABLE_LDAPS ON CACHE INTERNAL "Disable curl ldaps protocol?")
 +set(CURL_DISABLE_POP3 ON CACHE INTERNAL "Disable curl pop3 protocol?")
 +set(CURL_DISABLE_PROXY OFF CACHE INTERNAL "Do not disable curl proxy")
 +set(CURL_DISABLE_RTSP ON CACHE INTERNAL "Disable curl rtsp protocol?")
 +set(CURL_DISABLE_SMTP ON CACHE INTERNAL "Disable curl smtp protocol?")
 +set(CURL_DISABLE_TELNET ON CACHE INTERNAL "Disable curl telnet protocol?")
 +set(CURL_DISABLE_TFTP ON CACHE INTERNAL "Disable curl tftp protocol?")
 +set(CURL_DISABLE_VERBOSE_STRINGS OFF CACHE INTERNAL "Do not disable curl verbosity")
 +set(CURL_HIDDEN_SYMBOLS OFF CACHE INTERNAL "No curl hidden symbols")
 +set(CURL_STATICLIB ON CACHE INTERNAL "Static curl")
 +set(DISABLED_THREADSAFE OFF CACHE INTERNAL "Curl can use thread-safe functions")
 +set(ENABLE_ARES OFF CACHE INTERNAL "No curl c-ares support")
 +set(ENABLE_CURLDEBUG OFF CACHE INTERNAL "No curl TrackMemory features")
 +set(ENABLE_DEBUG OFF CACHE INTERNAL "No curl debug features")
 +set(ENABLE_IPV6 OFF CACHE INTERNAL "No curl IPv6 support")
 +set(ENABLE_MANUAL OFF CACHE INTERNAL "No curl built-in manual")
 +set(ENABLE_THREADED_RESOLVER OFF CACHE INTERNAL "No curl POSIX threaded DNS lookup")
 +set(ENABLE_UNIX_SOCKETS OFF CACHE INTERNAL "No curl Unix domain sockets support")
 +set(HTTP_ONLY OFF CACHE INTERNAL "Curl is not http-only")
 +set(USE_WIN32_LDAP OFF CACHE INTERNAL "No curl Windows LDAP")
 +
 +# Windows Vista and above have inet_pton, but this will link on
 +# older versions and then the executable will fail to launch at
 +# runtime on older versions because no DLL provides the symbol.
 +if(WIN32)
 +  set(HAVE_INET_PTON 0 CACHE INTERNAL "Do not use inet_pton")
 +endif()
 +
 +# Starting with OSX 10.11 there is an unrelated libnetwork library which will
 +# be picked up during curl configuration. Linking against this library is
 +# unnecessary and breaks backward compatibility of the resulting binaries
 +# because libnetwork is unavailable on older OSX versions.
 +if(APPLE)
 +  set(HAVE_LIBNETWORK 0 CACHE INTERNAL "Do not use libnetwork")
 +endif(APPLE)
 +
 +# Disable warnings to avoid changing 3rd party code.
 +if(CMAKE_C_COMPILER_ID MATCHES
 +    "^(GNU|Clang|AppleClang|XL|VisualAge|SunPro|MIPSpro|HP|Intel)$")
 +  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
 +elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
 +  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
 +endif()
 +
 +#***************************************************************************
 +#                                  _   _ ____  _
 +#  Project                     ___| | | |  _ \| |
 +#                             / __| | | | |_) | |
 +#                            | (__| |_| |  _ <| |___
 +#                             \___|\___/|_| \_\_____|
 +#
 +# Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
 +#
 +# This software is licensed as described in the file COPYING, which
 +# you should have received as part of this distribution. The terms
- # are also available at http://curl.haxx.se/docs/copyright.html.
++# 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.
 +#
 +###########################################################################
 +# cURL/libcurl CMake script
 +# by Tetetest and Sukender (Benoit Neil)
 +
 +# TODO:
 +# The output .so file lacks the soname number which we currently have within the lib/Makefile.am file
 +# Add full (4 or 5 libs) SSL support
 +# Add INSTALL target (EXTRA_DIST variables in Makefile.am may be moved to Makefile.inc so that CMake/CPack is aware of what's to include).
 +# Add CTests(?)
 +# Check on all possible platforms
 +# Test with as many configurations possible (With or without any option)
 +# Create scripts that help keeping the CMake build system up to date (to reduce maintenance). According to Tetetest:
 +#  - lists of headers that 'configure' checks for;
 +#  - curl-specific tests (the ones that are in m4/curl-*.m4 files);
 +#  - (most obvious thing:) curl version numbers.
 +# Add documentation subproject
 +#
 +# 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)
 +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake;${CMAKE_MODULE_PATH}")
 +include(Utilities)
 +include(Macros)
 +
 +project( CURL C )
 +
 +if(0) # This code not needed for building within CMake.
 +message(WARNING "the curl cmake build system is poorly maintained. Be aware")
 +endif()
 +
 +file (READ ${CURL_SOURCE_DIR}/include/curl/curlver.h CURL_VERSION_H_CONTENTS)
 +string (REGEX MATCH "#define LIBCURL_VERSION \"[^\"]*"
 +  CURL_VERSION ${CURL_VERSION_H_CONTENTS})
 +string (REGEX REPLACE "[^\"]+\"" "" CURL_VERSION ${CURL_VERSION})
 +string (REGEX MATCH "#define LIBCURL_VERSION_NUM 0x[0-9a-fA-F]+"
 +  CURL_VERSION_NUM ${CURL_VERSION_H_CONTENTS})
 +string (REGEX REPLACE "[^0]+0x" "" CURL_VERSION_NUM ${CURL_VERSION_NUM})
 +
 +include_regular_expression("^.*$")    # Sukender: Is it necessary?
 +
 +# Setup package meta-data
 +# SET(PACKAGE "curl")
 +if(0) # This code not needed for building within CMake.
 +message(STATUS "curl version=[${CURL_VERSION}]")
 +endif()
 +# SET(PACKAGE_TARNAME "curl")
 +# SET(PACKAGE_NAME "curl")
 +# SET(PACKAGE_VERSION "-")
 +# SET(PACKAGE_STRING "curl-")
- # SET(PACKAGE_BUGREPORT "a suitable curl mailing list => http://curl.haxx.se/mail/")
++# SET(PACKAGE_BUGREPORT "a suitable curl mailing list => https://curl.haxx.se/mail/")
 +set(OPERATING_SYSTEM "${CMAKE_SYSTEM_NAME}")
 +set(OS "\"${CMAKE_SYSTEM_NAME}\"")
 +
 +include_directories(${PROJECT_BINARY_DIR}/include/curl)
 +include_directories( ${CURL_SOURCE_DIR}/include )
 +
 +option(BUILD_CURL_EXE "Set to ON to build cURL executable." ON)
- option(BUILD_CURL_TESTS "Set to ON to build cURL tests." ON)
 +option(CURL_STATICLIB "Set to ON to build libcurl with static linking." OFF)
 +option(ENABLE_ARES "Set to ON to enable c-ares support" OFF)
 +option(ENABLE_THREADED_RESOLVER "Set to ON to enable POSIX threaded DNS lookup" OFF)
 +
 +option(ENABLE_DEBUG "Set to ON to enable curl debug features" OFF)
 +option(ENABLE_CURLDEBUG "Set to ON to build with TrackMemory feature enabled" OFF)
 +
 +if (ENABLE_DEBUG)
 +  # DEBUGBUILD will be defined only for Debug builds
 +  if(NOT CMAKE_VERSION VERSION_LESS 3.0)
 +    set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS $<$<CONFIG:Debug>:DEBUGBUILD>)
 +  else()
 +    set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_DEBUG DEBUGBUILD)
 +  endif()
 +  set(ENABLE_CURLDEBUG ON)
 +endif()
 +
 +if (ENABLE_CURLDEBUG)
 +  set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS CURLDEBUG)
 +endif()
 +
 +# initialize CURL_LIBS
 +set(CURL_LIBS "")
 +
 +if(ENABLE_THREADED_RESOLVER AND ENABLE_ARES)
 +  message(FATAL_ERROR "Options ENABLE_THREADED_RESOLVER and ENABLE_ARES are mutually exclusive")
 +endif()
 +
 +if(ENABLE_ARES)
 +  set(USE_ARES 1)
 +  find_package(CARES REQUIRED)
 +  list(APPEND CURL_LIBS ${CARES_LIBRARY} )
 +  set(CURL_LIBS ${CURL_LIBS} ${CARES_LIBRARY})
 +endif()
 +
- option(BUILD_DASHBOARD_REPORTS "Set to ON to activate reporting of cURL builds here http://www.cdash.org/CDashPublic/index.php?project=CURL" OFF)
- if(BUILD_DASHBOARD_REPORTS)
-   #INCLUDE(Dart)
-   include(CTest)
- endif(BUILD_DASHBOARD_REPORTS)
- 
 +if(MSVC)
 +  option(BUILD_RELEASE_DEBUG_DIRS "Set OFF to build each configuration to a separate directory" OFF)
 +  mark_as_advanced(BUILD_RELEASE_DEBUG_DIRS)
 +endif()
 +
 +option(CURL_HIDDEN_SYMBOLS "Set to ON to hide libcurl internal symbols (=hide all symbols that aren't officially external)." ON)
 +mark_as_advanced(CURL_HIDDEN_SYMBOLS)
 +
- # IF(WIN32)
- # OPTION(CURL_WINDOWS_SSPI "Use windows libraries to allow NTLM authentication without openssl" ON)
- # MARK_AS_ADVANCED(CURL_WINDOWS_SSPI)
- # ENDIF()
- 
 +option(HTTP_ONLY "disables all protocols except HTTP (This overrides all CURL_DISABLE_* options)" OFF)
 +mark_as_advanced(HTTP_ONLY)
 +option(CURL_DISABLE_FTP "disables FTP" OFF)
 +mark_as_advanced(CURL_DISABLE_FTP)
 +option(CURL_DISABLE_LDAP "disables LDAP" OFF)
 +mark_as_advanced(CURL_DISABLE_LDAP)
 +option(CURL_DISABLE_TELNET "disables Telnet" OFF)
 +mark_as_advanced(CURL_DISABLE_TELNET)
 +option(CURL_DISABLE_DICT "disables DICT" OFF)
 +mark_as_advanced(CURL_DISABLE_DICT)
 +option(CURL_DISABLE_FILE "disables FILE" OFF)
 +mark_as_advanced(CURL_DISABLE_FILE)
 +option(CURL_DISABLE_TFTP "disables TFTP" OFF)
 +mark_as_advanced(CURL_DISABLE_TFTP)
 +option(CURL_DISABLE_HTTP "disables HTTP" OFF)
 +mark_as_advanced(CURL_DISABLE_HTTP)
 +
 +option(CURL_DISABLE_LDAPS "to disable LDAPS" OFF)
 +mark_as_advanced(CURL_DISABLE_LDAPS)
 +
 +option(CURL_DISABLE_RTSP "to disable RTSP" OFF)
 +mark_as_advanced(CURL_DISABLE_RTSP)
 +option(CURL_DISABLE_PROXY "to disable proxy" OFF)
 +mark_as_advanced(CURL_DISABLE_PROXY)
 +option(CURL_DISABLE_POP3 "to disable POP3" OFF)
 +mark_as_advanced(CURL_DISABLE_POP3)
 +option(CURL_DISABLE_IMAP "to disable IMAP" OFF)
 +mark_as_advanced(CURL_DISABLE_IMAP)
 +option(CURL_DISABLE_SMTP "to disable SMTP" OFF)
 +mark_as_advanced(CURL_DISABLE_SMTP)
 +option(CURL_DISABLE_GOPHER "to disable Gopher" OFF)
 +mark_as_advanced(CURL_DISABLE_GOPHER)
 +
 +if(HTTP_ONLY)
 +  set(CURL_DISABLE_FTP ON)
 +  set(CURL_DISABLE_LDAP ON)
 +  set(CURL_DISABLE_LDAPS ON)
 +  set(CURL_DISABLE_TELNET ON)
 +  set(CURL_DISABLE_DICT ON)
 +  set(CURL_DISABLE_FILE ON)
 +  set(CURL_DISABLE_TFTP ON)
 +  set(CURL_DISABLE_RTSP ON)
 +  set(CURL_DISABLE_POP3 ON)
 +  set(CURL_DISABLE_IMAP ON)
 +  set(CURL_DISABLE_SMTP ON)
 +  set(CURL_DISABLE_GOPHER ON)
 +endif()
 +
 +option(CURL_DISABLE_COOKIES "to disable cookies support" OFF)
 +mark_as_advanced(CURL_DISABLE_COOKIES)
 +
 +option(CURL_DISABLE_CRYPTO_AUTH "to disable cryptographic authentication" OFF)
 +mark_as_advanced(CURL_DISABLE_CRYPTO_AUTH)
 +option(CURL_DISABLE_VERBOSE_STRINGS "to disable verbose strings" OFF)
 +mark_as_advanced(CURL_DISABLE_VERBOSE_STRINGS)
 +option(DISABLED_THREADSAFE "Set to explicitly specify we don't want to use thread-safe functions" OFF)
 +mark_as_advanced(DISABLED_THREADSAFE)
 +option(ENABLE_IPV6 "Define if you want to enable IPv6 support" ON)
 +mark_as_advanced(ENABLE_IPV6)
- if(ENABLE_IPV6)
++if(ENABLE_IPV6 AND NOT WIN32)
 +  include(CheckStructHasMember)
 +  check_struct_has_member("struct sockaddr_in6" sin6_addr "netinet/in.h"
 +                          HAVE_SOCKADDR_IN6_SIN6_ADDR)
 +  check_struct_has_member("struct sockaddr_in6" sin6_scope_id "netinet/in.h"
 +                          HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
 +  if(NOT HAVE_SOCKADDR_IN6_SIN6_ADDR)
 +    message(WARNING "struct sockaddr_in6 not available, disabling IPv6 support")
 +    # Force the feature off as this name is used as guard macro...
 +    set(ENABLE_IPV6 OFF
 +        CACHE BOOL "Define if you want to enable IPv6 support" FORCE)
 +  endif()
 +endif()
 +
 +option(ENABLE_MANUAL "to provide the built-in manual" ON)
 +unset(USE_MANUAL CACHE) # TODO: cache NROFF/NROFF_MANOPT/USE_MANUAL vars?
 +if(ENABLE_MANUAL)
 +  find_program(NROFF NAMES gnroff nroff)
 +  if(NROFF)
 +    # Need a way to write to stdin, this will do
 +    file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/nroff-input.txt" "test")
 +    # Tests for a valid nroff option to generate a manpage
 +    foreach(_MANOPT "-man" "-mandoc")
 +      execute_process(COMMAND "${NROFF}" ${_MANOPT}
 +        OUTPUT_VARIABLE NROFF_MANOPT_OUTPUT
 +        INPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/nroff-input.txt"
 +        ERROR_QUIET)
 +      # Save the option if it was valid
 +      if(NROFF_MANOPT_OUTPUT)
 +        message("Found *nroff option: -- ${_MANOPT}")
 +        set(NROFF_MANOPT ${_MANOPT})
 +        set(USE_MANUAL 1)
 +        break()
 +      endif()
 +    endforeach()
 +    # No need for the temporary file
 +    file(REMOVE "${CMAKE_CURRENT_BINARY_DIR}/nroff-input.txt")
 +    if(NOT USE_MANUAL)
 +      message(WARNING "Found no *nroff option to get plaintext from man pages")
 +    endif()
 +  else()
 +    message(WARNING "Found no *nroff program")
 +  endif()
 +endif()
 +
 +# We need ansi c-flags, especially on HP
 +set(CMAKE_C_FLAGS "${CMAKE_ANSI_CFLAGS} ${CMAKE_C_FLAGS}")
 +set(CMAKE_REQUIRED_FLAGS ${CMAKE_ANSI_CFLAGS})
 +
 +# Disable warnings on Borland to avoid changing 3rd party code.
 +if(BORLAND)
 +  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w-")
 +endif(BORLAND)
 +
 +# If we are on AIX, do the _ALL_SOURCE magic
 +if(${CMAKE_SYSTEM_NAME} MATCHES AIX)
 +  set(_ALL_SOURCE 1)
 +endif(${CMAKE_SYSTEM_NAME} MATCHES AIX)
 +
 +# Include all the necessary files for macros
 +include (CheckFunctionExists)
 +include (CheckIncludeFile)
 +include (CheckIncludeFiles)
 +include (CheckLibraryExists)
 +include (CheckSymbolExists)
 +include (CheckTypeSize)
 +include (CheckCSourceCompiles)
 +
 +# On windows preload settings
 +if(WIN32)
 +  set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -D_WINSOCKAPI_")
 +  include(${CMAKE_CURRENT_SOURCE_DIR}/CMake/Platforms/WindowsCache.cmake)
 +endif(WIN32)
 +
 +if(ENABLE_THREADED_RESOLVER)
 +  check_include_file_concat("pthread.h" HAVE_PTHREAD_H)
 +  if(HAVE_PTHREAD_H)
 +    set(CMAKE_THREAD_PREFER_PTHREAD 1)
 +    find_package(Threads)
 +    if(CMAKE_USE_PTHREADS_INIT)
 +      set(CURL_LIBS ${CURL_LIBS} ${CMAKE_THREAD_LIBS_INIT})
 +      set(USE_THREADS_POSIX 1)
 +    endif()
 +  endif()
 +endif()
 +
 +# Check for all needed libraries
 +if(0) # This code not needed for building within CMake.
 +check_library_exists_concat("dl"     dlopen       HAVE_LIBDL)
 +else()
 +  # Use the cmake-defined dl libs as dl is should not be used
 +  # on HPUX, but rather dld this avoids a warning
 +  list(APPEND CURL_LIBS ${CMAKE_DL_LIBS})
 +endif()
 +check_library_exists_concat("socket" connect      HAVE_LIBSOCKET)
 +check_library_exists("c" gethostbyname "" NOT_NEED_LIBNSL)
 +
 +# Yellowtab Zeta needs different libraries than BeOS 5.
 +if(BEOS)
 +  set(NOT_NEED_LIBNSL 1)
 +  check_library_exists_concat("bind" gethostbyname HAVE_LIBBIND)
 +  check_library_exists_concat("bnetapi" closesocket HAVE_LIBBNETAPI)
 +endif(BEOS)
 +
 +check_library_exists_concat("network" recv HAVE_LIBNETWORK)
 +
 +if(NOT NOT_NEED_LIBNSL)
 +  check_library_exists_concat("nsl"    gethostbyname  HAVE_LIBNSL)
 +endif(NOT NOT_NEED_LIBNSL)
 +
 +check_function_exists(gethostname HAVE_GETHOSTNAME)
 +
 +if(WIN32)
 +  check_library_exists_concat("ws2_32" getch        HAVE_LIBWS2_32)
 +  check_library_exists_concat("winmm"  getch        HAVE_LIBWINMM)
 +endif()
 +
 +set(USE_OPENSSL OFF)
 +set(HAVE_LIBCRYPTO OFF)
 +set(HAVE_LIBSSL OFF)
 +
 +if(CMAKE_USE_OPENSSL)
 +  find_package(OpenSSL)
 +  if(OPENSSL_FOUND)
 +    list(APPEND CURL_LIBS ${OPENSSL_LIBRARIES})
 +    set(USE_OPENSSL ON)
 +    set(HAVE_LIBCRYPTO ON)
 +    set(HAVE_LIBSSL ON)
 +    include_directories(${OPENSSL_INCLUDE_DIR})
 +    set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
 +    check_include_file("openssl/crypto.h" HAVE_OPENSSL_CRYPTO_H)
 +    check_include_file("openssl/engine.h" HAVE_OPENSSL_ENGINE_H)
 +    check_include_file("openssl/err.h"    HAVE_OPENSSL_ERR_H)
 +    check_include_file("openssl/pem.h"    HAVE_OPENSSL_PEM_H)
 +    check_include_file("openssl/pkcs12.h" HAVE_OPENSSL_PKCS12_H)
 +    check_include_file("openssl/rsa.h"    HAVE_OPENSSL_RSA_H)
 +    check_include_file("openssl/ssl.h"    HAVE_OPENSSL_SSL_H)
 +    check_include_file("openssl/x509.h"   HAVE_OPENSSL_X509_H)
 +    check_include_file("openssl/rand.h"   HAVE_OPENSSL_RAND_H)
 +
 +    # Optionally build with a specific CA cert bundle.
 +    if(CURL_CA_BUNDLE)
 +      add_definitions(-DCURL_CA_BUNDLE="${CURL_CA_BUNDLE}")
 +    endif()
 +    # Optionally build with a specific CA cert dir.
 +    if(CURL_CA_PATH)
 +      add_definitions(-DCURL_CA_PATH="${CURL_CA_PATH}")
 +    endif()
 +  endif()
 +elseif(WIN32)
 +  # Use Windows SSL/TLS native implementation.
-   add_definitions(-DUSE_SCHANNEL)
-   set(USE_WINDOWS_SSPI 1)
++  set(CURL_WINDOWS_SSPI ON)
 +elseif(APPLE)
 +  # Use OS X SSL/TLS native implementation if available on target version.
 +  if(CMAKE_OSX_DEPLOYMENT_TARGET)
 +    set(OSX_VERSION ${CMAKE_OSX_DEPLOYMENT_TARGET})
 +  else()
 +    execute_process(
 +      COMMAND sw_vers -productVersion
 +      OUTPUT_VARIABLE OSX_VERSION
 +      OUTPUT_STRIP_TRAILING_WHITESPACE
 +      )
 +  endif()
 +  if(NOT OSX_VERSION VERSION_LESS 10.6 AND
 +     CMAKE_C_COMPILER_ID MATCHES "GNU|Clang|AppleClang")
 +    add_definitions(-DUSE_DARWINSSL)
 +    list(APPEND CURL_LIBS
 +      "-framework CoreFoundation"
 +      "-framework Security"
 +      )
 +  endif()
 +endif()
 +
 +if(NOT CURL_DISABLE_LDAP)
- 
 +  if(WIN32)
 +    option(USE_WIN32_LDAP "Use Windows LDAP implementation" ON)
 +    if(USE_WIN32_LDAP)
-       check_library_exists("wldap32" cldap_open "" HAVE_WLDAP32)
++      check_library_exists_concat("wldap32" cldap_open HAVE_WLDAP32)
 +      if(NOT HAVE_WLDAP32)
 +        set(USE_WIN32_LDAP OFF)
 +      endif()
 +    endif()
 +  endif()
 +
 +  option(CMAKE_USE_OPENLDAP "Use OpenLDAP code." OFF)
 +  mark_as_advanced(CMAKE_USE_OPENLDAP)
 +  set(CMAKE_LDAP_LIB "ldap" CACHE STRING "Name or full path to ldap library")
 +  set(CMAKE_LBER_LIB "lber" CACHE STRING "Name or full path to lber library")
 +
 +  if(CMAKE_USE_OPENLDAP AND USE_WIN32_LDAP)
 +    message(FATAL_ERROR "Cannot use USE_WIN32_LDAP and CMAKE_USE_OPENLDAP at the same time")
 +  endif()
-   
++
 +  # Now that we know, we're not using windows LDAP...
-   if(NOT USE_WIN32_LDAP)
++  if(USE_WIN32_LDAP)
++    check_include_file_concat("winldap.h" HAVE_WINLDAP_H)
++    check_include_file_concat("winber.h"  HAVE_WINBER_H)
++  else()
 +    # Check for LDAP
 +    set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_LIBRARIES})
 +    check_library_exists_concat(${CMAKE_LDAP_LIB} ldap_init HAVE_LIBLDAP)
 +    check_library_exists_concat(${CMAKE_LBER_LIB} ber_init HAVE_LIBLBER)
-   else()
-     check_include_file_concat("winldap.h" HAVE_WINLDAP_H)
-     check_include_file_concat("winber.h"  HAVE_WINBER_H)
-   endif()
-   
-   set(CMAKE_LDAP_INCLUDE_DIR "" CACHE STRING "Path to LDAP include directory")
-   if(CMAKE_LDAP_INCLUDE_DIR)
-     set(CMAKE_REQUIRED_INCLUDES ${CMAKE_LDAP_INCLUDE_DIR})
-   endif()
-   check_include_file_concat("ldap.h"           HAVE_LDAP_H)
-   check_include_file_concat("lber.h"           HAVE_LBER_H)
- 
-   if(NOT HAVE_LDAP_H)
-     message(STATUS "LDAP_H not found CURL_DISABLE_LDAP set ON")
-     set(CURL_DISABLE_LDAP ON CACHE BOOL "" FORCE)
-   elseif(NOT HAVE_LIBLDAP)
-     message(STATUS "LDAP library '${CMAKE_LDAP_LIB}' not found CURL_DISABLE_LDAP set ON")
-     set(CURL_DISABLE_LDAP ON CACHE BOOL "" FORCE)
-   else()
-     if(CMAKE_USE_OPENLDAP)
-       set(USE_OPENLDAP ON)
-     endif()
++
++    set(CMAKE_REQUIRED_INCLUDES_BAK ${CMAKE_REQUIRED_INCLUDES})
++    set(CMAKE_LDAP_INCLUDE_DIR "" CACHE STRING "Path to LDAP include directory")
 +    if(CMAKE_LDAP_INCLUDE_DIR)
-       include_directories(${CMAKE_LDAP_INCLUDE_DIR})
++      list(APPEND CMAKE_REQUIRED_INCLUDES ${CMAKE_LDAP_INCLUDE_DIR})
 +    endif()
-     set(NEED_LBER_H ON)
-     set(_HEADER_LIST)
-     if(HAVE_WINDOWS_H)
-       list(APPEND _HEADER_LIST "windows.h")
-     endif()
-     if(HAVE_SYS_TYPES_H)
-       list(APPEND _HEADER_LIST "sys/types.h")
-     endif()
-     list(APPEND _HEADER_LIST "ldap.h")
++    check_include_file_concat("ldap.h"           HAVE_LDAP_H)
++    check_include_file_concat("lber.h"           HAVE_LBER_H)
++
++    if(NOT HAVE_LDAP_H)
++      message(STATUS "LDAP_H not found CURL_DISABLE_LDAP set ON")
++      set(CURL_DISABLE_LDAP ON CACHE BOOL "" FORCE)
++      set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES_BAK}) #LDAP includes won't be used
++    elseif(NOT HAVE_LIBLDAP)
++      message(STATUS "LDAP library '${CMAKE_LDAP_LIB}' not found CURL_DISABLE_LDAP set ON")
++      set(CURL_DISABLE_LDAP ON CACHE BOOL "" FORCE)
++      set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES_BAK}) #LDAP includes won't be used
++    else()
++      if(CMAKE_USE_OPENLDAP)
++        set(USE_OPENLDAP ON)
++      endif()
++      if(CMAKE_LDAP_INCLUDE_DIR)
++        include_directories(${CMAKE_LDAP_INCLUDE_DIR})
++      endif()
++      set(NEED_LBER_H ON)
++      set(_HEADER_LIST)
++      if(HAVE_WINDOWS_H)
++        list(APPEND _HEADER_LIST "windows.h")
++      endif()
++      if(HAVE_SYS_TYPES_H)
++        list(APPEND _HEADER_LIST "sys/types.h")
++      endif()
++      list(APPEND _HEADER_LIST "ldap.h")
 +
-     set(_SRC_STRING "")
-     foreach(_HEADER ${_HEADER_LIST})
-       set(_INCLUDE_STRING "${_INCLUDE_STRING}#include <${_HEADER}>\n")
-     endforeach()
++      set(_SRC_STRING "")
++      foreach(_HEADER ${_HEADER_LIST})
++        set(_INCLUDE_STRING "${_INCLUDE_STRING}#include <${_HEADER}>\n")
++      endforeach()
 +
-     set(_SRC_STRING
-       "
-       ${_INCLUDE_STRING}
-       int main(int argc, char ** argv)
-       {
-         BerValue *bvp = NULL;
-         BerElement *bep = ber_init(bvp);
-         ber_free(bep, 1);
-         return 0;
-       }"
-     )
-     set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -DLDAP_DEPRECATED=1")
-     list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_LDAP_LIB})
-     if(HAVE_LIBLBER)
-       list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_LBER_LIB})
-     endif()
-     check_c_source_compiles("${_SRC_STRING}" NOT_NEED_LBER_H)
++      set(_SRC_STRING
++        "
++        ${_INCLUDE_STRING}
++        int main(int argc, char ** argv)
++        {
++          BerValue *bvp = NULL;
++          BerElement *bep = ber_init(bvp);
++          ber_free(bep, 1);
++          return 0;
++        }"
++      )
++      set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -DLDAP_DEPRECATED=1")
++      list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_LDAP_LIB})
++      if(HAVE_LIBLBER)
++        list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_LBER_LIB})
++      endif()
++      check_c_source_compiles("${_SRC_STRING}" NOT_NEED_LBER_H)
 +
-     if(NOT_NEED_LBER_H)
-       set(NEED_LBER_H OFF)
-     else()
-       set(CURL_TEST_DEFINES "${CURL_TEST_DEFINES} -DNEED_LBER_H")
++      if(NOT_NEED_LBER_H)
++        set(NEED_LBER_H OFF)
++      else()
++        set(CURL_TEST_DEFINES "${CURL_TEST_DEFINES} -DNEED_LBER_H")
++      endif()
 +    endif()
 +  endif()
 +
 +endif()
 +
 +# No ldap, no ldaps.
 +if(CURL_DISABLE_LDAP)
 +  if(NOT CURL_DISABLE_LDAPS)
 +    message(STATUS "LDAP needs to be enabled to support LDAPS")
 +    set(CURL_DISABLE_LDAPS ON CACHE BOOL "" FORCE)
 +  endif()
 +endif()
 +
 +if(NOT CURL_DISABLE_LDAPS)
 +  check_include_file_concat("ldap_ssl.h" HAVE_LDAP_SSL_H)
 +  check_include_file_concat("ldapssl.h"  HAVE_LDAPSSL_H)
 +endif()
 +
 +# Check for idn
 +check_library_exists_concat("idn" idna_to_ascii_lz HAVE_LIBIDN)
 +
 +# Check for symbol dlopen (same as HAVE_LIBDL)
 +check_library_exists("${CURL_LIBS}" dlopen "" HAVE_DLOPEN)
 +
 +if(0) # This code not needed for building within CMake.
 +option(CURL_ZLIB "Set to ON to enable building cURL with zlib support." ON)
 +set(HAVE_LIBZ OFF)
 +set(HAVE_ZLIB_H OFF)
 +set(HAVE_ZLIB OFF)
 +if(CURL_ZLIB)
 +  find_package(ZLIB QUIET)
 +  if(ZLIB_FOUND)
 +    set(HAVE_ZLIB_H ON)
 +    set(HAVE_ZLIB ON)
 +    set(HAVE_LIBZ ON)
 +    list(APPEND CURL_LIBS ${ZLIB_LIBRARIES})
 +    include_directories(${ZLIB_INCLUDE_DIRS})
++    list(APPEND CMAKE_REQUIRED_INCLUDES ${ZLIB_INCLUDE_DIRS})
 +  endif()
 +endif()
 +endif()
 +
 +#-----------------------------------------------------------------------------
 +# CMake-specific curl code.
 +
 +if(CURL_SPECIAL_LIBZ)
 +  set(CURL_LIBS ${CURL_LIBS} "${CURL_SPECIAL_LIBZ}")
 +  include_directories(${CURL_SPECIAL_LIBZ_INCLUDES})
 +  set(HAVE_LIBZ 0)
 +  set(HAVE_ZLIB_H 0)
 +endif()
 +
 +#libSSH2
 +option(CMAKE_USE_LIBSSH2 "Use libSSH2" ON)
 +mark_as_advanced(CMAKE_USE_LIBSSH2)
 +set(USE_LIBSSH2 OFF)
 +set(HAVE_LIBSSH2 OFF)
 +set(HAVE_LIBSSH2_H OFF)
 +
 +if(CMAKE_USE_LIBSSH2)
 +  find_package(LibSSH2)
 +  if(LIBSSH2_FOUND)
 +    list(APPEND CURL_LIBS ${LIBSSH2_LIBRARY})
 +    set(CMAKE_REQUIRED_LIBRARIES ${LIBSSH2_LIBRARY})
-     set(CMAKE_REQUIRED_INCLUDES "${LIBSSH2_INCLUDE_DIR}")
++    list(APPEND CMAKE_REQUIRED_INCLUDES "${LIBSSH2_INCLUDE_DIR}")
 +    include_directories("${LIBSSH2_INCLUDE_DIR}")
 +    set(HAVE_LIBSSH2 ON)
 +    set(USE_LIBSSH2 ON)
 +
 +    # find_package has already found the headers
 +    set(HAVE_LIBSSH2_H ON)
 +    set(CURL_INCLUDES ${CURL_INCLUDES} "${LIBSSH2_INCLUDE_DIR}/libssh2.h")
 +    set(CURL_TEST_DEFINES "${CURL_TEST_DEFINES} -DHAVE_LIBSSH2_H")
 +
 +    # now check for specific libssh2 symbols as they were added in different versions
 +    set(CMAKE_EXTRA_INCLUDE_FILES "libssh2.h")
 +    check_function_exists(libssh2_version           HAVE_LIBSSH2_VERSION)
 +    check_function_exists(libssh2_init              HAVE_LIBSSH2_INIT)
 +    check_function_exists(libssh2_exit              HAVE_LIBSSH2_EXIT)
 +    check_function_exists(libssh2_scp_send64        HAVE_LIBSSH2_SCP_SEND64)
 +    check_function_exists(libssh2_session_handshake HAVE_LIBSSH2_SESSION_HANDSHAKE)
 +    set(CMAKE_EXTRA_INCLUDE_FILES "")
 +
 +  endif(LIBSSH2_FOUND)
 +endif(CMAKE_USE_LIBSSH2)
 +
 +option(CMAKE_USE_GSSAPI "Use GSSAPI implementation (right now only Heimdal is supported with CMake build)" OFF)
 +mark_as_advanced(CMAKE_USE_GSSAPI)
 +
 +if(CMAKE_USE_GSSAPI)
 +  find_package(GSS)
 +
 +  set(HAVE_GSSAPI ${GSS_FOUND})
 +  if(GSS_FOUND)
 +
 +    message(STATUS "Found ${GSS_FLAVOUR} GSSAPI version: \"${GSS_VERSION}\"")
 +
-     set(CMAKE_REQUIRED_INCLUDES ${GSS_INCLUDE_DIR})
++    list(APPEND CMAKE_REQUIRED_INCLUDES ${GSS_INCLUDE_DIRECTORIES})
 +    check_include_file_concat("gssapi/gssapi.h"  HAVE_GSSAPI_GSSAPI_H)
 +    check_include_file_concat("gssapi/gssapi_generic.h" HAVE_GSSAPI_GSSAPI_GENERIC_H)
 +    check_include_file_concat("gssapi/gssapi_krb5.h" HAVE_GSSAPI_GSSAPI_KRB5_H)
 +
 +    if(GSS_FLAVOUR STREQUAL "Heimdal")
 +      set(HAVE_GSSHEIMDAL ON)
 +    else() # MIT
 +      set(HAVE_GSSMIT ON)
 +      set(_INCLUDE_LIST "")
 +      if(HAVE_GSSAPI_GSSAPI_H)
 +        list(APPEND _INCLUDE_LIST "gssapi/gssapi.h")
 +      endif()
 +      if(HAVE_GSSAPI_GSSAPI_GENERIC_H)
 +        list(APPEND _INCLUDE_LIST "gssapi/gssapi_generic.h")
 +      endif()
 +      if(HAVE_GSSAPI_GSSAPI_KRB5_H)
 +        list(APPEND _INCLUDE_LIST "gssapi/gssapi_krb5.h")
 +      endif()
 +
 +      string(REPLACE ";" " " _COMPILER_FLAGS_STR "${GSS_COMPILER_FLAGS}")
 +      string(REPLACE ";" " " _LINKER_FLAGS_STR "${GSS_LINKER_FLAGS}")
 +
 +      foreach(_dir ${GSS_LINK_DIRECTORIES})
 +        set(_LINKER_FLAGS_STR "${_LINKER_FLAGS_STR} -L\"${_dir}\"")
 +      endforeach()
 +
 +      set(CMAKE_REQUIRED_FLAGS "${_COMPILER_FLAGS_STR} ${_LINKER_FLAGS_STR}")
 +      set(CMAKE_REQUIRED_LIBRARIES ${GSS_LIBRARIES})
 +      check_symbol_exists("GSS_C_NT_HOSTBASED_SERVICE" ${_INCLUDE_LIST} HAVE_GSS_C_NT_HOSTBASED_SERVICE)
 +      if(NOT HAVE_GSS_C_NT_HOSTBASED_SERVICE)
 +        set(HAVE_OLD_GSSMIT ON)
 +      endif()
 +
 +    endif()
 +
-     include_directories(${GSS_INCLUDE_DIR})
++    include_directories(${GSS_INCLUDE_DIRECTORIES})
 +    link_directories(${GSS_LINK_DIRECTORIES})
 +    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GSS_COMPILER_FLAGS}")
 +    set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${GSS_LINKER_FLAGS}")
 +    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GSS_LINKER_FLAGS}")
 +    list(APPEND CURL_LIBS ${GSS_LIBRARIES})
 +
 +  else()
 +    message(WARNING "GSSAPI support has been requested but no supporting libraries found. Skipping.")
 +  endif()
 +endif()
 +
 +option(ENABLE_UNIX_SOCKETS "Define if you want Unix domain sockets support" ON)
 +if(ENABLE_UNIX_SOCKETS)
 +  include(CheckStructHasMember)
 +  check_struct_has_member("struct sockaddr_un" sun_path "sys/un.h" USE_UNIX_SOCKETS)
 +else()
 +  unset(USE_UNIX_SOCKETS CACHE)
 +endif()
 +
++
 +# Check for header files
 +if(NOT UNIX)
 +  check_include_file_concat("windows.h"      HAVE_WINDOWS_H)
 +  check_include_file_concat("winsock.h"      HAVE_WINSOCK_H)
 +  check_include_file_concat("ws2tcpip.h"     HAVE_WS2TCPIP_H)
 +  check_include_file_concat("winsock2.h"     HAVE_WINSOCK2_H)
++  if(CURL_WINDOWS_SSPI)
++    set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -DSECURITY_WIN32")
++    check_include_file_concat("sspi.h"       HAVE_SSPI_H)
++    if(HAVE_SSPI_H)
++      check_include_file_concat("schannel.h" HAVE_SCHANNEL_H)
++      set(USE_WINDOWS_SSPI ON)
++      if(HAVE_SCHANNEL_H)
++        set(USE_SCHANNEL ON)
++        set(SSL_ENABLED ON)
++        set(CURL_LIBS ${CURL_LIBS} "crypt32")
++      endif()
++    endif()
++  endif()
 +else()
 +  set(HAVE_WINDOWS_H 0)
 +  set(HAVE_WINSOCK_H 0)
 +  set(HAVE_WS2TCPIP_H 0)
 +  set(HAVE_WINSOCK2_H 0)
 +endif()
 +
 +check_include_file_concat("stdio.h"          HAVE_STDIO_H)
 +check_include_file_concat("inttypes.h"       HAVE_INTTYPES_H)
 +check_include_file_concat("sys/filio.h"      HAVE_SYS_FILIO_H)
 +check_include_file_concat("sys/ioctl.h"      HAVE_SYS_IOCTL_H)
 +check_include_file_concat("sys/param.h"      HAVE_SYS_PARAM_H)
 +check_include_file_concat("sys/poll.h"       HAVE_SYS_POLL_H)
 +check_include_file_concat("sys/resource.h"   HAVE_SYS_RESOURCE_H)
 +check_include_file_concat("sys/select.h"     HAVE_SYS_SELECT_H)
 +check_include_file_concat("sys/socket.h"     HAVE_SYS_SOCKET_H)
 +check_include_file_concat("sys/sockio.h"     HAVE_SYS_SOCKIO_H)
 +check_include_file_concat("sys/stat.h"       HAVE_SYS_STAT_H)
 +check_include_file_concat("sys/time.h"       HAVE_SYS_TIME_H)
 +check_include_file_concat("sys/types.h"      HAVE_SYS_TYPES_H)
 +check_include_file_concat("sys/uio.h"        HAVE_SYS_UIO_H)
 +check_include_file_concat("sys/un.h"         HAVE_SYS_UN_H)
 +check_include_file_concat("sys/utime.h"      HAVE_SYS_UTIME_H)
 +check_include_file_concat("alloca.h"         HAVE_ALLOCA_H)
 +check_include_file_concat("arpa/inet.h"      HAVE_ARPA_INET_H)
 +check_include_file_concat("arpa/tftp.h"      HAVE_ARPA_TFTP_H)
 +check_include_file_concat("assert.h"         HAVE_ASSERT_H)
 +check_include_file_concat("crypto.h"         HAVE_CRYPTO_H)
 +check_include_file_concat("des.h"            HAVE_DES_H)
 +check_include_file_concat("err.h"            HAVE_ERR_H)
 +check_include_file_concat("errno.h"          HAVE_ERRNO_H)
 +check_include_file_concat("fcntl.h"          HAVE_FCNTL_H)
 +check_include_file_concat("idn-free.h"       HAVE_IDN_FREE_H)
 +check_include_file_concat("ifaddrs.h"        HAVE_IFADDRS_H)
 +check_include_file_concat("io.h"             HAVE_IO_H)
 +check_include_file_concat("krb.h"            HAVE_KRB_H)
 +check_include_file_concat("libgen.h"         HAVE_LIBGEN_H)
 +check_include_file_concat("limits.h"         HAVE_LIMITS_H)
 +check_include_file_concat("locale.h"         HAVE_LOCALE_H)
 +check_include_file_concat("net/if.h"         HAVE_NET_IF_H)
 +check_include_file_concat("netdb.h"          HAVE_NETDB_H)
 +check_include_file_concat("netinet/in.h"     HAVE_NETINET_IN_H)
 +check_include_file_concat("netinet/tcp.h"    HAVE_NETINET_TCP_H)
 +
 +check_include_file_concat("pem.h"            HAVE_PEM_H)
 +check_include_file_concat("poll.h"           HAVE_POLL_H)
 +check_include_file_concat("pwd.h"            HAVE_PWD_H)
 +check_include_file_concat("rsa.h"            HAVE_RSA_H)
 +check_include_file_concat("setjmp.h"         HAVE_SETJMP_H)
 +check_include_file_concat("sgtty.h"          HAVE_SGTTY_H)
 +check_include_file_concat("signal.h"         HAVE_SIGNAL_H)
 +check_include_file_concat("ssl.h"            HAVE_SSL_H)
 +check_include_file_concat("stdbool.h"        HAVE_STDBOOL_H)
 +check_include_file_concat("stdint.h"         HAVE_STDINT_H)
 +check_include_file_concat("stdio.h"          HAVE_STDIO_H)
 +check_include_file_concat("stdlib.h"         HAVE_STDLIB_H)
 +check_include_file_concat("string.h"         HAVE_STRING_H)
 +check_include_file_concat("strings.h"        HAVE_STRINGS_H)
 +check_include_file_concat("stropts.h"        HAVE_STROPTS_H)
 +check_include_file_concat("termio.h"         HAVE_TERMIO_H)
 +check_include_file_concat("termios.h"        HAVE_TERMIOS_H)
 +check_include_file_concat("time.h"           HAVE_TIME_H)
 +check_include_file_concat("tld.h"            HAVE_TLD_H)
 +check_include_file_concat("unistd.h"         HAVE_UNISTD_H)
 +check_include_file_concat("utime.h"          HAVE_UTIME_H)
 +check_include_file_concat("x509.h"           HAVE_X509_H)
 +
 +check_include_file_concat("process.h"        HAVE_PROCESS_H)
 +check_include_file_concat("stddef.h"         HAVE_STDDEF_H)
 +check_include_file_concat("dlfcn.h"          HAVE_DLFCN_H)
 +check_include_file_concat("malloc.h"         HAVE_MALLOC_H)
 +check_include_file_concat("memory.h"         HAVE_MEMORY_H)
 +check_include_file_concat("netinet/if_ether.h" HAVE_NETINET_IF_ETHER_H)
 +check_include_file_concat("stdint.h"        HAVE_STDINT_H)
 +check_include_file_concat("sockio.h"        HAVE_SOCKIO_H)
 +check_include_file_concat("sys/utsname.h"   HAVE_SYS_UTSNAME_H)
 +check_include_file_concat("idna.h"          HAVE_IDNA_H)
 +
 +
 +
 +check_type_size(size_t  SIZEOF_SIZE_T)
 +check_type_size(ssize_t  SIZEOF_SSIZE_T)
 +check_type_size("long long"  SIZEOF_LONG_LONG)
 +check_type_size("long"  SIZEOF_LONG)
 +check_type_size("short"  SIZEOF_SHORT)
 +check_type_size("int"  SIZEOF_INT)
 +check_type_size("__int64"  SIZEOF___INT64)
 +check_type_size("time_t"  SIZEOF_TIME_T)
 +check_type_size("off_t"  SIZEOF_OFF_T)
 +
 +# Make public versions of some type sizes for curlbuild.h.
 +foreach(t INT LONG LONG_LONG SSIZE_T)
 +  string(REPLACE "SIZEOF_" "CURL_SIZEOF_" CURL_SIZEOF_${t}_CODE "${SIZEOF_${t}_CODE}")
 +endforeach()
 +
 +if(HAVE_SIZEOF_LONG_LONG)
 +  set(HAVE_LONGLONG 1)
 +  set(HAVE_LL 1)
 +endif(HAVE_SIZEOF_LONG_LONG)
 +
 +find_file(RANDOM_FILE urandom /dev)
 +mark_as_advanced(RANDOM_FILE)
 +
 +# Check for some functions that are used
 +if(HAVE_LIBWS2_32)
 +  set(CMAKE_REQUIRED_LIBRARIES ws2_32)
 +elseif(HAVE_LIBSOCKET)
 +  set(CMAKE_REQUIRED_LIBRARIES socket)
 +endif()
 +
 +check_symbol_exists(basename      "${CURL_INCLUDES}" HAVE_BASENAME)
 +check_symbol_exists(socket        "${CURL_INCLUDES}" HAVE_SOCKET)
 +check_symbol_exists(poll          "${CURL_INCLUDES}" HAVE_POLL)
 +check_symbol_exists(select        "${CURL_INCLUDES}" HAVE_SELECT)
 +check_symbol_exists(strdup        "${CURL_INCLUDES}" HAVE_STRDUP)
 +check_symbol_exists(strstr        "${CURL_INCLUDES}" HAVE_STRSTR)
 +check_symbol_exists(strtok_r      "${CURL_INCLUDES}" HAVE_STRTOK_R)
 +check_symbol_exists(strftime      "${CURL_INCLUDES}" HAVE_STRFTIME)
 +check_symbol_exists(uname         "${CURL_INCLUDES}" HAVE_UNAME)
 +check_symbol_exists(strcasecmp    "${CURL_INCLUDES}" HAVE_STRCASECMP)
 +check_symbol_exists(stricmp       "${CURL_INCLUDES}" HAVE_STRICMP)
 +check_symbol_exists(strcmpi       "${CURL_INCLUDES}" HAVE_STRCMPI)
 +check_symbol_exists(strncmpi      "${CURL_INCLUDES}" HAVE_STRNCMPI)
 +check_symbol_exists(alarm         "${CURL_INCLUDES}" HAVE_ALARM)
 +if(NOT HAVE_STRNCMPI)
 +  set(HAVE_STRCMPI)
 +endif(NOT HAVE_STRNCMPI)
 +check_symbol_exists(gethostbyaddr "${CURL_INCLUDES}" HAVE_GETHOSTBYADDR)
 +check_symbol_exists(gethostbyaddr_r "${CURL_INCLUDES}" HAVE_GETHOSTBYADDR_R)
 +check_symbol_exists(gettimeofday  "${CURL_INCLUDES}" HAVE_GETTIMEOFDAY)
 +check_symbol_exists(inet_addr     "${CURL_INCLUDES}" HAVE_INET_ADDR)
 +check_symbol_exists(inet_ntoa     "${CURL_INCLUDES}" HAVE_INET_NTOA)
 +check_symbol_exists(inet_ntoa_r   "${CURL_INCLUDES}" HAVE_INET_NTOA_R)
 +check_symbol_exists(tcsetattr     "${CURL_INCLUDES}" HAVE_TCSETATTR)
 +check_symbol_exists(tcgetattr     "${CURL_INCLUDES}" HAVE_TCGETATTR)
 +check_symbol_exists(perror        "${CURL_INCLUDES}" HAVE_PERROR)
 +check_symbol_exists(closesocket   "${CURL_INCLUDES}" HAVE_CLOSESOCKET)
 +check_symbol_exists(setvbuf       "${CURL_INCLUDES}" HAVE_SETVBUF)
 +check_symbol_exists(sigsetjmp     "${CURL_INCLUDES}" HAVE_SIGSETJMP)
 +check_symbol_exists(getpass_r     "${CURL_INCLUDES}" HAVE_GETPASS_R)
 +check_symbol_exists(strlcat       "${CURL_INCLUDES}" HAVE_STRLCAT)
 +check_symbol_exists(getpwuid      "${CURL_INCLUDES}" HAVE_GETPWUID)
 +check_symbol_exists(geteuid       "${CURL_INCLUDES}" HAVE_GETEUID)
 +check_symbol_exists(utime         "${CURL_INCLUDES}" HAVE_UTIME)
 +if(CMAKE_USE_OPENSSL)
 +  check_symbol_exists(RAND_status   "${CURL_INCLUDES}" HAVE_RAND_STATUS)
 +  check_symbol_exists(RAND_screen   "${CURL_INCLUDES}" HAVE_RAND_SCREEN)
 +  check_symbol_exists(RAND_egd      "${CURL_INCLUDES}" HAVE_RAND_EGD)
 +  check_symbol_exists(CRYPTO_cleanup_all_ex_data "${CURL_INCLUDES}"
 +    HAVE_CRYPTO_CLEANUP_ALL_EX_DATA)
 +  if(HAVE_LIBCRYPTO AND HAVE_LIBSSL)
 +    set(USE_OPENSSL 1)
 +  endif(HAVE_LIBCRYPTO AND HAVE_LIBSSL)
 +endif(CMAKE_USE_OPENSSL)
 +check_symbol_exists(gmtime_r      "${CURL_INCLUDES}" HAVE_GMTIME_R)
 +check_symbol_exists(localtime_r   "${CURL_INCLUDES}" HAVE_LOCALTIME_R)
 +
 +check_symbol_exists(gethostbyname   "${CURL_INCLUDES}" HAVE_GETHOSTBYNAME)
 +check_symbol_exists(gethostbyname_r "${CURL_INCLUDES}" HAVE_GETHOSTBYNAME_R)
 +
 +check_symbol_exists(signal        "${CURL_INCLUDES}" HAVE_SIGNAL_FUNC)
 +check_symbol_exists(SIGALRM       "${CURL_INCLUDES}" HAVE_SIGNAL_MACRO)
 +if(HAVE_SIGNAL_FUNC AND HAVE_SIGNAL_MACRO)
 +  set(HAVE_SIGNAL 1)
 +endif(HAVE_SIGNAL_FUNC AND HAVE_SIGNAL_MACRO)
 +check_symbol_exists(uname          "${CURL_INCLUDES}" HAVE_UNAME)
 +check_symbol_exists(strtoll        "${CURL_INCLUDES}" HAVE_STRTOLL)
 +check_symbol_exists(_strtoi64      "${CURL_INCLUDES}" HAVE__STRTOI64)
 +check_symbol_exists(strerror_r     "${CURL_INCLUDES}" HAVE_STRERROR_R)
 +check_symbol_exists(siginterrupt   "${CURL_INCLUDES}" HAVE_SIGINTERRUPT)
 +check_symbol_exists(perror         "${CURL_INCLUDES}" HAVE_PERROR)
 +check_symbol_exists(fork           "${CURL_INCLUDES}" HAVE_FORK)
 +check_symbol_exists(getaddrinfo    "${CURL_INCLUDES}" HAVE_GETADDRINFO)
 +check_symbol_exists(freeaddrinfo   "${CURL_INCLUDES}" HAVE_FREEADDRINFO)
 +check_symbol_exists(freeifaddrs    "${CURL_INCLUDES}" HAVE_FREEIFADDRS)
 +check_symbol_exists(pipe           "${CURL_INCLUDES}" HAVE_PIPE)
 +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(idn_free       "${CURL_INCLUDES}" HAVE_IDN_FREE)
 +check_symbol_exists(idna_strerror  "${CURL_INCLUDES}" HAVE_IDNA_STRERROR)
 +check_symbol_exists(tld_strerror   "${CURL_INCLUDES}" HAVE_TLD_STRERROR)
 +check_symbol_exists(setlocale      "${CURL_INCLUDES}" HAVE_SETLOCALE)
 +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)
 +
 +# symbol exists in win32, but function does not.
 +check_function_exists(inet_pton HAVE_INET_PTON)
 +
 +# sigaction and sigsetjmp are special. Use special mechanism for
 +# detecting those, but only if previous attempt failed.
 +if(HAVE_SIGNAL_H)
 +  check_symbol_exists(sigaction "signal.h" HAVE_SIGACTION)
 +endif(HAVE_SIGNAL_H)
 +
 +if(NOT HAVE_SIGSETJMP)
 +  if(HAVE_SETJMP_H)
 +    check_symbol_exists(sigsetjmp "setjmp.h" HAVE_MACRO_SIGSETJMP)
 +    if(HAVE_MACRO_SIGSETJMP)
 +      set(HAVE_SIGSETJMP 1)
 +    endif(HAVE_MACRO_SIGSETJMP)
 +  endif(HAVE_SETJMP_H)
 +endif(NOT HAVE_SIGSETJMP)
 +
 +# If there is no stricmp(), do not allow LDAP to parse URLs
 +if(NOT HAVE_STRICMP)
 +  set(HAVE_LDAP_URL_PARSE 1)
 +endif(NOT HAVE_STRICMP)
 +
 +# Do curl specific tests
 +foreach(CURL_TEST
 +    HAVE_FCNTL_O_NONBLOCK
 +    HAVE_IOCTLSOCKET
 +    HAVE_IOCTLSOCKET_CAMEL
 +    HAVE_IOCTLSOCKET_CAMEL_FIONBIO
 +    HAVE_IOCTLSOCKET_FIONBIO
 +    HAVE_IOCTL_FIONBIO
 +    HAVE_IOCTL_SIOCGIFADDR
 +    HAVE_SETSOCKOPT_SO_NONBLOCK
 +    HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
 +    TIME_WITH_SYS_TIME
 +    HAVE_O_NONBLOCK
 +    HAVE_GETHOSTBYADDR_R_5
 +    HAVE_GETHOSTBYADDR_R_7
 +    HAVE_GETHOSTBYADDR_R_8
 +    HAVE_GETHOSTBYADDR_R_5_REENTRANT
 +    HAVE_GETHOSTBYADDR_R_7_REENTRANT
 +    HAVE_GETHOSTBYADDR_R_8_REENTRANT
 +    HAVE_GETHOSTBYNAME_R_3
 +    HAVE_GETHOSTBYNAME_R_5
 +    HAVE_GETHOSTBYNAME_R_6
 +    HAVE_GETHOSTBYNAME_R_3_REENTRANT
 +    HAVE_GETHOSTBYNAME_R_5_REENTRANT
 +    HAVE_GETHOSTBYNAME_R_6_REENTRANT
 +    HAVE_SOCKLEN_T
 +    HAVE_IN_ADDR_T
 +    HAVE_BOOL_T
 +    STDC_HEADERS
 +    RETSIGTYPE_TEST
 +    HAVE_INET_NTOA_R_DECL
 +    HAVE_INET_NTOA_R_DECL_REENTRANT
 +    HAVE_GETADDRINFO
 +    HAVE_FILE_OFFSET_BITS
 +    )
 +  curl_internal_test(${CURL_TEST})
 +endforeach(CURL_TEST)
 +if(HAVE_FILE_OFFSET_BITS)
 +  set(_FILE_OFFSET_BITS 64)
 +endif(HAVE_FILE_OFFSET_BITS)
 +foreach(CURL_TEST
 +    HAVE_GLIBC_STRERROR_R
 +    HAVE_POSIX_STRERROR_R
 +    )
 +  curl_internal_test_run(${CURL_TEST})
 +endforeach(CURL_TEST)
 +
 +# Check for reentrant
 +foreach(CURL_TEST
 +    HAVE_GETHOSTBYADDR_R_5
 +    HAVE_GETHOSTBYADDR_R_7
 +    HAVE_GETHOSTBYADDR_R_8
 +    HAVE_GETHOSTBYNAME_R_3
 +    HAVE_GETHOSTBYNAME_R_5
 +    HAVE_GETHOSTBYNAME_R_6
 +    HAVE_INET_NTOA_R_DECL_REENTRANT)
 +  if(NOT ${CURL_TEST})
 +    if(${CURL_TEST}_REENTRANT)
 +      set(NEED_REENTRANT 1)
 +    endif(${CURL_TEST}_REENTRANT)
 +  endif(NOT ${CURL_TEST})
 +endforeach(CURL_TEST)
 +
 +if(NEED_REENTRANT)
 +  foreach(CURL_TEST
 +      HAVE_GETHOSTBYADDR_R_5
 +      HAVE_GETHOSTBYADDR_R_7
 +      HAVE_GETHOSTBYADDR_R_8
 +      HAVE_GETHOSTBYNAME_R_3
 +      HAVE_GETHOSTBYNAME_R_5
 +      HAVE_GETHOSTBYNAME_R_6)
 +    set(${CURL_TEST} 0)
 +    if(${CURL_TEST}_REENTRANT)
 +      set(${CURL_TEST} 1)
 +    endif(${CURL_TEST}_REENTRANT)
 +  endforeach(CURL_TEST)
 +endif(NEED_REENTRANT)
 +
 +if(HAVE_INET_NTOA_R_DECL_REENTRANT)
 +  set(HAVE_INET_NTOA_R_DECL 1)
 +  set(NEED_REENTRANT 1)
 +endif(HAVE_INET_NTOA_R_DECL_REENTRANT)
 +
 +# Some other minor tests
 +
 +if(NOT HAVE_IN_ADDR_T)
 +  set(in_addr_t "unsigned long")
 +endif(NOT HAVE_IN_ADDR_T)
 +
 +# Fix libz / zlib.h
 +
 +if(NOT CURL_SPECIAL_LIBZ)
 +  if(NOT HAVE_LIBZ)
 +    set(HAVE_ZLIB_H 0)
 +  endif(NOT HAVE_LIBZ)
 +
 +  if(NOT HAVE_ZLIB_H)
 +    set(HAVE_LIBZ 0)
 +  endif(NOT HAVE_ZLIB_H)
 +endif(NOT CURL_SPECIAL_LIBZ)
 +
 +if(_FILE_OFFSET_BITS)
 +  set(_FILE_OFFSET_BITS 64)
 +endif(_FILE_OFFSET_BITS)
 +set(CMAKE_REQUIRED_FLAGS "-D_FILE_OFFSET_BITS=64")
 +set(CMAKE_EXTRA_INCLUDE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/curl/curl.h")
 +check_type_size("curl_off_t" SIZEOF_CURL_OFF_T)
 +set(CMAKE_EXTRA_INCLUDE_FILES)
 +set(CMAKE_REQUIRED_FLAGS)
 +
 +
 +# Check for nonblocking
 +set(HAVE_DISABLED_NONBLOCKING 1)
 +if(HAVE_FIONBIO OR
 +    HAVE_IOCTLSOCKET OR
 +    HAVE_IOCTLSOCKET_CASE OR
 +    HAVE_O_NONBLOCK)
 +  set(HAVE_DISABLED_NONBLOCKING)
 +endif(HAVE_FIONBIO OR
 +  HAVE_IOCTLSOCKET OR
 +  HAVE_IOCTLSOCKET_CASE OR
 +  HAVE_O_NONBLOCK)
 +
 +if(RETSIGTYPE_TEST)
 +  set(RETSIGTYPE void)
 +else(RETSIGTYPE_TEST)
 +  set(RETSIGTYPE int)
 +endif(RETSIGTYPE_TEST)
 +
 +if(CMAKE_COMPILER_IS_GNUCC AND APPLE)
 +  include(CheckCCompilerFlag)
 +  check_c_compiler_flag(-Wno-long-double HAVE_C_FLAG_Wno_long_double)
 +  if(HAVE_C_FLAG_Wno_long_double)
 +    # The Mac version of GCC warns about use of long double.  Disable it.
 +    get_source_file_property(MPRINTF_COMPILE_FLAGS mprintf.c COMPILE_FLAGS)
 +    if(MPRINTF_COMPILE_FLAGS)
 +      set(MPRINTF_COMPILE_FLAGS "${MPRINTF_COMPILE_FLAGS} -Wno-long-double")
 +    else(MPRINTF_COMPILE_FLAGS)
 +      set(MPRINTF_COMPILE_FLAGS "-Wno-long-double")
 +    endif(MPRINTF_COMPILE_FLAGS)
 +    set_source_files_properties(mprintf.c PROPERTIES
 +      COMPILE_FLAGS ${MPRINTF_COMPILE_FLAGS})
 +  endif(HAVE_C_FLAG_Wno_long_double)
 +endif(CMAKE_COMPILER_IS_GNUCC AND APPLE)
 +
 +if(HAVE_SOCKLEN_T)
 +  set(CURL_HAVE_SOCKLEN_T 1)
 +  set(CURL_TYPEOF_CURL_SOCKLEN_T "socklen_t")
 +  if(WIN32)
 +    set(CMAKE_EXTRA_INCLUDE_FILES "winsock2.h;ws2tcpip.h")
 +  elseif(HAVE_SYS_SOCKET_H)
 +    set(CMAKE_EXTRA_INCLUDE_FILES "sys/socket.h")
 +  endif()
 +  check_type_size("socklen_t" CURL_SIZEOF_CURL_SOCKLEN_T)
 +  set(CMAKE_EXTRA_INCLUDE_FILES)
 +  if(NOT HAVE_CURL_SIZEOF_CURL_SOCKLEN_T)
 +    message(FATAL_ERROR
 +     "Check for sizeof socklen_t failed, see CMakeFiles/CMakerror.log")
 +  endif()
 +else()
 +  set(CURL_HAVE_SOCKLEN_T 0)
 +endif()
 +
 +# TODO test which of these headers are required for the typedefs used in curlbuild.h
 +if(WIN32)
 +  set(CURL_PULL_WS2TCPIP_H ${HAVE_WS2TCPIP_H})
 +else()
 +  set(CURL_PULL_SYS_TYPES_H ${HAVE_SYS_TYPES_H})
 +  set(CURL_PULL_SYS_SOCKET_H ${HAVE_SYS_SOCKET_H})
 +  set(CURL_PULL_SYS_POLL_H ${HAVE_SYS_POLL_H})
 +endif()
 +set(CURL_PULL_STDINT_H ${HAVE_STDINT_H})
 +set(CURL_PULL_INTTYPES_H ${HAVE_INTTYPES_H})
 +
 +include(CMake/OtherTests.cmake)
 +
 +add_definitions(-DHAVE_CONFIG_H)
 +
 +# For windows, do not allow the compiler to use default target (Vista).
 +if(WIN32)
 +  add_definitions(-D_WIN32_WINNT=0x0501)
 +endif(WIN32)
 +
 +if(MSVC)
 +  add_definitions(-D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE)
 +endif(MSVC)
 +
 +# Ugly (but functional) way to include "Makefile.inc" by transforming it (= regenerate it).
 +function(TRANSFORM_MAKEFILE_INC INPUT_FILE OUTPUT_FILE)
 +  file(READ ${INPUT_FILE} MAKEFILE_INC_TEXT)
 +  string(REPLACE "$(top_srcdir)"   "\${CURL_SOURCE_DIR}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT})
 +  string(REPLACE "$(top_builddir)" "\${CURL_BINARY_DIR}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT})
 +
 +  string(REGEX REPLACE "\\\\\n" "§!§" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT})
 +  string(REGEX REPLACE "([a-zA-Z_][a-zA-Z0-9_]*)[\t ]*=[\t ]*([^\n]*)" "SET(\\1 \\2)" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT})
 +  string(REPLACE "§!§" "\n" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT})
 +
 +  string(REGEX REPLACE "\\$\\(([a-zA-Z_][a-zA-Z0-9_]*)\\)" "\${\\1}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT})    # Replace $() with ${}
 +  string(REGEX REPLACE "@([a-zA-Z_][a-zA-Z0-9_]*)@" "\${\\1}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT})    # Replace @@ with ${}, even if that may not be read by CMake scripts.
 +  file(WRITE ${OUTPUT_FILE} ${MAKEFILE_INC_TEXT})
 +
 +endfunction()
 +
 +add_subdirectory(lib)
 +if(BUILD_CURL_EXE)
 +  add_subdirectory(src)
 +endif()
- if(BUILD_CURL_TESTS)
-   add_subdirectory(tests)
- endif()
 +
 +#-----------------------------------------------------------------------------
 +# CMake-specific curl code.
 +add_executable(LIBCURL curltest.c)
 +target_link_libraries(LIBCURL cmcurl)
 +
 +if(CMAKE_CURL_TEST_URL)
 +  add_test(curl LIBCURL ${CMAKE_CURL_TEST_URL})
 +endif()
 +
 +install(FILES COPYING DESTINATION ${CMAKE_DOC_DIR}/cmcurl)
 +#-----------------------------------------------------------------------------
 +
 +if(0) # This code not needed for building within CMake.
++include(CTest)
++if(BUILD_TESTING)
++  add_subdirectory(tests)
++endif()
++
 +# TODO support GNUTLS, NSS, POLARSSL, AXTLS, CYASSL, WINSSL, DARWINSSL
 +if(USE_OPENSSL)
 +  set(SSL_ENABLED 1)
 +endif()
 +
 +# Helper to populate a list (_items) with a label when conditions (the remaining
 +# args) are satisfied
 +function(_add_if label)
 +  # TODO need to disable policy CMP0054 (CMake 3.1) to allow this indirection
 +  if(${ARGN})
 +    set(_items ${_items} "${label}" PARENT_SCOPE)
 +  endif()
 +endfunction()
 +
 +# Clear list and try to detect available features
 +set(_items)
- _add_if("SSL"           SSL_ENABLED)
++_add_if("WinSSL"        SSL_ENABLED AND USE_WINDOWS_SSPI)
++_add_if("OpenSSL"       SSL_ENABLED AND USE_OPENSSL)
 +_add_if("IPv6"          ENABLE_IPV6)
 +_add_if("unix-sockets"  USE_UNIX_SOCKETS)
 +_add_if("libz"          HAVE_LIBZ)
 +_add_if("AsynchDNS"     USE_ARES OR USE_THREADS_POSIX)
 +_add_if("IDN"           HAVE_LIBIDN)
 +# TODO SSP1 (WinSSL) check is missing
 +_add_if("SSPI"          USE_WINDOWS_SSPI)
 +_add_if("GSS-API"       HAVE_GSSAPI)
 +# TODO SSP1 missing for SPNEGO
 +_add_if("SPNEGO"        NOT CURL_DISABLE_CRYPTO_AUTH AND
 +                        (HAVE_GSSAPI OR USE_WINDOWS_SSPI))
 +_add_if("Kerberos"      NOT CURL_DISABLE_CRYPTO_AUTH AND
 +                        (HAVE_GSSAPI OR USE_WINDOWS_SSPI))
 +# NTLM support requires crypto function adaptions from various SSL libs
 +# TODO alternative SSL libs tests for SSP1, GNUTLS, NSS, DARWINSSL
 +if(NOT CURL_DISABLE_CRYPTO_AUTH AND (USE_OPENSSL OR
 +   USE_WINDOWS_SSPI OR GNUTLS_ENABLED OR NSS_ENABLED OR DARWINSSL_ENABLED))
 +  _add_if("NTLM"        1)
 +  # TODO missing option (autoconf: --enable-ntlm-wb)
 +  _add_if("NTLM_WB"     NOT CURL_DISABLE_HTTP AND NTLM_WB_ENABLED)
 +endif()
 +# TODO missing option (--enable-tls-srp), depends on GNUTLS_SRP/OPENSSL_SRP
 +_add_if("TLS-SRP"       USE_TLS_SRP)
 +# TODO option --with-nghttp2 tests for nghttp2 lib and nghttp2/nghttp2.h header
 +_add_if("HTTP2"         USE_NGHTTP2)
 +string(REPLACE ";" " " SUPPORT_FEATURES "${_items}")
 +message(STATUS "Enabled features: ${SUPPORT_FEATURES}")
 +
 +# Clear list and try to detect available protocols
 +set(_items)
 +_add_if("HTTP"          NOT CURL_DISABLE_HTTP)
 +_add_if("HTTPS"         NOT CURL_DISABLE_HTTP AND SSL_ENABLED)
 +_add_if("FTP"           NOT CURL_DISABLE_FTP)
 +_add_if("FTPS"          NOT CURL_DISABLE_FTP AND SSL_ENABLED)
 +_add_if("FILE"          NOT CURL_DISABLE_FILE)
 +_add_if("TELNET"        NOT CURL_DISABLE_TELNET)
 +_add_if("LDAP"          NOT CURL_DISABLE_LDAP)
 +# CURL_DISABLE_LDAP implies CURL_DISABLE_LDAPS
 +# TODO check HAVE_LDAP_SSL (in autoconf this is enabled with --enable-ldaps)
 +_add_if("LDAPS"         NOT CURL_DISABLE_LDAPS AND
 +                        ((USE_OPENLDAP AND SSL_ENABLED) OR
 +                        (NOT USE_OPENLDAP AND HAVE_LDAP_SSL)))
 +_add_if("DICT"          NOT CURL_DISABLE_DICT)
 +_add_if("TFTP"          NOT CURL_DISABLE_TFTP)
 +_add_if("GOPHER"        NOT CURL_DISABLE_GOPHER)
 +_add_if("POP3"          NOT CURL_DISABLE_POP3)
 +_add_if("POP3S"         NOT CURL_DISABLE_POP3 AND SSL_ENABLED)
 +_add_if("IMAP"          NOT CURL_DISABLE_IMAP)
 +_add_if("IMAPS"         NOT CURL_DISABLE_IMAP AND SSL_ENABLED)
 +_add_if("SMTP"          NOT CURL_DISABLE_SMTP)
 +_add_if("SMTPS"         NOT CURL_DISABLE_SMTP AND SSL_ENABLED)
 +_add_if("SCP"           USE_LIBSSH2)
 +_add_if("SFTP"          USE_LIBSSH2)
 +_add_if("RTSP"          NOT CURL_DISABLE_RTSP)
 +_add_if("RTMP"          USE_LIBRTMP)
 +list(SORT _items)
 +string(REPLACE ";" " " SUPPORT_PROTOCOLS "${_items}")
 +message(STATUS "Enabled protocols: ${SUPPORT_PROTOCOLS}")
 +
 +# curl-config needs the following options to be set.
 +set(CC                      "${CMAKE_C_COMPILER}")
 +# TODO probably put a -D... options here?
 +set(CONFIGURE_OPTIONS       "")
 +# TODO when to set "-DCURL_STATICLIB" for CPPFLAG_CURL_STATICLIB?
 +set(CPPFLAG_CURL_STATICLIB  "")
 +# TODO need to set this (see CURL_CHECK_CA_BUNDLE in acinclude.m4)
 +set(CURL_CA_BUNDLE          "")
 +set(CURLVERSION             "${CURL_VERSION}")
 +set(ENABLE_SHARED           "yes")
 +if(CURL_STATICLIB)
 +  # Broken: LIBCURL_LIBS below; .a lib is not built
 +  message(WARNING "Static linking is broken!")
 +  set(ENABLE_STATIC         "no")
 +else()
 +  set(ENABLE_STATIC         "no")
 +endif()
 +set(exec_prefix             "\${prefix}")
 +set(includedir              "\${prefix}/include")
 +set(LDFLAGS                 "${CMAKE_SHARED_LINKER_FLAGS}")
 +set(LIBCURL_LIBS            "")
 +set(libdir                  "${CMAKE_INSTALL_PREFIX}/lib")
 +# TODO CURL_LIBS also contains absolute paths which don't work with static -l...
 +foreach(_lib ${CMAKE_C_IMPLICIT_LINK_LIBRARIES} ${CURL_LIBS})
 +  set(LIBCURL_LIBS          "${LIBCURL_LIBS} -l${_lib}")
 +endforeach()
 +# "a" (Linux) or "lib" (Windows)
 +string(REPLACE "." "" libext "${CMAKE_STATIC_LIBRARY_SUFFIX}")
 +set(prefix                  "${CMAKE_INSTALL_PREFIX}")
 +# Set this to "yes" to append all libraries on which -lcurl is dependent
 +set(REQUIRE_LIB_DEPS        "no")
 +# SUPPORT_FEATURES
 +# SUPPORT_PROTOCOLS
 +set(VERSIONNUM              "${CURL_VERSION_NUM}")
 +
 +# Finally generate a "curl-config" matching this config
 +configure_file("${CURL_SOURCE_DIR}/curl-config.in"
 +               "${CURL_BINARY_DIR}/curl-config" @ONLY)
- install(FILES "${CMAKE_BINARY_DIR}/curl-config"
++install(FILES "${CURL_BINARY_DIR}/curl-config"
 +        DESTINATION bin
 +        PERMISSIONS
 +          OWNER_READ OWNER_WRITE OWNER_EXECUTE
 +          GROUP_READ GROUP_EXECUTE
 +          WORLD_READ WORLD_EXECUTE)
 +
 +# Finally generate a pkg-config file matching this config
 +configure_file("${CURL_SOURCE_DIR}/libcurl.pc.in"
 +               "${CURL_BINARY_DIR}/libcurl.pc" @ONLY)
- install(FILES "${CMAKE_BINARY_DIR}/libcurl.pc"
++install(FILES "${CURL_BINARY_DIR}/libcurl.pc"
 +        DESTINATION lib/pkgconfig)
 +
 +# This needs to be run very last so other parts of the scripts can take advantage of this.
 +if(NOT CURL_CONFIG_HAS_BEEN_RUN_BEFORE)
 +  set(CURL_CONFIG_HAS_BEEN_RUN_BEFORE 1 CACHE INTERNAL "Flag to track whether this is the first time running CMake or if CMake has been configured before")
 +endif()
 +
 +# Installation.
 +# First, install generated curlbuild.h
 +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/include/curl/curlbuild.h"
 +    DESTINATION include/curl )
 +# Next, install other headers excluding curlbuild.h
 +install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/curl"
 +    DESTINATION include
 +    FILES_MATCHING PATTERN "*.h"
 +    PATTERN "curlbuild.h" EXCLUDE)
 +
 +
 +# Workaround for MSVS10 to avoid the Dialog Hell
 +# FIXME: This could be removed with future version of CMake.
 +if(MSVC_VERSION EQUAL 1600)
 +  set(CURL_SLN_FILENAME "${CMAKE_CURRENT_BINARY_DIR}/CURL.sln")
 +  if(EXISTS "${CURL_SLN_FILENAME}")
 +    file(APPEND "${CURL_SLN_FILENAME}" "\n# This should be regenerated!\n")
 +  endif()
 +endif()
 +endif()
diff --cc Utilities/cmcurl/include/curl/curl.h
index 86ce1ff,0000000..dfaea5d
mode 100644,000000..100644
--- a/Utilities/cmcurl/include/curl/curl.h
+++ b/Utilities/cmcurl/include/curl/curl.h
@@@ -1,2382 -1,0 +1,2447 @@@
 +#ifndef __CURL_CURL_H
 +#define __CURL_CURL_H
 +/***************************************************************************
 + *                                  _   _ ____  _
 + *  Project                     ___| | | |  _ \| |
 + *                             / __| | | | |_) | |
 + *                            | (__| |_| |  _ <| |___
 + *                             \___|\___/|_| \_\_____|
 + *
-  * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
++ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
 + *
 + * This software is licensed as described in the file COPYING, which
 + * you should have received as part of this distribution. The terms
-  * are also available at http://curl.haxx.se/docs/copyright.html.
++ * 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.
 + *
 + ***************************************************************************/
 +
 +/*
 + * If you have libcurl problems, all docs and details are found here:
-  *   http://curl.haxx.se/libcurl/
++ *   https://curl.haxx.se/libcurl/
 + *
 + * curl-library mailing list subscription and unsubscription web interface:
-  *   http://cool.haxx.se/mailman/listinfo/curl-library/
++ *   https://cool.haxx.se/mailman/listinfo/curl-library/
 + */
 +
 +#include "curlver.h"         /* libcurl version defines   */
 +#include "cmcurl/include/curl/curlbuild.h" /* libcurl build definitions */
 +#include "curlrules.h"       /* libcurl rules enforcement */
 +
 +/*
 + * Define WIN32 when build target is Win32 API
 + */
 +
 +#if (defined(_WIN32) || defined(__WIN32__)) && \
 +     !defined(WIN32) && !defined(__SYMBIAN32__)
 +#define WIN32
 +#endif
 +
 +#include <stdio.h>
 +#include <limits.h>
 +
 +#if defined(__FreeBSD__) && (__FreeBSD__ >= 2)
 +/* Needed for __FreeBSD_version symbol definition */
 +#include <osreldate.h>
 +#endif
 +
 +/* The include stuff here below is mainly for time_t! */
 +#include <sys/types.h>
 +#include <time.h>
 +
 +#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__CYGWIN__)
- #if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H) || defined(__LWIP_OPT_H__))
++#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H) || \
++      defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H))
 +/* The check above prevents the winsock2 inclusion if winsock.h already was
 +   included, since they can't co-exist without problems */
 +#include <winsock2.h>
 +#include <ws2tcpip.h>
 +#endif
 +#endif
 +
 +/* HP-UX systems version 9, 10 and 11 lack sys/select.h and so does oldish
 +   libc5-based Linux systems. Only include it on systems that are known to
 +   require it! */
 +#if defined(_AIX) || defined(__NOVELL_LIBC__) || defined(__NetBSD__) || \
 +    defined(__minix) || defined(__SYMBIAN32__) || defined(__INTEGRITY) || \
 +    defined(ANDROID) || defined(__ANDROID__) || defined(__OpenBSD__) || \
 +   (defined(__FreeBSD_version) && (__FreeBSD_version < 800000))
 +#include <sys/select.h>
 +#endif
 +
 +#if !defined(WIN32) && !defined(_WIN32_WCE)
 +#include <sys/socket.h>
 +#endif
 +
 +#if !defined(WIN32) && !defined(__WATCOMC__) && !defined(__VXWORKS__)
 +#include <sys/time.h>
 +#endif
 +
 +#if defined __BEOS__ || defined __HAIKU__
 +#include <support/SupportDefs.h>
 +#endif
 +
 +#ifdef  __cplusplus
 +extern "C" {
 +#endif
 +
++#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER)
++typedef struct Curl_easy CURL;
++typedef struct Curl_share CURLSH;
++#else
 +typedef void CURL;
++typedef void CURLSH;
++#endif
 +
 +/*
 + * libcurl external API function linkage decorations.
 + */
 +
 +#ifdef CURL_STATICLIB
 +#  define CURL_EXTERN
 +#elif defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__)
 +#  if defined(BUILDING_LIBCURL)
 +#    define CURL_EXTERN  __declspec(dllexport)
 +#  else
 +#    define CURL_EXTERN  __declspec(dllimport)
 +#  endif
 +#elif defined(BUILDING_LIBCURL) && defined(CURL_HIDDEN_SYMBOLS)
 +#  define CURL_EXTERN CURL_EXTERN_SYMBOL
 +#else
 +#  define CURL_EXTERN
 +#endif
 +
 +#ifndef curl_socket_typedef
 +/* socket typedef */
- #if defined(WIN32) && !defined(__LWIP_OPT_H__)
++#if defined(WIN32) && !defined(__LWIP_OPT_H__) && !defined(LWIP_HDR_OPT_H)
 +typedef SOCKET curl_socket_t;
 +#define CURL_SOCKET_BAD INVALID_SOCKET
 +#else
 +typedef int curl_socket_t;
 +#define CURL_SOCKET_BAD -1
 +#endif
 +#define curl_socket_typedef
 +#endif /* curl_socket_typedef */
 +
 +struct curl_httppost {
 +  struct curl_httppost *next;       /* next entry in the list */
 +  char *name;                       /* pointer to allocated name */
 +  long namelength;                  /* length of name length */
 +  char *contents;                   /* pointer to allocated data contents */
-   long contentslength;              /* length of contents field */
++  long contentslength;              /* length of contents field, see also
++                                       CURL_HTTPPOST_LARGE */
 +  char *buffer;                     /* pointer to allocated buffer contents */
 +  long bufferlength;                /* length of buffer field */
 +  char *contenttype;                /* Content-Type */
 +  struct curl_slist* contentheader; /* list of extra headers for this form */
 +  struct curl_httppost *more;       /* if one field name has more than one
 +                                       file, this link should link to following
 +                                       files */
 +  long flags;                       /* as defined below */
- #define HTTPPOST_FILENAME (1<<0)    /* specified content is a file name */
- #define HTTPPOST_READFILE (1<<1)    /* specified content is a file name */
- #define HTTPPOST_PTRNAME (1<<2)     /* name is only stored pointer
-                                        do not free in formfree */
- #define HTTPPOST_PTRCONTENTS (1<<3) /* contents is only stored pointer
-                                        do not free in formfree */
- #define HTTPPOST_BUFFER (1<<4)      /* upload file from buffer */
- #define HTTPPOST_PTRBUFFER (1<<5)   /* upload file from pointer contents */
- #define HTTPPOST_CALLBACK (1<<6)    /* upload file contents by using the
-                                        regular read callback to get the data
-                                        and pass the given pointer as custom
-                                        pointer */
++
++/* specified content is a file name */
++#define CURL_HTTPPOST_FILENAME (1<<0)
++/* specified content is a file name */
++#define CURL_HTTPPOST_READFILE (1<<1)
++/* name is only stored pointer do not free in formfree */
++#define CURL_HTTPPOST_PTRNAME (1<<2)
++/* contents is only stored pointer do not free in formfree */
++#define CURL_HTTPPOST_PTRCONTENTS (1<<3)
++/* upload file from buffer */
++#define CURL_HTTPPOST_BUFFER (1<<4)
++/* upload file from pointer contents */
++#define CURL_HTTPPOST_PTRBUFFER (1<<5)
++/* upload file contents by using the regular read callback to get the data and
++   pass the given pointer as custom pointer */
++#define CURL_HTTPPOST_CALLBACK (1<<6)
++/* use size in 'contentlen', added in 7.46.0 */
++#define CURL_HTTPPOST_LARGE (1<<7)
 +
 +  char *showfilename;               /* The file name to show. If not set, the
 +                                       actual file name will be used (if this
 +                                       is a file part) */
 +  void *userp;                      /* custom pointer used for
 +                                       HTTPPOST_CALLBACK posts */
++  curl_off_t contentlen;            /* alternative length of contents
++                                       field. Used if CURL_HTTPPOST_LARGE is
++                                       set. Added in 7.46.0 */
 +};
 +
 +/* This is the CURLOPT_PROGRESSFUNCTION callback proto. It is now considered
 +   deprecated but was the only choice up until 7.31.0 */
 +typedef int (*curl_progress_callback)(void *clientp,
 +                                      double dltotal,
 +                                      double dlnow,
 +                                      double ultotal,
 +                                      double ulnow);
 +
 +/* This is the CURLOPT_XFERINFOFUNCTION callback proto. It was introduced in
 +   7.32.0, it avoids floating point and provides more detailed information. */
 +typedef int (*curl_xferinfo_callback)(void *clientp,
 +                                      curl_off_t dltotal,
 +                                      curl_off_t dlnow,
 +                                      curl_off_t ultotal,
 +                                      curl_off_t ulnow);
 +
 +#ifndef CURL_MAX_WRITE_SIZE
 +  /* Tests have proven that 20K is a very bad buffer size for uploads on
 +     Windows, while 16K for some odd reason performed a lot better.
 +     We do the ifndef check to allow this value to easier be changed at build
 +     time for those who feel adventurous. The practical minimum is about
 +     400 bytes since libcurl uses a buffer of this size as a scratch area
 +     (unrelated to network send operations). */
 +#define CURL_MAX_WRITE_SIZE 16384
 +#endif
 +
 +#ifndef CURL_MAX_HTTP_HEADER
 +/* The only reason to have a max limit for this is to avoid the risk of a bad
 +   server feeding libcurl with a never-ending header that will cause reallocs
 +   infinitely */
 +#define CURL_MAX_HTTP_HEADER (100*1024)
 +#endif
 +
 +/* This is a magic return code for the write callback that, when returned,
 +   will signal libcurl to pause receiving on the current transfer. */
 +#define CURL_WRITEFUNC_PAUSE 0x10000001
 +
 +typedef size_t (*curl_write_callback)(char *buffer,
 +                                      size_t size,
 +                                      size_t nitems,
 +                                      void *outstream);
 +
 +
 +
 +/* enumeration of file types */
 +typedef enum {
 +  CURLFILETYPE_FILE = 0,
 +  CURLFILETYPE_DIRECTORY,
 +  CURLFILETYPE_SYMLINK,
 +  CURLFILETYPE_DEVICE_BLOCK,
 +  CURLFILETYPE_DEVICE_CHAR,
 +  CURLFILETYPE_NAMEDPIPE,
 +  CURLFILETYPE_SOCKET,
 +  CURLFILETYPE_DOOR, /* is possible only on Sun Solaris now */
 +
 +  CURLFILETYPE_UNKNOWN /* should never occur */
 +} curlfiletype;
 +
 +#define CURLFINFOFLAG_KNOWN_FILENAME    (1<<0)
 +#define CURLFINFOFLAG_KNOWN_FILETYPE    (1<<1)
 +#define CURLFINFOFLAG_KNOWN_TIME        (1<<2)
 +#define CURLFINFOFLAG_KNOWN_PERM        (1<<3)
 +#define CURLFINFOFLAG_KNOWN_UID         (1<<4)
 +#define CURLFINFOFLAG_KNOWN_GID         (1<<5)
 +#define CURLFINFOFLAG_KNOWN_SIZE        (1<<6)
 +#define CURLFINFOFLAG_KNOWN_HLINKCOUNT  (1<<7)
 +
 +/* Content of this structure depends on information which is known and is
 +   achievable (e.g. by FTP LIST parsing). Please see the url_easy_setopt(3) man
 +   page for callbacks returning this structure -- some fields are mandatory,
 +   some others are optional. The FLAG field has special meaning. */
 +struct curl_fileinfo {
 +  char *filename;
 +  curlfiletype filetype;
 +  time_t time;
 +  unsigned int perm;
 +  int uid;
 +  int gid;
 +  curl_off_t size;
 +  long int hardlinks;
 +
 +  struct {
 +    /* If some of these fields is not NULL, it is a pointer to b_data. */
 +    char *time;
 +    char *perm;
 +    char *user;
 +    char *group;
 +    char *target; /* pointer to the target filename of a symlink */
 +  } strings;
 +
 +  unsigned int flags;
 +
 +  /* used internally */
 +  char * b_data;
 +  size_t b_size;
 +  size_t b_used;
 +};
 +
 +/* return codes for CURLOPT_CHUNK_BGN_FUNCTION */
 +#define CURL_CHUNK_BGN_FUNC_OK      0
 +#define CURL_CHUNK_BGN_FUNC_FAIL    1 /* tell the lib to end the task */
 +#define CURL_CHUNK_BGN_FUNC_SKIP    2 /* skip this chunk over */
 +
 +/* if splitting of data transfer is enabled, this callback is called before
 +   download of an individual chunk started. Note that parameter "remains" works
 +   only for FTP wildcard downloading (for now), otherwise is not used */
 +typedef long (*curl_chunk_bgn_callback)(const void *transfer_info,
 +                                        void *ptr,
 +                                        int remains);
 +
 +/* return codes for CURLOPT_CHUNK_END_FUNCTION */
 +#define CURL_CHUNK_END_FUNC_OK      0
 +#define CURL_CHUNK_END_FUNC_FAIL    1 /* tell the lib to end the task */
 +
 +/* If splitting of data transfer is enabled this callback is called after
 +   download of an individual chunk finished.
 +   Note! After this callback was set then it have to be called FOR ALL chunks.
 +   Even if downloading of this chunk was skipped in CHUNK_BGN_FUNC.
 +   This is the reason why we don't need "transfer_info" parameter in this
 +   callback and we are not interested in "remains" parameter too. */
 +typedef long (*curl_chunk_end_callback)(void *ptr);
 +
 +/* return codes for FNMATCHFUNCTION */
 +#define CURL_FNMATCHFUNC_MATCH    0 /* string corresponds to the pattern */
 +#define CURL_FNMATCHFUNC_NOMATCH  1 /* pattern doesn't match the string */
 +#define CURL_FNMATCHFUNC_FAIL     2 /* an error occurred */
 +
 +/* callback type for wildcard downloading pattern matching. If the
 +   string matches the pattern, return CURL_FNMATCHFUNC_MATCH value, etc. */
 +typedef int (*curl_fnmatch_callback)(void *ptr,
 +                                     const char *pattern,
 +                                     const char *string);
 +
 +/* These are the return codes for the seek callbacks */
 +#define CURL_SEEKFUNC_OK       0
 +#define CURL_SEEKFUNC_FAIL     1 /* fail the entire transfer */
 +#define CURL_SEEKFUNC_CANTSEEK 2 /* tell libcurl seeking can't be done, so
 +                                    libcurl might try other means instead */
 +typedef int (*curl_seek_callback)(void *instream,
 +                                  curl_off_t offset,
 +                                  int origin); /* 'whence' */
 +
 +/* This is a return code for the read callback that, when returned, will
 +   signal libcurl to immediately abort the current transfer. */
 +#define CURL_READFUNC_ABORT 0x10000000
 +/* This is a return code for the read callback that, when returned, will
 +   signal libcurl to pause sending data on the current transfer. */
 +#define CURL_READFUNC_PAUSE 0x10000001
 +
 +typedef size_t (*curl_read_callback)(char *buffer,
 +                                      size_t size,
 +                                      size_t nitems,
 +                                      void *instream);
 +
 +typedef enum  {
 +  CURLSOCKTYPE_IPCXN,  /* socket created for a specific IP connection */
 +  CURLSOCKTYPE_ACCEPT, /* socket created by accept() call */
 +  CURLSOCKTYPE_LAST    /* never use */
 +} curlsocktype;
 +
 +/* The return code from the sockopt_callback can signal information back
 +   to libcurl: */
 +#define CURL_SOCKOPT_OK 0
 +#define CURL_SOCKOPT_ERROR 1 /* causes libcurl to abort and return
 +                                CURLE_ABORTED_BY_CALLBACK */
 +#define CURL_SOCKOPT_ALREADY_CONNECTED 2
 +
 +typedef int (*curl_sockopt_callback)(void *clientp,
 +                                     curl_socket_t curlfd,
 +                                     curlsocktype purpose);
 +
 +struct curl_sockaddr {
 +  int family;
 +  int socktype;
 +  int protocol;
 +  unsigned int addrlen; /* addrlen was a socklen_t type before 7.18.0 but it
 +                           turned really ugly and painful on the systems that
 +                           lack this type */
 +  struct sockaddr addr;
 +};
 +
 +typedef curl_socket_t
 +(*curl_opensocket_callback)(void *clientp,
 +                            curlsocktype purpose,
 +                            struct curl_sockaddr *address);
 +
 +typedef int
 +(*curl_closesocket_callback)(void *clientp, curl_socket_t item);
 +
 +typedef enum {
 +  CURLIOE_OK,            /* I/O operation successful */
 +  CURLIOE_UNKNOWNCMD,    /* command was unknown to callback */
 +  CURLIOE_FAILRESTART,   /* failed to restart the read */
 +  CURLIOE_LAST           /* never use */
 +} curlioerr;
 +
 +typedef enum  {
 +  CURLIOCMD_NOP,         /* no operation */
 +  CURLIOCMD_RESTARTREAD, /* restart the read stream from start */
 +  CURLIOCMD_LAST         /* never use */
 +} curliocmd;
 +
 +typedef curlioerr (*curl_ioctl_callback)(CURL *handle,
 +                                         int cmd,
 +                                         void *clientp);
 +
++#ifndef CURL_DID_MEMORY_FUNC_TYPEDEFS
 +/*
 + * The following typedef's are signatures of malloc, free, realloc, strdup and
 + * calloc respectively.  Function pointers of these types can be passed to the
 + * curl_global_init_mem() function to set user defined memory management
 + * callback routines.
 + */
 +typedef void *(*curl_malloc_callback)(size_t size);
 +typedef void (*curl_free_callback)(void *ptr);
 +typedef void *(*curl_realloc_callback)(void *ptr, size_t size);
 +typedef char *(*curl_strdup_callback)(const char *str);
 +typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size);
 +
++#define CURL_DID_MEMORY_FUNC_TYPEDEFS
++#endif
++
 +/* the kind of data that is passed to information_callback*/
 +typedef enum {
 +  CURLINFO_TEXT = 0,
 +  CURLINFO_HEADER_IN,    /* 1 */
 +  CURLINFO_HEADER_OUT,   /* 2 */
 +  CURLINFO_DATA_IN,      /* 3 */
 +  CURLINFO_DATA_OUT,     /* 4 */
 +  CURLINFO_SSL_DATA_IN,  /* 5 */
 +  CURLINFO_SSL_DATA_OUT, /* 6 */
 +  CURLINFO_END
 +} curl_infotype;
 +
 +typedef int (*curl_debug_callback)
 +       (CURL *handle,      /* the handle/transfer this concerns */
 +        curl_infotype type, /* what kind of data */
 +        char *data,        /* points to the data */
 +        size_t size,       /* size of the data pointed to */
 +        void *userptr);    /* whatever the user please */
 +
 +/* All possible error codes from all sorts of curl functions. Future versions
 +   may return other values, stay prepared.
 +
 +   Always add new return codes last. Never *EVER* remove any. The return
 +   codes must remain the same!
 + */
 +
 +typedef enum {
 +  CURLE_OK = 0,
 +  CURLE_UNSUPPORTED_PROTOCOL,    /* 1 */
 +  CURLE_FAILED_INIT,             /* 2 */
 +  CURLE_URL_MALFORMAT,           /* 3 */
 +  CURLE_NOT_BUILT_IN,            /* 4 - [was obsoleted in August 2007 for
 +                                    7.17.0, reused in April 2011 for 7.21.5] */
 +  CURLE_COULDNT_RESOLVE_PROXY,   /* 5 */
 +  CURLE_COULDNT_RESOLVE_HOST,    /* 6 */
 +  CURLE_COULDNT_CONNECT,         /* 7 */
 +  CURLE_FTP_WEIRD_SERVER_REPLY,  /* 8 */
 +  CURLE_REMOTE_ACCESS_DENIED,    /* 9 a service was denied by the server
 +                                    due to lack of access - when login fails
 +                                    this is not returned. */
 +  CURLE_FTP_ACCEPT_FAILED,       /* 10 - [was obsoleted in April 2006 for
 +                                    7.15.4, reused in Dec 2011 for 7.24.0]*/
 +  CURLE_FTP_WEIRD_PASS_REPLY,    /* 11 */
 +  CURLE_FTP_ACCEPT_TIMEOUT,      /* 12 - timeout occurred accepting server
 +                                    [was obsoleted in August 2007 for 7.17.0,
 +                                    reused in Dec 2011 for 7.24.0]*/
 +  CURLE_FTP_WEIRD_PASV_REPLY,    /* 13 */
 +  CURLE_FTP_WEIRD_227_FORMAT,    /* 14 */
 +  CURLE_FTP_CANT_GET_HOST,       /* 15 */
 +  CURLE_HTTP2,                   /* 16 - A problem in the http2 framing layer.
 +                                    [was obsoleted in August 2007 for 7.17.0,
 +                                    reused in July 2014 for 7.38.0] */
 +  CURLE_FTP_COULDNT_SET_TYPE,    /* 17 */
 +  CURLE_PARTIAL_FILE,            /* 18 */
 +  CURLE_FTP_COULDNT_RETR_FILE,   /* 19 */
 +  CURLE_OBSOLETE20,              /* 20 - NOT USED */
 +  CURLE_QUOTE_ERROR,             /* 21 - quote command failure */
 +  CURLE_HTTP_RETURNED_ERROR,     /* 22 */
 +  CURLE_WRITE_ERROR,             /* 23 */
 +  CURLE_OBSOLETE24,              /* 24 - NOT USED */
 +  CURLE_UPLOAD_FAILED,           /* 25 - failed upload "command" */
 +  CURLE_READ_ERROR,              /* 26 - couldn't open/read from file */
 +  CURLE_OUT_OF_MEMORY,           /* 27 */
 +  /* Note: CURLE_OUT_OF_MEMORY may sometimes indicate a conversion error
 +           instead of a memory allocation error if CURL_DOES_CONVERSIONS
 +           is defined
 +  */
 +  CURLE_OPERATION_TIMEDOUT,      /* 28 - the timeout time was reached */
 +  CURLE_OBSOLETE29,              /* 29 - NOT USED */
 +  CURLE_FTP_PORT_FAILED,         /* 30 - FTP PORT operation failed */
 +  CURLE_FTP_COULDNT_USE_REST,    /* 31 - the REST command failed */
 +  CURLE_OBSOLETE32,              /* 32 - NOT USED */
 +  CURLE_RANGE_ERROR,             /* 33 - RANGE "command" didn't work */
 +  CURLE_HTTP_POST_ERROR,         /* 34 */
 +  CURLE_SSL_CONNECT_ERROR,       /* 35 - wrong when connecting with SSL */
 +  CURLE_BAD_DOWNLOAD_RESUME,     /* 36 - couldn't resume download */
 +  CURLE_FILE_COULDNT_READ_FILE,  /* 37 */
 +  CURLE_LDAP_CANNOT_BIND,        /* 38 */
 +  CURLE_LDAP_SEARCH_FAILED,      /* 39 */
 +  CURLE_OBSOLETE40,              /* 40 - NOT USED */
 +  CURLE_FUNCTION_NOT_FOUND,      /* 41 */
 +  CURLE_ABORTED_BY_CALLBACK,     /* 42 */
 +  CURLE_BAD_FUNCTION_ARGUMENT,   /* 43 */
 +  CURLE_OBSOLETE44,              /* 44 - NOT USED */
 +  CURLE_INTERFACE_FAILED,        /* 45 - CURLOPT_INTERFACE failed */
 +  CURLE_OBSOLETE46,              /* 46 - NOT USED */
-   CURLE_TOO_MANY_REDIRECTS ,     /* 47 - catch endless re-direct loops */
++  CURLE_TOO_MANY_REDIRECTS,      /* 47 - catch endless re-direct loops */
 +  CURLE_UNKNOWN_OPTION,          /* 48 - User specified an unknown option */
-   CURLE_TELNET_OPTION_SYNTAX ,   /* 49 - Malformed telnet option */
++  CURLE_TELNET_OPTION_SYNTAX,    /* 49 - Malformed telnet option */
 +  CURLE_OBSOLETE50,              /* 50 - NOT USED */
 +  CURLE_PEER_FAILED_VERIFICATION, /* 51 - peer's certificate or fingerprint
 +                                     wasn't verified fine */
 +  CURLE_GOT_NOTHING,             /* 52 - when this is a specific error */
 +  CURLE_SSL_ENGINE_NOTFOUND,     /* 53 - SSL crypto engine not found */
 +  CURLE_SSL_ENGINE_SETFAILED,    /* 54 - can not set SSL crypto engine as
 +                                    default */
 +  CURLE_SEND_ERROR,              /* 55 - failed sending network data */
 +  CURLE_RECV_ERROR,              /* 56 - failure in receiving network data */
 +  CURLE_OBSOLETE57,              /* 57 - NOT IN USE */
 +  CURLE_SSL_CERTPROBLEM,         /* 58 - problem with the local certificate */
 +  CURLE_SSL_CIPHER,              /* 59 - couldn't use specified cipher */
 +  CURLE_SSL_CACERT,              /* 60 - problem with the CA cert (path?) */
 +  CURLE_BAD_CONTENT_ENCODING,    /* 61 - Unrecognized/bad encoding */
 +  CURLE_LDAP_INVALID_URL,        /* 62 - Invalid LDAP URL */
 +  CURLE_FILESIZE_EXCEEDED,       /* 63 - Maximum file size exceeded */
 +  CURLE_USE_SSL_FAILED,          /* 64 - Requested FTP SSL level failed */
 +  CURLE_SEND_FAIL_REWIND,        /* 65 - Sending the data requires a rewind
 +                                    that failed */
 +  CURLE_SSL_ENGINE_INITFAILED,   /* 66 - failed to initialise ENGINE */
 +  CURLE_LOGIN_DENIED,            /* 67 - user, password or similar was not
 +                                    accepted and we failed to login */
 +  CURLE_TFTP_NOTFOUND,           /* 68 - file not found on server */
 +  CURLE_TFTP_PERM,               /* 69 - permission problem on server */
 +  CURLE_REMOTE_DISK_FULL,        /* 70 - out of disk space on server */
 +  CURLE_TFTP_ILLEGAL,            /* 71 - Illegal TFTP operation */
 +  CURLE_TFTP_UNKNOWNID,          /* 72 - Unknown transfer ID */
 +  CURLE_REMOTE_FILE_EXISTS,      /* 73 - File already exists */
 +  CURLE_TFTP_NOSUCHUSER,         /* 74 - No such user */
 +  CURLE_CONV_FAILED,             /* 75 - conversion failed */
 +  CURLE_CONV_REQD,               /* 76 - caller must register conversion
 +                                    callbacks using curl_easy_setopt options
 +                                    CURLOPT_CONV_FROM_NETWORK_FUNCTION,
 +                                    CURLOPT_CONV_TO_NETWORK_FUNCTION, and
 +                                    CURLOPT_CONV_FROM_UTF8_FUNCTION */
 +  CURLE_SSL_CACERT_BADFILE,      /* 77 - could not load CACERT file, missing
 +                                    or wrong format */
 +  CURLE_REMOTE_FILE_NOT_FOUND,   /* 78 - remote file not found */
 +  CURLE_SSH,                     /* 79 - error from the SSH layer, somewhat
 +                                    generic so the error message will be of
 +                                    interest when this has happened */
 +
 +  CURLE_SSL_SHUTDOWN_FAILED,     /* 80 - Failed to shut down the SSL
 +                                    connection */
 +  CURLE_AGAIN,                   /* 81 - socket is not ready for send/recv,
 +                                    wait till it's ready and try again (Added
 +                                    in 7.18.2) */
 +  CURLE_SSL_CRL_BADFILE,         /* 82 - could not load CRL file, missing or
 +                                    wrong format (Added in 7.19.0) */
 +  CURLE_SSL_ISSUER_ERROR,        /* 83 - Issuer check failed.  (Added in
 +                                    7.19.0) */
 +  CURLE_FTP_PRET_FAILED,         /* 84 - a PRET command failed */
 +  CURLE_RTSP_CSEQ_ERROR,         /* 85 - mismatch of RTSP CSeq numbers */
 +  CURLE_RTSP_SESSION_ERROR,      /* 86 - mismatch of RTSP Session Ids */
 +  CURLE_FTP_BAD_FILE_LIST,       /* 87 - unable to parse FTP file list */
 +  CURLE_CHUNK_FAILED,            /* 88 - chunk callback reported error */
 +  CURLE_NO_CONNECTION_AVAILABLE, /* 89 - No connection available, the
 +                                    session will be queued */
 +  CURLE_SSL_PINNEDPUBKEYNOTMATCH, /* 90 - specified pinned public key did not
 +                                     match */
 +  CURLE_SSL_INVALIDCERTSTATUS,   /* 91 - invalid certificate status */
++  CURLE_HTTP2_STREAM,            /* 92 - stream error in HTTP/2 framing layer
++                                    */
 +  CURL_LAST /* never use! */
 +} CURLcode;
 +
 +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
 +                          the obsolete stuff removed! */
 +
 +/* Previously obsolete error code re-used in 7.38.0 */
 +#define CURLE_OBSOLETE16 CURLE_HTTP2
 +
 +/* Previously obsolete error codes re-used in 7.24.0 */
 +#define CURLE_OBSOLETE10 CURLE_FTP_ACCEPT_FAILED
 +#define CURLE_OBSOLETE12 CURLE_FTP_ACCEPT_TIMEOUT
 +
 +/*  compatibility with older names */
 +#define CURLOPT_ENCODING CURLOPT_ACCEPT_ENCODING
 +
 +/* The following were added in 7.21.5, April 2011 */
 +#define CURLE_UNKNOWN_TELNET_OPTION CURLE_UNKNOWN_OPTION
 +
 +/* The following were added in 7.17.1 */
 +/* These are scheduled to disappear by 2009 */
 +#define CURLE_SSL_PEER_CERTIFICATE CURLE_PEER_FAILED_VERIFICATION
 +
 +/* The following were added in 7.17.0 */
 +/* These are scheduled to disappear by 2009 */
 +#define CURLE_OBSOLETE CURLE_OBSOLETE50 /* no one should be using this! */
 +#define CURLE_BAD_PASSWORD_ENTERED CURLE_OBSOLETE46
 +#define CURLE_BAD_CALLING_ORDER CURLE_OBSOLETE44
 +#define CURLE_FTP_USER_PASSWORD_INCORRECT CURLE_OBSOLETE10
 +#define CURLE_FTP_CANT_RECONNECT CURLE_OBSOLETE16
 +#define CURLE_FTP_COULDNT_GET_SIZE CURLE_OBSOLETE32
 +#define CURLE_FTP_COULDNT_SET_ASCII CURLE_OBSOLETE29
 +#define CURLE_FTP_WEIRD_USER_REPLY CURLE_OBSOLETE12
 +#define CURLE_FTP_WRITE_ERROR CURLE_OBSOLETE20
 +#define CURLE_LIBRARY_NOT_FOUND CURLE_OBSOLETE40
 +#define CURLE_MALFORMAT_USER CURLE_OBSOLETE24
 +#define CURLE_SHARE_IN_USE CURLE_OBSOLETE57
 +#define CURLE_URL_MALFORMAT_USER CURLE_NOT_BUILT_IN
 +
 +#define CURLE_FTP_ACCESS_DENIED CURLE_REMOTE_ACCESS_DENIED
 +#define CURLE_FTP_COULDNT_SET_BINARY CURLE_FTP_COULDNT_SET_TYPE
 +#define CURLE_FTP_QUOTE_ERROR CURLE_QUOTE_ERROR
 +#define CURLE_TFTP_DISKFULL CURLE_REMOTE_DISK_FULL
 +#define CURLE_TFTP_EXISTS CURLE_REMOTE_FILE_EXISTS
 +#define CURLE_HTTP_RANGE_ERROR CURLE_RANGE_ERROR
 +#define CURLE_FTP_SSL_FAILED CURLE_USE_SSL_FAILED
 +
 +/* The following were added earlier */
 +
 +#define CURLE_OPERATION_TIMEOUTED CURLE_OPERATION_TIMEDOUT
 +
 +#define CURLE_HTTP_NOT_FOUND CURLE_HTTP_RETURNED_ERROR
 +#define CURLE_HTTP_PORT_FAILED CURLE_INTERFACE_FAILED
 +#define CURLE_FTP_COULDNT_STOR_FILE CURLE_UPLOAD_FAILED
 +
 +#define CURLE_FTP_PARTIAL_FILE CURLE_PARTIAL_FILE
 +#define CURLE_FTP_BAD_DOWNLOAD_RESUME CURLE_BAD_DOWNLOAD_RESUME
 +
 +/* This was the error code 50 in 7.7.3 and a few earlier versions, this
 +   is no longer used by libcurl but is instead #defined here only to not
 +   make programs break */
 +#define CURLE_ALREADY_COMPLETE 99999
 +
 +/* Provide defines for really old option names */
 +#define CURLOPT_FILE CURLOPT_WRITEDATA /* name changed in 7.9.7 */
 +#define CURLOPT_INFILE CURLOPT_READDATA /* name changed in 7.9.7 */
 +#define CURLOPT_WRITEHEADER CURLOPT_HEADERDATA
 +
 +/* Since long deprecated options with no code in the lib that does anything
 +   with them. */
 +#define CURLOPT_WRITEINFO CURLOPT_OBSOLETE40
 +#define CURLOPT_CLOSEPOLICY CURLOPT_OBSOLETE72
 +
 +#endif /*!CURL_NO_OLDIES*/
 +
 +/* This prototype applies to all conversion callbacks */
 +typedef CURLcode (*curl_conv_callback)(char *buffer, size_t length);
 +
 +typedef CURLcode (*curl_ssl_ctx_callback)(CURL *curl,    /* easy handle */
 +                                          void *ssl_ctx, /* actually an
 +                                                            OpenSSL SSL_CTX */
 +                                          void *userptr);
 +
 +typedef enum {
 +  CURLPROXY_HTTP = 0,   /* added in 7.10, new in 7.19.4 default is to use
 +                           CONNECT HTTP/1.1 */
 +  CURLPROXY_HTTP_1_0 = 1,   /* added in 7.19.4, force to use CONNECT
 +                               HTTP/1.0  */
 +  CURLPROXY_SOCKS4 = 4, /* support added in 7.15.2, enum existed already
 +                           in 7.10 */
 +  CURLPROXY_SOCKS5 = 5, /* added in 7.10 */
 +  CURLPROXY_SOCKS4A = 6, /* added in 7.18.0 */
 +  CURLPROXY_SOCKS5_HOSTNAME = 7 /* Use the SOCKS5 protocol but pass along the
 +                                   host name rather than the IP address. added
 +                                   in 7.18.0 */
 +} curl_proxytype;  /* this enum was added in 7.10 */
 +
 +/*
 + * Bitmasks for CURLOPT_HTTPAUTH and CURLOPT_PROXYAUTH options:
 + *
 + * CURLAUTH_NONE         - No HTTP authentication
 + * CURLAUTH_BASIC        - HTTP Basic authentication (default)
 + * CURLAUTH_DIGEST       - HTTP Digest authentication
 + * CURLAUTH_NEGOTIATE    - HTTP Negotiate (SPNEGO) authentication
 + * CURLAUTH_GSSNEGOTIATE - Alias for CURLAUTH_NEGOTIATE (deprecated)
 + * CURLAUTH_NTLM         - HTTP NTLM authentication
 + * CURLAUTH_DIGEST_IE    - HTTP Digest authentication with IE flavour
 + * CURLAUTH_NTLM_WB      - HTTP NTLM authentication delegated to winbind helper
 + * CURLAUTH_ONLY         - Use together with a single other type to force no
 + *                         authentication or just that single type
 + * CURLAUTH_ANY          - All fine types set
 + * CURLAUTH_ANYSAFE      - All fine types except Basic
 + */
 +
 +#define CURLAUTH_NONE         ((unsigned long)0)
 +#define CURLAUTH_BASIC        (((unsigned long)1)<<0)
 +#define CURLAUTH_DIGEST       (((unsigned long)1)<<1)
 +#define CURLAUTH_NEGOTIATE    (((unsigned long)1)<<2)
 +/* Deprecated since the advent of CURLAUTH_NEGOTIATE */
 +#define CURLAUTH_GSSNEGOTIATE CURLAUTH_NEGOTIATE
 +#define CURLAUTH_NTLM         (((unsigned long)1)<<3)
 +#define CURLAUTH_DIGEST_IE    (((unsigned long)1)<<4)
 +#define CURLAUTH_NTLM_WB      (((unsigned long)1)<<5)
 +#define CURLAUTH_ONLY         (((unsigned long)1)<<31)
 +#define CURLAUTH_ANY          (~CURLAUTH_DIGEST_IE)
 +#define CURLAUTH_ANYSAFE      (~(CURLAUTH_BASIC|CURLAUTH_DIGEST_IE))
 +
 +#define CURLSSH_AUTH_ANY       ~0     /* all types supported by the server */
 +#define CURLSSH_AUTH_NONE      0      /* none allowed, silly but complete */
 +#define CURLSSH_AUTH_PUBLICKEY (1<<0) /* public/private key files */
 +#define CURLSSH_AUTH_PASSWORD  (1<<1) /* password */
 +#define CURLSSH_AUTH_HOST      (1<<2) /* host key files */
 +#define CURLSSH_AUTH_KEYBOARD  (1<<3) /* keyboard interactive */
 +#define CURLSSH_AUTH_AGENT     (1<<4) /* agent (ssh-agent, pageant...) */
 +#define CURLSSH_AUTH_DEFAULT CURLSSH_AUTH_ANY
 +
 +#define CURLGSSAPI_DELEGATION_NONE        0      /* no delegation (default) */
 +#define CURLGSSAPI_DELEGATION_POLICY_FLAG (1<<0) /* if permitted by policy */
 +#define CURLGSSAPI_DELEGATION_FLAG        (1<<1) /* delegate always */
 +
 +#define CURL_ERROR_SIZE 256
 +
 +enum curl_khtype {
 +  CURLKHTYPE_UNKNOWN,
 +  CURLKHTYPE_RSA1,
 +  CURLKHTYPE_RSA,
 +  CURLKHTYPE_DSS
 +};
 +
 +struct curl_khkey {
 +  const char *key; /* points to a zero-terminated string encoded with base64
 +                      if len is zero, otherwise to the "raw" data */
 +  size_t len;
 +  enum curl_khtype keytype;
 +};
 +
 +/* this is the set of return values expected from the curl_sshkeycallback
 +   callback */
 +enum curl_khstat {
 +  CURLKHSTAT_FINE_ADD_TO_FILE,
 +  CURLKHSTAT_FINE,
 +  CURLKHSTAT_REJECT, /* reject the connection, return an error */
 +  CURLKHSTAT_DEFER,  /* do not accept it, but we can't answer right now so
 +                        this causes a CURLE_DEFER error but otherwise the
 +                        connection will be left intact etc */
 +  CURLKHSTAT_LAST    /* not for use, only a marker for last-in-list */
 +};
 +
 +/* this is the set of status codes pass in to the callback */
 +enum curl_khmatch {
 +  CURLKHMATCH_OK,       /* match */
 +  CURLKHMATCH_MISMATCH, /* host found, key mismatch! */
 +  CURLKHMATCH_MISSING,  /* no matching host/key found */
 +  CURLKHMATCH_LAST      /* not for use, only a marker for last-in-list */
 +};
 +
 +typedef int
 +  (*curl_sshkeycallback) (CURL *easy,     /* easy handle */
 +                          const struct curl_khkey *knownkey, /* known */
 +                          const struct curl_khkey *foundkey, /* found */
 +                          enum curl_khmatch, /* libcurl's view on the keys */
 +                          void *clientp); /* custom pointer passed from app */
 +
 +/* parameter for the CURLOPT_USE_SSL option */
 +typedef enum {
 +  CURLUSESSL_NONE,    /* do not attempt to use SSL */
 +  CURLUSESSL_TRY,     /* try using SSL, proceed anyway otherwise */
 +  CURLUSESSL_CONTROL, /* SSL for the control connection or fail */
 +  CURLUSESSL_ALL,     /* SSL for all communication or fail */
 +  CURLUSESSL_LAST     /* not an option, never use */
 +} curl_usessl;
 +
 +/* Definition of bits for the CURLOPT_SSL_OPTIONS argument: */
 +
 +/* - ALLOW_BEAST tells libcurl to allow the BEAST SSL vulnerability in the
 +   name of improving interoperability with older servers. Some SSL libraries
 +   have introduced work-arounds for this flaw but those work-arounds sometimes
 +   make the SSL communication fail. To regain functionality with those broken
 +   servers, a user can this way allow the vulnerability back. */
 +#define CURLSSLOPT_ALLOW_BEAST (1<<0)
 +
 +/* - NO_REVOKE tells libcurl to disable certificate revocation checks for those
 +   SSL backends where such behavior is present. */
 +#define CURLSSLOPT_NO_REVOKE (1<<1)
 +
 +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
 +                          the obsolete stuff removed! */
 +
 +/* Backwards compatibility with older names */
 +/* These are scheduled to disappear by 2009 */
 +
 +#define CURLFTPSSL_NONE CURLUSESSL_NONE
 +#define CURLFTPSSL_TRY CURLUSESSL_TRY
 +#define CURLFTPSSL_CONTROL CURLUSESSL_CONTROL
 +#define CURLFTPSSL_ALL CURLUSESSL_ALL
 +#define CURLFTPSSL_LAST CURLUSESSL_LAST
 +#define curl_ftpssl curl_usessl
 +#endif /*!CURL_NO_OLDIES*/
 +
 +/* parameter for the CURLOPT_FTP_SSL_CCC option */
 +typedef enum {
 +  CURLFTPSSL_CCC_NONE,    /* do not send CCC */
 +  CURLFTPSSL_CCC_PASSIVE, /* Let the server initiate the shutdown */
 +  CURLFTPSSL_CCC_ACTIVE,  /* Initiate the shutdown */
 +  CURLFTPSSL_CCC_LAST     /* not an option, never use */
 +} curl_ftpccc;
 +
 +/* parameter for the CURLOPT_FTPSSLAUTH option */
 +typedef enum {
 +  CURLFTPAUTH_DEFAULT, /* let libcurl decide */
 +  CURLFTPAUTH_SSL,     /* use "AUTH SSL" */
 +  CURLFTPAUTH_TLS,     /* use "AUTH TLS" */
 +  CURLFTPAUTH_LAST /* not an option, never use */
 +} curl_ftpauth;
 +
 +/* parameter for the CURLOPT_FTP_CREATE_MISSING_DIRS option */
 +typedef enum {
 +  CURLFTP_CREATE_DIR_NONE,  /* do NOT create missing dirs! */
 +  CURLFTP_CREATE_DIR,       /* (FTP/SFTP) if CWD fails, try MKD and then CWD
 +                               again if MKD succeeded, for SFTP this does
 +                               similar magic */
 +  CURLFTP_CREATE_DIR_RETRY, /* (FTP only) if CWD fails, try MKD and then CWD
 +                               again even if MKD failed! */
 +  CURLFTP_CREATE_DIR_LAST   /* not an option, never use */
 +} curl_ftpcreatedir;
 +
 +/* parameter for the CURLOPT_FTP_FILEMETHOD option */
 +typedef enum {
 +  CURLFTPMETHOD_DEFAULT,   /* let libcurl pick */
 +  CURLFTPMETHOD_MULTICWD,  /* single CWD operation for each path part */
 +  CURLFTPMETHOD_NOCWD,     /* no CWD at all */
 +  CURLFTPMETHOD_SINGLECWD, /* one CWD to full dir, then work on file */
 +  CURLFTPMETHOD_LAST       /* not an option, never use */
 +} curl_ftpmethod;
 +
 +/* bitmask defines for CURLOPT_HEADEROPT */
 +#define CURLHEADER_UNIFIED  0
 +#define CURLHEADER_SEPARATE (1<<0)
 +
 +/* CURLPROTO_ defines are for the CURLOPT_*PROTOCOLS options */
 +#define CURLPROTO_HTTP   (1<<0)
 +#define CURLPROTO_HTTPS  (1<<1)
 +#define CURLPROTO_FTP    (1<<2)
 +#define CURLPROTO_FTPS   (1<<3)
 +#define CURLPROTO_SCP    (1<<4)
 +#define CURLPROTO_SFTP   (1<<5)
 +#define CURLPROTO_TELNET (1<<6)
 +#define CURLPROTO_LDAP   (1<<7)
 +#define CURLPROTO_LDAPS  (1<<8)
 +#define CURLPROTO_DICT   (1<<9)
 +#define CURLPROTO_FILE   (1<<10)
 +#define CURLPROTO_TFTP   (1<<11)
 +#define CURLPROTO_IMAP   (1<<12)
 +#define CURLPROTO_IMAPS  (1<<13)
 +#define CURLPROTO_POP3   (1<<14)
 +#define CURLPROTO_POP3S  (1<<15)
 +#define CURLPROTO_SMTP   (1<<16)
 +#define CURLPROTO_SMTPS  (1<<17)
 +#define CURLPROTO_RTSP   (1<<18)
 +#define CURLPROTO_RTMP   (1<<19)
 +#define CURLPROTO_RTMPT  (1<<20)
 +#define CURLPROTO_RTMPE  (1<<21)
 +#define CURLPROTO_RTMPTE (1<<22)
 +#define CURLPROTO_RTMPS  (1<<23)
 +#define CURLPROTO_RTMPTS (1<<24)
 +#define CURLPROTO_GOPHER (1<<25)
 +#define CURLPROTO_SMB    (1<<26)
 +#define CURLPROTO_SMBS   (1<<27)
 +#define CURLPROTO_ALL    (~0) /* enable everything */
 +
 +/* long may be 32 or 64 bits, but we should never depend on anything else
 +   but 32 */
 +#define CURLOPTTYPE_LONG          0
 +#define CURLOPTTYPE_OBJECTPOINT   10000
++#define CURLOPTTYPE_STRINGPOINT   10000
 +#define CURLOPTTYPE_FUNCTIONPOINT 20000
 +#define CURLOPTTYPE_OFF_T         30000
 +
++/* *STRINGPOINT is an alias for OBJECTPOINT to allow tools to extract the
++   string options from the header file */
++
 +/* name is uppercase CURLOPT_<name>,
 +   type is one of the defined CURLOPTTYPE_<type>
 +   number is unique identifier */
 +#ifdef CINIT
 +#undef CINIT
 +#endif
 +
 +#ifdef CURL_ISOCPP
 +#define CINIT(na,t,nu) CURLOPT_ ## na = CURLOPTTYPE_ ## t + nu
 +#else
 +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */
 +#define LONG          CURLOPTTYPE_LONG
 +#define OBJECTPOINT   CURLOPTTYPE_OBJECTPOINT
++#define STRINGPOINT   CURLOPTTYPE_OBJECTPOINT
 +#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT
 +#define OFF_T         CURLOPTTYPE_OFF_T
 +#define CINIT(name,type,number) CURLOPT_/**/name = type + number
 +#endif
 +
 +/*
 + * This macro-mania below setups the CURLOPT_[what] enum, to be used with
 + * curl_easy_setopt(). The first argument in the CINIT() macro is the [what]
 + * word.
 + */
 +
 +typedef enum {
 +  /* This is the FILE * or void * the regular output should be written to. */
 +  CINIT(WRITEDATA, OBJECTPOINT, 1),
 +
 +  /* The full URL to get/put */
-   CINIT(URL, OBJECTPOINT, 2),
++  CINIT(URL, STRINGPOINT, 2),
 +
 +  /* Port number to connect to, if other than default. */
 +  CINIT(PORT, LONG, 3),
 +
 +  /* Name of proxy to use. */
-   CINIT(PROXY, OBJECTPOINT, 4),
++  CINIT(PROXY, STRINGPOINT, 4),
 +
 +  /* "user:password;options" to use when fetching. */
-   CINIT(USERPWD, OBJECTPOINT, 5),
++  CINIT(USERPWD, STRINGPOINT, 5),
 +
 +  /* "user:password" to use with proxy. */
-   CINIT(PROXYUSERPWD, OBJECTPOINT, 6),
++  CINIT(PROXYUSERPWD, STRINGPOINT, 6),
 +
 +  /* Range to get, specified as an ASCII string. */
-   CINIT(RANGE, OBJECTPOINT, 7),
++  CINIT(RANGE, STRINGPOINT, 7),
 +
 +  /* not used */
 +
 +  /* Specified file stream to upload from (use as input): */
 +  CINIT(READDATA, OBJECTPOINT, 9),
 +
 +  /* Buffer to receive error messages in, must be at least CURL_ERROR_SIZE
 +   * bytes big. If this is not used, error messages go to stderr instead: */
 +  CINIT(ERRORBUFFER, OBJECTPOINT, 10),
 +
 +  /* Function that will be called to store the output (instead of fwrite). The
 +   * parameters will use fwrite() syntax, make sure to follow them. */
 +  CINIT(WRITEFUNCTION, FUNCTIONPOINT, 11),
 +
 +  /* Function that will be called to read the input (instead of fread). The
 +   * parameters will use fread() syntax, make sure to follow them. */
 +  CINIT(READFUNCTION, FUNCTIONPOINT, 12),
 +
 +  /* Time-out the read operation after this amount of seconds */
 +  CINIT(TIMEOUT, LONG, 13),
 +
 +  /* If the CURLOPT_INFILE is used, this can be used to inform libcurl about
 +   * how large the file being sent really is. That allows better error
 +   * checking and better verifies that the upload was successful. -1 means
 +   * unknown size.
 +   *
 +   * For large file support, there is also a _LARGE version of the key
 +   * which takes an off_t type, allowing platforms with larger off_t
 +   * sizes to handle larger files.  See below for INFILESIZE_LARGE.
 +   */
 +  CINIT(INFILESIZE, LONG, 14),
 +
 +  /* POST static input fields. */
 +  CINIT(POSTFIELDS, OBJECTPOINT, 15),
 +
 +  /* Set the referrer page (needed by some CGIs) */
-   CINIT(REFERER, OBJECTPOINT, 16),
++  CINIT(REFERER, STRINGPOINT, 16),
 +
 +  /* Set the FTP PORT string (interface name, named or numerical IP address)
 +     Use i.e '-' to use default address. */
-   CINIT(FTPPORT, OBJECTPOINT, 17),
++  CINIT(FTPPORT, STRINGPOINT, 17),
 +
 +  /* Set the User-Agent string (examined by some CGIs) */
-   CINIT(USERAGENT, OBJECTPOINT, 18),
++  CINIT(USERAGENT, STRINGPOINT, 18),
 +
 +  /* If the download receives less than "low speed limit" bytes/second
 +   * during "low speed time" seconds, the operations is aborted.
 +   * You could i.e if you have a pretty high speed connection, abort if
 +   * it is less than 2000 bytes/sec during 20 seconds.
 +   */
 +
 +  /* Set the "low speed limit" */
 +  CINIT(LOW_SPEED_LIMIT, LONG, 19),
 +
 +  /* Set the "low speed time" */
 +  CINIT(LOW_SPEED_TIME, LONG, 20),
 +
 +  /* Set the continuation offset.
 +   *
 +   * Note there is also a _LARGE version of this key which uses
 +   * off_t types, allowing for large file offsets on platforms which
 +   * use larger-than-32-bit off_t's.  Look below for RESUME_FROM_LARGE.
 +   */
 +  CINIT(RESUME_FROM, LONG, 21),
 +
 +  /* Set cookie in request: */
-   CINIT(COOKIE, OBJECTPOINT, 22),
++  CINIT(COOKIE, STRINGPOINT, 22),
 +
 +  /* This points to a linked list of headers, struct curl_slist kind. This
 +     list is also used for RTSP (in spite of its name) */
 +  CINIT(HTTPHEADER, OBJECTPOINT, 23),
 +
 +  /* This points to a linked list of post entries, struct curl_httppost */
 +  CINIT(HTTPPOST, OBJECTPOINT, 24),
 +
 +  /* name of the file keeping your private SSL-certificate */
-   CINIT(SSLCERT, OBJECTPOINT, 25),
++  CINIT(SSLCERT, STRINGPOINT, 25),
 +
 +  /* password for the SSL or SSH private key */
-   CINIT(KEYPASSWD, OBJECTPOINT, 26),
++  CINIT(KEYPASSWD, STRINGPOINT, 26),
 +
 +  /* send TYPE parameter? */
 +  CINIT(CRLF, LONG, 27),
 +
 +  /* send linked-list of QUOTE commands */
 +  CINIT(QUOTE, OBJECTPOINT, 28),
 +
 +  /* send FILE * or void * to store headers to, if you use a callback it
 +     is simply passed to the callback unmodified */
 +  CINIT(HEADERDATA, OBJECTPOINT, 29),
 +
 +  /* point to a file to read the initial cookies from, also enables
 +     "cookie awareness" */
-   CINIT(COOKIEFILE, OBJECTPOINT, 31),
++  CINIT(COOKIEFILE, STRINGPOINT, 31),
 +
 +  /* What version to specifically try to use.
 +     See CURL_SSLVERSION defines below. */
 +  CINIT(SSLVERSION, LONG, 32),
 +
 +  /* What kind of HTTP time condition to use, see defines */
 +  CINIT(TIMECONDITION, LONG, 33),
 +
 +  /* Time to use with the above condition. Specified in number of seconds
 +     since 1 Jan 1970 */
 +  CINIT(TIMEVALUE, LONG, 34),
 +
 +  /* 35 = OBSOLETE */
 +
 +  /* Custom request, for customizing the get command like
 +     HTTP: DELETE, TRACE and others
 +     FTP: to use a different list command
 +     */
-   CINIT(CUSTOMREQUEST, OBJECTPOINT, 36),
++  CINIT(CUSTOMREQUEST, STRINGPOINT, 36),
 +
-   /* HTTP request, for odd commands like DELETE, TRACE and others */
++  /* FILE handle to use instead of stderr */
 +  CINIT(STDERR, OBJECTPOINT, 37),
 +
 +  /* 38 is not used */
 +
 +  /* send linked-list of post-transfer QUOTE commands */
 +  CINIT(POSTQUOTE, OBJECTPOINT, 39),
 +
 +  CINIT(OBSOLETE40, OBJECTPOINT, 40), /* OBSOLETE, do not use! */
 +
 +  CINIT(VERBOSE, LONG, 41),      /* talk a lot */
 +  CINIT(HEADER, LONG, 42),       /* throw the header out too */
 +  CINIT(NOPROGRESS, LONG, 43),   /* shut off the progress meter */
 +  CINIT(NOBODY, LONG, 44),       /* use HEAD to get http document */
 +  CINIT(FAILONERROR, LONG, 45),  /* no output on http error codes >= 400 */
 +  CINIT(UPLOAD, LONG, 46),       /* this is an upload */
 +  CINIT(POST, LONG, 47),         /* HTTP POST method */
 +  CINIT(DIRLISTONLY, LONG, 48),  /* bare names when listing directories */
 +
 +  CINIT(APPEND, LONG, 50),       /* Append instead of overwrite on upload! */
 +
 +  /* Specify whether to read the user+password from the .netrc or the URL.
 +   * This must be one of the CURL_NETRC_* enums below. */
 +  CINIT(NETRC, LONG, 51),
 +
 +  CINIT(FOLLOWLOCATION, LONG, 52),  /* use Location: Luke! */
 +
 +  CINIT(TRANSFERTEXT, LONG, 53), /* transfer data in text/ASCII format */
 +  CINIT(PUT, LONG, 54),          /* HTTP PUT */
 +
 +  /* 55 = OBSOLETE */
 +
 +  /* DEPRECATED
 +   * Function that will be called instead of the internal progress display
 +   * function. This function should be defined as the curl_progress_callback
 +   * prototype defines. */
 +  CINIT(PROGRESSFUNCTION, FUNCTIONPOINT, 56),
 +
 +  /* Data passed to the CURLOPT_PROGRESSFUNCTION and CURLOPT_XFERINFOFUNCTION
 +     callbacks */
 +  CINIT(PROGRESSDATA, OBJECTPOINT, 57),
 +#define CURLOPT_XFERINFODATA CURLOPT_PROGRESSDATA
 +
 +  /* We want the referrer field set automatically when following locations */
 +  CINIT(AUTOREFERER, LONG, 58),
 +
 +  /* Port of the proxy, can be set in the proxy string as well with:
 +     "[host]:[port]" */
 +  CINIT(PROXYPORT, LONG, 59),
 +
 +  /* size of the POST input data, if strlen() is not good to use */
 +  CINIT(POSTFIELDSIZE, LONG, 60),
 +
 +  /* tunnel non-http operations through a HTTP proxy */
 +  CINIT(HTTPPROXYTUNNEL, LONG, 61),
 +
 +  /* Set the interface string to use as outgoing network interface */
-   CINIT(INTERFACE, OBJECTPOINT, 62),
++  CINIT(INTERFACE, STRINGPOINT, 62),
 +
 +  /* Set the krb4/5 security level, this also enables krb4/5 awareness.  This
 +   * is a string, 'clear', 'safe', 'confidential' or 'private'.  If the string
 +   * is set but doesn't match one of these, 'private' will be used.  */
-   CINIT(KRBLEVEL, OBJECTPOINT, 63),
++  CINIT(KRBLEVEL, STRINGPOINT, 63),
 +
 +  /* Set if we should verify the peer in ssl handshake, set 1 to verify. */
 +  CINIT(SSL_VERIFYPEER, LONG, 64),
 +
 +  /* The CApath or CAfile used to validate the peer certificate
 +     this option is used only if SSL_VERIFYPEER is true */
-   CINIT(CAINFO, OBJECTPOINT, 65),
++  CINIT(CAINFO, STRINGPOINT, 65),
 +
 +  /* 66 = OBSOLETE */
 +  /* 67 = OBSOLETE */
 +
 +  /* Maximum number of http redirects to follow */
 +  CINIT(MAXREDIRS, LONG, 68),
 +
 +  /* Pass a long set to 1 to get the date of the requested document (if
 +     possible)! Pass a zero to shut it off. */
 +  CINIT(FILETIME, LONG, 69),
 +
 +  /* This points to a linked list of telnet options */
 +  CINIT(TELNETOPTIONS, OBJECTPOINT, 70),
 +
 +  /* Max amount of cached alive connections */
 +  CINIT(MAXCONNECTS, LONG, 71),
 +
 +  CINIT(OBSOLETE72, LONG, 72), /* OBSOLETE, do not use! */
 +
 +  /* 73 = OBSOLETE */
 +
 +  /* Set to explicitly use a new connection for the upcoming transfer.
 +     Do not use this unless you're absolutely sure of this, as it makes the
 +     operation slower and is less friendly for the network. */
 +  CINIT(FRESH_CONNECT, LONG, 74),
 +
 +  /* Set to explicitly forbid the upcoming transfer's connection to be re-used
 +     when done. Do not use this unless you're absolutely sure of this, as it
 +     makes the operation slower and is less friendly for the network. */
 +  CINIT(FORBID_REUSE, LONG, 75),
 +
 +  /* Set to a file name that contains random data for libcurl to use to
 +     seed the random engine when doing SSL connects. */
-   CINIT(RANDOM_FILE, OBJECTPOINT, 76),
++  CINIT(RANDOM_FILE, STRINGPOINT, 76),
 +
 +  /* Set to the Entropy Gathering Daemon socket pathname */
-   CINIT(EGDSOCKET, OBJECTPOINT, 77),
++  CINIT(EGDSOCKET, STRINGPOINT, 77),
 +
 +  /* Time-out connect operations after this amount of seconds, if connects are
 +     OK within this time, then fine... This only aborts the connect phase. */
 +  CINIT(CONNECTTIMEOUT, LONG, 78),
 +
 +  /* Function that will be called to store headers (instead of fwrite). The
 +   * parameters will use fwrite() syntax, make sure to follow them. */
 +  CINIT(HEADERFUNCTION, FUNCTIONPOINT, 79),
 +
 +  /* Set this to force the HTTP request to get back to GET. Only really usable
 +     if POST, PUT or a custom request have been used first.
 +   */
 +  CINIT(HTTPGET, LONG, 80),
 +
 +  /* Set if we should verify the Common name from the peer certificate in ssl
 +   * handshake, set 1 to check existence, 2 to ensure that it matches the
 +   * provided hostname. */
 +  CINIT(SSL_VERIFYHOST, LONG, 81),
 +
 +  /* Specify which file name to write all known cookies in after completed
 +     operation. Set file name to "-" (dash) to make it go to stdout. */
-   CINIT(COOKIEJAR, OBJECTPOINT, 82),
++  CINIT(COOKIEJAR, STRINGPOINT, 82),
 +
 +  /* Specify which SSL ciphers to use */
-   CINIT(SSL_CIPHER_LIST, OBJECTPOINT, 83),
++  CINIT(SSL_CIPHER_LIST, STRINGPOINT, 83),
 +
 +  /* Specify which HTTP version to use! This must be set to one of the
 +     CURL_HTTP_VERSION* enums set below. */
 +  CINIT(HTTP_VERSION, LONG, 84),
 +
 +  /* Specifically switch on or off the FTP engine's use of the EPSV command. By
 +     default, that one will always be attempted before the more traditional
 +     PASV command. */
 +  CINIT(FTP_USE_EPSV, LONG, 85),
 +
 +  /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") */
-   CINIT(SSLCERTTYPE, OBJECTPOINT, 86),
++  CINIT(SSLCERTTYPE, STRINGPOINT, 86),
 +
 +  /* name of the file keeping your private SSL-key */
-   CINIT(SSLKEY, OBJECTPOINT, 87),
++  CINIT(SSLKEY, STRINGPOINT, 87),
 +
 +  /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") */
-   CINIT(SSLKEYTYPE, OBJECTPOINT, 88),
++  CINIT(SSLKEYTYPE, STRINGPOINT, 88),
 +
 +  /* crypto engine for the SSL-sub system */
-   CINIT(SSLENGINE, OBJECTPOINT, 89),
++  CINIT(SSLENGINE, STRINGPOINT, 89),
 +
 +  /* set the crypto engine for the SSL-sub system as default
 +     the param has no meaning...
 +   */
 +  CINIT(SSLENGINE_DEFAULT, LONG, 90),
 +
 +  /* Non-zero value means to use the global dns cache */
 +  CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91), /* DEPRECATED, do not use! */
 +
 +  /* DNS cache timeout */
 +  CINIT(DNS_CACHE_TIMEOUT, LONG, 92),
 +
 +  /* send linked-list of pre-transfer QUOTE commands */
 +  CINIT(PREQUOTE, OBJECTPOINT, 93),
 +
 +  /* set the debug function */
 +  CINIT(DEBUGFUNCTION, FUNCTIONPOINT, 94),
 +
 +  /* set the data for the debug function */
 +  CINIT(DEBUGDATA, OBJECTPOINT, 95),
 +
 +  /* mark this as start of a cookie session */
 +  CINIT(COOKIESESSION, LONG, 96),
 +
 +  /* The CApath directory used to validate the peer certificate
 +     this option is used only if SSL_VERIFYPEER is true */
-   CINIT(CAPATH, OBJECTPOINT, 97),
++  CINIT(CAPATH, STRINGPOINT, 97),
 +
 +  /* Instruct libcurl to use a smaller receive buffer */
 +  CINIT(BUFFERSIZE, LONG, 98),
 +
 +  /* Instruct libcurl to not use any signal/alarm handlers, even when using
 +     timeouts. This option is useful for multi-threaded applications.
 +     See libcurl-the-guide for more background information. */
 +  CINIT(NOSIGNAL, LONG, 99),
 +
 +  /* Provide a CURLShare for mutexing non-ts data */
 +  CINIT(SHARE, OBJECTPOINT, 100),
 +
 +  /* indicates type of proxy. accepted values are CURLPROXY_HTTP (default),
 +     CURLPROXY_SOCKS4, CURLPROXY_SOCKS4A and CURLPROXY_SOCKS5. */
 +  CINIT(PROXYTYPE, LONG, 101),
 +
 +  /* Set the Accept-Encoding string. Use this to tell a server you would like
 +     the response to be compressed. Before 7.21.6, this was known as
 +     CURLOPT_ENCODING */
-   CINIT(ACCEPT_ENCODING, OBJECTPOINT, 102),
++  CINIT(ACCEPT_ENCODING, STRINGPOINT, 102),
 +
 +  /* Set pointer to private data */
 +  CINIT(PRIVATE, OBJECTPOINT, 103),
 +
 +  /* Set aliases for HTTP 200 in the HTTP Response header */
 +  CINIT(HTTP200ALIASES, OBJECTPOINT, 104),
 +
 +  /* Continue to send authentication (user+password) when following locations,
 +     even when hostname changed. This can potentially send off the name
 +     and password to whatever host the server decides. */
 +  CINIT(UNRESTRICTED_AUTH, LONG, 105),
 +
 +  /* Specifically switch on or off the FTP engine's use of the EPRT command (
 +     it also disables the LPRT attempt). By default, those ones will always be
 +     attempted before the good old traditional PORT command. */
 +  CINIT(FTP_USE_EPRT, LONG, 106),
 +
 +  /* Set this to a bitmask value to enable the particular authentications
 +     methods you like. Use this in combination with CURLOPT_USERPWD.
 +     Note that setting multiple bits may cause extra network round-trips. */
 +  CINIT(HTTPAUTH, LONG, 107),
 +
 +  /* Set the ssl context callback function, currently only for OpenSSL ssl_ctx
 +     in second argument. The function must be matching the
 +     curl_ssl_ctx_callback proto. */
 +  CINIT(SSL_CTX_FUNCTION, FUNCTIONPOINT, 108),
 +
 +  /* Set the userdata for the ssl context callback function's third
 +     argument */
 +  CINIT(SSL_CTX_DATA, OBJECTPOINT, 109),
 +
 +  /* FTP Option that causes missing dirs to be created on the remote server.
 +     In 7.19.4 we introduced the convenience enums for this option using the
 +     CURLFTP_CREATE_DIR prefix.
 +  */
 +  CINIT(FTP_CREATE_MISSING_DIRS, LONG, 110),
 +
 +  /* Set this to a bitmask value to enable the particular authentications
 +     methods you like. Use this in combination with CURLOPT_PROXYUSERPWD.
 +     Note that setting multiple bits may cause extra network round-trips. */
 +  CINIT(PROXYAUTH, LONG, 111),
 +
 +  /* FTP option that changes the timeout, in seconds, associated with
 +     getting a response.  This is different from transfer timeout time and
 +     essentially places a demand on the FTP server to acknowledge commands
 +     in a timely manner. */
 +  CINIT(FTP_RESPONSE_TIMEOUT, LONG, 112),
 +#define CURLOPT_SERVER_RESPONSE_TIMEOUT CURLOPT_FTP_RESPONSE_TIMEOUT
 +
 +  /* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to
 +     tell libcurl to resolve names to those IP versions only. This only has
 +     affect on systems with support for more than one, i.e IPv4 _and_ IPv6. */
 +  CINIT(IPRESOLVE, LONG, 113),
 +
 +  /* Set this option to limit the size of a file that will be downloaded from
 +     an HTTP or FTP server.
 +
 +     Note there is also _LARGE version which adds large file support for
 +     platforms which have larger off_t sizes.  See MAXFILESIZE_LARGE below. */
 +  CINIT(MAXFILESIZE, LONG, 114),
 +
 +  /* See the comment for INFILESIZE above, but in short, specifies
 +   * the size of the file being uploaded.  -1 means unknown.
 +   */
 +  CINIT(INFILESIZE_LARGE, OFF_T, 115),
 +
 +  /* Sets the continuation offset.  There is also a LONG version of this;
 +   * look above for RESUME_FROM.
 +   */
 +  CINIT(RESUME_FROM_LARGE, OFF_T, 116),
 +
 +  /* Sets the maximum size of data that will be downloaded from
 +   * an HTTP or FTP server.  See MAXFILESIZE above for the LONG version.
 +   */
 +  CINIT(MAXFILESIZE_LARGE, OFF_T, 117),
 +
 +  /* Set this option to the file name of your .netrc file you want libcurl
 +     to parse (using the CURLOPT_NETRC option). If not set, libcurl will do
 +     a poor attempt to find the user's home directory and check for a .netrc
 +     file in there. */
-   CINIT(NETRC_FILE, OBJECTPOINT, 118),
++  CINIT(NETRC_FILE, STRINGPOINT, 118),
 +
 +  /* Enable SSL/TLS for FTP, pick one of:
 +     CURLUSESSL_TRY     - try using SSL, proceed anyway otherwise
 +     CURLUSESSL_CONTROL - SSL for the control connection or fail
 +     CURLUSESSL_ALL     - SSL for all communication or fail
 +  */
 +  CINIT(USE_SSL, LONG, 119),
 +
 +  /* The _LARGE version of the standard POSTFIELDSIZE option */
 +  CINIT(POSTFIELDSIZE_LARGE, OFF_T, 120),
 +
 +  /* Enable/disable the TCP Nagle algorithm */
 +  CINIT(TCP_NODELAY, LONG, 121),
 +
 +  /* 122 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */
 +  /* 123 OBSOLETE. Gone in 7.16.0 */
 +  /* 124 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */
 +  /* 125 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */
 +  /* 126 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */
 +  /* 127 OBSOLETE. Gone in 7.16.0 */
 +  /* 128 OBSOLETE. Gone in 7.16.0 */
 +
 +  /* When FTP over SSL/TLS is selected (with CURLOPT_USE_SSL), this option
 +     can be used to change libcurl's default action which is to first try
 +     "AUTH SSL" and then "AUTH TLS" in this order, and proceed when a OK
 +     response has been received.
 +
 +     Available parameters are:
 +     CURLFTPAUTH_DEFAULT - let libcurl decide
 +     CURLFTPAUTH_SSL     - try "AUTH SSL" first, then TLS
 +     CURLFTPAUTH_TLS     - try "AUTH TLS" first, then SSL
 +  */
 +  CINIT(FTPSSLAUTH, LONG, 129),
 +
 +  CINIT(IOCTLFUNCTION, FUNCTIONPOINT, 130),
 +  CINIT(IOCTLDATA, OBJECTPOINT, 131),
 +
 +  /* 132 OBSOLETE. Gone in 7.16.0 */
 +  /* 133 OBSOLETE. Gone in 7.16.0 */
 +
 +  /* zero terminated string for pass on to the FTP server when asked for
 +     "account" info */
-   CINIT(FTP_ACCOUNT, OBJECTPOINT, 134),
++  CINIT(FTP_ACCOUNT, STRINGPOINT, 134),
 +
-   /* feed cookies into cookie engine */
-   CINIT(COOKIELIST, OBJECTPOINT, 135),
++  /* feed cookie into cookie engine */
++  CINIT(COOKIELIST, STRINGPOINT, 135),
 +
 +  /* ignore Content-Length */
 +  CINIT(IGNORE_CONTENT_LENGTH, LONG, 136),
 +
 +  /* Set to non-zero to skip the IP address received in a 227 PASV FTP server
 +     response. Typically used for FTP-SSL purposes but is not restricted to
 +     that. libcurl will then instead use the same IP address it used for the
 +     control connection. */
 +  CINIT(FTP_SKIP_PASV_IP, LONG, 137),
 +
 +  /* Select "file method" to use when doing FTP, see the curl_ftpmethod
 +     above. */
 +  CINIT(FTP_FILEMETHOD, LONG, 138),
 +
 +  /* Local port number to bind the socket to */
 +  CINIT(LOCALPORT, LONG, 139),
 +
 +  /* Number of ports to try, including the first one set with LOCALPORT.
 +     Thus, setting it to 1 will make no additional attempts but the first.
 +  */
 +  CINIT(LOCALPORTRANGE, LONG, 140),
 +
 +  /* no transfer, set up connection and let application use the socket by
 +     extracting it with CURLINFO_LASTSOCKET */
 +  CINIT(CONNECT_ONLY, LONG, 141),
 +
 +  /* Function that will be called to convert from the
 +     network encoding (instead of using the iconv calls in libcurl) */
 +  CINIT(CONV_FROM_NETWORK_FUNCTION, FUNCTIONPOINT, 142),
 +
 +  /* Function that will be called to convert to the
 +     network encoding (instead of using the iconv calls in libcurl) */
 +  CINIT(CONV_TO_NETWORK_FUNCTION, FUNCTIONPOINT, 143),
 +
 +  /* Function that will be called to convert from UTF8
 +     (instead of using the iconv calls in libcurl)
 +     Note that this is used only for SSL certificate processing */
 +  CINIT(CONV_FROM_UTF8_FUNCTION, FUNCTIONPOINT, 144),
 +
 +  /* if the connection proceeds too quickly then need to slow it down */
 +  /* limit-rate: maximum number of bytes per second to send or receive */
 +  CINIT(MAX_SEND_SPEED_LARGE, OFF_T, 145),
 +  CINIT(MAX_RECV_SPEED_LARGE, OFF_T, 146),
 +
 +  /* Pointer to command string to send if USER/PASS fails. */
-   CINIT(FTP_ALTERNATIVE_TO_USER, OBJECTPOINT, 147),
++  CINIT(FTP_ALTERNATIVE_TO_USER, STRINGPOINT, 147),
 +
 +  /* callback function for setting socket options */
 +  CINIT(SOCKOPTFUNCTION, FUNCTIONPOINT, 148),
 +  CINIT(SOCKOPTDATA, OBJECTPOINT, 149),
 +
 +  /* set to 0 to disable session ID re-use for this transfer, default is
 +     enabled (== 1) */
 +  CINIT(SSL_SESSIONID_CACHE, LONG, 150),
 +
 +  /* allowed SSH authentication methods */
 +  CINIT(SSH_AUTH_TYPES, LONG, 151),
 +
 +  /* Used by scp/sftp to do public/private key authentication */
-   CINIT(SSH_PUBLIC_KEYFILE, OBJECTPOINT, 152),
-   CINIT(SSH_PRIVATE_KEYFILE, OBJECTPOINT, 153),
++  CINIT(SSH_PUBLIC_KEYFILE, STRINGPOINT, 152),
++  CINIT(SSH_PRIVATE_KEYFILE, STRINGPOINT, 153),
 +
 +  /* Send CCC (Clear Command Channel) after authentication */
 +  CINIT(FTP_SSL_CCC, LONG, 154),
 +
 +  /* Same as TIMEOUT and CONNECTTIMEOUT, but with ms resolution */
 +  CINIT(TIMEOUT_MS, LONG, 155),
 +  CINIT(CONNECTTIMEOUT_MS, LONG, 156),
 +
 +  /* set to zero to disable the libcurl's decoding and thus pass the raw body
 +     data to the application even when it is encoded/compressed */
 +  CINIT(HTTP_TRANSFER_DECODING, LONG, 157),
 +  CINIT(HTTP_CONTENT_DECODING, LONG, 158),
 +
 +  /* Permission used when creating new files and directories on the remote
 +     server for protocols that support it, SFTP/SCP/FILE */
 +  CINIT(NEW_FILE_PERMS, LONG, 159),
 +  CINIT(NEW_DIRECTORY_PERMS, LONG, 160),
 +
 +  /* Set the behaviour of POST when redirecting. Values must be set to one
 +     of CURL_REDIR* defines below. This used to be called CURLOPT_POST301 */
 +  CINIT(POSTREDIR, LONG, 161),
 +
 +  /* used by scp/sftp to verify the host's public key */
-   CINIT(SSH_HOST_PUBLIC_KEY_MD5, OBJECTPOINT, 162),
++  CINIT(SSH_HOST_PUBLIC_KEY_MD5, STRINGPOINT, 162),
 +
 +  /* Callback function for opening socket (instead of socket(2)). Optionally,
 +     callback is able change the address or refuse to connect returning
 +     CURL_SOCKET_BAD.  The callback should have type
 +     curl_opensocket_callback */
 +  CINIT(OPENSOCKETFUNCTION, FUNCTIONPOINT, 163),
 +  CINIT(OPENSOCKETDATA, OBJECTPOINT, 164),
 +
 +  /* POST volatile input fields. */
 +  CINIT(COPYPOSTFIELDS, OBJECTPOINT, 165),
 +
 +  /* set transfer mode (;type=<a|i>) when doing FTP via an HTTP proxy */
 +  CINIT(PROXY_TRANSFER_MODE, LONG, 166),
 +
 +  /* Callback function for seeking in the input stream */
 +  CINIT(SEEKFUNCTION, FUNCTIONPOINT, 167),
 +  CINIT(SEEKDATA, OBJECTPOINT, 168),
 +
 +  /* CRL file */
-   CINIT(CRLFILE, OBJECTPOINT, 169),
++  CINIT(CRLFILE, STRINGPOINT, 169),
 +
 +  /* Issuer certificate */
-   CINIT(ISSUERCERT, OBJECTPOINT, 170),
++  CINIT(ISSUERCERT, STRINGPOINT, 170),
 +
 +  /* (IPv6) Address scope */
 +  CINIT(ADDRESS_SCOPE, LONG, 171),
 +
 +  /* Collect certificate chain info and allow it to get retrievable with
 +     CURLINFO_CERTINFO after the transfer is complete. */
 +  CINIT(CERTINFO, LONG, 172),
 +
 +  /* "name" and "pwd" to use when fetching. */
-   CINIT(USERNAME, OBJECTPOINT, 173),
-   CINIT(PASSWORD, OBJECTPOINT, 174),
++  CINIT(USERNAME, STRINGPOINT, 173),
++  CINIT(PASSWORD, STRINGPOINT, 174),
 +
 +    /* "name" and "pwd" to use with Proxy when fetching. */
-   CINIT(PROXYUSERNAME, OBJECTPOINT, 175),
-   CINIT(PROXYPASSWORD, OBJECTPOINT, 176),
++  CINIT(PROXYUSERNAME, STRINGPOINT, 175),
++  CINIT(PROXYPASSWORD, STRINGPOINT, 176),
 +
 +  /* Comma separated list of hostnames defining no-proxy zones. These should
 +     match both hostnames directly, and hostnames within a domain. For
 +     example, local.com will match local.com and www.local.com, but NOT
 +     notlocal.com or www.notlocal.com. For compatibility with other
 +     implementations of this, .local.com will be considered to be the same as
 +     local.com. A single * is the only valid wildcard, and effectively
 +     disables the use of proxy. */
-   CINIT(NOPROXY, OBJECTPOINT, 177),
++  CINIT(NOPROXY, STRINGPOINT, 177),
 +
 +  /* block size for TFTP transfers */
 +  CINIT(TFTP_BLKSIZE, LONG, 178),
 +
 +  /* Socks Service */
-   CINIT(SOCKS5_GSSAPI_SERVICE, OBJECTPOINT, 179),
++  CINIT(SOCKS5_GSSAPI_SERVICE, STRINGPOINT, 179), /* DEPRECATED, do not use! */
 +
 +  /* Socks Service */
 +  CINIT(SOCKS5_GSSAPI_NEC, LONG, 180),
 +
 +  /* 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. */
 +  CINIT(PROTOCOLS, LONG, 181),
 +
 +  /* 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. */
 +  CINIT(REDIR_PROTOCOLS, LONG, 182),
 +
 +  /* set the SSH knownhost file name to use */
-   CINIT(SSH_KNOWNHOSTS, OBJECTPOINT, 183),
++  CINIT(SSH_KNOWNHOSTS, STRINGPOINT, 183),
 +
 +  /* set the SSH host key callback, must point to a curl_sshkeycallback
 +     function */
 +  CINIT(SSH_KEYFUNCTION, FUNCTIONPOINT, 184),
 +
 +  /* set the SSH host key callback custom pointer */
 +  CINIT(SSH_KEYDATA, OBJECTPOINT, 185),
 +
 +  /* set the SMTP mail originator */
-   CINIT(MAIL_FROM, OBJECTPOINT, 186),
++  CINIT(MAIL_FROM, STRINGPOINT, 186),
 +
-   /* set the SMTP mail receiver(s) */
++  /* set the list of SMTP mail receiver(s) */
 +  CINIT(MAIL_RCPT, OBJECTPOINT, 187),
 +
 +  /* FTP: send PRET before PASV */
 +  CINIT(FTP_USE_PRET, LONG, 188),
 +
 +  /* RTSP request method (OPTIONS, SETUP, PLAY, etc...) */
 +  CINIT(RTSP_REQUEST, LONG, 189),
 +
 +  /* The RTSP session identifier */
-   CINIT(RTSP_SESSION_ID, OBJECTPOINT, 190),
++  CINIT(RTSP_SESSION_ID, STRINGPOINT, 190),
 +
 +  /* The RTSP stream URI */
-   CINIT(RTSP_STREAM_URI, OBJECTPOINT, 191),
++  CINIT(RTSP_STREAM_URI, STRINGPOINT, 191),
 +
 +  /* The Transport: header to use in RTSP requests */
-   CINIT(RTSP_TRANSPORT, OBJECTPOINT, 192),
++  CINIT(RTSP_TRANSPORT, STRINGPOINT, 192),
 +
 +  /* Manually initialize the client RTSP CSeq for this handle */
 +  CINIT(RTSP_CLIENT_CSEQ, LONG, 193),
 +
 +  /* Manually initialize the server RTSP CSeq for this handle */
 +  CINIT(RTSP_SERVER_CSEQ, LONG, 194),
 +
 +  /* The stream to pass to INTERLEAVEFUNCTION. */
 +  CINIT(INTERLEAVEDATA, OBJECTPOINT, 195),
 +
 +  /* Let the application define a custom write method for RTP data */
 +  CINIT(INTERLEAVEFUNCTION, FUNCTIONPOINT, 196),
 +
 +  /* Turn on wildcard matching */
 +  CINIT(WILDCARDMATCH, LONG, 197),
 +
 +  /* Directory matching callback called before downloading of an
 +     individual file (chunk) started */
 +  CINIT(CHUNK_BGN_FUNCTION, FUNCTIONPOINT, 198),
 +
 +  /* Directory matching callback called after the file (chunk)
 +     was downloaded, or skipped */
 +  CINIT(CHUNK_END_FUNCTION, FUNCTIONPOINT, 199),
 +
 +  /* Change match (fnmatch-like) callback for wildcard matching */
 +  CINIT(FNMATCH_FUNCTION, FUNCTIONPOINT, 200),
 +
 +  /* Let the application define custom chunk data pointer */
 +  CINIT(CHUNK_DATA, OBJECTPOINT, 201),
 +
 +  /* FNMATCH_FUNCTION user pointer */
 +  CINIT(FNMATCH_DATA, OBJECTPOINT, 202),
 +
 +  /* send linked-list of name:port:address sets */
 +  CINIT(RESOLVE, OBJECTPOINT, 203),
 +
 +  /* Set a username for authenticated TLS */
-   CINIT(TLSAUTH_USERNAME, OBJECTPOINT, 204),
++  CINIT(TLSAUTH_USERNAME, STRINGPOINT, 204),
 +
 +  /* Set a password for authenticated TLS */
-   CINIT(TLSAUTH_PASSWORD, OBJECTPOINT, 205),
++  CINIT(TLSAUTH_PASSWORD, STRINGPOINT, 205),
 +
 +  /* Set authentication type for authenticated TLS */
-   CINIT(TLSAUTH_TYPE, OBJECTPOINT, 206),
++  CINIT(TLSAUTH_TYPE, STRINGPOINT, 206),
 +
 +  /* Set to 1 to enable the "TE:" header in HTTP requests to ask for
 +     compressed transfer-encoded responses. Set to 0 to disable the use of TE:
 +     in outgoing requests. The current default is 0, but it might change in a
 +     future libcurl release.
 +
 +     libcurl will ask for the compressed methods it knows of, and if that
 +     isn't any, it will not ask for transfer-encoding at all even if this
 +     option is set to 1.
 +
 +  */
 +  CINIT(TRANSFER_ENCODING, LONG, 207),
 +
 +  /* Callback function for closing socket (instead of close(2)). The callback
 +     should have type curl_closesocket_callback */
 +  CINIT(CLOSESOCKETFUNCTION, FUNCTIONPOINT, 208),
 +  CINIT(CLOSESOCKETDATA, OBJECTPOINT, 209),
 +
 +  /* allow GSSAPI credential delegation */
 +  CINIT(GSSAPI_DELEGATION, LONG, 210),
 +
 +  /* Set the name servers to use for DNS resolution */
-   CINIT(DNS_SERVERS, OBJECTPOINT, 211),
++  CINIT(DNS_SERVERS, STRINGPOINT, 211),
 +
 +  /* Time-out accept operations (currently for FTP only) after this amount
 +     of miliseconds. */
 +  CINIT(ACCEPTTIMEOUT_MS, LONG, 212),
 +
 +  /* Set TCP keepalive */
 +  CINIT(TCP_KEEPALIVE, LONG, 213),
 +
 +  /* non-universal keepalive knobs (Linux, AIX, HP-UX, more) */
 +  CINIT(TCP_KEEPIDLE, LONG, 214),
 +  CINIT(TCP_KEEPINTVL, LONG, 215),
 +
 +  /* Enable/disable specific SSL features with a bitmask, see CURLSSLOPT_* */
 +  CINIT(SSL_OPTIONS, LONG, 216),
 +
 +  /* Set the SMTP auth originator */
-   CINIT(MAIL_AUTH, OBJECTPOINT, 217),
++  CINIT(MAIL_AUTH, STRINGPOINT, 217),
 +
 +  /* Enable/disable SASL initial response */
 +  CINIT(SASL_IR, LONG, 218),
 +
 +  /* Function that will be called instead of the internal progress display
 +   * function. This function should be defined as the curl_xferinfo_callback
 +   * prototype defines. (Deprecates CURLOPT_PROGRESSFUNCTION) */
 +  CINIT(XFERINFOFUNCTION, FUNCTIONPOINT, 219),
 +
 +  /* The XOAUTH2 bearer token */
-   CINIT(XOAUTH2_BEARER, OBJECTPOINT, 220),
++  CINIT(XOAUTH2_BEARER, STRINGPOINT, 220),
 +
 +  /* Set the interface string to use as outgoing network
 +   * interface for DNS requests.
 +   * Only supported by the c-ares DNS backend */
-   CINIT(DNS_INTERFACE, OBJECTPOINT, 221),
++  CINIT(DNS_INTERFACE, STRINGPOINT, 221),
 +
 +  /* Set the local IPv4 address to use for outgoing DNS requests.
 +   * Only supported by the c-ares DNS backend */
-   CINIT(DNS_LOCAL_IP4, OBJECTPOINT, 222),
++  CINIT(DNS_LOCAL_IP4, STRINGPOINT, 222),
 +
 +  /* Set the local IPv4 address to use for outgoing DNS requests.
 +   * Only supported by the c-ares DNS backend */
-   CINIT(DNS_LOCAL_IP6, OBJECTPOINT, 223),
++  CINIT(DNS_LOCAL_IP6, STRINGPOINT, 223),
 +
 +  /* Set authentication options directly */
-   CINIT(LOGIN_OPTIONS, OBJECTPOINT, 224),
++  CINIT(LOGIN_OPTIONS, STRINGPOINT, 224),
 +
 +  /* Enable/disable TLS NPN extension (http2 over ssl might fail without) */
 +  CINIT(SSL_ENABLE_NPN, LONG, 225),
 +
 +  /* Enable/disable TLS ALPN extension (http2 over ssl might fail without) */
 +  CINIT(SSL_ENABLE_ALPN, LONG, 226),
 +
 +  /* Time to wait for a response to a HTTP request containing an
 +   * Expect: 100-continue header before sending the data anyway. */
 +  CINIT(EXPECT_100_TIMEOUT_MS, LONG, 227),
 +
 +  /* This points to a linked list of headers used for proxy requests only,
 +     struct curl_slist kind */
 +  CINIT(PROXYHEADER, OBJECTPOINT, 228),
 +
 +  /* Pass in a bitmask of "header options" */
 +  CINIT(HEADEROPT, LONG, 229),
 +
 +  /* The public key in DER form used to validate the peer public key
 +     this option is used only if SSL_VERIFYPEER is true */
-   CINIT(PINNEDPUBLICKEY, OBJECTPOINT, 230),
++  CINIT(PINNEDPUBLICKEY, STRINGPOINT, 230),
 +
 +  /* Path to Unix domain socket */
-   CINIT(UNIX_SOCKET_PATH, OBJECTPOINT, 231),
++  CINIT(UNIX_SOCKET_PATH, STRINGPOINT, 231),
 +
 +  /* Set if we should verify the certificate status. */
 +  CINIT(SSL_VERIFYSTATUS, LONG, 232),
 +
 +  /* Set if we should enable TLS false start. */
 +  CINIT(SSL_FALSESTART, LONG, 233),
 +
 +  /* Do not squash dot-dot sequences */
 +  CINIT(PATH_AS_IS, LONG, 234),
 +
 +  /* Proxy Service Name */
-   CINIT(PROXY_SERVICE_NAME, OBJECTPOINT, 235),
++  CINIT(PROXY_SERVICE_NAME, STRINGPOINT, 235),
 +
 +  /* Service Name */
-   CINIT(SERVICE_NAME, OBJECTPOINT, 236),
++  CINIT(SERVICE_NAME, STRINGPOINT, 236),
 +
 +  /* Wait/don't wait for pipe/mutex to clarify */
 +  CINIT(PIPEWAIT, LONG, 237),
 +
++  /* Set the protocol used when curl is given a URL without a protocol */
++  CINIT(DEFAULT_PROTOCOL, STRINGPOINT, 238),
++
++  /* Set stream weight, 1 - 256 (default is 16) */
++  CINIT(STREAM_WEIGHT, LONG, 239),
++
++  /* Set stream dependency on another CURL handle */
++  CINIT(STREAM_DEPENDS, OBJECTPOINT, 240),
++
++  /* Set E-xclusive stream dependency on another CURL handle */
++  CINIT(STREAM_DEPENDS_E, OBJECTPOINT, 241),
++
++  /* Do not send any tftp option requests to the server */
++  CINIT(TFTP_NO_OPTIONS, LONG, 242),
++
++  /* Linked-list of host:port:connect-to-host:connect-to-port,
++     overrides the URL's host:port (only for the network layer) */
++  CINIT(CONNECT_TO, OBJECTPOINT, 243),
++
++  /* Set TCP Fast Open */
++  CINIT(TCP_FASTOPEN, LONG, 244),
++
 +  CURLOPT_LASTENTRY /* the last unused */
 +} CURLoption;
 +
 +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
 +                          the obsolete stuff removed! */
 +
 +/* Backwards compatibility with older names */
 +/* These are scheduled to disappear by 2011 */
 +
 +/* This was added in version 7.19.1 */
 +#define CURLOPT_POST301 CURLOPT_POSTREDIR
 +
 +/* These are scheduled to disappear by 2009 */
 +
 +/* The following were added in 7.17.0 */
 +#define CURLOPT_SSLKEYPASSWD CURLOPT_KEYPASSWD
 +#define CURLOPT_FTPAPPEND CURLOPT_APPEND
 +#define CURLOPT_FTPLISTONLY CURLOPT_DIRLISTONLY
 +#define CURLOPT_FTP_SSL CURLOPT_USE_SSL
 +
 +/* The following were added earlier */
 +
 +#define CURLOPT_SSLCERTPASSWD CURLOPT_KEYPASSWD
 +#define CURLOPT_KRB4LEVEL CURLOPT_KRBLEVEL
 +
 +#else
 +/* This is set if CURL_NO_OLDIES is defined at compile-time */
 +#undef CURLOPT_DNS_USE_GLOBAL_CACHE /* soon obsolete */
 +#endif
 +
 +
 +  /* Below here follows defines for the CURLOPT_IPRESOLVE option. If a host
 +     name resolves addresses using more than one IP protocol version, this
 +     option might be handy to force libcurl to use a specific IP version. */
 +#define CURL_IPRESOLVE_WHATEVER 0 /* default, resolves addresses to all IP
 +                                     versions that your system allows */
 +#define CURL_IPRESOLVE_V4       1 /* resolve to IPv4 addresses */
 +#define CURL_IPRESOLVE_V6       2 /* resolve to IPv6 addresses */
 +
 +  /* three convenient "aliases" that follow the name scheme better */
 +#define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER
 +
 +  /* These enums are for use with the CURLOPT_HTTP_VERSION option. */
 +enum {
 +  CURL_HTTP_VERSION_NONE, /* setting this means we don't care, and that we'd
 +                             like the library to choose the best possible
 +                             for us! */
 +  CURL_HTTP_VERSION_1_0,  /* please use HTTP 1.0 in the request */
 +  CURL_HTTP_VERSION_1_1,  /* please use HTTP 1.1 in the request */
-   CURL_HTTP_VERSION_2_0,  /* please use HTTP 2.0 in the request */
++  CURL_HTTP_VERSION_2_0,  /* please use HTTP 2 in the request */
++  CURL_HTTP_VERSION_2TLS, /* use version 2 for HTTPS, version 1.1 for HTTP */
++  CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE,  /* please use HTTP 2 without HTTP/1.1
++                                           Upgrade */
 +
 +  CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */
 +};
 +
 +/* Convenience definition simple because the name of the version is HTTP/2 and
 +   not 2.0. The 2_0 version of the enum name was set while the version was
 +   still planned to be 2.0 and we stick to it for compatibility. */
 +#define CURL_HTTP_VERSION_2 CURL_HTTP_VERSION_2_0
 +
 +/*
 + * Public API enums for RTSP requests
 + */
 +enum {
 +    CURL_RTSPREQ_NONE, /* first in list */
 +    CURL_RTSPREQ_OPTIONS,
 +    CURL_RTSPREQ_DESCRIBE,
 +    CURL_RTSPREQ_ANNOUNCE,
 +    CURL_RTSPREQ_SETUP,
 +    CURL_RTSPREQ_PLAY,
 +    CURL_RTSPREQ_PAUSE,
 +    CURL_RTSPREQ_TEARDOWN,
 +    CURL_RTSPREQ_GET_PARAMETER,
 +    CURL_RTSPREQ_SET_PARAMETER,
 +    CURL_RTSPREQ_RECORD,
 +    CURL_RTSPREQ_RECEIVE,
 +    CURL_RTSPREQ_LAST /* last in list */
 +};
 +
 +  /* These enums are for use with the CURLOPT_NETRC option. */
 +enum CURL_NETRC_OPTION {
 +  CURL_NETRC_IGNORED,     /* The .netrc will never be read.
 +                           * This is the default. */
 +  CURL_NETRC_OPTIONAL,    /* A user:password in the URL will be preferred
 +                           * to one in the .netrc. */
 +  CURL_NETRC_REQUIRED,    /* A user:password in the URL will be ignored.
 +                           * Unless one is set programmatically, the .netrc
 +                           * will be queried. */
 +  CURL_NETRC_LAST
 +};
 +
 +enum {
 +  CURL_SSLVERSION_DEFAULT,
 +  CURL_SSLVERSION_TLSv1, /* TLS 1.x */
 +  CURL_SSLVERSION_SSLv2,
 +  CURL_SSLVERSION_SSLv3,
 +  CURL_SSLVERSION_TLSv1_0,
 +  CURL_SSLVERSION_TLSv1_1,
 +  CURL_SSLVERSION_TLSv1_2,
 +
 +  CURL_SSLVERSION_LAST /* never use, keep last */
 +};
 +
 +enum CURL_TLSAUTH {
 +  CURL_TLSAUTH_NONE,
 +  CURL_TLSAUTH_SRP,
 +  CURL_TLSAUTH_LAST /* never use, keep last */
 +};
 +
 +/* symbols to use with CURLOPT_POSTREDIR.
 +   CURL_REDIR_POST_301, CURL_REDIR_POST_302 and CURL_REDIR_POST_303
 +   can be bitwise ORed so that CURL_REDIR_POST_301 | CURL_REDIR_POST_302
 +   | CURL_REDIR_POST_303 == CURL_REDIR_POST_ALL */
 +
 +#define CURL_REDIR_GET_ALL  0
 +#define CURL_REDIR_POST_301 1
 +#define CURL_REDIR_POST_302 2
 +#define CURL_REDIR_POST_303 4
 +#define CURL_REDIR_POST_ALL \
 +    (CURL_REDIR_POST_301|CURL_REDIR_POST_302|CURL_REDIR_POST_303)
 +
 +typedef enum {
 +  CURL_TIMECOND_NONE,
 +
 +  CURL_TIMECOND_IFMODSINCE,
 +  CURL_TIMECOND_IFUNMODSINCE,
 +  CURL_TIMECOND_LASTMOD,
 +
 +  CURL_TIMECOND_LAST
 +} curl_TimeCond;
 +
 +
 +/* curl_strequal() and curl_strnequal() are subject for removal in a future
 +   libcurl, see lib/README.curlx for details */
 +CURL_EXTERN int (curl_strequal)(const char *s1, const char *s2);
 +CURL_EXTERN int (curl_strnequal)(const char *s1, const char *s2, size_t n);
 +
 +/* name is uppercase CURLFORM_<name> */
 +#ifdef CFINIT
 +#undef CFINIT
 +#endif
 +
 +#ifdef CURL_ISOCPP
 +#define CFINIT(name) CURLFORM_ ## name
 +#else
 +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */
 +#define CFINIT(name) CURLFORM_/**/name
 +#endif
 +
 +typedef enum {
 +  CFINIT(NOTHING),        /********* the first one is unused ************/
 +
 +  /*  */
 +  CFINIT(COPYNAME),
 +  CFINIT(PTRNAME),
 +  CFINIT(NAMELENGTH),
 +  CFINIT(COPYCONTENTS),
 +  CFINIT(PTRCONTENTS),
 +  CFINIT(CONTENTSLENGTH),
 +  CFINIT(FILECONTENT),
 +  CFINIT(ARRAY),
 +  CFINIT(OBSOLETE),
 +  CFINIT(FILE),
 +
 +  CFINIT(BUFFER),
 +  CFINIT(BUFFERPTR),
 +  CFINIT(BUFFERLENGTH),
 +
 +  CFINIT(CONTENTTYPE),
 +  CFINIT(CONTENTHEADER),
 +  CFINIT(FILENAME),
 +  CFINIT(END),
 +  CFINIT(OBSOLETE2),
 +
 +  CFINIT(STREAM),
++  CFINIT(CONTENTLEN), /* added in 7.46.0, provide a curl_off_t length */
 +
 +  CURLFORM_LASTENTRY /* the last unused */
 +} CURLformoption;
 +
 +#undef CFINIT /* done */
 +
 +/* structure to be used as parameter for CURLFORM_ARRAY */
 +struct curl_forms {
 +  CURLformoption option;
 +  const char     *value;
 +};
 +
 +/* use this for multipart formpost building */
 +/* Returns code for curl_formadd()
 + *
 + * Returns:
 + * CURL_FORMADD_OK             on success
 + * CURL_FORMADD_MEMORY         if the FormInfo allocation fails
 + * CURL_FORMADD_OPTION_TWICE   if one option is given twice for one Form
 + * CURL_FORMADD_NULL           if a null pointer was given for a char
 + * CURL_FORMADD_MEMORY         if the allocation of a FormInfo struct failed
 + * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used
 + * CURL_FORMADD_INCOMPLETE     if the some FormInfo is not complete (or error)
 + * CURL_FORMADD_MEMORY         if a curl_httppost struct cannot be allocated
 + * CURL_FORMADD_MEMORY         if some allocation for string copying failed.
 + * CURL_FORMADD_ILLEGAL_ARRAY  if an illegal option is used in an array
 + *
 + ***************************************************************************/
 +typedef enum {
 +  CURL_FORMADD_OK, /* first, no error */
 +
 +  CURL_FORMADD_MEMORY,
 +  CURL_FORMADD_OPTION_TWICE,
 +  CURL_FORMADD_NULL,
 +  CURL_FORMADD_UNKNOWN_OPTION,
 +  CURL_FORMADD_INCOMPLETE,
 +  CURL_FORMADD_ILLEGAL_ARRAY,
 +  CURL_FORMADD_DISABLED, /* libcurl was built with this disabled */
 +
 +  CURL_FORMADD_LAST /* last */
 +} CURLFORMcode;
 +
 +/*
 + * NAME curl_formadd()
 + *
 + * DESCRIPTION
 + *
 + * Pretty advanced function for building multi-part formposts. Each invoke
 + * adds one part that together construct a full post. Then use
 + * CURLOPT_HTTPPOST to send it off to libcurl.
 + */
 +CURL_EXTERN CURLFORMcode curl_formadd(struct curl_httppost **httppost,
 +                                      struct curl_httppost **last_post,
 +                                      ...);
 +
 +/*
 + * callback function for curl_formget()
 + * The void *arg pointer will be the one passed as second argument to
 + *   curl_formget().
 + * The character buffer passed to it must not be freed.
 + * Should return the buffer length passed to it as the argument "len" on
 + *   success.
 + */
 +typedef size_t (*curl_formget_callback)(void *arg, const char *buf,
 +                                        size_t len);
 +
 +/*
 + * NAME curl_formget()
 + *
 + * DESCRIPTION
 + *
 + * Serialize a curl_httppost struct built with curl_formadd().
 + * Accepts a void pointer as second argument which will be passed to
 + * the curl_formget_callback function.
 + * Returns 0 on success.
 + */
 +CURL_EXTERN int curl_formget(struct curl_httppost *form, void *arg,
 +                             curl_formget_callback append);
 +/*
 + * NAME curl_formfree()
 + *
 + * DESCRIPTION
 + *
 + * Free a multipart formpost previously built with curl_formadd().
 + */
 +CURL_EXTERN void curl_formfree(struct curl_httppost *form);
 +
 +/*
 + * NAME curl_getenv()
 + *
 + * DESCRIPTION
 + *
 + * Returns a malloc()'ed string that MUST be curl_free()ed after usage is
 + * complete. DEPRECATED - see lib/README.curlx
 + */
 +CURL_EXTERN char *curl_getenv(const char *variable);
 +
 +/*
 + * NAME curl_version()
 + *
 + * DESCRIPTION
 + *
 + * Returns a static ascii string of the libcurl version.
 + */
 +CURL_EXTERN char *curl_version(void);
 +
 +/*
 + * NAME curl_easy_escape()
 + *
 + * DESCRIPTION
 + *
 + * Escapes URL strings (converts all letters consider illegal in URLs to their
 + * %XX versions). This function returns a new allocated string or NULL if an
 + * error occurred.
 + */
 +CURL_EXTERN char *curl_easy_escape(CURL *handle,
 +                                   const char *string,
 +                                   int length);
 +
 +/* the previous version: */
 +CURL_EXTERN char *curl_escape(const char *string,
 +                              int length);
 +
 +
 +/*
 + * NAME curl_easy_unescape()
 + *
 + * DESCRIPTION
 + *
 + * Unescapes URL encoding in strings (converts all %XX codes to their 8bit
 + * versions). This function returns a new allocated string or NULL if an error
 + * occurred.
 + * Conversion Note: On non-ASCII platforms the ASCII %XX codes are
 + * converted into the host encoding.
 + */
 +CURL_EXTERN char *curl_easy_unescape(CURL *handle,
 +                                     const char *string,
 +                                     int length,
 +                                     int *outlength);
 +
 +/* the previous version */
 +CURL_EXTERN char *curl_unescape(const char *string,
 +                                int length);
 +
 +/*
 + * NAME curl_free()
 + *
 + * DESCRIPTION
 + *
 + * Provided for de-allocation in the same translation unit that did the
 + * allocation. Added in libcurl 7.10
 + */
 +CURL_EXTERN void curl_free(void *p);
 +
 +/*
 + * NAME curl_global_init()
 + *
 + * DESCRIPTION
 + *
 + * curl_global_init() should be invoked exactly once for each application that
 + * uses libcurl and before any call of other libcurl functions.
 + *
 + * This function is not thread-safe!
 + */
 +CURL_EXTERN CURLcode curl_global_init(long flags);
 +
 +/*
 + * NAME curl_global_init_mem()
 + *
 + * DESCRIPTION
 + *
 + * curl_global_init() or curl_global_init_mem() should be invoked exactly once
 + * for each application that uses libcurl.  This function can be used to
 + * initialize libcurl and set user defined memory management callback
 + * functions.  Users can implement memory management routines to check for
 + * memory leaks, check for mis-use of the curl library etc.  User registered
 + * callback routines with be invoked by this library instead of the system
 + * memory management routines like malloc, free etc.
 + */
 +CURL_EXTERN CURLcode curl_global_init_mem(long flags,
 +                                          curl_malloc_callback m,
 +                                          curl_free_callback f,
 +                                          curl_realloc_callback r,
 +                                          curl_strdup_callback s,
 +                                          curl_calloc_callback c);
 +
 +/*
 + * NAME curl_global_cleanup()
 + *
 + * DESCRIPTION
 + *
 + * curl_global_cleanup() should be invoked exactly once for each application
 + * that uses libcurl
 + */
 +CURL_EXTERN void curl_global_cleanup(void);
 +
 +/* linked-list structure for the CURLOPT_QUOTE option (and other) */
 +struct curl_slist {
 +  char *data;
 +  struct curl_slist *next;
 +};
 +
 +/*
 + * NAME curl_slist_append()
 + *
 + * DESCRIPTION
 + *
 + * Appends a string to a linked list. If no list exists, it will be created
 + * first. Returns the new list, after appending.
 + */
 +CURL_EXTERN struct curl_slist *curl_slist_append(struct curl_slist *,
 +                                                 const char *);
 +
 +/*
 + * NAME curl_slist_free_all()
 + *
 + * DESCRIPTION
 + *
 + * free a previously built curl_slist.
 + */
 +CURL_EXTERN void curl_slist_free_all(struct curl_slist *);
 +
 +/*
 + * NAME curl_getdate()
 + *
 + * DESCRIPTION
 + *
 + * Returns the time, in seconds since 1 Jan 1970 of the time string given in
 + * the first argument. The time argument in the second parameter is unused
 + * and should be set to NULL.
 + */
 +CURL_EXTERN time_t curl_getdate(const char *p, const time_t *unused);
 +
 +/* info about the certificate chain, only for OpenSSL builds. Asked
 +   for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */
 +struct curl_certinfo {
 +  int num_of_certs;             /* number of certificates with information */
 +  struct curl_slist **certinfo; /* for each index in this array, there's a
 +                                   linked list with textual information in the
 +                                   format "name: value" */
 +};
 +
 +/* enum for the different supported SSL backends */
 +typedef enum {
 +  CURLSSLBACKEND_NONE = 0,
 +  CURLSSLBACKEND_OPENSSL = 1,
 +  CURLSSLBACKEND_GNUTLS = 2,
 +  CURLSSLBACKEND_NSS = 3,
 +  CURLSSLBACKEND_OBSOLETE4 = 4,  /* Was QSOSSL. */
 +  CURLSSLBACKEND_GSKIT = 5,
 +  CURLSSLBACKEND_POLARSSL = 6,
 +  CURLSSLBACKEND_CYASSL = 7,
 +  CURLSSLBACKEND_SCHANNEL = 8,
 +  CURLSSLBACKEND_DARWINSSL = 9,
-   CURLSSLBACKEND_AXTLS = 10
++  CURLSSLBACKEND_AXTLS = 10,
++  CURLSSLBACKEND_MBEDTLS = 11
 +} curl_sslbackend;
 +
++/* aliases for library clones and renames */
++#define CURLSSLBACKEND_LIBRESSL 1
++#define CURLSSLBACKEND_BORINGSSL 1
++#define CURLSSLBACKEND_WOLFSSL 6
++
 +/* Information about the SSL library used and the respective internal SSL
 +   handle, which can be used to obtain further information regarding the
-    connection. Asked for with CURLINFO_TLS_SESSION. */
++   connection. Asked for with CURLINFO_TLS_SSL_PTR or CURLINFO_TLS_SESSION. */
 +struct curl_tlssessioninfo {
 +  curl_sslbackend backend;
 +  void *internals;
 +};
 +
 +#define CURLINFO_STRING   0x100000
 +#define CURLINFO_LONG     0x200000
 +#define CURLINFO_DOUBLE   0x300000
 +#define CURLINFO_SLIST    0x400000
++#define CURLINFO_SOCKET   0x500000
 +#define CURLINFO_MASK     0x0fffff
 +#define CURLINFO_TYPEMASK 0xf00000
 +
 +typedef enum {
 +  CURLINFO_NONE, /* first, never use this */
 +  CURLINFO_EFFECTIVE_URL    = CURLINFO_STRING + 1,
 +  CURLINFO_RESPONSE_CODE    = CURLINFO_LONG   + 2,
 +  CURLINFO_TOTAL_TIME       = CURLINFO_DOUBLE + 3,
 +  CURLINFO_NAMELOOKUP_TIME  = CURLINFO_DOUBLE + 4,
 +  CURLINFO_CONNECT_TIME     = CURLINFO_DOUBLE + 5,
 +  CURLINFO_PRETRANSFER_TIME = CURLINFO_DOUBLE + 6,
 +  CURLINFO_SIZE_UPLOAD      = CURLINFO_DOUBLE + 7,
 +  CURLINFO_SIZE_DOWNLOAD    = CURLINFO_DOUBLE + 8,
 +  CURLINFO_SPEED_DOWNLOAD   = CURLINFO_DOUBLE + 9,
 +  CURLINFO_SPEED_UPLOAD     = CURLINFO_DOUBLE + 10,
 +  CURLINFO_HEADER_SIZE      = CURLINFO_LONG   + 11,
 +  CURLINFO_REQUEST_SIZE     = CURLINFO_LONG   + 12,
 +  CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG   + 13,
 +  CURLINFO_FILETIME         = CURLINFO_LONG   + 14,
 +  CURLINFO_CONTENT_LENGTH_DOWNLOAD   = CURLINFO_DOUBLE + 15,
 +  CURLINFO_CONTENT_LENGTH_UPLOAD     = CURLINFO_DOUBLE + 16,
 +  CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17,
 +  CURLINFO_CONTENT_TYPE     = CURLINFO_STRING + 18,
 +  CURLINFO_REDIRECT_TIME    = CURLINFO_DOUBLE + 19,
 +  CURLINFO_REDIRECT_COUNT   = CURLINFO_LONG   + 20,
 +  CURLINFO_PRIVATE          = CURLINFO_STRING + 21,
 +  CURLINFO_HTTP_CONNECTCODE = CURLINFO_LONG   + 22,
 +  CURLINFO_HTTPAUTH_AVAIL   = CURLINFO_LONG   + 23,
 +  CURLINFO_PROXYAUTH_AVAIL  = CURLINFO_LONG   + 24,
 +  CURLINFO_OS_ERRNO         = CURLINFO_LONG   + 25,
 +  CURLINFO_NUM_CONNECTS     = CURLINFO_LONG   + 26,
 +  CURLINFO_SSL_ENGINES      = CURLINFO_SLIST  + 27,
 +  CURLINFO_COOKIELIST       = CURLINFO_SLIST  + 28,
 +  CURLINFO_LASTSOCKET       = CURLINFO_LONG   + 29,
 +  CURLINFO_FTP_ENTRY_PATH   = CURLINFO_STRING + 30,
 +  CURLINFO_REDIRECT_URL     = CURLINFO_STRING + 31,
 +  CURLINFO_PRIMARY_IP       = CURLINFO_STRING + 32,
 +  CURLINFO_APPCONNECT_TIME  = CURLINFO_DOUBLE + 33,
 +  CURLINFO_CERTINFO         = CURLINFO_SLIST  + 34,
 +  CURLINFO_CONDITION_UNMET  = CURLINFO_LONG   + 35,
 +  CURLINFO_RTSP_SESSION_ID  = CURLINFO_STRING + 36,
 +  CURLINFO_RTSP_CLIENT_CSEQ = CURLINFO_LONG   + 37,
 +  CURLINFO_RTSP_SERVER_CSEQ = CURLINFO_LONG   + 38,
 +  CURLINFO_RTSP_CSEQ_RECV   = CURLINFO_LONG   + 39,
 +  CURLINFO_PRIMARY_PORT     = CURLINFO_LONG   + 40,
 +  CURLINFO_LOCAL_IP         = CURLINFO_STRING + 41,
 +  CURLINFO_LOCAL_PORT       = CURLINFO_LONG   + 42,
 +  CURLINFO_TLS_SESSION      = CURLINFO_SLIST  + 43,
++  CURLINFO_ACTIVESOCKET     = CURLINFO_SOCKET + 44,
++  CURLINFO_TLS_SSL_PTR      = CURLINFO_SLIST  + 45,
++  CURLINFO_HTTP_VERSION     = CURLINFO_LONG   + 46,
 +  /* Fill in new entries below here! */
 +
-   CURLINFO_LASTONE          = 43
++  CURLINFO_LASTONE          = 46
 +} CURLINFO;
 +
 +/* CURLINFO_RESPONSE_CODE is the new name for the option previously known as
 +   CURLINFO_HTTP_CODE */
 +#define CURLINFO_HTTP_CODE CURLINFO_RESPONSE_CODE
 +
 +typedef enum {
 +  CURLCLOSEPOLICY_NONE, /* first, never use this */
 +
 +  CURLCLOSEPOLICY_OLDEST,
 +  CURLCLOSEPOLICY_LEAST_RECENTLY_USED,
 +  CURLCLOSEPOLICY_LEAST_TRAFFIC,
 +  CURLCLOSEPOLICY_SLOWEST,
 +  CURLCLOSEPOLICY_CALLBACK,
 +
 +  CURLCLOSEPOLICY_LAST /* last, never use this */
 +} curl_closepolicy;
 +
 +#define CURL_GLOBAL_SSL (1<<0)
 +#define CURL_GLOBAL_WIN32 (1<<1)
 +#define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32)
 +#define CURL_GLOBAL_NOTHING 0
 +#define CURL_GLOBAL_DEFAULT CURL_GLOBAL_ALL
 +#define CURL_GLOBAL_ACK_EINTR (1<<2)
 +
 +
 +/*****************************************************************************
 + * Setup defines, protos etc for the sharing stuff.
 + */
 +
 +/* Different data locks for a single share */
 +typedef enum {
 +  CURL_LOCK_DATA_NONE = 0,
 +  /*  CURL_LOCK_DATA_SHARE is used internally to say that
 +   *  the locking is just made to change the internal state of the share
 +   *  itself.
 +   */
 +  CURL_LOCK_DATA_SHARE,
 +  CURL_LOCK_DATA_COOKIE,
 +  CURL_LOCK_DATA_DNS,
 +  CURL_LOCK_DATA_SSL_SESSION,
 +  CURL_LOCK_DATA_CONNECT,
 +  CURL_LOCK_DATA_LAST
 +} curl_lock_data;
 +
 +/* Different lock access types */
 +typedef enum {
 +  CURL_LOCK_ACCESS_NONE = 0,   /* unspecified action */
 +  CURL_LOCK_ACCESS_SHARED = 1, /* for read perhaps */
 +  CURL_LOCK_ACCESS_SINGLE = 2, /* for write perhaps */
 +  CURL_LOCK_ACCESS_LAST        /* never use */
 +} curl_lock_access;
 +
 +typedef void (*curl_lock_function)(CURL *handle,
 +                                   curl_lock_data data,
 +                                   curl_lock_access locktype,
 +                                   void *userptr);
 +typedef void (*curl_unlock_function)(CURL *handle,
 +                                     curl_lock_data data,
 +                                     void *userptr);
 +
- typedef void CURLSH;
 +
 +typedef enum {
 +  CURLSHE_OK,  /* all is fine */
 +  CURLSHE_BAD_OPTION, /* 1 */
 +  CURLSHE_IN_USE,     /* 2 */
 +  CURLSHE_INVALID,    /* 3 */
 +  CURLSHE_NOMEM,      /* 4 out of memory */
 +  CURLSHE_NOT_BUILT_IN, /* 5 feature not present in lib */
 +  CURLSHE_LAST        /* never use */
 +} CURLSHcode;
 +
 +typedef enum {
 +  CURLSHOPT_NONE,  /* don't use */
 +  CURLSHOPT_SHARE,   /* specify a data type to share */
 +  CURLSHOPT_UNSHARE, /* specify which data type to stop sharing */
 +  CURLSHOPT_LOCKFUNC,   /* pass in a 'curl_lock_function' pointer */
 +  CURLSHOPT_UNLOCKFUNC, /* pass in a 'curl_unlock_function' pointer */
 +  CURLSHOPT_USERDATA,   /* pass in a user data pointer used in the lock/unlock
 +                           callback functions */
 +  CURLSHOPT_LAST  /* never use */
 +} CURLSHoption;
 +
 +CURL_EXTERN CURLSH *curl_share_init(void);
 +CURL_EXTERN CURLSHcode curl_share_setopt(CURLSH *, CURLSHoption option, ...);
 +CURL_EXTERN CURLSHcode curl_share_cleanup(CURLSH *);
 +
 +/****************************************************************************
 + * Structures for querying information about the curl library at runtime.
 + */
 +
 +typedef enum {
 +  CURLVERSION_FIRST,
 +  CURLVERSION_SECOND,
 +  CURLVERSION_THIRD,
 +  CURLVERSION_FOURTH,
 +  CURLVERSION_LAST /* never actually use this */
 +} CURLversion;
 +
 +/* The 'CURLVERSION_NOW' is the symbolic name meant to be used by
 +   basically all programs ever that want to get version information. It is
 +   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
 +
 +typedef struct {
 +  CURLversion age;          /* age of the returned struct */
 +  const char *version;      /* LIBCURL_VERSION */
 +  unsigned int version_num; /* LIBCURL_VERSION_NUM */
 +  const char *host;         /* OS/host/cpu/machine when configured */
 +  int features;             /* bitmask, see defines below */
 +  const char *ssl_version;  /* human readable string */
 +  long ssl_version_num;     /* not used anymore, always 0 */
 +  const char *libz_version; /* human readable string */
 +  /* protocols is terminated by an entry with a NULL protoname */
 +  const char * const *protocols;
 +
 +  /* The fields below this were added in CURLVERSION_SECOND */
 +  const char *ares;
 +  int ares_num;
 +
 +  /* This field was added in CURLVERSION_THIRD */
 +  const char *libidn;
 +
 +  /* These field were added in CURLVERSION_FOURTH */
 +
 +  /* Same as '_libiconv_version' if built with HAVE_ICONV */
 +  int iconv_ver_num;
 +
 +  const char *libssh_version; /* human readable string */
 +
 +} curl_version_info_data;
 +
 +#define CURL_VERSION_IPV6         (1<<0)  /* IPv6-enabled */
 +#define CURL_VERSION_KERBEROS4    (1<<1)  /* Kerberos V4 auth is supported
 +                                             (deprecated) */
 +#define CURL_VERSION_SSL          (1<<2)  /* SSL options are present */
 +#define CURL_VERSION_LIBZ         (1<<3)  /* libz features are present */
 +#define CURL_VERSION_NTLM         (1<<4)  /* NTLM auth is supported */
 +#define CURL_VERSION_GSSNEGOTIATE (1<<5)  /* Negotiate auth is supported
 +                                             (deprecated) */
 +#define CURL_VERSION_DEBUG        (1<<6)  /* Built with debug capabilities */
 +#define CURL_VERSION_ASYNCHDNS    (1<<7)  /* Asynchronous DNS resolves */
 +#define CURL_VERSION_SPNEGO       (1<<8)  /* SPNEGO auth is supported */
 +#define CURL_VERSION_LARGEFILE    (1<<9)  /* Supports files larger than 2GB */
 +#define CURL_VERSION_IDN          (1<<10) /* Internationized Domain Names are
 +                                             supported */
 +#define CURL_VERSION_SSPI         (1<<11) /* Built against Windows SSPI */
 +#define CURL_VERSION_CONV         (1<<12) /* Character conversions supported */
 +#define CURL_VERSION_CURLDEBUG    (1<<13) /* Debug memory tracking supported */
 +#define CURL_VERSION_TLSAUTH_SRP  (1<<14) /* TLS-SRP auth is supported */
 +#define CURL_VERSION_NTLM_WB      (1<<15) /* NTLM delegation to winbind helper
 +                                             is suported */
 +#define CURL_VERSION_HTTP2        (1<<16) /* HTTP2 support built-in */
 +#define CURL_VERSION_GSSAPI       (1<<17) /* Built against a GSS-API library */
 +#define CURL_VERSION_KERBEROS5    (1<<18) /* Kerberos V5 auth is supported */
 +#define CURL_VERSION_UNIX_SOCKETS (1<<19) /* Unix domain sockets support */
++#define CURL_VERSION_PSL          (1<<20) /* Mozilla's Public Suffix List, used
++                                             for cookie domain verification */
 +
 + /*
 + * NAME curl_version_info()
 + *
 + * DESCRIPTION
 + *
 + * This function returns a pointer to a static copy of the version info
 + * struct. See above.
 + */
 +CURL_EXTERN curl_version_info_data *curl_version_info(CURLversion);
 +
 +/*
 + * NAME curl_easy_strerror()
 + *
 + * DESCRIPTION
 + *
 + * The curl_easy_strerror function may be used to turn a CURLcode value
 + * into the equivalent human readable error string.  This is useful
 + * for printing meaningful error messages.
 + */
 +CURL_EXTERN const char *curl_easy_strerror(CURLcode);
 +
 +/*
 + * NAME curl_share_strerror()
 + *
 + * DESCRIPTION
 + *
 + * The curl_share_strerror function may be used to turn a CURLSHcode value
 + * into the equivalent human readable error string.  This is useful
 + * for printing meaningful error messages.
 + */
 +CURL_EXTERN const char *curl_share_strerror(CURLSHcode);
 +
 +/*
 + * NAME curl_easy_pause()
 + *
 + * DESCRIPTION
 + *
 + * The curl_easy_pause function pauses or unpauses transfers. Select the new
 + * state by setting the bitmask, use the convenience defines below.
 + *
 + */
 +CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask);
 +
 +#define CURLPAUSE_RECV      (1<<0)
 +#define CURLPAUSE_RECV_CONT (0)
 +
 +#define CURLPAUSE_SEND      (1<<2)
 +#define CURLPAUSE_SEND_CONT (0)
 +
 +#define CURLPAUSE_ALL       (CURLPAUSE_RECV|CURLPAUSE_SEND)
 +#define CURLPAUSE_CONT      (CURLPAUSE_RECV_CONT|CURLPAUSE_SEND_CONT)
 +
 +#ifdef  __cplusplus
 +}
 +#endif
 +
 +/* unfortunately, the easy.h and multi.h include files need options and info
 +  stuff before they can be included! */
 +#include "easy.h" /* nothing in curl is fun without the easy stuff */
 +#include "multi.h"
 +
 +/* the typechecker doesn't work in C++ (yet) */
 +#if defined(__GNUC__) && defined(__GNUC_MINOR__) && \
 +    ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) && \
 +    !defined(__cplusplus) && !defined(CURL_DISABLE_TYPECHECK)
 +#include "typecheck-gcc.h"
 +#else
 +#if defined(__STDC__) && (__STDC__ >= 1)
 +#if 0 /* Triggers clang -Wdisabled-macro-expansion, skip for CMake.  */
 +/* This preprocessor magic that replaces a call with the exact same call is
 +   only done to make sure application authors pass exactly three arguments
 +   to these functions. */
 +#define curl_easy_setopt(handle,opt,param) curl_easy_setopt(handle,opt,param)
 +#define curl_easy_getinfo(handle,info,arg) curl_easy_getinfo(handle,info,arg)
 +#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param)
 +#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param)
 +#endif
 +#endif /* __STDC__ >= 1 */
 +#endif /* gcc >= 4.3 && !__cplusplus */
 +
 +#endif /* __CURL_CURL_H */
diff --cc Utilities/cmcurl/include/curl/curlbuild.h.cmake
index 6608694,0000000..c8b4f52
mode 100644,000000..100644
--- a/Utilities/cmcurl/include/curl/curlbuild.h.cmake
+++ b/Utilities/cmcurl/include/curl/curlbuild.h.cmake
@@@ -1,218 -1,0 +1,218 @@@
 +#ifndef __CURL_CURLBUILD_H
 +#define __CURL_CURLBUILD_H
 +/***************************************************************************
 + *                                  _   _ ____  _
 + *  Project                     ___| | | |  _ \| |
 + *                             / __| | | | |_) | |
 + *                            | (__| |_| |  _ <| |___
 + *                             \___|\___/|_| \_\_____|
 + *
 + * Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel at haxx.se>, et al.
 + *
 + * This software is licensed as described in the file COPYING, which
 + * you should have received as part of this distribution. The terms
-  * are also available at http://curl.haxx.se/docs/copyright.html.
++ * 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.
 + *
 + ***************************************************************************/
 +
 +/* ================================================================ */
 +/*               NOTES FOR CONFIGURE CAPABLE SYSTEMS                */
 +/* ================================================================ */
 +
 +/*
 + * NOTE 1:
 + * -------
 + *
 + * Nothing in this file is intended to be modified or adjusted by the
 + * curl library user nor by the curl library builder.
 + *
 + * If you think that something actually needs to be changed, adjusted
 + * or fixed in this file, then, report it on the libcurl development
-  * mailing list: http://cool.haxx.se/mailman/listinfo/curl-library/
++ * mailing list: https://cool.haxx.se/mailman/listinfo/curl-library/
 + *
 + * This header file shall only export symbols which are 'curl' or 'CURL'
 + * prefixed, otherwise public name space would be polluted.
 + *
 + * NOTE 2:
 + * -------
 + *
 + * Right now you might be staring at file include/curl/curlbuild.h.in or
 + * at file include/curl/curlbuild.h, this is due to the following reason:
 + *
 + * On systems capable of running the configure script, the configure process
 + * will overwrite the distributed include/curl/curlbuild.h file with one that
 + * is suitable and specific to the library being configured and built, which
 + * is generated from the include/curl/curlbuild.h.in template file.
 + *
 + */
 +
 +/* ================================================================ */
 +/*  DEFINITION OF THESE SYMBOLS SHALL NOT TAKE PLACE ANYWHERE ELSE  */
 +/* ================================================================ */
 +
 +#ifdef CURL_SIZEOF_LONG
 +#error "CURL_SIZEOF_LONG shall not be defined except in curlbuild.h"
 +   Error Compilation_aborted_CURL_SIZEOF_LONG_already_defined
 +#endif
 +
 +#ifdef CURL_TYPEOF_CURL_SOCKLEN_T
 +#error "CURL_TYPEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h"
 +   Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_already_defined
 +#endif
 +
 +#ifdef CURL_SIZEOF_CURL_SOCKLEN_T
 +#error "CURL_SIZEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h"
 +   Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_already_defined
 +#endif
 +
 +#ifdef CURL_TYPEOF_CURL_OFF_T
 +#error "CURL_TYPEOF_CURL_OFF_T shall not be defined except in curlbuild.h"
 +   Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_already_defined
 +#endif
 +
 +#ifdef CURL_FORMAT_CURL_OFF_T
 +#error "CURL_FORMAT_CURL_OFF_T shall not be defined except in curlbuild.h"
 +   Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_already_defined
 +#endif
 +
 +#ifdef CURL_FORMAT_CURL_OFF_TU
 +#error "CURL_FORMAT_CURL_OFF_TU shall not be defined except in curlbuild.h"
 +   Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_already_defined
 +#endif
 +
 +#ifdef CURL_FORMAT_OFF_T
 +#error "CURL_FORMAT_OFF_T shall not be defined except in curlbuild.h"
 +   Error Compilation_aborted_CURL_FORMAT_OFF_T_already_defined
 +#endif
 +
 +#ifdef CURL_SIZEOF_CURL_OFF_T
 +#error "CURL_SIZEOF_CURL_OFF_T shall not be defined except in curlbuild.h"
 +   Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_already_defined
 +#endif
 +
 +#ifdef CURL_SUFFIX_CURL_OFF_T
 +#error "CURL_SUFFIX_CURL_OFF_T shall not be defined except in curlbuild.h"
 +   Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_already_defined
 +#endif
 +
 +#ifdef CURL_SUFFIX_CURL_OFF_TU
 +#error "CURL_SUFFIX_CURL_OFF_TU shall not be defined except in curlbuild.h"
 +   Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_already_defined
 +#endif
 +
 +/* ================================================================ */
 +/*  EXTERNAL INTERFACE SETTINGS FOR CONFIGURE CAPABLE SYSTEMS ONLY  */
 +/* ================================================================ */
 +
 +/* Configure process defines this to 1 when it finds out that system  */
 +/* header file ws2tcpip.h must be included by the external interface. */
 +#cmakedefine CURL_PULL_WS2TCPIP_H
 +#ifdef CURL_PULL_WS2TCPIP_H
 +#  ifndef WIN32_LEAN_AND_MEAN
 +#    define WIN32_LEAN_AND_MEAN
 +#  endif
 +#  include <windows.h>
 +#  include <winsock2.h>
 +#  include <ws2tcpip.h>
 +#endif
 +
 +/* Configure process defines this to 1 when it finds out that system   */
 +/* header file sys/types.h must be included by the external interface. */
 +#cmakedefine CURL_PULL_SYS_TYPES_H
 +#ifdef CURL_PULL_SYS_TYPES_H
 +#  include <sys/types.h>
 +#endif
 +
 +/* Configure process defines this to 1 when it finds out that system */
 +/* header file stdint.h must be included by the external interface.  */
 +#cmakedefine CURL_PULL_STDINT_H
 +#ifdef CURL_PULL_STDINT_H
 +#  include <stdint.h>
 +#endif
 +
 +/* Configure process defines this to 1 when it finds out that system  */
 +/* header file inttypes.h must be included by the external interface. */
 +#cmakedefine CURL_PULL_INTTYPES_H
 +#ifdef CURL_PULL_INTTYPES_H
 +#  include <inttypes.h>
 +#endif
 +
 +/* Configure process defines this to 1 when it finds out that system    */
 +/* header file sys/socket.h must be included by the external interface. */
 +#cmakedefine CURL_PULL_SYS_SOCKET_H
 +#ifdef CURL_PULL_SYS_SOCKET_H
 +#  include <sys/socket.h>
 +#endif
 +
 +/* Configure process defines this to 1 when it finds out that system  */
 +/* header file sys/poll.h must be included by the external interface. */
 +#cmakedefine CURL_PULL_SYS_POLL_H
 +#ifdef CURL_PULL_SYS_POLL_H
 +#  include <sys/poll.h>
 +#endif
 +
 +/* The size of `int', as computed by sizeof. */
 + at CURL_SIZEOF_INT_CODE@
 +
 +/* The size of `long', as computed by sizeof. */
 + at CURL_SIZEOF_LONG_CODE@
 +
 +/* The size of `long long', as computed by sizeof. */
 + at CURL_SIZEOF_LONG_LONG_CODE@
 +
 +/* The size of `ssize_t', as computed by sizeof. */
 + at CURL_SIZEOF_SSIZE_T_CODE@
 +
 +#define CURL_HAVE_SOCKLEN_T @CURL_HAVE_SOCKLEN_T@
 +#if CURL_HAVE_SOCKLEN_T
 +/* Integral data type used for curl_socklen_t. */
 +#define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
 +
 +/* The size of `curl_socklen_t', as computed by sizeof. */
 + at CURL_SIZEOF_CURL_SOCKLEN_T_CODE@
 +#else
 +# define CURL_TYPEOF_CURL_SOCKLEN_T int
 +# define CURL_SIZEOF_CURL_SOCKLEN_T CURL_SIZEOF_INT
 +#endif
 +
 +/* Data type definition of curl_socklen_t. */
 +typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t;
 +
 +#if CURL_SIZEOF_LONG == 8
 +# define CURL_TYPEOF_CURL_OFF_T long
 +# define CURL_SIZEOF_CURL_OFF_T 8
 +# define CURL_FORMAT_CURL_OFF_T "ld"
 +# define CURL_FORMAT_CURL_OFF_TU "lu"
 +# define CURL_FORMAT_OFF_T "%ld"
 +# define CURL_SUFFIX_CURL_OFF_T L
 +# define CURL_SUFFIX_CURL_OFF_TU UL
 +#elif CURL_SIZEOF_LONG_LONG == 8
 +# define CURL_TYPEOF_CURL_OFF_T long long
 +# define CURL_SIZEOF_CURL_OFF_T 8
 +# define CURL_FORMAT_CURL_OFF_T "lld"
 +# define CURL_FORMAT_CURL_OFF_TU "llu"
 +# define CURL_FORMAT_OFF_T "%lld"
 +# define CURL_SUFFIX_CURL_OFF_T LL
 +# define CURL_SUFFIX_CURL_OFF_TU ULL
 +#else
 +# define CURL_TYPEOF_CURL_OFF_T ssize_t
 +# define CURL_SIZEOF_CURL_OFF_T CURL_SIZEOF_SSIZE_T
 +/* TODO: need adjustment here. */
 +# define CURL_FORMAT_CURL_OFF_T "ld"
 +# define CURL_FORMAT_CURL_OFF_TU "lu"
 +# define CURL_FORMAT_OFF_T "%ld"
 +# define CURL_SUFFIX_CURL_OFF_T L
 +# define CURL_SUFFIX_CURL_OFF_TU UL
 +#endif
 +
 +/* Data type definition of curl_off_t. */
 +typedef CURL_TYPEOF_CURL_OFF_T curl_off_t;
 +
 +#endif /* __CURL_CURLBUILD_H */
diff --cc Utilities/cmcurl/include/curl/curlver.h
index a41fdef,0000000..09f612a
mode 100644,000000..100644
--- a/Utilities/cmcurl/include/curl/curlver.h
+++ b/Utilities/cmcurl/include/curl/curlver.h
@@@ -1,77 -1,0 +1,77 @@@
 +#ifndef __CURL_CURLVER_H
 +#define __CURL_CURLVER_H
 +/***************************************************************************
 + *                                  _   _ ____  _
 + *  Project                     ___| | | |  _ \| |
 + *                             / __| | | | |_) | |
 + *                            | (__| |_| |  _ <| |___
 + *                             \___|\___/|_| \_\_____|
 + *
-  * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
++ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
 + *
 + * This software is licensed as described in the file COPYING, which
 + * you should have received as part of this distribution. The terms
-  * are also available at http://curl.haxx.se/docs/copyright.html.
++ * 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.
 + *
 + ***************************************************************************/
 +
 +/* This header file contains nothing but libcurl version info, generated by
 +   a script at release-time. This was made its own header file in 7.11.2 */
 +
 +/* This is the global package copyright */
- #define LIBCURL_COPYRIGHT "1996 - 2015 Daniel Stenberg, <daniel at haxx.se>."
++#define LIBCURL_COPYRIGHT "1996 - 2016 Daniel Stenberg, <daniel at haxx.se>."
 +
 +/* This is the version number of the libcurl package from which this header
 +   file origins: */
- #define LIBCURL_VERSION "7.44.0"
++#define LIBCURL_VERSION "7.50.1"
 +
 +/* The numeric version number is also available "in parts" by using these
 +   defines: */
 +#define LIBCURL_VERSION_MAJOR 7
- #define LIBCURL_VERSION_MINOR 44
- #define LIBCURL_VERSION_PATCH 0
++#define LIBCURL_VERSION_MINOR 50
++#define LIBCURL_VERSION_PATCH 1
 +
 +/* This is the numeric version of the libcurl version number, meant for easier
 +   parsing and comparions by programs. The LIBCURL_VERSION_NUM define will
 +   always follow this syntax:
 +
 +         0xXXYYZZ
 +
 +   Where XX, YY and ZZ are the main version, release and patch numbers in
 +   hexadecimal (using 8 bits each). All three numbers are always represented
 +   using two digits.  1.2 would appear as "0x010200" while version 9.11.7
 +   appears as "0x090b07".
 +
 +   This 6-digit (24 bits) hexadecimal number does not show pre-release number,
 +   and it is always a greater number in a more recent release. It makes
 +   comparisons with greater than and less than work.
 +
 +   Note: This define is the full hex number and _does not_ use the
 +   CURL_VERSION_BITS() macro since curl's own configure script greps for it
 +   and needs it to contain the full number.
 +*/
- #define LIBCURL_VERSION_NUM 0x072C00
++#define LIBCURL_VERSION_NUM 0x073201
 +
 +/*
 + * This is the date and time when the full source package was created. The
 + * timestamp is not stored in git, as the timestamp is properly set in the
 + * tarballs by the maketgz script.
 + *
 + * The format of the date should follow this template:
 + *
 + * "Mon Feb 12 11:35:33 UTC 2007"
 + */
 +#define LIBCURL_TIMESTAMP "DEV"
 +
 +#define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|z)
 +#define CURL_AT_LEAST_VERSION(x,y,z) \
 +  (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(x, y, z))
 +
 +#endif /* __CURL_CURLVER_H */
diff --cc Utilities/cmcurl/include/curl/multi.h
index 0f1561d,0000000..f93e511
mode 100644,000000..100644
--- a/Utilities/cmcurl/include/curl/multi.h
+++ b/Utilities/cmcurl/include/curl/multi.h
@@@ -1,435 -1,0 +1,439 @@@
 +#ifndef __CURL_MULTI_H
 +#define __CURL_MULTI_H
 +/***************************************************************************
 + *                                  _   _ ____  _
 + *  Project                     ___| | | |  _ \| |
 + *                             / __| | | | |_) | |
 + *                            | (__| |_| |  _ <| |___
 + *                             \___|\___/|_| \_\_____|
 + *
-  * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
++ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
 + *
 + * This software is licensed as described in the file COPYING, which
 + * you should have received as part of this distribution. The terms
-  * are also available at http://curl.haxx.se/docs/copyright.html.
++ * 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.
 + *
 + ***************************************************************************/
 +/*
 +  This is an "external" header file. Don't give away any internals here!
 +
 +  GOALS
 +
 +  o Enable a "pull" interface. The application that uses libcurl decides where
 +    and when to ask libcurl to get/send data.
 +
 +  o Enable multiple simultaneous transfers in the same thread without making it
 +    complicated for the application.
 +
 +  o Enable the application to select() on its own file descriptors and curl's
 +    file descriptors simultaneous easily.
 +
 +*/
 +
 +/*
 + * This header file should not really need to include "curl.h" since curl.h
 + * itself includes this file and we expect user applications to do #include
 + * <curl/curl.h> without the need for especially including multi.h.
 + *
 + * For some reason we added this include here at one point, and rather than to
 + * break existing (wrongly written) libcurl applications, we leave it as-is
 + * but with this warning attached.
 + */
 +#include "curl.h"
 +
 +#ifdef  __cplusplus
 +extern "C" {
 +#endif
 +
++#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER)
++typedef struct Curl_multi CURLM;
++#else
 +typedef void CURLM;
++#endif
 +
 +typedef enum {
 +  CURLM_CALL_MULTI_PERFORM = -1, /* please call curl_multi_perform() or
 +                                    curl_multi_socket*() soon */
 +  CURLM_OK,
 +  CURLM_BAD_HANDLE,      /* the passed-in handle is not a valid CURLM handle */
 +  CURLM_BAD_EASY_HANDLE, /* an easy handle was not good/valid */
 +  CURLM_OUT_OF_MEMORY,   /* if you ever get this, you're in deep sh*t */
 +  CURLM_INTERNAL_ERROR,  /* this is a libcurl bug */
 +  CURLM_BAD_SOCKET,      /* the passed in socket argument did not match */
 +  CURLM_UNKNOWN_OPTION,  /* curl_multi_setopt() with unsupported option */
 +  CURLM_ADDED_ALREADY,   /* an easy handle already added to a multi handle was
 +                            attempted to get added - again */
 +  CURLM_LAST
 +} CURLMcode;
 +
 +/* just to make code nicer when using curl_multi_socket() you can now check
 +   for CURLM_CALL_MULTI_SOCKET too in the same style it works for
 +   curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */
 +#define CURLM_CALL_MULTI_SOCKET CURLM_CALL_MULTI_PERFORM
 +
 +/* bitmask bits for CURLMOPT_PIPELINING */
 +#define CURLPIPE_NOTHING   0L
 +#define CURLPIPE_HTTP1     1L
 +#define CURLPIPE_MULTIPLEX 2L
 +
 +typedef enum {
 +  CURLMSG_NONE, /* first, not used */
 +  CURLMSG_DONE, /* This easy handle has completed. 'result' contains
 +                   the CURLcode of the transfer */
 +  CURLMSG_LAST /* last, not used */
 +} CURLMSG;
 +
 +struct CURLMsg {
 +  CURLMSG msg;       /* what this message means */
 +  CURL *easy_handle; /* the handle it concerns */
 +  union {
 +    void *whatever;    /* message-specific data */
 +    CURLcode result;   /* return code for transfer */
 +  } data;
 +};
 +typedef struct CURLMsg CURLMsg;
 +
 +/* Based on poll(2) structure and values.
 + * We don't use pollfd and POLL* constants explicitly
 + * to cover platforms without poll(). */
 +#define CURL_WAIT_POLLIN    0x0001
 +#define CURL_WAIT_POLLPRI   0x0002
 +#define CURL_WAIT_POLLOUT   0x0004
 +
 +struct curl_waitfd {
 +  curl_socket_t fd;
 +  short events;
 +  short revents; /* not supported yet */
 +};
 +
 +/*
 + * Name:    curl_multi_init()
 + *
 + * Desc:    inititalize multi-style curl usage
 + *
 + * Returns: a new CURLM handle to use in all 'curl_multi' functions.
 + */
 +CURL_EXTERN CURLM *curl_multi_init(void);
 +
 +/*
 + * Name:    curl_multi_add_handle()
 + *
 + * Desc:    add a standard curl handle to the multi stack
 + *
 + * Returns: CURLMcode type, general multi error code.
 + */
 +CURL_EXTERN CURLMcode curl_multi_add_handle(CURLM *multi_handle,
 +                                            CURL *curl_handle);
 +
 + /*
 +  * Name:    curl_multi_remove_handle()
 +  *
 +  * Desc:    removes a curl handle from the multi stack again
 +  *
 +  * Returns: CURLMcode type, general multi error code.
 +  */
 +CURL_EXTERN CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
 +                                               CURL *curl_handle);
 +
 + /*
 +  * Name:    curl_multi_fdset()
 +  *
 +  * Desc:    Ask curl for its fd_set sets. The app can use these to select() or
 +  *          poll() on. We want curl_multi_perform() called as soon as one of
 +  *          them are ready.
 +  *
 +  * Returns: CURLMcode type, general multi error code.
 +  */
 +CURL_EXTERN CURLMcode curl_multi_fdset(CURLM *multi_handle,
 +                                       fd_set *read_fd_set,
 +                                       fd_set *write_fd_set,
 +                                       fd_set *exc_fd_set,
 +                                       int *max_fd);
 +
 +/*
 + * Name:     curl_multi_wait()
 + *
 + * Desc:     Poll on all fds within a CURLM set as well as any
 + *           additional fds passed to the function.
 + *
 + * Returns:  CURLMcode type, general multi error code.
 + */
 +CURL_EXTERN CURLMcode curl_multi_wait(CURLM *multi_handle,
 +                                      struct curl_waitfd extra_fds[],
 +                                      unsigned int extra_nfds,
 +                                      int timeout_ms,
 +                                      int *ret);
 +
 + /*
 +  * Name:    curl_multi_perform()
 +  *
 +  * Desc:    When the app thinks there's data available for curl it calls this
 +  *          function to read/write whatever there is right now. This returns
 +  *          as soon as the reads and writes are done. This function does not
 +  *          require that there actually is data available for reading or that
 +  *          data can be written, it can be called just in case. It returns
 +  *          the number of handles that still transfer data in the second
 +  *          argument's integer-pointer.
 +  *
 +  * Returns: CURLMcode type, general multi error code. *NOTE* that this only
 +  *          returns errors etc regarding the whole multi stack. There might
 +  *          still have occurred problems on invidual transfers even when this
 +  *          returns OK.
 +  */
 +CURL_EXTERN CURLMcode curl_multi_perform(CURLM *multi_handle,
 +                                         int *running_handles);
 +
 + /*
 +  * Name:    curl_multi_cleanup()
 +  *
 +  * Desc:    Cleans up and removes a whole multi stack. It does not free or
 +  *          touch any individual easy handles in any way. We need to define
 +  *          in what state those handles will be if this function is called
 +  *          in the middle of a transfer.
 +  *
 +  * Returns: CURLMcode type, general multi error code.
 +  */
 +CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle);
 +
 +/*
 + * Name:    curl_multi_info_read()
 + *
 + * Desc:    Ask the multi handle if there's any messages/informationals from
 + *          the individual transfers. Messages include informationals such as
 + *          error code from the transfer or just the fact that a transfer is
 + *          completed. More details on these should be written down as well.
 + *
 + *          Repeated calls to this function will return a new struct each
 + *          time, until a special "end of msgs" struct is returned as a signal
 + *          that there is no more to get at this point.
 + *
 + *          The data the returned pointer points to will not survive calling
 + *          curl_multi_cleanup().
 + *
 + *          The 'CURLMsg' struct is meant to be very simple and only contain
 + *          very basic information. If more involved information is wanted,
 + *          we will provide the particular "transfer handle" in that struct
 + *          and that should/could/would be used in subsequent
 + *          curl_easy_getinfo() calls (or similar). The point being that we
 + *          must never expose complex structs to applications, as then we'll
 + *          undoubtably get backwards compatibility problems in the future.
 + *
 + * Returns: A pointer to a filled-in struct, or NULL if it failed or ran out
 + *          of structs. It also writes the number of messages left in the
 + *          queue (after this read) in the integer the second argument points
 + *          to.
 + */
 +CURL_EXTERN CURLMsg *curl_multi_info_read(CURLM *multi_handle,
 +                                          int *msgs_in_queue);
 +
 +/*
 + * Name:    curl_multi_strerror()
 + *
 + * Desc:    The curl_multi_strerror function may be used to turn a CURLMcode
 + *          value into the equivalent human readable error string.  This is
 + *          useful for printing meaningful error messages.
 + *
 + * Returns: A pointer to a zero-terminated error message.
 + */
 +CURL_EXTERN const char *curl_multi_strerror(CURLMcode);
 +
 +/*
 + * Name:    curl_multi_socket() and
 + *          curl_multi_socket_all()
 + *
 + * Desc:    An alternative version of curl_multi_perform() that allows the
 + *          application to pass in one of the file descriptors that have been
 + *          detected to have "action" on them and let libcurl perform.
 + *          See man page for details.
 + */
 +#define CURL_POLL_NONE   0
 +#define CURL_POLL_IN     1
 +#define CURL_POLL_OUT    2
 +#define CURL_POLL_INOUT  3
 +#define CURL_POLL_REMOVE 4
 +
 +#define CURL_SOCKET_TIMEOUT CURL_SOCKET_BAD
 +
 +#define CURL_CSELECT_IN   0x01
 +#define CURL_CSELECT_OUT  0x02
 +#define CURL_CSELECT_ERR  0x04
 +
 +typedef int (*curl_socket_callback)(CURL *easy,      /* easy handle */
 +                                    curl_socket_t s, /* socket */
 +                                    int what,        /* see above */
 +                                    void *userp,     /* private callback
 +                                                        pointer */
 +                                    void *socketp);  /* private socket
 +                                                        pointer */
 +/*
 + * Name:    curl_multi_timer_callback
 + *
 + * Desc:    Called by libcurl whenever the library detects a change in the
 + *          maximum number of milliseconds the app is allowed to wait before
 + *          curl_multi_socket() or curl_multi_perform() must be called
 + *          (to allow libcurl's timed events to take place).
 + *
 + * Returns: The callback should return zero.
 + */
 +typedef int (*curl_multi_timer_callback)(CURLM *multi,    /* multi handle */
 +                                         long timeout_ms, /* see above */
 +                                         void *userp);    /* private callback
 +                                                             pointer */
 +
 +CURL_EXTERN CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s,
 +                                        int *running_handles);
 +
 +CURL_EXTERN CURLMcode curl_multi_socket_action(CURLM *multi_handle,
 +                                               curl_socket_t s,
 +                                               int ev_bitmask,
 +                                               int *running_handles);
 +
 +CURL_EXTERN CURLMcode curl_multi_socket_all(CURLM *multi_handle,
 +                                            int *running_handles);
 +
 +#ifndef CURL_ALLOW_OLD_MULTI_SOCKET
 +/* This macro below was added in 7.16.3 to push users who recompile to use
 +   the new curl_multi_socket_action() instead of the old curl_multi_socket()
 +*/
 +#define curl_multi_socket(x,y,z) curl_multi_socket_action(x,y,0,z)
 +#endif
 +
 +/*
 + * Name:    curl_multi_timeout()
 + *
 + * Desc:    Returns the maximum number of milliseconds the app is allowed to
 + *          wait before curl_multi_socket() or curl_multi_perform() must be
 + *          called (to allow libcurl's timed events to take place).
 + *
 + * Returns: CURLM error code.
 + */
 +CURL_EXTERN CURLMcode curl_multi_timeout(CURLM *multi_handle,
 +                                         long *milliseconds);
 +
 +#undef CINIT /* re-using the same name as in curl.h */
 +
 +#ifdef CURL_ISOCPP
 +#define CINIT(name,type,num) CURLMOPT_ ## name = CURLOPTTYPE_ ## type + num
 +#else
 +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */
 +#define LONG          CURLOPTTYPE_LONG
 +#define OBJECTPOINT   CURLOPTTYPE_OBJECTPOINT
 +#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT
 +#define OFF_T         CURLOPTTYPE_OFF_T
 +#define CINIT(name,type,number) CURLMOPT_/**/name = type + number
 +#endif
 +
 +typedef enum {
 +  /* This is the socket callback function pointer */
 +  CINIT(SOCKETFUNCTION, FUNCTIONPOINT, 1),
 +
 +  /* This is the argument passed to the socket callback */
 +  CINIT(SOCKETDATA, OBJECTPOINT, 2),
 +
 +    /* set to 1 to enable pipelining for this multi handle */
 +  CINIT(PIPELINING, LONG, 3),
 +
 +   /* This is the timer callback function pointer */
 +  CINIT(TIMERFUNCTION, FUNCTIONPOINT, 4),
 +
 +  /* This is the argument passed to the timer callback */
 +  CINIT(TIMERDATA, OBJECTPOINT, 5),
 +
 +  /* maximum number of entries in the connection cache */
 +  CINIT(MAXCONNECTS, LONG, 6),
 +
 +  /* maximum number of (pipelining) connections to one host */
 +  CINIT(MAX_HOST_CONNECTIONS, LONG, 7),
 +
 +  /* maximum number of requests in a pipeline */
 +  CINIT(MAX_PIPELINE_LENGTH, LONG, 8),
 +
 +  /* a connection with a content-length longer than this
 +     will not be considered for pipelining */
 +  CINIT(CONTENT_LENGTH_PENALTY_SIZE, OFF_T, 9),
 +
 +  /* a connection with a chunk length longer than this
 +     will not be considered for pipelining */
 +  CINIT(CHUNK_LENGTH_PENALTY_SIZE, OFF_T, 10),
 +
 +  /* a list of site names(+port) that are blacklisted from
 +     pipelining */
 +  CINIT(PIPELINING_SITE_BL, OBJECTPOINT, 11),
 +
 +  /* a list of server types that are blacklisted from
 +     pipelining */
 +  CINIT(PIPELINING_SERVER_BL, OBJECTPOINT, 12),
 +
 +  /* maximum number of open connections in total */
 +  CINIT(MAX_TOTAL_CONNECTIONS, LONG, 13),
 +
 +   /* This is the server push callback function pointer */
 +  CINIT(PUSHFUNCTION, FUNCTIONPOINT, 14),
 +
 +  /* This is the argument passed to the server push callback */
 +  CINIT(PUSHDATA, OBJECTPOINT, 15),
 +
 +  CURLMOPT_LASTENTRY /* the last unused */
 +} CURLMoption;
 +
 +
 +/*
 + * Name:    curl_multi_setopt()
 + *
 + * Desc:    Sets options for the multi handle.
 + *
 + * Returns: CURLM error code.
 + */
 +CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *multi_handle,
 +                                        CURLMoption option, ...);
 +
 +
 +/*
 + * Name:    curl_multi_assign()
 + *
 + * Desc:    This function sets an association in the multi handle between the
 + *          given socket and a private pointer of the application. This is
 + *          (only) useful for curl_multi_socket uses.
 + *
 + * Returns: CURLM error code.
 + */
 +CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle,
 +                                        curl_socket_t sockfd, void *sockp);
 +
 +
 +/*
 + * Name: curl_push_callback
 + *
 + * Desc: This callback gets called when a new stream is being pushed by the
 + *       server. It approves or denies the new stream.
 + *
 + * Returns: CURL_PUSH_OK or CURL_PUSH_DENY.
 + */
 +#define CURL_PUSH_OK   0
 +#define CURL_PUSH_DENY 1
 +
 +struct curl_pushheaders;  /* forward declaration only */
 +
 +CURL_EXTERN char *curl_pushheader_bynum(struct curl_pushheaders *h,
 +                                        size_t num);
 +CURL_EXTERN char *curl_pushheader_byname(struct curl_pushheaders *h,
 +                                         const char *name);
 +
 +typedef int (*curl_push_callback)(CURL *parent,
 +                                  CURL *easy,
 +                                  size_t num_headers,
 +                                  struct curl_pushheaders *headers,
 +                                  void *userp);
 +
 +#ifdef __cplusplus
 +} /* end of extern "C" */
 +#endif
 +
 +#endif
diff --cc Utilities/cmcurl/lib/curl_config.h.cmake
index 06201ec,0000000..20f212b
mode 100644,000000..100644
--- a/Utilities/cmcurl/lib/curl_config.h.cmake
+++ b/Utilities/cmcurl/lib/curl_config.h.cmake
@@@ -1,961 -1,0 +1,988 @@@
 +/* lib/curl_config.h.in.  Generated somehow by cmake.  */
 +
 +/* when building libcurl itself */
 +#cmakedefine BUILDING_LIBCURL 1
 +
 +/* to disable cookies support */
 +#cmakedefine CURL_DISABLE_COOKIES 1
 +
 +/* to disable cryptographic authentication */
 +#cmakedefine CURL_DISABLE_CRYPTO_AUTH 1
 +
 +/* to disable DICT */
 +#cmakedefine CURL_DISABLE_DICT 1
 +
 +/* to disable FILE */
 +#cmakedefine CURL_DISABLE_FILE 1
 +
 +/* to disable FTP */
 +#cmakedefine CURL_DISABLE_FTP 1
 +
++/* to disable GOPHER */
++#cmakedefine CURL_DISABLE_GOPHER 1
++
++/* to disable IMAP */
++#cmakedefine CURL_DISABLE_IMAP 1
++
 +/* to disable HTTP */
 +#cmakedefine CURL_DISABLE_HTTP 1
 +
 +/* to disable LDAP */
 +#cmakedefine CURL_DISABLE_LDAP 1
 +
 +/* to disable LDAPS */
 +#cmakedefine CURL_DISABLE_LDAPS 1
 +
++/* to disable POP3 */
++#cmakedefine CURL_DISABLE_POP3 1
++
 +/* to disable proxies */
 +#cmakedefine CURL_DISABLE_PROXY 1
 +
++/* to disable RTSP */
++#cmakedefine CURL_DISABLE_RTSP 1
++
++/* to disable RTMP */
++#cmakedefine CURL_DISABLE_RTMP 1
++
++/* to disable SMB */
++#cmakedefine CURL_DISABLE_SMB 1
++
++/* to disable SMTP */
++#cmakedefine CURL_DISABLE_SMTP 1
++
 +/* to disable TELNET */
 +#cmakedefine CURL_DISABLE_TELNET 1
 +
 +/* to disable TFTP */
 +#cmakedefine CURL_DISABLE_TFTP 1
 +
 +/* to disable verbose strings */
 +#cmakedefine CURL_DISABLE_VERBOSE_STRINGS 1
 +
 +/* to make a symbol visible */
 +#cmakedefine CURL_EXTERN_SYMBOL 1
 +/* Ensure using CURL_EXTERN_SYMBOL is possible */
 +#ifndef CURL_EXTERN_SYMBOL
 +#define CURL_EXTERN_SYMBOL
 +#endif
 +
 +/* Use Windows LDAP implementation */
 +#cmakedefine USE_WIN32_LDAP 1
 +
 +/* when not building a shared library */
 +#cmakedefine CURL_STATICLIB 1
 +
 +/* Set to explicitly specify we don't want to use thread-safe functions */
 +#cmakedefine DISABLED_THREADSAFE 1
 +
 +/* your Entropy Gathering Daemon socket pathname */
 +#cmakedefine EGD_SOCKET ${EGD_SOCKET}
 +
 +/* Define if you want to enable IPv6 support */
 +#cmakedefine ENABLE_IPV6 1
 +
 +/* Define to the type qualifier of arg 1 for getnameinfo. */
 +#cmakedefine GETNAMEINFO_QUAL_ARG1 ${GETNAMEINFO_QUAL_ARG1}
 +
 +/* Define to the type of arg 1 for getnameinfo. */
 +#cmakedefine GETNAMEINFO_TYPE_ARG1 ${GETNAMEINFO_TYPE_ARG1}
 +
 +/* Define to the type of arg 2 for getnameinfo. */
 +#cmakedefine GETNAMEINFO_TYPE_ARG2 ${GETNAMEINFO_TYPE_ARG2}
 +
 +/* Define to the type of args 4 and 6 for getnameinfo. */
 +#cmakedefine GETNAMEINFO_TYPE_ARG46 ${GETNAMEINFO_TYPE_ARG46}
 +
 +/* Define to the type of arg 7 for getnameinfo. */
 +#cmakedefine GETNAMEINFO_TYPE_ARG7 ${GETNAMEINFO_TYPE_ARG7}
 +
 +/* Specifies the number of arguments to getservbyport_r */
 +#cmakedefine GETSERVBYPORT_R_ARGS ${GETSERVBYPORT_R_ARGS}
 +
 +/* Specifies the size of the buffer to pass to getservbyport_r */
 +#cmakedefine GETSERVBYPORT_R_BUFSIZE ${GETSERVBYPORT_R_BUFSIZE}
 +
 +/* Define to 1 if you have the alarm function. */
 +#cmakedefine HAVE_ALARM 1
 +
 +/* Define to 1 if you have the <alloca.h> header file. */
 +#cmakedefine HAVE_ALLOCA_H 1
 +
 +/* Define to 1 if you have the <arpa/inet.h> header file. */
 +#cmakedefine HAVE_ARPA_INET_H 1
 +
 +/* Define to 1 if you have the <arpa/tftp.h> header file. */
 +#cmakedefine HAVE_ARPA_TFTP_H 1
 +
 +/* Define to 1 if you have the <assert.h> header file. */
 +#cmakedefine HAVE_ASSERT_H 1
 +
 +/* Define to 1 if you have the `basename' function. */
 +#cmakedefine HAVE_BASENAME 1
 +
 +/* Define to 1 if bool is an available type. */
 +#cmakedefine HAVE_BOOL_T 1
 +
 +/* Define to 1 if you have the clock_gettime function and monotonic timer. */
 +#cmakedefine HAVE_CLOCK_GETTIME_MONOTONIC 1
 +
 +/* Define to 1 if you have the `closesocket' function. */
 +#cmakedefine HAVE_CLOSESOCKET 1
 +
 +/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */
 +#cmakedefine HAVE_CRYPTO_CLEANUP_ALL_EX_DATA 1
 +
 +/* Define to 1 if you have the <crypto.h> header file. */
 +#cmakedefine HAVE_CRYPTO_H 1
 +
 +/* Define to 1 if you have the <des.h> header file. */
 +#cmakedefine HAVE_DES_H 1
 +
 +/* Define to 1 if you have the <dlfcn.h> header file. */
 +#cmakedefine HAVE_DLFCN_H 1
 +
 +/* Define to 1 if you have the `ENGINE_load_builtin_engines' function. */
 +#cmakedefine HAVE_ENGINE_LOAD_BUILTIN_ENGINES 1
 +
 +/* Define to 1 if you have the <errno.h> header file. */
 +#cmakedefine HAVE_ERRNO_H 1
 +
 +/* Define to 1 if you have the <err.h> header file. */
 +#cmakedefine HAVE_ERR_H 1
 +
 +/* Define to 1 if you have the fcntl function. */
 +#cmakedefine HAVE_FCNTL 1
 +
 +/* Define to 1 if you have the <fcntl.h> header file. */
 +#cmakedefine HAVE_FCNTL_H 1
 +
 +/* Define to 1 if you have a working fcntl O_NONBLOCK function. */
 +#cmakedefine HAVE_FCNTL_O_NONBLOCK 1
 +
 +/* Define to 1 if you have the fdopen function. */
 +#cmakedefine HAVE_FDOPEN 1
 +
 +/* Define to 1 if you have the `fork' function. */
 +#cmakedefine HAVE_FORK 1
 +
 +/* Define to 1 if you have the freeaddrinfo function. */
 +#cmakedefine HAVE_FREEADDRINFO 1
 +
 +/* Define to 1 if you have the freeifaddrs function. */
 +#cmakedefine HAVE_FREEIFADDRS 1
 +
 +/* Define to 1 if you have the ftruncate function. */
 +#cmakedefine HAVE_FTRUNCATE 1
 +
 +/* Define to 1 if you have a working getaddrinfo function. */
 +#cmakedefine HAVE_GETADDRINFO 1
 +
 +/* Define to 1 if you have the `geteuid' function. */
 +#cmakedefine HAVE_GETEUID 1
 +
 +/* Define to 1 if you have the gethostbyaddr function. */
 +#cmakedefine HAVE_GETHOSTBYADDR 1
 +
 +/* Define to 1 if you have the gethostbyaddr_r function. */
 +#cmakedefine HAVE_GETHOSTBYADDR_R 1
 +
 +/* gethostbyaddr_r() takes 5 args */
 +#cmakedefine HAVE_GETHOSTBYADDR_R_5 1
 +
 +/* gethostbyaddr_r() takes 7 args */
 +#cmakedefine HAVE_GETHOSTBYADDR_R_7 1
 +
 +/* gethostbyaddr_r() takes 8 args */
 +#cmakedefine HAVE_GETHOSTBYADDR_R_8 1
 +
 +/* Define to 1 if you have the gethostbyname function. */
 +#cmakedefine HAVE_GETHOSTBYNAME 1
 +
 +/* Define to 1 if you have the gethostbyname_r function. */
 +#cmakedefine HAVE_GETHOSTBYNAME_R 1
 +
 +/* gethostbyname_r() takes 3 args */
 +#cmakedefine HAVE_GETHOSTBYNAME_R_3 1
 +
 +/* gethostbyname_r() takes 5 args */
 +#cmakedefine HAVE_GETHOSTBYNAME_R_5 1
 +
 +/* gethostbyname_r() takes 6 args */
 +#cmakedefine HAVE_GETHOSTBYNAME_R_6 1
 +
 +/* Define to 1 if you have the gethostname function. */
 +#cmakedefine HAVE_GETHOSTNAME 1
 +
 +/* Define to 1 if you have a working getifaddrs function. */
 +#cmakedefine HAVE_GETIFADDRS 1
 +
 +/* Define to 1 if you have the getnameinfo function. */
 +#cmakedefine HAVE_GETNAMEINFO 1
 +
 +/* Define to 1 if you have the `getpass_r' function. */
 +#cmakedefine HAVE_GETPASS_R 1
 +
 +/* Define to 1 if you have the `getppid' function. */
 +#cmakedefine HAVE_GETPPID 1
 +
 +/* Define to 1 if you have the `getprotobyname' function. */
 +#cmakedefine HAVE_GETPROTOBYNAME 1
 +
 +/* Define to 1 if you have the `getpwuid' function. */
 +#cmakedefine HAVE_GETPWUID 1
 +
 +/* Define to 1 if you have the `getrlimit' function. */
 +#cmakedefine HAVE_GETRLIMIT 1
 +
 +/* Define to 1 if you have the getservbyport_r function. */
 +#cmakedefine HAVE_GETSERVBYPORT_R 1
 +
 +/* Define to 1 if you have the `gettimeofday' function. */
 +#cmakedefine HAVE_GETTIMEOFDAY 1
 +
 +/* Define to 1 if you have a working glibc-style strerror_r function. */
 +#cmakedefine HAVE_GLIBC_STRERROR_R 1
 +
 +/* Define to 1 if you have a working gmtime_r function. */
 +#cmakedefine HAVE_GMTIME_R 1
 +
 +/* if you have the gssapi libraries */
 +#cmakedefine HAVE_GSSAPI 1
 +
 +/* Define to 1 if you have the <gssapi/gssapi_generic.h> header file. */
 +#cmakedefine HAVE_GSSAPI_GSSAPI_GENERIC_H 1
 +
 +/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
 +#cmakedefine HAVE_GSSAPI_GSSAPI_H 1
 +
 +/* Define to 1 if you have the <gssapi/gssapi_krb5.h> header file. */
 +#cmakedefine HAVE_GSSAPI_GSSAPI_KRB5_H 1
 +
 +/* if you have the GNU gssapi libraries */
 +#cmakedefine HAVE_GSSGNU 1
 +
 +/* if you have the Heimdal gssapi libraries */
 +#cmakedefine HAVE_GSSHEIMDAL 1
 +
 +/* if you have the MIT gssapi libraries */
 +#cmakedefine HAVE_GSSMIT 1
 +
 +/* Define to 1 if you have the `idna_strerror' function. */
 +#cmakedefine HAVE_IDNA_STRERROR 1
 +
 +/* Define to 1 if you have the `idn_free' function. */
 +#cmakedefine HAVE_IDN_FREE 1
 +
 +/* Define to 1 if you have the <idn-free.h> header file. */
 +#cmakedefine HAVE_IDN_FREE_H 1
 +
 +/* Define to 1 if you have the <ifaddrs.h> header file. */
 +#cmakedefine HAVE_IFADDRS_H 1
 +
 +/* Define to 1 if you have the `inet_addr' function. */
 +#cmakedefine HAVE_INET_ADDR 1
 +
 +/* Define to 1 if you have the inet_ntoa_r function. */
 +#cmakedefine HAVE_INET_NTOA_R 1
 +
 +/* inet_ntoa_r() takes 2 args */
 +#cmakedefine HAVE_INET_NTOA_R_2 1
 +
 +/* inet_ntoa_r() takes 3 args */
 +#cmakedefine HAVE_INET_NTOA_R_3 1
 +
 +/* Define to 1 if you have a IPv6 capable working inet_ntop function. */
 +#cmakedefine HAVE_INET_NTOP 1
 +
 +/* Define to 1 if you have a IPv6 capable working inet_pton function. */
 +#cmakedefine HAVE_INET_PTON 1
 +
 +/* Define to 1 if you have the <inttypes.h> header file. */
 +#cmakedefine HAVE_INTTYPES_H 1
 +
 +/* Define to 1 if you have the ioctl function. */
 +#cmakedefine HAVE_IOCTL 1
 +
 +/* Define to 1 if you have the ioctlsocket function. */
 +#cmakedefine HAVE_IOCTLSOCKET 1
 +
 +/* Define to 1 if you have the IoctlSocket camel case function. */
 +#cmakedefine HAVE_IOCTLSOCKET_CAMEL 1
 +
 +/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function.
 +   */
 +#cmakedefine HAVE_IOCTLSOCKET_CAMEL_FIONBIO 1
 +
 +/* Define to 1 if you have a working ioctlsocket FIONBIO function. */
 +#cmakedefine HAVE_IOCTLSOCKET_FIONBIO 1
 +
 +/* Define to 1 if you have a working ioctl FIONBIO function. */
 +#cmakedefine HAVE_IOCTL_FIONBIO 1
 +
 +/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */
 +#cmakedefine HAVE_IOCTL_SIOCGIFADDR 1
 +
 +/* Define to 1 if you have the <io.h> header file. */
 +#cmakedefine HAVE_IO_H 1
 +
 +/* if you have the Kerberos4 libraries (including -ldes) */
 +#cmakedefine HAVE_KRB4 1
 +
 +/* Define to 1 if you have the `krb_get_our_ip_for_realm' function. */
 +#cmakedefine HAVE_KRB_GET_OUR_IP_FOR_REALM 1
 +
 +/* Define to 1 if you have the <krb.h> header file. */
 +#cmakedefine HAVE_KRB_H 1
 +
 +/* Define to 1 if you have the lber.h header file. */
 +#cmakedefine HAVE_LBER_H 1
 +
 +/* Define to 1 if you have the ldapssl.h header file. */
 +#cmakedefine HAVE_LDAPSSL_H 1
 +
 +/* Define to 1 if you have the ldap.h header file. */
 +#cmakedefine HAVE_LDAP_H 1
 +
 +/* Use LDAPS implementation */
 +#cmakedefine HAVE_LDAP_SSL 1
 +
 +/* Define to 1 if you have the ldap_ssl.h header file. */
 +#cmakedefine HAVE_LDAP_SSL_H 1
 +
 +/* Define to 1 if you have the `ldap_url_parse' function. */
 +#cmakedefine HAVE_LDAP_URL_PARSE 1
 +
 +/* Define to 1 if you have the <libgen.h> header file. */
 +#cmakedefine HAVE_LIBGEN_H 1
 +
 +/* Define to 1 if you have the `idn' library (-lidn). */
 +#cmakedefine HAVE_LIBIDN 1
 +
 +/* Define to 1 if you have the `resolv' library (-lresolv). */
 +#cmakedefine HAVE_LIBRESOLV 1
 +
 +/* Define to 1 if you have the `resolve' library (-lresolve). */
 +#cmakedefine HAVE_LIBRESOLVE 1
 +
 +/* Define to 1 if you have the `socket' library (-lsocket). */
 +#cmakedefine HAVE_LIBSOCKET 1
 +
 +/* Define to 1 if you have the `ssh2' library (-lssh2). */
 +#cmakedefine HAVE_LIBSSH2 1
 +
 +/* Define to 1 if libssh2 provides `libssh2_version'. */
 +#cmakedefine HAVE_LIBSSH2_VERSION 1
 +
 +/* Define to 1 if libssh2 provides `libssh2_init'. */
 +#cmakedefine HAVE_LIBSSH2_INIT 1
 +
 +/* Define to 1 if libssh2 provides `libssh2_exit'. */
 +#cmakedefine HAVE_LIBSSH2_EXIT 1
 +
 +/* Define to 1 if libssh2 provides `libssh2_scp_send64'. */
 +#cmakedefine HAVE_LIBSSH2_SCP_SEND64 1
 +
 +/* Define to 1 if libssh2 provides `libssh2_session_handshake'. */
 +#cmakedefine HAVE_LIBSSH2_SESSION_HANDSHAKE 1
 +
 +/* Define to 1 if you have the <libssh2.h> header file. */
 +#cmakedefine HAVE_LIBSSH2_H 1
 +
 +/* Define to 1 if you have the `ssl' library (-lssl). */
 +#cmakedefine HAVE_LIBSSL 1
 +
 +/* if zlib is available */
 +#cmakedefine HAVE_LIBZ 1
 +
 +/* Define to 1 if you have the <limits.h> header file. */
 +#cmakedefine HAVE_LIMITS_H 1
 +
 +/* if your compiler supports LL */
 +#cmakedefine HAVE_LL 1
 +
 +/* Define to 1 if you have the <locale.h> header file. */
 +#cmakedefine HAVE_LOCALE_H 1
 +
 +/* Define to 1 if you have a working localtime_r function. */
 +#cmakedefine HAVE_LOCALTIME_R 1
 +
 +/* Define to 1 if the compiler supports the 'long long' data type. */
 +#cmakedefine HAVE_LONGLONG 1
 +
 +/* Define to 1 if you have the malloc.h header file. */
 +#cmakedefine HAVE_MALLOC_H 1
 +
 +/* Define to 1 if you have the <memory.h> header file. */
 +#cmakedefine HAVE_MEMORY_H 1
 +
 +/* Define to 1 if you have the MSG_NOSIGNAL flag. */
 +#cmakedefine HAVE_MSG_NOSIGNAL 1
 +
 +/* Define to 1 if you have the <netdb.h> header file. */
 +#cmakedefine HAVE_NETDB_H 1
 +
 +/* Define to 1 if you have the <netinet/in.h> header file. */
 +#cmakedefine HAVE_NETINET_IN_H 1
 +
 +/* Define to 1 if you have the <netinet/tcp.h> header file. */
 +#cmakedefine HAVE_NETINET_TCP_H 1
 +
 +/* Define to 1 if you have the <net/if.h> header file. */
 +#cmakedefine HAVE_NET_IF_H 1
 +
 +/* Define to 1 if NI_WITHSCOPEID exists and works. */
 +#cmakedefine HAVE_NI_WITHSCOPEID 1
 +
 +/* if you have an old MIT gssapi library, lacking GSS_C_NT_HOSTBASED_SERVICE */
 +#cmakedefine HAVE_OLD_GSSMIT 1
 +
 +/* Define to 1 if you have the <openssl/crypto.h> header file. */
 +#cmakedefine HAVE_OPENSSL_CRYPTO_H 1
 +
 +/* Define to 1 if you have the <openssl/engine.h> header file. */
 +#cmakedefine HAVE_OPENSSL_ENGINE_H 1
 +
 +/* Define to 1 if you have the <openssl/err.h> header file. */
 +#cmakedefine HAVE_OPENSSL_ERR_H 1
 +
 +/* Define to 1 if you have the <openssl/pem.h> header file. */
 +#cmakedefine HAVE_OPENSSL_PEM_H 1
 +
 +/* Define to 1 if you have the <openssl/pkcs12.h> header file. */
 +#cmakedefine HAVE_OPENSSL_PKCS12_H 1
 +
 +/* Define to 1 if you have the <openssl/rsa.h> header file. */
 +#cmakedefine HAVE_OPENSSL_RSA_H 1
 +
 +/* Define to 1 if you have the <openssl/ssl.h> header file. */
 +#cmakedefine HAVE_OPENSSL_SSL_H 1
 +
 +/* Define to 1 if you have the <openssl/x509.h> header file. */
 +#cmakedefine HAVE_OPENSSL_X509_H 1
 +
 +/* Define to 1 if you have the <pem.h> header file. */
 +#cmakedefine HAVE_PEM_H 1
 +
 +/* Define to 1 if you have the `perror' function. */
 +#cmakedefine HAVE_PERROR 1
 +
 +/* Define to 1 if you have the `pipe' function. */
 +#cmakedefine HAVE_PIPE 1
 +
 +/* Define to 1 if you have a working poll function. */
 +#cmakedefine HAVE_POLL 1
 +
 +/* If you have a fine poll */
 +#cmakedefine HAVE_POLL_FINE 1
 +
 +/* Define to 1 if you have the <poll.h> header file. */
 +#cmakedefine HAVE_POLL_H 1
 +
 +/* Define to 1 if you have a working POSIX-style strerror_r function. */
 +#cmakedefine HAVE_POSIX_STRERROR_R 1
 +
 +/* Define to 1 if you have the <pthread.h> header file */
 +#cmakedefine HAVE_PTHREAD_H 1
 +
 +/* Define to 1 if you have the <pwd.h> header file. */
 +#cmakedefine HAVE_PWD_H 1
 +
 +/* Define to 1 if you have the `RAND_egd' function. */
 +#cmakedefine HAVE_RAND_EGD 1
 +
 +/* Define to 1 if you have the `RAND_screen' function. */
 +#cmakedefine HAVE_RAND_SCREEN 1
 +
 +/* Define to 1 if you have the `RAND_status' function. */
 +#cmakedefine HAVE_RAND_STATUS 1
 +
 +/* Define to 1 if you have the recv function. */
 +#cmakedefine HAVE_RECV 1
 +
 +/* Define to 1 if you have the recvfrom function. */
 +#cmakedefine HAVE_RECVFROM 1
 +
 +/* Define to 1 if you have the <rsa.h> header file. */
 +#cmakedefine HAVE_RSA_H 1
 +
 +/* Define to 1 if you have the select function. */
 +#cmakedefine HAVE_SELECT 1
 +
 +/* Define to 1 if you have the send function. */
 +#cmakedefine HAVE_SEND 1
 +
 +/* Define to 1 if you have the <setjmp.h> header file. */
 +#cmakedefine HAVE_SETJMP_H 1
 +
 +/* Define to 1 if you have the `setlocale' function. */
 +#cmakedefine HAVE_SETLOCALE 1
 +
 +/* Define to 1 if you have the `setmode' function. */
 +#cmakedefine HAVE_SETMODE 1
 +
 +/* Define to 1 if you have the `setrlimit' function. */
 +#cmakedefine HAVE_SETRLIMIT 1
 +
 +/* Define to 1 if you have the setsockopt function. */
 +#cmakedefine HAVE_SETSOCKOPT 1
 +
 +/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */
 +#cmakedefine HAVE_SETSOCKOPT_SO_NONBLOCK 1
 +
 +/* Define to 1 if you have the <sgtty.h> header file. */
 +#cmakedefine HAVE_SGTTY_H 1
 +
 +/* Define to 1 if you have the sigaction function. */
 +#cmakedefine HAVE_SIGACTION 1
 +
 +/* Define to 1 if you have the siginterrupt function. */
 +#cmakedefine HAVE_SIGINTERRUPT 1
 +
 +/* Define to 1 if you have the signal function. */
 +#cmakedefine HAVE_SIGNAL 1
 +
 +/* Define to 1 if you have the <signal.h> header file. */
 +#cmakedefine HAVE_SIGNAL_H 1
 +
 +/* Define to 1 if you have the sigsetjmp function or macro. */
 +#cmakedefine HAVE_SIGSETJMP 1
 +
 +/* Define to 1 if sig_atomic_t is an available typedef. */
 +#cmakedefine HAVE_SIG_ATOMIC_T 1
 +
 +/* Define to 1 if sig_atomic_t is already defined as volatile. */
 +#cmakedefine HAVE_SIG_ATOMIC_T_VOLATILE 1
 +
 +/* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */
 +#cmakedefine HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
 +
 +/* Define to 1 if you have the `socket' function. */
 +#cmakedefine HAVE_SOCKET 1
 +
 +/* Define to 1 if you have the `SSL_get_shutdown' function. */
 +#cmakedefine HAVE_SSL_GET_SHUTDOWN 1
 +
 +/* Define to 1 if you have the <ssl.h> header file. */
 +#cmakedefine HAVE_SSL_H 1
 +
 +/* Define to 1 if you have the <stdbool.h> header file. */
 +#cmakedefine HAVE_STDBOOL_H 1
 +
 +/* Define to 1 if you have the <stdint.h> header file. */
 +#cmakedefine HAVE_STDINT_H 1
 +
 +/* Define to 1 if you have the <stdio.h> header file. */
 +#cmakedefine HAVE_STDIO_H 1
 +
 +/* Define to 1 if you have the <stdlib.h> header file. */
 +#cmakedefine HAVE_STDLIB_H 1
 +
 +/* Define to 1 if you have the strcasecmp function. */
 +#cmakedefine HAVE_STRCASECMP 1
 +
 +/* Define to 1 if you have the strcasestr function. */
 +#cmakedefine HAVE_STRCASESTR 1
 +
 +/* Define to 1 if you have the strcmpi function. */
 +#cmakedefine HAVE_STRCMPI 1
 +
 +/* Define to 1 if you have the strdup function. */
 +#cmakedefine HAVE_STRDUP 1
 +
 +/* Define to 1 if you have the strerror_r function. */
 +#cmakedefine HAVE_STRERROR_R 1
 +
 +/* Define to 1 if you have the stricmp function. */
 +#cmakedefine HAVE_STRICMP 1
 +
 +/* Define to 1 if you have the <strings.h> header file. */
 +#cmakedefine HAVE_STRINGS_H 1
 +
 +/* Define to 1 if you have the <string.h> header file. */
 +#cmakedefine HAVE_STRING_H 1
 +
 +/* Define to 1 if you have the strlcat function. */
 +#cmakedefine HAVE_STRLCAT 1
 +
 +/* Define to 1 if you have the `strlcpy' function. */
 +#cmakedefine HAVE_STRLCPY 1
 +
 +/* Define to 1 if you have the strncasecmp function. */
 +#cmakedefine HAVE_STRNCASECMP 1
 +
 +/* Define to 1 if you have the strncmpi function. */
 +#cmakedefine HAVE_STRNCMPI 1
 +
 +/* Define to 1 if you have the strnicmp function. */
 +#cmakedefine HAVE_STRNICMP 1
 +
 +/* Define to 1 if you have the <stropts.h> header file. */
 +#cmakedefine HAVE_STROPTS_H 1
 +
 +/* Define to 1 if you have the strstr function. */
 +#cmakedefine HAVE_STRSTR 1
 +
 +/* Define to 1 if you have the strtok_r function. */
 +#cmakedefine HAVE_STRTOK_R 1
 +
 +/* Define to 1 if you have the strtoll function. */
 +#cmakedefine HAVE_STRTOLL 1
 +
 +/* if struct sockaddr_storage is defined */
 +#cmakedefine HAVE_STRUCT_SOCKADDR_STORAGE 1
 +
 +/* Define to 1 if you have the timeval struct. */
 +#cmakedefine HAVE_STRUCT_TIMEVAL 1
 +
 +/* Define to 1 if you have the <sys/filio.h> header file. */
 +#cmakedefine HAVE_SYS_FILIO_H 1
 +
 +/* Define to 1 if you have the <sys/ioctl.h> header file. */
 +#cmakedefine HAVE_SYS_IOCTL_H 1
 +
 +/* Define to 1 if you have the <sys/param.h> header file. */
 +#cmakedefine HAVE_SYS_PARAM_H 1
 +
 +/* Define to 1 if you have the <sys/poll.h> header file. */
 +#cmakedefine HAVE_SYS_POLL_H 1
 +
 +/* Define to 1 if you have the <sys/resource.h> header file. */
 +#cmakedefine HAVE_SYS_RESOURCE_H 1
 +
 +/* Define to 1 if you have the <sys/select.h> header file. */
 +#cmakedefine HAVE_SYS_SELECT_H 1
 +
 +/* Define to 1 if you have the <sys/socket.h> header file. */
 +#cmakedefine HAVE_SYS_SOCKET_H 1
 +
 +/* Define to 1 if you have the <sys/sockio.h> header file. */
 +#cmakedefine HAVE_SYS_SOCKIO_H 1
 +
 +/* Define to 1 if you have the <sys/stat.h> header file. */
 +#cmakedefine HAVE_SYS_STAT_H 1
 +
 +/* Define to 1 if you have the <sys/time.h> header file. */
 +#cmakedefine HAVE_SYS_TIME_H 1
 +
 +/* Define to 1 if you have the <sys/types.h> header file. */
 +#cmakedefine HAVE_SYS_TYPES_H 1
 +
 +/* Define to 1 if you have the <sys/uio.h> header file. */
 +#cmakedefine HAVE_SYS_UIO_H 1
 +
 +/* Define to 1 if you have the <sys/un.h> header file. */
 +#cmakedefine HAVE_SYS_UN_H 1
 +
 +/* Define to 1 if you have the <sys/utime.h> header file. */
 +#cmakedefine HAVE_SYS_UTIME_H 1
 +
 +/* Define to 1 if you have the <termios.h> header file. */
 +#cmakedefine HAVE_TERMIOS_H 1
 +
 +/* Define to 1 if you have the <termio.h> header file. */
 +#cmakedefine HAVE_TERMIO_H 1
 +
 +/* Define to 1 if you have the <time.h> header file. */
 +#cmakedefine HAVE_TIME_H 1
 +
 +/* Define to 1 if you have the <tld.h> header file. */
 +#cmakedefine HAVE_TLD_H 1
 +
 +/* Define to 1 if you have the `tld_strerror' function. */
 +#cmakedefine HAVE_TLD_STRERROR 1
 +
 +/* Define to 1 if you have the `uname' function. */
 +#cmakedefine HAVE_UNAME 1
 +
 +/* Define to 1 if you have the <unistd.h> header file. */
 +#cmakedefine HAVE_UNISTD_H 1
 +
 +/* Define to 1 if you have the `utime' function. */
 +#cmakedefine HAVE_UTIME 1
 +
 +/* Define to 1 if you have the <utime.h> header file. */
 +#cmakedefine HAVE_UTIME_H 1
 +
 +/* Define to 1 if compiler supports C99 variadic macro style. */
 +#cmakedefine HAVE_VARIADIC_MACROS_C99 1
 +
 +/* Define to 1 if compiler supports old gcc variadic macro style. */
 +#cmakedefine HAVE_VARIADIC_MACROS_GCC 1
 +
 +/* Define to 1 if you have the winber.h header file. */
 +#cmakedefine HAVE_WINBER_H 1
 +
 +/* Define to 1 if you have the windows.h header file. */
 +#cmakedefine HAVE_WINDOWS_H 1
 +
 +/* Define to 1 if you have the winldap.h header file. */
 +#cmakedefine HAVE_WINLDAP_H 1
 +
 +/* Define to 1 if you have the winsock2.h header file. */
 +#cmakedefine HAVE_WINSOCK2_H 1
 +
 +/* Define to 1 if you have the winsock.h header file. */
 +#cmakedefine HAVE_WINSOCK_H 1
 +
 +/* Define this symbol if your OS supports changing the contents of argv */
 +#cmakedefine HAVE_WRITABLE_ARGV 1
 +
 +/* Define to 1 if you have the writev function. */
 +#cmakedefine HAVE_WRITEV 1
 +
 +/* Define to 1 if you have the ws2tcpip.h header file. */
 +#cmakedefine HAVE_WS2TCPIP_H 1
 +
 +/* Define to 1 if you have the <x509.h> header file. */
 +#cmakedefine HAVE_X509_H 1
 +
 +/* Define if you have the <process.h> header file. */
 +#cmakedefine HAVE_PROCESS_H 1
 +
 +/* if you have the zlib.h header file */
 +#cmakedefine HAVE_ZLIB_H 1
 +
 +/* Define to the sub-directory in which libtool stores uninstalled libraries.
 +   */
 +#cmakedefine LT_OBJDIR ${LT_OBJDIR}
 +
 +/* If you lack a fine basename() prototype */
 +#cmakedefine NEED_BASENAME_PROTO 1
 +
 +/* Define to 1 if you need the lber.h header file even with ldap.h */
 +#cmakedefine NEED_LBER_H 1
 +
 +/* Define to 1 if you need the malloc.h header file even with stdlib.h */
 +#cmakedefine NEED_MALLOC_H 1
 +
 +/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */
 +#cmakedefine NEED_REENTRANT 1
 +
 +/* cpu-machine-OS */
 +#cmakedefine OS ${OS}
 +
 +/* Name of package */
 +#cmakedefine PACKAGE ${PACKAGE}
 +
 +/* Define to the address where bug reports for this package should be sent. */
 +#cmakedefine PACKAGE_BUGREPORT ${PACKAGE_BUGREPORT}
 +
 +/* Define to the full name of this package. */
 +#cmakedefine PACKAGE_NAME ${PACKAGE_NAME}
 +
 +/* Define to the full name and version of this package. */
 +#cmakedefine PACKAGE_STRING ${PACKAGE_STRING}
 +
 +/* Define to the one symbol short name of this package. */
 +#cmakedefine PACKAGE_TARNAME ${PACKAGE_TARNAME}
 +
 +/* Define to the version of this package. */
 +#cmakedefine PACKAGE_VERSION ${PACKAGE_VERSION}
 +
 +/* a suitable file to read random data from */
 +#cmakedefine RANDOM_FILE "${RANDOM_FILE}"
 +
 +/* Define to the type of arg 1 for recvfrom. */
 +#cmakedefine RECVFROM_TYPE_ARG1 ${RECVFROM_TYPE_ARG1}
 +
 +/* Define to the type pointed by arg 2 for recvfrom. */
 +#cmakedefine RECVFROM_TYPE_ARG2 ${RECVFROM_TYPE_ARG2}
 +
 +/* Define to 1 if the type pointed by arg 2 for recvfrom is void. */
 +#cmakedefine RECVFROM_TYPE_ARG2_IS_VOID 1
 +
 +/* Define to the type of arg 3 for recvfrom. */
 +#cmakedefine RECVFROM_TYPE_ARG3 ${RECVFROM_TYPE_ARG3}
 +
 +/* Define to the type of arg 4 for recvfrom. */
 +#cmakedefine RECVFROM_TYPE_ARG4 ${RECVFROM_TYPE_ARG4}
 +
 +/* Define to the type pointed by arg 5 for recvfrom. */
 +#cmakedefine RECVFROM_TYPE_ARG5 ${RECVFROM_TYPE_ARG5}
 +
 +/* Define to 1 if the type pointed by arg 5 for recvfrom is void. */
 +#cmakedefine RECVFROM_TYPE_ARG5_IS_VOID 1
 +
 +/* Define to the type pointed by arg 6 for recvfrom. */
 +#cmakedefine RECVFROM_TYPE_ARG6 ${RECVFROM_TYPE_ARG6}
 +
 +/* Define to 1 if the type pointed by arg 6 for recvfrom is void. */
 +#cmakedefine RECVFROM_TYPE_ARG6_IS_VOID 1
 +
 +/* Define to the function return type for recvfrom. */
 +#cmakedefine RECVFROM_TYPE_RETV ${RECVFROM_TYPE_RETV}
 +
 +/* Define to the type of arg 1 for recv. */
 +#cmakedefine RECV_TYPE_ARG1 ${RECV_TYPE_ARG1}
 +
 +/* Define to the type of arg 2 for recv. */
 +#cmakedefine RECV_TYPE_ARG2 ${RECV_TYPE_ARG2}
 +
 +/* Define to the type of arg 3 for recv. */
 +#cmakedefine RECV_TYPE_ARG3 ${RECV_TYPE_ARG3}
 +
 +/* Define to the type of arg 4 for recv. */
 +#cmakedefine RECV_TYPE_ARG4 ${RECV_TYPE_ARG4}
 +
 +/* Define to the function return type for recv. */
 +#cmakedefine RECV_TYPE_RETV ${RECV_TYPE_RETV}
 +
 +/* Define as the return type of signal handlers (`int' or `void'). */
 +#cmakedefine RETSIGTYPE ${RETSIGTYPE}
 +
 +/* Define to the type qualifier of arg 5 for select. */
 +#cmakedefine SELECT_QUAL_ARG5 ${SELECT_QUAL_ARG5}
 +
 +/* Define to the type of arg 1 for select. */
 +#cmakedefine SELECT_TYPE_ARG1 ${SELECT_TYPE_ARG1}
 +
 +/* Define to the type of args 2, 3 and 4 for select. */
 +#cmakedefine SELECT_TYPE_ARG234 ${SELECT_TYPE_ARG234}
 +
 +/* Define to the type of arg 5 for select. */
 +#cmakedefine SELECT_TYPE_ARG5 ${SELECT_TYPE_ARG5}
 +
 +/* Define to the function return type for select. */
 +#cmakedefine SELECT_TYPE_RETV ${SELECT_TYPE_RETV}
 +
 +/* Define to the type qualifier of arg 2 for send. */
 +#cmakedefine SEND_QUAL_ARG2 ${SEND_QUAL_ARG2}
 +
 +/* Define to the type of arg 1 for send. */
 +#cmakedefine SEND_TYPE_ARG1 ${SEND_TYPE_ARG1}
 +
 +/* Define to the type of arg 2 for send. */
 +#cmakedefine SEND_TYPE_ARG2 ${SEND_TYPE_ARG2}
 +
 +/* Define to the type of arg 3 for send. */
 +#cmakedefine SEND_TYPE_ARG3 ${SEND_TYPE_ARG3}
 +
 +/* Define to the type of arg 4 for send. */
 +#cmakedefine SEND_TYPE_ARG4 ${SEND_TYPE_ARG4}
 +
 +/* Define to the function return type for send. */
 +#cmakedefine SEND_TYPE_RETV ${SEND_TYPE_RETV}
 +
 +/* The size of `int', as computed by sizeof. */
 + at SIZEOF_INT_CODE@
 +
 +/* The size of `short', as computed by sizeof. */
 + at SIZEOF_SHORT_CODE@
 +
 +/* The size of `long', as computed by sizeof. */
 + at SIZEOF_LONG_CODE@
 +
 +/* The size of `off_t', as computed by sizeof. */
 + at SIZEOF_OFF_T_CODE@
 +
 +/* The size of `size_t', as computed by sizeof. */
 + at SIZEOF_SIZE_T_CODE@
 +
 +/* The size of `ssize_t', as computed by sizeof. */
 + at SIZEOF_SSIZE_T_CODE@
 +
 +/* The size of `time_t', as computed by sizeof. */
 + at SIZEOF_TIME_T_CODE@
 +
 +/* Define to 1 if you have the ANSI C header files. */
 +#cmakedefine STDC_HEADERS 1
 +
 +/* Define to the type of arg 3 for strerror_r. */
 +#cmakedefine STRERROR_R_TYPE_ARG3 ${STRERROR_R_TYPE_ARG3}
 +
 +/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
 +#cmakedefine TIME_WITH_SYS_TIME 1
 +
 +/* Define if you want to enable c-ares support */
 +#cmakedefine USE_ARES 1
 +
 +/* Define if you want to enable POSIX threaded DNS lookup */
 +#cmakedefine USE_THREADS_POSIX 1
 +
 +/* Define to disable non-blocking sockets. */
 +#cmakedefine USE_BLOCKING_SOCKETS 1
 +
 +/* if GnuTLS is enabled */
 +#cmakedefine USE_GNUTLS 1
 +
 +/* if PolarSSL is enabled */
 +#cmakedefine USE_POLARSSL 1
 +
++/* if mbedTLS is enabled */
++#cmakedefine USE_MBEDTLS 1
++
 +/* if libSSH2 is in use */
 +#cmakedefine USE_LIBSSH2 1
 +
 +/* If you want to build curl with the built-in manual */
 +#cmakedefine USE_MANUAL 1
 +
 +/* if NSS is enabled */
 +#cmakedefine USE_NSS 1
 +
 +/* if you want to use OpenLDAP code instead of legacy ldap implementation */
 +#cmakedefine USE_OPENLDAP 1
 +
 +/* if OpenSSL is in use */
 +#cmakedefine USE_OPENSSL 1
 +
 +/* if Unix domain sockets are enabled  */
 +#cmakedefine USE_UNIX_SOCKETS
 +
 +/* to enable SSPI support */
 +#cmakedefine USE_WINDOWS_SSPI 1
 +
++/* to enable Windows SSL  */
++#cmakedefine USE_SCHANNEL 1
++
 +/* Define to 1 if using yaSSL in OpenSSL compatibility mode. */
 +#cmakedefine USE_YASSLEMUL 1
 +
 +/* Version number of package */
 +#cmakedefine VERSION ${VERSION}
 +
 +/* Define to avoid automatic inclusion of winsock.h */
 +#cmakedefine WIN32_LEAN_AND_MEAN 1
 +
 +/* Define to 1 if OS is AIX. */
 +#ifndef _ALL_SOURCE
 +#  undef _ALL_SOURCE
 +#endif
 +
 +/* Number of bits in a file offset, on hosts where this is settable. */
 +#cmakedefine _FILE_OFFSET_BITS ${_FILE_OFFSET_BITS}
 +
 +/* Define for large files, on AIX-style hosts. */
 +#cmakedefine _LARGE_FILES ${_LARGE_FILES}
 +
 +/* define this if you need it to compile thread-safe code */
 +#cmakedefine _THREAD_SAFE ${_THREAD_SAFE}
 +
 +/* Define to empty if `const' does not conform to ANSI C. */
 +#cmakedefine const ${const}
 +
 +/* Type to use in place of in_addr_t when system does not provide it. */
 +#cmakedefine in_addr_t ${in_addr_t}
 +
 +/* Define to `__inline__' or `__inline' if that's what the C compiler
 +   calls it, or to nothing if 'inline' is not supported under any name.  */
 +#ifndef __cplusplus
 +#undef inline
 +#endif
 +
 +/* Define to `unsigned int' if <sys/types.h> does not define. */
 +#cmakedefine size_t ${size_t}
 +
 +/* the signed version of size_t */
 +#ifndef SIZEOF_SSIZE_T
 +# if SIZEOF_LONG == SIZEOF_SIZE_T
 +   typedef long ssize_t;
 +# elif SIZEOF_LONG_LONG == SIZEOF_SIZE_T
 +   typedef long long ssize_t;
 +# elif SIZEOF___INT64 == SIZEOF_SIZE_T
 +   typedef __int64 ssize_t;
 +# else
 +   typedef int ssize_t;
 +# endif
 +#endif
diff --cc Utilities/cmcurl/lib/curl_setup.h
index 19c1baf,0000000..2122220
mode 100644,000000..100644
--- a/Utilities/cmcurl/lib/curl_setup.h
+++ b/Utilities/cmcurl/lib/curl_setup.h
@@@ -1,745 -1,0 +1,764 @@@
 +#ifndef HEADER_CURL_SETUP_H
 +#define HEADER_CURL_SETUP_H
 +/***************************************************************************
 + *                                  _   _ ____  _
 + *  Project                     ___| | | |  _ \| |
 + *                             / __| | | | |_) | |
 + *                            | (__| |_| |  _ <| |___
 + *                             \___|\___/|_| \_\_____|
 + *
-  * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
++ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
 + *
 + * This software is licensed as described in the file COPYING, which
 + * you should have received as part of this distribution. The terms
-  * are also available at http://curl.haxx.se/docs/copyright.html.
++ * 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.
 + *
 + ***************************************************************************/
 +
 +/*
 + * Define WIN32 when build target is Win32 API
 + */
 +
 +#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) && \
 +    !defined(__SYMBIAN32__)
 +#define WIN32
 +#endif
 +
 +/*
 + * Include configuration script results or hand-crafted
 + * configuration file for platforms which lack config tool.
 + */
 +
 +#ifdef HAVE_CONFIG_H
 +
 +#include "curl_config.h"
 +
 +#else /* HAVE_CONFIG_H */
 +
 +#ifdef _WIN32_WCE
 +#  include "config-win32ce.h"
 +#else
 +#  ifdef WIN32
 +#    include "config-win32.h"
 +#  endif
 +#endif
 +
 +#if defined(macintosh) && defined(__MRC__)
 +#  include "config-mac.h"
 +#endif
 +
 +#ifdef __riscos__
 +#  include "config-riscos.h"
 +#endif
 +
 +#ifdef __AMIGA__
 +#  include "config-amigaos.h"
 +#endif
 +
 +#ifdef __SYMBIAN32__
 +#  include "config-symbian.h"
 +#endif
 +
 +#ifdef __OS400__
 +#  include "config-os400.h"
 +#endif
 +
 +#ifdef TPF
 +#  include "config-tpf.h"
 +#endif
 +
 +#ifdef __VXWORKS__
 +#  include "config-vxworks.h"
 +#endif
 +
 +#endif /* HAVE_CONFIG_H */
 +
 +#if defined(_MSC_VER)
 +# pragma warning(push,1)
 +#endif
 +
 +/* ================================================================ */
 +/* Definition of preprocessor macros/symbols which modify compiler  */
 +/* behavior or generated code characteristics must be done here,   */
 +/* as appropriate, before any system header file is included. It is */
 +/* also possible to have them defined in the config file included   */
 +/* before this point. As a result of all this we frown inclusion of */
 +/* system header files in our config files, avoid this at any cost. */
 +/* ================================================================ */
 +
 +/*
 + * AIX 4.3 and newer needs _THREAD_SAFE defined to build
 + * proper reentrant code. Others may also need it.
 + */
 +
 +#ifdef NEED_THREAD_SAFE
 +#  ifndef _THREAD_SAFE
 +#    define _THREAD_SAFE
 +#  endif
 +#endif
 +
 +/*
 + * Tru64 needs _REENTRANT set for a few function prototypes and
 + * things to appear in the system header files. Unixware needs it
 + * to build proper reentrant code. Others may also need it.
 + */
 +
 +#ifdef NEED_REENTRANT
 +#  ifndef _REENTRANT
 +#    define _REENTRANT
 +#  endif
 +#endif
 +
 +/* Solaris needs this to get a POSIX-conformant getpwuid_r */
 +#if defined(sun) || defined(__sun)
 +#  ifndef _POSIX_PTHREAD_SEMANTICS
 +#    define _POSIX_PTHREAD_SEMANTICS 1
 +#  endif
 +#endif
 +
 +/* ================================================================ */
 +/*  If you need to include a system header file for your platform,  */
 +/*  please, do it beyond the point further indicated in this file.  */
 +/* ================================================================ */
 +
 +/*
 + * libcurl's external interface definitions are also used internally,
 + * and might also include required system header files to define them.
 + */
 +
 +#include <curl/curlbuild.h>
 +
 +/*
 + * Compile time sanity checks must also be done when building the library.
 + */
 +
 +#include <curl/curlrules.h>
 +
 +/*
 + * Ensure that no one is using the old SIZEOF_CURL_OFF_T macro
 + */
 +
 +#ifdef SIZEOF_CURL_OFF_T
 +#  error "SIZEOF_CURL_OFF_T shall not be defined!"
 +   Error Compilation_aborted_SIZEOF_CURL_OFF_T_shall_not_be_defined
 +#endif
 +
 +/*
 + * Disable other protocols when http is the only one desired.
 + */
 +
 +#ifdef HTTP_ONLY
 +#  ifndef CURL_DISABLE_TFTP
 +#    define CURL_DISABLE_TFTP
 +#  endif
 +#  ifndef CURL_DISABLE_FTP
 +#    define CURL_DISABLE_FTP
 +#  endif
 +#  ifndef CURL_DISABLE_LDAP
 +#    define CURL_DISABLE_LDAP
 +#  endif
 +#  ifndef CURL_DISABLE_TELNET
 +#    define CURL_DISABLE_TELNET
 +#  endif
 +#  ifndef CURL_DISABLE_DICT
 +#    define CURL_DISABLE_DICT
 +#  endif
 +#  ifndef CURL_DISABLE_FILE
 +#    define CURL_DISABLE_FILE
 +#  endif
 +#  ifndef CURL_DISABLE_RTSP
 +#    define CURL_DISABLE_RTSP
 +#  endif
 +#  ifndef CURL_DISABLE_POP3
 +#    define CURL_DISABLE_POP3
 +#  endif
 +#  ifndef CURL_DISABLE_IMAP
 +#    define CURL_DISABLE_IMAP
 +#  endif
 +#  ifndef CURL_DISABLE_SMTP
 +#    define CURL_DISABLE_SMTP
 +#  endif
- #  ifndef CURL_DISABLE_RTSP
- #    define CURL_DISABLE_RTSP
- #  endif
 +#  ifndef CURL_DISABLE_RTMP
 +#    define CURL_DISABLE_RTMP
 +#  endif
 +#  ifndef CURL_DISABLE_GOPHER
 +#    define CURL_DISABLE_GOPHER
 +#  endif
 +#  ifndef CURL_DISABLE_SMB
 +#    define CURL_DISABLE_SMB
 +#  endif
 +#endif
 +
 +/*
 + * When http is disabled rtsp is not supported.
 + */
 +
 +#if defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_RTSP)
 +#  define CURL_DISABLE_RTSP
 +#endif
 +
 +/* ================================================================ */
 +/* No system header file shall be included in this file before this */
 +/* point. The only allowed ones are those included from curlbuild.h */
 +/* ================================================================ */
 +
 +/*
 + * OS/400 setup file includes some system headers.
 + */
 +
 +#ifdef __OS400__
 +#  include "setup-os400.h"
 +#endif
 +
 +/*
 + * VMS setup file includes some system headers.
 + */
 +
 +#ifdef __VMS
 +#  include "setup-vms.h"
 +#endif
 +
 +/*
++ * Use getaddrinfo to resolve the IPv4 address literal. If the current network
++ * interface doesn’t support IPv4, but supports IPv6, NAT64, and DNS64,
++ * performing this task will result in a synthesized IPv6 address.
++ */
++#ifdef  __APPLE__
++#define USE_RESOLVE_ON_IPS 1
++#endif
++
++/*
 + * Include header files for windows builds before redefining anything.
 + * Use this preprocessor block only to include or exclude windows.h,
 + * winsock2.h, ws2tcpip.h or winsock.h. Any other windows thing belongs
 + * to any other further and independent block.  Under Cygwin things work
 + * just as under linux (e.g. <sys/socket.h>) and the winsock headers should
 + * never be included when __CYGWIN__ is defined.  configure script takes
 + * care of this, not defining HAVE_WINDOWS_H, HAVE_WINSOCK_H, HAVE_WINSOCK2_H,
 + * neither HAVE_WS2TCPIP_H when __CYGWIN__ is defined.
 + */
 +
 +#ifdef HAVE_WINDOWS_H
 +#  if defined(UNICODE) && !defined(_UNICODE)
 +#    define _UNICODE
 +#  endif
 +#  if defined(_UNICODE) && !defined(UNICODE)
 +#    define UNICODE
 +#  endif
 +#  ifndef WIN32_LEAN_AND_MEAN
 +#    define WIN32_LEAN_AND_MEAN
 +#  endif
 +#  include <windows.h>
 +#  ifdef HAVE_WINSOCK2_H
 +#    include <winsock2.h>
 +#    ifdef HAVE_WS2TCPIP_H
- #       include <ws2tcpip.h>
++#      include <ws2tcpip.h>
 +#    endif
 +#  else
 +#    ifdef HAVE_WINSOCK_H
 +#      include <winsock.h>
 +#    endif
 +#  endif
 +#  include <tchar.h>
 +#  ifdef UNICODE
 +     typedef wchar_t *(*curl_wcsdup_callback)(const wchar_t *str);
 +#  endif
 +#endif
 +
 +/*
 + * Define USE_WINSOCK to 2 if we have and use WINSOCK2 API, else
 + * define USE_WINSOCK to 1 if we have and use WINSOCK  API, else
 + * undefine USE_WINSOCK.
 + */
 +
 +#undef USE_WINSOCK
 +
 +#ifdef HAVE_WINSOCK2_H
 +#  define USE_WINSOCK 2
 +#else
 +#  ifdef HAVE_WINSOCK_H
 +#    define USE_WINSOCK 1
 +#  endif
 +#endif
 +
 +#ifdef USE_LWIPSOCK
 +#  include <lwip/init.h>
 +#  include <lwip/sockets.h>
 +#  include <lwip/netdb.h>
 +#endif
 +
 +#ifdef HAVE_EXTRA_STRICMP_H
 +#  include <extra/stricmp.h>
 +#endif
 +
 +#ifdef HAVE_EXTRA_STRDUP_H
 +#  include <extra/strdup.h>
 +#endif
 +
 +#ifdef TPF
 +#  include <strings.h>    /* for bzero, strcasecmp, and strncasecmp */
 +#  include <string.h>     /* for strcpy and strlen */
 +#  include <stdlib.h>     /* for rand and srand */
 +#  include <sys/socket.h> /* for select and ioctl*/
 +#  include <netdb.h>      /* for in_addr_t definition */
 +#  include <tpf/sysapi.h> /* for tpf_process_signals */
 +   /* change which select is used for libcurl */
 +#  define select(a,b,c,d,e) tpf_select_libcurl(a,b,c,d,e)
 +#endif
 +
 +#ifdef __VXWORKS__
 +#  include <sockLib.h>    /* for generic BSD socket functions */
 +#  include <ioLib.h>      /* for basic I/O interface functions */
 +#endif
 +
 +#ifdef __AMIGA__
 +#  ifndef __ixemul__
 +#    include <exec/types.h>
 +#    include <exec/execbase.h>
 +#    include <proto/exec.h>
 +#    include <proto/dos.h>
 +#    define select(a,b,c,d,e) WaitSelect(a,b,c,d,e,0)
 +#  endif
 +#endif
 +
 +#include <stdio.h>
 +#ifdef HAVE_ASSERT_H
 +#include <assert.h>
 +#endif
 +
 +#ifdef __TANDEM /* for nsr-tandem-nsk systems */
 +#include <floss.h>
 +#endif
 +
 +#ifndef STDC_HEADERS /* no standard C headers! */
 +#include <curl/stdcheaders.h>
 +#endif
 +
 +#ifdef __POCC__
 +#  include <sys/types.h>
 +#  include <unistd.h>
 +#  define sys_nerr EILSEQ
 +#endif
 +
 +/*
 + * Salford-C kludge section (mostly borrowed from wxWidgets).
 + */
 +#ifdef __SALFORDC__
 +  #pragma suppress 353             /* Possible nested comments */
 +  #pragma suppress 593             /* Define not used */
 +  #pragma suppress 61              /* enum has no name */
 +  #pragma suppress 106             /* unnamed, unused parameter */
 +  #include <clib.h>
 +#endif
 +
 +/* Default Windows file API selection.  */
 +#ifdef _WIN32
 +# if defined(_MSC_VER) && (_INTEGRAL_MAX_BITS >= 64)
 +#  define USE_WIN32_LARGE_FILES
 +# elif defined(__MINGW32__)
 +#  define USE_WIN32_LARGE_FILES
 +# else
 +#  define USE_WIN32_SMALL_FILES
 +# endif
 +#endif
 +
 +/*
 + * Large file (>2Gb) support using WIN32 functions.
 + */
 +
 +#ifdef USE_WIN32_LARGE_FILES
 +#  include <io.h>
 +#  include <sys/types.h>
 +#  include <sys/stat.h>
 +#  undef  lseek
 +#  define lseek(fdes,offset,whence)  _lseeki64(fdes, offset, whence)
 +#  undef  fstat
 +#  define fstat(fdes,stp)            _fstati64(fdes, stp)
 +#  undef  stat
 +#  define stat(fname,stp)            _stati64(fname, stp)
 +#  define struct_stat                struct _stati64
 +#  define LSEEK_ERROR                (__int64)-1
 +#endif
 +
 +/*
 + * Small file (<2Gb) support using WIN32 functions.
 + */
 +
 +#ifdef USE_WIN32_SMALL_FILES
 +#  include <io.h>
 +#  include <sys/types.h>
 +#  include <sys/stat.h>
 +#  ifndef _WIN32_WCE
 +#    undef  lseek
 +#    define lseek(fdes,offset,whence)  _lseek(fdes, (long)offset, whence)
 +#    define fstat(fdes,stp)            _fstat(fdes, stp)
 +#    define stat(fname,stp)            _stat(fname, stp)
 +#    define struct_stat                struct _stat
 +#  endif
 +#  define LSEEK_ERROR                (long)-1
 +#endif
 +
 +#ifndef struct_stat
 +#  define struct_stat struct stat
 +#endif
 +
 +#ifndef LSEEK_ERROR
 +#  define LSEEK_ERROR (off_t)-1
 +#endif
 +
 +/*
 + * Default sizeof(off_t) in case it hasn't been defined in config file.
 + */
 +
 +#ifndef SIZEOF_OFF_T
 +#  if defined(__VMS) && !defined(__VAX)
 +#    if defined(_LARGEFILE)
 +#      define SIZEOF_OFF_T 8
 +#    endif
 +#  elif defined(__OS400__) && defined(__ILEC400__)
 +#    if defined(_LARGE_FILES)
 +#      define SIZEOF_OFF_T 8
 +#    endif
 +#  elif defined(__MVS__) && defined(__IBMC__)
 +#    if defined(_LP64) || defined(_LARGE_FILES)
 +#      define SIZEOF_OFF_T 8
 +#    endif
 +#  elif defined(__370__) && defined(__IBMC__)
 +#    if defined(_LP64) || defined(_LARGE_FILES)
 +#      define SIZEOF_OFF_T 8
 +#    endif
 +#  endif
 +#  ifndef SIZEOF_OFF_T
 +#    define SIZEOF_OFF_T 4
 +#  endif
 +#endif
 +
 +/*
 + * Arg 2 type for gethostname in case it hasn't been defined in config file.
 + */
 +
 +#ifndef GETHOSTNAME_TYPE_ARG2
 +#  ifdef USE_WINSOCK
 +#    define GETHOSTNAME_TYPE_ARG2 int
 +#  else
 +#    define GETHOSTNAME_TYPE_ARG2 size_t
 +#  endif
 +#endif
 +
 +/* Below we define some functions. They should
 +
 +   4. set the SIGALRM signal timeout
 +   5. set dir/file naming defines
 +   */
 +
 +#ifdef WIN32
 +
 +#  define DIR_CHAR      "\\"
 +#  define DOT_CHAR      "_"
 +
 +#else /* WIN32 */
 +
 +#  ifdef MSDOS  /* Watt-32 */
 +
 +#    include <sys/ioctl.h>
 +#    define select(n,r,w,x,t) select_s(n,r,w,x,t)
 +#    define ioctl(x,y,z) ioctlsocket(x,y,(char *)(z))
 +#    include <tcp.h>
 +#    ifdef word
 +#      undef word
 +#    endif
 +#    ifdef byte
 +#      undef byte
 +#    endif
 +
 +#  endif /* MSDOS */
 +
 +#  ifdef __minix
 +     /* Minix 3 versions up to at least 3.1.3 are missing these prototypes */
 +     extern char * strtok_r(char *s, const char *delim, char **last);
 +     extern struct tm * gmtime_r(const time_t * const timep, struct tm *tmp);
 +#  endif
 +
 +#  define DIR_CHAR      "/"
 +#  ifndef DOT_CHAR
 +#    define DOT_CHAR      "."
 +#  endif
 +
 +#  ifdef MSDOS
 +#    undef DOT_CHAR
 +#    define DOT_CHAR      "_"
 +#  endif
 +
 +#  ifndef fileno /* sunos 4 have this as a macro! */
-      int fileno( FILE *stream);
++     int fileno(FILE *stream);
 +#  endif
 +
 +#endif /* WIN32 */
 +
 +/*
 + * msvc 6.0 requires PSDK in order to have INET6_ADDRSTRLEN
 + * defined in ws2tcpip.h as well as to provide IPv6 support.
++ * Does not apply if lwIP is used.
 + */
 +
- #if defined(_MSC_VER) && !defined(__POCC__)
++#if defined(_MSC_VER) && !defined(__POCC__) && !defined(USE_LWIPSOCK)
 +#  if !defined(HAVE_WS2TCPIP_H) || \
 +     ((_MSC_VER < 1300) && !defined(INET6_ADDRSTRLEN))
 +#    undef HAVE_GETADDRINFO_THREADSAFE
 +#    undef HAVE_FREEADDRINFO
 +#    undef HAVE_GETADDRINFO
 +#    undef HAVE_GETNAMEINFO
 +#    undef ENABLE_IPV6
 +#  endif
 +#endif
 +
 +/* ---------------------------------------------------------------- */
 +/*             resolver specialty compile-time defines              */
 +/*         CURLRES_* defines to use in the host*.c sources          */
 +/* ---------------------------------------------------------------- */
 +
 +/*
 + * lcc-win32 doesn't have _beginthreadex(), lacks threads support.
 + */
 +
 +#if defined(__LCC__) && defined(WIN32)
 +#  undef USE_THREADS_POSIX
 +#  undef USE_THREADS_WIN32
 +#endif
 +
 +/*
 + * MSVC threads support requires a multi-threaded runtime library.
 + * _beginthreadex() is not available in single-threaded ones.
 + */
 +
 +#if defined(_MSC_VER) && !defined(__POCC__) && !defined(_MT)
 +#  undef USE_THREADS_POSIX
 +#  undef USE_THREADS_WIN32
 +#endif
 +
 +/*
 + * Mutually exclusive CURLRES_* definitions.
 + */
 +
 +#ifdef USE_ARES
 +#  define CURLRES_ASYNCH
 +#  define CURLRES_ARES
 +/* now undef the stock libc functions just to avoid them being used */
 +#  undef HAVE_GETADDRINFO
++#  undef HAVE_FREEADDRINFO
 +#  undef HAVE_GETHOSTBYNAME
 +#elif defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
 +#  define CURLRES_ASYNCH
 +#  define CURLRES_THREADED
 +#else
 +#  define CURLRES_SYNCH
 +#endif
 +
 +#ifdef ENABLE_IPV6
 +#  define CURLRES_IPV6
 +#else
 +#  define CURLRES_IPV4
 +#endif
 +
 +/* ---------------------------------------------------------------- */
 +
 +/*
 + * When using WINSOCK, TELNET protocol requires WINSOCK2 API.
 + */
 +
 +#if defined(USE_WINSOCK) && (USE_WINSOCK != 2)
 +#  define CURL_DISABLE_TELNET 1
 +#endif
 +
 +/*
 + * msvc 6.0 does not have struct sockaddr_storage and
 + * does not define IPPROTO_ESP in winsock2.h. But both
 + * are available if PSDK is properly installed.
 + */
 +
 +#if defined(_MSC_VER) && !defined(__POCC__)
 +#  if !defined(HAVE_WINSOCK2_H) || ((_MSC_VER < 1300) && !defined(IPPROTO_ESP))
 +#    undef HAVE_STRUCT_SOCKADDR_STORAGE
 +#  endif
 +#endif
 +
 +/*
 + * Intentionally fail to build when using msvc 6.0 without PSDK installed.
 + * The brave of heart can circumvent this, defining ALLOW_MSVC6_WITHOUT_PSDK
 + * in lib/config-win32.h although absolutely discouraged and unsupported.
 + */
 +
 +#if defined(_MSC_VER) && !defined(__POCC__)
 +#  if !defined(HAVE_WINDOWS_H) || ((_MSC_VER < 1300) && !defined(_FILETIME_))
 +#    if !defined(ALLOW_MSVC6_WITHOUT_PSDK)
 +#      error MSVC 6.0 requires "February 2003 Platform SDK" a.k.a. \
 +             "Windows Server 2003 PSDK"
 +#    else
 +#      define CURL_DISABLE_LDAP 1
 +#    endif
 +#  endif
 +#endif
 +
 +#ifdef NETWARE
 +int netware_init(void);
 +#ifndef __NOVELL_LIBC__
 +#include <sys/bsdskt.h>
 +#include <sys/timeval.h>
 +#endif
 +#endif
 +
 +#if defined(HAVE_LIBIDN) && defined(HAVE_TLD_H)
 +/* The lib was present and the tld.h header (which is missing in libidn 0.3.X
 +   but we only work with libidn 0.4.1 or later) */
 +#define USE_LIBIDN
 +#endif
 +
 +#ifndef SIZEOF_TIME_T
 +/* assume default size of time_t to be 32 bit */
 +#define SIZEOF_TIME_T 4
 +#endif
 +
 +#define LIBIDN_REQUIRED_VERSION "0.4.1"
 +
 +#if defined(USE_GNUTLS) || defined(USE_OPENSSL) || defined(USE_NSS) || \
-     defined(USE_POLARSSL) || defined(USE_AXTLS) || \
++    defined(USE_POLARSSL) || defined(USE_AXTLS) || defined(USE_MBEDTLS) || \
 +    defined(USE_CYASSL) || defined(USE_SCHANNEL) || \
 +    defined(USE_DARWINSSL) || defined(USE_GSKIT)
 +#define USE_SSL    /* SSL support has been enabled */
 +#endif
 +
 +/* Single point where USE_SPNEGO definition might be defined */
 +#if !defined(CURL_DISABLE_CRYPTO_AUTH) && \
 +    (defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI))
 +#define USE_SPNEGO
 +#endif
 +
 +/* Single point where USE_KERBEROS5 definition might be defined */
 +#if !defined(CURL_DISABLE_CRYPTO_AUTH) && \
 +    (defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI))
 +#define USE_KERBEROS5
 +#endif
 +
 +/* Single point where USE_NTLM definition might be defined */
 +#if !defined(CURL_DISABLE_NTLM) && !defined(CURL_DISABLE_CRYPTO_AUTH)
 +#if defined(USE_OPENSSL) || defined(USE_WINDOWS_SSPI) || \
 +    defined(USE_GNUTLS) || defined(USE_NSS) || defined(USE_DARWINSSL) || \
 +    defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO)
 +
- #ifdef HAVE_BORINGSSL /* BoringSSL is not NTLM capable */
- #undef USE_NTLM
- #else
 +#define USE_NTLM
 +#endif
 +#endif
- #endif
 +
 +/* non-configure builds may define CURL_WANTS_CA_BUNDLE_ENV */
 +#if defined(CURL_WANTS_CA_BUNDLE_ENV) && !defined(CURL_CA_BUNDLE)
 +#define CURL_CA_BUNDLE getenv("CURL_CA_BUNDLE")
 +#endif
 +
 +/*
 + * Provide a mechanism to silence picky compilers, such as gcc 4.6+.
 + * Parameters should of course normally not be unused, but for example when
 + * we have multiple implementations of the same interface it may happen.
 + */
 +
 +#if defined(__GNUC__) && ((__GNUC__ >= 3) || \
 +  ((__GNUC__ == 2) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ >= 7)))
 +#  define UNUSED_PARAM __attribute__((__unused__))
 +#  define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
 +#else
 +#  define UNUSED_PARAM /*NOTHING*/
 +#  define WARN_UNUSED_RESULT
 +#endif
 +
 +/*
 + * Include macros and defines that should only be processed once.
 + */
 +
 +#ifndef HEADER_CURL_SETUP_ONCE_H
 +#include "curl_setup_once.h"
 +#endif
 +
 +/*
 + * Definition of our NOP statement Object-like macro
 + */
 +
 +#ifndef Curl_nop_stmt
 +#  define Curl_nop_stmt do { } WHILE_FALSE
 +#endif
 +
 +/*
 + * Ensure that Winsock and lwIP TCP/IP stacks are not mixed.
 + */
 +
- #if defined(__LWIP_OPT_H__)
++#if defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H)
 +#  if defined(SOCKET) || \
 +     defined(USE_WINSOCK) || \
 +     defined(HAVE_WINSOCK_H) || \
 +     defined(HAVE_WINSOCK2_H) || \
 +     defined(HAVE_WS2TCPIP_H)
 +#    error "Winsock and lwIP TCP/IP stack definitions shall not coexist!"
 +#  endif
 +#endif
 +
 +/*
 + * Portable symbolic names for Winsock shutdown() mode flags.
 + */
 +
 +#ifdef USE_WINSOCK
 +#  define SHUT_RD   0x00
 +#  define SHUT_WR   0x01
 +#  define SHUT_RDWR 0x02
 +#endif
 +
 +/* Define S_ISREG if not defined by system headers, f.e. MSVC */
 +#if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG)
 +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
 +#endif
 +
 +/* Define S_ISDIR if not defined by system headers, f.e. MSVC */
 +#if !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFDIR)
 +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
 +#endif
 +
 +/* In Windows the default file mode is text but an application can override it.
- Therefore we specify it explicitly. https://github.com/bagder/curl/pull/258
++Therefore we specify it explicitly. https://github.com/curl/curl/pull/258
 +*/
 +#if defined(WIN32) || defined(MSDOS)
 +#define FOPEN_READTEXT "rt"
 +#define FOPEN_WRITETEXT "wt"
 +#elif defined(__CYGWIN__)
 +/* Cygwin has specific behavior we need to address when WIN32 is not defined.
 +https://cygwin.com/cygwin-ug-net/using-textbinary.html
 +For write we want our output to have line endings of LF and be compatible with
 +other Cygwin utilities. For read we want to handle input that may have line
 +endings either CRLF or LF so 't' is appropriate.
 +*/
 +#define FOPEN_READTEXT "rt"
 +#define FOPEN_WRITETEXT "w"
 +#else
 +#define FOPEN_READTEXT "r"
 +#define FOPEN_WRITETEXT "w"
 +#endif
 +
++/* WinSock destroys recv() buffer when send() failed.
++ * Enabled automatically for Windows and for Cygwin as Cygwin sockets are
++ * wrappers for WinSock sockets. https://github.com/curl/curl/issues/657
++ * Define DONT_USE_RECV_BEFORE_SEND_WORKAROUND to force disable workaround.
++ */
++#if !defined(DONT_USE_RECV_BEFORE_SEND_WORKAROUND)
++#  if defined(WIN32) || defined(__CYGWIN__)
++#    define USE_RECV_BEFORE_SEND_WORKAROUND
++#  endif
++#else  /* DONT_USE_RECV_BEFORE_SEND_WORKAROUNDS */
++#  ifdef USE_RECV_BEFORE_SEND_WORKAROUND
++#    undef USE_RECV_BEFORE_SEND_WORKAROUND
++#  endif
++#endif /* DONT_USE_RECV_BEFORE_SEND_WORKAROUNDS */
++
 +#endif /* HEADER_CURL_SETUP_H */
diff --cc Utilities/cmcurl/lib/ftp.c
index 29c840c,0000000..b0165bc
mode 100644,000000..100644
--- a/Utilities/cmcurl/lib/ftp.c
+++ b/Utilities/cmcurl/lib/ftp.c
@@@ -1,4599 -1,0 +1,4616 @@@
 +/***************************************************************************
 + *                                  _   _ ____  _
 + *  Project                     ___| | | |  _ \| |
 + *                             / __| | | | |_) | |
 + *                            | (__| |_| |  _ <| |___
 + *                             \___|\___/|_| \_\_____|
 + *
-  * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
++ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
 + *
 + * This software is licensed as described in the file COPYING, which
 + * you should have received as part of this distribution. The terms
-  * are also available at http://curl.haxx.se/docs/copyright.html.
++ * 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_FTP
 +
 +#ifdef HAVE_NETINET_IN_H
 +#include <netinet/in.h>
 +#endif
 +#ifdef HAVE_ARPA_INET_H
 +#include <arpa/inet.h>
 +#endif
 +#ifdef HAVE_UTSNAME_H
 +#include <sys/utsname.h>
 +#endif
 +#ifdef HAVE_NETDB_H
 +#include <netdb.h>
 +#endif
 +#ifdef __VMS
 +#include <in.h>
 +#include <inet.h>
 +#endif
 +
 +#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
 +#undef in_addr_t
 +#define in_addr_t unsigned long
 +#endif
 +
 +#include <curl/curl.h>
 +#include "urldata.h"
 +#include "sendf.h"
 +#include "if2ip.h"
 +#include "hostip.h"
 +#include "progress.h"
 +#include "transfer.h"
 +#include "escape.h"
 +#include "http.h" /* for HTTP proxy tunnel stuff */
 +#include "socks.h"
 +#include "ftp.h"
 +#include "fileinfo.h"
 +#include "ftplistparser.h"
 +#include "curl_sec.h"
 +#include "strtoofft.h"
 +#include "strequal.h"
 +#include "vtls/vtls.h"
 +#include "connect.h"
 +#include "strerror.h"
 +#include "inet_ntop.h"
 +#include "inet_pton.h"
 +#include "select.h"
 +#include "parsedate.h" /* for the week day and month names */
 +#include "sockaddr.h" /* required for Curl_sockaddr_storage */
 +#include "multiif.h"
 +#include "url.h"
 +#include "rawstr.h"
 +#include "speedcheck.h"
 +#include "warnless.h"
 +#include "http_proxy.h"
 +#include "non-ascii.h"
++/* The last 3 #include files should be in this order */
 +#include "curl_printf.h"
- 
 +#include "curl_memory.h"
- /* The last #include file should be: */
 +#include "memdebug.h"
 +
 +#ifndef NI_MAXHOST
 +#define NI_MAXHOST 1025
 +#endif
 +#ifndef INET_ADDRSTRLEN
 +#define INET_ADDRSTRLEN 16
 +#endif
 +
 +#ifdef CURL_DISABLE_VERBOSE_STRINGS
 +#define ftp_pasv_verbose(a,b,c,d)  Curl_nop_stmt
 +#endif
 +
 +/* Local API functions */
 +#ifndef DEBUGBUILD
 +static void _state(struct connectdata *conn,
 +                   ftpstate newstate);
 +#define state(x,y) _state(x,y)
 +#else
 +static void _state(struct connectdata *conn,
 +                   ftpstate newstate,
 +                   int lineno);
 +#define state(x,y) _state(x,y,__LINE__)
 +#endif
 +
 +static CURLcode ftp_sendquote(struct connectdata *conn,
 +                              struct curl_slist *quote);
 +static CURLcode ftp_quit(struct connectdata *conn);
 +static CURLcode ftp_parse_url_path(struct connectdata *conn);
 +static CURLcode ftp_regular_transfer(struct connectdata *conn, bool *done);
 +#ifndef CURL_DISABLE_VERBOSE_STRINGS
 +static void ftp_pasv_verbose(struct connectdata *conn,
 +                             Curl_addrinfo *ai,
 +                             char *newhost, /* ascii version */
 +                             int port);
 +#endif
 +static CURLcode ftp_state_prepare_transfer(struct connectdata *conn);
 +static CURLcode ftp_state_mdtm(struct connectdata *conn);
 +static CURLcode ftp_state_quote(struct connectdata *conn,
 +                                bool init, ftpstate instate);
 +static CURLcode ftp_nb_type(struct connectdata *conn,
 +                            bool ascii, ftpstate newstate);
 +static int ftp_need_type(struct connectdata *conn,
 +                         bool ascii);
 +static CURLcode ftp_do(struct connectdata *conn, bool *done);
 +static CURLcode ftp_done(struct connectdata *conn,
 +                         CURLcode, bool premature);
 +static CURLcode ftp_connect(struct connectdata *conn, bool *done);
 +static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection);
 +static CURLcode ftp_do_more(struct connectdata *conn, int *completed);
 +static CURLcode ftp_multi_statemach(struct connectdata *conn, bool *done);
 +static int ftp_getsock(struct connectdata *conn, curl_socket_t *socks,
 +                       int numsocks);
 +static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
 +                              int numsocks);
 +static CURLcode ftp_doing(struct connectdata *conn,
 +                          bool *dophase_done);
 +static CURLcode ftp_setup_connection(struct connectdata * conn);
 +
 +static CURLcode init_wc_data(struct connectdata *conn);
 +static CURLcode wc_statemach(struct connectdata *conn);
 +
 +static void wc_data_dtor(void *ptr);
 +
 +static CURLcode ftp_state_retr(struct connectdata *conn, curl_off_t filesize);
 +
 +static CURLcode ftp_readresp(curl_socket_t sockfd,
 +                             struct pingpong *pp,
 +                             int *ftpcode,
 +                             size_t *size);
 +static CURLcode ftp_dophase_done(struct connectdata *conn,
 +                                 bool connected);
 +
 +/* easy-to-use macro: */
- #define PPSENDF(x,y,z)  if((result = Curl_pp_sendf(x,y,z)))     \
-                               return result
++#define PPSENDF(x,y,z)  result = Curl_pp_sendf(x,y,z); \
++                        if(result)                     \
++                          return result
 +
 +
 +/*
 + * FTP protocol handler.
 + */
 +
 +const struct Curl_handler Curl_handler_ftp = {
 +  "FTP",                           /* scheme */
 +  ftp_setup_connection,            /* setup_connection */
 +  ftp_do,                          /* do_it */
 +  ftp_done,                        /* done */
 +  ftp_do_more,                     /* do_more */
 +  ftp_connect,                     /* connect_it */
 +  ftp_multi_statemach,             /* connecting */
 +  ftp_doing,                       /* doing */
 +  ftp_getsock,                     /* proto_getsock */
 +  ftp_getsock,                     /* doing_getsock */
 +  ftp_domore_getsock,              /* domore_getsock */
 +  ZERO_NULL,                       /* perform_getsock */
 +  ftp_disconnect,                  /* disconnect */
 +  ZERO_NULL,                       /* readwrite */
 +  PORT_FTP,                        /* defport */
 +  CURLPROTO_FTP,                   /* protocol */
 +  PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD
 +  | PROTOPT_NOURLQUERY /* flags */
 +};
 +
 +
 +#ifdef USE_SSL
 +/*
 + * FTPS protocol handler.
 + */
 +
 +const struct Curl_handler Curl_handler_ftps = {
 +  "FTPS",                          /* scheme */
 +  ftp_setup_connection,            /* setup_connection */
 +  ftp_do,                          /* do_it */
 +  ftp_done,                        /* done */
 +  ftp_do_more,                     /* do_more */
 +  ftp_connect,                     /* connect_it */
 +  ftp_multi_statemach,             /* connecting */
 +  ftp_doing,                       /* doing */
 +  ftp_getsock,                     /* proto_getsock */
 +  ftp_getsock,                     /* doing_getsock */
 +  ftp_domore_getsock,              /* domore_getsock */
 +  ZERO_NULL,                       /* perform_getsock */
 +  ftp_disconnect,                  /* disconnect */
 +  ZERO_NULL,                       /* readwrite */
 +  PORT_FTPS,                       /* defport */
 +  CURLPROTO_FTPS,                  /* protocol */
 +  PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION |
 +  PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY /* flags */
 +};
 +#endif
 +
 +#ifndef CURL_DISABLE_HTTP
 +/*
 + * HTTP-proxyed FTP protocol handler.
 + */
 +
 +static const struct Curl_handler Curl_handler_ftp_proxy = {
 +  "FTP",                                /* scheme */
 +  Curl_http_setup_conn,                 /* setup_connection */
 +  Curl_http,                            /* do_it */
 +  Curl_http_done,                       /* done */
 +  ZERO_NULL,                            /* do_more */
 +  ZERO_NULL,                            /* connect_it */
 +  ZERO_NULL,                            /* connecting */
 +  ZERO_NULL,                            /* doing */
 +  ZERO_NULL,                            /* proto_getsock */
 +  ZERO_NULL,                            /* doing_getsock */
 +  ZERO_NULL,                            /* domore_getsock */
 +  ZERO_NULL,                            /* perform_getsock */
 +  ZERO_NULL,                            /* disconnect */
 +  ZERO_NULL,                            /* readwrite */
 +  PORT_FTP,                             /* defport */
 +  CURLPROTO_HTTP,                       /* protocol */
 +  PROTOPT_NONE                          /* flags */
 +};
 +
 +
 +#ifdef USE_SSL
 +/*
 + * HTTP-proxyed FTPS protocol handler.
 + */
 +
 +static const struct Curl_handler Curl_handler_ftps_proxy = {
 +  "FTPS",                               /* scheme */
 +  Curl_http_setup_conn,                 /* setup_connection */
 +  Curl_http,                            /* do_it */
 +  Curl_http_done,                       /* done */
 +  ZERO_NULL,                            /* do_more */
 +  ZERO_NULL,                            /* connect_it */
 +  ZERO_NULL,                            /* connecting */
 +  ZERO_NULL,                            /* doing */
 +  ZERO_NULL,                            /* proto_getsock */
 +  ZERO_NULL,                            /* doing_getsock */
 +  ZERO_NULL,                            /* domore_getsock */
 +  ZERO_NULL,                            /* perform_getsock */
 +  ZERO_NULL,                            /* disconnect */
 +  ZERO_NULL,                            /* readwrite */
 +  PORT_FTPS,                            /* defport */
 +  CURLPROTO_HTTP,                       /* protocol */
 +  PROTOPT_NONE                          /* flags */
 +};
 +#endif
 +#endif
 +
++static void close_secondarysocket(struct connectdata *conn)
++{
++  if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
++    Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
++    conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
++  }
++  conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
++  conn->tunnel_state[SECONDARYSOCKET] = TUNNEL_INIT;
++}
 +
 +/*
 + * NOTE: back in the old days, we added code in the FTP code that made NOBODY
 + * requests on files respond with headers passed to the client/stdout that
 + * looked like HTTP ones.
 + *
 + * This approach is not very elegant, it causes confusion and is error-prone.
 + * It is subject for removal at the next (or at least a future) soname bump.
 + * Until then you can test the effects of the removal by undefining the
 + * following define named CURL_FTP_HTTPSTYLE_HEAD.
 + */
 +#define CURL_FTP_HTTPSTYLE_HEAD 1
 +
 +static void freedirs(struct ftp_conn *ftpc)
 +{
 +  int i;
 +  if(ftpc->dirs) {
 +    for(i=0; i < ftpc->dirdepth; i++) {
 +      free(ftpc->dirs[i]);
 +      ftpc->dirs[i]=NULL;
 +    }
 +    free(ftpc->dirs);
 +    ftpc->dirs = NULL;
 +    ftpc->dirdepth = 0;
 +  }
 +  Curl_safefree(ftpc->file);
 +
 +  /* no longer of any use */
 +  Curl_safefree(ftpc->newhost);
 +}
 +
 +/* Returns non-zero if the given string contains CR (\r) or LF (\n),
 +   which are not allowed within RFC 959 <string>.
 +   Note: The input string is in the client's encoding which might
 +   not be ASCII, so escape sequences \r & \n must be used instead
 +   of hex values 0x0d & 0x0a.
 +*/
 +static bool isBadFtpString(const char *string)
 +{
 +  return ((NULL != strchr(string, '\r')) ||
 +          (NULL != strchr(string, '\n'))) ? TRUE : FALSE;
 +}
 +
 +/***********************************************************************
 + *
 + * AcceptServerConnect()
 + *
 + * After connection request is received from the server this function is
 + * called to accept the connection and close the listening socket
 + *
 + */
 +static CURLcode AcceptServerConnect(struct connectdata *conn)
 +{
-   struct SessionHandle *data = conn->data;
++  struct Curl_easy *data = conn->data;
 +  curl_socket_t sock = conn->sock[SECONDARYSOCKET];
 +  curl_socket_t s = CURL_SOCKET_BAD;
 +#ifdef ENABLE_IPV6
 +  struct Curl_sockaddr_storage add;
 +#else
 +  struct sockaddr_in add;
 +#endif
 +  curl_socklen_t size = (curl_socklen_t) sizeof(add);
 +
 +  if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) {
 +    size = sizeof(add);
 +
 +    s=accept(sock, (struct sockaddr *) &add, &size);
 +  }
 +  Curl_closesocket(conn, sock); /* close the first socket */
 +
 +  if(CURL_SOCKET_BAD == s) {
 +    failf(data, "Error accept()ing server connect");
 +    return CURLE_FTP_PORT_FAILED;
 +  }
 +  infof(data, "Connection accepted from server\n");
++  /* when this happens within the DO state it is important that we mark us as
++     not needing DO_MORE anymore */
++  conn->bits.do_more = FALSE;
 +
 +  conn->sock[SECONDARYSOCKET] = s;
 +  (void)curlx_nonblock(s, TRUE); /* enable non-blocking */
 +  conn->sock_accepted[SECONDARYSOCKET] = TRUE;
 +
 +  if(data->set.fsockopt) {
 +    int error = 0;
 +
 +    /* activate callback for setting socket options */
 +    error = data->set.fsockopt(data->set.sockopt_client,
 +                               s,
 +                               CURLSOCKTYPE_ACCEPT);
 +
 +    if(error) {
-       Curl_closesocket(conn, s); /* close the socket and bail out */
-       conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
++      close_secondarysocket(conn);
 +      return CURLE_ABORTED_BY_CALLBACK;
 +    }
 +  }
 +
 +  return CURLE_OK;
 +
 +}
 +
 +/*
 + * ftp_timeleft_accept() returns the amount of milliseconds left allowed for
 + * waiting server to connect. If the value is negative, the timeout time has
 + * already elapsed.
 + *
 + * The start time is stored in progress.t_acceptdata - as set with
 + * Curl_pgrsTime(..., TIMER_STARTACCEPT);
 + *
 + */
- static long ftp_timeleft_accept(struct SessionHandle *data)
++static long ftp_timeleft_accept(struct Curl_easy *data)
 +{
 +  long timeout_ms = DEFAULT_ACCEPT_TIMEOUT;
 +  long other;
 +  struct timeval now;
 +
 +  if(data->set.accepttimeout > 0)
 +    timeout_ms = data->set.accepttimeout;
 +
 +  now = Curl_tvnow();
 +
 +  /* check if the generic timeout possibly is set shorter */
 +  other =  Curl_timeleft(data, &now, FALSE);
 +  if(other && (other < timeout_ms))
 +    /* note that this also works fine for when other happens to be negative
 +       due to it already having elapsed */
 +    timeout_ms = other;
 +  else {
 +    /* subtract elapsed time */
 +    timeout_ms -= Curl_tvdiff(now, data->progress.t_acceptdata);
 +    if(!timeout_ms)
 +      /* avoid returning 0 as that means no timeout! */
 +      return -1;
 +  }
 +
 +  return timeout_ms;
 +}
 +
 +
 +/***********************************************************************
 + *
 + * ReceivedServerConnect()
 + *
 + * After allowing server to connect to us from data port, this function
 + * checks both data connection for connection establishment and ctrl
 + * connection for a negative response regarding a failure in connecting
 + *
 + */
 +static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received)
 +{
-   struct SessionHandle *data = conn->data;
++  struct Curl_easy *data = conn->data;
 +  curl_socket_t ctrl_sock = conn->sock[FIRSTSOCKET];
 +  curl_socket_t data_sock = conn->sock[SECONDARYSOCKET];
 +  struct ftp_conn *ftpc = &conn->proto.ftpc;
 +  struct pingpong *pp = &ftpc->pp;
 +  int result;
 +  long timeout_ms;
 +  ssize_t nread;
 +  int ftpcode;
 +
 +  *received = FALSE;
 +
 +  timeout_ms = ftp_timeleft_accept(data);
 +  infof(data, "Checking for server connect\n");
 +  if(timeout_ms < 0) {
 +    /* if a timeout was already reached, bail out */
 +    failf(data, "Accept timeout occurred while waiting server connect");
 +    return CURLE_FTP_ACCEPT_TIMEOUT;
 +  }
 +
 +  /* First check whether there is a cached response from server */
 +  if(pp->cache_size && pp->cache && pp->cache[0] > '3') {
 +    /* Data connection could not be established, let's return */
 +    infof(data, "There is negative response in cache while serv connect\n");
 +    Curl_GetFTPResponse(&nread, conn, &ftpcode);
 +    return CURLE_FTP_ACCEPT_FAILED;
 +  }
 +
 +  result = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0);
 +
 +  /* see if the connection request is already here */
 +  switch (result) {
 +  case -1: /* error */
 +    /* let's die here */
 +    failf(data, "Error while waiting for server connect");
 +    return CURLE_FTP_ACCEPT_FAILED;
 +  case 0:  /* Server connect is not received yet */
 +    break; /* loop */
 +  default:
 +
 +    if(result & CURL_CSELECT_IN2) {
 +      infof(data, "Ready to accept data connection from server\n");
 +      *received = TRUE;
 +    }
 +    else if(result & CURL_CSELECT_IN) {
 +      infof(data, "Ctrl conn has data while waiting for data conn\n");
 +      Curl_GetFTPResponse(&nread, conn, &ftpcode);
 +
 +      if(ftpcode/100 > 3)
 +        return CURLE_FTP_ACCEPT_FAILED;
 +
 +      return CURLE_FTP_WEIRD_SERVER_REPLY;
 +    }
 +
 +    break;
 +  } /* switch() */
 +
 +  return CURLE_OK;
 +}
 +
 +
 +/***********************************************************************
 + *
 + * InitiateTransfer()
 + *
 + * After connection from server is accepted this function is called to
 + * setup transfer parameters and initiate the data transfer.
 + *
 + */
 +static CURLcode InitiateTransfer(struct connectdata *conn)
 +{
-   struct SessionHandle *data = conn->data;
++  struct Curl_easy *data = conn->data;
 +  struct FTP *ftp = data->req.protop;
 +  CURLcode result = CURLE_OK;
 +
 +  if(conn->ssl[SECONDARYSOCKET].use) {
 +    /* since we only have a plaintext TCP connection here, we must now
 +     * do the TLS stuff */
 +    infof(data, "Doing the SSL/TLS handshake on the data stream\n");
 +    result = Curl_ssl_connect(conn, SECONDARYSOCKET);
 +    if(result)
 +      return result;
 +  }
 +
 +  if(conn->proto.ftpc.state_saved == FTP_STOR) {
 +    *(ftp->bytecountp)=0;
 +
 +    /* When we know we're uploading a specified file, we can get the file
 +       size prior to the actual upload. */
 +
 +    Curl_pgrsSetUploadSize(data, data->state.infilesize);
 +
 +    /* set the SO_SNDBUF for the secondary socket for those who need it */
 +    Curl_sndbufset(conn->sock[SECONDARYSOCKET]);
 +
 +    Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */
 +                        SECONDARYSOCKET, ftp->bytecountp);
 +  }
 +  else {
 +    /* FTP download: */
 +    Curl_setup_transfer(conn, SECONDARYSOCKET,
 +                        conn->proto.ftpc.retr_size_saved, FALSE,
 +                        ftp->bytecountp, -1, NULL); /* no upload here */
 +  }
 +
 +  conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
 +  state(conn, FTP_STOP);
 +
 +  return CURLE_OK;
 +}
 +
 +/***********************************************************************
 + *
 + * AllowServerConnect()
 + *
 + * When we've issue the PORT command, we have told the server to connect to
 + * us. This function checks whether data connection is established if so it is
 + * accepted.
 + *
 + */
 +static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected)
 +{
-   struct SessionHandle *data = conn->data;
++  struct Curl_easy *data = conn->data;
 +  long timeout_ms;
 +  CURLcode result = CURLE_OK;
 +
 +  *connected = FALSE;
 +  infof(data, "Preparing for accepting server on data port\n");
 +
 +  /* Save the time we start accepting server connect */
 +  Curl_pgrsTime(data, TIMER_STARTACCEPT);
 +
 +  timeout_ms = ftp_timeleft_accept(data);
 +  if(timeout_ms < 0) {
 +    /* if a timeout was already reached, bail out */
 +    failf(data, "Accept timeout occurred while waiting server connect");
 +    return CURLE_FTP_ACCEPT_TIMEOUT;
 +  }
 +
 +  /* see if the connection request is already here */
 +  result = ReceivedServerConnect(conn, connected);
 +  if(result)
 +    return result;
 +
 +  if(*connected) {
 +    result = AcceptServerConnect(conn);
 +    if(result)
 +      return result;
 +
 +    result = InitiateTransfer(conn);
 +    if(result)
 +      return result;
 +  }
 +  else {
 +    /* Add timeout to multi handle and break out of the loop */
 +    if(!result && *connected == FALSE) {
 +      if(data->set.accepttimeout > 0)
 +        Curl_expire(data, data->set.accepttimeout);
 +      else
 +        Curl_expire(data, DEFAULT_ACCEPT_TIMEOUT);
 +    }
 +  }
 +
 +  return result;
 +}
 +
 +/* macro to check for a three-digit ftp status code at the start of the
 +   given string */
 +#define STATUSCODE(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) &&       \
 +                          ISDIGIT(line[2]))
 +
 +/* macro to check for the last line in an FTP server response */
 +#define LASTLINE(line) (STATUSCODE(line) && (' ' == line[3]))
 +
 +static bool ftp_endofresp(struct connectdata *conn, char *line, size_t len,
 +                          int *code)
 +{
 +  (void)conn;
 +
 +  if((len > 3) && LASTLINE(line)) {
 +    *code = curlx_sltosi(strtol(line, NULL, 10));
 +    return TRUE;
 +  }
 +
 +  return FALSE;
 +}
 +
 +static CURLcode ftp_readresp(curl_socket_t sockfd,
 +                             struct pingpong *pp,
 +                             int *ftpcode, /* return the ftp-code if done */
 +                             size_t *size) /* size of the response */
 +{
 +  struct connectdata *conn = pp->conn;
-   struct SessionHandle *data = conn->data;
++  struct Curl_easy *data = conn->data;
 +#ifdef HAVE_GSSAPI
 +  char * const buf = data->state.buffer;
 +#endif
 +  CURLcode result = CURLE_OK;
 +  int code;
 +
 +  result = Curl_pp_readresp(sockfd, pp, &code, size);
 +
 +#if defined(HAVE_GSSAPI)
 +  /* handle the security-oriented responses 6xx ***/
 +  /* FIXME: some errorchecking perhaps... ***/
 +  switch(code) {
 +  case 631:
 +    code = Curl_sec_read_msg(conn, buf, PROT_SAFE);
 +    break;
 +  case 632:
 +    code = Curl_sec_read_msg(conn, buf, PROT_PRIVATE);
 +    break;
 +  case 633:
 +    code = Curl_sec_read_msg(conn, buf, PROT_CONFIDENTIAL);
 +    break;
 +  default:
 +    /* normal ftp stuff we pass through! */
 +    break;
 +  }
 +#endif
 +
 +  /* store the latest code for later retrieval */
 +  data->info.httpcode=code;
 +
 +  if(ftpcode)
 +    *ftpcode = code;
 +
 +  if(421 == code) {
 +    /* 421 means "Service not available, closing control connection." and FTP
 +     * servers use it to signal that idle session timeout has been exceeded.
 +     * If we ignored the response, it could end up hanging in some cases.
 +     *
 +     * This response code can come at any point so having it treated
 +     * generically is a good idea.
 +     */
 +    infof(data, "We got a 421 - timeout!\n");
 +    state(conn, FTP_STOP);
 +    return CURLE_OPERATION_TIMEDOUT;
 +  }
 +
 +  return result;
 +}
 +
 +/* --- parse FTP server responses --- */
 +
 +/*
 + * Curl_GetFTPResponse() is a BLOCKING function to read the full response
 + * from a server after a command.
 + *
 + */
 +
 +CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
 +                             struct connectdata *conn,
 +                             int *ftpcode) /* return the ftp-code */
 +{
 +  /*
 +   * We cannot read just one byte per read() and then go back to select() as
 +   * the OpenSSL read() doesn't grok that properly.
 +   *
 +   * Alas, read as much as possible, split up into lines, use the ending
 +   * line in a response or continue reading.  */
 +
 +  curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
 +  long timeout;              /* timeout in milliseconds */
 +  long interval_ms;
-   struct SessionHandle *data = conn->data;
++  struct Curl_easy *data = conn->data;
 +  CURLcode result = CURLE_OK;
 +  struct ftp_conn *ftpc = &conn->proto.ftpc;
 +  struct pingpong *pp = &ftpc->pp;
 +  size_t nread;
 +  int cache_skip=0;
 +  int value_to_be_ignored=0;
 +
 +  if(ftpcode)
 +    *ftpcode = 0; /* 0 for errors */
 +  else
 +    /* make the pointer point to something for the rest of this function */
 +    ftpcode = &value_to_be_ignored;
 +
 +  *nreadp=0;
 +
 +  while(!*ftpcode && !result) {
 +    /* check and reset timeout value every lap */
 +    timeout = Curl_pp_state_timeout(pp);
 +
-     if(timeout <=0 ) {
++    if(timeout <=0) {
 +      failf(data, "FTP response timeout");
 +      return CURLE_OPERATION_TIMEDOUT; /* already too little time */
 +    }
 +
 +    interval_ms = 1000;  /* use 1 second timeout intervals */
 +    if(timeout < interval_ms)
 +      interval_ms = timeout;
 +
 +    /*
 +     * Since this function is blocking, we need to wait here for input on the
 +     * connection and only then we call the response reading function. We do
 +     * timeout at least every second to make the timeout check run.
 +     *
 +     * A caution here is that the ftp_readresp() function has a cache that may
 +     * contain pieces of a response from the previous invoke and we need to
 +     * make sure we don't just wait for input while there is unhandled data in
 +     * that cache. But also, if the cache is there, we call ftp_readresp() and
 +     * the cache wasn't good enough to continue we must not just busy-loop
 +     * around this function.
 +     *
 +     */
 +
 +    if(pp->cache && (cache_skip < 2)) {
 +      /*
 +       * There's a cache left since before. We then skipping the wait for
 +       * socket action, unless this is the same cache like the previous round
 +       * as then the cache was deemed not enough to act on and we then need to
 +       * wait for more data anyway.
 +       */
 +    }
 +    else {
 +      switch (Curl_socket_ready(sockfd, CURL_SOCKET_BAD, interval_ms)) {
 +      case -1: /* select() error, stop reading */
 +        failf(data, "FTP response aborted due to select/poll error: %d",
 +              SOCKERRNO);
 +        return CURLE_RECV_ERROR;
 +
 +      case 0: /* timeout */
 +        if(Curl_pgrsUpdate(conn))
 +          return CURLE_ABORTED_BY_CALLBACK;
 +        continue; /* just continue in our loop for the timeout duration */
 +
 +      default: /* for clarity */
 +        break;
 +      }
 +    }
 +    result = ftp_readresp(sockfd, pp, ftpcode, &nread);
 +    if(result)
 +      break;
 +
 +    if(!nread && pp->cache)
 +      /* bump cache skip counter as on repeated skips we must wait for more
 +         data */
 +      cache_skip++;
 +    else
 +      /* when we got data or there is no cache left, we reset the cache skip
 +         counter */
 +      cache_skip=0;
 +
 +    *nreadp += nread;
 +
 +  } /* while there's buffer left and loop is requested */
 +
 +  pp->pending_resp = FALSE;
 +
 +  return result;
 +}
 +
 +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
 +  /* for debug purposes */
 +static const char * const ftp_state_names[]={
 +  "STOP",
 +  "WAIT220",
 +  "AUTH",
 +  "USER",
 +  "PASS",
 +  "ACCT",
 +  "PBSZ",
 +  "PROT",
 +  "CCC",
 +  "PWD",
 +  "SYST",
 +  "NAMEFMT",
 +  "QUOTE",
 +  "RETR_PREQUOTE",
 +  "STOR_PREQUOTE",
 +  "POSTQUOTE",
 +  "CWD",
 +  "MKD",
 +  "MDTM",
 +  "TYPE",
 +  "LIST_TYPE",
 +  "RETR_TYPE",
 +  "STOR_TYPE",
 +  "SIZE",
 +  "RETR_SIZE",
 +  "STOR_SIZE",
 +  "REST",
 +  "RETR_REST",
 +  "PORT",
 +  "PRET",
 +  "PASV",
 +  "LIST",
 +  "RETR",
 +  "STOR",
 +  "QUIT"
 +};
 +#endif
 +
 +/* This is the ONLY way to change FTP state! */
 +static void _state(struct connectdata *conn,
 +                   ftpstate newstate
 +#ifdef DEBUGBUILD
 +                   , int lineno
 +#endif
 +  )
 +{
 +  struct ftp_conn *ftpc = &conn->proto.ftpc;
 +
 +#if defined(DEBUGBUILD)
 +
 +#if defined(CURL_DISABLE_VERBOSE_STRINGS)
 +  (void) lineno;
 +#else
 +  if(ftpc->state != newstate)
 +    infof(conn->data, "FTP %p (line %d) state change from %s to %s\n",
 +          (void *)ftpc, lineno, ftp_state_names[ftpc->state],
 +          ftp_state_names[newstate]);
 +#endif
 +#endif
 +
 +  ftpc->state = newstate;
 +}
 +
 +static CURLcode ftp_state_user(struct connectdata *conn)
 +{
 +  CURLcode result;
 +  struct FTP *ftp = conn->data->req.protop;
 +  /* send USER */
 +  PPSENDF(&conn->proto.ftpc.pp, "USER %s", ftp->user?ftp->user:"");
 +
 +  state(conn, FTP_USER);
 +  conn->data->state.ftp_trying_alternative = FALSE;
 +
 +  return CURLE_OK;
 +}
 +
 +static CURLcode ftp_state_pwd(struct connectdata *conn)
 +{
 +  CURLcode result;
 +
 +  /* send PWD to discover our entry point */
 +  PPSENDF(&conn->proto.ftpc.pp, "%s", "PWD");
 +  state(conn, FTP_PWD);
 +
 +  return CURLE_OK;
 +}
 +
 +/* For the FTP "protocol connect" and "doing" phases only */
 +static int ftp_getsock(struct connectdata *conn,
 +                       curl_socket_t *socks,
 +                       int numsocks)
 +{
 +  return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
 +}
 +
 +/* For the FTP "DO_MORE" phase only */
 +static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
 +                              int numsocks)
 +{
 +  struct ftp_conn *ftpc = &conn->proto.ftpc;
 +
 +  if(!numsocks)
 +    return GETSOCK_BLANK;
 +
 +  /* When in DO_MORE state, we could be either waiting for us to connect to a
 +   * remote site, or we could wait for that site to connect to us. Or just
 +   * handle ordinary commands.
 +   */
 +
 +  if(FTP_STOP == ftpc->state) {
 +    int bits = GETSOCK_READSOCK(0);
 +
 +    /* if stopped and still in this state, then we're also waiting for a
 +       connect on the secondary connection */
 +    socks[0] = conn->sock[FIRSTSOCKET];
 +
 +    if(!conn->data->set.ftp_use_port) {
 +      int s;
 +      int i;
 +      /* PORT is used to tell the server to connect to us, and during that we
 +         don't do happy eyeballs, but we do if we connect to the server */
 +      for(s=1, i=0; i<2; i++) {
 +        if(conn->tempsock[i] != CURL_SOCKET_BAD) {
 +          socks[s] = conn->tempsock[i];
 +          bits |= GETSOCK_WRITESOCK(s++);
 +        }
 +      }
 +    }
 +    else {
 +      socks[1] = conn->sock[SECONDARYSOCKET];
 +      bits |= GETSOCK_WRITESOCK(1);
 +    }
 +
 +    return bits;
 +  }
 +  else
 +    return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
 +}
 +
 +/* This is called after the FTP_QUOTE state is passed.
 +
 +   ftp_state_cwd() sends the range of CWD commands to the server to change to
 +   the correct directory. It may also need to send MKD commands to create
 +   missing ones, if that option is enabled.
 +*/
 +static CURLcode ftp_state_cwd(struct connectdata *conn)
 +{
 +  CURLcode result = CURLE_OK;
 +  struct ftp_conn *ftpc = &conn->proto.ftpc;
 +
 +  if(ftpc->cwddone)
 +    /* already done and fine */
 +    result = ftp_state_mdtm(conn);
 +  else {
 +    ftpc->count2 = 0; /* count2 counts failed CWDs */
 +
 +    /* count3 is set to allow a MKD to fail once. In the case when first CWD
 +       fails and then MKD fails (due to another session raced it to create the
 +       dir) this then allows for a second try to CWD to it */
 +    ftpc->count3 = (conn->data->set.ftp_create_missing_dirs==2)?1:0;
 +
 +    if(conn->bits.reuse && ftpc->entrypath) {
 +      /* This is a re-used connection. Since we change directory to where the
 +         transfer is taking place, we must first get back to the original dir
 +         where we ended up after login: */
 +      ftpc->count1 = 0; /* we count this as the first path, then we add one
 +                          for all upcoming ones in the ftp->dirs[] array */
 +      PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->entrypath);
 +      state(conn, FTP_CWD);
 +    }
 +    else {
 +      if(ftpc->dirdepth) {
 +        ftpc->count1 = 1;
 +        /* issue the first CWD, the rest is sent when the CWD responses are
 +           received... */
 +        PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->dirs[ftpc->count1 -1]);
 +        state(conn, FTP_CWD);
 +      }
 +      else {
 +        /* No CWD necessary */
 +        result = ftp_state_mdtm(conn);
 +      }
 +    }
 +  }
 +  return result;
 +}
 +
 +typedef enum {
 +  EPRT,
 +  PORT,
 +  DONE
 +} ftpport;
 +
 +static CURLcode ftp_state_use_port(struct connectdata *conn,
 +                                   ftpport fcmd) /* start with this */
 +
 +{
 +  CURLcode result = CURLE_OK;
 +  struct ftp_conn *ftpc = &conn->proto.ftpc;
-   struct SessionHandle *data=conn->data;
++  struct Curl_easy *data=conn->data;
 +  curl_socket_t portsock= CURL_SOCKET_BAD;
 +  char myhost[256] = "";
 +
 +  struct Curl_sockaddr_storage ss;
 +  Curl_addrinfo *res, *ai;
 +  curl_socklen_t sslen;
 +  char hbuf[NI_MAXHOST];
 +  struct sockaddr *sa=(struct sockaddr *)&ss;
 +  struct sockaddr_in * const sa4 = (void *)sa;
 +#ifdef ENABLE_IPV6
 +  struct sockaddr_in6 * const sa6 = (void *)sa;
 +#endif
 +  char tmp[1024];
 +  static const char mode[][5] = { "EPRT", "PORT" };
 +  int rc;
 +  int error;
 +  char *host = NULL;
 +  char *string_ftpport = data->set.str[STRING_FTPPORT];
 +  struct Curl_dns_entry *h=NULL;
 +  unsigned short port_min = 0;
 +  unsigned short port_max = 0;
 +  unsigned short port;
 +  bool possibly_non_local = TRUE;
 +
 +  char *addr = NULL;
 +
 +  /* Step 1, figure out what is requested,
 +   * accepted format :
 +   * (ipv4|ipv6|domain|interface)?(:port(-range)?)?
 +   */
 +
 +  if(data->set.str[STRING_FTPPORT] &&
 +     (strlen(data->set.str[STRING_FTPPORT]) > 1)) {
 +
 +#ifdef ENABLE_IPV6
 +    size_t addrlen = INET6_ADDRSTRLEN > strlen(string_ftpport) ?
 +      INET6_ADDRSTRLEN : strlen(string_ftpport);
 +#else
 +    size_t addrlen = INET_ADDRSTRLEN > strlen(string_ftpport) ?
 +      INET_ADDRSTRLEN : strlen(string_ftpport);
 +#endif
 +    char *ip_start = string_ftpport;
 +    char *ip_end = NULL;
 +    char *port_start = NULL;
 +    char *port_sep = NULL;
 +
 +    addr = calloc(addrlen+1, 1);
 +    if(!addr)
 +      return CURLE_OUT_OF_MEMORY;
 +
 +#ifdef ENABLE_IPV6
 +    if(*string_ftpport == '[') {
 +      /* [ipv6]:port(-range) */
 +      ip_start = string_ftpport + 1;
-       if((ip_end = strchr(string_ftpport, ']')) != NULL )
++      if((ip_end = strchr(string_ftpport, ']')) != NULL)
 +        strncpy(addr, ip_start, ip_end - ip_start);
 +    }
 +    else
 +#endif
 +      if(*string_ftpport == ':') {
 +        /* :port */
 +        ip_end = string_ftpport;
 +    }
 +    else if((ip_end = strchr(string_ftpport, ':')) != NULL) {
 +        /* either ipv6 or (ipv4|domain|interface):port(-range) */
 +#ifdef ENABLE_IPV6
 +      if(Curl_inet_pton(AF_INET6, string_ftpport, sa6) == 1) {
 +        /* ipv6 */
 +        port_min = port_max = 0;
 +        strcpy(addr, string_ftpport);
 +        ip_end = NULL; /* this got no port ! */
 +      }
 +      else
 +#endif
 +        /* (ipv4|domain|interface):port(-range) */
-         strncpy(addr, string_ftpport, ip_end - ip_start );
++        strncpy(addr, string_ftpport, ip_end - ip_start);
 +    }
 +    else
 +      /* ipv4|interface */
 +      strcpy(addr, string_ftpport);
 +
 +    /* parse the port */
 +    if(ip_end != NULL) {
 +      if((port_start = strchr(ip_end, ':')) != NULL) {
 +        port_min = curlx_ultous(strtoul(port_start+1, NULL, 10));
 +        if((port_sep = strchr(port_start, '-')) != NULL) {
 +          port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10));
 +        }
 +        else
 +          port_max = port_min;
 +      }
 +    }
 +
 +    /* correct errors like:
 +     *  :1234-1230
-      *  :-4711 , in this case port_min is (unsigned)-1,
++     *  :-4711,  in this case port_min is (unsigned)-1,
 +     *           therefore port_min > port_max for all cases
 +     *           but port_max = (unsigned)-1
 +     */
-     if(port_min > port_max )
++    if(port_min > port_max)
 +      port_min = port_max = 0;
 +
 +
 +    if(*addr != '\0') {
 +      /* attempt to get the address of the given interface name */
 +      switch(Curl_if2ip(conn->ip_addr->ai_family,
 +                        Curl_ipv6_scope(conn->ip_addr->ai_addr),
 +                        conn->scope_id, addr, hbuf, sizeof(hbuf))) {
 +        case IF2IP_NOT_FOUND:
 +          /* not an interface, use the given string as host name instead */
 +          host = addr;
 +          break;
 +        case IF2IP_AF_NOT_SUPPORTED:
 +          return CURLE_FTP_PORT_FAILED;
 +        case IF2IP_FOUND:
 +          host = hbuf; /* use the hbuf for host name */
 +      }
 +    }
 +    else
 +      /* there was only a port(-range) given, default the host */
 +      host = NULL;
 +  } /* data->set.ftpport */
 +
 +  if(!host) {
 +    /* not an interface and not a host name, get default by extracting
 +       the IP from the control connection */
 +
 +    sslen = sizeof(ss);
 +    if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
 +      failf(data, "getsockname() failed: %s",
 +          Curl_strerror(conn, SOCKERRNO) );
 +      free(addr);
 +      return CURLE_FTP_PORT_FAILED;
 +    }
 +    switch(sa->sa_family) {
 +#ifdef ENABLE_IPV6
 +    case AF_INET6:
 +      Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
 +      break;
 +#endif
 +    default:
 +      Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf));
 +      break;
 +    }
 +    host = hbuf; /* use this host name */
 +    possibly_non_local = FALSE; /* we know it is local now */
 +  }
 +
 +  /* resolv ip/host to ip */
 +  rc = Curl_resolv(conn, host, 0, &h);
 +  if(rc == CURLRESOLV_PENDING)
 +    (void)Curl_resolver_wait_resolv(conn, &h);
 +  if(h) {
 +    res = h->addr;
 +    /* when we return from this function, we can forget about this entry
 +       to we can unlock it now already */
 +    Curl_resolv_unlock(data, h);
 +  } /* (h) */
 +  else
 +    res = NULL; /* failure! */
 +
 +  if(res == NULL) {
 +    failf(data, "failed to resolve the address provided to PORT: %s", host);
 +    free(addr);
 +    return CURLE_FTP_PORT_FAILED;
 +  }
 +
 +  free(addr);
 +  host = NULL;
 +
 +  /* step 2, create a socket for the requested address */
 +
 +  portsock = CURL_SOCKET_BAD;
 +  error = 0;
 +  for(ai = res; ai; ai = ai->ai_next) {
 +    result = Curl_socket(conn, ai, NULL, &portsock);
 +    if(result) {
 +      error = SOCKERRNO;
 +      continue;
 +    }
 +    break;
 +  }
 +  if(!ai) {
 +    failf(data, "socket failure: %s", Curl_strerror(conn, error));
 +    return CURLE_FTP_PORT_FAILED;
 +  }
 +
 +  /* step 3, bind to a suitable local address */
 +
 +  memcpy(sa, ai->ai_addr, ai->ai_addrlen);
 +  sslen = ai->ai_addrlen;
 +
 +  for(port = port_min; port <= port_max;) {
 +    if(sa->sa_family == AF_INET)
 +      sa4->sin_port = htons(port);
 +#ifdef ENABLE_IPV6
 +    else
 +      sa6->sin6_port = htons(port);
 +#endif
 +    /* Try binding the given address. */
 +    if(bind(portsock, sa, sslen) ) {
 +      /* It failed. */
 +      error = SOCKERRNO;
 +      if(possibly_non_local && (error == EADDRNOTAVAIL)) {
 +        /* The requested bind address is not local.  Use the address used for
 +         * the control connection instead and restart the port loop
 +         */
 +
 +        infof(data, "bind(port=%hu) on non-local address failed: %s\n", port,
 +              Curl_strerror(conn, error) );
 +
 +        sslen = sizeof(ss);
 +        if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
 +          failf(data, "getsockname() failed: %s",
 +                Curl_strerror(conn, SOCKERRNO) );
 +          Curl_closesocket(conn, portsock);
 +          return CURLE_FTP_PORT_FAILED;
 +        }
 +        port = port_min;
 +        possibly_non_local = FALSE; /* don't try this again */
 +        continue;
 +      }
 +      else if(error != EADDRINUSE && error != EACCES) {
 +        failf(data, "bind(port=%hu) failed: %s", port,
 +              Curl_strerror(conn, error) );
 +        Curl_closesocket(conn, portsock);
 +        return CURLE_FTP_PORT_FAILED;
 +      }
 +    }
 +    else
 +      break;
 +
 +    port++;
 +  }
 +
 +  /* maybe all ports were in use already*/
 +  if(port > port_max) {
 +    failf(data, "bind() failed, we ran out of ports!");
 +    Curl_closesocket(conn, portsock);
 +    return CURLE_FTP_PORT_FAILED;
 +  }
 +
 +  /* get the name again after the bind() so that we can extract the
 +     port number it uses now */
 +  sslen = sizeof(ss);
 +  if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) {
 +    failf(data, "getsockname() failed: %s",
 +          Curl_strerror(conn, SOCKERRNO) );
 +    Curl_closesocket(conn, portsock);
 +    return CURLE_FTP_PORT_FAILED;
 +  }
 +
 +  /* step 4, listen on the socket */
 +
 +  if(listen(portsock, 1)) {
 +    failf(data, "socket failure: %s", Curl_strerror(conn, SOCKERRNO));
 +    Curl_closesocket(conn, portsock);
 +    return CURLE_FTP_PORT_FAILED;
 +  }
 +
 +  /* step 5, send the proper FTP command */
 +
 +  /* get a plain printable version of the numerical address to work with
 +     below */
 +  Curl_printable_address(ai, myhost, sizeof(myhost));
 +
 +#ifdef ENABLE_IPV6
 +  if(!conn->bits.ftp_use_eprt && conn->bits.ipv6)
 +    /* EPRT is disabled but we are connected to a IPv6 host, so we ignore the
 +       request and enable EPRT again! */
 +    conn->bits.ftp_use_eprt = TRUE;
 +#endif
 +
 +  for(; fcmd != DONE; fcmd++) {
 +
 +    if(!conn->bits.ftp_use_eprt && (EPRT == fcmd))
 +      /* if disabled, goto next */
 +      continue;
 +
 +    if((PORT == fcmd) && sa->sa_family != AF_INET)
 +      /* PORT is IPv4 only */
 +      continue;
 +
 +    switch(sa->sa_family) {
 +    case AF_INET:
 +      port = ntohs(sa4->sin_port);
 +      break;
 +#ifdef ENABLE_IPV6
 +    case AF_INET6:
 +      port = ntohs(sa6->sin6_port);
 +      break;
 +#endif
 +    default:
 +      continue; /* might as well skip this */
 +    }
 +
 +    if(EPRT == fcmd) {
 +      /*
 +       * Two fine examples from RFC2428;
 +       *
 +       * EPRT |1|132.235.1.2|6275|
 +       *
 +       * EPRT |2|1080::8:800:200C:417A|5282|
 +       */
 +
 +      result = Curl_pp_sendf(&ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd],
 +                             sa->sa_family == AF_INET?1:2,
 +                             myhost, port);
 +      if(result) {
 +        failf(data, "Failure sending EPRT command: %s",
 +              curl_easy_strerror(result));
 +        Curl_closesocket(conn, portsock);
 +        /* don't retry using PORT */
 +        ftpc->count1 = PORT;
 +        /* bail out */
 +        state(conn, FTP_STOP);
 +        return result;
 +      }
 +      break;
 +    }
 +    else if(PORT == fcmd) {
 +      char *source = myhost;
 +      char *dest = tmp;
 +
 +      /* translate x.x.x.x to x,x,x,x */
 +      while(source && *source) {
 +        if(*source == '.')
 +          *dest=',';
 +        else
 +          *dest = *source;
 +        dest++;
 +        source++;
 +      }
 +      *dest = 0;
 +      snprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff));
 +
 +      result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], tmp);
 +      if(result) {
 +        failf(data, "Failure sending PORT command: %s",
 +              curl_easy_strerror(result));
 +        Curl_closesocket(conn, portsock);
 +        /* bail out */
 +        state(conn, FTP_STOP);
 +        return result;
 +      }
 +      break;
 +    }
 +  }
 +
 +  /* store which command was sent */
 +  ftpc->count1 = fcmd;
 +
++  close_secondarysocket(conn);
++
 +  /* we set the secondary socket variable to this for now, it is only so that
 +     the cleanup function will close it in case we fail before the true
 +     secondary stuff is made */
-   if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET])
-     Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
 +  conn->sock[SECONDARYSOCKET] = portsock;
 +
 +  /* this tcpconnect assignment below is a hackish work-around to make the
 +     multi interface with active FTP work - as it will not wait for a
 +     (passive) connect in Curl_is_connected().
 +
 +     The *proper* fix is to make sure that the active connection from the
 +     server is done in a non-blocking way. Currently, it is still BLOCKING.
 +  */
 +  conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE;
 +
 +  state(conn, FTP_PORT);
 +  return result;
 +}
 +
 +static CURLcode ftp_state_use_pasv(struct connectdata *conn)
 +{
 +  struct ftp_conn *ftpc = &conn->proto.ftpc;
 +  CURLcode result = CURLE_OK;
 +  /*
 +    Here's the excecutive summary on what to do:
 +
 +    PASV is RFC959, expect:
 +    227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
 +
 +    LPSV is RFC1639, expect:
 +    228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2)
 +
 +    EPSV is RFC2428, expect:
 +    229 Entering Extended Passive Mode (|||port|)
 +
 +  */
 +
 +  static const char mode[][5] = { "EPSV", "PASV" };
 +  int modeoff;
 +
 +#ifdef PF_INET6
 +  if(!conn->bits.ftp_use_epsv && conn->bits.ipv6)
 +    /* EPSV is disabled but we are connected to a IPv6 host, so we ignore the
 +       request and enable EPSV again! */
 +    conn->bits.ftp_use_epsv = TRUE;
 +#endif
 +
 +  modeoff = conn->bits.ftp_use_epsv?0:1;
 +
 +  PPSENDF(&ftpc->pp, "%s", mode[modeoff]);
 +
 +  ftpc->count1 = modeoff;
 +  state(conn, FTP_PASV);
 +  infof(conn->data, "Connect data stream passively\n");
 +
 +  return result;
 +}
 +
 +/*
 + * ftp_state_prepare_transfer() starts PORT, PASV or PRET etc.
 + *
 + * REST is the last command in the chain of commands when a "head"-like
 + * request is made. Thus, if an actual transfer is to be made this is where we
 + * take off for real.
 + */
 +static CURLcode ftp_state_prepare_transfer(struct connectdata *conn)
 +{
 +  CURLcode result = CURLE_OK;
 +  struct FTP *ftp = conn->data->req.protop;
-   struct SessionHandle *data = conn->data;
++  struct Curl_easy *data = conn->data;
 +
 +  if(ftp->transfer != FTPTRANSFER_BODY) {
 +    /* doesn't transfer any data */
 +
 +    /* still possibly do PRE QUOTE jobs */
 +    state(conn, FTP_RETR_PREQUOTE);
 +    result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
 +  }
 +  else if(data->set.ftp_use_port) {
 +    /* We have chosen to use the PORT (or similar) command */
 +    result = ftp_state_use_port(conn, EPRT);
 +  }
 +  else {
 +    /* We have chosen (this is default) to use the PASV (or similar) command */
 +    if(data->set.ftp_use_pret) {
 +      /* The user has requested that we send a PRET command
 +         to prepare the server for the upcoming PASV */
 +      if(!conn->proto.ftpc.file) {
 +        PPSENDF(&conn->proto.ftpc.pp, "PRET %s",
 +                data->set.str[STRING_CUSTOMREQUEST]?
 +                data->set.str[STRING_CUSTOMREQUEST]:
 +                (data->set.ftp_list_only?"NLST":"LIST"));
 +      }
 +      else if(data->set.upload) {
 +        PPSENDF(&conn->proto.ftpc.pp, "PRET STOR %s", conn->proto.ftpc.file);
 +      }
 +      else {
 +        PPSENDF(&conn->proto.ftpc.pp, "PRET RETR %s", conn->proto.ftpc.file);
 +      }
 +      state(conn, FTP_PRET);
 +    }
 +    else {
 +      result = ftp_state_use_pasv(conn);
 +    }
 +  }
 +  return result;
 +}
 +
 +static CURLcode ftp_state_rest(struct connectdata *conn)
 +{
 +  CURLcode result = CURLE_OK;
 +  struct FTP *ftp = conn->data->req.protop;
 +  struct ftp_conn *ftpc = &conn->proto.ftpc;
 +
 +  if((ftp->transfer != FTPTRANSFER_BODY) && ftpc->file) {
 +    /* if a "head"-like request is being made (on a file) */
 +
 +    /* Determine if server can respond to REST command and therefore
 +       whether it supports range */
 +    PPSENDF(&conn->proto.ftpc.pp, "REST %d", 0);
 +
 +    state(conn, FTP_REST);
 +  }
 +  else
 +    result = ftp_state_prepare_transfer(conn);
 +
 +  return result;
 +}
 +
 +static CURLcode ftp_state_size(struct connectdata *conn)
 +{
 +  CURLcode result = CURLE_OK;
 +  struct FTP *ftp = conn->data->req.protop;
 +  struct ftp_conn *ftpc = &conn->proto.ftpc;
 +
 +  if((ftp->transfer == FTPTRANSFER_INFO) && ftpc->file) {
 +    /* if a "head"-like request is being made (on a file) */
 +
 +    /* we know ftpc->file is a valid pointer to a file name */
 +    PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
 +
 +    state(conn, FTP_SIZE);
 +  }
 +  else
 +    result = ftp_state_rest(conn);
 +
 +  return result;
 +}
 +
 +static CURLcode ftp_state_list(struct connectdata *conn)
 +{
 +  CURLcode result = CURLE_OK;
-   struct SessionHandle *data = conn->data;
++  struct Curl_easy *data = conn->data;
 +
 +  /* If this output is to be machine-parsed, the NLST command might be better
 +     to use, since the LIST command output is not specified or standard in any
 +     way. It has turned out that the NLST list output is not the same on all
 +     servers either... */
 +
 +  /*
 +     if FTPFILE_NOCWD was specified, we are currently in
 +     the user's home directory, so we should add the path
 +     as argument for the LIST / NLST / or custom command.
 +     Whether the server will support this, is uncertain.
 +
 +     The other ftp_filemethods will CWD into dir/dir/ first and
 +     then just do LIST (in that case: nothing to do here)
 +  */
 +  char *cmd, *lstArg, *slashPos;
 +
 +  lstArg = NULL;
 +  if((data->set.ftp_filemethod == FTPFILE_NOCWD) &&
 +     data->state.path &&
 +     data->state.path[0] &&
 +     strchr(data->state.path, '/')) {
 +
 +    lstArg = strdup(data->state.path);
 +    if(!lstArg)
 +      return CURLE_OUT_OF_MEMORY;
 +
 +    /* Check if path does not end with /, as then we cut off the file part */
 +    if(lstArg[strlen(lstArg) - 1] != '/')  {
 +
 +      /* chop off the file part if format is dir/dir/file */
 +      slashPos = strrchr(lstArg, '/');
 +      if(slashPos)
 +        *(slashPos+1) = '\0';
 +    }
 +  }
 +
-   cmd = aprintf( "%s%s%s",
-                  data->set.str[STRING_CUSTOMREQUEST]?
-                  data->set.str[STRING_CUSTOMREQUEST]:
-                  (data->set.ftp_list_only?"NLST":"LIST"),
-                  lstArg? " ": "",
-                  lstArg? lstArg: "" );
++  cmd = aprintf("%s%s%s",
++                data->set.str[STRING_CUSTOMREQUEST]?
++                data->set.str[STRING_CUSTOMREQUEST]:
++                (data->set.ftp_list_only?"NLST":"LIST"),
++                lstArg? " ": "",
++                lstArg? lstArg: "");
 +
 +  if(!cmd) {
 +    free(lstArg);
 +    return CURLE_OUT_OF_MEMORY;
 +  }
 +
 +  result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", cmd);
 +
 +  free(lstArg);
 +  free(cmd);
 +
 +  if(result)
 +    return result;
 +
 +  state(conn, FTP_LIST);
 +
 +  return result;
 +}
 +
 +static CURLcode ftp_state_retr_prequote(struct connectdata *conn)
 +{
 +  CURLcode result = CURLE_OK;
 +
 +  /* We've sent the TYPE, now we must send the list of prequote strings */
 +
 +  result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
 +
 +  return result;
 +}
 +
 +static CURLcode ftp_state_stor_prequote(struct connectdata *conn)
 +{
 +  CURLcode result = CURLE_OK;
 +
 +  /* We've sent the TYPE, now we must send the list of prequote strings */
 +
 +  result = ftp_state_quote(conn, TRUE, FTP_STOR_PREQUOTE);
 +
 +  return result;
 +}
 +
 +static CURLcode ftp_state_type(struct connectdata *conn)
 +{
 +  CURLcode result = CURLE_OK;
 +  struct FTP *ftp = conn->data->req.protop;
-   struct SessionHandle *data = conn->data;
++  struct Curl_easy *data = conn->data;
 +  struct ftp_conn *ftpc = &conn->proto.ftpc;
 +
 +  /* If we have selected NOBODY and HEADER, it means that we only want file
 +     information. Which in FTP can't be much more than the file size and
 +     date. */
 +  if(data->set.opt_no_body && ftpc->file &&
 +     ftp_need_type(conn, data->set.prefer_ascii)) {
 +    /* The SIZE command is _not_ RFC 959 specified, and therefor many servers
 +       may not support it! It is however the only way we have to get a file's
 +       size! */
 +
 +    ftp->transfer = FTPTRANSFER_INFO;
 +    /* this means no actual transfer will be made */
 +
 +    /* Some servers return different sizes for different modes, and thus we
 +       must set the proper type before we check the size */
 +    result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_TYPE);
 +    if(result)
 +      return result;
 +  }
 +  else
 +    result = ftp_state_size(conn);
 +
 +  return result;
 +}
 +
 +/* This is called after the CWD commands have been done in the beginning of
 +   the DO phase */
 +static CURLcode ftp_state_mdtm(struct connectdata *conn)
 +{
 +  CURLcode result = CURLE_OK;
-   struct SessionHandle *data = conn->data;
++  struct Curl_easy *data = conn->data;
 +  struct ftp_conn *ftpc = &conn->proto.ftpc;
 +
 +  /* Requested time of file or time-depended transfer? */
 +  if((data->set.get_filetime || data->set.timecondition) && ftpc->file) {
 +
 +    /* we have requested to get the modified-time of the file, this is a white
 +       spot as the MDTM is not mentioned in RFC959 */
 +    PPSENDF(&ftpc->pp, "MDTM %s", ftpc->file);
 +
 +    state(conn, FTP_MDTM);
 +  }
 +  else
 +    result = ftp_state_type(conn);
 +
 +  return result;
 +}
 +
 +
 +/* This is called after the TYPE and possible quote commands have been sent */
 +static CURLcode ftp_state_ul_setup(struct connectdata *conn,
 +                                   bool sizechecked)
 +{
 +  CURLcode result = CURLE_OK;
 +  struct FTP *ftp = conn->data->req.protop;
-   struct SessionHandle *data = conn->data;
++  struct Curl_easy *data = conn->data;
 +  struct ftp_conn *ftpc = &conn->proto.ftpc;
 +  int seekerr = CURL_SEEKFUNC_OK;
 +
 +  if((data->state.resume_from && !sizechecked) ||
 +     ((data->state.resume_from > 0) && sizechecked)) {
 +    /* we're about to continue the uploading of a file */
 +    /* 1. get already existing file's size. We use the SIZE command for this
 +       which may not exist in the server!  The SIZE command is not in
 +       RFC959. */
 +
 +    /* 2. This used to set REST. But since we can do append, we
 +       don't another ftp command. We just skip the source file
 +       offset and then we APPEND the rest on the file instead */
 +
 +    /* 3. pass file-size number of bytes in the source file */
 +    /* 4. lower the infilesize counter */
 +    /* => transfer as usual */
 +
-     if(data->state.resume_from < 0 ) {
++    if(data->state.resume_from < 0) {
 +      /* Got no given size to start from, figure it out */
 +      PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
 +      state(conn, FTP_STOR_SIZE);
 +      return result;
 +    }
 +
 +    /* enable append */
 +    data->set.ftp_append = TRUE;
 +
 +    /* Let's read off the proper amount of bytes from the input. */
 +    if(conn->seek_func) {
 +      seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
 +                                SEEK_SET);
 +    }
 +
 +    if(seekerr != CURL_SEEKFUNC_OK) {
 +      if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
 +        failf(data, "Could not seek stream");
 +        return CURLE_FTP_COULDNT_USE_REST;
 +      }
 +      /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
 +      else {
 +        curl_off_t passed=0;
 +        do {
 +          size_t readthisamountnow =
 +            (data->state.resume_from - passed > CURL_OFF_T_C(BUFSIZE)) ?
 +            BUFSIZE : curlx_sotouz(data->state.resume_from - passed);
 +
 +          size_t actuallyread =
-             data->set.fread_func(data->state.buffer, 1, readthisamountnow,
-                                  data->set.in);
++            data->state.fread_func(data->state.buffer, 1, readthisamountnow,
++                                   data->state.in);
 +
 +          passed += actuallyread;
 +          if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
 +            /* this checks for greater-than only to make sure that the
 +               CURL_READFUNC_ABORT return code still aborts */
 +            failf(data, "Failed to read data");
 +            return CURLE_FTP_COULDNT_USE_REST;
 +          }
 +        } while(passed < data->state.resume_from);
 +      }
 +    }
 +    /* now, decrease the size of the read */
 +    if(data->state.infilesize>0) {
 +      data->state.infilesize -= data->state.resume_from;
 +
 +      if(data->state.infilesize <= 0) {
 +        infof(data, "File already completely uploaded\n");
 +
 +        /* no data to transfer */
 +        Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
 +
 +        /* Set ->transfer so that we won't get any error in
 +         * ftp_done() because we didn't transfer anything! */
 +        ftp->transfer = FTPTRANSFER_NONE;
 +
 +        state(conn, FTP_STOP);
 +        return CURLE_OK;
 +      }
 +    }
 +    /* we've passed, proceed as normal */
 +  } /* resume_from */
 +
 +  PPSENDF(&ftpc->pp, data->set.ftp_append?"APPE %s":"STOR %s",
 +          ftpc->file);
 +
 +  state(conn, FTP_STOR);
 +
 +  return result;
 +}
 +
 +static CURLcode ftp_state_quote(struct connectdata *conn,
 +                                bool init,
 +                                ftpstate instate)
 +{
 +  CURLcode result = CURLE_OK;
-   struct SessionHandle *data = conn->data;
++  struct Curl_easy *data = conn->data;
 +  struct FTP *ftp = data->req.protop;
 +  struct ftp_conn *ftpc = &conn->proto.ftpc;
 +  bool quote=FALSE;
 +  struct curl_slist *item;
 +
 +  switch(instate) {
 +  case FTP_QUOTE:
 +  default:
 +    item = data->set.quote;
 +    break;
 +  case FTP_RETR_PREQUOTE:
 +  case FTP_STOR_PREQUOTE:
 +    item = data->set.prequote;
 +    break;
 +  case FTP_POSTQUOTE:
 +    item = data->set.postquote;
 +    break;
 +  }
 +
 +  /*
 +   * This state uses:
 +   * 'count1' to iterate over the commands to send
 +   * 'count2' to store wether to allow commands to fail
 +   */
 +
 +  if(init)
 +    ftpc->count1 = 0;
 +  else
 +    ftpc->count1++;
 +
 +  if(item) {
 +    int i = 0;
 +
 +    /* Skip count1 items in the linked list */
 +    while((i< ftpc->count1) && item) {
 +      item = item->next;
 +      i++;
 +    }
 +    if(item) {
 +      char *cmd = item->data;
 +      if(cmd[0] == '*') {
 +        cmd++;
 +        ftpc->count2 = 1; /* the sent command is allowed to fail */
 +      }
 +      else
 +        ftpc->count2 = 0; /* failure means cancel operation */
 +
 +      PPSENDF(&ftpc->pp, "%s", cmd);
 +      state(conn, instate);
 +      quote = TRUE;
 +    }
 +  }
 +
 +  if(!quote) {
 +    /* No more quote to send, continue to ... */
 +    switch(instate) {
 +    case FTP_QUOTE:
 +    default:
 +      result = ftp_state_cwd(conn);
 +      break;
 +    case FTP_RETR_PREQUOTE:
 +      if(ftp->transfer != FTPTRANSFER_BODY)
 +        state(conn, FTP_STOP);
 +      else {
 +        if(ftpc->known_filesize != -1) {
 +          Curl_pgrsSetDownloadSize(data, ftpc->known_filesize);
 +          result = ftp_state_retr(conn, ftpc->known_filesize);
 +        }
 +        else {
-           PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
-           state(conn, FTP_RETR_SIZE);
++          if(data->set.ignorecl) {
++            /* This code is to support download of growing files.  It prevents
++               the state machine from requesting the file size from the
++               server.  With an unknown file size the download continues until
++               the server terminates it, otherwise the client stops if the
++               received byte count exceeds the reported file size.  Set option
++               CURLOPT_IGNORE_CONTENT_LENGTH to 1 to enable this behavior.*/
++            PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
++            state(conn, FTP_RETR);
++          }
++          else {
++            PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
++            state(conn, FTP_RETR_SIZE);
++          }
 +        }
 +      }
 +      break;
 +    case FTP_STOR_PREQUOTE:
 +      result = ftp_state_ul_setup(conn, FALSE);
 +      break;
 +    case FTP_POSTQUOTE:
 +      break;
 +    }
 +  }
 +
 +  return result;
 +}
 +
 +/* called from ftp_state_pasv_resp to switch to PASV in case of EPSV
 +   problems */
 +static CURLcode ftp_epsv_disable(struct connectdata *conn)
 +{
 +  CURLcode result = CURLE_OK;
 +
 +  if(conn->bits.ipv6) {
 +    /* We can't disable EPSV when doing IPv6, so this is instead a fail */
 +    failf(conn->data, "Failed EPSV attempt, exiting\n");
 +    return CURLE_FTP_WEIRD_SERVER_REPLY;
 +  }
 +
 +  infof(conn->data, "Failed EPSV attempt. Disabling EPSV\n");
 +  /* disable it for next transfer */
 +  conn->bits.ftp_use_epsv = FALSE;
 +  conn->data->state.errorbuf = FALSE; /* allow error message to get
 +                                         rewritten */
 +  PPSENDF(&conn->proto.ftpc.pp, "%s", "PASV");
 +  conn->proto.ftpc.count1++;
 +  /* remain in/go to the FTP_PASV state */
 +  state(conn, FTP_PASV);
 +  return result;
 +}
 +
 +/*
 + * Perform the necessary magic that needs to be done once the TCP connection
 + * to the proxy has completed.
 + */
 +static CURLcode proxy_magic(struct connectdata *conn,
 +                            char *newhost, unsigned short newport,
 +                            bool *magicdone)
 +{
 +  CURLcode result = CURLE_OK;
-   struct SessionHandle *data = conn->data;
++  struct Curl_easy *data = conn->data;
 +
 +#if defined(CURL_DISABLE_PROXY)
 +  (void) newhost;
 +  (void) newport;
 +#endif
 +
 +  *magicdone = FALSE;
 +
 +  switch(conn->proxytype) {
 +  case CURLPROXY_SOCKS5:
 +  case CURLPROXY_SOCKS5_HOSTNAME:
 +    result = Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, newhost,
 +                         newport, SECONDARYSOCKET, conn);
 +    *magicdone = TRUE;
 +    break;
 +  case CURLPROXY_SOCKS4:
 +    result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
 +                         SECONDARYSOCKET, conn, FALSE);
 +    *magicdone = TRUE;
 +    break;
 +  case CURLPROXY_SOCKS4A:
 +    result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
 +                         SECONDARYSOCKET, conn, TRUE);
 +    *magicdone = TRUE;
 +    break;
 +  case CURLPROXY_HTTP:
 +  case CURLPROXY_HTTP_1_0:
 +    /* do nothing here. handled later. */
 +    break;
 +  default:
 +    failf(data, "unknown proxytype option given");
 +    result = CURLE_COULDNT_CONNECT;
 +    break;
 +  }
 +
 +  if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
 +    /* BLOCKING */
 +    /* We want "seamless" FTP operations through HTTP proxy tunnel */
 +
 +    /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the
 +     * member conn->proto.http; we want FTP through HTTP and we have to
 +     * change the member temporarily for connecting to the HTTP proxy. After
 +     * Curl_proxyCONNECT we have to set back the member to the original
 +     * struct FTP pointer
 +     */
 +    struct HTTP http_proxy;
 +    struct FTP *ftp_save = data->req.protop;
 +    memset(&http_proxy, 0, sizeof(http_proxy));
 +    data->req.protop = &http_proxy;
 +
 +    result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport, TRUE);
 +
 +    data->req.protop = ftp_save;
 +
 +    if(result)
 +      return result;
 +
 +    if(conn->tunnel_state[SECONDARYSOCKET] != TUNNEL_COMPLETE) {
 +      /* the CONNECT procedure is not complete, the tunnel is not yet up */
 +      state(conn, FTP_STOP); /* this phase is completed */
 +      return result;
 +    }
 +    else
 +      *magicdone = TRUE;
 +  }
 +
 +  return result;
 +}
 +
 +static char *control_address(struct connectdata *conn)
 +{
 +  /* Returns the control connection IP address.
 +     If a proxy tunnel is used, returns the original host name instead, because
 +     the effective control connection address is the proxy address,
 +     not the ftp host. */
 +  if(conn->bits.tunnel_proxy ||
 +     conn->proxytype == CURLPROXY_SOCKS5 ||
 +     conn->proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
 +     conn->proxytype == CURLPROXY_SOCKS4 ||
 +     conn->proxytype == CURLPROXY_SOCKS4A)
 +    return conn->host.name;
 +
 +  return conn->ip_addr_str;
 +}
 +
 +static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
 +                                    int ftpcode)
 +{
 +  struct ftp_conn *ftpc = &conn->proto.ftpc;
 +  CURLcode result;
-   struct SessionHandle *data=conn->data;
++  struct Curl_easy *data=conn->data;
 +  struct Curl_dns_entry *addr=NULL;
 +  int rc;
 +  unsigned short connectport; /* the local port connect() should use! */
 +  char *str=&data->state.buffer[4];  /* start on the first letter */
 +
 +  /* if we come here again, make sure the former name is cleared */
 +  Curl_safefree(ftpc->newhost);
 +
 +  if((ftpc->count1 == 0) &&
 +     (ftpcode == 229)) {
 +    /* positive EPSV response */
 +    char *ptr = strchr(str, '(');
 +    if(ptr) {
 +      unsigned int num;
 +      char separator[4];
 +      ptr++;
 +      if(5 == sscanf(ptr, "%c%c%c%u%c",
 +                     &separator[0],
 +                     &separator[1],
 +                     &separator[2],
 +                     &num,
 +                     &separator[3])) {
 +        const char sep1 = separator[0];
 +        int i;
 +
 +        /* The four separators should be identical, or else this is an oddly
 +           formatted reply and we bail out immediately. */
 +        for(i=1; i<4; i++) {
 +          if(separator[i] != sep1) {
 +            ptr=NULL; /* set to NULL to signal error */
 +            break;
 +          }
 +        }
 +        if(num > 0xffff) {
 +          failf(data, "Illegal port number in EPSV reply");
 +          return CURLE_FTP_WEIRD_PASV_REPLY;
 +        }
 +        if(ptr) {
 +          ftpc->newport = (unsigned short)(num & 0xffff);
 +          ftpc->newhost = strdup(control_address(conn));
 +          if(!ftpc->newhost)
 +            return CURLE_OUT_OF_MEMORY;
 +        }
 +      }
 +      else
 +        ptr=NULL;
 +    }
 +    if(!ptr) {
 +      failf(data, "Weirdly formatted EPSV reply");
 +      return CURLE_FTP_WEIRD_PASV_REPLY;
 +    }
 +  }
 +  else if((ftpc->count1 == 1) &&
 +          (ftpcode == 227)) {
 +    /* positive PASV response */
 +    int ip[4];
 +    int port[2];
 +
 +    /*
 +     * Scan for a sequence of six comma-separated numbers and use them as
 +     * IP+port indicators.
 +     *
 +     * Found reply-strings include:
 +     * "227 Entering Passive Mode (127,0,0,1,4,51)"
 +     * "227 Data transfer will passively listen to 127,0,0,1,4,51"
 +     * "227 Entering passive mode. 127,0,0,1,4,51"
 +     */
 +    while(*str) {
 +      if(6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
 +                     &ip[0], &ip[1], &ip[2], &ip[3],
 +                     &port[0], &port[1]))
 +        break;
 +      str++;
 +    }
 +
 +    if(!*str) {
 +      failf(data, "Couldn't interpret the 227-response");
 +      return CURLE_FTP_WEIRD_227_FORMAT;
 +    }
 +
 +    /* we got OK from server */
 +    if(data->set.ftp_skip_ip) {
 +      /* told to ignore the remotely given IP but instead use the host we used
 +         for the control connection */
 +      infof(data, "Skip %d.%d.%d.%d for data connection, re-use %s instead\n",
 +            ip[0], ip[1], ip[2], ip[3],
 +            conn->host.name);
 +      ftpc->newhost = strdup(control_address(conn));
 +    }
 +    else
 +      ftpc->newhost = aprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
 +
 +    if(!ftpc->newhost)
 +      return CURLE_OUT_OF_MEMORY;
 +
 +    ftpc->newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff);
 +  }
 +  else if(ftpc->count1 == 0) {
 +    /* EPSV failed, move on to PASV */
 +    return ftp_epsv_disable(conn);
 +  }
 +  else {
 +    failf(data, "Bad PASV/EPSV response: %03d", ftpcode);
 +    return CURLE_FTP_WEIRD_PASV_REPLY;
 +  }
 +
 +  if(conn->bits.proxy) {
 +    /*
 +     * This connection uses a proxy and we need to connect to the proxy again
 +     * here. We don't want to rely on a former host lookup that might've
 +     * expired now, instead we remake the lookup here and now!
 +     */
 +    rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &addr);
 +    if(rc == CURLRESOLV_PENDING)
 +      /* BLOCKING, ignores the return code but 'addr' will be NULL in
 +         case of failure */
 +      (void)Curl_resolver_wait_resolv(conn, &addr);
 +
 +    connectport =
 +      (unsigned short)conn->port; /* we connect to the proxy's port */
 +
 +    if(!addr) {
 +      failf(data, "Can't resolve proxy host %s:%hu",
 +            conn->proxy.name, connectport);
 +      return CURLE_FTP_CANT_GET_HOST;
 +    }
 +  }
 +  else {
 +    /* normal, direct, ftp connection */
 +    rc = Curl_resolv(conn, ftpc->newhost, ftpc->newport, &addr);
 +    if(rc == CURLRESOLV_PENDING)
 +      /* BLOCKING */
 +      (void)Curl_resolver_wait_resolv(conn, &addr);
 +
 +    connectport = ftpc->newport; /* we connect to the remote port */
 +
 +    if(!addr) {
 +      failf(data, "Can't resolve new host %s:%hu", ftpc->newhost, connectport);
 +      return CURLE_FTP_CANT_GET_HOST;
 +    }
 +  }
 +
 +  conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
 +  result = Curl_connecthost(conn, addr);
 +
 +  if(result) {
 +    Curl_resolv_unlock(data, addr); /* we're done using this address */
 +    if(ftpc->count1 == 0 && ftpcode == 229)
 +      return ftp_epsv_disable(conn);
 +
 +    return result;
 +  }
 +
 +
 +  /*
 +   * When this is used from the multi interface, this might've returned with
 +   * the 'connected' set to FALSE and thus we are now awaiting a non-blocking
 +   * connect to connect.
 +   */
 +
 +  if(data->set.verbose)
 +    /* this just dumps information about this second connection */
 +    ftp_pasv_verbose(conn, addr->addr, ftpc->newhost, connectport);
 +
 +  Curl_resolv_unlock(data, addr); /* we're done using this address */
 +  conn->bits.do_more = TRUE;
 +  state(conn, FTP_STOP); /* this phase is completed */
 +
 +  return result;
 +}
 +
 +static CURLcode ftp_state_port_resp(struct connectdata *conn,
 +                                    int ftpcode)
 +{
-   struct SessionHandle *data = conn->data;
++  struct Curl_easy *data = conn->data;
 +  struct ftp_conn *ftpc = &conn->proto.ftpc;
 +  ftpport fcmd = (ftpport)ftpc->count1;
 +  CURLcode result = CURLE_OK;
 +
 +  /* The FTP spec tells a positive response should have code 200.
 +     Be more permissive here to tolerate deviant servers. */
 +  if(ftpcode / 100 != 2) {
 +    /* the command failed */
 +
 +    if(EPRT == fcmd) {
 +      infof(data, "disabling EPRT usage\n");
 +      conn->bits.ftp_use_eprt = FALSE;
 +    }
 +    fcmd++;
 +
 +    if(fcmd == DONE) {
 +      failf(data, "Failed to do PORT");
 +      result = CURLE_FTP_PORT_FAILED;
 +    }
 +    else
 +      /* try next */
 +      result = ftp_state_use_port(conn, fcmd);
 +  }
 +  else {
 +    infof(data, "Connect data stream actively\n");
 +    state(conn, FTP_STOP); /* end of DO phase */
 +    result = ftp_dophase_done(conn, FALSE);
 +  }
 +
 +  return result;
 +}
 +
 +static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
 +                                    int ftpcode)
 +{
 +  CURLcode result = CURLE_OK;
-   struct SessionHandle *data=conn->data;
++  struct Curl_easy *data=conn->data;
 +  struct FTP *ftp = data->req.protop;
 +  struct ftp_conn *ftpc = &conn->proto.ftpc;
 +
 +  switch(ftpcode) {
 +  case 213:
 +    {
 +      /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
 +         last .sss part is optional and means fractions of a second */
 +      int year, month, day, hour, minute, second;
 +      char *buf = data->state.buffer;
 +      if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d",
 +                     &year, &month, &day, &hour, &minute, &second)) {
 +        /* we have a time, reformat it */
 +        time_t secs=time(NULL);
 +        /* using the good old yacc/bison yuck */
 +        snprintf(buf, sizeof(conn->data->state.buffer),
 +                 "%04d%02d%02d %02d:%02d:%02d GMT",
 +                 year, month, day, hour, minute, second);
 +        /* now, convert this into a time() value: */
 +        data->info.filetime = (long)curl_getdate(buf, &secs);
 +      }
 +
 +#ifdef CURL_FTP_HTTPSTYLE_HEAD
 +      /* If we asked for a time of the file and we actually got one as well,
 +         we "emulate" a HTTP-style header in our output. */
 +
 +      if(data->set.opt_no_body &&
 +         ftpc->file &&
 +         data->set.get_filetime &&
 +         (data->info.filetime>=0) ) {
 +        time_t filetime = (time_t)data->info.filetime;
 +        struct tm buffer;
 +        const struct tm *tm = &buffer;
 +
 +        result = Curl_gmtime(filetime, &buffer);
 +        if(result)
 +          return result;
 +
 +        /* format: "Tue, 15 Nov 1994 12:45:26" */
 +        snprintf(buf, BUFSIZE-1,
 +                 "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
 +                 Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
 +                 tm->tm_mday,
 +                 Curl_month[tm->tm_mon],
 +                 tm->tm_year + 1900,
 +                 tm->tm_hour,
 +                 tm->tm_min,
 +                 tm->tm_sec);
 +        result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
 +        if(result)
 +          return result;
 +      } /* end of a ridiculous amount of conditionals */
 +#endif
 +    }
 +    break;
 +  default:
 +    infof(data, "unsupported MDTM reply format\n");
 +    break;
 +  case 550: /* "No such file or directory" */
 +    failf(data, "Given file does not exist");
 +    result = CURLE_FTP_COULDNT_RETR_FILE;
 +    break;
 +  }
 +
 +  if(data->set.timecondition) {
 +    if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
 +      switch(data->set.timecondition) {
 +      case CURL_TIMECOND_IFMODSINCE:
 +      default:
 +        if(data->info.filetime <= data->set.timevalue) {
 +          infof(data, "The requested document is not new enough\n");
 +          ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
 +          data->info.timecond = TRUE;
 +          state(conn, FTP_STOP);
 +          return CURLE_OK;
 +        }
 +        break;
 +      case CURL_TIMECOND_IFUNMODSINCE:
 +        if(data->info.filetime > data->set.timevalue) {
 +          infof(data, "The requested document is not old enough\n");
 +          ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
 +          data->info.timecond = TRUE;
 +          state(conn, FTP_STOP);
 +          return CURLE_OK;
 +        }
 +        break;
 +      } /* switch */
 +    }
 +    else {
 +      infof(data, "Skipping time comparison\n");
 +    }
 +  }
 +
 +  if(!result)
 +    result = ftp_state_type(conn);
 +
 +  return result;
 +}
 +
 +static CURLcode ftp_state_type_resp(struct connectdata *conn,
 +                                    int ftpcode,
 +                                    ftpstate instate)
 +{
 +  CURLcode result = CURLE_OK;
-   struct SessionHandle *data=conn->data;
++  struct Curl_easy *data=conn->data;
 +
 +  if(ftpcode/100 != 2) {
 +    /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a
 +       successful 'TYPE I'. While that is not as RFC959 says, it is still a
 +       positive response code and we allow that. */
 +    failf(data, "Couldn't set desired mode");
 +    return CURLE_FTP_COULDNT_SET_TYPE;
 +  }
 +  if(ftpcode != 200)
 +    infof(data, "Got a %03d response code instead of the assumed 200\n",
 +          ftpcode);
 +
 +  if(instate == FTP_TYPE)
 +    result = ftp_state_size(conn);
 +  else if(instate == FTP_LIST_TYPE)
 +    result = ftp_state_list(conn);
 +  else if(instate == FTP_RETR_TYPE)
 +    result = ftp_state_retr_prequote(conn);
 +  else if(instate == FTP_STOR_TYPE)
 +    result = ftp_state_stor_prequote(conn);
 +
 +  return result;
 +}
 +
 +static CURLcode ftp_state_retr(struct connectdata *conn,
 +                                         curl_off_t filesize)
 +{
 +  CURLcode result = CURLE_OK;
-   struct SessionHandle *data=conn->data;
++  struct Curl_easy *data=conn->data;
 +  struct FTP *ftp = data->req.protop;
 +  struct ftp_conn *ftpc = &conn->proto.ftpc;
 +
 +  if(data->set.max_filesize && (filesize > data->set.max_filesize)) {
 +    failf(data, "Maximum file size exceeded");
 +    return CURLE_FILESIZE_EXCEEDED;
 +  }
 +  ftp->downloadsize = filesize;
 +
 +  if(data->state.resume_from) {
 +    /* We always (attempt to) get the size of downloads, so it is done before
 +       this even when not doing resumes. */
 +    if(filesize == -1) {
 +      infof(data, "ftp server doesn't support SIZE\n");
 +      /* We couldn't get the size and therefore we can't know if there really
 +         is a part of the file left to get, although the server will just
 +         close the connection when we start the connection so it won't cause
 +         us any harm, just not make us exit as nicely. */
 +    }
 +    else {
 +      /* We got a file size report, so we check that there actually is a
 +         part of the file left to get, or else we go home.  */
 +      if(data->state.resume_from< 0) {
 +        /* We're supposed to download the last abs(from) bytes */
 +        if(filesize < -data->state.resume_from) {
 +          failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
 +                ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
 +                data->state.resume_from, filesize);
 +          return CURLE_BAD_DOWNLOAD_RESUME;
 +        }
 +        /* convert to size to download */
 +        ftp->downloadsize = -data->state.resume_from;
 +        /* download from where? */
 +        data->state.resume_from = filesize - ftp->downloadsize;
 +      }
 +      else {
 +        if(filesize < data->state.resume_from) {
 +          failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
 +                ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
 +                data->state.resume_from, filesize);
 +          return CURLE_BAD_DOWNLOAD_RESUME;
 +        }
 +        /* Now store the number of bytes we are expected to download */
 +        ftp->downloadsize = filesize-data->state.resume_from;
 +      }
 +    }
 +
 +    if(ftp->downloadsize == 0) {
 +      /* no data to transfer */
 +      Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
 +      infof(data, "File already completely downloaded\n");
 +
 +      /* Set ->transfer so that we won't get any error in ftp_done()
 +       * because we didn't transfer the any file */
 +      ftp->transfer = FTPTRANSFER_NONE;
 +      state(conn, FTP_STOP);
 +      return CURLE_OK;
 +    }
 +
 +    /* Set resume file transfer offset */
 +    infof(data, "Instructs server to resume from offset %"
 +          CURL_FORMAT_CURL_OFF_T "\n", data->state.resume_from);
 +
 +    PPSENDF(&ftpc->pp, "REST %" CURL_FORMAT_CURL_OFF_T,
 +            data->state.resume_from);
 +
 +    state(conn, FTP_RETR_REST);
 +  }
 +  else {
 +    /* no resume */
 +    PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
 +    state(conn, FTP_RETR);
 +  }
 +
 +  return result;
 +}
 +
 +static CURLcode ftp_state_size_resp(struct connectdata *conn,
 +                                    int ftpcode,
 +                                    ftpstate instate)
 +{
 +  CURLcode result = CURLE_OK;
-   struct SessionHandle *data=conn->data;
++  struct Curl_easy *data=conn->data;
 +  curl_off_t filesize;
 +  char *buf = data->state.buffer;
 +
 +  /* get the size from the ascii string: */
 +  filesize = (ftpcode == 213)?curlx_strtoofft(buf+4, NULL, 0):-1;
 +
 +  if(instate == FTP_SIZE) {
 +#ifdef CURL_FTP_HTTPSTYLE_HEAD
 +    if(-1 != filesize) {
 +      snprintf(buf, sizeof(data->state.buffer),
 +               "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize);
 +      result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
 +      if(result)
 +        return result;
 +    }
 +#endif
 +    Curl_pgrsSetDownloadSize(data, filesize);
 +    result = ftp_state_rest(conn);
 +  }
 +  else if(instate == FTP_RETR_SIZE) {
 +    Curl_pgrsSetDownloadSize(data, filesize);
 +    result = ftp_state_retr(conn, filesize);
 +  }
 +  else if(instate == FTP_STOR_SIZE) {
 +    data->state.resume_from = filesize;
 +    result = ftp_state_ul_setup(conn, TRUE);
 +  }
 +
 +  return result;
 +}
 +
 +static CURLcode ftp_state_rest_resp(struct connectdata *conn,
 +                                    int ftpcode,
 +                                    ftpstate instate)
 +{
 +  CURLcode result = CURLE_OK;
 +  struct ftp_conn *ftpc = &conn->proto.ftpc;
 +
 +  switch(instate) {
 +  case FTP_REST:
 +  default:
 +#ifdef CURL_FTP_HTTPSTYLE_HEAD
 +    if(ftpcode == 350) {
 +      char buffer[24]= { "Accept-ranges: bytes\r\n" };
 +      result = Curl_client_write(conn, CLIENTWRITE_BOTH, buffer, 0);
 +      if(result)
 +        return result;
 +    }
 +#endif
 +    result = ftp_state_prepare_transfer(conn);
 +    break;
 +
 +  case FTP_RETR_REST:
 +    if(ftpcode != 350) {
 +      failf(conn->data, "Couldn't use REST");
 +      result = CURLE_FTP_COULDNT_USE_REST;
 +    }
 +    else {
 +      PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
 +      state(conn, FTP_RETR);
 +    }
 +    break;
 +  }
 +
 +  return result;
 +}
 +
 +static CURLcode ftp_state_stor_resp(struct connectdata *conn,
 +                                    int ftpcode, ftpstate instate)
 +{
 +  CURLcode result = CURLE_OK;
-   struct SessionHandle *data = conn->data;
++  struct Curl_easy *data = conn->data;
 +
 +  if(ftpcode>=400) {
 +    failf(data, "Failed FTP upload: %0d", ftpcode);
 +    state(conn, FTP_STOP);
 +    /* oops, we never close the sockets! */
 +    return CURLE_UPLOAD_FAILED;
 +  }
 +
 +  conn->proto.ftpc.state_saved = instate;
 +
 +  /* PORT means we are now awaiting the server to connect to us. */
 +  if(data->set.ftp_use_port) {
 +    bool connected;
 +
 +    state(conn, FTP_STOP); /* no longer in STOR state */
 +
 +    result = AllowServerConnect(conn, &connected);
 +    if(result)
 +      return result;
 +
 +    if(!connected) {
 +      struct ftp_conn *ftpc = &conn->proto.ftpc;
 +      infof(data, "Data conn was not available immediately\n");
 +      ftpc->wait_data_conn = TRUE;
 +    }
 +
 +    return CURLE_OK;
 +  }
 +  else
 +    return InitiateTransfer(conn);
 +}
 +
 +/* for LIST and RETR responses */
 +static CURLcode ftp_state_get_resp(struct connectdata *conn,
 +                                    int ftpcode,
 +                                    ftpstate instate)
 +{
 +  CURLcode result = CURLE_OK;
-   struct SessionHandle *data = conn->data;
++  struct Curl_easy *data = conn->data;
 +  struct FTP *ftp = data->req.protop;
 +  char *buf = data->state.buffer;
 +
 +  if((ftpcode == 150) || (ftpcode == 125)) {
 +
 +    /*
 +      A;
 +      150 Opening BINARY mode data connection for /etc/passwd (2241
 +      bytes).  (ok, the file is being transferred)
 +
 +      B:
 +      150 Opening ASCII mode data connection for /bin/ls
 +
 +      C:
 +      150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes).
 +
 +      D:
 +      150 Opening ASCII mode data connection for [file] (0.0.0.0,0) (545 bytes)
 +
 +      E:
 +      125 Data connection already open; Transfer starting. */
 +
 +    curl_off_t size=-1; /* default unknown size */
 +
 +
 +    /*
 +     * It appears that there are FTP-servers that return size 0 for files when
 +     * SIZE is used on the file while being in BINARY mode. To work around
 +     * that (stupid) behavior, we attempt to parse the RETR response even if
 +     * the SIZE returned size zero.
 +     *
 +     * Debugging help from Salvatore Sorrentino on February 26, 2003.
 +     */
 +
 +    if((instate != FTP_LIST) &&
 +       !data->set.prefer_ascii &&
 +       (ftp->downloadsize < 1)) {
 +      /*
 +       * It seems directory listings either don't show the size or very
 +       * often uses size 0 anyway. ASCII transfers may very well turn out
 +       * that the transferred amount of data is not the same as this line
 +       * tells, why using this number in those cases only confuses us.
 +       *
 +       * Example D above makes this parsing a little tricky */
 +      char *bytes;
 +      bytes=strstr(buf, " bytes");
 +      if(bytes--) {
 +        long in=(long)(bytes-buf);
 +        /* this is a hint there is size information in there! ;-) */
 +        while(--in) {
 +          /* scan for the left parenthesis and break there */
 +          if('(' == *bytes)
 +            break;
 +          /* skip only digits */
 +          if(!ISDIGIT(*bytes)) {
 +            bytes=NULL;
 +            break;
 +          }
 +          /* one more estep backwards */
 +          bytes--;
 +        }
 +        /* if we have nothing but digits: */
 +        if(bytes++) {
 +          /* get the number! */
 +          size = curlx_strtoofft(bytes, NULL, 0);
 +        }
 +      }
 +    }
 +    else if(ftp->downloadsize > -1)
 +      size = ftp->downloadsize;
 +
 +    if(size > data->req.maxdownload && data->req.maxdownload > 0)
 +      size = data->req.size = data->req.maxdownload;
 +    else if((instate != FTP_LIST) && (data->set.prefer_ascii))
 +      size = -1; /* kludge for servers that understate ASCII mode file size */
 +
 +    infof(data, "Maxdownload = %" CURL_FORMAT_CURL_OFF_T "\n",
 +          data->req.maxdownload);
 +
 +    if(instate != FTP_LIST)
 +      infof(data, "Getting file with size: %" CURL_FORMAT_CURL_OFF_T "\n",
 +            size);
 +
 +    /* FTP download: */
 +    conn->proto.ftpc.state_saved = instate;
 +    conn->proto.ftpc.retr_size_saved = size;
 +
 +    if(data->set.ftp_use_port) {
 +      bool connected;
 +
 +      result = AllowServerConnect(conn, &connected);
 +      if(result)
 +        return result;
 +
 +      if(!connected) {
 +        struct ftp_conn *ftpc = &conn->proto.ftpc;
 +        infof(data, "Data conn was not available immediately\n");
 +        state(conn, FTP_STOP);
 +        ftpc->wait_data_conn = TRUE;
 +      }
 +    }
 +    else
 +      return InitiateTransfer(conn);
 +  }
 +  else {
 +    if((instate == FTP_LIST) && (ftpcode == 450)) {
 +      /* simply no matching files in the dir listing */
 +      ftp->transfer = FTPTRANSFER_NONE; /* don't download anything */
 +      state(conn, FTP_STOP); /* this phase is over */
 +    }
 +    else {
 +      failf(data, "RETR response: %03d", ftpcode);
 +      return instate == FTP_RETR && ftpcode == 550?
 +        CURLE_REMOTE_FILE_NOT_FOUND:
 +        CURLE_FTP_COULDNT_RETR_FILE;
 +    }
 +  }
 +
 +  return result;
 +}
 +
 +/* after USER, PASS and ACCT */
 +static CURLcode ftp_state_loggedin(struct connectdata *conn)
 +{
 +  CURLcode result = CURLE_OK;
 +
 +  if(conn->ssl[FIRSTSOCKET].use) {
 +    /* PBSZ = PROTECTION BUFFER SIZE.
 +
 +    The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says:
 +
 +    Specifically, the PROT command MUST be preceded by a PBSZ
 +    command and a PBSZ command MUST be preceded by a successful
 +    security data exchange (the TLS negotiation in this case)
 +
 +    ... (and on page 8):
 +
 +    Thus the PBSZ command must still be issued, but must have a
 +    parameter of '0' to indicate that no buffering is taking place
 +    and the data connection should not be encapsulated.
 +    */
 +    PPSENDF(&conn->proto.ftpc.pp, "PBSZ %d", 0);
 +    state(conn, FTP_PBSZ);
 +  }
 +  else {
 +    result = ftp_state_pwd(conn);
 +  }
 +  return result;
 +}
 +
 +/* for USER and PASS responses */
 +static CURLcode ftp_state_user_resp(struct connectdata *conn,
 +                                    int ftpcode,
 +                                    ftpstate instate)
 +{
 +  CURLcode result = CURLE_OK;
-   struct SessionHandle *data = conn->data;
++  struct Curl_easy *data = conn->data;
 +  struct FTP *ftp = data->req.protop;
 +  struct ftp_conn *ftpc = &conn->proto.ftpc;
 +  (void)instate; /* no use for this yet */
 +
 +  /* some need password anyway, and others just return 2xx ignored */
 +  if((ftpcode == 331) && (ftpc->state == FTP_USER)) {
 +    /* 331 Password required for ...
 +       (the server requires to send the user's password too) */
 +    PPSENDF(&ftpc->pp, "PASS %s", ftp->passwd?ftp->passwd:"");
 +    state(conn, FTP_PASS);
 +  }
 +  else if(ftpcode/100 == 2) {
 +    /* 230 User ... logged in.
 +       (the user logged in with or without password) */
 +    result = ftp_state_loggedin(conn);
 +  }
 +  else if(ftpcode == 332) {
 +    if(data->set.str[STRING_FTP_ACCOUNT]) {
 +      PPSENDF(&ftpc->pp, "ACCT %s", data->set.str[STRING_FTP_ACCOUNT]);
 +      state(conn, FTP_ACCT);
 +    }
 +    else {
 +      failf(data, "ACCT requested but none available");
 +      result = CURLE_LOGIN_DENIED;
 +    }
 +  }
 +  else {
 +    /* All other response codes, like:
 +
 +    530 User ... access denied
 +    (the server denies to log the specified user) */
 +
 +    if(conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] &&
 +        !conn->data->state.ftp_trying_alternative) {
 +      /* Ok, USER failed.  Let's try the supplied command. */
 +      PPSENDF(&conn->proto.ftpc.pp, "%s",
 +              conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
 +      conn->data->state.ftp_trying_alternative = TRUE;
 +      state(conn, FTP_USER);
 +      result = CURLE_OK;
 +    }
 +    else {
 +      failf(data, "Access denied: %03d", ftpcode);
 +      result = CURLE_LOGIN_DENIED;
 +    }
 +  }
 +  return result;
 +}
 +
 +/* for ACCT response */
 +static CURLcode ftp_state_acct_resp(struct connectdata *conn,
 +                                    int ftpcode)
 +{
 +  CURLcode result = CURLE_OK;
-   struct SessionHandle *data = conn->data;
++  struct Curl_easy *data = conn->data;
 +  if(ftpcode != 230) {
 +    failf(data, "ACCT rejected by server: %03d", ftpcode);
 +    result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */
 +  }
 +  else
 +    result = ftp_state_loggedin(conn);
 +
 +  return result;
 +}
 +
 +
 +static CURLcode ftp_statemach_act(struct connectdata *conn)
 +{
 +  CURLcode result;
 +  curl_socket_t sock = conn->sock[FIRSTSOCKET];
-   struct SessionHandle *data=conn->data;
++  struct Curl_easy *data=conn->data;
 +  int ftpcode;
 +  struct ftp_conn *ftpc = &conn->proto.ftpc;
 +  struct pingpong *pp = &ftpc->pp;
 +  static const char ftpauth[][4]  = { "SSL", "TLS" };
 +  size_t nread = 0;
 +
 +  if(pp->sendleft)
 +    return Curl_pp_flushsend(pp);
 +
 +  result = ftp_readresp(sock, pp, &ftpcode, &nread);
 +  if(result)
 +    return result;
 +
 +  if(ftpcode) {
 +    /* we have now received a full FTP server response */
 +    switch(ftpc->state) {
 +    case FTP_WAIT220:
 +      if(ftpcode == 230)
 +        /* 230 User logged in - already! */
 +        return ftp_state_user_resp(conn, ftpcode, ftpc->state);
 +      else if(ftpcode != 220) {
 +        failf(data, "Got a %03d ftp-server response when 220 was expected",
 +              ftpcode);
 +        return CURLE_FTP_WEIRD_SERVER_REPLY;
 +      }
 +
 +      /* We have received a 220 response fine, now we proceed. */
 +#ifdef HAVE_GSSAPI
 +      if(data->set.krb) {
 +        /* If not anonymous login, try a secure login. Note that this
 +           procedure is still BLOCKING. */
 +
 +        Curl_sec_request_prot(conn, "private");
 +        /* We set private first as default, in case the line below fails to
 +           set a valid level */
 +        Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]);
 +
 +        if(Curl_sec_login(conn))
 +          infof(data, "Logging in with password in cleartext!\n");
 +        else
 +          infof(data, "Authentication successful\n");
 +      }
 +#endif
 +
 +      if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
 +        /* We don't have a SSL/TLS connection yet, but FTPS is
 +           requested. Try a FTPS connection now */
 +
 +        ftpc->count3=0;
 +        switch(data->set.ftpsslauth) {
 +        case CURLFTPAUTH_DEFAULT:
 +        case CURLFTPAUTH_SSL:
 +          ftpc->count2 = 1; /* add one to get next */
 +          ftpc->count1 = 0;
 +          break;
 +        case CURLFTPAUTH_TLS:
 +          ftpc->count2 = -1; /* subtract one to get next */
 +          ftpc->count1 = 1;
 +          break;
 +        default:
 +          failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d",
 +                (int)data->set.ftpsslauth);
 +          return CURLE_UNKNOWN_OPTION; /* we don't know what to do */
 +        }
 +        PPSENDF(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
 +        state(conn, FTP_AUTH);
 +      }
 +      else {
 +        result = ftp_state_user(conn);
 +        if(result)
 +          return result;
 +      }
 +
 +      break;
 +
 +    case FTP_AUTH:
 +      /* we have gotten the response to a previous AUTH command */
 +
 +      /* RFC2228 (page 5) says:
 +       *
 +       * If the server is willing to accept the named security mechanism,
 +       * and does not require any security data, it must respond with
 +       * reply code 234/334.
 +       */
 +
 +      if((ftpcode == 234) || (ftpcode == 334)) {
 +        /* Curl_ssl_connect is BLOCKING */
 +        result = Curl_ssl_connect(conn, FIRSTSOCKET);
 +        if(!result) {
 +          conn->ssl[SECONDARYSOCKET].use = FALSE; /* clear-text data */
 +          result = ftp_state_user(conn);
 +        }
 +      }
 +      else if(ftpc->count3 < 1) {
 +        ftpc->count3++;
 +        ftpc->count1 += ftpc->count2; /* get next attempt */
 +        result = Curl_pp_sendf(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
 +        /* remain in this same state */
 +      }
 +      else {
 +        if(data->set.use_ssl > CURLUSESSL_TRY)
 +          /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */
 +          result = CURLE_USE_SSL_FAILED;
 +        else
 +          /* ignore the failure and continue */
 +          result = ftp_state_user(conn);
 +      }
 +
 +      if(result)
 +        return result;
 +      break;
 +
 +    case FTP_USER:
 +    case FTP_PASS:
 +      result = ftp_state_user_resp(conn, ftpcode, ftpc->state);
 +      break;
 +
 +    case FTP_ACCT:
 +      result = ftp_state_acct_resp(conn, ftpcode);
 +      break;
 +
 +    case FTP_PBSZ:
 +      PPSENDF(&ftpc->pp, "PROT %c",
 +              data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
 +      state(conn, FTP_PROT);
 +
 +      break;
 +
 +    case FTP_PROT:
 +      if(ftpcode/100 == 2)
 +        /* We have enabled SSL for the data connection! */
 +        conn->ssl[SECONDARYSOCKET].use =
 +          (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE;
 +      /* FTP servers typically responds with 500 if they decide to reject
 +         our 'P' request */
 +      else if(data->set.use_ssl > CURLUSESSL_CONTROL)
 +        /* we failed and bails out */
 +        return CURLE_USE_SSL_FAILED;
 +
 +      if(data->set.ftp_ccc) {
 +        /* CCC - Clear Command Channel
 +         */
 +        PPSENDF(&ftpc->pp, "%s", "CCC");
 +        state(conn, FTP_CCC);
 +      }
 +      else {
 +        result = ftp_state_pwd(conn);
 +        if(result)
 +          return result;
 +      }
 +      break;
 +
 +    case FTP_CCC:
 +      if(ftpcode < 500) {
 +        /* First shut down the SSL layer (note: this call will block) */
 +        result = Curl_ssl_shutdown(conn, FIRSTSOCKET);
 +
 +        if(result) {
 +          failf(conn->data, "Failed to clear the command channel (CCC)");
 +          return result;
 +        }
 +      }
 +
 +      /* Then continue as normal */
 +      result = ftp_state_pwd(conn);
 +      if(result)
 +        return result;
 +      break;
 +
 +    case FTP_PWD:
 +      if(ftpcode == 257) {
 +        char *ptr=&data->state.buffer[4];  /* start on the first letter */
 +        char *dir;
 +        char *store;
 +
 +        dir = malloc(nread + 1);
 +        if(!dir)
 +          return CURLE_OUT_OF_MEMORY;
 +
 +        /* Reply format is like
 +           257<space>[rubbish]"<directory-name>"<space><commentary> and the
 +           RFC959 says
 +
 +           The directory name can contain any character; embedded
 +           double-quotes should be escaped by double-quotes (the
 +           "quote-doubling" convention).
 +        */
 +
 +        /* scan for the first double-quote for non-standard responses */
 +        while(ptr < &data->state.buffer[sizeof(data->state.buffer)]
 +              && *ptr != '\n' && *ptr != '\0' && *ptr != '"')
 +          ptr++;
 +
 +        if('\"' == *ptr) {
 +          /* it started good */
 +          ptr++;
 +          for(store = dir; *ptr;) {
 +            if('\"' == *ptr) {
 +              if('\"' == ptr[1]) {
 +                /* "quote-doubling" */
 +                *store = ptr[1];
 +                ptr++;
 +              }
 +              else {
 +                /* end of path */
 +                *store = '\0'; /* zero terminate */
 +                break; /* get out of this loop */
 +              }
 +            }
 +            else
 +              *store = *ptr;
 +            store++;
 +            ptr++;
 +          }
 +
 +          /* If the path name does not look like an absolute path (i.e.: it
 +             does not start with a '/'), we probably need some server-dependent
 +             adjustments. For example, this is the case when connecting to
 +             an OS400 FTP server: this server supports two name syntaxes,
 +             the default one being incompatible with standard pathes. In
 +             addition, this server switches automatically to the regular path
 +             syntax when one is encountered in a command: this results in
 +             having an entrypath in the wrong syntax when later used in CWD.
 +               The method used here is to check the server OS: we do it only
 +             if the path name looks strange to minimize overhead on other
 +             systems. */
 +
 +          if(!ftpc->server_os && dir[0] != '/') {
 +
 +            result = Curl_pp_sendf(&ftpc->pp, "%s", "SYST");
 +            if(result) {
 +              free(dir);
 +              return result;
 +            }
 +            Curl_safefree(ftpc->entrypath);
 +            ftpc->entrypath = dir; /* remember this */
 +            infof(data, "Entry path is '%s'\n", ftpc->entrypath);
 +            /* also save it where getinfo can access it: */
 +            data->state.most_recent_ftp_entrypath = ftpc->entrypath;
 +            state(conn, FTP_SYST);
 +            break;
 +          }
 +
 +          Curl_safefree(ftpc->entrypath);
 +          ftpc->entrypath = dir; /* remember this */
 +          infof(data, "Entry path is '%s'\n", ftpc->entrypath);
 +          /* also save it where getinfo can access it: */
 +          data->state.most_recent_ftp_entrypath = ftpc->entrypath;
 +        }
 +        else {
 +          /* couldn't get the path */
 +          free(dir);
 +          infof(data, "Failed to figure out path\n");
 +        }
 +      }
 +      state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
 +      DEBUGF(infof(data, "protocol connect phase DONE\n"));
 +      break;
 +
 +    case FTP_SYST:
 +      if(ftpcode == 215) {
 +        char *ptr=&data->state.buffer[4];  /* start on the first letter */
 +        char *os;
 +        char *store;
 +
 +        os = malloc(nread + 1);
 +        if(!os)
 +          return CURLE_OUT_OF_MEMORY;
 +
 +        /* Reply format is like
 +           215<space><OS-name><space><commentary>
 +        */
 +        while(*ptr == ' ')
 +          ptr++;
 +        for(store = os; *ptr && *ptr != ' ';)
 +          *store++ = *ptr++;
 +        *store = '\0'; /* zero terminate */
 +
 +        /* Check for special servers here. */
 +
 +        if(strequal(os, "OS/400")) {
 +          /* Force OS400 name format 1. */
 +          result = Curl_pp_sendf(&ftpc->pp, "%s", "SITE NAMEFMT 1");
 +          if(result) {
 +            free(os);
 +            return result;
 +          }
 +          /* remember target server OS */
 +          Curl_safefree(ftpc->server_os);
 +          ftpc->server_os = os;
 +          state(conn, FTP_NAMEFMT);
 +          break;
 +        }
 +        else {
 +          /* Nothing special for the target server. */
 +          /* remember target server OS */
 +          Curl_safefree(ftpc->server_os);
 +          ftpc->server_os = os;
 +        }
 +      }
 +      else {
 +        /* Cannot identify server OS. Continue anyway and cross fingers. */
 +      }
 +
 +      state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
 +      DEBUGF(infof(data, "protocol connect phase DONE\n"));
 +      break;
 +
 +    case FTP_NAMEFMT:
 +      if(ftpcode == 250) {
 +        /* Name format change successful: reload initial path. */
 +        ftp_state_pwd(conn);
 +        break;
 +      }
 +
 +      state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
 +      DEBUGF(infof(data, "protocol connect phase DONE\n"));
 +      break;
 +
 +    case FTP_QUOTE:
 +    case FTP_POSTQUOTE:
 +    case FTP_RETR_PREQUOTE:
 +    case FTP_STOR_PREQUOTE:
 +      if((ftpcode >= 400) && !ftpc->count2) {
 +        /* failure response code, and not allowed to fail */
 +        failf(conn->data, "QUOT command failed with %03d", ftpcode);
 +        return CURLE_QUOTE_ERROR;
 +      }
 +      result = ftp_state_quote(conn, FALSE, ftpc->state);
 +      if(result)
 +        return result;
 +
 +      break;
 +
 +    case FTP_CWD:
 +      if(ftpcode/100 != 2) {
 +        /* failure to CWD there */
 +        if(conn->data->set.ftp_create_missing_dirs &&
 +           ftpc->count1 && !ftpc->count2) {
 +          /* try making it */
 +          ftpc->count2++; /* counter to prevent CWD-MKD loops */
 +          PPSENDF(&ftpc->pp, "MKD %s", ftpc->dirs[ftpc->count1 - 1]);
 +          state(conn, FTP_MKD);
 +        }
 +        else {
 +          /* return failure */
 +          failf(data, "Server denied you to change to the given directory");
 +          ftpc->cwdfail = TRUE; /* don't remember this path as we failed
 +                                   to enter it */
 +          return CURLE_REMOTE_ACCESS_DENIED;
 +        }
 +      }
 +      else {
 +        /* success */
 +        ftpc->count2=0;
 +        if(++ftpc->count1 <= ftpc->dirdepth) {
 +          /* send next CWD */
 +          PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
 +        }
 +        else {
 +          result = ftp_state_mdtm(conn);
 +          if(result)
 +            return result;
 +        }
 +      }
 +      break;
 +
 +    case FTP_MKD:
 +      if((ftpcode/100 != 2) && !ftpc->count3--) {
 +        /* failure to MKD the dir */
 +        failf(data, "Failed to MKD dir: %03d", ftpcode);
 +        return CURLE_REMOTE_ACCESS_DENIED;
 +      }
 +      state(conn, FTP_CWD);
 +      /* send CWD */
 +      PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
 +      break;
 +
 +    case FTP_MDTM:
 +      result = ftp_state_mdtm_resp(conn, ftpcode);
 +      break;
 +
 +    case FTP_TYPE:
 +    case FTP_LIST_TYPE:
 +    case FTP_RETR_TYPE:
 +    case FTP_STOR_TYPE:
 +      result = ftp_state_type_resp(conn, ftpcode, ftpc->state);
 +      break;
 +
 +    case FTP_SIZE:
 +    case FTP_RETR_SIZE:
 +    case FTP_STOR_SIZE:
 +      result = ftp_state_size_resp(conn, ftpcode, ftpc->state);
 +      break;
 +
 +    case FTP_REST:
 +    case FTP_RETR_REST:
 +      result = ftp_state_rest_resp(conn, ftpcode, ftpc->state);
 +      break;
 +
 +    case FTP_PRET:
 +      if(ftpcode != 200) {
 +        /* there only is this one standard OK return code. */
 +        failf(data, "PRET command not accepted: %03d", ftpcode);
 +        return CURLE_FTP_PRET_FAILED;
 +      }
 +      result = ftp_state_use_pasv(conn);
 +      break;
 +
 +    case FTP_PASV:
 +      result = ftp_state_pasv_resp(conn, ftpcode);
 +      break;
 +
 +    case FTP_PORT:
 +      result = ftp_state_port_resp(conn, ftpcode);
 +      break;
 +
 +    case FTP_LIST:
 +    case FTP_RETR:
 +      result = ftp_state_get_resp(conn, ftpcode, ftpc->state);
 +      break;
 +
 +    case FTP_STOR:
 +      result = ftp_state_stor_resp(conn, ftpcode, ftpc->state);
 +      break;
 +
 +    case FTP_QUIT:
 +      /* fallthrough, just stop! */
 +    default:
 +      /* internal error */
 +      state(conn, FTP_STOP);
 +      break;
 +    }
 +  } /* if(ftpcode) */
 +
 +  return result;
 +}
 +
 +
 +/* called repeatedly until done from multi.c */
 +static CURLcode ftp_multi_statemach(struct connectdata *conn,
 +                                    bool *done)
 +{
 +  struct ftp_conn *ftpc = &conn->proto.ftpc;
 +  CURLcode result = Curl_pp_statemach(&ftpc->pp, FALSE);
 +
 +  /* Check for the state outside of the Curl_socket_ready() return code checks
 +     since at times we are in fact already in this state when this function
 +     gets called. */
 +  *done = (ftpc->state == FTP_STOP) ? TRUE : FALSE;
 +
 +  return result;
 +}
 +
 +static CURLcode ftp_block_statemach(struct connectdata *conn)
 +{
 +  struct ftp_conn *ftpc = &conn->proto.ftpc;
 +  struct pingpong *pp = &ftpc->pp;
 +  CURLcode result = CURLE_OK;
 +
 +  while(ftpc->state != FTP_STOP) {
 +    result = Curl_pp_statemach(pp, TRUE);
 +    if(result)
 +      break;
 +  }
 +
 +  return result;
 +}
 +
 +/*
 + * ftp_connect() should do everything that is to be considered a part of
 + * the connection phase.
 + *
 + * The variable 'done' points to will be TRUE if the protocol-layer connect
 + * phase is done when this function returns, or FALSE if not.
 + *
 + */
 +static CURLcode ftp_connect(struct connectdata *conn,
 +                                 bool *done) /* see description above */
 +{
 +  CURLcode result;
 +  struct ftp_conn *ftpc = &conn->proto.ftpc;
 +  struct pingpong *pp = &ftpc->pp;
 +
 +  *done = FALSE; /* default to not done yet */
 +
 +  /* We always support persistent connections on ftp */
 +  connkeep(conn, "FTP default");
 +
 +  pp->response_time = RESP_TIMEOUT; /* set default response time-out */
 +  pp->statemach_act = ftp_statemach_act;
 +  pp->endofresp = ftp_endofresp;
 +  pp->conn = conn;
 +
 +  if(conn->handler->flags & PROTOPT_SSL) {
 +    /* BLOCKING */
 +    result = Curl_ssl_connect(conn, FIRSTSOCKET);
 +    if(result)
 +      return result;
 +  }
 +
 +  Curl_pp_init(pp); /* init the generic pingpong data */
 +
 +  /* When we connect, we start in the state where we await the 220
 +     response */
 +  state(conn, FTP_WAIT220);
 +
 +  result = ftp_multi_statemach(conn, done);
 +
 +  return result;
 +}
 +
 +/***********************************************************************
 + *
 + * ftp_done()
 + *
 + * The DONE function. This does what needs to be done after a single DO has
 + * performed.
 + *
 + * Input argument is already checked for validity.
 + */
 +static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
-                               bool premature)
++                         bool premature)
 +{
-   struct SessionHandle *data = conn->data;
++  struct Curl_easy *data = conn->data;
 +  struct FTP *ftp = data->req.protop;
 +  struct ftp_conn *ftpc = &conn->proto.ftpc;
 +  struct pingpong *pp = &ftpc->pp;
 +  ssize_t nread;
 +  int ftpcode;
 +  CURLcode result = CURLE_OK;
 +  bool was_ctl_valid = ftpc->ctl_valid;
 +  char *path;
 +  const char *path_to_use = data->state.path;
 +
 +  if(!ftp)
-     /* When the easy handle is removed from the multi while libcurl is still
-      * trying to resolve the host name, it seems that the ftp struct is not
-      * yet initialized, but the removal action calls Curl_done() which calls
-      * this function. So we simply return success if no ftp pointer is set.
-      */
 +    return CURLE_OK;
 +
 +  switch(status) {
 +  case CURLE_BAD_DOWNLOAD_RESUME:
 +  case CURLE_FTP_WEIRD_PASV_REPLY:
 +  case CURLE_FTP_PORT_FAILED:
 +  case CURLE_FTP_ACCEPT_FAILED:
 +  case CURLE_FTP_ACCEPT_TIMEOUT:
 +  case CURLE_FTP_COULDNT_SET_TYPE:
 +  case CURLE_FTP_COULDNT_RETR_FILE:
 +  case CURLE_PARTIAL_FILE:
 +  case CURLE_UPLOAD_FAILED:
 +  case CURLE_REMOTE_ACCESS_DENIED:
 +  case CURLE_FILESIZE_EXCEEDED:
 +  case CURLE_REMOTE_FILE_NOT_FOUND:
 +  case CURLE_WRITE_ERROR:
 +    /* the connection stays alive fine even though this happened */
 +    /* fall-through */
 +  case CURLE_OK: /* doesn't affect the control connection's status */
 +    if(!premature) {
 +      ftpc->ctl_valid = was_ctl_valid;
 +      break;
 +    }
 +    /* until we cope better with prematurely ended requests, let them
 +     * fallback as if in complete failure */
 +  default:       /* by default, an error means the control connection is
 +                    wedged and should not be used anymore */
 +    ftpc->ctl_valid = FALSE;
 +    ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the
 +                             current path, as this connection is going */
 +    connclose(conn, "FTP ended with bad error code");
 +    result = status;      /* use the already set error code */
 +    break;
 +  }
 +
 +  /* now store a copy of the directory we are in */
 +  free(ftpc->prevpath);
 +
 +  if(data->set.wildcardmatch) {
 +    if(data->set.chunk_end && ftpc->file) {
 +      data->set.chunk_end(data->wildcard.customptr);
 +    }
 +    ftpc->known_filesize = -1;
 +  }
 +
 +  /* get the "raw" path */
 +  path = curl_easy_unescape(data, path_to_use, 0, NULL);
 +  if(!path) {
 +    /* out of memory, but we can limp along anyway (and should try to
 +     * since we may already be in the out of memory cleanup path) */
 +    if(!result)
 +      result = CURLE_OUT_OF_MEMORY;
 +    ftpc->ctl_valid = FALSE; /* mark control connection as bad */
 +    connclose(conn, "FTP: out of memory!"); /* mark for connection closure */
 +    ftpc->prevpath = NULL; /* no path remembering */
 +  }
 +  else {
 +    size_t flen = ftpc->file?strlen(ftpc->file):0; /* file is "raw" already */
 +    size_t dlen = strlen(path)-flen;
 +    if(!ftpc->cwdfail) {
 +      if(dlen && (data->set.ftp_filemethod != FTPFILE_NOCWD)) {
 +        ftpc->prevpath = path;
 +        if(flen)
 +          /* if 'path' is not the whole string */
 +          ftpc->prevpath[dlen]=0; /* terminate */
 +      }
 +      else {
 +        /* we never changed dir */
 +        ftpc->prevpath=strdup("");
 +        free(path);
 +      }
 +      if(ftpc->prevpath)
 +        infof(data, "Remembering we are in dir \"%s\"\n", ftpc->prevpath);
 +    }
 +    else {
 +      ftpc->prevpath = NULL; /* no path */
 +      free(path);
 +    }
 +  }
 +  /* free the dir tree and file parts */
 +  freedirs(ftpc);
 +
 +  /* shut down the socket to inform the server we're done */
 +
 +#ifdef _WIN32_WCE
 +  shutdown(conn->sock[SECONDARYSOCKET], 2);  /* SD_BOTH */
 +#endif
 +
 +  if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
 +    if(!result && ftpc->dont_check && data->req.maxdownload > 0) {
 +      /* partial download completed */
 +      result = Curl_pp_sendf(pp, "%s", "ABOR");
 +      if(result) {
 +        failf(data, "Failure sending ABOR command: %s",
 +              curl_easy_strerror(result));
 +        ftpc->ctl_valid = FALSE; /* mark control connection as bad */
 +        connclose(conn, "ABOR command failed"); /* connection closure */
 +      }
 +    }
 +
 +    if(conn->ssl[SECONDARYSOCKET].use) {
 +      /* The secondary socket is using SSL so we must close down that part
 +         first before we close the socket for real */
 +      Curl_ssl_close(conn, SECONDARYSOCKET);
 +
 +      /* Note that we keep "use" set to TRUE since that (next) connection is
 +         still requested to use SSL */
 +    }
-     if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
-       Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
-       conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
-       conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
-     }
++    close_secondarysocket(conn);
 +  }
 +
 +  if(!result && (ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid &&
 +     pp->pending_resp && !premature) {
 +    /*
 +     * Let's see what the server says about the transfer we just performed,
 +     * but lower the timeout as sometimes this connection has died while the
 +     * data has been transferred. This happens when doing through NATs etc that
 +     * abandon old silent connections.
 +     */
 +    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 */
 +
 +    result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
 +
 +    pp->response_time = old_time; /* set this back to previous value */
 +
 +    if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
 +      failf(data, "control connection looks dead");
 +      ftpc->ctl_valid = FALSE; /* mark control connection as bad */
 +      connclose(conn, "Timeout or similar in FTP DONE operation"); /* close */
 +    }
 +
 +    if(result)
 +      return result;
 +
 +    if(ftpc->dont_check && data->req.maxdownload > 0) {
 +      /* we have just sent ABOR and there is no reliable way to check if it was
 +       * successful or not; we have to close the connection now */
 +      infof(data, "partial download completed, closing connection\n");
 +      connclose(conn, "Partial download with no ability to check");
 +      return result;
 +    }
 +
 +    if(!ftpc->dont_check) {
 +      /* 226 Transfer complete, 250 Requested file action okay, completed. */
 +      if((ftpcode != 226) && (ftpcode != 250)) {
 +        failf(data, "server did not report OK, got %d", ftpcode);
 +        result = CURLE_PARTIAL_FILE;
 +      }
 +    }
 +  }
 +
 +  if(result || premature)
 +    /* the response code from the transfer showed an error already so no
 +       use checking further */
 +    ;
 +  else if(data->set.upload) {
 +    if((-1 != data->state.infilesize) &&
 +       (data->state.infilesize != *ftp->bytecountp) &&
 +       !data->set.crlf &&
 +       (ftp->transfer == FTPTRANSFER_BODY)) {
 +      failf(data, "Uploaded unaligned file size (%" CURL_FORMAT_CURL_OFF_T
 +            " out of %" CURL_FORMAT_CURL_OFF_T " bytes)",
 +            *ftp->bytecountp, data->state.infilesize);
 +      result = CURLE_PARTIAL_FILE;
 +    }
 +  }
 +  else {
 +    if((-1 != data->req.size) &&
 +       (data->req.size != *ftp->bytecountp) &&
 +#ifdef CURL_DO_LINEEND_CONV
 +       /* Most FTP servers don't adjust their file SIZE response for CRLFs, so
 +        * we'll check to see if the discrepancy can be explained by the number
 +        * of CRLFs we've changed to LFs.
 +        */
 +       ((data->req.size + data->state.crlf_conversions) !=
 +        *ftp->bytecountp) &&
 +#endif /* CURL_DO_LINEEND_CONV */
 +       (data->req.maxdownload != *ftp->bytecountp)) {
 +      failf(data, "Received only partial file: %" CURL_FORMAT_CURL_OFF_T
 +            " bytes", *ftp->bytecountp);
 +      result = CURLE_PARTIAL_FILE;
 +    }
 +    else if(!ftpc->dont_check &&
 +            !*ftp->bytecountp &&
 +            (data->req.size>0)) {
 +      failf(data, "No data was received!");
 +      result = CURLE_FTP_COULDNT_RETR_FILE;
 +    }
 +  }
 +
 +  /* clear these for next connection */
 +  ftp->transfer = FTPTRANSFER_BODY;
 +  ftpc->dont_check = FALSE;
 +
 +  /* Send any post-transfer QUOTE strings? */
 +  if(!status && !result && !premature && data->set.postquote)
 +    result = ftp_sendquote(conn, data->set.postquote);
 +
 +  return result;
 +}
 +
 +/***********************************************************************
 + *
 + * ftp_sendquote()
 + *
 + * Where a 'quote' means a list of custom commands to send to the server.
 + * The quote list is passed as an argument.
 + *
 + * BLOCKING
 + */
 +
 +static
 +CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
 +{
 +  struct curl_slist *item;
 +  ssize_t nread;
 +  int ftpcode;
 +  CURLcode result;
 +  struct ftp_conn *ftpc = &conn->proto.ftpc;
 +  struct pingpong *pp = &ftpc->pp;
 +
 +  item = quote;
 +  while(item) {
 +    if(item->data) {
 +      char *cmd = item->data;
 +      bool acceptfail = FALSE;
 +
 +      /* if a command starts with an asterisk, which a legal FTP command never
 +         can, the command will be allowed to fail without it causing any
 +         aborts or cancels etc. It will cause libcurl to act as if the command
 +         is successful, whatever the server reponds. */
 +
 +      if(cmd[0] == '*') {
 +        cmd++;
 +        acceptfail = TRUE;
 +      }
 +
 +      PPSENDF(&conn->proto.ftpc.pp, "%s", cmd);
 +
 +      pp->response = Curl_tvnow(); /* timeout relative now */
 +
 +      result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
 +      if(result)
 +        return result;
 +
 +      if(!acceptfail && (ftpcode >= 400)) {
 +        failf(conn->data, "QUOT string not accepted: %s", cmd);
 +        return CURLE_QUOTE_ERROR;
 +      }
 +    }
 +
 +    item = item->next;
 +  }
 +
 +  return CURLE_OK;
 +}
 +
 +/***********************************************************************
 + *
 + * ftp_need_type()
 + *
 + * Returns TRUE if we in the current situation should send TYPE
 + */
 +static int ftp_need_type(struct connectdata *conn,
 +                         bool ascii_wanted)
 +{
 +  return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I');
 +}
 +
 +/***********************************************************************
 + *
 + * ftp_nb_type()
 + *
 + * Set TYPE. We only deal with ASCII or BINARY so this function
 + * sets one of them.
 + * If the transfer type is not sent, simulate on OK response in newstate
 + */
 +static CURLcode ftp_nb_type(struct connectdata *conn,
 +                            bool ascii, ftpstate newstate)
 +{
 +  struct ftp_conn *ftpc = &conn->proto.ftpc;
 +  CURLcode result;
 +  char want = (char)(ascii?'A':'I');
 +
 +  if(ftpc->transfertype == want) {
 +    state(conn, newstate);
 +    return ftp_state_type_resp(conn, 200, newstate);
 +  }
 +
 +  PPSENDF(&ftpc->pp, "TYPE %c", want);
 +  state(conn, newstate);
 +
 +  /* keep track of our current transfer type */
 +  ftpc->transfertype = want;
 +  return CURLE_OK;
 +}
 +
 +/***************************************************************************
 + *
 + * ftp_pasv_verbose()
 + *
 + * This function only outputs some informationals about this second connection
 + * when we've issued a PASV command before and thus we have connected to a
 + * possibly new IP address.
 + *
 + */
 +#ifndef CURL_DISABLE_VERBOSE_STRINGS
 +static void
 +ftp_pasv_verbose(struct connectdata *conn,
 +                 Curl_addrinfo *ai,
 +                 char *newhost, /* ascii version */
 +                 int port)
 +{
 +  char buf[256];
 +  Curl_printable_address(ai, buf, sizeof(buf));
 +  infof(conn->data, "Connecting to %s (%s) port %d\n", newhost, buf, port);
 +}
 +#endif
 +
 +/*
 +  Check if this is a range download, and if so, set the internal variables
 +  properly.
 + */
 +
 +static CURLcode ftp_range(struct connectdata *conn)
 +{
 +  curl_off_t from, to;
 +  char *ptr;
 +  char *ptr2;
-   struct SessionHandle *data = conn->data;
++  struct Curl_easy *data = conn->data;
 +  struct ftp_conn *ftpc = &conn->proto.ftpc;
 +
 +  if(data->state.use_range && data->state.range) {
 +    from=curlx_strtoofft(data->state.range, &ptr, 0);
 +    while(*ptr && (ISSPACE(*ptr) || (*ptr=='-')))
 +      ptr++;
 +    to=curlx_strtoofft(ptr, &ptr2, 0);
 +    if(ptr == ptr2) {
 +      /* we didn't get any digit */
 +      to=-1;
 +    }
 +    if((-1 == to) && (from>=0)) {
 +      /* X - */
 +      data->state.resume_from = from;
 +      DEBUGF(infof(conn->data, "FTP RANGE %" CURL_FORMAT_CURL_OFF_T
 +                   " to end of file\n", from));
 +    }
 +    else if(from < 0) {
 +      /* -Y */
 +      data->req.maxdownload = -from;
 +      data->state.resume_from = from;
 +      DEBUGF(infof(conn->data, "FTP RANGE the last %" CURL_FORMAT_CURL_OFF_T
 +                   " bytes\n", -from));
 +    }
 +    else {
 +      /* X-Y */
 +      data->req.maxdownload = (to-from)+1; /* include last byte */
 +      data->state.resume_from = from;
 +      DEBUGF(infof(conn->data, "FTP RANGE from %" CURL_FORMAT_CURL_OFF_T
 +                   " getting %" CURL_FORMAT_CURL_OFF_T " bytes\n",
 +                   from, data->req.maxdownload));
 +    }
 +    DEBUGF(infof(conn->data, "range-download from %" CURL_FORMAT_CURL_OFF_T
 +                 " to %" CURL_FORMAT_CURL_OFF_T ", totally %"
 +                 CURL_FORMAT_CURL_OFF_T " bytes\n",
 +                 from, to, data->req.maxdownload));
 +    ftpc->dont_check = TRUE; /* dont check for successful transfer */
 +  }
 +  else
 +    data->req.maxdownload = -1;
 +  return CURLE_OK;
 +}
 +
 +
 +/*
 + * ftp_do_more()
 + *
 + * This function shall be called when the second FTP (data) connection is
 + * connected.
 + *
 + * 'complete' can return 0 for incomplete, 1 for done and -1 for go back
 + * (which basically is only for when PASV is being sent to retry a failed
 + * EPSV).
 + */
 +
 +static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
 +{
-   struct SessionHandle *data=conn->data;
++  struct Curl_easy *data=conn->data;
 +  struct ftp_conn *ftpc = &conn->proto.ftpc;
 +  CURLcode result = CURLE_OK;
 +  bool connected = FALSE;
 +  bool complete = FALSE;
 +
 +  /* the ftp struct is inited in ftp_connect() */
 +  struct FTP *ftp = data->req.protop;
 +
 +  /* if the second connection isn't done yet, wait for it */
 +  if(!conn->bits.tcpconnect[SECONDARYSOCKET]) {
 +    if(conn->tunnel_state[SECONDARYSOCKET] == TUNNEL_CONNECT) {
 +      /* As we're in TUNNEL_CONNECT state now, we know the proxy name and port
 +         aren't used so we blank their arguments. TODO: make this nicer */
 +      result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0, FALSE);
 +
 +      return result;
 +    }
 +
 +    result = Curl_is_connected(conn, SECONDARYSOCKET, &connected);
 +
 +    /* Ready to do more? */
 +    if(connected) {
 +      DEBUGF(infof(data, "DO-MORE connected phase starts\n"));
 +      if(conn->bits.proxy) {
 +        infof(data, "Connection to proxy confirmed\n");
 +        result = proxy_magic(conn, ftpc->newhost, ftpc->newport, &connected);
 +      }
 +    }
 +    else {
 +      if(result && (ftpc->count1 == 0)) {
 +        *completep = -1; /* go back to DOING please */
 +        /* this is a EPSV connect failing, try PASV instead */
 +        return ftp_epsv_disable(conn);
 +      }
 +      return result;
 +    }
 +  }
 +
 +  if(ftpc->state) {
 +    /* already in a state so skip the initial commands.
 +       They are only done to kickstart the do_more state */
 +    result = ftp_multi_statemach(conn, &complete);
 +
 +    *completep = (int)complete;
 +
 +    /* if we got an error or if we don't wait for a data connection return
 +       immediately */
 +    if(result || (ftpc->wait_data_conn != TRUE))
 +      return result;
 +
 +    if(ftpc->wait_data_conn)
 +      /* if we reach the end of the FTP state machine here, *complete will be
 +         TRUE but so is ftpc->wait_data_conn, which says we need to wait for
 +         the data connection and therefore we're not actually complete */
 +      *completep = 0;
 +  }
 +
 +  if(ftp->transfer <= FTPTRANSFER_INFO) {
 +    /* a transfer is about to take place, or if not a file name was given
 +       so we'll do a SIZE on it later and then we need the right TYPE first */
 +
 +    if(ftpc->wait_data_conn == TRUE) {
 +      bool serv_conned;
 +
 +      result = ReceivedServerConnect(conn, &serv_conned);
 +      if(result)
 +        return result; /* Failed to accept data connection */
 +
 +      if(serv_conned) {
 +        /* It looks data connection is established */
 +        result = AcceptServerConnect(conn);
 +        ftpc->wait_data_conn = FALSE;
 +        if(!result)
 +          result = InitiateTransfer(conn);
 +
 +        if(result)
 +          return result;
 +
 +        *completep = 1; /* this state is now complete when the server has
 +                           connected back to us */
 +      }
 +    }
 +    else if(data->set.upload) {
 +      result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE);
 +      if(result)
 +        return result;
 +
 +      result = ftp_multi_statemach(conn, &complete);
-       *completep = (int)complete;
++      if(ftpc->wait_data_conn)
++        /* if we reach the end of the FTP state machine here, *complete will be
++           TRUE but so is ftpc->wait_data_conn, which says we need to wait for
++           the data connection and therefore we're not actually complete */
++        *completep = 0;
++      else
++        *completep = (int)complete;
 +    }
 +    else {
 +      /* download */
 +      ftp->downloadsize = -1; /* unknown as of yet */
 +
 +      result = ftp_range(conn);
 +      if(result)
 +        ;
 +      else if(data->set.ftp_list_only || !ftpc->file) {
 +        /* The specified path ends with a slash, and therefore we think this
 +           is a directory that is requested, use LIST. But before that we
 +           need to set ASCII transfer mode. */
 +
 +        /* But only if a body transfer was requested. */
 +        if(ftp->transfer == FTPTRANSFER_BODY) {
 +          result = ftp_nb_type(conn, TRUE, FTP_LIST_TYPE);
 +          if(result)
 +            return result;
 +        }
 +        /* otherwise just fall through */
 +      }
 +      else {
 +        result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_RETR_TYPE);
 +        if(result)
 +          return result;
 +      }
 +
 +      result = ftp_multi_statemach(conn, &complete);
 +      *completep = (int)complete;
 +    }
 +    return result;
 +  }
 +
 +  if(!result && (ftp->transfer != FTPTRANSFER_BODY))
 +    /* no data to transfer. FIX: it feels like a kludge to have this here
 +       too! */
 +    Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
 +
 +  if(!ftpc->wait_data_conn) {
 +    /* no waiting for the data connection so this is now complete */
 +    *completep = 1;
 +    DEBUGF(infof(data, "DO-MORE phase ends with %d\n", (int)result));
 +  }
 +
 +  return result;
 +}
 +
 +
 +
 +/***********************************************************************
 + *
 + * ftp_perform()
 + *
 + * This is the actual DO function for FTP. Get a file/directory according to
 + * the options previously setup.
 + */
 +
 +static
 +CURLcode ftp_perform(struct connectdata *conn,
 +                     bool *connected,  /* connect status after PASV / PORT */
 +                     bool *dophase_done)
 +{
 +  /* this is FTP and no proxy */
 +  CURLcode result=CURLE_OK;
 +
 +  DEBUGF(infof(conn->data, "DO phase starts\n"));
 +
 +  if(conn->data->set.opt_no_body) {
 +    /* requested no body means no transfer... */
 +    struct FTP *ftp = conn->data->req.protop;
 +    ftp->transfer = FTPTRANSFER_INFO;
 +  }
 +
 +  *dophase_done = FALSE; /* not done yet */
 +
 +  /* start the first command in the DO phase */
 +  result = ftp_state_quote(conn, TRUE, FTP_QUOTE);
 +  if(result)
 +    return result;
 +
 +  /* run the state-machine */
 +  result = ftp_multi_statemach(conn, dophase_done);
 +
 +  *connected = conn->bits.tcpconnect[SECONDARYSOCKET];
 +
 +  infof(conn->data, "ftp_perform ends with SECONDARY: %d\n", *connected);
 +
 +  if(*dophase_done) {
 +    DEBUGF(infof(conn->data, "DO phase is complete1\n"));
 +  }
 +
 +  return result;
 +}
 +
 +static void wc_data_dtor(void *ptr)
 +{
 +  struct ftp_wc_tmpdata *tmp = ptr;
 +  if(tmp)
 +    Curl_ftp_parselist_data_free(&tmp->parser);
 +  free(tmp);
 +}
 +
 +static CURLcode init_wc_data(struct connectdata *conn)
 +{
 +  char *last_slash;
 +  char *path = conn->data->state.path;
 +  struct WildcardData *wildcard = &(conn->data->wildcard);
 +  CURLcode result = CURLE_OK;
 +  struct ftp_wc_tmpdata *ftp_tmp;
 +
 +  last_slash = strrchr(conn->data->state.path, '/');
 +  if(last_slash) {
 +    last_slash++;
 +    if(last_slash[0] == '\0') {
 +      wildcard->state = CURLWC_CLEAN;
 +      result = ftp_parse_url_path(conn);
 +      return result;
 +    }
 +    else {
 +      wildcard->pattern = strdup(last_slash);
 +      if(!wildcard->pattern)
 +        return CURLE_OUT_OF_MEMORY;
 +      last_slash[0] = '\0'; /* cut file from path */
 +    }
 +  }
 +  else { /* there is only 'wildcard pattern' or nothing */
 +    if(path[0]) {
 +      wildcard->pattern = strdup(path);
 +      if(!wildcard->pattern)
 +        return CURLE_OUT_OF_MEMORY;
 +      path[0] = '\0';
 +    }
 +    else { /* only list */
 +      wildcard->state = CURLWC_CLEAN;
 +      result = ftp_parse_url_path(conn);
 +      return result;
 +    }
 +  }
 +
 +  /* program continues only if URL is not ending with slash, allocate needed
 +     resources for wildcard transfer */
 +
 +  /* allocate ftp protocol specific temporary wildcard data */
 +  ftp_tmp = calloc(1, sizeof(struct ftp_wc_tmpdata));
 +  if(!ftp_tmp) {
 +    Curl_safefree(wildcard->pattern);
 +    return CURLE_OUT_OF_MEMORY;
 +  }
 +
 +  /* INITIALIZE parselist structure */
 +  ftp_tmp->parser = Curl_ftp_parselist_data_alloc();
 +  if(!ftp_tmp->parser) {
 +    Curl_safefree(wildcard->pattern);
 +    free(ftp_tmp);
 +    return CURLE_OUT_OF_MEMORY;
 +  }
 +
 +  wildcard->tmp = ftp_tmp; /* put it to the WildcardData tmp pointer */
 +  wildcard->tmp_dtor = wc_data_dtor;
 +
 +  /* wildcard does not support NOCWD option (assert it?) */
 +  if(conn->data->set.ftp_filemethod == FTPFILE_NOCWD)
 +    conn->data->set.ftp_filemethod = FTPFILE_MULTICWD;
 +
 +  /* try to parse ftp url */
 +  result = ftp_parse_url_path(conn);
 +  if(result) {
 +    Curl_safefree(wildcard->pattern);
 +    wildcard->tmp_dtor(wildcard->tmp);
 +    wildcard->tmp_dtor = ZERO_NULL;
 +    wildcard->tmp = NULL;
 +    return result;
 +  }
 +
 +  wildcard->path = strdup(conn->data->state.path);
 +  if(!wildcard->path) {
 +    Curl_safefree(wildcard->pattern);
 +    wildcard->tmp_dtor(wildcard->tmp);
 +    wildcard->tmp_dtor = ZERO_NULL;
 +    wildcard->tmp = NULL;
 +    return CURLE_OUT_OF_MEMORY;
 +  }
 +
 +  /* backup old write_function */
 +  ftp_tmp->backup.write_function = conn->data->set.fwrite_func;
 +  /* parsing write function */
 +  conn->data->set.fwrite_func = Curl_ftp_parselist;
 +  /* backup old file descriptor */
 +  ftp_tmp->backup.file_descriptor = conn->data->set.out;
 +  /* let the writefunc callback know what curl pointer is working with */
 +  conn->data->set.out = conn;
 +
 +  infof(conn->data, "Wildcard - Parsing started\n");
 +  return CURLE_OK;
 +}
 +
 +/* This is called recursively */
 +static CURLcode wc_statemach(struct connectdata *conn)
 +{
 +  struct WildcardData * const wildcard = &(conn->data->wildcard);
 +  CURLcode result = CURLE_OK;
 +
 +  switch (wildcard->state) {
 +  case CURLWC_INIT:
 +    result = init_wc_data(conn);
 +    if(wildcard->state == CURLWC_CLEAN)
 +      /* only listing! */
 +      break;
 +    else
 +      wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING;
 +    break;
 +
 +  case CURLWC_MATCHING: {
 +    /* In this state is LIST response successfully parsed, so lets restore
 +       previous WRITEFUNCTION callback and WRITEDATA pointer */
 +    struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
 +    conn->data->set.fwrite_func = ftp_tmp->backup.write_function;
 +    conn->data->set.out = ftp_tmp->backup.file_descriptor;
 +    ftp_tmp->backup.write_function = ZERO_NULL;
 +    ftp_tmp->backup.file_descriptor = NULL;
 +    wildcard->state = CURLWC_DOWNLOADING;
 +
 +    if(Curl_ftp_parselist_geterror(ftp_tmp->parser)) {
 +      /* error found in LIST parsing */
 +      wildcard->state = CURLWC_CLEAN;
 +      return wc_statemach(conn);
 +    }
 +    else if(wildcard->filelist->size == 0) {
 +      /* no corresponding file */
 +      wildcard->state = CURLWC_CLEAN;
 +      return CURLE_REMOTE_FILE_NOT_FOUND;
 +    }
 +    return wc_statemach(conn);
 +  }
 +
 +  case CURLWC_DOWNLOADING: {
 +    /* filelist has at least one file, lets get first one */
 +    struct ftp_conn *ftpc = &conn->proto.ftpc;
 +    struct curl_fileinfo *finfo = wildcard->filelist->head->ptr;
 +
 +    char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
 +    if(!tmp_path)
 +      return CURLE_OUT_OF_MEMORY;
 +
 +    /* switch default "state.pathbuffer" and tmp_path, good to see
 +       ftp_parse_url_path function to understand this trick */
 +    Curl_safefree(conn->data->state.pathbuffer);
 +    conn->data->state.pathbuffer = tmp_path;
 +    conn->data->state.path = tmp_path;
 +
 +    infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
 +    if(conn->data->set.chunk_bgn) {
 +      long userresponse = conn->data->set.chunk_bgn(
 +          finfo, wildcard->customptr, (int)wildcard->filelist->size);
 +      switch(userresponse) {
 +      case CURL_CHUNK_BGN_FUNC_SKIP:
 +        infof(conn->data, "Wildcard - \"%s\" skipped by user\n",
 +              finfo->filename);
 +        wildcard->state = CURLWC_SKIP;
 +        return wc_statemach(conn);
 +      case CURL_CHUNK_BGN_FUNC_FAIL:
 +        return CURLE_CHUNK_FAILED;
 +      }
 +    }
 +
 +    if(finfo->filetype != CURLFILETYPE_FILE) {
 +      wildcard->state = CURLWC_SKIP;
 +      return wc_statemach(conn);
 +    }
 +
 +    if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
 +      ftpc->known_filesize = finfo->size;
 +
 +    result = ftp_parse_url_path(conn);
 +    if(result)
 +      return result;
 +
 +    /* we don't need the Curl_fileinfo of first file anymore */
 +    Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
 +
 +    if(wildcard->filelist->size == 0) { /* remains only one file to down. */
 +      wildcard->state = CURLWC_CLEAN;
 +      /* after that will be ftp_do called once again and no transfer
 +         will be done because of CURLWC_CLEAN state */
 +      return CURLE_OK;
 +    }
 +  } break;
 +
 +  case CURLWC_SKIP: {
 +    if(conn->data->set.chunk_end)
 +      conn->data->set.chunk_end(conn->data->wildcard.customptr);
 +    Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
 +    wildcard->state = (wildcard->filelist->size == 0) ?
 +                      CURLWC_CLEAN : CURLWC_DOWNLOADING;
 +    return wc_statemach(conn);
 +  }
 +
 +  case CURLWC_CLEAN: {
 +    struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
 +    result = CURLE_OK;
 +    if(ftp_tmp)
 +      result = Curl_ftp_parselist_geterror(ftp_tmp->parser);
 +
 +    wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE;
 +  } break;
 +
 +  case CURLWC_DONE:
 +  case CURLWC_ERROR:
 +    break;
 +  }
 +
 +  return result;
 +}
 +
 +/***********************************************************************
 + *
 + * ftp_do()
 + *
 + * This function is registered as 'curl_do' function. It decodes the path
 + * parts etc as a wrapper to the actual DO function (ftp_perform).
 + *
 + * The input argument is already checked for validity.
 + */
 +static CURLcode ftp_do(struct connectdata *conn, bool *done)
 +{
 +  CURLcode result = CURLE_OK;
 +  struct ftp_conn *ftpc = &conn->proto.ftpc;
 +
 +  *done = FALSE; /* default to false */
 +  ftpc->wait_data_conn = FALSE; /* default to no such wait */
 +
 +  if(conn->data->set.wildcardmatch) {
 +    result = wc_statemach(conn);
 +    if(conn->data->wildcard.state == CURLWC_SKIP ||
 +      conn->data->wildcard.state == CURLWC_DONE) {
 +      /* do not call ftp_regular_transfer */
 +      return CURLE_OK;
 +    }
 +    if(result) /* error, loop or skipping the file */
 +      return result;
 +  }
 +  else { /* no wildcard FSM needed */
 +    result = ftp_parse_url_path(conn);
 +    if(result)
 +      return result;
 +  }
 +
 +  result = ftp_regular_transfer(conn, done);
 +
 +  return result;
 +}
 +
 +
 +CURLcode Curl_ftpsendf(struct connectdata *conn,
 +                       const char *fmt, ...)
 +{
 +  ssize_t bytes_written;
 +#define SBUF_SIZE 1024
 +  char s[SBUF_SIZE];
 +  size_t write_len;
 +  char *sptr=s;
 +  CURLcode result = CURLE_OK;
 +#ifdef HAVE_GSSAPI
 +  enum protection_level data_sec = conn->data_prot;
 +#endif
 +
 +  va_list ap;
 +  va_start(ap, fmt);
 +  write_len = vsnprintf(s, SBUF_SIZE-3, fmt, ap);
 +  va_end(ap);
 +
 +  strcpy(&s[write_len], "\r\n"); /* append a trailing CRLF */
 +  write_len +=2;
 +
 +  bytes_written=0;
 +
 +  result = Curl_convert_to_network(conn->data, s, write_len);
 +  /* Curl_convert_to_network calls failf if unsuccessful */
 +  if(result)
 +    return result;
 +
 +  for(;;) {
 +#ifdef HAVE_GSSAPI
 +    conn->data_prot = PROT_CMD;
 +#endif
 +    result = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
 +                        &bytes_written);
 +#ifdef HAVE_GSSAPI
 +    DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
 +    conn->data_prot = data_sec;
 +#endif
 +
 +    if(result)
 +      break;
 +
 +    if(conn->data->set.verbose)
 +      Curl_debug(conn->data, CURLINFO_HEADER_OUT,
 +                 sptr, (size_t)bytes_written, conn);
 +
 +    if(bytes_written != (ssize_t)write_len) {
 +      write_len -= bytes_written;
 +      sptr += bytes_written;
 +    }
 +    else
 +      break;
 +  }
 +
 +  return result;
 +}
 +
 +/***********************************************************************
 + *
 + * ftp_quit()
 + *
 + * This should be called before calling sclose() on an ftp control connection
 + * (not data connections). We should then wait for the response from the
 + * server before returning. The calling code should then try to close the
 + * connection.
 + *
 + */
 +static CURLcode ftp_quit(struct connectdata *conn)
 +{
 +  CURLcode result = CURLE_OK;
 +
 +  if(conn->proto.ftpc.ctl_valid) {
 +    result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", "QUIT");
 +    if(result) {
 +      failf(conn->data, "Failure sending QUIT command: %s",
 +            curl_easy_strerror(result));
 +      conn->proto.ftpc.ctl_valid = FALSE; /* mark control connection as bad */
 +      connclose(conn, "QUIT command failed"); /* mark for connection closure */
 +      state(conn, FTP_STOP);
 +      return result;
 +    }
 +
 +    state(conn, FTP_QUIT);
 +
 +    result = ftp_block_statemach(conn);
 +  }
 +
 +  return result;
 +}
 +
 +/***********************************************************************
 + *
 + * ftp_disconnect()
 + *
 + * Disconnect from an FTP server. Cleanup protocol-specific per-connection
 + * resources. BLOCKING.
 + */
 +static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection)
 +{
 +  struct ftp_conn *ftpc= &conn->proto.ftpc;
 +  struct pingpong *pp = &ftpc->pp;
 +
 +  /* We cannot send quit unconditionally. If this connection is stale or
 +     bad in any way, sending quit and waiting around here will make the
 +     disconnect wait in vain and cause more problems than we need to.
 +
 +     ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
 +     will try to send the QUIT command, otherwise it will just return.
 +  */
 +  if(dead_connection)
 +    ftpc->ctl_valid = FALSE;
 +
 +  /* The FTP session may or may not have been allocated/setup at this point! */
 +  (void)ftp_quit(conn); /* ignore errors on the QUIT */
 +
 +  if(ftpc->entrypath) {
-     struct SessionHandle *data = conn->data;
++    struct Curl_easy *data = conn->data;
 +    if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) {
 +      data->state.most_recent_ftp_entrypath = NULL;
 +    }
 +    free(ftpc->entrypath);
 +    ftpc->entrypath = NULL;
 +  }
 +
 +  freedirs(ftpc);
 +  free(ftpc->prevpath);
 +  ftpc->prevpath = NULL;
 +  free(ftpc->server_os);
 +  ftpc->server_os = NULL;
 +
 +  Curl_pp_disconnect(pp);
 +
 +#ifdef HAVE_GSSAPI
 +  Curl_sec_end(conn);
 +#endif
 +
 +  return CURLE_OK;
 +}
 +
 +/***********************************************************************
 + *
 + * ftp_parse_url_path()
 + *
 + * Parse the URL path into separate path components.
 + *
 + */
 +static
 +CURLcode ftp_parse_url_path(struct connectdata *conn)
 +{
-   struct SessionHandle *data = conn->data;
++  struct Curl_easy *data = conn->data;
 +  /* the ftp struct is already inited in ftp_connect() */
 +  struct FTP *ftp = data->req.protop;
 +  struct ftp_conn *ftpc = &conn->proto.ftpc;
 +  const char *slash_pos;  /* position of the first '/' char in curpos */
 +  const char *path_to_use = data->state.path;
 +  const char *cur_pos;
 +  const char *filename = NULL;
 +
 +  cur_pos = path_to_use; /* current position in path. point at the begin
 +                            of next path component */
 +
 +  ftpc->ctl_valid = FALSE;
 +  ftpc->cwdfail = FALSE;
 +
 +  switch(data->set.ftp_filemethod) {
 +  case FTPFILE_NOCWD:
 +    /* fastest, but less standard-compliant */
 +
 +    /*
 +      The best time to check whether the path is a file or directory is right
 +      here. so:
 +
 +      the first condition in the if() right here, is there just in case
 +      someone decides to set path to NULL one day
 +   */
-     if(data->state.path &&
-        data->state.path[0] &&
-        (data->state.path[strlen(data->state.path) - 1] != '/') )
-       filename = data->state.path;  /* this is a full file path */
-       /*
++    if(path_to_use[0] &&
++       (path_to_use[strlen(path_to_use) - 1] != '/') )
++      filename = path_to_use;  /* this is a full file path */
++    /*
++      else {
 +        ftpc->file is not used anywhere other than for operations on a file.
 +        In other words, never for directory operations.
 +        So we can safely leave filename as NULL here and use it as a
 +        argument in dir/file decisions.
-       */
++      }
++    */
 +    break;
 +
 +  case FTPFILE_SINGLECWD:
 +    /* get the last slash */
 +    if(!path_to_use[0]) {
 +      /* no dir, no file */
 +      ftpc->dirdepth = 0;
 +      break;
 +    }
 +    slash_pos=strrchr(cur_pos, '/');
 +    if(slash_pos || !*cur_pos) {
 +      size_t dirlen = slash_pos-cur_pos;
 +
 +      ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0]));
 +      if(!ftpc->dirs)
 +        return CURLE_OUT_OF_MEMORY;
 +
 +      if(!dirlen)
 +        dirlen++;
 +
 +      ftpc->dirs[0] = curl_easy_unescape(conn->data, slash_pos ? cur_pos : "/",
 +                                         slash_pos ? curlx_uztosi(dirlen) : 1,
 +                                         NULL);
 +      if(!ftpc->dirs[0]) {
 +        freedirs(ftpc);
 +        return CURLE_OUT_OF_MEMORY;
 +      }
 +      ftpc->dirdepth = 1; /* we consider it to be a single dir */
 +      filename = slash_pos ? slash_pos+1 : cur_pos; /* rest is file name */
 +    }
 +    else
 +      filename = cur_pos;  /* this is a file name only */
 +    break;
 +
 +  default: /* allow pretty much anything */
 +  case FTPFILE_MULTICWD:
 +    ftpc->dirdepth = 0;
 +    ftpc->diralloc = 5; /* default dir depth to allocate */
 +    ftpc->dirs = calloc(ftpc->diralloc, sizeof(ftpc->dirs[0]));
 +    if(!ftpc->dirs)
 +      return CURLE_OUT_OF_MEMORY;
 +
 +    /* we have a special case for listing the root dir only */
 +    if(strequal(path_to_use, "/")) {
 +      cur_pos++; /* make it point to the zero byte */
 +      ftpc->dirs[0] = strdup("/");
 +      ftpc->dirdepth++;
 +    }
 +    else {
 +      /* parse the URL path into separate path components */
 +      while((slash_pos = strchr(cur_pos, '/')) != NULL) {
 +        /* 1 or 0 pointer offset to indicate absolute directory */
 +        ssize_t absolute_dir = ((cur_pos - data->state.path > 0) &&
 +                                (ftpc->dirdepth == 0))?1:0;
 +
 +        /* seek out the next path component */
 +        if(slash_pos-cur_pos) {
 +          /* we skip empty path components, like "x//y" since the FTP command
 +             CWD requires a parameter and a non-existent parameter a) doesn't
 +             work on many servers and b) has no effect on the others. */
 +          int len = curlx_sztosi(slash_pos - cur_pos + absolute_dir);
 +          ftpc->dirs[ftpc->dirdepth] =
 +            curl_easy_unescape(conn->data, cur_pos - absolute_dir, len, NULL);
 +          if(!ftpc->dirs[ftpc->dirdepth]) { /* run out of memory ... */
 +            failf(data, "no memory");
 +            freedirs(ftpc);
 +            return CURLE_OUT_OF_MEMORY;
 +          }
 +          if(isBadFtpString(ftpc->dirs[ftpc->dirdepth])) {
 +            free(ftpc->dirs[ftpc->dirdepth]);
 +            freedirs(ftpc);
 +            return CURLE_URL_MALFORMAT;
 +          }
 +        }
 +        else {
 +          cur_pos = slash_pos + 1; /* jump to the rest of the string */
 +          if(!ftpc->dirdepth) {
 +            /* path starts with a slash, add that as a directory */
 +            ftpc->dirs[ftpc->dirdepth] = strdup("/");
 +            if(!ftpc->dirs[ftpc->dirdepth++]) { /* run out of memory ... */
 +              failf(data, "no memory");
 +              freedirs(ftpc);
 +              return CURLE_OUT_OF_MEMORY;
 +            }
 +          }
 +          continue;
 +        }
 +
 +        cur_pos = slash_pos + 1; /* jump to the rest of the string */
 +        if(++ftpc->dirdepth >= ftpc->diralloc) {
 +          /* enlarge array */
 +          char **bigger;
 +          ftpc->diralloc *= 2; /* double the size each time */
 +          bigger = realloc(ftpc->dirs, ftpc->diralloc * sizeof(ftpc->dirs[0]));
 +          if(!bigger) {
 +            freedirs(ftpc);
 +            return CURLE_OUT_OF_MEMORY;
 +          }
 +          ftpc->dirs = bigger;
 +        }
 +      }
 +    }
 +    filename = cur_pos;  /* the rest is the file name */
 +    break;
 +  } /* switch */
 +
 +  if(filename && *filename) {
 +    ftpc->file = curl_easy_unescape(conn->data, filename, 0, NULL);
 +    if(NULL == ftpc->file) {
 +      freedirs(ftpc);
 +      failf(data, "no memory");
 +      return CURLE_OUT_OF_MEMORY;
 +    }
 +    if(isBadFtpString(ftpc->file)) {
 +      freedirs(ftpc);
 +      return CURLE_URL_MALFORMAT;
 +    }
 +  }
 +  else
 +    ftpc->file=NULL; /* instead of point to a zero byte, we make it a NULL
 +                       pointer */
 +
 +  if(data->set.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) {
 +    /* We need a file name when uploading. Return error! */
 +    failf(data, "Uploading to a URL without a file name!");
 +    return CURLE_URL_MALFORMAT;
 +  }
 +
 +  ftpc->cwddone = FALSE; /* default to not done */
 +
 +  if(ftpc->prevpath) {
 +    /* prevpath is "raw" so we convert the input path before we compare the
 +       strings */
 +    int dlen;
 +    char *path = curl_easy_unescape(conn->data, data->state.path, 0, &dlen);
 +    if(!path) {
 +      freedirs(ftpc);
 +      return CURLE_OUT_OF_MEMORY;
 +    }
 +
 +    dlen -= ftpc->file?curlx_uztosi(strlen(ftpc->file)):0;
 +    if((dlen == curlx_uztosi(strlen(ftpc->prevpath))) &&
 +       strnequal(path, ftpc->prevpath, dlen)) {
 +      infof(data, "Request has same path as previous transfer\n");
 +      ftpc->cwddone = TRUE;
 +    }
 +    free(path);
 +  }
 +
 +  return CURLE_OK;
 +}
 +
 +/* call this when the DO phase has completed */
 +static CURLcode ftp_dophase_done(struct connectdata *conn,
 +                                 bool connected)
 +{
 +  struct FTP *ftp = conn->data->req.protop;
 +  struct ftp_conn *ftpc = &conn->proto.ftpc;
 +
 +  if(connected) {
 +    int completed;
 +    CURLcode result = ftp_do_more(conn, &completed);
 +
 +    if(result) {
-       if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
-         /* close the second socket if it was created already */
-         Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
-         conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
-       }
++      close_secondarysocket(conn);
 +      return result;
 +    }
 +  }
 +
 +  if(ftp->transfer != FTPTRANSFER_BODY)
 +    /* no data to transfer */
 +    Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
 +  else if(!connected)
 +    /* since we didn't connect now, we want do_more to get called */
 +    conn->bits.do_more = TRUE;
 +
 +  ftpc->ctl_valid = TRUE; /* seems good */
 +
 +  return CURLE_OK;
 +}
 +
 +/* called from multi.c while DOing */
 +static CURLcode ftp_doing(struct connectdata *conn,
 +                          bool *dophase_done)
 +{
 +  CURLcode result = ftp_multi_statemach(conn, dophase_done);
 +
 +  if(result)
 +    DEBUGF(infof(conn->data, "DO phase failed\n"));
 +  else if(*dophase_done) {
 +    result = ftp_dophase_done(conn, FALSE /* not connected */);
 +
 +    DEBUGF(infof(conn->data, "DO phase is complete2\n"));
 +  }
 +  return result;
 +}
 +
 +/***********************************************************************
 + *
 + * ftp_regular_transfer()
 + *
 + * The input argument is already checked for validity.
 + *
 + * Performs all commands done before a regular transfer between a local and a
 + * remote host.
 + *
 + * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
 + * ftp_done() function without finding any major problem.
 + */
 +static
 +CURLcode ftp_regular_transfer(struct connectdata *conn,
 +                              bool *dophase_done)
 +{
 +  CURLcode result=CURLE_OK;
 +  bool connected=FALSE;
-   struct SessionHandle *data = conn->data;
++  struct Curl_easy *data = conn->data;
 +  struct ftp_conn *ftpc = &conn->proto.ftpc;
 +  data->req.size = -1; /* make sure this is unknown at this point */
 +
 +  Curl_pgrsSetUploadCounter(data, 0);
 +  Curl_pgrsSetDownloadCounter(data, 0);
 +  Curl_pgrsSetUploadSize(data, -1);
 +  Curl_pgrsSetDownloadSize(data, -1);
 +
 +  ftpc->ctl_valid = TRUE; /* starts good */
 +
 +  result = ftp_perform(conn,
 +                       &connected, /* have we connected after PASV/PORT */
 +                       dophase_done); /* all commands in the DO-phase done? */
 +
 +  if(!result) {
 +
 +    if(!*dophase_done)
 +      /* the DO phase has not completed yet */
 +      return CURLE_OK;
 +
 +    result = ftp_dophase_done(conn, connected);
 +
 +    if(result)
 +      return result;
 +  }
 +  else
 +    freedirs(ftpc);
 +
 +  return result;
 +}
 +
 +static CURLcode ftp_setup_connection(struct connectdata *conn)
 +{
-   struct SessionHandle *data = conn->data;
++  struct Curl_easy *data = conn->data;
 +  char *type;
 +  char command;
 +  struct FTP *ftp;
 +
 +  if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
 +    /* Unless we have asked to tunnel ftp operations through the proxy, we
 +       switch and use HTTP operations only */
 +#ifndef CURL_DISABLE_HTTP
 +    if(conn->handler == &Curl_handler_ftp)
 +      conn->handler = &Curl_handler_ftp_proxy;
 +    else {
 +#ifdef USE_SSL
 +      conn->handler = &Curl_handler_ftps_proxy;
 +#else
 +      failf(data, "FTPS not supported!");
 +      return CURLE_UNSUPPORTED_PROTOCOL;
 +#endif
 +    }
 +    /* set it up as a HTTP connection instead */
 +    return conn->handler->setup_connection(conn);
 +#else
 +    failf(data, "FTP over http proxy requires HTTP support built-in!");
 +    return CURLE_UNSUPPORTED_PROTOCOL;
 +#endif
 +  }
 +
 +  conn->data->req.protop = ftp = malloc(sizeof(struct FTP));
 +  if(NULL == ftp)
 +    return CURLE_OUT_OF_MEMORY;
 +
 +  data->state.path++;   /* don't include the initial slash */
 +  data->state.slash_removed = TRUE; /* we've skipped the slash */
 +
 +  /* FTP URLs support an extension like ";type=<typecode>" that
 +   * we'll try to get now! */
 +  type = strstr(data->state.path, ";type=");
 +
 +  if(!type)
 +    type = strstr(conn->host.rawalloc, ";type=");
 +
 +  if(type) {
 +    *type = 0;                     /* it was in the middle of the hostname */
 +    command = Curl_raw_toupper(type[6]);
 +    conn->bits.type_set = TRUE;
 +
 +    switch (command) {
 +    case 'A': /* ASCII mode */
 +      data->set.prefer_ascii = TRUE;
 +      break;
 +
 +    case 'D': /* directory mode */
 +      data->set.ftp_list_only = TRUE;
 +      break;
 +
 +    case 'I': /* binary mode */
 +    default:
 +      /* switch off ASCII */
 +      data->set.prefer_ascii = FALSE;
 +      break;
 +    }
 +  }
 +
 +  /* get some initial data into the ftp struct */
 +  ftp->bytecountp = &conn->data->req.bytecount;
 +  ftp->transfer = FTPTRANSFER_BODY;
 +  ftp->downloadsize = 0;
 +
 +  /* No need to duplicate user+password, the connectdata struct won't change
 +     during a session, but we re-init them here since on subsequent inits
 +     since the conn struct may have changed or been replaced.
 +  */
 +  ftp->user = conn->user;
 +  ftp->passwd = conn->passwd;
 +  if(isBadFtpString(ftp->user))
 +    return CURLE_URL_MALFORMAT;
 +  if(isBadFtpString(ftp->passwd))
 +    return CURLE_URL_MALFORMAT;
 +
 +  conn->proto.ftpc.known_filesize = -1; /* unknown size for now */
 +
 +  return CURLE_OK;
 +}
 +
 +#endif /* CURL_DISABLE_FTP */
diff --cc Utilities/cmcurl/lib/mprintf.c
index 7412dc3,0000000..380c3d6
mode 100644,000000..100644
--- a/Utilities/cmcurl/lib/mprintf.c
+++ b/Utilities/cmcurl/lib/mprintf.c
@@@ -1,1138 -1,0 +1,1156 @@@
 +/***************************************************************************
 + *                                  _   _ ____  _
 + *  Project                     ___| | | |  _ \| |
 + *                             / __| | | | |_) | |
 + *                            | (__| |_| |  _ <| |___
 + *                             \___|\___/|_| \_\_____|
 + *
-  * Copyright (C) 1999 - 2014, Daniel Stenberg, <daniel at haxx.se>, et al.
++ * Copyright (C) 1999 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
 + *
 + * This software is licensed as described in the file COPYING, which
 + * you should have received as part of this distribution. The terms
-  * are also available at http://curl.haxx.se/docs/copyright.html.
++ * 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.
 + *
 + *
 + * Purpose:
 + *  A merge of Bjorn Reese's format() function and Daniel's dsprintf()
 + *  1.0. A full blooded printf() clone with full support for <num>$
 + *  everywhere (parameters, widths and precisions) including variabled
 + *  sized parameters (like doubles, long longs, long doubles and even
 + *  void * in 64-bit architectures).
 + *
 + * Current restrictions:
 + * - Max 128 parameters
 + * - No 'long double' support.
 + *
 + * If you ever want truly portable and good *printf() clones, the project that
 + * took on from here is named 'Trio' and you find more details on the trio web
-  * page at http://daniel.haxx.se/trio/
++ * page at https://daniel.haxx.se/projects/trio/
 + */
 +
 +#include "curl_setup.h"
- 
- #if defined(DJGPP) && (DJGPP_MINOR < 4)
- #undef _MPRINTF_REPLACE /* don't use x_was_used() here */
- #endif
- 
 +#include <curl/mprintf.h>
 +
 +#include "curl_memory.h"
 +/* The last #include file should be: */
 +#include "memdebug.h"
 +
 +/*
 + * If SIZEOF_SIZE_T has not been defined, default to the size of long.
 + */
 +
 +#ifndef SIZEOF_SIZE_T
 +#  define SIZEOF_SIZE_T CURL_SIZEOF_LONG
 +#endif
 +
 +#ifdef HAVE_LONGLONG
 +#  define LONG_LONG_TYPE long long
 +#  define HAVE_LONG_LONG_TYPE
 +#else
 +#  if defined(_MSC_VER) && (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64)
 +#    define LONG_LONG_TYPE __int64
 +#    define HAVE_LONG_LONG_TYPE
 +#  else
 +#    undef LONG_LONG_TYPE
 +#    undef HAVE_LONG_LONG_TYPE
 +#  endif
 +#endif
 +
 +/*
 + * Non-ANSI integer extensions
 + */
 +
 +#if (defined(__BORLANDC__) && (__BORLANDC__ >= 0x520)) || \
 +    (defined(__WATCOMC__) && defined(__386__)) || \
 +    (defined(__POCC__) && defined(_MSC_VER)) || \
 +    (defined(_WIN32_WCE)) || \
 +    (defined(__MINGW32__)) || \
 +    (defined(_MSC_VER) && (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64))
 +#  define MP_HAVE_INT_EXTENSIONS
 +#endif
 +
 +/*
 + * Max integer data types that mprintf.c is capable
 + */
 +
 +#ifdef HAVE_LONG_LONG_TYPE
 +#  define mp_intmax_t LONG_LONG_TYPE
 +#  define mp_uintmax_t unsigned LONG_LONG_TYPE
 +#else
 +#  define mp_intmax_t long
 +#  define mp_uintmax_t unsigned long
 +#endif
 +
 +#define BUFFSIZE 256 /* buffer for long-to-str and float-to-str calcs */
 +#define MAX_PARAMETERS 128 /* lame static limit */
 +
 +#ifdef __AMIGA__
 +# undef FORMAT_INT
 +#endif
 +
 +/* Lower-case digits.  */
 +static const char lower_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
 +
 +/* Upper-case digits.  */
 +static const char upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
 +
 +#define OUTCHAR(x) \
 +  do{ \
 +    if(stream((unsigned char)(x), (FILE *)data) != -1) \
 +      done++; \
 +    else \
 +     return done; /* return immediately on failure */ \
 +  } WHILE_FALSE
 +
 +/* Data type to read from the arglist */
 +typedef enum  {
 +  FORMAT_UNKNOWN = 0,
 +  FORMAT_STRING,
 +  FORMAT_PTR,
 +  FORMAT_INT,
 +  FORMAT_INTPTR,
 +  FORMAT_LONG,
 +  FORMAT_LONGLONG,
 +  FORMAT_DOUBLE,
 +  FORMAT_LONGDOUBLE,
 +  FORMAT_WIDTH /* For internal use */
 +} FormatType;
 +
 +/* conversion and display flags */
 +enum {
 +  FLAGS_NEW        = 0,
 +  FLAGS_SPACE      = 1<<0,
 +  FLAGS_SHOWSIGN   = 1<<1,
 +  FLAGS_LEFT       = 1<<2,
 +  FLAGS_ALT        = 1<<3,
 +  FLAGS_SHORT      = 1<<4,
 +  FLAGS_LONG       = 1<<5,
 +  FLAGS_LONGLONG   = 1<<6,
 +  FLAGS_LONGDOUBLE = 1<<7,
 +  FLAGS_PAD_NIL    = 1<<8,
 +  FLAGS_UNSIGNED   = 1<<9,
 +  FLAGS_OCTAL      = 1<<10,
 +  FLAGS_HEX        = 1<<11,
 +  FLAGS_UPPER      = 1<<12,
 +  FLAGS_WIDTH      = 1<<13, /* '*' or '*<num>$' used */
 +  FLAGS_WIDTHPARAM = 1<<14, /* width PARAMETER was specified */
 +  FLAGS_PREC       = 1<<15, /* precision was specified */
 +  FLAGS_PRECPARAM  = 1<<16, /* precision PARAMETER was specified */
 +  FLAGS_CHAR       = 1<<17, /* %c story */
 +  FLAGS_FLOATE     = 1<<18, /* %e or %E */
 +  FLAGS_FLOATG     = 1<<19  /* %g or %G */
 +};
 +
 +typedef struct {
 +  FormatType type;
 +  int flags;
 +  long width;     /* width OR width parameter number */
 +  long precision; /* precision OR precision parameter number */
 +  union {
 +    char *str;
 +    void *ptr;
 +    union {
 +      mp_intmax_t as_signed;
 +      mp_uintmax_t as_unsigned;
 +    } num;
 +    double dnum;
 +  } data;
 +} va_stack_t;
 +
 +struct nsprintf {
 +  char *buffer;
 +  size_t length;
 +  size_t max;
 +};
 +
 +struct asprintf {
 +  char *buffer; /* allocated buffer */
 +  size_t len;   /* length of string */
 +  size_t alloc; /* length of alloc */
 +  int fail;     /* (!= 0) if an alloc has failed and thus
 +                   the output is not the complete data */
 +};
 +
 +static long dprintf_DollarString(char *input, char **end)
 +{
 +  int number=0;
 +  while(ISDIGIT(*input)) {
 +    number *= 10;
 +    number += *input-'0';
 +    input++;
 +  }
 +  if(number && ('$'==*input++)) {
 +    *end = input;
 +    return number;
 +  }
 +  return 0;
 +}
 +
 +static bool dprintf_IsQualifierNoDollar(const char *fmt)
 +{
 +#if defined(MP_HAVE_INT_EXTENSIONS)
 +  if(!strncmp(fmt, "I32", 3) || !strncmp(fmt, "I64", 3)) {
 +    return TRUE;
 +  }
 +#endif
 +
 +  switch(*fmt) {
 +  case '-': case '+': case ' ': case '#': case '.':
 +  case '0': case '1': case '2': case '3': case '4':
 +  case '5': case '6': case '7': case '8': case '9':
 +  case 'h': case 'l': case 'L': case 'z': case 'q':
 +  case '*': case 'O':
 +#if defined(MP_HAVE_INT_EXTENSIONS)
 +  case 'I':
 +#endif
 +    return TRUE;
 +
 +  default:
 +    return FALSE;
 +  }
 +}
 +
 +/******************************************************************
 + *
 + * Pass 1:
 + * Create an index with the type of each parameter entry and its
 + * value (may vary in size)
 + *
 + ******************************************************************/
 +
 +static long dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos,
 +                          va_list arglist)
 +{
 +  char *fmt = (char *)format;
 +  int param_num = 0;
 +  long this_param;
 +  long width;
 +  long precision;
 +  int flags;
 +  long max_param=0;
 +  long i;
 +
 +  while(*fmt) {
 +    if(*fmt++ == '%') {
 +      if(*fmt == '%') {
 +        fmt++;
 +        continue; /* while */
 +      }
 +
 +      flags = FLAGS_NEW;
 +
 +      /* Handle the positional case (N$) */
 +
 +      param_num++;
 +
 +      this_param = dprintf_DollarString(fmt, &fmt);
 +      if(0 == this_param)
 +        /* we got no positional, get the next counter */
 +        this_param = param_num;
 +
 +      if(this_param > max_param)
 +        max_param = this_param;
 +
 +      /*
 +       * The parameter with number 'i' should be used. Next, we need
 +       * to get SIZE and TYPE of the parameter. Add the information
 +       * to our array.
 +       */
 +
 +      width = 0;
 +      precision = 0;
 +
 +      /* Handle the flags */
 +
 +      while(dprintf_IsQualifierNoDollar(fmt)) {
 +#if defined(MP_HAVE_INT_EXTENSIONS)
 +        if(!strncmp(fmt, "I32", 3)) {
 +          flags |= FLAGS_LONG;
 +          fmt += 3;
 +        }
 +        else if(!strncmp(fmt, "I64", 3)) {
 +          flags |= FLAGS_LONGLONG;
 +          fmt += 3;
 +        }
 +        else
 +#endif
 +
 +        switch(*fmt++) {
 +        case ' ':
 +          flags |= FLAGS_SPACE;
 +          break;
 +        case '+':
 +          flags |= FLAGS_SHOWSIGN;
 +          break;
 +        case '-':
 +          flags |= FLAGS_LEFT;
 +          flags &= ~FLAGS_PAD_NIL;
 +          break;
 +        case '#':
 +          flags |= FLAGS_ALT;
 +          break;
 +        case '.':
 +          flags |= FLAGS_PREC;
 +          if('*' == *fmt) {
 +            /* The precision is picked from a specified parameter */
 +
 +            flags |= FLAGS_PRECPARAM;
 +            fmt++;
 +            param_num++;
 +
 +            i = dprintf_DollarString(fmt, &fmt);
 +            if(i)
 +              precision = i;
 +            else
 +              precision = param_num;
 +
 +            if(precision > max_param)
 +              max_param = precision;
 +          }
 +          else {
 +            flags |= FLAGS_PREC;
 +            precision = strtol(fmt, &fmt, 10);
 +          }
 +          break;
 +        case 'h':
 +          flags |= FLAGS_SHORT;
 +          break;
 +#if defined(MP_HAVE_INT_EXTENSIONS)
 +        case 'I':
 +#if (CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG)
 +          flags |= FLAGS_LONGLONG;
 +#else
 +          flags |= FLAGS_LONG;
 +#endif
 +          break;
 +#endif
 +        case 'l':
 +          if(flags & FLAGS_LONG)
 +            flags |= FLAGS_LONGLONG;
 +          else
 +            flags |= FLAGS_LONG;
 +          break;
 +        case 'L':
 +          flags |= FLAGS_LONGDOUBLE;
 +          break;
 +        case 'q':
 +          flags |= FLAGS_LONGLONG;
 +          break;
 +        case 'z':
 +          /* the code below generates a warning if -Wunreachable-code is
 +             used */
 +#if (SIZEOF_SIZE_T > CURL_SIZEOF_LONG)
 +          flags |= FLAGS_LONGLONG;
 +#else
 +          flags |= FLAGS_LONG;
 +#endif
 +          break;
 +        case 'O':
 +#if (CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG)
 +          flags |= FLAGS_LONGLONG;
 +#else
 +          flags |= FLAGS_LONG;
 +#endif
 +          break;
 +        case '0':
 +          if(!(flags & FLAGS_LEFT))
 +            flags |= FLAGS_PAD_NIL;
 +          /* FALLTHROUGH */
 +        case '1': case '2': case '3': case '4':
 +        case '5': case '6': case '7': case '8': case '9':
 +          flags |= FLAGS_WIDTH;
 +          width = strtol(fmt-1, &fmt, 10);
 +          break;
 +        case '*':  /* Special case */
 +          flags |= FLAGS_WIDTHPARAM;
 +          param_num++;
 +
 +          i = dprintf_DollarString(fmt, &fmt);
 +          if(i)
 +            width = i;
 +          else
 +            width = param_num;
 +          if(width > max_param)
 +            max_param=width;
 +          break;
 +        default:
 +          break;
 +        }
 +      } /* switch */
 +
 +      /* Handle the specifier */
 +
 +      i = this_param - 1;
 +
 +      switch (*fmt) {
 +      case 'S':
 +        flags |= FLAGS_ALT;
 +        /* FALLTHROUGH */
 +      case 's':
 +        vto[i].type = FORMAT_STRING;
 +        break;
 +      case 'n':
 +        vto[i].type = FORMAT_INTPTR;
 +        break;
 +      case 'p':
 +        vto[i].type = FORMAT_PTR;
 +        break;
 +      case 'd': case 'i':
 +        vto[i].type = FORMAT_INT;
 +        break;
 +      case 'u':
 +        vto[i].type = FORMAT_INT;
 +        flags |= FLAGS_UNSIGNED;
 +        break;
 +      case 'o':
 +        vto[i].type = FORMAT_INT;
 +        flags |= FLAGS_OCTAL;
 +        break;
 +      case 'x':
 +        vto[i].type = FORMAT_INT;
 +        flags |= FLAGS_HEX|FLAGS_UNSIGNED;
 +        break;
 +      case 'X':
 +        vto[i].type = FORMAT_INT;
 +        flags |= FLAGS_HEX|FLAGS_UPPER|FLAGS_UNSIGNED;
 +        break;
 +      case 'c':
 +        vto[i].type = FORMAT_INT;
 +        flags |= FLAGS_CHAR;
 +        break;
 +      case 'f':
 +        vto[i].type = FORMAT_DOUBLE;
 +        break;
 +      case 'e':
 +        vto[i].type = FORMAT_DOUBLE;
 +        flags |= FLAGS_FLOATE;
 +        break;
 +      case 'E':
 +        vto[i].type = FORMAT_DOUBLE;
 +        flags |= FLAGS_FLOATE|FLAGS_UPPER;
 +        break;
 +      case 'g':
 +        vto[i].type = FORMAT_DOUBLE;
 +        flags |= FLAGS_FLOATG;
 +        break;
 +      case 'G':
 +        vto[i].type = FORMAT_DOUBLE;
 +        flags |= FLAGS_FLOATG|FLAGS_UPPER;
 +        break;
 +      default:
 +        vto[i].type = FORMAT_UNKNOWN;
 +        break;
 +      } /* switch */
 +
 +      vto[i].flags = flags;
 +      vto[i].width = width;
 +      vto[i].precision = precision;
 +
 +      if(flags & FLAGS_WIDTHPARAM) {
 +        /* we have the width specified from a parameter, so we make that
 +           parameter's info setup properly */
-         vto[i].width = width - 1;
-         i = width - 1;
-         vto[i].type = FORMAT_WIDTH;
-         vto[i].flags = FLAGS_NEW;
-         vto[i].precision = vto[i].width = 0; /* can't use width or precision
-                                                 of width! */
++        long k = width - 1;
++        vto[i].width = k;
++        vto[k].type = FORMAT_WIDTH;
++        vto[k].flags = FLAGS_NEW;
++        /* can't use width or precision of width! */
++        vto[k].width = 0;
++        vto[k].precision = 0;
 +      }
 +      if(flags & FLAGS_PRECPARAM) {
 +        /* we have the precision specified from a parameter, so we make that
 +           parameter's info setup properly */
-         vto[i].precision = precision - 1;
-         i = precision - 1;
-         vto[i].type = FORMAT_WIDTH;
-         vto[i].flags = FLAGS_NEW;
-         vto[i].precision = vto[i].width = 0; /* can't use width or precision
-                                                 of width! */
++        long k = precision - 1;
++        vto[i].precision = k;
++        vto[k].type = FORMAT_WIDTH;
++        vto[k].flags = FLAGS_NEW;
++        /* can't use width or precision of width! */
++        vto[k].width = 0;
++        vto[k].precision = 0;
 +      }
 +      *endpos++ = fmt + 1; /* end of this sequence */
 +    }
 +  }
 +
 +  /* Read the arg list parameters into our data list */
 +  for(i=0; i<max_param; i++) {
-     if((i + 1 < max_param) && (vto[i + 1].type == FORMAT_WIDTH)) {
-       /* Width/precision arguments must be read before the main argument
-        * they are attached to
-        */
-       vto[i + 1].data.num.as_signed = (mp_intmax_t)va_arg(arglist, int);
++    /* Width/precision arguments must be read before the main argument
++       they are attached to */
++    if(vto[i].flags & FLAGS_WIDTHPARAM) {
++      vto[vto[i].width].data.num.as_signed =
++        (mp_intmax_t)va_arg(arglist, int);
++    }
++    if(vto[i].flags & FLAGS_PRECPARAM) {
++      vto[vto[i].precision].data.num.as_signed =
++        (mp_intmax_t)va_arg(arglist, int);
 +    }
 +
 +    switch (vto[i].type) {
 +    case FORMAT_STRING:
 +      vto[i].data.str = va_arg(arglist, char *);
 +      break;
 +
 +    case FORMAT_INTPTR:
 +    case FORMAT_UNKNOWN:
 +    case FORMAT_PTR:
 +      vto[i].data.ptr = va_arg(arglist, void *);
 +      break;
 +
 +    case FORMAT_INT:
 +#ifdef HAVE_LONG_LONG_TYPE
 +      if((vto[i].flags & FLAGS_LONGLONG) && (vto[i].flags & FLAGS_UNSIGNED))
 +        vto[i].data.num.as_unsigned =
 +          (mp_uintmax_t)va_arg(arglist, mp_uintmax_t);
 +      else if(vto[i].flags & FLAGS_LONGLONG)
 +        vto[i].data.num.as_signed =
 +          (mp_intmax_t)va_arg(arglist, mp_intmax_t);
 +      else
 +#endif
 +      {
 +        if((vto[i].flags & FLAGS_LONG) && (vto[i].flags & FLAGS_UNSIGNED))
 +          vto[i].data.num.as_unsigned =
 +            (mp_uintmax_t)va_arg(arglist, unsigned long);
 +        else if(vto[i].flags & FLAGS_LONG)
 +          vto[i].data.num.as_signed =
 +            (mp_intmax_t)va_arg(arglist, long);
 +        else if(vto[i].flags & FLAGS_UNSIGNED)
 +          vto[i].data.num.as_unsigned =
 +            (mp_uintmax_t)va_arg(arglist, unsigned int);
 +        else
 +          vto[i].data.num.as_signed =
 +            (mp_intmax_t)va_arg(arglist, int);
 +      }
 +      break;
 +
 +    case FORMAT_DOUBLE:
 +      vto[i].data.dnum = va_arg(arglist, double);
 +      break;
 +
 +    case FORMAT_WIDTH:
 +      /* Argument has been read. Silently convert it into an integer
 +       * for later use
 +       */
 +      vto[i].type = FORMAT_INT;
 +      break;
 +
 +    default:
 +      break;
 +    }
 +  }
 +
 +  return max_param;
 +
 +}
 +
 +static int dprintf_formatf(
 +  void *data, /* untouched by format(), just sent to the stream() function in
 +                 the second argument */
 +  /* function pointer called for each output character */
 +  int (*stream)(int, FILE *),
 +  const char *format,    /* %-formatted string */
 +  va_list ap_save) /* list of parameters */
 +{
 +  /* Base-36 digits for numbers.  */
 +  const char *digits = lower_digits;
 +
 +  /* Pointer into the format string.  */
 +  char *f;
 +
 +  /* Number of characters written.  */
 +  int done = 0;
 +
 +  long param; /* current parameter to read */
 +  long param_num=0; /* parameter counter */
 +
 +  va_stack_t vto[MAX_PARAMETERS];
 +  char *endpos[MAX_PARAMETERS];
 +  char **end;
 +
 +  char work[BUFFSIZE];
 +
 +  va_stack_t *p;
 +
++  /* 'workend' points to the final buffer byte position, but with an extra
++     byte as margin to avoid the (false?) warning Coverity gives us
++     otherwise */
++  char *workend = &work[sizeof(work) - 2];
++
 +  /* Do the actual %-code parsing */
 +  dprintf_Pass1(format, vto, endpos, ap_save);
 +
 +  end = &endpos[0]; /* the initial end-position from the list dprintf_Pass1()
 +                       created for us */
 +
 +  f = (char *)format;
 +  while(*f != '\0') {
 +    /* Format spec modifiers.  */
 +    int is_alt;
 +
 +    /* Width of a field.  */
 +    long width;
 +
 +    /* Precision of a field.  */
 +    long prec;
 +
 +    /* Decimal integer is negative.  */
 +    int is_neg;
 +
 +    /* Base of a number to be written.  */
 +    long base;
 +
 +    /* Integral values to be written.  */
 +    mp_uintmax_t num;
 +
 +    /* Used to convert negative in positive.  */
 +    mp_intmax_t signed_num;
 +
++    char *w;
++
 +    if(*f != '%') {
 +      /* This isn't a format spec, so write everything out until the next one
 +         OR end of string is reached.  */
 +      do {
 +        OUTCHAR(*f);
 +      } while(*++f && ('%' != *f));
 +      continue;
 +    }
 +
 +    ++f;
 +
 +    /* Check for "%%".  Note that although the ANSI standard lists
 +       '%' as a conversion specifier, it says "The complete format
 +       specification shall be `%%'," so we can avoid all the width
 +       and precision processing.  */
 +    if(*f == '%') {
 +      ++f;
 +      OUTCHAR('%');
 +      continue;
 +    }
 +
 +    /* If this is a positional parameter, the position must follow immediately
 +       after the %, thus create a %<num>$ sequence */
 +    param=dprintf_DollarString(f, &f);
 +
 +    if(!param)
 +      param = param_num;
 +    else
 +      --param;
 +
 +    param_num++; /* increase this always to allow "%2$s %1$s %s" and then the
 +                    third %s will pick the 3rd argument */
 +
 +    p = &vto[param];
 +
 +    /* pick up the specified width */
-     if(p->flags & FLAGS_WIDTHPARAM)
++    if(p->flags & FLAGS_WIDTHPARAM) {
 +      width = (long)vto[p->width].data.num.as_signed;
++      param_num++; /* since the width is extracted from a parameter, we
++                      must skip that to get to the next one properly */
++      if(width < 0) {
++        /* "A negative field width is taken as a '-' flag followed by a
++           positive field width." */
++        width = -width;
++        p->flags |= FLAGS_LEFT;
++        p->flags &= ~FLAGS_PAD_NIL;
++      }
++    }
 +    else
 +      width = p->width;
 +
 +    /* pick up the specified precision */
 +    if(p->flags & FLAGS_PRECPARAM) {
 +      prec = (long)vto[p->precision].data.num.as_signed;
-       param_num++; /* since the precision is extraced from a parameter, we
++      param_num++; /* since the precision is extracted from a parameter, we
 +                      must skip that to get to the next one properly */
++      if(prec < 0)
++        /* "A negative precision is taken as if the precision were
++           omitted." */
++        prec = -1;
 +    }
 +    else if(p->flags & FLAGS_PREC)
 +      prec = p->precision;
 +    else
 +      prec = -1;
 +
 +    is_alt = (p->flags & FLAGS_ALT) ? 1 : 0;
 +
 +    switch (p->type) {
 +    case FORMAT_INT:
 +      num = p->data.num.as_unsigned;
 +      if(p->flags & FLAGS_CHAR) {
 +        /* Character.  */
 +        if(!(p->flags & FLAGS_LEFT))
 +          while(--width > 0)
 +            OUTCHAR(' ');
 +        OUTCHAR((char) num);
 +        if(p->flags & FLAGS_LEFT)
 +          while(--width > 0)
 +            OUTCHAR(' ');
 +        break;
 +      }
 +      if(p->flags & FLAGS_OCTAL) {
 +        /* Octal unsigned integer.  */
 +        base = 8;
 +        goto unsigned_number;
 +      }
 +      else if(p->flags & FLAGS_HEX) {
 +        /* Hexadecimal unsigned integer.  */
 +
 +        digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits;
 +        base = 16;
 +        goto unsigned_number;
 +      }
 +      else if(p->flags & FLAGS_UNSIGNED) {
 +        /* Decimal unsigned integer.  */
 +        base = 10;
 +        goto unsigned_number;
 +      }
 +
 +      /* Decimal integer.  */
 +      base = 10;
 +
 +      is_neg = (p->data.num.as_signed < (mp_intmax_t)0) ? 1 : 0;
 +      if(is_neg) {
 +        /* signed_num might fail to hold absolute negative minimum by 1 */
 +        signed_num = p->data.num.as_signed + (mp_intmax_t)1;
 +        signed_num = -signed_num;
 +        num = (mp_uintmax_t)signed_num;
 +        num += (mp_uintmax_t)1;
 +      }
 +
 +      goto number;
 +
 +      unsigned_number:
 +      /* Unsigned number of base BASE.  */
 +      is_neg = 0;
 +
 +      number:
 +      /* Number of base BASE.  */
-       {
-         char *workend = &work[sizeof(work) - 1];
-         char *w;
- 
-         /* Supply a default precision if none was given.  */
-         if(prec == -1)
-           prec = 1;
- 
-         /* Put the number in WORK.  */
-         w = workend;
-         while(num > 0) {
-           *w-- = digits[num % base];
-           num /= base;
-         }
-         width -= (long)(workend - w);
-         prec -= (long)(workend - w);
 +
-         if(is_alt && base == 8 && prec <= 0) {
-           *w-- = '0';
-           --width;
-         }
++      /* Supply a default precision if none was given.  */
++      if(prec == -1)
++        prec = 1;
 +
-         if(prec > 0) {
-           width -= prec;
-           while(prec-- > 0)
-             *w-- = '0';
-         }
++      /* Put the number in WORK.  */
++      w = workend;
++      while(num > 0) {
++        *w-- = digits[num % base];
++        num /= base;
++      }
++      width -= (long)(workend - w);
++      prec -= (long)(workend - w);
++
++      if(is_alt && base == 8 && prec <= 0) {
++        *w-- = '0';
++        --width;
++      }
 +
-         if(is_alt && base == 16)
-           width -= 2;
++      if(prec > 0) {
++        width -= prec;
++        while(prec-- > 0)
++          *w-- = '0';
++      }
 +
-         if(is_neg || (p->flags & FLAGS_SHOWSIGN) || (p->flags & FLAGS_SPACE))
-           --width;
++      if(is_alt && base == 16)
++        width -= 2;
 +
-         if(!(p->flags & FLAGS_LEFT) && !(p->flags & FLAGS_PAD_NIL))
-           while(width-- > 0)
-             OUTCHAR(' ');
++      if(is_neg || (p->flags & FLAGS_SHOWSIGN) || (p->flags & FLAGS_SPACE))
++        --width;
 +
-         if(is_neg)
-           OUTCHAR('-');
-         else if(p->flags & FLAGS_SHOWSIGN)
-           OUTCHAR('+');
-         else if(p->flags & FLAGS_SPACE)
++      if(!(p->flags & FLAGS_LEFT) && !(p->flags & FLAGS_PAD_NIL))
++        while(width-- > 0)
 +          OUTCHAR(' ');
 +
-         if(is_alt && base == 16) {
-           OUTCHAR('0');
-           if(p->flags & FLAGS_UPPER)
-             OUTCHAR('X');
-           else
-             OUTCHAR('x');
-         }
- 
-         if(!(p->flags & FLAGS_LEFT) && (p->flags & FLAGS_PAD_NIL))
-           while(width-- > 0)
-             OUTCHAR('0');
++      if(is_neg)
++        OUTCHAR('-');
++      else if(p->flags & FLAGS_SHOWSIGN)
++        OUTCHAR('+');
++      else if(p->flags & FLAGS_SPACE)
++        OUTCHAR(' ');
++
++      if(is_alt && base == 16) {
++        OUTCHAR('0');
++        if(p->flags & FLAGS_UPPER)
++          OUTCHAR('X');
++        else
++          OUTCHAR('x');
++      }
 +
-         /* Write the number.  */
-         while(++w <= workend) {
-           OUTCHAR(*w);
-         }
++      if(!(p->flags & FLAGS_LEFT) && (p->flags & FLAGS_PAD_NIL))
++        while(width-- > 0)
++          OUTCHAR('0');
 +
-         if(p->flags & FLAGS_LEFT)
-           while(width-- > 0)
-             OUTCHAR(' ');
++      /* Write the number.  */
++      while(++w <= workend) {
++        OUTCHAR(*w);
 +      }
++
++      if(p->flags & FLAGS_LEFT)
++        while(width-- > 0)
++          OUTCHAR(' ');
 +      break;
 +
 +    case FORMAT_STRING:
 +            /* String.  */
 +      {
 +        static const char null[] = "(nil)";
 +        const char *str;
 +        size_t len;
 +
 +        str = (char *) p->data.str;
 +        if(str == NULL) {
 +          /* Write null[] if there's space.  */
 +          if(prec == -1 || prec >= (long) sizeof(null) - 1) {
 +            str = null;
 +            len = sizeof(null) - 1;
 +            /* Disable quotes around (nil) */
 +            p->flags &= (~FLAGS_ALT);
 +          }
 +          else {
 +            str = "";
 +            len = 0;
 +          }
 +        }
 +        else if(prec != -1)
 +          len = (size_t)prec;
 +        else
 +          len = strlen(str);
 +
-         width -= (long)len;
++        width -= (len > LONG_MAX) ? LONG_MAX : (long)len;
 +
 +        if(p->flags & FLAGS_ALT)
 +          OUTCHAR('"');
 +
 +        if(!(p->flags&FLAGS_LEFT))
 +          while(width-- > 0)
 +            OUTCHAR(' ');
 +
 +        while((len-- > 0) && *str)
 +          OUTCHAR(*str++);
 +        if(p->flags&FLAGS_LEFT)
 +          while(width-- > 0)
 +            OUTCHAR(' ');
 +
 +        if(p->flags & FLAGS_ALT)
 +          OUTCHAR('"');
 +      }
 +      break;
 +
 +    case FORMAT_PTR:
 +      /* Generic pointer.  */
 +      {
 +        void *ptr;
 +        ptr = (void *) p->data.ptr;
 +        if(ptr != NULL) {
 +          /* If the pointer is not NULL, write it as a %#x spec.  */
 +          base = 16;
 +          digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits;
 +          is_alt = 1;
 +          num = (size_t) ptr;
 +          is_neg = 0;
 +          goto number;
 +        }
 +        else {
 +          /* Write "(nil)" for a nil pointer.  */
 +          static const char strnil[] = "(nil)";
 +          const char *point;
 +
 +          width -= (long)(sizeof(strnil) - 1);
 +          if(p->flags & FLAGS_LEFT)
 +            while(width-- > 0)
 +              OUTCHAR(' ');
 +          for(point = strnil; *point != '\0'; ++point)
 +            OUTCHAR(*point);
 +          if(! (p->flags & FLAGS_LEFT))
 +            while(width-- > 0)
 +              OUTCHAR(' ');
 +        }
 +      }
 +      break;
 +
 +    case FORMAT_DOUBLE:
 +      {
 +        char formatbuf[32]="%";
 +        char *fptr = &formatbuf[1];
 +        size_t left = sizeof(formatbuf)-strlen(formatbuf);
 +        int len;
 +
 +        width = -1;
 +        if(p->flags & FLAGS_WIDTH)
 +          width = p->width;
 +        else if(p->flags & FLAGS_WIDTHPARAM)
 +          width = (long)vto[p->width].data.num.as_signed;
 +
 +        prec = -1;
 +        if(p->flags & FLAGS_PREC)
 +          prec = p->precision;
 +        else if(p->flags & FLAGS_PRECPARAM)
 +          prec = (long)vto[p->precision].data.num.as_signed;
 +
 +        if(p->flags & FLAGS_LEFT)
 +          *fptr++ = '-';
 +        if(p->flags & FLAGS_SHOWSIGN)
 +          *fptr++ = '+';
 +        if(p->flags & FLAGS_SPACE)
 +          *fptr++ = ' ';
 +        if(p->flags & FLAGS_ALT)
 +          *fptr++ = '#';
 +
 +        *fptr = 0;
 +
 +        if(width >= 0) {
 +          /* RECURSIVE USAGE */
 +          len = curl_msnprintf(fptr, left, "%ld", width);
 +          fptr += len;
 +          left -= len;
 +        }
 +        if(prec >= 0) {
 +          /* RECURSIVE USAGE */
 +          len = curl_msnprintf(fptr, left, ".%ld", prec);
 +          fptr += len;
 +        }
 +        if(p->flags & FLAGS_LONG)
 +          *fptr++ = 'l';
 +
 +        if(p->flags & FLAGS_FLOATE)
 +          *fptr++ = (char)((p->flags & FLAGS_UPPER) ? 'E':'e');
 +        else if(p->flags & FLAGS_FLOATG)
 +          *fptr++ = (char)((p->flags & FLAGS_UPPER) ? 'G' : 'g');
 +        else
 +          *fptr++ = 'f';
 +
 +        *fptr = 0; /* and a final zero termination */
 +
 +        /* NOTE NOTE NOTE!! Not all sprintf implementations return number of
 +           output characters */
 +        (sprintf)(work, formatbuf, p->data.dnum);
 +
 +        for(fptr=work; *fptr; fptr++)
 +          OUTCHAR(*fptr);
 +      }
 +      break;
 +
 +    case FORMAT_INTPTR:
 +      /* Answer the count of characters written.  */
 +#ifdef HAVE_LONG_LONG_TYPE
 +      if(p->flags & FLAGS_LONGLONG)
 +        *(LONG_LONG_TYPE *) p->data.ptr = (LONG_LONG_TYPE)done;
 +      else
 +#endif
 +        if(p->flags & FLAGS_LONG)
 +          *(long *) p->data.ptr = (long)done;
 +      else if(!(p->flags & FLAGS_SHORT))
 +        *(int *) p->data.ptr = (int)done;
 +      else
 +        *(short *) p->data.ptr = (short)done;
 +      break;
 +
 +    default:
 +      break;
 +    }
 +    f = *end++; /* goto end of %-code */
 +
 +  }
 +  return done;
 +}
 +
 +/* fputc() look-alike */
 +static int addbyter(int output, FILE *data)
 +{
 +  struct nsprintf *infop=(struct nsprintf *)data;
 +  unsigned char outc = (unsigned char)output;
 +
 +  if(infop->length < infop->max) {
 +    /* only do this if we haven't reached max length yet */
 +    infop->buffer[0] = outc; /* store */
 +    infop->buffer++; /* increase pointer */
 +    infop->length++; /* we are now one byte larger */
 +    return outc;     /* fputc() returns like this on success */
 +  }
 +  return -1;
 +}
 +
 +int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format,
 +                    va_list ap_save)
 +{
 +  int retcode;
 +  struct nsprintf info;
 +
 +  info.buffer = buffer;
 +  info.length = 0;
 +  info.max = maxlength;
 +
 +  retcode = dprintf_formatf(&info, addbyter, format, ap_save);
 +  if(info.max) {
 +    /* we terminate this with a zero byte */
 +    if(info.max == info.length)
 +      /* we're at maximum, scrap the last letter */
 +      info.buffer[-1] = 0;
 +    else
 +      info.buffer[0] = 0;
 +  }
 +  return retcode;
 +}
 +
 +int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...)
 +{
 +  int retcode;
 +  va_list ap_save; /* argument pointer */
 +  va_start(ap_save, format);
 +  retcode = curl_mvsnprintf(buffer, maxlength, format, ap_save);
 +  va_end(ap_save);
 +  return retcode;
 +}
 +
 +/* fputc() look-alike */
 +static int alloc_addbyter(int output, FILE *data)
 +{
 +  struct asprintf *infop=(struct asprintf *)data;
 +  unsigned char outc = (unsigned char)output;
 +
 +  if(!infop->buffer) {
 +    infop->buffer = malloc(32);
 +    if(!infop->buffer) {
 +      infop->fail = 1;
 +      return -1; /* fail */
 +    }
 +    infop->alloc = 32;
 +    infop->len =0;
 +  }
 +  else if(infop->len+1 >= infop->alloc) {
 +    char *newptr;
 +
 +    newptr = realloc(infop->buffer, infop->alloc*2);
 +
 +    if(!newptr) {
 +      infop->fail = 1;
 +      return -1; /* fail */
 +    }
 +    infop->buffer = newptr;
 +    infop->alloc *= 2;
 +  }
 +
 +  infop->buffer[ infop->len ] = outc;
 +
 +  infop->len++;
 +
 +  return outc; /* fputc() returns like this on success */
 +}
 +
 +char *curl_maprintf(const char *format, ...)
 +{
 +  va_list ap_save; /* argument pointer */
 +  int retcode;
 +  struct asprintf info;
 +
 +  info.buffer = NULL;
 +  info.len = 0;
 +  info.alloc = 0;
 +  info.fail = 0;
 +
 +  va_start(ap_save, format);
 +  retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save);
 +  va_end(ap_save);
 +  if((-1 == retcode) || info.fail) {
 +    if(info.alloc)
 +      free(info.buffer);
 +    return NULL;
 +  }
 +  if(info.alloc) {
 +    info.buffer[info.len] = 0; /* we terminate this with a zero byte */
 +    return info.buffer;
 +  }
 +  else
 +    return strdup("");
 +}
 +
 +char *curl_mvaprintf(const char *format, va_list ap_save)
 +{
 +  int retcode;
 +  struct asprintf info;
 +
 +  info.buffer = NULL;
 +  info.len = 0;
 +  info.alloc = 0;
 +  info.fail = 0;
 +
 +  retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save);
 +  if((-1 == retcode) || info.fail) {
 +    if(info.alloc)
 +      free(info.buffer);
 +    return NULL;
 +  }
 +
 +  if(info.alloc) {
 +    info.buffer[info.len] = 0; /* we terminate this with a zero byte */
 +    return info.buffer;
 +  }
 +  else
 +    return strdup("");
 +}
 +
 +static int storebuffer(int output, FILE *data)
 +{
 +  char **buffer = (char **)data;
 +  unsigned char outc = (unsigned char)output;
 +  **buffer = outc;
 +  (*buffer)++;
 +  return outc; /* act like fputc() ! */
 +}
 +
 +int curl_msprintf(char *buffer, const char *format, ...)
 +{
 +  va_list ap_save; /* argument pointer */
 +  int retcode;
 +  va_start(ap_save, format);
 +  retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save);
 +  va_end(ap_save);
 +  *buffer=0; /* we terminate this with a zero byte */
 +  return retcode;
 +}
 +
 +int curl_mprintf(const char *format, ...)
 +{
 +  int retcode;
 +  va_list ap_save; /* argument pointer */
 +  va_start(ap_save, format);
 +
 +  retcode = dprintf_formatf(stdout, fputc, format, ap_save);
 +  va_end(ap_save);
 +  return retcode;
 +}
 +
 +int curl_mfprintf(FILE *whereto, const char *format, ...)
 +{
 +  int retcode;
 +  va_list ap_save; /* argument pointer */
 +  va_start(ap_save, format);
 +  retcode = dprintf_formatf(whereto, fputc, format, ap_save);
 +  va_end(ap_save);
 +  return retcode;
 +}
 +
 +int curl_mvsprintf(char *buffer, const char *format, va_list ap_save)
 +{
 +  int retcode;
 +  retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save);
 +  *buffer=0; /* we terminate this with a zero byte */
 +  return retcode;
 +}
 +
 +int curl_mvprintf(const char *format, va_list ap_save)
 +{
 +  return dprintf_formatf(stdout, fputc, format, ap_save);
 +}
 +
 +int curl_mvfprintf(FILE *whereto, const char *format, va_list ap_save)
 +{
 +  return dprintf_formatf(whereto, fputc, format, ap_save);
 +}
diff --cc Utilities/cmcurl/lib/select.c
index 6eff070,0000000..2002349
mode 100644,000000..100644
--- a/Utilities/cmcurl/lib/select.c
+++ b/Utilities/cmcurl/lib/select.c
@@@ -1,578 -1,0 +1,578 @@@
 +/***************************************************************************
 + *                                  _   _ ____  _
 + *  Project                     ___| | | |  _ \| |
 + *                             / __| | | | |_) | |
 + *                            | (__| |_| |  _ <| |___
 + *                             \___|\___/|_| \_\_____|
 + *
 + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
 + *
 + * This software is licensed as described in the file COPYING, which
 + * you should have received as part of this distribution. The terms
-  * are also available at http://curl.haxx.se/docs/copyright.html.
++ * 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_SYS_SELECT_H
 +#include <sys/select.h>
 +#endif
 +
 +#if !defined(HAVE_SELECT) && !defined(HAVE_POLL_FINE)
 +#error "We can't compile without select() or poll() support."
 +#endif
 +
 +#if defined(__BEOS__)
 +/* BeOS has FD_SET defined in socket.h */
 +#include <socket.h>
 +#endif
 +
 +#ifdef MSDOS
 +#include <dos.h>  /* delay() */
 +#endif
 +
 +#ifdef __VXWORKS__
 +#include <strings.h>  /* bzero() in FD_SET */
 +#endif
 +
 +#include <curl/curl.h>
 +
 +#include "urldata.h"
 +#include "connect.h"
 +#include "select.h"
 +#include "warnless.h"
 +
 +/* Convenience local macros */
 +
 +#define elapsed_ms  (int)curlx_tvdiff(curlx_tvnow(), initial_tv)
 +
 +int Curl_ack_eintr = 0;
 +#define error_not_EINTR (Curl_ack_eintr || error != EINTR)
 +
 +/*
 + * Internal function used for waiting a specific amount of ms
 + * in Curl_socket_ready() and Curl_poll() when no file descriptor
 + * is provided to wait on, just being used to delay execution.
 + * WinSock select() and poll() timeout mechanisms need a valid
 + * socket descriptor in a not null file descriptor set to work.
 + * Waiting indefinitely with this function is not allowed, a
 + * zero or negative timeout value will return immediately.
 + * Timeout resolution, accuracy, as well as maximum supported
 + * value is system dependent, neither factor is a citical issue
 + * for the intended use of this function in the library.
 + *
 + * Return values:
 + *   -1 = system call error, invalid timeout value, or interrupted
 + *    0 = specified timeout has elapsed
 + */
 +int Curl_wait_ms(int timeout_ms)
 +{
 +#if !defined(MSDOS) && !defined(USE_WINSOCK)
 +#ifndef HAVE_POLL_FINE
 +  struct timeval pending_tv;
 +#endif
 +  struct timeval initial_tv;
 +  int pending_ms;
 +  int error;
 +#endif
 +  int r = 0;
 +
 +  if(!timeout_ms)
 +    return 0;
 +  if(timeout_ms < 0) {
 +    SET_SOCKERRNO(EINVAL);
 +    return -1;
 +  }
 +#if defined(MSDOS)
 +  delay(timeout_ms);
 +#elif defined(USE_WINSOCK)
 +  Sleep(timeout_ms);
 +#else
 +  pending_ms = timeout_ms;
 +  initial_tv = curlx_tvnow();
 +  do {
 +#if defined(HAVE_POLL_FINE)
 +    r = poll(NULL, 0, pending_ms);
 +#else
 +    pending_tv.tv_sec = pending_ms / 1000;
 +    pending_tv.tv_usec = (pending_ms % 1000) * 1000;
 +    r = select(0, NULL, NULL, NULL, &pending_tv);
 +#endif /* HAVE_POLL_FINE */
 +    if(r != -1)
 +      break;
 +    error = SOCKERRNO;
 +    if(error && error_not_EINTR)
 +      break;
 +    pending_ms = timeout_ms - elapsed_ms;
 +    if(pending_ms <= 0) {
 +      r = 0;  /* Simulate a "call timed out" case */
 +      break;
 +    }
 +  } while(r == -1);
 +#endif /* USE_WINSOCK */
 +  if(r)
 +    r = -1;
 +  return r;
 +}
 +
 +/*
 + * Wait for read or write events on a set of file descriptors. It uses poll()
 + * when a fine poll() is available, in order to avoid limits with FD_SETSIZE,
 + * otherwise select() is used.  An error is returned if select() is being used
 + * and a file descriptor is too large for FD_SETSIZE.
 + *
 + * A negative timeout value makes this function wait indefinitely,
 + * unles no valid file descriptor is given, when this happens the
 + * negative timeout is ignored and the function times out immediately.
 + *
 + * Return values:
 + *   -1 = system call error or fd >= FD_SETSIZE
 + *    0 = timeout
 + *    [bitmask] = action as described below
 + *
 + * CURL_CSELECT_IN - first socket is readable
 + * CURL_CSELECT_IN2 - second socket is readable
 + * CURL_CSELECT_OUT - write socket is writable
 + * CURL_CSELECT_ERR - an error condition occurred
 + */
 +int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */
 +                      curl_socket_t readfd1,
 +                      curl_socket_t writefd, /* socket to write to */
 +                      long timeout_ms)       /* milliseconds to wait */
 +{
 +#ifdef HAVE_POLL_FINE
 +  struct pollfd pfd[3];
 +  int num;
 +#else
 +  struct timeval pending_tv;
 +  struct timeval *ptimeout;
 +  fd_set fds_read;
 +  fd_set fds_write;
 +  fd_set fds_err;
 +  curl_socket_t maxfd;
 +#endif
 +  struct timeval initial_tv = {0, 0};
 +  int pending_ms = 0;
 +  int error;
 +  int r;
 +  int ret;
 +
 +  if((readfd0 == CURL_SOCKET_BAD) && (readfd1 == CURL_SOCKET_BAD) &&
 +     (writefd == CURL_SOCKET_BAD)) {
 +    /* no sockets, just wait */
 +    r = Curl_wait_ms((int)timeout_ms);
 +    return r;
 +  }
 +
 +  /* Avoid initial timestamp, avoid curlx_tvnow() 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();
 +  }
 +
 +#ifdef HAVE_POLL_FINE
 +
 +  num = 0;
 +  if(readfd0 != CURL_SOCKET_BAD) {
 +    pfd[num].fd = readfd0;
 +    pfd[num].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI;
 +    pfd[num].revents = 0;
 +    num++;
 +  }
 +  if(readfd1 != CURL_SOCKET_BAD) {
 +    pfd[num].fd = readfd1;
 +    pfd[num].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI;
 +    pfd[num].revents = 0;
 +    num++;
 +  }
 +  if(writefd != CURL_SOCKET_BAD) {
 +    pfd[num].fd = writefd;
 +    pfd[num].events = POLLWRNORM|POLLOUT;
 +    pfd[num].revents = 0;
 +    num++;
 +  }
 +
 +  do {
 +    if(timeout_ms < 0)
 +      pending_ms = -1;
 +    else if(!timeout_ms)
 +      pending_ms = 0;
 +    r = poll(pfd, num, pending_ms);
 +    if(r != -1)
 +      break;
 +    error = SOCKERRNO;
 +    if(error && error_not_EINTR)
 +      break;
 +    if(timeout_ms > 0) {
 +      pending_ms = (int)(timeout_ms - elapsed_ms);
 +      if(pending_ms <= 0) {
 +        r = 0;  /* Simulate a "call timed out" case */
 +        break;
 +      }
 +    }
 +  } while(r == -1);
 +
 +  if(r < 0)
 +    return -1;
 +  if(r == 0)
 +    return 0;
 +
 +  ret = 0;
 +  num = 0;
 +  if(readfd0 != CURL_SOCKET_BAD) {
 +    if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP))
 +      ret |= CURL_CSELECT_IN;
 +    if(pfd[num].revents & (POLLRDBAND|POLLPRI|POLLNVAL))
 +      ret |= CURL_CSELECT_ERR;
 +    num++;
 +  }
 +  if(readfd1 != CURL_SOCKET_BAD) {
 +    if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP))
 +      ret |= CURL_CSELECT_IN2;
 +    if(pfd[num].revents & (POLLRDBAND|POLLPRI|POLLNVAL))
 +      ret |= CURL_CSELECT_ERR;
 +    num++;
 +  }
 +  if(writefd != CURL_SOCKET_BAD) {
 +    if(pfd[num].revents & (POLLWRNORM|POLLOUT))
 +      ret |= CURL_CSELECT_OUT;
 +    if(pfd[num].revents & (POLLERR|POLLHUP|POLLNVAL))
 +      ret |= CURL_CSELECT_ERR;
 +  }
 +
 +  return ret;
 +
 +#else  /* HAVE_POLL_FINE */
 +
 +  FD_ZERO(&fds_err);
 +  maxfd = (curl_socket_t)-1;
 +
 +  FD_ZERO(&fds_read);
 +  if(readfd0 != CURL_SOCKET_BAD) {
 +    VERIFY_SOCK(readfd0);
 +    FD_SET(readfd0, &fds_read);
 +    FD_SET(readfd0, &fds_err);
 +    maxfd = readfd0;
 +  }
 +  if(readfd1 != CURL_SOCKET_BAD) {
 +    VERIFY_SOCK(readfd1);
 +    FD_SET(readfd1, &fds_read);
 +    FD_SET(readfd1, &fds_err);
 +    if(readfd1 > maxfd)
 +      maxfd = readfd1;
 +  }
 +
 +  FD_ZERO(&fds_write);
 +  if(writefd != CURL_SOCKET_BAD) {
 +    VERIFY_SOCK(writefd);
 +    FD_SET(writefd, &fds_write);
 +    FD_SET(writefd, &fds_err);
 +    if(writefd > maxfd)
 +      maxfd = writefd;
 +  }
 +
 +  ptimeout = (timeout_ms < 0) ? NULL : &pending_tv;
 +
 +  do {
 +    if(timeout_ms > 0) {
 +      pending_tv.tv_sec = pending_ms / 1000;
 +      pending_tv.tv_usec = (pending_ms % 1000) * 1000;
 +    }
 +    else if(!timeout_ms) {
 +      pending_tv.tv_sec = 0;
 +      pending_tv.tv_usec = 0;
 +    }
 +
 +    /* WinSock select() must not be called with an fd_set that contains zero
 +       fd flags, or it will return WSAEINVAL.  But, it also can't be called
 +       with no fd_sets at all!  From the documentation:
 +
 +         Any two of the parameters, readfds, writefds, or exceptfds, can be
 +         given as null. At least one must be non-null, and any non-null
 +         descriptor set must contain at least one handle to a socket.
 +
 +       We know that we have at least one bit set in at least two fd_sets in
 +       this case, but we may have no bits set in either fds_read or fd_write,
 +       so check for that and handle it.  Luckily, with WinSock, we can _also_
 +       ask how many bits are set on an fd_set.
 +
 +       It is unclear why WinSock doesn't just handle this for us instead of
 +       calling this an error.
 +
 +       Note also that WinSock ignores the first argument, so we don't worry
 +       about the fact that maxfd is computed incorrectly with WinSock (since
 +       curl_socket_t is unsigned in such cases and thus -1 is the largest
 +       value).
 +    */
++#ifdef USE_WINSOCK
 +    r = select((int)maxfd + 1,
- #ifndef USE_WINSOCK
-                &fds_read,
-                &fds_write,
- #else
 +               fds_read.fd_count ? &fds_read : NULL,
 +               fds_write.fd_count ? &fds_write : NULL,
- #endif
 +               &fds_err, ptimeout);
++#else
++    r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout);
++#endif
++
 +    if(r != -1)
 +      break;
 +    error = SOCKERRNO;
 +    if(error && error_not_EINTR)
 +      break;
 +    if(timeout_ms > 0) {
 +      pending_ms = timeout_ms - elapsed_ms;
 +      if(pending_ms <= 0) {
 +        r = 0;  /* Simulate a "call timed out" case */
 +        break;
 +      }
 +    }
 +  } while(r == -1);
 +
 +  if(r < 0)
 +    return -1;
 +  if(r == 0)
 +    return 0;
 +
 +  ret = 0;
 +  if(readfd0 != CURL_SOCKET_BAD) {
 +    if(FD_ISSET(readfd0, &fds_read))
 +      ret |= CURL_CSELECT_IN;
 +    if(FD_ISSET(readfd0, &fds_err))
 +      ret |= CURL_CSELECT_ERR;
 +  }
 +  if(readfd1 != CURL_SOCKET_BAD) {
 +    if(FD_ISSET(readfd1, &fds_read))
 +      ret |= CURL_CSELECT_IN2;
 +    if(FD_ISSET(readfd1, &fds_err))
 +      ret |= CURL_CSELECT_ERR;
 +  }
 +  if(writefd != CURL_SOCKET_BAD) {
 +    if(FD_ISSET(writefd, &fds_write))
 +      ret |= CURL_CSELECT_OUT;
 +    if(FD_ISSET(writefd, &fds_err))
 +      ret |= CURL_CSELECT_ERR;
 +  }
 +
 +  return ret;
 +
 +#endif  /* HAVE_POLL_FINE */
 +
 +}
 +
 +/*
 + * This is a wrapper around poll().  If poll() does not exist, then
 + * select() is used instead.  An error is returned if select() is
 + * being used and a file descriptor is too large for FD_SETSIZE.
 + * A negative timeout value makes this function wait indefinitely,
 + * unles no valid file descriptor is given, when this happens the
 + * negative timeout is ignored and the function times out immediately.
 + *
 + * Return values:
 + *   -1 = system call error or fd >= FD_SETSIZE
 + *    0 = timeout
 + *    N = number of structures with non zero revent fields
 + */
 +int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms)
 +{
 +#ifndef HAVE_POLL_FINE
 +  struct timeval pending_tv;
 +  struct timeval *ptimeout;
 +  fd_set fds_read;
 +  fd_set fds_write;
 +  fd_set fds_err;
 +  curl_socket_t maxfd;
 +#endif
 +  struct timeval initial_tv = {0, 0};
 +  bool fds_none = TRUE;
 +  unsigned int i;
 +  int pending_ms = 0;
 +  int error;
 +  int r;
 +
 +  if(ufds) {
 +    for(i = 0; i < nfds; i++) {
 +      if(ufds[i].fd != CURL_SOCKET_BAD) {
 +        fds_none = FALSE;
 +        break;
 +      }
 +    }
 +  }
 +  if(fds_none) {
 +    r = Curl_wait_ms(timeout_ms);
 +    return r;
 +  }
 +
 +  /* Avoid initial timestamp, avoid curlx_tvnow() 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();
 +  }
 +
 +#ifdef HAVE_POLL_FINE
 +
 +  do {
 +    if(timeout_ms < 0)
 +      pending_ms = -1;
 +    else if(!timeout_ms)
 +      pending_ms = 0;
 +    r = poll(ufds, nfds, pending_ms);
 +    if(r != -1)
 +      break;
 +    error = SOCKERRNO;
 +    if(error && error_not_EINTR)
 +      break;
 +    if(timeout_ms > 0) {
 +      pending_ms = timeout_ms - elapsed_ms;
 +      if(pending_ms <= 0) {
 +        r = 0;  /* Simulate a "call timed out" case */
 +        break;
 +      }
 +    }
 +  } while(r == -1);
 +
 +  if(r < 0)
 +    return -1;
 +  if(r == 0)
 +    return 0;
 +
 +  for(i = 0; i < nfds; i++) {
 +    if(ufds[i].fd == CURL_SOCKET_BAD)
 +      continue;
 +    if(ufds[i].revents & POLLHUP)
 +      ufds[i].revents |= POLLIN;
 +    if(ufds[i].revents & POLLERR)
 +      ufds[i].revents |= (POLLIN|POLLOUT);
 +  }
 +
 +#else  /* HAVE_POLL_FINE */
 +
 +  FD_ZERO(&fds_read);
 +  FD_ZERO(&fds_write);
 +  FD_ZERO(&fds_err);
 +  maxfd = (curl_socket_t)-1;
 +
 +  for(i = 0; i < nfds; i++) {
 +    ufds[i].revents = 0;
 +    if(ufds[i].fd == CURL_SOCKET_BAD)
 +      continue;
 +    VERIFY_SOCK(ufds[i].fd);
 +    if(ufds[i].events & (POLLIN|POLLOUT|POLLPRI|
 +                          POLLRDNORM|POLLWRNORM|POLLRDBAND)) {
 +      if(ufds[i].fd > maxfd)
 +        maxfd = ufds[i].fd;
 +      if(ufds[i].events & (POLLRDNORM|POLLIN))
 +        FD_SET(ufds[i].fd, &fds_read);
 +      if(ufds[i].events & (POLLWRNORM|POLLOUT))
 +        FD_SET(ufds[i].fd, &fds_write);
 +      if(ufds[i].events & (POLLRDBAND|POLLPRI))
 +        FD_SET(ufds[i].fd, &fds_err);
 +    }
 +  }
 +
 +#ifdef USE_WINSOCK
 +  /* WinSock select() can't handle zero events.  See the comment about this in
 +     Curl_check_socket(). */
 +  if(fds_read.fd_count == 0 && fds_write.fd_count == 0
 +     && fds_err.fd_count == 0) {
 +    r = Curl_wait_ms(timeout_ms);
 +    return r;
 +  }
 +#endif
 +
 +  ptimeout = (timeout_ms < 0) ? NULL : &pending_tv;
 +
 +  do {
 +    if(timeout_ms > 0) {
 +      pending_tv.tv_sec = pending_ms / 1000;
 +      pending_tv.tv_usec = (pending_ms % 1000) * 1000;
 +    }
 +    else if(!timeout_ms) {
 +      pending_tv.tv_sec = 0;
 +      pending_tv.tv_usec = 0;
 +    }
++
++#ifdef USE_WINSOCK
 +    r = select((int)maxfd + 1,
- #ifndef USE_WINSOCK
-                &fds_read, &fds_write, &fds_err,
- #else
 +               /* WinSock select() can't handle fd_sets with zero bits set, so
 +                  don't give it such arguments.  See the comment about this in
 +                  Curl_check_socket().
 +               */
 +               fds_read.fd_count ? &fds_read : NULL,
 +               fds_write.fd_count ? &fds_write : NULL,
-                fds_err.fd_count ? &fds_err : NULL,
++               fds_err.fd_count ? &fds_err : NULL, ptimeout);
++#else
++    r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout);
 +#endif
-                ptimeout);
 +    if(r != -1)
 +      break;
 +    error = SOCKERRNO;
 +    if(error && error_not_EINTR)
 +      break;
 +    if(timeout_ms > 0) {
 +      pending_ms = timeout_ms - elapsed_ms;
 +      if(pending_ms <= 0) {
 +        r = 0;  /* Simulate a "call timed out" case */
 +        break;
 +      }
 +    }
 +  } while(r == -1);
 +
 +  if(r < 0)
 +    return -1;
 +  if(r == 0)
 +    return 0;
 +
 +  r = 0;
 +  for(i = 0; i < nfds; i++) {
 +    ufds[i].revents = 0;
 +    if(ufds[i].fd == CURL_SOCKET_BAD)
 +      continue;
 +    if(FD_ISSET(ufds[i].fd, &fds_read))
 +      ufds[i].revents |= POLLIN;
 +    if(FD_ISSET(ufds[i].fd, &fds_write))
 +      ufds[i].revents |= POLLOUT;
 +    if(FD_ISSET(ufds[i].fd, &fds_err))
 +      ufds[i].revents |= POLLPRI;
 +    if(ufds[i].revents != 0)
 +      r++;
 +  }
 +
 +#endif  /* HAVE_POLL_FINE */
 +
 +  return r;
 +}
 +
 +#ifdef TPF
 +/*
 + * This is a replacement for select() on the TPF platform.
 + * It is used whenever libcurl calls select().
 + * The call below to tpf_process_signals() is required because
 + * TPF's select calls are not signal interruptible.
 + *
 + * Return values are the same as select's.
 + */
 +int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes,
 +                       fd_set* excepts, struct timeval* tv)
 +{
 +   int rc;
 +
 +   rc = tpf_select_bsd(maxfds, reads, writes, excepts, tv);
 +   tpf_process_signals();
 +   return rc;
 +}
 +#endif /* TPF */
diff --cc Utilities/cmcurl/lib/system_win32.c
index 0000000,d6a998b..d6a998b
mode 000000,100644..100644
--- a/Utilities/cmcurl/lib/system_win32.c
+++ b/Utilities/cmcurl/lib/system_win32.c
diff --cc Utilities/cmcurl/lib/system_win32.h
index 0000000,1e77285..1e77285
mode 000000,100644..100644
--- a/Utilities/cmcurl/lib/system_win32.h
+++ b/Utilities/cmcurl/lib/system_win32.h
diff --cc Utilities/cmcurl/lib/vauth/cleartext.c
index 0000000,4e906bc..4e906bc
mode 000000,100644..100644
--- a/Utilities/cmcurl/lib/vauth/cleartext.c
+++ b/Utilities/cmcurl/lib/vauth/cleartext.c
diff --cc Utilities/cmcurl/lib/vauth/cram.c
index 0000000,3074a16..3074a16
mode 000000,100644..100644
--- a/Utilities/cmcurl/lib/vauth/cram.c
+++ b/Utilities/cmcurl/lib/vauth/cram.c
diff --cc Utilities/cmcurl/lib/vauth/digest.c
index 0000000,26ea7b5..26ea7b5
mode 000000,100644..100644
--- a/Utilities/cmcurl/lib/vauth/digest.c
+++ b/Utilities/cmcurl/lib/vauth/digest.c
diff --cc Utilities/cmcurl/lib/vauth/digest_sspi.c
index 0000000,6a7315e..6a7315e
mode 000000,100644..100644
--- a/Utilities/cmcurl/lib/vauth/digest_sspi.c
+++ b/Utilities/cmcurl/lib/vauth/digest_sspi.c
diff --cc Utilities/cmcurl/lib/vauth/krb5_sspi.c
index 0000000,08774f6..08774f6
mode 000000,100644..100644
--- a/Utilities/cmcurl/lib/vauth/krb5_sspi.c
+++ b/Utilities/cmcurl/lib/vauth/krb5_sspi.c
diff --cc Utilities/cmcurl/lib/vauth/ntlm_sspi.c
index 0000000,982a9d3..982a9d3
mode 000000,100644..100644
--- a/Utilities/cmcurl/lib/vauth/ntlm_sspi.c
+++ b/Utilities/cmcurl/lib/vauth/ntlm_sspi.c
diff --cc Utilities/cmcurl/lib/vauth/oauth2.c
index 0000000,6288f89..6288f89
mode 000000,100644..100644
--- a/Utilities/cmcurl/lib/vauth/oauth2.c
+++ b/Utilities/cmcurl/lib/vauth/oauth2.c
diff --cc Utilities/cmcurl/lib/vauth/spnego_gssapi.c
index 0000000,b256ee6..b256ee6
mode 000000,100644..100644
--- a/Utilities/cmcurl/lib/vauth/spnego_gssapi.c
+++ b/Utilities/cmcurl/lib/vauth/spnego_gssapi.c
diff --cc Utilities/cmcurl/lib/vauth/spnego_sspi.c
index 0000000,b6176ec..b6176ec
mode 000000,100644..100644
--- a/Utilities/cmcurl/lib/vauth/spnego_sspi.c
+++ b/Utilities/cmcurl/lib/vauth/spnego_sspi.c
diff --cc Utilities/cmcurl/lib/vauth/vauth.c
index 0000000,702e2d4..702e2d4
mode 000000,100644..100644
--- a/Utilities/cmcurl/lib/vauth/vauth.c
+++ b/Utilities/cmcurl/lib/vauth/vauth.c
diff --cc Utilities/cmcurl/lib/vauth/vauth.h
index 0000000,38806ee..38806ee
mode 000000,100644..100644
--- a/Utilities/cmcurl/lib/vauth/vauth.h
+++ b/Utilities/cmcurl/lib/vauth/vauth.h
diff --cc Utilities/cmcurl/lib/vtls/mbedtls.c
index 0000000,a1e7d23..a1e7d23
mode 000000,100644..100644
--- a/Utilities/cmcurl/lib/vtls/mbedtls.c
+++ b/Utilities/cmcurl/lib/vtls/mbedtls.c
diff --cc Utilities/cmcurl/lib/vtls/mbedtls.h
index 0000000,1021d54..1021d54
mode 000000,100644..100644
--- a/Utilities/cmcurl/lib/vtls/mbedtls.h
+++ b/Utilities/cmcurl/lib/vtls/mbedtls.h

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=202adcfe056681109fe61569ecdb3bd69f0b4f97
commit 202adcfe056681109fe61569ecdb3bd69f0b4f97
Author:     Curl Upstream <curl-library at cool.haxx.se>
AuthorDate: Wed Aug 3 08:37:16 2016 +0200
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Wed Aug 3 14:26:29 2016 -0400

    curl 2016-08-03 (f2cb3a01)
    
    Code extracted from:
    
        https://github.com/bagder/curl.git
    
    at commit f2cb3a01192d36395d16acec6cdb93446ca6fd45 (curl-7_50_1).

diff --git a/CMake/CurlTests.c b/CMake/CurlTests.c
index 04d5e7e..ceff391 100644
--- a/CMake/CurlTests.c
+++ b/CMake/CurlTests.c
@@ -9,7 +9,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -139,7 +139,7 @@ int main(void)
   rc = gethostbyname_r(address, &h, &hdata);
 #elif defined(HAVE_GETHOSTBYNAME_R_5) || \
       defined(HAVE_GETHOSTBYNAME_R_5_REENTRANT)
-  rc = gethostbyname_r(address, &h, buffer, 8192, 0, &h_errnop);
+  rc = gethostbyname_r(address, &h, buffer, 8192, &h_errnop);
   (void)hp; /* not used for test */
 #elif defined(HAVE_GETHOSTBYNAME_R_6) || \
       defined(HAVE_GETHOSTBYNAME_R_6_REENTRANT)
diff --git a/CMake/OtherTests.cmake b/CMake/OtherTests.cmake
index 4f07f22..d599498 100644
--- a/CMake/OtherTests.cmake
+++ b/CMake/OtherTests.cmake
@@ -10,8 +10,8 @@ endmacro(add_header_include)
 
 set(signature_call_conv)
 if(HAVE_WINDOWS_H)
-  add_header_include(HAVE_WINDOWS_H "windows.h")
   add_header_include(HAVE_WINSOCK2_H "winsock2.h")
+  add_header_include(HAVE_WINDOWS_H "windows.h")
   add_header_include(HAVE_WINSOCK_H "winsock.h")
   set(_source_epilogue
       "${_source_epilogue}\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN\n#endif")
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9a42cc7..7f7c4d6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -9,7 +9,7 @@
 #
 # 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 http://curl.haxx.se/docs/copyright.html.
+# 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
@@ -64,7 +64,7 @@ message(STATUS "curl version=[${CURL_VERSION}]")
 # SET(PACKAGE_NAME "curl")
 # SET(PACKAGE_VERSION "-")
 # SET(PACKAGE_STRING "curl-")
-# SET(PACKAGE_BUGREPORT "a suitable curl mailing list => http://curl.haxx.se/mail/")
+# SET(PACKAGE_BUGREPORT "a suitable curl mailing list => https://curl.haxx.se/mail/")
 set(OPERATING_SYSTEM "${CMAKE_SYSTEM_NAME}")
 set(OS "\"${CMAKE_SYSTEM_NAME}\"")
 
@@ -72,7 +72,6 @@ include_directories(${PROJECT_BINARY_DIR}/include/curl)
 include_directories( ${CURL_SOURCE_DIR}/include )
 
 option(BUILD_CURL_EXE "Set to ON to build cURL executable." ON)
-option(BUILD_CURL_TESTS "Set to ON to build cURL tests." ON)
 option(CURL_STATICLIB "Set to ON to build libcurl with static linking." OFF)
 option(ENABLE_ARES "Set to ON to enable c-ares support" OFF)
 option(ENABLE_THREADED_RESOLVER "Set to ON to enable POSIX threaded DNS lookup" OFF)
@@ -108,12 +107,6 @@ if(ENABLE_ARES)
   set(CURL_LIBS ${CURL_LIBS} ${CARES_LIBRARY})
 endif()
 
-option(BUILD_DASHBOARD_REPORTS "Set to ON to activate reporting of cURL builds here http://www.cdash.org/CDashPublic/index.php?project=CURL" OFF)
-if(BUILD_DASHBOARD_REPORTS)
-  #INCLUDE(Dart)
-  include(CTest)
-endif(BUILD_DASHBOARD_REPORTS)
-
 if(MSVC)
   option(BUILD_RELEASE_DEBUG_DIRS "Set OFF to build each configuration to a separate directory" OFF)
   mark_as_advanced(BUILD_RELEASE_DEBUG_DIRS)
@@ -122,11 +115,6 @@ endif()
 option(CURL_HIDDEN_SYMBOLS "Set to ON to hide libcurl internal symbols (=hide all symbols that aren't officially external)." ON)
 mark_as_advanced(CURL_HIDDEN_SYMBOLS)
 
-# IF(WIN32)
-# OPTION(CURL_WINDOWS_SSPI "Use windows libraries to allow NTLM authentication without openssl" ON)
-# MARK_AS_ADVANCED(CURL_WINDOWS_SSPI)
-# ENDIF()
-
 option(HTTP_ONLY "disables all protocols except HTTP (This overrides all CURL_DISABLE_* options)" OFF)
 mark_as_advanced(HTTP_ONLY)
 option(CURL_DISABLE_FTP "disables FTP" OFF)
@@ -186,7 +174,7 @@ option(DISABLED_THREADSAFE "Set to explicitly specify we don't want to use threa
 mark_as_advanced(DISABLED_THREADSAFE)
 option(ENABLE_IPV6 "Define if you want to enable IPv6 support" ON)
 mark_as_advanced(ENABLE_IPV6)
-if(ENABLE_IPV6)
+if(ENABLE_IPV6 AND NOT WIN32)
   include(CheckStructHasMember)
   check_struct_has_member("struct sockaddr_in6" sin6_addr "netinet/in.h"
                           HAVE_SOCKADDR_IN6_SIN6_ADDR)
@@ -253,6 +241,7 @@ include (CheckLibraryExists)
 include (CheckSymbolExists)
 include (CheckTypeSize)
 include (CheckCSourceCompiles)
+include (CMakeDependentOption)
 
 # On windows preload settings
 if(WIN32)
@@ -290,14 +279,22 @@ endif(NOT NOT_NEED_LIBNSL)
 
 check_function_exists(gethostname HAVE_GETHOSTNAME)
 
+set(OPENSSL_DEFAULT ON)
 if(WIN32)
+  set(OPENSSL_DEFAULT OFF)
   check_library_exists_concat("ws2_32" getch        HAVE_LIBWS2_32)
   check_library_exists_concat("winmm"  getch        HAVE_LIBWINMM)
 endif()
 
-option(CMAKE_USE_OPENSSL "Use OpenSSL code. Experimental" ON)
+option(CMAKE_USE_OPENSSL "Use OpenSSL code. Experimental" ${OPENSSL_DEFAULT})
 mark_as_advanced(CMAKE_USE_OPENSSL)
 
+if(WIN32)
+  CMAKE_DEPENDENT_OPTION(CURL_WINDOWS_SSPI "Use windows libraries to allow NTLM authentication without openssl" ON
+    "NOT CMAKE_USE_OPENSSL" OFF)
+  mark_as_advanced(CURL_WINDOWS_SSPI)
+endif()
+
 set(USE_OPENSSL OFF)
 set(HAVE_LIBCRYPTO OFF)
 set(HAVE_LIBSSL OFF)
@@ -320,15 +317,16 @@ if(CMAKE_USE_OPENSSL)
     check_include_file("openssl/ssl.h"    HAVE_OPENSSL_SSL_H)
     check_include_file("openssl/x509.h"   HAVE_OPENSSL_X509_H)
     check_include_file("openssl/rand.h"   HAVE_OPENSSL_RAND_H)
+  elseif(WIN32)
+    set(CURL_WINDOWS_SSPI ON)
   endif()
 endif()
 
 if(NOT CURL_DISABLE_LDAP)
-
   if(WIN32)
     option(USE_WIN32_LDAP "Use Windows LDAP implementation" ON)
     if(USE_WIN32_LDAP)
-      check_library_exists("wldap32" cldap_open "" HAVE_WLDAP32)
+      check_library_exists_concat("wldap32" cldap_open HAVE_WLDAP32)
       if(NOT HAVE_WLDAP32)
         set(USE_WIN32_LDAP OFF)
       endif()
@@ -343,75 +341,78 @@ if(NOT CURL_DISABLE_LDAP)
   if(CMAKE_USE_OPENLDAP AND USE_WIN32_LDAP)
     message(FATAL_ERROR "Cannot use USE_WIN32_LDAP and CMAKE_USE_OPENLDAP at the same time")
   endif()
-  
+
   # Now that we know, we're not using windows LDAP...
-  if(NOT USE_WIN32_LDAP)
+  if(USE_WIN32_LDAP)
+    check_include_file_concat("winldap.h" HAVE_WINLDAP_H)
+    check_include_file_concat("winber.h"  HAVE_WINBER_H)
+  else()
     # Check for LDAP
     set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_LIBRARIES})
     check_library_exists_concat(${CMAKE_LDAP_LIB} ldap_init HAVE_LIBLDAP)
     check_library_exists_concat(${CMAKE_LBER_LIB} ber_init HAVE_LIBLBER)
-  else()
-    check_include_file_concat("winldap.h" HAVE_WINLDAP_H)
-    check_include_file_concat("winber.h"  HAVE_WINBER_H)
-  endif()
-  
-  set(CMAKE_LDAP_INCLUDE_DIR "" CACHE STRING "Path to LDAP include directory")
-  if(CMAKE_LDAP_INCLUDE_DIR)
-    set(CMAKE_REQUIRED_INCLUDES ${CMAKE_LDAP_INCLUDE_DIR})
-  endif()
-  check_include_file_concat("ldap.h"           HAVE_LDAP_H)
-  check_include_file_concat("lber.h"           HAVE_LBER_H)
-
-  if(NOT HAVE_LDAP_H)
-    message(STATUS "LDAP_H not found CURL_DISABLE_LDAP set ON")
-    set(CURL_DISABLE_LDAP ON CACHE BOOL "" FORCE)
-  elseif(NOT HAVE_LIBLDAP)
-    message(STATUS "LDAP library '${CMAKE_LDAP_LIB}' not found CURL_DISABLE_LDAP set ON")
-    set(CURL_DISABLE_LDAP ON CACHE BOOL "" FORCE)
-  else()
-    if(CMAKE_USE_OPENLDAP)
-      set(USE_OPENLDAP ON)
-    endif()
+
+    set(CMAKE_REQUIRED_INCLUDES_BAK ${CMAKE_REQUIRED_INCLUDES})
+    set(CMAKE_LDAP_INCLUDE_DIR "" CACHE STRING "Path to LDAP include directory")
     if(CMAKE_LDAP_INCLUDE_DIR)
-      include_directories(${CMAKE_LDAP_INCLUDE_DIR})
-    endif()
-    set(NEED_LBER_H ON)
-    set(_HEADER_LIST)
-    if(HAVE_WINDOWS_H)
-      list(APPEND _HEADER_LIST "windows.h")
+      list(APPEND CMAKE_REQUIRED_INCLUDES ${CMAKE_LDAP_INCLUDE_DIR})
     endif()
-    if(HAVE_SYS_TYPES_H)
-      list(APPEND _HEADER_LIST "sys/types.h")
-    endif()
-    list(APPEND _HEADER_LIST "ldap.h")
+    check_include_file_concat("ldap.h"           HAVE_LDAP_H)
+    check_include_file_concat("lber.h"           HAVE_LBER_H)
+
+    if(NOT HAVE_LDAP_H)
+      message(STATUS "LDAP_H not found CURL_DISABLE_LDAP set ON")
+      set(CURL_DISABLE_LDAP ON CACHE BOOL "" FORCE)
+      set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES_BAK}) #LDAP includes won't be used
+    elseif(NOT HAVE_LIBLDAP)
+      message(STATUS "LDAP library '${CMAKE_LDAP_LIB}' not found CURL_DISABLE_LDAP set ON")
+      set(CURL_DISABLE_LDAP ON CACHE BOOL "" FORCE)
+      set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES_BAK}) #LDAP includes won't be used
+    else()
+      if(CMAKE_USE_OPENLDAP)
+        set(USE_OPENLDAP ON)
+      endif()
+      if(CMAKE_LDAP_INCLUDE_DIR)
+        include_directories(${CMAKE_LDAP_INCLUDE_DIR})
+      endif()
+      set(NEED_LBER_H ON)
+      set(_HEADER_LIST)
+      if(HAVE_WINDOWS_H)
+        list(APPEND _HEADER_LIST "windows.h")
+      endif()
+      if(HAVE_SYS_TYPES_H)
+        list(APPEND _HEADER_LIST "sys/types.h")
+      endif()
+      list(APPEND _HEADER_LIST "ldap.h")
 
-    set(_SRC_STRING "")
-    foreach(_HEADER ${_HEADER_LIST})
-      set(_INCLUDE_STRING "${_INCLUDE_STRING}#include <${_HEADER}>\n")
-    endforeach()
+      set(_SRC_STRING "")
+      foreach(_HEADER ${_HEADER_LIST})
+        set(_INCLUDE_STRING "${_INCLUDE_STRING}#include <${_HEADER}>\n")
+      endforeach()
 
-    set(_SRC_STRING
-      "
-      ${_INCLUDE_STRING}
-      int main(int argc, char ** argv)
-      {
-        BerValue *bvp = NULL;
-        BerElement *bep = ber_init(bvp);
-        ber_free(bep, 1);
-        return 0;
-      }"
-    )
-    set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -DLDAP_DEPRECATED=1")
-    list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_LDAP_LIB})
-    if(HAVE_LIBLBER)
-      list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_LBER_LIB})
-    endif()
-    check_c_source_compiles("${_SRC_STRING}" NOT_NEED_LBER_H)
+      set(_SRC_STRING
+        "
+        ${_INCLUDE_STRING}
+        int main(int argc, char ** argv)
+        {
+          BerValue *bvp = NULL;
+          BerElement *bep = ber_init(bvp);
+          ber_free(bep, 1);
+          return 0;
+        }"
+      )
+      set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -DLDAP_DEPRECATED=1")
+      list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_LDAP_LIB})
+      if(HAVE_LIBLBER)
+        list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_LBER_LIB})
+      endif()
+      check_c_source_compiles("${_SRC_STRING}" NOT_NEED_LBER_H)
 
-    if(NOT_NEED_LBER_H)
-      set(NEED_LBER_H OFF)
-    else()
-      set(CURL_TEST_DEFINES "${CURL_TEST_DEFINES} -DNEED_LBER_H")
+      if(NOT_NEED_LBER_H)
+        set(NEED_LBER_H OFF)
+      else()
+        set(CURL_TEST_DEFINES "${CURL_TEST_DEFINES} -DNEED_LBER_H")
+      endif()
     endif()
   endif()
 
@@ -448,6 +449,7 @@ if(CURL_ZLIB)
     set(HAVE_LIBZ ON)
     list(APPEND CURL_LIBS ${ZLIB_LIBRARIES})
     include_directories(${ZLIB_INCLUDE_DIRS})
+    list(APPEND CMAKE_REQUIRED_INCLUDES ${ZLIB_INCLUDE_DIRS})
   endif()
 endif()
 
@@ -463,7 +465,7 @@ if(CMAKE_USE_LIBSSH2)
   if(LIBSSH2_FOUND)
     list(APPEND CURL_LIBS ${LIBSSH2_LIBRARY})
     set(CMAKE_REQUIRED_LIBRARIES ${LIBSSH2_LIBRARY})
-    set(CMAKE_REQUIRED_INCLUDES "${LIBSSH2_INCLUDE_DIR}")
+    list(APPEND CMAKE_REQUIRED_INCLUDES "${LIBSSH2_INCLUDE_DIR}")
     include_directories("${LIBSSH2_INCLUDE_DIR}")
     set(HAVE_LIBSSH2 ON)
     set(USE_LIBSSH2 ON)
@@ -496,7 +498,7 @@ if(CMAKE_USE_GSSAPI)
 
     message(STATUS "Found ${GSS_FLAVOUR} GSSAPI version: \"${GSS_VERSION}\"")
 
-    set(CMAKE_REQUIRED_INCLUDES ${GSS_INCLUDE_DIR})
+    list(APPEND CMAKE_REQUIRED_INCLUDES ${GSS_INCLUDE_DIRECTORIES})
     check_include_file_concat("gssapi/gssapi.h"  HAVE_GSSAPI_GSSAPI_H)
     check_include_file_concat("gssapi/gssapi_generic.h" HAVE_GSSAPI_GSSAPI_GENERIC_H)
     check_include_file_concat("gssapi/gssapi_krb5.h" HAVE_GSSAPI_GSSAPI_KRB5_H)
@@ -532,7 +534,7 @@ if(CMAKE_USE_GSSAPI)
 
     endif()
 
-    include_directories(${GSS_INCLUDE_DIR})
+    include_directories(${GSS_INCLUDE_DIRECTORIES})
     link_directories(${GSS_LINK_DIRECTORIES})
     set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GSS_COMPILER_FLAGS}")
     set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${GSS_LINKER_FLAGS}")
@@ -552,12 +554,26 @@ else()
   unset(USE_UNIX_SOCKETS CACHE)
 endif()
 
+
 # Check for header files
 if(NOT UNIX)
   check_include_file_concat("windows.h"      HAVE_WINDOWS_H)
   check_include_file_concat("winsock.h"      HAVE_WINSOCK_H)
   check_include_file_concat("ws2tcpip.h"     HAVE_WS2TCPIP_H)
   check_include_file_concat("winsock2.h"     HAVE_WINSOCK2_H)
+  if(CURL_WINDOWS_SSPI)
+    set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -DSECURITY_WIN32")
+    check_include_file_concat("sspi.h"       HAVE_SSPI_H)
+    if(HAVE_SSPI_H)
+      check_include_file_concat("schannel.h" HAVE_SCHANNEL_H)
+      set(USE_WINDOWS_SSPI ON)
+      if(HAVE_SCHANNEL_H)
+        set(USE_SCHANNEL ON)
+        set(SSL_ENABLED ON)
+        set(CURL_LIBS ${CURL_LIBS} "crypt32")
+      endif()
+    endif()
+  endif()
 endif(NOT UNIX)
 
 check_include_file_concat("stdio.h"          HAVE_STDIO_H)
@@ -1018,7 +1034,9 @@ add_subdirectory(lib)
 if(BUILD_CURL_EXE)
   add_subdirectory(src)
 endif()
-if(BUILD_CURL_TESTS)
+
+include(CTest)
+if(BUILD_TESTING)
   add_subdirectory(tests)
 endif()
 
@@ -1038,7 +1056,8 @@ endfunction()
 
 # Clear list and try to detect available features
 set(_items)
-_add_if("SSL"           SSL_ENABLED)
+_add_if("WinSSL"        SSL_ENABLED AND USE_WINDOWS_SSPI)
+_add_if("OpenSSL"       SSL_ENABLED AND USE_OPENSSL)
 _add_if("IPv6"          ENABLE_IPV6)
 _add_if("unix-sockets"  USE_UNIX_SOCKETS)
 _add_if("libz"          HAVE_LIBZ)
@@ -1136,7 +1155,7 @@ set(VERSIONNUM              "${CURL_VERSION_NUM}")
 # Finally generate a "curl-config" matching this config
 configure_file("${CURL_SOURCE_DIR}/curl-config.in"
                "${CURL_BINARY_DIR}/curl-config" @ONLY)
-install(FILES "${CMAKE_BINARY_DIR}/curl-config"
+install(FILES "${CURL_BINARY_DIR}/curl-config"
         DESTINATION bin
         PERMISSIONS
           OWNER_READ OWNER_WRITE OWNER_EXECUTE
@@ -1146,7 +1165,7 @@ install(FILES "${CMAKE_BINARY_DIR}/curl-config"
 # Finally generate a pkg-config file matching this config
 configure_file("${CURL_SOURCE_DIR}/libcurl.pc.in"
                "${CURL_BINARY_DIR}/libcurl.pc" @ONLY)
-install(FILES "${CMAKE_BINARY_DIR}/libcurl.pc"
+install(FILES "${CURL_BINARY_DIR}/libcurl.pc"
         DESTINATION lib/pkgconfig)
 
 # This needs to be run very last so other parts of the scripts can take advantage of this.
diff --git a/COPYING b/COPYING
index 6b5d59f..a98663e 100644
--- a/COPYING
+++ b/COPYING
@@ -1,6 +1,7 @@
 COPYRIGHT AND PERMISSION NOTICE
 
-Copyright (c) 1996 - 2015, Daniel Stenberg, <daniel at haxx.se>.
+Copyright (c) 1996 - 2016, Daniel Stenberg, <daniel at haxx.se>, and many
+contributors, see the THANKS file.
 
 All rights reserved.
 
diff --git a/include/curl/curl.h b/include/curl/curl.h
index 64f9261..7fd6d1f 100644
--- a/include/curl/curl.h
+++ b/include/curl/curl.h
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -24,10 +24,10 @@
 
 /*
  * If you have libcurl problems, all docs and details are found here:
- *   http://curl.haxx.se/libcurl/
+ *   https://curl.haxx.se/libcurl/
  *
  * curl-library mailing list subscription and unsubscription web interface:
- *   http://cool.haxx.se/mailman/listinfo/curl-library/
+ *   https://cool.haxx.se/mailman/listinfo/curl-library/
  */
 
 #include "curlver.h"         /* libcurl version defines   */
@@ -56,7 +56,8 @@
 #include <time.h>
 
 #if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__CYGWIN__)
-#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H) || defined(__LWIP_OPT_H__))
+#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H) || \
+      defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H))
 /* The check above prevents the winsock2 inclusion if winsock.h already was
    included, since they can't co-exist without problems */
 #include <winsock2.h>
@@ -90,7 +91,13 @@
 extern "C" {
 #endif
 
+#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER)
+typedef struct Curl_easy CURL;
+typedef struct Curl_share CURLSH;
+#else
 typedef void CURL;
+typedef void CURLSH;
+#endif
 
 /*
  * libcurl external API function linkage decorations.
@@ -112,7 +119,7 @@ typedef void CURL;
 
 #ifndef curl_socket_typedef
 /* socket typedef */
-#if defined(WIN32) && !defined(__LWIP_OPT_H__)
+#if defined(WIN32) && !defined(__LWIP_OPT_H__) && !defined(LWIP_HDR_OPT_H)
 typedef SOCKET curl_socket_t;
 #define CURL_SOCKET_BAD INVALID_SOCKET
 #else
@@ -127,7 +134,8 @@ struct curl_httppost {
   char *name;                       /* pointer to allocated name */
   long namelength;                  /* length of name length */
   char *contents;                   /* pointer to allocated data contents */
-  long contentslength;              /* length of contents field */
+  long contentslength;              /* length of contents field, see also
+                                       CURL_HTTPPOST_LARGE */
   char *buffer;                     /* pointer to allocated buffer contents */
   long bufferlength;                /* length of buffer field */
   char *contenttype;                /* Content-Type */
@@ -136,24 +144,33 @@ struct curl_httppost {
                                        file, this link should link to following
                                        files */
   long flags;                       /* as defined below */
-#define HTTPPOST_FILENAME (1<<0)    /* specified content is a file name */
-#define HTTPPOST_READFILE (1<<1)    /* specified content is a file name */
-#define HTTPPOST_PTRNAME (1<<2)     /* name is only stored pointer
-                                       do not free in formfree */
-#define HTTPPOST_PTRCONTENTS (1<<3) /* contents is only stored pointer
-                                       do not free in formfree */
-#define HTTPPOST_BUFFER (1<<4)      /* upload file from buffer */
-#define HTTPPOST_PTRBUFFER (1<<5)   /* upload file from pointer contents */
-#define HTTPPOST_CALLBACK (1<<6)    /* upload file contents by using the
-                                       regular read callback to get the data
-                                       and pass the given pointer as custom
-                                       pointer */
+
+/* specified content is a file name */
+#define CURL_HTTPPOST_FILENAME (1<<0)
+/* specified content is a file name */
+#define CURL_HTTPPOST_READFILE (1<<1)
+/* name is only stored pointer do not free in formfree */
+#define CURL_HTTPPOST_PTRNAME (1<<2)
+/* contents is only stored pointer do not free in formfree */
+#define CURL_HTTPPOST_PTRCONTENTS (1<<3)
+/* upload file from buffer */
+#define CURL_HTTPPOST_BUFFER (1<<4)
+/* upload file from pointer contents */
+#define CURL_HTTPPOST_PTRBUFFER (1<<5)
+/* upload file contents by using the regular read callback to get the data and
+   pass the given pointer as custom pointer */
+#define CURL_HTTPPOST_CALLBACK (1<<6)
+/* use size in 'contentlen', added in 7.46.0 */
+#define CURL_HTTPPOST_LARGE (1<<7)
 
   char *showfilename;               /* The file name to show. If not set, the
                                        actual file name will be used (if this
                                        is a file part) */
   void *userp;                      /* custom pointer used for
                                        HTTPPOST_CALLBACK posts */
+  curl_off_t contentlen;            /* alternative length of contents
+                                       field. Used if CURL_HTTPPOST_LARGE is
+                                       set. Added in 7.46.0 */
 };
 
 /* This is the CURLOPT_PROGRESSFUNCTION callback proto. It is now considered
@@ -362,6 +379,7 @@ typedef curlioerr (*curl_ioctl_callback)(CURL *handle,
                                          int cmd,
                                          void *clientp);
 
+#ifndef CURL_DID_MEMORY_FUNC_TYPEDEFS
 /*
  * The following typedef's are signatures of malloc, free, realloc, strdup and
  * calloc respectively.  Function pointers of these types can be passed to the
@@ -374,6 +392,9 @@ typedef void *(*curl_realloc_callback)(void *ptr, size_t size);
 typedef char *(*curl_strdup_callback)(const char *str);
 typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size);
 
+#define CURL_DID_MEMORY_FUNC_TYPEDEFS
+#endif
+
 /* the kind of data that is passed to information_callback*/
 typedef enum {
   CURLINFO_TEXT = 0,
@@ -460,9 +481,9 @@ typedef enum {
   CURLE_OBSOLETE44,              /* 44 - NOT USED */
   CURLE_INTERFACE_FAILED,        /* 45 - CURLOPT_INTERFACE failed */
   CURLE_OBSOLETE46,              /* 46 - NOT USED */
-  CURLE_TOO_MANY_REDIRECTS ,     /* 47 - catch endless re-direct loops */
+  CURLE_TOO_MANY_REDIRECTS,      /* 47 - catch endless re-direct loops */
   CURLE_UNKNOWN_OPTION,          /* 48 - User specified an unknown option */
-  CURLE_TELNET_OPTION_SYNTAX ,   /* 49 - Malformed telnet option */
+  CURLE_TELNET_OPTION_SYNTAX,    /* 49 - Malformed telnet option */
   CURLE_OBSOLETE50,              /* 50 - NOT USED */
   CURLE_PEER_FAILED_VERIFICATION, /* 51 - peer's certificate or fingerprint
                                      wasn't verified fine */
@@ -524,6 +545,8 @@ typedef enum {
   CURLE_SSL_PINNEDPUBKEYNOTMATCH, /* 90 - specified pinned public key did not
                                      match */
   CURLE_SSL_INVALIDCERTSTATUS,   /* 91 - invalid certificate status */
+  CURLE_HTTP2_STREAM,            /* 92 - stream error in HTTP/2 framing layer
+                                    */
   CURL_LAST /* never use! */
 } CURLcode;
 
@@ -818,9 +841,13 @@ typedef enum {
    but 32 */
 #define CURLOPTTYPE_LONG          0
 #define CURLOPTTYPE_OBJECTPOINT   10000
+#define CURLOPTTYPE_STRINGPOINT   10000
 #define CURLOPTTYPE_FUNCTIONPOINT 20000
 #define CURLOPTTYPE_OFF_T         30000
 
+/* *STRINGPOINT is an alias for OBJECTPOINT to allow tools to extract the
+   string options from the header file */
+
 /* name is uppercase CURLOPT_<name>,
    type is one of the defined CURLOPTTYPE_<type>
    number is unique identifier */
@@ -834,6 +861,7 @@ typedef enum {
 /* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */
 #define LONG          CURLOPTTYPE_LONG
 #define OBJECTPOINT   CURLOPTTYPE_OBJECTPOINT
+#define STRINGPOINT   CURLOPTTYPE_OBJECTPOINT
 #define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT
 #define OFF_T         CURLOPTTYPE_OFF_T
 #define CINIT(name,type,number) CURLOPT_/**/name = type + number
@@ -850,22 +878,22 @@ typedef enum {
   CINIT(WRITEDATA, OBJECTPOINT, 1),
 
   /* The full URL to get/put */
-  CINIT(URL, OBJECTPOINT, 2),
+  CINIT(URL, STRINGPOINT, 2),
 
   /* Port number to connect to, if other than default. */
   CINIT(PORT, LONG, 3),
 
   /* Name of proxy to use. */
-  CINIT(PROXY, OBJECTPOINT, 4),
+  CINIT(PROXY, STRINGPOINT, 4),
 
   /* "user:password;options" to use when fetching. */
-  CINIT(USERPWD, OBJECTPOINT, 5),
+  CINIT(USERPWD, STRINGPOINT, 5),
 
   /* "user:password" to use with proxy. */
-  CINIT(PROXYUSERPWD, OBJECTPOINT, 6),
+  CINIT(PROXYUSERPWD, STRINGPOINT, 6),
 
   /* Range to get, specified as an ASCII string. */
-  CINIT(RANGE, OBJECTPOINT, 7),
+  CINIT(RANGE, STRINGPOINT, 7),
 
   /* not used */
 
@@ -902,14 +930,14 @@ typedef enum {
   CINIT(POSTFIELDS, OBJECTPOINT, 15),
 
   /* Set the referrer page (needed by some CGIs) */
-  CINIT(REFERER, OBJECTPOINT, 16),
+  CINIT(REFERER, STRINGPOINT, 16),
 
   /* Set the FTP PORT string (interface name, named or numerical IP address)
      Use i.e '-' to use default address. */
-  CINIT(FTPPORT, OBJECTPOINT, 17),
+  CINIT(FTPPORT, STRINGPOINT, 17),
 
   /* Set the User-Agent string (examined by some CGIs) */
-  CINIT(USERAGENT, OBJECTPOINT, 18),
+  CINIT(USERAGENT, STRINGPOINT, 18),
 
   /* If the download receives less than "low speed limit" bytes/second
    * during "low speed time" seconds, the operations is aborted.
@@ -932,7 +960,7 @@ typedef enum {
   CINIT(RESUME_FROM, LONG, 21),
 
   /* Set cookie in request: */
-  CINIT(COOKIE, OBJECTPOINT, 22),
+  CINIT(COOKIE, STRINGPOINT, 22),
 
   /* This points to a linked list of headers, struct curl_slist kind. This
      list is also used for RTSP (in spite of its name) */
@@ -942,10 +970,10 @@ typedef enum {
   CINIT(HTTPPOST, OBJECTPOINT, 24),
 
   /* name of the file keeping your private SSL-certificate */
-  CINIT(SSLCERT, OBJECTPOINT, 25),
+  CINIT(SSLCERT, STRINGPOINT, 25),
 
   /* password for the SSL or SSH private key */
-  CINIT(KEYPASSWD, OBJECTPOINT, 26),
+  CINIT(KEYPASSWD, STRINGPOINT, 26),
 
   /* send TYPE parameter? */
   CINIT(CRLF, LONG, 27),
@@ -959,7 +987,7 @@ typedef enum {
 
   /* point to a file to read the initial cookies from, also enables
      "cookie awareness" */
-  CINIT(COOKIEFILE, OBJECTPOINT, 31),
+  CINIT(COOKIEFILE, STRINGPOINT, 31),
 
   /* What version to specifically try to use.
      See CURL_SSLVERSION defines below. */
@@ -978,9 +1006,9 @@ typedef enum {
      HTTP: DELETE, TRACE and others
      FTP: to use a different list command
      */
-  CINIT(CUSTOMREQUEST, OBJECTPOINT, 36),
+  CINIT(CUSTOMREQUEST, STRINGPOINT, 36),
 
-  /* HTTP request, for odd commands like DELETE, TRACE and others */
+  /* FILE handle to use instead of stderr */
   CINIT(STDERR, OBJECTPOINT, 37),
 
   /* 38 is not used */
@@ -1037,19 +1065,19 @@ typedef enum {
   CINIT(HTTPPROXYTUNNEL, LONG, 61),
 
   /* Set the interface string to use as outgoing network interface */
-  CINIT(INTERFACE, OBJECTPOINT, 62),
+  CINIT(INTERFACE, STRINGPOINT, 62),
 
   /* Set the krb4/5 security level, this also enables krb4/5 awareness.  This
    * is a string, 'clear', 'safe', 'confidential' or 'private'.  If the string
    * is set but doesn't match one of these, 'private' will be used.  */
-  CINIT(KRBLEVEL, OBJECTPOINT, 63),
+  CINIT(KRBLEVEL, STRINGPOINT, 63),
 
   /* Set if we should verify the peer in ssl handshake, set 1 to verify. */
   CINIT(SSL_VERIFYPEER, LONG, 64),
 
   /* The CApath or CAfile used to validate the peer certificate
      this option is used only if SSL_VERIFYPEER is true */
-  CINIT(CAINFO, OBJECTPOINT, 65),
+  CINIT(CAINFO, STRINGPOINT, 65),
 
   /* 66 = OBSOLETE */
   /* 67 = OBSOLETE */
@@ -1083,10 +1111,10 @@ typedef enum {
 
   /* Set to a file name that contains random data for libcurl to use to
      seed the random engine when doing SSL connects. */
-  CINIT(RANDOM_FILE, OBJECTPOINT, 76),
+  CINIT(RANDOM_FILE, STRINGPOINT, 76),
 
   /* Set to the Entropy Gathering Daemon socket pathname */
-  CINIT(EGDSOCKET, OBJECTPOINT, 77),
+  CINIT(EGDSOCKET, STRINGPOINT, 77),
 
   /* Time-out connect operations after this amount of seconds, if connects are
      OK within this time, then fine... This only aborts the connect phase. */
@@ -1108,10 +1136,10 @@ typedef enum {
 
   /* Specify which file name to write all known cookies in after completed
      operation. Set file name to "-" (dash) to make it go to stdout. */
-  CINIT(COOKIEJAR, OBJECTPOINT, 82),
+  CINIT(COOKIEJAR, STRINGPOINT, 82),
 
   /* Specify which SSL ciphers to use */
-  CINIT(SSL_CIPHER_LIST, OBJECTPOINT, 83),
+  CINIT(SSL_CIPHER_LIST, STRINGPOINT, 83),
 
   /* Specify which HTTP version to use! This must be set to one of the
      CURL_HTTP_VERSION* enums set below. */
@@ -1123,16 +1151,16 @@ typedef enum {
   CINIT(FTP_USE_EPSV, LONG, 85),
 
   /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") */
-  CINIT(SSLCERTTYPE, OBJECTPOINT, 86),
+  CINIT(SSLCERTTYPE, STRINGPOINT, 86),
 
   /* name of the file keeping your private SSL-key */
-  CINIT(SSLKEY, OBJECTPOINT, 87),
+  CINIT(SSLKEY, STRINGPOINT, 87),
 
   /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") */
-  CINIT(SSLKEYTYPE, OBJECTPOINT, 88),
+  CINIT(SSLKEYTYPE, STRINGPOINT, 88),
 
   /* crypto engine for the SSL-sub system */
-  CINIT(SSLENGINE, OBJECTPOINT, 89),
+  CINIT(SSLENGINE, STRINGPOINT, 89),
 
   /* set the crypto engine for the SSL-sub system as default
      the param has no meaning...
@@ -1159,7 +1187,7 @@ typedef enum {
 
   /* The CApath directory used to validate the peer certificate
      this option is used only if SSL_VERIFYPEER is true */
-  CINIT(CAPATH, OBJECTPOINT, 97),
+  CINIT(CAPATH, STRINGPOINT, 97),
 
   /* Instruct libcurl to use a smaller receive buffer */
   CINIT(BUFFERSIZE, LONG, 98),
@@ -1179,7 +1207,7 @@ typedef enum {
   /* Set the Accept-Encoding string. Use this to tell a server you would like
      the response to be compressed. Before 7.21.6, this was known as
      CURLOPT_ENCODING */
-  CINIT(ACCEPT_ENCODING, OBJECTPOINT, 102),
+  CINIT(ACCEPT_ENCODING, STRINGPOINT, 102),
 
   /* Set pointer to private data */
   CINIT(PRIVATE, OBJECTPOINT, 103),
@@ -1260,7 +1288,7 @@ typedef enum {
      to parse (using the CURLOPT_NETRC option). If not set, libcurl will do
      a poor attempt to find the user's home directory and check for a .netrc
      file in there. */
-  CINIT(NETRC_FILE, OBJECTPOINT, 118),
+  CINIT(NETRC_FILE, STRINGPOINT, 118),
 
   /* Enable SSL/TLS for FTP, pick one of:
      CURLUSESSL_TRY     - try using SSL, proceed anyway otherwise
@@ -1303,10 +1331,10 @@ typedef enum {
 
   /* zero terminated string for pass on to the FTP server when asked for
      "account" info */
-  CINIT(FTP_ACCOUNT, OBJECTPOINT, 134),
+  CINIT(FTP_ACCOUNT, STRINGPOINT, 134),
 
-  /* feed cookies into cookie engine */
-  CINIT(COOKIELIST, OBJECTPOINT, 135),
+  /* feed cookie into cookie engine */
+  CINIT(COOKIELIST, STRINGPOINT, 135),
 
   /* ignore Content-Length */
   CINIT(IGNORE_CONTENT_LENGTH, LONG, 136),
@@ -1352,7 +1380,7 @@ typedef enum {
   CINIT(MAX_RECV_SPEED_LARGE, OFF_T, 146),
 
   /* Pointer to command string to send if USER/PASS fails. */
-  CINIT(FTP_ALTERNATIVE_TO_USER, OBJECTPOINT, 147),
+  CINIT(FTP_ALTERNATIVE_TO_USER, STRINGPOINT, 147),
 
   /* callback function for setting socket options */
   CINIT(SOCKOPTFUNCTION, FUNCTIONPOINT, 148),
@@ -1366,8 +1394,8 @@ typedef enum {
   CINIT(SSH_AUTH_TYPES, LONG, 151),
 
   /* Used by scp/sftp to do public/private key authentication */
-  CINIT(SSH_PUBLIC_KEYFILE, OBJECTPOINT, 152),
-  CINIT(SSH_PRIVATE_KEYFILE, OBJECTPOINT, 153),
+  CINIT(SSH_PUBLIC_KEYFILE, STRINGPOINT, 152),
+  CINIT(SSH_PRIVATE_KEYFILE, STRINGPOINT, 153),
 
   /* Send CCC (Clear Command Channel) after authentication */
   CINIT(FTP_SSL_CCC, LONG, 154),
@@ -1391,7 +1419,7 @@ typedef enum {
   CINIT(POSTREDIR, LONG, 161),
 
   /* used by scp/sftp to verify the host's public key */
-  CINIT(SSH_HOST_PUBLIC_KEY_MD5, OBJECTPOINT, 162),
+  CINIT(SSH_HOST_PUBLIC_KEY_MD5, STRINGPOINT, 162),
 
   /* Callback function for opening socket (instead of socket(2)). Optionally,
      callback is able change the address or refuse to connect returning
@@ -1411,10 +1439,10 @@ typedef enum {
   CINIT(SEEKDATA, OBJECTPOINT, 168),
 
   /* CRL file */
-  CINIT(CRLFILE, OBJECTPOINT, 169),
+  CINIT(CRLFILE, STRINGPOINT, 169),
 
   /* Issuer certificate */
-  CINIT(ISSUERCERT, OBJECTPOINT, 170),
+  CINIT(ISSUERCERT, STRINGPOINT, 170),
 
   /* (IPv6) Address scope */
   CINIT(ADDRESS_SCOPE, LONG, 171),
@@ -1424,12 +1452,12 @@ typedef enum {
   CINIT(CERTINFO, LONG, 172),
 
   /* "name" and "pwd" to use when fetching. */
-  CINIT(USERNAME, OBJECTPOINT, 173),
-  CINIT(PASSWORD, OBJECTPOINT, 174),
+  CINIT(USERNAME, STRINGPOINT, 173),
+  CINIT(PASSWORD, STRINGPOINT, 174),
 
     /* "name" and "pwd" to use with Proxy when fetching. */
-  CINIT(PROXYUSERNAME, OBJECTPOINT, 175),
-  CINIT(PROXYPASSWORD, OBJECTPOINT, 176),
+  CINIT(PROXYUSERNAME, STRINGPOINT, 175),
+  CINIT(PROXYPASSWORD, STRINGPOINT, 176),
 
   /* Comma separated list of hostnames defining no-proxy zones. These should
      match both hostnames directly, and hostnames within a domain. For
@@ -1438,13 +1466,13 @@ typedef enum {
      implementations of this, .local.com will be considered to be the same as
      local.com. A single * is the only valid wildcard, and effectively
      disables the use of proxy. */
-  CINIT(NOPROXY, OBJECTPOINT, 177),
+  CINIT(NOPROXY, STRINGPOINT, 177),
 
   /* block size for TFTP transfers */
   CINIT(TFTP_BLKSIZE, LONG, 178),
 
   /* Socks Service */
-  CINIT(SOCKS5_GSSAPI_SERVICE, OBJECTPOINT, 179),
+  CINIT(SOCKS5_GSSAPI_SERVICE, STRINGPOINT, 179), /* DEPRECATED, do not use! */
 
   /* Socks Service */
   CINIT(SOCKS5_GSSAPI_NEC, LONG, 180),
@@ -1462,7 +1490,7 @@ typedef enum {
   CINIT(REDIR_PROTOCOLS, LONG, 182),
 
   /* set the SSH knownhost file name to use */
-  CINIT(SSH_KNOWNHOSTS, OBJECTPOINT, 183),
+  CINIT(SSH_KNOWNHOSTS, STRINGPOINT, 183),
 
   /* set the SSH host key callback, must point to a curl_sshkeycallback
      function */
@@ -1472,9 +1500,9 @@ typedef enum {
   CINIT(SSH_KEYDATA, OBJECTPOINT, 185),
 
   /* set the SMTP mail originator */
-  CINIT(MAIL_FROM, OBJECTPOINT, 186),
+  CINIT(MAIL_FROM, STRINGPOINT, 186),
 
-  /* set the SMTP mail receiver(s) */
+  /* set the list of SMTP mail receiver(s) */
   CINIT(MAIL_RCPT, OBJECTPOINT, 187),
 
   /* FTP: send PRET before PASV */
@@ -1484,13 +1512,13 @@ typedef enum {
   CINIT(RTSP_REQUEST, LONG, 189),
 
   /* The RTSP session identifier */
-  CINIT(RTSP_SESSION_ID, OBJECTPOINT, 190),
+  CINIT(RTSP_SESSION_ID, STRINGPOINT, 190),
 
   /* The RTSP stream URI */
-  CINIT(RTSP_STREAM_URI, OBJECTPOINT, 191),
+  CINIT(RTSP_STREAM_URI, STRINGPOINT, 191),
 
   /* The Transport: header to use in RTSP requests */
-  CINIT(RTSP_TRANSPORT, OBJECTPOINT, 192),
+  CINIT(RTSP_TRANSPORT, STRINGPOINT, 192),
 
   /* Manually initialize the client RTSP CSeq for this handle */
   CINIT(RTSP_CLIENT_CSEQ, LONG, 193),
@@ -1528,13 +1556,13 @@ typedef enum {
   CINIT(RESOLVE, OBJECTPOINT, 203),
 
   /* Set a username for authenticated TLS */
-  CINIT(TLSAUTH_USERNAME, OBJECTPOINT, 204),
+  CINIT(TLSAUTH_USERNAME, STRINGPOINT, 204),
 
   /* Set a password for authenticated TLS */
-  CINIT(TLSAUTH_PASSWORD, OBJECTPOINT, 205),
+  CINIT(TLSAUTH_PASSWORD, STRINGPOINT, 205),
 
   /* Set authentication type for authenticated TLS */
-  CINIT(TLSAUTH_TYPE, OBJECTPOINT, 206),
+  CINIT(TLSAUTH_TYPE, STRINGPOINT, 206),
 
   /* Set to 1 to enable the "TE:" header in HTTP requests to ask for
      compressed transfer-encoded responses. Set to 0 to disable the use of TE:
@@ -1557,7 +1585,7 @@ typedef enum {
   CINIT(GSSAPI_DELEGATION, LONG, 210),
 
   /* Set the name servers to use for DNS resolution */
-  CINIT(DNS_SERVERS, OBJECTPOINT, 211),
+  CINIT(DNS_SERVERS, STRINGPOINT, 211),
 
   /* Time-out accept operations (currently for FTP only) after this amount
      of miliseconds. */
@@ -1574,7 +1602,7 @@ typedef enum {
   CINIT(SSL_OPTIONS, LONG, 216),
 
   /* Set the SMTP auth originator */
-  CINIT(MAIL_AUTH, OBJECTPOINT, 217),
+  CINIT(MAIL_AUTH, STRINGPOINT, 217),
 
   /* Enable/disable SASL initial response */
   CINIT(SASL_IR, LONG, 218),
@@ -1585,23 +1613,23 @@ typedef enum {
   CINIT(XFERINFOFUNCTION, FUNCTIONPOINT, 219),
 
   /* The XOAUTH2 bearer token */
-  CINIT(XOAUTH2_BEARER, OBJECTPOINT, 220),
+  CINIT(XOAUTH2_BEARER, STRINGPOINT, 220),
 
   /* Set the interface string to use as outgoing network
    * interface for DNS requests.
    * Only supported by the c-ares DNS backend */
-  CINIT(DNS_INTERFACE, OBJECTPOINT, 221),
+  CINIT(DNS_INTERFACE, STRINGPOINT, 221),
 
   /* Set the local IPv4 address to use for outgoing DNS requests.
    * Only supported by the c-ares DNS backend */
-  CINIT(DNS_LOCAL_IP4, OBJECTPOINT, 222),
+  CINIT(DNS_LOCAL_IP4, STRINGPOINT, 222),
 
   /* Set the local IPv4 address to use for outgoing DNS requests.
    * Only supported by the c-ares DNS backend */
-  CINIT(DNS_LOCAL_IP6, OBJECTPOINT, 223),
+  CINIT(DNS_LOCAL_IP6, STRINGPOINT, 223),
 
   /* Set authentication options directly */
-  CINIT(LOGIN_OPTIONS, OBJECTPOINT, 224),
+  CINIT(LOGIN_OPTIONS, STRINGPOINT, 224),
 
   /* Enable/disable TLS NPN extension (http2 over ssl might fail without) */
   CINIT(SSL_ENABLE_NPN, LONG, 225),
@@ -1622,10 +1650,10 @@ typedef enum {
 
   /* The public key in DER form used to validate the peer public key
      this option is used only if SSL_VERIFYPEER is true */
-  CINIT(PINNEDPUBLICKEY, OBJECTPOINT, 230),
+  CINIT(PINNEDPUBLICKEY, STRINGPOINT, 230),
 
   /* Path to Unix domain socket */
-  CINIT(UNIX_SOCKET_PATH, OBJECTPOINT, 231),
+  CINIT(UNIX_SOCKET_PATH, STRINGPOINT, 231),
 
   /* Set if we should verify the certificate status. */
   CINIT(SSL_VERIFYSTATUS, LONG, 232),
@@ -1637,14 +1665,36 @@ typedef enum {
   CINIT(PATH_AS_IS, LONG, 234),
 
   /* Proxy Service Name */
-  CINIT(PROXY_SERVICE_NAME, OBJECTPOINT, 235),
+  CINIT(PROXY_SERVICE_NAME, STRINGPOINT, 235),
 
   /* Service Name */
-  CINIT(SERVICE_NAME, OBJECTPOINT, 236),
+  CINIT(SERVICE_NAME, STRINGPOINT, 236),
 
   /* Wait/don't wait for pipe/mutex to clarify */
   CINIT(PIPEWAIT, LONG, 237),
 
+  /* Set the protocol used when curl is given a URL without a protocol */
+  CINIT(DEFAULT_PROTOCOL, STRINGPOINT, 238),
+
+  /* Set stream weight, 1 - 256 (default is 16) */
+  CINIT(STREAM_WEIGHT, LONG, 239),
+
+  /* Set stream dependency on another CURL handle */
+  CINIT(STREAM_DEPENDS, OBJECTPOINT, 240),
+
+  /* Set E-xclusive stream dependency on another CURL handle */
+  CINIT(STREAM_DEPENDS_E, OBJECTPOINT, 241),
+
+  /* Do not send any tftp option requests to the server */
+  CINIT(TFTP_NO_OPTIONS, LONG, 242),
+
+  /* Linked-list of host:port:connect-to-host:connect-to-port,
+     overrides the URL's host:port (only for the network layer) */
+  CINIT(CONNECT_TO, OBJECTPOINT, 243),
+
+  /* Set TCP Fast Open */
+  CINIT(TCP_FASTOPEN, LONG, 244),
+
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
 
@@ -1694,7 +1744,10 @@ enum {
                              for us! */
   CURL_HTTP_VERSION_1_0,  /* please use HTTP 1.0 in the request */
   CURL_HTTP_VERSION_1_1,  /* please use HTTP 1.1 in the request */
-  CURL_HTTP_VERSION_2_0,  /* please use HTTP 2.0 in the request */
+  CURL_HTTP_VERSION_2_0,  /* please use HTTP 2 in the request */
+  CURL_HTTP_VERSION_2TLS, /* use version 2 for HTTPS, version 1.1 for HTTP */
+  CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE,  /* please use HTTP 2 without HTTP/1.1
+                                           Upgrade */
 
   CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */
 };
@@ -1819,6 +1872,7 @@ typedef enum {
   CFINIT(OBSOLETE2),
 
   CFINIT(STREAM),
+  CFINIT(CONTENTLEN), /* added in 7.46.0, provide a curl_off_t length */
 
   CURLFORM_LASTENTRY /* the last unused */
 } CURLformoption;
@@ -2073,12 +2127,18 @@ typedef enum {
   CURLSSLBACKEND_CYASSL = 7,
   CURLSSLBACKEND_SCHANNEL = 8,
   CURLSSLBACKEND_DARWINSSL = 9,
-  CURLSSLBACKEND_AXTLS = 10
+  CURLSSLBACKEND_AXTLS = 10,
+  CURLSSLBACKEND_MBEDTLS = 11
 } curl_sslbackend;
 
+/* aliases for library clones and renames */
+#define CURLSSLBACKEND_LIBRESSL 1
+#define CURLSSLBACKEND_BORINGSSL 1
+#define CURLSSLBACKEND_WOLFSSL 6
+
 /* Information about the SSL library used and the respective internal SSL
    handle, which can be used to obtain further information regarding the
-   connection. Asked for with CURLINFO_TLS_SESSION. */
+   connection. Asked for with CURLINFO_TLS_SSL_PTR or CURLINFO_TLS_SESSION. */
 struct curl_tlssessioninfo {
   curl_sslbackend backend;
   void *internals;
@@ -2088,6 +2148,7 @@ struct curl_tlssessioninfo {
 #define CURLINFO_LONG     0x200000
 #define CURLINFO_DOUBLE   0x300000
 #define CURLINFO_SLIST    0x400000
+#define CURLINFO_SOCKET   0x500000
 #define CURLINFO_MASK     0x0fffff
 #define CURLINFO_TYPEMASK 0xf00000
 
@@ -2136,9 +2197,12 @@ typedef enum {
   CURLINFO_LOCAL_IP         = CURLINFO_STRING + 41,
   CURLINFO_LOCAL_PORT       = CURLINFO_LONG   + 42,
   CURLINFO_TLS_SESSION      = CURLINFO_SLIST  + 43,
+  CURLINFO_ACTIVESOCKET     = CURLINFO_SOCKET + 44,
+  CURLINFO_TLS_SSL_PTR      = CURLINFO_SLIST  + 45,
+  CURLINFO_HTTP_VERSION     = CURLINFO_LONG   + 46,
   /* Fill in new entries below here! */
 
-  CURLINFO_LASTONE          = 43
+  CURLINFO_LASTONE          = 46
 } CURLINFO;
 
 /* CURLINFO_RESPONSE_CODE is the new name for the option previously known as
@@ -2200,7 +2264,6 @@ typedef void (*curl_unlock_function)(CURL *handle,
                                      curl_lock_data data,
                                      void *userptr);
 
-typedef void CURLSH;
 
 typedef enum {
   CURLSHE_OK,  /* all is fine */
@@ -2298,6 +2361,8 @@ typedef struct {
 #define CURL_VERSION_GSSAPI       (1<<17) /* Built against a GSS-API library */
 #define CURL_VERSION_KERBEROS5    (1<<18) /* Kerberos V5 auth is supported */
 #define CURL_VERSION_UNIX_SOCKETS (1<<19) /* Unix domain sockets support */
+#define CURL_VERSION_PSL          (1<<20) /* Mozilla's Public Suffix List, used
+                                             for cookie domain verification */
 
  /*
  * NAME curl_version_info()
diff --git a/include/curl/curlbuild.h.cmake b/include/curl/curlbuild.h.cmake
index 60bc7a7..bbb31a9 100644
--- a/include/curl/curlbuild.h.cmake
+++ b/include/curl/curlbuild.h.cmake
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -35,7 +35,7 @@
  *
  * If you think that something actually needs to be changed, adjusted
  * or fixed in this file, then, report it on the libcurl development
- * mailing list: http://cool.haxx.se/mailman/listinfo/curl-library/
+ * mailing list: https://cool.haxx.se/mailman/listinfo/curl-library/
  *
  * This header file shall only export symbols which are 'curl' or 'CURL'
  * prefixed, otherwise public name space would be polluted.
diff --git a/include/curl/curlrules.h b/include/curl/curlrules.h
index 7c2ede3..55d21f6 100644
--- a/include/curl/curlrules.h
+++ b/include/curl/curlrules.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -47,7 +47,7 @@
  * library is properly built and used.
  *
  * You can find further help on the libcurl development mailing list:
- * http://cool.haxx.se/mailman/listinfo/curl-library/
+ * https://cool.haxx.se/mailman/listinfo/curl-library/
  *
  * NOTE 2
  * ------
diff --git a/include/curl/curlver.h b/include/curl/curlver.h
index f73d7de..81563f2 100644
--- a/include/curl/curlver.h
+++ b/include/curl/curlver.h
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -26,17 +26,17 @@
    a script at release-time. This was made its own header file in 7.11.2 */
 
 /* This is the global package copyright */
-#define LIBCURL_COPYRIGHT "1996 - 2015 Daniel Stenberg, <daniel at haxx.se>."
+#define LIBCURL_COPYRIGHT "1996 - 2016 Daniel Stenberg, <daniel at haxx.se>."
 
 /* This is the version number of the libcurl package from which this header
    file origins: */
-#define LIBCURL_VERSION "7.44.0-DEV"
+#define LIBCURL_VERSION "7.50.1-DEV"
 
 /* The numeric version number is also available "in parts" by using these
    defines: */
 #define LIBCURL_VERSION_MAJOR 7
-#define LIBCURL_VERSION_MINOR 44
-#define LIBCURL_VERSION_PATCH 0
+#define LIBCURL_VERSION_MINOR 50
+#define LIBCURL_VERSION_PATCH 1
 
 /* This is the numeric version of the libcurl version number, meant for easier
    parsing and comparions by programs. The LIBCURL_VERSION_NUM define will
@@ -57,7 +57,7 @@
    CURL_VERSION_BITS() macro since curl's own configure script greps for it
    and needs it to contain the full number.
 */
-#define LIBCURL_VERSION_NUM 0x072C00
+#define LIBCURL_VERSION_NUM 0x073201
 
 /*
  * This is the date and time when the full source package was created. The
diff --git a/include/curl/easy.h b/include/curl/easy.h
index c1e3e76..afc766c 100644
--- a/include/curl/easy.h
+++ b/include/curl/easy.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/include/curl/mprintf.h b/include/curl/mprintf.h
index c6b0d76..e20f546 100644
--- a/include/curl/mprintf.h
+++ b/include/curl/mprintf.h
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -24,8 +24,7 @@
 
 #include <stdarg.h>
 #include <stdio.h> /* needed for FILE */
-
-#include "curl.h"
+#include "curl.h"  /* for CURL_EXTERN */
 
 #ifdef  __cplusplus
 extern "C" {
@@ -44,29 +43,6 @@ CURL_EXTERN int curl_mvsnprintf(char *buffer, size_t maxlength,
 CURL_EXTERN char *curl_maprintf(const char *format, ...);
 CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args);
 
-#ifdef _MPRINTF_REPLACE
-# undef printf
-# undef fprintf
-# undef sprintf
-# undef vsprintf
-# undef snprintf
-# undef vprintf
-# undef vfprintf
-# undef vsnprintf
-# undef aprintf
-# undef vaprintf
-# define printf curl_mprintf
-# define fprintf curl_mfprintf
-# define sprintf curl_msprintf
-# define vsprintf curl_mvsprintf
-# define snprintf curl_msnprintf
-# define vprintf curl_mvprintf
-# define vfprintf curl_mvfprintf
-# define vsnprintf curl_mvsnprintf
-# define aprintf curl_maprintf
-# define vaprintf curl_mvaprintf
-#endif
-
 #ifdef  __cplusplus
 }
 #endif
diff --git a/include/curl/multi.h b/include/curl/multi.h
index 36e2e94..d1e00cc 100644
--- a/include/curl/multi.h
+++ b/include/curl/multi.h
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -52,7 +52,11 @@
 extern "C" {
 #endif
 
+#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER)
+typedef struct Curl_multi CURLM;
+#else
 typedef void CURLM;
+#endif
 
 typedef enum {
   CURLM_CALL_MULTI_PERFORM = -1, /* please call curl_multi_perform() or
diff --git a/include/curl/stdcheaders.h b/include/curl/stdcheaders.h
index ad82ef6..6f0f7f3 100644
--- a/include/curl/stdcheaders.h
+++ b/include/curl/stdcheaders.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/include/curl/typecheck-gcc.h b/include/curl/typecheck-gcc.h
index 13fb0fa..6ec8bcf 100644
--- a/include/curl/typecheck-gcc.h
+++ b/include/curl/typecheck-gcc.h
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -218,60 +218,67 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_slist,
 
 /* evaluates to true if option takes a char* argument */
 #define _curl_is_string_option(option)                                        \
-  ((option) == CURLOPT_URL ||                                                 \
-   (option) == CURLOPT_PROXY ||                                               \
-   (option) == CURLOPT_INTERFACE ||                                           \
-   (option) == CURLOPT_NETRC_FILE ||                                          \
-   (option) == CURLOPT_USERPWD ||                                             \
-   (option) == CURLOPT_USERNAME ||                                            \
-   (option) == CURLOPT_PASSWORD ||                                            \
-   (option) == CURLOPT_PROXYUSERPWD ||                                        \
-   (option) == CURLOPT_PROXYUSERNAME ||                                       \
-   (option) == CURLOPT_PROXYPASSWORD ||                                       \
-   (option) == CURLOPT_NOPROXY ||                                             \
-   (option) == CURLOPT_ACCEPT_ENCODING ||                                     \
-   (option) == CURLOPT_REFERER ||                                             \
-   (option) == CURLOPT_USERAGENT ||                                           \
+  ((option) == CURLOPT_ACCEPT_ENCODING ||                                     \
+   (option) == CURLOPT_CAINFO ||                                              \
+   (option) == CURLOPT_CAPATH ||                                              \
    (option) == CURLOPT_COOKIE ||                                              \
    (option) == CURLOPT_COOKIEFILE ||                                          \
    (option) == CURLOPT_COOKIEJAR ||                                           \
    (option) == CURLOPT_COOKIELIST ||                                          \
+   (option) == CURLOPT_CRLFILE ||                                             \
+   (option) == CURLOPT_CUSTOMREQUEST ||                                       \
+   (option) == CURLOPT_DEFAULT_PROTOCOL ||                                    \
+   (option) == CURLOPT_DNS_INTERFACE ||                                       \
+   (option) == CURLOPT_DNS_LOCAL_IP4 ||                                       \
+   (option) == CURLOPT_DNS_LOCAL_IP6 ||                                       \
+   (option) == CURLOPT_DNS_SERVERS ||                                         \
+   (option) == CURLOPT_EGDSOCKET ||                                           \
    (option) == CURLOPT_FTPPORT ||                                             \
-   (option) == CURLOPT_FTP_ALTERNATIVE_TO_USER ||                             \
    (option) == CURLOPT_FTP_ACCOUNT ||                                         \
-   (option) == CURLOPT_RANGE ||                                               \
-   (option) == CURLOPT_CUSTOMREQUEST ||                                       \
-   (option) == CURLOPT_SSLCERT ||                                             \
-   (option) == CURLOPT_SSLCERTTYPE ||                                         \
-   (option) == CURLOPT_SSLKEY ||                                              \
-   (option) == CURLOPT_SSLKEYTYPE ||                                          \
+   (option) == CURLOPT_FTP_ALTERNATIVE_TO_USER ||                             \
+   (option) == CURLOPT_INTERFACE ||                                           \
+   (option) == CURLOPT_ISSUERCERT ||                                          \
    (option) == CURLOPT_KEYPASSWD ||                                           \
-   (option) == CURLOPT_SSLENGINE ||                                           \
-   (option) == CURLOPT_CAINFO ||                                              \
-   (option) == CURLOPT_CAPATH ||                                              \
-   (option) == CURLOPT_RANDOM_FILE ||                                         \
-   (option) == CURLOPT_EGDSOCKET ||                                           \
-   (option) == CURLOPT_SSL_CIPHER_LIST ||                                     \
    (option) == CURLOPT_KRBLEVEL ||                                            \
-   (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 ||                             \
-   (option) == CURLOPT_SSH_PUBLIC_KEYFILE ||                                  \
-   (option) == CURLOPT_SSH_PRIVATE_KEYFILE ||                                 \
-   (option) == CURLOPT_CRLFILE ||                                             \
-   (option) == CURLOPT_ISSUERCERT ||                                          \
-   (option) == CURLOPT_SOCKS5_GSSAPI_SERVICE ||                               \
-   (option) == CURLOPT_SSH_KNOWNHOSTS ||                                      \
+   (option) == CURLOPT_LOGIN_OPTIONS ||                                       \
+   (option) == CURLOPT_MAIL_AUTH ||                                           \
    (option) == CURLOPT_MAIL_FROM ||                                           \
+   (option) == CURLOPT_NETRC_FILE ||                                          \
+   (option) == CURLOPT_NOPROXY ||                                             \
+   (option) == CURLOPT_PASSWORD ||                                            \
+   (option) == CURLOPT_PINNEDPUBLICKEY ||                                     \
+   (option) == CURLOPT_PROXY ||                                               \
+   (option) == CURLOPT_PROXYPASSWORD ||                                       \
+   (option) == CURLOPT_PROXYUSERNAME ||                                       \
+   (option) == CURLOPT_PROXYUSERPWD ||                                        \
+   (option) == CURLOPT_PROXY_SERVICE_NAME ||                                  \
+   (option) == CURLOPT_RANDOM_FILE ||                                         \
+   (option) == CURLOPT_RANGE ||                                               \
+   (option) == CURLOPT_REFERER ||                                             \
    (option) == CURLOPT_RTSP_SESSION_ID ||                                     \
    (option) == CURLOPT_RTSP_STREAM_URI ||                                     \
    (option) == CURLOPT_RTSP_TRANSPORT ||                                      \
-   (option) == CURLOPT_XOAUTH2_BEARER ||                                      \
-   (option) == CURLOPT_DNS_SERVERS ||                                         \
-   (option) == CURLOPT_DNS_INTERFACE ||                                       \
-   (option) == CURLOPT_DNS_LOCAL_IP4 ||                                       \
-   (option) == CURLOPT_DNS_LOCAL_IP6 ||                                       \
-   (option) == CURLOPT_LOGIN_OPTIONS ||                                       \
-   (option) == CURLOPT_PROXY_SERVICE_NAME ||                                  \
    (option) == CURLOPT_SERVICE_NAME ||                                        \
+   (option) == CURLOPT_SOCKS5_GSSAPI_SERVICE ||                               \
+   (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 ||                             \
+   (option) == CURLOPT_SSH_KNOWNHOSTS ||                                      \
+   (option) == CURLOPT_SSH_PRIVATE_KEYFILE ||                                 \
+   (option) == CURLOPT_SSH_PUBLIC_KEYFILE ||                                  \
+   (option) == CURLOPT_SSLCERT ||                                             \
+   (option) == CURLOPT_SSLCERTTYPE ||                                         \
+   (option) == CURLOPT_SSLENGINE ||                                           \
+   (option) == CURLOPT_SSLKEY ||                                              \
+   (option) == CURLOPT_SSLKEYTYPE ||                                          \
+   (option) == CURLOPT_SSL_CIPHER_LIST ||                                     \
+   (option) == CURLOPT_TLSAUTH_PASSWORD ||                                    \
+   (option) == CURLOPT_TLSAUTH_TYPE ||                                        \
+   (option) == CURLOPT_TLSAUTH_USERNAME ||                                    \
+   (option) == CURLOPT_UNIX_SOCKET_PATH ||                                    \
+   (option) == CURLOPT_URL ||                                                 \
+   (option) == CURLOPT_USERAGENT ||                                           \
+   (option) == CURLOPT_USERNAME ||                                            \
+   (option) == CURLOPT_USERPWD ||                                             \
+   (option) == CURLOPT_XOAUTH2_BEARER ||                                      \
    0)
 
 /* evaluates to true if option takes a curl_write_callback argument */
@@ -287,21 +294,22 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_slist,
 
 /* evaluates to true if option takes a data argument to pass to a callback */
 #define _curl_is_cb_data_option(option)                                       \
-  ((option) == CURLOPT_WRITEDATA ||                                           \
-   (option) == CURLOPT_READDATA ||                                            \
+  ((option) == CURLOPT_CHUNK_DATA ||                                          \
+   (option) == CURLOPT_CLOSESOCKETDATA ||                                     \
+   (option) == CURLOPT_DEBUGDATA ||                                           \
+   (option) == CURLOPT_FNMATCH_DATA ||                                        \
+   (option) == CURLOPT_HEADERDATA ||                                          \
+   (option) == CURLOPT_INTERLEAVEDATA ||                                      \
    (option) == CURLOPT_IOCTLDATA ||                                           \
-   (option) == CURLOPT_SOCKOPTDATA ||                                         \
    (option) == CURLOPT_OPENSOCKETDATA ||                                      \
+   (option) == CURLOPT_PRIVATE ||                                             \
    (option) == CURLOPT_PROGRESSDATA ||                                        \
-   (option) == CURLOPT_HEADERDATA ||                                         \
-   (option) == CURLOPT_DEBUGDATA ||                                           \
-   (option) == CURLOPT_SSL_CTX_DATA ||                                        \
+   (option) == CURLOPT_READDATA ||                                            \
    (option) == CURLOPT_SEEKDATA ||                                            \
-   (option) == CURLOPT_PRIVATE ||                                             \
+   (option) == CURLOPT_SOCKOPTDATA ||                                         \
    (option) == CURLOPT_SSH_KEYDATA ||                                         \
-   (option) == CURLOPT_INTERLEAVEDATA ||                                      \
-   (option) == CURLOPT_CHUNK_DATA ||                                          \
-   (option) == CURLOPT_FNMATCH_DATA ||                                        \
+   (option) == CURLOPT_SSL_CTX_DATA ||                                        \
+   (option) == CURLOPT_WRITEDATA ||                                           \
    0)
 
 /* evaluates to true if option takes a POST data argument (void* or char*) */
@@ -312,13 +320,15 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_slist,
 
 /* evaluates to true if option takes a struct curl_slist * argument */
 #define _curl_is_slist_option(option)                                         \
-  ((option) == CURLOPT_HTTPHEADER ||                                          \
-   (option) == CURLOPT_HTTP200ALIASES ||                                      \
-   (option) == CURLOPT_QUOTE ||                                               \
+  ((option) == CURLOPT_HTTP200ALIASES ||                                      \
+   (option) == CURLOPT_HTTPHEADER ||                                          \
+   (option) == CURLOPT_MAIL_RCPT ||                                           \
    (option) == CURLOPT_POSTQUOTE ||                                           \
    (option) == CURLOPT_PREQUOTE ||                                            \
+   (option) == CURLOPT_PROXYHEADER ||                                         \
+   (option) == CURLOPT_QUOTE ||                                               \
+   (option) == CURLOPT_RESOLVE ||                                             \
    (option) == CURLOPT_TELNETOPTIONS ||                                       \
-   (option) == CURLOPT_MAIL_RCPT ||                                           \
    0)
 
 /* groups of curl_easy_getinfo infos that take the same type of argument */
diff --git a/lib/Makefile.inc b/lib/Makefile.inc
index d444a6b..0ed998c 100644
--- a/lib/Makefile.inc
+++ b/lib/Makefile.inc
@@ -5,11 +5,11 @@
 #                            | (__| |_| |  _ <| |___
 #                             \___|\___/|_| \_\_____|
 #
-# Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+# Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
 #
 # This software is licensed as described in the file COPYING, which
 # you should have received as part of this distribution. The terms
-# are also available at http://curl.haxx.se/docs/copyright.html.
+# 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
@@ -20,13 +20,22 @@
 #
 ###########################################################################
 
+LIB_VAUTH_CFILES = 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 vauth/spnego_sspi.c
+
+LIB_VAUTH_HFILES = vauth/vauth.h vauth/digest.h vauth/ntlm.h
+
 LIB_VTLS_CFILES = vtls/openssl.c vtls/gtls.c vtls/vtls.c vtls/nss.c     \
   vtls/polarssl.c vtls/polarssl_threadlock.c vtls/axtls.c               \
-  vtls/cyassl.c vtls/schannel.c vtls/darwinssl.c vtls/gskit.c
+  vtls/cyassl.c vtls/schannel.c vtls/darwinssl.c vtls/gskit.c           \
+  vtls/mbedtls.c
 
 LIB_VTLS_HFILES = vtls/openssl.h vtls/vtls.h vtls/gtls.h                \
   vtls/nssg.h vtls/polarssl.h vtls/polarssl_threadlock.h vtls/axtls.h   \
-  vtls/cyassl.h vtls/schannel.h vtls/darwinssl.h vtls/gskit.h
+  vtls/cyassl.h vtls/schannel.h vtls/darwinssl.h vtls/gskit.h           \
+  vtls/mbedtls.h
 
 LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c   \
   cookie.c http.c sendf.c ftp.c url.c dict.c if2ip.c speedcheck.c       \
@@ -41,12 +50,10 @@ LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c   \
   curl_sspi.c slist.c nonblock.c curl_memrchr.c imap.c pop3.c smtp.c    \
   pingpong.c rtsp.c curl_threads.c warnless.c hmac.c curl_rtmp.c        \
   openldap.c curl_gethostname.c gopher.c idn_win32.c                    \
-  http_negotiate_sspi.c http_proxy.c non-ascii.c asyn-ares.c            \
-  asyn-thread.c curl_gssapi.c curl_ntlm.c curl_ntlm_wb.c                \
-  curl_ntlm_core.c curl_ntlm_msgs.c curl_sasl.c curl_multibyte.c        \
-  hostcheck.c conncache.c pipeline.c dotdot.c x509asn1.c                \
-  http2.c curl_sasl_sspi.c smb.c curl_sasl_gssapi.c curl_endian.c       \
-  curl_des.c
+  http_proxy.c non-ascii.c asyn-ares.c asyn-thread.c curl_gssapi.c      \
+  http_ntlm.c curl_ntlm_wb.c curl_ntlm_core.c curl_sasl.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
 
 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         \
@@ -61,13 +68,13 @@ LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \
   slist.h nonblock.h curl_memrchr.h imap.h pop3.h smtp.h pingpong.h     \
   rtsp.h curl_threads.h warnless.h curl_hmac.h curl_rtmp.h              \
   curl_gethostname.h gopher.h http_proxy.h non-ascii.h asyn.h           \
-  curl_ntlm.h curl_gssapi.h curl_ntlm_wb.h curl_ntlm_core.h             \
-  curl_ntlm_msgs.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
+  http_ntlm.h curl_gssapi.h curl_ntlm_wb.h curl_ntlm_core.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
 
 LIB_RCFILES = libcurl.rc
 
-CSOURCES = $(LIB_CFILES) $(LIB_VTLS_CFILES)
-HHEADERS = $(LIB_HFILES) $(LIB_VTLS_HFILES)
+CSOURCES = $(LIB_CFILES) $(LIB_VAUTH_CFILES) $(LIB_VTLS_CFILES)
+HHEADERS = $(LIB_HFILES) $(LIB_VAUTH_HFILES) $(LIB_VTLS_HFILES)
diff --git a/lib/amigaos.c b/lib/amigaos.c
index e3ff85f..5591d22 100644
--- a/lib/amigaos.c
+++ b/lib/amigaos.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -35,7 +35,7 @@ extern int errno, h_errno;
 #include <stabs.h>
 void __request(const char *msg);
 #else
-# define __request( msg )       Printf( msg "\n\a")
+# define __request(msg)       Printf(msg "\n\a")
 #endif
 
 void Curl_amiga_cleanup()
diff --git a/lib/amigaos.h b/lib/amigaos.h
index 76578be..02bee16 100644
--- a/lib/amigaos.h
+++ b/lib/amigaos.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/arpa_telnet.h b/lib/arpa_telnet.h
index 098d9a9..ec23872 100644
--- a/lib/arpa_telnet.h
+++ b/lib/arpa_telnet.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c
index 98ecdfd..2aed94f 100644
--- a/lib/asyn-ares.c
+++ b/lib/asyn-ares.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -68,7 +68,6 @@
 #include "connect.h"
 #include "select.h"
 #include "progress.h"
-#include "curl_printf.h"
 
 #  if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \
      (defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__))
@@ -83,8 +82,9 @@
 #define HAVE_CARES_CALLBACK_TIMEOUTS 1
 #endif
 
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
 #include "curl_memory.h"
-/* The last #include file should be: */
 #include "memdebug.h"
 
 struct ResolverResults {
@@ -249,7 +249,7 @@ int Curl_resolver_getsock(struct connectdata *conn,
 
 static int waitperform(struct connectdata *conn, int timeout_ms)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   int nfds;
   int bitmask;
   ares_socket_t socks[ARES_GETSOCK_MAXNUM];
@@ -309,7 +309,7 @@ static int waitperform(struct connectdata *conn, int timeout_ms)
 CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
                                    struct Curl_dns_entry **dns)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct ResolverResults *res = (struct ResolverResults *)
     conn->async.os_specific;
   CURLcode result = CURLE_OK;
@@ -353,7 +353,7 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
                                    struct Curl_dns_entry **entry)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   long timeout;
   struct timeval now = Curl_tvnow();
   struct Curl_dns_entry *temp_entry;
@@ -492,7 +492,7 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
                                          int *waitp)
 {
   char *bufp;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct in_addr in;
   int family = PF_INET;
 #ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
@@ -583,7 +583,7 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
   return NULL; /* no struct yet */
 }
 
-CURLcode Curl_set_dns_servers(struct SessionHandle *data,
+CURLcode Curl_set_dns_servers(struct Curl_easy *data,
                               char *servers)
 {
   CURLcode result = CURLE_NOT_BUILT_IN;
@@ -621,7 +621,7 @@ CURLcode Curl_set_dns_servers(struct SessionHandle *data,
   return result;
 }
 
-CURLcode Curl_set_dns_interface(struct SessionHandle *data,
+CURLcode Curl_set_dns_interface(struct Curl_easy *data,
                                 const char *interf)
 {
 #if (ARES_VERSION >= 0x010704)
@@ -638,7 +638,7 @@ CURLcode Curl_set_dns_interface(struct SessionHandle *data,
 #endif
 }
 
-CURLcode Curl_set_dns_local_ip4(struct SessionHandle *data,
+CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
                                 const char *local_ip4)
 {
 #if (ARES_VERSION >= 0x010704)
@@ -663,7 +663,7 @@ CURLcode Curl_set_dns_local_ip4(struct SessionHandle *data,
 #endif
 }
 
-CURLcode Curl_set_dns_local_ip6(struct SessionHandle *data,
+CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
                                 const char *local_ip6)
 {
 #if (ARES_VERSION >= 0x010704) && defined(ENABLE_IPV6)
diff --git a/lib/asyn-thread.c b/lib/asyn-thread.c
index bd47d5a..7cce01a 100644
--- a/lib/asyn-thread.c
+++ b/lib/asyn-thread.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -69,10 +69,9 @@
 #include "inet_ntop.h"
 #include "curl_threads.h"
 #include "connect.h"
+/* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_memory.h"
-
-/* The last #include file should be: */
 #include "memdebug.h"
 
 /***********************************************************************
@@ -280,6 +279,9 @@ static unsigned int CURL_STDCALL getaddrinfo_thread (void *arg)
     if(tsd->sock_error == 0)
       tsd->sock_error = RESOLVER_ENOMEM;
   }
+  else {
+    Curl_addrinfo_set_port(tsd->res, tsd->port);
+  }
 
   Curl_mutex_acquire(tsd->mtx);
   if(tsd->done) {
@@ -495,7 +497,7 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
 CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
                                    struct Curl_dns_entry **entry)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct thread_data   *td = (struct thread_data*) conn->async.os_specific;
   int done = 0;
 
@@ -603,6 +605,7 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
 
   *waitp = 0; /* default to synchronous response */
 
+#ifndef USE_RESOLVE_ON_IPS
   /* First check if this is an IPv4 address string */
   if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
     /* This is a dotted IP address 123.123.123.123-style */
@@ -610,10 +613,13 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
 
 #ifdef CURLRES_IPV6
   /* check if this is an IPv6 address string */
-  if(Curl_inet_pton (AF_INET6, hostname, &in6) > 0)
+  if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0)
     /* This is an IPv6 address literal */
     return Curl_ip2addr(AF_INET6, &in6, hostname, port);
+#endif /* CURLRES_IPV6 */
+#endif /* !USE_RESOLVE_ON_IPS */
 
+#ifdef CURLRES_IPV6
   /*
    * Check if a limited name resolve has been requested.
    */
@@ -632,7 +638,6 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
   if((pf != PF_INET) && !Curl_ipv6works())
     /* The stack seems to be a non-IPv6 one */
     pf = PF_INET;
-
 #endif /* CURLRES_IPV6 */
 
   memset(&hints, 0, sizeof(hints));
@@ -657,12 +662,16 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
           hostname, port, Curl_strerror(conn, SOCKERRNO));
     return NULL;
   }
+  else {
+    Curl_addrinfo_set_port(res, port);
+  }
+
   return res;
 }
 
 #endif /* !HAVE_GETADDRINFO */
 
-CURLcode Curl_set_dns_servers(struct SessionHandle *data,
+CURLcode Curl_set_dns_servers(struct Curl_easy *data,
                               char *servers)
 {
   (void)data;
@@ -671,7 +680,7 @@ CURLcode Curl_set_dns_servers(struct SessionHandle *data,
 
 }
 
-CURLcode Curl_set_dns_interface(struct SessionHandle *data,
+CURLcode Curl_set_dns_interface(struct Curl_easy *data,
                                 const char *interf)
 {
   (void)data;
@@ -679,7 +688,7 @@ CURLcode Curl_set_dns_interface(struct SessionHandle *data,
   return CURLE_NOT_BUILT_IN;
 }
 
-CURLcode Curl_set_dns_local_ip4(struct SessionHandle *data,
+CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
                                 const char *local_ip4)
 {
   (void)data;
@@ -687,7 +696,7 @@ CURLcode Curl_set_dns_local_ip4(struct SessionHandle *data,
   return CURLE_NOT_BUILT_IN;
 }
 
-CURLcode Curl_set_dns_local_ip6(struct SessionHandle *data,
+CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
                                 const char *local_ip6)
 {
   (void)data;
diff --git a/lib/asyn.h b/lib/asyn.h
index 1b681ea..3adc366 100644
--- a/lib/asyn.h
+++ b/lib/asyn.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -27,7 +27,7 @@
 
 struct addrinfo;
 struct hostent;
-struct SessionHandle;
+struct Curl_easy;
 struct connectdata;
 struct Curl_dns_entry;
 
diff --git a/lib/base64.c b/lib/base64.c
index 6b87eed..ad25459 100644
--- a/lib/base64.c
+++ b/lib/base64.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -23,13 +23,13 @@
 /* Base64 encoding/decoding */
 
 #include "curl_setup.h"
-#include "curl_printf.h"
-#include "urldata.h" /* for the SessionHandle definition */
+#include "urldata.h" /* for the Curl_easy definition */
 #include "warnless.h"
 #include "curl_base64.h"
 #include "non-ascii.h"
 
-/* The last #include files should be: */
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
 #include "curl_memory.h"
 #include "memdebug.h"
 
@@ -169,11 +169,11 @@ CURLcode Curl_base64_decode(const char *src,
 }
 
 static CURLcode base64_encode(const char *table64,
-                              struct SessionHandle *data,
+                              struct Curl_easy *data,
                               const char *inputbuff, size_t insize,
                               char **outptr, size_t *outlen)
 {
-  CURLcode error;
+  CURLcode result;
   unsigned char ibuf[3];
   unsigned char obuf[4];
   int i;
@@ -187,11 +187,11 @@ static CURLcode base64_encode(const char *table64,
   *outptr = NULL;
   *outlen = 0;
 
-  if(0 == insize)
+  if(!insize)
     insize = strlen(indata);
 
-  base64data = output = malloc(insize*4/3+4);
-  if(NULL == output)
+  base64data = output = malloc(insize * 4 / 3 + 4);
+  if(!output)
     return CURLE_OUT_OF_MEMORY;
 
   /*
@@ -199,10 +199,10 @@ static CURLcode base64_encode(const char *table64,
    * not the host encoding.  And we can't change the actual input
    * so we copy it to a buffer, translate it, and use that instead.
    */
-  error = Curl_convert_clone(data, indata, insize, &convbuf);
-  if(error) {
+  result = Curl_convert_clone(data, indata, insize, &convbuf);
+  if(result) {
     free(output);
-    return error;
+    return result;
   }
 
   if(convbuf)
@@ -233,28 +233,35 @@ static CURLcode base64_encode(const char *table64,
                table64[obuf[0]],
                table64[obuf[1]]);
       break;
+
     case 2: /* two bytes read */
       snprintf(output, 5, "%c%c%c=",
                table64[obuf[0]],
                table64[obuf[1]],
                table64[obuf[2]]);
       break;
+
     default:
       snprintf(output, 5, "%c%c%c%c",
                table64[obuf[0]],
                table64[obuf[1]],
                table64[obuf[2]],
-               table64[obuf[3]] );
+               table64[obuf[3]]);
       break;
     }
     output += 4;
   }
+
+  /* Zero terminate */
   *output = '\0';
-  *outptr = base64data; /* return pointer to new data, allocated memory */
+
+  /* Return the pointer to the new data (allocated memory) */
+  *outptr = base64data;
 
   free(convbuf);
 
-  *outlen = strlen(base64data); /* return the length of the new data */
+  /* Return the length of the new data */
+  *outlen = strlen(base64data);
 
   return CURLE_OK;
 }
@@ -276,7 +283,7 @@ static CURLcode base64_encode(const char *table64,
  *
  * @unittest: 1302
  */
-CURLcode Curl_base64_encode(struct SessionHandle *data,
+CURLcode Curl_base64_encode(struct Curl_easy *data,
                             const char *inputbuff, size_t insize,
                             char **outptr, size_t *outlen)
 {
@@ -300,10 +307,9 @@ CURLcode Curl_base64_encode(struct SessionHandle *data,
  *
  * @unittest: 1302
  */
-CURLcode Curl_base64url_encode(struct SessionHandle *data,
+CURLcode Curl_base64url_encode(struct Curl_easy *data,
                                const char *inputbuff, size_t insize,
                                char **outptr, size_t *outlen)
 {
   return base64_encode(base64url, data, inputbuff, insize, outptr, outlen);
 }
-/* ---- End of Base64 Encoding ---- */
diff --git a/lib/conncache.c b/lib/conncache.c
index c712ed7..32a7030 100644
--- a/lib/conncache.c
+++ b/lib/conncache.c
@@ -5,12 +5,12 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2012, Linus Nielsen Feltzing, <linus at haxx.se>
+ * Copyright (C) 2012, 2016, Linus Nielsen Feltzing, <linus at haxx.se>
  * Copyright (C) 2012 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -32,10 +32,9 @@
 #include "sendf.h"
 #include "rawstr.h"
 #include "conncache.h"
+/* The last 3 #include files should be in this order */
 #include "curl_printf.h"
-
 #include "curl_memory.h"
-/* The last #include file should be: */
 #include "memdebug.h"
 
 static void conn_llist_dtor(void *user, void *element)
@@ -46,7 +45,7 @@ static void conn_llist_dtor(void *user, void *element)
   data->bundle = NULL;
 }
 
-static CURLcode bundle_create(struct SessionHandle *data,
+static CURLcode bundle_create(struct Curl_easy *data,
                               struct connectbundle **cb_ptr)
 {
   (void)data;
@@ -132,9 +131,16 @@ void Curl_conncache_destroy(struct conncache *connc)
 /* returns an allocated key to find a bundle for this connection */
 static char *hashkey(struct connectdata *conn)
 {
-  return aprintf("%s:%d",
-                 conn->bits.proxy?conn->proxy.name:conn->host.name,
-                 conn->localport);
+  const char *hostname;
+
+  if(conn->bits.proxy)
+    hostname = conn->proxy.name;
+  else if(conn->bits.conn_to_host)
+    hostname = conn->conn_to_host.name;
+  else
+    hostname = conn->host.name;
+
+  return aprintf("%s:%d", hostname, conn->port);
 }
 
 /* Look up the bundle with all the connections to the same host this
@@ -193,7 +199,7 @@ CURLcode Curl_conncache_add_conn(struct conncache *connc,
   CURLcode result;
   struct connectbundle *bundle;
   struct connectbundle *new_bundle = NULL;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   bundle = Curl_conncache_find_bundle(conn, data->state.conn_cache);
   if(!bundle) {
diff --git a/lib/conncache.h b/lib/conncache.h
index 59181bf..b1dadf9 100644
--- a/lib/conncache.h
+++ b/lib/conncache.h
@@ -12,7 +12,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/connect.c b/lib/connect.c
index 18ac32c..0047f9a 100644
--- a/lib/connect.c
+++ b/lib/connect.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -56,7 +56,6 @@
 #include <inet.h>
 #endif
 
-#include "curl_printf.h"
 #include "urldata.h"
 #include "sendf.h"
 #include "if2ip.h"
@@ -73,8 +72,10 @@
 #include "warnless.h"
 #include "conncache.h"
 #include "multihandle.h"
+#include "system_win32.h"
 
-/* The last #include files should be: */
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
 #include "curl_memory.h"
 #include "memdebug.h"
 
@@ -103,7 +104,7 @@ struct tcp_keepalive {
 #endif
 
 static void
-tcpkeepalive(struct SessionHandle *data,
+tcpkeepalive(struct Curl_easy *data,
              curl_socket_t sockfd)
 {
   int optval = data->set.tcp_keepalive?1:0;
@@ -178,7 +179,7 @@ singleipconnect(struct connectdata *conn,
  *
  * @unittest: 1303
  */
-long Curl_timeleft(struct SessionHandle *data,
+long Curl_timeleft(struct Curl_easy *data,
                    struct timeval *nowp,
                    bool duringconnect)
 {
@@ -238,7 +239,7 @@ long Curl_timeleft(struct SessionHandle *data,
 static CURLcode bindlocal(struct connectdata *conn,
                           curl_socket_t sockfd, int af, unsigned int scope)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   struct Curl_sockaddr_storage sa;
   struct sockaddr *sock = (struct sockaddr *)&sa;  /* bind to this address */
@@ -619,7 +620,7 @@ static bool getaddressinfo(struct sockaddr* sa, char* addr,
 
   switch (sa->sa_family) {
     case AF_INET:
-      si = (struct sockaddr_in*) sa;
+      si = (struct sockaddr_in*)(void*) sa;
       if(Curl_inet_ntop(sa->sa_family, &si->sin_addr,
                         addr, MAX_IPADR_LEN)) {
         us_port = ntohs(si->sin_port);
@@ -629,7 +630,7 @@ static bool getaddressinfo(struct sockaddr* sa, char* addr,
       break;
 #ifdef ENABLE_IPV6
     case AF_INET6:
-      si6 = (struct sockaddr_in6*)sa;
+      si6 = (struct sockaddr_in6*)(void*) sa;
       if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr,
                         addr, MAX_IPADR_LEN)) {
         us_port = ntohs(si6->sin6_port);
@@ -662,13 +663,13 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
   curl_socklen_t len;
   struct Curl_sockaddr_storage ssrem;
   struct Curl_sockaddr_storage ssloc;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   if(conn->socktype == SOCK_DGRAM)
     /* there's no connection! */
     return;
 
-  if(!conn->bits.reuse) {
+  if(!conn->bits.reuse && !conn->bits.tcp_fastopen) {
     int error;
 
     len = sizeof(struct Curl_sockaddr_storage);
@@ -719,7 +720,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
                            int sockindex,
                            bool *connected)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   CURLcode result = CURLE_OK;
   long allow;
   int error = 0;
@@ -764,6 +765,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
     rc = Curl_socket_ready(CURL_SOCKET_BAD, conn->tempsock[i], 0);
 
     if(rc == 0) { /* no connection yet */
+      error = 0;
       if(curlx_tvdiff(now, conn->connecttime) >= conn->timeoutms_per_addr) {
         infof(data, "After %ldms connect time, move on!\n",
               conn->timeoutms_per_addr);
@@ -776,7 +778,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
         trynextip(conn, sockindex, 1);
       }
     }
-    else if(rc == CURL_CSELECT_OUT) {
+    else if(rc == CURL_CSELECT_OUT || conn->bits.tcp_fastopen) {
       if(verifyconnect(conn->tempsock[i], &error)) {
         /* we are connected with TCP, awesome! */
 
@@ -841,6 +843,8 @@ CURLcode Curl_is_connected(struct connectdata *conn,
   if(result) {
     /* no more addresses to try */
 
+    const char* hostname;
+
     /* if the first address family runs out of addresses to try before
        the happy eyeball timeout, go ahead and try the next family now */
     if(conn->tempaddr[1] == NULL) {
@@ -849,20 +853,27 @@ CURLcode Curl_is_connected(struct connectdata *conn,
         return result;
     }
 
+    if(conn->bits.proxy)
+      hostname = conn->proxy.name;
+    else if(conn->bits.conn_to_host)
+      hostname = conn->conn_to_host.name;
+    else
+      hostname = conn->host.name;
+
     failf(data, "Failed to connect to %s port %ld: %s",
-          conn->bits.proxy?conn->proxy.name:conn->host.name,
-          conn->port, Curl_strerror(conn, error));
+        hostname, conn->port, Curl_strerror(conn, error));
   }
 
   return result;
 }
 
-static void tcpnodelay(struct connectdata *conn,
-                       curl_socket_t sockfd)
+void Curl_tcpnodelay(struct connectdata *conn, curl_socket_t sockfd)
 {
-#ifdef TCP_NODELAY
-  struct SessionHandle *data= conn->data;
-  curl_socklen_t onoff = (curl_socklen_t) data->set.tcp_nodelay;
+#if defined(TCP_NODELAY)
+#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
+  struct Curl_easy *data = conn->data;
+#endif
+  curl_socklen_t onoff = (curl_socklen_t) 1;
   int level = IPPROTO_TCP;
 
 #if 0
@@ -878,6 +889,10 @@ static void tcpnodelay(struct connectdata *conn,
     level = pe->p_proto;
 #endif
 
+#if defined(CURL_DISABLE_VERBOSE_STRINGS)
+  (void) conn;
+#endif
+
   if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff,
                 sizeof(onoff)) < 0)
     infof(data, "Could not set TCP_NODELAY: %s\n",
@@ -898,7 +913,7 @@ static void tcpnodelay(struct connectdata *conn,
 static void nosigpipe(struct connectdata *conn,
                       curl_socket_t sockfd)
 {
-  struct SessionHandle *data= conn->data;
+  struct Curl_easy *data= conn->data;
   int onoff = 1;
   if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
                 sizeof(onoff)) < 0)
@@ -913,7 +928,7 @@ static void nosigpipe(struct connectdata *conn,
 /* When you run a program that uses the Windows Sockets API, you may
    experience slow performance when you copy data to a TCP server.
 
-   http://support.microsoft.com/kb/823764
+   https://support.microsoft.com/kb/823764
 
    Work-around: Make the Socket Send Buffer Size Larger Than the Program Send
    Buffer Size
@@ -931,43 +946,15 @@ void Curl_sndbufset(curl_socket_t sockfd)
   int val = CURL_MAX_WRITE_SIZE + 32;
   int curval = 0;
   int curlen = sizeof(curval);
-  DWORD majorVersion = 6;
 
   static int detectOsState = DETECT_OS_NONE;
 
   if(detectOsState == DETECT_OS_NONE) {
-#if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_WIN2K) || \
-    (_WIN32_WINNT < _WIN32_WINNT_WIN2K)
-    OSVERSIONINFO osver;
-
-    memset(&osver, 0, sizeof(osver));
-    osver.dwOSVersionInfoSize = sizeof(osver);
-
-    detectOsState = DETECT_OS_PREVISTA;
-    if(GetVersionEx(&osver)) {
-      if(osver.dwMajorVersion >= majorVersion)
-        detectOsState = DETECT_OS_VISTA_OR_LATER;
-    }
-#else
-    ULONGLONG cm;
-    OSVERSIONINFOEX osver;
-
-    memset(&osver, 0, sizeof(osver));
-    osver.dwOSVersionInfoSize = sizeof(osver);
-    osver.dwMajorVersion = majorVersion;
-
-    cm = VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL);
-    cm = VerSetConditionMask(cm, VER_MINORVERSION, VER_GREATER_EQUAL);
-    cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
-    cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL);
-
-    if(VerifyVersionInfo(&osver, (VER_MAJORVERSION | VER_MINORVERSION |
-                                  VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR),
-                         cm))
+    if(Curl_verify_windows_version(6, 0, PLATFORM_WINNT,
+                                   VERSION_GREATER_THAN_EQUAL))
       detectOsState = DETECT_OS_VISTA_OR_LATER;
     else
       detectOsState = DETECT_OS_PREVISTA;
-#endif
   }
 
   if(detectOsState == DETECT_OS_VISTA_OR_LATER)
@@ -995,10 +982,10 @@ static CURLcode singleipconnect(struct connectdata *conn,
                                 curl_socket_t *sockp)
 {
   struct Curl_sockaddr_ex addr;
-  int rc;
+  int rc = -1;
   int error = 0;
   bool isconnected = FALSE;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   curl_socket_t sockfd;
   CURLcode result;
   char ipaddress[MAX_IPADR_LEN];
@@ -1033,7 +1020,7 @@ static CURLcode singleipconnect(struct connectdata *conn,
   is_tcp = (addr.family == AF_INET) && addr.socktype == SOCK_STREAM;
 #endif
   if(is_tcp && data->set.tcp_nodelay)
-    tcpnodelay(conn, sockfd);
+    Curl_tcpnodelay(conn, sockfd);
 
   nosigpipe(conn, sockfd);
 
@@ -1084,7 +1071,29 @@ static CURLcode singleipconnect(struct connectdata *conn,
 
   /* Connect TCP sockets, bind UDP */
   if(!isconnected && (conn->socktype == SOCK_STREAM)) {
-    rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
+    if(conn->bits.tcp_fastopen) {
+#if defined(CONNECT_DATA_IDEMPOTENT) /* OS X */
+      sa_endpoints_t endpoints;
+      endpoints.sae_srcif = 0;
+      endpoints.sae_srcaddr = NULL;
+      endpoints.sae_srcaddrlen = 0;
+      endpoints.sae_dstaddr = &addr.sa_addr;
+      endpoints.sae_dstaddrlen = addr.addrlen;
+
+      rc = connectx(sockfd, &endpoints, SAE_ASSOCID_ANY,
+                    CONNECT_RESUME_ON_READ_WRITE | CONNECT_DATA_IDEMPOTENT,
+                    NULL, 0, NULL, NULL);
+#elif defined(MSG_FASTOPEN) /* Linux */
+      if(conn->given->flags & PROTOPT_SSL)
+        rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
+      else
+        rc = 0; /* Do nothing */
+#endif
+    }
+    else {
+      rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
+    }
+
     if(-1 == rc)
       error = SOCKERRNO;
   }
@@ -1140,7 +1149,7 @@ static CURLcode singleipconnect(struct connectdata *conn,
 CURLcode Curl_connecthost(struct connectdata *conn,  /* context */
                           const struct Curl_dns_entry *remotehost)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct timeval before = Curl_tvnow();
   CURLcode result = CURLE_COULDNT_CONNECT;
 
@@ -1199,11 +1208,11 @@ static int conn_is_conn(struct connectdata *conn, void *param)
 
 /*
  * Used to extract socket and connectdata struct for the most recent
- * transfer on the given SessionHandle.
+ * transfer on the given Curl_easy.
  *
  * The returned socket will be CURL_SOCKET_BAD in case of failure!
  */
-curl_socket_t Curl_getconnectinfo(struct SessionHandle *data,
+curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
                                   struct connectdata **connp)
 {
   curl_socket_t sockfd;
@@ -1243,10 +1252,10 @@ curl_socket_t Curl_getconnectinfo(struct SessionHandle *data,
     }
 /* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */
 #ifdef MSG_PEEK
-    else {
+    else if(sockfd != CURL_SOCKET_BAD) {
       /* use the socket */
       char buf;
-      if(recv((RECV_TYPE_ARG1)c->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf,
+      if(recv((RECV_TYPE_ARG1)sockfd, (RECV_TYPE_ARG2)&buf,
               (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK) == 0) {
         return CURL_SOCKET_BAD;   /* FIN received */
       }
@@ -1303,7 +1312,7 @@ CURLcode Curl_socket(struct connectdata *conn,
                      struct Curl_sockaddr_ex *addr,
                      curl_socket_t *sockfd)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct Curl_sockaddr_ex dummy;
 
   if(!addr)
diff --git a/lib/connect.h b/lib/connect.h
index 91646c7..6d60e0d 100644
--- a/lib/connect.h
+++ b/lib/connect.h
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -35,7 +35,7 @@ CURLcode Curl_connecthost(struct connectdata *conn,
 
 /* generic function that returns how much time there's left to run, according
    to the timeouts set */
-long Curl_timeleft(struct SessionHandle *data,
+long Curl_timeleft(struct Curl_easy *data,
                    struct timeval *nowp,
                    bool duringconnect);
 
@@ -45,18 +45,18 @@ long Curl_timeleft(struct SessionHandle *data,
 
 /*
  * Used to extract socket and connectdata struct for the most recent
- * transfer on the given SessionHandle.
+ * transfer on the given Curl_easy.
  *
  * The returned socket will be CURL_SOCKET_BAD in case of failure!
  */
-curl_socket_t Curl_getconnectinfo(struct SessionHandle *data,
+curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
                                   struct connectdata **connp);
 
 #ifdef USE_WINSOCK
 /* When you run a program that uses the Windows Sockets API, you may
    experience slow performance when you copy data to a TCP server.
 
-   http://support.microsoft.com/kb/823764
+   https://support.microsoft.com/kb/823764
 
    Work-around: Make the Socket Send Buffer Size Larger Than the Program Send
    Buffer Size
@@ -102,6 +102,8 @@ CURLcode Curl_socket(struct connectdata *conn,
                      struct Curl_sockaddr_ex *addr,
                      curl_socket_t *sockfd);
 
+void Curl_tcpnodelay(struct connectdata *conn, curl_socket_t sockfd);
+
 #ifdef CURLDEBUG
 /*
  * Curl_connclose() sets the bit.close bit to TRUE with an explanation.
diff --git a/lib/content_encoding.c b/lib/content_encoding.c
index c68e6e5..fa36aca 100644
--- a/lib/content_encoding.c
+++ b/lib/content_encoding.c
@@ -9,7 +9,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -67,7 +67,7 @@ zfree_cb(voidpf opaque, voidpf ptr)
 static CURLcode
 process_zlib_error(struct connectdata *conn, z_stream *z)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   if(z->msg)
     failf (data, "Error while processing content unencoding: %s",
            z->msg);
@@ -425,7 +425,7 @@ Curl_unencode_gzip_write(struct connectdata *conn,
 
 void Curl_unencode_cleanup(struct connectdata *conn)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct SingleRequest *k = &data->req;
   z_stream *z = &k->z;
   if(k->zlib_init != ZLIB_UNINIT)
diff --git a/lib/content_encoding.h b/lib/content_encoding.h
index 501f6c8..3fadd28 100644
--- a/lib/content_encoding.h
+++ b/lib/content_encoding.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/cookie.c b/lib/cookie.c
index 22730cf..d5a83fd 100644
--- a/lib/cookie.c
+++ b/lib/cookie.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -26,13 +26,13 @@
 RECEIVING COOKIE INFORMATION
 ============================
 
-struct CookieInfo *Curl_cookie_init(struct SessionHandle *data,
+struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
                     const char *file, struct CookieInfo *inc, bool newsession);
 
         Inits a cookie struct to store data in a local file. This is always
         called before any cookies are set.
 
-struct Cookie *Curl_cookie_add(struct SessionHandle *data,
+struct Cookie *Curl_cookie_add(struct Curl_easy *data,
                  struct CookieInfo *c, bool httpheader, char *lineptr,
                  const char *domain, const char *path);
 
@@ -84,7 +84,10 @@ Example set of cookies:
 
 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
 
-#include "curl_printf.h"
+#ifdef USE_LIBPSL
+# include <libpsl.h>
+#endif
+
 #include "urldata.h"
 #include "cookie.h"
 #include "strequal.h"
@@ -97,7 +100,8 @@ Example set of cookies:
 #include "curl_memrchr.h"
 #include "inet_pton.h"
 
-/* The last #include files should be: */
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
 #include "curl_memory.h"
 #include "memdebug.h"
 
@@ -256,7 +260,7 @@ static char *sanitize_cookie_path(const char *cookie_path)
  *
  * NOTE: OOM or cookie parsing failures are ignored.
  */
-void Curl_cookie_loadfiles(struct SessionHandle *data)
+void Curl_cookie_loadfiles(struct Curl_easy *data)
 {
   struct curl_slist *list = data->change.cookielist;
   if(list) {
@@ -305,7 +309,7 @@ static void remove_expired(struct CookieInfo *cookies)
   pv = NULL;
   while(co) {
     nx = co->next;
-    if((co->expirestr || co->maxage) && co->expires < now) {
+    if(co->expires && co->expires < now) {
       if(co == cookies->cookies) {
         cookies->cookies = co->next;
       }
@@ -358,7 +362,7 @@ static bool isip(const char *domain)
  ***************************************************************************/
 
 struct Cookie *
-Curl_cookie_add(struct SessionHandle *data,
+Curl_cookie_add(struct Curl_easy *data,
                 /* The 'data' pointer here may be NULL at times, and thus
                    must only be used very carefully for things that can deal
                    with data being NULL. Such as infof() and similar */
@@ -379,6 +383,10 @@ Curl_cookie_add(struct SessionHandle *data,
   bool replace_old = FALSE;
   bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */
 
+#ifdef USE_LIBPSL
+  const psl_ctx_t *psl;
+#endif
+
 #ifdef CURL_DISABLE_VERBOSE_STRINGS
   (void)data;
 #endif
@@ -409,7 +417,7 @@ Curl_cookie_add(struct SessionHandle *data,
     do {
       /* we have a <what>=<this> pair or a stand-alone word here */
       name[0]=what[0]=0; /* init the buffers */
-      if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;\r\n =] =%"
+      if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;\r\n=] =%"
                      MAX_COOKIE_LINE_TXT "[^;\r\n]",
                      name, what)) {
         /* Use strstore() below to properly deal with received cookie
@@ -419,15 +427,24 @@ Curl_cookie_add(struct SessionHandle *data,
         bool done = FALSE;
         bool sep;
         size_t len=strlen(what);
-        const char *endofn = &ptr[ strlen(name) ];
-
-        /* skip trailing spaces in name */
-        while(*endofn && ISBLANK(*endofn))
-          endofn++;
+        size_t nlen = strlen(name);
+        const char *endofn = &ptr[ nlen ];
 
         /* name ends with a '=' ? */
         sep = (*endofn == '=')?TRUE:FALSE;
 
+        if(nlen) {
+          endofn--; /* move to the last character */
+          if(ISBLANK(*endofn)) {
+            /* skip trailing spaces in name */
+            while(*endofn && ISBLANK(*endofn) && nlen) {
+              endofn--;
+              nlen--;
+            }
+            name[nlen]=0; /* new end of name */
+          }
+        }
+
         /* Strip off trailing whitespace from the 'what' */
         while(len && ISBLANK(what[len-1])) {
           what[len-1]=0;
@@ -439,7 +456,16 @@ Curl_cookie_add(struct SessionHandle *data,
         while(*whatptr && ISBLANK(*whatptr))
           whatptr++;
 
-        if(!len) {
+        if(!co->name && sep) {
+          /* The very first name/value pair is the actual cookie name */
+          co->name = strdup(name);
+          co->value = strdup(whatptr);
+          if(!co->name || !co->value) {
+            badcookie = TRUE;
+            break;
+          }
+        }
+        else if(!len) {
           /* this was a "<name>=" with no content, and we must allow
              'secure' and 'httponly' specified this weirdly */
           done = TRUE;
@@ -533,14 +559,6 @@ Curl_cookie_add(struct SessionHandle *data,
             break;
           }
         }
-        else if(!co->name) {
-          co->name = strdup(name);
-          co->value = strdup(whatptr);
-          if(!co->name || !co->value) {
-            badcookie = TRUE;
-            break;
-          }
-        }
         /*
           else this is the second (or more) name we don't know
           about! */
@@ -777,6 +795,21 @@ Curl_cookie_add(struct SessionHandle *data,
   /* at first, remove expired cookies */
   remove_expired(c);
 
+#ifdef USE_LIBPSL
+  /* Check if the domain is a Public Suffix and if yes, ignore the cookie.
+     This needs a libpsl compiled with builtin data. */
+  if(domain && co->domain && !isip(co->domain)) {
+    if(((psl = psl_builtin()) != NULL)
+        && !psl_is_cookie_domain_acceptable(psl, domain, co->domain)) {
+      infof(data,
+            "cookie '%s' dropped, domain '%s' must not set cookies for '%s'\n",
+            co->name, domain, co->domain);
+      freecookie(co);
+      return NULL;
+    }
+  }
+#endif
+
   clist = c->cookies;
   replace_old = FALSE;
   while(clist) {
@@ -880,7 +913,7 @@ Curl_cookie_add(struct SessionHandle *data,
  *
  * Returns NULL on out of memory. Invalid cookies are ignored.
  ****************************************************************************/
-struct CookieInfo *Curl_cookie_init(struct SessionHandle *data,
+struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
                                     const char *file,
                                     struct CookieInfo *inc,
                                     bool newsession)
@@ -1247,6 +1280,7 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere)
   struct Cookie *co;
   FILE *out;
   bool use_stdout=FALSE;
+  char *format_ptr;
 
   if((NULL == c) || (0 == c->numcookies))
     /* If there are no known cookies, we don't write or even create any
@@ -1267,27 +1301,23 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere)
       return 1; /* failure */
   }
 
-  if(c) {
-    char *format_ptr;
+  fputs("# Netscape HTTP Cookie File\n"
+        "# https://curl.haxx.se/docs/http-cookies.html\n"
+        "# This file was generated by libcurl! Edit at your own risk.\n\n",
+        out);
 
-    fputs("# Netscape HTTP Cookie File\n"
-          "# http://curl.haxx.se/docs/http-cookies.html\n"
-          "# This file was generated by libcurl! Edit at your own risk.\n\n",
-          out);
-
-    for(co = c->cookies; co; co = co->next) {
-      if(!co->domain)
-        continue;
-      format_ptr = get_netscape_format(co);
-      if(format_ptr == NULL) {
-        fprintf(out, "#\n# Fatal libcurl error\n");
-        if(!use_stdout)
-          fclose(out);
-        return 1;
-      }
-      fprintf(out, "%s\n", format_ptr);
-      free(format_ptr);
+  for(co = c->cookies; co; co = co->next) {
+    if(!co->domain)
+      continue;
+    format_ptr = get_netscape_format(co);
+    if(format_ptr == NULL) {
+      fprintf(out, "#\n# Fatal libcurl error\n");
+      if(!use_stdout)
+        fclose(out);
+      return 1;
     }
+    fprintf(out, "%s\n", format_ptr);
+    free(format_ptr);
   }
 
   if(!use_stdout)
@@ -1296,7 +1326,7 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere)
   return 0;
 }
 
-struct curl_slist *Curl_cookie_list(struct SessionHandle *data)
+struct curl_slist *Curl_cookie_list(struct Curl_easy *data)
 {
   struct curl_slist *list = NULL;
   struct curl_slist *beg;
@@ -1327,7 +1357,7 @@ struct curl_slist *Curl_cookie_list(struct SessionHandle *data)
   return list;
 }
 
-void Curl_flush_cookies(struct SessionHandle *data, int cleanup)
+void Curl_flush_cookies(struct Curl_easy *data, int cleanup)
 {
   if(data->set.str[STRING_COOKIEJAR]) {
     if(data->change.cookielist) {
diff --git a/lib/cookie.h b/lib/cookie.h
index bd89082..cd7c54a 100644
--- a/lib/cookie.h
+++ b/lib/cookie.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -70,13 +70,13 @@ struct CookieInfo {
 #define MAX_NAME 1024
 #define MAX_NAME_TXT "1023"
 
-struct SessionHandle;
+struct Curl_easy;
 /*
  * Add a cookie to the internal list of cookies. The domain and path arguments
  * are only used if the header boolean is TRUE.
  */
 
-struct Cookie *Curl_cookie_add(struct SessionHandle *data,
+struct Cookie *Curl_cookie_add(struct Curl_easy *data,
                                struct CookieInfo *, bool header, char *lineptr,
                                const char *domain, const char *path);
 
@@ -93,12 +93,12 @@ void Curl_cookie_clearsess(struct CookieInfo *cookies);
 #define Curl_cookie_cleanup(x) Curl_nop_stmt
 #define Curl_flush_cookies(x,y) Curl_nop_stmt
 #else
-void Curl_flush_cookies(struct SessionHandle *data, int cleanup);
+void Curl_flush_cookies(struct Curl_easy *data, int cleanup);
 void Curl_cookie_cleanup(struct CookieInfo *);
-struct CookieInfo *Curl_cookie_init(struct SessionHandle *data,
+struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
                                     const char *, struct CookieInfo *, bool);
-struct curl_slist *Curl_cookie_list(struct SessionHandle *data);
-void Curl_cookie_loadfiles(struct SessionHandle *data);
+struct curl_slist *Curl_cookie_list(struct Curl_easy *data);
+void Curl_cookie_loadfiles(struct Curl_easy *data);
 #endif
 
 #endif /* HEADER_CURL_COOKIE_H */
diff --git a/lib/curl_addrinfo.c b/lib/curl_addrinfo.c
index 6627a6b..35eb2dd 100644
--- a/lib/curl_addrinfo.c
+++ b/lib/curl_addrinfo.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -50,10 +50,9 @@
 #include "curl_addrinfo.h"
 #include "inet_pton.h"
 #include "warnless.h"
+/* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_memory.h"
-
-/* The last #include file should be: */
 #include "memdebug.h"
 
 /*
@@ -521,7 +520,11 @@ void
 curl_dofreeaddrinfo(struct addrinfo *freethis,
                     int line, const char *source)
 {
+#ifdef USE_LWIPSOCK
+  lwip_freeaddrinfo(freethis);
+#else
   (freeaddrinfo)(freethis);
+#endif
   curl_memlog("ADDR %s:%d freeaddrinfo(%p)\n",
               source, line, (void *)freethis);
 }
@@ -544,7 +547,11 @@ curl_dogetaddrinfo(const char *hostname,
                    struct addrinfo **result,
                    int line, const char *source)
 {
+#ifdef USE_LWIPSOCK
+  int res=lwip_getaddrinfo(hostname, service, hints, result);
+#else
   int res=(getaddrinfo)(hostname, service, hints, result);
+#endif
   if(0 == res)
     /* success */
     curl_memlog("ADDR %s:%d getaddrinfo() = %p\n",
@@ -556,3 +563,32 @@ curl_dogetaddrinfo(const char *hostname,
 }
 #endif /* defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) */
 
+#if defined(HAVE_GETADDRINFO) && defined(USE_RESOLVE_ON_IPS)
+/*
+ * Work-arounds the sin6_port is always zero bug on iOS 9.3.2 and Mac OS X
+ * 10.11.5.
+ */
+void Curl_addrinfo_set_port(Curl_addrinfo *addrinfo, int port)
+{
+  Curl_addrinfo *ca;
+  struct sockaddr_in *addr;
+#ifdef ENABLE_IPV6
+  struct sockaddr_in6 *addr6;
+#endif
+  for(ca = addrinfo; ca != NULL; ca = ca->ai_next) {
+    switch (ca->ai_family) {
+    case AF_INET:
+      addr = (void *)ca->ai_addr; /* storage area for this info */
+      addr->sin_port = htons((unsigned short)port);
+      break;
+
+#ifdef ENABLE_IPV6
+    case AF_INET6:
+      addr6 = (void *)ca->ai_addr; /* storage area for this info */
+      addr6->sin6_port = htons((unsigned short)port);
+      break;
+#endif
+    }
+  }
+}
+#endif
diff --git a/lib/curl_addrinfo.h b/lib/curl_addrinfo.h
index 4ef8827..1a681e6 100644
--- a/lib/curl_addrinfo.h
+++ b/lib/curl_addrinfo.h
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -83,7 +83,8 @@ Curl_addrinfo *Curl_str2addr(char *dotted, int port);
 Curl_addrinfo *Curl_unix2addr(const char *path);
 #endif
 
-#if defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO)
+#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) && \
+    defined(HAVE_FREEADDRINFO)
 void
 curl_dofreeaddrinfo(struct addrinfo *freethis,
                     int line, const char *source);
@@ -98,4 +99,12 @@ curl_dogetaddrinfo(const char *hostname,
                    int line, const char *source);
 #endif
 
+#ifdef HAVE_GETADDRINFO
+#ifdef USE_RESOLVE_ON_IPS
+void Curl_addrinfo_set_port(Curl_addrinfo *addrinfo, int port);
+#else
+#define Curl_addrinfo_set_port(x,y)
+#endif
+#endif
+
 #endif /* HEADER_CURL_ADDRINFO_H */
diff --git a/lib/curl_base64.h b/lib/curl_base64.h
index 92896fe..7e9fc26 100644
--- a/lib/curl_base64.h
+++ b/lib/curl_base64.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -22,10 +22,10 @@
  *
  ***************************************************************************/
 
-CURLcode Curl_base64_encode(struct SessionHandle *data,
+CURLcode Curl_base64_encode(struct Curl_easy *data,
                             const char *inputbuff, size_t insize,
                             char **outptr, size_t *outlen);
-CURLcode Curl_base64url_encode(struct SessionHandle *data,
+CURLcode Curl_base64url_encode(struct Curl_easy *data,
                                const char *inputbuff, size_t insize,
                                char **outptr, size_t *outlen);
 
diff --git a/lib/curl_config.h.cmake b/lib/curl_config.h.cmake
index 5376aa7..65a414b 100644
--- a/lib/curl_config.h.cmake
+++ b/lib/curl_config.h.cmake
@@ -24,6 +24,12 @@
 /* to disable FTP */
 #cmakedefine CURL_DISABLE_FTP 1
 
+/* to disable GOPHER */
+#cmakedefine CURL_DISABLE_GOPHER 1
+
+/* to disable IMAP */
+#cmakedefine CURL_DISABLE_IMAP 1
+
 /* to disable HTTP */
 #cmakedefine CURL_DISABLE_HTTP 1
 
@@ -33,9 +39,24 @@
 /* to disable LDAPS */
 #cmakedefine CURL_DISABLE_LDAPS 1
 
+/* to disable POP3 */
+#cmakedefine CURL_DISABLE_POP3 1
+
 /* to disable proxies */
 #cmakedefine CURL_DISABLE_PROXY 1
 
+/* to disable RTSP */
+#cmakedefine CURL_DISABLE_RTSP 1
+
+/* to disable RTMP */
+#cmakedefine CURL_DISABLE_RTMP 1
+
+/* to disable SMB */
+#cmakedefine CURL_DISABLE_SMB 1
+
+/* to disable SMTP */
+#cmakedefine CURL_DISABLE_SMTP 1
+
 /* to disable TELNET */
 #cmakedefine CURL_DISABLE_TELNET 1
 
@@ -894,6 +915,9 @@
 /* if PolarSSL is enabled */
 #cmakedefine USE_POLARSSL 1
 
+/* if mbedTLS is enabled */
+#cmakedefine USE_MBEDTLS 1
+
 /* if libSSH2 is in use */
 #cmakedefine USE_LIBSSH2 1
 
@@ -919,6 +943,9 @@
 /* to enable SSPI support */
 #cmakedefine USE_WINDOWS_SSPI 1
 
+/* to enable Windows SSL  */
+#cmakedefine USE_SCHANNEL 1
+
 /* Define to 1 if using yaSSL in OpenSSL compatibility mode. */
 #cmakedefine USE_YASSLEMUL 1
 
diff --git a/lib/curl_des.c b/lib/curl_des.c
index 42c1df9..421c9f7 100644
--- a/lib/curl_des.c
+++ b/lib/curl_des.c
@@ -9,7 +9,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -22,7 +22,7 @@
 
 #include "curl_setup.h"
 
-#if defined(USE_NTLM) && (!defined(USE_OPENSSL) || defined(HAVE_BORINGSSL))
+#if defined(USE_NTLM) && !defined(USE_OPENSSL)
 
 #include "curl_des.h"
 
@@ -60,4 +60,4 @@ void Curl_des_set_odd_parity(unsigned char *bytes, size_t len)
   }
 }
 
-#endif /* USE_NTLM && (!USE_OPENSSL || HAVE_BORINGSSL) */
+#endif /* USE_NTLM && !USE_OPENSSL */
diff --git a/lib/curl_des.h b/lib/curl_des.h
index b855db4..129060f 100644
--- a/lib/curl_des.h
+++ b/lib/curl_des.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -24,11 +24,11 @@
 
 #include "curl_setup.h"
 
-#if defined(USE_NTLM) && (!defined(USE_OPENSSL) || defined(HAVE_BORINGSSL))
+#if defined(USE_NTLM) && !defined(USE_OPENSSL)
 
 /* Applies odd parity to the given byte array */
 void Curl_des_set_odd_parity(unsigned char *bytes, size_t length);
 
-#endif /* USE_NTLM && (!USE_OPENSSL || HAVE_BORINGSSL) */
+#endif /* USE_NTLM && !USE_OPENSSL */
 
 #endif /* HEADER_CURL_DES_H */
diff --git a/lib/curl_endian.c b/lib/curl_endian.c
index bcd66ed..76deca6 100644
--- a/lib/curl_endian.c
+++ b/lib/curl_endian.c
@@ -9,7 +9,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/curl_endian.h b/lib/curl_endian.h
index e384279..df8398c 100644
--- a/lib/curl_endian.h
+++ b/lib/curl_endian.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/curl_fnmatch.c b/lib/curl_fnmatch.c
index 1e53918..e8108bb 100644
--- a/lib/curl_fnmatch.c
+++ b/lib/curl_fnmatch.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -22,6 +22,8 @@
 
 #include "curl_setup.h"
 
+#include <curl/curl.h>
+
 #include "curl_fnmatch.h"
 #include "curl_memory.h"
 
diff --git a/lib/curl_fnmatch.h b/lib/curl_fnmatch.h
index 6335d03..69ffe39 100644
--- a/lib/curl_fnmatch.h
+++ b/lib/curl_fnmatch.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/curl_gethostname.c b/lib/curl_gethostname.c
index ded1e6f..2591fd8 100644
--- a/lib/curl_gethostname.c
+++ b/lib/curl_gethostname.c
@@ -9,7 +9,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/curl_gethostname.h b/lib/curl_gethostname.h
index 48740f6..07517c5 100644
--- a/lib/curl_gethostname.h
+++ b/lib/curl_gethostname.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/curl_gssapi.c b/lib/curl_gssapi.c
index 9baece5..bf7c766 100644
--- a/lib/curl_gssapi.c
+++ b/lib/curl_gssapi.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2011 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 2011 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -33,7 +33,7 @@ static char krb5_oid_bytes[] = "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02";
 gss_OID_desc Curl_krb5_mech_oid = { 9, &krb5_oid_bytes };
 
 OM_uint32 Curl_gss_init_sec_context(
-    struct SessionHandle *data,
+    struct Curl_easy *data,
     OM_uint32 *minor_status,
     gss_ctx_id_t *context,
     gss_name_t target_name,
@@ -76,45 +76,56 @@ OM_uint32 Curl_gss_init_sec_context(
                               NULL /* time_rec */);
 }
 
-/*
- * Curl_gss_log_error()
- *
- * This is used to log a GSS-API error status.
- *
- * Parameters:
- *
- * data    [in] - The session handle.
- * status  [in] - The status code.
- * prefix  [in] - The prefix of the log message.
- */
-void Curl_gss_log_error(struct SessionHandle *data, OM_uint32 status,
-                        const char *prefix)
-{
+#define GSS_LOG_BUFFER_LEN 1024
+static size_t display_gss_error(OM_uint32 status, int type,
+                                char *buf, size_t len) {
   OM_uint32 maj_stat;
   OM_uint32 min_stat;
   OM_uint32 msg_ctx = 0;
   gss_buffer_desc status_string;
-  char buf[1024];
-  size_t len;
 
-  snprintf(buf, sizeof(buf), "%s", prefix);
-  len = strlen(buf);
   do {
     maj_stat = gss_display_status(&min_stat,
                                   status,
-                                  GSS_C_MECH_CODE,
+                                  type,
                                   GSS_C_NO_OID,
                                   &msg_ctx,
                                   &status_string);
-    if(sizeof(buf) > len + status_string.length + 1) {
-      snprintf(buf + len, sizeof(buf) - len,
-        ": %s", (char*)status_string.value);
-      len += status_string.length;
+    if(GSS_LOG_BUFFER_LEN > len + status_string.length + 3) {
+      len += snprintf(buf + len, GSS_LOG_BUFFER_LEN - len,
+                      "%.*s. ", (int)status_string.length,
+                      (char*)status_string.value);
     }
     gss_release_buffer(&min_stat, &status_string);
   } while(!GSS_ERROR(maj_stat) && msg_ctx != 0);
 
-  infof(data, "%s\n", buf);
+  return len;
+}
+
+/*
+ * Curl_gss_log_error()
+ *
+ * This is used to log a GSS-API error status.
+ *
+ * Parameters:
+ *
+ * data    [in] - The session handle.
+ * prefix  [in] - The prefix of the log message.
+ * major   [in] - The major status code.
+ * minor   [in] - The minor status code.
+ */
+void Curl_gss_log_error(struct Curl_easy *data, const char *prefix,
+                        OM_uint32 major, OM_uint32 minor)
+{
+  char buf[GSS_LOG_BUFFER_LEN];
+  size_t len = 0;
+
+  if(major != GSS_S_FAILURE)
+    len = display_gss_error(major, GSS_C_GSS_CODE, buf, len);
+
+  display_gss_error(minor, GSS_C_MECH_CODE, buf, len);
+
+  infof(data, "%s%s\n", prefix, buf);
 }
 
 #endif /* HAVE_GSSAPI */
diff --git a/lib/curl_gssapi.h b/lib/curl_gssapi.h
index 19aab64..9700a28 100644
--- a/lib/curl_gssapi.h
+++ b/lib/curl_gssapi.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -44,7 +44,7 @@ extern gss_OID_desc Curl_krb5_mech_oid;
 
 /* Common method for using GSS-API */
 OM_uint32 Curl_gss_init_sec_context(
-    struct SessionHandle *data,
+    struct Curl_easy *data,
     OM_uint32 *minor_status,
     gss_ctx_id_t *context,
     gss_name_t target_name,
@@ -56,8 +56,8 @@ OM_uint32 Curl_gss_init_sec_context(
     OM_uint32 *ret_flags);
 
 /* Helper to log a GSS-API error status */
-void Curl_gss_log_error(struct SessionHandle *data, OM_uint32 status,
-                        const char *prefix);
+void Curl_gss_log_error(struct Curl_easy *data, const char *prefix,
+                        OM_uint32 major, OM_uint32 minor);
 
 /* Provide some definitions missing in old headers */
 #ifdef HAVE_OLD_GSSMIT
diff --git a/lib/curl_hmac.h b/lib/curl_hmac.h
index 9b65c8c..41703b4 100644
--- a/lib/curl_hmac.h
+++ b/lib/curl_hmac.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/curl_ldap.h b/lib/curl_ldap.h
index 93fb4b0..27d0381 100644
--- a/lib/curl_ldap.h
+++ b/lib/curl_ldap.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/curl_md4.h b/lib/curl_md4.h
index 13c7903..8c26d12 100644
--- a/lib/curl_md4.h
+++ b/lib/curl_md4.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/curl_md5.h b/lib/curl_md5.h
index 9c0e0b5..5f70c96 100644
--- a/lib/curl_md5.h
+++ b/lib/curl_md5.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/curl_memory.h b/lib/curl_memory.h
index bc744cc..6f792ff 100644
--- a/lib/curl_memory.h
+++ b/lib/curl_memory.h
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -83,7 +83,20 @@
 
 #ifndef CURLX_NO_MEMORY_CALLBACKS
 
-#include <curl/curl.h> /* for the callback typedefs */
+#ifndef CURL_DID_MEMORY_FUNC_TYPEDEFS /* only if not already done */
+/*
+ * The following memory function replacement typedef's are COPIED from
+ * curl/curl.h and MUST match the originals. We copy them to avoid having to
+ * include curl/curl.h here. We avoid that include since it includes stdio.h
+ * and other headers that may get messed up with defines done here.
+ */
+typedef void *(*curl_malloc_callback)(size_t size);
+typedef void (*curl_free_callback)(void *ptr);
+typedef void *(*curl_realloc_callback)(void *ptr, size_t size);
+typedef char *(*curl_strdup_callback)(const char *str);
+typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size);
+#define CURL_DID_MEMORY_FUNC_TYPEDEFS
+#endif
 
 extern curl_malloc_callback Curl_cmalloc;
 extern curl_free_callback Curl_cfree;
diff --git a/lib/curl_memrchr.c b/lib/curl_memrchr.c
index 6722c6a..c521497 100644
--- a/lib/curl_memrchr.c
+++ b/lib/curl_memrchr.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -21,6 +21,9 @@
  ***************************************************************************/
 
 #include "curl_setup.h"
+
+#include <curl/curl.h>
+
 #include "curl_memrchr.h"
 #include "curl_memory.h"
 
diff --git a/lib/curl_memrchr.h b/lib/curl_memrchr.h
index 324c73a..747509c 100644
--- a/lib/curl_memrchr.h
+++ b/lib/curl_memrchr.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/curl_multibyte.c b/lib/curl_multibyte.c
index 403d005..e78bb50 100644
--- a/lib/curl_multibyte.c
+++ b/lib/curl_multibyte.c
@@ -9,7 +9,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -22,6 +22,8 @@
 
 #include "curl_setup.h"
 
+#include <curl/curl.h>
+
 #if defined(USE_WIN32_IDN) || ((defined(USE_WINDOWS_SSPI) || \
                                 defined(USE_WIN32_LDAP)) && defined(UNICODE))
 
diff --git a/lib/curl_multibyte.h b/lib/curl_multibyte.h
index dc7ed4c..615f5c0 100644
--- a/lib/curl_multibyte.h
+++ b/lib/curl_multibyte.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/curl_ntlm_core.c b/lib/curl_ntlm_core.c
index 2e5b573..f3fb013 100644
--- a/lib/curl_ntlm_core.c
+++ b/lib/curl_ntlm_core.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -28,7 +28,7 @@
  * NTLM details:
  *
  * http://davenport.sourceforge.net/ntlm.html
- * http://www.innovation.ch/java/ntlm.html
+ * https://www.innovation.ch/java/ntlm.html
  */
 
 #if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO)
@@ -107,9 +107,8 @@
 #include "warnless.h"
 #include "curl_endian.h"
 #include "curl_des.h"
+/* The last 3 #include files should be in this order */
 #include "curl_printf.h"
-
-/* The last #include files should be: */
 #include "curl_memory.h"
 #include "memdebug.h"
 
@@ -143,14 +142,10 @@ static void setup_des_key(const unsigned char *key_56,
   DES_cblock key;
 
   /* Expand the 56-bit key to 64-bits */
-  extend_key_56_to_64(key_56, (char *) key);
+  extend_key_56_to_64(key_56, (char *) &key);
 
   /* Set the key parity to odd */
-#if defined(HAVE_BORINGSSL)
-  Curl_des_set_odd_parity((unsigned char *) &key, sizeof(key));
-#else
   DES_set_odd_parity(&key);
-#endif
 
   /* Set the key */
   DES_set_key(&key, ks);
@@ -416,7 +411,7 @@ void Curl_ntlm_core_lm_resp(const unsigned char *keys,
 /*
  * Set up lanmanager hashed password
  */
-CURLcode Curl_ntlm_core_mk_lm_hash(struct SessionHandle *data,
+CURLcode Curl_ntlm_core_mk_lm_hash(struct Curl_easy *data,
                                    const char *password,
                                    unsigned char *lmbuffer /* 21 bytes */)
 {
@@ -510,7 +505,7 @@ static void ascii_uppercase_to_unicode_le(unsigned char *dest,
  * Set up nt hashed passwords
  * @unittest: 1600
  */
-CURLcode Curl_ntlm_core_mk_nt_hash(struct SessionHandle *data,
+CURLcode Curl_ntlm_core_mk_nt_hash(struct Curl_easy *data,
                                    const char *password,
                                    unsigned char *ntbuffer /* 21 bytes */)
 {
@@ -664,21 +659,22 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash,
   unsigned int len = 0;
   unsigned char *ptr = NULL;
   unsigned char hmac_output[NTLM_HMAC_MD5_LEN];
-#if defined(HAVE_LONGLONG)
-  long long tw;
-#else
-  __int64 tw;
-#endif
+  curl_off_t tw;
+
   CURLcode result = CURLE_OK;
 
+#if CURL_SIZEOF_CURL_OFF_T < 8
+#error "this section needs 64bit support to work"
+#endif
+
   /* Calculate the timestamp */
 #ifdef DEBUGBUILD
   char *force_timestamp = getenv("CURL_FORCETIME");
   if(force_timestamp)
-    tw = 11644473600ULL * 10000000ULL;
+    tw = CURL_OFF_T_C(11644473600) * 10000000;
   else
 #endif
-  tw = ((long long)time(NULL) + 11644473600ULL) * 10000000ULL;
+    tw = ((curl_off_t)time(NULL) + CURL_OFF_T_C(11644473600)) * 10000000;
 
   /* Calculate the response len */
   len = NTLM_HMAC_MD5_LEN + NTLMv2_BLOB_LEN;
diff --git a/lib/curl_ntlm_core.h b/lib/curl_ntlm_core.h
index 3a76359..c5f90e7 100644
--- a/lib/curl_ntlm_core.h
+++ b/lib/curl_ntlm_core.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -64,12 +64,12 @@ void Curl_ntlm_core_lm_resp(const unsigned char *keys,
                             const unsigned char *plaintext,
                             unsigned char *results);
 
-CURLcode Curl_ntlm_core_mk_lm_hash(struct SessionHandle *data,
+CURLcode Curl_ntlm_core_mk_lm_hash(struct Curl_easy *data,
                                    const char *password,
                                    unsigned char *lmbuffer /* 21 bytes */);
 
 #if USE_NTRESPONSES
-CURLcode Curl_ntlm_core_mk_nt_hash(struct SessionHandle *data,
+CURLcode Curl_ntlm_core_mk_nt_hash(struct Curl_easy *data,
                                    const char *password,
                                    unsigned char *ntbuffer /* 21 bytes */);
 
diff --git a/lib/curl_ntlm_wb.c b/lib/curl_ntlm_wb.c
index b2a5fb3..afdea16 100644
--- a/lib/curl_ntlm_wb.c
+++ b/lib/curl_ntlm_wb.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -29,7 +29,7 @@
  * NTLM details:
  *
  * http://davenport.sourceforge.net/ntlm.html
- * http://www.innovation.ch/java/ntlm.html
+ * https://www.innovation.ch/java/ntlm.html
  */
 
 #define DEBUG_ME 0
@@ -47,13 +47,12 @@
 #include "urldata.h"
 #include "sendf.h"
 #include "select.h"
-#include "curl_ntlm_msgs.h"
+#include "vauth/ntlm.h"
 #include "curl_ntlm_wb.h"
 #include "url.h"
 #include "strerror.h"
+/* The last 3 #include files should be in this order */
 #include "curl_printf.h"
-
-/* The last #include files should be: */
 #include "curl_memory.h"
 #include "memdebug.h"
 
@@ -373,8 +372,8 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn,
      * by delegating the NTLM challenge/response protocal to a helper
      * in ntlm_auth.
      * http://devel.squid-cache.org/ntlm/squid_helper_protocol.html
-     * http://www.samba.org/samba/docs/man/manpages-3/winbindd.8.html
-     * http://www.samba.org/samba/docs/man/manpages-3/ntlm_auth.1.html
+     * https://www.samba.org/samba/docs/man/manpages-3/winbindd.8.html
+     * https://www.samba.org/samba/docs/man/manpages-3/ntlm_auth.1.html
      * Preprocessor symbol 'NTLM_WB_ENABLED' is defined when this
      * feature is enabled and 'NTLM_WB_FILE' symbol holds absolute
      * filename of ntlm_auth helper.
diff --git a/lib/curl_ntlm_wb.h b/lib/curl_ntlm_wb.h
index 828bb57..aba3d46 100644
--- a/lib/curl_ntlm_wb.h
+++ b/lib/curl_ntlm_wb.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/curl_printf.h b/lib/curl_printf.h
index 086923f..49857cd 100644
--- a/lib/curl_printf.h
+++ b/lib/curl_printf.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/curl_rtmp.c b/lib/curl_rtmp.c
index 2938972..06dd047 100644
--- a/lib/curl_rtmp.c
+++ b/lib/curl_rtmp.c
@@ -10,7 +10,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -55,7 +55,7 @@ static Curl_recv rtmp_recv;
 static Curl_send rtmp_send;
 
 /*
- * RTMP protocol handler.h, based on http://rtmpdump.mplayerhq.hu
+ * RTMP protocol handler.h, based on https://rtmpdump.mplayerhq.hu
  */
 
 const struct Curl_handler Curl_handler_rtmp = {
diff --git a/lib/curl_rtmp.h b/lib/curl_rtmp.h
index 4a9e9e6..3306e22 100644
--- a/lib/curl_rtmp.h
+++ b/lib/curl_rtmp.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/curl_sasl.c b/lib/curl_sasl.c
index 68646bc..35e9fea 100644
--- a/lib/curl_sasl.c
+++ b/lib/curl_sasl.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2012 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 2012 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -24,6 +24,7 @@
  * RFC4422 Simple Authentication and Security Layer (SASL)
  * RFC4616 PLAIN authentication
  * RFC6749 OAuth 2.0 Authorization Framework
+ * RFC7628 A Set of SASL Mechanisms for OAuth
  * Draft   LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt>
  *
  ***************************************************************************/
@@ -35,6 +36,7 @@
 
 #include "curl_base64.h"
 #include "curl_md5.h"
+#include "vauth/vauth.h"
 #include "vtls/vtls.h"
 #include "curl_hmac.h"
 #include "curl_sasl.h"
@@ -44,9 +46,8 @@
 #include "rawstr.h"
 #include "sendf.h"
 #include "non-ascii.h" /* included for Curl_convert_... prototypes */
+/* The last 3 #include files should be in this order */
 #include "curl_printf.h"
-
-/* The last #include files should be: */
 #include "curl_memory.h"
 #include "memdebug.h"
 
@@ -56,1140 +57,18 @@ const struct {
   size_t        len;   /* Name length */
   unsigned int  bit;   /* Flag bit */
 } mechtable[] = {
-  { "LOGIN",      5,  SASL_MECH_LOGIN },
-  { "PLAIN",      5,  SASL_MECH_PLAIN },
-  { "CRAM-MD5",   8,  SASL_MECH_CRAM_MD5 },
-  { "DIGEST-MD5", 10, SASL_MECH_DIGEST_MD5 },
-  { "GSSAPI",     6,  SASL_MECH_GSSAPI },
-  { "EXTERNAL",   8,  SASL_MECH_EXTERNAL },
-  { "NTLM",       4,  SASL_MECH_NTLM },
-  { "XOAUTH2",    7,  SASL_MECH_XOAUTH2 },
-  { ZERO_NULL,    0,  0 }
+  { "LOGIN",        5,  SASL_MECH_LOGIN },
+  { "PLAIN",        5,  SASL_MECH_PLAIN },
+  { "CRAM-MD5",     8,  SASL_MECH_CRAM_MD5 },
+  { "DIGEST-MD5",   10, SASL_MECH_DIGEST_MD5 },
+  { "GSSAPI",       6,  SASL_MECH_GSSAPI },
+  { "EXTERNAL",     8,  SASL_MECH_EXTERNAL },
+  { "NTLM",         4,  SASL_MECH_NTLM },
+  { "XOAUTH2",      7,  SASL_MECH_XOAUTH2 },
+  { "OAUTHBEARER",  11, SASL_MECH_OAUTHBEARER },
+  { ZERO_NULL,      0,  0 }
 };
 
-#if !defined(CURL_DISABLE_CRYPTO_AUTH) && !defined(USE_WINDOWS_SSPI)
-#define DIGEST_QOP_VALUE_AUTH             (1 << 0)
-#define DIGEST_QOP_VALUE_AUTH_INT         (1 << 1)
-#define DIGEST_QOP_VALUE_AUTH_CONF        (1 << 2)
-
-#define DIGEST_QOP_VALUE_STRING_AUTH      "auth"
-#define DIGEST_QOP_VALUE_STRING_AUTH_INT  "auth-int"
-#define DIGEST_QOP_VALUE_STRING_AUTH_CONF "auth-conf"
-
-/* The CURL_OUTPUT_DIGEST_CONV macro below is for non-ASCII machines.
-   It converts digest text to ASCII so the MD5 will be correct for
-   what ultimately goes over the network.
-*/
-#define CURL_OUTPUT_DIGEST_CONV(a, b) \
-  result = Curl_convert_to_network(a, (char *)b, strlen((const char*)b)); \
-  if(result) { \
-    free(b); \
-    return result; \
-  }
-
-#endif
-
-#if !defined(CURL_DISABLE_CRYPTO_AUTH)
-/*
- * Returns 0 on success and then the buffers are filled in fine.
- *
- * Non-zero means failure to parse.
- */
-int Curl_sasl_digest_get_pair(const char *str, char *value, char *content,
-                              const char **endptr)
-{
-  int c;
-  bool starts_with_quote = FALSE;
-  bool escape = FALSE;
-
-  for(c = DIGEST_MAX_VALUE_LENGTH - 1; (*str && (*str != '=') && c--); )
-    *value++ = *str++;
-  *value = 0;
-
-  if('=' != *str++)
-    /* eek, no match */
-    return 1;
-
-  if('\"' == *str) {
-    /* this starts with a quote so it must end with one as well! */
-    str++;
-    starts_with_quote = TRUE;
-  }
-
-  for(c = DIGEST_MAX_CONTENT_LENGTH - 1; *str && c--; str++) {
-    switch(*str) {
-    case '\\':
-      if(!escape) {
-        /* possibly the start of an escaped quote */
-        escape = TRUE;
-        *content++ = '\\'; /* even though this is an escape character, we still
-                              store it as-is in the target buffer */
-        continue;
-      }
-      break;
-    case ',':
-      if(!starts_with_quote) {
-        /* this signals the end of the content if we didn't get a starting
-           quote and then we do "sloppy" parsing */
-        c = 0; /* the end */
-        continue;
-      }
-      break;
-    case '\r':
-    case '\n':
-      /* end of string */
-      c = 0;
-      continue;
-    case '\"':
-      if(!escape && starts_with_quote) {
-        /* end of string */
-        c = 0;
-        continue;
-      }
-      break;
-    }
-    escape = FALSE;
-    *content++ = *str;
-  }
-  *content = 0;
-
-  *endptr = str;
-
-  return 0; /* all is fine! */
-}
-#endif
-
-#if !defined(CURL_DISABLE_CRYPTO_AUTH) && !defined(USE_WINDOWS_SSPI)
-/* Convert md5 chunk to RFC2617 (section 3.1.3) -suitable ascii string*/
-static void sasl_digest_md5_to_ascii(unsigned char *source, /* 16 bytes */
-                                     unsigned char *dest) /* 33 bytes */
-{
-  int i;
-  for(i = 0; i < 16; i++)
-    snprintf((char *)&dest[i*2], 3, "%02x", source[i]);
-}
-
-/* Perform quoted-string escaping as described in RFC2616 and its errata */
-static char *sasl_digest_string_quoted(const char *source)
-{
-  char *dest, *d;
-  const char *s = source;
-  size_t n = 1; /* null terminator */
-
-  /* Calculate size needed */
-  while(*s) {
-    ++n;
-    if(*s == '"' || *s == '\\') {
-      ++n;
-    }
-    ++s;
-  }
-
-  dest = malloc(n);
-  if(dest) {
-    s = source;
-    d = dest;
-    while(*s) {
-      if(*s == '"' || *s == '\\') {
-        *d++ = '\\';
-      }
-      *d++ = *s++;
-    }
-    *d = 0;
-  }
-
-  return dest;
-}
-
-/* Retrieves the value for a corresponding key from the challenge string
- * returns TRUE if the key could be found, FALSE if it does not exists
- */
-static bool sasl_digest_get_key_value(const char *chlg,
-                                      const char *key,
-                                      char *value,
-                                      size_t max_val_len,
-                                      char end_char)
-{
-  char *find_pos;
-  size_t i;
-
-  find_pos = strstr(chlg, key);
-  if(!find_pos)
-    return FALSE;
-
-  find_pos += strlen(key);
-
-  for(i = 0; *find_pos && *find_pos != end_char && i < max_val_len - 1; ++i)
-    value[i] = *find_pos++;
-  value[i] = '\0';
-
-  return TRUE;
-}
-
-static CURLcode sasl_digest_get_qop_values(const char *options, int *value)
-{
-  char *tmp;
-  char *token;
-  char *tok_buf;
-
-  /* Initialise the output */
-  *value = 0;
-
-  /* Tokenise the list of qop values. Use a temporary clone of the buffer since
-     strtok_r() ruins it. */
-  tmp = strdup(options);
-  if(!tmp)
-    return CURLE_OUT_OF_MEMORY;
-
-  token = strtok_r(tmp, ",", &tok_buf);
-  while(token != NULL) {
-    if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH))
-      *value |= DIGEST_QOP_VALUE_AUTH;
-    else if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH_INT))
-      *value |= DIGEST_QOP_VALUE_AUTH_INT;
-    else if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH_CONF))
-      *value |= DIGEST_QOP_VALUE_AUTH_CONF;
-
-    token = strtok_r(NULL, ",", &tok_buf);
-  }
-
-  free(tmp);
-
-  return CURLE_OK;
-}
-#endif /* !CURL_DISABLE_CRYPTO_AUTH && !USE_WINDOWS_SSPI */
-
-#if !defined(USE_WINDOWS_SSPI)
-/*
- * Curl_sasl_build_spn()
- *
- * This is used to build a SPN string in the format service/host.
- *
- * Parameters:
- *
- * service  [in] - The service type such as www, smtp, pop or imap.
- * host     [in] - The host name or realm.
- *
- * Returns a pointer to the newly allocated SPN.
- */
-char *Curl_sasl_build_spn(const char *service, const char *host)
-{
-  /* Generate and return our SPN */
-  return aprintf("%s/%s", service, host);
-}
-#endif
-
-/*
- * sasl_create_plain_message()
- *
- * This is used to generate an already encoded PLAIN message ready
- * for sending to the recipient.
- *
- * Parameters:
- *
- * data    [in]     - The session handle.
- * userp   [in]     - The user name.
- * passdwp [in]     - The user's password.
- * 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.
- */
-static CURLcode sasl_create_plain_message(struct SessionHandle *data,
-                                          const char *userp,
-                                          const char *passwdp,
-                                          char **outptr, size_t *outlen)
-{
-  CURLcode result;
-  char *plainauth;
-  size_t ulen;
-  size_t plen;
-
-  ulen = strlen(userp);
-  plen = strlen(passwdp);
-
-  plainauth = malloc(2 * ulen + plen + 2);
-  if(!plainauth) {
-    *outlen = 0;
-    *outptr = NULL;
-    return CURLE_OUT_OF_MEMORY;
-  }
-
-  /* Calculate the reply */
-  memcpy(plainauth, userp, ulen);
-  plainauth[ulen] = '\0';
-  memcpy(plainauth + ulen + 1, userp, ulen);
-  plainauth[2 * ulen + 1] = '\0';
-  memcpy(plainauth + 2 * ulen + 2, passwdp, plen);
-
-  /* Base64 encode the reply */
-  result = Curl_base64_encode(data, plainauth, 2 * ulen + plen + 2, outptr,
-                              outlen);
-  free(plainauth);
-  return result;
-}
-
-/*
- * sasl_create_login_message()
- *
- * This is used to generate an already encoded LOGIN message containing the
- * user name or password ready for sending to the recipient.
- *
- * Parameters:
- *
- * data    [in]     - The session handle.
- * valuep  [in]     - The user name or user's password.
- * 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.
- */
-static CURLcode sasl_create_login_message(struct SessionHandle *data,
-                                          const char *valuep, char **outptr,
-                                          size_t *outlen)
-{
-  size_t vlen = strlen(valuep);
-
-  if(!vlen) {
-    /* Calculate an empty reply */
-    *outptr = strdup("=");
-    if(*outptr) {
-      *outlen = (size_t) 1;
-      return CURLE_OK;
-    }
-
-    *outlen = 0;
-    return CURLE_OUT_OF_MEMORY;
-  }
-
-  /* Base64 encode the value */
-  return Curl_base64_encode(data, valuep, vlen, outptr, outlen);
-}
-
-/*
- * sasl_create_external_message()
- *
- * This is used to generate an already encoded EXTERNAL message containing
- * the user name ready for sending to the recipient.
- *
- * Parameters:
- *
- * data    [in]     - The session handle.
- * user    [in]     - The user name.
- * 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.
- */
-static CURLcode sasl_create_external_message(struct SessionHandle *data,
-                                             const char *user, char **outptr,
-                                             size_t *outlen)
-{
-  /* This is the same formatting as the login message. */
-  return sasl_create_login_message(data, user, outptr, outlen);
-}
-
-#ifndef CURL_DISABLE_CRYPTO_AUTH
- /*
- * sasl_decode_cram_md5_message()
- *
- * This is used to decode an already encoded CRAM-MD5 challenge message.
- *
- * Parameters:
- *
- * chlg64  [in]     - The base64 encoded challenge message.
- * 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.
- */
-static CURLcode sasl_decode_cram_md5_message(const char *chlg64, char **outptr,
-                                             size_t *outlen)
-{
-  CURLcode result = CURLE_OK;
-  size_t chlg64len = strlen(chlg64);
-
-  *outptr = NULL;
-  *outlen = 0;
-
-  /* Decode the challenge if necessary */
-  if(chlg64len && *chlg64 != '=')
-    result = Curl_base64_decode(chlg64, (unsigned char **) outptr, outlen);
-
-    return result;
- }
-
- /*
- * sasl_create_cram_md5_message()
- *
- * This is used to generate an already encoded CRAM-MD5 response message ready
- * for sending to the recipient.
- *
- * Parameters:
- *
- * data    [in]     - The session handle.
- * chlg    [in]     - The challenge.
- * userp   [in]     - The user name.
- * passdwp [in]     - The user's password.
- * 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.
- */
-static CURLcode sasl_create_cram_md5_message(struct SessionHandle *data,
-                                             const char *chlg,
-                                             const char *userp,
-                                             const char *passwdp,
-                                             char **outptr, size_t *outlen)
-{
-  CURLcode result = CURLE_OK;
-  size_t chlglen = 0;
-  HMAC_context *ctxt;
-  unsigned char digest[MD5_DIGEST_LEN];
-  char *response;
-
-  if(chlg)
-    chlglen = strlen(chlg);
-
-  /* Compute the digest using the password as the key */
-  ctxt = Curl_HMAC_init(Curl_HMAC_MD5,
-                        (const unsigned char *) passwdp,
-                        curlx_uztoui(strlen(passwdp)));
-  if(!ctxt)
-    return CURLE_OUT_OF_MEMORY;
-
-  /* Update the digest with the given challenge */
-  if(chlglen > 0)
-    Curl_HMAC_update(ctxt, (const unsigned char *) chlg,
-                     curlx_uztoui(chlglen));
-
-  /* Finalise the digest */
-  Curl_HMAC_final(ctxt, digest);
-
-  /* Generate the response */
-  response = aprintf(
-      "%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
-           userp, digest[0], digest[1], digest[2], digest[3], digest[4],
-           digest[5], digest[6], digest[7], digest[8], digest[9], digest[10],
-           digest[11], digest[12], digest[13], digest[14], digest[15]);
-  if(!response)
-    return CURLE_OUT_OF_MEMORY;
-
-  /* Base64 encode the response */
-  result = Curl_base64_encode(data, response, 0, outptr, outlen);
-
-  free(response);
-
-  return result;
-}
-
-#ifndef USE_WINDOWS_SSPI
-/*
- * sasl_decode_digest_md5_message()
- *
- * This is used internally to decode an already encoded DIGEST-MD5 challenge
- * message into the seperate attributes.
- *
- * Parameters:
- *
- * chlg64  [in]     - The base64 encoded challenge message.
- * nonce   [in/out] - The buffer where the nonce will be stored.
- * nlen    [in]     - The length of the nonce buffer.
- * realm   [in/out] - The buffer where the realm will be stored.
- * rlen    [in]     - The length of the realm buffer.
- * alg     [in/out] - The buffer where the algorithm will be stored.
- * alen    [in]     - The length of the algorithm buffer.
- * qop     [in/out] - The buffer where the qop-options will be stored.
- * qlen    [in]     - The length of the qop buffer.
- *
- * Returns CURLE_OK on success.
- */
-static CURLcode sasl_decode_digest_md5_message(const char *chlg64,
-                                               char *nonce, size_t nlen,
-                                               char *realm, size_t rlen,
-                                               char *alg, size_t alen,
-                                               char *qop, size_t qlen)
-{
-  CURLcode result = CURLE_OK;
-  unsigned char *chlg = NULL;
-  size_t chlglen = 0;
-  size_t chlg64len = strlen(chlg64);
-
-  /* Decode the base-64 encoded challenge message */
-  if(chlg64len && *chlg64 != '=') {
-    result = Curl_base64_decode(chlg64, &chlg, &chlglen);
-    if(result)
-      return result;
-  }
-
-  /* Ensure we have a valid challenge message */
-  if(!chlg)
-    return CURLE_BAD_CONTENT_ENCODING;
-
-  /* Retrieve nonce string from the challenge */
-  if(!sasl_digest_get_key_value((char *)chlg, "nonce=\"", nonce, nlen, '\"')) {
-    free(chlg);
-    return CURLE_BAD_CONTENT_ENCODING;
-  }
-
-  /* Retrieve realm string from the challenge */
-  if(!sasl_digest_get_key_value((char *)chlg, "realm=\"", realm, rlen, '\"')) {
-    /* Challenge does not have a realm, set empty string [RFC2831] page 6 */
-    strcpy(realm, "");
-  }
-
-  /* Retrieve algorithm string from the challenge */
-  if(!sasl_digest_get_key_value((char *)chlg, "algorithm=", alg, alen, ',')) {
-    free(chlg);
-    return CURLE_BAD_CONTENT_ENCODING;
-  }
-
-  /* Retrieve qop-options string from the challenge */
-  if(!sasl_digest_get_key_value((char *)chlg, "qop=\"", qop, qlen, '\"')) {
-    free(chlg);
-    return CURLE_BAD_CONTENT_ENCODING;
-  }
-
-  free(chlg);
-
-  return CURLE_OK;
-}
-
-/*
- * Curl_sasl_create_digest_md5_message()
- *
- * This is used to generate an already encoded DIGEST-MD5 response message
- * ready for sending to the recipient.
- *
- * Parameters:
- *
- * data    [in]     - The session handle.
- * chlg64  [in]     - The base64 encoded challenge message.
- * userp   [in]     - The user name.
- * passdwp [in]     - The user's password.
- * service [in]     - The service type such as www, smtp, pop or imap.
- * 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_sasl_create_digest_md5_message(struct SessionHandle *data,
-                                             const char *chlg64,
-                                             const char *userp,
-                                             const char *passwdp,
-                                             const char *service,
-                                             char **outptr, size_t *outlen)
-{
-  CURLcode result = CURLE_OK;
-  size_t i;
-  MD5_context *ctxt;
-  char *response = NULL;
-  unsigned char digest[MD5_DIGEST_LEN];
-  char HA1_hex[2 * MD5_DIGEST_LEN + 1];
-  char HA2_hex[2 * MD5_DIGEST_LEN + 1];
-  char resp_hash_hex[2 * MD5_DIGEST_LEN + 1];
-  char nonce[64];
-  char realm[128];
-  char algorithm[64];
-  char qop_options[64];
-  int qop_values;
-  char cnonce[33];
-  unsigned int entropy[4];
-  char nonceCount[] = "00000001";
-  char method[]     = "AUTHENTICATE";
-  char qop[]        = DIGEST_QOP_VALUE_STRING_AUTH;
-  char *spn         = NULL;
-
-  /* Decode the challange message */
-  result = sasl_decode_digest_md5_message(chlg64, nonce, sizeof(nonce),
-                                          realm, sizeof(realm),
-                                          algorithm, sizeof(algorithm),
-                                          qop_options, sizeof(qop_options));
-  if(result)
-    return result;
-
-  /* We only support md5 sessions */
-  if(strcmp(algorithm, "md5-sess") != 0)
-    return CURLE_BAD_CONTENT_ENCODING;
-
-  /* Get the qop-values from the qop-options */
-  result = sasl_digest_get_qop_values(qop_options, &qop_values);
-  if(result)
-    return result;
-
-  /* We only support auth quality-of-protection */
-  if(!(qop_values & DIGEST_QOP_VALUE_AUTH))
-    return CURLE_BAD_CONTENT_ENCODING;
-
-  /* Generate 16 bytes of random data */
-  entropy[0] = Curl_rand(data);
-  entropy[1] = Curl_rand(data);
-  entropy[2] = Curl_rand(data);
-  entropy[3] = Curl_rand(data);
-
-  /* Convert the random data into a 32 byte hex string */
-  snprintf(cnonce, sizeof(cnonce), "%08x%08x%08x%08x",
-           entropy[0], entropy[1], entropy[2], entropy[3]);
-
-  /* So far so good, now calculate A1 and H(A1) according to RFC 2831 */
-  ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
-  if(!ctxt)
-    return CURLE_OUT_OF_MEMORY;
-
-  Curl_MD5_update(ctxt, (const unsigned char *) userp,
-                  curlx_uztoui(strlen(userp)));
-  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
-  Curl_MD5_update(ctxt, (const unsigned char *) realm,
-                  curlx_uztoui(strlen(realm)));
-  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
-  Curl_MD5_update(ctxt, (const unsigned char *) passwdp,
-                  curlx_uztoui(strlen(passwdp)));
-  Curl_MD5_final(ctxt, digest);
-
-  ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
-  if(!ctxt)
-    return CURLE_OUT_OF_MEMORY;
-
-  Curl_MD5_update(ctxt, (const unsigned char *) digest, MD5_DIGEST_LEN);
-  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
-  Curl_MD5_update(ctxt, (const unsigned char *) nonce,
-                  curlx_uztoui(strlen(nonce)));
-  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
-  Curl_MD5_update(ctxt, (const unsigned char *) cnonce,
-                  curlx_uztoui(strlen(cnonce)));
-  Curl_MD5_final(ctxt, digest);
-
-  /* Convert calculated 16 octet hex into 32 bytes string */
-  for(i = 0; i < MD5_DIGEST_LEN; i++)
-    snprintf(&HA1_hex[2 * i], 3, "%02x", digest[i]);
-
-  /* Generate our SPN */
-  spn = Curl_sasl_build_spn(service, realm);
-  if(!spn)
-    return CURLE_OUT_OF_MEMORY;
-
-  /* Calculate H(A2) */
-  ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
-  if(!ctxt) {
-    free(spn);
-
-    return CURLE_OUT_OF_MEMORY;
-  }
-
-  Curl_MD5_update(ctxt, (const unsigned char *) method,
-                  curlx_uztoui(strlen(method)));
-  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
-  Curl_MD5_update(ctxt, (const unsigned char *) spn,
-                  curlx_uztoui(strlen(spn)));
-  Curl_MD5_final(ctxt, digest);
-
-  for(i = 0; i < MD5_DIGEST_LEN; i++)
-    snprintf(&HA2_hex[2 * i], 3, "%02x", digest[i]);
-
-  /* Now calculate the response hash */
-  ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
-  if(!ctxt) {
-    free(spn);
-
-    return CURLE_OUT_OF_MEMORY;
-  }
-
-  Curl_MD5_update(ctxt, (const unsigned char *) HA1_hex, 2 * MD5_DIGEST_LEN);
-  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
-  Curl_MD5_update(ctxt, (const unsigned char *) nonce,
-                  curlx_uztoui(strlen(nonce)));
-  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
-
-  Curl_MD5_update(ctxt, (const unsigned char *) nonceCount,
-                  curlx_uztoui(strlen(nonceCount)));
-  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
-  Curl_MD5_update(ctxt, (const unsigned char *) cnonce,
-                  curlx_uztoui(strlen(cnonce)));
-  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
-  Curl_MD5_update(ctxt, (const unsigned char *) qop,
-                  curlx_uztoui(strlen(qop)));
-  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
-
-  Curl_MD5_update(ctxt, (const unsigned char *) HA2_hex, 2 * MD5_DIGEST_LEN);
-  Curl_MD5_final(ctxt, digest);
-
-  for(i = 0; i < MD5_DIGEST_LEN; i++)
-    snprintf(&resp_hash_hex[2 * i], 3, "%02x", digest[i]);
-
-  /* Generate the response */
-  response = aprintf("username=\"%s\",realm=\"%s\",nonce=\"%s\","
-                     "cnonce=\"%s\",nc=\"%s\",digest-uri=\"%s\",response=%s,"
-                     "qop=%s",
-                     userp, realm, nonce,
-                     cnonce, nonceCount, spn, resp_hash_hex, qop);
-  free(spn);
-  if(!response)
-    return CURLE_OUT_OF_MEMORY;
-
-  /* Base64 encode the response */
-  result = Curl_base64_encode(data, response, 0, outptr, outlen);
-
-  free(response);
-
-  return result;
-}
-
-/*
- * Curl_sasl_decode_digest_http_message()
- *
- * This is used to decode a HTTP DIGEST challenge message into the seperate
- * attributes.
- *
- * Parameters:
- *
- * chlg    [in]     - The challenge message.
- * digest  [in/out] - The digest data struct being used and modified.
- *
- * Returns CURLE_OK on success.
- */
-CURLcode Curl_sasl_decode_digest_http_message(const char *chlg,
-                                              struct digestdata *digest)
-{
-  bool before = FALSE; /* got a nonce before */
-  bool foundAuth = FALSE;
-  bool foundAuthInt = FALSE;
-  char *token = NULL;
-  char *tmp = NULL;
-
-  /* If we already have received a nonce, keep that in mind */
-  if(digest->nonce)
-    before = TRUE;
-
-  /* Clean up any former leftovers and initialise to defaults */
-  Curl_sasl_digest_cleanup(digest);
-
-  for(;;) {
-    char value[DIGEST_MAX_VALUE_LENGTH];
-    char content[DIGEST_MAX_CONTENT_LENGTH];
-
-    /* Pass all additional spaces here */
-    while(*chlg && ISSPACE(*chlg))
-      chlg++;
-
-    /* Extract a value=content pair */
-    if(!Curl_sasl_digest_get_pair(chlg, value, content, &chlg)) {
-      if(Curl_raw_equal(value, "nonce")) {
-        digest->nonce = strdup(content);
-        if(!digest->nonce)
-          return CURLE_OUT_OF_MEMORY;
-      }
-      else if(Curl_raw_equal(value, "stale")) {
-        if(Curl_raw_equal(content, "true")) {
-          digest->stale = TRUE;
-          digest->nc = 1; /* we make a new nonce now */
-        }
-      }
-      else if(Curl_raw_equal(value, "realm")) {
-        digest->realm = strdup(content);
-        if(!digest->realm)
-          return CURLE_OUT_OF_MEMORY;
-      }
-      else if(Curl_raw_equal(value, "opaque")) {
-        digest->opaque = strdup(content);
-        if(!digest->opaque)
-          return CURLE_OUT_OF_MEMORY;
-      }
-      else if(Curl_raw_equal(value, "qop")) {
-        char *tok_buf;
-        /* Tokenize the list and choose auth if possible, use a temporary
-            clone of the buffer since strtok_r() ruins it */
-        tmp = strdup(content);
-        if(!tmp)
-          return CURLE_OUT_OF_MEMORY;
-
-        token = strtok_r(tmp, ",", &tok_buf);
-        while(token != NULL) {
-          if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH)) {
-            foundAuth = TRUE;
-          }
-          else if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) {
-            foundAuthInt = TRUE;
-          }
-          token = strtok_r(NULL, ",", &tok_buf);
-        }
-
-        free(tmp);
-
-        /* Select only auth or auth-int. Otherwise, ignore */
-        if(foundAuth) {
-          digest->qop = strdup(DIGEST_QOP_VALUE_STRING_AUTH);
-          if(!digest->qop)
-            return CURLE_OUT_OF_MEMORY;
-        }
-        else if(foundAuthInt) {
-          digest->qop = strdup(DIGEST_QOP_VALUE_STRING_AUTH_INT);
-          if(!digest->qop)
-            return CURLE_OUT_OF_MEMORY;
-        }
-      }
-      else if(Curl_raw_equal(value, "algorithm")) {
-        digest->algorithm = strdup(content);
-        if(!digest->algorithm)
-          return CURLE_OUT_OF_MEMORY;
-
-        if(Curl_raw_equal(content, "MD5-sess"))
-          digest->algo = CURLDIGESTALGO_MD5SESS;
-        else if(Curl_raw_equal(content, "MD5"))
-          digest->algo = CURLDIGESTALGO_MD5;
-        else
-          return CURLE_BAD_CONTENT_ENCODING;
-      }
-      else {
-        /* unknown specifier, ignore it! */
-      }
-    }
-    else
-      break; /* we're done here */
-
-    /* Pass all additional spaces here */
-    while(*chlg && ISSPACE(*chlg))
-      chlg++;
-
-    /* Allow the list to be comma-separated */
-    if(',' == *chlg)
-      chlg++;
-  }
-
-  /* We had a nonce since before, and we got another one now without
-     'stale=true'. This means we provided bad credentials in the previous
-     request */
-  if(before && !digest->stale)
-    return CURLE_BAD_CONTENT_ENCODING;
-
-  /* We got this header without a nonce, that's a bad Digest line! */
-  if(!digest->nonce)
-    return CURLE_BAD_CONTENT_ENCODING;
-
-  return CURLE_OK;
-}
-
-/*
- * Curl_sasl_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_sasl_create_digest_http_message(struct SessionHandle *data,
-                                              const char *userp,
-                                              const char *passwdp,
-                                              const unsigned char *request,
-                                              const unsigned char *uripath,
-                                              struct digestdata *digest,
-                                              char **outptr, size_t *outlen)
-{
-  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 */
-  char cnoncebuf[33];
-  char *cnonce = NULL;
-  size_t cnonce_sz = 0;
-  char *userp_quoted;
-  char *response = NULL;
-  char *tmp = NULL;
-
-  if(!digest->nc)
-    digest->nc = 1;
-
-  if(!digest->cnonce) {
-    snprintf(cnoncebuf, sizeof(cnoncebuf), "%08x%08x%08x%08x",
-             Curl_rand(data), Curl_rand(data),
-             Curl_rand(data), Curl_rand(data));
-
-    result = Curl_base64_encode(data, cnoncebuf, strlen(cnoncebuf),
-                                &cnonce, &cnonce_sz);
-    if(result)
-      return result;
-
-    digest->cnonce = cnonce;
-  }
-
-  /*
-    if the algorithm is "MD5" or unspecified (which then defaults to MD5):
-
-    A1 = unq(username-value) ":" unq(realm-value) ":" passwd
-
-    if the algorithm is "MD5-sess" then:
-
-    A1 = H( unq(username-value) ":" unq(realm-value) ":" passwd )
-         ":" unq(nonce-value) ":" unq(cnonce-value)
-  */
-
-  md5this = (unsigned char *)
-    aprintf("%s:%s:%s", userp, digest->realm, passwdp);
-  if(!md5this)
-    return CURLE_OUT_OF_MEMORY;
-
-  CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */
-  Curl_md5it(md5buf, md5this);
-  free(md5this);
-  sasl_digest_md5_to_ascii(md5buf, ha1);
-
-  if(digest->algo == CURLDIGESTALGO_MD5SESS) {
-    /* 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);
-    free(tmp);
-    sasl_digest_md5_to_ascii(md5buf, ha1);
-  }
-
-  /*
-    If the "qop" directive's value is "auth" or is unspecified, then A2 is:
-
-      A2       = Method ":" digest-uri-value
-
-          If the "qop" value is "auth-int", then A2 is:
-
-      A2       = Method ":" digest-uri-value ":" H(entity-body)
-
-    (The "Method" value is the HTTP request method as specified in section
-    5.1.1 of RFC 2616)
-  */
-
-  md5this = (unsigned char *)aprintf("%s:%s", request, uripath);
-
-  if(digest->qop && Curl_raw_equal(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;
-  }
-
-  if(!md5this)
-    return CURLE_OUT_OF_MEMORY;
-
-  CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */
-  Curl_md5it(md5buf, md5this);
-  free(md5this);
-  sasl_digest_md5_to_ascii(md5buf, ha2);
-
-  if(digest->qop) {
-    md5this = (unsigned char *)aprintf("%s:%s:%08x:%s:%s:%s",
-                                       ha1,
-                                       digest->nonce,
-                                       digest->nc,
-                                       digest->cnonce,
-                                       digest->qop,
-                                       ha2);
-  }
-  else {
-    md5this = (unsigned char *)aprintf("%s:%s:%s",
-                                       ha1,
-                                       digest->nonce,
-                                       ha2);
-  }
-
-  if(!md5this)
-    return CURLE_OUT_OF_MEMORY;
-
-  CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */
-  Curl_md5it(md5buf, md5this);
-  free(md5this);
-  sasl_digest_md5_to_ascii(md5buf, request_digest);
-
-  /* for test case 64 (snooped from a Mozilla 1.3a request)
-
-    Authorization: Digest username="testuser", realm="testrealm", \
-    nonce="1053604145", uri="/64", response="c55f7f30d83d774a3d2dcacf725abaca"
-
-    Digest parameters are all quoted strings.  Username which is provided by
-    the user will need double quotes and backslashes within it escaped.  For
-    the other fields, this shouldn't be an issue.  realm, nonce, and opaque
-    are copied as is from the server, escapes and all.  cnonce is generated
-    with web-safe characters.  uri is already percent encoded.  nc is 8 hex
-    characters.  algorithm and qop with standard values only contain web-safe
-    chracters.
-  */
-  userp_quoted = sasl_digest_string_quoted(userp);
-  if(!userp_quoted)
-    return CURLE_OUT_OF_MEMORY;
-
-  if(digest->qop) {
-    response = aprintf("username=\"%s\", "
-                       "realm=\"%s\", "
-                       "nonce=\"%s\", "
-                       "uri=\"%s\", "
-                       "cnonce=\"%s\", "
-                       "nc=%08x, "
-                       "qop=%s, "
-                       "response=\"%s\"",
-                       userp_quoted,
-                       digest->realm,
-                       digest->nonce,
-                       uripath,
-                       digest->cnonce,
-                       digest->nc,
-                       digest->qop,
-                       request_digest);
-
-    if(Curl_raw_equal(digest->qop, "auth"))
-      digest->nc++; /* The nc (from RFC) has to be a 8 hex digit number 0
-                       padded which tells to the server how many times you are
-                       using the same nonce in the qop=auth mode */
-  }
-  else {
-    response = aprintf("username=\"%s\", "
-                       "realm=\"%s\", "
-                       "nonce=\"%s\", "
-                       "uri=\"%s\", "
-                       "response=\"%s\"",
-                       userp_quoted,
-                       digest->realm,
-                       digest->nonce,
-                       uripath,
-                       request_digest);
-  }
-  free(userp_quoted);
-  if(!response)
-    return CURLE_OUT_OF_MEMORY;
-
-  /* Add the optional fields */
-  if(digest->opaque) {
-    /* Append the opaque */
-    tmp = aprintf("%s, opaque=\"%s\"", response, digest->opaque);
-    free(response);
-    if(!tmp)
-      return CURLE_OUT_OF_MEMORY;
-
-    response = tmp;
-  }
-
-  if(digest->algorithm) {
-    /* Append the algorithm */
-    tmp = aprintf("%s, algorithm=\"%s\"", response, digest->algorithm);
-    free(response);
-    if(!tmp)
-      return CURLE_OUT_OF_MEMORY;
-
-    response = tmp;
-  }
-
-  /* Return the output */
-  *outptr = response;
-  *outlen = strlen(response);
-
-  return CURLE_OK;
-}
-
-/*
- * Curl_sasl_digest_cleanup()
- *
- * This is used to clean up the digest specific data.
- *
- * Parameters:
- *
- * digest    [in/out] - The digest data struct being cleaned up.
- *
- */
-void Curl_sasl_digest_cleanup(struct digestdata *digest)
-{
-  Curl_safefree(digest->nonce);
-  Curl_safefree(digest->cnonce);
-  Curl_safefree(digest->realm);
-  Curl_safefree(digest->opaque);
-  Curl_safefree(digest->qop);
-  Curl_safefree(digest->algorithm);
-
-  digest->nc = 0;
-  digest->algo = CURLDIGESTALGO_MD5; /* default algorithm */
-  digest->stale = FALSE; /* default means normal, not stale */
-}
-#endif  /* !USE_WINDOWS_SSPI */
-
-#endif  /* CURL_DISABLE_CRYPTO_AUTH */
-
-#if defined(USE_NTLM) && !defined(USE_WINDOWS_SSPI)
-/*
- * Curl_sasl_ntlm_cleanup()
- *
- * This is used to clean up the ntlm specific data.
- *
- * Parameters:
- *
- * ntlm    [in/out] - The ntlm data struct being cleaned up.
- *
- */
-void Curl_sasl_ntlm_cleanup(struct ntlmdata *ntlm)
-{
-  /* Free the target info */
-  Curl_safefree(ntlm->target_info);
-
-  /* Reset any variables */
-  ntlm->target_info_len = 0;
-}
-#endif /* USE_NTLM && !USE_WINDOWS_SSPI*/
-
-/*
- * sasl_create_xoauth2_message()
- *
- * This is used to generate an already encoded OAuth 2.0 message ready for
- * sending to the recipient.
- *
- * Parameters:
- *
- * data    [in]     - The session handle.
- * user    [in]     - The user name.
- * bearer  [in]     - The bearer token.
- * 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.
- */
-static CURLcode sasl_create_xoauth2_message(struct SessionHandle *data,
-                                            const char *user,
-                                            const char *bearer,
-                                            char **outptr, size_t *outlen)
-{
-  CURLcode result = CURLE_OK;
-  char *xoauth = NULL;
-
-  /* Generate the message */
-  xoauth = aprintf("user=%s\1auth=Bearer %s\1\1", user, bearer);
-  if(!xoauth)
-    return CURLE_OUT_OF_MEMORY;
-
-  /* Base64 encode the reply */
-  result = Curl_base64_encode(data, xoauth, strlen(xoauth), outptr, outlen);
-
-  free(xoauth);
-
-  return result;
-}
-
 /*
  * Curl_sasl_cleanup()
  *
@@ -1206,14 +85,14 @@ void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused)
 #if defined(USE_KERBEROS5)
   /* Cleanup the gssapi structure */
   if(authused == SASL_MECH_GSSAPI) {
-    Curl_sasl_gssapi_cleanup(&conn->krb5);
+    Curl_auth_gssapi_cleanup(&conn->krb5);
   }
 #endif
 
 #if defined(USE_NTLM)
-  /* Cleanup the ntlm structure */
+  /* Cleanup the NTLM structure */
   if(authused == SASL_MECH_NTLM) {
-    Curl_sasl_ntlm_cleanup(&conn->ntlm);
+    Curl_auth_ntlm_cleanup(&conn->ntlm);
   }
 #endif
 
@@ -1275,18 +154,20 @@ CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl,
   if(!len)
     return CURLE_URL_MALFORMAT;
 
-    if(sasl->resetprefs) {
-      sasl->resetprefs = FALSE;
-      sasl->prefmech = SASL_AUTH_NONE;
-    }
+  if(sasl->resetprefs) {
+    sasl->resetprefs = FALSE;
+    sasl->prefmech = SASL_AUTH_NONE;
+  }
 
-    if(strnequal(value, "*", len))
-      sasl->prefmech = SASL_AUTH_DEFAULT;
-    else if((mechbit = Curl_sasl_decode_mech(value, len, &mechlen)) &&
-            mechlen == len)
+  if(strnequal(value, "*", len))
+    sasl->prefmech = SASL_AUTH_DEFAULT;
+  else {
+    mechbit = Curl_sasl_decode_mech(value, len, &mechlen);
+    if(mechbit && mechlen == len)
       sasl->prefmech |= mechbit;
     else
       result = CURLE_URL_MALFORMAT;
+  }
 
   return result;
 }
@@ -1332,7 +213,8 @@ static void state(struct SASL *sasl, struct connectdata *conn,
     "GSSAPI",
     "GSSAPI_TOKEN",
     "GSSAPI_NO_DATA",
-    "XOAUTH2",
+    "OAUTH2",
+    "OAUTH2_RESP",
     "CANCEL",
     "FINAL",
     /* LAST */
@@ -1375,13 +257,18 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
                          bool force_ir, saslprogress *progress)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   unsigned int enabledmechs;
   const char *mech = NULL;
   char *resp = NULL;
   size_t len = 0;
   saslstate state1 = SASL_STOP;
   saslstate state2 = SASL_FINAL;
+#if defined(USE_KERBEROS5)
+  const char* service = data->set.str[STRING_SERVICE_NAME] ?
+                        data->set.str[STRING_SERVICE_NAME] :
+                        sasl->params->service;
+#endif
 
   sasl->force_ir = force_ir;    /* Latch for future use */
   sasl->authused = 0;           /* No mechanism used yet */
@@ -1396,7 +283,8 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
     sasl->authused = SASL_MECH_EXTERNAL;
 
     if(force_ir || data->set.sasl_ir)
-      result = sasl_create_external_message(data, conn->user, &resp, &len);
+      result = Curl_auth_create_external_message(data, conn->user, &resp,
+                                                 &len);
   }
   else if(conn->bits.user_passwd) {
 #if defined(USE_KERBEROS5)
@@ -1408,9 +296,11 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
       sasl->authused = SASL_MECH_GSSAPI;
 
       if(force_ir || data->set.sasl_ir)
-        result = Curl_sasl_create_gssapi_user_message(data, conn->user,
+        result = Curl_auth_create_gssapi_user_message(data, conn->user,
                                                       conn->passwd,
-                                                      sasl->params->service,
+                                                      service,
+                                                      data->easy_conn->
+                                                            host.name,
                                                       sasl->mutual_auth,
                                                       NULL, &conn->krb5,
                                                       &resp, &len);
@@ -1438,20 +328,34 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
       sasl->authused = SASL_MECH_NTLM;
 
       if(force_ir || data->set.sasl_ir)
-        result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd,
+        result = Curl_auth_create_ntlm_type1_message(conn->user, conn->passwd,
                                                      &conn->ntlm, &resp, &len);
       }
     else
 #endif
-    if((enabledmechs & SASL_MECH_XOAUTH2) || conn->xoauth2_bearer) {
+    if((enabledmechs & SASL_MECH_OAUTHBEARER) && conn->oauth_bearer) {
+      mech = SASL_MECH_STRING_OAUTHBEARER;
+      state1 = SASL_OAUTH2;
+      state2 = SASL_OAUTH2_RESP;
+      sasl->authused = SASL_MECH_OAUTHBEARER;
+
+      if(force_ir || data->set.sasl_ir)
+        result = Curl_auth_create_oauth_bearer_message(data, conn->user,
+                                                       conn->host.name,
+                                                       conn->port,
+                                                       conn->oauth_bearer,
+                                                       &resp, &len);
+    }
+    else if((enabledmechs & SASL_MECH_XOAUTH2) && conn->oauth_bearer) {
       mech = SASL_MECH_STRING_XOAUTH2;
-      state1 = SASL_XOAUTH2;
+      state1 = SASL_OAUTH2;
       sasl->authused = SASL_MECH_XOAUTH2;
 
       if(force_ir || data->set.sasl_ir)
-        result = sasl_create_xoauth2_message(data, conn->user,
-                                             conn->xoauth2_bearer,
-                                             &resp, &len);
+        result = Curl_auth_create_oauth_bearer_message(data, conn->user,
+                                                       NULL, 0,
+                                                       conn->oauth_bearer,
+                                                       &resp, &len);
     }
     else if(enabledmechs & SASL_MECH_LOGIN) {
       mech = SASL_MECH_STRING_LOGIN;
@@ -1460,7 +364,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
       sasl->authused = SASL_MECH_LOGIN;
 
       if(force_ir || data->set.sasl_ir)
-        result = sasl_create_login_message(data, conn->user, &resp, &len);
+        result = Curl_auth_create_login_message(data, conn->user, &resp, &len);
     }
     else if(enabledmechs & SASL_MECH_PLAIN) {
       mech = SASL_MECH_STRING_PLAIN;
@@ -1468,24 +372,22 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
       sasl->authused = SASL_MECH_PLAIN;
 
       if(force_ir || data->set.sasl_ir)
-        result = sasl_create_plain_message(data, conn->user, conn->passwd,
-                                           &resp, &len);
+        result = Curl_auth_create_plain_message(data, conn->user, conn->passwd,
+                                                &resp, &len);
     }
   }
 
-  if(!result) {
+  if(!result && mech) {
     if(resp && sasl->params->maxirlen &&
        strlen(mech) + len > sasl->params->maxirlen) {
       free(resp);
       resp = NULL;
     }
 
-    if(mech) {
-      result = sasl->params->sendauth(conn, mech, resp);
-      if(!result) {
-        *progress = SASL_INPROGRESS;
-        state(sasl, conn, resp? state2: state1);
-      }
+    result = sasl->params->sendauth(conn, mech, resp);
+    if(!result) {
+      *progress = SASL_INPROGRESS;
+      state(sasl, conn, resp ? state2 : state1);
     }
   }
 
@@ -1503,7 +405,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
                             int code, saslprogress *progress)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   saslstate newstate = SASL_FINAL;
   char *resp = NULL;
 #if !defined(CURL_DISABLE_CRYPTO_AUTH)
@@ -1511,6 +413,11 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
   char *chlg = NULL;
   size_t chlglen = 0;
 #endif
+#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5)
+  const char *service = data->set.str[STRING_SERVICE_NAME] ?
+                        data->set.str[STRING_SERVICE_NAME] :
+                        sasl->params->service;
+#endif
   size_t len = 0;
 
   *progress = SASL_INPROGRESS;
@@ -1523,7 +430,8 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
     return result;
   }
 
-  if(sasl->state != SASL_CANCEL && code != sasl->params->contcode) {
+  if(sasl->state != SASL_CANCEL && sasl->state != SASL_OAUTH2_RESP &&
+     code != sasl->params->contcode) {
     *progress = SASL_DONE;
     state(sasl, conn, SASL_STOP);
     return CURLE_LOGIN_DENIED;
@@ -1534,39 +442,41 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
     *progress = SASL_DONE;
     return result;
   case SASL_PLAIN:
-    result = sasl_create_plain_message(data, conn->user, conn->passwd, &resp,
-                                       &len);
+    result = Curl_auth_create_plain_message(data, conn->user, conn->passwd,
+                                            &resp,
+                                            &len);
     break;
   case SASL_LOGIN:
-    result = sasl_create_login_message(data, conn->user, &resp, &len);
+    result = Curl_auth_create_login_message(data, conn->user, &resp, &len);
     newstate = SASL_LOGIN_PASSWD;
     break;
   case SASL_LOGIN_PASSWD:
-    result = sasl_create_login_message(data, conn->passwd, &resp, &len);
+    result = Curl_auth_create_login_message(data, conn->passwd, &resp, &len);
     break;
   case SASL_EXTERNAL:
-    result = sasl_create_external_message(data, conn->user, &resp, &len);
+    result = Curl_auth_create_external_message(data, conn->user, &resp, &len);
     break;
 
 #ifndef CURL_DISABLE_CRYPTO_AUTH
   case SASL_CRAMMD5:
     sasl->params->getmessage(data->state.buffer, &serverdata);
-    result = sasl_decode_cram_md5_message(serverdata, &chlg, &chlglen);
+    result = Curl_auth_decode_cram_md5_message(serverdata, &chlg, &chlglen);
     if(!result)
-      result = sasl_create_cram_md5_message(data, chlg, conn->user,
-                                            conn->passwd, &resp, &len);
+      result = Curl_auth_create_cram_md5_message(data, chlg, conn->user,
+                                                 conn->passwd, &resp, &len);
     free(chlg);
     break;
   case SASL_DIGESTMD5:
     sasl->params->getmessage(data->state.buffer, &serverdata);
-    result = Curl_sasl_create_digest_md5_message(data, serverdata,
+    result = Curl_auth_create_digest_md5_message(data, serverdata,
                                                  conn->user, conn->passwd,
-                                                 sasl->params->service,
+                                                 service,
                                                  &resp, &len);
     newstate = SASL_DIGESTMD5_RESP;
     break;
   case SASL_DIGESTMD5_RESP:
-    if(!(resp = strdup("")))
+    resp = strdup("");
+    if(!resp)
       result = CURLE_OUT_OF_MEMORY;
     break;
 #endif
@@ -1574,17 +484,17 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
 #ifdef USE_NTLM
   case SASL_NTLM:
     /* Create the type-1 message */
-    result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd,
+    result = Curl_auth_create_ntlm_type1_message(conn->user, conn->passwd,
                                                  &conn->ntlm, &resp, &len);
     newstate = SASL_NTLM_TYPE2MSG;
     break;
   case SASL_NTLM_TYPE2MSG:
     /* Decode the type-2 message */
     sasl->params->getmessage(data->state.buffer, &serverdata);
-    result = Curl_sasl_decode_ntlm_type2_message(data, serverdata,
+    result = Curl_auth_decode_ntlm_type2_message(data, serverdata,
                                                  &conn->ntlm);
     if(!result)
-      result = Curl_sasl_create_ntlm_type3_message(data, conn->user,
+      result = Curl_auth_create_ntlm_type3_message(data, conn->user,
                                                    conn->passwd, &conn->ntlm,
                                                    &resp, &len);
     break;
@@ -1592,9 +502,10 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
 
 #if defined(USE_KERBEROS5)
   case SASL_GSSAPI:
-    result = Curl_sasl_create_gssapi_user_message(data, conn->user,
+    result = Curl_auth_create_gssapi_user_message(data, conn->user,
                                                   conn->passwd,
-                                                  sasl->params->service,
+                                                  service,
+                                                  data->easy_conn->host.name,
                                                   sasl->mutual_auth, NULL,
                                                   &conn->krb5,
                                                   &resp, &len);
@@ -1605,7 +516,8 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
     if(sasl->mutual_auth) {
       /* Decode the user token challenge and create the optional response
          message */
-      result = Curl_sasl_create_gssapi_user_message(data, NULL, NULL, NULL,
+      result = Curl_auth_create_gssapi_user_message(data, NULL, NULL,
+                                                    NULL, NULL,
                                                     sasl->mutual_auth,
                                                     serverdata, &conn->krb5,
                                                     &resp, &len);
@@ -1613,24 +525,60 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
     }
     else
       /* Decode the security challenge and create the response message */
-      result = Curl_sasl_create_gssapi_security_message(data, serverdata,
+      result = Curl_auth_create_gssapi_security_message(data, serverdata,
                                                         &conn->krb5,
                                                         &resp, &len);
     break;
   case SASL_GSSAPI_NO_DATA:
     sasl->params->getmessage(data->state.buffer, &serverdata);
     /* Decode the security challenge and create the response message */
-    result = Curl_sasl_create_gssapi_security_message(data, serverdata,
+    result = Curl_auth_create_gssapi_security_message(data, serverdata,
                                                       &conn->krb5,
                                                       &resp, &len);
     break;
 #endif
 
-  case SASL_XOAUTH2:
+  case SASL_OAUTH2:
     /* Create the authorisation message */
-    result = sasl_create_xoauth2_message(data, conn->user,
-                                         conn->xoauth2_bearer, &resp, &len);
+    if(sasl->authused == SASL_MECH_OAUTHBEARER) {
+      result = Curl_auth_create_oauth_bearer_message(data, conn->user,
+                                                     conn->host.name,
+                                                     conn->port,
+                                                     conn->oauth_bearer,
+                                                     &resp, &len);
+
+      /* Failures maybe sent by the server as continuations for OAUTHBEARER */
+      newstate = SASL_OAUTH2_RESP;
+    }
+    else
+      result = Curl_auth_create_oauth_bearer_message(data, conn->user,
+                                                     NULL, 0,
+                                                     conn->oauth_bearer,
+                                                     &resp, &len);
     break;
+
+  case SASL_OAUTH2_RESP:
+    /* The continuation is optional so check the response code */
+    if(code == sasl->params->finalcode) {
+      /* Final response was received so we are done */
+      *progress = SASL_DONE;
+      state(sasl, conn, SASL_STOP);
+      return result;
+    }
+    else if(code == sasl->params->contcode) {
+      /* Acknowledge the continuation by sending a 0x01 response base64
+         encoded */
+      resp = strdup("AQ==");
+      if(!resp)
+        result = CURLE_OUT_OF_MEMORY;
+      break;
+    }
+    else {
+      *progress = SASL_DONE;
+      state(sasl, conn, SASL_STOP);
+      return CURLE_LOGIN_DENIED;
+    }
+
   case SASL_CANCEL:
     /* Remove the offending mechanism from the supported list */
     sasl->authmechs ^= sasl->authused;
diff --git a/lib/curl_sasl.h b/lib/curl_sasl.h
index 117d60e..7647a48 100644
--- a/lib/curl_sasl.h
+++ b/lib/curl_sasl.h
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2012 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 2012 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -24,21 +24,9 @@
 
 #include <curl/curl.h>
 
-struct SessionHandle;
+struct Curl_easy;
 struct connectdata;
 
-#if !defined(CURL_DISABLE_CRYPTO_AUTH)
-struct digestdata;
-#endif
-
-#if defined(USE_NTLM)
-struct ntlmdata;
-#endif
-
-#if defined(USE_KERBEROS5)
-struct kerberos5data;
-#endif
-
 /* Authentication mechanism flags */
 #define SASL_MECH_LOGIN             (1 << 0)
 #define SASL_MECH_PLAIN             (1 << 1)
@@ -48,32 +36,23 @@ struct kerberos5data;
 #define SASL_MECH_EXTERNAL          (1 << 5)
 #define SASL_MECH_NTLM              (1 << 6)
 #define SASL_MECH_XOAUTH2           (1 << 7)
+#define SASL_MECH_OAUTHBEARER       (1 << 8)
 
 /* Authentication mechanism values */
 #define SASL_AUTH_NONE          0
 #define SASL_AUTH_ANY           ~0U
-#define SASL_AUTH_DEFAULT       (SASL_AUTH_ANY & \
-                                 ~(SASL_MECH_EXTERNAL | SASL_MECH_XOAUTH2))
+#define SASL_AUTH_DEFAULT       (SASL_AUTH_ANY & ~SASL_MECH_EXTERNAL)
 
 /* Authentication mechanism strings */
-#define SASL_MECH_STRING_LOGIN      "LOGIN"
-#define SASL_MECH_STRING_PLAIN      "PLAIN"
-#define SASL_MECH_STRING_CRAM_MD5   "CRAM-MD5"
-#define SASL_MECH_STRING_DIGEST_MD5 "DIGEST-MD5"
-#define SASL_MECH_STRING_GSSAPI     "GSSAPI"
-#define SASL_MECH_STRING_EXTERNAL   "EXTERNAL"
-#define SASL_MECH_STRING_NTLM       "NTLM"
-#define SASL_MECH_STRING_XOAUTH2    "XOAUTH2"
-
-#if !defined(CURL_DISABLE_CRYPTO_AUTH)
-#define DIGEST_MAX_VALUE_LENGTH           256
-#define DIGEST_MAX_CONTENT_LENGTH         1024
-#endif
-
-enum {
-  CURLDIGESTALGO_MD5,
-  CURLDIGESTALGO_MD5SESS
-};
+#define SASL_MECH_STRING_LOGIN        "LOGIN"
+#define SASL_MECH_STRING_PLAIN        "PLAIN"
+#define SASL_MECH_STRING_CRAM_MD5     "CRAM-MD5"
+#define SASL_MECH_STRING_DIGEST_MD5   "DIGEST-MD5"
+#define SASL_MECH_STRING_GSSAPI       "GSSAPI"
+#define SASL_MECH_STRING_EXTERNAL     "EXTERNAL"
+#define SASL_MECH_STRING_NTLM         "NTLM"
+#define SASL_MECH_STRING_XOAUTH2      "XOAUTH2"
+#define SASL_MECH_STRING_OAUTHBEARER  "OAUTHBEARER"
 
 /* SASL machine states */
 typedef enum {
@@ -90,7 +69,8 @@ typedef enum {
   SASL_GSSAPI,
   SASL_GSSAPI_TOKEN,
   SASL_GSSAPI_NO_DATA,
-  SASL_XOAUTH2,
+  SASL_OAUTH2,
+  SASL_OAUTH2_RESP,
   SASL_CANCEL,
   SASL_FINAL
 } saslstate;
@@ -134,97 +114,6 @@ struct SASL {
   (wordlen == (sizeof(mech) - 1) / sizeof(char) && \
    !memcmp(line, mech, wordlen))
 
-/* This is used to build a SPN string */
-#if !defined(USE_WINDOWS_SSPI)
-char *Curl_sasl_build_spn(const char *service, const char *instance);
-#else
-TCHAR *Curl_sasl_build_spn(const char *service, const char *instance);
-#endif
-
-/* This is used to extract the realm from a challenge message */
-int Curl_sasl_digest_get_pair(const char *str, char *value, char *content,
-                              const char **endptr);
-
-#if defined(HAVE_GSSAPI)
-char *Curl_sasl_build_gssapi_spn(const char *service, const char *host);
-#endif
-
-#ifndef CURL_DISABLE_CRYPTO_AUTH
-
-/* This is used to generate a base64 encoded DIGEST-MD5 response message */
-CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data,
-                                             const char *chlg64,
-                                             const char *userp,
-                                             const char *passwdp,
-                                             const char *service,
-                                             char **outptr, size_t *outlen);
-
-/* This is used to decode a HTTP DIGEST challenge message */
-CURLcode Curl_sasl_decode_digest_http_message(const char *chlg,
-                                              struct digestdata *digest);
-
-/* This is used to generate a HTTP DIGEST response message */
-CURLcode Curl_sasl_create_digest_http_message(struct SessionHandle *data,
-                                              const char *userp,
-                                              const char *passwdp,
-                                              const unsigned char *request,
-                                              const unsigned char *uri,
-                                              struct digestdata *digest,
-                                              char **outptr, size_t *outlen);
-
-/* This is used to clean up the digest specific data */
-void Curl_sasl_digest_cleanup(struct digestdata *digest);
-#endif
-
-#ifdef USE_NTLM
-/* This is used to generate a base64 encoded NTLM type-1 message */
-CURLcode Curl_sasl_create_ntlm_type1_message(const char *userp,
-                                             const char *passwdp,
-                                             struct ntlmdata *ntlm,
-                                             char **outptr,
-                                             size_t *outlen);
-
-/* This is used to decode a base64 encoded NTLM type-2 message */
-CURLcode Curl_sasl_decode_ntlm_type2_message(struct SessionHandle *data,
-                                             const char *type2msg,
-                                             struct ntlmdata *ntlm);
-
-/* This is used to generate a base64 encoded NTLM type-3 message */
-CURLcode Curl_sasl_create_ntlm_type3_message(struct SessionHandle *data,
-                                             const char *userp,
-                                             const char *passwdp,
-                                             struct ntlmdata *ntlm,
-                                             char **outptr, size_t *outlen);
-
-/* This is used to clean up the ntlm specific data */
-void Curl_sasl_ntlm_cleanup(struct ntlmdata *ntlm);
-
-#endif /* USE_NTLM */
-
-#if defined(USE_KERBEROS5)
-/* This is used to generate a base64 encoded GSSAPI (Kerberos V5) user token
-   message */
-CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data,
-                                              const char *userp,
-                                              const char *passwdp,
-                                              const char *service,
-                                              const bool mutual,
-                                              const char *chlg64,
-                                              struct kerberos5data *krb5,
-                                              char **outptr, size_t *outlen);
-
-/* This is used to generate a base64 encoded GSSAPI (Kerberos V5) security
-   token message */
-CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data,
-                                                  const char *input,
-                                                  struct kerberos5data *krb5,
-                                                  char **outptr,
-                                                  size_t *outlen);
-
-/* This is used to clean up the gssapi specific data */
-void Curl_sasl_gssapi_cleanup(struct kerberos5data *krb5);
-#endif /* USE_KERBEROS5 */
-
 /* This is used to cleanup any libraries or curl modules used by the sasl
    functions */
 void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused);
diff --git a/lib/curl_sasl_sspi.c b/lib/curl_sasl_sspi.c
deleted file mode 100644
index b149530..0000000
--- a/lib/curl_sasl_sspi.c
+++ /dev/null
@@ -1,1281 +0,0 @@
-/***************************************************************************
- *                                  _   _ ____  _
- *  Project                     ___| | | |  _ \| |
- *                             / __| | | | |_) | |
- *                            | (__| |_| |  _ <| |___
- *                             \___|\___/|_| \_\_____|
- *
- * Copyright (C) 2014 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
- * Copyright (C) 2014, Steve Holme, <steve_holme at hotmail.com>.
- *
- * 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 http://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.
- *
- * RFC2617 Basic and Digest Access Authentication
- * RFC2831 DIGEST-MD5 authentication
- * RFC4422 Simple Authentication and Security Layer (SASL)
- * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism
- *
- ***************************************************************************/
-
-#include "curl_setup.h"
-
-#if defined(USE_WINDOWS_SSPI)
-
-#include <curl/curl.h>
-
-#include "curl_sasl.h"
-#include "urldata.h"
-#include "curl_base64.h"
-#include "warnless.h"
-#include "curl_multibyte.h"
-#include "sendf.h"
-#include "strdup.h"
-#include "curl_printf.h"
-#include "rawstr.h"
-
-/* The last #include files should be: */
-#include "curl_memory.h"
-#include "memdebug.h"
-
-/*
- * Curl_sasl_build_spn()
- *
- * This is used to build a SPN string in the format service/host.
- *
- * Parameters:
- *
- * serivce  [in] - The service type such as www, smtp, pop or imap.
- * host     [in] - The host name or realm.
- *
- * Returns a pointer to the newly allocated SPN.
- */
-TCHAR *Curl_sasl_build_spn(const char *service, const char *host)
-{
-  char *utf8_spn = NULL;
-  TCHAR *tchar_spn = NULL;
-
-  /* Note: We could use DsMakeSPN() or DsClientMakeSpnForTargetServer() rather
-     than doing this ourselves but the first is only available in Windows XP
-     and Windows Server 2003 and the latter is only available in Windows 2000
-     but not Windows95/98/ME or Windows NT4.0 unless the Active Directory
-     Client Extensions are installed. As such it is far simpler for us to
-     formulate the SPN instead. */
-
-  /* Allocate our UTF8 based SPN */
-  utf8_spn = aprintf("%s/%s", service, host);
-  if(!utf8_spn) {
-    return NULL;
-  }
-
-  /* Allocate our TCHAR based SPN */
-  tchar_spn = Curl_convert_UTF8_to_tchar(utf8_spn);
-  if(!tchar_spn) {
-    free(utf8_spn);
-
-    return NULL;
-  }
-
-  /* Release the UTF8 variant when operating with Unicode */
-  Curl_unicodefree(utf8_spn);
-
-  /* Return our newly allocated SPN */
-  return tchar_spn;
-}
-
-#if !defined(CURL_DISABLE_CRYPTO_AUTH)
-/*
- * Curl_sasl_create_digest_md5_message()
- *
- * This is used to generate an already encoded DIGEST-MD5 response message
- * ready for sending to the recipient.
- *
- * Parameters:
- *
- * data    [in]     - The session handle.
- * chlg64  [in]     - The base64 encoded challenge message.
- * userp   [in]     - The user name in the format User or Domain\User.
- * passdwp [in]     - The user's password.
- * service [in]     - The service type such as www, smtp, pop or imap.
- * 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_sasl_create_digest_md5_message(struct SessionHandle *data,
-                                             const char *chlg64,
-                                             const char *userp,
-                                             const char *passwdp,
-                                             const char *service,
-                                             char **outptr, size_t *outlen)
-{
-  CURLcode result = CURLE_OK;
-  TCHAR *spn = NULL;
-  size_t chlglen = 0;
-  size_t token_max = 0;
-  unsigned char *input_token = NULL;
-  unsigned char *output_token = NULL;
-  CredHandle credentials;
-  CtxtHandle context;
-  PSecPkgInfo SecurityPackage;
-  SEC_WINNT_AUTH_IDENTITY identity;
-  SEC_WINNT_AUTH_IDENTITY *p_identity;
-  SecBuffer chlg_buf;
-  SecBuffer resp_buf;
-  SecBufferDesc chlg_desc;
-  SecBufferDesc resp_desc;
-  SECURITY_STATUS status;
-  unsigned long attrs;
-  TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
-
-  /* Decode the base-64 encoded challenge message */
-  if(strlen(chlg64) && *chlg64 != '=') {
-    result = Curl_base64_decode(chlg64, &input_token, &chlglen);
-    if(result)
-      return result;
-  }
-
-  /* Ensure we have a valid challenge message */
-  if(!input_token) {
-    infof(data, "DIGEST-MD5 handshake failure (empty challenge message)\n");
-
-    return CURLE_BAD_CONTENT_ENCODING;
-  }
-
-  /* Query the security package for DigestSSP */
-  status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST),
-                                              &SecurityPackage);
-  if(status != SEC_E_OK) {
-    free(input_token);
-
-    return CURLE_NOT_BUILT_IN;
-  }
-
-  token_max = SecurityPackage->cbMaxToken;
-
-  /* Release the package buffer as it is not required anymore */
-  s_pSecFn->FreeContextBuffer(SecurityPackage);
-
-  /* Allocate our response buffer */
-  output_token = malloc(token_max);
-  if(!output_token) {
-    free(input_token);
-
-    return CURLE_OUT_OF_MEMORY;
-  }
-
-  /* Generate our SPN */
-  spn = Curl_sasl_build_spn(service, data->easy_conn->host.name);
-  if(!spn) {
-    free(output_token);
-    free(input_token);
-
-    return CURLE_OUT_OF_MEMORY;
-  }
-
-  if(userp && *userp) {
-    /* Populate our identity structure */
-    result = Curl_create_sspi_identity(userp, passwdp, &identity);
-    if(result) {
-      free(spn);
-      free(output_token);
-      free(input_token);
-
-      return result;
-    }
-
-    /* Allow proper cleanup of the identity structure */
-    p_identity = &identity;
-  }
-  else
-    /* Use the current Windows user */
-    p_identity = NULL;
-
-  /* Acquire our credentials handle */
-  status = s_pSecFn->AcquireCredentialsHandle(NULL,
-                                              (TCHAR *) TEXT(SP_NAME_DIGEST),
-                                              SECPKG_CRED_OUTBOUND, NULL,
-                                              p_identity, NULL, NULL,
-                                              &credentials, &expiry);
-
-  if(status != SEC_E_OK) {
-    Curl_sspi_free_identity(p_identity);
-    free(spn);
-    free(output_token);
-    free(input_token);
-
-    return CURLE_LOGIN_DENIED;
-  }
-
-  /* Setup the challenge "input" security buffer */
-  chlg_desc.ulVersion = SECBUFFER_VERSION;
-  chlg_desc.cBuffers  = 1;
-  chlg_desc.pBuffers  = &chlg_buf;
-  chlg_buf.BufferType = SECBUFFER_TOKEN;
-  chlg_buf.pvBuffer   = input_token;
-  chlg_buf.cbBuffer   = curlx_uztoul(chlglen);
-
-  /* Setup the response "output" security buffer */
-  resp_desc.ulVersion = SECBUFFER_VERSION;
-  resp_desc.cBuffers  = 1;
-  resp_desc.pBuffers  = &resp_buf;
-  resp_buf.BufferType = SECBUFFER_TOKEN;
-  resp_buf.pvBuffer   = output_token;
-  resp_buf.cbBuffer   = curlx_uztoul(token_max);
-
-  /* Generate our response message */
-  status = s_pSecFn->InitializeSecurityContext(&credentials, NULL, spn,
-                                               0, 0, 0, &chlg_desc, 0,
-                                               &context, &resp_desc, &attrs,
-                                               &expiry);
-
-  if(status == SEC_I_COMPLETE_NEEDED ||
-     status == SEC_I_COMPLETE_AND_CONTINUE)
-    s_pSecFn->CompleteAuthToken(&credentials, &resp_desc);
-  else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) {
-    s_pSecFn->FreeCredentialsHandle(&credentials);
-    Curl_sspi_free_identity(p_identity);
-    free(spn);
-    free(output_token);
-    free(input_token);
-
-    return CURLE_RECV_ERROR;
-  }
-
-  /* Base64 encode the response */
-  result = Curl_base64_encode(data, (char *) output_token, resp_buf.cbBuffer,
-                              outptr, outlen);
-
-  /* Free our handles */
-  s_pSecFn->DeleteSecurityContext(&context);
-  s_pSecFn->FreeCredentialsHandle(&credentials);
-
-  /* Free the identity structure */
-  Curl_sspi_free_identity(p_identity);
-
-  /* Free the SPN */
-  free(spn);
-
-  /* Free the response buffer */
-  free(output_token);
-
-  /* Free the decoded challenge message */
-  free(input_token);
-
-  return result;
-}
-
-/*
-* Curl_override_sspi_http_realm()
-*
-* This is used to populate the domain in a SSPI identity structure
-* The realm is extracted from the challenge message and used as the
-* domain if it is not already explicitly set.
-*
-* Parameters:
-*
-* chlg     [in]     - The challenge message.
-* identity [in/out] - The identity structure.
-*
-* Returns CURLE_OK on success.
-*/
-CURLcode Curl_override_sspi_http_realm(const char *chlg,
-                                       SEC_WINNT_AUTH_IDENTITY *identity)
-{
-  xcharp_u domain, dup_domain;
-
-  /* If domain is blank or unset, check challenge message for realm */
-  if(!identity->Domain || !identity->DomainLength) {
-    for(;;) {
-      char value[DIGEST_MAX_VALUE_LENGTH];
-      char content[DIGEST_MAX_CONTENT_LENGTH];
-
-      /* Pass all additional spaces here */
-      while(*chlg && ISSPACE(*chlg))
-        chlg++;
-
-      /* Extract a value=content pair */
-      if(!Curl_sasl_digest_get_pair(chlg, value, content, &chlg)) {
-        if(Curl_raw_equal(value, "realm")) {
-
-          /* Setup identity's domain and length */
-          domain.tchar_ptr = Curl_convert_UTF8_to_tchar((char *)content);
-          if(!domain.tchar_ptr)
-            return CURLE_OUT_OF_MEMORY;
-          dup_domain.tchar_ptr = _tcsdup(domain.tchar_ptr);
-          if(!dup_domain.tchar_ptr) {
-            Curl_unicodefree(domain.tchar_ptr);
-            return CURLE_OUT_OF_MEMORY;
-          }
-          identity->Domain = dup_domain.tbyte_ptr;
-          identity->DomainLength = curlx_uztoul(_tcslen(dup_domain.tchar_ptr));
-          dup_domain.tchar_ptr = NULL;
-
-          Curl_unicodefree(domain.tchar_ptr);
-        }
-        else {
-          /* unknown specifier, ignore it! */
-        }
-      }
-      else
-        break; /* we're done here */
-
-      /* Pass all additional spaces here */
-      while(*chlg && ISSPACE(*chlg))
-        chlg++;
-
-      /* Allow the list to be comma-separated */
-      if(',' == *chlg)
-        chlg++;
-    }
-  }
-
-  return CURLE_OK;
-}
-
-/*
- * Curl_sasl_decode_digest_http_message()
- *
- * This is used to decode a HTTP DIGEST challenge message into the seperate
- * attributes.
- *
- * Parameters:
- *
- * chlg    [in]     - The challenge message.
- * digest  [in/out] - The digest data struct being used and modified.
- *
- * Returns CURLE_OK on success.
- */
-CURLcode Curl_sasl_decode_digest_http_message(const char *chlg,
-                                              struct digestdata *digest)
-{
-  size_t chlglen = strlen(chlg);
-
-  /* We had an input token before and we got another one now. This means we
-  provided bad credentials in the previous request. */
-  if(digest->input_token)
-    return CURLE_BAD_CONTENT_ENCODING;
-
-  /* Simply store the challenge for use later */
-  digest->input_token = (BYTE *) Curl_memdup(chlg, chlglen);
-  if(!digest->input_token)
-    return CURLE_OUT_OF_MEMORY;
-
-  digest->input_token_len = chlglen;
-
-  return CURLE_OK;
-}
-
-/*
- * Curl_sasl_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 in the format User or Domain\User.
- * 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_sasl_create_digest_http_message(struct SessionHandle *data,
-                                              const char *userp,
-                                              const char *passwdp,
-                                              const unsigned char *request,
-                                              const unsigned char *uripath,
-                                              struct digestdata *digest,
-                                              char **outptr, size_t *outlen)
-{
-  size_t token_max;
-  CredHandle credentials;
-  CtxtHandle context;
-  char *resp;
-  BYTE *output_token;
-  PSecPkgInfo SecurityPackage;
-  SEC_WINNT_AUTH_IDENTITY identity;
-  SEC_WINNT_AUTH_IDENTITY *p_identity;
-  SecBuffer chlg_buf[3];
-  SecBuffer resp_buf;
-  SecBufferDesc chlg_desc;
-  SecBufferDesc resp_desc;
-  SECURITY_STATUS status;
-  unsigned long attrs;
-  TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
-
-  (void) data;
-
-  /* Query the security package for DigestSSP */
-  status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST),
-                                              &SecurityPackage);
-  if(status != SEC_E_OK)
-    return CURLE_NOT_BUILT_IN;
-
-  token_max = SecurityPackage->cbMaxToken;
-
-  /* Release the package buffer as it is not required anymore */
-  s_pSecFn->FreeContextBuffer(SecurityPackage);
-
-  /* Allocate the output buffer according to the max token size as indicated
-     by the security package */
-  output_token = malloc(token_max);
-  if(!output_token)
-    return CURLE_OUT_OF_MEMORY;
-
-  if(userp && *userp) {
-    /* Populate our identity structure */
-    if(Curl_create_sspi_identity(userp, passwdp, &identity))
-      return CURLE_OUT_OF_MEMORY;
-
-    /* Populate our identity domain */
-    if(Curl_override_sspi_http_realm((const char*)digest->input_token,
-                                     &identity))
-      return CURLE_OUT_OF_MEMORY;
-
-    /* Allow proper cleanup of the identity structure */
-    p_identity = &identity;
-  }
-  else
-    /* Use the current Windows user */
-    p_identity = NULL;
-
-  /* Acquire our credentials handle */
-  status = s_pSecFn->AcquireCredentialsHandle(NULL,
-                                              (TCHAR *) TEXT(SP_NAME_DIGEST),
-                                              SECPKG_CRED_OUTBOUND, NULL,
-                                              p_identity, NULL, NULL,
-                                              &credentials, &expiry);
-  if(status != SEC_E_OK) {
-    free(output_token);
-
-    return CURLE_LOGIN_DENIED;
-  }
-
-  /* Setup the challenge "input" security buffer if present */
-  chlg_desc.ulVersion    = SECBUFFER_VERSION;
-  chlg_desc.cBuffers     = 3;
-  chlg_desc.pBuffers     = chlg_buf;
-  chlg_buf[0].BufferType = SECBUFFER_TOKEN;
-  chlg_buf[0].pvBuffer   = digest->input_token;
-  chlg_buf[0].cbBuffer   = curlx_uztoul(digest->input_token_len);
-  chlg_buf[1].BufferType = SECBUFFER_PKG_PARAMS;
-  chlg_buf[1].pvBuffer   = (void *)request;
-  chlg_buf[1].cbBuffer   = curlx_uztoul(strlen((const char *) request));
-  chlg_buf[2].BufferType = SECBUFFER_PKG_PARAMS;
-  chlg_buf[2].pvBuffer   = NULL;
-  chlg_buf[2].cbBuffer   = 0;
-
-  /* Setup the response "output" security buffer */
-  resp_desc.ulVersion = SECBUFFER_VERSION;
-  resp_desc.cBuffers  = 1;
-  resp_desc.pBuffers  = &resp_buf;
-  resp_buf.BufferType = SECBUFFER_TOKEN;
-  resp_buf.pvBuffer   = output_token;
-  resp_buf.cbBuffer   = curlx_uztoul(token_max);
-
-  /* Generate our reponse message */
-  status = s_pSecFn->InitializeSecurityContext(&credentials, NULL,
-                                               (TCHAR *) uripath,
-                                               ISC_REQ_USE_HTTP_STYLE, 0, 0,
-                                               &chlg_desc, 0, &context,
-                                               &resp_desc, &attrs, &expiry);
-
-  if(status == SEC_I_COMPLETE_NEEDED ||
-     status == SEC_I_COMPLETE_AND_CONTINUE)
-    s_pSecFn->CompleteAuthToken(&credentials, &resp_desc);
-  else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) {
-    s_pSecFn->FreeCredentialsHandle(&credentials);
-
-    free(output_token);
-
-    return CURLE_OUT_OF_MEMORY;
-  }
-
-  resp = malloc(resp_buf.cbBuffer + 1);
-  if(!resp) {
-    s_pSecFn->DeleteSecurityContext(&context);
-    s_pSecFn->FreeCredentialsHandle(&credentials);
-
-    free(output_token);
-
-    return CURLE_OUT_OF_MEMORY;
-  }
-
-  /* Copy the generated reponse */
-  memcpy(resp, resp_buf.pvBuffer, resp_buf.cbBuffer);
-  resp[resp_buf.cbBuffer] = 0x00;
-
-  /* Return the response */
-  *outptr = resp;
-  *outlen = resp_buf.cbBuffer;
-
-  /* Free our handles */
-  s_pSecFn->DeleteSecurityContext(&context);
-  s_pSecFn->FreeCredentialsHandle(&credentials);
-
-  /* Free the identity structure */
-  Curl_sspi_free_identity(p_identity);
-
-  /* Free the response buffer */
-  free(output_token);
-
-  return CURLE_OK;
-}
-
-/*
- * Curl_sasl_digest_cleanup()
- *
- * This is used to clean up the digest specific data.
- *
- * Parameters:
- *
- * digest    [in/out] - The digest data struct being cleaned up.
- *
- */
-void Curl_sasl_digest_cleanup(struct digestdata *digest)
-{
-  /* Free the input token */
-  Curl_safefree(digest->input_token);
-
-  /* Reset any variables */
-  digest->input_token_len = 0;
-}
-#endif /* !CURL_DISABLE_CRYPTO_AUTH */
-
-#if defined USE_NTLM
-/*
-* Curl_sasl_create_ntlm_type1_message()
-*
-* This is used to generate an already encoded NTLM type-1 message ready for
-* sending to the recipient.
-*
-* Parameters:
-*
-* userp   [in]     - The user name in the format User or Domain\User.
-* passdwp [in]     - The user's password.
-* ntlm    [in/out] - The ntlm 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_sasl_create_ntlm_type1_message(const char *userp,
-                                             const char *passwdp,
-                                             struct ntlmdata *ntlm,
-                                             char **outptr, size_t *outlen)
-{
-  PSecPkgInfo SecurityPackage;
-  SecBuffer type_1_buf;
-  SecBufferDesc type_1_desc;
-  SECURITY_STATUS status;
-  unsigned long attrs;
-  TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
-
-  /* Clean up any former leftovers and initialise to defaults */
-  Curl_sasl_ntlm_cleanup(ntlm);
-
-  /* Query the security package for NTLM */
-  status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM),
-                                              &SecurityPackage);
-  if(status != SEC_E_OK)
-    return CURLE_NOT_BUILT_IN;
-
-  ntlm->token_max = SecurityPackage->cbMaxToken;
-
-  /* Release the package buffer as it is not required anymore */
-  s_pSecFn->FreeContextBuffer(SecurityPackage);
-
-  /* Allocate our output buffer */
-  ntlm->output_token = malloc(ntlm->token_max);
-  if(!ntlm->output_token)
-    return CURLE_OUT_OF_MEMORY;
-
-  if(userp && *userp) {
-    CURLcode result;
-
-    /* Populate our identity structure */
-    result = Curl_create_sspi_identity(userp, passwdp, &ntlm->identity);
-    if(result)
-      return result;
-
-    /* Allow proper cleanup of the identity structure */
-    ntlm->p_identity = &ntlm->identity;
-  }
-  else
-    /* Use the current Windows user */
-    ntlm->p_identity = NULL;
-
-  /* Allocate our credentials handle */
-  ntlm->credentials = malloc(sizeof(CredHandle));
-  if(!ntlm->credentials)
-    return CURLE_OUT_OF_MEMORY;
-
-  memset(ntlm->credentials, 0, sizeof(CredHandle));
-
-  /* Acquire our credentials handle */
-  status = s_pSecFn->AcquireCredentialsHandle(NULL,
-                                              (TCHAR *) TEXT(SP_NAME_NTLM),
-                                              SECPKG_CRED_OUTBOUND, NULL,
-                                              ntlm->p_identity, NULL, NULL,
-                                              ntlm->credentials, &expiry);
-  if(status != SEC_E_OK)
-    return CURLE_LOGIN_DENIED;
-
-  /* Allocate our new context handle */
-  ntlm->context = malloc(sizeof(CtxtHandle));
-  if(!ntlm->context)
-    return CURLE_OUT_OF_MEMORY;
-
-  memset(ntlm->context, 0, sizeof(CtxtHandle));
-
-  /* Setup the type-1 "output" security buffer */
-  type_1_desc.ulVersion = SECBUFFER_VERSION;
-  type_1_desc.cBuffers  = 1;
-  type_1_desc.pBuffers  = &type_1_buf;
-  type_1_buf.BufferType = SECBUFFER_TOKEN;
-  type_1_buf.pvBuffer   = ntlm->output_token;
-  type_1_buf.cbBuffer   = curlx_uztoul(ntlm->token_max);
-
-  /* Generate our type-1 message */
-  status = s_pSecFn->InitializeSecurityContext(ntlm->credentials, NULL,
-                                               (TCHAR *) TEXT(""),
-                                               0, 0, SECURITY_NETWORK_DREP,
-                                               NULL, 0,
-                                               ntlm->context, &type_1_desc,
-                                               &attrs, &expiry);
-  if(status == SEC_I_COMPLETE_NEEDED ||
-    status == SEC_I_COMPLETE_AND_CONTINUE)
-    s_pSecFn->CompleteAuthToken(ntlm->context, &type_1_desc);
-  else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED)
-    return CURLE_RECV_ERROR;
-
-  /* Base64 encode the response */
-  return Curl_base64_encode(NULL, (char *) ntlm->output_token,
-                            type_1_buf.cbBuffer, outptr, outlen);
-}
-
-/*
-* Curl_sasl_decode_ntlm_type2_message()
-*
-* This is used to decode an already encoded NTLM type-2 message.
-*
-* Parameters:
-*
-* data     [in]     - The session handle.
-* type2msg [in]     - The base64 encoded type-2 message.
-* ntlm     [in/out] - The ntlm data struct being used and modified.
-*
-* Returns CURLE_OK on success.
-*/
-CURLcode Curl_sasl_decode_ntlm_type2_message(struct SessionHandle *data,
-                                             const char *type2msg,
-                                             struct ntlmdata *ntlm)
-{
-  CURLcode result = CURLE_OK;
-  unsigned char *type2 = NULL;
-  size_t type2_len = 0;
-
-#if defined(CURL_DISABLE_VERBOSE_STRINGS)
-  (void) data;
-#endif
-
-  /* Decode the base-64 encoded type-2 message */
-  if(strlen(type2msg) && *type2msg != '=') {
-    result = Curl_base64_decode(type2msg, &type2, &type2_len);
-    if(result)
-      return result;
-  }
-
-  /* Ensure we have a valid type-2 message */
-  if(!type2) {
-    infof(data, "NTLM handshake failure (empty type-2 message)\n");
-
-    return CURLE_BAD_CONTENT_ENCODING;
-  }
-
-  /* Simply store the challenge for use later */
-  ntlm->input_token = type2;
-  ntlm->input_token_len = type2_len;
-
-  return result;
-}
-
-/*
-* Curl_sasl_create_ntlm_type3_message()
-*
-* This is used to generate an already encoded NTLM type-3 message ready for
-* sending to the recipient.
-*
-* Parameters:
-*
-* data    [in]     - The session handle.
-* userp   [in]     - The user name in the format User or Domain\User.
-* passdwp [in]     - The user's password.
-* ntlm    [in/out] - The ntlm 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_sasl_create_ntlm_type3_message(struct SessionHandle *data,
-                                             const char *userp,
-                                             const char *passwdp,
-                                             struct ntlmdata *ntlm,
-                                             char **outptr, size_t *outlen)
-{
-  CURLcode result = CURLE_OK;
-  SecBuffer type_2_buf;
-  SecBuffer type_3_buf;
-  SecBufferDesc type_2_desc;
-  SecBufferDesc type_3_desc;
-  SECURITY_STATUS status;
-  unsigned long attrs;
-  TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
-
-  (void) passwdp;
-  (void) userp;
-
-  /* Setup the type-2 "input" security buffer */
-  type_2_desc.ulVersion = SECBUFFER_VERSION;
-  type_2_desc.cBuffers  = 1;
-  type_2_desc.pBuffers  = &type_2_buf;
-  type_2_buf.BufferType = SECBUFFER_TOKEN;
-  type_2_buf.pvBuffer   = ntlm->input_token;
-  type_2_buf.cbBuffer   = curlx_uztoul(ntlm->input_token_len);
-
-  /* Setup the type-3 "output" security buffer */
-  type_3_desc.ulVersion = SECBUFFER_VERSION;
-  type_3_desc.cBuffers  = 1;
-  type_3_desc.pBuffers  = &type_3_buf;
-  type_3_buf.BufferType = SECBUFFER_TOKEN;
-  type_3_buf.pvBuffer   = ntlm->output_token;
-  type_3_buf.cbBuffer   = curlx_uztoul(ntlm->token_max);
-
-  /* Generate our type-3 message */
-  status = s_pSecFn->InitializeSecurityContext(ntlm->credentials,
-                                               ntlm->context,
-                                               (TCHAR *) TEXT(""),
-                                               0, 0, SECURITY_NETWORK_DREP,
-                                               &type_2_desc,
-                                               0, ntlm->context,
-                                               &type_3_desc,
-                                               &attrs, &expiry);
-  if(status != SEC_E_OK) {
-    infof(data, "NTLM handshake failure (type-3 message): Status=%x\n",
-          status);
-
-    return CURLE_RECV_ERROR;
-  }
-
-  /* Base64 encode the response */
-  result = Curl_base64_encode(data, (char *) ntlm->output_token,
-                              type_3_buf.cbBuffer, outptr, outlen);
-
-  Curl_sasl_ntlm_cleanup(ntlm);
-
-  return result;
-}
-
-/*
- * Curl_sasl_ntlm_cleanup()
- *
- * This is used to clean up the ntlm specific data.
- *
- * Parameters:
- *
- * ntlm    [in/out] - The ntlm data struct being cleaned up.
- *
- */
-void Curl_sasl_ntlm_cleanup(struct ntlmdata *ntlm)
-{
-  /* Free our security context */
-  if(ntlm->context) {
-    s_pSecFn->DeleteSecurityContext(ntlm->context);
-    free(ntlm->context);
-    ntlm->context = NULL;
-  }
-
-  /* Free our credentials handle */
-  if(ntlm->credentials) {
-    s_pSecFn->FreeCredentialsHandle(ntlm->credentials);
-    free(ntlm->credentials);
-    ntlm->credentials = NULL;
-  }
-
-  /* Free our identity */
-  Curl_sspi_free_identity(ntlm->p_identity);
-  ntlm->p_identity = NULL;
-
-  /* Free the input and output tokens */
-  Curl_safefree(ntlm->input_token);
-  Curl_safefree(ntlm->output_token);
-
-  /* Reset any variables */
-  ntlm->token_max = 0;
-}
-#endif /* USE_NTLM */
-
-#if defined(USE_KERBEROS5)
-/*
- * Curl_sasl_create_gssapi_user_message()
- *
- * This is used to generate an already encoded GSSAPI (Kerberos V5) user token
- * message ready for sending to the recipient.
- *
- * Parameters:
- *
- * data        [in]     - The session handle.
- * userp       [in]     - The user name in the format User or Domain\User.
- * passdwp     [in]     - The user's password.
- * service     [in]     - The service type such as www, smtp, pop or imap.
- * mutual_auth [in]     - Flag specifing whether or not mutual authentication
- *                        is enabled.
- * chlg64      [in]     - The optional base64 encoded challenge message.
- * krb5        [in/out] - The gssapi 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_sasl_create_gssapi_user_message(struct SessionHandle *data,
-                                              const char *userp,
-                                              const char *passwdp,
-                                              const char *service,
-                                              const bool mutual_auth,
-                                              const char *chlg64,
-                                              struct kerberos5data *krb5,
-                                              char **outptr, size_t *outlen)
-{
-  CURLcode result = CURLE_OK;
-  size_t chlglen = 0;
-  unsigned char *chlg = NULL;
-  CtxtHandle context;
-  PSecPkgInfo SecurityPackage;
-  SecBuffer chlg_buf;
-  SecBuffer resp_buf;
-  SecBufferDesc chlg_desc;
-  SecBufferDesc resp_desc;
-  SECURITY_STATUS status;
-  unsigned long attrs;
-  TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
-
-  if(!krb5->credentials) {
-    /* Query the security package for Kerberos */
-    status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *)
-                                                TEXT(SP_NAME_KERBEROS),
-                                                &SecurityPackage);
-    if(status != SEC_E_OK) {
-      return CURLE_NOT_BUILT_IN;
-    }
-
-    krb5->token_max = SecurityPackage->cbMaxToken;
-
-    /* Release the package buffer as it is not required anymore */
-    s_pSecFn->FreeContextBuffer(SecurityPackage);
-
-    /* Allocate our response buffer */
-    krb5->output_token = malloc(krb5->token_max);
-    if(!krb5->output_token)
-      return CURLE_OUT_OF_MEMORY;
-
-    /* Generate our SPN */
-    krb5->spn = Curl_sasl_build_spn(service, data->easy_conn->host.name);
-    if(!krb5->spn)
-      return CURLE_OUT_OF_MEMORY;
-
-    if(userp && *userp) {
-      /* Populate our identity structure */
-      result = Curl_create_sspi_identity(userp, passwdp, &krb5->identity);
-      if(result)
-        return result;
-
-      /* Allow proper cleanup of the identity structure */
-      krb5->p_identity = &krb5->identity;
-    }
-    else
-      /* Use the current Windows user */
-      krb5->p_identity = NULL;
-
-    /* Allocate our credentials handle */
-    krb5->credentials = malloc(sizeof(CredHandle));
-    if(!krb5->credentials)
-      return CURLE_OUT_OF_MEMORY;
-
-    memset(krb5->credentials, 0, sizeof(CredHandle));
-
-    /* Acquire our credentials handle */
-    status = s_pSecFn->AcquireCredentialsHandle(NULL,
-                                                (TCHAR *)
-                                                TEXT(SP_NAME_KERBEROS),
-                                                SECPKG_CRED_OUTBOUND, NULL,
-                                                krb5->p_identity, NULL, NULL,
-                                                krb5->credentials, &expiry);
-    if(status != SEC_E_OK)
-      return CURLE_LOGIN_DENIED;
-
-    /* Allocate our new context handle */
-    krb5->context = malloc(sizeof(CtxtHandle));
-    if(!krb5->context)
-      return CURLE_OUT_OF_MEMORY;
-
-    memset(krb5->context, 0, sizeof(CtxtHandle));
-  }
-  else {
-    /* Decode the base-64 encoded challenge message */
-    if(strlen(chlg64) && *chlg64 != '=') {
-      result = Curl_base64_decode(chlg64, &chlg, &chlglen);
-      if(result)
-        return result;
-    }
-
-    /* Ensure we have a valid challenge message */
-    if(!chlg) {
-      infof(data, "GSSAPI handshake failure (empty challenge message)\n");
-
-      return CURLE_BAD_CONTENT_ENCODING;
-    }
-
-    /* Setup the challenge "input" security buffer */
-    chlg_desc.ulVersion = SECBUFFER_VERSION;
-    chlg_desc.cBuffers  = 1;
-    chlg_desc.pBuffers  = &chlg_buf;
-    chlg_buf.BufferType = SECBUFFER_TOKEN;
-    chlg_buf.pvBuffer   = chlg;
-    chlg_buf.cbBuffer   = curlx_uztoul(chlglen);
-  }
-
-  /* Setup the response "output" security buffer */
-  resp_desc.ulVersion = SECBUFFER_VERSION;
-  resp_desc.cBuffers  = 1;
-  resp_desc.pBuffers  = &resp_buf;
-  resp_buf.BufferType = SECBUFFER_TOKEN;
-  resp_buf.pvBuffer   = krb5->output_token;
-  resp_buf.cbBuffer   = curlx_uztoul(krb5->token_max);
-
-  /* Generate our challenge-response message */
-  status = s_pSecFn->InitializeSecurityContext(krb5->credentials,
-                                               chlg ? krb5->context : NULL,
-                                               krb5->spn,
-                                               (mutual_auth ?
-                                                 ISC_REQ_MUTUAL_AUTH : 0),
-                                               0, SECURITY_NATIVE_DREP,
-                                               chlg ? &chlg_desc : NULL, 0,
-                                               &context,
-                                               &resp_desc, &attrs,
-                                               &expiry);
-
-  if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) {
-    free(chlg);
-
-    return CURLE_RECV_ERROR;
-  }
-
-  if(memcmp(&context, krb5->context, sizeof(context))) {
-    s_pSecFn->DeleteSecurityContext(krb5->context);
-
-    memcpy(krb5->context, &context, sizeof(context));
-  }
-
-  if(resp_buf.cbBuffer) {
-    /* Base64 encode the response */
-    result = Curl_base64_encode(data, (char *)resp_buf.pvBuffer,
-                                resp_buf.cbBuffer, outptr, outlen);
-  }
-
-  /* Free the decoded challenge */
-  free(chlg);
-
-  return result;
-}
-
-/*
- * Curl_sasl_create_gssapi_security_message()
- *
- * This is used to generate an already encoded GSSAPI (Kerberos V5) security
- * token message ready for sending to the recipient.
- *
- * Parameters:
- *
- * data    [in]     - The session handle.
- * chlg64  [in]     - The optional base64 encoded challenge message.
- * krb5    [in/out] - The gssapi 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_sasl_create_gssapi_security_message(struct SessionHandle *data,
-                                                  const char *chlg64,
-                                                  struct kerberos5data *krb5,
-                                                  char **outptr,
-                                                  size_t *outlen)
-{
-  CURLcode result = CURLE_OK;
-  size_t offset = 0;
-  size_t chlglen = 0;
-  size_t messagelen = 0;
-  size_t appdatalen = 0;
-  unsigned char *chlg = NULL;
-  unsigned char *trailer = NULL;
-  unsigned char *message = NULL;
-  unsigned char *padding = NULL;
-  unsigned char *appdata = NULL;
-  SecBuffer input_buf[2];
-  SecBuffer wrap_buf[3];
-  SecBufferDesc input_desc;
-  SecBufferDesc wrap_desc;
-  unsigned long indata = 0;
-  unsigned long outdata = 0;
-  unsigned long qop = 0;
-  unsigned long sec_layer = 0;
-  unsigned long max_size = 0;
-  SecPkgContext_Sizes sizes;
-  SecPkgCredentials_Names names;
-  SECURITY_STATUS status;
-  char *user_name;
-
-  /* Decode the base-64 encoded input message */
-  if(strlen(chlg64) && *chlg64 != '=') {
-    result = Curl_base64_decode(chlg64, &chlg, &chlglen);
-    if(result)
-      return result;
-  }
-
-  /* Ensure we have a valid challenge message */
-  if(!chlg) {
-    infof(data, "GSSAPI handshake failure (empty security message)\n");
-
-    return CURLE_BAD_CONTENT_ENCODING;
-  }
-
-  /* Get our response size information */
-  status = s_pSecFn->QueryContextAttributes(krb5->context,
-                                            SECPKG_ATTR_SIZES,
-                                            &sizes);
-  if(status != SEC_E_OK) {
-    free(chlg);
-
-    return CURLE_OUT_OF_MEMORY;
-  }
-
-  /* Get the fully qualified username back from the context */
-  status = s_pSecFn->QueryCredentialsAttributes(krb5->credentials,
-                                                SECPKG_CRED_ATTR_NAMES,
-                                                &names);
-  if(status != SEC_E_OK) {
-    free(chlg);
-
-    return CURLE_RECV_ERROR;
-  }
-
-  /* Setup the "input" security buffer */
-  input_desc.ulVersion = SECBUFFER_VERSION;
-  input_desc.cBuffers = 2;
-  input_desc.pBuffers = input_buf;
-  input_buf[0].BufferType = SECBUFFER_STREAM;
-  input_buf[0].pvBuffer = chlg;
-  input_buf[0].cbBuffer = curlx_uztoul(chlglen);
-  input_buf[1].BufferType = SECBUFFER_DATA;
-  input_buf[1].pvBuffer = NULL;
-  input_buf[1].cbBuffer = 0;
-
-  /* Decrypt the inbound challenge and obtain the qop */
-  status = s_pSecFn->DecryptMessage(krb5->context, &input_desc, 0, &qop);
-  if(status != SEC_E_OK) {
-    infof(data, "GSSAPI handshake failure (empty security message)\n");
-
-    free(chlg);
-
-    return CURLE_BAD_CONTENT_ENCODING;
-  }
-
-  /* Not 4 octets long so fail as per RFC4752 Section 3.1 */
-  if(input_buf[1].cbBuffer != 4) {
-    infof(data, "GSSAPI handshake failure (invalid security data)\n");
-
-    free(chlg);
-
-    return CURLE_BAD_CONTENT_ENCODING;
-  }
-
-  /* Copy the data out and free the challenge as it is not required anymore */
-  memcpy(&indata, input_buf[1].pvBuffer, 4);
-  s_pSecFn->FreeContextBuffer(input_buf[1].pvBuffer);
-  free(chlg);
-
-  /* Extract the security layer */
-  sec_layer = indata & 0x000000FF;
-  if(!(sec_layer & KERB_WRAP_NO_ENCRYPT)) {
-    infof(data, "GSSAPI handshake failure (invalid security layer)\n");
-
-    return CURLE_BAD_CONTENT_ENCODING;
-  }
-
-  /* Extract the maximum message size the server can receive */
-  max_size = ntohl(indata & 0xFFFFFF00);
-  if(max_size > 0) {
-    /* The server has told us it supports a maximum receive buffer, however, as
-       we don't require one unless we are encrypting data, we tell the server
-       our receive buffer is zero. */
-    max_size = 0;
-  }
-
-  /* Allocate the trailer */
-  trailer = malloc(sizes.cbSecurityTrailer);
-  if(!trailer)
-    return CURLE_OUT_OF_MEMORY;
-
-  /* Convert the user name to UTF8 when operating with Unicode */
-  user_name = Curl_convert_tchar_to_UTF8(names.sUserName);
-  if(!user_name) {
-    free(trailer);
-
-    return CURLE_OUT_OF_MEMORY;
-  }
-
-  /* Allocate our message */
-  messagelen = sizeof(outdata) + strlen(user_name) + 1;
-  message = malloc(messagelen);
-  if(!message) {
-    free(trailer);
-    Curl_unicodefree(user_name);
-
-    return CURLE_OUT_OF_MEMORY;
-  }
-
-  /* Populate the message with the security layer, client supported receive
-     message size and authorization identity including the 0x00 based
-     terminator. Note: Dispite RFC4752 Section 3.1 stating "The authorization
-     identity is not terminated with the zero-valued (%x00) octet." it seems
-     necessary to include it. */
-  outdata = htonl(max_size) | sec_layer;
-  memcpy(message, &outdata, sizeof(outdata));
-  strcpy((char *) message + sizeof(outdata), user_name);
-  Curl_unicodefree(user_name);
-
-  /* Allocate the padding */
-  padding = malloc(sizes.cbBlockSize);
-  if(!padding) {
-    free(message);
-    free(trailer);
-
-    return CURLE_OUT_OF_MEMORY;
-  }
-
-  /* Setup the "authentication data" security buffer */
-  wrap_desc.ulVersion    = SECBUFFER_VERSION;
-  wrap_desc.cBuffers     = 3;
-  wrap_desc.pBuffers     = wrap_buf;
-  wrap_buf[0].BufferType = SECBUFFER_TOKEN;
-  wrap_buf[0].pvBuffer   = trailer;
-  wrap_buf[0].cbBuffer   = sizes.cbSecurityTrailer;
-  wrap_buf[1].BufferType = SECBUFFER_DATA;
-  wrap_buf[1].pvBuffer   = message;
-  wrap_buf[1].cbBuffer   = curlx_uztoul(messagelen);
-  wrap_buf[2].BufferType = SECBUFFER_PADDING;
-  wrap_buf[2].pvBuffer   = padding;
-  wrap_buf[2].cbBuffer   = sizes.cbBlockSize;
-
-  /* Encrypt the data */
-  status = s_pSecFn->EncryptMessage(krb5->context, KERB_WRAP_NO_ENCRYPT,
-                                    &wrap_desc, 0);
-  if(status != SEC_E_OK) {
-    free(padding);
-    free(message);
-    free(trailer);
-
-    return CURLE_OUT_OF_MEMORY;
-  }
-
-  /* Allocate the encryption (wrap) buffer */
-  appdatalen = wrap_buf[0].cbBuffer + wrap_buf[1].cbBuffer +
-               wrap_buf[2].cbBuffer;
-  appdata = malloc(appdatalen);
-  if(!appdata) {
-    free(padding);
-    free(message);
-    free(trailer);
-
-    return CURLE_OUT_OF_MEMORY;
-  }
-
-  /* Populate the encryption buffer */
-  memcpy(appdata, wrap_buf[0].pvBuffer, wrap_buf[0].cbBuffer);
-  offset += wrap_buf[0].cbBuffer;
-  memcpy(appdata + offset, wrap_buf[1].pvBuffer, wrap_buf[1].cbBuffer);
-  offset += wrap_buf[1].cbBuffer;
-  memcpy(appdata + offset, wrap_buf[2].pvBuffer, wrap_buf[2].cbBuffer);
-
-  /* Base64 encode the response */
-  result = Curl_base64_encode(data, (char *)appdata, appdatalen, outptr,
-                              outlen);
-
-  /* Free all of our local buffers */
-  free(appdata);
-  free(padding);
-  free(message);
-  free(trailer);
-
-  return result;
-}
-
-/*
- * Curl_sasl_gssapi_cleanup()
- *
- * This is used to clean up the gssapi specific data.
- *
- * Parameters:
- *
- * krb5     [in/out] - The kerberos 5 data struct being cleaned up.
- *
- */
-void Curl_sasl_gssapi_cleanup(struct kerberos5data *krb5)
-{
-  /* Free our security context */
-  if(krb5->context) {
-    s_pSecFn->DeleteSecurityContext(krb5->context);
-    free(krb5->context);
-    krb5->context = NULL;
-  }
-
-  /* Free our credentials handle */
-  if(krb5->credentials) {
-    s_pSecFn->FreeCredentialsHandle(krb5->credentials);
-    free(krb5->credentials);
-    krb5->credentials = NULL;
-  }
-
-  /* Free our identity */
-  Curl_sspi_free_identity(krb5->p_identity);
-  krb5->p_identity = NULL;
-
-  /* Free the SPN and output token */
-  Curl_safefree(krb5->spn);
-  Curl_safefree(krb5->output_token);
-
-  /* Reset any variables */
-  krb5->token_max = 0;
-}
-#endif /* USE_KERBEROS5 */
-
-#endif /* USE_WINDOWS_SSPI */
diff --git a/lib/curl_sec.h b/lib/curl_sec.h
index 6c48da2..3f94e14 100644
--- a/lib/curl_sec.h
+++ b/lib/curl_sec.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/curl_setup.h b/lib/curl_setup.h
index ab0c139..7dcc4c4 100644
--- a/lib/curl_setup.h
+++ b/lib/curl_setup.h
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -181,9 +181,6 @@
 #  ifndef CURL_DISABLE_SMTP
 #    define CURL_DISABLE_SMTP
 #  endif
-#  ifndef CURL_DISABLE_RTSP
-#    define CURL_DISABLE_RTSP
-#  endif
 #  ifndef CURL_DISABLE_RTMP
 #    define CURL_DISABLE_RTMP
 #  endif
@@ -225,6 +222,15 @@
 #endif
 
 /*
+ * Use getaddrinfo to resolve the IPv4 address literal. If the current network
+ * interface doesn’t support IPv4, but supports IPv6, NAT64, and DNS64,
+ * performing this task will result in a synthesized IPv6 address.
+ */
+#ifdef  __APPLE__
+#define USE_RESOLVE_ON_IPS 1
+#endif
+
+/*
  * Include header files for windows builds before redefining anything.
  * Use this preprocessor block only to include or exclude windows.h,
  * winsock2.h, ws2tcpip.h or winsock.h. Any other windows thing belongs
@@ -249,7 +255,7 @@
 #  ifdef HAVE_WINSOCK2_H
 #    include <winsock2.h>
 #    ifdef HAVE_WS2TCPIP_H
-#       include <ws2tcpip.h>
+#      include <ws2tcpip.h>
 #    endif
 #  else
 #    ifdef HAVE_WINSOCK_H
@@ -476,7 +482,7 @@
 #  endif
 
 #  ifndef fileno /* sunos 4 have this as a macro! */
-     int fileno( FILE *stream);
+     int fileno(FILE *stream);
 #  endif
 
 #endif /* WIN32 */
@@ -484,9 +490,10 @@
 /*
  * msvc 6.0 requires PSDK in order to have INET6_ADDRSTRLEN
  * defined in ws2tcpip.h as well as to provide IPv6 support.
+ * Does not apply if lwIP is used.
  */
 
-#if defined(_MSC_VER) && !defined(__POCC__)
+#if defined(_MSC_VER) && !defined(__POCC__) && !defined(USE_LWIPSOCK)
 #  if !defined(HAVE_WS2TCPIP_H) || \
      ((_MSC_VER < 1300) && !defined(INET6_ADDRSTRLEN))
 #    undef HAVE_GETADDRINFO_THREADSAFE
@@ -530,6 +537,7 @@
 #  define CURLRES_ARES
 /* now undef the stock libc functions just to avoid them being used */
 #  undef HAVE_GETADDRINFO
+#  undef HAVE_FREEADDRINFO
 #  undef HAVE_GETHOSTBYNAME
 #elif defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
 #  define CURLRES_ASYNCH
@@ -605,7 +613,7 @@ int netware_init(void);
 #define LIBIDN_REQUIRED_VERSION "0.4.1"
 
 #if defined(USE_GNUTLS) || defined(USE_OPENSSL) || defined(USE_NSS) || \
-    defined(USE_POLARSSL) || defined(USE_AXTLS) || \
+    defined(USE_POLARSSL) || defined(USE_AXTLS) || defined(USE_MBEDTLS) || \
     defined(USE_CYASSL) || defined(USE_SCHANNEL) || \
     defined(USE_DARWINSSL) || defined(USE_GSKIT)
 #define USE_SSL    /* SSL support has been enabled */
@@ -629,13 +637,9 @@ int netware_init(void);
     defined(USE_GNUTLS) || defined(USE_NSS) || defined(USE_DARWINSSL) || \
     defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO)
 
-#ifdef HAVE_BORINGSSL /* BoringSSL is not NTLM capable */
-#undef USE_NTLM
-#else
 #define USE_NTLM
 #endif
 #endif
-#endif
 
 /* non-configure builds may define CURL_WANTS_CA_BUNDLE_ENV */
 #if defined(CURL_WANTS_CA_BUNDLE_ENV) && !defined(CURL_CA_BUNDLE)
@@ -677,7 +681,7 @@ int netware_init(void);
  * Ensure that Winsock and lwIP TCP/IP stacks are not mixed.
  */
 
-#if defined(__LWIP_OPT_H__)
+#if defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H)
 #  if defined(SOCKET) || \
      defined(USE_WINSOCK) || \
      defined(HAVE_WINSOCK_H) || \
@@ -708,7 +712,7 @@ int netware_init(void);
 #endif
 
 /* In Windows the default file mode is text but an application can override it.
-Therefore we specify it explicitly. https://github.com/bagder/curl/pull/258
+Therefore we specify it explicitly. https://github.com/curl/curl/pull/258
 */
 #if defined(WIN32) || defined(MSDOS)
 #define FOPEN_READTEXT "rt"
@@ -727,4 +731,19 @@ endings either CRLF or LF so 't' is appropriate.
 #define FOPEN_WRITETEXT "w"
 #endif
 
+/* WinSock destroys recv() buffer when send() failed.
+ * Enabled automatically for Windows and for Cygwin as Cygwin sockets are
+ * wrappers for WinSock sockets. https://github.com/curl/curl/issues/657
+ * Define DONT_USE_RECV_BEFORE_SEND_WORKAROUND to force disable workaround.
+ */
+#if !defined(DONT_USE_RECV_BEFORE_SEND_WORKAROUND)
+#  if defined(WIN32) || defined(__CYGWIN__)
+#    define USE_RECV_BEFORE_SEND_WORKAROUND
+#  endif
+#else  /* DONT_USE_RECV_BEFORE_SEND_WORKAROUNDS */
+#  ifdef USE_RECV_BEFORE_SEND_WORKAROUND
+#    undef USE_RECV_BEFORE_SEND_WORKAROUND
+#  endif
+#endif /* DONT_USE_RECV_BEFORE_SEND_WORKAROUNDS */
+
 #endif /* HEADER_CURL_SETUP_H */
diff --git a/lib/curl_setup_once.h b/lib/curl_setup_once.h
index 69d6d47..4da8349 100644
--- a/lib/curl_setup_once.h
+++ b/lib/curl_setup_once.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/curl_sspi.c b/lib/curl_sspi.c
index 070424d..ee3f1b1 100644
--- a/lib/curl_sspi.c
+++ b/lib/curl_sspi.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -27,6 +27,7 @@
 #include <curl/curl.h>
 #include "curl_sspi.h"
 #include "curl_multibyte.h"
+#include "system_win32.h"
 #include "warnless.h"
 
 /* The last #include files should be: */
@@ -66,7 +67,6 @@ PSecurityFunctionTable s_pSecFn = NULL;
  */
 CURLcode Curl_sspi_global_init(void)
 {
-  bool securityDll = FALSE;
   INITSECURITYINTERFACE_FN pInitSecurityInterface;
 
   /* If security interface is not yet initialized try to do this */
@@ -74,52 +74,12 @@ CURLcode Curl_sspi_global_init(void)
     /* Security Service Provider Interface (SSPI) functions are located in
      * security.dll on WinNT 4.0 and in secur32.dll on Win9x. Win2K and XP
      * have both these DLLs (security.dll forwards calls to secur32.dll) */
-    DWORD majorVersion = 4;
-    DWORD platformId = VER_PLATFORM_WIN32_NT;
-
-#if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_WIN2K) || \
-    (_WIN32_WINNT < _WIN32_WINNT_WIN2K)
-    OSVERSIONINFO osver;
-
-    memset(&osver, 0, sizeof(osver));
-    osver.dwOSVersionInfoSize = sizeof(osver);
-
-    /* Find out Windows version */
-    if(!GetVersionEx(&osver))
-      return CURLE_FAILED_INIT;
-
-    /* Verify the major version number == 4 and platform id == WIN_NT */
-    if(osver.dwMajorVersion == majorVersion &&
-       osver.dwPlatformId == platformId)
-      securityDll = TRUE;
-#else
-    ULONGLONG cm;
-    OSVERSIONINFOEX osver;
-
-    memset(&osver, 0, sizeof(osver));
-    osver.dwOSVersionInfoSize = sizeof(osver);
-    osver.dwMajorVersion = majorVersion;
-    osver.dwPlatformId = platformId;
-
-    cm = VerSetConditionMask(0, VER_MAJORVERSION, VER_EQUAL);
-    cm = VerSetConditionMask(cm, VER_MINORVERSION, VER_GREATER_EQUAL);
-    cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
-    cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL);
-    cm = VerSetConditionMask(cm, VER_PLATFORMID, VER_EQUAL);
-
-    /* Verify the major version number == 4 and platform id == WIN_NT */
-    if(VerifyVersionInfo(&osver, (VER_MAJORVERSION | VER_MINORVERSION |
-                                  VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR |
-                                  VER_PLATFORMID),
-                         cm))
-      securityDll = TRUE;
-#endif
 
     /* Load SSPI dll into the address space of the calling process */
-    if(securityDll)
-      s_hSecDll = LoadLibrary(TEXT("security.dll"));
+    if(Curl_verify_windows_version(4, 0, PLATFORM_WINNT, VERSION_EQUAL))
+      s_hSecDll = Curl_load_library(TEXT("security.dll"));
     else
-      s_hSecDll = LoadLibrary(TEXT("secur32.dll"));
+      s_hSecDll = Curl_load_library(TEXT("secur32.dll"));
     if(!s_hSecDll)
       return CURLE_FAILED_INIT;
 
diff --git a/lib/curl_sspi.h b/lib/curl_sspi.h
index 8655715..2bbf947 100644
--- a/lib/curl_sspi.h
+++ b/lib/curl_sspi.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -327,6 +327,10 @@ extern PSecurityFunctionTable s_pSecFn;
 # define SEC_I_SIGNATURE_NEEDED               ((HRESULT)0x0009035CL)
 #endif
 
+#ifndef CRYPT_E_REVOKED
+# define CRYPT_E_REVOKED                      ((HRESULT)0x80092010L)
+#endif
+
 #ifdef UNICODE
 #  define SECFLAG_WINNT_AUTH_IDENTITY \
      (unsigned long)SEC_WINNT_AUTH_IDENTITY_UNICODE
diff --git a/lib/curl_threads.c b/lib/curl_threads.c
index f9b812e..c98d8bb 100644
--- a/lib/curl_threads.c
+++ b/lib/curl_threads.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -22,6 +22,8 @@
 
 #include "curl_setup.h"
 
+#include <curl/curl.h>
+
 #if defined(USE_THREADS_POSIX)
 #  ifdef HAVE_PTHREAD_H
 #    include <pthread.h>
diff --git a/lib/curl_threads.h b/lib/curl_threads.h
index 0f3191a..8cbac63 100644
--- a/lib/curl_threads.h
+++ b/lib/curl_threads.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/curlx.h b/lib/curlx.h
index 979e7d7..448a34f 100644
--- a/lib/curlx.h
+++ b/lib/curlx.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/dict.c b/lib/dict.c
index 06d7699..a7b5965 100644
--- a/lib/dict.c
+++ b/lib/dict.c
@@ -9,7 +9,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -91,7 +91,7 @@ const struct Curl_handler Curl_handler_dict = {
   PROTOPT_NONE | PROTOPT_NOURLQUERY      /* flags */
 };
 
-static char *unescape_word(struct SessionHandle *data, const char *inputbuff)
+static char *unescape_word(struct Curl_easy *data, const char *inputbuff)
 {
   char *newp;
   char *dictp;
@@ -133,7 +133,7 @@ static CURLcode dict_do(struct connectdata *conn, bool *done)
   char *nthdef = NULL; /* This is not part of the protocol, but required
                           by RFC 2229 */
   CURLcode result=CURLE_OK;
-  struct SessionHandle *data=conn->data;
+  struct Curl_easy *data=conn->data;
   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
 
   char *path = data->state.path;
diff --git a/lib/dict.h b/lib/dict.h
index 44fd9d4..12c0f33 100644
--- a/lib/dict.h
+++ b/lib/dict.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/dotdot.c b/lib/dotdot.c
index ae16941..ea7c8a0 100644
--- a/lib/dotdot.c
+++ b/lib/dotdot.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -22,19 +22,22 @@
 
 #include "curl_setup.h"
 
-#include "dotdot.h"
+#include <curl/curl.h>
 
+#include "dotdot.h"
 #include "curl_memory.h"
+
 /* The last #include file should be: */
 #include "memdebug.h"
 
 /*
  * "Remove Dot Segments"
- * http://tools.ietf.org/html/rfc3986#section-5.2.4
+ * https://tools.ietf.org/html/rfc3986#section-5.2.4
  */
 
 /*
  * Curl_dedotdotify()
+ * @unittest: 1395
  *
  * This function gets a zero-terminated path with dot and dotdot sequences
  * passed in and strips them off according to the rules in RFC 3986 section
@@ -68,6 +71,12 @@ char *Curl_dedotdotify(const char *input)
   orgclone = clone;
   outptr = out;
 
+  if(!*clone) {
+    /* zero length string, return that */
+    free(out);
+    return clone;
+  }
+
   /*
    * To handle query-parts properly, we must find it and remove it during the
    * dotdot-operation and then append it again at the end to the output
diff --git a/lib/dotdot.h b/lib/dotdot.h
index cd57822..fac8e6f 100644
--- a/lib/dotdot.h
+++ b/lib/dotdot.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/easy.c b/lib/easy.c
index 316acb1..dc7139f 100644
--- a/lib/easy.c
+++ b/lib/easy.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -64,7 +64,6 @@
 #include "easyif.h"
 #include "select.h"
 #include "sendf.h" /* for failf function prototype */
-#include "curl_ntlm.h"
 #include "connect.h" /* for Curl_getconnectinfo */
 #include "slist.h"
 #include "amigaos.h"
@@ -74,12 +73,13 @@
 #include "multiif.h"
 #include "sigpipe.h"
 #include "ssh.h"
+/* The last 3 #include files should be in this order */
 #include "curl_printf.h"
-
-/* The last #include files should be: */
 #include "curl_memory.h"
 #include "memdebug.h"
 
+void Curl_version_init(void);
+
 /* win32_cleanup() is for win32 socket cleanup functionality, the opposite
    of win32_init() */
 static void win32_cleanup(void)
@@ -120,8 +120,8 @@ static CURLcode win32_init(void)
   /* wVersionRequested in wVersion. wHighVersion contains the */
   /* highest supported version. */
 
-  if(LOBYTE( wsaData.wVersion ) != LOBYTE(wVersionRequested) ||
-     HIBYTE( wsaData.wVersion ) != HIBYTE(wVersionRequested) ) {
+  if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) ||
+     HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested) ) {
     /* Tell the user that we couldn't find a useable */
 
     /* winsock.dll. */
@@ -220,20 +220,22 @@ curl_calloc_callback Curl_ccalloc;
  * curl_global_init() globally initializes cURL given a bitwise set of the
  * different features of what to initialize.
  */
-CURLcode curl_global_init(long flags)
+static CURLcode global_init(long flags, bool memoryfuncs)
 {
   if(initialized++)
     return CURLE_OK;
 
-  /* Setup the default memory functions here (again) */
-  Curl_cmalloc = (curl_malloc_callback)malloc;
-  Curl_cfree = (curl_free_callback)free;
-  Curl_crealloc = (curl_realloc_callback)realloc;
-  Curl_cstrdup = (curl_strdup_callback)system_strdup;
-  Curl_ccalloc = (curl_calloc_callback)calloc;
+  if(memoryfuncs) {
+    /* Setup the default memory functions here (again) */
+    Curl_cmalloc = (curl_malloc_callback)malloc;
+    Curl_cfree = (curl_free_callback)free;
+    Curl_crealloc = (curl_realloc_callback)realloc;
+    Curl_cstrdup = (curl_strdup_callback)system_strdup;
+    Curl_ccalloc = (curl_calloc_callback)calloc;
 #if defined(WIN32) && defined(UNICODE)
-  Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup;
+    Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup;
 #endif
+  }
 
   if(flags & CURL_GLOBAL_SSL)
     if(!Curl_ssl_init()) {
@@ -269,6 +271,8 @@ CURLcode curl_global_init(long flags)
     return CURLE_FAILED_INIT;
   }
 
+  (void)Curl_ipv6works();
+
 #if defined(USE_LIBSSH2) && defined(HAVE_LIBSSH2_INIT)
   if(libssh2_init(0)) {
     DEBUGF(fprintf(stderr, "Error: libssh2_init failed\n"));
@@ -279,11 +283,23 @@ CURLcode curl_global_init(long flags)
   if(flags & CURL_GLOBAL_ACK_EINTR)
     Curl_ack_eintr = 1;
 
-  init_flags  = flags;
+  init_flags = flags;
+
+  Curl_version_init();
 
   return CURLE_OK;
 }
 
+
+/**
+ * curl_global_init() globally initializes cURL given a bitwise set of the
+ * different features of what to initialize.
+ */
+CURLcode curl_global_init(long flags)
+{
+  return global_init(flags, TRUE);
+}
+
 /*
  * curl_global_init_mem() globally initializes cURL and also registers the
  * user provided callback routines.
@@ -292,8 +308,6 @@ CURLcode curl_global_init_mem(long flags, curl_malloc_callback m,
                               curl_free_callback f, curl_realloc_callback r,
                               curl_strdup_callback s, curl_calloc_callback c)
 {
-  CURLcode result = CURLE_OK;
-
   /* Invalid input, return immediately */
   if(!m || !f || !r || !s || !c)
     return CURLE_FAILED_INIT;
@@ -306,17 +320,16 @@ CURLcode curl_global_init_mem(long flags, curl_malloc_callback m,
     return CURLE_OK;
   }
 
-  /* Call the actual init function first */
-  result = curl_global_init(flags);
-  if(!result) {
-    Curl_cmalloc = m;
-    Curl_cfree = f;
-    Curl_cstrdup = s;
-    Curl_crealloc = r;
-    Curl_ccalloc = c;
-  }
+  /* set memory functions before global_init() in case it wants memory
+     functions */
+  Curl_cmalloc = m;
+  Curl_cfree = f;
+  Curl_cstrdup = s;
+  Curl_crealloc = r;
+  Curl_ccalloc = c;
 
-  return result;
+  /* Call the actual init function, but without setting */
+  return global_init(flags, FALSE);
 }
 
 /**
@@ -354,10 +367,10 @@ void curl_global_cleanup(void)
  * curl_easy_init() is the external interface to alloc, setup and init an
  * easy handle that is returned. If anything goes wrong, NULL is returned.
  */
-CURL *curl_easy_init(void)
+struct Curl_easy *curl_easy_init(void)
 {
   CURLcode result;
-  struct SessionHandle *data;
+  struct Curl_easy *data;
 
   /* Make sure we inited the global SSL stuff */
   if(!initialized) {
@@ -385,13 +398,12 @@ CURL *curl_easy_init(void)
  */
 
 #undef curl_easy_setopt
-CURLcode curl_easy_setopt(CURL *curl, CURLoption tag, ...)
+CURLcode curl_easy_setopt(struct Curl_easy *data, CURLoption tag, ...)
 {
   va_list arg;
-  struct SessionHandle *data = curl;
   CURLcode result;
 
-  if(!curl)
+  if(!data)
     return CURLE_BAD_FUNCTION_ARGUMENT;
 
   va_start(arg, tag);
@@ -423,7 +435,7 @@ struct events {
  * updated.
  */
 
-static int events_timer(CURLM *multi,    /* multi handle */
+static int events_timer(struct Curl_multi *multi,    /* multi handle */
                         long timeout_ms, /* see above */
                         void *userp)    /* private callback pointer */
 {
@@ -478,7 +490,7 @@ static short socketcb2poll(int pollmask)
  * Callback that gets called with information about socket activity to
  * monitor.
  */
-static int events_socket(CURL *easy,      /* easy handle */
+static int events_socket(struct Curl_easy *easy,      /* easy handle */
                          curl_socket_t s, /* socket */
                          int what,        /* see above */
                          void *userp,     /* private callback
@@ -532,14 +544,18 @@ static int events_socket(CURL *easy,      /* easy handle */
     }
     else {
       m = malloc(sizeof(struct socketmonitor));
-      m->next = ev->list;
-      m->socket.fd = s;
-      m->socket.events = socketcb2poll(what);
-      m->socket.revents = 0;
-      ev->list = m;
-      infof(easy, "socket cb: socket %d ADDED as %s%s\n", s,
-            what&CURL_POLL_IN?"IN":"",
-            what&CURL_POLL_OUT?"OUT":"");
+      if(m) {
+        m->next = ev->list;
+        m->socket.fd = s;
+        m->socket.events = socketcb2poll(what);
+        m->socket.revents = 0;
+        ev->list = m;
+        infof(easy, "socket cb: socket %d ADDED as %s%s\n", s,
+              what&CURL_POLL_IN?"IN":"",
+              what&CURL_POLL_OUT?"OUT":"");
+      }
+      else
+        return CURLE_OUT_OF_MEMORY;
     }
   }
 
@@ -552,7 +568,7 @@ static int events_socket(CURL *easy,      /* easy handle */
  *
  * Do the multi handle setups that only event-based transfers need.
  */
-static void events_setup(CURLM *multi, struct events *ev)
+static void events_setup(struct Curl_multi *multi, struct events *ev)
 {
   /* timer callback */
   curl_multi_setopt(multi, CURLMOPT_TIMERFUNCTION, events_timer);
@@ -609,7 +625,7 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
     if(0 == pollrc) {
       /* timeout! */
       ev->ms = 0;
-      /* fprintf(stderr, "call curl_multi_socket_action( TIMEOUT )\n"); */
+      /* fprintf(stderr, "call curl_multi_socket_action(TIMEOUT)\n"); */
       mcode = curl_multi_socket_action(multi, CURL_SOCKET_TIMEOUT, 0,
                                        &ev->running_handles);
     }
@@ -619,7 +635,7 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
         if(fds[i].revents) {
           /* socket activity, tell libcurl */
           int act = poll2cselect(fds[i].revents); /* convert */
-          infof(multi->easyp, "call curl_multi_socket_action( socket %d )\n",
+          infof(multi->easyp, "call curl_multi_socket_action(socket %d)\n",
                 fds[i].fd);
           mcode = curl_multi_socket_action(multi, fds[i].fd, act,
                                            &ev->running_handles);
@@ -656,7 +672,7 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
  *
  * Runs a transfer in a blocking manner using the events-based API
  */
-static CURLcode easy_events(CURLM *multi)
+static CURLcode easy_events(struct Curl_multi *multi)
 {
   struct events evs= {2, FALSE, 0, NULL, 0};
 
@@ -670,7 +686,7 @@ static CURLcode easy_events(CURLM *multi)
 #define easy_events(x) CURLE_NOT_BUILT_IN
 #endif
 
-static CURLcode easy_transfer(CURLM *multi)
+static CURLcode easy_transfer(struct Curl_multi *multi)
 {
   bool done = FALSE;
   CURLMcode mcode = CURLM_OK;
@@ -681,26 +697,22 @@ static CURLcode easy_transfer(CURLM *multi)
 
   while(!done && !mcode) {
     int still_running = 0;
-    int ret;
+    int rc;
 
     before = curlx_tvnow();
-    mcode = curl_multi_wait(multi, NULL, 0, 1000, &ret);
+    mcode = curl_multi_wait(multi, NULL, 0, 1000, &rc);
 
-    if(mcode == CURLM_OK) {
-      if(ret == -1) {
-        /* poll() failed not on EINTR, indicate a network problem */
-        result = CURLE_RECV_ERROR;
-        break;
-      }
-      else if(ret == 0) {
+    if(!mcode) {
+      if(!rc) {
         struct timeval after = curlx_tvnow();
+
         /* 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) {
           without_fds++;
           if(without_fds > 2) {
-            int sleep_ms = without_fds < 10 ? (1 << (without_fds-1)): 1000;
+            int sleep_ms = without_fds < 10 ? (1 << (without_fds - 1)) : 1000;
             Curl_wait_ms(sleep_ms);
           }
         }
@@ -716,8 +728,7 @@ static CURLcode easy_transfer(CURLM *multi)
     }
 
     /* only read 'still_running' if curl_multi_perform() return OK */
-    if((mcode == CURLM_OK) && !still_running) {
-      int rc;
+    if(!mcode && !still_running) {
       CURLMsg *msg = curl_multi_info_read(multi, &rc);
       if(msg) {
         result = msg->data.result;
@@ -728,10 +739,10 @@ static CURLcode easy_transfer(CURLM *multi)
 
   /* Make sure to return some kind of error if there was a multi problem */
   if(mcode) {
-    return (mcode == CURLM_OUT_OF_MEMORY) ? CURLE_OUT_OF_MEMORY :
-            /* The other multi errors should never happen, so return
-               something suitably generic */
-            CURLE_BAD_FUNCTION_ARGUMENT;
+    result = (mcode == CURLM_OUT_OF_MEMORY) ? CURLE_OUT_OF_MEMORY :
+              /* The other multi errors should never happen, so return
+                 something suitably generic */
+              CURLE_BAD_FUNCTION_ARGUMENT;
   }
 
   return result;
@@ -755,9 +766,9 @@ static CURLcode easy_transfer(CURLM *multi)
  * DEBUG: if 'events' is set TRUE, this function will use a replacement engine
  * instead of curl_multi_perform() and use curl_multi_socket_action().
  */
-static CURLcode easy_perform(struct SessionHandle *data, bool events)
+static CURLcode easy_perform(struct Curl_easy *data, bool events)
 {
-  CURLM *multi;
+  struct Curl_multi *multi;
   CURLMcode mcode;
   CURLcode result = CURLE_OK;
   SIGPIPE_VARIABLE(pipe_st);
@@ -817,9 +828,9 @@ static CURLcode easy_perform(struct SessionHandle *data, bool events)
  * curl_easy_perform() is the external interface that performs a blocking
  * transfer as previously setup.
  */
-CURLcode curl_easy_perform(CURL *easy)
+CURLcode curl_easy_perform(struct Curl_easy *data)
 {
-  return easy_perform(easy, FALSE);
+  return easy_perform(data, FALSE);
 }
 
 #ifdef CURLDEBUG
@@ -827,9 +838,9 @@ CURLcode curl_easy_perform(CURL *easy)
  * curl_easy_perform_ev() is the external interface that performs a blocking
  * transfer using the event-based API internally.
  */
-CURLcode curl_easy_perform_ev(CURL *easy)
+CURLcode curl_easy_perform_ev(struct Curl_easy *data)
 {
-  return easy_perform(easy, TRUE);
+  return easy_perform(data, TRUE);
 }
 
 #endif
@@ -838,9 +849,8 @@ CURLcode curl_easy_perform_ev(CURL *easy)
  * curl_easy_cleanup() is the external interface to cleaning/freeing the given
  * easy handle.
  */
-void curl_easy_cleanup(CURL *curl)
+void curl_easy_cleanup(struct Curl_easy *data)
 {
-  struct SessionHandle *data = (struct SessionHandle *)curl;
   SIGPIPE_VARIABLE(pipe_st);
 
   if(!data)
@@ -856,12 +866,11 @@ void curl_easy_cleanup(CURL *curl)
  * information from a performed transfer and similar.
  */
 #undef curl_easy_getinfo
-CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...)
+CURLcode curl_easy_getinfo(struct Curl_easy *data, CURLINFO info, ...)
 {
   va_list arg;
   void *paramp;
   CURLcode result;
-  struct SessionHandle *data = (struct SessionHandle *)curl;
 
   va_start(arg, info);
   paramp = va_arg(arg, void *);
@@ -877,11 +886,9 @@ CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...)
  * given input easy handle. The returned handle will be a new working handle
  * with all options set exactly as the input source handle.
  */
-CURL *curl_easy_duphandle(CURL *incurl)
+struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
 {
-  struct SessionHandle *data=(struct SessionHandle *)incurl;
-
-  struct SessionHandle *outcurl = calloc(1, sizeof(struct SessionHandle));
+  struct Curl_easy *outcurl = calloc(1, sizeof(struct Curl_easy));
   if(NULL == outcurl)
     goto fail;
 
@@ -972,10 +979,8 @@ CURL *curl_easy_duphandle(CURL *incurl)
  * curl_easy_reset() is an external interface that allows an app to re-
  * initialize a session handle to the default values.
  */
-void curl_easy_reset(CURL *curl)
+void curl_easy_reset(struct Curl_easy *data)
 {
-  struct SessionHandle *data = (struct SessionHandle *)curl;
-
   Curl_safefree(data->state.pathbuffer);
 
   data->state.path = NULL;
@@ -1004,9 +1009,8 @@ void curl_easy_reset(CURL *curl)
  *
  * Action is a bitmask consisting of CURLPAUSE_* bits in curl/curl.h
  */
-CURLcode curl_easy_pause(CURL *curl, int action)
+CURLcode curl_easy_pause(struct Curl_easy *data, int action)
 {
-  struct SessionHandle *data = (struct SessionHandle *)curl;
   struct SingleRequest *k = &data->req;
   CURLcode result = CURLE_OK;
 
@@ -1046,7 +1050,7 @@ CURLcode curl_easy_pause(CURL *curl, int action)
 }
 
 
-static CURLcode easy_connection(struct SessionHandle *data,
+static CURLcode easy_connection(struct Curl_easy *data,
                                 curl_socket_t *sfd,
                                 struct connectdata **connp)
 {
@@ -1074,13 +1078,13 @@ static CURLcode easy_connection(struct SessionHandle *data,
  * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
  * Returns CURLE_OK on success, error code on error.
  */
-CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, size_t *n)
+CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen,
+                        size_t *n)
 {
   curl_socket_t sfd;
   CURLcode result;
   ssize_t n1;
   struct connectdata *c;
-  struct SessionHandle *data = (struct SessionHandle *)curl;
 
   result = easy_connection(data, &sfd, &c);
   if(result)
@@ -1101,14 +1105,13 @@ CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, size_t *n)
  * Sends data over the connected socket. Use after successful
  * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
  */
-CURLcode curl_easy_send(CURL *curl, const void *buffer, size_t buflen,
-                        size_t *n)
+CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer,
+                        size_t buflen, size_t *n)
 {
   curl_socket_t sfd;
   CURLcode result;
   ssize_t n1;
   struct connectdata *c = NULL;
-  struct SessionHandle *data = (struct SessionHandle *)curl;
 
   result = easy_connection(data, &sfd, &c);
   if(result)
diff --git a/lib/easyif.h b/lib/easyif.h
index 043ff43..f6132cc 100644
--- a/lib/easyif.h
+++ b/lib/easyif.h
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -26,7 +26,7 @@
  * Prototypes for library-wide functions provided by easy.c
  */
 #ifdef CURLDEBUG
-CURL_EXTERN CURLcode curl_easy_perform_ev(CURL *easy);
+CURL_EXTERN CURLcode curl_easy_perform_ev(struct Curl_easy *easy);
 #endif
 
 #endif /* HEADER_CURL_EASYIF_H */
diff --git a/lib/escape.c b/lib/escape.c
index 24abb93..04230b4 100644
--- a/lib/escape.c
+++ b/lib/escape.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -31,15 +31,14 @@
 #include "warnless.h"
 #include "non-ascii.h"
 #include "escape.h"
+/* The last 3 #include files should be in this order */
 #include "curl_printf.h"
-
-/* The last #include files should be: */
 #include "curl_memory.h"
 #include "memdebug.h"
 
 /* Portable character check (remember EBCDIC). Do not use isalnum() because
    its behavior is altered by the current locale.
-   See http://tools.ietf.org/html/rfc3986#section-2.3
+   See https://tools.ietf.org/html/rfc3986#section-2.3
 */
 static bool Curl_isunreserved(unsigned char in)
 {
@@ -76,7 +75,8 @@ char *curl_unescape(const char *string, int length)
   return curl_easy_unescape(NULL, string, length, NULL);
 }
 
-char *curl_easy_escape(CURL *handle, const char *string, int inlength)
+char *curl_easy_escape(struct Curl_easy *data, const char *string,
+                       int inlength)
 {
   size_t alloc = (inlength?(size_t)inlength:strlen(string))+1;
   char *ns;
@@ -105,7 +105,7 @@ char *curl_easy_escape(CURL *handle, const char *string, int inlength)
         alloc *= 2;
         testing_ptr = realloc(ns, alloc);
         if(!testing_ptr) {
-          free( ns );
+          free(ns);
           return NULL;
         }
         else {
@@ -113,7 +113,7 @@ char *curl_easy_escape(CURL *handle, const char *string, int inlength)
         }
       }
 
-      result = Curl_convert_to_network(handle, &in, 1);
+      result = Curl_convert_to_network(data, &in, 1);
       if(result) {
         /* Curl_convert_to_network calls failf if unsuccessful */
         free(ns);
@@ -140,7 +140,7 @@ char *curl_easy_escape(CURL *handle, const char *string, int inlength)
  * *olen. If length == 0, the length is assumed to be strlen(string).
  *
  */
-CURLcode Curl_urldecode(struct SessionHandle *data,
+CURLcode Curl_urldecode(struct Curl_easy *data,
                         const char *string, size_t length,
                         char **ostring, size_t *olen,
                         bool reject_ctrl)
@@ -207,13 +207,13 @@ CURLcode Curl_urldecode(struct SessionHandle *data,
  * If length == 0, the length is assumed to be strlen(string).
  * If olen == NULL, no output length is stored.
  */
-char *curl_easy_unescape(CURL *handle, const char *string, int length,
-                         int *olen)
+char *curl_easy_unescape(struct Curl_easy *data, const char *string,
+                         int length, int *olen)
 {
   char *str = NULL;
   size_t inputlen = length;
   size_t outputlen;
-  CURLcode res = Curl_urldecode(handle, string, inputlen, &str, &outputlen,
+  CURLcode res = Curl_urldecode(data, string, inputlen, &str, &outputlen,
                                 FALSE);
   if(res)
     return NULL;
diff --git a/lib/escape.h b/lib/escape.h
index 731b136..638666f 100644
--- a/lib/escape.h
+++ b/lib/escape.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -24,7 +24,7 @@
 /* Escape and unescape URL encoding in strings. The functions return a new
  * allocated string or NULL if an error occurred.  */
 
-CURLcode Curl_urldecode(struct SessionHandle *data,
+CURLcode Curl_urldecode(struct Curl_easy *data,
                         const char *string, size_t length,
                         char **ostring, size_t *olen,
                         bool reject_crlf);
diff --git a/lib/file.c b/lib/file.c
index 175b107..b534ec1 100644
--- a/lib/file.c
+++ b/lib/file.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -61,9 +61,8 @@
 #include "url.h"
 #include "parsedate.h" /* for the week day and month names */
 #include "warnless.h"
+/* The last 3 #include files should be in this order */
 #include "curl_printf.h"
-
-/* The last #include files should be: */
 #include "curl_memory.h"
 #include "memdebug.h"
 
@@ -136,7 +135,7 @@ static CURLcode file_range(struct connectdata *conn)
   curl_off_t totalsize=-1;
   char *ptr;
   char *ptr2;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   if(data->state.use_range && data->state.range) {
     from=curlx_strtoofft(data->state.range, &ptr, 0);
@@ -186,7 +185,7 @@ static CURLcode file_range(struct connectdata *conn)
  */
 static CURLcode file_connect(struct connectdata *conn, bool *done)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   char *real_path;
   struct FILEPROTO *file = data->req.protop;
   int fd;
@@ -228,15 +227,19 @@ static CURLcode file_connect(struct connectdata *conn, bool *done)
   for(i=0; i < real_path_len; ++i)
     if(actual_path[i] == '/')
       actual_path[i] = '\\';
-    else if(!actual_path[i]) /* binary zero */
+    else if(!actual_path[i]) { /* binary zero */
+      Curl_safefree(real_path);
       return CURLE_URL_MALFORMAT;
+    }
 
   fd = open_readonly(actual_path, O_RDONLY|O_BINARY);
   file->path = actual_path;
 #else
-  if(memchr(real_path, 0, real_path_len))
+  if(memchr(real_path, 0, real_path_len)) {
     /* binary zeroes indicate foul play */
+    Curl_safefree(real_path);
     return CURLE_URL_MALFORMAT;
+  }
 
   fd = open_readonly(real_path, O_RDONLY);
   file->path = real_path;
@@ -302,7 +305,7 @@ static CURLcode file_upload(struct connectdata *conn)
   int fd;
   int mode;
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   char *buf = data->state.buffer;
   size_t nread;
   size_t nwrite;
@@ -368,7 +371,7 @@ static CURLcode file_upload(struct connectdata *conn)
 
     /*skip bytes before resume point*/
     if(data->state.resume_from) {
-      if((curl_off_t)nread <= data->state.resume_from ) {
+      if((curl_off_t)nread <= data->state.resume_from) {
         data->state.resume_from -= nread;
         nread = 0;
         buf2 = buf;
@@ -426,9 +429,10 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
                           Windows version to have a different struct without
                           having to redefine the simple word 'stat' */
   curl_off_t expected_size=0;
+  bool size_known;
   bool fstated=FALSE;
   ssize_t nread;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   char *buf = data->state.buffer;
   curl_off_t bytecount = 0;
   int fd;
@@ -468,6 +472,9 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
      information. Which for FILE can't be much more than the file size and
      date. */
   if(data->set.opt_no_body && data->set.include_header && fstated) {
+    time_t filetime;
+    struct tm buffer;
+    const struct tm *tm = &buffer;
     snprintf(buf, sizeof(data->state.buffer),
              "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", expected_size);
     result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
@@ -479,29 +486,24 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
     if(result)
       return result;
 
-    if(fstated) {
-      time_t filetime = (time_t)statbuf.st_mtime;
-      struct tm buffer;
-      const struct tm *tm = &buffer;
-      result = Curl_gmtime(filetime, &buffer);
-      if(result)
-        return result;
-
-      /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
-      snprintf(buf, BUFSIZE-1,
-               "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
-               Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
-               tm->tm_mday,
-               Curl_month[tm->tm_mon],
-               tm->tm_year + 1900,
-               tm->tm_hour,
-               tm->tm_min,
-               tm->tm_sec);
-      result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
-    }
-    /* if we fstat()ed the file, set the file size to make it available post-
-       transfer */
-    if(fstated)
+    filetime = (time_t)statbuf.st_mtime;
+    result = Curl_gmtime(filetime, &buffer);
+    if(result)
+      return result;
+
+    /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
+    snprintf(buf, BUFSIZE-1,
+             "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
+             Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
+             tm->tm_mday,
+             Curl_month[tm->tm_mon],
+             tm->tm_year + 1900,
+             tm->tm_hour,
+             tm->tm_min,
+             tm->tm_sec);
+    result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
+    if(!result)
+      /* set the file size to make it available post transfer */
       Curl_pgrsSetDownloadSize(data, expected_size);
     return result;
   }
@@ -531,8 +533,10 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
   if(data->req.maxdownload > 0)
     expected_size = data->req.maxdownload;
 
-  if(fstated && (expected_size == 0))
-    return CURLE_OK;
+  if(!fstated || (expected_size == 0))
+    size_known = FALSE;
+  else
+    size_known = TRUE;
 
   /* The following is a shortcut implementation of file reading
      this is both more efficient than the former call to download() and
@@ -551,20 +555,27 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
 
   while(!result) {
     /* Don't fill a whole buffer if we want less than all data */
-    size_t bytestoread =
-      (expected_size < CURL_OFF_T_C(BUFSIZE) - CURL_OFF_T_C(1)) ?
-      curlx_sotouz(expected_size) : BUFSIZE - 1;
+    size_t bytestoread;
+
+    if(size_known) {
+      bytestoread =
+        (expected_size < CURL_OFF_T_C(BUFSIZE) - CURL_OFF_T_C(1)) ?
+        curlx_sotouz(expected_size) : BUFSIZE - 1;
+    }
+    else
+      bytestoread = BUFSIZE-1;
 
     nread = read(fd, buf, bytestoread);
 
     if(nread > 0)
       buf[nread] = 0;
 
-    if(nread <= 0 || expected_size == 0)
+    if(nread <= 0 || (size_known && (expected_size == 0)))
       break;
 
     bytecount += nread;
-    expected_size -= nread;
+    if(size_known)
+      expected_size -= nread;
 
     result = Curl_client_write(conn, CLIENTWRITE_BODY, buf, nread);
     if(result)
diff --git a/lib/file.h b/lib/file.h
index 997474b..c12ae0e 100644
--- a/lib/file.h
+++ b/lib/file.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/fileinfo.c b/lib/fileinfo.c
index 0904937..144c65b 100644
--- a/lib/fileinfo.c
+++ b/lib/fileinfo.c
@@ -9,7 +9,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/fileinfo.h b/lib/fileinfo.h
index b0e5e59..5324f1a 100644
--- a/lib/fileinfo.h
+++ b/lib/fileinfo.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/formdata.c b/lib/formdata.c
index 9e8ce4e..673759d 100644
--- a/lib/formdata.c
+++ b/lib/formdata.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -30,15 +30,14 @@
 #include <libgen.h>
 #endif
 
-#include "urldata.h" /* for struct SessionHandle */
+#include "urldata.h" /* for struct Curl_easy */
 #include "formdata.h"
 #include "vtls/vtls.h"
 #include "strequal.h"
 #include "sendf.h"
 #include "strdup.h"
+/* The last 3 #include files should be in this order */
 #include "curl_printf.h"
-
-/* The last #include files should be: */
 #include "curl_memory.h"
 #include "memdebug.h"
 
@@ -48,7 +47,7 @@ static char *Curl_basename(char *path);
 #endif
 
 static size_t readfromfile(struct Form *form, char *buffer, size_t size);
-static char *formboundary(struct SessionHandle *data);
+static char *formboundary(struct Curl_easy *data);
 
 /* What kind of Content-Type to use on un-specified files with unrecognized
    extensions. */
@@ -57,6 +56,14 @@ static char *formboundary(struct SessionHandle *data);
 #define FORM_FILE_SEPARATOR ','
 #define FORM_TYPE_SEPARATOR ';'
 
+#define HTTPPOST_PTRNAME CURL_HTTPPOST_PTRNAME
+#define HTTPPOST_FILENAME CURL_HTTPPOST_FILENAME
+#define HTTPPOST_PTRCONTENTS CURL_HTTPPOST_PTRCONTENTS
+#define HTTPPOST_READFILE CURL_HTTPPOST_READFILE
+#define HTTPPOST_PTRBUFFER CURL_HTTPPOST_PTRBUFFER
+#define HTTPPOST_CALLBACK CURL_HTTPPOST_CALLBACK
+#define HTTPPOST_BUFFER CURL_HTTPPOST_BUFFER
+
 /***************************************************************************
  *
  * AddHttpPost()
@@ -69,7 +76,7 @@ static char *formboundary(struct SessionHandle *data);
  ***************************************************************************/
 static struct curl_httppost *
 AddHttpPost(char *name, size_t namelength,
-            char *value, size_t contentslength,
+            char *value, curl_off_t contentslength,
             char *buffer, size_t bufferlength,
             char *contenttype,
             long flags,
@@ -85,14 +92,14 @@ AddHttpPost(char *name, size_t namelength,
     post->name = name;
     post->namelength = (long)(name?(namelength?namelength:strlen(name)):0);
     post->contents = value;
-    post->contentslength = (long)contentslength;
+    post->contentlen = contentslength;
     post->buffer = buffer;
     post->bufferlength = (long)bufferlength;
     post->contenttype = contenttype;
     post->contentheader = contentHeader;
     post->showfilename = showfilename;
     post->userp = userp,
-    post->flags = flags;
+    post->flags = flags | CURL_HTTPPOST_LARGE;
   }
   else
     return NULL;
@@ -372,11 +379,14 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
       }
       break;
     case CURLFORM_CONTENTSLENGTH:
-      if(current_form->contentslength)
-        return_value = CURL_FORMADD_OPTION_TWICE;
-      else
-        current_form->contentslength =
-          array_state?(size_t)array_value:(size_t)va_arg(params, long);
+      current_form->contentslength =
+        array_state?(size_t)array_value:(size_t)va_arg(params, long);
+      break;
+
+    case CURLFORM_CONTENTLEN:
+      current_form->flags |= CURL_HTTPPOST_LARGE;
+      current_form->contentslength =
+        array_state?(curl_off_t)(size_t)array_value:va_arg(params, curl_off_t);
       break;
 
       /* Get contents from a given file name */
@@ -538,7 +548,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
         /* this "cast increases required alignment of target type" but
            we consider it OK anyway */
         struct curl_slist* list = array_state?
-          (struct curl_slist*)array_value:
+          (struct curl_slist*)(void*)array_value:
           va_arg(params, struct curl_slist*);
 
         if(current_form->contentheader)
@@ -621,7 +631,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
       else {
         if(((form->flags & HTTPPOST_FILENAME) ||
             (form->flags & HTTPPOST_BUFFER)) &&
-           !form->contenttype ) {
+           !form->contenttype) {
           char *f = form->flags & HTTPPOST_BUFFER?
             form->showfilename : form->value;
 
@@ -653,9 +663,12 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
                             HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER |
                             HTTPPOST_CALLBACK)) && form->value) {
           /* copy value (without strdup; possibly contains null characters) */
-          form->value = Curl_memdup(form->value, form->contentslength?
-                                    form->contentslength:
-                                    strlen(form->value)+1);
+          size_t clen  = (size_t) form->contentslength;
+          if(!clen)
+            clen = strlen(form->value)+1;
+
+          form->value = Curl_memdup(form->value, clen);
+
           if(!form->value) {
             return_value = CURL_FORMADD_MEMORY;
             break;
@@ -756,7 +769,7 @@ curl_off_t VmsRealFileSize(const char * name,
   int ret_stat;
   FILE * file;
 
-  file = fopen(name, "r"); /* VMS */
+  file = fopen(name, FOPEN_READTEXT); /* VMS */
   if(file == NULL)
     return 0;
 
@@ -808,10 +821,16 @@ static curl_off_t VmsSpecialSize(const char * name,
 static CURLcode AddFormData(struct FormData **formp,
                             enum formtype type,
                             const void *line,
-                            size_t length,
+                            curl_off_t length,
                             curl_off_t *size)
 {
-  struct FormData *newform = malloc(sizeof(struct FormData));
+  struct FormData *newform;
+  char *alloc2 = NULL;
+  CURLcode result = CURLE_OK;
+  if(length < 0 || (size && *size < 0))
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  newform = malloc(sizeof(struct FormData));
   if(!newform)
     return CURLE_OUT_OF_MEMORY;
   newform->next = NULL;
@@ -820,15 +839,22 @@ static CURLcode AddFormData(struct FormData **formp,
     /* we make it easier for plain strings: */
     if(!length)
       length = strlen((char *)line);
+#if (SIZEOF_SIZE_T < CURL_SIZEOF_CURL_OFF_T)
+    else if(length >= (curl_off_t)(size_t)-1) {
+      result = CURLE_BAD_FUNCTION_ARGUMENT;
+      goto error;
+    }
+#endif
 
-    newform->line = malloc(length+1);
+    newform->line = malloc((size_t)length+1);
     if(!newform->line) {
-      free(newform);
-      return CURLE_OUT_OF_MEMORY;
+      result = CURLE_OUT_OF_MEMORY;
+      goto error;
     }
-    memcpy(newform->line, line, length);
-    newform->length = length;
-    newform->line[length]=0; /* zero terminate for easier debugging */
+    alloc2 = newform->line;
+    memcpy(newform->line, line, (size_t)length);
+    newform->length = (size_t)length;
+    newform->line[(size_t)length]=0; /* zero terminate for easier debugging */
   }
   else
     /* For callbacks and files we don't have any actual data so we just keep a
@@ -856,12 +882,20 @@ static CURLcode AddFormData(struct FormData **formp,
         struct_stat file;
         if(!stat(newform->line, &file) && !S_ISDIR(file.st_mode))
           *size += filesize(newform->line, file);
-        else
-          return CURLE_BAD_FUNCTION_ARGUMENT;
+        else {
+          result = CURLE_BAD_FUNCTION_ARGUMENT;
+          goto error;
+        }
       }
     }
   }
   return CURLE_OK;
+  error:
+  if(newform)
+    free(newform);
+  if(alloc2)
+    free(alloc2);
+  return result;
 }
 
 /*
@@ -1102,7 +1136,7 @@ static CURLcode formdata_add_filename(const struct curl_httppost *file,
  * a NULL pointer in the 'data' argument.
  */
 
-CURLcode Curl_getformdata(struct SessionHandle *data,
+CURLcode Curl_getformdata(struct Curl_easy *data,
                           struct FormData **finalform,
                           struct curl_httppost *post,
                           const char *custom_content_type,
@@ -1238,7 +1272,7 @@ CURLcode Curl_getformdata(struct SessionHandle *data,
       curList = file->contentheader;
       while(curList) {
         /* Process the additional headers specified for this form */
-        result = AddFormDataf( &form, &size, "\r\n%s", curList->data );
+        result = AddFormDataf(&form, &size, "\r\n%s", curList->data);
         if(result)
           break;
         curList = curList->next;
@@ -1298,15 +1332,16 @@ CURLcode Curl_getformdata(struct SessionHandle *data,
         result = AddFormData(&form, FORM_CONTENT, post->buffer,
                              post->bufferlength, &size);
       else if(post->flags & HTTPPOST_CALLBACK)
-        /* the contents should be read with the callback and the size
-           is set with the contentslength */
+        /* the contents should be read with the callback and the size is set
+           with the contentslength */
         result = AddFormData(&form, FORM_CALLBACK, post->userp,
-                             post->contentslength, &size);
+                             post->flags&CURL_HTTPPOST_LARGE?
+                             post->contentlen:post->contentslength, &size);
       else
         /* include the contents we got */
         result = AddFormData(&form, FORM_CONTENT, post->contents,
-                             post->contentslength, &size);
-
+                             post->flags&CURL_HTTPPOST_LARGE?
+                             post->contentlen:post->contentslength, &size);
       file = file->more;
     } while(file && !result); /* for each specified file for this field */
 
@@ -1350,7 +1385,7 @@ CURLcode Curl_getformdata(struct SessionHandle *data,
  * Curl_FormInit() inits the struct 'form' points to with the 'formdata'
  * and resets the 'sent' counter.
  */
-int Curl_FormInit(struct Form *form, struct FormData *formdata )
+int Curl_FormInit(struct Form *form, struct FormData *formdata)
 {
   if(!formdata)
     return 1; /* error */
@@ -1385,10 +1420,10 @@ static FILE * vmsfopenread(const char *file, const char *mode) {
   case FAB$C_VAR:
   case FAB$C_VFC:
   case FAB$C_STMCR:
-    return fopen(file, "r"); /* VMS */
+    return fopen(file, FOPEN_READTEXT); /* VMS */
     break;
   default:
-    return fopen(file, "r", "rfm=stmlf", "ctx=stm");
+    return fopen(file, FOPEN_READTEXT, "rfm=stmlf", "ctx=stm");
   }
 }
 #endif
@@ -1463,9 +1498,9 @@ size_t Curl_FormReader(char *buffer,
   }
   do {
 
-    if((form->data->length - form->sent ) > wantedsize - gotsize) {
+    if((form->data->length - form->sent) > wantedsize - gotsize) {
 
-      memcpy(buffer + gotsize , form->data->line + form->sent,
+      memcpy(buffer + gotsize, form->data->line + form->sent,
              wantedsize - gotsize);
 
       form->sent += wantedsize-gotsize;
@@ -1514,7 +1549,7 @@ char *Curl_formpostheader(void *formp, size_t *len)
  * formboundary() creates a suitable boundary string and returns an allocated
  * one.
  */
-static char *formboundary(struct SessionHandle *data)
+static char *formboundary(struct Curl_easy *data)
 {
   /* 24 dashes and 16 hexadecimal digits makes 64 bit (18446744073709551615)
      combinations */
diff --git a/lib/formdata.h b/lib/formdata.h
index 22f504b..6eb7c6c 100644
--- a/lib/formdata.h
+++ b/lib/formdata.h
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -54,7 +54,7 @@ typedef struct FormInfo {
   size_t namelength;
   char *value;
   bool value_alloc;
-  size_t contentslength;
+  curl_off_t contentslength;
   char *contenttype;
   bool contenttype_alloc;
   long flags;
@@ -68,9 +68,9 @@ typedef struct FormInfo {
   struct FormInfo *more;
 } FormInfo;
 
-int Curl_FormInit(struct Form *form, struct FormData *formdata );
+int Curl_FormInit(struct Form *form, struct FormData *formdata);
 
-CURLcode Curl_getformdata(struct SessionHandle *data,
+CURLcode Curl_getformdata(struct Curl_easy *data,
                           struct FormData **,
                           struct curl_httppost *post,
                           const char *custom_contenttype,
@@ -93,6 +93,6 @@ char *Curl_FormBoundary(void);
 
 void Curl_formclean(struct FormData **);
 
-CURLcode Curl_formconvert(struct SessionHandle *, struct FormData *);
+CURLcode Curl_formconvert(struct Curl_easy *, struct FormData *);
 
 #endif /* HEADER_CURL_FORMDATA_H */
diff --git a/lib/ftp.c b/lib/ftp.c
index fade092..8af6531 100644
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -77,10 +77,9 @@
 #include "warnless.h"
 #include "http_proxy.h"
 #include "non-ascii.h"
+/* The last 3 #include files should be in this order */
 #include "curl_printf.h"
-
 #include "curl_memory.h"
-/* The last #include file should be: */
 #include "memdebug.h"
 
 #ifndef NI_MAXHOST
@@ -155,8 +154,9 @@ static CURLcode ftp_dophase_done(struct connectdata *conn,
                                  bool connected);
 
 /* easy-to-use macro: */
-#define PPSENDF(x,y,z)  if((result = Curl_pp_sendf(x,y,z)))     \
-                              return result
+#define PPSENDF(x,y,z)  result = Curl_pp_sendf(x,y,z); \
+                        if(result)                     \
+                          return result
 
 
 /*
@@ -265,6 +265,15 @@ static const struct Curl_handler Curl_handler_ftps_proxy = {
 #endif
 #endif
 
+static void close_secondarysocket(struct connectdata *conn)
+{
+  if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
+    Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
+    conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
+  }
+  conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
+  conn->tunnel_state[SECONDARYSOCKET] = TUNNEL_INIT;
+}
 
 /*
  * NOTE: back in the old days, we added code in the FTP code that made NOBODY
@@ -318,7 +327,7 @@ static bool isBadFtpString(const char *string)
  */
 static CURLcode AcceptServerConnect(struct connectdata *conn)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   curl_socket_t sock = conn->sock[SECONDARYSOCKET];
   curl_socket_t s = CURL_SOCKET_BAD;
 #ifdef ENABLE_IPV6
@@ -340,6 +349,9 @@ static CURLcode AcceptServerConnect(struct connectdata *conn)
     return CURLE_FTP_PORT_FAILED;
   }
   infof(data, "Connection accepted from server\n");
+  /* when this happens within the DO state it is important that we mark us as
+     not needing DO_MORE anymore */
+  conn->bits.do_more = FALSE;
 
   conn->sock[SECONDARYSOCKET] = s;
   (void)curlx_nonblock(s, TRUE); /* enable non-blocking */
@@ -354,8 +366,7 @@ static CURLcode AcceptServerConnect(struct connectdata *conn)
                                CURLSOCKTYPE_ACCEPT);
 
     if(error) {
-      Curl_closesocket(conn, s); /* close the socket and bail out */
-      conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
+      close_secondarysocket(conn);
       return CURLE_ABORTED_BY_CALLBACK;
     }
   }
@@ -373,7 +384,7 @@ static CURLcode AcceptServerConnect(struct connectdata *conn)
  * Curl_pgrsTime(..., TIMER_STARTACCEPT);
  *
  */
-static long ftp_timeleft_accept(struct SessionHandle *data)
+static long ftp_timeleft_accept(struct Curl_easy *data)
 {
   long timeout_ms = DEFAULT_ACCEPT_TIMEOUT;
   long other;
@@ -413,7 +424,7 @@ static long ftp_timeleft_accept(struct SessionHandle *data)
  */
 static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   curl_socket_t ctrl_sock = conn->sock[FIRSTSOCKET];
   curl_socket_t data_sock = conn->sock[SECONDARYSOCKET];
   struct ftp_conn *ftpc = &conn->proto.ftpc;
@@ -484,7 +495,7 @@ static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received)
  */
 static CURLcode InitiateTransfer(struct connectdata *conn)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct FTP *ftp = data->req.protop;
   CURLcode result = CURLE_OK;
 
@@ -535,7 +546,7 @@ static CURLcode InitiateTransfer(struct connectdata *conn)
  */
 static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   long timeout_ms;
   CURLcode result = CURLE_OK;
 
@@ -606,7 +617,7 @@ static CURLcode ftp_readresp(curl_socket_t sockfd,
                              size_t *size) /* size of the response */
 {
   struct connectdata *conn = pp->conn;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 #ifdef HAVE_GSSAPI
   char * const buf = data->state.buffer;
 #endif
@@ -678,7 +689,7 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
   long timeout;              /* timeout in milliseconds */
   long interval_ms;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   CURLcode result = CURLE_OK;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   struct pingpong *pp = &ftpc->pp;
@@ -698,7 +709,7 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
     /* check and reset timeout value every lap */
     timeout = Curl_pp_state_timeout(pp);
 
-    if(timeout <=0 ) {
+    if(timeout <=0) {
       failf(data, "FTP response timeout");
       return CURLE_OPERATION_TIMEDOUT; /* already too little time */
     }
@@ -969,7 +980,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
 {
   CURLcode result = CURLE_OK;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
-  struct SessionHandle *data=conn->data;
+  struct Curl_easy *data=conn->data;
   curl_socket_t portsock= CURL_SOCKET_BAD;
   char myhost[256] = "";
 
@@ -1024,7 +1035,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
     if(*string_ftpport == '[') {
       /* [ipv6]:port(-range) */
       ip_start = string_ftpport + 1;
-      if((ip_end = strchr(string_ftpport, ']')) != NULL )
+      if((ip_end = strchr(string_ftpport, ']')) != NULL)
         strncpy(addr, ip_start, ip_end - ip_start);
     }
     else
@@ -1045,7 +1056,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
       else
 #endif
         /* (ipv4|domain|interface):port(-range) */
-        strncpy(addr, string_ftpport, ip_end - ip_start );
+        strncpy(addr, string_ftpport, ip_end - ip_start);
     }
     else
       /* ipv4|interface */
@@ -1065,11 +1076,11 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
 
     /* correct errors like:
      *  :1234-1230
-     *  :-4711 , in this case port_min is (unsigned)-1,
+     *  :-4711,  in this case port_min is (unsigned)-1,
      *           therefore port_min > port_max for all cases
      *           but port_max = (unsigned)-1
      */
-    if(port_min > port_max )
+    if(port_min > port_max)
       port_min = port_max = 0;
 
 
@@ -1322,11 +1333,11 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
   /* store which command was sent */
   ftpc->count1 = fcmd;
 
+  close_secondarysocket(conn);
+
   /* we set the secondary socket variable to this for now, it is only so that
      the cleanup function will close it in case we fail before the true
      secondary stuff is made */
-  if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET])
-    Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
   conn->sock[SECONDARYSOCKET] = portsock;
 
   /* this tcpconnect assignment below is a hackish work-around to make the
@@ -1392,7 +1403,7 @@ static CURLcode ftp_state_prepare_transfer(struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
   struct FTP *ftp = conn->data->req.protop;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   if(ftp->transfer != FTPTRANSFER_BODY) {
     /* doesn't transfer any data */
@@ -1475,7 +1486,7 @@ static CURLcode ftp_state_size(struct connectdata *conn)
 static CURLcode ftp_state_list(struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   /* If this output is to be machine-parsed, the NLST command might be better
      to use, since the LIST command output is not specified or standard in any
@@ -1513,12 +1524,12 @@ static CURLcode ftp_state_list(struct connectdata *conn)
     }
   }
 
-  cmd = aprintf( "%s%s%s",
-                 data->set.str[STRING_CUSTOMREQUEST]?
-                 data->set.str[STRING_CUSTOMREQUEST]:
-                 (data->set.ftp_list_only?"NLST":"LIST"),
-                 lstArg? " ": "",
-                 lstArg? lstArg: "" );
+  cmd = aprintf("%s%s%s",
+                data->set.str[STRING_CUSTOMREQUEST]?
+                data->set.str[STRING_CUSTOMREQUEST]:
+                (data->set.ftp_list_only?"NLST":"LIST"),
+                lstArg? " ": "",
+                lstArg? lstArg: "");
 
   if(!cmd) {
     free(lstArg);
@@ -1564,7 +1575,7 @@ static CURLcode ftp_state_type(struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
   struct FTP *ftp = conn->data->req.protop;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
 
   /* If we have selected NOBODY and HEADER, it means that we only want file
@@ -1596,7 +1607,7 @@ static CURLcode ftp_state_type(struct connectdata *conn)
 static CURLcode ftp_state_mdtm(struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
 
   /* Requested time of file or time-depended transfer? */
@@ -1621,7 +1632,7 @@ static CURLcode ftp_state_ul_setup(struct connectdata *conn,
 {
   CURLcode result = CURLE_OK;
   struct FTP *ftp = conn->data->req.protop;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   int seekerr = CURL_SEEKFUNC_OK;
 
@@ -1640,7 +1651,7 @@ static CURLcode ftp_state_ul_setup(struct connectdata *conn,
     /* 4. lower the infilesize counter */
     /* => transfer as usual */
 
-    if(data->state.resume_from < 0 ) {
+    if(data->state.resume_from < 0) {
       /* Got no given size to start from, figure it out */
       PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
       state(conn, FTP_STOR_SIZE);
@@ -1670,8 +1681,8 @@ static CURLcode ftp_state_ul_setup(struct connectdata *conn,
             BUFSIZE : curlx_sotouz(data->state.resume_from - passed);
 
           size_t actuallyread =
-            data->set.fread_func(data->state.buffer, 1, readthisamountnow,
-                                 data->set.in);
+            data->state.fread_func(data->state.buffer, 1, readthisamountnow,
+                                   data->state.in);
 
           passed += actuallyread;
           if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
@@ -1717,7 +1728,7 @@ static CURLcode ftp_state_quote(struct connectdata *conn,
                                 ftpstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct FTP *ftp = data->req.protop;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   bool quote=FALSE;
@@ -1787,8 +1798,20 @@ static CURLcode ftp_state_quote(struct connectdata *conn,
           result = ftp_state_retr(conn, ftpc->known_filesize);
         }
         else {
-          PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
-          state(conn, FTP_RETR_SIZE);
+          if(data->set.ignorecl) {
+            /* This code is to support download of growing files.  It prevents
+               the state machine from requesting the file size from the
+               server.  With an unknown file size the download continues until
+               the server terminates it, otherwise the client stops if the
+               received byte count exceeds the reported file size.  Set option
+               CURLOPT_IGNORE_CONTENT_LENGTH to 1 to enable this behavior.*/
+            PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
+            state(conn, FTP_RETR);
+          }
+          else {
+            PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
+            state(conn, FTP_RETR_SIZE);
+          }
         }
       }
       break;
@@ -1836,7 +1859,7 @@ static CURLcode proxy_magic(struct connectdata *conn,
                             bool *magicdone)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
 #if defined(CURL_DISABLE_PROXY)
   (void) newhost;
@@ -1927,7 +1950,7 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
 {
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   CURLcode result;
-  struct SessionHandle *data=conn->data;
+  struct Curl_easy *data=conn->data;
   struct Curl_dns_entry *addr=NULL;
   int rc;
   unsigned short connectport; /* the local port connect() should use! */
@@ -2102,7 +2125,7 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
 static CURLcode ftp_state_port_resp(struct connectdata *conn,
                                     int ftpcode)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   ftpport fcmd = (ftpport)ftpc->count1;
   CURLcode result = CURLE_OK;
@@ -2139,7 +2162,7 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
                                     int ftpcode)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data=conn->data;
+  struct Curl_easy *data=conn->data;
   struct FTP *ftp = data->req.protop;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
 
@@ -2244,7 +2267,7 @@ static CURLcode ftp_state_type_resp(struct connectdata *conn,
                                     ftpstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data=conn->data;
+  struct Curl_easy *data=conn->data;
 
   if(ftpcode/100 != 2) {
     /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a
@@ -2273,7 +2296,7 @@ static CURLcode ftp_state_retr(struct connectdata *conn,
                                          curl_off_t filesize)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data=conn->data;
+  struct Curl_easy *data=conn->data;
   struct FTP *ftp = data->req.protop;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
 
@@ -2356,7 +2379,7 @@ static CURLcode ftp_state_size_resp(struct connectdata *conn,
                                     ftpstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data=conn->data;
+  struct Curl_easy *data=conn->data;
   curl_off_t filesize;
   char *buf = data->state.buffer;
 
@@ -2428,7 +2451,7 @@ static CURLcode ftp_state_stor_resp(struct connectdata *conn,
                                     int ftpcode, ftpstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   if(ftpcode>=400) {
     failf(data, "Failed FTP upload: %0d", ftpcode);
@@ -2467,7 +2490,7 @@ static CURLcode ftp_state_get_resp(struct connectdata *conn,
                                     ftpstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct FTP *ftp = data->req.protop;
   char *buf = data->state.buffer;
 
@@ -2624,7 +2647,7 @@ static CURLcode ftp_state_user_resp(struct connectdata *conn,
                                     ftpstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct FTP *ftp = data->req.protop;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   (void)instate; /* no use for this yet */
@@ -2679,7 +2702,7 @@ static CURLcode ftp_state_acct_resp(struct connectdata *conn,
                                     int ftpcode)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   if(ftpcode != 230) {
     failf(data, "ACCT rejected by server: %03d", ftpcode);
     result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */
@@ -2695,7 +2718,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
 {
   CURLcode result;
   curl_socket_t sock = conn->sock[FIRSTSOCKET];
-  struct SessionHandle *data=conn->data;
+  struct Curl_easy *data=conn->data;
   int ftpcode;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   struct pingpong *pp = &ftpc->pp;
@@ -3218,9 +3241,9 @@ static CURLcode ftp_connect(struct connectdata *conn,
  * Input argument is already checked for validity.
  */
 static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
-                              bool premature)
+                         bool premature)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct FTP *ftp = data->req.protop;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   struct pingpong *pp = &ftpc->pp;
@@ -3232,11 +3255,6 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
   const char *path_to_use = data->state.path;
 
   if(!ftp)
-    /* When the easy handle is removed from the multi while libcurl is still
-     * trying to resolve the host name, it seems that the ftp struct is not
-     * yet initialized, but the removal action calls Curl_done() which calls
-     * this function. So we simply return success if no ftp pointer is set.
-     */
     return CURLE_OK;
 
   switch(status) {
@@ -3345,11 +3363,7 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
       /* Note that we keep "use" set to TRUE since that (next) connection is
          still requested to use SSL */
     }
-    if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
-      Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
-      conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
-      conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
-    }
+    close_secondarysocket(conn);
   }
 
   if(!result && (ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid &&
@@ -3573,7 +3587,7 @@ static CURLcode ftp_range(struct connectdata *conn)
   curl_off_t from, to;
   char *ptr;
   char *ptr2;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
 
   if(data->state.use_range && data->state.range) {
@@ -3631,7 +3645,7 @@ static CURLcode ftp_range(struct connectdata *conn)
 
 static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
 {
-  struct SessionHandle *data=conn->data;
+  struct Curl_easy *data=conn->data;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   CURLcode result = CURLE_OK;
   bool connected = FALSE;
@@ -3720,7 +3734,13 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
         return result;
 
       result = ftp_multi_statemach(conn, &complete);
-      *completep = (int)complete;
+      if(ftpc->wait_data_conn)
+        /* if we reach the end of the FTP state machine here, *complete will be
+           TRUE but so is ftpc->wait_data_conn, which says we need to wait for
+           the data connection and therefore we're not actually complete */
+        *completep = 0;
+      else
+        *completep = (int)complete;
     }
     else {
       /* download */
@@ -4189,7 +4209,7 @@ static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection)
   (void)ftp_quit(conn); /* ignore errors on the QUIT */
 
   if(ftpc->entrypath) {
-    struct SessionHandle *data = conn->data;
+    struct Curl_easy *data = conn->data;
     if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) {
       data->state.most_recent_ftp_entrypath = NULL;
     }
@@ -4222,7 +4242,7 @@ static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection)
 static
 CURLcode ftp_parse_url_path(struct connectdata *conn)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   /* the ftp struct is already inited in ftp_connect() */
   struct FTP *ftp = data->req.protop;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
@@ -4248,16 +4268,17 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
       the first condition in the if() right here, is there just in case
       someone decides to set path to NULL one day
    */
-    if(data->state.path &&
-       data->state.path[0] &&
-       (data->state.path[strlen(data->state.path) - 1] != '/') )
-      filename = data->state.path;  /* this is a full file path */
-      /*
+    if(path_to_use[0] &&
+       (path_to_use[strlen(path_to_use) - 1] != '/') )
+      filename = path_to_use;  /* this is a full file path */
+    /*
+      else {
         ftpc->file is not used anywhere other than for operations on a file.
         In other words, never for directory operations.
         So we can safely leave filename as NULL here and use it as a
         argument in dir/file decisions.
-      */
+      }
+    */
     break;
 
   case FTPFILE_SINGLECWD:
@@ -4422,11 +4443,7 @@ static CURLcode ftp_dophase_done(struct connectdata *conn,
     CURLcode result = ftp_do_more(conn, &completed);
 
     if(result) {
-      if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
-        /* close the second socket if it was created already */
-        Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
-        conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
-      }
+      close_secondarysocket(conn);
       return result;
     }
   }
@@ -4477,7 +4494,7 @@ CURLcode ftp_regular_transfer(struct connectdata *conn,
 {
   CURLcode result=CURLE_OK;
   bool connected=FALSE;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   data->req.size = -1; /* make sure this is unknown at this point */
 
@@ -4511,7 +4528,7 @@ CURLcode ftp_regular_transfer(struct connectdata *conn,
 
 static CURLcode ftp_setup_connection(struct connectdata *conn)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   char *type;
   char command;
   struct FTP *ftp;
diff --git a/lib/ftp.h b/lib/ftp.h
index 833447b..2ed5b43 100644
--- a/lib/ftp.h
+++ b/lib/ftp.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -97,9 +97,9 @@ typedef enum {
                             file */
 } curl_ftpfile;
 
-/* This FTP struct is used in the SessionHandle. All FTP data that is
+/* This FTP struct is used in the Curl_easy. All FTP data that is
    connection-oriented must be in FTP_conn to properly deal with the fact that
-   perhaps the SessionHandle is changed between the times the connection is
+   perhaps the Curl_easy is changed between the times the connection is
    used. */
 struct FTP {
   curl_off_t *bytecountp;
diff --git a/lib/ftplistparser.c b/lib/ftplistparser.c
index 17e0a66..abbf76e 100644
--- a/lib/ftplistparser.c
+++ b/lib/ftplistparser.c
@@ -9,7 +9,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -275,26 +275,6 @@ static void PL_ERROR(struct connectdata *conn, CURLcode err)
   parser->error = err;
 }
 
-static bool ftp_pl_gettime(struct ftp_parselist_data *parser, char *string)
-{
-  (void)parser;
-  (void)string;
-  /* TODO
-   * There could be possible parse timestamp from server. Leaving unimplemented
-   * for now.
-   * If you want implement this, please add CURLFINFOFLAG_KNOWN_TIME flag to
-   * parser->file_data->flags
-   *
-   * Ftp servers are giving usually these formats:
-   *  Apr 11  1998 (unknown time.. set it to 00:00:00?)
-   *  Apr 11 12:21 (unknown year -> set it to NOW() time?)
-   *  08-05-09  02:49PM  (ms-dos format)
-   *  20100421092538 -> for MLST/MLSD response
-   */
-
-  return FALSE;
-}
-
 static CURLcode ftp_pl_insert_finfo(struct connectdata *conn,
                                     struct curl_fileinfo *finfo)
 {
@@ -715,9 +695,11 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
           if(c == ' ') {
             finfo->b_data[parser->item_offset + parser->item_length -1] = 0;
             parser->offsets.time = parser->item_offset;
-            if(ftp_pl_gettime(parser, finfo->b_data + parser->item_offset)) {
-              parser->file_data->flags |= CURLFINFOFLAG_KNOWN_TIME;
-            }
+            /*
+              if(ftp_pl_gettime(parser, finfo->b_data + parser->item_offset)) {
+                parser->file_data->flags |= CURLFINFOFLAG_KNOWN_TIME;
+              }
+            */
             if(finfo->filetype == CURLFILETYPE_SYMLINK) {
               parser->state.UNIX.main = PL_UNIX_SYMLINK;
               parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRESPACE;
@@ -746,7 +728,6 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
         case PL_UNIX_FILENAME_NAME:
           parser->item_length++;
           if(c == '\r') {
-            parser->item_length--;
             parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_WINDOWSEOL;
           }
           else if(c == '\n') {
@@ -762,7 +743,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
           break;
         case PL_UNIX_FILENAME_WINDOWSEOL:
           if(c == '\n') {
-            finfo->b_data[parser->item_offset + parser->item_length] = 0;
+            finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
             parser->offsets.filename = parser->item_offset;
             parser->state.UNIX.main = PL_UNIX_FILETYPE;
             result = ftp_pl_insert_finfo(conn, finfo);
@@ -853,9 +834,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
           }
           break;
         case PL_UNIX_SYMLINK_TARGET:
-          parser->item_length ++;
+          parser->item_length++;
           if(c == '\r') {
-            parser->item_length --;
             parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_WINDOWSEOL;
           }
           else if(c == '\n') {
diff --git a/lib/ftplistparser.h b/lib/ftplistparser.h
index 96764e2..8128887 100644
--- a/lib/ftplistparser.h
+++ b/lib/ftplistparser.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/getenv.c b/lib/getenv.c
index 36215aa..50bb79f 100644
--- a/lib/getenv.c
+++ b/lib/getenv.c
@@ -9,7 +9,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/getinfo.c b/lib/getinfo.c
index 910f520..262cd93 100644
--- a/lib/getinfo.c
+++ b/lib/getinfo.c
@@ -9,7 +9,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -39,7 +39,7 @@
  * This is supposed to be called in the beginning of a perform() session
  * and should reset all session-info variables
  */
-CURLcode Curl_initinfo(struct SessionHandle *data)
+CURLcode Curl_initinfo(struct Curl_easy *data)
 {
   struct Progress *pro = &data->progress;
   struct PureInfo *info = &data->info;
@@ -73,7 +73,7 @@ CURLcode Curl_initinfo(struct SessionHandle *data)
   return CURLE_OK;
 }
 
-static CURLcode getinfo_char(struct SessionHandle *data, CURLINFO info,
+static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info,
                              char **param_charp)
 {
   switch(info) {
@@ -113,13 +113,13 @@ static CURLcode getinfo_char(struct SessionHandle *data, CURLINFO info,
     break;
 
   default:
-    return CURLE_BAD_FUNCTION_ARGUMENT;
+    return CURLE_UNKNOWN_OPTION;
   }
 
   return CURLE_OK;
 }
 
-static CURLcode getinfo_long(struct SessionHandle *data, CURLINFO info,
+static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
                              long *param_longp)
 {
   curl_socket_t sockfd;
@@ -198,15 +198,31 @@ static CURLcode getinfo_long(struct SessionHandle *data, CURLINFO info,
   case CURLINFO_RTSP_CSEQ_RECV:
     *param_longp = data->state.rtsp_CSeq_recv;
     break;
+  case CURLINFO_HTTP_VERSION:
+    switch (data->info.httpversion) {
+    case 10:
+      *param_longp = CURL_HTTP_VERSION_1_0;
+      break;
+    case 11:
+      *param_longp = CURL_HTTP_VERSION_1_1;
+      break;
+    case 20:
+      *param_longp = CURL_HTTP_VERSION_2_0;
+      break;
+    default:
+      *param_longp = CURL_HTTP_VERSION_NONE;
+      break;
+    }
+    break;
 
   default:
-    return CURLE_BAD_FUNCTION_ARGUMENT;
+    return CURLE_UNKNOWN_OPTION;
   }
 
   return CURLE_OK;
 }
 
-static CURLcode getinfo_double(struct SessionHandle *data, CURLINFO info,
+static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info,
                                double *param_doublep)
 {
   switch(info) {
@@ -253,13 +269,13 @@ static CURLcode getinfo_double(struct SessionHandle *data, CURLINFO info,
     break;
 
   default:
-    return CURLE_BAD_FUNCTION_ARGUMENT;
+    return CURLE_UNKNOWN_OPTION;
   }
 
   return CURLE_OK;
 }
 
-static CURLcode getinfo_slist(struct SessionHandle *data, CURLINFO info,
+static CURLcode getinfo_slist(struct Curl_easy *data, CURLINFO info,
                               struct curl_slist **param_slistp)
 {
   union {
@@ -281,69 +297,84 @@ static CURLcode getinfo_slist(struct SessionHandle *data, CURLINFO info,
     *param_slistp = ptr.to_slist;
     break;
   case CURLINFO_TLS_SESSION:
+  case CURLINFO_TLS_SSL_PTR:
     {
       struct curl_tlssessioninfo **tsip = (struct curl_tlssessioninfo **)
                                           param_slistp;
       struct curl_tlssessioninfo *tsi = &data->tsi;
       struct connectdata *conn = data->easy_conn;
-      unsigned int sockindex = 0;
-      void *internals = NULL;
 
       *tsip = tsi;
-      tsi->backend = CURLSSLBACKEND_NONE;
+      tsi->backend = Curl_ssl_backend();
       tsi->internals = NULL;
 
-      if(!conn)
-        break;
-
-      /* Find the active ("in use") SSL connection, if any */
-      while((sockindex < sizeof(conn->ssl) / sizeof(conn->ssl[0])) &&
-            (!conn->ssl[sockindex].use))
-        sockindex++;
-
-      if(sockindex == sizeof(conn->ssl) / sizeof(conn->ssl[0]))
-        break; /* no SSL session found */
-
-      /* Return the TLS session information from the relevant backend */
-#ifdef USE_OPENSSL
-      internals = conn->ssl[sockindex].ctx;
+      if(conn && tsi->backend != CURLSSLBACKEND_NONE) {
+        unsigned int i;
+        for(i = 0; i < (sizeof(conn->ssl) / sizeof(conn->ssl[0])); ++i) {
+          if(conn->ssl[i].use) {
+#if defined(USE_AXTLS)
+            tsi->internals = (void *)conn->ssl[i].ssl;
+#elif defined(USE_CYASSL)
+            tsi->internals = (void *)conn->ssl[i].handle;
+#elif defined(USE_DARWINSSL)
+            tsi->internals = (void *)conn->ssl[i].ssl_ctx;
+#elif defined(USE_GNUTLS)
+            tsi->internals = (void *)conn->ssl[i].session;
+#elif defined(USE_GSKIT)
+            tsi->internals = (void *)conn->ssl[i].handle;
+#elif defined(USE_MBEDTLS)
+            tsi->internals = (void *)&conn->ssl[i].ssl;
+#elif defined(USE_NSS)
+            tsi->internals = (void *)conn->ssl[i].handle;
+#elif defined(USE_OPENSSL)
+            /* Legacy: CURLINFO_TLS_SESSION must return an SSL_CTX pointer. */
+            tsi->internals = ((info == CURLINFO_TLS_SESSION) ?
+                              (void *)conn->ssl[i].ctx :
+                              (void *)conn->ssl[i].handle);
+#elif defined(USE_POLARSSL)
+            tsi->internals = (void *)&conn->ssl[i].ssl;
+#elif defined(USE_SCHANNEL)
+            tsi->internals = (void *)&conn->ssl[i].ctxt->ctxt_handle;
+#elif defined(USE_SSL)
+#error "SSL backend specific information missing for CURLINFO_TLS_SSL_PTR"
 #endif
-#ifdef USE_GNUTLS
-      internals = conn->ssl[sockindex].session;
-#endif
-#ifdef USE_NSS
-      internals = conn->ssl[sockindex].handle;
-#endif
-#ifdef USE_GSKIT
-      internals = conn->ssl[sockindex].handle;
-#endif
-      if(internals) {
-        tsi->backend = Curl_ssl_backend();
-        tsi->internals = internals;
+            break;
+          }
+        }
       }
-      /* NOTE: For other SSL backends, it is not immediately clear what data
-         to return from 'struct ssl_connect_data'; thus, for now we keep the
-         backend as CURLSSLBACKEND_NONE in those cases, which should be
-         interpreted as "not supported" */
     }
     break;
   default:
-    return CURLE_BAD_FUNCTION_ARGUMENT;
+    return CURLE_UNKNOWN_OPTION;
+  }
+
+  return CURLE_OK;
+}
+
+static CURLcode getinfo_socket(struct Curl_easy *data, CURLINFO info,
+                               curl_socket_t *param_socketp)
+{
+  switch(info) {
+  case CURLINFO_ACTIVESOCKET:
+    *param_socketp = Curl_getconnectinfo(data, NULL);
+    break;
+  default:
+    return CURLE_UNKNOWN_OPTION;
   }
 
   return CURLE_OK;
 }
 
-CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...)
+CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...)
 {
   va_list arg;
   long *param_longp = NULL;
   double *param_doublep = NULL;
   char **param_charp = NULL;
   struct curl_slist **param_slistp = NULL;
+  curl_socket_t *param_socketp = NULL;
   int type;
-  /* default return code is to error out! */
-  CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
+  CURLcode result = CURLE_UNKNOWN_OPTION;
 
   if(!data)
     return result;
@@ -372,6 +403,11 @@ CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...)
     if(param_slistp)
       result = getinfo_slist(data, info, param_slistp);
     break;
+  case CURLINFO_SOCKET:
+    param_socketp = va_arg(arg, curl_socket_t *);
+    if(param_socketp)
+      result = getinfo_socket(data, info, param_socketp);
+    break;
   default:
     break;
   }
diff --git a/lib/getinfo.h b/lib/getinfo.h
index 3879ff7..aecf717 100644
--- a/lib/getinfo.h
+++ b/lib/getinfo.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -21,7 +21,7 @@
  * KIND, either express or implied.
  *
  ***************************************************************************/
-CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...);
-CURLcode Curl_initinfo(struct SessionHandle *data);
+CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...);
+CURLcode Curl_initinfo(struct Curl_easy *data);
 
 #endif /* HEADER_CURL_GETINFO_H */
diff --git a/lib/gopher.c b/lib/gopher.c
index 954cad8..f1efb60 100644
--- a/lib/gopher.c
+++ b/lib/gopher.c
@@ -9,7 +9,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -75,7 +75,7 @@ const struct Curl_handler Curl_handler_gopher = {
 static CURLcode gopher_do(struct connectdata *conn, bool *done)
 {
   CURLcode result=CURLE_OK;
-  struct SessionHandle *data=conn->data;
+  struct Curl_easy *data=conn->data;
   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
 
   curl_off_t *bytecount = &data->req.bytecount;
@@ -83,16 +83,18 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done)
   char *sel;
   char *sel_org = NULL;
   ssize_t amount, k;
+  int len;
 
   *done = TRUE; /* unconditionally */
 
   /* Create selector. Degenerate cases: / and /1 => convert to "" */
-  if(strlen(path) <= 2)
+  if(strlen(path) <= 2) {
     sel = (char *)"";
+    len = (int)strlen(sel);
+  }
   else {
     char *newp;
     size_t j, i;
-    int len;
 
     /* Otherwise, drop / and the first character (i.e., item type) ... */
     newp = path;
@@ -113,7 +115,7 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done)
 
   /* We use Curl_write instead of Curl_sendf to make sure the entire buffer is
      sent, which could be sizeable with long selectors. */
-  k = curlx_uztosz(strlen(sel));
+  k = curlx_uztosz(len);
 
   for(;;) {
     result = Curl_write(conn, sockfd, sel, k, &amount);
diff --git a/lib/gopher.h b/lib/gopher.h
index 38bbc4b..501c990 100644
--- a/lib/gopher.h
+++ b/lib/gopher.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/hash.c b/lib/hash.c
index c46760a..937381b 100644
--- a/lib/hash.c
+++ b/lib/hash.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -22,9 +22,12 @@
 
 #include "curl_setup.h"
 
+#include <curl/curl.h>
+
 #include "hash.h"
 #include "llist.h"
 #include "curl_memory.h"
+
 /* The last #include file should be: */
 #include "memdebug.h"
 
@@ -46,7 +49,12 @@ hash_element_dtor(void *user, void *element)
   free(e);
 }
 
-/* return 1 on error, 0 is fine */
+/* Initializes a hash structure.
+ * Return 1 on error, 0 is fine.
+ *
+ * @unittest: 1602
+ * @unittest: 1603
+ */
 int
 Curl_hash_init(struct curl_hash *h,
                int slots,
@@ -119,6 +127,8 @@ mk_hash_element(const void *key, size_t key_len, const void *p)
  * that data is replaced.
  *
  * @unittest: 1305
+ * @unittest: 1602
+ * @unittest: 1603
  */
 void *
 Curl_hash_add(struct curl_hash *h, void *key, size_t key_len, void *p)
@@ -155,7 +165,11 @@ Curl_hash_add(struct curl_hash *h, void *key, size_t key_len, void *p)
   return NULL; /* failure */
 }
 
-/* remove the identified hash entry, returns non-zero on failure */
+/* Remove the identified hash entry.
+ * Returns non-zero on failure.
+ *
+ * @unittest: 1603
+ */
 int Curl_hash_delete(struct curl_hash *h, void *key, size_t key_len)
 {
   struct curl_llist_element *le;
@@ -173,6 +187,10 @@ int Curl_hash_delete(struct curl_hash *h, void *key, size_t key_len)
   return 1;
 }
 
+/* Retrieves a hash element.
+ *
+ * @unittest: 1603
+ */
 void *
 Curl_hash_pick(struct curl_hash *h, void *key, size_t key_len)
 {
@@ -214,6 +232,10 @@ Curl_hash_apply(curl_hash *h, void *user,
 
 /* Destroys all the entries in the given hash and resets its attributes,
  * prepping the given hash for [static|dynamic] deallocation.
+ *
+ * @unittest: 1305
+ * @unittest: 1602
+ * @unittest: 1603
  */
 void
 Curl_hash_destroy(struct curl_hash *h)
diff --git a/lib/hash.h b/lib/hash.h
index b13a236..57a17f0 100644
--- a/lib/hash.h
+++ b/lib/hash.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/hmac.c b/lib/hmac.c
index 0d2d5f4..3df4715 100644
--- a/lib/hmac.c
+++ b/lib/hmac.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -26,8 +26,11 @@
 
 #ifndef CURL_DISABLE_CRYPTO_AUTH
 
+#include <curl/curl.h>
+
 #include "curl_hmac.h"
 #include "curl_memory.h"
+
 /* The last #include file should be: */
 #include "memdebug.h"
 
diff --git a/lib/hostasyn.c b/lib/hostasyn.c
index 17b8be0..28bdf7a 100644
--- a/lib/hostasyn.c
+++ b/lib/hostasyn.c
@@ -9,7 +9,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -77,7 +77,7 @@ CURLcode Curl_addrinfo_callback(struct connectdata *conn,
 
   if(CURL_ASYNC_SUCCESS == status) {
     if(ai) {
-      struct SessionHandle *data = conn->data;
+      struct Curl_easy *data = conn->data;
 
       if(data->share)
         Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
diff --git a/lib/hostcheck.c b/lib/hostcheck.c
index 62a26e4..4db9e6b 100644
--- a/lib/hostcheck.c
+++ b/lib/hostcheck.c
@@ -9,7 +9,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -43,7 +43,7 @@
  *  "foo.host.com" matches "*.host.com".
  *
  * We use the matching rule described in RFC6125, section 6.4.3.
- * http://tools.ietf.org/html/rfc6125#section-6.4.3
+ * https://tools.ietf.org/html/rfc6125#section-6.4.3
  *
  * In addition: ignore trailing dots in the host names and wildcards, so that
  * the names are used normalized. This is what the browsers do.
diff --git a/lib/hostcheck.h b/lib/hostcheck.h
index f4a517a..86e3b96 100644
--- a/lib/hostcheck.h
+++ b/lib/hostcheck.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/hostip.c b/lib/hostip.c
index 82f3897..f2d9841 100644
--- a/lib/hostip.c
+++ b/lib/hostip.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -56,9 +56,9 @@
 #include "url.h"
 #include "inet_ntop.h"
 #include "warnless.h"
+/* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_memory.h"
-/* The last #include file should be: */
 #include "memdebug.h"
 
 #if defined(CURLRES_SYNCH) && \
@@ -254,7 +254,7 @@ hostcache_prune(struct curl_hash *hostcache, long cache_timeout, time_t now)
  * Library-wide function for pruning the DNS cache. This function takes and
  * returns the appropriate locks.
  */
-void Curl_hostcache_prune(struct SessionHandle *data)
+void Curl_hostcache_prune(struct Curl_easy *data)
 {
   time_t now;
 
@@ -293,7 +293,7 @@ fetch_addr(struct connectdata *conn,
   char *entry_id = NULL;
   struct Curl_dns_entry *dns = NULL;
   size_t entry_len;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   /* Create an entry id, based upon the hostname and port */
   entry_id = create_hostcache_id(hostname, port);
@@ -345,7 +345,7 @@ Curl_fetch_addr(struct connectdata *conn,
                 const char *hostname,
                 int port)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct Curl_dns_entry *dns = NULL;
 
   if(data->share)
@@ -353,7 +353,8 @@ Curl_fetch_addr(struct connectdata *conn,
 
   dns = fetch_addr(conn, hostname, port);
 
-  if(dns) dns->inuse++; /* we use it! */
+  if(dns)
+    dns->inuse++; /* we use it! */
 
   if(data->share)
     Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
@@ -371,7 +372,7 @@ Curl_fetch_addr(struct connectdata *conn,
  * Returns the Curl_dns_entry entry pointer or NULL if the storage failed.
  */
 struct Curl_dns_entry *
-Curl_cache_addr(struct SessionHandle *data,
+Curl_cache_addr(struct Curl_easy *data,
                 Curl_addrinfo *addr,
                 const char *hostname,
                 int port)
@@ -446,7 +447,7 @@ int Curl_resolv(struct connectdata *conn,
                 struct Curl_dns_entry **entry)
 {
   struct Curl_dns_entry *dns = NULL;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   CURLcode result;
   int rc = CURLRESOLV_ERROR; /* default to failure */
 
@@ -581,7 +582,7 @@ int Curl_resolv_timeout(struct connectdata *conn,
 #endif /* HAVE_SIGACTION */
   volatile long timeout;
   volatile unsigned int prev_alarm = 0;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 #endif /* USE_ALARM_TIMEOUT */
   int rc;
 
@@ -715,7 +716,7 @@ clean_up:
  *
  * May be called with 'data' == NULL for global cache.
  */
-void Curl_resolv_unlock(struct SessionHandle *data, struct Curl_dns_entry *dns)
+void Curl_resolv_unlock(struct Curl_easy *data, struct Curl_dns_entry *dns)
 {
   if(data && data->share)
     Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
@@ -757,7 +758,7 @@ int Curl_mk_dnscache(struct curl_hash *hash)
  * can be done!
  */
 
-void Curl_hostcache_clean(struct SessionHandle *data,
+void Curl_hostcache_clean(struct Curl_easy *data,
                           struct curl_hash *hash)
 {
   if(data && data->share)
@@ -770,14 +771,14 @@ void Curl_hostcache_clean(struct SessionHandle *data,
 }
 
 
-CURLcode Curl_loadhostpairs(struct SessionHandle *data)
+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 ) {
+  for(hostp = data->change.resolve; hostp; hostp = hostp->next) {
     if(!hostp->data)
       continue;
     if(hostp->data[0] == '-') {
diff --git a/lib/hostip.h b/lib/hostip.h
index d5b44bc..9098ee3 100644
--- a/lib/hostip.h
+++ b/lib/hostip.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -50,7 +50,7 @@
 
 struct addrinfo;
 struct hostent;
-struct SessionHandle;
+struct Curl_easy;
 struct connectdata;
 
 /*
@@ -118,7 +118,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
 
 
 /* unlock a previously resolved dns entry */
-void Curl_resolv_unlock(struct SessionHandle *data,
+void Curl_resolv_unlock(struct Curl_easy *data,
                         struct Curl_dns_entry *dns);
 
 /* for debugging purposes only: */
@@ -128,7 +128,7 @@ void Curl_scan_cache_used(void *user, void *ptr);
 int Curl_mk_dnscache(struct curl_hash *hash);
 
 /* prune old entries from the DNS cache */
-void Curl_hostcache_prune(struct SessionHandle *data);
+void Curl_hostcache_prune(struct Curl_easy *data);
 
 /* Return # of adresses in a Curl_addrinfo struct */
 int Curl_num_addresses (const Curl_addrinfo *addr);
@@ -188,7 +188,7 @@ Curl_fetch_addr(struct connectdata *conn,
  * Returns the Curl_dns_entry entry pointer or NULL if the storage failed.
  */
 struct Curl_dns_entry *
-Curl_cache_addr(struct SessionHandle *data, Curl_addrinfo *addr,
+Curl_cache_addr(struct Curl_easy *data, Curl_addrinfo *addr,
                 const char *hostname, int port);
 
 #ifndef INADDR_NONE
@@ -209,42 +209,42 @@ extern sigjmp_buf curl_jmpenv;
 /*
  * Function provided by the resolver backend to set DNS servers to use.
  */
-CURLcode Curl_set_dns_servers(struct SessionHandle *data, char *servers);
+CURLcode Curl_set_dns_servers(struct Curl_easy *data, char *servers);
 
 /*
  * Function provided by the resolver backend to set
  * outgoing interface to use for DNS requests
  */
-CURLcode Curl_set_dns_interface(struct SessionHandle *data,
+CURLcode Curl_set_dns_interface(struct Curl_easy *data,
                                 const char *interf);
 
 /*
  * Function provided by the resolver backend to set
  * local IPv4 address to use as source address for DNS requests
  */
-CURLcode Curl_set_dns_local_ip4(struct SessionHandle *data,
+CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
                                 const char *local_ip4);
 
 /*
  * Function provided by the resolver backend to set
  * local IPv6 address to use as source address for DNS requests
  */
-CURLcode Curl_set_dns_local_ip6(struct SessionHandle *data,
+CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
                                 const char *local_ip6);
 
 /*
  * Clean off entries from the cache
  */
-void Curl_hostcache_clean(struct SessionHandle *data, struct curl_hash *hash);
+void Curl_hostcache_clean(struct Curl_easy *data, struct curl_hash *hash);
 
 /*
  * Destroy the hostcache of this handle.
  */
-void Curl_hostcache_destroy(struct SessionHandle *data);
+void Curl_hostcache_destroy(struct Curl_easy *data);
 
 /*
  * Populate the cache with specified entries from CURLOPT_RESOLVE.
  */
-CURLcode Curl_loadhostpairs(struct SessionHandle *data);
+CURLcode Curl_loadhostpairs(struct Curl_easy *data);
 
 #endif /* HEADER_CURL_HOSTIP_H */
diff --git a/lib/hostip4.c b/lib/hostip4.c
index 37b0369..15895d7 100644
--- a/lib/hostip4.c
+++ b/lib/hostip4.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -48,9 +48,9 @@
 #include "strerror.h"
 #include "url.h"
 #include "inet_pton.h"
+/* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_memory.h"
-/* The last #include file should be: */
 #include "memdebug.h"
 
 /***********************************************************************
diff --git a/lib/hostip6.c b/lib/hostip6.c
index 6ab131a..4ebfc2d 100644
--- a/lib/hostip6.c
+++ b/lib/hostip6.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -49,9 +49,9 @@
 #include "url.h"
 #include "inet_pton.h"
 #include "connect.h"
+/* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_memory.h"
-/* The last #include file should be: */
 #include "memdebug.h"
 
 /***********************************************************************
@@ -59,7 +59,6 @@
  **********************************************************************/
 #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
@@ -124,6 +123,7 @@ bool Curl_ipvalid(struct connectdata *conn)
 {
   if(conn->ip_version == CURL_IPRESOLVE_V6)
     return Curl_ipv6works();
+
   return TRUE;
 }
 
@@ -167,15 +167,17 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
   int error;
   char sbuf[12];
   char *sbufptr = NULL;
+#ifndef USE_RESOLVE_ON_IPS
   char addrbuf[128];
+#endif
   int pf;
-  struct SessionHandle *data = conn->data;
+#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
+  struct Curl_easy *data = conn->data;
+#endif
 
   *waitp = 0; /* synchronous response only */
 
-  /*
-   * Check if a limited name resolve has been requested.
-   */
+  /* Check if a limited name resolve has been requested */
   switch(conn->ip_version) {
   case CURL_IPRESOLVE_V4:
     pf = PF_INET;
@@ -196,26 +198,37 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
   hints.ai_family = pf;
   hints.ai_socktype = conn->socktype;
 
+#ifndef USE_RESOLVE_ON_IPS
+  /*
+   * The AI_NUMERICHOST must not be set to get synthesized IPv6 address from
+   * an IPv4 address on iOS and Mac OS X.
+   */
   if((1 == Curl_inet_pton(AF_INET, hostname, addrbuf)) ||
      (1 == Curl_inet_pton(AF_INET6, hostname, addrbuf))) {
     /* the given address is numerical only, prevent a reverse lookup */
     hints.ai_flags = AI_NUMERICHOST;
   }
+#endif
 
   if(port) {
     snprintf(sbuf, sizeof(sbuf), "%d", port);
     sbufptr=sbuf;
   }
+
   error = Curl_getaddrinfo_ex(hostname, sbufptr, &hints, &res);
   if(error) {
     infof(data, "getaddrinfo(3) failed for %s:%d\n", hostname, port);
     return NULL;
   }
 
+  if(port) {
+    Curl_addrinfo_set_port(res, port);
+  }
+
   dump_addrinfo(conn, res);
 
   return res;
 }
 #endif /* CURLRES_SYNCH */
-#endif /* CURLRES_IPV6 */
 
+#endif /* CURLRES_IPV6 */
diff --git a/lib/hostsyn.c b/lib/hostsyn.c
index fb1de35..1a95263 100644
--- a/lib/hostsyn.c
+++ b/lib/hostsyn.c
@@ -9,7 +9,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -59,7 +59,7 @@
 /*
  * Function provided by the resolver backend to set DNS servers to use.
  */
-CURLcode Curl_set_dns_servers(struct SessionHandle *data,
+CURLcode Curl_set_dns_servers(struct Curl_easy *data,
                               char *servers)
 {
   (void)data;
@@ -72,7 +72,7 @@ CURLcode Curl_set_dns_servers(struct SessionHandle *data,
  * Function provided by the resolver backend to set
  * outgoing interface to use for DNS requests
  */
-CURLcode Curl_set_dns_interface(struct SessionHandle *data,
+CURLcode Curl_set_dns_interface(struct Curl_easy *data,
                                 const char *interf)
 {
   (void)data;
@@ -84,7 +84,7 @@ CURLcode Curl_set_dns_interface(struct SessionHandle *data,
  * Function provided by the resolver backend to set
  * local IPv4 address to use as source address for DNS requests
  */
-CURLcode Curl_set_dns_local_ip4(struct SessionHandle *data,
+CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
                                 const char *local_ip4)
 {
   (void)data;
@@ -96,7 +96,7 @@ CURLcode Curl_set_dns_local_ip4(struct SessionHandle *data,
  * Function provided by the resolver backend to set
  * local IPv6 address to use as source address for DNS requests
  */
-CURLcode Curl_set_dns_local_ip6(struct SessionHandle *data,
+CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
                                 const char *local_ip6)
 {
   (void)data;
diff --git a/lib/http.c b/lib/http.c
index 9817d72..378d8f7 100644
--- a/lib/http.c
+++ b/lib/http.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -54,9 +54,10 @@
 #include "curl_base64.h"
 #include "cookie.h"
 #include "strequal.h"
+#include "vauth/vauth.h"
 #include "vtls/vtls.h"
 #include "http_digest.h"
-#include "curl_ntlm.h"
+#include "http_ntlm.h"
 #include "curl_ntlm_wb.h"
 #include "http_negotiate.h"
 #include "url.h"
@@ -76,9 +77,9 @@
 #include "pipeline.h"
 #include "http2.h"
 #include "connect.h"
-#include "curl_printf.h"
 
-/* The last #include files should be: */
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
 #include "curl_memory.h"
 #include "memdebug.h"
 
@@ -144,14 +145,13 @@ const struct Curl_handler Curl_handler_https = {
   ZERO_NULL,                            /* readwrite */
   PORT_HTTPS,                           /* defport */
   CURLPROTO_HTTPS,                      /* protocol */
-  PROTOPT_SSL | PROTOPT_CREDSPERREQUEST /* flags */
+  PROTOPT_SSL | PROTOPT_CREDSPERREQUEST | PROTOPT_ALPN_NPN /* flags */
 };
 #endif
 
-
 CURLcode Curl_http_setup_conn(struct connectdata *conn)
 {
-  /* allocate the HTTP-specific struct for the SessionHandle, only to survive
+  /* allocate the HTTP-specific struct for the Curl_easy, only to survive
      during this request */
   struct HTTP *http;
   DEBUGASSERT(conn->data->req.protop == NULL);
@@ -179,12 +179,13 @@ char *Curl_checkheaders(const struct connectdata *conn,
 {
   struct curl_slist *head;
   size_t thislen = strlen(thisheader);
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   for(head = data->set.headers;head; head=head->next) {
     if(Curl_raw_nequal(head->data, thisheader, thislen))
       return head->data;
   }
+
   return NULL;
 }
 
@@ -193,24 +194,24 @@ char *Curl_checkheaders(const struct connectdata *conn,
  * if proxy headers are not available, then it will lookup into http header
  * link list
  *
- * It takes a connectdata struct as input instead of the SessionHandle simply
+ * It takes a connectdata struct as input instead of the Curl_easy simply
  * to know if this is a proxy request or not, as it then might check a
  * different header list.
- *
  */
 char *Curl_checkProxyheaders(const struct connectdata *conn,
                              const char *thisheader)
 {
   struct curl_slist *head;
   size_t thislen = strlen(thisheader);
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
-  for(head = (conn->bits.proxy && data->set.sep_headers)?
-        data->set.proxyheaders:data->set.headers;
+  for(head = (conn->bits.proxy && data->set.sep_headers) ?
+        data->set.proxyheaders : data->set.headers;
       head; head=head->next) {
     if(Curl_raw_nequal(head->data, thisheader, thislen))
       return head->data;
   }
+
   return NULL;
 }
 
@@ -279,7 +280,7 @@ static CURLcode http_output_basic(struct connectdata *conn, bool proxy)
 {
   size_t size = 0;
   char *authorization = NULL;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   char **userp;
   const char *user;
   const char *pwd;
@@ -309,7 +310,7 @@ static CURLcode http_output_basic(struct connectdata *conn, bool proxy)
 
   free(*userp);
   *userp = aprintf("%sAuthorization: Basic %s\r\n",
-                   proxy?"Proxy-":"",
+                   proxy ? "Proxy-" : "",
                    authorization);
   free(authorization);
   if(!*userp)
@@ -376,7 +377,7 @@ static bool pickoneauth(struct auth *pick)
  */
 static CURLcode http_perhapsrewind(struct connectdata *conn)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct HTTP *http = data->req.protop;
   curl_off_t bytessent;
   curl_off_t expectsend = -1; /* default is unknown */
@@ -484,7 +485,7 @@ static CURLcode http_perhapsrewind(struct connectdata *conn)
 
 CURLcode Curl_http_auth_act(struct connectdata *conn)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   bool pickhost = FALSE;
   bool pickproxy = FALSE;
   CURLcode result = CURLE_OK;
@@ -528,7 +529,6 @@ CURLcode Curl_http_auth_act(struct connectdata *conn)
         return result;
     }
   }
-
   else if((data->req.httpcode < 300) &&
           (!data->state.authhost.done) &&
           conn->bits.authneg) {
@@ -553,7 +553,6 @@ CURLcode Curl_http_auth_act(struct connectdata *conn)
   return result;
 }
 
-
 /*
  * Output the correct authentication header depending on the auth type
  * and whether or not it is to a proxy.
@@ -567,12 +566,12 @@ output_auth_headers(struct connectdata *conn,
 {
   const char *auth = NULL;
   CURLcode result = CURLE_OK;
-#if defined(USE_SPNEGO) || !defined(CURL_DISABLE_VERBOSE_STRINGS)
-  struct SessionHandle *data = conn->data;
+#if !defined(CURL_DISABLE_VERBOSE_STRINGS) || defined(USE_SPNEGO)
+  struct Curl_easy *data = conn->data;
 #endif
 #ifdef USE_SPNEGO
-  struct negotiatedata *negdata = proxy?
-    &data->state.proxyneg:&data->state.negotiate;
+  struct negotiatedata *negdata = proxy ?
+    &data->state.proxyneg : &data->state.negotiate;
 #endif
 
 #ifdef CURL_DISABLE_CRYPTO_AUTH
@@ -584,7 +583,7 @@ output_auth_headers(struct connectdata *conn,
   negdata->state = GSS_AUTHNONE;
   if((authstatus->picked == CURLAUTH_NEGOTIATE) &&
      negdata->context && !GSS_ERROR(negdata->status)) {
-    auth="Negotiate";
+    auth = "Negotiate";
     result = Curl_output_negotiate(conn, proxy);
     if(result)
       return result;
@@ -595,7 +594,7 @@ output_auth_headers(struct connectdata *conn,
 #endif
 #ifdef USE_NTLM
   if(authstatus->picked == CURLAUTH_NTLM) {
-    auth="NTLM";
+    auth = "NTLM";
     result = Curl_output_ntlm(conn, proxy);
     if(result)
       return result;
@@ -613,7 +612,7 @@ output_auth_headers(struct connectdata *conn,
 #endif
 #ifndef CURL_DISABLE_CRYPTO_AUTH
   if(authstatus->picked == CURLAUTH_DIGEST) {
-    auth="Digest";
+    auth = "Digest";
     result = Curl_output_digest(conn,
                                 proxy,
                                 (const unsigned char *)request,
@@ -629,11 +628,12 @@ output_auth_headers(struct connectdata *conn,
         !Curl_checkProxyheaders(conn, "Proxy-authorization:")) ||
        (!proxy && conn->bits.user_passwd &&
         !Curl_checkheaders(conn, "Authorization:"))) {
-      auth="Basic";
+      auth = "Basic";
       result = http_output_basic(conn, proxy);
       if(result)
         return result;
     }
+
     /* NOTE: this function should set 'done' TRUE, as the other auth
        functions work that way */
     authstatus->done = TRUE;
@@ -641,9 +641,9 @@ output_auth_headers(struct connectdata *conn,
 
   if(auth) {
     infof(data, "%s auth using %s with user '%s'\n",
-          proxy?"Proxy":"Server", auth,
-          proxy?(conn->proxyuser?conn->proxyuser:""):
-                (conn->user?conn->user:""));
+          proxy ? "Proxy" : "Server", auth,
+          proxy ? (conn->proxyuser ? conn->proxyuser : "") :
+                  (conn->user ? conn->user : ""));
     authstatus->multi = (!authstatus->done) ? TRUE : FALSE;
   }
   else
@@ -674,7 +674,7 @@ Curl_http_output_auth(struct connectdata *conn,
                                            up the proxy tunnel */
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct auth *authhost;
   struct auth *authproxy;
 
@@ -735,7 +735,6 @@ Curl_http_output_auth(struct connectdata *conn,
   return result;
 }
 
-
 /*
  * Curl_http_input_auth() deals with Proxy-Authenticate: and WWW-Authenticate:
  * headers. They are dealt with both in the transfer.c main loop and in the
@@ -748,7 +747,7 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy,
   /*
    * This resource requires authentication
    */
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
 #ifdef USE_SPNEGO
   struct negotiatedata *negdata = proxy?
@@ -780,7 +779,6 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy,
    * request is sent, and then it is again set _after_ all response 401/407
    * headers have been received but then only to a single preferred method
    * (bit).
-   *
    */
 
   while(*auth) {
@@ -893,6 +891,7 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy,
     while(*auth && ISSPACE(*auth))
       auth++;
   }
+
   return CURLE_OK;
 }
 
@@ -908,7 +907,7 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy,
  */
 static int http_should_fail(struct connectdata *conn)
 {
-  struct SessionHandle *data;
+  struct Curl_easy *data;
   int httpcode;
 
   DEBUGASSERT(conn);
@@ -934,8 +933,7 @@ static int http_should_fail(struct connectdata *conn)
   ** Any code >= 400 that's not 401 or 407 is always
   ** a terminal error
   */
-  if((httpcode != 401) &&
-      (httpcode != 407))
+  if((httpcode != 401) && (httpcode != 407))
     return 1;
 
   /*
@@ -986,7 +984,7 @@ static size_t readmoredata(char *buffer,
   struct HTTP *http = conn->data->req.protop;
   size_t fullsize = size * nitems;
 
-  if(0 == http->postsize)
+  if(!http->postsize)
     /* nothing to return */
     return 0;
 
@@ -1001,8 +999,8 @@ static size_t readmoredata(char *buffer,
       /* move backup data into focus and continue on that */
       http->postdata = http->backup.postdata;
       http->postsize = http->backup.postsize;
-      conn->data->set.fread_func = http->backup.fread_func;
-      conn->data->set.in = http->backup.fread_in;
+      conn->data->state.fread_func = http->backup.fread_func;
+      conn->data->state.in = http->backup.fread_in;
 
       http->sending++; /* move one step up */
 
@@ -1092,15 +1090,14 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
     return result;
   }
 
-
-  if(conn->handler->flags & PROTOPT_SSL) {
+  if((conn->handler->flags & PROTOPT_SSL) && conn->httpversion != 20) {
     /* We never send more than CURL_MAX_WRITE_SIZE bytes in one single chunk
        when we speak HTTPS, as if only a fraction of it is sent now, this data
        needs to fit into the normal read-callback buffer later on and that
        buffer is using this size.
     */
 
-    sendsize= (size > CURL_MAX_WRITE_SIZE)?CURL_MAX_WRITE_SIZE:size;
+    sendsize = (size > CURL_MAX_WRITE_SIZE) ? CURL_MAX_WRITE_SIZE : size;
 
     /* OpenSSL is very picky and we must send the SAME buffer pointer to the
        library when we attempt to re-send this buffer. Sending the same data
@@ -1123,7 +1120,7 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
      * only send away a part).
      */
     /* how much of the header that was sent */
-    size_t headlen = (size_t)amount>headersize?headersize:(size_t)amount;
+    size_t headlen = (size_t)amount>headersize ? headersize : (size_t)amount;
     size_t bodylen = amount - headlen;
 
     if(conn->data->set.verbose) {
@@ -1136,10 +1133,6 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
                    ptr+headlen, bodylen, conn);
       }
     }
-    if(bodylen)
-      /* since we sent a piece of the body here, up the byte counter for it
-         accordingly */
-      http->writebytecount += bodylen;
 
     /* 'amount' can never be a very large value here so typecasting it so a
        signed 31 bit value should not cause problems even if ssize_t is
@@ -1147,6 +1140,10 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
     *bytes_written += (long)amount;
 
     if(http) {
+      /* if we sent a piece of the body here, up the byte counter for it
+         accordingly */
+      http->writebytecount += bodylen;
+
       if((size_t)amount != size) {
         /* The whole request could not be sent in one system call. We must
            queue it up and send it later when we get the chance. We must not
@@ -1157,14 +1154,14 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
         ptr = in->buffer + amount;
 
         /* backup the currently set pointers */
-        http->backup.fread_func = conn->data->set.fread_func;
-        http->backup.fread_in = conn->data->set.in;
+        http->backup.fread_func = conn->data->state.fread_func;
+        http->backup.fread_in = conn->data->state.in;
         http->backup.postdata = http->postdata;
         http->backup.postsize = http->postsize;
 
         /* set the new pointers for the request-sending */
-        conn->data->set.fread_func = (curl_read_callback)readmoredata;
-        conn->data->set.in = (void *)conn;
+        conn->data->state.fread_func = (curl_read_callback)readmoredata;
+        conn->data->state.in = (void *)conn;
         http->postdata = ptr;
         http->postsize = (curl_off_t)size;
 
@@ -1242,11 +1239,11 @@ CURLcode Curl_add_buffer(Curl_send_buffer *in, const void *inptr, size_t size)
        buffer size that doubles the required size. If this new size
        would wrap size_t, then just use the largest possible one */
 
-    if((size > (size_t)-1/2) || (in->size_used > (size_t)-1/2) ||
-       (~(size*2) < (in->size_used*2)))
+    if((size > (size_t)-1 / 2) || (in->size_used > (size_t)-1 / 2) ||
+       (~(size * 2) < (in->size_used * 2)))
       new_size = (size_t)-1;
     else
-      new_size = (in->size_used+size)*2;
+      new_size = (in->size_used+size) * 2;
 
     if(in->buffer)
       /* we have a buffer, enlarge the existing one */
@@ -1394,7 +1391,8 @@ static CURLcode https_connecting(struct connectdata *conn, bool *done)
 #endif
 
 #if defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) || \
-    defined(USE_DARWINSSL) || defined(USE_POLARSSL) || defined(USE_NSS)
+    defined(USE_DARWINSSL) || defined(USE_POLARSSL) || defined(USE_NSS) || \
+    defined(USE_MBEDTLS)
 /* This function is for OpenSSL, GnuTLS, darwinssl, schannel and polarssl only.
    It should be made to query the generic SSL layer instead. */
 static int https_getsock(struct connectdata *conn,
@@ -1418,6 +1416,7 @@ static int https_getsock(struct connectdata *conn,
       return GETSOCK_READSOCK(0);
     }
   }
+
   return CURLE_OK;
 }
 #else
@@ -1435,14 +1434,14 @@ static int https_getsock(struct connectdata *conn,
 #endif /* USE_OPENSSL || USE_GNUTLS || USE_SCHANNEL */
 
 /*
- * Curl_http_done() gets called from Curl_done() after a single HTTP request
- * has been performed.
+ * Curl_http_done() gets called after a single HTTP request has been
+ * performed.
  */
 
 CURLcode Curl_http_done(struct connectdata *conn,
                         CURLcode status, bool premature)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct HTTP *http = data->req.protop;
 #ifdef USE_NGHTTP2
   struct http_conn *httpc = &conn->proto.httpc;
@@ -1455,8 +1454,10 @@ CURLcode Curl_http_done(struct connectdata *conn,
      data->state.negotiate.state == GSS_AUTHSENT) {
     /* add forbid re-use if http-code != 401/407 as a WA only needed for
      * 401/407 that signal auth failure (empty) otherwise state will be RECV
-     * with current code */
-    if((data->req.httpcode != 401) && (data->req.httpcode != 407))
+     * with current code.
+     * Do not close CONNECT_ONLY connections. */
+    if((data->req.httpcode != 401) && (data->req.httpcode != 407) &&
+       !data->set.connect_only)
       connclose(conn, "Negotiate transfer completed");
     Curl_cleanup_negotiate(data);
   }
@@ -1466,7 +1467,7 @@ CURLcode Curl_http_done(struct connectdata *conn,
   conn->seek_func = data->set.seek_func; /* restore */
   conn->seek_client = data->set.seek_client; /* restore */
 
-  if(http == NULL)
+  if(!http)
     return CURLE_OK;
 
   if(http->send_buffer) {
@@ -1479,11 +1480,16 @@ CURLcode Curl_http_done(struct connectdata *conn,
     DEBUGF(infof(data, "free header_recvbuf!!\n"));
     Curl_add_buffer_free(http->header_recvbuf);
     http->header_recvbuf = NULL; /* clear the pointer */
-    for(; http->push_headers_used > 0; --http->push_headers_used) {
-      free(http->push_headers[http->push_headers_used - 1]);
+    Curl_add_buffer_free(http->trailer_recvbuf);
+    http->trailer_recvbuf = NULL; /* clear the pointer */
+    if(http->push_headers) {
+      /* if they weren't used and then freed before */
+      for(; http->push_headers_used > 0; --http->push_headers_used) {
+        free(http->push_headers[http->push_headers_used - 1]);
+      }
+      free(http->push_headers);
+      http->push_headers = NULL;
     }
-    free(http->push_headers);
-    http->push_headers = NULL;
   }
   if(http->stream_id) {
     nghttp2_session_set_stream_user_data(httpc->h2, http->stream_id, 0);
@@ -1511,9 +1517,9 @@ CURLcode Curl_http_done(struct connectdata *conn,
                       entire operation is complete */
      !conn->bits.retry &&
      !data->set.connect_only &&
-     ((http->readbytecount +
-       data->req.headerbytecount -
-       data->req.deductheadercount)) <= 0) {
+     (http->readbytecount +
+      data->req.headerbytecount -
+      data->req.deductheadercount) <= 0) {
     /* If this connection isn't simply closed to be retried, AND nothing was
        read from the HTTP server (that counts), this can't be right so we
        return an error here */
@@ -1524,7 +1530,6 @@ CURLcode Curl_http_done(struct connectdata *conn,
   return CURLE_OK;
 }
 
-
 /*
  * Determine if we should use HTTP 1.1 (OR BETTER) for this request. Reasons
  * to avoid it include:
@@ -1534,18 +1539,20 @@ CURLcode Curl_http_done(struct connectdata *conn,
  * - if any server previously contacted to handle this request only supports
  * 1.0.
  */
-static bool use_http_1_1plus(const struct SessionHandle *data,
+static bool use_http_1_1plus(const struct Curl_easy *data,
                              const struct connectdata *conn)
 {
-  return ((data->set.httpversion >= CURL_HTTP_VERSION_1_1) ||
-         ((data->set.httpversion != CURL_HTTP_VERSION_1_0) &&
-          ((conn->httpversion == 11) ||
-           ((conn->httpversion != 10) &&
-            (data->state.httpversion != 10))))) ? TRUE : FALSE;
+  if((data->state.httpversion == 10) || (conn->httpversion == 10))
+    return FALSE;
+  if((data->set.httpversion == CURL_HTTP_VERSION_1_0) &&
+     (conn->httpversion <= 10))
+    return FALSE;
+  return ((data->set.httpversion == CURL_HTTP_VERSION_NONE) ||
+          (data->set.httpversion >= CURL_HTTP_VERSION_1_1));
 }
 
 /* check and possibly add an Expect: header */
-static CURLcode expect100(struct SessionHandle *data,
+static CURLcode expect100(struct Curl_easy *data,
                           struct connectdata *conn,
                           Curl_send_buffer *req_buffer)
 {
@@ -1570,6 +1577,7 @@ static CURLcode expect100(struct SessionHandle *data,
         data->state.expect100header = TRUE;
     }
   }
+
   return result;
 }
 
@@ -1587,7 +1595,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
   struct curl_slist *h[2];
   struct curl_slist *headers;
   int numlists=1; /* by default */
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   int i;
 
   enum proxy_use proxy;
@@ -1688,16 +1696,23 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
       headers = headers->next;
     }
   }
+
   return CURLE_OK;
 }
 
-CURLcode Curl_add_timecondition(struct SessionHandle *data,
+CURLcode Curl_add_timecondition(struct Curl_easy *data,
                                 Curl_send_buffer *req_buffer)
 {
   const struct tm *tm;
   char *buf = data->state.buffer;
   struct tm keeptime;
-  CURLcode result = Curl_gmtime(data->set.timevalue, &keeptime);
+  CURLcode result;
+
+  if(data->set.timecondition == CURL_TIMECOND_NONE)
+    /* no condition was asked for */
+    return CURLE_OK;
+
+  result = Curl_gmtime(data->set.timevalue, &keeptime);
   if(result) {
     failf(data, "Invalid TIMEVALUE");
     return result;
@@ -1723,8 +1738,9 @@ CURLcode Curl_add_timecondition(struct SessionHandle *data,
            tm->tm_sec);
 
   switch(data->set.timecondition) {
-  case CURL_TIMECOND_IFMODSINCE:
   default:
+    break;
+  case CURL_TIMECOND_IFMODSINCE:
     result = Curl_add_bufferf(req_buffer,
                               "If-Modified-Since: %s\r\n", buf);
     break;
@@ -1742,13 +1758,13 @@ CURLcode Curl_add_timecondition(struct SessionHandle *data,
 }
 
 /*
- * Curl_http() gets called from the generic Curl_do() function when a HTTP
+ * Curl_http() gets called from the generic multi_do() function when a HTTP
  * request is to be performed. This creates and sends a properly constructed
  * HTTP request.
  */
 CURLcode Curl_http(struct connectdata *conn, bool *done)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   CURLcode result = CURLE_OK;
   struct HTTP *http;
   const char *ppath = data->state.path;
@@ -1776,15 +1792,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
   if(conn->httpversion < 20) { /* unless the connection is re-used and already
                                   http2 */
     switch(conn->negnpn) {
-    case CURL_HTTP_VERSION_2_0:
+    case CURL_HTTP_VERSION_2:
       conn->httpversion = 20; /* we know we're on HTTP/2 now */
-      result = Curl_http2_init(conn);
-      if(result)
-        return result;
-
-      result = Curl_http2_setup(conn);
-      if(result)
-        return result;
 
       result = Curl_http2_switched(conn, NULL, 0);
       if(result)
@@ -1794,7 +1803,18 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
       /* continue with HTTP/1.1 when explicitly requested */
       break;
     default:
-      /* and as fallback */
+      /* Check if user wants to use HTTP/2 with clear TCP*/
+#ifdef USE_NGHTTP2
+      if(conn->data->set.httpversion ==
+         CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) {
+        DEBUGF(infof(data, "HTTP/2 over clean TCP\n"));
+        conn->httpversion = 20;
+
+        result = Curl_http2_switched(conn, NULL, 0);
+        if(result)
+          return result;
+      }
+#endif
       break;
     }
   }
@@ -1814,6 +1834,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
     data->state.first_host = strdup(conn->host.name);
     if(!data->state.first_host)
       return CURLE_OUT_OF_MEMORY;
+
+    data->state.first_remote_port = conn->remote_port;
   }
   http->writebytecount = http->readbytecount = 0;
 
@@ -1895,6 +1917,10 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
     if(!conn->allocptr.accept_encoding)
       return CURLE_OUT_OF_MEMORY;
   }
+  else {
+    Curl_safefree(conn->allocptr.accept_encoding);
+    conn->allocptr.accept_encoding = NULL;
+  }
 
 #ifdef HAVE_LIBZ
   /* we only consider transfer-encoding magic if libz support is built-in */
@@ -2130,7 +2156,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
      * file size before we continue this venture in the dark lands of HTTP.
      *********************************************************************/
 
-    if(data->state.resume_from < 0 ) {
+    if(data->state.resume_from < 0) {
       /*
        * This is meant to get the size of the present remote-file by itself.
        * We don't support this now. Bail out!
@@ -2162,8 +2188,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
               BUFSIZE : curlx_sotouz(data->state.resume_from - passed);
 
             size_t actuallyread =
-              data->set.fread_func(data->state.buffer, 1, readthisamountnow,
-                                   data->set.in);
+              data->state.fread_func(data->state.buffer, 1, readthisamountnow,
+                                     data->state.in);
 
             passed += actuallyread;
             if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
@@ -2279,7 +2305,6 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
                      "%s" /* TE: */
                      "%s" /* accept-encoding */
                      "%s" /* referer */
-                     "%s" /* Proxy-Connection */
                      "%s",/* transfer-encoding */
 
                      ftp_typecode,
@@ -2302,10 +2327,6 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
                      conn->allocptr.accept_encoding:"",
                      (data->change.referer && conn->allocptr.ref)?
                      conn->allocptr.ref:"" /* Referer: <data> */,
-                     (conn->bits.httpproxy &&
-                      !conn->bits.tunnel_proxy &&
-                      !Curl_checkProxyheaders(conn, "Proxy-Connection:"))?
-                     "Proxy-Connection: Keep-Alive\r\n":"",
                      te
       );
 
@@ -2329,7 +2350,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
 
   if(!(conn->handler->flags&PROTOPT_SSL) &&
      conn->httpversion != 20 &&
-     (data->set.httpversion == CURL_HTTP_VERSION_2_0)) {
+     (data->set.httpversion == CURL_HTTP_VERSION_2)) {
     /* append HTTP2 upgrade magic stuff to the HTTP request if it isn't done
        over SSL */
     result = Curl_http2_request_upgrade(req_buffer, conn);
@@ -2390,11 +2411,9 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
   }
 #endif
 
-  if(data->set.timecondition) {
-    result = Curl_add_timecondition(data, req_buffer);
-    if(result)
-      return result;
-  }
+  result = Curl_add_timecondition(data, req_buffer);
+  if(result)
+    return result;
 
   result = Curl_add_custom_headers(conn, FALSE, req_buffer);
   if(result)
@@ -2437,11 +2456,11 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
        on. The data->set.fread_func pointer itself will be changed for the
        multipart case to the function that returns a multipart formatted
        stream. */
-    http->form.fread_func = data->set.fread_func;
+    http->form.fread_func = data->state.fread_func;
 
     /* Set the read function to read from the generated form data */
-    data->set.fread_func = (curl_read_callback)Curl_FormReader;
-    data->set.in = &http->form;
+    data->state.fread_func = (curl_read_callback)Curl_FormReader;
+    data->state.in = &http->form;
 
     http->sending = HTTPSEND_BODY;
 
@@ -2659,8 +2678,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
 
         http->sending = HTTPSEND_BODY;
 
-        data->set.fread_func = (curl_read_callback)readmoredata;
-        data->set.in = (void *)conn;
+        data->state.fread_func = (curl_read_callback)readmoredata;
+        data->state.in = (void *)conn;
 
         /* set the upload size to the progress meter */
         Curl_pgrsSetUploadSize(data, http->postsize);
@@ -2758,7 +2777,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
  * Returns TRUE if member of the list matches prefix of string
  */
 static bool
-checkhttpprefix(struct SessionHandle *data,
+checkhttpprefix(struct Curl_easy *data,
                 const char *s)
 {
   struct curl_slist *head = data->set.http200aliases;
@@ -2797,7 +2816,7 @@ checkhttpprefix(struct SessionHandle *data,
 
 #ifndef CURL_DISABLE_RTSP
 static bool
-checkrtspprefix(struct SessionHandle *data,
+checkrtspprefix(struct Curl_easy *data,
                 const char *s)
 {
 
@@ -2825,7 +2844,7 @@ checkrtspprefix(struct SessionHandle *data,
 #endif /* CURL_DISABLE_RTSP */
 
 static bool
-checkprotoprefix(struct SessionHandle *data, struct connectdata *conn,
+checkprotoprefix(struct Curl_easy *data, struct connectdata *conn,
                  const char *s)
 {
 #ifndef CURL_DISABLE_RTSP
@@ -2843,7 +2862,7 @@ checkprotoprefix(struct SessionHandle *data, struct connectdata *conn,
  * header. We make sure that the full string fit in the allocated header
  * buffer, or else we enlarge it.
  */
-static CURLcode header_append(struct SessionHandle *data,
+static CURLcode header_append(struct Curl_easy *data,
                               struct SingleRequest *k,
                               size_t length)
 {
@@ -2881,7 +2900,7 @@ static CURLcode header_append(struct SessionHandle *data,
   return CURLE_OK;
 }
 
-static void print_http_error(struct SessionHandle *data)
+static void print_http_error(struct Curl_easy *data)
 {
   struct SingleRequest *k = &data->req;
   char *beg = k->p;
@@ -2921,7 +2940,7 @@ static void print_http_error(struct SessionHandle *data)
 /*
  * Read any HTTP header lines from the server and pass them to the client app.
  */
-CURLcode Curl_http_readwrite_headers(struct SessionHandle *data,
+CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
                                        struct connectdata *conn,
                                        ssize_t *nread,
                                        bool *stop_reading)
@@ -3035,7 +3054,7 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data,
         switch(k->httpcode) {
         case 100:
           /* if we did wait for this do enable write now! */
-          if(k->exp100) {
+          if(k->exp100 > EXP100_SEND_DATA) {
             k->exp100 = EXP100_SEND_DATA;
             k->keepon |= KEEP_SEND;
           }
@@ -3119,52 +3138,50 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data,
       data->req.deductheadercount =
         (100 <= k->httpcode && 199 >= k->httpcode)?data->req.headerbytecount:0;
 
-      if(!*stop_reading) {
-        /* Curl_http_auth_act() checks what authentication methods
-         * that are available and decides which one (if any) to
-         * use. It will set 'newurl' if an auth method was picked. */
-        result = Curl_http_auth_act(conn);
+      /* Curl_http_auth_act() checks what authentication methods
+       * that are available and decides which one (if any) to
+       * use. It will set 'newurl' if an auth method was picked. */
+      result = Curl_http_auth_act(conn);
 
-        if(result)
-          return result;
+      if(result)
+        return result;
 
-        if(k->httpcode >= 300) {
-          if((!conn->bits.authneg) && !conn->bits.close &&
-             !conn->bits.rewindaftersend) {
-            /*
-             * General treatment of errors when about to send data. Including :
-             * "417 Expectation Failed", while waiting for 100-continue.
-             *
-             * The check for close above is done simply because of something
-             * else has already deemed the connection to get closed then
-             * something else should've considered the big picture and we
-             * avoid this check.
-             *
-             * rewindaftersend indicates that something has told libcurl to
-             * continue sending even if it gets discarded
+      if(k->httpcode >= 300) {
+        if((!conn->bits.authneg) && !conn->bits.close &&
+           !conn->bits.rewindaftersend) {
+          /*
+           * General treatment of errors when about to send data. Including :
+           * "417 Expectation Failed", while waiting for 100-continue.
+           *
+           * The check for close above is done simply because of something
+           * else has already deemed the connection to get closed then
+           * something else should've considered the big picture and we
+           * avoid this check.
+           *
+           * rewindaftersend indicates that something has told libcurl to
+           * continue sending even if it gets discarded
+           */
+
+          switch(data->set.httpreq) {
+          case HTTPREQ_PUT:
+          case HTTPREQ_POST:
+          case HTTPREQ_POST_FORM:
+            /* We got an error response. If this happened before the whole
+             * request body has been sent we stop sending and mark the
+             * connection for closure after we've read the entire response.
              */
-
-            switch(data->set.httpreq) {
-            case HTTPREQ_PUT:
-            case HTTPREQ_POST:
-            case HTTPREQ_POST_FORM:
-              /* We got an error response. If this happened before the whole
-               * request body has been sent we stop sending and mark the
-               * connection for closure after we've read the entire response.
-               */
-              if(!k->upload_done) {
-                infof(data, "HTTP error before end of send, stop sending\n");
-                connclose(conn, "Stop sending data before everything sent");
-                k->upload_done = TRUE;
-                k->keepon &= ~KEEP_SEND; /* don't send */
-                if(data->state.expect100header)
-                  k->exp100 = EXP100_FAILED;
-              }
-              break;
-
-            default: /* default label present to avoid compiler warnings */
-              break;
+            if(!k->upload_done) {
+              infof(data, "HTTP error before end of send, stop sending\n");
+              connclose(conn, "Stop sending data before everything sent");
+              k->upload_done = TRUE;
+              k->keepon &= ~KEEP_SEND; /* don't send */
+              if(data->state.expect100header)
+                k->exp100 = EXP100_FAILED;
             }
+            break;
+
+          default: /* default label present to avoid compiler warnings */
+            break;
           }
         }
 
@@ -3185,6 +3202,16 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data,
          */
         if(data->set.opt_no_body)
           *stop_reading = TRUE;
+#ifndef CURL_DISABLE_RTSP
+        else if((conn->handler->protocol & CURLPROTO_RTSP) &&
+                (data->set.rtspreq == RTSPREQ_DESCRIBE) &&
+                (k->size <= -1))
+          /* Respect section 4.4 of rfc2326: If the Content-Length header is
+             absent, a length 0 must be assumed.  It will prevent libcurl from
+             hanging on DESCRIBE request that got refused for whatever
+             reason */
+          *stop_reading = TRUE;
+#endif
         else {
           /* If we know the expected size of this document, we set the
              maximum download size to the size of the expected
@@ -3279,6 +3306,13 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data,
                     &httpversion_major,
                     &conn->httpversion,
                     &k->httpcode);
+
+        if(nc == 1 && httpversion_major == 2 &&
+           1 == sscanf(HEADER1, " HTTP/2 %d", &k->httpcode)) {
+          conn->httpversion = 0;
+          nc = 3;
+        }
+
         if(nc==3) {
           conn->httpversion += 10 * httpversion_major;
 
@@ -3576,8 +3610,7 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data,
 
     }
     else if(checkprefix("Content-Encoding:", k->p) &&
-            (data->set.str[STRING_ENCODING] ||
-             conn->httpversion == 20)) {
+            data->set.str[STRING_ENCODING]) {
       /*
        * Process Content-Encoding. Look for the values: identity,
        * gzip, deflate, compress, x-gzip and x-compress. x-gzip and
@@ -3726,7 +3759,7 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data,
     k->hbufp = data->state.headerbuff;
     k->hbuflen = 0;
   }
-  while(!*stop_reading && *k->str); /* header line within buffer */
+  while(*k->str); /* header line within buffer */
 
   /* We might have reached the end of the header part here, but
      there might be a non-header part left in the end of the read
diff --git a/lib/http.h b/lib/http.h
index fe4f39b..6529005 100644
--- a/lib/http.h
+++ b/lib/http.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -69,7 +69,7 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
                               size_t included_body_bytes,
                               int socketindex);
 
-CURLcode Curl_add_timecondition(struct SessionHandle *data,
+CURLcode Curl_add_timecondition(struct Curl_easy *data,
                                 Curl_send_buffer *buf);
 CURLcode Curl_add_custom_headers(struct connectdata *conn,
                                  bool is_connect,
@@ -87,7 +87,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn, char *datap,
                               ssize_t length, ssize_t *wrote);
 
 /* These functions are in http.c */
-void Curl_http_auth_stage(struct SessionHandle *data, int stage);
+void Curl_http_auth_stage(struct Curl_easy *data, int stage);
 CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy,
                               const char *auth);
 CURLcode Curl_http_auth_act(struct connectdata *conn);
@@ -163,6 +163,7 @@ struct HTTP {
   Curl_send_buffer *header_recvbuf;
   size_t nread_header_recvbuf; /* number of bytes in header_recvbuf fed into
                                   upper layer */
+  Curl_send_buffer *trailer_recvbuf;
   int status_code; /* HTTP status code */
   const uint8_t *pausedata; /* pointer to data received in on_data_chunk */
   size_t pauselen; /* the number of bytes left in data */
@@ -213,15 +214,16 @@ struct http_conn {
      them for both cases. */
   int32_t pause_stream_id; /* stream ID which paused
                               nghttp2_session_mem_recv */
+  size_t drain_total; /* sum of all stream's UrlState.drain */
 
-  /* this is a hash of all individual streams (SessionHandle structs) */
+  /* this is a hash of all individual streams (Curl_easy structs) */
   struct h2settings settings;
 #else
   int unused; /* prevent a compiler warning */
 #endif
 };
 
-CURLcode Curl_http_readwrite_headers(struct SessionHandle *data,
+CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
                                      struct connectdata *conn,
                                      ssize_t *nread,
                                      bool *stop_reading);
diff --git a/lib/http2.c b/lib/http2.c
index 0024add..efc082d 100644
--- a/lib/http2.c
+++ b/lib/http2.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -23,7 +23,6 @@
 #include "curl_setup.h"
 
 #ifdef USE_NGHTTP2
-#include "curl_printf.h"
 #include <nghttp2/nghttp2.h>
 #include "urldata.h"
 #include "http2.h"
@@ -34,17 +33,50 @@
 #include "multiif.h"
 #include "conncache.h"
 #include "url.h"
+#include "connect.h"
+#include "strtoofft.h"
 
-/* The last #include files should be: */
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
 #include "curl_memory.h"
 #include "memdebug.h"
 
 #define MIN(x,y) ((x)<(y)?(x):(y))
 
-#if (NGHTTP2_VERSION_NUM < 0x000600)
+#if (NGHTTP2_VERSION_NUM < 0x010000)
 #error too old nghttp2 version, upgrade!
 #endif
 
+#if (NGHTTP2_VERSION_NUM > 0x010800)
+#define NGHTTP2_HAS_HTTP2_STRERROR 1
+#endif
+
+#if (NGHTTP2_VERSION_NUM >= 0x010900)
+/* nghttp2_session_callbacks_set_error_callback is present in nghttp2 1.9.0 or
+   later */
+#define NGHTTP2_HAS_ERROR_CALLBACK 1
+#else
+#define nghttp2_session_callbacks_set_error_callback(x,y)
+#endif
+
+/*
+ * Curl_http2_init_state() is called when the easy handle is created and
+ * allows for HTTP/2 specific init of state.
+ */
+void Curl_http2_init_state(struct UrlState *state)
+{
+  state->stream_weight = NGHTTP2_DEFAULT_WEIGHT;
+}
+
+/*
+ * Curl_http2_init_userset() is called when the easy handle is created and
+ * allows for HTTP/2 specific user-set fields.
+ */
+void Curl_http2_init_userset(struct UserDefined *set)
+{
+  set->stream_weight = NGHTTP2_DEFAULT_WEIGHT;
+}
+
 static int http2_perform_getsock(const struct connectdata *conn,
                                  curl_socket_t *sock, /* points to
                                                          numsocks
@@ -92,6 +124,8 @@ static CURLcode http2_disconnect(struct connectdata *conn,
   if(http) {
     Curl_add_buffer_free(http->header_recvbuf);
     http->header_recvbuf = NULL; /* clear the pointer */
+    Curl_add_buffer_free(http->trailer_recvbuf);
+    http->trailer_recvbuf = NULL; /* clear the pointer */
     for(; http->push_headers_used > 0; --http->push_headers_used) {
       free(http->push_headers[http->push_headers_used - 1]);
     }
@@ -105,7 +139,7 @@ static CURLcode http2_disconnect(struct connectdata *conn,
 }
 
 /* called from Curl_http_setup_conn */
-void Curl_http2_setup_req(struct SessionHandle *data)
+void Curl_http2_setup_req(struct Curl_easy *data)
 {
   struct HTTP *http = data->req.protop;
 
@@ -134,7 +168,7 @@ void Curl_http2_setup_conn(struct connectdata *conn)
  * HTTP to HTTP2.
  */
 const struct Curl_handler Curl_handler_http2 = {
-  "HTTP2",                              /* scheme */
+  "HTTP",                               /* scheme */
   ZERO_NULL,                            /* setup_connection */
   Curl_http,                            /* do_it */
   Curl_http_done,                       /* done */
@@ -154,7 +188,7 @@ const struct Curl_handler Curl_handler_http2 = {
 };
 
 const struct Curl_handler Curl_handler_http2_ssl = {
-  "HTTP2",                              /* scheme */
+  "HTTPS",                              /* scheme */
   ZERO_NULL,                            /* setup_connection */
   Curl_http,                            /* do_it */
   Curl_http_done,                       /* done */
@@ -183,6 +217,34 @@ int Curl_http2_ver(char *p, size_t len)
   return snprintf(p, len, " nghttp2/%s", h2->version_str);
 }
 
+/* HTTP/2 error code to name based on the Error Code Registry.
+https://tools.ietf.org/html/rfc7540#page-77
+nghttp2_error_code enums are identical.
+*/
+const char *Curl_http2_strerror(uint32_t err) {
+#ifndef NGHTTP2_HAS_HTTP2_STRERROR
+  const char *str[] = {
+    "NO_ERROR",             /* 0x0 */
+    "PROTOCOL_ERROR",       /* 0x1 */
+    "INTERNAL_ERROR",       /* 0x2 */
+    "FLOW_CONTROL_ERROR",   /* 0x3 */
+    "SETTINGS_TIMEOUT",     /* 0x4 */
+    "STREAM_CLOSED",        /* 0x5 */
+    "FRAME_SIZE_ERROR",     /* 0x6 */
+    "REFUSED_STREAM",       /* 0x7 */
+    "CANCEL",               /* 0x8 */
+    "COMPRESSION_ERROR",    /* 0x9 */
+    "CONNECT_ERROR",        /* 0xA */
+    "ENHANCE_YOUR_CALM",    /* 0xB */
+    "INADEQUATE_SECURITY",  /* 0xC */
+    "HTTP_1_1_REQUIRED"     /* 0xD */
+  };
+  return (err < sizeof str / sizeof str[0]) ? str[err] : "unknown";
+#else
+  return nghttp2_http2_strerror(err);
+#endif
+}
+
 /*
  * The implementation of nghttp2_send_callback type. Here we write |data| with
  * size |length| to the network and return the number of bytes actually
@@ -222,7 +284,7 @@ static ssize_t send_callback(nghttp2_session *h2,
 /* We pass a pointer to this struct in the push callback, but the contents of
    the struct are hidden from the user. */
 struct curl_pushheaders {
-  struct SessionHandle *data;
+  struct Curl_easy *data;
   const nghttp2_push_promise *frame;
 };
 
@@ -263,7 +325,7 @@ char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header)
     size_t i;
     for(i=0; i<stream->push_headers_used; i++) {
       if(!strncmp(header, stream->push_headers[i], len)) {
-        /* sub-match, make sure that it us followed by a colon */
+        /* sub-match, make sure that it is followed by a colon */
         if(stream->push_headers[i][len] != ':')
           continue;
         return &stream->push_headers[i][len+1];
@@ -273,9 +335,9 @@ char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header)
   return NULL;
 }
 
-static CURL *duphandle(struct SessionHandle *data)
+static struct Curl_easy *duphandle(struct Curl_easy *data)
 {
-  struct SessionHandle *second = curl_easy_duphandle(data);
+  struct Curl_easy *second = curl_easy_duphandle(data);
   if(second) {
     /* setup the request struct */
     struct HTTP *http = calloc(1, sizeof(struct HTTP));
@@ -291,15 +353,17 @@ static CURL *duphandle(struct SessionHandle *data)
         (void)Curl_close(second);
         second = NULL;
       }
-      else
+      else {
         Curl_http2_setup_req(second);
+        second->state.stream_weight = data->state.stream_weight;
+      }
     }
   }
   return second;
 }
 
 
-static int push_promise(struct SessionHandle *data,
+static int push_promise(struct Curl_easy *data,
                         struct connectdata *conn,
                         const nghttp2_push_promise *frame)
 {
@@ -308,12 +372,13 @@ static int push_promise(struct SessionHandle *data,
                frame->promised_stream_id));
   if(data->multi->push_cb) {
     struct HTTP *stream;
+    struct HTTP *newstream;
     struct curl_pushheaders heads;
     CURLMcode rc;
     struct http_conn *httpc;
     size_t i;
     /* clone the parent */
-    CURL *newhandle = duphandle(data);
+    struct Curl_easy *newhandle = duphandle(data);
     if(!newhandle) {
       infof(data, "failed to duplicate handle\n");
       rv = 1; /* FAIL HARD */
@@ -348,6 +413,11 @@ static int push_promise(struct SessionHandle *data,
       goto fail;
     }
 
+    newstream = newhandle->req.protop;
+    newstream->stream_id = frame->promised_stream_id;
+    newhandle->req.maxdownload = -1;
+    newhandle->req.size = -1;
+
     /* approved, add to the multi handle and immediately switch to PERFORM
        state with the given connection !*/
     rc = Curl_multi_add_perform(data->multi, newhandle, conn);
@@ -373,29 +443,46 @@ static int push_promise(struct SessionHandle *data,
 static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
                          void *userp)
 {
-  struct connectdata *conn = NULL;
-  struct http_conn *httpc = NULL;
-  struct SessionHandle *data_s = NULL;
+  struct connectdata *conn = (struct connectdata *)userp;
+  struct http_conn *httpc = &conn->proto.httpc;
+  struct Curl_easy *data_s = NULL;
   struct HTTP *stream = NULL;
   static int lastStream = -1;
   int rv;
   size_t left, ncopy;
   int32_t stream_id = frame->hd.stream_id;
 
-  (void)userp;
-
   if(!stream_id) {
     /* stream ID zero is for connection-oriented stuff */
+    if(frame->hd.type == NGHTTP2_SETTINGS) {
+      uint32_t max_conn = httpc->settings.max_concurrent_streams;
+      DEBUGF(infof(conn->data, "Got SETTINGS\n"));
+      httpc->settings.max_concurrent_streams =
+        nghttp2_session_get_remote_settings(
+          session, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS);
+      httpc->settings.enable_push =
+        nghttp2_session_get_remote_settings(
+          session, NGHTTP2_SETTINGS_ENABLE_PUSH);
+      DEBUGF(infof(conn->data, "MAX_CONCURRENT_STREAMS == %d\n",
+                   httpc->settings.max_concurrent_streams));
+      DEBUGF(infof(conn->data, "ENABLE_PUSH == %s\n",
+                   httpc->settings.enable_push?"TRUE":"false"));
+      if(max_conn != httpc->settings.max_concurrent_streams) {
+        /* only signal change if the value actually changed */
+        infof(conn->data,
+              "Connection state changed (MAX_CONCURRENT_STREAMS updated)!\n");
+        Curl_multi_connchanged(conn->data->multi);
+      }
+    }
     return 0;
   }
-  data_s = nghttp2_session_get_stream_user_data(session,
-                                                frame->hd.stream_id);
-  if(lastStream != frame->hd.stream_id) {
-    lastStream = frame->hd.stream_id;
+  data_s = nghttp2_session_get_stream_user_data(session, stream_id);
+  if(lastStream != stream_id) {
+    lastStream = stream_id;
   }
   if(!data_s) {
     DEBUGF(infof(conn->data,
-                 "No SessionHandle associated with stream: %x\n",
+                 "No Curl_easy associated with stream: %x\n",
                  stream_id));
     return 0;
   }
@@ -407,10 +494,6 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
   DEBUGF(infof(data_s, "on_frame_recv() header %x stream %x\n",
                frame->hd.type, stream_id));
 
-  conn = data_s->easy_conn;
-  assert(conn);
-  assert(conn->data == data_s);
-  httpc = &conn->proto.httpc;
   switch(frame->hd.type) {
   case NGHTTP2_DATA:
     /* If body started on this stream, then receiving DATA is illegal. */
@@ -424,13 +507,9 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
     }
     break;
   case NGHTTP2_HEADERS:
-    if(frame->headers.cat == NGHTTP2_HCAT_REQUEST)
-      break;
-
     if(stream->bodystarted) {
       /* Only valid HEADERS after body started is trailer HEADERS.  We
-         ignores trailer HEADERS for now.  nghttp2 guarantees that it
-         has END_STREAM flag set. */
+         buffer them in on_header callback. */
       break;
     }
 
@@ -461,7 +540,15 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
     stream->memlen += ncopy;
 
     data_s->state.drain++;
-    Curl_expire(data_s, 1);
+    httpc->drain_total++;
+    {
+      /* get the pointer from userp again since it was re-assigned above */
+      struct connectdata *conn_s = (struct connectdata *)userp;
+
+      /* if we receive data for another handle, wake that up */
+      if(conn_s->data != data_s)
+        Curl_expire(data_s, 1);
+    }
     break;
   case NGHTTP2_PUSH_PROMISE:
     rv = push_promise(data_s, conn, &frame->push_promise);
@@ -474,28 +561,6 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
       }
     }
     break;
-  case NGHTTP2_SETTINGS:
-  {
-    uint32_t max_conn = httpc->settings.max_concurrent_streams;
-    DEBUGF(infof(conn->data, "Got SETTINGS for stream %u!\n", stream_id));
-    httpc->settings.max_concurrent_streams =
-      nghttp2_session_get_remote_settings(
-        session, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS);
-    httpc->settings.enable_push =
-      nghttp2_session_get_remote_settings(
-        session, NGHTTP2_SETTINGS_ENABLE_PUSH);
-    DEBUGF(infof(conn->data, "MAX_CONCURRENT_STREAMS == %d\n",
-                 httpc->settings.max_concurrent_streams));
-    DEBUGF(infof(conn->data, "ENABLE_PUSH == %s\n",
-                 httpc->settings.enable_push?"TRUE":"false"));
-    if(max_conn != httpc->settings.max_concurrent_streams) {
-      /* only signal change if the value actually changed */
-      infof(conn->data,
-            "Connection state changed (MAX_CONCURRENT_STREAMS updated)!\n");
-      Curl_multi_connchanged(conn->data->multi);
-    }
-  }
-  break;
   default:
     DEBUGF(infof(conn->data, "Got frame type %x for stream %u!\n",
                  frame->hd.type, stream_id));
@@ -508,7 +573,7 @@ static int on_invalid_frame_recv(nghttp2_session *session,
                                  const nghttp2_frame *frame,
                                  int lib_error_code, void *userp)
 {
-  struct SessionHandle *data_s = NULL;
+  struct Curl_easy *data_s = NULL;
   (void)userp;
 
   data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
@@ -525,12 +590,12 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
                               const uint8_t *data, size_t len, void *userp)
 {
   struct HTTP *stream;
-  struct SessionHandle *data_s;
+  struct Curl_easy *data_s;
   size_t nread;
+  struct connectdata *conn = (struct connectdata *)userp;
   (void)session;
   (void)flags;
   (void)data;
-  (void)userp;
 
   DEBUGASSERT(stream_id); /* should never be a zero stream ID here */
 
@@ -552,8 +617,12 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
   stream->memlen += nread;
 
   data_s->state.drain++;
-  Curl_expire(data_s, 1); /* TODO: fix so that this can be set to 0 for
-                             immediately? */
+  conn->proto.httpc.drain_total++;
+
+  /* if we receive data for another handle, wake that up */
+  if(conn->data != data_s)
+    Curl_expire(data_s, 1); /* TODO: fix so that this can be set to 0 for
+                               immediately? */
 
   DEBUGF(infof(data_s, "%zu data received for stream %u "
                "(%zu left in buffer %p, total %zu)\n",
@@ -568,8 +637,18 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
                  ", stream %u\n",
                  len - nread, stream_id));
     data_s->easy_conn->proto.httpc.pause_stream_id = stream_id;
+
     return NGHTTP2_ERR_PAUSE;
   }
+
+  /* pause execution of nghttp2 if we received data for another handle
+     in order to process them first. */
+  if(conn->data != data_s) {
+    data_s->easy_conn->proto.httpc.pause_stream_id = stream_id;
+
+    return NGHTTP2_ERR_PAUSE;
+  }
+
   return 0;
 }
 
@@ -577,7 +656,7 @@ static int before_frame_send(nghttp2_session *session,
                              const nghttp2_frame *frame,
                              void *userp)
 {
-  struct SessionHandle *data_s;
+  struct Curl_easy *data_s;
   (void)userp;
 
   data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
@@ -591,7 +670,7 @@ static int on_frame_send(nghttp2_session *session,
                          const nghttp2_frame *frame,
                          void *userp)
 {
-  struct SessionHandle *data_s;
+  struct Curl_easy *data_s;
   (void)userp;
 
   data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
@@ -605,7 +684,7 @@ static int on_frame_not_send(nghttp2_session *session,
                              const nghttp2_frame *frame,
                              int lib_error_code, void *userp)
 {
-  struct SessionHandle *data_s;
+  struct Curl_easy *data_s;
   (void)userp;
 
   data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
@@ -619,11 +698,11 @@ static int on_frame_not_send(nghttp2_session *session,
 static int on_stream_close(nghttp2_session *session, int32_t stream_id,
                            uint32_t error_code, void *userp)
 {
-  struct SessionHandle *data_s;
+  struct Curl_easy *data_s;
   struct HTTP *stream;
+  struct connectdata *conn = (struct connectdata *)userp;
   (void)session;
   (void)stream_id;
-  (void)userp;
 
   if(stream_id) {
     /* get the stream from the hash based on Stream ID, stream ID zero is for
@@ -634,14 +713,16 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id,
          decided to reject stream (e.g., PUSH_PROMISE). */
       return 0;
     }
-    DEBUGF(infof(data_s, "on_stream_close(), error_code = %d, stream %u\n",
-                 error_code, stream_id));
+    DEBUGF(infof(data_s, "on_stream_close(), %s (err %d), stream %u\n",
+                 Curl_http2_strerror(error_code), error_code, stream_id));
     stream = data_s->req.protop;
     if(!stream)
       return NGHTTP2_ERR_CALLBACK_FAILURE;
 
     stream->error_code = error_code;
     stream->closed = TRUE;
+    data_s->state.drain++;
+    conn->proto.httpc.drain_total++;
 
     /* remove the entry from the hash as the stream is now gone */
     nghttp2_session_set_stream_user_data(session, stream_id, 0);
@@ -653,13 +734,36 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id,
 static int on_begin_headers(nghttp2_session *session,
                             const nghttp2_frame *frame, void *userp)
 {
-  struct SessionHandle *data_s = NULL;
+  struct HTTP *stream;
+  struct Curl_easy *data_s = NULL;
   (void)userp;
 
   data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
-  if(data_s) {
-    DEBUGF(infof(data_s, "on_begin_headers() was called\n"));
+  if(!data_s) {
+    return 0;
+  }
+
+  DEBUGF(infof(data_s, "on_begin_headers() was called\n"));
+
+  if(frame->hd.type != NGHTTP2_HEADERS) {
+    return 0;
+  }
+
+  stream = data_s->req.protop;
+  if(!stream || !stream->bodystarted) {
+    return 0;
   }
+
+  /* This is trailer HEADERS started.  Allocate buffer for them. */
+  DEBUGF(infof(data_s, "trailer field started\n"));
+
+  assert(stream->trailer_recvbuf == NULL);
+
+  stream->trailer_recvbuf = Curl_add_buffer_init();
+  if(!stream->trailer_recvbuf) {
+    return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
+  }
+
   return 0;
 }
 
@@ -698,11 +802,10 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
                      void *userp)
 {
   struct HTTP *stream;
-  struct SessionHandle *data_s;
+  struct Curl_easy *data_s;
   int32_t stream_id = frame->hd.stream_id;
-
+  struct connectdata *conn = (struct connectdata *)userp;
   (void)flags;
-  (void)userp;
 
   DEBUGASSERT(stream_id); /* should never be a zero stream ID here */
 
@@ -719,11 +822,6 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
     return NGHTTP2_ERR_CALLBACK_FAILURE;
   }
 
-  if(stream->bodystarted)
-    /* Ignore trailer or HEADERS not mapped to HTTP semantics.  The
-       consequence is handled in on_frame_recv(). */
-    return 0;
-
   /* Store received PUSH_PROMISE headers to be used when the subsequent
      PUSH_PROMISE callback comes */
   if(frame->hd.type == NGHTTP2_PUSH_PROMISE) {
@@ -754,6 +852,23 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
     return 0;
   }
 
+  if(stream->bodystarted) {
+    /* This is trailer fields. */
+    /* 3 is for ":" and "\r\n". */
+    uint32_t n = (uint32_t)(namelen + valuelen + 3);
+
+    DEBUGF(infof(data_s, "h2 trailer: %.*s: %.*s\n", namelen, name, valuelen,
+                 value));
+
+    Curl_add_buffer(stream->trailer_recvbuf, &n, sizeof(n));
+    Curl_add_buffer(stream->trailer_recvbuf, name, namelen);
+    Curl_add_buffer(stream->trailer_recvbuf, ": ", 2);
+    Curl_add_buffer(stream->trailer_recvbuf, value, valuelen);
+    Curl_add_buffer(stream->trailer_recvbuf, "\r\n\0", 3);
+
+    return 0;
+  }
+
   if(namelen == sizeof(":status") - 1 &&
      memcmp(":status", name, namelen) == 0) {
     /* nghttp2 guarantees :status is received first and only once, and
@@ -762,14 +877,16 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
     stream->status_code = decode_status_code(value, valuelen);
     DEBUGASSERT(stream->status_code != -1);
 
-    Curl_add_buffer(stream->header_recvbuf, "HTTP/2.0 ", 9);
+    Curl_add_buffer(stream->header_recvbuf, "HTTP/2 ", 7);
     Curl_add_buffer(stream->header_recvbuf, value, valuelen);
-    Curl_add_buffer(stream->header_recvbuf, "\r\n", 2);
-    data_s->state.drain++;
-    Curl_expire(data_s, 1);
-
-    DEBUGF(infof(data_s, "h2 status: HTTP/2 %03d\n",
-                 stream->status_code));
+    /* the space character after the status code is mandatory */
+    Curl_add_buffer(stream->header_recvbuf, " \r\n", 3);
+    /* if we receive data for another handle, wake that up */
+    if(conn->data != data_s)
+      Curl_expire(data_s, 1);
+
+    DEBUGF(infof(data_s, "h2 status: HTTP/2 %03d (easy %p)\n",
+                 stream->status_code, data_s));
     return 0;
   }
 
@@ -777,11 +894,12 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
      received, and this is not pseudo-header field . */
   /* convert to a HTTP1-style header */
   Curl_add_buffer(stream->header_recvbuf, name, namelen);
-  Curl_add_buffer(stream->header_recvbuf, ":", 1);
+  Curl_add_buffer(stream->header_recvbuf, ": ", 2);
   Curl_add_buffer(stream->header_recvbuf, value, valuelen);
   Curl_add_buffer(stream->header_recvbuf, "\r\n", 2);
-  data_s->state.drain++;
-  Curl_expire(data_s, 1);
+  /* if we receive data for another handle, wake that up */
+  if(conn->data != data_s)
+    Curl_expire(data_s, 1);
 
   DEBUGF(infof(data_s, "h2 header: %.*s: %.*s\n", namelen, name, valuelen,
                value));
@@ -796,7 +914,7 @@ static ssize_t data_source_read_callback(nghttp2_session *session,
                                          nghttp2_data_source *source,
                                          void *userp)
 {
-  struct SessionHandle *data_s;
+  struct Curl_easy *data_s;
   struct HTTP *stream = NULL;
   size_t nread;
   (void)source;
@@ -848,6 +966,19 @@ static nghttp2_settings_entry settings[] = {
 
 #define H2_BUFSIZE 32768
 
+#ifdef NGHTTP2_HAS_ERROR_CALLBACK
+static int error_callback(nghttp2_session *session,
+                          const char *msg,
+                          size_t len,
+                          void *userp)
+{
+  struct connectdata *conn = (struct connectdata *)userp;
+  (void)session;
+  infof(conn->data, "http2 error: %.*s\n", len, msg);
+  return 0;
+}
+#endif
+
 /*
  * Initialize nghttp2 for a Curl connection
  */
@@ -897,6 +1028,8 @@ CURLcode Curl_http2_init(struct connectdata *conn)
     /* nghttp2_on_header_callback */
     nghttp2_session_callbacks_set_on_header_callback(callbacks, on_header);
 
+    nghttp2_session_callbacks_set_error_callback(callbacks, error_callback);
+
     /* The nghttp2 session is not yet setup, do it */
     rc = nghttp2_session_client_new(&conn->proto.httpc.h2, callbacks, conn);
 
@@ -906,25 +1039,11 @@ CURLcode Curl_http2_init(struct connectdata *conn)
       failf(conn->data, "Couldn't initialize nghttp2!");
       return CURLE_OUT_OF_MEMORY; /* most likely at least */
     }
-
-    if(rc) {
-      failf(conn->data, "Couldn't init stream hash!");
-      return CURLE_OUT_OF_MEMORY; /* most likely at least */
-    }
   }
   return CURLE_OK;
 }
 
 /*
- * Send a request using http2
- */
-CURLcode Curl_http2_send_request(struct connectdata *conn)
-{
-  (void)conn;
-  return CURLE_OK;
-}
-
-/*
  * Append headers to ask for a HTTP1.1 to HTTP2 upgrade.
  */
 CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req,
@@ -969,26 +1088,187 @@ CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req,
   return result;
 }
 
-static ssize_t http2_handle_stream_close(struct http_conn *httpc,
-                                         struct SessionHandle *data,
+/*
+ * Returns nonzero if current HTTP/2 session should be closed.
+ */
+static int should_close_session(struct http_conn *httpc) {
+  return httpc->drain_total == 0 && !nghttp2_session_want_read(httpc->h2) &&
+         !nghttp2_session_want_write(httpc->h2);
+}
+
+static int h2_session_send(struct Curl_easy *data,
+                           nghttp2_session *h2);
+
+/*
+ * h2_process_pending_input() processes pending input left in
+ * httpc->inbuf.  Then, call h2_session_send() to send pending data.
+ * This function returns 0 if it succeeds, or -1 and error code will
+ * be assigned to *err.
+ */
+static int h2_process_pending_input(struct Curl_easy *data,
+                                    struct http_conn *httpc,
+                                    CURLcode *err) {
+  ssize_t nread;
+  char *inbuf;
+  ssize_t rv;
+
+  nread = httpc->inbuflen - httpc->nread_inbuf;
+  inbuf = httpc->inbuf + httpc->nread_inbuf;
+
+  rv = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)inbuf, nread);
+  if(rv < 0) {
+    failf(data,
+          "h2_process_pending_input: nghttp2_session_mem_recv() returned "
+          "%d:%s\n", rv, nghttp2_strerror((int)rv));
+    *err = CURLE_RECV_ERROR;
+    return -1;
+  }
+
+  if(nread == rv) {
+    DEBUGF(infof(data,
+                 "h2_process_pending_input: All data in connection buffer "
+                 "processed\n"));
+    httpc->inbuflen = 0;
+    httpc->nread_inbuf = 0;
+  }
+  else {
+    httpc->nread_inbuf += rv;
+    DEBUGF(infof(data,
+                 "h2_process_pending_input: %zu bytes left in connection "
+                 "buffer\n",
+                 httpc->inbuflen - httpc->nread_inbuf));
+  }
+
+  rv = h2_session_send(data, httpc->h2);
+  if(rv != 0) {
+    *err = CURLE_SEND_ERROR;
+    return -1;
+  }
+
+  if(should_close_session(httpc)) {
+    DEBUGF(infof(data,
+                 "h2_process_pending_input: nothing to do in this session\n"));
+    *err = CURLE_HTTP2;
+    return -1;
+  }
+
+  return 0;
+}
+
+static ssize_t http2_handle_stream_close(struct connectdata *conn,
+                                         struct Curl_easy *data,
                                          struct HTTP *stream, CURLcode *err) {
+  char *trailer_pos, *trailer_end;
+  CURLcode result;
+  struct http_conn *httpc = &conn->proto.httpc;
+
   if(httpc->pause_stream_id == stream->stream_id) {
     httpc->pause_stream_id = 0;
   }
+
+  DEBUGASSERT(httpc->drain_total >= data->state.drain);
+  httpc->drain_total -= data->state.drain;
+  data->state.drain = 0;
+
+  if(httpc->pause_stream_id == 0) {
+    if(h2_process_pending_input(data, httpc, err) != 0) {
+      return -1;
+    }
+  }
+
+  DEBUGASSERT(data->state.drain == 0);
+
   /* Reset to FALSE to prevent infinite loop in readwrite_data
    function. */
   stream->closed = FALSE;
   if(stream->error_code != NGHTTP2_NO_ERROR) {
-    failf(data, "HTTP/2 stream %u was not closed cleanly: error_code = %d",
-          stream->stream_id, stream->error_code);
-    *err = CURLE_HTTP2;
+    failf(data, "HTTP/2 stream %u was not closed cleanly: %s (err %d)",
+          stream->stream_id, Curl_http2_strerror(stream->error_code),
+          stream->error_code);
+    *err = CURLE_HTTP2_STREAM;
+    return -1;
+  }
+
+  if(!stream->bodystarted) {
+    failf(data, "HTTP/2 stream %u was closed cleanly, but before getting "
+          " all response header fields, teated as error",
+          stream->stream_id);
+    *err = CURLE_HTTP2_STREAM;
     return -1;
   }
+
+  if(stream->trailer_recvbuf && stream->trailer_recvbuf->buffer) {
+    trailer_pos = stream->trailer_recvbuf->buffer;
+    trailer_end = trailer_pos + stream->trailer_recvbuf->size_used;
+
+    for(; trailer_pos < trailer_end;) {
+      uint32_t n;
+      memcpy(&n, trailer_pos, sizeof(n));
+      trailer_pos += sizeof(n);
+
+      result = Curl_client_write(conn, CLIENTWRITE_HEADER, trailer_pos, n);
+      if(result) {
+        *err = result;
+        return -1;
+      }
+
+      trailer_pos += n + 1;
+    }
+  }
+
   DEBUGF(infof(data, "http2_recv returns 0, http2_handle_stream_close\n"));
   return 0;
 }
 
 /*
+ * h2_pri_spec() fills in the pri_spec struct, used by nghttp2 to send weight
+ * and dependency to the peer. It also stores the updated values in the state
+ * struct.
+ */
+
+static void h2_pri_spec(struct Curl_easy *data,
+                        nghttp2_priority_spec *pri_spec)
+{
+  struct HTTP *depstream = (data->set.stream_depends_on?
+                            data->set.stream_depends_on->req.protop:NULL);
+  int32_t depstream_id = depstream? depstream->stream_id:0;
+  nghttp2_priority_spec_init(pri_spec, depstream_id, data->set.stream_weight,
+                             data->set.stream_depends_e);
+  data->state.stream_weight = data->set.stream_weight;
+  data->state.stream_depends_e = data->set.stream_depends_e;
+  data->state.stream_depends_on = data->set.stream_depends_on;
+}
+
+/*
+ * h2_session_send() checks if there's been an update in the priority /
+ * dependency settings and if so it submits a PRIORITY frame with the updated
+ * info.
+ */
+static int h2_session_send(struct Curl_easy *data,
+                           nghttp2_session *h2)
+{
+  struct HTTP *stream = data->req.protop;
+  if((data->set.stream_weight != data->state.stream_weight) ||
+     (data->set.stream_depends_e != data->state.stream_depends_e) ||
+     (data->set.stream_depends_on != data->state.stream_depends_on) ) {
+    /* send new weight and/or dependency */
+    nghttp2_priority_spec pri_spec;
+    int rv;
+
+    h2_pri_spec(data, &pri_spec);
+
+    DEBUGF(infof(data, "Queuing PRIORITY on stream %u (easy %p)\n",
+                 stream->stream_id, data));
+    rv = nghttp2_submit_priority(h2, NGHTTP2_FLAG_NONE, stream->stream_id,
+                                 &pri_spec);
+    if(rv)
+      return rv;
+  }
+
+  return nghttp2_session_send(h2);
+}
+
+/*
  * If the read would block (EWOULDBLOCK) we return -1. Otherwise we return
  * a regular CURLcode value.
  */
@@ -999,17 +1279,16 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
   ssize_t rv;
   ssize_t nread;
   struct http_conn *httpc = &conn->proto.httpc;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct HTTP *stream = data->req.protop;
 
   (void)sockindex; /* we always do HTTP2 on sockindex 0 */
 
-  /* If stream is closed, return 0 to signal the http routine to close
-     the connection.  We need to handle stream closure here,
-     otherwise, we may be going to read from underlying connection,
-     and gets EAGAIN, and we will get stuck there. */
-  if(stream->memlen == 0 && stream->closed) {
-    return http2_handle_stream_close(httpc, data, stream, err);
+  if(should_close_session(httpc)) {
+    DEBUGF(infof(data,
+                 "http2_recv: nothing to do in this session\n"));
+    *err = CURLE_HTTP2;
+    return -1;
   }
 
   /* Nullify here because we call nghttp2_session_send() and they
@@ -1018,7 +1297,7 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
   stream->upload_len = 0;
 
   /*
-   * At this point 'stream' is just in the SessionHandle the connection
+   * At this point 'stream' is just in the Curl_easy the connection
    * identifies as its owner at this time.
    */
 
@@ -1032,13 +1311,13 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
            ncopy);
     stream->nread_header_recvbuf += ncopy;
 
-    infof(data, "http2_recv: Got %d bytes from header_recvbuf\n",
-          (int)ncopy);
+    DEBUGF(infof(data, "http2_recv: Got %d bytes from header_recvbuf\n",
+                 (int)ncopy));
     return ncopy;
   }
 
-  infof(data, "http2_recv: %d bytes buffer at %p (stream %u)\n",
-        len, mem, stream->stream_id);
+  DEBUGF(infof(data, "http2_recv: easy %p (stream %u)\n",
+               data, stream->stream_id));
 
   if((data->state.drain) && stream->memlen) {
     DEBUGF(infof(data, "http2_recv: DRAIN %zu bytes stream %u!! (%p => %p)\n",
@@ -1051,8 +1330,18 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
       stream->len = len - stream->memlen;
       stream->mem = mem;
     }
+    if(httpc->pause_stream_id == stream->stream_id && !stream->pausedata) {
+      /* We have paused nghttp2, but we have no pause data (see
+         on_data_chunk_recv). */
+      httpc->pause_stream_id = 0;
+      if(h2_process_pending_input(data, httpc, &result) != 0) {
+        *err = result;
+        return -1;
+      }
+    }
   }
   else if(stream->pausedata) {
+    DEBUGASSERT(httpc->pause_stream_id == stream->stream_id);
     nread = MIN(len, stream->pauselen);
     memcpy(mem, stream->pausedata, nread);
 
@@ -1067,9 +1356,21 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
 
       stream->pausedata = NULL;
       stream->pauselen = 0;
+
+      /* When NGHTTP2_ERR_PAUSE is returned from
+         data_source_read_callback, we might not process DATA frame
+         fully.  Calling nghttp2_session_mem_recv() again will
+         continue to process DATA frame, but if there is no incoming
+         frames, then we have to call it again with 0-length data.
+         Without this, on_stream_close callback will not be called,
+         and stream could be hanged. */
+      if(h2_process_pending_input(data, httpc, &result) != 0) {
+        *err = result;
+        return -1;
+      }
     }
-    infof(data, "http2_recv: returns unpaused %zd bytes on stream %u\n",
-          nread, stream->stream_id);
+    DEBUGF(infof(data, "http2_recv: returns unpaused %zd bytes on stream %u\n",
+                 nread, stream->stream_id));
     return nread;
   }
   else if(httpc->pause_stream_id) {
@@ -1096,15 +1397,15 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
       nread = ((Curl_recv *)httpc->recv_underlying)(
           conn, FIRSTSOCKET, httpc->inbuf, H2_BUFSIZE, &result);
 
-      if(result == CURLE_AGAIN) {
-        *err = result;
-        return -1;
-      }
-
       if(nread == -1) {
-        failf(data, "Failed receiving HTTP2 data");
+        if(result != CURLE_AGAIN)
+          failf(data, "Failed receiving HTTP2 data");
+        else if(stream->closed)
+          /* received when the stream was already closed! */
+          return http2_handle_stream_close(conn, data, stream, err);
+
         *err = result;
-        return 0;
+        return -1;
       }
 
       if(nread == 0) {
@@ -1146,16 +1447,22 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
     }
     /* Always send pending frames in nghttp2 session, because
        nghttp2_session_mem_recv() may queue new frame */
-    rv = nghttp2_session_send(httpc->h2);
+    rv = h2_session_send(data, httpc->h2);
     if(rv != 0) {
       *err = CURLE_SEND_ERROR;
       return 0;
     }
+
+    if(should_close_session(httpc)) {
+      DEBUGF(infof(data, "http2_recv: nothing to do in this session\n"));
+      *err = CURLE_HTTP2;
+      return -1;
+    }
   }
   if(stream->memlen) {
     ssize_t retlen = stream->memlen;
-    infof(data, "http2_recv: returns %zd for stream %u\n",
-          retlen, stream->stream_id);
+    DEBUGF(infof(data, "http2_recv: returns %zd for stream %u\n",
+                 retlen, stream->stream_id));
     stream->memlen = 0;
 
     if(httpc->pause_stream_id == stream->stream_id) {
@@ -1164,15 +1471,18 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
       DEBUGF(infof(data, "Data returned for PAUSED stream %u\n",
                    stream->stream_id));
     }
-    else
+    else if(!stream->closed) {
+      DEBUGASSERT(httpc->drain_total >= data->state.drain);
+      httpc->drain_total -= data->state.drain;
       data->state.drain = 0; /* this stream is hereby drained */
+    }
 
     return retlen;
   }
   /* If stream is closed, return 0 to signal the http routine to close
      the connection */
   if(stream->closed) {
-    return http2_handle_stream_close(httpc, data, stream, err);
+    return http2_handle_stream_close(conn, data, stream, err);
   }
   *err = CURLE_AGAIN;
   DEBUGF(infof(data, "http2_recv returns AGAIN for stream %u\n",
@@ -1184,6 +1494,9 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
    field list. */
 #define AUTHORITY_DST_IDX 3
 
+#define HEADER_OVERFLOW(x) \
+  (x.namelen > (uint16_t)-1 || x.valuelen > (uint16_t)-1 - x.namelen)
+
 /* return number of received (decrypted) bytes */
 static ssize_t http2_send(struct connectdata *conn, int sockindex,
                           const void *mem, size_t len, CURLcode *err)
@@ -1196,15 +1509,16 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
   int rv;
   struct http_conn *httpc = &conn->proto.httpc;
   struct HTTP *stream = conn->data->req.protop;
-  nghttp2_nv *nva;
+  nghttp2_nv *nva = NULL;
   size_t nheader;
   size_t i;
   size_t authority_idx;
   char *hdbuf = (char*)mem;
-  char *end;
+  char *end, *line_end;
   nghttp2_data_provider data_prd;
   int32_t stream_id;
   nghttp2_session *h2 = httpc->h2;
+  nghttp2_priority_spec pri_spec;
 
   (void)sockindex;
 
@@ -1216,7 +1530,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
     stream->upload_mem = mem;
     stream->upload_len = len;
     nghttp2_session_resume_data(h2, stream->stream_id);
-    rv = nghttp2_session_send(h2);
+    rv = h2_session_send(conn->data, h2);
     if(nghttp2_is_fatal(rv)) {
       *err = CURLE_SEND_ERROR;
       return -1;
@@ -1228,6 +1542,12 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
     stream->upload_mem = NULL;
     stream->upload_len = 0;
 
+    if(should_close_session(httpc)) {
+      DEBUGF(infof(conn->data, "http2_send: nothing to do in this session\n"));
+      *err = CURLE_HTTP2;
+      return -1;
+    }
+
     if(stream->upload_left) {
       /* we are sure that we have more data to send here.  Calling the
          following API will make nghttp2_session_want_write() return
@@ -1245,12 +1565,16 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
   /* Here, we assume the curl http code generate *correct* HTTP header
      field block */
   nheader = 0;
-  for(i = 0; i < len; ++i) {
-    if(hdbuf[i] == 0x0a) {
+  for(i = 1; i < len; ++i) {
+    if(hdbuf[i] == '\n' && hdbuf[i - 1] == '\r') {
       ++nheader;
+      ++i;
     }
   }
-  /* We counted additional 2 \n in the first and last line. We need 3
+  if(nheader < 2)
+    goto fail;
+
+  /* We counted additional 2 \r\n in the first and last line. We need 3
      new headers: :method, :path and :scheme. Therefore we need one
      more space. */
   nheader += 1;
@@ -1259,81 +1583,133 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
     *err = CURLE_OUT_OF_MEMORY;
     return -1;
   }
+
   /* Extract :method, :path from request line */
-  end = strchr(hdbuf, ' ');
-  if(!end)
+  line_end = strstr(hdbuf, "\r\n");
+
+  /* Method does not contain spaces */
+  end = memchr(hdbuf, ' ', line_end - hdbuf);
+  if(!end || end == hdbuf)
     goto fail;
   nva[0].name = (unsigned char *)":method";
-  nva[0].namelen = (uint16_t)strlen((char *)nva[0].name);
+  nva[0].namelen = strlen((char *)nva[0].name);
   nva[0].value = (unsigned char *)hdbuf;
-  nva[0].valuelen = (uint16_t)(end - hdbuf);
+  nva[0].valuelen = (size_t)(end - hdbuf);
   nva[0].flags = NGHTTP2_NV_FLAG_NONE;
+  if(HEADER_OVERFLOW(nva[0])) {
+    failf(conn->data, "Failed sending HTTP request: Header overflow");
+    goto fail;
+  }
 
   hdbuf = end + 1;
 
-  end = strchr(hdbuf, ' ');
-  if(!end)
+  /* Path may contain spaces so scan backwards */
+  end = NULL;
+  for(i = (size_t)(line_end - hdbuf); i; --i) {
+    if(hdbuf[i - 1] == ' ') {
+      end = &hdbuf[i - 1];
+      break;
+    }
+  }
+  if(!end || end == hdbuf)
     goto fail;
   nva[1].name = (unsigned char *)":path";
-  nva[1].namelen = (uint16_t)strlen((char *)nva[1].name);
+  nva[1].namelen = strlen((char *)nva[1].name);
   nva[1].value = (unsigned char *)hdbuf;
-  nva[1].valuelen = (uint16_t)(end - hdbuf);
+  nva[1].valuelen = (size_t)(end - hdbuf);
   nva[1].flags = NGHTTP2_NV_FLAG_NONE;
+  if(HEADER_OVERFLOW(nva[1])) {
+    failf(conn->data, "Failed sending HTTP request: Header overflow");
+    goto fail;
+  }
+
+  hdbuf = end + 1;
 
+  end = line_end;
   nva[2].name = (unsigned char *)":scheme";
-  nva[2].namelen = (uint16_t)strlen((char *)nva[2].name);
+  nva[2].namelen = strlen((char *)nva[2].name);
   if(conn->handler->flags & PROTOPT_SSL)
     nva[2].value = (unsigned char *)"https";
   else
     nva[2].value = (unsigned char *)"http";
-  nva[2].valuelen = (uint16_t)strlen((char *)nva[2].value);
+  nva[2].valuelen = strlen((char *)nva[2].value);
   nva[2].flags = NGHTTP2_NV_FLAG_NONE;
-
-  hdbuf = strchr(hdbuf, 0x0a);
-  if(!hdbuf)
+  if(HEADER_OVERFLOW(nva[2])) {
+    failf(conn->data, "Failed sending HTTP request: Header overflow");
     goto fail;
-  ++hdbuf;
+  }
 
   authority_idx = 0;
+  i = 3;
+  while(i < nheader) {
+    size_t hlen;
+    int skip = 0;
+
+    hdbuf = line_end + 2;
+
+    line_end = strstr(hdbuf, "\r\n");
+    if(line_end == hdbuf)
+      goto fail;
+
+    /* header continuation lines are not supported */
+    if(*hdbuf == ' ' || *hdbuf == '\t')
+      goto fail;
 
-  for(i = 3; i < nheader; ++i) {
-    end = strchr(hdbuf, ':');
-    if(!end)
+    for(end = hdbuf; end < line_end && *end != ':'; ++end)
+      ;
+    if(end == hdbuf || end == line_end)
       goto fail;
-    if(end - hdbuf == 4 && Curl_raw_nequal("host", hdbuf, 4)) {
+    hlen = end - hdbuf;
+
+    if(hlen == 10 && Curl_raw_nequal("connection", hdbuf, 10)) {
+      /* skip Connection: headers! */
+      skip = 1;
+      --nheader;
+    }
+    else if(hlen == 4 && Curl_raw_nequal("host", hdbuf, 4)) {
       authority_idx = i;
       nva[i].name = (unsigned char *)":authority";
-      nva[i].namelen = (uint16_t)strlen((char *)nva[i].name);
+      nva[i].namelen = strlen((char *)nva[i].name);
     }
     else {
       nva[i].name = (unsigned char *)hdbuf;
-      nva[i].namelen = (uint16_t)(end - hdbuf);
+      nva[i].namelen = (size_t)(end - hdbuf);
     }
     hdbuf = end + 1;
-    for(; *hdbuf == ' '; ++hdbuf);
-    end = strchr(hdbuf, 0x0d);
-    if(!end)
-      goto fail;
-    nva[i].value = (unsigned char *)hdbuf;
-    nva[i].valuelen = (uint16_t)(end - hdbuf);
-    nva[i].flags = NGHTTP2_NV_FLAG_NONE;
-
-    hdbuf = end + 2;
-    /* Inspect Content-Length header field and retrieve the request
-       entity length so that we can set END_STREAM to the last DATA
-       frame. */
-    if(nva[i].namelen == 14 &&
-       Curl_raw_nequal("content-length", (char*)nva[i].name, 14)) {
-      size_t j;
-      stream->upload_left = 0;
-      for(j = 0; j < nva[i].valuelen; ++j) {
-        stream->upload_left *= 10;
-        stream->upload_left += nva[i].value[j] - '0';
+    while(*hdbuf == ' ' || *hdbuf == '\t')
+      ++hdbuf;
+    end = line_end;
+    if(!skip) {
+      nva[i].value = (unsigned char *)hdbuf;
+      nva[i].valuelen = (size_t)(end - hdbuf);
+      nva[i].flags = NGHTTP2_NV_FLAG_NONE;
+      if(HEADER_OVERFLOW(nva[i])) {
+        failf(conn->data, "Failed sending HTTP request: Header overflow");
+        goto fail;
       }
-      DEBUGF(infof(conn->data,
-                   "request content-length=%"
-                   CURL_FORMAT_CURL_OFF_T
-                   "\n", stream->upload_left));
+      /* Inspect Content-Length header field and retrieve the request
+         entity length so that we can set END_STREAM to the last DATA
+         frame. */
+      if(nva[i].namelen == 14 &&
+         Curl_raw_nequal("content-length", (char*)nva[i].name, 14)) {
+        size_t j;
+        stream->upload_left = 0;
+        if(!nva[i].valuelen)
+          goto fail;
+        for(j = 0; j < nva[i].valuelen; ++j) {
+          if(nva[i].value[j] < '0' || nva[i].value[j] > '9')
+            goto fail;
+          if(stream->upload_left >= CURL_OFF_T_MAX / 10)
+            goto fail;
+          stream->upload_left *= 10;
+          stream->upload_left += nva[i].value[j] - '0';
+        }
+        DEBUGF(infof(conn->data,
+                     "request content-length=%"
+                     CURL_FORMAT_CURL_OFF_T
+                     "\n", stream->upload_left));
+      }
+      ++i;
     }
   }
 
@@ -1346,17 +1722,42 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
     nva[i] = authority;
   }
 
+  /* Warn stream may be rejected if cumulative length of headers is too large.
+     It appears nghttp2 will not send a header frame larger than 64KB. */
+  {
+    size_t acc = 0;
+    const size_t max_acc = 60000;  /* <64KB to account for some overhead */
+
+    for(i = 0; i < nheader; ++i) {
+      if(nva[i].namelen > max_acc - acc)
+        break;
+      acc += nva[i].namelen;
+
+      if(nva[i].valuelen > max_acc - acc)
+        break;
+      acc += nva[i].valuelen;
+    }
+
+    if(i != nheader) {
+      infof(conn->data, "http2_send: Warning: The cumulative length of all "
+                        "headers exceeds %zu bytes and that could cause the "
+                        "stream to be rejected.\n", max_acc);
+    }
+  }
+
+  h2_pri_spec(conn->data, &pri_spec);
+
   switch(conn->data->set.httpreq) {
   case HTTPREQ_POST:
   case HTTPREQ_POST_FORM:
   case HTTPREQ_PUT:
     data_prd.read_callback = data_source_read_callback;
     data_prd.source.ptr = NULL;
-    stream_id = nghttp2_submit_request(h2, NULL, nva, nheader,
+    stream_id = nghttp2_submit_request(h2, &pri_spec, nva, nheader,
                                        &data_prd, conn->data);
     break;
   default:
-    stream_id = nghttp2_submit_request(h2, NULL, nva, nheader,
+    stream_id = nghttp2_submit_request(h2, &pri_spec, nva, nheader,
                                        NULL, conn->data);
   }
 
@@ -1372,6 +1773,8 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
         stream_id, conn->data);
   stream->stream_id = stream_id;
 
+  /* this does not call h2_session_send() since there can not have been any
+   * priority upodate since the nghttp2_submit_request() call above */
   rv = nghttp2_session_send(h2);
 
   if(rv != 0) {
@@ -1379,6 +1782,12 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
     return -1;
   }
 
+  if(should_close_session(httpc)) {
+    DEBUGF(infof(conn->data, "http2_send: nothing to do in this session\n"));
+    *err = CURLE_HTTP2;
+    return -1;
+  }
+
   if(stream->stream_id != -1) {
     /* If whole HEADERS frame was sent off to the underlying socket,
        the nghttp2 library calls data_source_read_callback. But only
@@ -1393,7 +1802,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
 
   return len;
 
-  fail:
+fail:
   free(nva);
   *err = CURLE_SEND_ERROR;
   return -1;
@@ -1432,6 +1841,7 @@ CURLcode Curl_http2_setup(struct connectdata *conn)
   httpc->nread_inbuf = 0;
 
   httpc->pause_stream_id = 0;
+  httpc->drain_total = 0;
 
   conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
   conn->httpversion = 20;
@@ -1440,6 +1850,10 @@ CURLcode Curl_http2_setup(struct connectdata *conn)
   infof(conn->data, "Connection state changed (HTTP/2 confirmed)\n");
   Curl_multi_connchanged(conn->data->multi);
 
+  /* switch on TCP_NODELAY as we need to send off packets without delay for
+     maximum throughput */
+  Curl_tcpnodelay(conn, conn->sock[FIRSTSOCKET]);
+
   return CURLE_OK;
 }
 
@@ -1450,7 +1864,7 @@ CURLcode Curl_http2_switched(struct connectdata *conn,
   struct http_conn *httpc = &conn->proto.httpc;
   int rv;
   ssize_t nproc;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct HTTP *stream = conn->data->req.protop;
 
   result = Curl_http2_setup(conn);
@@ -1527,7 +1941,7 @@ CURLcode Curl_http2_switched(struct connectdata *conn,
   }
 
   /* Try to send some frames since we may read SETTINGS already. */
-  rv = nghttp2_session_send(httpc->h2);
+  rv = h2_session_send(data, httpc->h2);
 
   if(rv != 0) {
     failf(data, "nghttp2_session_send() failed: %s(%d)",
@@ -1535,6 +1949,12 @@ CURLcode Curl_http2_switched(struct connectdata *conn,
     return CURLE_HTTP2;
   }
 
+  if(should_close_session(httpc)) {
+    DEBUGF(infof(data,
+                 "nghttp2_session_send(): nothing to do in this session\n"));
+    return CURLE_HTTP2;
+  }
+
   return CURLE_OK;
 }
 
diff --git a/lib/http2.h b/lib/http2.h
index bb7ad9c..bedbebf 100644
--- a/lib/http2.h
+++ b/lib/http2.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -37,7 +37,11 @@
  */
 int Curl_http2_ver(char *p, size_t len);
 
+const char *Curl_http2_strerror(uint32_t err);
+
 CURLcode Curl_http2_init(struct connectdata *conn);
+void Curl_http2_init_state(struct UrlState *state);
+void Curl_http2_init_userset(struct UserDefined *set);
 CURLcode Curl_http2_send_request(struct connectdata *conn);
 CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req,
                                     struct connectdata *conn);
@@ -46,7 +50,7 @@ CURLcode Curl_http2_switched(struct connectdata *conn,
                              const char *data, size_t nread);
 /* called from Curl_http_setup_conn */
 void Curl_http2_setup_conn(struct connectdata *conn);
-void Curl_http2_setup_req(struct SessionHandle *data);
+void Curl_http2_setup_req(struct Curl_easy *data);
 #else /* USE_NGHTTP2 */
 #define Curl_http2_init(x) CURLE_UNSUPPORTED_PROTOCOL
 #define Curl_http2_send_request(x) CURLE_UNSUPPORTED_PROTOCOL
@@ -55,6 +59,8 @@ void Curl_http2_setup_req(struct SessionHandle *data);
 #define Curl_http2_switched(x,y,z) CURLE_UNSUPPORTED_PROTOCOL
 #define Curl_http2_setup_conn(x)
 #define Curl_http2_setup_req(x)
+#define Curl_http2_init_state(x)
+#define Curl_http2_init_userset(x)
 #endif
 
 #endif /* HEADER_CURL_HTTP2_H */
diff --git a/lib/http_chunks.c b/lib/http_chunks.c
index 7e91b37..ea17109 100644
--- a/lib/http_chunks.c
+++ b/lib/http_chunks.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -80,7 +80,7 @@ static bool Curl_isxdigit(char digit)
 {
   return ( (digit >= 0x30 && digit <= 0x39) /* 0-9 */
         || (digit >= 0x41 && digit <= 0x46) /* A-F */
-        || (digit >= 0x61 && digit <= 0x66) /* a-f */ ) ? TRUE : FALSE;
+        || (digit >= 0x61 && digit <= 0x66) /* a-f */) ? TRUE : FALSE;
 }
 
 void Curl_httpchunk_init(struct connectdata *conn)
@@ -108,7 +108,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
                               ssize_t *wrotep)
 {
   CURLcode result=CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct Curl_chunker *ch = &conn->chunk;
   struct SingleRequest *k = &data->req;
   size_t piece;
diff --git a/lib/http_chunks.h b/lib/http_chunks.h
index 0489eb8..3a8b4dd 100644
--- a/lib/http_chunks.h
+++ b/lib/http_chunks.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/http_digest.c b/lib/http_digest.c
index 929e2c6..97230e7 100644
--- a/lib/http_digest.c
+++ b/lib/http_digest.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -26,11 +26,10 @@
 
 #include "urldata.h"
 #include "rawstr.h"
-#include "curl_sasl.h"
+#include "vauth/vauth.h"
 #include "http_digest.h"
+/* The last 3 #include files should be in this order */
 #include "curl_printf.h"
-
-/* The last #include files should be: */
 #include "curl_memory.h"
 #include "memdebug.h"
 
@@ -46,7 +45,7 @@ CURLcode Curl_input_digest(struct connectdata *conn,
                            const char *header) /* rest of the *-authenticate:
                                                   header */
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   /* Point to the correct struct with this */
   struct digestdata *digest;
@@ -65,7 +64,7 @@ CURLcode Curl_input_digest(struct connectdata *conn,
   while(*header && ISSPACE(*header))
     header++;
 
-  return Curl_sasl_decode_digest_http_message(header, digest);
+  return Curl_auth_decode_digest_http_message(header, digest);
 }
 
 CURLcode Curl_output_digest(struct connectdata *conn,
@@ -74,7 +73,7 @@ CURLcode Curl_output_digest(struct connectdata *conn,
                             const unsigned char *uripath)
 {
   CURLcode result;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   unsigned char *path;
   char *tmp;
   char *response;
@@ -135,7 +134,7 @@ CURLcode Curl_output_digest(struct connectdata *conn,
 
      Apache servers can be set to do the Digest IE-style automatically using
      the BrowserMatch feature:
-     http://httpd.apache.org/docs/2.2/mod/mod_auth_digest.html#msie
+     https://httpd.apache.org/docs/2.2/mod/mod_auth_digest.html#msie
 
      Further details on Digest implementation differences:
      http://www.fngtps.com/2006/09/http-authentication
@@ -152,7 +151,7 @@ CURLcode Curl_output_digest(struct connectdata *conn,
   if(!path)
     return CURLE_OUT_OF_MEMORY;
 
-  result = Curl_sasl_create_digest_http_message(data, userp, passwdp, request,
+  result = Curl_auth_create_digest_http_message(data, userp, passwdp, request,
                                                 path, digest, &response, &len);
   free(path);
   if(result)
@@ -170,10 +169,10 @@ CURLcode Curl_output_digest(struct connectdata *conn,
   return CURLE_OK;
 }
 
-void Curl_digest_cleanup(struct SessionHandle *data)
+void Curl_digest_cleanup(struct Curl_easy *data)
 {
-  Curl_sasl_digest_cleanup(&data->state.digest);
-  Curl_sasl_digest_cleanup(&data->state.proxydigest);
+  Curl_auth_digest_cleanup(&data->state.digest);
+  Curl_auth_digest_cleanup(&data->state.proxydigest);
 }
 
 #endif
diff --git a/lib/http_digest.h b/lib/http_digest.h
index d13d563..fd225c7 100644
--- a/lib/http_digest.h
+++ b/lib/http_digest.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -34,7 +34,7 @@ CURLcode Curl_output_digest(struct connectdata *conn,
                             const unsigned char *uripath);
 
 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
-void Curl_digest_cleanup(struct SessionHandle *data);
+void Curl_digest_cleanup(struct Curl_easy *data);
 #else
 #define Curl_digest_cleanup(x) Curl_nop_stmt
 #endif
diff --git a/lib/http_negotiate.c b/lib/http_negotiate.c
index a1baf29..c39d6f3 100644
--- a/lib/http_negotiate.c
+++ b/lib/http_negotiate.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -22,156 +22,94 @@
 
 #include "curl_setup.h"
 
-#if defined(HAVE_GSSAPI) && !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO)
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO)
 
 #include "urldata.h"
 #include "sendf.h"
-#include "curl_gssapi.h"
 #include "rawstr.h"
-#include "curl_base64.h"
 #include "http_negotiate.h"
-#include "curl_sasl.h"
-#include "url.h"
-#include "curl_printf.h"
+#include "vauth/vauth.h"
 
-/* The last #include files should be: */
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
 #include "curl_memory.h"
 #include "memdebug.h"
 
 CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy,
                               const char *header)
 {
-  struct SessionHandle *data = conn->data;
-  struct negotiatedata *neg_ctx = proxy?&data->state.proxyneg:
-    &data->state.negotiate;
-  OM_uint32 major_status, minor_status, discard_st;
-  gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER;
-  gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
-  gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
+  struct Curl_easy *data = conn->data;
   size_t len;
-  size_t rawlen = 0;
-  CURLcode result;
 
-  if(neg_ctx->context && neg_ctx->status == GSS_S_COMPLETE) {
-    /* We finished successfully our part of authentication, but server
-     * rejected it (since we're again here). Exit with an error since we
-     * can't invent anything better */
-    Curl_cleanup_negotiate(data);
-    return CURLE_LOGIN_DENIED;
-  }
+  /* Point to the username, password, service and host */
+  const char *userp;
+  const char *passwdp;
+  const char *service;
+  const char *host;
 
-  if(!neg_ctx->server_name) {
-    /* Generate our SPN */
-    char *spn = Curl_sasl_build_gssapi_spn(
-      proxy ? data->set.str[STRING_PROXY_SERVICE_NAME] :
-      data->set.str[STRING_SERVICE_NAME],
-      proxy ? conn->proxy.name : conn->host.name);
-    if(!spn)
-      return CURLE_OUT_OF_MEMORY;
-
-    /* Populate the SPN structure */
-    spn_token.value = spn;
-    spn_token.length = strlen(spn);
-
-    /* Import the SPN */
-    major_status = gss_import_name(&minor_status, &spn_token,
-                                   GSS_C_NT_HOSTBASED_SERVICE,
-                                   &neg_ctx->server_name);
-    if(GSS_ERROR(major_status)) {
-      Curl_gss_log_error(data, minor_status, "gss_import_name() failed: ");
-
-      free(spn);
-
-      return CURLE_OUT_OF_MEMORY;
-    }
+  /* Point to the correct struct with this */
+  struct negotiatedata *neg_ctx;
 
-    free(spn);
+  if(proxy) {
+    userp = conn->proxyuser;
+    passwdp = conn->proxypasswd;
+    service = data->set.str[STRING_PROXY_SERVICE_NAME] ?
+              data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP";
+    host = conn->proxy.name;
+    neg_ctx = &data->state.proxyneg;
+  }
+  else {
+    userp = conn->user;
+    passwdp = conn->passwd;
+    service = data->set.str[STRING_SERVICE_NAME] ?
+              data->set.str[STRING_SERVICE_NAME] : "HTTP";
+    host = conn->host.name;
+    neg_ctx = &data->state.negotiate;
   }
 
+  /* Not set means empty */
+  if(!userp)
+    userp = "";
+
+  if(!passwdp)
+    passwdp = "";
+
+  /* Obtain the input token, if any */
   header += strlen("Negotiate");
   while(*header && ISSPACE(*header))
     header++;
 
   len = strlen(header);
-  if(len > 0) {
-    result = Curl_base64_decode(header, (unsigned char **)&input_token.value,
-                                &rawlen);
-    if(result)
-      return result;
-
-    if(!rawlen) {
-      infof(data, "Negotiate handshake failure (empty challenge message)\n");
-
-      return CURLE_BAD_CONTENT_ENCODING;
+  if(!len) {
+    /* Is this the first call in a new negotiation? */
+    if(neg_ctx->context) {
+      /* The server rejected our authentication and hasn't suppled any more
+      negotiation mechanisms */
+      return CURLE_LOGIN_DENIED;
     }
-
-    input_token.length = rawlen;
-
-    DEBUGASSERT(input_token.value != NULL);
-  }
-
-  major_status = Curl_gss_init_sec_context(data,
-                                           &minor_status,
-                                           &neg_ctx->context,
-                                           neg_ctx->server_name,
-                                           &Curl_spnego_mech_oid,
-                                           GSS_C_NO_CHANNEL_BINDINGS,
-                                           &input_token,
-                                           &output_token,
-                                           TRUE,
-                                           NULL);
-  Curl_safefree(input_token.value);
-
-  neg_ctx->status = major_status;
-  if(GSS_ERROR(major_status)) {
-    if(output_token.value)
-      gss_release_buffer(&discard_st, &output_token);
-    Curl_gss_log_error(conn->data, minor_status,
-                       "gss_init_sec_context() failed: ");
-    return CURLE_OUT_OF_MEMORY;
-  }
-
-  if(!output_token.value || !output_token.length) {
-    if(output_token.value)
-      gss_release_buffer(&discard_st, &output_token);
-    return CURLE_OUT_OF_MEMORY;
   }
 
-  neg_ctx->output_token = output_token;
-
-  return CURLE_OK;
+  /* Initilise the security context and decode our challenge */
+  return Curl_auth_decode_spnego_message(data, userp, passwdp, service, host,
+                                         header, neg_ctx);
 }
 
 CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy)
 {
-  struct negotiatedata *neg_ctx = proxy?&conn->data->state.proxyneg:
+  struct negotiatedata *neg_ctx = proxy ? &conn->data->state.proxyneg :
     &conn->data->state.negotiate;
-  char *encoded = NULL;
+  char *base64 = NULL;
   size_t len = 0;
   char *userp;
   CURLcode result;
-  OM_uint32 discard_st;
-
-  result = Curl_base64_encode(conn->data,
-                              neg_ctx->output_token.value,
-                              neg_ctx->output_token.length,
-                              &encoded, &len);
-  if(result) {
-    gss_release_buffer(&discard_st, &neg_ctx->output_token);
-    neg_ctx->output_token.value = NULL;
-    neg_ctx->output_token.length = 0;
-    return result;
-  }
 
-  if(!encoded || !len) {
-    gss_release_buffer(&discard_st, &neg_ctx->output_token);
-    neg_ctx->output_token.value = NULL;
-    neg_ctx->output_token.length = 0;
-    return CURLE_REMOTE_ACCESS_DENIED;
-  }
+  result = Curl_auth_create_spnego_message(conn->data, neg_ctx, &base64, &len);
+  if(result)
+    return result;
 
   userp = aprintf("%sAuthorization: Negotiate %s\r\n", proxy ? "Proxy-" : "",
-                  encoded);
+                  base64);
+
   if(proxy) {
     Curl_safefree(conn->allocptr.proxyuserpwd);
     conn->allocptr.proxyuserpwd = userp;
@@ -181,30 +119,15 @@ CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy)
     conn->allocptr.userpwd = userp;
   }
 
-  free(encoded);
+  free(base64);
 
   return (userp == NULL) ? CURLE_OUT_OF_MEMORY : CURLE_OK;
 }
 
-static void cleanup(struct negotiatedata *neg_ctx)
-{
-  OM_uint32 minor_status;
-  if(neg_ctx->context != GSS_C_NO_CONTEXT)
-    gss_delete_sec_context(&minor_status, &neg_ctx->context, GSS_C_NO_BUFFER);
-
-  if(neg_ctx->output_token.value)
-    gss_release_buffer(&minor_status, &neg_ctx->output_token);
-
-  if(neg_ctx->server_name != GSS_C_NO_NAME)
-    gss_release_name(&minor_status, &neg_ctx->server_name);
-
-  memset(neg_ctx, 0, sizeof(*neg_ctx));
-}
-
-void Curl_cleanup_negotiate(struct SessionHandle *data)
+void Curl_cleanup_negotiate(struct Curl_easy *data)
 {
-  cleanup(&data->state.negotiate);
-  cleanup(&data->state.proxyneg);
+  Curl_auth_spnego_cleanup(&data->state.negotiate);
+  Curl_auth_spnego_cleanup(&data->state.proxyneg);
 }
 
-#endif /* HAVE_GSSAPI && !CURL_DISABLE_HTTP && USE_SPNEGO */
+#endif /* !CURL_DISABLE_HTTP && USE_SPNEGO */
diff --git a/lib/http_negotiate.h b/lib/http_negotiate.h
index a8eb980..c64e548 100644
--- a/lib/http_negotiate.h
+++ b/lib/http_negotiate.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -31,11 +31,7 @@ CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy,
 /* this is for creating Negotiate header output */
 CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy);
 
-void Curl_cleanup_negotiate(struct SessionHandle *data);
-
-#ifdef USE_WINDOWS_SSPI
-#define GSS_ERROR(status) (status & 0x80000000)
-#endif
+void Curl_cleanup_negotiate(struct Curl_easy *data);
 
 #endif /* USE_SPNEGO */
 
diff --git a/lib/http_negotiate_sspi.c b/lib/http_negotiate_sspi.c
deleted file mode 100644
index a50ea96..0000000
--- a/lib/http_negotiate_sspi.c
+++ /dev/null
@@ -1,300 +0,0 @@
-/***************************************************************************
- *                                  _   _ ____  _
- *  Project                     ___| | | |  _ \| |
- *                             / __| | | | |_) | |
- *                            | (__| |_| |  _ <| |___
- *                             \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://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 USE_WINDOWS_SSPI
-
-#if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO)
-
-#include "urldata.h"
-#include "sendf.h"
-#include "rawstr.h"
-#include "warnless.h"
-#include "curl_base64.h"
-#include "curl_sasl.h"
-#include "http_negotiate.h"
-#include "curl_multibyte.h"
-#include "curl_printf.h"
-
-/* The last #include files should be: */
-#include "curl_memory.h"
-#include "memdebug.h"
-
-CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy,
-                              const char *header)
-{
-  struct SessionHandle *data = conn->data;
-  BYTE              *input_token = NULL;
-  SecBufferDesc     out_buff_desc;
-  SecBuffer         out_sec_buff;
-  SecBufferDesc     in_buff_desc;
-  SecBuffer         in_sec_buff;
-  SECURITY_STATUS   status;
-  unsigned long     attrs;
-  TimeStamp         expiry; /* For Windows 9x compatibility of SSPI calls */
-  size_t len = 0, input_token_len = 0;
-  CURLcode result;
-
-  /* Point to the username and password */
-  const char *userp;
-  const char *passwdp;
-
-  /* Point to the correct struct with this */
-  struct negotiatedata *neg_ctx;
-
-  if(proxy) {
-    userp = conn->proxyuser;
-    passwdp = conn->proxypasswd;
-    neg_ctx = &data->state.proxyneg;
-  }
-  else {
-    userp = conn->user;
-    passwdp = conn->passwd;
-    neg_ctx = &data->state.negotiate;
-  }
-
-  /* Not set means empty */
-  if(!userp)
-    userp = "";
-
-  if(!passwdp)
-    passwdp = "";
-
-  if(neg_ctx->context && neg_ctx->status == SEC_E_OK) {
-    /* We finished successfully our part of authentication, but server
-     * rejected it (since we're again here). Exit with an error since we
-     * can't invent anything better */
-    Curl_cleanup_negotiate(data);
-    return CURLE_LOGIN_DENIED;
-  }
-
-  if(!neg_ctx->server_name) {
-    /* Check proxy auth requested but no given proxy name */
-    if(proxy && !conn->proxy.name)
-      return CURLE_BAD_FUNCTION_ARGUMENT;
-
-    /* Generate our SPN */
-    neg_ctx->server_name = Curl_sasl_build_spn(
-      proxy ? data->set.str[STRING_PROXY_SERVICE_NAME] :
-      data->set.str[STRING_SERVICE_NAME],
-      proxy ? conn->proxy.name : conn->host.name);
-    if(!neg_ctx->server_name)
-      return CURLE_OUT_OF_MEMORY;
-  }
-
-  if(!neg_ctx->output_token) {
-    PSecPkgInfo SecurityPackage;
-    status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *)
-                                                TEXT(SP_NAME_NEGOTIATE),
-                                                &SecurityPackage);
-    if(status != SEC_E_OK)
-      return CURLE_NOT_BUILT_IN;
-
-    /* Allocate input and output buffers according to the max token size
-       as indicated by the security package */
-    neg_ctx->token_max = SecurityPackage->cbMaxToken;
-    neg_ctx->output_token = malloc(neg_ctx->token_max);
-    s_pSecFn->FreeContextBuffer(SecurityPackage);
-  }
-
-  /* Obtain the input token, if any */
-  header += strlen("Negotiate");
-  while(*header && ISSPACE(*header))
-    header++;
-
-  len = strlen(header);
-  if(!len) {
-    /* Is this the first call in a new negotiation? */
-    if(neg_ctx->context) {
-      /* The server rejected our authentication and hasn't suppled any more
-         negotiation mechanisms */
-      return CURLE_LOGIN_DENIED;
-    }
-
-    /* We have to acquire credentials and allocate memory for the context */
-    neg_ctx->credentials = malloc(sizeof(CredHandle));
-    neg_ctx->context = malloc(sizeof(CtxtHandle));
-
-    if(!neg_ctx->credentials || !neg_ctx->context)
-      return CURLE_OUT_OF_MEMORY;
-
-    if(userp && *userp) {
-      /* Populate our identity structure */
-      result = Curl_create_sspi_identity(userp, passwdp, &neg_ctx->identity);
-      if(result)
-        return result;
-
-      /* Allow proper cleanup of the identity structure */
-      neg_ctx->p_identity = &neg_ctx->identity;
-    }
-    else
-      /* Use the current Windows user */
-      neg_ctx->p_identity = NULL;
-
-    /* Acquire our credientials handle */
-    neg_ctx->status =
-      s_pSecFn->AcquireCredentialsHandle(NULL,
-                                         (TCHAR *) TEXT(SP_NAME_NEGOTIATE),
-                                         SECPKG_CRED_OUTBOUND, NULL,
-                                         neg_ctx->p_identity, NULL, NULL,
-                                         neg_ctx->credentials, &expiry);
-    if(neg_ctx->status != SEC_E_OK)
-      return CURLE_LOGIN_DENIED;
-  }
-  else {
-    result = Curl_base64_decode(header,
-                                (unsigned char **)&input_token,
-                                &input_token_len);
-    if(result)
-      return result;
-
-    if(!input_token_len) {
-      infof(data,
-            "Negotiate handshake failure (empty challenge message)\n");
-
-      return CURLE_BAD_CONTENT_ENCODING;
-    }
-  }
-
-  /* Setup the "output" security buffer */
-  out_buff_desc.ulVersion = SECBUFFER_VERSION;
-  out_buff_desc.cBuffers  = 1;
-  out_buff_desc.pBuffers  = &out_sec_buff;
-  out_sec_buff.BufferType = SECBUFFER_TOKEN;
-  out_sec_buff.pvBuffer   = neg_ctx->output_token;
-  out_sec_buff.cbBuffer   = curlx_uztoul(neg_ctx->token_max);
-
-  /* Setup the "input" security buffer if present */
-  if(input_token) {
-    in_buff_desc.ulVersion = SECBUFFER_VERSION;
-    in_buff_desc.cBuffers  = 1;
-    in_buff_desc.pBuffers  = &in_sec_buff;
-    in_sec_buff.BufferType = SECBUFFER_TOKEN;
-    in_sec_buff.pvBuffer   = input_token;
-    in_sec_buff.cbBuffer   = curlx_uztoul(input_token_len);
-  }
-
-  /* Generate our message */
-  neg_ctx->status = s_pSecFn->InitializeSecurityContext(
-    neg_ctx->credentials,
-    input_token ? neg_ctx->context : NULL,
-    neg_ctx->server_name,
-    ISC_REQ_CONFIDENTIALITY,
-    0,
-    SECURITY_NATIVE_DREP,
-    input_token ? &in_buff_desc : NULL,
-    0,
-    neg_ctx->context,
-    &out_buff_desc,
-    &attrs,
-    &expiry);
-
-  free(input_token);
-
-  if(GSS_ERROR(neg_ctx->status))
-    return CURLE_OUT_OF_MEMORY;
-
-  if(neg_ctx->status == SEC_I_COMPLETE_NEEDED ||
-     neg_ctx->status == SEC_I_COMPLETE_AND_CONTINUE) {
-    neg_ctx->status = s_pSecFn->CompleteAuthToken(neg_ctx->context,
-                                                  &out_buff_desc);
-    if(GSS_ERROR(neg_ctx->status))
-      return CURLE_RECV_ERROR;
-  }
-
-  neg_ctx->output_token_length = out_sec_buff.cbBuffer;
-
-  return CURLE_OK;
-}
-
-CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy)
-{
-  struct negotiatedata *neg_ctx = proxy?&conn->data->state.proxyneg:
-    &conn->data->state.negotiate;
-  char *encoded = NULL;
-  size_t len = 0;
-  char *userp;
-  CURLcode error;
-
-  error = Curl_base64_encode(conn->data,
-                             (const char*)neg_ctx->output_token,
-                             neg_ctx->output_token_length,
-                             &encoded, &len);
-  if(error)
-    return error;
-
-  if(!len)
-    return CURLE_REMOTE_ACCESS_DENIED;
-
-  userp = aprintf("%sAuthorization: Negotiate %s\r\n", proxy ? "Proxy-" : "",
-                  encoded);
-
-  if(proxy) {
-    Curl_safefree(conn->allocptr.proxyuserpwd);
-    conn->allocptr.proxyuserpwd = userp;
-  }
-  else {
-    Curl_safefree(conn->allocptr.userpwd);
-    conn->allocptr.userpwd = userp;
-  }
-  free(encoded);
-  return (userp == NULL) ? CURLE_OUT_OF_MEMORY : CURLE_OK;
-}
-
-static void cleanup(struct negotiatedata *neg_ctx)
-{
-  /* Free our security context */
-  if(neg_ctx->context) {
-    s_pSecFn->DeleteSecurityContext(neg_ctx->context);
-    free(neg_ctx->context);
-    neg_ctx->context = NULL;
-  }
-
-  /* Free our credentials handle */
-  if(neg_ctx->credentials) {
-    s_pSecFn->FreeCredentialsHandle(neg_ctx->credentials);
-    free(neg_ctx->credentials);
-    neg_ctx->credentials = NULL;
-  }
-
-  /* Free our identity */
-  Curl_sspi_free_identity(neg_ctx->p_identity);
-  neg_ctx->p_identity = NULL;
-
-  /* Free the SPN and output token */
-  Curl_safefree(neg_ctx->server_name);
-  Curl_safefree(neg_ctx->output_token);
-
-  /* Reset any variables */
-  neg_ctx->token_max = 0;
-}
-
-void Curl_cleanup_negotiate(struct SessionHandle *data)
-{
-  cleanup(&data->state.negotiate);
-  cleanup(&data->state.proxyneg);
-}
-
-#endif /* !CURL_DISABLE_HTTP && USE_SPNEGO */
-
-#endif /* USE_WINDOWS_SSPI */
diff --git a/lib/curl_ntlm.c b/lib/http_ntlm.c
similarity index 91%
rename from lib/curl_ntlm.c
rename to lib/http_ntlm.c
index f9ddf50..935df25 100644
--- a/lib/curl_ntlm.c
+++ b/lib/http_ntlm.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -28,7 +28,7 @@
  * NTLM details:
  *
  * http://davenport.sourceforge.net/ntlm.html
- * http://www.innovation.ch/java/ntlm.html
+ * https://www.innovation.ch/java/ntlm.html
  */
 
 #define DEBUG_ME 0
@@ -36,12 +36,10 @@
 #include "urldata.h"
 #include "sendf.h"
 #include "rawstr.h"
-#include "curl_ntlm.h"
-#include "curl_ntlm_msgs.h"
+#include "http_ntlm.h"
 #include "curl_ntlm_wb.h"
-#include "curl_sasl.h"
+#include "vauth/vauth.h"
 #include "url.h"
-#include "curl_printf.h"
 
 #if defined(USE_NSS)
 #include "vtls/nssg.h"
@@ -49,7 +47,8 @@
 #include "curl_sspi.h"
 #endif
 
-/* The last #include files should be: */
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
 #include "curl_memory.h"
 #include "memdebug.h"
 
@@ -77,7 +76,7 @@ CURLcode Curl_input_ntlm(struct connectdata *conn,
       header++;
 
     if(*header) {
-      result = Curl_sasl_decode_ntlm_type2_message(conn->data, header, ntlm);
+      result = Curl_auth_decode_ntlm_type2_message(conn->data, header, ntlm);
       if(result)
         return result;
 
@@ -171,7 +170,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
   case NTLMSTATE_TYPE1:
   default: /* for the weird cases we (re)start here */
     /* Create a type-1 message */
-    result = Curl_sasl_create_ntlm_type1_message(userp, passwdp, ntlm, &base64,
+    result = Curl_auth_create_ntlm_type1_message(userp, passwdp, ntlm, &base64,
                                                  &len);
     if(result)
       return result;
@@ -191,7 +190,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
 
   case NTLMSTATE_TYPE2:
     /* We already received the type-2 message, create a type-3 message */
-    result = Curl_sasl_create_ntlm_type3_message(conn->data, userp, passwdp,
+    result = Curl_auth_create_ntlm_type3_message(conn->data, userp, passwdp,
                                                  ntlm, &base64, &len);
     if(result)
       return result;
@@ -216,7 +215,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
     /* connection is already authenticated,
      * don't send a header in future requests */
     ntlm->state = NTLMSTATE_LAST;
-
+    /* fall-through */
   case NTLMSTATE_LAST:
     Curl_safefree(*allocuserpwd);
     authp->done = TRUE;
@@ -228,8 +227,8 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
 
 void Curl_http_ntlm_cleanup(struct connectdata *conn)
 {
-  Curl_sasl_ntlm_cleanup(&conn->ntlm);
-  Curl_sasl_ntlm_cleanup(&conn->proxyntlm);
+  Curl_auth_ntlm_cleanup(&conn->ntlm);
+  Curl_auth_ntlm_cleanup(&conn->proxyntlm);
 
 #if defined(NTLM_WB_ENABLED)
   Curl_ntlm_wb_cleanup(conn);
diff --git a/lib/curl_ntlm.h b/lib/http_ntlm.h
similarity index 95%
rename from lib/curl_ntlm.h
rename to lib/http_ntlm.h
index 947eac2..d186bbe 100644
--- a/lib/curl_ntlm.h
+++ b/lib/http_ntlm.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/http_proxy.c b/lib/http_proxy.c
index 4373d62..c6b05e3 100644
--- a/lib/http_proxy.c
+++ b/lib/http_proxy.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -35,11 +35,11 @@
 #include "progress.h"
 #include "non-ascii.h"
 #include "connect.h"
-#include "curl_printf.h"
 #include "curlx.h"
 
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
 #include "curl_memory.h"
-/* The last #include file should be: */
 #include "memdebug.h"
 
 CURLcode Curl_proxy_connect(struct connectdata *conn)
@@ -49,6 +49,8 @@ CURLcode Curl_proxy_connect(struct connectdata *conn)
     /* for [protocol] tunneled through HTTP proxy */
     struct HTTP http_proxy;
     void *prot_save;
+    const char *hostname;
+    int remote_port;
     CURLcode result;
 
     /* BLOCKING */
@@ -67,8 +69,16 @@ CURLcode Curl_proxy_connect(struct connectdata *conn)
     memset(&http_proxy, 0, sizeof(http_proxy));
     conn->data->req.protop = &http_proxy;
     connkeep(conn, "HTTP proxy CONNECT");
-    result = Curl_proxyCONNECT(conn, FIRSTSOCKET,
-                               conn->host.name, conn->remote_port, FALSE);
+    if(conn->bits.conn_to_host)
+      hostname = conn->conn_to_host.name;
+    else
+      hostname = conn->host.name;
+    if(conn->bits.conn_to_port)
+      remote_port = conn->conn_to_port;
+    else
+      remote_port = conn->remote_port;
+    result = Curl_proxyCONNECT(conn, FIRSTSOCKET, hostname,
+                               remote_port, FALSE);
     conn->data->req.protop = prot_save;
     if(CURLE_OK != result)
       return result;
@@ -97,7 +107,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
                            bool blocking)
 {
   int subversion=0;
-  struct SessionHandle *data=conn->data;
+  struct Curl_easy *data=conn->data;
   struct SingleRequest *k = &data->req;
   CURLcode result;
   curl_socket_t tunnelsocket = conn->sock[sockindex];
@@ -150,13 +160,17 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
 
       if(!result) {
         char *host=(char *)"";
-        const char *proxyconn="";
         const char *useragent="";
         const char *http = (conn->proxytype == CURLPROXY_HTTP_1_0) ?
           "1.0" : "1.1";
-        char *hostheader= /* host:port with IPv6 support */
-          aprintf("%s%s%s:%hu", conn->bits.ipv6_ip?"[":"",
-                  hostname, conn->bits.ipv6_ip?"]":"",
+        bool ipv6_ip = conn->bits.ipv6_ip;
+        char *hostheader;
+
+        /* the hostname may be different */
+        if(hostname != conn->host.name)
+          ipv6_ip = (strchr(hostname, ':') != NULL);
+        hostheader= /* host:port with IPv6 support */
+          aprintf("%s%s%s:%hu", ipv6_ip?"[":"", hostname, ipv6_ip?"]":"",
                   remote_port);
         if(!hostheader) {
           Curl_add_buffer_free(req_buffer);
@@ -171,9 +185,6 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
             return CURLE_OUT_OF_MEMORY;
           }
         }
-        if(!Curl_checkProxyheaders(conn, "Proxy-Connection:"))
-          proxyconn = "Proxy-Connection: Keep-Alive\r\n";
-
         if(!Curl_checkProxyheaders(conn, "User-Agent:") &&
            data->set.str[STRING_USERAGENT])
           useragent = conn->allocptr.uagent;
@@ -183,15 +194,13 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
                            "CONNECT %s HTTP/%s\r\n"
                            "%s"  /* Host: */
                            "%s"  /* Proxy-Authorization */
-                           "%s"  /* User-Agent */
-                           "%s", /* Proxy-Connection */
+                           "%s", /* User-Agent */
                            hostheader,
                            http,
                            host,
                            conn->allocptr.proxyuserpwd?
                            conn->allocptr.proxyuserpwd:"",
-                           useragent,
-                           proxyconn);
+                           useragent);
 
         if(host && *host)
           free(host);
diff --git a/lib/http_proxy.h b/lib/http_proxy.h
index 9c4f020..fd04330 100644
--- a/lib/http_proxy.h
+++ b/lib/http_proxy.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/idn_win32.c b/lib/idn_win32.c
index b369723..8dc300b 100644
--- a/lib/idn_win32.c
+++ b/lib/idn_win32.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -29,9 +29,10 @@
 #ifdef USE_WIN32_IDN
 
 #include "curl_multibyte.h"
-
 #include "curl_memory.h"
-/* The last #include file should be: */
+#include "warnless.h"
+
+  /* The last #include file should be: */
 #include "memdebug.h"
 
 #ifdef WANT_IDN_PROTOTYPES
@@ -64,45 +65,47 @@ WINBASEAPI int WINAPI IdnToUnicode(DWORD dwFlags,
 
 #define IDN_MAX_LENGTH 255
 
-int curl_win32_idn_to_ascii(const char *in, char **out);
-int curl_win32_ascii_to_idn(const char *in, size_t in_len, char **out_utf8);
+bool curl_win32_idn_to_ascii(const char *in, char **out);
+bool curl_win32_ascii_to_idn(const char *in, char **out);
 
-int curl_win32_idn_to_ascii(const char *in, char **out)
+bool curl_win32_idn_to_ascii(const char *in, char **out)
 {
+  bool success = FALSE;
+
   wchar_t *in_w = Curl_convert_UTF8_to_wchar(in);
   if(in_w) {
     wchar_t punycode[IDN_MAX_LENGTH];
-    if(IdnToAscii(0, in_w, -1, punycode, IDN_MAX_LENGTH) == 0) {
-      wprintf(L"ERROR %d converting to Punycode\n", GetLastError());
-      free(in_w);
-      return 0;
-    }
+    int chars = IdnToAscii(0, in_w, -1, punycode, IDN_MAX_LENGTH);
     free(in_w);
-
-    *out = Curl_convert_wchar_to_UTF8(punycode);
-    if(!*out)
-      return 0;
+    if(chars) {
+      *out = Curl_convert_wchar_to_UTF8(punycode);
+      if(*out)
+        success = TRUE;
+    }
   }
-  return 1;
+
+  return success;
 }
 
-int curl_win32_ascii_to_idn(const char *in, size_t in_len, char **out_utf8)
+bool curl_win32_ascii_to_idn(const char *in, char **out)
 {
-  (void)in_len; /* unused */
-  if(in) {
-    WCHAR unicode[IDN_MAX_LENGTH];
+  bool success = FALSE;
 
-    if(IdnToUnicode(0, (wchar_t *)in, -1, unicode, IDN_MAX_LENGTH) == 0) {
-      wprintf(L"ERROR %d converting to Punycode\n", GetLastError());
-      return 0;
-    }
-    else {
-      *out_utf8 = Curl_convert_wchar_to_UTF8(unicode);
-      if(!*out_utf8)
-        return 0;
+  wchar_t *in_w = Curl_convert_UTF8_to_wchar(in);
+  if(in_w) {
+    size_t in_len = wcslen(in_w) + 1;
+    wchar_t unicode[IDN_MAX_LENGTH];
+    int chars = IdnToUnicode(0, in_w, curlx_uztosi(in_len),
+                             unicode, IDN_MAX_LENGTH);
+    free(in_w);
+    if(chars) {
+      *out = Curl_convert_wchar_to_UTF8(unicode);
+      if(*out)
+        success = TRUE;
     }
   }
-  return 1;
+
+  return success;
 }
 
 #endif /* USE_WIN32_IDN */
diff --git a/lib/if2ip.c b/lib/if2ip.c
index 6e6f969..2f92b2d 100644
--- a/lib/if2ip.c
+++ b/lib/if2ip.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -53,10 +53,9 @@
 #include "inet_ntop.h"
 #include "strequal.h"
 #include "if2ip.h"
+/* The last 3 #include files should be in this order */
 #include "curl_printf.h"
-
 #include "curl_memory.h"
-/* The last #include file should be: */
 #include "memdebug.h"
 
 /* ------------------------------------------------------------------ */
@@ -68,7 +67,7 @@ unsigned int Curl_ipv6_scope(const struct sockaddr *sa)
   (void) sa;
 #else
   if(sa->sa_family == AF_INET6) {
-    const struct sockaddr_in6 * sa6 = (const struct sockaddr_in6 *) sa;
+    const struct sockaddr_in6 * sa6 = (const struct sockaddr_in6 *)(void *) sa;
     const unsigned char * b = sa6->sin6_addr.s6_addr;
     unsigned short w = (unsigned short) ((b[0] << 8) | b[1]);
 
@@ -152,11 +151,12 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
                 continue;
               }
 
-              addr = &((struct sockaddr_in6 *)iface->ifa_addr)->sin6_addr;
+              addr =
+                &((struct sockaddr_in6 *)(void *)iface->ifa_addr)->sin6_addr;
 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
               /* Include the scope of this interface as part of the address */
-              scopeid =
-                ((struct sockaddr_in6 *)iface->ifa_addr)->sin6_scope_id;
+              scopeid = ((struct sockaddr_in6 *)(void *)iface->ifa_addr)
+                            ->sin6_scope_id;
 
               /* If given, scope id should match. */
               if(remote_scope_id && scopeid != remote_scope_id) {
@@ -171,7 +171,8 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
             }
             else
 #endif
-              addr = &((struct sockaddr_in *)iface->ifa_addr)->sin_addr;
+              addr =
+                  &((struct sockaddr_in *)(void *)iface->ifa_addr)->sin_addr;
             res = IF2IP_FOUND;
             ip = (char *) Curl_inet_ntop(af, addr, ipstr, sizeof(ipstr));
             snprintf(buf, buf_size, "%s%s", ip, scope);
diff --git a/lib/if2ip.h b/lib/if2ip.h
index 78bb0bd..f3a7ff0 100644
--- a/lib/if2ip.h
+++ b/lib/if2ip.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/imap.c b/lib/imap.c
index e6d83f2..123ea3b 100644
--- a/lib/imap.c
+++ b/lib/imap.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -80,10 +80,10 @@
 #include "rawstr.h"
 #include "curl_sasl.h"
 #include "warnless.h"
-#include "curl_printf.h"
 
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
 #include "curl_memory.h"
-/* The last #include file should be: */
 #include "memdebug.h"
 
 /* Local API functions */
@@ -98,7 +98,7 @@ static int imap_getsock(struct connectdata *conn, curl_socket_t *socks,
                         int numsocks);
 static CURLcode imap_doing(struct connectdata *conn, bool *dophase_done);
 static CURLcode imap_setup_connection(struct connectdata *conn);
-static char *imap_atom(const char *str);
+static char *imap_atom(const char *str, bool escape_only);
 static CURLcode imap_sendf(struct connectdata *conn, const char *fmt, ...);
 static CURLcode imap_parse_url_options(struct connectdata *conn);
 static CURLcode imap_parse_url_path(struct connectdata *conn);
@@ -227,7 +227,11 @@ static const struct SASLproto saslimap = {
 #ifdef USE_SSL
 static void imap_to_imaps(struct connectdata *conn)
 {
+  /* Change the connection handler */
   conn->handler = &Curl_handler_imaps;
+
+  /* Set the connection's upgraded to TLS flag */
+  conn->tls_upgraded = TRUE;
 }
 #else
 #define imap_to_imaps(x) Curl_nop_stmt
@@ -360,8 +364,8 @@ static bool imap_endofresp(struct connectdata *conn, char *line, size_t len,
      a space and optionally some text as per RFC-3501 for the AUTHENTICATE and
      APPEND commands and as outlined in Section 4. Examples of RFC-4959 but
      some e-mail servers ignore this and only send a single + instead. */
-  if((len == 3 && !memcmp("+", line, 1)) ||
-     (len >= 2 && !memcmp("+ ", line, 2))) {
+  if(imap && !imap->custom && ((len == 3 && !memcmp("+", line, 1)) ||
+     (len >= 2 && !memcmp("+ ", line, 2)))) {
     switch(imapc->state) {
       /* States which are interested in continuation responses */
       case IMAP_AUTHENTICATE:
@@ -540,8 +544,8 @@ static CURLcode imap_perform_login(struct connectdata *conn)
   }
 
   /* Make sure the username and password are in the correct atom format */
-  user = imap_atom(conn->user);
-  passwd = imap_atom(conn->passwd);
+  user = imap_atom(conn->user, false);
+  passwd = imap_atom(conn->passwd, false);
 
   /* Send the LOGIN command */
   result = imap_sendf(conn, "LOGIN %s %s", user ? user : "",
@@ -644,7 +648,7 @@ static CURLcode imap_perform_authentication(struct connectdata *conn)
 static CURLcode imap_perform_list(struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct IMAP *imap = data->req.protop;
   char *mailbox;
 
@@ -653,8 +657,8 @@ static CURLcode imap_perform_list(struct connectdata *conn)
     result = imap_sendf(conn, "%s%s", imap->custom,
                         imap->custom_params ? imap->custom_params : "");
   else {
-    /* Make sure the mailbox is in the correct atom format */
-    mailbox = imap_atom(imap->mailbox ? imap->mailbox : "");
+    /* Make sure the mailbox is in the correct atom format if necessary */
+    mailbox = imap->mailbox ? imap_atom(imap->mailbox, true) : strdup("");
     if(!mailbox)
       return CURLE_OUT_OF_MEMORY;
 
@@ -679,7 +683,7 @@ static CURLcode imap_perform_list(struct connectdata *conn)
 static CURLcode imap_perform_select(struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct IMAP *imap = data->req.protop;
   struct imap_conn *imapc = &conn->proto.imapc;
   char *mailbox;
@@ -695,7 +699,7 @@ static CURLcode imap_perform_select(struct connectdata *conn)
   }
 
   /* Make sure the mailbox is in the correct atom format */
-  mailbox = imap_atom(imap->mailbox);
+  mailbox = imap_atom(imap->mailbox, false);
   if(!mailbox)
     return CURLE_OUT_OF_MEMORY;
 
@@ -769,7 +773,7 @@ static CURLcode imap_perform_append(struct connectdata *conn)
   }
 
   /* Make sure the mailbox is in the correct atom format */
-  mailbox = imap_atom(imap->mailbox);
+  mailbox = imap_atom(imap->mailbox, false);
   if(!mailbox)
     return CURLE_OUT_OF_MEMORY;
 
@@ -836,7 +840,7 @@ static CURLcode imap_state_servergreet_resp(struct connectdata *conn,
                                             imapstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   (void)instate; /* no use for this yet */
 
@@ -856,7 +860,7 @@ static CURLcode imap_state_capability_resp(struct connectdata *conn,
                                            imapstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct imap_conn *imapc = &conn->proto.imapc;
   const char *line = data->state.buffer;
   size_t wordlen;
@@ -906,8 +910,8 @@ static CURLcode imap_state_capability_resp(struct connectdata *conn,
         wordlen -= 5;
 
         /* Test the word for a matching authentication mechanism */
-        if((mechbit = Curl_sasl_decode_mech(line, wordlen, &llen)) &&
-           llen == wordlen)
+        mechbit = Curl_sasl_decode_mech(line, wordlen, &llen);
+        if(mechbit && llen == wordlen)
           imapc->sasl.authmechs |= mechbit;
       }
 
@@ -943,7 +947,7 @@ static CURLcode imap_state_starttls_resp(struct connectdata *conn,
                                          imapstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   (void)instate; /* no use for this yet */
 
@@ -967,7 +971,7 @@ static CURLcode imap_state_auth_resp(struct connectdata *conn,
                                      imapstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct imap_conn *imapc = &conn->proto.imapc;
   saslprogress progress;
 
@@ -1001,7 +1005,7 @@ static CURLcode imap_state_login_resp(struct connectdata *conn,
                                       imapstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   (void)instate; /* no use for this yet */
 
@@ -1016,9 +1020,10 @@ static CURLcode imap_state_login_resp(struct connectdata *conn,
   return result;
 }
 
-/* For LIST responses */
-static CURLcode imap_state_list_resp(struct connectdata *conn, int imapcode,
-                                     imapstate instate)
+/* For LIST and SEARCH responses */
+static CURLcode imap_state_listsearch_resp(struct connectdata *conn,
+                                           int imapcode,
+                                           imapstate instate)
 {
   CURLcode result = CURLE_OK;
   char *line = conn->data->state.buffer;
@@ -1046,7 +1051,7 @@ static CURLcode imap_state_select_resp(struct connectdata *conn, int imapcode,
                                        imapstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct IMAP *imap = conn->data->req.protop;
   struct imap_conn *imapc = &conn->proto.imapc;
   const char *line = data->state.buffer;
@@ -1093,12 +1098,12 @@ static CURLcode imap_state_fetch_resp(struct connectdata *conn, int imapcode,
                                       imapstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct imap_conn *imapc = &conn->proto.imapc;
   struct pingpong *pp = &imapc->pp;
   const char *ptr = data->state.buffer;
   bool parsed = FALSE;
-  curl_off_t size;
+  curl_off_t size = 0;
 
   (void)instate; /* no use for this yet */
 
@@ -1206,7 +1211,7 @@ static CURLcode imap_state_append_resp(struct connectdata *conn, int imapcode,
                                        imapstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   (void)instate; /* No use for this yet */
 
@@ -1245,31 +1250,6 @@ static CURLcode imap_state_append_final_resp(struct connectdata *conn,
   return result;
 }
 
-/* For SEARCH responses */
-static CURLcode imap_state_search_resp(struct connectdata *conn, int imapcode,
-                                       imapstate instate)
-{
-  CURLcode result = CURLE_OK;
-  char *line = conn->data->state.buffer;
-  size_t len = strlen(line);
-
-  (void)instate; /* No use for this yet */
-
-  if(imapcode == '*') {
-    /* Temporarily add the LF character back and send as body to the client */
-    line[len] = '\n';
-    result = Curl_client_write(conn, CLIENTWRITE_BODY, line, len + 1);
-    line[len] = '\0';
-  }
-  else if(imapcode != 'O')
-    result = CURLE_QUOTE_ERROR; /* TODO: Fix error code */
-  else
-    /* End of DO phase */
-    state(conn, IMAP_STOP);
-
-  return result;
-}
-
 static CURLcode imap_statemach_act(struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
@@ -1323,7 +1303,7 @@ static CURLcode imap_statemach_act(struct connectdata *conn)
       break;
 
     case IMAP_LIST:
-      result = imap_state_list_resp(conn, imapcode, imapc->state);
+      result = imap_state_listsearch_resp(conn, imapcode, imapc->state);
       break;
 
     case IMAP_SELECT:
@@ -1347,7 +1327,7 @@ static CURLcode imap_statemach_act(struct connectdata *conn)
       break;
 
     case IMAP_SEARCH:
-      result = imap_state_search_resp(conn, imapcode, imapc->state);
+      result = imap_state_listsearch_resp(conn, imapcode, imapc->state);
       break;
 
     case IMAP_LOGOUT:
@@ -1391,12 +1371,12 @@ static CURLcode imap_block_statemach(struct connectdata *conn)
   return result;
 }
 
-/* Allocate and initialize the struct IMAP for the current SessionHandle if
+/* Allocate and initialize the struct IMAP for the current Curl_easy if
    required */
 static CURLcode imap_init(struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct IMAP *imap;
 
   imap = data->req.protop = calloc(sizeof(struct IMAP), 1);
@@ -1476,16 +1456,12 @@ static CURLcode imap_done(struct connectdata *conn, CURLcode status,
                           bool premature)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct IMAP *imap = data->req.protop;
 
   (void)premature;
 
   if(!imap)
-    /* When the easy handle is removed from the multi interface while libcurl
-       is still trying to resolve the host name, the IMAP struct is not yet
-       initialized. However, the removal action calls Curl_done() which in
-       turn calls this function, so we simply return success. */
     return CURLE_OK;
 
   if(status) {
@@ -1508,8 +1484,7 @@ static CURLcode imap_done(struct connectdata *conn, CURLcode status,
 
        TODO: when the multi interface is used, this _really_ should be using
        the imap_multi_statemach function but we have no general support for
-       non-blocking DONE operations, not in the multi state machine and with
-       Curl_done() invokes on several places in the code!
+       non-blocking DONE operations!
     */
     if(!result)
       result = imap_block_statemach(conn);
@@ -1543,7 +1518,7 @@ static CURLcode imap_perform(struct connectdata *conn, bool *connected,
 {
   /* This is IMAP and no proxy */
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct IMAP *imap = data->req.protop;
   struct imap_conn *imapc = &conn->proto.imapc;
   bool selected = FALSE;
@@ -1708,7 +1683,7 @@ static CURLcode imap_regular_transfer(struct connectdata *conn,
 {
   CURLcode result = CURLE_OK;
   bool connected = FALSE;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   /* Make sure size is unknown at this point */
   data->req.size = -1;
@@ -1731,13 +1706,17 @@ static CURLcode imap_regular_transfer(struct connectdata *conn,
 
 static CURLcode imap_setup_connection(struct connectdata *conn)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   /* Initialise the IMAP layer */
   CURLcode result = imap_init(conn);
   if(result)
     return result;
 
+  /* Clear the TLS upgraded flag */
+  conn->tls_upgraded = FALSE;
+
+  /* Set up the proxy if necessary */
   if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
     /* Unless we have asked to tunnel IMAP operations through the proxy, we
        switch and use HTTP operations only */
@@ -1815,38 +1794,49 @@ static CURLcode imap_sendf(struct connectdata *conn, const char *fmt, ...)
  * The returned string needs to be freed.
  *
  */
-static char *imap_atom(const char *str)
+static char *imap_atom(const char *str, bool escape_only)
 {
+  /* !checksrc! disable PARENBRACE 1 */
+  const char atom_specials[] = "(){ %*]";
   const char *p1;
   char *p2;
   size_t backsp_count = 0;
   size_t quote_count = 0;
-  bool space_exists = FALSE;
+  bool others_exists = FALSE;
   size_t newlen = 0;
   char *newstr = NULL;
 
   if(!str)
     return NULL;
 
-  /* Count any unescaped characters */
+  /* Look for "atom-specials", counting the backslash and quote characters as
+     these will need escapping */
   p1 = str;
   while(*p1) {
     if(*p1 == '\\')
       backsp_count++;
     else if(*p1 == '"')
       quote_count++;
-    else if(*p1 == ' ')
-      space_exists = TRUE;
+    else if(!escape_only) {
+      const char *p3 = atom_specials;
+
+      while(*p3 && !others_exists) {
+        if(*p1 == *p3)
+          others_exists = TRUE;
+
+        p3++;
+      }
+    }
 
     p1++;
   }
 
-  /* Does the input contain any unescaped characters? */
-  if(!backsp_count && !quote_count && !space_exists)
+  /* Does the input contain any "atom-special" characters? */
+  if(!backsp_count && !quote_count && !others_exists)
     return strdup(str);
 
   /* Calculate the new string length */
-  newlen = strlen(str) + backsp_count + quote_count + (space_exists ? 2 : 0);
+  newlen = strlen(str) + backsp_count + quote_count + (others_exists ? 2 : 0);
 
   /* Allocate the new string */
   newstr = (char *) malloc((newlen + 1) * sizeof(char));
@@ -1855,7 +1845,7 @@ static char *imap_atom(const char *str)
 
   /* Surround the string in quotes if necessary */
   p2 = newstr;
-  if(space_exists) {
+  if(others_exists) {
     newstr[0] = '"';
     newstr[newlen - 1] = '"';
     p2++;
@@ -1981,7 +1971,7 @@ static CURLcode imap_parse_url_path(struct connectdata *conn)
 {
   /* The imap struct is already initialised in imap_connect() */
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct IMAP *imap = data->req.protop;
   const char *begin = data->state.path;
   const char *ptr = begin;
@@ -2111,7 +2101,7 @@ static CURLcode imap_parse_url_path(struct connectdata *conn)
 static CURLcode imap_parse_custom_request(struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct IMAP *imap = data->req.protop;
   const char *custom = data->set.str[STRING_CUSTOMREQUEST];
 
diff --git a/lib/imap.h b/lib/imap.h
index 3189daa..5e0e228 100644
--- a/lib/imap.h
+++ b/lib/imap.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -49,9 +49,9 @@ typedef enum {
   IMAP_LAST          /* never used */
 } imapstate;
 
-/* This IMAP struct is used in the SessionHandle. All IMAP data that is
+/* This IMAP struct is used in the Curl_easy. All IMAP data that is
    connection-oriented must be in imap_conn to properly deal with the fact that
-   perhaps the SessionHandle is changed between the times the connection is
+   perhaps the Curl_easy is changed between the times the connection is
    used. */
 struct IMAP {
   curl_pp_transfer transfer;
diff --git a/lib/inet_ntop.c b/lib/inet_ntop.c
index da9a3ab..416005c 100644
--- a/lib/inet_ntop.c
+++ b/lib/inet_ntop.c
@@ -32,9 +32,8 @@
 #include <arpa/inet.h>
 #endif
 
-#include "curl_printf.h"
-
 #include "inet_ntop.h"
+#include "curl_printf.h"
 
 #define IN6ADDRSZ       16
 #define INADDRSZ         4
@@ -57,10 +56,10 @@ static char *inet_ntop4 (const unsigned char *src, char *dst, size_t size)
 
   tmp[0] = '\0';
   (void)snprintf(tmp, sizeof(tmp), "%d.%d.%d.%d",
-          ((int)((unsigned char)src[0])) & 0xff,
-          ((int)((unsigned char)src[1])) & 0xff,
-          ((int)((unsigned char)src[2])) & 0xff,
-          ((int)((unsigned char)src[3])) & 0xff);
+                 ((int)((unsigned char)src[0])) & 0xff,
+                 ((int)((unsigned char)src[1])) & 0xff,
+                 ((int)((unsigned char)src[2])) & 0xff,
+                 ((int)((unsigned char)src[3])) & 0xff);
 
   len = strlen(tmp);
   if(len == 0 || len >= size) {
diff --git a/lib/inet_ntop.h b/lib/inet_ntop.h
index cc4bdbb..9f44612 100644
--- a/lib/inet_ntop.h
+++ b/lib/inet_ntop.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/inet_pton.c b/lib/inet_pton.c
index f50b365..cf8b88a 100644
--- a/lib/inet_pton.c
+++ b/lib/inet_pton.c
@@ -188,8 +188,8 @@ inet_pton6(const char *src, unsigned char *dst)
       }
       if(tp + INT16SZ > endp)
         return (0);
-      *tp++ = (unsigned char) (val >> 8) & 0xff;
-      *tp++ = (unsigned char) val & 0xff;
+      *tp++ = (unsigned char) ((val >> 8) & 0xff);
+      *tp++ = (unsigned char) (val & 0xff);
       saw_xdigit = 0;
       val = 0;
       continue;
@@ -205,8 +205,8 @@ inet_pton6(const char *src, unsigned char *dst)
   if(saw_xdigit) {
     if(tp + INT16SZ > endp)
       return (0);
-    *tp++ = (unsigned char) (val >> 8) & 0xff;
-    *tp++ = (unsigned char) val & 0xff;
+    *tp++ = (unsigned char) ((val >> 8) & 0xff);
+    *tp++ = (unsigned char) (val & 0xff);
   }
   if(colonp != NULL) {
     /*
diff --git a/lib/inet_pton.h b/lib/inet_pton.h
index 43c5491..9188d95 100644
--- a/lib/inet_pton.h
+++ b/lib/inet_pton.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/krb5.c b/lib/krb5.c
index ad7dd67..87ce8ee 100644
--- a/lib/krb5.c
+++ b/lib/krb5.c
@@ -2,7 +2,7 @@
  *
  * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan
  * (Royal Institute of Technology, Stockholm, Sweden).
- * Copyright (c) 2004 - 2015 Daniel Stenberg
+ * Copyright (c) 2004 - 2016 Daniel Stenberg
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -47,15 +47,12 @@
 #include "sendf.h"
 #include "curl_sec.h"
 #include "warnless.h"
-#include "curl_printf.h"
 
-/* The last #include files should be: */
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
 #include "curl_memory.h"
 #include "memdebug.h"
 
-#define LOCAL_ADDR (&conn->local_addr)
-#define REMOTE_ADDR conn->ip_addr->ai_addr
-
 static int
 krb5_init(void *app_data)
 {
@@ -153,28 +150,31 @@ krb5_auth(void *app_data, struct connectdata *conn)
   const char *host = conn->host.name;
   ssize_t nread;
   curl_socklen_t l = sizeof(conn->local_addr);
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   CURLcode result;
-  const char *service = "ftp", *srv_host = "host";
+  const char *service = data->set.str[STRING_SERVICE_NAME] ?
+                        data->set.str[STRING_SERVICE_NAME] :
+                        "ftp";
+  const char *srv_host = "host";
   gss_buffer_desc input_buffer, output_buffer, _gssresp, *gssresp;
   OM_uint32 maj, min;
   gss_name_t gssname;
   gss_ctx_id_t *context = app_data;
   struct gss_channel_bindings_struct chan;
   size_t base64_sz = 0;
+  struct sockaddr_in **remote_addr =
+    (struct sockaddr_in **)&conn->ip_addr->ai_addr;
 
   if(getsockname(conn->sock[FIRSTSOCKET],
-                 (struct sockaddr *)LOCAL_ADDR, &l) < 0)
+                 (struct sockaddr *)&conn->local_addr, &l) < 0)
     perror("getsockname()");
 
   chan.initiator_addrtype = GSS_C_AF_INET;
   chan.initiator_address.length = l - 4;
-  chan.initiator_address.value =
-    &((struct sockaddr_in *)LOCAL_ADDR)->sin_addr.s_addr;
+  chan.initiator_address.value = &conn->local_addr.sin_addr.s_addr;
   chan.acceptor_addrtype = GSS_C_AF_INET;
   chan.acceptor_address.length = l - 4;
-  chan.acceptor_address.value =
-    &((struct sockaddr_in *)REMOTE_ADDR)->sin_addr.s_addr;
+  chan.acceptor_address.value = &(*remote_addr)->sin_addr.s_addr;
   chan.application_data.length = 0;
   chan.application_data.value = NULL;
 
@@ -183,9 +183,9 @@ krb5_auth(void *app_data, struct connectdata *conn)
     /* this really shouldn't be repeated here, but can't help it */
     if(service == srv_host) {
       result = Curl_ftpsendf(conn, "AUTH GSSAPI");
-
       if(result)
         return -2;
+
       if(Curl_GetFTPResponse(&nread, conn, NULL))
         return -1;
 
diff --git a/lib/ldap.c b/lib/ldap.c
index 4d91282..a164627 100644
--- a/lib/ldap.c
+++ b/lib/ldap.c
@@ -5,11 +5,11 @@
  *                | (__| |_| |  _ <| |___
  *                 \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -76,9 +76,8 @@
 #include "curl_base64.h"
 #include "rawstr.h"
 #include "connect.h"
+/* The last 3 #include files should be in this order */
 #include "curl_printf.h"
-
-/* The last #include files should be: */
 #include "curl_memory.h"
 #include "memdebug.h"
 
@@ -193,7 +192,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
   LDAPMessage *ldapmsg = NULL;
   LDAPMessage *entryIterator;
   int num = 0;
-  struct SessionHandle *data=conn->data;
+  struct Curl_easy *data=conn->data;
   int ldap_proto = LDAP_VERSION3;
   int ldap_ssl = 0;
   char *val_b64 = NULL;
@@ -228,7 +227,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
     goto quit;
   }
 
-  /* Get the URL scheme ( either ldap or ldaps ) */
+  /* Get the URL scheme (either ldap or ldaps) */
   if(conn->given->flags & PROTOPT_SSL)
     ldap_ssl = 1;
   infof(data, "LDAP local: trying to establish %s connection\n",
@@ -717,7 +716,7 @@ static int str2scope (const char *p)
      return LDAP_SCOPE_BASE;
   if(strequal(p, "sub"))
      return LDAP_SCOPE_SUBTREE;
-  if(strequal( p, "subtree"))
+  if(strequal(p, "subtree"))
      return LDAP_SCOPE_SUBTREE;
   return (-1);
 }
diff --git a/lib/libcurl.rc b/lib/libcurl.rc
index 47b944a..50b365d 100644
--- a/lib/libcurl.rc
+++ b/lib/libcurl.rc
@@ -9,7 +9,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -44,7 +44,7 @@ BEGIN
   BEGIN
     BLOCK "040904b0"
     BEGIN
-      VALUE "CompanyName",      "The cURL library, http://curl.haxx.se/\0"
+      VALUE "CompanyName",      "The cURL library, https://curl.haxx.se/\0"
       VALUE "FileDescription",  "libcurl Shared Library\0"
       VALUE "FileVersion",      LIBCURL_VERSION "\0"
       VALUE "InternalName",     "libcurl\0"
@@ -52,7 +52,7 @@ BEGIN
       VALUE "ProductName",      "The cURL library\0"
       VALUE "ProductVersion",   LIBCURL_VERSION "\0"
       VALUE "LegalCopyright",   "© " LIBCURL_COPYRIGHT "\0"
-      VALUE "License",          "http://curl.haxx.se/docs/copyright.html\0"
+      VALUE "License",          "https://curl.haxx.se/docs/copyright.html\0"
     END
   END
 
diff --git a/lib/llist.c b/lib/llist.c
index 40bb628..482aaa0 100644
--- a/lib/llist.c
+++ b/lib/llist.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -22,6 +22,8 @@
 
 #include "curl_setup.h"
 
+#include <curl/curl.h>
+
 #include "llist.h"
 #include "curl_memory.h"
 
diff --git a/lib/llist.h b/lib/llist.h
index 27ddb71..39ff408 100644
--- a/lib/llist.h
+++ b/lib/llist.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/md5.c b/lib/md5.c
index b604c10..84adb99 100644
--- a/lib/md5.c
+++ b/lib/md5.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -24,6 +24,8 @@
 
 #ifndef CURL_DISABLE_CRYPTO_AUTH
 
+#include <curl/curl.h>
+
 #include "curl_md5.h"
 #include "curl_hmac.h"
 #include "warnless.h"
diff --git a/lib/memdebug.c b/lib/memdebug.c
index dd8889b..ccbf461 100644
--- a/lib/memdebug.c
+++ b/lib/memdebug.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -26,10 +26,12 @@
 
 #include <curl/curl.h>
 
-#include "curl_printf.h"
 #include "urldata.h"
 
 #define MEMDEBUG_NODEFINES /* don't redefine the standard functions */
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
 #include "curl_memory.h"
 #include "memdebug.h"
 
@@ -117,7 +119,7 @@ void curl_memdebug(const char *logname)
       logfile = stderr;
 #ifdef MEMDEBUG_LOG_SYNC
     /* Flush the log file after every line so the log isn't lost in a crash */
-    setvbuf(logfile, (char *)NULL, _IOLBF, 0);
+    setbuf(logfile, (char *)NULL);
 #endif
   }
 }
@@ -146,6 +148,7 @@ static bool countcheck(const char *func, int line, const char *source)
         /* log to stderr also */
         fprintf(stderr, "LIMIT %s:%d %s reached memlimit\n",
                 source, line, func);
+        fflush(logfile); /* because it might crash now */
       }
       SET_ERRNO(ENOMEM);
       return TRUE; /* RETURN ERROR! */
@@ -153,10 +156,6 @@ static bool countcheck(const char *func, int line, const char *source)
     else
       memsize--; /* countdown */
 
-    /* log the countdown */
-    if(source)
-      curl_memlog("LIMIT %s:%d %ld ALLOCS left\n",
-                  source, line, memsize);
 
   }
 
diff --git a/lib/memdebug.h b/lib/memdebug.h
index cfac1e0..835dab3 100644
--- a/lib/memdebug.h
+++ b/lib/memdebug.h
@@ -8,11 +8,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -28,10 +28,6 @@
  * as well as the library. Do not mix with library internals!
  */
 
-#include "curl_setup.h"
-
-#include <curl/curl.h>
-
 #define CURL_MT_LOGFNAME_BUFSIZE 512
 
 #define logfile curl_debuglogfile
@@ -57,17 +53,17 @@ CURL_EXTERN void curl_memlog(const char *format, ...);
 
 /* file descriptor manipulators */
 CURL_EXTERN curl_socket_t curl_socket(int domain, int type, int protocol,
-                                      int line , const char *source);
+                                      int line, const char *source);
 CURL_EXTERN void curl_mark_sclose(curl_socket_t sockfd,
-                                  int line , const char *source);
+                                  int line, const char *source);
 CURL_EXTERN int curl_sclose(curl_socket_t sockfd,
-                            int line , const char *source);
+                            int line, const char *source);
 CURL_EXTERN curl_socket_t curl_accept(curl_socket_t s, void *a, void *alen,
                                       int line, const char *source);
 #ifdef HAVE_SOCKETPAIR
 CURL_EXTERN int curl_socketpair(int domain, int type, int protocol,
                                 curl_socket_t socket_vector[2],
-                                int line , const char *source);
+                                int line, const char *source);
 #endif
 
 /* FILE functions */
@@ -103,6 +99,7 @@ CURL_EXTERN int curl_fclose(FILE *file, int line, const char *source);
 #  endif
 #endif
 
+#undef socket
 #define socket(domain,type,protocol)\
  curl_socket(domain, type, protocol, __LINE__, __FILE__)
 #undef accept /* for those with accept as a macro */
diff --git a/lib/mprintf.c b/lib/mprintf.c
index 23070a7..73f854b 100644
--- a/lib/mprintf.c
+++ b/lib/mprintf.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1999 - 2014, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1999 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -32,15 +32,10 @@
  *
  * If you ever want truly portable and good *printf() clones, the project that
  * took on from here is named 'Trio' and you find more details on the trio web
- * page at http://daniel.haxx.se/trio/
+ * page at https://daniel.haxx.se/projects/trio/
  */
 
 #include "curl_setup.h"
-
-#if defined(DJGPP) && (DJGPP_MINOR < 4)
-#undef _MPRINTF_REPLACE /* don't use x_was_used() here */
-#endif
-
 #include <curl/mprintf.h>
 
 #include "curl_memory.h"
@@ -465,22 +460,24 @@ static long dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos,
       if(flags & FLAGS_WIDTHPARAM) {
         /* we have the width specified from a parameter, so we make that
            parameter's info setup properly */
-        vto[i].width = width - 1;
-        i = width - 1;
-        vto[i].type = FORMAT_WIDTH;
-        vto[i].flags = FLAGS_NEW;
-        vto[i].precision = vto[i].width = 0; /* can't use width or precision
-                                                of width! */
+        long k = width - 1;
+        vto[i].width = k;
+        vto[k].type = FORMAT_WIDTH;
+        vto[k].flags = FLAGS_NEW;
+        /* can't use width or precision of width! */
+        vto[k].width = 0;
+        vto[k].precision = 0;
       }
       if(flags & FLAGS_PRECPARAM) {
         /* we have the precision specified from a parameter, so we make that
            parameter's info setup properly */
-        vto[i].precision = precision - 1;
-        i = precision - 1;
-        vto[i].type = FORMAT_WIDTH;
-        vto[i].flags = FLAGS_NEW;
-        vto[i].precision = vto[i].width = 0; /* can't use width or precision
-                                                of width! */
+        long k = precision - 1;
+        vto[i].precision = k;
+        vto[k].type = FORMAT_WIDTH;
+        vto[k].flags = FLAGS_NEW;
+        /* can't use width or precision of width! */
+        vto[k].width = 0;
+        vto[k].precision = 0;
       }
       *endpos++ = fmt + 1; /* end of this sequence */
     }
@@ -488,11 +485,15 @@ static long dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos,
 
   /* Read the arg list parameters into our data list */
   for(i=0; i<max_param; i++) {
-    if((i + 1 < max_param) && (vto[i + 1].type == FORMAT_WIDTH)) {
-      /* Width/precision arguments must be read before the main argument
-       * they are attached to
-       */
-      vto[i + 1].data.num.as_signed = (mp_intmax_t)va_arg(arglist, int);
+    /* Width/precision arguments must be read before the main argument
+       they are attached to */
+    if(vto[i].flags & FLAGS_WIDTHPARAM) {
+      vto[vto[i].width].data.num.as_signed =
+        (mp_intmax_t)va_arg(arglist, int);
+    }
+    if(vto[i].flags & FLAGS_PRECPARAM) {
+      vto[vto[i].precision].data.num.as_signed =
+        (mp_intmax_t)va_arg(arglist, int);
     }
 
     switch (vto[i].type) {
@@ -580,6 +581,11 @@ static int dprintf_formatf(
 
   va_stack_t *p;
 
+  /* 'workend' points to the final buffer byte position, but with an extra
+     byte as margin to avoid the (false?) warning Coverity gives us
+     otherwise */
+  char *workend = &work[sizeof(work) - 2];
+
   /* Do the actual %-code parsing */
   dprintf_Pass1(format, vto, endpos, ap_save);
 
@@ -609,6 +615,8 @@ static int dprintf_formatf(
     /* Used to convert negative in positive.  */
     mp_intmax_t signed_num;
 
+    char *w;
+
     if(*f != '%') {
       /* This isn't a format spec, so write everything out until the next one
          OR end of string is reached.  */
@@ -645,16 +653,30 @@ static int dprintf_formatf(
     p = &vto[param];
 
     /* pick up the specified width */
-    if(p->flags & FLAGS_WIDTHPARAM)
+    if(p->flags & FLAGS_WIDTHPARAM) {
       width = (long)vto[p->width].data.num.as_signed;
+      param_num++; /* since the width is extracted from a parameter, we
+                      must skip that to get to the next one properly */
+      if(width < 0) {
+        /* "A negative field width is taken as a '-' flag followed by a
+           positive field width." */
+        width = -width;
+        p->flags |= FLAGS_LEFT;
+        p->flags &= ~FLAGS_PAD_NIL;
+      }
+    }
     else
       width = p->width;
 
     /* pick up the specified precision */
     if(p->flags & FLAGS_PRECPARAM) {
       prec = (long)vto[p->precision].data.num.as_signed;
-      param_num++; /* since the precision is extraced from a parameter, we
+      param_num++; /* since the precision is extracted from a parameter, we
                       must skip that to get to the next one properly */
+      if(prec < 0)
+        /* "A negative precision is taken as if the precision were
+           omitted." */
+        prec = -1;
     }
     else if(p->flags & FLAGS_PREC)
       prec = p->precision;
@@ -715,72 +737,68 @@ static int dprintf_formatf(
 
       number:
       /* Number of base BASE.  */
-      {
-        char *workend = &work[sizeof(work) - 1];
-        char *w;
-
-        /* Supply a default precision if none was given.  */
-        if(prec == -1)
-          prec = 1;
-
-        /* Put the number in WORK.  */
-        w = workend;
-        while(num > 0) {
-          *w-- = digits[num % base];
-          num /= base;
-        }
-        width -= (long)(workend - w);
-        prec -= (long)(workend - w);
 
-        if(is_alt && base == 8 && prec <= 0) {
-          *w-- = '0';
-          --width;
-        }
+      /* Supply a default precision if none was given.  */
+      if(prec == -1)
+        prec = 1;
 
-        if(prec > 0) {
-          width -= prec;
-          while(prec-- > 0)
-            *w-- = '0';
-        }
+      /* Put the number in WORK.  */
+      w = workend;
+      while(num > 0) {
+        *w-- = digits[num % base];
+        num /= base;
+      }
+      width -= (long)(workend - w);
+      prec -= (long)(workend - w);
 
-        if(is_alt && base == 16)
-          width -= 2;
+      if(is_alt && base == 8 && prec <= 0) {
+        *w-- = '0';
+        --width;
+      }
 
-        if(is_neg || (p->flags & FLAGS_SHOWSIGN) || (p->flags & FLAGS_SPACE))
-          --width;
+      if(prec > 0) {
+        width -= prec;
+        while(prec-- > 0)
+          *w-- = '0';
+      }
 
-        if(!(p->flags & FLAGS_LEFT) && !(p->flags & FLAGS_PAD_NIL))
-          while(width-- > 0)
-            OUTCHAR(' ');
+      if(is_alt && base == 16)
+        width -= 2;
 
-        if(is_neg)
-          OUTCHAR('-');
-        else if(p->flags & FLAGS_SHOWSIGN)
-          OUTCHAR('+');
-        else if(p->flags & FLAGS_SPACE)
-          OUTCHAR(' ');
+      if(is_neg || (p->flags & FLAGS_SHOWSIGN) || (p->flags & FLAGS_SPACE))
+        --width;
 
-        if(is_alt && base == 16) {
-          OUTCHAR('0');
-          if(p->flags & FLAGS_UPPER)
-            OUTCHAR('X');
-          else
-            OUTCHAR('x');
-        }
+      if(!(p->flags & FLAGS_LEFT) && !(p->flags & FLAGS_PAD_NIL))
+        while(width-- > 0)
+          OUTCHAR(' ');
 
-        if(!(p->flags & FLAGS_LEFT) && (p->flags & FLAGS_PAD_NIL))
-          while(width-- > 0)
-            OUTCHAR('0');
+      if(is_neg)
+        OUTCHAR('-');
+      else if(p->flags & FLAGS_SHOWSIGN)
+        OUTCHAR('+');
+      else if(p->flags & FLAGS_SPACE)
+        OUTCHAR(' ');
+
+      if(is_alt && base == 16) {
+        OUTCHAR('0');
+        if(p->flags & FLAGS_UPPER)
+          OUTCHAR('X');
+        else
+          OUTCHAR('x');
+      }
 
-        /* Write the number.  */
-        while(++w <= workend) {
-          OUTCHAR(*w);
-        }
+      if(!(p->flags & FLAGS_LEFT) && (p->flags & FLAGS_PAD_NIL))
+        while(width-- > 0)
+          OUTCHAR('0');
 
-        if(p->flags & FLAGS_LEFT)
-          while(width-- > 0)
-            OUTCHAR(' ');
+      /* Write the number.  */
+      while(++w <= workend) {
+        OUTCHAR(*w);
       }
+
+      if(p->flags & FLAGS_LEFT)
+        while(width-- > 0)
+          OUTCHAR(' ');
       break;
 
     case FORMAT_STRING:
@@ -809,7 +827,7 @@ static int dprintf_formatf(
         else
           len = strlen(str);
 
-        width -= (long)len;
+        width -= (len > LONG_MAX) ? LONG_MAX : (long)len;
 
         if(p->flags & FLAGS_ALT)
           OUTCHAR('"');
diff --git a/lib/multi.c b/lib/multi.c
index 0052087..8bb9366 100644
--- a/lib/multi.c
+++ b/lib/multi.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -42,9 +42,9 @@
 #include "multihandle.h"
 #include "pipeline.h"
 #include "sigpipe.h"
+/* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_memory.h"
-/* The last #include file should be: */
 #include "memdebug.h"
 
 /*
@@ -61,15 +61,15 @@
 #define CURL_MULTI_HANDLE 0x000bab1e
 
 #define GOOD_MULTI_HANDLE(x) \
-  ((x) && (((struct Curl_multi *)(x))->type == CURL_MULTI_HANDLE))
+  ((x) && (x)->type == CURL_MULTI_HANDLE)
 
 static void singlesocket(struct Curl_multi *multi,
-                         struct SessionHandle *data);
+                         struct Curl_easy *data);
 static int update_timer(struct Curl_multi *multi);
 
 static CURLMcode add_next_timeout(struct timeval now,
                                   struct Curl_multi *multi,
-                                  struct SessionHandle *d);
+                                  struct Curl_easy *d);
 static CURLMcode multi_timeout(struct Curl_multi *multi,
                                long *timeout_ms);
 
@@ -99,14 +99,23 @@ static const char * const statename[]={
 
 static void multi_freetimeout(void *a, void *b);
 
+/* function pointer called once when switching TO a state */
+typedef void (*init_multistate_func)(struct Curl_easy *data);
+
 /* always use this function to change state, to make debugging easier */
-static void mstate(struct SessionHandle *data, CURLMstate state
+static void mstate(struct Curl_easy *data, CURLMstate state
 #ifdef DEBUGBUILD
                    , int lineno
 #endif
 )
 {
   CURLMstate oldstate = data->mstate;
+  static const init_multistate_func finit[CURLM_STATE_LAST] = {
+    NULL,
+    NULL,
+    Curl_init_CONNECT, /* CONNECT */
+    /* the rest is NULL too */
+  };
 
 #if defined(DEBUGBUILD) && defined(CURL_DISABLE_VERBOSE_STRINGS)
   (void) lineno;
@@ -127,7 +136,7 @@ static void mstate(struct SessionHandle *data, CURLMstate state
       connection_id = data->easy_conn->connection_id;
 
     infof(data,
-          "STATE: %s => %s handle %p; line %d (connection #%ld) \n",
+          "STATE: %s => %s handle %p; line %d (connection #%ld)\n",
           statename[oldstate], statename[data->mstate],
           (void *)data, lineno, connection_id);
   }
@@ -136,6 +145,10 @@ static void mstate(struct SessionHandle *data, CURLMstate state
   if(state == CURLM_STATE_COMPLETED)
     /* changing to COMPLETED means there's one less easy handle 'alive' */
     data->multi->num_alive--;
+
+  /* if this state has an init-function, run it */
+  if(finit[state])
+    finit[state](data);
 }
 
 #ifndef DEBUGBUILD
@@ -149,7 +162,7 @@ static void mstate(struct SessionHandle *data, CURLMstate state
  */
 
 struct Curl_sh_entry {
-  struct SessionHandle *easy;
+  struct Curl_easy *easy;
   int action;  /* what action READ/WRITE this socket waits for */
   curl_socket_t socket; /* mainly to ease debugging */
   void *socketp; /* settable by users with curl_multi_assign() */
@@ -159,13 +172,22 @@ struct Curl_sh_entry {
 #define SH_READ  1
 #define SH_WRITE 2
 
+/* look up a given socket in the socket hash, skip invalid sockets */
+static struct Curl_sh_entry *sh_getentry(struct curl_hash *sh,
+                                         curl_socket_t s)
+{
+  if(s != CURL_SOCKET_BAD)
+    /* only look for proper sockets */
+    return Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t));
+  return NULL;
+}
+
 /* make sure this socket is present in the hash for this handle */
 static struct Curl_sh_entry *sh_addentry(struct curl_hash *sh,
                                          curl_socket_t s,
-                                         struct SessionHandle *data)
+                                         struct Curl_easy *data)
 {
-  struct Curl_sh_entry *there =
-    Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t));
+  struct Curl_sh_entry *there = sh_getentry(sh, s);
   struct Curl_sh_entry *check;
 
   if(there)
@@ -193,15 +215,9 @@ static struct Curl_sh_entry *sh_addentry(struct curl_hash *sh,
 /* delete the given socket + handle from the hash */
 static void sh_delentry(struct curl_hash *sh, curl_socket_t s)
 {
-  struct Curl_sh_entry *there =
-    Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t));
-
-  if(there) {
-    /* this socket is in the hash */
-    /* We remove the hash entry. (This'll end up in a call to
-       sh_freeentry().) */
-    Curl_hash_delete(sh, (char *)&s, sizeof(curl_socket_t));
-  }
+  /* We remove the hash entry. This will end up in a call to
+     sh_freeentry(). */
+  Curl_hash_delete(sh, (char *)&s, sizeof(curl_socket_t));
 }
 
 /*
@@ -218,15 +234,15 @@ static size_t fd_key_compare(void *k1, size_t k1_len, void *k2, size_t k2_len)
 {
   (void) k1_len; (void) k2_len;
 
-  return (*((int *) k1)) == (*((int *) k2));
+  return (*((curl_socket_t *) k1)) == (*((curl_socket_t *) k2));
 }
 
 static size_t hash_fd(void *key, size_t key_length, size_t slots_num)
 {
-  int fd = *((int *) key);
+  curl_socket_t fd = *((curl_socket_t *) key);
   (void) key_length;
 
-  return (fd % (int)slots_num);
+  return (fd % slots_num);
 }
 
 /*
@@ -318,7 +334,7 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
 
   /* -1 means it not set by user, use the default value */
   multi->maxconnects = -1;
-  return (CURLM *) multi;
+  return multi;
 
   error:
 
@@ -334,25 +350,23 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
   return NULL;
 }
 
-CURLM *curl_multi_init(void)
+struct Curl_multi *curl_multi_init(void)
 {
   return Curl_multi_handle(CURL_SOCKET_HASH_TABLE_SIZE,
                            CURL_CONNECTION_HASH_SIZE);
 }
 
-CURLMcode curl_multi_add_handle(CURLM *multi_handle,
-                                CURL *easy_handle)
+CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
+                                struct Curl_easy *data)
 {
   struct curl_llist *timeoutlist;
-  struct Curl_multi *multi = (struct Curl_multi *)multi_handle;
-  struct SessionHandle *data = (struct SessionHandle *)easy_handle;
 
   /* First, make some basic checks that the CURLM handle is a good handle */
   if(!GOOD_MULTI_HANDLE(multi))
     return CURLM_BAD_HANDLE;
 
   /* Verify that we got a somewhat good easy handle too */
-  if(!GOOD_EASY_HANDLE(easy_handle))
+  if(!GOOD_EASY_HANDLE(data))
     return CURLM_BAD_EASY_HANDLE;
 
   /* Prevent users from adding same easy handle more than once and prevent
@@ -401,14 +415,14 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle,
   data->state.conn_cache = &multi->conn_cache;
 
   /* This adds the new entry at the 'end' of the doubly-linked circular
-     list of SessionHandle structs to try and maintain a FIFO queue so
+     list of Curl_easy structs to try and maintain a FIFO queue so
      the pipelined requests are in order. */
 
   /* We add this new entry last in the list. */
 
   data->next = NULL; /* end of the line */
   if(multi->easyp) {
-    struct SessionHandle *last = multi->easylp;
+    struct Curl_easy *last = multi->easylp;
     last->next = data;
     data->prev = last;
     multi->easylp = data; /* the new last node */
@@ -419,8 +433,8 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle,
     multi->easylp = multi->easyp = data; /* both first and last */
   }
 
-  /* make the SessionHandle refer back to this multi handle */
-  data->multi = multi_handle;
+  /* make the Curl_easy refer back to this multi handle */
+  data->multi = multi;
 
   /* Set the timeout for this handle to expire really soon so that it will
      be taken care of even when this handle is added in the midst of operation
@@ -468,12 +482,171 @@ static void debug_print_sock_hash(void *p)
 }
 #endif
 
-CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
-                                   CURL *curl_handle)
+/* Mark the connection as 'idle', or close it if the cache is full.
+   Returns TRUE if the connection is kept, or FALSE if it was closed. */
+static bool
+ConnectionDone(struct Curl_easy *data, struct connectdata *conn)
+{
+  /* data->multi->maxconnects can be negative, deal with it. */
+  size_t maxconnects =
+    (data->multi->maxconnects < 0) ? data->multi->num_easy * 4:
+    data->multi->maxconnects;
+  struct connectdata *conn_candidate = NULL;
+
+  /* Mark the current connection as 'unused' */
+  conn->inuse = FALSE;
+
+  if(maxconnects > 0 &&
+     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);
+
+    if(conn_candidate) {
+      /* Set the connection's owner correctly */
+      conn_candidate->data = data;
+
+      /* the winner gets the honour of being disconnected */
+      (void)Curl_disconnect(conn_candidate, /* dead_connection */ FALSE);
+    }
+  }
+
+  return (conn_candidate == conn) ? FALSE : TRUE;
+}
+
+static CURLcode multi_done(struct connectdata **connp,
+                          CURLcode status,  /* an error if this is called
+                                               after an error was detected */
+                          bool premature)
 {
-  struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
-  struct SessionHandle *easy = curl_handle;
-  struct SessionHandle *data = easy;
+  CURLcode result;
+  struct connectdata *conn;
+  struct Curl_easy *data;
+
+  DEBUGASSERT(*connp);
+
+  conn = *connp;
+  data = conn->data;
+
+  DEBUGF(infof(data, "multi_done\n"));
+
+  if(data->state.done)
+    /* Stop if multi_done() has already been called */
+    return CURLE_OK;
+
+  Curl_getoff_all_pipelines(data, conn);
+
+  /* Cleanup possible redirect junk */
+  free(data->req.newurl);
+  data->req.newurl = NULL;
+  free(data->req.location);
+  data->req.location = NULL;
+
+  switch(status) {
+  case CURLE_ABORTED_BY_CALLBACK:
+  case CURLE_READ_ERROR:
+  case CURLE_WRITE_ERROR:
+    /* When we're aborted due to a callback return code it basically have to
+       be counted as premature as there is trouble ahead if we don't. We have
+       many callbacks and protocols work differently, we could potentially do
+       this more fine-grained in the future. */
+    premature = TRUE;
+  default:
+    break;
+  }
+
+  /* this calls the protocol-specific function pointer previously set */
+  if(conn->handler->done)
+    result = conn->handler->done(conn, status, premature);
+  else
+    result = status;
+
+  if(CURLE_ABORTED_BY_CALLBACK != result) {
+    /* avoid this if we already aborted by callback to avoid this calling
+       another callback */
+    CURLcode rc = Curl_pgrsDone(conn);
+    if(!result && rc)
+      result = CURLE_ABORTED_BY_CALLBACK;
+  }
+
+  if((!premature &&
+      conn->send_pipe->size + conn->recv_pipe->size != 0 &&
+      !data->set.reuse_forbid &&
+      !conn->bits.close)) {
+    /* Stop if pipeline is not empty and we do not have to close
+       connection. */
+    DEBUGF(infof(data, "Connection still in use, no more multi_done now!\n"));
+    return CURLE_OK;
+  }
+
+  data->state.done = TRUE; /* called just now! */
+  Curl_resolver_cancel(conn);
+
+  if(conn->dns_entry) {
+    Curl_resolv_unlock(data, conn->dns_entry); /* done with this */
+    conn->dns_entry = NULL;
+  }
+
+  /* if the transfer was completed in a paused state there can be buffered
+     data left to write and then kill */
+  free(data->state.tempwrite);
+  data->state.tempwrite = NULL;
+
+  /* if data->set.reuse_forbid is TRUE, it means the libcurl client has
+     forced us to close this connection. This is ignored for requests taking
+     place in a NTLM authentication handshake
+
+     if conn->bits.close is TRUE, it means that the connection should be
+     closed in spite of all our efforts to be nice, due to protocol
+     restrictions in our or the server's end
+
+     if premature is TRUE, it means this connection was said to be DONE before
+     the entire request operation is complete and thus we can't know in what
+     state it is for re-using, so we're forced to close it. In a perfect world
+     we can add code that keep track of if we really must close it here or not,
+     but currently we have no such detail knowledge.
+  */
+
+  if((data->set.reuse_forbid
+#if defined(USE_NTLM)
+      && !(conn->ntlm.state == NTLMSTATE_TYPE2 ||
+           conn->proxyntlm.state == NTLMSTATE_TYPE2)
+#endif
+     ) || conn->bits.close || premature) {
+    CURLcode res2 = Curl_disconnect(conn, premature); /* close connection */
+
+    /* If we had an error already, make sure we return that one. But
+       if we got a new error, return that. */
+    if(!result && res2)
+      result = res2;
+  }
+  else {
+    /* the connection is no longer in use */
+    if(ConnectionDone(data, conn)) {
+      /* remember the most recently used connection */
+      data->state.lastconnect = conn;
+
+      infof(data, "Connection #%ld to host %s left intact\n",
+            conn->connection_id,
+            conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname);
+    }
+    else
+      data->state.lastconnect = NULL;
+  }
+
+  *connp = NULL; /* to make the caller of this function better detect that
+                    this was either closed or handed over to the connection
+                    cache here, and therefore cannot be used from this point on
+                 */
+  Curl_free_request_state(data);
+
+  return result;
+}
+
+CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
+                                   struct Curl_easy *data)
+{
+  struct Curl_easy *easy = data;
   bool premature;
   bool easy_owns_conn;
   struct curl_llist_element *e;
@@ -483,7 +656,7 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
     return CURLM_BAD_HANDLE;
 
   /* Verify that we got a somewhat good easy handle too */
-  if(!GOOD_EASY_HANDLE(curl_handle))
+  if(!GOOD_EASY_HANDLE(data))
     return CURLM_BAD_EASY_HANDLE;
 
   /* Prevent users from trying to remove same easy handle more than once */
@@ -513,8 +686,8 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
        request but not received its response yet, we need to close
        connection. */
     connclose(data->easy_conn, "Removed with partial response");
-    /* Set connection owner so that Curl_done() closes it.
-       We can safely do this here since connection is killed. */
+    /* Set connection owner so that the DONE function closes it.  We can
+       safely do this here since connection is killed. */
     data->easy_conn->data = easy;
     easy_owns_conn = TRUE;
   }
@@ -524,12 +697,6 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
      curl_easy_cleanup is called. */
   Curl_expire(data, 0);
 
-  /* destroy the timeout list that is held in the easy handle */
-  if(data->state.timeoutlist) {
-    Curl_llist_destroy(data->state.timeoutlist, NULL);
-    data->state.timeoutlist = NULL;
-  }
-
   if(data->dns.hostcachetype == HCACHE_MULTI) {
     /* stop using the multi handle's DNS cache */
     data->dns.hostcache = NULL;
@@ -538,24 +705,31 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
 
   if(data->easy_conn) {
 
-    /* we must call Curl_done() here (if we still "own it") so that we don't
-       leave a half-baked one around */
+    /* we must call multi_done() here (if we still own the connection) so that
+       we don't leave a half-baked one around */
     if(easy_owns_conn) {
 
-      /* Curl_done() clears the conn->data field to lose the association
+      /* multi_done() clears the conn->data field to lose the association
          between the easy handle and the connection
 
          Note that this ignores the return code simply because there's
          nothing really useful to do with it anyway! */
-      (void)Curl_done(&data->easy_conn, data->result, premature);
+      (void)multi_done(&data->easy_conn, data->result, premature);
     }
     else
-      /* Clear connection pipelines, if Curl_done above was not called */
+      /* Clear connection pipelines, if multi_done above was not called */
       Curl_getoff_all_pipelines(data, data->easy_conn);
   }
 
   Curl_wildcard_dtor(&data->wildcard);
 
+  /* destroy the timeout list that is held in the easy handle, do this *after*
+     multi_done() as that may actually call Curl_expire that uses this */
+  if(data->state.timeoutlist) {
+    Curl_llist_destroy(data->state.timeoutlist, NULL);
+    data->state.timeoutlist = NULL;
+  }
+
   /* as this was using a shared connection cache we clear the pointer to that
      since we're not part of that multi handle anymore */
   data->state.conn_cache = NULL;
@@ -613,7 +787,7 @@ bool Curl_pipeline_wanted(const struct Curl_multi *multi, int bits)
   return (multi && (multi->pipelining & bits)) ? TRUE : FALSE;
 }
 
-void Curl_multi_handlePipeBreak(struct SessionHandle *data)
+void Curl_multi_handlePipeBreak(struct Curl_easy *data)
 {
   data->easy_conn = NULL;
 }
@@ -666,7 +840,7 @@ static int domore_getsock(struct connectdata *conn,
 }
 
 /* returns bitmapped flags for this handle and its sockets */
-static int multi_getsock(struct SessionHandle *data,
+static int multi_getsock(struct Curl_easy *data,
                          curl_socket_t *socks, /* points to numsocks number
                                                   of sockets */
                          int numsocks)
@@ -732,15 +906,14 @@ static int multi_getsock(struct SessionHandle *data,
 
 }
 
-CURLMcode curl_multi_fdset(CURLM *multi_handle,
+CURLMcode curl_multi_fdset(struct Curl_multi *multi,
                            fd_set *read_fd_set, fd_set *write_fd_set,
                            fd_set *exc_fd_set, int *max_fd)
 {
   /* Scan through all the easy handles to get the file descriptors set.
      Some easy handles may not have connected to the remote host yet,
      and then we must make sure that is done. */
-  struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
-  struct SessionHandle *data;
+  struct Curl_easy *data;
   int this_max_fd=-1;
   curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE];
   int bitmap;
@@ -782,14 +955,13 @@ CURLMcode curl_multi_fdset(CURLM *multi_handle,
   return CURLM_OK;
 }
 
-CURLMcode curl_multi_wait(CURLM *multi_handle,
+CURLMcode curl_multi_wait(struct Curl_multi *multi,
                           struct curl_waitfd extra_fds[],
                           unsigned int extra_nfds,
                           int timeout_ms,
                           int *ret)
 {
-  struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
-  struct SessionHandle *data;
+  struct Curl_easy *data;
   curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE];
   int bitmap;
   unsigned int i;
@@ -797,6 +969,7 @@ CURLMcode curl_multi_wait(CURLM *multi_handle,
   unsigned int curlfds;
   struct pollfd *ufds = NULL;
   long timeout_internal;
+  int retcode = 0;
 
   if(!GOOD_MULTI_HANDLE(multi))
     return CURLM_BAD_HANDLE;
@@ -889,18 +1062,20 @@ CURLMcode curl_multi_wait(CURLM *multi_handle,
   }
 
   if(nfds) {
+    int pollrc;
     /* wait... */
-    infof(data, "Curl_poll(%d ds, %d ms)\n", nfds, timeout_ms);
-    i = Curl_poll(ufds, nfds, timeout_ms);
+    pollrc = Curl_poll(ufds, nfds, timeout_ms);
+    DEBUGF(infof(data, "Curl_poll(%d ds, %d ms) == %d\n",
+                 nfds, timeout_ms, pollrc));
 
-    if(i) {
-      unsigned int j;
+    if(pollrc > 0) {
+      retcode = pollrc;
       /* copy revents results from the poll to the curl_multi_wait poll
          struct, the bit values of the actual underlying poll() implementation
          may not be the same as the ones in the public libcurl API! */
-      for(j = 0; j < extra_nfds; j++) {
+      for(i = 0; i < extra_nfds; i++) {
         unsigned short mask = 0;
-        unsigned r = ufds[curlfds + j].revents;
+        unsigned r = ufds[curlfds + i].revents;
 
         if(r & POLLIN)
           mask |= CURL_WAIT_POLLIN;
@@ -909,16 +1084,14 @@ CURLMcode curl_multi_wait(CURLM *multi_handle,
         if(r & POLLPRI)
           mask |= CURL_WAIT_POLLPRI;
 
-        extra_fds[j].revents = mask;
+        extra_fds[i].revents = mask;
       }
     }
   }
-  else
-    i = 0;
 
   free(ufds);
   if(ret)
-    *ret = i;
+    *ret = retcode;
   return CURLM_OK;
 }
 
@@ -951,7 +1124,7 @@ static bool multi_ischanged(struct Curl_multi *multi, bool clear)
 }
 
 CURLMcode Curl_multi_add_perform(struct Curl_multi *multi,
-                                 struct SessionHandle *data,
+                                 struct Curl_easy *data,
                                  struct connectdata *conn)
 {
   CURLMcode rc;
@@ -972,9 +1145,142 @@ CURLMcode Curl_multi_add_perform(struct Curl_multi *multi,
   return rc;
 }
 
+static CURLcode multi_reconnect_request(struct connectdata **connp)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = *connp;
+  struct Curl_easy *data = conn->data;
+
+  /* This was a re-use of a connection and we got a write error in the
+   * DO-phase. Then we DISCONNECT this connection and have another attempt to
+   * CONNECT and then DO again! The retry cannot possibly find another
+   * connection to re-use, since we only keep one possible connection for
+   * each.  */
+
+  infof(data, "Re-used connection seems dead, get a new one\n");
+
+  connclose(conn, "Reconnect dead connection"); /* enforce close */
+  result = multi_done(&conn, result, FALSE); /* we are so done with this */
+
+  /* conn may no longer be a good pointer, clear it to avoid mistakes by
+     parent functions */
+  *connp = NULL;
+
+  /*
+   * We need to check for CURLE_SEND_ERROR here as well. This could happen
+   * when the request failed on a FTP connection and thus multi_done() itself
+   * tried to use the connection (again).
+   */
+  if(!result || (CURLE_SEND_ERROR == result)) {
+    bool async;
+    bool protocol_done = TRUE;
+
+    /* Now, redo the connect and get a new connection */
+    result = Curl_connect(data, connp, &async, &protocol_done);
+    if(!result) {
+      /* We have connected or sent away a name resolve query fine */
+
+      conn = *connp; /* setup conn to again point to something nice */
+      if(async) {
+        /* Now, if async is TRUE here, we need to wait for the name
+           to resolve */
+        result = Curl_resolver_wait_resolv(conn, NULL);
+        if(result)
+          return result;
+
+        /* Resolved, continue with the connection */
+        result = Curl_async_resolved(conn, &protocol_done);
+        if(result)
+          return result;
+      }
+    }
+  }
+
+  return result;
+}
+
+/*
+ * do_complete is called when the DO actions are complete.
+ *
+ * We init chunking and trailer bits to their default values here immediately
+ * before receiving any header data for the current request in the pipeline.
+ */
+static void do_complete(struct connectdata *conn)
+{
+  conn->data->req.chunk=FALSE;
+  conn->data->req.maxfd = (conn->sockfd>conn->writesockfd?
+                           conn->sockfd:conn->writesockfd)+1;
+  Curl_pgrsTime(conn->data, TIMER_PRETRANSFER);
+}
+
+static CURLcode multi_do(struct connectdata **connp, bool *done)
+{
+  CURLcode result=CURLE_OK;
+  struct connectdata *conn = *connp;
+  struct Curl_easy *data = conn->data;
+
+  if(conn->handler->do_it) {
+    /* generic protocol-specific function pointer set in curl_connect() */
+    result = conn->handler->do_it(conn, done);
+
+    /* This was formerly done in transfer.c, but we better do it here */
+    if((CURLE_SEND_ERROR == result) && conn->bits.reuse) {
+      /*
+       * If the connection is using an easy handle, call reconnect
+       * to re-establish the connection.  Otherwise, let the multi logic
+       * figure out how to re-establish the connection.
+       */
+      if(!data->multi) {
+        result = multi_reconnect_request(connp);
+
+        if(!result) {
+          /* ... finally back to actually retry the DO phase */
+          conn = *connp; /* re-assign conn since multi_reconnect_request
+                            creates a new connection */
+          result = conn->handler->do_it(conn, done);
+        }
+      }
+      else
+        return result;
+    }
+
+    if(!result && *done)
+      /* do_complete must be called after the protocol-specific DO function */
+      do_complete(conn);
+  }
+  return result;
+}
+
+/*
+ * multi_do_more() is called during the DO_MORE multi state. It is basically a
+ * second stage DO state which (wrongly) was introduced to support FTP's
+ * second connection.
+ *
+ * TODO: A future libcurl should be able to work away this state.
+ *
+ * 'complete' can return 0 for incomplete, 1 for done and -1 for go back to
+ * DOING state there's more work to do!
+ */
+
+static CURLcode multi_do_more(struct connectdata *conn, int *complete)
+{
+  CURLcode result=CURLE_OK;
+
+  *complete = 0;
+
+  if(conn->handler->do_more)
+    result = conn->handler->do_more(conn, complete);
+
+  if(!result && (*complete == 1))
+    /* do_complete must be called after the protocol-specific DO function */
+    do_complete(conn);
+
+  return result;
+}
+
 static CURLMcode multi_runsingle(struct Curl_multi *multi,
                                  struct timeval now,
-                                 struct SessionHandle *data)
+                                 struct Curl_easy *data)
 {
   struct Curl_message *msg = NULL;
   bool connected;
@@ -1057,7 +1363,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
             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),
+                  Curl_tvdiff(now, data->progress.t_startsingle),
                   k->bytecount, k->size);
           }
           else {
@@ -1074,7 +1380,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
           disconnect_conn = TRUE;
         }
         result = CURLE_OPERATION_TIMEDOUT;
-        (void)Curl_done(&data->easy_conn, result, TRUE);
+        (void)multi_done(&data->easy_conn, result, TRUE);
         /* Skip the statemachine and go directly to error handling section. */
         goto statemachine_end;
       }
@@ -1152,9 +1458,17 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
     {
       struct Curl_dns_entry *dns = NULL;
       struct connectdata *conn = data->easy_conn;
+      const char *hostname;
+
+      if(conn->bits.proxy)
+        hostname = conn->proxy.name;
+      else if(conn->bits.conn_to_host)
+        hostname = conn->conn_to_host.name;
+      else
+        hostname = conn->host.name;
 
       /* check if we have the name resolved by now */
-      dns = Curl_fetch_addr(conn, conn->host.name, (int)conn->port);
+      dns = Curl_fetch_addr(conn, hostname, (int)conn->port);
 
       if(dns) {
 #ifdef CURLRES_ASYNCH
@@ -1162,7 +1476,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
         conn->async.done = TRUE;
 #endif
         result = CURLE_OK;
-        infof(data, "Hostname was found in DNS cache\n");
+        infof(data, "Hostname '%s' was found in DNS cache\n", hostname);
       }
 
       if(!dns)
@@ -1215,17 +1529,19 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
       /* this is HTTP-specific, but sending CONNECT to a proxy is HTTP... */
       result = Curl_http_connect(data->easy_conn, &protocol_connect);
 
-      rc = CURLM_CALL_MULTI_PERFORM;
       if(data->easy_conn->bits.proxy_connect_closed) {
+        rc = CURLM_CALL_MULTI_PERFORM;
         /* connect back to proxy again */
         result = CURLE_OK;
-        Curl_done(&data->easy_conn, CURLE_OK, FALSE);
+        multi_done(&data->easy_conn, CURLE_OK, FALSE);
         multistate(data, CURLM_STATE_CONNECT);
       }
       else if(!result) {
-        if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_COMPLETE)
+        if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_COMPLETE) {
+          rc = CURLM_CALL_MULTI_PERFORM;
           /* initiate protocol connect phase */
           multistate(data, CURLM_STATE_SENDPROTOCONNECT);
+        }
       }
       break;
 #endif
@@ -1261,7 +1577,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
       else if(result) {
         /* failure detected */
         Curl_posttransfer(data);
-        Curl_done(&data->easy_conn, result, TRUE);
+        multi_done(&data->easy_conn, result, TRUE);
         disconnect_conn = TRUE;
       }
       break;
@@ -1278,7 +1594,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
       else if(result) {
         /* failure detected */
         Curl_posttransfer(data);
-        Curl_done(&data->easy_conn, result, TRUE);
+        multi_done(&data->easy_conn, result, TRUE);
         disconnect_conn = TRUE;
       }
       break;
@@ -1302,9 +1618,9 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
       }
       else {
         /* Perform the protocol's DO action */
-        result = Curl_do(&data->easy_conn, &dophase_done);
+        result = multi_do(&data->easy_conn, &dophase_done);
 
-        /* When Curl_do() returns failure, data->easy_conn might be NULL! */
+        /* When multi_do() returns failure, data->easy_conn might be NULL! */
 
         if(!result) {
           if(!dophase_done) {
@@ -1313,7 +1629,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
               struct WildcardData *wc = &data->wildcard;
               if(wc->state == CURLWC_DONE || wc->state == CURLWC_SKIP) {
                 /* skip some states if it is important */
-                Curl_done(&data->easy_conn, CURLE_OK, FALSE);
+                multi_done(&data->easy_conn, CURLE_OK, FALSE);
                 multistate(data, CURLM_STATE_DONE);
                 rc = CURLM_CALL_MULTI_PERFORM;
                 break;
@@ -1360,7 +1676,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
             retry = (newurl)?TRUE:FALSE;
 
           Curl_posttransfer(data);
-          drc = Curl_done(&data->easy_conn, result, FALSE);
+          drc = multi_done(&data->easy_conn, result, FALSE);
 
           /* When set to retry the connection, we must to go back to
            * the CONNECT state */
@@ -1395,7 +1711,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
           /* failure detected */
           Curl_posttransfer(data);
           if(data->easy_conn)
-            Curl_done(&data->easy_conn, result, FALSE);
+            multi_done(&data->easy_conn, result, FALSE);
           disconnect_conn = TRUE;
         }
       }
@@ -1417,7 +1733,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
       else {
         /* failure detected */
         Curl_posttransfer(data);
-        Curl_done(&data->easy_conn, result, FALSE);
+        multi_done(&data->easy_conn, result, FALSE);
         disconnect_conn = TRUE;
       }
       break;
@@ -1426,10 +1742,10 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
       /*
        * When we are connected, DO MORE and then go DO_DONE
        */
-      result = Curl_do_more(data->easy_conn, &control);
+      result = multi_do_more(data->easy_conn, &control);
 
       /* No need to remove this handle from the send pipeline here since that
-         is done in Curl_done() */
+         is done in multi_done() */
       if(!result) {
         if(control) {
           /* if positive, advance to DO_DONE
@@ -1446,7 +1762,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
       else {
         /* failure detected */
         Curl_posttransfer(data);
-        Curl_done(&data->easy_conn, result, FALSE);
+        multi_done(&data->easy_conn, result, FALSE);
         disconnect_conn = TRUE;
       }
       break;
@@ -1484,7 +1800,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
         result = Curl_speedcheck(data, now);
 
       if(( (data->set.max_send_speed == 0) ||
-           (data->progress.ulspeed < data->set.max_send_speed ))  &&
+           (data->progress.ulspeed < data->set.max_send_speed))  &&
          ( (data->set.max_recv_speed == 0) ||
            (data->progress.dlspeed < data->set.max_recv_speed)))
         multistate(data, CURLM_STATE_PERFORM);
@@ -1566,11 +1882,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
          * happened in the data connection.
          */
 
-        if(!(data->easy_conn->handler->flags & PROTOPT_DUAL))
+        if(!(data->easy_conn->handler->flags & PROTOPT_DUAL) &&
+           result != CURLE_HTTP2_STREAM)
           connclose(data->easy_conn, "Transfer returned error");
 
         Curl_posttransfer(data);
-        Curl_done(&data->easy_conn, result, FALSE);
+        multi_done(&data->easy_conn, result, FALSE);
       }
       else if(done) {
         followtype follow=FOLLOW_NONE;
@@ -1601,7 +1918,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
           }
           else
             follow = FOLLOW_RETRY;
-          result = Curl_done(&data->easy_conn, CURLE_OK, FALSE);
+          result = multi_done(&data->easy_conn, CURLE_OK, FALSE);
           if(!result) {
             result = Curl_follow(data, newurl, follow);
             if(!result) {
@@ -1651,14 +1968,14 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
         Curl_multi_process_pending_handles(multi);
 
         /* post-transfer command */
-        res = Curl_done(&data->easy_conn, result, FALSE);
+        res = multi_done(&data->easy_conn, result, FALSE);
 
         /* allow a previously set error code take precedence */
         if(!result)
           result = res;
 
         /*
-         * If there are other handles on the pipeline, Curl_done won't set
+         * If there are other handles on the pipeline, multi_done won't set
          * easy_conn to NULL.  In such a case, curl_multi_remove_handle() can
          * access free'd data, if the connection is free'd and the handle
          * removed before we perform the processing in CURLM_STATE_COMPLETED
@@ -1677,7 +1994,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
       }
 
       /* after we have DONE what we're supposed to do, go COMPLETED, and
-         it doesn't matter what the Curl_done() returned! */
+         it doesn't matter what the multi_done() returned! */
       multistate(data, CURLM_STATE_COMPLETED);
       break;
 
@@ -1779,10 +2096,9 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
 }
 
 
-CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
+CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles)
 {
-  struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
-  struct SessionHandle *data;
+  struct Curl_easy *data;
   CURLMcode returncode=CURLM_OK;
   struct Curl_tree *t;
   struct timeval now = Curl_tvnow();
@@ -1793,27 +2109,12 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
   data=multi->easyp;
   while(data) {
     CURLMcode result;
-    struct WildcardData *wc = &data->wildcard;
     SIGPIPE_VARIABLE(pipe_st);
 
-    if(data->set.wildcardmatch) {
-      if(!wc->filelist) {
-        CURLcode ret = Curl_wildcard_init(wc); /* init wildcard structures */
-        if(ret)
-          return CURLM_OUT_OF_MEMORY;
-      }
-    }
-
     sigpipe_ignore(data, &pipe_st);
     result = multi_runsingle(multi, now, data);
     sigpipe_restore(&pipe_st);
 
-    if(data->set.wildcardmatch) {
-      /* destruct wildcard structures if it is needed */
-      if(wc->state == CURLWC_DONE || result)
-        Curl_wildcard_dtor(wc);
-    }
-
     if(result)
       returncode = result;
 
@@ -1856,6 +2157,8 @@ static void close_all_connections(struct Curl_multi *multi)
     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 */
     (void)Curl_disconnect(conn, FALSE);
     sigpipe_restore(&pipe_st);
@@ -1864,11 +2167,10 @@ static void close_all_connections(struct Curl_multi *multi)
   }
 }
 
-CURLMcode curl_multi_cleanup(CURLM *multi_handle)
+CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
 {
-  struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
-  struct SessionHandle *data;
-  struct SessionHandle *nextdata;
+  struct Curl_easy *data;
+  struct Curl_easy *nextdata;
 
   if(GOOD_MULTI_HANDLE(multi)) {
     bool restore_pipe = FALSE;
@@ -1939,9 +2241,8 @@ CURLMcode curl_multi_cleanup(CURLM *multi_handle)
  * beyond. The current design is fully O(1).
  */
 
-CURLMsg *curl_multi_info_read(CURLM *multi_handle, int *msgs_in_queue)
+CURLMsg *curl_multi_info_read(struct Curl_multi *multi, int *msgs_in_queue)
 {
-  struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
   struct Curl_message *msg;
 
   *msgs_in_queue = 0; /* default to none */
@@ -1972,7 +2273,7 @@ CURLMsg *curl_multi_info_read(CURLM *multi_handle, int *msgs_in_queue)
  * call the callback accordingly.
  */
 static void singlesocket(struct Curl_multi *multi,
-                         struct SessionHandle *data)
+                         struct Curl_easy *data)
 {
   curl_socket_t socks[MAX_SOCKSPEREASYHANDLE];
   int i;
@@ -1980,7 +2281,6 @@ static void singlesocket(struct Curl_multi *multi,
   curl_socket_t s;
   int num;
   unsigned int curraction;
-  bool remove_sock_from_hash;
 
   for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++)
     socks[i] = CURL_SOCKET_BAD;
@@ -2002,7 +2302,7 @@ static void singlesocket(struct Curl_multi *multi,
     s = socks[i];
 
     /* get it from the hash */
-    entry = Curl_hash_pick(&multi->sockhash, (char *)&s, sizeof(s));
+    entry = sh_getentry(&multi->sockhash, s);
 
     if(curraction & GETSOCK_READSOCK(i))
       action |= CURL_POLL_IN;
@@ -2048,57 +2348,50 @@ static void singlesocket(struct Curl_multi *multi,
         break;
       }
     }
-    if(s != CURL_SOCKET_BAD) {
 
+    entry = sh_getentry(&multi->sockhash, s);
+    if(entry) {
       /* this socket has been removed. Tell the app to remove it */
-      remove_sock_from_hash = TRUE;
-
-      entry = Curl_hash_pick(&multi->sockhash, (char *)&s, sizeof(s));
-      if(entry) {
-        /* check if the socket to be removed serves a connection which has
-           other easy-s in a pipeline. In this case the socket should not be
-           removed. */
-        struct connectdata *easy_conn = data->easy_conn;
-        if(easy_conn) {
-          if(easy_conn->recv_pipe && easy_conn->recv_pipe->size > 1) {
-            /* the handle should not be removed from the pipe yet */
-            remove_sock_from_hash = FALSE;
-
-            /* Update the sockhash entry to instead point to the next in line
-               for the recv_pipe, or the first (in case this particular easy
-               isn't already) */
-            if(entry->easy == data) {
-              if(Curl_recvpipe_head(data, easy_conn))
-                entry->easy = easy_conn->recv_pipe->head->next->ptr;
-              else
-                entry->easy = easy_conn->recv_pipe->head->ptr;
-            }
+      bool remove_sock_from_hash = TRUE;
+
+      /* check if the socket to be removed serves a connection which has
+         other easy-s in a pipeline. In this case the socket should not be
+         removed. */
+      struct connectdata *easy_conn = data->easy_conn;
+      if(easy_conn) {
+        if(easy_conn->recv_pipe && easy_conn->recv_pipe->size > 1) {
+          /* the handle should not be removed from the pipe yet */
+          remove_sock_from_hash = FALSE;
+
+          /* Update the sockhash entry to instead point to the next in line
+             for the recv_pipe, or the first (in case this particular easy
+             isn't already) */
+          if(entry->easy == data) {
+            if(Curl_recvpipe_head(data, easy_conn))
+              entry->easy = easy_conn->recv_pipe->head->next->ptr;
+            else
+              entry->easy = easy_conn->recv_pipe->head->ptr;
           }
-          if(easy_conn->send_pipe  && easy_conn->send_pipe->size > 1) {
-            /* the handle should not be removed from the pipe yet */
-            remove_sock_from_hash = FALSE;
-
-            /* Update the sockhash entry to instead point to the next in line
-               for the send_pipe, or the first (in case this particular easy
-               isn't already) */
-            if(entry->easy == data) {
-              if(Curl_sendpipe_head(data, easy_conn))
-                entry->easy = easy_conn->send_pipe->head->next->ptr;
-              else
-                entry->easy = easy_conn->send_pipe->head->ptr;
-            }
+        }
+        if(easy_conn->send_pipe  && easy_conn->send_pipe->size > 1) {
+          /* the handle should not be removed from the pipe yet */
+          remove_sock_from_hash = FALSE;
+
+          /* Update the sockhash entry to instead point to the next in line
+             for the send_pipe, or the first (in case this particular easy
+             isn't already) */
+          if(entry->easy == data) {
+            if(Curl_sendpipe_head(data, easy_conn))
+              entry->easy = easy_conn->send_pipe->head->next->ptr;
+            else
+              entry->easy = easy_conn->send_pipe->head->ptr;
           }
-          /* Don't worry about overwriting recv_pipe head with send_pipe_head,
-             when action will be asked on the socket (see multi_socket()), the
-             head of the correct pipe will be taken according to the
-             action. */
         }
+        /* Don't worry about overwriting recv_pipe head with send_pipe_head,
+           when action will be asked on the socket (see multi_socket()), the
+           head of the correct pipe will be taken according to the
+           action. */
       }
-      else
-        /* just a precaution, this socket really SHOULD be in the hash already
-           but in case it isn't, we don't have to tell the app to remove it
-           either since it never got to know about it */
-        remove_sock_from_hash = FALSE;
 
       if(remove_sock_from_hash) {
         /* in this case 'entry' is always non-NULL */
@@ -2110,9 +2403,8 @@ static void singlesocket(struct Curl_multi *multi,
                            entry->socketp);
         sh_delentry(&multi->sockhash, s);
       }
-
-    }
-  }
+    } /* if sockhash entry existed */
+  } /* for loop over numsocks */
 
   memcpy(data->sockets, socks, num*sizeof(curl_socket_t));
   data->numsocks = num;
@@ -2134,8 +2426,7 @@ void Curl_multi_closed(struct connectdata *conn, curl_socket_t s)
   if(multi) {
     /* this is set if this connection is part of a handle that is added to
        a multi handle, and only then this is necessary */
-    struct Curl_sh_entry *entry =
-      Curl_hash_pick(&multi->sockhash, (char *)&s, sizeof(s));
+    struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);
 
     if(entry) {
       if(multi->socket_cb)
@@ -2154,7 +2445,7 @@ void Curl_multi_closed(struct connectdata *conn, curl_socket_t s)
 /*
  * add_next_timeout()
  *
- * Each SessionHandle has a list of timeouts. The add_next_timeout() is called
+ * Each Curl_easy has a list of timeouts. The add_next_timeout() is called
  * when it has just been removed from the splay tree because the timeout has
  * expired. This function is then to advance in the list to pick the next
  * timeout to use (skip the already expired ones) and add this node back to
@@ -2165,7 +2456,7 @@ void Curl_multi_closed(struct connectdata *conn, curl_socket_t s)
  */
 static CURLMcode add_next_timeout(struct timeval now,
                                   struct Curl_multi *multi,
-                                  struct SessionHandle *d)
+                                  struct Curl_easy *d)
 {
   struct timeval *tv = &d->state.expiretime;
   struct curl_llist *list = d->state.timeoutlist;
@@ -2174,7 +2465,7 @@ static CURLMcode add_next_timeout(struct timeval now,
   /* move over the timeout list for this specific handle and remove all
      timeouts that are now passed tense and store the next pending
      timeout in *tv */
-  for(e = list->head; e; ) {
+  for(e = list->head; e;) {
     struct curl_llist_element *n = e->next;
     long diff = curlx_tvdiff(*(struct timeval *)e->ptr, now);
     if(diff <= 0)
@@ -2213,7 +2504,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
                               int *running_handles)
 {
   CURLMcode result = CURLM_OK;
-  struct SessionHandle *data = NULL;
+  struct Curl_easy *data = NULL;
   struct Curl_tree *t;
   struct timeval now = Curl_tvnow();
 
@@ -2236,8 +2527,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
   }
   else if(s != CURL_SOCKET_TIMEOUT) {
 
-    struct Curl_sh_entry *entry =
-      Curl_hash_pick(&multi->sockhash, (char *)&s, sizeof(s));
+    struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);
 
     if(!entry)
       /* Unmatched socket, we can't act on it but we ignore this fact.  In
@@ -2342,10 +2632,9 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
 }
 
 #undef curl_multi_setopt
-CURLMcode curl_multi_setopt(CURLM *multi_handle,
+CURLMcode curl_multi_setopt(struct Curl_multi *multi,
                             CURLMoption option, ...)
 {
-  struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
   CURLMcode res = CURLM_OK;
   va_list param;
 
@@ -2413,33 +2702,32 @@ CURLMcode curl_multi_setopt(CURLM *multi_handle,
 /* we define curl_multi_socket() in the public multi.h header */
 #undef curl_multi_socket
 
-CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s,
+CURLMcode curl_multi_socket(struct Curl_multi *multi, curl_socket_t s,
                             int *running_handles)
 {
-  CURLMcode result = multi_socket((struct Curl_multi *)multi_handle, FALSE, s,
-                                  0, running_handles);
+  CURLMcode result = multi_socket(multi, FALSE, s, 0, running_handles);
   if(CURLM_OK >= result)
-    update_timer((struct Curl_multi *)multi_handle);
+    update_timer(multi);
   return result;
 }
 
-CURLMcode curl_multi_socket_action(CURLM *multi_handle, curl_socket_t s,
+CURLMcode curl_multi_socket_action(struct Curl_multi *multi, curl_socket_t s,
                                    int ev_bitmask, int *running_handles)
 {
-  CURLMcode result = multi_socket((struct Curl_multi *)multi_handle, FALSE, s,
+  CURLMcode result = multi_socket(multi, FALSE, s,
                                   ev_bitmask, running_handles);
   if(CURLM_OK >= result)
-    update_timer((struct Curl_multi *)multi_handle);
+    update_timer(multi);
   return result;
 }
 
-CURLMcode curl_multi_socket_all(CURLM *multi_handle, int *running_handles)
+CURLMcode curl_multi_socket_all(struct Curl_multi *multi, int *running_handles)
 
 {
-  CURLMcode result = multi_socket((struct Curl_multi *)multi_handle,
-                                  TRUE, CURL_SOCKET_BAD, 0, running_handles);
+  CURLMcode result = multi_socket(multi, TRUE, CURL_SOCKET_BAD, 0,
+                                  running_handles);
   if(CURLM_OK >= result)
-    update_timer((struct Curl_multi *)multi_handle);
+    update_timer(multi);
   return result;
 }
 
@@ -2478,11 +2766,9 @@ static CURLMcode multi_timeout(struct Curl_multi *multi,
   return CURLM_OK;
 }
 
-CURLMcode curl_multi_timeout(CURLM *multi_handle,
+CURLMcode curl_multi_timeout(struct Curl_multi *multi,
                              long *timeout_ms)
 {
-  struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
-
   /* First, make some basic checks that the CURLM handle is a good handle */
   if(!GOOD_MULTI_HANDLE(multi))
     return CURLM_BAD_HANDLE;
@@ -2509,7 +2795,7 @@ static int update_timer(struct Curl_multi *multi)
       multi->timer_lastcall = none;
       /* there's no timeout now but there was one previously, tell the app to
          disable it */
-      return multi->timer_cb((CURLM*)multi, -1, multi->timer_userp);
+      return multi->timer_cb(multi, -1, multi->timer_userp);
     }
     return 0;
   }
@@ -2523,7 +2809,7 @@ static int update_timer(struct Curl_multi *multi)
 
   multi->timer_lastcall = multi->timetree->key;
 
-  return multi->timer_cb((CURLM*)multi, timeout_ms, multi->timer_userp);
+  return multi->timer_cb(multi, timeout_ms, multi->timer_userp);
 }
 
 /*
@@ -2595,7 +2881,7 @@ multi_addtimeout(struct curl_llist *timeoutlist,
  *
  * Pass zero to clear all timeout values for this handle.
 */
-void Curl_expire(struct SessionHandle *data, long milli)
+void Curl_expire(struct Curl_easy *data, long milli)
 {
   struct Curl_multi *multi = data->multi;
   struct timeval *nowp = &data->state.expiretime;
@@ -2689,7 +2975,7 @@ void Curl_expire(struct SessionHandle *data, long milli)
  * time-out period to expire.
  *
  */
-void Curl_expire_latest(struct SessionHandle *data, long milli)
+void Curl_expire_latest(struct Curl_easy *data, long milli)
 {
   struct timeval *expire = &data->state.expiretime;
 
@@ -2718,15 +3004,12 @@ void Curl_expire_latest(struct SessionHandle *data, long milli)
   Curl_expire(data, milli);
 }
 
-CURLMcode curl_multi_assign(CURLM *multi_handle,
-                            curl_socket_t s, void *hashp)
+CURLMcode curl_multi_assign(struct Curl_multi *multi, curl_socket_t s,
+                            void *hashp)
 {
   struct Curl_sh_entry *there = NULL;
-  struct Curl_multi *multi = (struct Curl_multi *)multi_handle;
 
-  if(s != CURL_SOCKET_BAD)
-    there = Curl_hash_pick(&multi->sockhash, (char *)&s,
-                           sizeof(curl_socket_t));
+  there = sh_getentry(&multi->sockhash, s);
 
   if(!there)
     return CURLM_BAD_SOCKET;
@@ -2771,7 +3054,7 @@ void Curl_multi_process_pending_handles(struct Curl_multi *multi)
   struct curl_llist_element *e = multi->pending->head;
 
   while(e) {
-    struct SessionHandle *data = e->ptr;
+    struct Curl_easy *data = e->ptr;
     struct curl_llist_element *next = e->next;
 
     if(data->mstate == CURLM_STATE_CONNECT_PEND) {
@@ -2789,10 +3072,9 @@ void Curl_multi_process_pending_handles(struct Curl_multi *multi)
 }
 
 #ifdef DEBUGBUILD
-void Curl_multi_dump(const struct Curl_multi *multi_handle)
+void Curl_multi_dump(struct Curl_multi *multi)
 {
-  struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
-  struct SessionHandle *data;
+  struct Curl_easy *data;
   int i;
   fprintf(stderr, "* Multi status: %d handles, %d alive\n",
           multi->num_easy, multi->num_alive);
@@ -2804,8 +3086,7 @@ void Curl_multi_dump(const struct Curl_multi *multi_handle)
               statename[data->mstate], data->numsocks);
       for(i=0; i < data->numsocks; i++) {
         curl_socket_t s = data->sockets[i];
-        struct Curl_sh_entry *entry =
-          Curl_hash_pick(&multi->sockhash, (char *)&s, sizeof(s));
+        struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);
 
         fprintf(stderr, "%d ", (int)s);
         if(!entry) {
diff --git a/lib/multihandle.h b/lib/multihandle.h
index 6c24f50..c56b6ae 100644
--- a/lib/multihandle.h
+++ b/lib/multihandle.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -71,8 +71,8 @@ struct Curl_multi {
   long type;
 
   /* We have a doubly-linked circular list with easy handles */
-  struct SessionHandle *easyp;
-  struct SessionHandle *easylp; /* last node */
+  struct Curl_easy *easyp;
+  struct Curl_easy *easylp; /* last node */
 
   int num_easy; /* amount of entries in the linked list above. */
   int num_alive; /* amount of easy handles that are added but have not yet
@@ -80,7 +80,7 @@ struct Curl_multi {
 
   struct curl_llist *msglist; /* a list of messages from completed transfers */
 
-  struct curl_llist *pending; /* SessionHandles that are in the
+  struct curl_llist *pending; /* Curl_easys that are in the
                                  CURLM_STATE_CONNECT_PEND state */
 
   /* callback function and user data pointer for the *socket() API */
@@ -113,7 +113,7 @@ struct Curl_multi {
 
   /* This handle will be used for closing the cached connections in
      curl_multi_cleanup() */
-  struct SessionHandle *closure_handle;
+  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/multiif.h b/lib/multiif.h
index e6323ad..fd2df55 100644
--- a/lib/multiif.h
+++ b/lib/multiif.h
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -25,10 +25,10 @@
 /*
  * Prototypes for library-wide functions provided by multi.c
  */
-void Curl_expire(struct SessionHandle *data, long milli);
-void Curl_expire_latest(struct SessionHandle *data, long milli);
+void Curl_expire(struct Curl_easy *data, long milli);
+void Curl_expire_latest(struct Curl_easy *data, long milli);
 bool Curl_pipeline_wanted(const struct Curl_multi* multi, int bits);
-void Curl_multi_handlePipeBreak(struct SessionHandle *data);
+void Curl_multi_handlePipeBreak(struct Curl_easy *data);
 
 /* Internal version of curl_multi_init() accepts size parameters for the
    socket and connection hashes */
@@ -51,7 +51,7 @@ struct Curl_multi *Curl_multi_handle(int hashsize, int chashsize);
   * allow easier tracking of the internal handle's state and what sockets
   * they use. Only for research and development DEBUGBUILD enabled builds.
   */
-void Curl_multi_dump(const struct Curl_multi *multi_handle);
+void Curl_multi_dump(struct Curl_multi *multi);
 #endif
 
 void Curl_multi_process_pending_handles(struct Curl_multi *multi);
@@ -92,6 +92,6 @@ void Curl_multi_closed(struct connectdata *conn, curl_socket_t s);
  * Add a handle and move it into PERFORM state at once. For pushed streams.
  */
 CURLMcode Curl_multi_add_perform(struct Curl_multi *multi,
-                                 struct SessionHandle *data,
+                                 struct Curl_easy *data,
                                  struct connectdata *conn);
 #endif /* HEADER_CURL_MULTIIF_H */
diff --git a/lib/netrc.c b/lib/netrc.c
index 06f8ea1..46f427a 100644
--- a/lib/netrc.c
+++ b/lib/netrc.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -32,9 +32,9 @@
 #include "strequal.h"
 #include "strtok.h"
 #include "rawstr.h"
-#include "curl_printf.h"
 
-/* The last #include files should be: */
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
 #include "curl_memory.h"
 #include "memdebug.h"
 
diff --git a/lib/netrc.h b/lib/netrc.h
index a145601..d980166 100644
--- a/lib/netrc.h
+++ b/lib/netrc.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/non-ascii.c b/lib/non-ascii.c
index 6ccb449..ed14618 100644
--- a/lib/non-ascii.c
+++ b/lib/non-ascii.c
@@ -9,7 +9,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -51,7 +51,7 @@
  * Curl_convert_clone() returns a malloced copy of the source string (if
  * returning CURLE_OK), with the data converted to network format.
  */
-CURLcode Curl_convert_clone(struct SessionHandle *data,
+CURLcode Curl_convert_clone(struct Curl_easy *data,
                            const char *indata,
                            size_t insize,
                            char **outbuf)
@@ -79,7 +79,7 @@ CURLcode Curl_convert_clone(struct SessionHandle *data,
  * Curl_convert_to_network() is an internal function for performing ASCII
  * conversions on non-ASCII platforms. It convers the buffer _in place_.
  */
-CURLcode Curl_convert_to_network(struct SessionHandle *data,
+CURLcode Curl_convert_to_network(struct Curl_easy *data,
                                  char *buffer, size_t length)
 {
   if(data->set.convtonetwork) {
@@ -139,7 +139,7 @@ CURLcode Curl_convert_to_network(struct SessionHandle *data,
  * Curl_convert_from_network() is an internal function for performing ASCII
  * conversions on non-ASCII platforms. It convers the buffer _in place_.
  */
-CURLcode Curl_convert_from_network(struct SessionHandle *data,
+CURLcode Curl_convert_from_network(struct Curl_easy *data,
                                    char *buffer, size_t length)
 {
   if(data->set.convfromnetwork) {
@@ -199,7 +199,7 @@ CURLcode Curl_convert_from_network(struct SessionHandle *data,
  * Curl_convert_from_utf8() is an internal function for performing UTF-8
  * conversions on non-ASCII platforms.
  */
-CURLcode Curl_convert_from_utf8(struct SessionHandle *data,
+CURLcode Curl_convert_from_utf8(struct Curl_easy *data,
                                 char *buffer, size_t length)
 {
   if(data->set.convfromutf8) {
@@ -261,9 +261,9 @@ CURLcode Curl_convert_from_utf8(struct SessionHandle *data,
 }
 
 /*
- * Init conversion stuff for a SessionHandle
+ * Init conversion stuff for a Curl_easy
  */
-void Curl_convert_init(struct SessionHandle *data)
+void Curl_convert_init(struct Curl_easy *data)
 {
 #if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
   /* conversion descriptors for iconv calls */
@@ -276,9 +276,9 @@ void Curl_convert_init(struct SessionHandle *data)
 }
 
 /*
- * Setup conversion stuff for a SessionHandle
+ * Setup conversion stuff for a Curl_easy
  */
-void Curl_convert_setup(struct SessionHandle *data)
+void Curl_convert_setup(struct Curl_easy *data)
 {
   data->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
                                 CURL_ICONV_CODESET_OF_NETWORK);
@@ -289,10 +289,10 @@ void Curl_convert_setup(struct SessionHandle *data)
 }
 
 /*
- * Close conversion stuff for a SessionHandle
+ * Close conversion stuff for a Curl_easy
  */
 
-void Curl_convert_close(struct SessionHandle *data)
+void Curl_convert_close(struct Curl_easy *data)
 {
 #ifdef HAVE_ICONV
   /* close iconv conversion descriptors */
@@ -314,7 +314,7 @@ void Curl_convert_close(struct SessionHandle *data)
  * Curl_convert_form() is used from http.c, this converts any form items that
    need to be sent in the network encoding.  Returns CURLE_OK on success.
  */
-CURLcode Curl_convert_form(struct SessionHandle *data, struct FormData *form)
+CURLcode Curl_convert_form(struct Curl_easy *data, struct FormData *form)
 {
   CURLcode result;
 
diff --git a/lib/non-ascii.h b/lib/non-ascii.h
index 8b4b7c2..e27f1f4 100644
--- a/lib/non-ascii.h
+++ b/lib/non-ascii.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -33,22 +33,22 @@
  *
  * If no conversion was needed *outbuf may be NULL.
  */
-CURLcode Curl_convert_clone(struct SessionHandle *data,
+CURLcode Curl_convert_clone(struct Curl_easy *data,
                             const char *indata,
                             size_t insize,
                             char **outbuf);
 
-void Curl_convert_init(struct SessionHandle *data);
-void Curl_convert_setup(struct SessionHandle *data);
-void Curl_convert_close(struct SessionHandle *data);
+void Curl_convert_init(struct Curl_easy *data);
+void Curl_convert_setup(struct Curl_easy *data);
+void Curl_convert_close(struct Curl_easy *data);
 
-CURLcode Curl_convert_to_network(struct SessionHandle *data,
+CURLcode Curl_convert_to_network(struct Curl_easy *data,
                                  char *buffer, size_t length);
-CURLcode Curl_convert_from_network(struct SessionHandle *data,
+CURLcode Curl_convert_from_network(struct Curl_easy *data,
                                  char *buffer, size_t length);
-CURLcode Curl_convert_from_utf8(struct SessionHandle *data,
+CURLcode Curl_convert_from_utf8(struct Curl_easy *data,
                                  char *buffer, size_t length);
-CURLcode Curl_convert_form(struct SessionHandle *data, struct FormData *form);
+CURLcode Curl_convert_form(struct Curl_easy *data, struct FormData *form);
 #else
 #define Curl_convert_clone(a,b,c,d) ((void)a, CURLE_OK)
 #define Curl_convert_init(x) Curl_nop_stmt
diff --git a/lib/nonblock.c b/lib/nonblock.c
index 1447c87..b764278 100644
--- a/lib/nonblock.c
+++ b/lib/nonblock.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -77,7 +77,7 @@ int curlx_nonblock(curl_socket_t sockfd,    /* operate on this */
 
   /* Amiga */
   long flags = nonblock ? 1L : 0L;
-  return IoctlSocket(sockfd, FIONBIO, flags);
+  return IoctlSocket(sockfd, FIONBIO, (char *)&flags);
 
 #elif defined(HAVE_SETSOCKOPT_SO_NONBLOCK)
 
diff --git a/lib/nonblock.h b/lib/nonblock.h
index b540ae4..98cdc25 100644
--- a/lib/nonblock.h
+++ b/lib/nonblock.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/nwlib.c b/lib/nwlib.c
index bd3f27e..42b6aa0 100644
--- a/lib/nwlib.c
+++ b/lib/nwlib.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -58,26 +58,26 @@ rtag_t      gAllocTag   = (rtag_t) NULL;
 NXMutex_t   *gLibLock   = (NXMutex_t *) NULL;
 
 /* internal library function prototypes... */
-int  DisposeLibraryData( void * );
-void DisposeThreadData( void * );
-int  GetOrSetUpData( int id, libdata_t **data, libthreaddata_t **threaddata );
-
-
-int _NonAppStart( void        *NLMHandle,
-                  void        *errorScreen,
-                  const char  *cmdLine,
-                  const char  *loadDirPath,
-                  size_t      uninitializedDataLength,
-                  void        *NLMFileHandle,
-                  int         (*readRoutineP)( int conn,
-                                               void *fileHandle, size_t offset,
-                                               size_t nbytes,
-                                               size_t *bytesRead,
-                                               void *buffer ),
+int  DisposeLibraryData(void *);
+void DisposeThreadData(void *);
+int  GetOrSetUpData(int id, libdata_t **data, libthreaddata_t **threaddata);
+
+
+int _NonAppStart(void        *NLMHandle,
+                 void        *errorScreen,
+                 const char  *cmdLine,
+                 const char  *loadDirPath,
+                 size_t      uninitializedDataLength,
+                 void        *NLMFileHandle,
+                 int         (*readRoutineP)(int conn,
+                                             void *fileHandle, size_t offset,
+                                             size_t nbytes,
+                                             size_t *bytesRead,
+                                             void *buffer),
                   size_t      customDataOffset,
                   size_t      customDataSize,
                   int         messageCount,
-                  const char  **messages )
+                  const char  **messages)
 {
   NX_LOCK_INFO_ALLOC(liblock, "Per-Application Data Lock", 0);
 
@@ -132,7 +132,7 @@ int _NonAppStart( void        *NLMHandle,
  * Here we clean up any resources we allocated. Resource tags is a big part
  * of what we created, but NetWare doesn't ask us to free those.
  */
-void _NonAppStop( void )
+void _NonAppStop(void)
 {
   (void) unregister_library(gLibId);
   NXMutexFree(gLibLock);
@@ -149,13 +149,13 @@ void _NonAppStop( void )
  * we return a non-zero value. Right now, there isn't any reason not to allow
  * it.
  */
-int _NonAppCheckUnload( void )
+int _NonAppCheckUnload(void)
 {
     return 0;
 }
 
 int GetOrSetUpData(int id, libdata_t **appData,
-                   libthreaddata_t **threadData )
+                   libthreaddata_t **threadData)
 {
   int                 err;
   libdata_t           *app_data;
@@ -277,7 +277,7 @@ int GetOrSetUpData(int id, libdata_t **appData,
   return err;
 }
 
-int DisposeLibraryData( void *data )
+int DisposeLibraryData(void *data)
 {
   if(data) {
     void *tenbytes = ((libdata_t *) data)->tenbytes;
@@ -289,7 +289,7 @@ int DisposeLibraryData( void *data )
   return 0;
 }
 
-void DisposeThreadData( void *data )
+void DisposeThreadData(void *data)
 {
   if(data) {
     void *twentybytes = ((libthreaddata_t *) data)->twentybytes;
@@ -303,7 +303,7 @@ void DisposeThreadData( void *data )
 /* For native CLib-based NLM seems we can do a bit more simple. */
 #include <nwthread.h>
 
-int main ( void )
+int main (void)
 {
   /* initialize any globals here... */
 
diff --git a/lib/nwos.c b/lib/nwos.c
index 23ff2a7..385f9c8 100644
--- a/lib/nwos.c
+++ b/lib/nwos.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -26,7 +26,7 @@
 
 #ifdef __NOVELL_LIBC__
 /* For native LibC-based NLM we need to do nothing. */
-int netware_init ( void )
+int netware_init (void)
 {
   return 0;
 }
@@ -45,7 +45,7 @@ NETDB_DEFINE_CONTEXT
 #include <arpa/inet.h>
 NETINET_DEFINE_CONTEXT
 
-int netware_init ( void )
+int netware_init (void)
 {
   int rc = 0;
   unsigned int myHandle = GetNLMHandle();
@@ -72,13 +72,13 @@ int netware_init ( void )
 }
 
 /* dummy function to satisfy newer prelude */
-int __init_environment ( void )
+int __init_environment (void)
 {
   return 0;
 }
 
 /* dummy function to satisfy newer prelude */
-int __deinit_environment ( void )
+int __deinit_environment (void)
 {
   return 0;
 }
diff --git a/lib/openldap.c b/lib/openldap.c
index bee552f..4b8cfb9 100644
--- a/lib/openldap.c
+++ b/lib/openldap.c
@@ -6,11 +6,11 @@
  *                 \___|\___/|_| \_\_____|
  *
  * Copyright (C) 2010, Howard Chu, <hyc at openldap.org>
- * Copyright (C) 2011 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 2011 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -46,9 +46,8 @@
 #include "curl_ldap.h"
 #include "curl_base64.h"
 #include "connect.h"
+/* The last 3 #include files should be in this order */
 #include "curl_printf.h"
-
-/* The last #include files should be: */
 #include "curl_memory.h"
 #include "memdebug.h"
 
@@ -151,7 +150,7 @@ static CURLcode ldap_setup_connection(struct connectdata *conn)
 {
   ldapconninfo *li;
   LDAPURLDesc *lud;
-  struct SessionHandle *data=conn->data;
+  struct Curl_easy *data=conn->data;
   int rc, proto;
   CURLcode status;
 
@@ -189,7 +188,7 @@ static Sockbuf_IO ldapsb_tls;
 static CURLcode ldap_connect(struct connectdata *conn, bool *done)
 {
   ldapconninfo *li = conn->proto.generic;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   int rc, proto = LDAP_VERSION3;
   char hosturl[1024];
   char *ptr;
@@ -227,7 +226,7 @@ static CURLcode ldap_connect(struct connectdata *conn, bool *done)
 static CURLcode ldap_connecting(struct connectdata *conn, bool *done)
 {
   ldapconninfo *li = conn->proto.generic;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   LDAPMessage *msg = NULL;
   struct timeval tv = {0, 1}, *tvp;
   int rc, err;
@@ -353,7 +352,7 @@ static CURLcode ldap_do(struct connectdata *conn, bool *done)
   int rc = 0;
   LDAPURLDesc *ludp = NULL;
   int msgid;
-  struct SessionHandle *data=conn->data;
+  struct Curl_easy *data=conn->data;
 
   connkeep(conn, "OpenLDAP do");
 
@@ -416,7 +415,7 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
                          size_t len, CURLcode *err)
 {
   ldapconninfo *li = conn->proto.generic;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   ldapreqinfo *lr = data->req.protop;
   int rc, ret;
   LDAPMessage *msg = NULL;
@@ -446,6 +445,7 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
     ent = ldap_next_message(li->ld, ent)) {
     struct berval bv, *bvals, **bvp = &bvals;
     int binary = 0, msgtype;
+    CURLcode writeerr;
 
     msgtype = ldap_msgtype(ent);
     if(msgtype == LDAP_RES_SEARCH_RESULT) {
@@ -485,18 +485,24 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
       *err = CURLE_RECV_ERROR;
       return -1;
     }
-    *err = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4);
-    if(*err)
+    writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4);
+    if(writeerr) {
+      *err = writeerr;
       return -1;
+    }
 
-    *err = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val,
-                             bv.bv_len);
-    if(*err)
+    writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val,
+                                 bv.bv_len);
+    if(writeerr) {
+      *err = writeerr;
       return -1;
+    }
 
-    *err = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
-    if(*err)
+    writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
+    if(writeerr) {
+      *err = writeerr;
       return -1;
+    }
     data->req.bytecount += bv.bv_len + 5;
 
     for(rc = ldap_get_attribute_ber(li->ld, ent, ber, &bv, bvp);
@@ -513,18 +519,24 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
 
       for(i=0; bvals[i].bv_val != NULL; i++) {
         int binval = 0;
-        *err = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1);
-        if(*err)
-          return -1;
-
-        *err = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val,
-                                 bv.bv_len);
-        if(*err)
+        writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1);
+        if(writeerr) {
+          *err = writeerr;
           return -1;
+        }
 
-        *err = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)":", 1);
-        if(*err)
-          return -1;
+       writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val,
+                                    bv.bv_len);
+       if(writeerr) {
+         *err = writeerr;
+         return -1;
+       }
+
+        writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)":", 1);
+       if(writeerr) {
+         *err = writeerr;
+         return -1;
+       }
         data->req.bytecount += bv.bv_len + 2;
 
         if(!binary) {
@@ -558,47 +570,62 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
             *err = error;
             return -1;
           }
-          *err = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)": ", 2);
-          if(*err)
+          writeerr = Curl_client_write(conn, CLIENTWRITE_BODY,
+                                       (char *)": ", 2);
+          if(writeerr) {
+            *err = writeerr;
             return -1;
+          }
 
           data->req.bytecount += 2;
           if(val_b64_sz > 0) {
-            *err = Curl_client_write(conn, CLIENTWRITE_BODY, val_b64,
+            writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, val_b64,
                                      val_b64_sz);
-            if(*err)
+            if(writeerr) {
+              *err = writeerr;
               return -1;
+            }
             free(val_b64);
             data->req.bytecount += val_b64_sz;
           }
         }
         else {
-          *err = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)" ", 1);
-          if(*err)
+          writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)" ", 1);
+          if(writeerr) {
+            *err = writeerr;
             return -1;
+          }
 
-          *err = Curl_client_write(conn, CLIENTWRITE_BODY, bvals[i].bv_val,
-                                   bvals[i].bv_len);
-          if(*err)
+          writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, bvals[i].bv_val,
+                                       bvals[i].bv_len);
+          if(writeerr) {
+            *err = writeerr;
             return -1;
+          }
 
           data->req.bytecount += bvals[i].bv_len + 1;
         }
-        *err = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0);
-        if(*err)
+        writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0);
+        if(writeerr) {
+          *err = writeerr;
           return -1;
+        }
 
         data->req.bytecount++;
       }
       ber_memfree(bvals);
-      *err = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0);
-      if(*err)
+      writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0);
+      if(writeerr) {
+        *err = writeerr;
         return -1;
+      }
       data->req.bytecount++;
     }
-    *err = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0);
-    if(*err)
+    writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0);
+    if(writeerr) {
+      *err = writeerr;
       return -1;
+    }
     data->req.bytecount++;
     ber_free(ber, 0);
   }
diff --git a/lib/parsedate.c b/lib/parsedate.c
index 3e168f5..dfcf855 100644
--- a/lib/parsedate.c
+++ b/lib/parsedate.c
@@ -9,7 +9,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/parsedate.h b/lib/parsedate.h
index ade0f4f..2e59eb1 100644
--- a/lib/parsedate.h
+++ b/lib/parsedate.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/pingpong.c b/lib/pingpong.c
index 1670792..92ff84b 100644
--- a/lib/pingpong.c
+++ b/lib/pingpong.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -34,10 +34,10 @@
 #include "multiif.h"
 #include "non-ascii.h"
 #include "vtls/vtls.h"
-#include "curl_printf.h"
 
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
 #include "curl_memory.h"
-/* The last #include file should be: */
 #include "memdebug.h"
 
 #ifdef USE_PINGPONG
@@ -47,7 +47,7 @@
 long Curl_pp_state_timeout(struct pingpong *pp)
 {
   struct connectdata *conn = pp->conn;
-  struct SessionHandle *data=conn->data;
+  struct Curl_easy *data=conn->data;
   long timeout_ms; /* in milliseconds */
   long timeout2_ms; /* in milliseconds */
   long response_time= (data->set.server_response_timeout)?
@@ -85,10 +85,10 @@ CURLcode Curl_pp_statemach(struct pingpong *pp, bool block)
   int rc;
   long interval_ms;
   long timeout_ms = Curl_pp_state_timeout(pp);
-  struct SessionHandle *data=conn->data;
+  struct Curl_easy *data=conn->data;
   CURLcode result = CURLE_OK;
 
-  if(timeout_ms <=0 ) {
+  if(timeout_ms <=0) {
     failf(data, "server response timeout");
     return CURLE_OPERATION_TIMEDOUT; /* already too little time */
   }
@@ -165,7 +165,7 @@ CURLcode Curl_pp_vsendf(struct pingpong *pp,
   char *s;
   CURLcode result;
   struct connectdata *conn = pp->conn;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
 #ifdef HAVE_GSSAPI
   enum protection_level data_sec = conn->data_prot;
@@ -271,7 +271,7 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd,
   ssize_t gotbytes;
   char *ptr;
   struct connectdata *conn = pp->conn;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   char * const buf = data->state.buffer;
   CURLcode result = CURLE_OK;
 
diff --git a/lib/pingpong.h b/lib/pingpong.h
index b925ab9..2f649d5 100644
--- a/lib/pingpong.h
+++ b/lib/pingpong.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/pipeline.c b/lib/pipeline.c
index 1b38836..0ff82f0 100644
--- a/lib/pipeline.c
+++ b/lib/pipeline.c
@@ -10,7 +10,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -57,7 +57,7 @@ static void server_blacklist_llist_dtor(void *user, void *element)
   free(element);
 }
 
-bool Curl_pipeline_penalized(struct SessionHandle *data,
+bool Curl_pipeline_penalized(struct Curl_easy *data,
                              struct connectdata *conn)
 {
   if(data) {
@@ -70,7 +70,7 @@ bool Curl_pipeline_penalized(struct SessionHandle *data,
 
     /* Find the head of the recv pipe, if any */
     if(conn->recv_pipe && conn->recv_pipe->head) {
-      struct SessionHandle *recv_handle = conn->recv_pipe->head->ptr;
+      struct Curl_easy *recv_handle = conn->recv_pipe->head->ptr;
 
       recv_size = recv_handle->req.size;
 
@@ -91,7 +91,7 @@ bool Curl_pipeline_penalized(struct SessionHandle *data,
   return FALSE;
 }
 
-static CURLcode addHandleToPipeline(struct SessionHandle *data,
+static CURLcode addHandleToPipeline(struct Curl_easy *data,
                                     struct curl_llist *pipeline)
 {
   if(!Curl_llist_insert_next(pipeline, pipeline->tail, data))
@@ -100,7 +100,7 @@ static CURLcode addHandleToPipeline(struct SessionHandle *data,
 }
 
 
-CURLcode Curl_add_handle_to_pipeline(struct SessionHandle *handle,
+CURLcode Curl_add_handle_to_pipeline(struct Curl_easy *handle,
                                      struct connectdata *conn)
 {
   struct curl_llist_element *sendhead = conn->send_pipe->head;
@@ -130,7 +130,7 @@ CURLcode Curl_add_handle_to_pipeline(struct SessionHandle *handle,
    checked to update what sockets it acts on.
 
 */
-void Curl_move_handle_from_send_to_recv_pipe(struct SessionHandle *handle,
+void Curl_move_handle_from_send_to_recv_pipe(struct Curl_easy *handle,
                                              struct connectdata *conn)
 {
   struct curl_llist_element *curr;
@@ -162,7 +162,7 @@ void Curl_move_handle_from_send_to_recv_pipe(struct SessionHandle *handle,
   }
 }
 
-bool Curl_pipeline_site_blacklisted(struct SessionHandle *handle,
+bool Curl_pipeline_site_blacklisted(struct Curl_easy *handle,
                                     struct connectdata *conn)
 {
   if(handle->multi) {
@@ -254,7 +254,7 @@ CURLMcode Curl_pipeline_set_site_blacklist(char **sites,
   return CURLM_OK;
 }
 
-bool Curl_pipeline_server_blacklisted(struct SessionHandle *handle,
+bool Curl_pipeline_server_blacklisted(struct Curl_easy *handle,
                                       char *server_name)
 {
   if(handle->multi && server_name) {
@@ -299,11 +299,16 @@ CURLMcode Curl_pipeline_set_server_blacklist(char **servers,
       char *server_name;
 
       server_name = strdup(*servers);
-      if(!server_name)
+      if(!server_name) {
+        Curl_llist_destroy(new_list, NULL);
         return CURLM_OUT_OF_MEMORY;
+      }
 
-      if(!Curl_llist_insert_next(new_list, new_list->tail, server_name))
+      if(!Curl_llist_insert_next(new_list, new_list->tail, server_name)) {
+        Curl_llist_destroy(new_list, NULL);
+        Curl_safefree(server_name);
         return CURLM_OUT_OF_MEMORY;
+      }
 
       servers++;
     }
@@ -320,25 +325,26 @@ CURLMcode Curl_pipeline_set_server_blacklist(char **servers,
   return CURLM_OK;
 }
 
-static bool pipe_head(struct SessionHandle *data,
+static bool pipe_head(struct Curl_easy *data,
                       struct curl_llist *pipeline)
 {
-  struct curl_llist_element *curr = pipeline->head;
-  if(curr)
-    return (curr->ptr == data) ? TRUE : FALSE;
-
+  if(pipeline) {
+    struct curl_llist_element *curr = pipeline->head;
+    if(curr)
+      return (curr->ptr == data) ? TRUE : FALSE;
+  }
   return FALSE;
 }
 
 /* returns TRUE if the given handle is head of the recv pipe */
-bool Curl_recvpipe_head(struct SessionHandle *data,
+bool Curl_recvpipe_head(struct Curl_easy *data,
                         struct connectdata *conn)
 {
   return pipe_head(data, conn->recv_pipe);
 }
 
 /* returns TRUE if the given handle is head of the send pipe */
-bool Curl_sendpipe_head(struct SessionHandle *data,
+bool Curl_sendpipe_head(struct Curl_easy *data,
                         struct connectdata *conn)
 {
   return pipe_head(data, conn->send_pipe);
@@ -352,7 +358,7 @@ bool Curl_sendpipe_head(struct SessionHandle *data,
  * If not available, return FALSE.
  */
 
-bool Curl_pipeline_checkget_write(struct SessionHandle *data,
+bool Curl_pipeline_checkget_write(struct Curl_easy *data,
                                   struct connectdata *conn)
 {
   if(conn->bits.multiplex)
@@ -375,7 +381,7 @@ bool Curl_pipeline_checkget_write(struct SessionHandle *data,
  * If not available, return FALSE.
  */
 
-bool Curl_pipeline_checkget_read(struct SessionHandle *data,
+bool Curl_pipeline_checkget_read(struct Curl_easy *data,
                                  struct connectdata *conn)
 {
   if(conn->bits.multiplex)
@@ -412,7 +418,7 @@ void print_pipeline(struct connectdata *conn)
 {
   struct curl_llist_element *curr;
   struct connectbundle *cb_ptr;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   cb_ptr = conn->bundle;
 
diff --git a/lib/pipeline.h b/lib/pipeline.h
index bf229f1..a64f710 100644
--- a/lib/pipeline.h
+++ b/lib/pipeline.h
@@ -12,7 +12,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -23,34 +23,34 @@
  *
  ***************************************************************************/
 
-CURLcode Curl_add_handle_to_pipeline(struct SessionHandle *handle,
+CURLcode Curl_add_handle_to_pipeline(struct Curl_easy *handle,
                                      struct connectdata *conn);
-void Curl_move_handle_from_send_to_recv_pipe(struct SessionHandle *handle,
+void Curl_move_handle_from_send_to_recv_pipe(struct Curl_easy *handle,
                                              struct connectdata *conn);
-bool Curl_pipeline_penalized(struct SessionHandle *data,
+bool Curl_pipeline_penalized(struct Curl_easy *data,
                              struct connectdata *conn);
 
-bool Curl_pipeline_site_blacklisted(struct SessionHandle *handle,
+bool Curl_pipeline_site_blacklisted(struct Curl_easy *handle,
                                     struct connectdata *conn);
 
 CURLMcode Curl_pipeline_set_site_blacklist(char **sites,
                                            struct curl_llist **list_ptr);
 
-bool Curl_pipeline_server_blacklisted(struct SessionHandle *handle,
+bool Curl_pipeline_server_blacklisted(struct Curl_easy *handle,
                                       char *server_name);
 
 CURLMcode Curl_pipeline_set_server_blacklist(char **servers,
                                              struct curl_llist **list_ptr);
 
-bool Curl_pipeline_checkget_write(struct SessionHandle *data,
+bool Curl_pipeline_checkget_write(struct Curl_easy *data,
                                   struct connectdata *conn);
-bool Curl_pipeline_checkget_read(struct SessionHandle *data,
+bool Curl_pipeline_checkget_read(struct Curl_easy *data,
                                  struct connectdata *conn);
 void Curl_pipeline_leave_write(struct connectdata *conn);
 void Curl_pipeline_leave_read(struct connectdata *conn);
-bool Curl_recvpipe_head(struct SessionHandle *data,
+bool Curl_recvpipe_head(struct Curl_easy *data,
                         struct connectdata *conn);
-bool Curl_sendpipe_head(struct SessionHandle *data,
+bool Curl_sendpipe_head(struct Curl_easy *data,
                         struct connectdata *conn);
 
 #endif /* HEADER_CURL_PIPELINE_H */
diff --git a/lib/pop3.c b/lib/pop3.c
index 53510a2..591e877 100644
--- a/lib/pop3.c
+++ b/lib/pop3.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -83,9 +83,9 @@
 #include "curl_sasl.h"
 #include "curl_md5.h"
 #include "warnless.h"
+/* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_memory.h"
-/* The last #include file should be: */
 #include "memdebug.h"
 
 /* Local API functions */
@@ -214,7 +214,7 @@ static const struct Curl_handler Curl_handler_pop3s_proxy = {
 /* SASL parameters for the pop3 protocol */
 static const struct SASLproto saslpop3 = {
   "pop",                      /* The service name */
-  '+',                        /* Code received when continuation is expected */
+  '*',                        /* Code received when continuation is expected */
   '+',                        /* Code to receive upon authentication success */
   255 - 8,                    /* Maximum initial response length (no max) */
   pop3_perform_auth,          /* Send authentication command */
@@ -225,7 +225,11 @@ static const struct SASLproto saslpop3 = {
 #ifdef USE_SSL
 static void pop3_to_pop3s(struct connectdata *conn)
 {
+  /* Change the connection handler */
   conn->handler = &Curl_handler_pop3s;
+
+  /* Set the connection's upgraded to TLS flag */
+  conn->tls_upgraded = TRUE;
 }
 #else
 #define pop3_to_pop3s(x) Curl_nop_stmt
@@ -256,21 +260,29 @@ static bool pop3_endofresp(struct connectdata *conn, char *line, size_t len,
   if(pop3c->state == POP3_CAPA) {
     /* Do we have the terminating line? */
     if(len >= 1 && !memcmp(line, ".", 1))
+      /* Treat the response as a success */
       *resp = '+';
     else
+      /* Treat the response as an untagged continuation */
       *resp = '*';
 
     return TRUE;
   }
 
-  /* Do we have a command or continuation response? */
-  if((len >= 3 && !memcmp("+OK", line, 3)) ||
-     (len >= 1 && !memcmp("+", line, 1))) {
+  /* Do we have a success response? */
+  if(len >= 3 && !memcmp("+OK", line, 3)) {
     *resp = '+';
 
     return TRUE;
   }
 
+  /* Do we have a continuation response? */
+  if(len >= 1 && !memcmp("+", line, 1)) {
+    *resp = '*';
+
+    return TRUE;
+  }
+
   return FALSE; /* Nothing for us */
 }
 
@@ -585,7 +597,7 @@ static CURLcode pop3_perform_authentication(struct connectdata *conn)
 static CURLcode pop3_perform_command(struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct POP3 *pop3 = data->req.protop;
   const char *command = NULL;
 
@@ -641,7 +653,7 @@ static CURLcode pop3_state_servergreet_resp(struct connectdata *conn,
                                             pop3state instate)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct pop3_conn *pop3c = &conn->proto.pop3c;
   const char *line = data->state.buffer;
   size_t len = strlen(line);
@@ -692,7 +704,7 @@ static CURLcode pop3_state_capa_resp(struct connectdata *conn, int pop3code,
                                      pop3state instate)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct pop3_conn *pop3c = &conn->proto.pop3c;
   const char *line = data->state.buffer;
   size_t len = strlen(line);
@@ -700,7 +712,7 @@ static CURLcode pop3_state_capa_resp(struct connectdata *conn, int pop3code,
 
   (void)instate; /* no use for this yet */
 
-  /* Do we have a untagged response? */
+  /* Do we have a untagged continuation response? */
   if(pop3code == '*') {
     /* Does the server support the STLS capability? */
     if(len >= 4 && !memcmp(line, "STLS", 4))
@@ -741,8 +753,8 @@ static CURLcode pop3_state_capa_resp(struct connectdata *conn, int pop3code,
           wordlen++;
 
         /* Test the word for a matching authentication mechanism */
-        if((mechbit = Curl_sasl_decode_mech(line, wordlen, &llen)) &&
-           llen == wordlen)
+        mechbit = Curl_sasl_decode_mech(line, wordlen, &llen);
+        if(mechbit && llen == wordlen)
           pop3c->sasl.authmechs |= mechbit;
 
         line += wordlen;
@@ -783,7 +795,7 @@ static CURLcode pop3_state_starttls_resp(struct connectdata *conn,
                                          pop3state instate)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   (void)instate; /* no use for this yet */
 
@@ -807,7 +819,7 @@ static CURLcode pop3_state_auth_resp(struct connectdata *conn,
                                      pop3state instate)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct pop3_conn *pop3c = &conn->proto.pop3c;
   saslprogress progress;
 
@@ -847,7 +859,7 @@ static CURLcode pop3_state_apop_resp(struct connectdata *conn, int pop3code,
                                      pop3state instate)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   (void)instate; /* no use for this yet */
 
@@ -868,7 +880,7 @@ static CURLcode pop3_state_user_resp(struct connectdata *conn, int pop3code,
                                      pop3state instate)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   (void)instate; /* no use for this yet */
 
@@ -891,7 +903,7 @@ static CURLcode pop3_state_pass_resp(struct connectdata *conn, int pop3code,
                                      pop3state instate)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   (void)instate; /* no use for this yet */
 
@@ -912,7 +924,7 @@ static CURLcode pop3_state_command_resp(struct connectdata *conn,
                                         pop3state instate)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct POP3 *pop3 = data->req.protop;
   struct pop3_conn *pop3c = &conn->proto.pop3c;
   struct pingpong *pp = &pop3c->pp;
@@ -1066,12 +1078,12 @@ static CURLcode pop3_block_statemach(struct connectdata *conn)
   return result;
 }
 
-/* Allocate and initialize the POP3 struct for the current SessionHandle if
+/* Allocate and initialize the POP3 struct for the current Curl_easy if
    required */
 static CURLcode pop3_init(struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct POP3 *pop3;
 
   pop3 = data->req.protop = calloc(sizeof(struct POP3), 1);
@@ -1148,16 +1160,12 @@ static CURLcode pop3_done(struct connectdata *conn, CURLcode status,
                           bool premature)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct POP3 *pop3 = data->req.protop;
 
   (void)premature;
 
   if(!pop3)
-    /* When the easy handle is removed from the multi interface while libcurl
-       is still trying to resolve the host name, the POP3 struct is not yet
-       initialized. However, the removal action calls Curl_done() which in
-       turn calls this function, so we simply return success. */
     return CURLE_OK;
 
   if(status) {
@@ -1316,7 +1324,7 @@ static CURLcode pop3_regular_transfer(struct connectdata *conn,
 {
   CURLcode result = CURLE_OK;
   bool connected = FALSE;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   /* Make sure size is unknown at this point */
   data->req.size = -1;
@@ -1339,13 +1347,17 @@ static CURLcode pop3_regular_transfer(struct connectdata *conn,
 
 static CURLcode pop3_setup_connection(struct connectdata *conn)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   /* Initialise the POP3 layer */
   CURLcode result = pop3_init(conn);
   if(result)
     return result;
 
+  /* Clear the TLS upgraded flag */
+  conn->tls_upgraded = FALSE;
+
+  /* Set up the proxy if necessary */
   if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
     /* Unless we have asked to tunnel POP3 operations through the proxy, we
        switch and use HTTP operations only */
@@ -1442,7 +1454,7 @@ static CURLcode pop3_parse_url_options(struct connectdata *conn)
 static CURLcode pop3_parse_url_path(struct connectdata *conn)
 {
   /* The POP3 struct is already initialised in pop3_connect() */
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct POP3 *pop3 = data->req.protop;
   const char *path = data->state.path;
 
@@ -1459,7 +1471,7 @@ static CURLcode pop3_parse_url_path(struct connectdata *conn)
 static CURLcode pop3_parse_custom_request(struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct POP3 *pop3 = data->req.protop;
   const char *custom = data->set.str[STRING_CUSTOMREQUEST];
 
@@ -1481,7 +1493,7 @@ CURLcode Curl_pop3_write(struct connectdata *conn, char *str, size_t nread)
 {
   /* This code could be made into a special function in the handler struct */
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct SingleRequest *k = &data->req;
 
   struct pop3_conn *pop3c = &conn->proto.pop3c;
diff --git a/lib/pop3.h b/lib/pop3.h
index 7bc53aa..a8e697c 100644
--- a/lib/pop3.h
+++ b/lib/pop3.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -45,9 +45,9 @@ typedef enum {
   POP3_LAST          /* never used */
 } pop3state;
 
-/* This POP3 struct is used in the SessionHandle. All POP3 data that is
+/* This POP3 struct is used in the Curl_easy. All POP3 data that is
    connection-oriented must be in pop3_conn to properly deal with the fact that
-   perhaps the SessionHandle is changed between the times the connection is
+   perhaps the Curl_easy is changed between the times the connection is
    used. */
 struct POP3 {
   curl_pp_transfer transfer;
diff --git a/lib/progress.c b/lib/progress.c
index b46e274..760ca1c 100644
--- a/lib/progress.c
+++ b/lib/progress.c
@@ -9,7 +9,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -133,7 +133,7 @@ static char *max5data(curl_off_t bytes, char *max5)
 int Curl_pgrsDone(struct connectdata *conn)
 {
   int rc;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   data->progress.lastshow=0;
   rc = Curl_pgrsUpdate(conn); /* the final (forced) update */
   if(rc)
@@ -150,7 +150,7 @@ int Curl_pgrsDone(struct connectdata *conn)
 }
 
 /* reset all times except redirect, and reset the known transfer sizes */
-void Curl_pgrsResetTimesSizes(struct SessionHandle *data)
+void Curl_pgrsResetTimesSizes(struct Curl_easy *data)
 {
   data->progress.t_nslookup = 0.0;
   data->progress.t_connect = 0.0;
@@ -161,7 +161,7 @@ void Curl_pgrsResetTimesSizes(struct SessionHandle *data)
   Curl_pgrsSetUploadSize(data, -1);
 }
 
-void Curl_pgrsTime(struct SessionHandle *data, timerid timer)
+void Curl_pgrsTime(struct Curl_easy *data, timerid timer)
 {
   struct timeval now = Curl_tvnow();
 
@@ -212,7 +212,7 @@ void Curl_pgrsTime(struct SessionHandle *data, timerid timer)
   }
 }
 
-void Curl_pgrsStartNow(struct SessionHandle *data)
+void Curl_pgrsStartNow(struct Curl_easy *data)
 {
   data->progress.speeder_c = 0; /* reset the progress meter display */
   data->progress.start = Curl_tvnow();
@@ -220,17 +220,17 @@ void Curl_pgrsStartNow(struct SessionHandle *data)
   data->progress.flags &= PGRS_HIDE|PGRS_HEADERS_OUT;
 }
 
-void Curl_pgrsSetDownloadCounter(struct SessionHandle *data, curl_off_t size)
+void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size)
 {
   data->progress.downloaded = size;
 }
 
-void Curl_pgrsSetUploadCounter(struct SessionHandle *data, curl_off_t size)
+void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size)
 {
   data->progress.uploaded = size;
 }
 
-void Curl_pgrsSetDownloadSize(struct SessionHandle *data, curl_off_t size)
+void Curl_pgrsSetDownloadSize(struct Curl_easy *data, curl_off_t size)
 {
   if(size >= 0) {
     data->progress.size_dl = size;
@@ -242,7 +242,7 @@ void Curl_pgrsSetDownloadSize(struct SessionHandle *data, curl_off_t size)
   }
 }
 
-void Curl_pgrsSetUploadSize(struct SessionHandle *data, curl_off_t size)
+void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size)
 {
   if(size >= 0) {
     data->progress.size_ul = size;
@@ -269,7 +269,7 @@ int Curl_pgrsUpdate(struct connectdata *conn)
   curl_off_t total_transfer;
   curl_off_t total_expected_transfer;
   curl_off_t timespent;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   int nowindex = data->progress.speeder_c% CURR_TIME;
   int checkindex;
   int countindex; /* amount of seconds stored in the speeder array */
diff --git a/lib/progress.h b/lib/progress.h
index a1e6f1a..a77b7ce 100644
--- a/lib/progress.h
+++ b/lib/progress.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -41,14 +41,14 @@ typedef enum {
 } timerid;
 
 int Curl_pgrsDone(struct connectdata *);
-void Curl_pgrsStartNow(struct SessionHandle *data);
-void Curl_pgrsSetDownloadSize(struct SessionHandle *data, curl_off_t size);
-void Curl_pgrsSetUploadSize(struct SessionHandle *data, curl_off_t size);
-void Curl_pgrsSetDownloadCounter(struct SessionHandle *data, curl_off_t size);
-void Curl_pgrsSetUploadCounter(struct SessionHandle *data, curl_off_t size);
+void Curl_pgrsStartNow(struct Curl_easy *data);
+void Curl_pgrsSetDownloadSize(struct Curl_easy *data, curl_off_t size);
+void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size);
+void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size);
+void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size);
 int Curl_pgrsUpdate(struct connectdata *);
-void Curl_pgrsResetTimesSizes(struct SessionHandle *data);
-void Curl_pgrsTime(struct SessionHandle *data, timerid timer);
+void Curl_pgrsResetTimesSizes(struct Curl_easy *data);
+void Curl_pgrsTime(struct Curl_easy *data, timerid timer);
 
 
 /* Don't show progress for sizes smaller than: */
diff --git a/lib/rawstr.c b/lib/rawstr.c
index e27dac4..5665ebd 100644
--- a/lib/rawstr.c
+++ b/lib/rawstr.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -28,6 +28,10 @@
    its behavior is altered by the current locale. */
 char Curl_raw_toupper(char in)
 {
+#if !defined(CURL_DOES_CONVERSIONS)
+  if(in >= 'a' && in <= 'z')
+    return (char)('A' + in - 'a');
+#else
   switch (in) {
   case 'a':
     return 'A';
@@ -82,13 +86,15 @@ char Curl_raw_toupper(char in)
   case 'z':
     return 'Z';
   }
+#endif
+
   return in;
 }
 
 /*
  * Curl_raw_equal() is for doing "raw" case insensitive strings. This is meant
  * to be locale independent and only compare strings we know are safe for
- * this.  See http://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for
+ * this.  See https://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for
  * some further explanation to why this function is necessary.
  *
  * The function is capable of comparing a-z case insensitively even for
diff --git a/lib/rawstr.h b/lib/rawstr.h
index b491460..4af00f1 100644
--- a/lib/rawstr.h
+++ b/lib/rawstr.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/rtsp.c b/lib/rtsp.c
index c30afd3..27955bc 100644
--- a/lib/rtsp.c
+++ b/lib/rtsp.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -36,9 +36,8 @@
 #include "rawstr.h"
 #include "select.h"
 #include "connect.h"
+/* The last 3 #include files should be in this order */
 #include "curl_printf.h"
-
-/* The last #include files should be: */
 #include "curl_memory.h"
 #include "memdebug.h"
 
@@ -74,7 +73,7 @@ static int rtsp_getsock_do(struct connectdata *conn,
  *        data is parsed and k->str is moved up
  * readmore: whether or not the RTP parser needs more data right away
  */
-static CURLcode rtsp_rtp_readwrite(struct SessionHandle *data,
+static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data,
                                    struct connectdata *conn,
                                    ssize_t *nread,
                                    bool *readmore);
@@ -159,7 +158,7 @@ bool Curl_rtsp_connisdead(struct connectdata *check)
   }
   else if((sval & CURL_CSELECT_IN) && check->data) {
     /* readable with no error. could be closed or could be alive but we can
-       only check if we have a proper SessionHandle for the connection */
+       only check if we have a proper Curl_easy for the connection */
     curl_socket_t connectinfo = Curl_getconnectinfo(check->data, &check);
     if(connectinfo != CURL_SOCKET_BAD)
       ret_val = FALSE;
@@ -171,7 +170,7 @@ bool Curl_rtsp_connisdead(struct connectdata *check)
 static CURLcode rtsp_connect(struct connectdata *conn, bool *done)
 {
   CURLcode httpStatus;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   httpStatus = Curl_http_connect(conn, done);
 
@@ -197,7 +196,7 @@ static CURLcode rtsp_disconnect(struct connectdata *conn, bool dead)
 static CURLcode rtsp_done(struct connectdata *conn,
                           CURLcode status, bool premature)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct RTSP *rtsp = data->req.protop;
   CURLcode httpStatus;
   long CSeq_sent;
@@ -231,7 +230,7 @@ static CURLcode rtsp_done(struct connectdata *conn,
 
 static CURLcode rtsp_do(struct connectdata *conn, bool *done)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   CURLcode result=CURLE_OK;
   Curl_RtspReq rtspreq = data->set.rtspreq;
   struct RTSP *rtsp = data->req.protop;
@@ -249,6 +248,8 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
   const char *p_stream_uri = NULL;
   const char *p_transport = NULL;
   const char *p_uagent = NULL;
+  const char *p_proxyuserpwd = NULL;
+  const char *p_userpwd = NULL;
 
   *done = TRUE;
 
@@ -326,7 +327,6 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
     return CURLE_BAD_FUNCTION_ARGUMENT;
   }
 
-  /* TODO: auth? */
   /* TODO: proxy? */
 
   /* Stream URI. Default to server '*' if not specified */
@@ -392,6 +392,14 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
     p_uagent = conn->allocptr.uagent;
   }
 
+  /* setup the authentication headers */
+  result = Curl_http_output_auth(conn, p_request, p_stream_uri, FALSE);
+  if(result)
+    return result;
+
+  p_proxyuserpwd = conn->allocptr.proxyuserpwd;
+  p_userpwd = conn->allocptr.userpwd;
+
   /* Referrer */
   Curl_safefree(conn->allocptr.ref);
   if(data->change.referer && !Curl_checkheaders(conn, "Referer:"))
@@ -464,13 +472,25 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
                             "%s" /* range */
                             "%s" /* referrer */
                             "%s" /* user-agent */
+                            "%s" /* proxyuserpwd */
+                            "%s" /* userpwd */
                             ,
                             p_transport ? p_transport : "",
                             p_accept ? p_accept : "",
                             p_accept_encoding ? p_accept_encoding : "",
                             p_range ? p_range : "",
                             p_referrer ? p_referrer : "",
-                            p_uagent ? p_uagent : "");
+                            p_uagent ? p_uagent : "",
+                            p_proxyuserpwd ? p_proxyuserpwd : "",
+                            p_userpwd ? p_userpwd : "");
+
+  /*
+   * Free userpwd now --- cannot reuse this for Negotiate and possibly NTLM
+   * with basic and digest, it will be freed anyway by the next request
+   */
+  Curl_safefree (conn->allocptr.userpwd);
+  conn->allocptr.userpwd = NULL;
+
   if(result)
     return result;
 
@@ -580,7 +600,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
 }
 
 
-static CURLcode rtsp_rtp_readwrite(struct SessionHandle *data,
+static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data,
                                    struct connectdata *conn,
                                    ssize_t *nread,
                                    bool *readmore) {
@@ -711,7 +731,7 @@ static CURLcode rtsp_rtp_readwrite(struct SessionHandle *data,
 static
 CURLcode rtp_client_write(struct connectdata *conn, char *ptr, size_t len)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   size_t wrote;
   curl_write_callback writeit;
 
@@ -739,7 +759,7 @@ CURLcode rtp_client_write(struct connectdata *conn, char *ptr, size_t len)
 CURLcode Curl_rtsp_parseheader(struct connectdata *conn,
                                char *header)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   long CSeq = 0;
 
   if(checkprefix("CSeq:", header)) {
diff --git a/lib/rtsp.h b/lib/rtsp.h
index 3ffa70c..5a8d555 100644
--- a/lib/rtsp.h
+++ b/lib/rtsp.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/security.c b/lib/security.c
index 014bbf1..a0bcaea 100644
--- a/lib/security.c
+++ b/lib/security.c
@@ -476,7 +476,7 @@ Curl_sec_request_prot(struct connectdata *conn, const char *level)
 static CURLcode choose_mech(struct connectdata *conn)
 {
   int ret;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   void *tmp_allocation;
   const struct Curl_sec_client_mech *mech = &Curl_krb5_client_mech;
 
diff --git a/lib/select.c b/lib/select.c
index 24dc5fd..abf55d8 100644
--- a/lib/select.c
+++ b/lib/select.c
@@ -9,7 +9,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -316,15 +316,15 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */
        curl_socket_t is unsigned in such cases and thus -1 is the largest
        value).
     */
+#ifdef USE_WINSOCK
     r = select((int)maxfd + 1,
-#ifndef USE_WINSOCK
-               &fds_read,
-               &fds_write,
-#else
                fds_read.fd_count ? &fds_read : NULL,
                fds_write.fd_count ? &fds_write : NULL,
-#endif
                &fds_err, ptimeout);
+#else
+    r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout);
+#endif
+
     if(r != -1)
       break;
     error = SOCKERRNO;
@@ -505,19 +505,19 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms)
       pending_tv.tv_sec = 0;
       pending_tv.tv_usec = 0;
     }
+
+#ifdef USE_WINSOCK
     r = select((int)maxfd + 1,
-#ifndef USE_WINSOCK
-               &fds_read, &fds_write, &fds_err,
-#else
                /* WinSock select() can't handle fd_sets with zero bits set, so
                   don't give it such arguments.  See the comment about this in
                   Curl_check_socket().
                */
                fds_read.fd_count ? &fds_read : NULL,
                fds_write.fd_count ? &fds_write : NULL,
-               fds_err.fd_count ? &fds_err : NULL,
+               fds_err.fd_count ? &fds_err : NULL, ptimeout);
+#else
+    r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout);
 #endif
-               ptimeout);
     if(r != -1)
       break;
     error = SOCKERRNO;
diff --git a/lib/select.h b/lib/select.h
index c00afe1..695bb69 100644
--- a/lib/select.h
+++ b/lib/select.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/sendf.c b/lib/sendf.c
index 5f39d1f..2101797 100644
--- a/lib/sendf.c
+++ b/lib/sendf.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -31,10 +31,11 @@
 #include "ssh.h"
 #include "multiif.h"
 #include "non-ascii.h"
-#include "curl_printf.h"
 #include "strerror.h"
+#include "select.h"
 
-/* The last #include files should be: */
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
 #include "curl_memory.h"
 #include "memdebug.h"
 
@@ -45,7 +46,7 @@
  * blocks of data.  Remaining, bare CRs are changed to LFs.  The possibly new
  * size of the data is returned.
  */
-static size_t convert_lineends(struct SessionHandle *data,
+static size_t convert_lineends(struct Curl_easy *data,
                                char *startPtr, size_t size)
 {
   char *inPtr, *outPtr;
@@ -120,9 +121,93 @@ static size_t convert_lineends(struct SessionHandle *data,
 }
 #endif /* CURL_DO_LINEEND_CONV */
 
+#ifdef USE_RECV_BEFORE_SEND_WORKAROUND
+static void pre_receive_plain(struct connectdata *conn, int num)
+{
+  const curl_socket_t sockfd = conn->sock[num];
+  struct postponed_data * const psnd = &(conn->postponed[num]);
+  size_t bytestorecv = psnd->allocated_size - psnd->recv_size;
+  /* WinSock will destroy unread received data if send() is
+     failed.
+     To avoid lossage of received data, recv() must be
+     performed before every send() if any incoming data is
+     available. However, skip this, if buffer is already full. */
+  if((conn->handler->protocol&PROTO_FAMILY_HTTP) != 0 &&
+     conn->recv[num] == Curl_recv_plain &&
+     (!psnd->buffer || bytestorecv)) {
+    const int readymask = Curl_socket_check(sockfd, CURL_SOCKET_BAD,
+                                            CURL_SOCKET_BAD, 0);
+    if(readymask != -1 && (readymask & CURL_CSELECT_IN) != 0) {
+      /* Have some incoming data */
+      if(!psnd->buffer) {
+        /* Use buffer double default size for intermediate buffer */
+        psnd->allocated_size = 2 * BUFSIZE;
+        psnd->buffer = malloc(psnd->allocated_size);
+        psnd->recv_size = 0;
+        psnd->recv_processed = 0;
+#ifdef DEBUGBUILD
+        psnd->bindsock = sockfd; /* Used only for DEBUGASSERT */
+#endif /* DEBUGBUILD */
+        bytestorecv = psnd->allocated_size;
+      }
+      if(psnd->buffer) {
+        ssize_t recvedbytes;
+        DEBUGASSERT(psnd->bindsock == sockfd);
+        recvedbytes = sread(sockfd, psnd->buffer + psnd->recv_size,
+                            bytestorecv);
+        if(recvedbytes > 0)
+          psnd->recv_size += recvedbytes;
+      }
+      else
+        psnd->allocated_size = 0;
+    }
+  }
+}
+
+static ssize_t get_pre_recved(struct connectdata *conn, int num, char *buf,
+                              size_t len)
+{
+  struct postponed_data * const psnd = &(conn->postponed[num]);
+  size_t copysize;
+  if(!psnd->buffer)
+    return 0;
+
+  DEBUGASSERT(psnd->allocated_size > 0);
+  DEBUGASSERT(psnd->recv_size <= psnd->allocated_size);
+  DEBUGASSERT(psnd->recv_processed <= psnd->recv_size);
+  /* Check and process data that already received and storied in internal
+     intermediate buffer */
+  if(psnd->recv_size > psnd->recv_processed) {
+    DEBUGASSERT(psnd->bindsock == conn->sock[num]);
+    copysize = CURLMIN(len, psnd->recv_size - psnd->recv_processed);
+    memcpy(buf, psnd->buffer + psnd->recv_processed, copysize);
+    psnd->recv_processed += copysize;
+  }
+  else
+    copysize = 0; /* buffer was allocated, but nothing was received */
+
+  /* Free intermediate buffer if it has no unprocessed data */
+  if(psnd->recv_processed == psnd->recv_size) {
+    free(psnd->buffer);
+    psnd->buffer = NULL;
+    psnd->allocated_size = 0;
+    psnd->recv_size = 0;
+    psnd->recv_processed = 0;
+#ifdef DEBUGBUILD
+    psnd->bindsock = CURL_SOCKET_BAD;
+#endif /* DEBUGBUILD */
+  }
+  return (ssize_t)copysize;
+}
+#else  /* ! USE_RECV_BEFORE_SEND_WORKAROUND */
+/* Use "do-nothing" macros instead of functions when workaround not used */
+#define pre_receive_plain(c,n) do {} WHILE_FALSE
+#define get_pre_recved(c,n,b,l) 0
+#endif /* ! USE_RECV_BEFORE_SEND_WORKAROUND */
+
 /* Curl_infof() is for info message along the way */
 
-void Curl_infof(struct SessionHandle *data, const char *fmt, ...)
+void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
 {
   if(data && data->set.verbose) {
     va_list ap;
@@ -140,7 +225,7 @@ void Curl_infof(struct SessionHandle *data, const char *fmt, ...)
  * The message SHALL NOT include any LF or CR.
  */
 
-void Curl_failf(struct SessionHandle *data, const char *fmt, ...)
+void Curl_failf(struct Curl_easy *data, const char *fmt, ...)
 {
   va_list ap;
   size_t len;
@@ -168,7 +253,7 @@ void Curl_failf(struct SessionHandle *data, const char *fmt, ...)
 CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn,
                     const char *fmt, ...)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   ssize_t bytes_written;
   size_t write_len;
   CURLcode result = CURLE_OK;
@@ -254,7 +339,23 @@ ssize_t Curl_send_plain(struct connectdata *conn, int num,
                         const void *mem, size_t len, CURLcode *code)
 {
   curl_socket_t sockfd = conn->sock[num];
-  ssize_t bytes_written = swrite(sockfd, mem, len);
+  ssize_t bytes_written;
+  /* WinSock will destroy unread received data if send() is
+     failed.
+     To avoid lossage of received data, recv() must be
+     performed before every send() if any incoming data is
+     available. */
+  pre_receive_plain(conn, num);
+
+#ifdef MSG_FASTOPEN /* Linux */
+  if(conn->bits.tcp_fastopen) {
+    bytes_written = sendto(sockfd, mem, len, MSG_FASTOPEN,
+                           conn->ip_addr->ai_addr, conn->ip_addr->ai_addrlen);
+    conn->bits.tcp_fastopen = FALSE;
+  }
+  else
+#endif
+    bytes_written = swrite(sockfd, mem, len);
 
   *code = CURLE_OK;
   if(-1 == bytes_written) {
@@ -268,7 +369,8 @@ ssize_t Curl_send_plain(struct connectdata *conn, int num,
       /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
          due to its inability to send off data without blocking. We therefor
          treat both error codes the same here */
-      (EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err)
+      (EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err) ||
+      (EINPROGRESS == err)
 #endif
       ) {
       /* this is just a case of EWOULDBLOCK */
@@ -311,7 +413,16 @@ ssize_t Curl_recv_plain(struct connectdata *conn, int num, char *buf,
                         size_t len, CURLcode *code)
 {
   curl_socket_t sockfd = conn->sock[num];
-  ssize_t nread = sread(sockfd, buf, len);
+  ssize_t nread;
+  /* Check and return data that already received and storied in internal
+     intermediate buffer */
+  nread = get_pre_recved(conn, num, buf, len);
+  if(nread > 0) {
+    *code = CURLE_OK;
+    return nread;
+  }
+
+  nread = sread(sockfd, buf, len);
 
   *code = CURLE_OK;
   if(-1 == nread) {
@@ -341,7 +452,7 @@ ssize_t Curl_recv_plain(struct connectdata *conn, int num, char *buf,
   return nread;
 }
 
-static CURLcode pausewrite(struct SessionHandle *data,
+static CURLcode pausewrite(struct Curl_easy *data,
                            int type, /* what type of data */
                            const char *ptr,
                            size_t len)
@@ -380,7 +491,7 @@ CURLcode Curl_client_chop_write(struct connectdata *conn,
                                 char * ptr,
                                 size_t len)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   curl_write_callback writeheader = NULL;
   curl_write_callback writebody = NULL;
 
@@ -487,7 +598,7 @@ CURLcode Curl_client_write(struct connectdata *conn,
                            char *ptr,
                            size_t len)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   if(0 == len)
     len = strlen(ptr);
@@ -520,11 +631,13 @@ CURLcode Curl_read_plain(curl_socket_t sockfd,
 
   if(-1 == nread) {
     int err = SOCKERRNO;
+    int return_error;
 #ifdef USE_WINSOCK
-    if(WSAEWOULDBLOCK == err)
+    return_error = WSAEWOULDBLOCK == err;
 #else
-    if((EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err))
+    return_error = EWOULDBLOCK == err || EAGAIN == err || EINTR == err;
 #endif
+    if(return_error)
       return CURLE_AGAIN;
     else
       return CURLE_RECV_ERROR;
@@ -551,7 +664,10 @@ CURLcode Curl_read(struct connectdata *conn, /* connection data */
   ssize_t nread = 0;
   size_t bytesfromsocket = 0;
   char *buffertofill = NULL;
-  bool pipelining = Curl_pipeline_wanted(conn->data->multi, CURLPIPE_HTTP1);
+
+  /* if HTTP/1 pipelining is both wanted and possible */
+  bool pipelining = Curl_pipeline_wanted(conn->data->multi, CURLPIPE_HTTP1) &&
+    (conn->bundle->multiuse == BUNDLE_PIPELINING);
 
   /* Set 'num' to 0 or 1, depending on which socket that has been sent here.
      If it is the second socket, we set num to 1. Otherwise to 0. This lets
@@ -602,7 +718,7 @@ CURLcode Curl_read(struct connectdata *conn, /* connection data */
 }
 
 /* return 0 on success */
-static int showit(struct SessionHandle *data, curl_infotype type,
+static int showit(struct Curl_easy *data, curl_infotype type,
                   char *ptr, size_t size)
 {
   static const char s_infotype[CURLINFO_END][3] = {
@@ -671,7 +787,7 @@ static int showit(struct SessionHandle *data, curl_infotype type,
   return 0;
 }
 
-int Curl_debug(struct SessionHandle *data, curl_infotype type,
+int Curl_debug(struct Curl_easy *data, curl_infotype type,
                char *ptr, size_t size,
                struct connectdata *conn)
 {
diff --git a/lib/sendf.h b/lib/sendf.h
index 86f06cf..a951a0b 100644
--- a/lib/sendf.h
+++ b/lib/sendf.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -26,8 +26,8 @@
 
 CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *,
                     const char *fmt, ...);
-void Curl_infof(struct SessionHandle *, const char *fmt, ...);
-void Curl_failf(struct SessionHandle *, const char *fmt, ...);
+void Curl_infof(struct Curl_easy *, const char *fmt, ...);
+void Curl_failf(struct Curl_easy *, const char *fmt, ...);
 
 #if defined(CURL_DISABLE_VERBOSE_STRINGS)
 
@@ -84,7 +84,7 @@ CURLcode Curl_write_plain(struct connectdata *conn,
                           ssize_t *written);
 
 /* the function used to output verbose information */
-int Curl_debug(struct SessionHandle *handle, curl_infotype type,
+int Curl_debug(struct Curl_easy *handle, curl_infotype type,
                char *data, size_t size,
                struct connectdata *conn);
 
diff --git a/lib/setup-os400.h b/lib/setup-os400.h
index fae8567..e32b72f 100644
--- a/lib/setup-os400.h
+++ b/lib/setup-os400.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/setup-vms.h b/lib/setup-vms.h
index 520a35d..4b78e0b 100644
--- a/lib/setup-vms.h
+++ b/lib/setup-vms.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/share.c b/lib/share.c
index 1720248..5b3957f 100644
--- a/lib/share.c
+++ b/lib/share.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -31,7 +31,7 @@
 /* The last #include file should be: */
 #include "memdebug.h"
 
-CURLSH *
+struct Curl_share *
 curl_share_init(void)
 {
   struct Curl_share *share = calloc(1, sizeof(struct Curl_share));
@@ -49,9 +49,8 @@ curl_share_init(void)
 
 #undef curl_share_setopt
 CURLSHcode
-curl_share_setopt(CURLSH *sh, CURLSHoption option, ...)
+curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...)
 {
-  struct Curl_share *share = (struct Curl_share *)sh;
   va_list param;
   int type;
   curl_lock_function lockfunc;
@@ -71,14 +70,14 @@ curl_share_setopt(CURLSH *sh, CURLSHoption option, ...)
     /* this is a type this share will share */
     type = va_arg(param, int);
     share->specifier |= (1<<type);
-    switch( type ) {
+    switch(type) {
     case CURL_LOCK_DATA_DNS:
       break;
 
     case CURL_LOCK_DATA_COOKIE:
 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
       if(!share->cookies) {
-        share->cookies = Curl_cookie_init(NULL, NULL, NULL, TRUE );
+        share->cookies = Curl_cookie_init(NULL, NULL, NULL, TRUE);
         if(!share->cookies)
           res = CURLSHE_NOMEM;
       }
@@ -114,7 +113,7 @@ curl_share_setopt(CURLSH *sh, CURLSHoption option, ...)
     /* this is a type this share will no longer share */
     type = va_arg(param, int);
     share->specifier &= ~(1<<type);
-    switch( type ) {
+    switch(type) {
     case CURL_LOCK_DATA_DNS:
       break;
 
@@ -172,10 +171,8 @@ curl_share_setopt(CURLSH *sh, CURLSHoption option, ...)
 }
 
 CURLSHcode
-curl_share_cleanup(CURLSH *sh)
+curl_share_cleanup(struct Curl_share *share)
 {
-  struct Curl_share *share = (struct Curl_share *)sh;
-
   if(share == NULL)
     return CURLSHE_INVALID;
 
@@ -213,7 +210,7 @@ curl_share_cleanup(CURLSH *sh)
 
 
 CURLSHcode
-Curl_share_lock(struct SessionHandle *data, curl_lock_data type,
+Curl_share_lock(struct Curl_easy *data, curl_lock_data type,
                 curl_lock_access accesstype)
 {
   struct Curl_share *share = data->share;
@@ -231,7 +228,7 @@ Curl_share_lock(struct SessionHandle *data, curl_lock_data type,
 }
 
 CURLSHcode
-Curl_share_unlock(struct SessionHandle *data, curl_lock_data type)
+Curl_share_unlock(struct Curl_easy *data, curl_lock_data type)
 {
   struct Curl_share *share = data->share;
 
diff --git a/lib/share.h b/lib/share.h
index 8e6629b..e689ff2 100644
--- a/lib/share.h
+++ b/lib/share.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -54,8 +54,8 @@ struct Curl_share {
   long sessionage;
 };
 
-CURLSHcode Curl_share_lock (struct SessionHandle *, curl_lock_data,
+CURLSHcode Curl_share_lock (struct Curl_easy *, curl_lock_data,
                             curl_lock_access);
-CURLSHcode Curl_share_unlock (struct SessionHandle *, curl_lock_data);
+CURLSHcode Curl_share_unlock (struct Curl_easy *, curl_lock_data);
 
 #endif /* HEADER_CURL_SHARE_H */
diff --git a/lib/sigpipe.h b/lib/sigpipe.h
index e8d2acd..800f9d3 100644
--- a/lib/sigpipe.h
+++ b/lib/sigpipe.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -38,10 +38,10 @@ struct sigpipe_ignore {
  * internals, and then sigpipe_restore() will restore the situation when we
  * return from libcurl again.
  */
-static void sigpipe_ignore(struct SessionHandle *data,
+static void sigpipe_ignore(struct Curl_easy *data,
                            struct sigpipe_ignore *ig)
 {
-  /* get a local copy of no_signal because the SessionHandle might not be
+  /* get a local copy of no_signal because the Curl_easy might not be
      around when we restore */
   ig->no_signal = data->set.no_signal;
   if(!data->set.no_signal) {
diff --git a/lib/slist.c b/lib/slist.c
index 9c0b2a5..e5adc0e 100644
--- a/lib/slist.c
+++ b/lib/slist.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -22,6 +22,8 @@
 
 #include "curl_setup.h"
 
+#include <curl/curl.h>
+
 #include "slist.h"
 
 /* The last #include files should be: */
diff --git a/lib/slist.h b/lib/slist.h
index ea7dcc4..b3f498c 100644
--- a/lib/slist.h
+++ b/lib/slist.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/smb.c b/lib/smb.c
index d461a71..56a38c2 100644
--- a/lib/smb.c
+++ b/lib/smb.c
@@ -10,7 +10,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -131,7 +131,7 @@ const struct Curl_handler Curl_handler_smbs = {
    defined(__OS400__)
 static unsigned short smb_swap16(unsigned short x)
 {
-  return (x << 8) | ((x >> 8) & 0xff);
+  return (unsigned short) ((x << 8) | ((x >> 8) & 0xff));
 }
 
 static unsigned int smb_swap32(unsigned int x)
@@ -143,12 +143,14 @@ static unsigned int smb_swap32(unsigned int x)
 #ifdef HAVE_LONGLONG
 static unsigned long long smb_swap64(unsigned long long x)
 {
-  return ((unsigned long long)smb_swap32(x) << 32) | smb_swap32(x >> 32);
+  return ((unsigned long long) smb_swap32((unsigned int) x) << 32) |
+          smb_swap32((unsigned int) (x >> 32));
 }
 #else
 static unsigned __int64 smb_swap64(unsigned __int64 x)
 {
-  return ((unsigned __int64)smb_swap32(x) << 32) | smb_swap32(x >> 32);
+  return ((unsigned __int64) smb_swap32((unsigned int) x) << 32) |
+          smb_swap32((unsigned int) (x >> 32));
 }
 #endif
 #else
@@ -903,7 +905,6 @@ static CURLcode smb_disconnect(struct connectdata *conn, bool dead)
   /* smb_done is not always called, so cleanup the request */
   if(req) {
     Curl_safefree(req->share);
-    Curl_safefree(conn->data->req.protop);
   }
 
   return CURLE_OK;
@@ -928,7 +929,7 @@ static int smb_getsock(struct connectdata *conn, curl_socket_t *socks,
 static CURLcode smb_parse_url_path(struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct smb_request *req = data->req.protop;
   char *path;
   char *slash;
diff --git a/lib/smb.h b/lib/smb.h
index 7852fa1..1a4f66e 100644
--- a/lib/smb.h
+++ b/lib/smb.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/smtp.c b/lib/smtp.c
index dada087..d203b53 100644
--- a/lib/smtp.c
+++ b/lib/smtp.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -82,9 +82,9 @@
 #include "curl_gethostname.h"
 #include "curl_sasl.h"
 #include "warnless.h"
+/* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_memory.h"
-/* The last #include file should be: */
 #include "memdebug.h"
 
 /* Local API functions */
@@ -224,7 +224,11 @@ static const struct SASLproto saslsmtp = {
 #ifdef USE_SSL
 static void smtp_to_smtps(struct connectdata *conn)
 {
+  /* Change the connection handler */
   conn->handler = &Curl_handler_smtps;
+
+  /* Set the connection's upgraded to TLS flag */
+  conn->tls_upgraded = TRUE;
 }
 #else
 #define smtp_to_smtps(x) Curl_nop_stmt
@@ -288,7 +292,7 @@ static void smtp_get_message(char *buffer, char** outptr)
   /* Find the end of the message */
   for(len = strlen(message); len--;)
     if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
-        message[len] != '\t')
+       message[len] != '\t')
       break;
 
   /* Terminate the message */
@@ -486,7 +490,7 @@ static CURLcode smtp_perform_authentication(struct connectdata *conn)
   /* Check we have enough data to authenticate with, and the
      server supports authentiation, and end the connect phase if not */
   if(!smtpc->auth_supported ||
-      !Curl_sasl_can_authenticate(&smtpc->sasl, conn)) {
+     !Curl_sasl_can_authenticate(&smtpc->sasl, conn)) {
     state(conn, SMTP_STOP);
     return result;
   }
@@ -516,15 +520,15 @@ static CURLcode smtp_perform_authentication(struct connectdata *conn)
 static CURLcode smtp_perform_command(struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct SMTP *smtp = data->req.protop;
 
   /* Send the command */
   if(smtp->rcpt)
     result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s %s",
-                            smtp->custom && smtp->custom[0] != '\0' ?
-                            smtp->custom : "VRFY",
-                            smtp->rcpt->data);
+                           smtp->custom && smtp->custom[0] != '\0' ?
+                           smtp->custom : "VRFY",
+                           smtp->rcpt->data);
   else
     result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s",
                            smtp->custom && smtp->custom[0] != '\0' ?
@@ -548,7 +552,7 @@ static CURLcode smtp_perform_mail(struct connectdata *conn)
   char *auth = NULL;
   char *size = NULL;
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   /* Calculate the FROM parameter */
   if(!data->set.str[STRING_MAIL_FROM])
@@ -623,16 +627,16 @@ static CURLcode smtp_perform_mail(struct connectdata *conn)
 static CURLcode smtp_perform_rcpt_to(struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct SMTP *smtp = data->req.protop;
 
   /* Send the RCPT TO command */
   if(smtp->rcpt->data[0] == '<')
     result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:%s",
-                            smtp->rcpt->data);
+                           smtp->rcpt->data);
   else
     result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:<%s>",
-                            smtp->rcpt->data);
+                           smtp->rcpt->data);
   if(!result)
     state(conn, SMTP_RCPT);
 
@@ -664,7 +668,7 @@ static CURLcode smtp_state_servergreet_resp(struct connectdata *conn,
                                             smtpstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   (void)instate; /* no use for this yet */
 
@@ -684,7 +688,7 @@ static CURLcode smtp_state_starttls_resp(struct connectdata *conn,
                                          smtpstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   (void)instate; /* no use for this yet */
 
@@ -707,7 +711,7 @@ static CURLcode smtp_state_ehlo_resp(struct connectdata *conn, int smtpcode,
                                      smtpstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct smtp_conn *smtpc = &conn->proto.smtpc;
   const char *line = data->state.buffer;
   size_t len = strlen(line);
@@ -766,8 +770,8 @@ static CURLcode smtp_state_ehlo_resp(struct connectdata *conn, int smtpcode,
           wordlen++;
 
         /* Test the word for a matching authentication mechanism */
-        if((mechbit = Curl_sasl_decode_mech(line, wordlen, &llen)) &&
-           llen == wordlen)
+        mechbit = Curl_sasl_decode_mech(line, wordlen, &llen);
+        if(mechbit && llen == wordlen)
           smtpc->sasl.authmechs |= mechbit;
 
         line += wordlen;
@@ -802,7 +806,7 @@ static CURLcode smtp_state_helo_resp(struct connectdata *conn, int smtpcode,
                                      smtpstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   (void)instate; /* no use for this yet */
 
@@ -823,7 +827,7 @@ static CURLcode smtp_state_auth_resp(struct connectdata *conn,
                                      smtpstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct smtp_conn *smtpc = &conn->proto.smtpc;
   saslprogress progress;
 
@@ -851,7 +855,7 @@ static CURLcode smtp_state_command_resp(struct connectdata *conn, int smtpcode,
                                         smtpstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct SMTP *smtp = data->req.protop;
   char *line = data->state.buffer;
   size_t len = strlen(line);
@@ -897,7 +901,7 @@ static CURLcode smtp_state_mail_resp(struct connectdata *conn, int smtpcode,
                                      smtpstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   (void)instate; /* no use for this yet */
 
@@ -917,7 +921,7 @@ static CURLcode smtp_state_rcpt_resp(struct connectdata *conn, int smtpcode,
                                      smtpstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct SMTP *smtp = data->req.protop;
 
   (void)instate; /* no use for this yet */
@@ -949,7 +953,7 @@ static CURLcode smtp_state_data_resp(struct connectdata *conn, int smtpcode,
                                      smtpstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   (void)instate; /* no use for this yet */
 
@@ -994,7 +998,7 @@ static CURLcode smtp_statemach_act(struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
   curl_socket_t sock = conn->sock[FIRSTSOCKET];
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   int smtpcode;
   struct smtp_conn *smtpc = &conn->proto.smtpc;
   struct pingpong *pp = &smtpc->pp;
@@ -1104,12 +1108,12 @@ static CURLcode smtp_block_statemach(struct connectdata *conn)
   return result;
 }
 
-/* Allocate and initialize the SMTP struct for the current SessionHandle if
+/* Allocate and initialize the SMTP struct for the current Curl_easy if
    required */
 static CURLcode smtp_init(struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct SMTP *smtp;
 
   smtp = data->req.protop = calloc(sizeof(struct SMTP), 1);
@@ -1190,7 +1194,7 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
                           bool premature)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct SMTP *smtp = data->req.protop;
   struct pingpong *pp = &conn->proto.smtpc.pp;
   char *eob;
@@ -1200,10 +1204,6 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
   (void)premature;
 
   if(!smtp || !pp->conn)
-    /* When the easy handle is removed from the multi interface while libcurl
-       is still trying to resolve the host name, the SMTP struct is not yet
-       initialized. However, the removal action calls Curl_done() which in
-       turn calls this function, so we simply return success. */
     return CURLE_OK;
 
   if(status) {
@@ -1258,8 +1258,7 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
 
        TODO: when the multi interface is used, this _really_ should be using
        the smtp_multi_statemach function but we have no general support for
-       non-blocking DONE operations, not in the multi state machine and with
-       Curl_done() invokes on several places in the code!
+       non-blocking DONE operations!
     */
     result = smtp_block_statemach(conn);
   }
@@ -1285,7 +1284,7 @@ static CURLcode smtp_perform(struct connectdata *conn, bool *connected,
 {
   /* This is SMTP and no proxy */
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct SMTP *smtp = data->req.protop;
 
   DEBUGF(infof(conn->data, "DO phase starts\n"));
@@ -1424,7 +1423,7 @@ static CURLcode smtp_regular_transfer(struct connectdata *conn,
 {
   CURLcode result = CURLE_OK;
   bool connected = FALSE;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   /* Make sure size is unknown at this point */
   data->req.size = -1;
@@ -1447,9 +1446,13 @@ static CURLcode smtp_regular_transfer(struct connectdata *conn,
 
 static CURLcode smtp_setup_connection(struct connectdata *conn)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   CURLcode result;
 
+  /* Clear the TLS upgraded flag */
+  conn->tls_upgraded = FALSE;
+
+  /* Set up the proxy if necessary */
   if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
     /* Unless we have asked to tunnel SMTP operations through the proxy, we
        switch and use HTTP operations only */
@@ -1502,7 +1505,7 @@ static CURLcode smtp_parse_url_options(struct connectdata *conn)
     const char *value;
 
     while(*ptr && *ptr != '=')
-        ptr++;
+      ptr++;
 
     value = ptr + 1;
 
@@ -1531,7 +1534,7 @@ static CURLcode smtp_parse_url_options(struct connectdata *conn)
 static CURLcode smtp_parse_url_path(struct connectdata *conn)
 {
   /* The SMTP struct is already initialised in smtp_connect() */
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct smtp_conn *smtpc = &conn->proto.smtpc;
   const char *path = data->state.path;
   char localhost[HOSTNAME_MAX + 1];
@@ -1557,7 +1560,7 @@ static CURLcode smtp_parse_url_path(struct connectdata *conn)
 static CURLcode smtp_parse_custom_request(struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct SMTP *smtp = data->req.protop;
   const char *custom = data->set.str[STRING_CUSTOMREQUEST];
 
@@ -1578,7 +1581,7 @@ CURLcode Curl_smtp_escape_eob(struct connectdata *conn, const ssize_t nread)
   */
   ssize_t i;
   ssize_t si;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct SMTP *smtp = data->req.protop;
   char *scratch = data->state.scratch;
   char *newscratch = NULL;
diff --git a/lib/smtp.h b/lib/smtp.h
index 9fbe0c5..b67340a 100644
--- a/lib/smtp.h
+++ b/lib/smtp.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -47,9 +47,9 @@ typedef enum {
   SMTP_LAST         /* never used */
 } smtpstate;
 
-/* This SMTP struct is used in the SessionHandle. All SMTP data that is
+/* This SMTP struct is used in the Curl_easy. All SMTP data that is
    connection-oriented must be in smtp_conn to properly deal with the fact that
-   perhaps the SessionHandle is changed between the times the connection is
+   perhaps the Curl_easy is changed between the times the connection is
    used. */
 struct SMTP {
   curl_pp_transfer transfer;
diff --git a/lib/sockaddr.h b/lib/sockaddr.h
index 6a2151c..95ba4c3 100644
--- a/lib/sockaddr.h
+++ b/lib/sockaddr.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/socks.c b/lib/socks.c
index 7d3f782..fccb16d 100644
--- a/lib/socks.c
+++ b/lib/socks.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -119,7 +119,7 @@ CURLcode Curl_SOCKS4(const char *proxy_name,
   int result;
   CURLcode code;
   curl_socket_t sock = conn->sock[sockindex];
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   if(Curl_timeleft(data, NULL, TRUE) < 0) {
     /* time-out, bail out, go home */
@@ -173,8 +173,8 @@ CURLcode Curl_SOCKS4(const char *proxy_name,
       unsigned short ip[4];
       Curl_printable_address(hp, buf, sizeof(buf));
 
-      if(4 == sscanf( buf, "%hu.%hu.%hu.%hu",
-                      &ip[0], &ip[1], &ip[2], &ip[3])) {
+      if(4 == sscanf(buf, "%hu.%hu.%hu.%hu",
+                     &ip[0], &ip[1], &ip[2], &ip[3])) {
         /* Set DSTIP */
         socksreq[4] = (unsigned char)ip[0];
         socksreq[5] = (unsigned char)ip[1];
@@ -300,8 +300,8 @@ CURLcode Curl_SOCKS4(const char *proxy_name,
             ", request rejected or failed.",
             (unsigned char)socksreq[4], (unsigned char)socksreq[5],
             (unsigned char)socksreq[6], (unsigned char)socksreq[7],
-            ((socksreq[8] << 8) | socksreq[9]),
-            socksreq[1]);
+            (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]),
+            (unsigned char)socksreq[1]);
       return CURLE_COULDNT_CONNECT;
     case 92:
       failf(data,
@@ -310,8 +310,8 @@ CURLcode Curl_SOCKS4(const char *proxy_name,
             "identd on the client.",
             (unsigned char)socksreq[4], (unsigned char)socksreq[5],
             (unsigned char)socksreq[6], (unsigned char)socksreq[7],
-            ((socksreq[8] << 8) | socksreq[9]),
-            socksreq[1]);
+            (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]),
+            (unsigned char)socksreq[1]);
       return CURLE_COULDNT_CONNECT;
     case 93:
       failf(data,
@@ -320,8 +320,8 @@ CURLcode Curl_SOCKS4(const char *proxy_name,
             "report different user-ids.",
             (unsigned char)socksreq[4], (unsigned char)socksreq[5],
             (unsigned char)socksreq[6], (unsigned char)socksreq[7],
-            ((socksreq[8] << 8) | socksreq[9]),
-            socksreq[1]);
+            (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]),
+            (unsigned char)socksreq[1]);
       return CURLE_COULDNT_CONNECT;
     default:
       failf(data,
@@ -329,8 +329,8 @@ CURLcode Curl_SOCKS4(const char *proxy_name,
             ", Unknown.",
             (unsigned char)socksreq[4], (unsigned char)socksreq[5],
             (unsigned char)socksreq[6], (unsigned char)socksreq[7],
-            ((socksreq[8] << 8) | socksreq[9]),
-            socksreq[1]);
+            (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]),
+            (unsigned char)socksreq[1]);
       return CURLE_COULDNT_CONNECT;
     }
   }
@@ -374,7 +374,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name,
   int result;
   CURLcode code;
   curl_socket_t sock = conn->sock[sockindex];
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   long timeout;
   bool socks5_resolve_local = (conn->proxytype == CURLPROXY_SOCKS5)?TRUE:FALSE;
   const size_t hostname_len = strlen(hostname);
@@ -603,7 +603,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name,
       if(hp->ai_family == AF_INET) {
         socksreq[len++] = 1; /* ATYP: IPv4 = 1 */
 
-        saddr_in = (struct sockaddr_in*)hp->ai_addr;
+        saddr_in = (struct sockaddr_in*)(void*)hp->ai_addr;
         for(i = 0; i < 4; i++) {
           socksreq[len++] = ((unsigned char*)&saddr_in->sin_addr.s_addr)[i];
           infof(data, "%d\n", socksreq[len-1]);
@@ -613,7 +613,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name,
       else if(hp->ai_family == AF_INET6) {
         socksreq[len++] = 4; /* ATYP: IPv6 = 4 */
 
-        saddr_in6 = (struct sockaddr_in6*)hp->ai_addr;
+        saddr_in6 = (struct sockaddr_in6*)(void*)hp->ai_addr;
         for(i = 0; i < 16; i++) {
           socksreq[len++] = ((unsigned char*)&saddr_in6->sin6_addr.s6_addr)[i];
         }
@@ -674,15 +674,15 @@ CURLcode Curl_SOCKS5(const char *proxy_name,
             "Can't complete SOCKS5 connection to %d.%d.%d.%d:%d. (%d)",
             (unsigned char)socksreq[4], (unsigned char)socksreq[5],
             (unsigned char)socksreq[6], (unsigned char)socksreq[7],
-            ((socksreq[8] << 8) | socksreq[9]),
-            socksreq[1]);
+            (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]),
+            (unsigned char)socksreq[1]);
     }
     else if(socksreq[3] == 3) {
       failf(data,
             "Can't complete SOCKS5 connection to %s:%d. (%d)",
             hostname,
-            ((socksreq[8] << 8) | socksreq[9]),
-            socksreq[1]);
+            (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]),
+            (unsigned char)socksreq[1]);
     }
     else if(socksreq[3] == 4) {
       failf(data,
@@ -696,8 +696,8 @@ CURLcode Curl_SOCKS5(const char *proxy_name,
             (unsigned char)socksreq[14], (unsigned char)socksreq[15],
             (unsigned char)socksreq[16], (unsigned char)socksreq[17],
             (unsigned char)socksreq[18], (unsigned char)socksreq[19],
-            ((socksreq[8] << 8) | socksreq[9]),
-            socksreq[1]);
+            (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]),
+            (unsigned char)socksreq[1]);
     }
     return CURLE_COULDNT_CONNECT;
   }
diff --git a/lib/socks.h b/lib/socks.h
index 29e3bf0..a44ada6 100644
--- a/lib/socks.h
+++ b/lib/socks.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/socks_gssapi.c b/lib/socks_gssapi.c
index 8e575c2..369245a 100644
--- a/lib/socks_gssapi.c
+++ b/lib/socks_gssapi.c
@@ -6,11 +6,11 @@
  *                             \___|\___/|_| \_\_____|
  *
  * Copyright (C) 2009, 2011, Markus Moeller, <markus_moeller at compuserve.com>
- * Copyright (C) 2012 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 2012 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -32,9 +32,10 @@
 #include "timeval.h"
 #include "socks.h"
 #include "warnless.h"
+
+/* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_memory.h"
-/* The last #include file should be: */
 #include "memdebug.h"
 
 static gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT;
@@ -42,7 +43,7 @@ static gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT;
 /*
  * Helper GSS-API error functions.
  */
-static int check_gss_err(struct SessionHandle *data,
+static int check_gss_err(struct Curl_easy *data,
                          OM_uint32 major_status,
                          OM_uint32 minor_status,
                          const char* function)
@@ -101,7 +102,7 @@ static int check_gss_err(struct SessionHandle *data,
 CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
                                       struct connectdata *conn)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   curl_socket_t sock = conn->sock[sockindex];
   CURLcode code;
   ssize_t actualread;
@@ -120,7 +121,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
   unsigned short   us_length;
   char             *user=NULL;
   unsigned char socksreq[4]; /* room for GSS-API exchange header only */
-  char *serviceptr = data->set.str[STRING_SOCKS5_GSSAPI_SERVICE];
+  const char *serviceptr = data->set.str[STRING_PROXY_SERVICE_NAME] ?
+                           data->set.str[STRING_PROXY_SERVICE_NAME] : "rcmd";
 
   /*   GSS-API request looks like
    * +----+------+-----+----------------+
diff --git a/lib/socks_sspi.c b/lib/socks_sspi.c
index a7708b2..6053490 100644
--- a/lib/socks_sspi.c
+++ b/lib/socks_sspi.c
@@ -5,12 +5,12 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2012 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 2012 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  * Copyright (C) 2009, 2011, Markus Moeller, <markus_moeller at compuserve.com>
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -34,9 +34,10 @@
 #include "curl_sspi.h"
 #include "curl_multibyte.h"
 #include "warnless.h"
+#include "strdup.h"
+/* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_memory.h"
-/* The last #include file should be: */
 #include "memdebug.h"
 
 /*
@@ -61,7 +62,7 @@ static int check_sspi_err(struct connectdata *conn,
 CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
                                       struct connectdata *conn)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   curl_socket_t sock = conn->sock[sockindex];
   CURLcode code;
   ssize_t actualread;
@@ -70,7 +71,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
   /* Needs GSS-API authentication */
   SECURITY_STATUS status;
   unsigned long sspi_ret_flags = 0;
-  int gss_enc;
+  unsigned char gss_enc;
   SecBuffer sspi_send_token, sspi_recv_token, sspi_w_token[3];
   SecBufferDesc input_desc, output_desc, wrap_desc;
   SecPkgContext_Sizes sspi_sizes;
@@ -83,7 +84,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
   unsigned short us_length;
   unsigned long qop;
   unsigned char socksreq[4]; /* room for GSS-API exchange header only */
-  char *service = data->set.str[STRING_SOCKS5_GSSAPI_SERVICE];
+  const char *service = data->set.str[STRING_PROXY_SERVICE_NAME] ?
+                        data->set.str[STRING_PROXY_SERVICE_NAME]  : "rcmd";
 
   /*   GSS-API request looks like
    * +----+------+-----+----------------+
@@ -95,10 +97,9 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
 
   /* prepare service name */
   if(strchr(service, '/')) {
-    service_name = malloc(strlen(service));
+    service_name = strdup(service);
     if(!service_name)
       return CURLE_OUT_OF_MEMORY;
-    memcpy(service_name, service, strlen(service));
   }
   else {
     service_name = malloc(strlen(service) + strlen(conn->proxy.name) + 2);
diff --git a/lib/speedcheck.c b/lib/speedcheck.c
index ac7447c..13c34af 100644
--- a/lib/speedcheck.c
+++ b/lib/speedcheck.c
@@ -9,7 +9,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -28,12 +28,12 @@
 #include "multiif.h"
 #include "speedcheck.h"
 
-void Curl_speedinit(struct SessionHandle *data)
+void Curl_speedinit(struct Curl_easy *data)
 {
   memset(&data->state.keeps_speed, 0, sizeof(struct timeval));
 }
 
-CURLcode Curl_speedcheck(struct SessionHandle *data,
+CURLcode Curl_speedcheck(struct Curl_easy *data,
                          struct timeval now)
 {
   if((data->progress.current_speed >= 0) &&
diff --git a/lib/speedcheck.h b/lib/speedcheck.h
index 786cd12..7dbe3d6 100644
--- a/lib/speedcheck.h
+++ b/lib/speedcheck.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -26,8 +26,8 @@
 
 #include "timeval.h"
 
-void Curl_speedinit(struct SessionHandle *data);
-CURLcode Curl_speedcheck(struct SessionHandle *data,
+void Curl_speedinit(struct Curl_easy *data);
+CURLcode Curl_speedcheck(struct Curl_easy *data,
                          struct timeval now);
 
 #endif /* HEADER_CURL_SPEEDCHECK_H */
diff --git a/lib/splay.c b/lib/splay.c
index b87b6cf..7aa2e4b 100644
--- a/lib/splay.c
+++ b/lib/splay.c
@@ -9,7 +9,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/splay.h b/lib/splay.h
index 5f9ef24..427bfc8 100644
--- a/lib/splay.h
+++ b/lib/splay.h
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1997 - 2011, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1997 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -55,7 +55,7 @@ int Curl_splayremovebyaddr(struct Curl_tree *t,
 #define Curl_splaycomparekeys(i,j) ( ((i.tv_sec)  < (j.tv_sec))  ? -1 : \
                                    ( ((i.tv_sec)  > (j.tv_sec))  ?  1 : \
                                    ( ((i.tv_usec) < (j.tv_usec)) ? -1 : \
-                                   ( ((i.tv_usec) > (j.tv_usec)) ?  1 : 0 ))))
+                                   ( ((i.tv_usec) > (j.tv_usec)) ?  1 : 0))))
 
 #ifdef DEBUGBUILD
 void Curl_splayprint(struct Curl_tree * t, int d, char output);
diff --git a/lib/ssh.c b/lib/ssh.c
index 94195a7..7bc3136 100644
--- a/lib/ssh.c
+++ b/lib/ssh.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -83,9 +83,10 @@
 #include "multiif.h"
 #include "select.h"
 #include "warnless.h"
+
+/* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_memory.h"
-/* The last #include file should be: */
 #include "memdebug.h"
 
 #ifdef WIN32
@@ -101,6 +102,11 @@
                          have their definition hidden well */
 #endif
 
+#if LIBSSH2_VERSION_NUM >= 0x010206
+/* libssh2_sftp_statvfs and friends were added in 1.2.6 */
+#define HAS_STATVFS_SUPPORT 1
+#endif
+
 #define sftp_libssh2_last_error(s) curlx_ultosi(libssh2_sftp_last_error(s))
 
 #define sftp_libssh2_realpath(s,p,t,m) \
@@ -362,6 +368,9 @@ static void state(struct connectdata *conn, sshstate nowstate)
     "SSH_SFTP_QUOTE_RENAME",
     "SSH_SFTP_QUOTE_RMDIR",
     "SSH_SFTP_QUOTE_UNLINK",
+    "SSH_SFTP_QUOTE_STATVFS",
+    "SSH_SFTP_GETINFO",
+    "SSH_SFTP_FILETIME",
     "SSH_SFTP_TRANS_INIT",
     "SSH_SFTP_UPLOAD_INIT",
     "SSH_SFTP_CREATE_DIRS_INIT",
@@ -404,7 +413,7 @@ static CURLcode ssh_getworkingpath(struct connectdata *conn,
                                    char **path) /* returns the  allocated
                                                    real path to work with */
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   char *real_path = NULL;
   char *working_path;
   int working_path_len;
@@ -414,7 +423,7 @@ static CURLcode ssh_getworkingpath(struct connectdata *conn,
   if(!working_path)
     return CURLE_OUT_OF_MEMORY;
 
-  /* Check for /~/ , indicating relative to the user's home directory */
+  /* Check for /~/, indicating relative to the user's home directory */
   if(conn->handler->protocol & CURLPROTO_SCP) {
     real_path = malloc(working_path_len+1);
     if(real_path == NULL) {
@@ -464,7 +473,7 @@ static CURLcode ssh_getworkingpath(struct connectdata *conn,
 }
 
 #ifdef HAVE_LIBSSH2_KNOWNHOST_API
-static int sshkeycallback(CURL *easy,
+static int sshkeycallback(struct Curl_easy *easy,
                           const struct curl_khkey *knownkey, /* known */
                           const struct curl_khkey *foundkey, /* found */
                           enum curl_khmatch match,
@@ -513,7 +522,7 @@ static CURLcode ssh_knownhost(struct connectdata *conn)
   CURLcode result = CURLE_OK;
 
 #ifdef HAVE_LIBSSH2_KNOWNHOST_API
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
     /* we're asked to verify the host against a file */
@@ -648,7 +657,7 @@ static CURLcode ssh_knownhost(struct connectdata *conn)
 static CURLcode ssh_check_fingerprint(struct connectdata *conn)
 {
   struct ssh_conn *sshc = &conn->proto.sshc;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   const char *pubkey_md5 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5];
   char md5buffer[33];
   int i;
@@ -699,7 +708,7 @@ static CURLcode ssh_check_fingerprint(struct connectdata *conn)
 static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct SSHPROTO *sftp_scp = data->req.protop;
   struct ssh_conn *sshc = &conn->proto.sshc;
   curl_socket_t sock = conn->sock[FIRSTSOCKET];
@@ -848,7 +857,9 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
          * libssh2 extract the public key from the private key file.
          * This is done by simply passing sshc->rsa_pub = NULL.
          */
-        if(data->set.str[STRING_SSH_PUBLIC_KEY]) {
+        if(data->set.str[STRING_SSH_PUBLIC_KEY]
+            /* treat empty string the same way as NULL */
+            && data->set.str[STRING_SSH_PUBLIC_KEY][0]) {
           sshc->rsa_pub = strdup(data->set.str[STRING_SSH_PUBLIC_KEY]);
           if(!sshc->rsa_pub)
             out_of_memory = TRUE;
@@ -869,7 +880,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
 
         free(home);
 
-        infof(data, "Using SSH public key file '%s'\n", sshc->rsa_pub);
+        if(sshc->rsa_pub)
+          infof(data, "Using SSH public key file '%s'\n", sshc->rsa_pub);
         infof(data, "Using SSH private key file '%s'\n", sshc->rsa);
 
         state(conn, SSH_AUTH_PKEY);
@@ -1149,8 +1161,13 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
       else {
         /* Return the error type */
         err = sftp_libssh2_last_error(sshc->sftp_session);
-        result = sftp_libssh2_error_to_CURLE(err);
-        sshc->actualcode = result?result:CURLE_SSH;
+        if(err)
+          result = sftp_libssh2_error_to_CURLE(err);
+        else
+          /* in this case, the error wasn't in the SFTP level but for example
+             a time-out or similar */
+          result = CURLE_SSH;
+        sshc->actualcode = result;
         DEBUGF(infof(data, "error = %d makes libcurl = %d\n",
                      err, (int)result));
         state(conn, SSH_STOP);
@@ -1180,7 +1197,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
         state(conn, SSH_SFTP_QUOTE);
       }
       else {
-        state(conn, SSH_SFTP_TRANS_INIT);
+        state(conn, SSH_SFTP_GETINFO);
       }
       break;
 
@@ -1358,6 +1375,12 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
           state(conn, SSH_SFTP_QUOTE_UNLINK);
           break;
         }
+#ifdef HAS_STATVFS_SUPPORT
+        else if(curl_strnequal(cmd, "statvfs ", 8)) {
+          state(conn, SSH_SFTP_QUOTE_STATVFS);
+          break;
+        }
+#endif
 
         failf(data, "Unknown SFTP command");
         Curl_safefree(sshc->quote_path1);
@@ -1369,7 +1392,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
       }
     }
     if(!sshc->quote_item) {
-      state(conn, SSH_SFTP_TRANS_INIT);
+      state(conn, SSH_SFTP_GETINFO);
     }
     break;
 
@@ -1388,7 +1411,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
           sshc->nextstate = SSH_NO_STATE;
         }
         else {
-          state(conn, SSH_SFTP_TRANS_INIT);
+          state(conn, SSH_SFTP_GETINFO);
         }
       }
       break;
@@ -1608,6 +1631,88 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
       state(conn, SSH_SFTP_NEXT_QUOTE);
       break;
 
+#ifdef HAS_STATVFS_SUPPORT
+    case SSH_SFTP_QUOTE_STATVFS:
+    {
+      LIBSSH2_SFTP_STATVFS statvfs;
+      rc = libssh2_sftp_statvfs(sshc->sftp_session, sshc->quote_path1,
+                                curlx_uztoui(strlen(sshc->quote_path1)),
+                                &statvfs);
+
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      else if(rc != 0 && !sshc->acceptfail) {
+        err = sftp_libssh2_last_error(sshc->sftp_session);
+        Curl_safefree(sshc->quote_path1);
+        failf(data, "statvfs command failed: %s", sftp_libssh2_strerror(err));
+        state(conn, SSH_SFTP_CLOSE);
+        sshc->nextstate = SSH_NO_STATE;
+        sshc->actualcode = CURLE_QUOTE_ERROR;
+        break;
+      }
+      else if(rc == 0) {
+        char *tmp = aprintf("statvfs:\n"
+                            "f_bsize: %llu\n" "f_frsize: %llu\n"
+                            "f_blocks: %llu\n" "f_bfree: %llu\n"
+                            "f_bavail: %llu\n" "f_files: %llu\n"
+                            "f_ffree: %llu\n" "f_favail: %llu\n"
+                            "f_fsid: %llu\n" "f_flag: %llu\n"
+                            "f_namemax: %llu\n",
+                            statvfs.f_bsize, statvfs.f_frsize,
+                            statvfs.f_blocks, statvfs.f_bfree,
+                            statvfs.f_bavail, statvfs.f_files,
+                            statvfs.f_ffree, statvfs.f_favail,
+                            statvfs.f_fsid, statvfs.f_flag,
+                            statvfs.f_namemax);
+        if(!tmp) {
+          result = CURLE_OUT_OF_MEMORY;
+          state(conn, SSH_SFTP_CLOSE);
+          sshc->nextstate = SSH_NO_STATE;
+          break;
+        }
+
+        result = Curl_client_write(conn, CLIENTWRITE_HEADER, tmp, strlen(tmp));
+        free(tmp);
+        if(result) {
+          state(conn, SSH_SFTP_CLOSE);
+          sshc->nextstate = SSH_NO_STATE;
+          sshc->actualcode = result;
+        }
+      }
+      state(conn, SSH_SFTP_NEXT_QUOTE);
+      break;
+    }
+#endif
+    case SSH_SFTP_GETINFO:
+    {
+      if(data->set.get_filetime) {
+        state(conn, SSH_SFTP_FILETIME);
+      }
+      else {
+        state(conn, SSH_SFTP_TRANS_INIT);
+      }
+      break;
+    }
+
+    case SSH_SFTP_FILETIME:
+    {
+      LIBSSH2_SFTP_ATTRIBUTES attrs;
+
+      rc = libssh2_sftp_stat_ex(sshc->sftp_session, sftp_scp->path,
+                                curlx_uztoui(strlen(sftp_scp->path)),
+                                LIBSSH2_SFTP_STAT, &attrs);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      else if(rc == 0) {
+        data->info.filetime = (long)attrs.mtime;
+      }
+
+      state(conn, SSH_SFTP_TRANS_INIT);
+      break;
+    }
+
     case SSH_SFTP_TRANS_INIT:
       if(data->set.upload)
         state(conn, SSH_SFTP_UPLOAD_INIT);
@@ -1740,8 +1845,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
                 BUFSIZE : curlx_sotouz(data->state.resume_from - passed);
 
               size_t actuallyread =
-                data->set.fread_func(data->state.buffer, 1, readthisamountnow,
-                                     data->set.in);
+                data->state.fread_func(data->state.buffer, 1,
+                                       readthisamountnow, data->state.in);
 
               passed += actuallyread;
               if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
@@ -2368,19 +2473,30 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
 
     case SSH_SCP_DOWNLOAD_INIT:
     {
+      curl_off_t bytecount;
+
       /*
        * We must check the remote file; if it is a directory no values will
        * be set in sb
        */
-      struct stat sb;
-      curl_off_t bytecount;
 
-      /* clear the struct scp recv will fill in */
-      memset(&sb, 0, sizeof(struct stat));
+       /*
+        * If support for >2GB files exists, use it.
+        */
 
       /* get a fresh new channel from the ssh layer */
+#if LIBSSH2_VERSION_NUM < 0x010700
+      struct stat sb;
+      memset(&sb, 0, sizeof(struct stat));
       sshc->ssh_channel = libssh2_scp_recv(sshc->ssh_session,
                                            sftp_scp->path, &sb);
+#else
+      libssh2_struct_stat sb;
+      memset(&sb, 0, sizeof(libssh2_struct_stat));
+      sshc->ssh_channel = libssh2_scp_recv2(sshc->ssh_session,
+                                            sftp_scp->path, &sb);
+#endif
+
       if(!sshc->ssh_channel) {
         if(libssh2_session_last_errno(sshc->ssh_session) ==
            LIBSSH2_ERROR_EAGAIN) {
@@ -2708,7 +2824,7 @@ static CURLcode ssh_block_statemach(struct connectdata *conn,
 {
   struct ssh_conn *sshc = &conn->proto.sshc;
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   while((sshc->state != SSH_STOP) && !result) {
     bool block;
@@ -2782,7 +2898,7 @@ static CURLcode ssh_connect(struct connectdata *conn, bool *done)
 #endif
   struct ssh_conn *ssh;
   CURLcode result;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   /* initialize per-handle data if not already */
   if(!data->req.protop)
@@ -2908,7 +3024,7 @@ static CURLcode ssh_do(struct connectdata *conn, bool *done)
 {
   CURLcode result;
   bool connected = 0;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct ssh_conn *sshc = &conn->proto.sshc;
 
   *done = FALSE; /* default to false */
@@ -2941,8 +3057,6 @@ static CURLcode scp_disconnect(struct connectdata *conn, bool dead_connection)
   struct ssh_conn *ssh = &conn->proto.sshc;
   (void) dead_connection;
 
-  Curl_safefree(conn->data->req.protop);
-
   if(ssh->ssh_session) {
     /* only if there's a session still around to use! */
 
@@ -2966,8 +3080,7 @@ static CURLcode ssh_done(struct connectdata *conn, CURLcode status)
 
        TODO: when the multi interface is used, this _really_ should be using
        the ssh_multi_statemach function but we have no general support for
-       non-blocking DONE operations, not in the multi state machine and with
-       Curl_done() invokes on several places in the code!
+       non-blocking DONE operations!
     */
     result = ssh_block_statemach(conn, FALSE);
   }
@@ -3105,8 +3218,6 @@ static CURLcode sftp_disconnect(struct connectdata *conn, bool dead_connection)
 
   DEBUGF(infof(conn->data, "SSH DISCONNECT starts now\n"));
 
-  Curl_safefree(conn->data->req.protop);
-
   if(conn->proto.sshc.ssh_session) {
     /* only if there's a session still around to use! */
     state(conn, SSH_SFTP_SHUTDOWN);
diff --git a/lib/ssh.h b/lib/ssh.h
index b3cc54c..b350dcf 100644
--- a/lib/ssh.h
+++ b/lib/ssh.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -66,6 +66,9 @@ typedef enum {
   SSH_SFTP_QUOTE_RENAME,
   SSH_SFTP_QUOTE_RMDIR,
   SSH_SFTP_QUOTE_UNLINK,
+  SSH_SFTP_QUOTE_STATVFS,
+  SSH_SFTP_GETINFO,
+  SSH_SFTP_FILETIME,
   SSH_SFTP_TRANS_INIT,
   SSH_SFTP_UPLOAD_INIT,
   SSH_SFTP_CREATE_DIRS_INIT,
@@ -95,7 +98,7 @@ typedef enum {
 } sshstate;
 
 /* this struct is used in the HandleData struct which is part of the
-   SessionHandle, which means this is used on a per-easy handle basis.
+   Curl_easy, which means this is used on a per-easy handle basis.
    Everything that is strictly related to a connection is banned from this
    struct. */
 struct SSHPROTO {
diff --git a/lib/strdup.c b/lib/strdup.c
index 5685b81..23f554e 100644
--- a/lib/strdup.c
+++ b/lib/strdup.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -19,7 +19,11 @@
  * KIND, either express or implied.
  *
  ***************************************************************************/
+
 #include "curl_setup.h"
+
+#include <curl/curl.h>
+
 #include "strdup.h"
 #include "curl_memory.h"
 
diff --git a/lib/strdup.h b/lib/strdup.h
index 23a71f8..4c48ca4 100644
--- a/lib/strdup.h
+++ b/lib/strdup.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/strequal.c b/lib/strequal.c
index 5f2f508..01c3784 100644
--- a/lib/strequal.c
+++ b/lib/strequal.c
@@ -9,7 +9,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/strequal.h b/lib/strequal.h
index 117a305..ff56df5 100644
--- a/lib/strequal.h
+++ b/lib/strequal.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/strerror.c b/lib/strerror.c
index 5657141..0e268d5 100644
--- a/lib/strerror.c
+++ b/lib/strerror.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2004 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 2004 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -39,10 +39,14 @@
 #include <idna.h>
 #endif
 
+#ifdef USE_WINDOWS_SSPI
+#include "curl_sspi.h"
+#endif
+
 #include "strerror.h"
+/* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_memory.h"
-/* The last #include file should be: */
 #include "memdebug.h"
 
 const char *
@@ -301,6 +305,9 @@ curl_easy_strerror(CURLcode error)
   case CURLE_SSL_INVALIDCERTSTATUS:
     return "SSL server certificate status verification FAILED";
 
+  case CURLE_HTTP2_STREAM:
+    return "Stream error in the HTTP/2 framing layer";
+
     /* error codes not used by current libcurl */
   case CURLE_OBSOLETE20:
   case CURLE_OBSOLETE24:
@@ -1072,14 +1079,13 @@ const char *Curl_sspi_strerror (struct connectdata *conn, int err)
     strncpy(outbuf, txt, outmax);
   else if(err == SEC_E_ILLEGAL_MESSAGE)
     snprintf(outbuf, outmax,
-             "SEC_E_ILLEGAL_MESSAGE (0x%04X%04X) - This error usually occurs "
+             "SEC_E_ILLEGAL_MESSAGE (0x%08X) - This error usually occurs "
              "when a fatal SSL/TLS alert is received (e.g. handshake failed). "
              "More detail may be available in the Windows System event log.",
-             (err >> 16) & 0xffff, err & 0xffff);
+             err);
   else {
     str = txtbuf;
-    snprintf(txtbuf, sizeof(txtbuf), "%s (0x%04X%04X)",
-             txt, (err >> 16) & 0xffff, err & 0xffff);
+    snprintf(txtbuf, sizeof(txtbuf), "%s (0x%08X)", txt, err);
     txtbuf[sizeof(txtbuf)-1] = '\0';
 
 #ifdef _WIN32_WCE
diff --git a/lib/strerror.h b/lib/strerror.h
index f1b2221..ae8c96b 100644
--- a/lib/strerror.h
+++ b/lib/strerror.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/strtok.c b/lib/strtok.c
index 0d31351..460eb87 100644
--- a/lib/strtok.c
+++ b/lib/strtok.c
@@ -9,7 +9,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/strtok.h b/lib/strtok.h
index 1147d70..90b831e 100644
--- a/lib/strtok.h
+++ b/lib/strtok.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/strtoofft.c b/lib/strtoofft.c
index 03a97e8..6d5d2d5 100644
--- a/lib/strtoofft.c
+++ b/lib/strtoofft.c
@@ -9,7 +9,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/strtoofft.h b/lib/strtoofft.h
index 75c73d4..f4039f3 100644
--- a/lib/strtoofft.h
+++ b/lib/strtoofft.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/system_win32.c b/lib/system_win32.c
new file mode 100644
index 0000000..d6a998b
--- /dev/null
+++ b/lib/system_win32.c
@@ -0,0 +1,294 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2016, Steve Holme, <steve_holme at hotmail.com>.
+ *
+ * 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"
+
+#if defined(WIN32)
+
+#include <curl/curl.h>
+#include "system_win32.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#if defined(USE_WINDOWS_SSPI) || (!defined(CURL_DISABLE_TELNET) && \
+                                  defined(USE_WINSOCK))
+
+
+#if !defined(LOAD_WITH_ALTERED_SEARCH_PATH)
+#define LOAD_WITH_ALTERED_SEARCH_PATH  0x00000008
+#endif
+
+#if !defined(LOAD_LIBRARY_SEARCH_SYSTEM32)
+#define LOAD_LIBRARY_SEARCH_SYSTEM32   0x00000800
+#endif
+
+/* We use our own typedef here since some headers might lack these */
+typedef HMODULE (APIENTRY *LOADLIBRARYEX_FN)(LPCTSTR, HANDLE, DWORD);
+
+/* See function definitions in winbase.h */
+#ifdef UNICODE
+#  ifdef _WIN32_WCE
+#    define LOADLIBARYEX  L"LoadLibraryExW"
+#  else
+#    define LOADLIBARYEX  "LoadLibraryExW"
+#  endif
+#else
+#  define LOADLIBARYEX    "LoadLibraryExA"
+#endif
+
+#endif /* USE_WINDOWS_SSPI || (!CURL_DISABLE_TELNET && USE_WINSOCK) */
+
+/*
+ * Curl_verify_windows_version()
+ *
+ * This is used to verify if we are running on a specific windows version.
+ *
+ * Parameters:
+ *
+ * majorVersion [in] - The major version number.
+ * minorVersion [in] - The minor version number.
+ * platform     [in] - The optional platform identifer.
+ * condition    [in] - The test condition used to specifier whether we are
+ *                     checking a version less then, equal to or greater than
+ *                     what is specified in the major and minor version
+ *                     numbers.
+ *
+ * Returns TRUE if matched; otherwise FALSE.
+ */
+bool Curl_verify_windows_version(const unsigned int majorVersion,
+                                 const unsigned int minorVersion,
+                                 const PlatformIdentifier platform,
+                                 const VersionCondition condition)
+{
+  bool matched = FALSE;
+
+#if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_WIN2K) || \
+    (_WIN32_WINNT < _WIN32_WINNT_WIN2K)
+  OSVERSIONINFO osver;
+
+  memset(&osver, 0, sizeof(osver));
+  osver.dwOSVersionInfoSize = sizeof(osver);
+
+  /* Find out Windows version */
+  if(GetVersionEx(&osver)) {
+    /* Verify the Operating System version number */
+    switch(condition) {
+    case VERSION_LESS_THAN:
+      if(osver.dwMajorVersion < majorVersion ||
+        (osver.dwMajorVersion == majorVersion &&
+         osver.dwMinorVersion < minorVersion))
+        matched = TRUE;
+      break;
+
+    case VERSION_LESS_THAN_EQUAL:
+      if(osver.dwMajorVersion <= majorVersion &&
+         osver.dwMinorVersion <= minorVersion)
+        matched = TRUE;
+      break;
+
+    case VERSION_EQUAL:
+      if(osver.dwMajorVersion == majorVersion &&
+         osver.dwMinorVersion == minorVersion)
+        matched = TRUE;
+      break;
+
+    case VERSION_GREATER_THAN_EQUAL:
+      if(osver.dwMajorVersion >= majorVersion &&
+         osver.dwMinorVersion >= minorVersion)
+        matched = TRUE;
+      break;
+
+    case VERSION_GREATER_THAN:
+      if(osver.dwMajorVersion > majorVersion ||
+        (osver.dwMajorVersion == majorVersion &&
+         osver.dwMinorVersion > minorVersion))
+        matched = TRUE;
+      break;
+    }
+
+    /* Verify the platform identifier (if necessary) */
+    if(matched && platform != PLATFORM_DONT_CARE) {
+      switch(platform) {
+      case PLATFORM_WINDOWS:
+        if(osver.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS)
+          matched = FALSE;
+        break;
+
+      case PLATFORM_WINNT:
+        if(osver.dwPlatformId != VER_PLATFORM_WIN32_NT)
+          matched = FALSE;
+      }
+    }
+  }
+#else
+  ULONGLONG cm = 0;
+  OSVERSIONINFOEX osver;
+  BYTE majorCondition;
+  BYTE minorCondition;
+  BYTE spMajorCondition;
+  BYTE spMinorCondition;
+
+  switch(condition) {
+  case VERSION_LESS_THAN:
+    majorCondition = VER_LESS;
+    minorCondition = VER_LESS;
+    spMajorCondition = VER_LESS_EQUAL;
+    spMinorCondition = VER_LESS_EQUAL;
+    break;
+
+  case VERSION_LESS_THAN_EQUAL:
+    majorCondition = VER_LESS_EQUAL;
+    minorCondition = VER_LESS_EQUAL;
+    spMajorCondition = VER_LESS_EQUAL;
+    spMinorCondition = VER_LESS_EQUAL;
+    break;
+
+  case VERSION_EQUAL:
+    majorCondition = VER_EQUAL;
+    minorCondition = VER_EQUAL;
+    spMajorCondition = VER_GREATER_EQUAL;
+    spMinorCondition = VER_GREATER_EQUAL;
+    break;
+
+  case VERSION_GREATER_THAN_EQUAL:
+    majorCondition = VER_GREATER_EQUAL;
+    minorCondition = VER_GREATER_EQUAL;
+    spMajorCondition = VER_GREATER_EQUAL;
+    spMinorCondition = VER_GREATER_EQUAL;
+    break;
+
+  case VERSION_GREATER_THAN:
+    majorCondition = VER_GREATER;
+    minorCondition = VER_GREATER;
+    spMajorCondition = VER_GREATER_EQUAL;
+    spMinorCondition = VER_GREATER_EQUAL;
+    break;
+
+  default:
+    return FALSE;
+  }
+
+  memset(&osver, 0, sizeof(osver));
+  osver.dwOSVersionInfoSize = sizeof(osver);
+  osver.dwMajorVersion = majorVersion;
+  osver.dwMinorVersion = minorVersion;
+  if(platform == PLATFORM_WINDOWS)
+    osver.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS;
+  else if(platform == PLATFORM_WINNT)
+    osver.dwPlatformId = VER_PLATFORM_WIN32_NT;
+
+  cm = VerSetConditionMask(cm, VER_MAJORVERSION, majorCondition);
+  cm = VerSetConditionMask(cm, VER_MINORVERSION, minorCondition);
+  cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, spMajorCondition);
+  cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, spMinorCondition);
+  if(platform != PLATFORM_DONT_CARE)
+    cm = VerSetConditionMask(cm, VER_PLATFORMID, VER_EQUAL);
+
+  if(VerifyVersionInfo(&osver, (VER_MAJORVERSION | VER_MINORVERSION |
+                                VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR),
+                       cm))
+    matched = TRUE;
+#endif
+
+  return matched;
+}
+
+#if defined(USE_WINDOWS_SSPI) || (!defined(CURL_DISABLE_TELNET) && \
+                                  defined(USE_WINSOCK))
+
+/*
+ * Curl_load_library()
+ *
+ * This is used to dynamically load DLLs using the most secure method available
+ * for the version of Windows that we are running on.
+ *
+ * Parameters:
+ *
+ * filename  [in] - The filename or full path of the DLL to load. If only the
+ *                  filename is passed then the DLL will be loaded from the
+ *                  Windows system directory.
+ *
+ * Returns the handle of the module on success; otherwise NULL.
+ */
+HMODULE Curl_load_library(LPCTSTR filename)
+{
+  HMODULE hModule = NULL;
+  LOADLIBRARYEX_FN pLoadLibraryEx = NULL;
+
+  /* Get a handle to kernel32 so we can access it's functions at runtime */
+  HMODULE hKernel32 = GetModuleHandle(TEXT("kernel32"));
+  if(!hKernel32)
+    return NULL;
+
+  /* Attempt to find LoadLibraryEx() which is only available on Windows 2000
+     and above */
+  pLoadLibraryEx = (LOADLIBRARYEX_FN) GetProcAddress(hKernel32, LOADLIBARYEX);
+
+  /* Detect if there's already a path in the filename and load the library if
+     there is. Note: Both back slashes and forward slashes have been supported
+     since the earlier days of DOS at an API level although they are not
+     supported by command prompt */
+  if(_tcspbrk(filename, TEXT("\\/"))) {
+    /** !checksrc! disable BANNEDFUNC 1 **/
+    hModule = pLoadLibraryEx ?
+      pLoadLibraryEx(filename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) :
+      LoadLibrary(filename);
+  }
+  /* Detect if KB2533623 is installed, as LOAD_LIBARY_SEARCH_SYSTEM32 is only
+     supported on Windows Vista, Windows Server 2008, Windows 7 and Windows
+     Server 2008 R2 with this patch or natively on Windows 8 and above */
+  else if(pLoadLibraryEx && GetProcAddress(hKernel32, "AddDllDirectory")) {
+    /* Load the DLL from the Windows system directory */
+    hModule = pLoadLibraryEx(filename, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
+  }
+  else {
+    /* Attempt to get the Windows system path */
+    UINT systemdirlen = GetSystemDirectory(NULL, 0);
+    if(systemdirlen) {
+      /* Allocate space for the full DLL path (Room for the null terminator
+         is included in systemdirlen) */
+      size_t filenamelen = _tcslen(filename);
+      TCHAR *path = malloc(sizeof(TCHAR) * (systemdirlen + 1 + filenamelen));
+      if(path && GetSystemDirectory(path, systemdirlen)) {
+        /* Calculate the full DLL path */
+        _tcscpy(path + _tcslen(path), TEXT("\\"));
+        _tcscpy(path + _tcslen(path), filename);
+
+        /* Load the DLL from the Windows system directory */
+        /** !checksrc! disable BANNEDFUNC 1 **/
+        hModule = pLoadLibraryEx ?
+          pLoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) :
+          LoadLibrary(path);
+
+      }
+      free(path);
+    }
+  }
+
+  return hModule;
+}
+
+#endif /* USE_WINDOWS_SSPI || (!CURL_DISABLE_TELNET && USE_WINSOCK) */
+
+#endif /* WIN32 */
diff --git a/lib/system_win32.h b/lib/system_win32.h
new file mode 100644
index 0000000..1e77285
--- /dev/null
+++ b/lib/system_win32.h
@@ -0,0 +1,61 @@
+#ifndef HEADER_CURL_SYSTEM_WIN32_H
+#define HEADER_CURL_SYSTEM_WIN32_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2016, Steve Holme, <steve_holme at hotmail.com>.
+ *
+ * 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"
+
+#if defined(WIN32)
+
+/* Version condition */
+typedef enum {
+  VERSION_LESS_THAN,
+  VERSION_LESS_THAN_EQUAL,
+  VERSION_EQUAL,
+  VERSION_GREATER_THAN_EQUAL,
+  VERSION_GREATER_THAN
+} VersionCondition;
+
+/* Platform identifier */
+typedef enum {
+  PLATFORM_DONT_CARE,
+  PLATFORM_WINDOWS,
+  PLATFORM_WINNT
+} PlatformIdentifier;
+
+/* This is used to verify if we are running on a specific windows version */
+bool Curl_verify_windows_version(const unsigned int majorVersion,
+                                 const unsigned int minorVersion,
+                                 const PlatformIdentifier platform,
+                                 const VersionCondition condition);
+
+#if defined(USE_WINDOWS_SSPI) || (!defined(CURL_DISABLE_TELNET) && \
+                                  defined(USE_WINSOCK))
+
+/* This is used to dynamically load DLLs */
+HMODULE Curl_load_library(LPCTSTR filename);
+
+#endif /* USE_WINDOWS_SSPI || (!CURL_DISABLE_TELNET && USE_WINSOCK) */
+
+#endif /* WIN32 */
+
+#endif /* HEADER_CURL_SYSTEM_WIN32_H */
diff --git a/lib/telnet.c b/lib/telnet.c
index aabf99d..cc705cf 100644
--- a/lib/telnet.c
+++ b/lib/telnet.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -51,7 +51,7 @@
 #include "telnet.h"
 #include "connect.h"
 #include "progress.h"
-#include "curl_printf.h"
+#include "system_win32.h"
 
 #define  TELOPTS
 #define  TELCMDS
@@ -62,7 +62,8 @@
 #include "rawstr.h"
 #include "warnless.h"
 
-/* The last #include files should be: */
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
 #include "curl_memory.h"
 #include "memdebug.h"
 
@@ -91,7 +92,7 @@
 
 #ifdef USE_WINSOCK
 typedef FARPROC WSOCK2_FUNC;
-static CURLcode check_wsock2 ( struct SessionHandle *data );
+static CURLcode check_wsock2 (struct Curl_easy *data);
 #endif
 
 static
@@ -100,7 +101,7 @@ CURLcode telrcv(struct connectdata *,
                 ssize_t count);             /* Number of bytes received */
 
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
-static void printoption(struct SessionHandle *data,
+static void printoption(struct Curl_easy *data,
                         const char *direction,
                         int cmd, int option);
 #endif
@@ -110,7 +111,7 @@ static void send_negotiation(struct connectdata *, int cmd, int option);
 static void set_local_option(struct connectdata *, int cmd, int option);
 static void set_remote_option(struct connectdata *, int cmd, int option);
 
-static void printsub(struct SessionHandle *data,
+static void printsub(struct Curl_easy *data,
                      int direction, unsigned char *pointer,
                      size_t length);
 static void suboption(struct connectdata *);
@@ -198,7 +199,7 @@ const struct Curl_handler Curl_handler_telnet = {
 
 #ifdef USE_WINSOCK
 static CURLcode
-check_wsock2 ( struct SessionHandle *data )
+check_wsock2(struct Curl_easy *data)
 {
   int err;
   WORD wVersionRequested;
@@ -305,7 +306,7 @@ static void negotiate(struct connectdata *conn)
 }
 
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
-static void printoption(struct SessionHandle *data,
+static void printoption(struct Curl_easy *data,
                         const char *direction, int cmd, int option)
 {
   const char *fmt;
@@ -346,7 +347,7 @@ static void send_negotiation(struct connectdata *conn, int cmd, int option)
    unsigned char buf[3];
    ssize_t bytes_written;
    int err;
-   struct SessionHandle *data = conn->data;
+   struct Curl_easy *data = conn->data;
 
    buf[0] = CURL_IAC;
    buf[1] = (unsigned char)cmd;
@@ -702,7 +703,7 @@ void rec_dont(struct connectdata *conn, int option)
 }
 
 
-static void printsub(struct SessionHandle *data,
+static void printsub(struct Curl_easy *data,
                      int direction,             /* '<' or '>' */
                      unsigned char *pointer,    /* where suboption data is */
                      size_t length)             /* length of suboption data */
@@ -821,7 +822,7 @@ static CURLcode check_telnet_options(struct connectdata *conn)
   struct curl_slist *beg;
   char option_keyword[128] = "";
   char option_arg[256] = "";
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
   CURLcode result = CURLE_OK;
   int binary_option;
@@ -931,7 +932,7 @@ static void suboption(struct connectdata *conn)
   int err;
   char varname[128] = "";
   char varval[128] = "";
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct TELNET *tn = (struct TELNET *)data->req.protop;
 
   printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn)+2);
@@ -1006,7 +1007,7 @@ static void sendsuboption(struct connectdata *conn, int option)
   unsigned short x, y;
   unsigned char*uc1, *uc2;
 
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct TELNET *tn = (struct TELNET *)data->req.protop;
 
   switch (option) {
@@ -1064,7 +1065,7 @@ CURLcode telrcv(struct connectdata *conn,
   CURLcode result;
   int in = 0;
   int startwrite=-1;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct TELNET *tn = (struct TELNET *)data->req.protop;
 
 #define startskipping()                                       \
@@ -1281,7 +1282,7 @@ static CURLcode telnet_done(struct connectdata *conn,
 static CURLcode telnet_do(struct connectdata *conn, bool *done)
 {
   CURLcode result;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
 #ifdef USE_WINSOCK
   HMODULE wsock2;
@@ -1334,7 +1335,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done)
 
   /* OK, so we have WinSock 2.0.  We need to dynamically */
   /* load ws2_32.dll and get the function pointers we need. */
-  wsock2 = LoadLibrary(TEXT("WS2_32.DLL"));
+  wsock2 = Curl_load_library(TEXT("WS2_32.DLL"));
   if(wsock2 == NULL) {
     failf(data, "failed to load WS2_32.DLL (%d)", ERRNO);
     return CURLE_FAILED_INIT;
@@ -1423,8 +1424,8 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done)
       for(;;) {
         if(data->set.is_fread_set) {
           /* read from user-supplied method */
-          result = (int)data->set.fread_func(buf, 1, BUFSIZE - 1,
-                                             data->set.in);
+          result = (int)data->state.fread_func(buf, 1, BUFSIZE - 1,
+                                               data->state.in);
           if(result == CURL_READFUNC_ABORT) {
             keepon = FALSE;
             result = CURLE_READ_ERROR;
@@ -1563,13 +1564,13 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done)
   pfd[0].fd = sockfd;
   pfd[0].events = POLLIN;
 
-  if(data->set.fread_func != (curl_read_callback)fread) {
+  if(data->set.is_fread_set) {
     poll_cnt = 1;
     interval_ms = 100; /* poll user-supplied read function */
   }
   else {
     /* really using fread, so infile is a FILE* */
-    pfd[1].fd = fileno((FILE *)data->set.in);
+    pfd[1].fd = fileno((FILE *)data->state.in);
     pfd[1].events = POLLIN;
     poll_cnt = 2;
     interval_ms = 1 * 1000;
@@ -1628,7 +1629,8 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done)
       }
       else {
         /* read from user-supplied method */
-        nread = (int)data->set.fread_func(buf, 1, BUFSIZE - 1, data->set.in);
+        nread = (int)data->state.fread_func(buf, 1, BUFSIZE - 1,
+                                            data->state.in);
         if(nread == CURL_READFUNC_ABORT) {
           keepon = FALSE;
           break;
diff --git a/lib/telnet.h b/lib/telnet.h
index ddb9e54..419a399 100644
--- a/lib/telnet.h
+++ b/lib/telnet.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/tftp.c b/lib/tftp.c
index 4c5796f..d7ff94f 100644
--- a/lib/tftp.c
+++ b/lib/tftp.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -57,10 +57,10 @@
 #include "url.h"
 #include "rawstr.h"
 #include "speedcheck.h"
-#include "curl_printf.h"
 #include "select.h"
 
-/* The last #include files should be: */
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
 #include "curl_memory.h"
 #include "memdebug.h"
 
@@ -312,14 +312,14 @@ static const char *tftp_option_get(const char *buf, size_t len,
 {
   size_t loc;
 
-  loc = Curl_strnlen( buf, len );
+  loc = Curl_strnlen(buf, len);
   loc++; /* NULL term */
 
   if(loc >= len)
     return NULL;
   *option = buf;
 
-  loc += Curl_strnlen( buf+loc, len-loc );
+  loc += Curl_strnlen(buf+loc, len-loc);
   loc++; /* NULL term */
 
   if(loc > len)
@@ -333,7 +333,7 @@ static CURLcode tftp_parse_option_ack(tftp_state_data_t *state,
                                       const char *ptr, int len)
 {
   const char *tmp = ptr;
-  struct SessionHandle *data = state->conn->data;
+  struct Curl_easy *data = state->conn->data;
 
   /* if OACK doesn't contain blksize option, the default (512) must be used */
   state->blksize = TFTP_BLKSIZE_DEFAULT;
@@ -352,7 +352,7 @@ static CURLcode tftp_parse_option_ack(tftp_state_data_t *state,
     if(checkprefix(option, TFTP_OPTION_BLKSIZE)) {
       long blksize;
 
-      blksize = strtol( value, NULL, 10 );
+      blksize = strtol(value, NULL, 10);
 
       if(!blksize) {
         failf(data, "invalid blocksize value in OACK packet");
@@ -384,7 +384,7 @@ static CURLcode tftp_parse_option_ack(tftp_state_data_t *state,
     else if(checkprefix(option, TFTP_OPTION_TSIZE)) {
       long tsize = 0;
 
-      tsize = strtol( value, NULL, 10 );
+      tsize = strtol(value, NULL, 10);
       infof(data, "%s (%ld)\n", "tsize parsed from OACK", tsize);
 
       /* tsize should be ignored on upload: Who cares about the size of the
@@ -405,7 +405,7 @@ static CURLcode tftp_parse_option_ack(tftp_state_data_t *state,
 static size_t tftp_option_add(tftp_state_data_t *state, size_t csize,
                               char *buf, const char *option)
 {
-  if(( strlen(option) + csize + 1 ) > (size_t)state->blksize)
+  if(( strlen(option) + csize + 1) > (size_t)state->blksize)
     return 0;
   strcpy(buf, option);
   return strlen(option) + 1;
@@ -416,7 +416,7 @@ static CURLcode tftp_connect_for_tx(tftp_state_data_t *state,
 {
   CURLcode result;
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
-  struct SessionHandle *data = state->conn->data;
+  struct Curl_easy *data = state->conn->data;
 
   infof(data, "%s\n", "Connected for transmit");
 #endif
@@ -432,7 +432,7 @@ static CURLcode tftp_connect_for_rx(tftp_state_data_t *state,
 {
   CURLcode result;
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
-  struct SessionHandle *data = state->conn->data;
+  struct Curl_easy *data = state->conn->data;
 
   infof(data, "%s\n", "Connected for receive");
 #endif
@@ -450,7 +450,7 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
   const char *mode = "octet";
   char *filename;
   char buf[64];
-  struct SessionHandle *data = state->conn->data;
+  struct Curl_easy *data = state->conn->data;
   CURLcode result = CURLE_OK;
 
   /* Set ascii mode if -B flag was used */
@@ -494,33 +494,36 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
              "%s%c%s%c", filename, '\0',  mode, '\0');
     sbytes = 4 + strlen(filename) + strlen(mode);
 
-    /* add tsize option */
-    if(data->set.upload && (data->state.infilesize != -1))
-      snprintf(buf, sizeof(buf), "%" CURL_FORMAT_CURL_OFF_T,
-               data->state.infilesize);
-    else
-      strcpy(buf, "0"); /* the destination is large enough */
-
-    sbytes += tftp_option_add(state, sbytes,
-                              (char *)state->spacket.data+sbytes,
-                              TFTP_OPTION_TSIZE);
-    sbytes += tftp_option_add(state, sbytes,
-                              (char *)state->spacket.data+sbytes, buf);
-    /* add blksize option */
-    snprintf( buf, sizeof(buf), "%d", state->requested_blksize );
-    sbytes += tftp_option_add(state, sbytes,
-                              (char *)state->spacket.data+sbytes,
-                              TFTP_OPTION_BLKSIZE);
-    sbytes += tftp_option_add(state, sbytes,
-                              (char *)state->spacket.data+sbytes, buf );
-
-    /* add timeout option */
-    snprintf( buf, sizeof(buf), "%d", state->retry_time);
-    sbytes += tftp_option_add(state, sbytes,
-                              (char *)state->spacket.data+sbytes,
-                              TFTP_OPTION_INTERVAL);
-    sbytes += tftp_option_add(state, sbytes,
-                              (char *)state->spacket.data+sbytes, buf );
+    /* optional addition of TFTP options */
+    if(!data->set.tftp_no_options) {
+      /* add tsize option */
+      if(data->set.upload && (data->state.infilesize != -1))
+        snprintf(buf, sizeof(buf), "%" CURL_FORMAT_CURL_OFF_T,
+                 data->state.infilesize);
+      else
+        strcpy(buf, "0"); /* the destination is large enough */
+
+      sbytes += tftp_option_add(state, sbytes,
+                                (char *)state->spacket.data+sbytes,
+                                TFTP_OPTION_TSIZE);
+      sbytes += tftp_option_add(state, sbytes,
+                                (char *)state->spacket.data+sbytes, buf);
+      /* add blksize option */
+      snprintf(buf, sizeof(buf), "%d", state->requested_blksize);
+      sbytes += tftp_option_add(state, sbytes,
+                                (char *)state->spacket.data+sbytes,
+                                TFTP_OPTION_BLKSIZE);
+      sbytes += tftp_option_add(state, sbytes,
+                                (char *)state->spacket.data+sbytes, buf);
+
+      /* add timeout option */
+      snprintf(buf, sizeof(buf), "%d", state->retry_time);
+      sbytes += tftp_option_add(state, sbytes,
+                                (char *)state->spacket.data+sbytes,
+                                TFTP_OPTION_INTERVAL);
+      sbytes += tftp_option_add(state, sbytes,
+                                (char *)state->spacket.data+sbytes, buf);
+    }
 
     /* the typecase for the 3rd argument is mostly for systems that do
        not have a size_t argument, like older unixes that want an 'int' */
@@ -578,7 +581,7 @@ static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event)
 {
   ssize_t sbytes;
   int rblock;
-  struct SessionHandle *data = state->conn->data;
+  struct Curl_easy *data = state->conn->data;
 
   switch(event) {
 
@@ -697,7 +700,7 @@ static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event)
  **********************************************************/
 static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event)
 {
-  struct SessionHandle *data = state->conn->data;
+  struct Curl_easy *data = state->conn->data;
   ssize_t sbytes;
   int rblock;
   CURLcode result = CURLE_OK;
@@ -886,7 +889,7 @@ static CURLcode tftp_state_machine(tftp_state_data_t *state,
                                    tftp_event_t event)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = state->conn->data;
+  struct Curl_easy *data = state->conn->data;
 
   switch(state->state) {
   case TFTP_STATE_START:
@@ -957,7 +960,7 @@ static CURLcode tftp_connect(struct connectdata *conn, bool *done)
   /* alloc pkt buffers based on specified blksize */
   if(conn->data->set.tftp_blksize) {
     blksize = (int)conn->data->set.tftp_blksize;
-    if(blksize > TFTP_BLKSIZE_MAX || blksize < TFTP_BLKSIZE_MIN )
+    if(blksize > TFTP_BLKSIZE_MAX || blksize < TFTP_BLKSIZE_MIN)
       return CURLE_TFTP_ILLEGAL;
   }
 
@@ -975,7 +978,7 @@ static CURLcode tftp_connect(struct connectdata *conn, bool *done)
       return CURLE_OUT_OF_MEMORY;
   }
 
-  /* we don't keep TFTP connections up bascially because there's none or very
+  /* we don't keep TFTP connections up basically because there's none or very
    * little gain for UDP */
   connclose(conn, "TFTP");
 
@@ -1078,7 +1081,7 @@ static CURLcode tftp_receive_packet(struct connectdata *conn)
   struct Curl_sockaddr_storage fromaddr;
   curl_socklen_t        fromlen;
   CURLcode              result = CURLE_OK;
-  struct SessionHandle  *data = conn->data;
+  struct Curl_easy  *data = conn->data;
   tftp_state_data_t     *state = (tftp_state_data_t *)conn->proto.tftpc;
   struct SingleRequest  *k = &data->req;
 
@@ -1197,7 +1200,7 @@ static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done)
   int                   rc;
   tftp_event_t          event;
   CURLcode              result = CURLE_OK;
-  struct SessionHandle  *data = conn->data;
+  struct Curl_easy  *data = conn->data;
   tftp_state_data_t     *state = (tftp_state_data_t *)conn->proto.tftpc;
   long                  timeout_ms = tftp_state_timeout(conn, &event);
 
@@ -1339,7 +1342,7 @@ static CURLcode tftp_do(struct connectdata *conn, bool *done)
 
 static CURLcode tftp_setup_connection(struct connectdata * conn)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   char * type;
   char command;
 
diff --git a/lib/tftp.h b/lib/tftp.h
index 117b40f..c2325b2 100644
--- a/lib/tftp.h
+++ b/lib/tftp.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/timeval.c b/lib/timeval.c
index 45731ac..629f1c8 100644
--- a/lib/timeval.c
+++ b/lib/timeval.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -113,10 +113,18 @@ struct timeval curlx_tvnow(void)
  * 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.
+ * Returns: the time difference in number of milliseconds. For large diffs it
+ * returns 0x7fffffff on 32bit time_t systems.
  */
 long curlx_tvdiff(struct timeval newer, struct timeval 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+
     (long)(newer.tv_usec-older.tv_usec)/1000;
 }
diff --git a/lib/timeval.h b/lib/timeval.h
index 3f1b9ea..50c31a2 100644
--- a/lib/timeval.h
+++ b/lib/timeval.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/transfer.c b/lib/transfer.c
index 718139b..f5987fe 100644
--- a/lib/transfer.c
+++ b/lib/transfer.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -71,17 +71,13 @@
 #include "url.h"
 #include "getinfo.h"
 #include "vtls/vtls.h"
-#include "http_digest.h"
-#include "curl_ntlm.h"
-#include "http_negotiate.h"
-#include "share.h"
 #include "select.h"
 #include "multiif.h"
 #include "connect.h"
 #include "non-ascii.h"
-#include "curl_printf.h"
 
-/* The last #include files should be: */
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
 #include "curl_memory.h"
 #include "memdebug.h"
 
@@ -91,7 +87,7 @@
  */
 CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   size_t buffersize = (size_t)bytes;
   int nread;
 #ifdef CURL_DOES_CONVERSIONS
@@ -115,8 +111,8 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp)
 
   /* this function returns a size_t, so we typecast to int to prevent warnings
      with picky compilers */
-  nread = (int)data->set.fread_func(data->req.upload_fromhere, 1,
-                                    buffersize, data->set.in);
+  nread = (int)data->state.fread_func(data->req.upload_fromhere, 1,
+                                      buffersize, data->state.in);
 
   if(nread == CURL_READFUNC_ABORT) {
     failf(data, "operation aborted by callback");
@@ -246,7 +242,7 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp)
  */
 CURLcode Curl_readrewind(struct connectdata *conn)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   conn->bits.rewindaftersend = FALSE; /* we rewind now */
 
@@ -289,8 +285,8 @@ CURLcode Curl_readrewind(struct connectdata *conn)
       /* If no CURLOPT_READFUNCTION is used, we know that we operate on a
          given FILE * stream and we can actually attempt to rewind that
          ourselves with fseek() */
-      if(data->set.fread_func == (curl_read_callback)fread) {
-        if(-1 != fseek(data->set.in, 0, SEEK_SET))
+      if(data->state.fread_func == (curl_read_callback)fread) {
+        if(-1 != fseek(data->state.in, 0, SEEK_SET))
           /* successful rewind */
           return CURLE_OK;
       }
@@ -356,7 +352,7 @@ static void read_rewind(struct connectdata *conn,
  * Check to see if CURLOPT_TIMECONDITION was met by comparing the time of the
  * remote document with the time provided by CURLOPT_TIMEVAL
  */
-bool Curl_meets_timecondition(struct SessionHandle *data, time_t timeofdoc)
+bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc)
 {
   if((timeofdoc == 0) || (data->set.timevalue == 0))
     return TRUE;
@@ -389,7 +385,7 @@ bool Curl_meets_timecondition(struct SessionHandle *data, time_t timeofdoc)
  * the stream was rewound (in which case we have data in a
  * buffer)
  */
-static CURLcode readwrite_data(struct SessionHandle *data,
+static CURLcode readwrite_data(struct Curl_easy *data,
                                struct connectdata *conn,
                                struct SingleRequest *k,
                                int *didwhat, bool *done)
@@ -399,6 +395,7 @@ static CURLcode readwrite_data(struct SessionHandle *data,
   size_t excess = 0; /* excess bytes read */
   bool is_empty_data = FALSE;
   bool readmore = FALSE; /* used by RTP to signal for more data */
+  int maxloops = 100;
 
   *done = FALSE;
 
@@ -409,7 +406,18 @@ static CURLcode readwrite_data(struct SessionHandle *data,
       data->set.buffer_size : BUFSIZE;
     size_t bytestoread = buffersize;
 
-    if(k->size != -1 && !k->header) {
+    if(
+#if defined(USE_NGHTTP2)
+       /* For HTTP/2, read data without caring about the content
+          length. This is safe because body in HTTP/2 is always
+          segmented thanks to its framing layer. Meanwhile, we have to
+          call Curl_read to ensure that http2_handle_stream_close is
+          called when we read all incoming bytes for a particular
+          stream. */
+       !((conn->handler->protocol & PROTO_FAMILY_HTTP) &&
+         conn->httpversion == 20) &&
+#endif
+       k->size != -1 && !k->header) {
       /* make sure we don't read "too much" if we can help it since we
          might be pipelining and then someone else might want to read what
          follows! */
@@ -686,7 +694,7 @@ static CURLcode readwrite_data(struct SessionHandle *data,
         }
 
         nread = (ssize_t) (k->maxdownload - k->bytecount);
-        if(nread < 0 ) /* this should be unusual */
+        if(nread < 0) /* this should be unusual */
           nread = 0;
 
         k->keepon &= ~KEEP_RECV; /* we're done reading */
@@ -771,7 +779,7 @@ static CURLcode readwrite_data(struct SessionHandle *data,
           return result;
       }
 
-    } /* if(! header and data to read ) */
+    } /* if(!header and data to read) */
 
     if(conn->handler->readwrite &&
        (excess > 0 && !conn->bits.stream_was_rewound)) {
@@ -794,10 +802,10 @@ static CURLcode readwrite_data(struct SessionHandle *data,
       k->keepon &= ~KEEP_RECV;
     }
 
-  } while(data_pending(conn));
+  } while(data_pending(conn) && maxloops--);
 
   if(((k->keepon & (KEEP_RECV|KEEP_SEND)) == KEEP_SEND) &&
-     conn->bits.close ) {
+     conn->bits.close) {
     /* When we've read the entire thing and the close bit is set, the server
        may now close the connection. If there's now any kind of sending going
        on from our side, we need to stop that immediately. */
@@ -808,10 +816,24 @@ static CURLcode readwrite_data(struct SessionHandle *data,
   return CURLE_OK;
 }
 
+static CURLcode done_sending(struct connectdata *conn,
+                             struct SingleRequest *k)
+{
+  k->keepon &= ~KEEP_SEND; /* we're done writing */
+
+  if(conn->bits.rewindaftersend) {
+    CURLcode result = Curl_readrewind(conn);
+    if(result)
+      return result;
+  }
+  return CURLE_OK;
+}
+
+
 /*
  * Send data to upload to the server, when the socket is writable.
  */
-static CURLcode readwrite_upload(struct SessionHandle *data,
+static CURLcode readwrite_upload(struct Curl_easy *data,
                                  struct connectdata *conn,
                                  struct SingleRequest *k,
                                  int *didwhat)
@@ -879,14 +901,9 @@ static CURLcode readwrite_upload(struct SessionHandle *data,
         break;
       }
       else if(nread<=0) {
-        /* done */
-        k->keepon &= ~KEEP_SEND; /* we're done writing */
-
-        if(conn->bits.rewindaftersend) {
-          result = Curl_readrewind(conn);
-          if(result)
-            return result;
-        }
+        result = done_sending(conn, k);
+        if(result)
+          return result;
         break;
       }
 
@@ -923,7 +940,8 @@ static CURLcode readwrite_upload(struct SessionHandle *data,
             if(!data->set.crlf) {
               /* we're here only because FTP is in ASCII mode...
                  bump infilesize for the LF we just added */
-              data->state.infilesize++;
+              if(data->state.infilesize != -1)
+                data->state.infilesize++;
             }
           }
           else
@@ -995,8 +1013,9 @@ static CURLcode readwrite_upload(struct SessionHandle *data,
       data->req.upload_present = 0; /* no more bytes left */
 
       if(k->upload_done) {
-        /* switch off writing, we're done! */
-        k->keepon &= ~KEEP_SEND; /* we're done writing */
+        result = done_sending(conn, k);
+        if(result)
+          return result;
       }
     }
 
@@ -1012,7 +1031,7 @@ static CURLcode readwrite_upload(struct SessionHandle *data,
  * be read and written to/from the connection.
  */
 CURLcode Curl_readwrite(struct connectdata *conn,
-                        struct SessionHandle *data,
+                        struct Curl_easy *data,
                         bool *done)
 {
   struct SingleRequest *k = &data->req;
@@ -1189,7 +1208,7 @@ int Curl_single_getsock(const struct connectdata *conn,
                                                 of sockets */
                         int numsocks)
 {
-  const struct SessionHandle *data = conn->data;
+  const struct Curl_easy *data = conn->data;
   int bitmap = GETSOCK_BLANK;
   unsigned sockindex = 0;
 
@@ -1284,10 +1303,20 @@ long Curl_sleep_time(curl_off_t rate_bps, curl_off_t cur_rate_bps,
   return (long)rv;
 }
 
+/* Curl_init_CONNECT() gets called each time the handle switches to CONNECT
+   which means this gets called once for each subsequent redirect etc */
+void Curl_init_CONNECT(struct Curl_easy *data)
+{
+  data->state.fread_func = data->set.fread_func_set;
+  data->state.in = data->set.in_set;
+}
+
 /*
- * Curl_pretransfer() is called immediately before a transfer starts.
+ * Curl_pretransfer() is called immediately before a transfer starts, and only
+ * once for one transfer no matter if it has redirects or do multi-pass
+ * authentication etc.
  */
-CURLcode Curl_pretransfer(struct SessionHandle *data)
+CURLcode Curl_pretransfer(struct Curl_easy *data)
 {
   CURLcode result;
   if(!data->change.url) {
@@ -1356,6 +1385,16 @@ CURLcode Curl_pretransfer(struct SessionHandle *data)
        consider to be fine */
     data->state.authhost.picked &= data->state.authhost.want;
     data->state.authproxy.picked &= data->state.authproxy.want;
+
+    if(data->set.wildcardmatch) {
+      struct WildcardData *wc = &data->wildcard;
+      if(!wc->filelist) {
+        result = Curl_wildcard_init(wc); /* init wildcard structures */
+        if(result)
+          return CURLE_OUT_OF_MEMORY;
+      }
+    }
+
   }
 
   return result;
@@ -1364,7 +1403,7 @@ CURLcode Curl_pretransfer(struct SessionHandle *data)
 /*
  * Curl_posttransfer() is called immediately after a transfer ends
  */
-CURLcode Curl_posttransfer(struct SessionHandle *data)
+CURLcode Curl_posttransfer(struct Curl_easy *data)
 {
 #if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(HAVE_MSG_NOSIGNAL)
   /* restore the signal handler for SIGPIPE before we get back */
@@ -1384,16 +1423,18 @@ CURLcode Curl_posttransfer(struct SessionHandle *data)
  */
 static size_t strlen_url(const char *url)
 {
-  const char *ptr;
+  const unsigned char *ptr;
   size_t newlen=0;
   bool left=TRUE; /* left side of the ? */
 
-  for(ptr=url; *ptr; ptr++) {
+  for(ptr=(unsigned char *)url; *ptr; ptr++) {
     switch(*ptr) {
     case '?':
       left=FALSE;
       /* fall through */
     default:
+      if(*ptr >= 0x80)
+        newlen += 2;
       newlen++;
       break;
     case ' ':
@@ -1414,9 +1455,9 @@ static void strcpy_url(char *output, const char *url)
 {
   /* we must add this with whitespace-replacing */
   bool left=TRUE;
-  const char *iptr;
+  const unsigned char *iptr;
   char *optr = output;
-  for(iptr = url;    /* read from here */
+  for(iptr = (unsigned char *)url;    /* read from here */
       *iptr;         /* until zero byte */
       iptr++) {
     switch(*iptr) {
@@ -1424,7 +1465,12 @@ static void strcpy_url(char *output, const char *url)
       left=FALSE;
       /* fall through */
     default:
-      *optr++=*iptr;
+      if(*iptr >= 0x80) {
+        snprintf(optr, 4, "%%%02x", *iptr);
+        optr += 3;
+      }
+      else
+        *optr++=*iptr;
       break;
     case ' ':
       if(left) {
@@ -1614,7 +1660,7 @@ static char *concat_url(const char *base, const char *relurl)
  * Curl_follow() handles the URL redirect magic. Pass in the 'newurl' string
  * as given by the remote server and set up the new URL to request.
  */
-CURLcode Curl_follow(struct SessionHandle *data,
+CURLcode Curl_follow(struct Curl_easy *data,
                      char *newurl, /* this 'newurl' is the Location: string,
                                       and it must be malloc()ed before passed
                                       here */
@@ -1672,23 +1718,21 @@ CURLcode Curl_follow(struct SessionHandle *data,
     newurl = absolute;
   }
   else {
+    /* The new URL MAY contain space or high byte values, that means a mighty
+       stupid redirect URL but we still make an effort to do "right". */
+    char *newest;
+    size_t newlen = strlen_url(newurl);
+
     /* This is an absolute URL, don't allow the custom port number */
     disallowport = TRUE;
 
-    if(strchr(newurl, ' ')) {
-      /* This new URL contains at least one space, this is a mighty stupid
-         redirect but we still make an effort to do "right". */
-      char *newest;
-      size_t newlen = strlen_url(newurl);
-
-      newest = malloc(newlen+1); /* get memory for this */
-      if(!newest)
-        return CURLE_OUT_OF_MEMORY;
-      strcpy_url(newest, newurl); /* create a space-free URL */
+    newest = malloc(newlen+1); /* get memory for this */
+    if(!newest)
+      return CURLE_OUT_OF_MEMORY;
+    strcpy_url(newest, newurl); /* create a space-free URL */
 
-      free(newurl); /* that was no good */
-      newurl = newest; /* use this instead now */
-    }
+    free(newurl); /* that was no good */
+    newurl = newest; /* use this instead now */
 
   }
 
@@ -1814,70 +1858,13 @@ CURLcode Curl_follow(struct SessionHandle *data,
 #endif /* CURL_DISABLE_HTTP */
 }
 
-CURLcode
-Curl_reconnect_request(struct connectdata **connp)
-{
-  CURLcode result = CURLE_OK;
-  struct connectdata *conn = *connp;
-  struct SessionHandle *data = conn->data;
-
-  /* This was a re-use of a connection and we got a write error in the
-   * DO-phase. Then we DISCONNECT this connection and have another attempt to
-   * CONNECT and then DO again! The retry cannot possibly find another
-   * connection to re-use, since we only keep one possible connection for
-   * each.  */
-
-  infof(data, "Re-used connection seems dead, get a new one\n");
-
-  connclose(conn, "Reconnect dead connection"); /* enforce close */
-  result = Curl_done(&conn, result, FALSE); /* we are so done with this */
-
-  /* conn may no longer be a good pointer, clear it to avoid mistakes by
-     parent functions */
-  *connp = NULL;
-
-  /*
-   * According to bug report #1330310. We need to check for CURLE_SEND_ERROR
-   * here as well. I figure this could happen when the request failed on a FTP
-   * connection and thus Curl_done() itself tried to use the connection
-   * (again). Slight Lack of feedback in the report, but I don't think this
-   * extra check can do much harm.
-   */
-  if(!result || (CURLE_SEND_ERROR == result)) {
-    bool async;
-    bool protocol_done = TRUE;
-
-    /* Now, redo the connect and get a new connection */
-    result = Curl_connect(data, connp, &async, &protocol_done);
-    if(!result) {
-      /* We have connected or sent away a name resolve query fine */
-
-      conn = *connp; /* setup conn to again point to something nice */
-      if(async) {
-        /* Now, if async is TRUE here, we need to wait for the name
-           to resolve */
-        result = Curl_resolver_wait_resolv(conn, NULL);
-        if(result)
-          return result;
-
-        /* Resolved, continue with the connection */
-        result = Curl_async_resolved(conn, &protocol_done);
-        if(result)
-          return result;
-      }
-    }
-  }
-
-  return result;
-}
-
 /* Returns CURLE_OK *and* sets '*url' if a request retry is wanted.
 
    NOTE: that the *url is malloc()ed. */
 CURLcode Curl_retry_request(struct connectdata *conn,
                             char **url)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   *url = NULL;
 
@@ -1933,7 +1920,7 @@ Curl_setup_transfer(
   curl_off_t *writecountp   /* return number of bytes written or NULL */
   )
 {
-  struct SessionHandle *data;
+  struct Curl_easy *data;
   struct SingleRequest *k;
 
   DEBUGASSERT(conn != NULL);
diff --git a/lib/transfer.h b/lib/transfer.h
index 316aeae..0e253e3 100644
--- a/lib/transfer.h
+++ b/lib/transfer.h
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -22,9 +22,11 @@
  *
  ***************************************************************************/
 
-CURLcode Curl_pretransfer(struct SessionHandle *data);
+void Curl_init_CONNECT(struct Curl_easy *data);
+
+CURLcode Curl_pretransfer(struct Curl_easy *data);
 CURLcode Curl_second_connect(struct connectdata *conn);
-CURLcode Curl_posttransfer(struct SessionHandle *data);
+CURLcode Curl_posttransfer(struct Curl_easy *data);
 
 typedef enum {
   FOLLOW_NONE,  /* not used within the function, just a placeholder to
@@ -36,20 +38,19 @@ typedef enum {
   FOLLOW_LAST   /* never used */
 } followtype;
 
-CURLcode Curl_follow(struct SessionHandle *data, char *newurl,
+CURLcode Curl_follow(struct Curl_easy *data, char *newurl,
                      followtype type);
 
 
 CURLcode Curl_readwrite(struct connectdata *conn,
-                        struct SessionHandle *data, bool *done);
+                        struct Curl_easy *data, bool *done);
 int Curl_single_getsock(const struct connectdata *conn,
                         curl_socket_t *socks,
                         int numsocks);
 CURLcode Curl_readrewind(struct connectdata *conn);
 CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp);
-CURLcode Curl_reconnect_request(struct connectdata **connp);
 CURLcode Curl_retry_request(struct connectdata *conn, char **url);
-bool Curl_meets_timecondition(struct SessionHandle *data, time_t timeofdoc);
+bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc);
 
 /* This sets up a forthcoming transfer */
 void
diff --git a/lib/url.c b/lib/url.c
index 406c1f0..e547e5c 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -75,7 +75,7 @@ void idn_free (void *ptr);
 #endif
 #elif defined(USE_WIN32_IDN)
 /* prototype for curl_win32_idn_to_ascii() */
-int curl_win32_idn_to_ascii(const char *in, char **out);
+bool curl_win32_idn_to_ascii(const char *in, char **out);
 #endif  /* USE_LIBIDN */
 
 #include "urldata.h"
@@ -111,6 +111,7 @@ int curl_win32_idn_to_ascii(const char *in, char **out);
 #include "telnet.h"
 #include "tftp.h"
 #include "http.h"
+#include "http2.h"
 #include "file.h"
 #include "curl_ldap.h"
 #include "ssh.h"
@@ -118,7 +119,7 @@ int curl_win32_idn_to_ascii(const char *in, char **out);
 #include "url.h"
 #include "connect.h"
 #include "inet_ntop.h"
-#include "curl_ntlm.h"
+#include "http_ntlm.h"
 #include "curl_ntlm_wb.h"
 #include "socks.h"
 #include "curl_rtmp.h"
@@ -129,26 +130,27 @@ int curl_win32_idn_to_ascii(const char *in, char **out);
 #include "pipeline.h"
 #include "dotdot.h"
 #include "strdup.h"
+/* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_memory.h"
-/* The last #include file should be: */
 #include "memdebug.h"
 
 /* Local static prototypes */
 static struct connectdata *
-find_oldest_idle_connection(struct SessionHandle *data);
-static struct connectdata *
-find_oldest_idle_connection_in_bundle(struct SessionHandle *data,
+find_oldest_idle_connection_in_bundle(struct Curl_easy *data,
                                       struct connectbundle *bundle);
 static void conn_free(struct connectdata *conn);
+static void free_fixed_hostname(struct hostname *host);
 static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke);
-static CURLcode parse_url_login(struct SessionHandle *data,
+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);
+
 /*
  * Protocol table.
  */
@@ -275,7 +277,7 @@ static const struct Curl_handler Curl_handler_dummy = {
   PROTOPT_NONE                          /* flags */
 };
 
-void Curl_freeset(struct SessionHandle *data)
+void Curl_freeset(struct Curl_easy *data)
 {
   /* Free all dynamic strings stored in the data->set substructure. */
   enum dupstring i;
@@ -295,7 +297,7 @@ void Curl_freeset(struct SessionHandle *data)
   data->change.url = NULL;
 }
 
-static CURLcode setstropt(char **charp, char *s)
+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. */
@@ -303,12 +305,12 @@ static CURLcode setstropt(char **charp, char *s)
   Curl_safefree(*charp);
 
   if(s) {
-    s = strdup(s);
+    char *str = strdup(s);
 
-    if(!s)
+    if(!str)
       return CURLE_OUT_OF_MEMORY;
 
-    *charp = s;
+    *charp = str;
   }
 
   return CURLE_OK;
@@ -353,7 +355,7 @@ static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp)
   return result;
 }
 
-CURLcode Curl_dupset(struct SessionHandle *dst, struct SessionHandle *src)
+CURLcode Curl_dupset(struct Curl_easy *dst, struct Curl_easy *src)
 {
   CURLcode result = CURLE_OK;
   enum dupstring i;
@@ -396,7 +398,7 @@ CURLcode Curl_dupset(struct SessionHandle *dst, struct SessionHandle *src)
  * when curl_easy_perform() is invoked.
  */
 
-CURLcode Curl_close(struct SessionHandle *data)
+CURLcode Curl_close(struct Curl_easy *data)
 {
   struct Curl_multi *m;
 
@@ -482,28 +484,34 @@ CURLcode Curl_close(struct SessionHandle *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);
+  }
+
   Curl_freeset(data);
   free(data);
   return CURLE_OK;
 }
 
 /*
- * Initialize the UserDefined fields within a SessionHandle.
- * This may be safely called on a new or existing SessionHandle.
+ * Initialize the UserDefined fields within a Curl_easy.
+ * This may be safely called on a new or existing Curl_easy.
  */
 CURLcode Curl_init_userdefined(struct UserDefined *set)
 {
   CURLcode result = CURLE_OK;
 
   set->out = stdout; /* default output to stdout */
-  set->in  = stdin;  /* default input from stdin */
+  set->in_set = stdin;  /* default input from stdin */
   set->err  = stderr;  /* default stderr to stderr */
 
   /* use fwrite as default function to store output */
   set->fwrite_func = (curl_write_callback)fwrite;
 
   /* use fread as default function to read input */
-  set->fread_func = (curl_read_callback)fread;
+  set->fread_func_set = (curl_read_callback)fread;
   set->is_fread_set = 0;
   set->is_fwrite_set = 0;
 
@@ -569,33 +577,16 @@ CURLcode Curl_init_userdefined(struct UserDefined *set)
    * seem not to follow rfc1961 section 4.3/4.4
    */
   set->socks5_gssapi_nec = FALSE;
-  /* set default GSS-API service name */
-  result = setstropt(&set->str[STRING_SOCKS5_GSSAPI_SERVICE],
-                     (char *) CURL_DEFAULT_SOCKS5_GSSAPI_SERVICE);
-  if(result)
-    return result;
-
-  /* set default negotiate proxy service name */
-  result = setstropt(&set->str[STRING_PROXY_SERVICE_NAME],
-                     (char *) CURL_DEFAULT_PROXY_SERVICE_NAME);
-  if(result)
-    return result;
-
-  /* set default negotiate service name */
-  result = setstropt(&set->str[STRING_SERVICE_NAME],
-                     (char *) CURL_DEFAULT_SERVICE_NAME);
-  if(result)
-    return result;
 #endif
 
   /* This is our preferred CA cert bundle/path since install time */
 #if defined(CURL_CA_BUNDLE)
-  result = setstropt(&set->str[STRING_SSL_CAFILE], (char *) CURL_CA_BUNDLE);
+  result = setstropt(&set->str[STRING_SSL_CAFILE], CURL_CA_BUNDLE);
   if(result)
     return result;
 #endif
 #if defined(CURL_CA_PATH)
-  result = setstropt(&set->str[STRING_SSL_CAPATH], (char *) CURL_CA_PATH);
+  result = setstropt(&set->str[STRING_SSL_CAPATH], CURL_CA_PATH);
   if(result)
     return result;
 #endif
@@ -610,12 +601,15 @@ CURLcode Curl_init_userdefined(struct UserDefined *set)
   set->tcp_keepalive = FALSE;
   set->tcp_keepintvl = 60;
   set->tcp_keepidle = 60;
+  set->tcp_fastopen = FALSE;
 
   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 */
+
+  Curl_http2_init_userset(set);
   return result;
 }
 
@@ -627,16 +621,16 @@ CURLcode Curl_init_userdefined(struct UserDefined *set)
  * @return CURLcode
  */
 
-CURLcode Curl_open(struct SessionHandle **curl)
+CURLcode Curl_open(struct Curl_easy **curl)
 {
   CURLcode result;
-  struct SessionHandle *data;
+  struct Curl_easy *data;
 
   /* Very simple start-up: alloc the struct, init it with zeroes and return */
-  data = calloc(1, sizeof(struct SessionHandle));
+  data = calloc(1, sizeof(struct Curl_easy));
   if(!data) {
     /* this is a very serious error */
-    DEBUGF(fprintf(stderr, "Error: calloc of SessionHandle failed\n"));
+    DEBUGF(fprintf(stderr, "Error: calloc of Curl_easy failed\n"));
     return CURLE_OUT_OF_MEMORY;
   }
 
@@ -673,6 +667,8 @@ CURLcode Curl_open(struct SessionHandle **curl)
     data->wildcard.filelist = NULL;
     data->set.fnmatch = ZERO_NULL;
     data->set.maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */
+
+    Curl_http2_init_state(&data->state);
   }
 
   if(result) {
@@ -688,7 +684,7 @@ CURLcode Curl_open(struct SessionHandle **curl)
   return result;
 }
 
-CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
+CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option,
                      va_list param)
 {
   char *argptr;
@@ -705,7 +701,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
   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;
+    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 */
@@ -740,33 +736,33 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
      * 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;
+    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;
+    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;
+    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;
+    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;
+    data->set.hide_progress = (0 != va_arg(param, long)) ? TRUE : FALSE;
     if(data->set.hide_progress)
       data->progress.flags |= PGRS_HIDE;
     else
@@ -776,14 +772,14 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
     /*
      * Do not include the body part in the output data stream.
      */
-    data->set.opt_no_body = (0 != va_arg(param, long))?TRUE:FALSE;
+    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;
+    data->set.http_fail_on_error = (0 != va_arg(param, long)) ? TRUE : FALSE;
     break;
   case CURLOPT_UPLOAD:
   case CURLOPT_PUT:
@@ -791,7 +787,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
      * 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;
+    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;
@@ -807,7 +803,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
      * 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;
+    data->set.get_filetime = (0 != va_arg(param, long)) ? TRUE : FALSE;
     break;
   case CURLOPT_FTP_CREATE_MISSING_DIRS:
     /*
@@ -835,11 +831,18 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
      * Option that specifies how quickly an server response must be obtained
      * before it is considered failure. For pingpong protocols.
      */
-    data->set.server_response_timeout = va_arg( param , long ) * 1000;
+    data->set.server_response_timeout = va_arg(param, long) * 1000;
+    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
+     * TFTP option that specifies the block size to use for data transmission.
      */
     data->set.tftp_blksize = va_arg(param, long);
     break;
@@ -848,13 +851,13 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
      * 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;
+    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;
+    data->set.ftp_append = (0 != va_arg(param, long)) ? TRUE : FALSE;
     break;
   case CURLOPT_FTP_FILEMETHOD:
     /*
@@ -882,7 +885,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
      *
      * Transfer using ASCII (instead of BINARY).
      */
-    data->set.prefer_ascii = (0 != va_arg(param, long))?TRUE:FALSE;
+    data->set.prefer_ascii = (0 != va_arg(param, long)) ? TRUE : FALSE;
     break;
   case CURLOPT_TIMECONDITION:
     /*
@@ -915,7 +918,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
     /*
      * Switch on automatic referer that gets set if curl follows locations.
      */
-    data->set.http_auto_referer = (0 != va_arg(param, long))?TRUE:FALSE;
+    data->set.http_auto_referer = (0 != va_arg(param, long)) ? TRUE : FALSE;
     break;
 
   case CURLOPT_ACCEPT_ENCODING:
@@ -931,18 +934,19 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
     argptr = va_arg(param, char *);
     result = setstropt(&data->set.str[STRING_ENCODING],
                        (argptr && !*argptr)?
-                       (char *) ALL_CONTENT_ENCODINGS: argptr);
+                       ALL_CONTENT_ENCODINGS: argptr);
     break;
 
   case CURLOPT_TRANSFER_ENCODING:
-    data->set.http_transfer_encoding = (0 != va_arg(param, long))?TRUE:FALSE;
+    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;
+    data->set.http_follow_location = (0 != va_arg(param, long)) ? TRUE : FALSE;
     break;
 
   case CURLOPT_UNRESTRICTED_AUTH:
@@ -951,7 +955,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
      * hostname changed.
      */
     data->set.http_disable_hostname_check_before_authentication =
-      (0 != va_arg(param, long))?TRUE:FALSE;
+      (0 != va_arg(param, long)) ? TRUE : FALSE;
     break;
 
   case CURLOPT_MAXREDIRS:
@@ -1212,7 +1216,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
      * We run mostly with the original cookie spec, as hardly anyone implements
      * anything else.
      */
-    data->set.cookiesession = (0 != va_arg(param, long))?TRUE:FALSE;
+    data->set.cookiesession = (0 != va_arg(param, long)) ? TRUE : FALSE;
     break;
 
   case CURLOPT_COOKIELIST:
@@ -1289,7 +1293,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
      */
     arg = va_arg(param, long);
 #ifndef USE_NGHTTP2
-    if(arg == CURL_HTTP_VERSION_2_0)
+    if(arg >= CURL_HTTP_VERSION_2)
       return CURLE_UNSUPPORTED_PROTOCOL;
 #endif
     data->set.httpversion = arg;
@@ -1311,7 +1315,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
 
     /* 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;
+    data->state.authhost.iestyle = (auth & CURLAUTH_DIGEST_IE) ? TRUE : FALSE;
 
     if(auth & CURLAUTH_DIGEST_IE) {
       auth |= CURLAUTH_DIGEST; /* set standard digest bit */
@@ -1374,7 +1378,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
     /*
      * Tunnel operations through the proxy instead of normal proxy use
      */
-    data->set.tunnel_thru_httpproxy = (0 != va_arg(param, long))?TRUE:FALSE;
+    data->set.tunnel_thru_httpproxy = (0 != va_arg(param, long)) ?
+                                      TRUE : FALSE;
     break;
 
   case CURLOPT_PROXYPORT:
@@ -1400,7 +1405,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
 
     /* 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;
+    data->state.authproxy.iestyle = (auth & CURLAUTH_DIGEST_IE) ? TRUE : FALSE;
 
     if(auth & CURLAUTH_DIGEST_IE) {
       auth |= CURLAUTH_DIGEST; /* set standard digest bit */
@@ -1475,32 +1480,28 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
 #endif   /* CURL_DISABLE_PROXY */
 
 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
-  case CURLOPT_SOCKS5_GSSAPI_SERVICE:
+  case CURLOPT_SOCKS5_GSSAPI_NEC:
     /*
-     * Set GSS-API service name
+     * Set flag for NEC SOCK5 support
      */
-    result = setstropt(&data->set.str[STRING_SOCKS5_GSSAPI_SERVICE],
-                       va_arg(param, char *));
+    data->set.socks5_gssapi_nec = (0 != va_arg(param, long)) ? TRUE : FALSE;
     break;
 
+  case CURLOPT_SOCKS5_GSSAPI_SERVICE:
   case CURLOPT_PROXY_SERVICE_NAME:
     /*
-     * Set negotiate 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
 
-  case CURLOPT_SOCKS5_GSSAPI_NEC:
-    /*
-     * set flag for nec socks5 support
-     */
-    data->set.socks5_gssapi_nec = (0 != va_arg(param, long))?TRUE:FALSE;
-    break;
-
+#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) || \
+    defined(USE_SPNEGO)
   case CURLOPT_SERVICE_NAME:
     /*
-     * Set negotiate service identity
+     * Set authentication service name for DIGEST-MD5, Kerberos 5 and SPNEGO
      */
     result = setstropt(&data->set.str[STRING_SERVICE_NAME],
                        va_arg(param, char *));
@@ -1534,20 +1535,19 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
      */
     result = setstropt(&data->set.str[STRING_FTPPORT],
                        va_arg(param, char *));
-    data->set.ftp_use_port = (NULL != data->set.str[STRING_FTPPORT]) ?
-                             TRUE:FALSE;
+    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;
+    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;
+    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;
+    data->set.ftp_use_pret = (0 != va_arg(param, long)) ? TRUE : FALSE;
     break;
 
   case CURLOPT_FTP_SSL_CCC:
@@ -1559,7 +1559,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
      * 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;
+    data->set.ftp_skip_ip = (0 != va_arg(param, long)) ? TRUE : FALSE;
     break;
 
   case CURLOPT_READDATA:
@@ -1567,7 +1567,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
      * FILE pointer to read the file to be uploaded from. Or possibly
      * used as argument to the read callback.
      */
-    data->set.in = va_arg(param, void *);
+    data->set.in_set = va_arg(param, void *);
     break;
   case CURLOPT_INFILESIZE:
     /*
@@ -1695,7 +1695,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
 
   case CURLOPT_XOAUTH2_BEARER:
     /*
-     * XOAUTH2 bearer token to use in the operation
+     * OAuth 2.0 bearer token to use in the operation
      */
     result = setstropt(&data->set.str[STRING_BEARER],
                        va_arg(param, char *));
@@ -1862,11 +1862,11 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
     /*
      * Read data callback
      */
-    data->set.fread_func = va_arg(param, curl_read_callback);
-    if(!data->set.fread_func) {
+    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 = (curl_read_callback)fread;
+      data->set.fread_func_set = (curl_read_callback)fread;
     }
     else
       data->set.is_fread_set = 1;
@@ -1967,7 +1967,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
     /*
      * Kludgy option to enable CRLF conversions. Subject for removal.
      */
-    data->set.crlf = (0 != va_arg(param, long))?TRUE:FALSE;
+    data->set.crlf = (0 != va_arg(param, long)) ? TRUE : FALSE;
     break;
 
   case CURLOPT_INTERFACE:
@@ -1996,7 +1996,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
      */
     result = setstropt(&data->set.str[STRING_KRB_LEVEL],
                        va_arg(param, char *));
-    data->set.krb = (NULL != data->set.str[STRING_KRB_LEVEL])?TRUE:FALSE;
+    data->set.krb = (data->set.str[STRING_KRB_LEVEL]) ? TRUE : FALSE;
     break;
   case CURLOPT_GSSAPI_DELEGATION:
     /*
@@ -2008,7 +2008,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
     /*
      * Enable peer SSL verifying.
      */
-    data->set.ssl.verifypeer = (0 != va_arg(param, long))?TRUE:FALSE;
+    data->set.ssl.verifypeer = (0 != va_arg(param, long)) ? TRUE : FALSE;
     break;
   case CURLOPT_SSL_VERIFYHOST:
     /*
@@ -2026,7 +2026,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
       return CURLE_BAD_FUNCTION_ARGUMENT;
     }
 
-    data->set.ssl.verifyhost = (0 != arg)?TRUE:FALSE;
+    data->set.ssl.verifyhost = (0 != arg) ? TRUE : FALSE;
     break;
   case CURLOPT_SSL_VERIFYSTATUS:
     /*
@@ -2037,7 +2037,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
       break;
     }
 
-    data->set.ssl.verifystatus = (0 != va_arg(param, long))?TRUE:FALSE;
+    data->set.ssl.verifystatus = (0 != va_arg(param, long)) ? TRUE : FALSE;
     break;
   case CURLOPT_SSL_CTX_FUNCTION:
 #ifdef have_curlssl_ssl_ctx
@@ -2068,22 +2068,26 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
       break;
     }
 
-    data->set.ssl.falsestart = (0 != va_arg(param, long))?TRUE:FALSE;
+    data->set.ssl.falsestart = (0 != va_arg(param, long)) ? TRUE : FALSE;
     break;
   case CURLOPT_CERTINFO:
 #ifdef have_curlssl_certinfo
-    data->set.ssl.certinfo = (0 != va_arg(param, long))?TRUE:FALSE;
+    data->set.ssl.certinfo = (0 != va_arg(param, long)) ? TRUE : FALSE;
 #else
     result = CURLE_NOT_BUILT_IN;
 #endif
     break;
   case CURLOPT_PINNEDPUBLICKEY:
+#ifdef have_curlssl_pinnedpubkey /* only by supported backends */
     /*
      * Set pinned public key for SSL connection.
      * Specify file name of the public key in DER format.
      */
     result = setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY],
                        va_arg(param, char *));
+#else
+    result = CURLE_NOT_BUILT_IN;
+#endif
     break;
   case CURLOPT_CAINFO:
     /*
@@ -2135,7 +2139,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
      */
     data->set.buffer_size = va_arg(param, long);
 
-    if((data->set.buffer_size> (BUFSIZE -1 )) ||
+    if((data->set.buffer_size> (BUFSIZE -1)) ||
        (data->set.buffer_size < 1))
       data->set.buffer_size = 0; /* huge internal default */
 
@@ -2146,7 +2150,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
      * 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;
+    data->set.no_signal = (0 != va_arg(param, long)) ? TRUE : FALSE;
     break;
 
   case CURLOPT_SHARE:
@@ -2262,7 +2266,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
      * Enable or disable TCP_NODELAY, which will disable/enable the Nagle
      * algorithm
      */
-    data->set.tcp_nodelay = (0 != va_arg(param, long))?TRUE:FALSE;
+    data->set.tcp_nodelay = (0 != va_arg(param, long)) ? TRUE : FALSE;
     break;
 
   case CURLOPT_FTP_ACCOUNT:
@@ -2271,14 +2275,14 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
     break;
 
   case CURLOPT_IGNORE_CONTENT_LENGTH:
-    data->set.ignorecl = (0 != va_arg(param, long))?TRUE:FALSE;
+    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;
+    data->set.connect_only = (0 != va_arg(param, long)) ? TRUE : FALSE;
     break;
 
   case CURLOPT_FTP_ALTERNATIVE_TO_USER:
@@ -2331,7 +2335,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
     break;
 
   case CURLOPT_SSL_SESSIONID_CACHE:
-    data->set.ssl.sessionid = (0 != va_arg(param, long))?TRUE:FALSE;
+    data->set.ssl.sessionid = (0 != va_arg(param, long)) ? TRUE : FALSE;
     break;
 
 #ifdef USE_LIBSSH2
@@ -2392,14 +2396,14 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
     /*
      * disable libcurl transfer encoding is used
      */
-    data->set.http_te_skip = (0 == va_arg(param, long))?TRUE:FALSE;
+    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;
+    data->set.http_ce_skip = (0 == va_arg(param, long)) ? TRUE : FALSE;
     break;
 
   case CURLOPT_NEW_FILE_PERMS:
@@ -2441,6 +2445,12 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
     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],
@@ -2573,7 +2583,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
     break;
 
   case CURLOPT_WILDCARDMATCH:
-    data->set.wildcardmatch = (0 != va_arg(param, long))?TRUE:FALSE;
+    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);
@@ -2624,7 +2634,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
     break;
 
   case CURLOPT_TCP_KEEPALIVE:
-    data->set.tcp_keepalive = (0 != va_arg(param, long))?TRUE:FALSE;
+    data->set.tcp_keepalive = (0 != va_arg(param, long)) ? TRUE : FALSE;
     break;
   case CURLOPT_TCP_KEEPIDLE:
     data->set.tcp_keepidle = va_arg(param, long);
@@ -2632,11 +2642,18 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
   case CURLOPT_TCP_KEEPINTVL:
     data->set.tcp_keepintvl = va_arg(param, long);
     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;
+    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;
+    data->set.ssl_enable_alpn = (0 != va_arg(param, long)) ? TRUE : FALSE;
     break;
 
 #ifdef USE_UNIX_SOCKETS
@@ -2647,10 +2664,36 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
 #endif
 
   case CURLOPT_PATH_AS_IS:
-    data->set.path_as_is = (0 != va_arg(param, long))?TRUE:FALSE;
+    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;
+    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)) {
+      data->set.stream_depends_on = dep;
+      data->set.stream_depends_e = (option == CURLOPT_STREAM_DEPENDS_E);
+    }
+    break;
+#endif
+  }
+  case CURLOPT_CONNECT_TO:
+    data->set.connect_to = va_arg(param, struct curl_slist *);
     break;
   default:
     /* unknown tag and its companion, just ignore: */
@@ -2661,6 +2704,45 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
   return result;
 }
 
+#ifdef USE_RECV_BEFORE_SEND_WORKAROUND
+static void conn_reset_postponed_data(struct connectdata *conn, int num)
+{
+  struct postponed_data * const psnd = &(conn->postponed[num]);
+  if(psnd->buffer) {
+    DEBUGASSERT(psnd->allocated_size > 0);
+    DEBUGASSERT(psnd->recv_size <= psnd->allocated_size);
+    DEBUGASSERT(psnd->recv_size ?
+                (psnd->recv_processed < psnd->recv_size) :
+                (psnd->recv_processed == 0));
+    DEBUGASSERT(psnd->bindsock != CURL_SOCKET_BAD);
+    free(psnd->buffer);
+    psnd->buffer = NULL;
+    psnd->allocated_size = 0;
+    psnd->recv_size = 0;
+    psnd->recv_processed = 0;
+#ifdef DEBUGBUILD
+    psnd->bindsock = CURL_SOCKET_BAD; /* used only for DEBUGASSERT */
+#endif /* DEBUGBUILD */
+  }
+  else {
+    DEBUGASSERT (psnd->allocated_size == 0);
+    DEBUGASSERT (psnd->recv_size == 0);
+    DEBUGASSERT (psnd->recv_processed == 0);
+    DEBUGASSERT (psnd->bindsock == CURL_SOCKET_BAD);
+  }
+}
+
+static void conn_reset_all_postponed_data(struct connectdata *conn)
+{
+  conn_reset_postponed_data(conn, 0);
+  conn_reset_postponed_data(conn, 1);
+}
+#else  /* ! USE_RECV_BEFORE_SEND_WORKAROUND */
+/* Use "do-nothing" macros instead of functions when workaround not used */
+#define conn_reset_postponed_data(c,n) do {} WHILE_FALSE
+#define conn_reset_all_postponed_data(c) do {} WHILE_FALSE
+#endif /* ! USE_RECV_BEFORE_SEND_WORKAROUND */
+
 static void conn_free(struct connectdata *conn)
 {
   if(!conn)
@@ -2691,7 +2773,7 @@ static void conn_free(struct connectdata *conn)
 
   Curl_safefree(conn->user);
   Curl_safefree(conn->passwd);
-  Curl_safefree(conn->xoauth2_bearer);
+  Curl_safefree(conn->oauth_bearer);
   Curl_safefree(conn->options);
   Curl_safefree(conn->proxyuser);
   Curl_safefree(conn->proxypasswd);
@@ -2707,9 +2789,12 @@ static void conn_free(struct connectdata *conn)
   Curl_safefree(conn->allocptr.rtsp_transport);
   Curl_safefree(conn->trailer);
   Curl_safefree(conn->host.rawalloc); /* host name buffer */
+  Curl_safefree(conn->conn_to_host.rawalloc); /* host name buffer */
   Curl_safefree(conn->proxy.rawalloc); /* proxy name buffer */
   Curl_safefree(conn->master_buffer);
 
+  conn_reset_all_postponed_data(conn);
+
   Curl_llist_destroy(conn->send_pipe, NULL);
   Curl_llist_destroy(conn->recv_pipe, NULL);
 
@@ -2727,14 +2812,14 @@ static void conn_free(struct connectdata *conn)
  * primary connection, like when freeing room in the connection cache or
  * killing of a dead old connection.
  *
- * This function MUST NOT reset state in the SessionHandle struct if that
+ * This function MUST NOT reset state in the Curl_easy struct if that
  * isn't strictly bound to the life-time of *this* particular connection.
  *
  */
 
 CURLcode Curl_disconnect(struct connectdata *conn, bool dead_connection)
 {
-  struct SessionHandle *data;
+  struct Curl_easy *data;
   if(!conn)
     return CURLE_OK; /* this is closed and fine already */
   data = conn->data;
@@ -2764,23 +2849,9 @@ CURLcode Curl_disconnect(struct connectdata *conn, bool dead_connection)
   infof(data, "Closing connection %ld\n", conn->connection_id);
   Curl_conncache_remove_conn(data->state.conn_cache, conn);
 
-#if defined(USE_LIBIDN)
-  if(conn->host.encalloc)
-    idn_free(conn->host.encalloc); /* encoded host name buffer, must be freed
-                                      with idn_free() since this was allocated
-                                      by libidn */
-  if(conn->proxy.encalloc)
-    idn_free(conn->proxy.encalloc); /* encoded proxy name buffer, must be
-                                       freed with idn_free() since this was
-                                       allocated by libidn */
-#elif defined(USE_WIN32_IDN)
-  free(conn->host.encalloc); /* encoded host name buffer, must be freed with
-                                idn_free() since this was allocated by
-                                curl_win32_idn_to_ascii */
-  free(conn->proxy.encalloc); /* encoded proxy name buffer, must be freed
-                                 with idn_free() since this was allocated by
-                                 curl_win32_idn_to_ascii */
-#endif
+  free_fixed_hostname(&conn->host);
+  free_fixed_hostname(&conn->conn_to_host);
+  free_fixed_hostname(&conn->proxy);
 
   Curl_ssl_close(conn, FIRSTSOCKET);
 
@@ -2817,7 +2888,7 @@ static bool SocketIsDead(curl_socket_t sock)
  * IsPipeliningPossible() returns TRUE if the options set would allow
  * pipelining/multiplexing and the connection is using a HTTP protocol.
  */
-static bool IsPipeliningPossible(const struct SessionHandle *handle,
+static bool IsPipeliningPossible(const struct Curl_easy *handle,
                                  const struct connectdata *conn)
 {
   /* If a HTTP protocol and pipelining is enabled */
@@ -2831,25 +2902,27 @@ static bool IsPipeliningPossible(const struct SessionHandle *handle,
       return TRUE;
 
     if(Curl_pipeline_wanted(handle->multi, CURLPIPE_MULTIPLEX) &&
-       (handle->set.httpversion == CURL_HTTP_VERSION_2_0))
+       (handle->set.httpversion >= CURL_HTTP_VERSION_2))
       /* allows HTTP/2 */
       return TRUE;
   }
   return FALSE;
 }
 
-int Curl_removeHandleFromPipeline(struct SessionHandle *handle,
+int Curl_removeHandleFromPipeline(struct Curl_easy *handle,
                                   struct curl_llist *pipeline)
 {
-  struct curl_llist_element *curr;
+  if(pipeline) {
+    struct curl_llist_element *curr;
 
-  curr = pipeline->head;
-  while(curr) {
-    if(curr->ptr == handle) {
-      Curl_llist_remove(pipeline, curr, NULL);
-      return 1; /* we removed a handle */
+    curr = pipeline->head;
+    while(curr) {
+      if(curr->ptr == handle) {
+        Curl_llist_remove(pipeline, curr, NULL);
+        return 1; /* we removed a handle */
+      }
+      curr = curr->next;
     }
-    curr = curr->next;
   }
 
   return 0;
@@ -2862,18 +2935,18 @@ static void Curl_printPipeline(struct curl_llist *pipeline)
 
   curr = pipeline->head;
   while(curr) {
-    struct SessionHandle *data = (struct SessionHandle *) curr->ptr;
+    struct Curl_easy *data = (struct Curl_easy *) curr->ptr;
     infof(data, "Handle in pipeline: %s\n", data->state.path);
     curr = curr->next;
   }
 }
 #endif
 
-static struct SessionHandle* gethandleathead(struct curl_llist *pipeline)
+static struct Curl_easy* gethandleathead(struct curl_llist *pipeline)
 {
   struct curl_llist_element *curr = pipeline->head;
   if(curr) {
-    return (struct SessionHandle *) curr->ptr;
+    return (struct Curl_easy *) curr->ptr;
   }
 
   return NULL;
@@ -2881,7 +2954,7 @@ static struct SessionHandle* gethandleathead(struct curl_llist *pipeline)
 
 /* remove the specified connection from all (possible) pipelines and related
    queues */
-void Curl_getoff_all_pipelines(struct SessionHandle *data,
+void Curl_getoff_all_pipelines(struct Curl_easy *data,
                                struct connectdata *conn)
 {
   bool recv_head = (conn->readchannel_inuse &&
@@ -2905,7 +2978,7 @@ static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke)
   curr = pipeline->head;
   while(curr) {
     struct curl_llist_element *next = curr->next;
-    struct SessionHandle *data = (struct SessionHandle *) curr->ptr;
+    struct Curl_easy *data = (struct Curl_easy *) curr->ptr;
 
 #ifdef DEBUGBUILD /* debug-only code */
     if(data->magic != CURLEASY_MAGIC_NUMBER) {
@@ -2929,8 +3002,8 @@ static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke)
  * Returns the pointer to the oldest idle connection, or NULL if none was
  * found.
  */
-static struct connectdata *
-find_oldest_idle_connection(struct SessionHandle *data)
+struct connectdata *
+Curl_oldest_idle_connection(struct Curl_easy *data)
 {
   struct conncache *bc = data->state.conn_cache;
   struct curl_hash_iterator iter;
@@ -2982,7 +3055,7 @@ find_oldest_idle_connection(struct SessionHandle *data)
  * found.
  */
 static struct connectdata *
-find_oldest_idle_connection_in_bundle(struct SessionHandle *data,
+find_oldest_idle_connection_in_bundle(struct Curl_easy *data,
                                       struct connectbundle *bundle)
 {
   struct curl_llist_element *curr;
@@ -3022,7 +3095,7 @@ find_oldest_idle_connection_in_bundle(struct SessionHandle *data,
  * Returns TRUE if the connection actually was dead and disconnected.
  */
 static bool disconnect_if_dead(struct connectdata *conn,
-                               struct SessionHandle *data)
+                               struct Curl_easy *data)
 {
   size_t pipeLen = conn->send_pipe->size + conn->recv_pipe->size;
   if(!pipeLen && !conn->inuse) {
@@ -3056,7 +3129,7 @@ static bool disconnect_if_dead(struct connectdata *conn,
 static int call_disconnect_if_dead(struct connectdata *conn,
                                       void *param)
 {
-  struct SessionHandle* data = (struct SessionHandle*)param;
+  struct Curl_easy* data = (struct Curl_easy*)param;
   disconnect_if_dead(conn, data);
   return 0; /* continue iteration */
 }
@@ -3066,7 +3139,7 @@ static int call_disconnect_if_dead(struct connectdata *conn,
  * closes and removes them.
  * The cleanup is done at most once per second.
  */
-static void prune_dead_connections(struct SessionHandle *data)
+static void prune_dead_connections(struct Curl_easy *data)
 {
   struct timeval now = Curl_tvnow();
   long elapsed = Curl_tvdiff(now, data->state.conn_cache->last_cleanup);
@@ -3098,7 +3171,7 @@ static size_t max_pipeline_length(struct Curl_multi *multi)
  * the pipelining strategy wants to open a new connection instead of reusing.
  */
 static bool
-ConnectionExists(struct SessionHandle *data,
+ConnectionExists(struct Curl_easy *data,
                  struct connectdata *needle,
                  struct connectdata **usethis,
                  bool *force_reuse,
@@ -3106,13 +3179,19 @@ ConnectionExists(struct SessionHandle *data,
 {
   struct connectdata *check;
   struct connectdata *chosen = 0;
+  bool foundPendingCandidate = FALSE;
   bool canPipeline = IsPipeliningPossible(data, needle);
+  struct connectbundle *bundle;
+
 #ifdef USE_NTLM
-  bool wantNTLMhttp = ((data->state.authhost.want & CURLAUTH_NTLM) ||
-                       (data->state.authhost.want & CURLAUTH_NTLM_WB)) &&
-    (needle->handler->protocol & PROTO_FAMILY_HTTP) ? TRUE : FALSE;
+  bool wantNTLMhttp = ((data->state.authhost.want &
+                      (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
+                      (needle->handler->protocol & PROTO_FAMILY_HTTP));
+  bool wantProxyNTLMhttp = (needle->bits.proxy_user_passwd &&
+                           ((data->state.authproxy.want &
+                           (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
+                           (needle->handler->protocol & PROTO_FAMILY_HTTP)));
 #endif
-  struct connectbundle *bundle;
 
   *force_reuse = FALSE;
   *waitpipe = FALSE;
@@ -3131,9 +3210,19 @@ ConnectionExists(struct SessionHandle *data,
       max_pipeline_length(data->multi):0;
     size_t best_pipe_len = max_pipe_len;
     struct curl_llist_element *curr;
+    const char *hostname;
 
-    infof(data, "Found bundle for host %s: %p\n",
-          needle->host.name, (void *)bundle);
+    if(needle->bits.conn_to_host)
+      hostname = needle->conn_to_host.name;
+    else
+      hostname = needle->host.name;
+
+    infof(data, "Found bundle for host %s: %p [%s]\n",
+          hostname, (void *)bundle,
+          (bundle->multiuse== BUNDLE_PIPELINING?
+           "can pipeline":
+           (bundle->multiuse== BUNDLE_MULTIPLEX?
+            "can multiplex":"serially")));
 
     /* We can't pipe if we don't know anything about the server */
     if(canPipeline) {
@@ -3147,19 +3236,27 @@ ConnectionExists(struct SessionHandle *data,
         infof(data, "Server doesn't support multi-use (yet)\n");
         canPipeline = FALSE;
       }
+      if((bundle->multiuse == BUNDLE_PIPELINING) &&
+         !Curl_pipeline_wanted(data->multi, CURLPIPE_HTTP1)) {
+        /* not asked for, switch off */
+        infof(data, "Could pipeline, but not asked to!\n");
+        canPipeline = FALSE;
+      }
+      else if((bundle->multiuse == BUNDLE_MULTIPLEX) &&
+              !Curl_pipeline_wanted(data->multi, CURLPIPE_MULTIPLEX)) {
+        infof(data, "Could multiplex, but not asked to!\n");
+        canPipeline = FALSE;
+      }
     }
 
     curr = bundle->conn_list->head;
     while(curr) {
       bool match = FALSE;
-#if defined(USE_NTLM)
-      bool credentialsMatch = FALSE;
-#endif
       size_t pipeLen;
 
       /*
-       * Note that if we use a HTTP proxy, we check connections to that
-       * proxy and not to the actual remote server.
+       * Note that if we use a HTTP proxy in normal mode (no tunneling), we
+       * check connections to that proxy and not to the actual remote server.
        */
       check = curr->ptr;
       curr = curr->next;
@@ -3173,8 +3270,8 @@ ConnectionExists(struct SessionHandle *data,
 
         if(!check->bits.multiplex) {
           /* If not multiplexing, make sure the pipe has only GET requests */
-          struct SessionHandle* sh = gethandleathead(check->send_pipe);
-          struct SessionHandle* rh = gethandleathead(check->recv_pipe);
+          struct Curl_easy* sh = gethandleathead(check->send_pipe);
+          struct Curl_easy* rh = gethandleathead(check->recv_pipe);
           if(sh) {
             if(!IsPipeliningPossible(sh, check))
               continue;
@@ -3205,6 +3302,8 @@ ConnectionExists(struct SessionHandle *data,
 
         if((check->sock[FIRSTSOCKET] == CURL_SOCKET_BAD) ||
            check->bits.close) {
+          if(!check->bits.close)
+            foundPendingCandidate = TRUE;
           /* Don't pick a connection that hasn't connected yet or that is going
              to get closed. */
           infof(data, "Connection #%ld isn't open enough, can't reuse\n",
@@ -3223,7 +3322,8 @@ ConnectionExists(struct SessionHandle *data,
       if((needle->handler->flags&PROTOPT_SSL) !=
          (check->handler->flags&PROTOPT_SSL))
         /* don't do mixed SSL and non-SSL connections */
-        if(!(needle->handler->protocol & check->handler->protocol))
+        if(get_protocol_family(check->handler->protocol) !=
+           needle->handler->protocol || !check->tls_upgraded)
           /* except protocols that have been upgraded via TLS */
           continue;
 
@@ -3237,6 +3337,25 @@ ConnectionExists(struct SessionHandle *data,
         /* don't do mixed proxy and non-proxy connections */
         continue;
 
+      if(needle->bits.proxy &&
+         (needle->proxytype != check->proxytype ||
+          needle->bits.httpproxy != check->bits.httpproxy ||
+          needle->bits.tunnel_proxy != check->bits.tunnel_proxy ||
+          !Curl_raw_equal(needle->proxy.name, check->proxy.name) ||
+          needle->port != check->port))
+        /* don't mix connections that use different proxies */
+        continue;
+
+      if(needle->bits.conn_to_host != check->bits.conn_to_host)
+        /* don't mix connections that use the "connect to host" feature and
+         * connections that don't use this feature */
+        continue;
+
+      if(needle->bits.conn_to_port != check->bits.conn_to_port)
+        /* don't mix connections that use the "connect to port" feature and
+         * connections that don't use this feature */
+        continue;
+
       if(!canPipeline && check->inuse)
         /* this request can't be pipelined but the checked connection is
            already in use so we skip it */
@@ -3262,37 +3381,33 @@ ConnectionExists(struct SessionHandle *data,
           continue;
       }
 
-      if((!(needle->handler->flags & PROTOPT_CREDSPERREQUEST))
-#ifdef USE_NTLM
-         || (wantNTLMhttp || check->ntlm.state != NTLMSTATE_NONE)
-#endif
-        ) {
-        /* This protocol requires credentials per connection or is HTTP+NTLM,
+      if(!(needle->handler->flags & PROTOPT_CREDSPERREQUEST)) {
+        /* This protocol requires credentials per connection,
            so verify that we're using the same name and password as well */
         if(!strequal(needle->user, check->user) ||
            !strequal(needle->passwd, check->passwd)) {
           /* one of them was different */
           continue;
         }
-#if defined(USE_NTLM)
-        credentialsMatch = TRUE;
-#endif
       }
 
-      if(!needle->bits.httpproxy || needle->handler->flags&PROTOPT_SSL ||
-         (needle->bits.httpproxy && check->bits.httpproxy &&
-          needle->bits.tunnel_proxy && check->bits.tunnel_proxy &&
-          Curl_raw_equal(needle->proxy.name, check->proxy.name) &&
-          (needle->port == check->port))) {
+      if(!needle->bits.httpproxy || (needle->handler->flags&PROTOPT_SSL) ||
+         (needle->bits.httpproxy && needle->bits.tunnel_proxy)) {
         /* The requested connection does not use a HTTP proxy or it uses SSL or
-           it is a non-SSL protocol tunneled over the same http proxy name and
-           port number or it is a non-SSL protocol which is allowed to be
-           upgraded via TLS */
-
+           it is a non-SSL protocol tunneled over the same HTTP proxy name and
+           port number */
         if((Curl_raw_equal(needle->handler->scheme, check->handler->scheme) ||
-            needle->handler->protocol & check->handler->protocol) &&
+            (get_protocol_family(check->handler->protocol) ==
+             needle->handler->protocol && check->tls_upgraded)) &&
+           (!needle->bits.conn_to_host || Curl_raw_equal(
+            needle->conn_to_host.name, check->conn_to_host.name)) &&
+           (!needle->bits.conn_to_port ||
+             needle->conn_to_port == check->conn_to_port) &&
            Curl_raw_equal(needle->host.name, check->host.name) &&
            needle->remote_port == check->remote_port) {
+          /* The schemes match or the the protocol family is the same and the
+             previous connection was TLS upgraded, and the hostname and host
+             port match */
           if(needle->handler->flags & PROTOPT_SSL) {
             /* This is a SSL connection so verify that we're using the same
                SSL options as well */
@@ -3305,6 +3420,7 @@ ConnectionExists(struct SessionHandle *data,
               continue;
             }
             else if(check->ssl[FIRSTSOCKET].state != ssl_connection_complete) {
+              foundPendingCandidate = TRUE;
               DEBUGF(infof(data,
                            "Connection #%ld has not started SSL connect, "
                            "can't reuse\n",
@@ -3315,16 +3431,10 @@ ConnectionExists(struct SessionHandle *data,
           match = TRUE;
         }
       }
-      else { /* The requested needle connection is using a proxy,
-                is the checked one using the same host, port and type? */
-        if(check->bits.proxy &&
-           (needle->proxytype == check->proxytype) &&
-           (needle->bits.tunnel_proxy == check->bits.tunnel_proxy) &&
-           Curl_raw_equal(needle->proxy.name, check->proxy.name) &&
-           needle->port == check->port) {
-          /* This is the same proxy connection, use it! */
-          match = TRUE;
-        }
+      else {
+        /* The requested connection is using the same HTTP proxy in normal
+           mode (no tunneling) */
+        match = TRUE;
       }
 
       if(match) {
@@ -3335,20 +3445,47 @@ ConnectionExists(struct SessionHandle *data,
            possible. (Especially we must not reuse the same connection if
            partway through a handshake!) */
         if(wantNTLMhttp) {
-          if(credentialsMatch && check->ntlm.state != NTLMSTATE_NONE) {
-            chosen = check;
+          if(!strequal(needle->user, check->user) ||
+             !strequal(needle->passwd, check->passwd))
+            continue;
+        }
+        else if(check->ntlm.state != NTLMSTATE_NONE) {
+          /* Connection is using NTLM auth but we don't want NTLM */
+          continue;
+        }
+
+        /* Same for Proxy NTLM authentication */
+        if(wantProxyNTLMhttp) {
+          /* Both check->proxyuser and check->proxypasswd can be NULL */
+          if(!check->proxyuser || !check->proxypasswd)
+            continue;
 
+          if(!strequal(needle->proxyuser, check->proxyuser) ||
+             !strequal(needle->proxypasswd, check->proxypasswd))
+            continue;
+        }
+        else if(check->proxyntlm.state != NTLMSTATE_NONE) {
+          /* Proxy connection is using NTLM auth but we don't want NTLM */
+          continue;
+        }
+
+        if(wantNTLMhttp || wantProxyNTLMhttp) {
+          /* Credentials are already checked, we can use this connection */
+          chosen = check;
+
+          if((wantNTLMhttp &&
+             (check->ntlm.state != NTLMSTATE_NONE)) ||
+              (wantProxyNTLMhttp &&
+               (check->proxyntlm.state != NTLMSTATE_NONE))) {
             /* We must use this connection, no other */
             *force_reuse = TRUE;
             break;
           }
-          else if(credentialsMatch)
-            /* this is a backup choice */
-            chosen = check;
+
+          /* Continue look up for a better connection */
           continue;
         }
 #endif
-
         if(canPipeline) {
           /* We can pipeline if we want to. Let's continue looking for
              the optimal connection to use, i.e the shortest pipe that is not
@@ -3413,39 +3550,13 @@ ConnectionExists(struct SessionHandle *data,
     return TRUE; /* yes, we found one to use! */
   }
 
-  return FALSE; /* no matching connecting exists */
-}
-
-/* Mark the connection as 'idle', or close it if the cache is full.
-   Returns TRUE if the connection is kept, or FALSE if it was closed. */
-static bool
-ConnectionDone(struct SessionHandle *data, struct connectdata *conn)
-{
-  /* data->multi->maxconnects can be negative, deal with it. */
-  size_t maxconnects =
-    (data->multi->maxconnects < 0) ? data->multi->num_easy * 4:
-    data->multi->maxconnects;
-  struct connectdata *conn_candidate = NULL;
-
-  /* Mark the current connection as 'unused' */
-  conn->inuse = FALSE;
-
-  if(maxconnects > 0 &&
-     data->state.conn_cache->num_connections > maxconnects) {
-    infof(data, "Connection cache is full, closing the oldest one.\n");
-
-    conn_candidate = find_oldest_idle_connection(data);
-
-    if(conn_candidate) {
-      /* Set the connection's owner correctly */
-      conn_candidate->data = data;
-
-      /* the winner gets the honour of being disconnected */
-      (void)Curl_disconnect(conn_candidate, /* dead_connection */ FALSE);
-    }
+  if(foundPendingCandidate && data->set.pipewait) {
+    infof(data,
+          "Found pending candidate for reuse and CURLOPT_PIPEWAIT is set\n");
+    *waitpipe = TRUE;
   }
 
-  return (conn_candidate == conn) ? FALSE : TRUE;
+  return FALSE; /* no matching connecting exists */
 }
 
 /* after a TCP connection to the proxy has been verified, this function does
@@ -3467,16 +3578,27 @@ CURLcode Curl_connected_proxy(struct connectdata *conn,
   case CURLPROXY_SOCKS5:
   case CURLPROXY_SOCKS5_HOSTNAME:
     return Curl_SOCKS5(conn->proxyuser, conn->proxypasswd,
-                       conn->host.name, conn->remote_port,
+                       conn->bits.conn_to_host ? conn->conn_to_host.name :
+                       conn->host.name,
+                       conn->bits.conn_to_port ? conn->conn_to_port :
+                       conn->remote_port,
                        FIRSTSOCKET, conn);
 
   case CURLPROXY_SOCKS4:
-    return Curl_SOCKS4(conn->proxyuser, conn->host.name,
-                       conn->remote_port, FIRSTSOCKET, conn, FALSE);
+    return Curl_SOCKS4(conn->proxyuser,
+                       conn->bits.conn_to_host ? conn->conn_to_host.name :
+                       conn->host.name,
+                       conn->bits.conn_to_port ? conn->conn_to_port :
+                       conn->remote_port,
+                       FIRSTSOCKET, conn, FALSE);
 
   case CURLPROXY_SOCKS4A:
-    return Curl_SOCKS4(conn->proxyuser, conn->host.name,
-                       conn->remote_port, FIRSTSOCKET, conn, TRUE);
+    return Curl_SOCKS4(conn->proxyuser,
+                       conn->bits.conn_to_host ? conn->conn_to_host.name :
+                       conn->host.name,
+                       conn->bits.conn_to_port ? conn->conn_to_port :
+                       conn->remote_port,
+                       FIRSTSOCKET, conn, TRUE);
 
 #endif /* CURL_DISABLE_PROXY */
   case CURLPROXY_HTTP:
@@ -3634,7 +3756,7 @@ static bool is_ASCII_name(const char *hostname)
 /*
  * Check if characters in hostname is allowed in Top Level Domain.
  */
-static bool tld_check_name(struct SessionHandle *data,
+static bool tld_check_name(struct Curl_easy *data,
                            const char *ace_hostname)
 {
   size_t err_pos;
@@ -3651,17 +3773,16 @@ static bool tld_check_name(struct SessionHandle *data,
   if(rc != IDNA_SUCCESS)
     return FALSE;
 
+  /* Warning: err_pos receives "the decoded character offset rather than the
+     byte position in the string." And as of libidn 1.32 that character offset
+     is for UTF-8, even if the passed in string is another locale. */
   rc = tld_check_lz(uc_name, &err_pos, NULL);
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
 #ifdef HAVE_TLD_STRERROR
   if(rc != TLD_SUCCESS)
     tld_errmsg = tld_strerror((Tld_rc)rc);
 #endif
-  if(rc == TLD_INVALID)
-    infof(data, "WARNING: %s; pos %u = `%c'/0x%02X\n",
-          tld_errmsg, err_pos, uc_name[err_pos],
-          uc_name[err_pos] & 255);
-  else if(rc != TLD_SUCCESS)
+  if(rc != TLD_SUCCESS)
     infof(data, "WARNING: TLD check for %s failed; %s\n",
           uc_name, tld_errmsg);
 #endif /* CURL_DISABLE_VERBOSE_STRINGS */
@@ -3677,7 +3798,7 @@ static bool tld_check_name(struct SessionHandle *data,
 /*
  * Perform any necessary IDN conversion of hostname
  */
-static void fix_hostname(struct SessionHandle *data,
+static void fix_hostname(struct Curl_easy *data,
                          struct connectdata *conn, struct hostname *host)
 {
   size_t len;
@@ -3698,49 +3819,64 @@ static void fix_hostname(struct SessionHandle *data,
        there's no use for it */
     host->name[len-1]=0;
 
+  /* Check name for non-ASCII and convert hostname to ACE form if we can */
   if(!is_ASCII_name(host->name)) {
 #ifdef USE_LIBIDN
-  /*************************************************************
-   * Check name for non-ASCII and convert hostname to ACE form.
-   *************************************************************/
-  if(stringprep_check_version(LIBIDN_REQUIRED_VERSION)) {
-    char *ace_hostname = NULL;
-    int rc = idna_to_ascii_lz(host->name, &ace_hostname, 0);
-    infof (data, "Input domain encoded as `%s'\n",
-           stringprep_locale_charset ());
-    if(rc != IDNA_SUCCESS)
-      infof(data, "Failed to convert %s to ACE; %s\n",
-            host->name, Curl_idn_strerror(conn, rc));
-    else {
-      /* tld_check_name() displays a warning if the host name contains
-         "illegal" characters for this TLD */
-      (void)tld_check_name(data, ace_hostname);
-
-      host->encalloc = ace_hostname;
-      /* change the name pointer to point to the encoded hostname */
-      host->name = host->encalloc;
+    if(stringprep_check_version(LIBIDN_REQUIRED_VERSION)) {
+      char *ace_hostname = NULL;
+
+      int rc = idna_to_ascii_lz(host->name, &ace_hostname, 0);
+      infof(data, "Input domain encoded as `%s'\n",
+            stringprep_locale_charset());
+      if(rc == IDNA_SUCCESS) {
+        /* tld_check_name() displays a warning if the host name contains
+           "illegal" characters for this TLD */
+        (void)tld_check_name(data, ace_hostname);
+
+        host->encalloc = ace_hostname;
+        /* 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,
+              Curl_idn_strerror(conn, rc));
     }
-  }
 #elif defined(USE_WIN32_IDN)
-  /*************************************************************
-   * Check name for non-ASCII and convert hostname to ACE form.
-   *************************************************************/
     char *ace_hostname = NULL;
-    int rc = curl_win32_idn_to_ascii(host->name, &ace_hostname);
-    if(rc == 0)
-      infof(data, "Failed to convert %s to ACE;\n",
-            host->name);
-    else {
+
+    if(curl_win32_idn_to_ascii(host->name, &ace_hostname)) {
       host->encalloc = ace_hostname;
       /* change the name pointer to point to the encoded hostname */
       host->name = host->encalloc;
     }
+    else
+      infof(data, "Failed to convert %s to ACE;\n", host->name);
 #else
     infof(data, "IDN support not present, can't parse Unicode domains\n");
 #endif
   }
 }
 
+/*
+ * Frees data allocated by fix_hostname()
+ */
+static void free_fixed_hostname(struct hostname *host)
+{
+#if defined(USE_LIBIDN)
+  if(host->encalloc) {
+    idn_free(host->encalloc); /* must be freed with idn_free() since this was
+                                 allocated by libidn */
+    host->encalloc = NULL;
+  }
+#elif defined(USE_WIN32_IDN)
+  free(host->encalloc); /* must be freed withidn_free() since this was
+                           allocated by curl_win32_idn_to_ascii */
+  host->encalloc = NULL;
+#else
+  (void)host;
+#endif
+}
+
 static void llist_dtor(void *user, void *element)
 {
   (void)user;
@@ -3751,7 +3887,7 @@ static void llist_dtor(void *user, void *element)
 /*
  * Allocate and initialize a new connectdata object.
  */
-static struct connectdata *allocate_conn(struct SessionHandle *data)
+static struct connectdata *allocate_conn(struct Curl_easy *data)
 {
   struct connectdata *conn = calloc(1, sizeof(struct connectdata));
   if(!conn)
@@ -3770,6 +3906,10 @@ static struct connectdata *allocate_conn(struct SessionHandle *data)
   conn->connection_id = -1;    /* no ID */
   conn->port = -1; /* unknown at this point */
   conn->remote_port = -1; /* unknown */
+#if defined(USE_RECV_BEFORE_SEND_WORKAROUND) && defined(DEBUGBUILD)
+  conn->postponed[0].bindsock = CURL_SOCKET_BAD; /* no file descriptor */
+  conn->postponed[1].bindsock = CURL_SOCKET_BAD; /* no file descriptor */
+#endif /* USE_RECV_BEFORE_SEND_WORKAROUND && DEBUGBUILD */
 
   /* Default protocol-independent behavior doesn't support persistent
      connections, so we set this to force-close. Protocols that support
@@ -3780,7 +3920,7 @@ static struct connectdata *allocate_conn(struct SessionHandle *data)
   conn->created = Curl_tvnow();
 
   conn->data = data; /* Setup the association between this connection
-                        and the SessionHandle */
+                        and the Curl_easy */
 
   conn->proxytype = data->set.proxytype; /* type */
 
@@ -3796,17 +3936,18 @@ static struct connectdata *allocate_conn(struct SessionHandle *data)
   /* note that these two proxy bits are now just on what looks to be
      requested, they may be altered down the road */
   conn->bits.proxy = (data->set.str[STRING_PROXY] &&
-                      *data->set.str[STRING_PROXY])?TRUE:FALSE;
+                      *data->set.str[STRING_PROXY]) ? TRUE : FALSE;
   conn->bits.httpproxy = (conn->bits.proxy &&
                           (conn->proxytype == CURLPROXY_HTTP ||
-                           conn->proxytype == CURLPROXY_HTTP_1_0))?TRUE:FALSE;
-  conn->bits.proxy_user_passwd =
-    (NULL != data->set.str[STRING_PROXYUSERNAME])?TRUE:FALSE;
+                           conn->proxytype == CURLPROXY_HTTP_1_0)) ?
+                          TRUE : FALSE;
+  conn->bits.proxy_user_passwd = (data->set.str[STRING_PROXYUSERNAME]) ?
+                                 TRUE : FALSE;
   conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy;
 
 #endif /* CURL_DISABLE_PROXY */
 
-  conn->bits.user_passwd = (NULL != data->set.str[STRING_USERNAME])?TRUE:FALSE;
+  conn->bits.user_passwd = (data->set.str[STRING_USERNAME]) ? TRUE : FALSE;
   conn->bits.ftp_use_epsv = data->set.ftp_use_epsv;
   conn->bits.ftp_use_eprt = data->set.ftp_use_eprt;
 
@@ -3851,7 +3992,7 @@ static struct connectdata *allocate_conn(struct SessionHandle *data)
   conn->localport = data->set.localport;
 
   /* the close socket stuff needs to be copied to the connection struct as
-     it may live on without (this specific) SessionHandle */
+     it may live on without (this specific) Curl_easy */
   conn->fclosesocket = data->set.fclosesocket;
   conn->closesocket_client = data->set.closesocket_client;
 
@@ -3870,7 +4011,7 @@ static struct connectdata *allocate_conn(struct SessionHandle *data)
   return NULL;
 }
 
-static CURLcode findprotocol(struct SessionHandle *data,
+static CURLcode findprotocol(struct Curl_easy *data,
                              struct connectdata *conn,
                              const char *protostr)
 {
@@ -3915,7 +4056,7 @@ static CURLcode findprotocol(struct SessionHandle *data,
 /*
  * Parse URL and fill in the relevant members of the connection struct.
  */
-static CURLcode parseurlandfillconn(struct SessionHandle *data,
+static CURLcode parseurlandfillconn(struct Curl_easy *data,
                                     struct connectdata *conn,
                                     bool *prot_missing,
                                     char **userp, char **passwdp,
@@ -4000,12 +4141,17 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data,
   }
   else {
     /* clear path */
+    char slashbuf[4];
     path[0]=0;
 
-    if(2 > sscanf(data->change.url,
-                   "%15[^\n:]://%[^\n/?]%[^\n]",
-                   protobuf,
-                   conn->host.name, path)) {
+    rc = sscanf(data->change.url,
+                "%15[^\n:]:%3[/]%[^\n/?]%[^\n]",
+                protobuf, slashbuf, conn->host.name, path);
+    if(2 == rc) {
+      failf(data, "Bad URL");
+      return CURLE_URL_MALFORMAT;
+    }
+    if(3 > rc) {
 
       /*
        * The URL was badly formatted, let's try the browser-style _without_
@@ -4028,33 +4174,51 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data,
       }
 
       /*
-       * Since there was no protocol part specified, we guess what protocol it
-       * is based on the first letters of the server name.
+       * Since there was no protocol part specified in the URL use the
+       * user-specified default protocol. If we weren't given a default make a
+       * guess by matching some protocols against the host's outermost
+       * sub-domain name. Finally if there was no match use HTTP.
        */
 
-      /* Note: if you add a new protocol, please update the list in
-       * lib/version.c too! */
-
-      if(checkprefix("FTP.", conn->host.name))
-        protop = "ftp";
-      else if(checkprefix("DICT.", conn->host.name))
-        protop = "DICT";
-      else if(checkprefix("LDAP.", conn->host.name))
-        protop = "LDAP";
-      else if(checkprefix("IMAP.", conn->host.name))
-        protop = "IMAP";
-      else if(checkprefix("SMTP.", conn->host.name))
-        protop = "smtp";
-      else if(checkprefix("POP3.", conn->host.name))
-        protop = "pop3";
-      else {
-        protop = "http";
+      protop = data->set.str[STRING_DEFAULT_PROTOCOL];
+      if(!protop) {
+        /* Note: if you add a new protocol, please update the list in
+         * lib/version.c too! */
+        if(checkprefix("FTP.", conn->host.name))
+          protop = "ftp";
+        else if(checkprefix("DICT.", conn->host.name))
+          protop = "DICT";
+        else if(checkprefix("LDAP.", conn->host.name))
+          protop = "LDAP";
+        else if(checkprefix("IMAP.", conn->host.name))
+          protop = "IMAP";
+        else if(checkprefix("SMTP.", conn->host.name))
+          protop = "smtp";
+        else if(checkprefix("POP3.", conn->host.name))
+          protop = "pop3";
+        else
+          protop = "http";
       }
 
       *prot_missing = TRUE; /* not given in URL */
     }
-    else
+    else {
+      size_t s = strlen(slashbuf);
       protop = protobuf;
+      if(s != 2) {
+        infof(data, "Unwillingly accepted illegal URL using %d slash%s!\n",
+              s, s>1?"es":"");
+
+        if(data->change.url_alloc)
+          free(data->change.url);
+        /* repair the URL to use two slashes */
+        data->change.url = aprintf("%s://%s%s",
+                                   protobuf, conn->host.name, path);
+        if(!data->change.url)
+          return CURLE_OUT_OF_MEMORY;
+        data->change.url_alloc = TRUE;
+      }
+    }
   }
 
   /* We search for '?' in the host name (but only on the right side of a
@@ -4260,7 +4424,7 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data,
  * If we're doing a resumed transfer, we need to setup our stuff
  * properly.
  */
-static CURLcode setup_range(struct SessionHandle *data)
+static CURLcode setup_range(struct Curl_easy *data)
 {
   struct UrlState *s = &data->state;
   s->resume_from = data->set.set_resume_from;
@@ -4273,7 +4437,7 @@ static CURLcode setup_range(struct SessionHandle *data)
     else
       s->range = strdup(data->set.str[STRING_SET_RANGE]);
 
-    s->rangestringalloc = (s->range)?TRUE:FALSE;
+    s->rangestringalloc = (s->range) ? TRUE : FALSE;
 
     if(!s->range)
       return CURLE_OUT_OF_MEMORY;
@@ -4292,7 +4456,7 @@ static CURLcode setup_range(struct SessionHandle *data)
  * setup_connection_internals() -
  *
  * Setup connection internals specific to the requested protocol in the
- * SessionHandle. This is inited and setup before the connection is made but
+ * Curl_easy. This is inited and setup before the connection is made but
  * is about the particular protocol that is to be used.
  *
  * This MUST get called after proxy magic has been figured out.
@@ -4301,7 +4465,7 @@ static CURLcode setup_connection_internals(struct connectdata *conn)
 {
   const struct Curl_handler * p;
   CURLcode result;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   /* in some case in the multi state-machine, we go back to the CONNECT state
      and then a second (or third or...) call to this function will be made
@@ -4332,20 +4496,15 @@ static CURLcode setup_connection_internals(struct connectdata *conn)
        was very likely already set to the proxy port */
     conn->port = p->defport;
 
-  /* only if remote_port was not already parsed off the URL we use the
-     default port number */
-  if(conn->remote_port < 0)
-    conn->remote_port = (unsigned short)conn->given->defport;
-
   return CURLE_OK;
 }
 
 /*
  * Curl_free_request_state() should free temp data that was allocated in the
- * SessionHandle for this single request.
+ * Curl_easy for this single request.
  */
 
-void Curl_free_request_state(struct SessionHandle *data)
+void Curl_free_request_state(struct Curl_easy *data)
 {
   Curl_safefree(data->req.protop);
   Curl_safefree(data->req.newurl);
@@ -4519,7 +4678,7 @@ static char *detect_proxy(struct connectdata *conn)
  * host name, so that we can re-use an existing connection
  * that may exist registered to the same proxy host.
  */
-static CURLcode parse_proxy(struct SessionHandle *data,
+static CURLcode parse_proxy(struct Curl_easy *data,
                             struct connectdata *conn, char *proxy)
 {
   char *prox_portno;
@@ -4611,7 +4770,7 @@ static CURLcode parse_proxy(struct SessionHandle *data,
       if(strncmp("%25", ptr, 3))
         infof(data, "Please URL encode %% as %%25, see RFC 6874.\n");
       ptr++;
-      /* Allow unresered characters as defined in RFC 3986 */
+      /* Allow unreserved characters as defined in RFC 3986 */
       while(*ptr && (ISALPHA(*ptr) || ISXDIGIT(*ptr) || (*ptr == '-') ||
                      (*ptr == '.') || (*ptr == '_') || (*ptr == '~')))
         ptr++;
@@ -4631,10 +4790,24 @@ static CURLcode parse_proxy(struct SessionHandle *data,
   /* Get port number off proxy.server.com:1080 */
   prox_portno = strchr(portptr, ':');
   if(prox_portno) {
+    char *endp = NULL;
+    long port = 0;
     *prox_portno = 0x0; /* cut off number from host name */
     prox_portno ++;
     /* now set the local port number */
-    conn->port = strtol(prox_portno, NULL, 10);
+    port = strtol(prox_portno, &endp, 10);
+    if((endp && *endp && (*endp != '/') && (*endp != ' ')) ||
+       (port < 0) || (port > 65535)) {
+      /* meant to detect for example invalid IPv6 numerical addresses without
+         brackets: "2a00:fac0:a000::7:13". Accept a trailing slash only
+         because we then allow "URL style" with the number followed by a
+         slash, used in curl test cases already. Space is also an acceptable
+         terminating symbol. */
+      infof(data, "No valid port number in proxy string (%s)\n",
+            prox_portno);
+    }
+    else
+      conn->port = port;
   }
   else {
     if(proxyptr[0]=='/')
@@ -4647,7 +4820,7 @@ static CURLcode parse_proxy(struct SessionHandle *data,
        a slash so we strip everything from the first slash */
     atsign = strchr(proxyptr, '/');
     if(atsign)
-      *atsign = 0x0; /* cut off path part from host name */
+      *atsign = '\0'; /* cut off path part from host name */
 
     if(data->set.proxyport)
       /* None given in the proxy string, then get the default one if it is
@@ -4668,7 +4841,7 @@ static CURLcode parse_proxy(struct SessionHandle *data,
 /*
  * Extract the user and password from the authentication string
  */
-static CURLcode parse_proxy_auth(struct SessionHandle *data,
+static CURLcode parse_proxy_auth(struct Curl_easy *data,
                                  struct connectdata *conn)
 {
   char proxyuser[MAX_CURL_USER_LENGTH]="";
@@ -4713,7 +4886,7 @@ static CURLcode parse_proxy_auth(struct SessionHandle *data,
  *          options                 - non-zero length if defined
  *          conn->host.name         - remove user name and password
  */
-static CURLcode parse_url_login(struct SessionHandle *data,
+static CURLcode parse_url_login(struct Curl_easy *data,
                                 struct connectdata *conn,
                                 char **user, char **passwd, char **options)
 {
@@ -4952,7 +5125,7 @@ static CURLcode parse_login_details(const char *login, const size_t len,
  *
  * The port number embedded in the URL is replaced, if necessary.
  *************************************************************/
-static CURLcode parse_remote_port(struct SessionHandle *data,
+static CURLcode parse_remote_port(struct Curl_easy *data,
                                   struct connectdata *conn)
 {
   char *portptr;
@@ -5051,6 +5224,12 @@ static CURLcode parse_remote_port(struct SessionHandle *data,
          use the default port. Firefox and Chrome both do that. */
       *portptr = '\0';
   }
+
+  /* only if remote_port was not already parsed off the URL we use the
+     default port number */
+  if(conn->remote_port < 0)
+    conn->remote_port = (unsigned short)conn->given->defport;
+
   return CURLE_OK;
 }
 
@@ -5058,7 +5237,7 @@ static CURLcode parse_remote_port(struct SessionHandle *data,
  * Override the login details from the URL with that in the CURLOPT_USERPWD
  * option or a .netrc file, if applicable.
  */
-static CURLcode override_login(struct SessionHandle *data,
+static CURLcode override_login(struct Curl_easy *data,
                                struct connectdata *conn,
                                char **userp, char **passwdp, char **optionsp)
 {
@@ -5093,7 +5272,7 @@ static CURLcode override_login(struct SessionHandle *data,
             DOT_CHAR "netrc file; using defaults\n",
             conn->host.name);
     }
-    else if(ret < 0 ) {
+    else if(ret < 0) {
       return CURLE_OUT_OF_MEMORY;
     }
     else {
@@ -5156,10 +5335,218 @@ static CURLcode set_login(struct connectdata *conn,
   return result;
 }
 
+/*
+ * Parses a "host:port" string to connect to.
+ * The hostname and the port may be empty; in this case, NULL is returned for
+ * the hostname and -1 for the port.
+ */
+static CURLcode parse_connect_to_host_port(struct Curl_easy *data,
+                                           const char *host,
+                                           char **hostname_result,
+                                           int *port_result)
+{
+  char *host_dup;
+  char *hostptr;
+  char *host_portno;
+  char *portptr;
+  int port = -1;
+
+  *hostname_result = NULL;
+  *port_result = -1;
+
+  if(!host || !*host)
+    return CURLE_OK;
+
+  host_dup = strdup(host);
+  if(!host_dup)
+    return CURLE_OUT_OF_MEMORY;
+
+  hostptr = host_dup;
+
+  /* start scanning for port number at this point */
+  portptr = hostptr;
+
+  /* detect and extract RFC6874-style IPv6-addresses */
+  if(*hostptr == '[') {
+    char *ptr = ++hostptr; /* advance beyond the initial bracket */
+    while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':') || (*ptr == '.')))
+      ptr++;
+    if(*ptr == '%') {
+      /* There might be a zone identifier */
+      if(strncmp("%25", ptr, 3))
+        infof(data, "Please URL encode %% as %%25, see RFC 6874.\n");
+      ptr++;
+      /* Allow unreserved characters as defined in RFC 3986 */
+      while(*ptr && (ISALPHA(*ptr) || ISXDIGIT(*ptr) || (*ptr == '-') ||
+                     (*ptr == '.') || (*ptr == '_') || (*ptr == '~')))
+        ptr++;
+    }
+    if(*ptr == ']')
+      /* yeps, it ended nicely with a bracket as well */
+      *ptr++ = '\0';
+    else
+      infof(data, "Invalid IPv6 address format\n");
+    portptr = ptr;
+    /* Note that if this didn't end with a bracket, we still advanced the
+     * hostptr first, but I can't see anything wrong with that as no host
+     * name nor a numeric can legally start with a bracket.
+     */
+  }
+
+  /* Get port number off server.com:1080 */
+  host_portno = strchr(portptr, ':');
+  if(host_portno) {
+    char *endp = NULL;
+    *host_portno = '\0'; /* cut off number from host name */
+    host_portno++;
+    if(*host_portno) {
+      long portparse = strtol(host_portno, &endp, 10);
+      if((endp && *endp) || (portparse < 0) || (portparse > 65535)) {
+        infof(data, "No valid port number in connect to host string (%s)\n",
+              host_portno);
+        hostptr = NULL;
+        port = -1;
+      }
+      else
+        port = (int)portparse; /* we know it will fit */
+    }
+  }
+
+  /* now, clone the cleaned host name */
+  if(hostptr) {
+    *hostname_result = strdup(hostptr);
+    if(!*hostname_result) {
+      free(host_dup);
+      return CURLE_OUT_OF_MEMORY;
+    }
+  }
+
+  *port_result = port;
+
+  free(host_dup);
+  return CURLE_OK;
+}
+
+/*
+ * Parses one "connect to" string in the form:
+ * "HOST:PORT:CONNECT-TO-HOST:CONNECT-TO-PORT".
+ */
+static CURLcode parse_connect_to_string(struct Curl_easy *data,
+                                        struct connectdata *conn,
+                                        const char *conn_to_host,
+                                        char **host_result,
+                                        int *port_result)
+{
+  CURLcode result = CURLE_OK;
+  const char *ptr = conn_to_host;
+  int host_match = FALSE;
+  int port_match = FALSE;
+
+  if(*ptr == ':') {
+    /* an empty hostname always matches */
+    host_match = TRUE;
+    ptr++;
+  }
+  else {
+    /* check whether the URL's hostname matches */
+    size_t hostname_to_match_len;
+    char *hostname_to_match = aprintf("%s%s%s",
+                                      conn->bits.ipv6_ip ? "[" : "",
+                                      conn->host.name,
+                                      conn->bits.ipv6_ip ? "]" : "");
+    if(!hostname_to_match)
+      return CURLE_OUT_OF_MEMORY;
+    hostname_to_match_len = strlen(hostname_to_match);
+    host_match = curl_strnequal(ptr, hostname_to_match, hostname_to_match_len);
+    free(hostname_to_match);
+    ptr += hostname_to_match_len;
+
+    host_match = host_match && *ptr == ':';
+    ptr++;
+  }
+
+  if(host_match) {
+    if(*ptr == ':') {
+      /* an empty port always matches */
+      port_match = TRUE;
+      ptr++;
+    }
+    else {
+      /* check whether the URL's port matches */
+      char *ptr_next = strchr(ptr, ':');
+      if(ptr_next) {
+        char *endp = NULL;
+        long port_to_match = strtol(ptr, &endp, 10);
+        if((endp == ptr_next) && (port_to_match == conn->remote_port)) {
+          port_match = TRUE;
+          ptr = ptr_next + 1;
+        }
+      }
+    }
+  }
+
+  if(host_match && port_match) {
+    /* parse the hostname and port to connect to */
+    result = parse_connect_to_host_port(data, ptr, host_result, port_result);
+  }
+
+  return result;
+}
+
+/*
+ * Processes all strings in the "connect to" slist, and uses the "connect
+ * to host" and "connect to port" of the first string that matches.
+ */
+static CURLcode parse_connect_to_slist(struct Curl_easy *data,
+                                       struct connectdata *conn,
+                                       struct curl_slist *conn_to_host)
+{
+  CURLcode result = CURLE_OK;
+  char *host = NULL;
+  int port = 0;
+
+  while(conn_to_host && !host) {
+    result = parse_connect_to_string(data, conn, conn_to_host->data,
+                                     &host, &port);
+    if(result)
+      return result;
+
+    if(host && *host) {
+      bool ipv6host;
+      conn->conn_to_host.rawalloc = host;
+      conn->conn_to_host.name = host;
+      conn->bits.conn_to_host = TRUE;
+
+      ipv6host = strchr(host, ':') != NULL;
+      infof(data, "Connecting to hostname: %s%s%s\n",
+            ipv6host ? "[" : "", host, ipv6host ? "]" : "");
+    }
+    else {
+      /* no "connect to host" */
+      conn->bits.conn_to_host = FALSE;
+      free(host);
+    }
+
+    if(port >= 0) {
+      conn->conn_to_port = port;
+      conn->bits.conn_to_port = TRUE;
+      infof(data, "Connecting to port: %d\n", port);
+    }
+    else {
+      /* no "connect to port" */
+      conn->bits.conn_to_port = FALSE;
+    }
+
+    conn_to_host = conn_to_host->next;
+  }
+
+  return result;
+}
+
 /*************************************************************
  * Resolve the address of the server or proxy
  *************************************************************/
-static CURLcode resolve_server(struct SessionHandle *data,
+static CURLcode resolve_server(struct Curl_easy *data,
                                struct connectdata *conn,
                                bool *async)
 {
@@ -5180,9 +5567,6 @@ static CURLcode resolve_server(struct SessionHandle *data,
     int rc;
     struct Curl_dns_entry *hostaddr;
 
-    /* set a pointer to the hostname we display */
-    fix_hostname(data, conn, &conn->host);
-
 #ifdef USE_UNIX_SOCKETS
     if(data->set.str[STRING_UNIX_SOCKET_PATH]) {
       /* Unix domain sockets are local. The host gets ignored, just use the
@@ -5210,12 +5594,21 @@ static CURLcode resolve_server(struct SessionHandle *data,
     else
 #endif
     if(!conn->proxy.name || !*conn->proxy.name) {
+      struct hostname *connhost;
+      if(conn->bits.conn_to_host)
+        connhost = &conn->conn_to_host;
+      else
+        connhost = &conn->host;
+
       /* If not connecting via a proxy, extract the port from the URL, if it is
        * there, thus overriding any defaults that might have been set above. */
-      conn->port =  conn->remote_port; /* it is the same port */
+      if(conn->bits.conn_to_port)
+        conn->port = conn->conn_to_port;
+      else
+        conn->port = conn->remote_port; /* it is the same port */
 
       /* Resolve target host right on */
-      rc = Curl_resolv_timeout(conn, conn->host.name, (int)conn->port,
+      rc = Curl_resolv_timeout(conn, connhost->name, (int)conn->port,
                                &hostaddr, timeout_ms);
       if(rc == CURLRESOLV_PENDING)
         *async = TRUE;
@@ -5224,7 +5617,7 @@ static CURLcode resolve_server(struct SessionHandle *data,
         result = CURLE_OPERATION_TIMEDOUT;
 
       else if(!hostaddr) {
-        failf(data, "Couldn't resolve host '%s'", conn->host.dispname);
+        failf(data, "Couldn't resolve host '%s'", connhost->dispname);
         result =  CURLE_COULDNT_RESOLVE_HOST;
         /* don't return yet, we need to clean up the timeout first */
       }
@@ -5232,9 +5625,6 @@ static CURLcode resolve_server(struct SessionHandle *data,
     else {
       /* This is a proxy that hasn't been resolved yet. */
 
-      /* IDN-fix the proxy name */
-      fix_hostname(data, conn, &conn->proxy);
-
       /* resolve proxy */
       rc = Curl_resolv_timeout(conn, conn->proxy.name, (int)conn->port,
                                &hostaddr, timeout_ms);
@@ -5266,6 +5656,7 @@ static CURLcode resolve_server(struct SessionHandle *data,
 static void reuse_conn(struct connectdata *old_conn,
                        struct connectdata *conn)
 {
+  free_fixed_hostname(&old_conn->proxy);
   free(old_conn->proxy.rawalloc);
 
   /* free the SSL config struct from this connection struct as this was
@@ -5300,12 +5691,22 @@ static void reuse_conn(struct connectdata *old_conn,
 
   /* host can change, when doing keepalive with a proxy or if the case is
      different this time etc */
+  free_fixed_hostname(&conn->host);
+  free_fixed_hostname(&conn->conn_to_host);
   Curl_safefree(conn->host.rawalloc);
+  Curl_safefree(conn->conn_to_host.rawalloc);
   conn->host=old_conn->host;
+  conn->bits.conn_to_host = old_conn->bits.conn_to_host;
+  conn->conn_to_host = old_conn->conn_to_host;
+  conn->bits.conn_to_port = old_conn->bits.conn_to_port;
+  conn->conn_to_port = old_conn->conn_to_port;
 
   /* persist connection info in session handle */
   Curl_persistconninfo(conn);
 
+  conn_reset_all_postponed_data(old_conn); /* free buffers */
+  conn_reset_all_postponed_data(conn);     /* reset unprocessed data */
+
   /* re-use init */
   conn->bits.reuse = TRUE; /* yes, we're re-using here */
 
@@ -5340,7 +5741,7 @@ static void reuse_conn(struct connectdata *old_conn,
  * *NOTE* this function assigns the conn->data pointer!
  */
 
-static CURLcode create_conn(struct SessionHandle *data,
+static CURLcode create_conn(struct Curl_easy *data,
                             struct connectdata **in_connect,
                             bool *async)
 {
@@ -5448,6 +5849,7 @@ static CURLcode create_conn(struct SessionHandle *data,
        we're gonna follow a Location: later or... then we need the protocol
        part added so that we have a valid URL. */
     char *reurl;
+    char *ch_lower;
 
     reurl = aprintf("%s://%s", conn->handler->scheme, data->change.url);
 
@@ -5456,6 +5858,10 @@ static CURLcode create_conn(struct SessionHandle *data,
       goto out;
     }
 
+    /* Change protocol prefix to lower-case */
+    for(ch_lower = reurl; *ch_lower != ':'; ch_lower++)
+      *ch_lower = (char)TOLOWER(*ch_lower);
+
     if(data->change.url_alloc) {
       Curl_safefree(data->change.url);
       data->change.url_alloc = FALSE;
@@ -5484,8 +5890,8 @@ static CURLcode create_conn(struct SessionHandle *data,
   }
 
   if(data->set.str[STRING_BEARER]) {
-    conn->xoauth2_bearer = strdup(data->set.str[STRING_BEARER]);
-    if(!conn->xoauth2_bearer) {
+    conn->oauth_bearer = strdup(data->set.str[STRING_BEARER]);
+    if(!conn->oauth_bearer) {
       result = CURLE_OUT_OF_MEMORY;
       goto out;
     }
@@ -5605,6 +6011,48 @@ static CURLcode create_conn(struct SessionHandle *data,
     goto out;
 
   /*************************************************************
+   * Process the "connect to" linked list of hostname/port mappings.
+   * Do this after the remote port number has been fixed in the URL.
+   *************************************************************/
+  result = parse_connect_to_slist(data, conn, data->set.connect_to);
+  if(result)
+    goto out;
+
+  /*************************************************************
+   * IDN-fix the hostnames
+   *************************************************************/
+  fix_hostname(data, conn, &conn->host);
+  if(conn->bits.conn_to_host)
+    fix_hostname(data, conn, &conn->conn_to_host);
+  if(conn->proxy.name && *conn->proxy.name)
+    fix_hostname(data, conn, &conn->proxy);
+
+  /*************************************************************
+   * Check whether the host and the "connect to host" are equal.
+   * Do this after the hostnames have been IDN-fixed .
+   *************************************************************/
+  if(conn->bits.conn_to_host &&
+      Curl_raw_equal(conn->conn_to_host.name, conn->host.name)) {
+    conn->bits.conn_to_host = FALSE;
+  }
+
+  /*************************************************************
+   * Check whether the port and the "connect to port" are equal.
+   * Do this after the remote port number has been fixed in the URL.
+   *************************************************************/
+  if(conn->bits.conn_to_port && conn->conn_to_port == conn->remote_port) {
+    conn->bits.conn_to_port = FALSE;
+  }
+
+  /*************************************************************
+   * If the "connect to" feature is used with an HTTP proxy,
+   * we set the tunnel_proxy bit.
+   *************************************************************/
+  if((conn->bits.conn_to_host || conn->bits.conn_to_port) &&
+      conn->bits.httpproxy)
+    conn->bits.tunnel_proxy = TRUE;
+
+  /*************************************************************
    * Setup internals depending on protocol. Needs to be done after
    * we figured out what/if proxy to use.
    *************************************************************/
@@ -5617,6 +6065,8 @@ static CURLcode create_conn(struct SessionHandle *data,
   conn->recv[SECONDARYSOCKET] = Curl_recv_plain;
   conn->send[SECONDARYSOCKET] = Curl_send_plain;
 
+  conn->bits.tcp_fastopen = data->set.tcp_fastopen;
+
   /***********************************************************************
    * file: is a special case in that it doesn't need a network connection
    ***********************************************************************/
@@ -5663,7 +6113,7 @@ static CURLcode create_conn(struct SessionHandle *data,
      strings in the session handle strings array!
 
      Keep in mind that the pointers in the master copy are pointing to strings
-     that will be freed as part of the SessionHandle struct, but all cloned
+     that will be freed as part of the Curl_easy struct, but all cloned
      copies will be separately allocated.
   */
   data->set.ssl.CApath = data->set.str[STRING_SSL_CAPATH];
@@ -5673,6 +6123,7 @@ static CURLcode create_conn(struct SessionHandle *data,
   data->set.ssl.random_file = data->set.str[STRING_SSL_RANDOM_FILE];
   data->set.ssl.egdsocket = data->set.str[STRING_SSL_EGDSOCKET];
   data->set.ssl.cipher_list = data->set.str[STRING_SSL_CIPHER_LIST];
+  data->set.ssl.clientcert = data->set.str[STRING_CERT];
 #ifdef USE_TLS_SRP
   data->set.ssl.username = data->set.str[STRING_TLSAUTH_USERNAME];
   data->set.ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD];
@@ -5732,9 +6183,6 @@ static CURLcode create_conn(struct SessionHandle *data,
     conn = conn_temp;
     *in_connect = conn;
 
-    /* set a pointer to the hostname we display */
-    fix_hostname(data, conn, &conn->host);
-
     infof(data, "Re-using existing connection! (#%ld) with %s %s\n",
           conn->connection_id,
           conn->bits.proxy?"proxy":"host",
@@ -5746,6 +6194,15 @@ static CURLcode create_conn(struct SessionHandle *data,
        connections we are allowed to open. */
     struct connectbundle *bundle = NULL;
 
+    if(conn->handler->flags & PROTOPT_ALPN_NPN) {
+      /* The protocol wants it, so set the bits if enabled in the easy handle
+         (default) */
+      if(data->set.ssl_enable_alpn)
+        conn->bits.tls_enable_alpn = TRUE;
+      if(data->set.ssl_enable_npn)
+        conn->bits.tls_enable_npn = TRUE;
+    }
+
     if(waitpipe)
       /* There is a connection that *might* become usable for pipelining
          "soon", and we wait for that */
@@ -5778,7 +6235,7 @@ static CURLcode create_conn(struct SessionHandle *data,
       struct connectdata *conn_candidate;
 
       /* The cache is full. Let's see if we can kill a connection. */
-      conn_candidate = find_oldest_idle_connection(data);
+      conn_candidate = Curl_oldest_idle_connection(data);
 
       if(conn_candidate) {
         /* Set the connection's owner correctly, then kill it */
@@ -5816,12 +6273,14 @@ static CURLcode create_conn(struct SessionHandle *data,
        data->state.authhost.done) {
       infof(data, "NTLM picked AND auth done set, clear picked!\n");
       data->state.authhost.picked = CURLAUTH_NONE;
+      data->state.authhost.done = FALSE;
     }
 
     if((data->state.authproxy.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
        data->state.authproxy.done) {
       infof(data, "NTLM-proxy picked AND auth done set, clear picked!\n");
       data->state.authproxy.picked = CURLAUTH_NONE;
+      data->state.authproxy.done = FALSE;
     }
 #endif
   }
@@ -5874,7 +6333,7 @@ CURLcode Curl_setup_conn(struct connectdata *conn,
                          bool *protocol_done)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   Curl_pgrsTime(data, TIMER_NAMELOOKUP);
 
@@ -5948,7 +6407,7 @@ CURLcode Curl_setup_conn(struct connectdata *conn,
   return result;
 }
 
-CURLcode Curl_connect(struct SessionHandle *data,
+CURLcode Curl_connect(struct Curl_easy *data,
                       struct connectdata **in_connect,
                       bool *asyncp,
                       bool *protocol_done)
@@ -5988,140 +6447,17 @@ CURLcode Curl_connect(struct SessionHandle *data,
   return result;
 }
 
-CURLcode Curl_done(struct connectdata **connp,
-                   CURLcode status,  /* an error if this is called after an
-                                        error was detected */
-                   bool premature)
-{
-  CURLcode result;
-  struct connectdata *conn;
-  struct SessionHandle *data;
-
-  DEBUGASSERT(*connp);
-
-  conn = *connp;
-  data = conn->data;
-
-  DEBUGF(infof(data, "Curl_done\n"));
-
-  if(data->state.done)
-    /* Stop if Curl_done() has already been called */
-    return CURLE_OK;
-
-  Curl_getoff_all_pipelines(data, conn);
-
-  /* Cleanup possible redirect junk */
-  free(data->req.newurl);
-  data->req.newurl = NULL;
-  free(data->req.location);
-  data->req.location = NULL;
-
-  switch(status) {
-  case CURLE_ABORTED_BY_CALLBACK:
-  case CURLE_READ_ERROR:
-  case CURLE_WRITE_ERROR:
-    /* When we're aborted due to a callback return code it basically have to
-       be counted as premature as there is trouble ahead if we don't. We have
-       many callbacks and protocols work differently, we could potentially do
-       this more fine-grained in the future. */
-    premature = TRUE;
-  default:
-    break;
-  }
-
-  /* this calls the protocol-specific function pointer previously set */
-  if(conn->handler->done)
-    result = conn->handler->done(conn, status, premature);
-  else
-    result = status;
-
-  if(!result && Curl_pgrsDone(conn))
-    result = CURLE_ABORTED_BY_CALLBACK;
-
-  if((conn->send_pipe->size + conn->recv_pipe->size != 0 &&
-      !data->set.reuse_forbid &&
-      !conn->bits.close)) {
-    /* Stop if pipeline is not empty and we do not have to close
-       connection. */
-    DEBUGF(infof(data, "Connection still in use, no more Curl_done now!\n"));
-    return CURLE_OK;
-  }
-
-  data->state.done = TRUE; /* called just now! */
-  Curl_resolver_cancel(conn);
-
-  if(conn->dns_entry) {
-    Curl_resolv_unlock(data, conn->dns_entry); /* done with this */
-    conn->dns_entry = NULL;
-  }
-
-  /* if the transfer was completed in a paused state there can be buffered
-     data left to write and then kill */
-  free(data->state.tempwrite);
-  data->state.tempwrite = NULL;
-
-  /* if data->set.reuse_forbid is TRUE, it means the libcurl client has
-     forced us to close this connection. This is ignored for requests taking
-     place in a NTLM authentication handshake
-
-     if conn->bits.close is TRUE, it means that the connection should be
-     closed in spite of all our efforts to be nice, due to protocol
-     restrictions in our or the server's end
-
-     if premature is TRUE, it means this connection was said to be DONE before
-     the entire request operation is complete and thus we can't know in what
-     state it is for re-using, so we're forced to close it. In a perfect world
-     we can add code that keep track of if we really must close it here or not,
-     but currently we have no such detail knowledge.
-  */
-
-  if((data->set.reuse_forbid
-#if defined(USE_NTLM)
-      && !(conn->ntlm.state == NTLMSTATE_TYPE2 ||
-           conn->proxyntlm.state == NTLMSTATE_TYPE2)
-#endif
-     ) || conn->bits.close || premature) {
-    CURLcode res2 = Curl_disconnect(conn, premature); /* close connection */
-
-    /* If we had an error already, make sure we return that one. But
-       if we got a new error, return that. */
-    if(!result && res2)
-      result = res2;
-  }
-  else {
-    /* the connection is no longer in use */
-    if(ConnectionDone(data, conn)) {
-      /* remember the most recently used connection */
-      data->state.lastconnect = conn;
-
-      infof(data, "Connection #%ld to host %s left intact\n",
-            conn->connection_id,
-            conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname);
-    }
-    else
-      data->state.lastconnect = NULL;
-  }
-
-  *connp = NULL; /* to make the caller of this function better detect that
-                    this was either closed or handed over to the connection
-                    cache here, and therefore cannot be used from this point on
-                 */
-  Curl_free_request_state(data);
-
-  return result;
-}
-
 /*
  * Curl_init_do() inits the readwrite session. This is inited each time (in
  * the DO function before the protocol-specific DO functions are invoked) for
- * a transfer, sometimes multiple times on the same SessionHandle. Make sure
+ * a transfer, sometimes multiple times on the same Curl_easy. Make sure
  * nothing in here depends on stuff that are setup dynamically for the
  * transfer.
  *
  * Allow this function to get called with 'conn' set to NULL.
  */
 
-CURLcode Curl_init_do(struct SessionHandle *data, struct connectdata *conn)
+CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
 {
   struct SingleRequest *k = &data->req;
 
@@ -6129,7 +6465,7 @@ CURLcode Curl_init_do(struct SessionHandle *data, struct connectdata *conn)
     conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to
                                  * use */
 
-  data->state.done = FALSE; /* Curl_done() is not called yet */
+  data->state.done = FALSE; /* *_done() is not called yet */
   data->state.expect100header = FALSE;
 
   if(data->set.opt_no_body)
@@ -6163,80 +6499,111 @@ CURLcode Curl_init_do(struct SessionHandle *data, struct connectdata *conn)
 }
 
 /*
- * do_complete is called when the DO actions are complete.
- *
- * We init chunking and trailer bits to their default values here immediately
- * before receiving any header data for the current request in the pipeline.
- */
-static void do_complete(struct connectdata *conn)
-{
-  conn->data->req.chunk=FALSE;
-  conn->data->req.maxfd = (conn->sockfd>conn->writesockfd?
-                           conn->sockfd:conn->writesockfd)+1;
-  Curl_pgrsTime(conn->data, TIMER_PRETRANSFER);
-}
+* get_protocol_family()
+*
+* This is used to return the protocol family for a given protocol.
+*
+* Parameters:
+*
+* protocol  [in]  - A single bit protocol identifier such as HTTP or HTTPS.
+*
+* Returns the family as a single bit protocol identifier.
+*/
 
-CURLcode Curl_do(struct connectdata **connp, bool *done)
+unsigned int get_protocol_family(unsigned int protocol)
 {
-  CURLcode result=CURLE_OK;
-  struct connectdata *conn = *connp;
-  struct SessionHandle *data = conn->data;
+  unsigned int family;
 
-  if(conn->handler->do_it) {
-    /* generic protocol-specific function pointer set in curl_connect() */
-    result = conn->handler->do_it(conn, done);
+  switch(protocol) {
+  case CURLPROTO_HTTP:
+  case CURLPROTO_HTTPS:
+    family = CURLPROTO_HTTP;
+    break;
 
-    /* This was formerly done in transfer.c, but we better do it here */
-    if((CURLE_SEND_ERROR == result) && conn->bits.reuse) {
-      /*
-       * If the connection is using an easy handle, call reconnect
-       * to re-establish the connection.  Otherwise, let the multi logic
-       * figure out how to re-establish the connection.
-       */
-      if(!data->multi) {
-        result = Curl_reconnect_request(connp);
-
-        if(!result) {
-          /* ... finally back to actually retry the DO phase */
-          conn = *connp; /* re-assign conn since Curl_reconnect_request
-                            creates a new connection */
-          result = conn->handler->do_it(conn, done);
-        }
-      }
-      else
-        return result;
-    }
+  case CURLPROTO_FTP:
+  case CURLPROTO_FTPS:
+    family = CURLPROTO_FTP;
+    break;
 
-    if(!result && *done)
-      /* do_complete must be called after the protocol-specific DO function */
-      do_complete(conn);
-  }
-  return result;
-}
+  case CURLPROTO_SCP:
+    family = CURLPROTO_SCP;
+    break;
 
-/*
- * Curl_do_more() is called during the DO_MORE multi state. It is basically a
- * second stage DO state which (wrongly) was introduced to support FTP's
- * second connection.
- *
- * TODO: A future libcurl should be able to work away this state.
- *
- * 'complete' can return 0 for incomplete, 1 for done and -1 for go back to
- * DOING state there's more work to do!
- */
+  case CURLPROTO_SFTP:
+    family = CURLPROTO_SFTP;
+    break;
 
-CURLcode Curl_do_more(struct connectdata *conn, int *complete)
-{
-  CURLcode result=CURLE_OK;
+  case CURLPROTO_TELNET:
+    family = CURLPROTO_TELNET;
+    break;
 
-  *complete = 0;
+  case CURLPROTO_LDAP:
+  case CURLPROTO_LDAPS:
+    family = CURLPROTO_LDAP;
+    break;
 
-  if(conn->handler->do_more)
-    result = conn->handler->do_more(conn, complete);
+  case CURLPROTO_DICT:
+    family = CURLPROTO_DICT;
+    break;
 
-  if(!result && (*complete == 1))
-    /* do_complete must be called after the protocol-specific DO function */
-    do_complete(conn);
+  case CURLPROTO_FILE:
+    family = CURLPROTO_FILE;
+    break;
 
-  return result;
+  case CURLPROTO_TFTP:
+    family = CURLPROTO_TFTP;
+    break;
+
+  case CURLPROTO_IMAP:
+  case CURLPROTO_IMAPS:
+    family = CURLPROTO_IMAP;
+    break;
+
+  case CURLPROTO_POP3:
+  case CURLPROTO_POP3S:
+    family = CURLPROTO_POP3;
+    break;
+
+  case CURLPROTO_SMTP:
+  case CURLPROTO_SMTPS:
+      family = CURLPROTO_SMTP;
+      break;
+
+  case CURLPROTO_RTSP:
+    family = CURLPROTO_RTSP;
+    break;
+
+  case CURLPROTO_RTMP:
+  case CURLPROTO_RTMPS:
+    family = CURLPROTO_RTMP;
+    break;
+
+  case CURLPROTO_RTMPT:
+  case CURLPROTO_RTMPTS:
+    family = CURLPROTO_RTMPT;
+    break;
+
+  case CURLPROTO_RTMPE:
+    family = CURLPROTO_RTMPE;
+    break;
+
+  case CURLPROTO_RTMPTE:
+    family = CURLPROTO_RTMPTE;
+    break;
+
+  case CURLPROTO_GOPHER:
+    family = CURLPROTO_GOPHER;
+    break;
+
+  case CURLPROTO_SMB:
+  case CURLPROTO_SMBS:
+    family = CURLPROTO_SMB;
+    break;
+
+  default:
+      family = 0;
+      break;
+  }
+
+  return family;
 }
diff --git a/lib/url.h b/lib/url.h
index f9667cb..90d9db3 100644
--- a/lib/url.h
+++ b/lib/url.h
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -27,26 +27,23 @@
  * Prototypes for library-wide functions provided by url.c
  */
 
-CURLcode Curl_init_do(struct SessionHandle *data, struct connectdata *conn);
-CURLcode Curl_open(struct SessionHandle **curl);
+CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn);
+CURLcode Curl_open(struct Curl_easy **curl);
 CURLcode Curl_init_userdefined(struct UserDefined *set);
-CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
+CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option,
                      va_list arg);
-CURLcode Curl_dupset(struct SessionHandle * dst, struct SessionHandle * src);
-void Curl_freeset(struct SessionHandle * data);
-CURLcode Curl_close(struct SessionHandle *data); /* opposite of curl_open() */
-CURLcode Curl_connect(struct SessionHandle *, struct connectdata **,
+CURLcode Curl_dupset(struct Curl_easy * dst, struct Curl_easy * src);
+void Curl_freeset(struct Curl_easy * data);
+CURLcode Curl_close(struct Curl_easy *data); /* opposite of curl_open() */
+CURLcode Curl_connect(struct Curl_easy *, struct connectdata **,
                       bool *async, bool *protocol_connect);
-CURLcode Curl_do(struct connectdata **, bool *done);
-CURLcode Curl_do_more(struct connectdata *, int *completed);
-CURLcode Curl_done(struct connectdata **, CURLcode, bool premature);
 CURLcode Curl_disconnect(struct connectdata *, bool dead_connection);
 CURLcode Curl_protocol_connect(struct connectdata *conn, bool *done);
 CURLcode Curl_protocol_connecting(struct connectdata *conn, bool *done);
 CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done);
 CURLcode Curl_setup_conn(struct connectdata *conn,
                          bool *protocol_done);
-void Curl_free_request_state(struct SessionHandle *data);
+void Curl_free_request_state(struct Curl_easy *data);
 
 int Curl_protocol_getsock(struct connectdata *conn,
                           curl_socket_t *socks,
@@ -55,24 +52,21 @@ int Curl_doing_getsock(struct connectdata *conn,
                        curl_socket_t *socks,
                        int numsocks);
 
-bool Curl_isPipeliningEnabled(const struct SessionHandle *handle);
-CURLcode Curl_addHandleToPipeline(struct SessionHandle *handle,
+bool Curl_isPipeliningEnabled(const struct Curl_easy *handle);
+CURLcode Curl_addHandleToPipeline(struct Curl_easy *handle,
                                   struct curl_llist *pipeline);
-int Curl_removeHandleFromPipeline(struct SessionHandle *handle,
+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 SessionHandle *data,
+void Curl_getoff_all_pipelines(struct Curl_easy *data,
                                struct connectdata *conn);
 
-void Curl_close_connections(struct SessionHandle *data);
+void Curl_close_connections(struct Curl_easy *data);
 
 #define CURL_DEFAULT_PROXY_PORT 1080 /* default proxy port unless specified */
-#define CURL_DEFAULT_SOCKS5_GSSAPI_SERVICE "rcmd" /* default socks5 gssapi
-                                                     service */
-#define CURL_DEFAULT_PROXY_SERVICE_NAME "HTTP" /* default negotiate proxy
-                                                  service */
-#define CURL_DEFAULT_SERVICE_NAME "HTTP"  /* default negotiate service */
 
 CURLcode Curl_connected_proxy(struct connectdata *conn, int sockindex);
 
diff --git a/lib/urldata.h b/lib/urldata.h
index b1c2056..3cf7ed9 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -93,7 +93,15 @@
 #include <gnutls/gnutls.h>
 #endif
 
-#ifdef USE_POLARSSL
+#ifdef USE_MBEDTLS
+
+#include <mbedtls/ssl.h>
+#include <mbedtls/version.h>
+#include <mbedtls/entropy.h>
+#include <mbedtls/ctr_drbg.h>
+
+#elif defined USE_POLARSSL
+
 #include <polarssl/ssl.h>
 #include <polarssl/version.h>
 #if POLARSSL_VERSION_NUMBER<0x01010000
@@ -102,6 +110,7 @@
 #include <polarssl/entropy.h>
 #include <polarssl/ctr_drbg.h>
 #endif /* POLARSSL_VERSION_NUMBER<0x01010000 */
+
 #endif /* USE_POLARSSL */
 
 #ifdef USE_CYASSL
@@ -199,14 +208,13 @@
 
 #define CURLEASY_MAGIC_NUMBER 0xc0dedbadU
 #define GOOD_EASY_HANDLE(x) \
-  ((x) && (((struct SessionHandle *)(x))->magic == CURLEASY_MAGIC_NUMBER))
+  ((x) && ((x)->magic == CURLEASY_MAGIC_NUMBER))
 
 /* Some convenience macros to get the larger/smaller value out of two given.
    We prefix with CURL to prevent name collisions. */
 #define CURLMAX(x,y) ((x)>(y)?(x):(y))
 #define CURLMIN(x,y) ((x)<(y)?(x):(y))
 
-
 #ifdef HAVE_GSSAPI
 /* Types needed for krb5-ftp connections */
 struct krb5buffer {
@@ -233,7 +241,6 @@ struct curl_schannel_cred {
   CredHandle cred_handle;
   TimeStamp time_stamp;
   int refcount;
-  bool cached;
 };
 
 struct curl_schannel_ctxt {
@@ -265,61 +272,57 @@ struct ssl_connect_data {
      current state of the connection. */
   bool use;
   ssl_connection_state state;
-#ifdef USE_OPENSSL
+  ssl_connect_state connecting_state;
+#if defined(USE_OPENSSL)
   /* these ones requires specific SSL-types */
   SSL_CTX* ctx;
   SSL*     handle;
   X509*    server_cert;
-  ssl_connect_state connecting_state;
-#endif /* USE_OPENSSL */
-#ifdef USE_GNUTLS
+#elif defined(USE_GNUTLS)
   gnutls_session_t session;
   gnutls_certificate_credentials_t cred;
 #ifdef USE_TLS_SRP
   gnutls_srp_client_credentials_t srp_client_cred;
 #endif
-  ssl_connect_state connecting_state;
-#endif /* USE_GNUTLS */
-#ifdef USE_POLARSSL
+#elif defined(USE_MBEDTLS)
+  mbedtls_ctr_drbg_context ctr_drbg;
+  mbedtls_entropy_context entropy;
+  mbedtls_ssl_context ssl;
+  int server_fd;
+  mbedtls_x509_crt cacert;
+  mbedtls_x509_crt clicert;
+  mbedtls_x509_crl crl;
+  mbedtls_pk_context pk;
+  mbedtls_ssl_config config;
+  const char *protocols[3];
+#elif defined(USE_POLARSSL)
   ctr_drbg_context ctr_drbg;
   entropy_context entropy;
   ssl_context ssl;
-  ssl_session ssn;
   int server_fd;
   x509_crt cacert;
   x509_crt clicert;
   x509_crl crl;
   rsa_context rsa;
-  ssl_connect_state connecting_state;
-#endif /* USE_POLARSSL */
-#ifdef USE_CYASSL
+#elif defined(USE_CYASSL)
   SSL_CTX* ctx;
   SSL*     handle;
-  ssl_connect_state connecting_state;
-#endif /* USE_CYASSL */
-#ifdef USE_NSS
+#elif defined(USE_NSS)
   PRFileDesc *handle;
   char *client_nickname;
-  struct SessionHandle *data;
+  struct Curl_easy *data;
   struct curl_llist *obj_list;
   PK11GenericObject *obj_clicert;
-  ssl_connect_state connecting_state;
-#endif /* USE_NSS */
-#ifdef USE_GSKIT
+#elif defined(USE_GSKIT)
   gsk_handle handle;
   int iocport;
-  ssl_connect_state connecting_state;
-#endif
-#ifdef USE_AXTLS
+#elif defined(USE_AXTLS)
   SSL_CTX* ssl_ctx;
   SSL*     ssl;
-  ssl_connect_state connecting_state;
-#endif /* USE_AXTLS */
-#ifdef USE_SCHANNEL
+#elif defined(USE_SCHANNEL)
   struct curl_schannel_cred *cred;
   struct curl_schannel_ctxt *ctxt;
   SecPkgContext_StreamSizes stream_sizes;
-  ssl_connect_state connecting_state;
   size_t encdata_length, decdata_length;
   size_t encdata_offset, decdata_offset;
   unsigned char *encdata_buffer, *decdata_buffer;
@@ -327,14 +330,14 @@ struct ssl_connect_data {
   CURLcode recv_unrecoverable_err; /* schannel_recv had an unrecoverable err */
   bool recv_sspi_close_notify; /* true if connection closed by close_notify */
   bool recv_connection_closed; /* true if connection closed, regardless how */
-#endif /* USE_SCHANNEL */
-#ifdef USE_DARWINSSL
+#elif defined(USE_DARWINSSL)
   SSLContextRef ssl_ctx;
   curl_socket_t ssl_sockfd;
-  ssl_connect_state connecting_state;
   bool ssl_direction; /* true if writing, false if reading */
   size_t ssl_write_buffered_length;
-#endif /* USE_DARWINSSL */
+#elif defined(USE_SSL)
+#error "SSL backend specific information missing from ssl_connect_data"
+#endif
 };
 
 struct ssl_config_data {
@@ -348,6 +351,7 @@ struct ssl_config_data {
   char *CAfile;          /* certificate to verify peer against */
   const char *CRLfile;   /* CRL to check certificate revocation */
   const char *issuercert;/* optional issuer certificate filename */
+  char *clientcert;
   char *random_file;     /* path to file containing "random" data */
   char *egdsocket;       /* path to file containing the EGD daemon socket */
   char *cipher_list;     /* list of ciphers to use */
@@ -368,10 +372,12 @@ struct ssl_config_data {
 /* information stored about one single SSL session */
 struct curl_ssl_session {
   char *name;       /* host name for which this ID was used */
+  char *conn_to_host; /* host name for the connection (may be NULL) */
   void *sessionid;  /* as returned from the SSL layer */
   size_t idsize;    /* if known, otherwise 0 */
   long age;         /* just a number, the higher the more recent */
-  int remote_port;  /* remote port to connect to */
+  int remote_port;  /* remote port */
+  int conn_to_port; /* remote port for the connection (may be -1) */
   struct ssl_config_data ssl_config; /* setup for this session */
 };
 
@@ -457,7 +463,7 @@ struct negotiatedata {
 #ifdef HAVE_GSSAPI
   OM_uint32 status;
   gss_ctx_id_t context;
-  gss_name_t server_name;
+  gss_name_t spn;
   gss_buffer_desc output_token;
 #else
 #ifdef USE_WINDOWS_SSPI
@@ -466,7 +472,7 @@ struct negotiatedata {
   CtxtHandle *context;
   SEC_WINNT_AUTH_IDENTITY identity;
   SEC_WINNT_AUTH_IDENTITY *p_identity;
-  TCHAR *server_name;
+  TCHAR *spn;
   size_t token_max;
   BYTE *output_token;
   size_t output_token_length;
@@ -483,6 +489,10 @@ struct ConnectBits {
   /* always modify bits.close with the connclose() and connkeep() macros! */
   bool close; /* if set, we close the connection after this request */
   bool reuse; /* if set, this is a re-used connection */
+  bool conn_to_host; /* if set, this connection has a "connect to host"
+                        that overrides the host in the URL */
+  bool conn_to_port; /* if set, this connection has a "connect to port"
+                        that overrides the port in the URL (remote port) */
   bool proxy; /* if set, this transfer is done through a proxy - any type */
   bool httpproxy;    /* if set, this transfer is done through a http proxy */
   bool user_passwd;    /* do we use user+password for this connection? */
@@ -531,6 +541,10 @@ struct ConnectBits {
                  connection */
   bool type_set;  /* type= was used in the URL */
   bool multiplex; /* connection is multiplexed */
+
+  bool tcp_fastopen; /* use TCP Fast Open */
+  bool tls_enable_npn;  /* TLS NPN extension? */
+  bool tls_enable_alpn; /* TLS ALPN extension? */
 };
 
 struct hostname {
@@ -604,9 +618,9 @@ enum upgrade101 {
 };
 
 /*
- * Request specific data in the easy handle (SessionHandle).  Previously,
+ * Request specific data in the easy handle (Curl_easy).  Previously,
  * these members were on the connectdata struct but since a conn struct may
- * now be shared between different SessionHandles, we store connection-specific
+ * now be shared between different Curl_easys, we store connection-specific
  * data here. This struct only keeps stuff that's interesting for *this*
  * request, as it will be cleared between multiple ones
  */
@@ -777,7 +791,7 @@ struct Curl_handler {
 
   /* If used, this function gets called from transfer.c:readwrite_data() to
      allow the protocol to do extra reads/writes */
-  CURLcode (*readwrite)(struct SessionHandle *data, struct connectdata *conn,
+  CURLcode (*readwrite)(struct Curl_easy *data, struct connectdata *conn,
                         ssize_t *nread, bool *readmore);
 
   long defport;           /* Default port. */
@@ -802,7 +816,7 @@ struct Curl_handler {
                                         url query strings (?foo=bar) ! */
 #define PROTOPT_CREDSPERREQUEST (1<<7) /* requires login credentials per
                                           request instead of per connection */
-
+#define PROTOPT_ALPN_NPN (1<<8) /* set ALPN and/or NPN for this */
 
 /* return the count of bytes sent, or -1 on error */
 typedef ssize_t (Curl_send)(struct connectdata *conn, /* connection data */
@@ -818,15 +832,29 @@ typedef ssize_t (Curl_recv)(struct connectdata *conn, /* connection data */
                             size_t len,               /* max amount to read */
                             CURLcode *err);           /* error to return */
 
+#ifdef USE_RECV_BEFORE_SEND_WORKAROUND
+struct postponed_data {
+  char *buffer;          /* Temporal store for received data during
+                            sending, must be freed */
+  size_t allocated_size; /* Size of temporal store */
+  size_t recv_size;      /* Size of received data during sending */
+  size_t recv_processed; /* Size of processed part of postponed data */
+#ifdef DEBUGBUILD
+  curl_socket_t bindsock;/* Structure must be bound to specific socket,
+                            used only for DEBUGASSERT */
+#endif /* DEBUGBUILD */
+};
+#endif /* USE_RECV_BEFORE_SEND_WORKAROUND */
+
 /*
  * The connectdata struct contains all fields and variables that should be
  * unique for an entire connection.
  */
 struct connectdata {
-  /* 'data' is the CURRENT SessionHandle using this connection -- take great
+  /* 'data' is the CURRENT Curl_easy using this connection -- take great
      caution that this might very well vary between different times this
      connection is used! */
-  struct SessionHandle *data;
+  struct Curl_easy *data;
 
   /* chunk is for HTTP chunked encoding, but is in the general connectdata
      struct only because we can do just about any protocol through a HTTP proxy
@@ -867,10 +895,14 @@ struct connectdata {
   int socktype;  /* SOCK_STREAM or SOCK_DGRAM */
 
   struct hostname host;
+  struct hostname conn_to_host; /* the host to connect to. valid only if
+                                   bits.conn_to_host is set */
   struct hostname proxy;
 
   long port;       /* which port to use locally */
-  int remote_port; /* what remote port to connect to, not the proxy port! */
+  int remote_port; /* the remote port, not the proxy port! */
+  int conn_to_port; /* the remote port to connect to. valid only if
+                       bits.conn_to_port is set */
 
   /* 'primary_ip' and 'primary_port' get filled with peer's numerical
      ip address and port number whenever an outgoing connection is
@@ -893,7 +925,7 @@ struct connectdata {
   char *passwd;  /* password string, allocated */
   char *options; /* options string, allocated */
 
-  char *xoauth2_bearer; /* bearer token for xoauth2, allocated */
+  char *oauth_bearer; /* bearer token for OAuth 2.0, allocated */
 
   char *proxyuser;    /* proxy user name string, allocated */
   char *proxypasswd;  /* proxy password string, allocated */
@@ -912,8 +944,12 @@ struct connectdata {
   Curl_recv *recv[2];
   Curl_send *send[2];
 
+#ifdef USE_RECV_BEFORE_SEND_WORKAROUND
+  struct postponed_data postponed[2]; /* two buffers for two sockets */
+#endif /* USE_RECV_BEFORE_SEND_WORKAROUND */
   struct ssl_connect_data ssl[2]; /* this is for ssl-stuff */
   struct ssl_config_data ssl_config;
+  bool tls_upgraded;
 
   struct ConnectBits bits;    /* various state-flags for this connection */
 
@@ -929,7 +965,7 @@ struct connectdata {
   const struct Curl_handler *handler; /* Connection's protocol handler */
   const struct Curl_handler *given;   /* The protocol first given */
 
-  long ip_version; /* copied from the SessionHandle at creation time */
+  long ip_version; /* copied from the Curl_easy at creation time */
 
   /**** curl_get() phase fields */
 
@@ -1172,7 +1208,7 @@ typedef enum {
 /*
  * Values that are generated, temporary or calculated internally for a
  * "session handle" must be defined within the 'struct UrlState'.  This struct
- * will be used within the SessionHandle struct. When the 'SessionHandle'
+ * will be used within the Curl_easy struct. When the 'Curl_easy'
  * struct is cloned, this data MUST NOT be copied.
  *
  * Remember that any "state" information goes globally for the curl handle.
@@ -1218,11 +1254,13 @@ struct UrlState {
                                 bytes / second */
   bool this_is_a_follow; /* this is a followed Location: request */
 
-  char *first_host; /* if set, this should be the host name that we will
+  char *first_host; /* host name of the first (not followed) request.
+                       if set, this should be the host name that we will
                        sent authorization to, no else. Used to make Location:
                        following not keep sending user+password... This is
                        strdup() data.
                     */
+  int first_remote_port; /* remote port of the first (not followed) request */
   struct curl_ssl_session *session; /* array of 'max_ssl_sessions' size */
   long sessionage;                  /* number of the most recent session */
   char *tempwrite;      /* allocated buffer to keep data in when a write
@@ -1306,12 +1344,19 @@ struct UrlState {
   curl_off_t infilesize; /* size of file to upload, -1 means unknown.
                             Copied from set.filesize at start of operation */
 
-  int drain; /* Increased when this stream has data to read, even if its
-                socket not necessarily is readable. Decreased when
-                checked. */
-  bool done; /* set to FALSE when Curl_do() is called and set to TRUE when
-                Curl_done() is called, to prevent Curl_done() to get invoked
-                twice when the multi interface is used. */
+  size_t drain; /* Increased when this stream has data to read, even if its
+                   socket is not necessarily is readable. Decreased when
+                   checked. */
+  bool done; /* set to FALSE when Curl_init_do() is called and set to TRUE
+                when multi_done() is called, to prevent multi_done() to get
+                invoked twice when the multi interface is used. */
+
+  curl_read_callback fread_func; /* read callback/function */
+  void *in;                      /* CURLOPT_READDATA */
+
+  struct Curl_easy *stream_depends_on;
+  bool stream_depends_e; /* set or don't set the Exclusive bit */
+  int stream_weight;
 };
 
 
@@ -1350,6 +1395,7 @@ enum dupstring {
   STRING_COOKIE,          /* HTTP cookie string to send */
   STRING_COOKIEJAR,       /* dump all cookies to this file */
   STRING_CUSTOMREQUEST,   /* HTTP/FTP/RTSP request/method to use */
+  STRING_DEFAULT_PROTOCOL, /* Protocol to use when the URL doesn't specify */
   STRING_DEVICE,          /* local network interface/address to use */
   STRING_ENCODING,        /* Accept-Encoding string */
   STRING_FTP_ACCOUNT,     /* ftp account data */
@@ -1391,8 +1437,10 @@ enum dupstring {
   STRING_SSH_KNOWNHOSTS,  /* file name of knownhosts file */
 #endif
 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
-  STRING_SOCKS5_GSSAPI_SERVICE, /* GSSAPI service name */
   STRING_PROXY_SERVICE_NAME, /* Proxy service name */
+#endif
+#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) || \
+    defined(USE_SPNEGO)
   STRING_SERVICE_NAME,    /* Service name */
 #endif
   STRING_MAIL_FROM,
@@ -1427,7 +1475,7 @@ struct UserDefined {
                      proxy string features a ":[port]" that one will override
                      this. */
   void *out;         /* CURLOPT_WRITEDATA */
-  void *in;          /* CURLOPT_READDATA */
+  void *in_set;      /* CURLOPT_READDATA */
   void *writeheader; /* write the header to this if non-NULL */
   void *rtp_out;     /* write RTP to this if non-NULL */
   long use_port;     /* which port to use (when not using default) */
@@ -1452,7 +1500,7 @@ struct UserDefined {
   curl_write_callback fwrite_func;   /* function that stores the output */
   curl_write_callback fwrite_header; /* function that stores headers */
   curl_write_callback fwrite_rtp;    /* function that stores interleaved RTP */
-  curl_read_callback fread_func;     /* function that reads the input */
+  curl_read_callback fread_func_set; /* function that reads the input */
   int is_fread_set; /* boolean, has read callback been set to non-NULL? */
   int is_fwrite_set; /* boolean, has write callback been set to non-NULL? */
   curl_progress_callback fprogress; /* OLD and deprecated progress callback  */
@@ -1484,7 +1532,8 @@ struct UserDefined {
   long connecttimeout;  /* in milliseconds, 0 means no timeout */
   long accepttimeout;   /* in milliseconds, 0 means no timeout */
   long server_response_timeout; /* in milliseconds, 0 means no timeout */
-  long tftp_blksize ; /* in bytes, 0 means use default */
+  long tftp_blksize;    /* in bytes, 0 means use default */
+  bool tftp_no_options; /* do not send TFTP options requests */
   curl_off_t filesize;  /* size of file to upload, -1 means unknown */
   long low_speed_limit; /* bytes/second */
   long low_speed_time;  /* number of seconds */
@@ -1509,6 +1558,8 @@ struct UserDefined {
   struct curl_slist *telnet_options; /* linked list of telnet options */
   struct curl_slist *resolve;     /* list of names to add/remove from
                                      DNS cache */
+  struct curl_slist *connect_to; /* list of host:port mappings to override
+                                    the hostname and port to connect to */
   curl_TimeCond timecondition; /* kind of time/date comparison */
   time_t timevalue;       /* what time to compare with */
   Curl_HttpReq httpreq;   /* what kind of HTTP request (if any) is this */
@@ -1556,7 +1607,6 @@ struct UserDefined {
   bool http_set_referer; /* is a custom referer used */
   bool http_auto_referer; /* set "correct" referer when following location: */
   bool opt_no_body;      /* as set with CURLOPT_NOBODY */
-  bool set_port;         /* custom port number used */
   bool upload;           /* upload request */
   enum CURL_NETRC_OPTION
        use_netrc;        /* defined in include/curl.h */
@@ -1596,7 +1646,7 @@ struct UserDefined {
   long allowed_protocols;
   long redir_protocols;
 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
-  long socks5_gssapi_nec; /* flag to support nec socks5 server */
+  bool socks5_gssapi_nec; /* Flag to support NEC SOCKS5 server */
 #endif
   struct curl_slist *mail_rcpt; /* linked list of mail recipients */
   bool sasl_ir;         /* Enable/disable SASL initial response */
@@ -1618,15 +1668,20 @@ struct UserDefined {
   bool tcp_keepalive;    /* use TCP keepalives */
   long tcp_keepidle;     /* seconds in idle before sending keepalive probe */
   long tcp_keepintvl;    /* seconds between TCP keepalive probes */
+  bool tcp_fastopen;     /* use TCP Fast Open */
 
   size_t maxconnects;  /* Max idle connections in the connection cache */
 
-  bool ssl_enable_npn;  /* TLS NPN extension? */
-  bool ssl_enable_alpn; /* TLS ALPN extension? */
+  bool ssl_enable_npn;      /* TLS NPN extension? */
+  bool ssl_enable_alpn;     /* TLS ALPN extension? */
   bool path_as_is;      /* allow dotdots? */
   bool pipewait;        /* wait for pipe/multiplex status before starting a
                            new connection */
   long expect_100_timeout; /* in milliseconds */
+
+  struct Curl_easy *stream_depends_on;
+  bool stream_depends_e; /* set or don't set the Exclusive bit */
+  int stream_weight;
 };
 
 struct Names {
@@ -1649,10 +1704,10 @@ struct Names {
  * 'struct UrlState' instead.
  */
 
-struct SessionHandle {
+struct Curl_easy {
   /* first, two fields for the linked list of these */
-  struct SessionHandle *next;
-  struct SessionHandle *prev;
+  struct Curl_easy *next;
+  struct Curl_easy *prev;
 
   struct connectdata *easy_conn;     /* the "unit's" connection */
 
diff --git a/lib/vauth/cleartext.c b/lib/vauth/cleartext.c
new file mode 100644
index 0000000..4e906bc
--- /dev/null
+++ b/lib/vauth/cleartext.c
@@ -0,0 +1,157 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.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.
+ *
+ * RFC4616 PLAIN authentication
+ * Draft   LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt>
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+#include "urldata.h"
+
+#include "vauth/vauth.h"
+#include "curl_base64.h"
+#include "curl_md5.h"
+#include "warnless.h"
+#include "strtok.h"
+#include "strequal.h"
+#include "rawstr.h"
+#include "sendf.h"
+#include "curl_printf.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Curl_auth_create_plain_message()
+ *
+ * This is used to generate an already encoded PLAIN message ready
+ * for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data    [in]     - The session handle.
+ * userp   [in]     - The user name.
+ * passdwp [in]     - The user's password.
+ * 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_plain_message(struct Curl_easy *data,
+                                        const char *userp,
+                                        const char *passwdp,
+                                        char **outptr, size_t *outlen)
+{
+  CURLcode result;
+  char *plainauth;
+  size_t ulen;
+  size_t plen;
+
+  ulen = strlen(userp);
+  plen = strlen(passwdp);
+
+  plainauth = malloc(2 * ulen + plen + 2);
+  if(!plainauth) {
+    *outlen = 0;
+    *outptr = NULL;
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  /* Calculate the reply */
+  memcpy(plainauth, userp, ulen);
+  plainauth[ulen] = '\0';
+  memcpy(plainauth + ulen + 1, userp, ulen);
+  plainauth[2 * ulen + 1] = '\0';
+  memcpy(plainauth + 2 * ulen + 2, passwdp, plen);
+
+  /* Base64 encode the reply */
+  result = Curl_base64_encode(data, plainauth, 2 * ulen + plen + 2, outptr,
+                              outlen);
+  free(plainauth);
+
+  return result;
+}
+
+/*
+ * Curl_auth_create_login_message()
+ *
+ * This is used to generate an already encoded LOGIN message containing the
+ * user name or password ready for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data    [in]     - The session handle.
+ * valuep  [in]     - The user name or user's password.
+ * 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_login_message(struct Curl_easy *data,
+                                        const char *valuep, char **outptr,
+                                        size_t *outlen)
+{
+  size_t vlen = strlen(valuep);
+
+  if(!vlen) {
+    /* Calculate an empty reply */
+    *outptr = strdup("=");
+    if(*outptr) {
+      *outlen = (size_t) 1;
+      return CURLE_OK;
+    }
+
+    *outlen = 0;
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  /* Base64 encode the value */
+  return Curl_base64_encode(data, valuep, vlen, outptr, outlen);
+}
+
+/*
+ * Curl_auth_create_external_message()
+ *
+ * This is used to generate an already encoded EXTERNAL message containing
+ * the user name ready for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data    [in]     - The session handle.
+ * user    [in]     - The user name.
+ * 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_external_message(struct Curl_easy *data,
+                                           const char *user, char **outptr,
+                                           size_t *outlen)
+{
+  /* This is the same formatting as the login message */
+  return Curl_auth_create_login_message(data, user, outptr, outlen);
+}
diff --git a/lib/vauth/cram.c b/lib/vauth/cram.c
new file mode 100644
index 0000000..3074a16
--- /dev/null
+++ b/lib/vauth/cram.c
@@ -0,0 +1,138 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.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.
+ *
+ * RFC2195 CRAM-MD5 authentication
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_CRYPTO_AUTH)
+
+#include <curl/curl.h>
+#include "urldata.h"
+
+#include "vauth/vauth.h"
+#include "curl_base64.h"
+#include "curl_hmac.h"
+#include "curl_md5.h"
+#include "warnless.h"
+#include "curl_printf.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Curl_auth_decode_cram_md5_message()
+ *
+ * This is used to decode an already encoded CRAM-MD5 challenge message.
+ *
+ * Parameters:
+ *
+ * chlg64  [in]     - The base64 encoded challenge message.
+ * 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_decode_cram_md5_message(const char *chlg64, char **outptr,
+                                           size_t *outlen)
+{
+  CURLcode result = CURLE_OK;
+  size_t chlg64len = strlen(chlg64);
+
+  *outptr = NULL;
+  *outlen = 0;
+
+  /* Decode the challenge if necessary */
+  if(chlg64len && *chlg64 != '=')
+    result = Curl_base64_decode(chlg64, (unsigned char **) outptr, outlen);
+
+  return result;
+}
+
+/*
+ * Curl_auth_create_cram_md5_message()
+ *
+ * This is used to generate an already encoded CRAM-MD5 response message ready
+ * for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data    [in]     - The session handle.
+ * chlg    [in]     - The challenge.
+ * userp   [in]     - The user name.
+ * passdwp [in]     - The user's password.
+ * 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_cram_md5_message(struct Curl_easy *data,
+                                           const char *chlg,
+                                           const char *userp,
+                                           const char *passwdp,
+                                           char **outptr, size_t *outlen)
+{
+  CURLcode result = CURLE_OK;
+  size_t chlglen = 0;
+  HMAC_context *ctxt;
+  unsigned char digest[MD5_DIGEST_LEN];
+  char *response;
+
+  if(chlg)
+    chlglen = strlen(chlg);
+
+  /* Compute the digest using the password as the key */
+  ctxt = Curl_HMAC_init(Curl_HMAC_MD5,
+                        (const unsigned char *) passwdp,
+                        curlx_uztoui(strlen(passwdp)));
+  if(!ctxt)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* Update the digest with the given challenge */
+  if(chlglen > 0)
+    Curl_HMAC_update(ctxt, (const unsigned char *) chlg,
+                     curlx_uztoui(chlglen));
+
+  /* Finalise the digest */
+  Curl_HMAC_final(ctxt, digest);
+
+  /* Generate the response */
+  response = aprintf(
+    "%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
+    userp, digest[0], digest[1], digest[2], digest[3], digest[4],
+    digest[5], digest[6], digest[7], digest[8], digest[9], digest[10],
+    digest[11], digest[12], digest[13], digest[14], digest[15]);
+  if(!response)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* Base64 encode the response */
+  result = Curl_base64_encode(data, response, 0, outptr, outlen);
+
+  free(response);
+
+  return result;
+}
+
+#endif /* !CURL_DISABLE_CRYPTO_AUTH */
diff --git a/lib/vauth/digest.c b/lib/vauth/digest.c
new file mode 100644
index 0000000..26ea7b5
--- /dev/null
+++ b/lib/vauth/digest.c
@@ -0,0 +1,883 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.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.
+ *
+ * RFC2831 DIGEST-MD5 authentication
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_CRYPTO_AUTH)
+
+#include <curl/curl.h>
+
+#include "vauth/vauth.h"
+#include "vauth/digest.h"
+#include "urldata.h"
+#include "curl_base64.h"
+#include "curl_hmac.h"
+#include "curl_md5.h"
+#include "vtls/vtls.h"
+#include "warnless.h"
+#include "strtok.h"
+#include "rawstr.h"
+#include "non-ascii.h" /* included for Curl_convert_... prototypes */
+#include "curl_printf.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#if !defined(USE_WINDOWS_SSPI)
+#define DIGEST_QOP_VALUE_AUTH             (1 << 0)
+#define DIGEST_QOP_VALUE_AUTH_INT         (1 << 1)
+#define DIGEST_QOP_VALUE_AUTH_CONF        (1 << 2)
+
+#define DIGEST_QOP_VALUE_STRING_AUTH      "auth"
+#define DIGEST_QOP_VALUE_STRING_AUTH_INT  "auth-int"
+#define DIGEST_QOP_VALUE_STRING_AUTH_CONF "auth-conf"
+
+/* The CURL_OUTPUT_DIGEST_CONV macro below is for non-ASCII machines.
+   It converts digest text to ASCII so the MD5 will be correct for
+   what ultimately goes over the network.
+*/
+#define CURL_OUTPUT_DIGEST_CONV(a, b) \
+  result = Curl_convert_to_network(a, (char *)b, strlen((const char*)b)); \
+  if(result) { \
+    free(b); \
+    return result; \
+  }
+#endif /* !USE_WINDOWS_SSPI */
+
+bool Curl_auth_digest_get_pair(const char *str, char *value, char *content,
+                               const char **endptr)
+{
+  int c;
+  bool starts_with_quote = FALSE;
+  bool escape = FALSE;
+
+  for(c = DIGEST_MAX_VALUE_LENGTH - 1; (*str && (*str != '=') && c--);)
+    *value++ = *str++;
+  *value = 0;
+
+  if('=' != *str++)
+    /* eek, no match */
+    return FALSE;
+
+  if('\"' == *str) {
+    /* This starts with a quote so it must end with one as well! */
+    str++;
+    starts_with_quote = TRUE;
+  }
+
+  for(c = DIGEST_MAX_CONTENT_LENGTH - 1; *str && c--; str++) {
+    switch(*str) {
+    case '\\':
+      if(!escape) {
+        /* possibly the start of an escaped quote */
+        escape = TRUE;
+        *content++ = '\\'; /* Even though this is an escape character, we still
+                              store it as-is in the target buffer */
+        continue;
+      }
+      break;
+
+    case ',':
+      if(!starts_with_quote) {
+        /* This signals the end of the content if we didn't get a starting
+           quote and then we do "sloppy" parsing */
+        c = 0; /* the end */
+        continue;
+      }
+      break;
+
+    case '\r':
+    case '\n':
+      /* end of string */
+      c = 0;
+      continue;
+
+    case '\"':
+      if(!escape && starts_with_quote) {
+        /* end of string */
+        c = 0;
+        continue;
+      }
+      break;
+    }
+
+    escape = FALSE;
+    *content++ = *str;
+  }
+
+  *content = 0;
+  *endptr = str;
+
+  return TRUE;
+}
+
+#if !defined(USE_WINDOWS_SSPI)
+/* Convert md5 chunk to RFC2617 (section 3.1.3) -suitable ascii string*/
+static void auth_digest_md5_to_ascii(unsigned char *source, /* 16 bytes */
+                                     unsigned char *dest) /* 33 bytes */
+{
+  int i;
+  for(i = 0; i < 16; 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)
+{
+  char *dest, *d;
+  const char *s = source;
+  size_t n = 1; /* null terminator */
+
+  /* Calculate size needed */
+  while(*s) {
+    ++n;
+    if(*s == '"' || *s == '\\') {
+      ++n;
+    }
+    ++s;
+  }
+
+  dest = malloc(n);
+  if(dest) {
+    s = source;
+    d = dest;
+    while(*s) {
+      if(*s == '"' || *s == '\\') {
+        *d++ = '\\';
+      }
+      *d++ = *s++;
+    }
+    *d = 0;
+  }
+
+  return dest;
+}
+
+/* Retrieves the value for a corresponding key from the challenge string
+ * returns TRUE if the key could be found, FALSE if it does not exists
+ */
+static bool auth_digest_get_key_value(const char *chlg,
+                                      const char *key,
+                                      char *value,
+                                      size_t max_val_len,
+                                      char end_char)
+{
+  char *find_pos;
+  size_t i;
+
+  find_pos = strstr(chlg, key);
+  if(!find_pos)
+    return FALSE;
+
+  find_pos += strlen(key);
+
+  for(i = 0; *find_pos && *find_pos != end_char && i < max_val_len - 1; ++i)
+    value[i] = *find_pos++;
+  value[i] = '\0';
+
+  return TRUE;
+}
+
+static CURLcode auth_digest_get_qop_values(const char *options, int *value)
+{
+  char *tmp;
+  char *token;
+  char *tok_buf;
+
+  /* Initialise the output */
+  *value = 0;
+
+  /* Tokenise the list of qop values. Use a temporary clone of the buffer since
+     strtok_r() ruins it. */
+  tmp = strdup(options);
+  if(!tmp)
+    return CURLE_OUT_OF_MEMORY;
+
+  token = strtok_r(tmp, ",", &tok_buf);
+  while(token != NULL) {
+    if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH))
+      *value |= DIGEST_QOP_VALUE_AUTH;
+    else if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH_INT))
+      *value |= DIGEST_QOP_VALUE_AUTH_INT;
+    else if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH_CONF))
+      *value |= DIGEST_QOP_VALUE_AUTH_CONF;
+
+    token = strtok_r(NULL, ",", &tok_buf);
+  }
+
+  free(tmp);
+
+  return CURLE_OK;
+}
+
+/*
+ * auth_decode_digest_md5_message()
+ *
+ * This is used internally to decode an already encoded DIGEST-MD5 challenge
+ * message into the seperate attributes.
+ *
+ * Parameters:
+ *
+ * chlg64  [in]     - The base64 encoded challenge message.
+ * nonce   [in/out] - The buffer where the nonce will be stored.
+ * nlen    [in]     - The length of the nonce buffer.
+ * realm   [in/out] - The buffer where the realm will be stored.
+ * rlen    [in]     - The length of the realm buffer.
+ * alg     [in/out] - The buffer where the algorithm will be stored.
+ * alen    [in]     - The length of the algorithm buffer.
+ * qop     [in/out] - The buffer where the qop-options will be stored.
+ * qlen    [in]     - The length of the qop buffer.
+ *
+ * Returns CURLE_OK on success.
+ */
+static CURLcode auth_decode_digest_md5_message(const char *chlg64,
+                                               char *nonce, size_t nlen,
+                                               char *realm, size_t rlen,
+                                               char *alg, size_t alen,
+                                               char *qop, size_t qlen)
+{
+  CURLcode result = CURLE_OK;
+  unsigned char *chlg = NULL;
+  size_t chlglen = 0;
+  size_t chlg64len = strlen(chlg64);
+
+  /* Decode the base-64 encoded challenge message */
+  if(chlg64len && *chlg64 != '=') {
+    result = Curl_base64_decode(chlg64, &chlg, &chlglen);
+    if(result)
+      return result;
+  }
+
+  /* Ensure we have a valid challenge message */
+  if(!chlg)
+    return CURLE_BAD_CONTENT_ENCODING;
+
+  /* Retrieve nonce string from the challenge */
+  if(!auth_digest_get_key_value((char *) chlg, "nonce=\"", nonce, nlen,
+                                '\"')) {
+    free(chlg);
+    return CURLE_BAD_CONTENT_ENCODING;
+  }
+
+  /* Retrieve realm string from the challenge */
+  if(!auth_digest_get_key_value((char *) chlg, "realm=\"", realm, rlen,
+                                '\"')) {
+    /* Challenge does not have a realm, set empty string [RFC2831] page 6 */
+    strcpy(realm, "");
+  }
+
+  /* Retrieve algorithm string from the challenge */
+  if(!auth_digest_get_key_value((char *) chlg, "algorithm=", alg, alen, ',')) {
+    free(chlg);
+    return CURLE_BAD_CONTENT_ENCODING;
+  }
+
+  /* Retrieve qop-options string from the challenge */
+  if(!auth_digest_get_key_value((char *) chlg, "qop=\"", qop, qlen, '\"')) {
+    free(chlg);
+    return CURLE_BAD_CONTENT_ENCODING;
+  }
+
+  free(chlg);
+
+  return CURLE_OK;
+}
+
+/*
+ * Curl_auth_create_digest_md5_message()
+ *
+ * This is used to generate an already encoded DIGEST-MD5 response message
+ * ready for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data    [in]     - The session handle.
+ * chlg64  [in]     - The base64 encoded challenge message.
+ * userp   [in]     - The user name.
+ * passdwp [in]     - The user's password.
+ * service [in]     - The service type such as http, smtp, pop or imap.
+ * 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_md5_message(struct Curl_easy *data,
+                                             const char *chlg64,
+                                             const char *userp,
+                                             const char *passwdp,
+                                             const char *service,
+                                             char **outptr, size_t *outlen)
+{
+  CURLcode result = CURLE_OK;
+  size_t i;
+  MD5_context *ctxt;
+  char *response = NULL;
+  unsigned char digest[MD5_DIGEST_LEN];
+  char HA1_hex[2 * MD5_DIGEST_LEN + 1];
+  char HA2_hex[2 * MD5_DIGEST_LEN + 1];
+  char resp_hash_hex[2 * MD5_DIGEST_LEN + 1];
+  char nonce[64];
+  char realm[128];
+  char algorithm[64];
+  char qop_options[64];
+  int qop_values;
+  char cnonce[33];
+  unsigned int entropy[4];
+  char nonceCount[] = "00000001";
+  char method[]     = "AUTHENTICATE";
+  char qop[]        = DIGEST_QOP_VALUE_STRING_AUTH;
+  char *spn         = NULL;
+
+  /* Decode the challange message */
+  result = auth_decode_digest_md5_message(chlg64, nonce, sizeof(nonce),
+                                          realm, sizeof(realm),
+                                          algorithm, sizeof(algorithm),
+                                          qop_options, sizeof(qop_options));
+  if(result)
+    return result;
+
+  /* We only support md5 sessions */
+  if(strcmp(algorithm, "md5-sess") != 0)
+    return CURLE_BAD_CONTENT_ENCODING;
+
+  /* Get the qop-values from the qop-options */
+  result = auth_digest_get_qop_values(qop_options, &qop_values);
+  if(result)
+    return result;
+
+  /* We only support auth quality-of-protection */
+  if(!(qop_values & DIGEST_QOP_VALUE_AUTH))
+    return CURLE_BAD_CONTENT_ENCODING;
+
+  /* Generate 16 bytes of random data */
+  entropy[0] = Curl_rand(data);
+  entropy[1] = Curl_rand(data);
+  entropy[2] = Curl_rand(data);
+  entropy[3] = Curl_rand(data);
+
+  /* Convert the random data into a 32 byte hex string */
+  snprintf(cnonce, sizeof(cnonce), "%08x%08x%08x%08x",
+           entropy[0], entropy[1], entropy[2], entropy[3]);
+
+  /* So far so good, now calculate A1 and H(A1) according to RFC 2831 */
+  ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
+  if(!ctxt)
+    return CURLE_OUT_OF_MEMORY;
+
+  Curl_MD5_update(ctxt, (const unsigned char *) userp,
+                  curlx_uztoui(strlen(userp)));
+  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+  Curl_MD5_update(ctxt, (const unsigned char *) realm,
+                  curlx_uztoui(strlen(realm)));
+  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+  Curl_MD5_update(ctxt, (const unsigned char *) passwdp,
+                  curlx_uztoui(strlen(passwdp)));
+  Curl_MD5_final(ctxt, digest);
+
+  ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
+  if(!ctxt)
+    return CURLE_OUT_OF_MEMORY;
+
+  Curl_MD5_update(ctxt, (const unsigned char *) digest, MD5_DIGEST_LEN);
+  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+  Curl_MD5_update(ctxt, (const unsigned char *) nonce,
+                  curlx_uztoui(strlen(nonce)));
+  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+  Curl_MD5_update(ctxt, (const unsigned char *) cnonce,
+                  curlx_uztoui(strlen(cnonce)));
+  Curl_MD5_final(ctxt, digest);
+
+  /* Convert calculated 16 octet hex into 32 bytes string */
+  for(i = 0; i < MD5_DIGEST_LEN; i++)
+    snprintf(&HA1_hex[2 * i], 3, "%02x", digest[i]);
+
+  /* Generate our SPN */
+  spn = Curl_auth_build_spn(service, realm, NULL);
+  if(!spn)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* Calculate H(A2) */
+  ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
+  if(!ctxt) {
+    free(spn);
+
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  Curl_MD5_update(ctxt, (const unsigned char *) method,
+                  curlx_uztoui(strlen(method)));
+  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+  Curl_MD5_update(ctxt, (const unsigned char *) spn,
+                  curlx_uztoui(strlen(spn)));
+  Curl_MD5_final(ctxt, digest);
+
+  for(i = 0; i < MD5_DIGEST_LEN; i++)
+    snprintf(&HA2_hex[2 * i], 3, "%02x", digest[i]);
+
+  /* Now calculate the response hash */
+  ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
+  if(!ctxt) {
+    free(spn);
+
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  Curl_MD5_update(ctxt, (const unsigned char *) HA1_hex, 2 * MD5_DIGEST_LEN);
+  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+  Curl_MD5_update(ctxt, (const unsigned char *) nonce,
+                  curlx_uztoui(strlen(nonce)));
+  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+
+  Curl_MD5_update(ctxt, (const unsigned char *) nonceCount,
+                  curlx_uztoui(strlen(nonceCount)));
+  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+  Curl_MD5_update(ctxt, (const unsigned char *) cnonce,
+                  curlx_uztoui(strlen(cnonce)));
+  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+  Curl_MD5_update(ctxt, (const unsigned char *) qop,
+                  curlx_uztoui(strlen(qop)));
+  Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+
+  Curl_MD5_update(ctxt, (const unsigned char *) HA2_hex, 2 * MD5_DIGEST_LEN);
+  Curl_MD5_final(ctxt, digest);
+
+  for(i = 0; i < MD5_DIGEST_LEN; i++)
+    snprintf(&resp_hash_hex[2 * i], 3, "%02x", digest[i]);
+
+  /* Generate the response */
+  response = aprintf("username=\"%s\",realm=\"%s\",nonce=\"%s\","
+                     "cnonce=\"%s\",nc=\"%s\",digest-uri=\"%s\",response=%s,"
+                     "qop=%s",
+                     userp, realm, nonce,
+                     cnonce, nonceCount, spn, resp_hash_hex, qop);
+  free(spn);
+  if(!response)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* Base64 encode the response */
+  result = Curl_base64_encode(data, response, 0, outptr, outlen);
+
+  free(response);
+
+  return result;
+}
+
+/*
+ * Curl_auth_decode_digest_http_message()
+ *
+ * This is used to decode a HTTP DIGEST challenge message into the seperate
+ * attributes.
+ *
+ * Parameters:
+ *
+ * chlg    [in]     - The challenge message.
+ * digest  [in/out] - The digest data struct being used and modified.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
+                                              struct digestdata *digest)
+{
+  bool before = FALSE; /* got a nonce before */
+  bool foundAuth = FALSE;
+  bool foundAuthInt = FALSE;
+  char *token = NULL;
+  char *tmp = NULL;
+
+  /* If we already have received a nonce, keep that in mind */
+  if(digest->nonce)
+    before = TRUE;
+
+  /* Clean up any former leftovers and initialise to defaults */
+  Curl_auth_digest_cleanup(digest);
+
+  for(;;) {
+    char value[DIGEST_MAX_VALUE_LENGTH];
+    char content[DIGEST_MAX_CONTENT_LENGTH];
+
+    /* Pass all additional spaces here */
+    while(*chlg && ISSPACE(*chlg))
+      chlg++;
+
+    /* Extract a value=content pair */
+    if(Curl_auth_digest_get_pair(chlg, value, content, &chlg)) {
+      if(Curl_raw_equal(value, "nonce")) {
+        free(digest->nonce);
+        digest->nonce = strdup(content);
+        if(!digest->nonce)
+          return CURLE_OUT_OF_MEMORY;
+      }
+      else if(Curl_raw_equal(value, "stale")) {
+        if(Curl_raw_equal(content, "true")) {
+          digest->stale = TRUE;
+          digest->nc = 1; /* we make a new nonce now */
+        }
+      }
+      else if(Curl_raw_equal(value, "realm")) {
+        free(digest->realm);
+        digest->realm = strdup(content);
+        if(!digest->realm)
+          return CURLE_OUT_OF_MEMORY;
+      }
+      else if(Curl_raw_equal(value, "opaque")) {
+        free(digest->opaque);
+        digest->opaque = strdup(content);
+        if(!digest->opaque)
+          return CURLE_OUT_OF_MEMORY;
+      }
+      else if(Curl_raw_equal(value, "qop")) {
+        char *tok_buf;
+        /* Tokenize the list and choose auth if possible, use a temporary
+           clone of the buffer since strtok_r() ruins it */
+        tmp = strdup(content);
+        if(!tmp)
+          return CURLE_OUT_OF_MEMORY;
+
+        token = strtok_r(tmp, ",", &tok_buf);
+        while(token != NULL) {
+          if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH)) {
+            foundAuth = TRUE;
+          }
+          else if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) {
+            foundAuthInt = TRUE;
+          }
+          token = strtok_r(NULL, ",", &tok_buf);
+        }
+
+        free(tmp);
+
+        /* Select only auth or auth-int. Otherwise, ignore */
+        if(foundAuth) {
+          free(digest->qop);
+          digest->qop = strdup(DIGEST_QOP_VALUE_STRING_AUTH);
+          if(!digest->qop)
+            return CURLE_OUT_OF_MEMORY;
+        }
+        else if(foundAuthInt) {
+          free(digest->qop);
+          digest->qop = strdup(DIGEST_QOP_VALUE_STRING_AUTH_INT);
+          if(!digest->qop)
+            return CURLE_OUT_OF_MEMORY;
+        }
+      }
+      else if(Curl_raw_equal(value, "algorithm")) {
+        free(digest->algorithm);
+        digest->algorithm = strdup(content);
+        if(!digest->algorithm)
+          return CURLE_OUT_OF_MEMORY;
+
+        if(Curl_raw_equal(content, "MD5-sess"))
+          digest->algo = CURLDIGESTALGO_MD5SESS;
+        else if(Curl_raw_equal(content, "MD5"))
+          digest->algo = CURLDIGESTALGO_MD5;
+        else
+          return CURLE_BAD_CONTENT_ENCODING;
+      }
+      else {
+        /* Unknown specifier, ignore it! */
+      }
+    }
+    else
+      break; /* We're done here */
+
+    /* Pass all additional spaces here */
+    while(*chlg && ISSPACE(*chlg))
+      chlg++;
+
+    /* Allow the list to be comma-separated */
+    if(',' == *chlg)
+      chlg++;
+  }
+
+  /* We had a nonce since before, and we got another one now without
+     'stale=true'. This means we provided bad credentials in the previous
+     request */
+  if(before && !digest->stale)
+    return CURLE_BAD_CONTENT_ENCODING;
+
+  /* We got this header without a nonce, that's a bad Digest line! */
+  if(!digest->nonce)
+    return CURLE_BAD_CONTENT_ENCODING;
+
+  return CURLE_OK;
+}
+
+/*
+ * 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)
+{
+  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 */
+  char cnoncebuf[33];
+  char *cnonce = NULL;
+  size_t cnonce_sz = 0;
+  char *userp_quoted;
+  char *response = NULL;
+  char *tmp = NULL;
+
+  if(!digest->nc)
+    digest->nc = 1;
+
+  if(!digest->cnonce) {
+    snprintf(cnoncebuf, sizeof(cnoncebuf), "%08x%08x%08x%08x",
+             Curl_rand(data), Curl_rand(data),
+             Curl_rand(data), Curl_rand(data));
+
+    result = Curl_base64_encode(data, cnoncebuf, strlen(cnoncebuf),
+                                &cnonce, &cnonce_sz);
+    if(result)
+      return result;
+
+    digest->cnonce = cnonce;
+  }
+
+  /*
+    If the algorithm is "MD5" or unspecified (which then defaults to MD5):
+
+      A1 = unq(username-value) ":" unq(realm-value) ":" passwd
+
+    If the algorithm is "MD5-sess" then:
+
+      A1 = H(unq(username-value) ":" unq(realm-value) ":" passwd) ":"
+           unq(nonce-value) ":" unq(cnonce-value)
+  */
+
+  md5this = (unsigned char *)
+    aprintf("%s:%s:%s", userp, digest->realm, passwdp);
+  if(!md5this)
+    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);
+
+  if(digest->algo == CURLDIGESTALGO_MD5SESS) {
+    /* 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);
+    free(tmp);
+    auth_digest_md5_to_ascii(md5buf, ha1);
+  }
+
+  /*
+    If the "qop" directive's value is "auth" or is unspecified, then A2 is:
+
+      A2 = Method ":" digest-uri-value
+
+    If the "qop" value is "auth-int", then A2 is:
+
+      A2 = Method ":" digest-uri-value ":" H(entity-body)
+
+    (The "Method" value is the HTTP request method as specified in section
+    5.1.1 of RFC 2616)
+  */
+
+  md5this = (unsigned char *) aprintf("%s:%s", request, uripath);
+
+  if(digest->qop && Curl_raw_equal(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;
+  }
+
+  if(!md5this)
+    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);
+
+  if(digest->qop) {
+    md5this = (unsigned char *) aprintf("%s:%s:%08x:%s:%s:%s",
+                                        ha1,
+                                        digest->nonce,
+                                        digest->nc,
+                                        digest->cnonce,
+                                        digest->qop,
+                                        ha2);
+  }
+  else {
+    md5this = (unsigned char *) aprintf("%s:%s:%s",
+                                        ha1,
+                                        digest->nonce,
+                                        ha2);
+  }
+
+  if(!md5this)
+    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);
+
+  /* For test case 64 (snooped from a Mozilla 1.3a request)
+
+     Authorization: Digest username="testuser", realm="testrealm", \
+     nonce="1053604145", uri="/64", response="c55f7f30d83d774a3d2dcacf725abaca"
+
+     Digest parameters are all quoted strings.  Username which is provided by
+     the user will need double quotes and backslashes within it escaped.  For
+     the other fields, this shouldn't be an issue.  realm, nonce, and opaque
+     are copied as is from the server, escapes and all.  cnonce is generated
+     with web-safe characters.  uri is already percent encoded.  nc is 8 hex
+     characters.  algorithm and qop with standard values only contain web-safe
+     characters.
+  */
+  userp_quoted = auth_digest_string_quoted(userp);
+  if(!userp_quoted)
+    return CURLE_OUT_OF_MEMORY;
+
+  if(digest->qop) {
+    response = aprintf("username=\"%s\", "
+                       "realm=\"%s\", "
+                       "nonce=\"%s\", "
+                       "uri=\"%s\", "
+                       "cnonce=\"%s\", "
+                       "nc=%08x, "
+                       "qop=%s, "
+                       "response=\"%s\"",
+                       userp_quoted,
+                       digest->realm,
+                       digest->nonce,
+                       uripath,
+                       digest->cnonce,
+                       digest->nc,
+                       digest->qop,
+                       request_digest);
+
+    if(Curl_raw_equal(digest->qop, "auth"))
+      digest->nc++; /* The nc (from RFC) has to be a 8 hex digit number 0
+                       padded which tells to the server how many times you are
+                       using the same nonce in the qop=auth mode */
+  }
+  else {
+    response = aprintf("username=\"%s\", "
+                       "realm=\"%s\", "
+                       "nonce=\"%s\", "
+                       "uri=\"%s\", "
+                       "response=\"%s\"",
+                       userp_quoted,
+                       digest->realm,
+                       digest->nonce,
+                       uripath,
+                       request_digest);
+  }
+  free(userp_quoted);
+  if(!response)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* Add the optional fields */
+  if(digest->opaque) {
+    /* Append the opaque */
+    tmp = aprintf("%s, opaque=\"%s\"", response, digest->opaque);
+    free(response);
+    if(!tmp)
+      return CURLE_OUT_OF_MEMORY;
+
+    response = tmp;
+  }
+
+  if(digest->algorithm) {
+    /* Append the algorithm */
+    tmp = aprintf("%s, algorithm=\"%s\"", response, digest->algorithm);
+    free(response);
+    if(!tmp)
+      return CURLE_OUT_OF_MEMORY;
+
+    response = tmp;
+  }
+
+  /* Return the output */
+  *outptr = response;
+  *outlen = strlen(response);
+
+  return CURLE_OK;
+}
+
+/*
+ * Curl_auth_digest_cleanup()
+ *
+ * This is used to clean up the digest specific data.
+ *
+ * Parameters:
+ *
+ * digest    [in/out] - The digest data struct being cleaned up.
+ *
+ */
+void Curl_auth_digest_cleanup(struct digestdata *digest)
+{
+  Curl_safefree(digest->nonce);
+  Curl_safefree(digest->cnonce);
+  Curl_safefree(digest->realm);
+  Curl_safefree(digest->opaque);
+  Curl_safefree(digest->qop);
+  Curl_safefree(digest->algorithm);
+
+  digest->nc = 0;
+  digest->algo = CURLDIGESTALGO_MD5; /* default algorithm */
+  digest->stale = FALSE; /* default means normal, not stale */
+}
+#endif  /* !USE_WINDOWS_SSPI */
+
+#endif  /* CURL_DISABLE_CRYPTO_AUTH */
diff --git a/lib/strequal.h b/lib/vauth/digest.h
similarity index 59%
copy from lib/strequal.h
copy to lib/vauth/digest.h
index 117a305..5722dce 100644
--- a/lib/strequal.h
+++ b/lib/vauth/digest.h
@@ -1,5 +1,5 @@
-#ifndef HEADER_CURL_STREQUAL_H
-#define HEADER_CURL_STREQUAL_H
+#ifndef HEADER_CURL_DIGEST_H
+#define HEADER_CURL_DIGEST_H
 /***************************************************************************
  *                                  _   _ ____  _
  *  Project                     ___| | | |  _ \| |
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -24,8 +24,20 @@
 
 #include <curl/curl.h>
 
-#define strequal(a,b) curl_strequal(a,b)
-#define strnequal(a,b,c) curl_strnequal(a,b,c)
+#if !defined(CURL_DISABLE_CRYPTO_AUTH)
 
-#endif /* HEADER_CURL_STREQUAL_H */
+#define DIGEST_MAX_VALUE_LENGTH           256
+#define DIGEST_MAX_CONTENT_LENGTH         1024
 
+enum {
+  CURLDIGESTALGO_MD5,
+  CURLDIGESTALGO_MD5SESS
+};
+
+/* This is used to extract the realm from a challenge message */
+bool Curl_auth_digest_get_pair(const char *str, char *value, char *content,
+                               const char **endptr);
+
+#endif
+
+#endif /* HEADER_CURL_DIGEST_H */
diff --git a/lib/vauth/digest_sspi.c b/lib/vauth/digest_sspi.c
new file mode 100644
index 0000000..6a7315e
--- /dev/null
+++ b/lib/vauth/digest_sspi.c
@@ -0,0 +1,533 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2014 - 2016, Steve Holme, <steve_holme at hotmail.com>.
+ * Copyright (C) 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.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.
+ *
+ * RFC2831 DIGEST-MD5 authentication
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_WINDOWS_SSPI) && !defined(CURL_DISABLE_CRYPTO_AUTH)
+
+#include <curl/curl.h>
+
+#include "vauth/vauth.h"
+#include "vauth/digest.h"
+#include "urldata.h"
+#include "curl_base64.h"
+#include "warnless.h"
+#include "curl_multibyte.h"
+#include "sendf.h"
+#include "strdup.h"
+#include "rawstr.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Curl_auth_create_digest_md5_message()
+ *
+ * This is used to generate an already encoded DIGEST-MD5 response message
+ * ready for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data    [in]     - The session handle.
+ * chlg64  [in]     - The base64 encoded challenge message.
+ * userp   [in]     - The user name in the format User or Domain\User.
+ * passdwp [in]     - The user's password.
+ * service [in]     - The service type such as http, smtp, pop or imap.
+ * 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_md5_message(struct Curl_easy *data,
+                                             const char *chlg64,
+                                             const char *userp,
+                                             const char *passwdp,
+                                             const char *service,
+                                             char **outptr, size_t *outlen)
+{
+  CURLcode result = CURLE_OK;
+  TCHAR *spn = NULL;
+  size_t chlglen = 0;
+  size_t token_max = 0;
+  unsigned char *input_token = NULL;
+  unsigned char *output_token = NULL;
+  CredHandle credentials;
+  CtxtHandle context;
+  PSecPkgInfo SecurityPackage;
+  SEC_WINNT_AUTH_IDENTITY identity;
+  SEC_WINNT_AUTH_IDENTITY *p_identity;
+  SecBuffer chlg_buf;
+  SecBuffer resp_buf;
+  SecBufferDesc chlg_desc;
+  SecBufferDesc resp_desc;
+  SECURITY_STATUS status;
+  unsigned long attrs;
+  TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
+
+  /* Decode the base-64 encoded challenge message */
+  if(strlen(chlg64) && *chlg64 != '=') {
+    result = Curl_base64_decode(chlg64, &input_token, &chlglen);
+    if(result)
+      return result;
+  }
+
+  /* Ensure we have a valid challenge message */
+  if(!input_token) {
+    infof(data, "DIGEST-MD5 handshake failure (empty challenge message)\n");
+
+    return CURLE_BAD_CONTENT_ENCODING;
+  }
+
+  /* Query the security package for DigestSSP */
+  status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST),
+                                              &SecurityPackage);
+  if(status != SEC_E_OK) {
+    free(input_token);
+
+    return CURLE_NOT_BUILT_IN;
+  }
+
+  token_max = SecurityPackage->cbMaxToken;
+
+  /* Release the package buffer as it is not required anymore */
+  s_pSecFn->FreeContextBuffer(SecurityPackage);
+
+  /* Allocate our response buffer */
+  output_token = malloc(token_max);
+  if(!output_token) {
+    free(input_token);
+
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  /* Generate our SPN */
+  spn = Curl_auth_build_spn(service, data->easy_conn->host.name, NULL);
+  if(!spn) {
+    free(output_token);
+    free(input_token);
+
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  if(userp && *userp) {
+    /* Populate our identity structure */
+    result = Curl_create_sspi_identity(userp, passwdp, &identity);
+    if(result) {
+      free(spn);
+      free(output_token);
+      free(input_token);
+
+      return result;
+    }
+
+    /* Allow proper cleanup of the identity structure */
+    p_identity = &identity;
+  }
+  else
+    /* Use the current Windows user */
+    p_identity = NULL;
+
+  /* Acquire our credentials handle */
+  status = s_pSecFn->AcquireCredentialsHandle(NULL,
+                                              (TCHAR *) TEXT(SP_NAME_DIGEST),
+                                              SECPKG_CRED_OUTBOUND, NULL,
+                                              p_identity, NULL, NULL,
+                                              &credentials, &expiry);
+
+  if(status != SEC_E_OK) {
+    Curl_sspi_free_identity(p_identity);
+    free(spn);
+    free(output_token);
+    free(input_token);
+
+    return CURLE_LOGIN_DENIED;
+  }
+
+  /* Setup the challenge "input" security buffer */
+  chlg_desc.ulVersion = SECBUFFER_VERSION;
+  chlg_desc.cBuffers  = 1;
+  chlg_desc.pBuffers  = &chlg_buf;
+  chlg_buf.BufferType = SECBUFFER_TOKEN;
+  chlg_buf.pvBuffer   = input_token;
+  chlg_buf.cbBuffer   = curlx_uztoul(chlglen);
+
+  /* Setup the response "output" security buffer */
+  resp_desc.ulVersion = SECBUFFER_VERSION;
+  resp_desc.cBuffers  = 1;
+  resp_desc.pBuffers  = &resp_buf;
+  resp_buf.BufferType = SECBUFFER_TOKEN;
+  resp_buf.pvBuffer   = output_token;
+  resp_buf.cbBuffer   = curlx_uztoul(token_max);
+
+  /* Generate our response message */
+  status = s_pSecFn->InitializeSecurityContext(&credentials, NULL, spn,
+                                               0, 0, 0, &chlg_desc, 0,
+                                               &context, &resp_desc, &attrs,
+                                               &expiry);
+
+  if(status == SEC_I_COMPLETE_NEEDED ||
+     status == SEC_I_COMPLETE_AND_CONTINUE)
+    s_pSecFn->CompleteAuthToken(&credentials, &resp_desc);
+  else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) {
+    s_pSecFn->FreeCredentialsHandle(&credentials);
+    Curl_sspi_free_identity(p_identity);
+    free(spn);
+    free(output_token);
+    free(input_token);
+
+    return CURLE_RECV_ERROR;
+  }
+
+  /* Base64 encode the response */
+  result = Curl_base64_encode(data, (char *) output_token, resp_buf.cbBuffer,
+                              outptr, outlen);
+
+  /* Free our handles */
+  s_pSecFn->DeleteSecurityContext(&context);
+  s_pSecFn->FreeCredentialsHandle(&credentials);
+
+  /* Free the identity structure */
+  Curl_sspi_free_identity(p_identity);
+
+  /* Free the SPN */
+  free(spn);
+
+  /* Free the response buffer */
+  free(output_token);
+
+  /* Free the decoded challenge message */
+  free(input_token);
+
+  return result;
+}
+
+/*
+ * Curl_override_sspi_http_realm()
+ *
+ * This is used to populate the domain in a SSPI identity structure
+ * The realm is extracted from the challenge message and used as the
+ * domain if it is not already explicitly set.
+ *
+ * Parameters:
+ *
+ * chlg     [in]     - The challenge message.
+ * identity [in/out] - The identity structure.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_override_sspi_http_realm(const char *chlg,
+                                       SEC_WINNT_AUTH_IDENTITY *identity)
+{
+  xcharp_u domain, dup_domain;
+
+  /* If domain is blank or unset, check challenge message for realm */
+  if(!identity->Domain || !identity->DomainLength) {
+    for(;;) {
+      char value[DIGEST_MAX_VALUE_LENGTH];
+      char content[DIGEST_MAX_CONTENT_LENGTH];
+
+      /* Pass all additional spaces here */
+      while(*chlg && ISSPACE(*chlg))
+        chlg++;
+
+      /* Extract a value=content pair */
+      if(Curl_auth_digest_get_pair(chlg, value, content, &chlg)) {
+        if(Curl_raw_equal(value, "realm")) {
+
+          /* Setup identity's domain and length */
+          domain.tchar_ptr = Curl_convert_UTF8_to_tchar((char *) content);
+          if(!domain.tchar_ptr)
+            return CURLE_OUT_OF_MEMORY;
+
+          dup_domain.tchar_ptr = _tcsdup(domain.tchar_ptr);
+          if(!dup_domain.tchar_ptr) {
+            Curl_unicodefree(domain.tchar_ptr);
+            return CURLE_OUT_OF_MEMORY;
+          }
+
+          free(identity->Domain);
+          identity->Domain = dup_domain.tbyte_ptr;
+          identity->DomainLength = curlx_uztoul(_tcslen(dup_domain.tchar_ptr));
+          dup_domain.tchar_ptr = NULL;
+
+          Curl_unicodefree(domain.tchar_ptr);
+        }
+        else {
+          /* Unknown specifier, ignore it! */
+        }
+      }
+      else
+        break; /* We're done here */
+
+      /* Pass all additional spaces here */
+      while(*chlg && ISSPACE(*chlg))
+        chlg++;
+
+      /* Allow the list to be comma-separated */
+      if(',' == *chlg)
+        chlg++;
+    }
+  }
+
+  return CURLE_OK;
+}
+
+/*
+ * Curl_auth_decode_digest_http_message()
+ *
+ * This is used to decode a HTTP DIGEST challenge message into the seperate
+ * attributes.
+ *
+ * Parameters:
+ *
+ * chlg    [in]     - The challenge message.
+ * digest  [in/out] - The digest data struct being used and modified.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
+                                              struct digestdata *digest)
+{
+  size_t chlglen = strlen(chlg);
+
+  /* We had an input token before and we got another one now. This means we
+     provided bad credentials in the previous request. */
+  if(digest->input_token)
+    return CURLE_BAD_CONTENT_ENCODING;
+
+  /* Simply store the challenge for use later */
+  digest->input_token = (BYTE *) Curl_memdup(chlg, chlglen);
+  if(!digest->input_token)
+    return CURLE_OUT_OF_MEMORY;
+
+  digest->input_token_len = chlglen;
+
+  return CURLE_OK;
+}
+
+/*
+ * 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 in the format User or Domain\User.
+ * 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)
+{
+  size_t token_max;
+  CredHandle credentials;
+  CtxtHandle context;
+  char *resp;
+  BYTE *output_token;
+  PSecPkgInfo SecurityPackage;
+  SEC_WINNT_AUTH_IDENTITY identity;
+  SEC_WINNT_AUTH_IDENTITY *p_identity;
+  SecBuffer chlg_buf[3];
+  SecBuffer resp_buf;
+  SecBufferDesc chlg_desc;
+  SecBufferDesc resp_desc;
+  SECURITY_STATUS status;
+  unsigned long attrs;
+  TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
+  TCHAR *spn;
+
+  (void) data;
+
+  /* Query the security package for DigestSSP */
+  status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST),
+                                              &SecurityPackage);
+  if(status != SEC_E_OK)
+    return CURLE_NOT_BUILT_IN;
+
+  token_max = SecurityPackage->cbMaxToken;
+
+  /* Release the package buffer as it is not required anymore */
+  s_pSecFn->FreeContextBuffer(SecurityPackage);
+
+  if(userp && *userp) {
+    /* Populate our identity structure */
+    if(Curl_create_sspi_identity(userp, passwdp, &identity))
+      return CURLE_OUT_OF_MEMORY;
+
+    /* Populate our identity domain */
+    if(Curl_override_sspi_http_realm((const char*) digest->input_token,
+                                     &identity))
+      return CURLE_OUT_OF_MEMORY;
+
+    /* Allow proper cleanup of the identity structure */
+    p_identity = &identity;
+  }
+  else
+    /* Use the current Windows user */
+    p_identity = NULL;
+
+  /* Acquire our credentials handle */
+  status = s_pSecFn->AcquireCredentialsHandle(NULL,
+                                              (TCHAR *) TEXT(SP_NAME_DIGEST),
+                                              SECPKG_CRED_OUTBOUND, NULL,
+                                              p_identity, NULL, NULL,
+                                              &credentials, &expiry);
+  if(status != SEC_E_OK) {
+    Curl_sspi_free_identity(p_identity);
+
+    return CURLE_LOGIN_DENIED;
+  }
+
+  /* Allocate the output buffer according to the max token size as indicated
+     by the security package */
+  output_token = malloc(token_max);
+  if(!output_token) {
+    s_pSecFn->FreeCredentialsHandle(&credentials);
+
+    Curl_sspi_free_identity(p_identity);
+
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  /* Setup the challenge "input" security buffer if present */
+  chlg_desc.ulVersion    = SECBUFFER_VERSION;
+  chlg_desc.cBuffers     = 3;
+  chlg_desc.pBuffers     = chlg_buf;
+  chlg_buf[0].BufferType = SECBUFFER_TOKEN;
+  chlg_buf[0].pvBuffer   = digest->input_token;
+  chlg_buf[0].cbBuffer   = curlx_uztoul(digest->input_token_len);
+  chlg_buf[1].BufferType = SECBUFFER_PKG_PARAMS;
+  chlg_buf[1].pvBuffer   = (void *) request;
+  chlg_buf[1].cbBuffer   = curlx_uztoul(strlen((const char *) request));
+  chlg_buf[2].BufferType = SECBUFFER_PKG_PARAMS;
+  chlg_buf[2].pvBuffer   = NULL;
+  chlg_buf[2].cbBuffer   = 0;
+
+  /* Setup the response "output" security buffer */
+  resp_desc.ulVersion = SECBUFFER_VERSION;
+  resp_desc.cBuffers  = 1;
+  resp_desc.pBuffers  = &resp_buf;
+  resp_buf.BufferType = SECBUFFER_TOKEN;
+  resp_buf.pvBuffer   = output_token;
+  resp_buf.cbBuffer   = curlx_uztoul(token_max);
+
+  spn = Curl_convert_UTF8_to_tchar((char *) uripath);
+  if(!spn) {
+    s_pSecFn->FreeCredentialsHandle(&credentials);
+
+    Curl_sspi_free_identity(p_identity);
+    free(output_token);
+
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  /* Generate our reponse message */
+  status = s_pSecFn->InitializeSecurityContext(&credentials, NULL,
+                                               spn,
+                                               ISC_REQ_USE_HTTP_STYLE, 0, 0,
+                                               &chlg_desc, 0, &context,
+                                               &resp_desc, &attrs, &expiry);
+  Curl_unicodefree(spn);
+
+  if(status == SEC_I_COMPLETE_NEEDED ||
+     status == SEC_I_COMPLETE_AND_CONTINUE)
+    s_pSecFn->CompleteAuthToken(&credentials, &resp_desc);
+  else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) {
+    s_pSecFn->FreeCredentialsHandle(&credentials);
+
+    Curl_sspi_free_identity(p_identity);
+    free(output_token);
+
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  resp = malloc(resp_buf.cbBuffer + 1);
+  if(!resp) {
+    s_pSecFn->DeleteSecurityContext(&context);
+    s_pSecFn->FreeCredentialsHandle(&credentials);
+
+    Curl_sspi_free_identity(p_identity);
+    free(output_token);
+
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  /* Copy the generated reponse */
+  memcpy(resp, resp_buf.pvBuffer, resp_buf.cbBuffer);
+  resp[resp_buf.cbBuffer] = 0x00;
+
+  /* Return the response */
+  *outptr = resp;
+  *outlen = resp_buf.cbBuffer;
+
+  /* Free our handles */
+  s_pSecFn->DeleteSecurityContext(&context);
+  s_pSecFn->FreeCredentialsHandle(&credentials);
+
+  /* Free the identity structure */
+  Curl_sspi_free_identity(p_identity);
+
+  /* Free the response buffer */
+  free(output_token);
+
+  return CURLE_OK;
+}
+
+/*
+ * Curl_auth_digest_cleanup()
+ *
+ * This is used to clean up the digest specific data.
+ *
+ * Parameters:
+ *
+ * digest    [in/out] - The digest data struct being cleaned up.
+ *
+ */
+void Curl_auth_digest_cleanup(struct digestdata *digest)
+{
+  /* Free the input token */
+  Curl_safefree(digest->input_token);
+
+  /* Reset any variables */
+  digest->input_token_len = 0;
+}
+
+#endif /* USE_WINDOWS_SSPI && !CURL_DISABLE_CRYPTO_AUTH */
diff --git a/lib/curl_sasl_gssapi.c b/lib/vauth/krb5_gssapi.c
similarity index 66%
rename from lib/curl_sasl_gssapi.c
rename to lib/vauth/krb5_gssapi.c
index 3c6f3ce..31c8c7d 100644
--- a/lib/curl_sasl_gssapi.c
+++ b/lib/vauth/krb5_gssapi.c
@@ -5,12 +5,12 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2014 - 2015, Steve Holme, <steve_holme at hotmail.com>.
+ * Copyright (C) 2014 - 2016, Steve Holme, <steve_holme at hotmail.com>.
  * Copyright (C) 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -29,6 +29,7 @@
 
 #include <curl/curl.h>
 
+#include "vauth/vauth.h"
 #include "curl_sasl.h"
 #include "urldata.h"
 #include "curl_base64.h"
@@ -41,25 +42,7 @@
 #include "memdebug.h"
 
 /*
-* Curl_sasl_build_gssapi_spn()
-*
-* This is used to build a SPN string in the format service at host.
-*
-* Parameters:
-*
-* serivce  [in] - The service type such as www, smtp, pop or imap.
-* host     [in] - The host name or realm.
-*
-* Returns a pointer to the newly allocated SPN.
-*/
-char *Curl_sasl_build_gssapi_spn(const char *service, const char *host)
-{
-  /* Generate and return our SPN */
-  return aprintf("%s@%s", service, host);
-}
-
-/*
- * Curl_sasl_create_gssapi_user_message()
+ * Curl_auth_create_gssapi_user_message()
  *
  * This is used to generate an already encoded GSSAPI (Kerberos V5) user token
  * message ready for sending to the recipient.
@@ -69,22 +52,24 @@ char *Curl_sasl_build_gssapi_spn(const char *service, const char *host)
  * data        [in]     - The session handle.
  * userp       [in]     - The user name.
  * passdwp     [in]     - The user's password.
- * service     [in]     - The service type such as www, smtp, pop or imap.
+ * service     [in]     - The service type such as http, smtp, pop or imap.
+ * host        [in[     - The host name.
  * mutual_auth [in]     - Flag specifing whether or not mutual authentication
  *                        is enabled.
  * chlg64      [in]     - Pointer to the optional base64 encoded challenge
  *                        message.
- * krb5        [in/out] - The gssapi data struct being used and modified.
+ * krb5        [in/out] - The Kerberos 5 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_sasl_create_gssapi_user_message(struct SessionHandle *data,
+CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
                                               const char *userp,
                                               const char *passwdp,
                                               const char *service,
+                                              const char *host,
                                               const bool mutual_auth,
                                               const char *chlg64,
                                               struct kerberos5data *krb5,
@@ -93,9 +78,9 @@ CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data,
   CURLcode result = CURLE_OK;
   size_t chlglen = 0;
   unsigned char *chlg = NULL;
-  OM_uint32 gss_status;
-  OM_uint32 gss_major_status;
-  OM_uint32 gss_minor_status;
+  OM_uint32 major_status;
+  OM_uint32 minor_status;
+  OM_uint32 unused_status;
   gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER;
   gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
   gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
@@ -103,10 +88,9 @@ CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data,
   (void) userp;
   (void) passwdp;
 
-  if(krb5->context == GSS_C_NO_CONTEXT) {
+  if(!krb5->spn) {
     /* Generate our SPN */
-    char *spn = Curl_sasl_build_gssapi_spn(service,
-                                           data->easy_conn->host.name);
+    char *spn = Curl_auth_build_spn(service, NULL, host);
     if(!spn)
       return CURLE_OUT_OF_MEMORY;
 
@@ -115,10 +99,11 @@ CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data,
     spn_token.length = strlen(spn);
 
     /* Import the SPN */
-    gss_major_status = gss_import_name(&gss_minor_status, &spn_token,
-                                       GSS_C_NT_HOSTBASED_SERVICE, &krb5->spn);
-    if(GSS_ERROR(gss_major_status)) {
-      Curl_gss_log_error(data, gss_minor_status, "gss_import_name() failed: ");
+    major_status = gss_import_name(&minor_status, &spn_token,
+                                   GSS_C_NT_HOSTBASED_SERVICE, &krb5->spn);
+    if(GSS_ERROR(major_status)) {
+      Curl_gss_log_error(data, "gss_import_name() failed: ",
+                         major_status, minor_status);
 
       free(spn);
 
@@ -127,9 +112,10 @@ CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data,
 
     free(spn);
   }
-  else {
+
+  if(chlg64 && *chlg64) {
     /* Decode the base-64 encoded challenge message */
-    if(strlen(chlg64) && *chlg64 != '=') {
+    if(*chlg64 != '=') {
       result = Curl_base64_decode(chlg64, &chlg, &chlglen);
       if(result)
         return result;
@@ -147,25 +133,26 @@ CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data,
     input_token.length = chlglen;
   }
 
-  gss_major_status = Curl_gss_init_sec_context(data,
-                                               &gss_minor_status,
-                                               &krb5->context,
-                                               krb5->spn,
-                                               &Curl_krb5_mech_oid,
-                                               GSS_C_NO_CHANNEL_BINDINGS,
-                                               &input_token,
-                                               &output_token,
-                                               mutual_auth,
-                                               NULL);
-
+  major_status = Curl_gss_init_sec_context(data,
+                                           &minor_status,
+                                           &krb5->context,
+                                           krb5->spn,
+                                           &Curl_krb5_mech_oid,
+                                           GSS_C_NO_CHANNEL_BINDINGS,
+                                           &input_token,
+                                           &output_token,
+                                           mutual_auth,
+                                           NULL);
+
+  /* Free the decoded challenge as it is not required anymore */
   free(input_token.value);
 
-  if(GSS_ERROR(gss_major_status)) {
+  if(GSS_ERROR(major_status)) {
     if(output_token.value)
-      gss_release_buffer(&gss_status, &output_token);
+      gss_release_buffer(&unused_status, &output_token);
 
-    Curl_gss_log_error(data, gss_minor_status,
-                       "gss_init_sec_context() failed: ");
+    Curl_gss_log_error(data, "gss_init_sec_context() failed: ",
+                       major_status, minor_status);
 
     return CURLE_RECV_ERROR;
   }
@@ -175,14 +162,19 @@ CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data,
     result = Curl_base64_encode(data, (char *) output_token.value,
                                 output_token.length, outptr, outlen);
 
-    gss_release_buffer(&gss_status, &output_token);
+    gss_release_buffer(&unused_status, &output_token);
+  }
+  else if(mutual_auth) {
+    *outptr = strdup("");
+    if(!*outptr)
+      result = CURLE_OUT_OF_MEMORY;
   }
 
   return result;
 }
 
 /*
- * Curl_sasl_create_gssapi_security_message()
+ * Curl_auth_create_gssapi_security_message()
  *
  * This is used to generate an already encoded GSSAPI (Kerberos V5) security
  * token message ready for sending to the recipient.
@@ -191,14 +183,14 @@ CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data,
  *
  * data    [in]     - The session handle.
  * chlg64  [in]     - Pointer to the optional base64 encoded challenge message.
- * krb5    [in/out] - The gssapi data struct being used and modified.
+ * krb5    [in/out] - The Kerberos 5 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_sasl_create_gssapi_security_message(struct SessionHandle *data,
+CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
                                                   const char *chlg64,
                                                   struct kerberos5data *krb5,
                                                   char **outptr,
@@ -209,9 +201,9 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data,
   size_t messagelen = 0;
   unsigned char *chlg = NULL;
   unsigned char *message = NULL;
-  OM_uint32 gss_status;
-  OM_uint32 gss_major_status;
-  OM_uint32 gss_minor_status;
+  OM_uint32 major_status;
+  OM_uint32 minor_status;
+  OM_uint32 unused_status;
   gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
   gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
   unsigned int indata = 0;
@@ -237,12 +229,12 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data,
   }
 
   /* Get the fully qualified username back from the context */
-  gss_major_status = gss_inquire_context(&gss_minor_status, krb5->context,
-                                         &username, NULL, NULL, NULL, NULL,
-                                         NULL, NULL);
-  if(GSS_ERROR(gss_major_status)) {
-    Curl_gss_log_error(data, gss_minor_status,
-                       "gss_inquire_context() failed: ");
+  major_status = gss_inquire_context(&minor_status, krb5->context,
+                                     &username, NULL, NULL, NULL, NULL,
+                                     NULL, NULL);
+  if(GSS_ERROR(major_status)) {
+    Curl_gss_log_error(data, "gss_inquire_context() failed: ",
+                       major_status, minor_status);
 
     free(chlg);
 
@@ -250,10 +242,11 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data,
   }
 
   /* Convert the username from internal format to a displayable token */
-  gss_major_status = gss_display_name(&gss_minor_status, username,
-                                      &username_token, NULL);
-  if(GSS_ERROR(gss_major_status)) {
-    Curl_gss_log_error(data, gss_minor_status, "gss_display_name() failed: ");
+  major_status = gss_display_name(&minor_status, username,
+                                  &username_token, NULL);
+  if(GSS_ERROR(major_status)) {
+    Curl_gss_log_error(data, "gss_display_name() failed: ",
+                       major_status, minor_status);
 
     free(chlg);
 
@@ -265,12 +258,13 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data,
   input_token.length = chlglen;
 
   /* Decrypt the inbound challenge and obtain the qop */
-  gss_major_status = gss_unwrap(&gss_minor_status, krb5->context, &input_token,
-                                &output_token, NULL, &qop);
-  if(GSS_ERROR(gss_major_status)) {
-    Curl_gss_log_error(data, gss_minor_status, "gss_unwrap() failed: ");
+  major_status = gss_unwrap(&minor_status, krb5->context, &input_token,
+                            &output_token, NULL, &qop);
+  if(GSS_ERROR(major_status)) {
+    Curl_gss_log_error(data, "gss_unwrap() failed: ",
+                       major_status, minor_status);
 
-    gss_release_buffer(&gss_status, &username_token);
+    gss_release_buffer(&unused_status, &username_token);
     free(chlg);
 
     return CURLE_BAD_CONTENT_ENCODING;
@@ -280,7 +274,7 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data,
   if(output_token.length != 4) {
     infof(data, "GSSAPI handshake failure (invalid security data)\n");
 
-    gss_release_buffer(&gss_status, &username_token);
+    gss_release_buffer(&unused_status, &username_token);
     free(chlg);
 
     return CURLE_BAD_CONTENT_ENCODING;
@@ -288,7 +282,7 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data,
 
   /* Copy the data out and free the challenge as it is not required anymore */
   memcpy(&indata, output_token.value, 4);
-  gss_release_buffer(&gss_status, &output_token);
+  gss_release_buffer(&unused_status, &output_token);
   free(chlg);
 
   /* Extract the security layer */
@@ -296,7 +290,7 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data,
   if(!(sec_layer & GSSAUTH_P_NONE)) {
     infof(data, "GSSAPI handshake failure (invalid security layer)\n");
 
-    gss_release_buffer(&gss_status, &username_token);
+    gss_release_buffer(&unused_status, &username_token);
 
     return CURLE_BAD_CONTENT_ENCODING;
   }
@@ -314,14 +308,14 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data,
   messagelen = sizeof(outdata) + username_token.length + 1;
   message = malloc(messagelen);
   if(!message) {
-    gss_release_buffer(&gss_status, &username_token);
+    gss_release_buffer(&unused_status, &username_token);
 
     return CURLE_OUT_OF_MEMORY;
   }
 
   /* Populate the message with the security layer, client supported receive
      message size and authorization identity including the 0x00 based
-     terminator. Note: Dispite RFC4752 Section 3.1 stating "The authorization
+     terminator. Note: Despite RFC4752 Section 3.1 stating "The authorization
      identity is not terminated with the zero-valued (%x00) octet." it seems
      necessary to include it. */
   outdata = htonl(max_size) | sec_layer;
@@ -331,18 +325,19 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data,
   message[messagelen - 1] = '\0';
 
   /* Free the username token as it is not required anymore */
-  gss_release_buffer(&gss_status, &username_token);
+  gss_release_buffer(&unused_status, &username_token);
 
   /* Setup the "authentication data" security buffer */
   input_token.value = message;
   input_token.length = messagelen;
 
   /* Encrypt the data */
-  gss_major_status = gss_wrap(&gss_minor_status, krb5->context, 0,
-                              GSS_C_QOP_DEFAULT, &input_token, NULL,
-                              &output_token);
-  if(GSS_ERROR(gss_major_status)) {
-    Curl_gss_log_error(data, gss_minor_status, "gss_wrap() failed: ");
+  major_status = gss_wrap(&minor_status, krb5->context, 0,
+                          GSS_C_QOP_DEFAULT, &input_token, NULL,
+                          &output_token);
+  if(GSS_ERROR(major_status)) {
+    Curl_gss_log_error(data, "gss_wrap() failed: ",
+                       major_status, minor_status);
 
     free(message);
 
@@ -354,7 +349,7 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data,
                               output_token.length, outptr, outlen);
 
   /* Free the output buffer */
-  gss_release_buffer(&gss_status, &output_token);
+  gss_release_buffer(&unused_status, &output_token);
 
   /* Free the message buffer */
   free(message);
@@ -363,16 +358,16 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data,
 }
 
 /*
- * Curl_sasl_gssapi_cleanup()
+ * Curl_auth_gssapi_cleanup()
  *
- * This is used to clean up the gssapi specific data.
+ * This is used to clean up the GSSAPI (Kerberos V5) specific data.
  *
  * Parameters:
  *
- * krb5     [in/out] - The kerberos 5 data struct being cleaned up.
+ * krb5     [in/out] - The Kerberos 5 data struct being cleaned up.
  *
  */
-void Curl_sasl_gssapi_cleanup(struct kerberos5data *krb5)
+void Curl_auth_gssapi_cleanup(struct kerberos5data *krb5)
 {
   OM_uint32 minor_status;
 
diff --git a/lib/vauth/krb5_sspi.c b/lib/vauth/krb5_sspi.c
new file mode 100644
index 0000000..08774f6
--- /dev/null
+++ b/lib/vauth/krb5_sspi.c
@@ -0,0 +1,496 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2014 - 2016, Steve Holme, <steve_holme at hotmail.com>.
+ *
+ * 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.
+ *
+ * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_WINDOWS_SSPI) && defined(USE_KERBEROS5)
+
+#include <curl/curl.h>
+
+#include "vauth/vauth.h"
+#include "urldata.h"
+#include "curl_base64.h"
+#include "warnless.h"
+#include "curl_multibyte.h"
+#include "sendf.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Curl_auth_create_gssapi_user_message()
+ *
+ * This is used to generate an already encoded GSSAPI (Kerberos V5) user token
+ * message ready for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data        [in]     - The session handle.
+ * userp       [in]     - The user name in the format User or Domain\User.
+ * passdwp     [in]     - The user's password.
+ * service     [in]     - The service type such as http, smtp, pop or imap.
+ * host        [in]     - The host name.
+ * mutual_auth [in]     - Flag specifing whether or not mutual authentication
+ *                        is enabled.
+ * chlg64      [in]     - The optional base64 encoded challenge message.
+ * krb5        [in/out] - The Kerberos 5 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_gssapi_user_message(struct Curl_easy *data,
+                                              const char *userp,
+                                              const char *passwdp,
+                                              const char *service,
+                                              const char *host,
+                                              const bool mutual_auth,
+                                              const char *chlg64,
+                                              struct kerberos5data *krb5,
+                                              char **outptr, size_t *outlen)
+{
+  CURLcode result = CURLE_OK;
+  size_t chlglen = 0;
+  unsigned char *chlg = NULL;
+  CtxtHandle context;
+  PSecPkgInfo SecurityPackage;
+  SecBuffer chlg_buf;
+  SecBuffer resp_buf;
+  SecBufferDesc chlg_desc;
+  SecBufferDesc resp_desc;
+  SECURITY_STATUS status;
+  unsigned long attrs;
+  TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
+
+  if(!krb5->spn) {
+    /* Generate our SPN */
+    krb5->spn = Curl_auth_build_spn(service, host, NULL);
+    if(!krb5->spn)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  if(!krb5->output_token) {
+    /* Query the security package for Kerberos */
+    status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *)
+                                                TEXT(SP_NAME_KERBEROS),
+                                                &SecurityPackage);
+    if(status != SEC_E_OK) {
+      return CURLE_NOT_BUILT_IN;
+    }
+
+    krb5->token_max = SecurityPackage->cbMaxToken;
+
+    /* Release the package buffer as it is not required anymore */
+    s_pSecFn->FreeContextBuffer(SecurityPackage);
+
+    /* Allocate our response buffer */
+    krb5->output_token = malloc(krb5->token_max);
+    if(!krb5->output_token)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  if(!krb5->credentials) {
+    /* Do we have credientials to use or are we using single sign-on? */
+    if(userp && *userp) {
+      /* Populate our identity structure */
+      result = Curl_create_sspi_identity(userp, passwdp, &krb5->identity);
+      if(result)
+        return result;
+
+      /* Allow proper cleanup of the identity structure */
+      krb5->p_identity = &krb5->identity;
+    }
+    else
+      /* Use the current Windows user */
+      krb5->p_identity = NULL;
+
+    /* Allocate our credentials handle */
+    krb5->credentials = malloc(sizeof(CredHandle));
+    if(!krb5->credentials)
+      return CURLE_OUT_OF_MEMORY;
+
+    memset(krb5->credentials, 0, sizeof(CredHandle));
+
+    /* Acquire our credentials handle */
+    status = s_pSecFn->AcquireCredentialsHandle(NULL,
+                                                (TCHAR *)
+                                                TEXT(SP_NAME_KERBEROS),
+                                                SECPKG_CRED_OUTBOUND, NULL,
+                                                krb5->p_identity, NULL, NULL,
+                                                krb5->credentials, &expiry);
+    if(status != SEC_E_OK)
+      return CURLE_LOGIN_DENIED;
+
+    /* Allocate our new context handle */
+    krb5->context = malloc(sizeof(CtxtHandle));
+    if(!krb5->context)
+      return CURLE_OUT_OF_MEMORY;
+
+    memset(krb5->context, 0, sizeof(CtxtHandle));
+  }
+
+  if(chlg64 && *chlg64) {
+    /* Decode the base-64 encoded challenge message */
+    if(*chlg64 != '=') {
+      result = Curl_base64_decode(chlg64, &chlg, &chlglen);
+      if(result)
+        return result;
+    }
+
+    /* Ensure we have a valid challenge message */
+    if(!chlg) {
+      infof(data, "GSSAPI handshake failure (empty challenge message)\n");
+
+      return CURLE_BAD_CONTENT_ENCODING;
+    }
+
+    /* Setup the challenge "input" security buffer */
+    chlg_desc.ulVersion = SECBUFFER_VERSION;
+    chlg_desc.cBuffers  = 1;
+    chlg_desc.pBuffers  = &chlg_buf;
+    chlg_buf.BufferType = SECBUFFER_TOKEN;
+    chlg_buf.pvBuffer   = chlg;
+    chlg_buf.cbBuffer   = curlx_uztoul(chlglen);
+  }
+
+  /* Setup the response "output" security buffer */
+  resp_desc.ulVersion = SECBUFFER_VERSION;
+  resp_desc.cBuffers  = 1;
+  resp_desc.pBuffers  = &resp_buf;
+  resp_buf.BufferType = SECBUFFER_TOKEN;
+  resp_buf.pvBuffer   = krb5->output_token;
+  resp_buf.cbBuffer   = curlx_uztoul(krb5->token_max);
+
+  /* Generate our challenge-response message */
+  status = s_pSecFn->InitializeSecurityContext(krb5->credentials,
+                                               chlg ? krb5->context : NULL,
+                                               krb5->spn,
+                                               (mutual_auth ?
+                                                ISC_REQ_MUTUAL_AUTH : 0),
+                                               0, SECURITY_NATIVE_DREP,
+                                               chlg ? &chlg_desc : NULL, 0,
+                                               &context,
+                                               &resp_desc, &attrs,
+                                               &expiry);
+
+  /* Free the decoded challenge as it is not required anymore */
+  free(chlg);
+
+  if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) {
+    return CURLE_RECV_ERROR;
+  }
+
+  if(memcmp(&context, krb5->context, sizeof(context))) {
+    s_pSecFn->DeleteSecurityContext(krb5->context);
+
+    memcpy(krb5->context, &context, sizeof(context));
+  }
+
+  if(resp_buf.cbBuffer) {
+    /* Base64 encode the response */
+    result = Curl_base64_encode(data, (char *) resp_buf.pvBuffer,
+                                resp_buf.cbBuffer, outptr, outlen);
+  }
+  else if(mutual_auth) {
+    *outptr = strdup("");
+    if(!*outptr)
+      result = CURLE_OUT_OF_MEMORY;
+  }
+
+  return result;
+}
+
+/*
+ * Curl_auth_create_gssapi_security_message()
+ *
+ * This is used to generate an already encoded GSSAPI (Kerberos V5) security
+ * token message ready for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data    [in]     - The session handle.
+ * chlg64  [in]     - The optional base64 encoded challenge message.
+ * krb5    [in/out] - The Kerberos 5 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_gssapi_security_message(struct Curl_easy *data,
+                                                  const char *chlg64,
+                                                  struct kerberos5data *krb5,
+                                                  char **outptr,
+                                                  size_t *outlen)
+{
+  CURLcode result = CURLE_OK;
+  size_t offset = 0;
+  size_t chlglen = 0;
+  size_t messagelen = 0;
+  size_t appdatalen = 0;
+  unsigned char *chlg = NULL;
+  unsigned char *trailer = NULL;
+  unsigned char *message = NULL;
+  unsigned char *padding = NULL;
+  unsigned char *appdata = NULL;
+  SecBuffer input_buf[2];
+  SecBuffer wrap_buf[3];
+  SecBufferDesc input_desc;
+  SecBufferDesc wrap_desc;
+  unsigned long indata = 0;
+  unsigned long outdata = 0;
+  unsigned long qop = 0;
+  unsigned long sec_layer = 0;
+  unsigned long max_size = 0;
+  SecPkgContext_Sizes sizes;
+  SecPkgCredentials_Names names;
+  SECURITY_STATUS status;
+  char *user_name;
+
+  /* Decode the base-64 encoded input message */
+  if(strlen(chlg64) && *chlg64 != '=') {
+    result = Curl_base64_decode(chlg64, &chlg, &chlglen);
+    if(result)
+      return result;
+  }
+
+  /* Ensure we have a valid challenge message */
+  if(!chlg) {
+    infof(data, "GSSAPI handshake failure (empty security message)\n");
+
+    return CURLE_BAD_CONTENT_ENCODING;
+  }
+
+  /* Get our response size information */
+  status = s_pSecFn->QueryContextAttributes(krb5->context,
+                                            SECPKG_ATTR_SIZES,
+                                            &sizes);
+  if(status != SEC_E_OK) {
+    free(chlg);
+
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  /* Get the fully qualified username back from the context */
+  status = s_pSecFn->QueryCredentialsAttributes(krb5->credentials,
+                                                SECPKG_CRED_ATTR_NAMES,
+                                                &names);
+  if(status != SEC_E_OK) {
+    free(chlg);
+
+    return CURLE_RECV_ERROR;
+  }
+
+  /* Setup the "input" security buffer */
+  input_desc.ulVersion = SECBUFFER_VERSION;
+  input_desc.cBuffers = 2;
+  input_desc.pBuffers = input_buf;
+  input_buf[0].BufferType = SECBUFFER_STREAM;
+  input_buf[0].pvBuffer = chlg;
+  input_buf[0].cbBuffer = curlx_uztoul(chlglen);
+  input_buf[1].BufferType = SECBUFFER_DATA;
+  input_buf[1].pvBuffer = NULL;
+  input_buf[1].cbBuffer = 0;
+
+  /* Decrypt the inbound challenge and obtain the qop */
+  status = s_pSecFn->DecryptMessage(krb5->context, &input_desc, 0, &qop);
+  if(status != SEC_E_OK) {
+    infof(data, "GSSAPI handshake failure (empty security message)\n");
+
+    free(chlg);
+
+    return CURLE_BAD_CONTENT_ENCODING;
+  }
+
+  /* Not 4 octets long so fail as per RFC4752 Section 3.1 */
+  if(input_buf[1].cbBuffer != 4) {
+    infof(data, "GSSAPI handshake failure (invalid security data)\n");
+
+    free(chlg);
+
+    return CURLE_BAD_CONTENT_ENCODING;
+  }
+
+  /* Copy the data out and free the challenge as it is not required anymore */
+  memcpy(&indata, input_buf[1].pvBuffer, 4);
+  s_pSecFn->FreeContextBuffer(input_buf[1].pvBuffer);
+  free(chlg);
+
+  /* Extract the security layer */
+  sec_layer = indata & 0x000000FF;
+  if(!(sec_layer & KERB_WRAP_NO_ENCRYPT)) {
+    infof(data, "GSSAPI handshake failure (invalid security layer)\n");
+
+    return CURLE_BAD_CONTENT_ENCODING;
+  }
+
+  /* Extract the maximum message size the server can receive */
+  max_size = ntohl(indata & 0xFFFFFF00);
+  if(max_size > 0) {
+    /* The server has told us it supports a maximum receive buffer, however, as
+       we don't require one unless we are encrypting data, we tell the server
+       our receive buffer is zero. */
+    max_size = 0;
+  }
+
+  /* Allocate the trailer */
+  trailer = malloc(sizes.cbSecurityTrailer);
+  if(!trailer)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* Convert the user name to UTF8 when operating with Unicode */
+  user_name = Curl_convert_tchar_to_UTF8(names.sUserName);
+  if(!user_name) {
+    free(trailer);
+
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  /* Allocate our message */
+  messagelen = sizeof(outdata) + strlen(user_name) + 1;
+  message = malloc(messagelen);
+  if(!message) {
+    free(trailer);
+    Curl_unicodefree(user_name);
+
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  /* Populate the message with the security layer, client supported receive
+     message size and authorization identity including the 0x00 based
+     terminator. Note: Despite RFC4752 Section 3.1 stating "The authorization
+     identity is not terminated with the zero-valued (%x00) octet." it seems
+     necessary to include it. */
+  outdata = htonl(max_size) | sec_layer;
+  memcpy(message, &outdata, sizeof(outdata));
+  strcpy((char *) message + sizeof(outdata), user_name);
+  Curl_unicodefree(user_name);
+
+  /* Allocate the padding */
+  padding = malloc(sizes.cbBlockSize);
+  if(!padding) {
+    free(message);
+    free(trailer);
+
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  /* Setup the "authentication data" security buffer */
+  wrap_desc.ulVersion    = SECBUFFER_VERSION;
+  wrap_desc.cBuffers     = 3;
+  wrap_desc.pBuffers     = wrap_buf;
+  wrap_buf[0].BufferType = SECBUFFER_TOKEN;
+  wrap_buf[0].pvBuffer   = trailer;
+  wrap_buf[0].cbBuffer   = sizes.cbSecurityTrailer;
+  wrap_buf[1].BufferType = SECBUFFER_DATA;
+  wrap_buf[1].pvBuffer   = message;
+  wrap_buf[1].cbBuffer   = curlx_uztoul(messagelen);
+  wrap_buf[2].BufferType = SECBUFFER_PADDING;
+  wrap_buf[2].pvBuffer   = padding;
+  wrap_buf[2].cbBuffer   = sizes.cbBlockSize;
+
+  /* Encrypt the data */
+  status = s_pSecFn->EncryptMessage(krb5->context, KERB_WRAP_NO_ENCRYPT,
+                                    &wrap_desc, 0);
+  if(status != SEC_E_OK) {
+    free(padding);
+    free(message);
+    free(trailer);
+
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  /* Allocate the encryption (wrap) buffer */
+  appdatalen = wrap_buf[0].cbBuffer + wrap_buf[1].cbBuffer +
+               wrap_buf[2].cbBuffer;
+  appdata = malloc(appdatalen);
+  if(!appdata) {
+    free(padding);
+    free(message);
+    free(trailer);
+
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  /* Populate the encryption buffer */
+  memcpy(appdata, wrap_buf[0].pvBuffer, wrap_buf[0].cbBuffer);
+  offset += wrap_buf[0].cbBuffer;
+  memcpy(appdata + offset, wrap_buf[1].pvBuffer, wrap_buf[1].cbBuffer);
+  offset += wrap_buf[1].cbBuffer;
+  memcpy(appdata + offset, wrap_buf[2].pvBuffer, wrap_buf[2].cbBuffer);
+
+  /* Base64 encode the response */
+  result = Curl_base64_encode(data, (char *) appdata, appdatalen, outptr,
+                              outlen);
+
+  /* Free all of our local buffers */
+  free(appdata);
+  free(padding);
+  free(message);
+  free(trailer);
+
+  return result;
+}
+
+/*
+ * Curl_auth_gssapi_cleanup()
+ *
+ * This is used to clean up the GSSAPI (Kerberos V5) specific data.
+ *
+ * Parameters:
+ *
+ * krb5     [in/out] - The Kerberos 5 data struct being cleaned up.
+ *
+ */
+void Curl_auth_gssapi_cleanup(struct kerberos5data *krb5)
+{
+  /* Free our security context */
+  if(krb5->context) {
+    s_pSecFn->DeleteSecurityContext(krb5->context);
+    free(krb5->context);
+    krb5->context = NULL;
+  }
+
+  /* Free our credentials handle */
+  if(krb5->credentials) {
+    s_pSecFn->FreeCredentialsHandle(krb5->credentials);
+    free(krb5->credentials);
+    krb5->credentials = NULL;
+  }
+
+  /* Free our identity */
+  Curl_sspi_free_identity(krb5->p_identity);
+  krb5->p_identity = NULL;
+
+  /* Free the SPN and output token */
+  Curl_safefree(krb5->spn);
+  Curl_safefree(krb5->output_token);
+
+  /* Reset any variables */
+  krb5->token_max = 0;
+}
+
+#endif /* USE_WINDOWS_SSPI && USE_KERBEROS5*/
diff --git a/lib/curl_ntlm_msgs.c b/lib/vauth/ntlm.c
similarity index 94%
rename from lib/curl_ntlm_msgs.c
rename to lib/vauth/ntlm.c
index 7f07dec..c85fe42 100644
--- a/lib/curl_ntlm_msgs.c
+++ b/lib/vauth/ntlm.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -28,7 +28,7 @@
  * NTLM details:
  *
  * http://davenport.sourceforge.net/ntlm.html
- * http://www.innovation.ch/java/ntlm.html
+ * https://www.innovation.ch/java/ntlm.html
  */
 
 #define DEBUG_ME 0
@@ -49,8 +49,8 @@
 #endif
 
 #define BUILDING_CURL_NTLM_MSGS_C
-#include "curl_ntlm_msgs.h"
-#include "curl_sasl.h"
+#include "vauth/vauth.h"
+#include "vauth/ntlm.h"
 #include "curl_endian.h"
 #include "curl_printf.h"
 
@@ -138,7 +138,9 @@ static void ntlm_print_flags(FILE *handle, unsigned long flags)
 static void ntlm_print_hex(FILE *handle, const char *buf, size_t len)
 {
   const char *p = buf;
-  (void)handle;
+
+  (void) handle;
+
   fprintf(stderr, "0x");
   while(len-- > 0)
     fprintf(stderr, "%02.2x", (unsigned int)*p++);
@@ -150,7 +152,7 @@ static void ntlm_print_hex(FILE *handle, const char *buf, size_t len)
 /*
  * ntlm_decode_type2_target()
  *
- * This is used to decode the "target info" in the ntlm type-2 message
+ * This is used to decode the "target info" in the NTLM type-2 message
  * received.
  *
  * Parameters:
@@ -158,11 +160,11 @@ static void ntlm_print_hex(FILE *handle, const char *buf, size_t len)
  * data      [in]     - The session handle.
  * buffer    [in]     - The decoded type-2 message.
  * size      [in]     - The input buffer size, at least 32 bytes.
- * ntlm      [in/out] - The ntlm data struct being used and modified.
+ * ntlm      [in/out] - The NTLM data struct being used and modified.
  *
  * Returns CURLE_OK on success.
  */
-static CURLcode ntlm_decode_type2_target(struct SessionHandle *data,
+static CURLcode ntlm_decode_type2_target(struct Curl_easy *data,
                                          unsigned char *buffer,
                                          size_t size,
                                          struct ntlmdata *ntlm)
@@ -170,6 +172,10 @@ static CURLcode ntlm_decode_type2_target(struct SessionHandle *data,
   unsigned short target_info_len = 0;
   unsigned int target_info_offset = 0;
 
+#if defined(CURL_DISABLE_VERBOSE_STRINGS)
+  (void) data;
+#endif
+
   if(size >= 48) {
     target_info_len = Curl_read16_le(&buffer[40]);
     target_info_offset = Curl_read32_le(&buffer[44]);
@@ -211,7 +217,7 @@ static CURLcode ntlm_decode_type2_target(struct SessionHandle *data,
 */
 
 /*
- * Curl_sasl_decode_ntlm_type2_message()
+ * Curl_auth_decode_ntlm_type2_message()
  *
  * This is used to decode an already encoded NTLM type-2 message. The message
  * is first decoded from a base64 string into a raw NTLM message and checked
@@ -222,11 +228,11 @@ static CURLcode ntlm_decode_type2_target(struct SessionHandle *data,
  *
  * data     [in]     - The session handle.
  * type2msg [in]     - The base64 encoded type-2 message.
- * ntlm     [in/out] - The ntlm data struct being used and modified.
+ * ntlm     [in/out] - The NTLM data struct being used and modified.
  *
  * Returns CURLE_OK on success.
  */
-CURLcode Curl_sasl_decode_ntlm_type2_message(struct SessionHandle *data,
+CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data,
                                              const char *type2msg,
                                              struct ntlmdata *ntlm)
 {
@@ -323,7 +329,7 @@ static void unicodecpy(unsigned char *dest, const char *src, size_t length)
 }
 
 /*
- * Curl_sasl_create_ntlm_type1_message()
+ * Curl_auth_create_ntlm_type1_message()
  *
  * This is used to generate an already encoded NTLM type-1 message ready for
  * sending to the recipient using the appropriate compile time crypto API.
@@ -332,14 +338,14 @@ static void unicodecpy(unsigned char *dest, const char *src, size_t length)
  *
  * userp   [in]     - The user name in the format User or Domain\User.
  * passdwp [in]     - The user's password.
- * ntlm    [in/out] - The ntlm data struct being used and modified.
+ * ntlm    [in/out] - The NTLM 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_sasl_create_ntlm_type1_message(const char *userp,
+CURLcode Curl_auth_create_ntlm_type1_message(const char *userp,
                                              const char *passwdp,
                                              struct ntlmdata *ntlm,
                                              char **outptr, size_t *outlen)
@@ -372,7 +378,7 @@ CURLcode Curl_sasl_create_ntlm_type1_message(const char *userp,
   (void)passwdp;
 
   /* Clean up any former leftovers and initialise to defaults */
-  Curl_sasl_ntlm_cleanup(ntlm);
+  Curl_auth_ntlm_cleanup(ntlm);
 
 #if USE_NTRESPONSES && USE_NTLM2SESSION
 #define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY
@@ -442,7 +448,7 @@ CURLcode Curl_sasl_create_ntlm_type1_message(const char *userp,
 }
 
 /*
- * Curl_sasl_create_ntlm_type3_message()
+ * Curl_auth_create_ntlm_type3_message()
  *
  * This is used to generate an already encoded NTLM type-3 message ready for
  * sending to the recipient using the appropriate compile time crypto API.
@@ -452,14 +458,14 @@ CURLcode Curl_sasl_create_ntlm_type1_message(const char *userp,
  * data    [in]     - The session handle.
  * userp   [in]     - The user name in the format User or Domain\User.
  * passdwp [in]     - The user's password.
- * ntlm    [in/out] - The ntlm data struct being used and modified.
+ * ntlm    [in/out] - The NTLM 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_sasl_create_ntlm_type3_message(struct SessionHandle *data,
+CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
                                              const char *userp,
                                              const char *passwdp,
                                              struct ntlmdata *ntlm,
@@ -809,9 +815,28 @@ CURLcode Curl_sasl_create_ntlm_type3_message(struct SessionHandle *data,
   /* Return with binary blob encoded into base64 */
   result = Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, outlen);
 
-  Curl_sasl_ntlm_cleanup(ntlm);
+  Curl_auth_ntlm_cleanup(ntlm);
 
   return result;
 }
 
+/*
+* Curl_auth_ntlm_cleanup()
+*
+* This is used to clean up the NTLM specific data.
+*
+* Parameters:
+*
+* ntlm    [in/out] - The NTLM data struct being cleaned up.
+*
+*/
+void Curl_auth_ntlm_cleanup(struct ntlmdata *ntlm)
+{
+  /* Free the target info */
+  Curl_safefree(ntlm->target_info);
+
+  /* Reset any variables */
+  ntlm->target_info_len = 0;
+}
+
 #endif /* USE_NTLM && !USE_WINDOWS_SSPI */
diff --git a/lib/curl_ntlm_msgs.h b/lib/vauth/ntlm.h
similarity index 95%
rename from lib/curl_ntlm_msgs.h
rename to lib/vauth/ntlm.h
index 2a71431..b14e7a5 100644
--- a/lib/curl_ntlm_msgs.h
+++ b/lib/vauth/ntlm.h
@@ -1,5 +1,5 @@
-#ifndef HEADER_CURL_NTLM_MSGS_H
-#define HEADER_CURL_NTLM_MSGS_H
+#ifndef HEADER_CURL_NTLM_H
+#define HEADER_CURL_NTLM_H
 /***************************************************************************
  *                                  _   _ ____  _
  *  Project                     ___| | | |  _ \| |
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -140,4 +140,4 @@
 
 #endif /* USE_NTLM */
 
-#endif /* HEADER_CURL_NTLM_MSGS_H */
+#endif /* HEADER_CURL_NTLM_H */
diff --git a/lib/vauth/ntlm_sspi.c b/lib/vauth/ntlm_sspi.c
new file mode 100644
index 0000000..982a9d3
--- /dev/null
+++ b/lib/vauth/ntlm_sspi.c
@@ -0,0 +1,314 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.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"
+
+#if defined(USE_WINDOWS_SSPI) && defined(USE_NTLM)
+
+#include <curl/curl.h>
+
+#include "vauth/vauth.h"
+#include "urldata.h"
+#include "curl_base64.h"
+#include "warnless.h"
+#include "curl_multibyte.h"
+#include "sendf.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Curl_auth_create_ntlm_type1_message()
+ *
+ * This is used to generate an already encoded NTLM type-1 message ready for
+ * sending to the recipient.
+ *
+ * Parameters:
+ *
+ * userp   [in]     - The user name in the format User or Domain\User.
+ * passdwp [in]     - The user's password.
+ * ntlm    [in/out] - The NTLM 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_ntlm_type1_message(const char *userp,
+                                             const char *passwdp,
+                                             struct ntlmdata *ntlm,
+                                             char **outptr, size_t *outlen)
+{
+  PSecPkgInfo SecurityPackage;
+  SecBuffer type_1_buf;
+  SecBufferDesc type_1_desc;
+  SECURITY_STATUS status;
+  unsigned long attrs;
+  TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
+
+  /* Clean up any former leftovers and initialise to defaults */
+  Curl_auth_ntlm_cleanup(ntlm);
+
+  /* Query the security package for NTLM */
+  status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM),
+                                              &SecurityPackage);
+  if(status != SEC_E_OK)
+    return CURLE_NOT_BUILT_IN;
+
+  ntlm->token_max = SecurityPackage->cbMaxToken;
+
+  /* Release the package buffer as it is not required anymore */
+  s_pSecFn->FreeContextBuffer(SecurityPackage);
+
+  /* Allocate our output buffer */
+  ntlm->output_token = malloc(ntlm->token_max);
+  if(!ntlm->output_token)
+    return CURLE_OUT_OF_MEMORY;
+
+  if(userp && *userp) {
+    CURLcode result;
+
+    /* Populate our identity structure */
+    result = Curl_create_sspi_identity(userp, passwdp, &ntlm->identity);
+    if(result)
+      return result;
+
+    /* Allow proper cleanup of the identity structure */
+    ntlm->p_identity = &ntlm->identity;
+  }
+  else
+    /* Use the current Windows user */
+    ntlm->p_identity = NULL;
+
+  /* Allocate our credentials handle */
+  ntlm->credentials = malloc(sizeof(CredHandle));
+  if(!ntlm->credentials)
+    return CURLE_OUT_OF_MEMORY;
+
+  memset(ntlm->credentials, 0, sizeof(CredHandle));
+
+  /* Acquire our credentials handle */
+  status = s_pSecFn->AcquireCredentialsHandle(NULL,
+                                              (TCHAR *) TEXT(SP_NAME_NTLM),
+                                              SECPKG_CRED_OUTBOUND, NULL,
+                                              ntlm->p_identity, NULL, NULL,
+                                              ntlm->credentials, &expiry);
+  if(status != SEC_E_OK)
+    return CURLE_LOGIN_DENIED;
+
+  /* Allocate our new context handle */
+  ntlm->context = malloc(sizeof(CtxtHandle));
+  if(!ntlm->context)
+    return CURLE_OUT_OF_MEMORY;
+
+  memset(ntlm->context, 0, sizeof(CtxtHandle));
+
+  /* Setup the type-1 "output" security buffer */
+  type_1_desc.ulVersion = SECBUFFER_VERSION;
+  type_1_desc.cBuffers  = 1;
+  type_1_desc.pBuffers  = &type_1_buf;
+  type_1_buf.BufferType = SECBUFFER_TOKEN;
+  type_1_buf.pvBuffer   = ntlm->output_token;
+  type_1_buf.cbBuffer   = curlx_uztoul(ntlm->token_max);
+
+  /* Generate our type-1 message */
+  status = s_pSecFn->InitializeSecurityContext(ntlm->credentials, NULL,
+                                               (TCHAR *) TEXT(""),
+                                               0, 0, SECURITY_NETWORK_DREP,
+                                               NULL, 0,
+                                               ntlm->context, &type_1_desc,
+                                               &attrs, &expiry);
+  if(status == SEC_I_COMPLETE_NEEDED ||
+    status == SEC_I_COMPLETE_AND_CONTINUE)
+    s_pSecFn->CompleteAuthToken(ntlm->context, &type_1_desc);
+  else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED)
+    return CURLE_RECV_ERROR;
+
+  /* Base64 encode the response */
+  return Curl_base64_encode(NULL, (char *) ntlm->output_token,
+                            type_1_buf.cbBuffer, outptr, outlen);
+}
+
+/*
+ * Curl_auth_decode_ntlm_type2_message()
+ *
+ * This is used to decode an already encoded NTLM type-2 message.
+ *
+ * Parameters:
+ *
+ * data     [in]     - The session handle.
+ * type2msg [in]     - The base64 encoded type-2 message.
+ * ntlm     [in/out] - The NTLM data struct being used and modified.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data,
+                                             const char *type2msg,
+                                             struct ntlmdata *ntlm)
+{
+  CURLcode result = CURLE_OK;
+  unsigned char *type2 = NULL;
+  size_t type2_len = 0;
+
+#if defined(CURL_DISABLE_VERBOSE_STRINGS)
+  (void) data;
+#endif
+
+  /* Decode the base-64 encoded type-2 message */
+  if(strlen(type2msg) && *type2msg != '=') {
+    result = Curl_base64_decode(type2msg, &type2, &type2_len);
+    if(result)
+      return result;
+  }
+
+  /* Ensure we have a valid type-2 message */
+  if(!type2) {
+    infof(data, "NTLM handshake failure (empty type-2 message)\n");
+
+    return CURLE_BAD_CONTENT_ENCODING;
+  }
+
+  /* Simply store the challenge for use later */
+  ntlm->input_token = type2;
+  ntlm->input_token_len = type2_len;
+
+  return result;
+}
+
+/*
+* Curl_auth_create_ntlm_type3_message()
+ * Curl_auth_create_ntlm_type3_message()
+ *
+ * This is used to generate an already encoded NTLM type-3 message ready for
+ * sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data    [in]     - The session handle.
+ * userp   [in]     - The user name in the format User or Domain\User.
+ * passdwp [in]     - The user's password.
+ * ntlm    [in/out] - The NTLM 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_ntlm_type3_message(struct Curl_easy *data,
+                                             const char *userp,
+                                             const char *passwdp,
+                                             struct ntlmdata *ntlm,
+                                             char **outptr, size_t *outlen)
+{
+  CURLcode result = CURLE_OK;
+  SecBuffer type_2_buf;
+  SecBuffer type_3_buf;
+  SecBufferDesc type_2_desc;
+  SecBufferDesc type_3_desc;
+  SECURITY_STATUS status;
+  unsigned long attrs;
+  TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
+
+  (void) passwdp;
+  (void) userp;
+
+  /* Setup the type-2 "input" security buffer */
+  type_2_desc.ulVersion = SECBUFFER_VERSION;
+  type_2_desc.cBuffers  = 1;
+  type_2_desc.pBuffers  = &type_2_buf;
+  type_2_buf.BufferType = SECBUFFER_TOKEN;
+  type_2_buf.pvBuffer   = ntlm->input_token;
+  type_2_buf.cbBuffer   = curlx_uztoul(ntlm->input_token_len);
+
+  /* Setup the type-3 "output" security buffer */
+  type_3_desc.ulVersion = SECBUFFER_VERSION;
+  type_3_desc.cBuffers  = 1;
+  type_3_desc.pBuffers  = &type_3_buf;
+  type_3_buf.BufferType = SECBUFFER_TOKEN;
+  type_3_buf.pvBuffer   = ntlm->output_token;
+  type_3_buf.cbBuffer   = curlx_uztoul(ntlm->token_max);
+
+  /* Generate our type-3 message */
+  status = s_pSecFn->InitializeSecurityContext(ntlm->credentials,
+                                               ntlm->context,
+                                               (TCHAR *) TEXT(""),
+                                               0, 0, SECURITY_NETWORK_DREP,
+                                               &type_2_desc,
+                                               0, ntlm->context,
+                                               &type_3_desc,
+                                               &attrs, &expiry);
+  if(status != SEC_E_OK) {
+    infof(data, "NTLM handshake failure (type-3 message): Status=%x\n",
+          status);
+
+    return CURLE_RECV_ERROR;
+  }
+
+  /* Base64 encode the response */
+  result = Curl_base64_encode(data, (char *) ntlm->output_token,
+                              type_3_buf.cbBuffer, outptr, outlen);
+
+  Curl_auth_ntlm_cleanup(ntlm);
+
+  return result;
+}
+
+/*
+ * Curl_auth_ntlm_cleanup()
+ *
+ * This is used to clean up the NTLM specific data.
+ *
+ * Parameters:
+ *
+ * ntlm    [in/out] - The NTLM data struct being cleaned up.
+ *
+ */
+void Curl_auth_ntlm_cleanup(struct ntlmdata *ntlm)
+{
+  /* Free our security context */
+  if(ntlm->context) {
+    s_pSecFn->DeleteSecurityContext(ntlm->context);
+    free(ntlm->context);
+    ntlm->context = NULL;
+  }
+
+  /* Free our credentials handle */
+  if(ntlm->credentials) {
+    s_pSecFn->FreeCredentialsHandle(ntlm->credentials);
+    free(ntlm->credentials);
+    ntlm->credentials = NULL;
+  }
+
+  /* Free our identity */
+  Curl_sspi_free_identity(ntlm->p_identity);
+  ntlm->p_identity = NULL;
+
+  /* Free the input and output tokens */
+  Curl_safefree(ntlm->input_token);
+  Curl_safefree(ntlm->output_token);
+
+  /* Reset any variables */
+  ntlm->token_max = 0;
+}
+
+#endif /* USE_WINDOWS_SSPI && USE_NTLM */
diff --git a/lib/vauth/oauth2.c b/lib/vauth/oauth2.c
new file mode 100644
index 0000000..6288f89
--- /dev/null
+++ b/lib/vauth/oauth2.c
@@ -0,0 +1,86 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.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.
+ *
+ * RFC6749 OAuth 2.0 Authorization Framework
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+#include "urldata.h"
+
+#include "vauth/vauth.h"
+#include "curl_base64.h"
+#include "warnless.h"
+#include "curl_printf.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Curl_auth_create_oauth_bearer_message()
+ *
+ * This is used to generate an already encoded OAuth 2.0 message ready for
+ * sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data[in]         - The session handle.
+ * user[in]         - The user name.
+ * host[in]         - The host name(for OAUTHBEARER).
+ * port[in]         - The port(for OAUTHBEARER when not Port 80).
+ * bearer[in]       - The bearer token.
+ * 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_oauth_bearer_message(struct Curl_easy *data,
+                                               const char *user,
+                                               const char *host,
+                                               const long port,
+                                               const char *bearer,
+                                               char **outptr, size_t *outlen)
+{
+  CURLcode result = CURLE_OK;
+  char *oauth = NULL;
+
+  /* Generate the message */
+  if(host == NULL && (port == 0 || port == 80))
+    oauth = aprintf("user=%s\1auth=Bearer %s\1\1", user, bearer);
+  else if(port == 0 || port == 80)
+    oauth = aprintf("user=%s\1host=%s\1auth=Bearer %s\1\1", user, host,
+                    bearer);
+  else
+    oauth = aprintf("user=%s\1host=%s\1port=%ld\1auth=Bearer %s\1\1", user,
+                    host, port, bearer);
+  if(!oauth)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* Base64 encode the reply */
+  result = Curl_base64_encode(data, oauth, strlen(oauth), outptr, outlen);
+
+  free(oauth);
+
+  return result;
+}
diff --git a/lib/vauth/spnego_gssapi.c b/lib/vauth/spnego_gssapi.c
new file mode 100644
index 0000000..b256ee6
--- /dev/null
+++ b/lib/vauth/spnego_gssapi.c
@@ -0,0 +1,260 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.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.
+ *
+ * RFC4178 Simple and Protected GSS-API Negotiation Mechanism
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(HAVE_GSSAPI) && defined(USE_SPNEGO)
+
+#include <curl/curl.h>
+
+#include "vauth/vauth.h"
+#include "urldata.h"
+#include "curl_base64.h"
+#include "curl_gssapi.h"
+#include "warnless.h"
+#include "curl_multibyte.h"
+#include "sendf.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Curl_auth_decode_spnego_message()
+ *
+ * This is used to decode an already encoded SPNEGO (Negotiate) challenge
+ * message.
+ *
+ * Parameters:
+ *
+ * data        [in]     - The session handle.
+ * userp       [in]     - The user name in the format User or Domain\User.
+ * passdwp     [in]     - The user's password.
+ * service     [in]     - The service type such as http, smtp, pop or imap.
+ * host        [in]     - The host name.
+ * chlg64      [in]     - The optional base64 encoded challenge message.
+ * nego        [in/out] - The Negotiate data struct being used and modified.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
+                                         const char *user,
+                                         const char *password,
+                                         const char *service,
+                                         const char *host,
+                                         const char *chlg64,
+                                         struct negotiatedata *nego)
+{
+  CURLcode result = CURLE_OK;
+  size_t chlglen = 0;
+  unsigned char *chlg = NULL;
+  OM_uint32 major_status;
+  OM_uint32 minor_status;
+  OM_uint32 unused_status;
+  gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER;
+  gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
+  gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
+
+  (void) user;
+  (void) password;
+
+  if(nego->context && nego->status == GSS_S_COMPLETE) {
+    /* We finished successfully our part of authentication, but server
+     * rejected it (since we're again here). Exit with an error since we
+     * can't invent anything better */
+    Curl_auth_spnego_cleanup(nego);
+    return CURLE_LOGIN_DENIED;
+  }
+
+  if(!nego->spn) {
+    /* Generate our SPN */
+    char *spn = Curl_auth_build_spn(service, NULL, host);
+    if(!spn)
+      return CURLE_OUT_OF_MEMORY;
+
+    /* Populate the SPN structure */
+    spn_token.value = spn;
+    spn_token.length = strlen(spn);
+
+    /* Import the SPN */
+    major_status = gss_import_name(&minor_status, &spn_token,
+                                   GSS_C_NT_HOSTBASED_SERVICE,
+                                   &nego->spn);
+    if(GSS_ERROR(major_status)) {
+      Curl_gss_log_error(data, "gss_import_name() failed: ",
+                         major_status, minor_status);
+
+      free(spn);
+
+      return CURLE_OUT_OF_MEMORY;
+    }
+
+    free(spn);
+  }
+
+  if(chlg64 && *chlg64) {
+    /* Decode the base-64 encoded challenge message */
+    if(*chlg64 != '=') {
+      result = Curl_base64_decode(chlg64, &chlg, &chlglen);
+      if(result)
+        return result;
+    }
+
+    /* Ensure we have a valid challenge message */
+    if(!chlg) {
+      infof(data, "SPNEGO handshake failure (empty challenge message)\n");
+
+      return CURLE_BAD_CONTENT_ENCODING;
+    }
+
+    /* Setup the challenge "input" security buffer */
+    input_token.value = chlg;
+    input_token.length = chlglen;
+  }
+
+  /* Generate our challenge-response message */
+  major_status = Curl_gss_init_sec_context(data,
+                                           &minor_status,
+                                           &nego->context,
+                                           nego->spn,
+                                           &Curl_spnego_mech_oid,
+                                           GSS_C_NO_CHANNEL_BINDINGS,
+                                           &input_token,
+                                           &output_token,
+                                           TRUE,
+                                           NULL);
+
+  /* Free the decoded challenge as it is not required anymore */
+  Curl_safefree(input_token.value);
+
+  nego->status = major_status;
+  if(GSS_ERROR(major_status)) {
+    if(output_token.value)
+      gss_release_buffer(&unused_status, &output_token);
+
+    Curl_gss_log_error(data, "gss_init_sec_context() failed: ",
+                       major_status, minor_status);
+
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  if(!output_token.value || !output_token.length) {
+    if(output_token.value)
+      gss_release_buffer(&unused_status, &output_token);
+
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  nego->output_token = output_token;
+
+  return CURLE_OK;
+}
+
+/*
+ * Curl_auth_create_spnego_message()
+ *
+ * This is used to generate an already encoded SPNEGO (Negotiate) response
+ * message ready for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data        [in]     - The session handle.
+ * nego        [in/out] - The Negotiate 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_spnego_message(struct Curl_easy *data,
+                                         struct negotiatedata *nego,
+                                         char **outptr, size_t *outlen)
+{
+  CURLcode result;
+  OM_uint32 minor_status;
+
+  /* Base64 encode the already generated response */
+  result = Curl_base64_encode(data,
+                              nego->output_token.value,
+                              nego->output_token.length,
+                              outptr, outlen);
+
+  if(result) {
+    gss_release_buffer(&minor_status, &nego->output_token);
+    nego->output_token.value = NULL;
+    nego->output_token.length = 0;
+
+    return result;
+  }
+
+  if(!*outptr || !*outlen) {
+    gss_release_buffer(&minor_status, &nego->output_token);
+    nego->output_token.value = NULL;
+    nego->output_token.length = 0;
+
+    return CURLE_REMOTE_ACCESS_DENIED;
+  }
+
+  return CURLE_OK;
+}
+
+/*
+ * Curl_auth_spnego_cleanup()
+ *
+ * This is used to clean up the SPNEGO (Negotiate) specific data.
+ *
+ * Parameters:
+ *
+ * nego     [in/out] - The Negotiate data struct being cleaned up.
+ *
+ */
+void Curl_auth_spnego_cleanup(struct negotiatedata *nego)
+{
+  OM_uint32 minor_status;
+
+  /* Free our security context */
+  if(nego->context != GSS_C_NO_CONTEXT) {
+    gss_delete_sec_context(&minor_status, &nego->context, GSS_C_NO_BUFFER);
+    nego->context = GSS_C_NO_CONTEXT;
+  }
+
+  /* Free the output token */
+  if(nego->output_token.value) {
+    gss_release_buffer(&minor_status, &nego->output_token);
+    nego->output_token.value = NULL;
+    nego->output_token.length = 0;
+
+  }
+
+  /* Free the SPN */
+  if(nego->spn != GSS_C_NO_NAME) {
+    gss_release_name(&minor_status, &nego->spn);
+    nego->spn = GSS_C_NO_NAME;
+  }
+
+  /* Reset any variables */
+  nego->status = 0;
+}
+
+#endif /* HAVE_GSSAPI && USE_SPNEGO */
diff --git a/lib/vauth/spnego_sspi.c b/lib/vauth/spnego_sspi.c
new file mode 100644
index 0000000..b6176ec
--- /dev/null
+++ b/lib/vauth/spnego_sspi.c
@@ -0,0 +1,297 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.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.
+ *
+ * RFC4178 Simple and Protected GSS-API Negotiation Mechanism
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_WINDOWS_SSPI) && defined(USE_SPNEGO)
+
+#include <curl/curl.h>
+
+#include "vauth/vauth.h"
+#include "urldata.h"
+#include "curl_base64.h"
+#include "warnless.h"
+#include "curl_multibyte.h"
+#include "sendf.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Curl_auth_decode_spnego_message()
+ *
+ * This is used to decode an already encoded SPNEGO (Negotiate) challenge
+ * message.
+ *
+ * Parameters:
+ *
+ * data        [in]     - The session handle.
+ * userp       [in]     - The user name in the format User or Domain\User.
+ * passdwp     [in]     - The user's password.
+ * service     [in]     - The service type such as http, smtp, pop or imap.
+ * host        [in]     - The host name.
+ * chlg64      [in]     - The optional base64 encoded challenge message.
+ * nego        [in/out] - The Negotiate data struct being used and modified.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
+                                         const char *user,
+                                         const char *password,
+                                         const char *service,
+                                         const char *host,
+                                         const char *chlg64,
+                                         struct negotiatedata *nego)
+{
+  CURLcode result = CURLE_OK;
+  size_t chlglen = 0;
+  unsigned char *chlg = NULL;
+  PSecPkgInfo SecurityPackage;
+  SecBuffer chlg_buf;
+  SecBuffer resp_buf;
+  SecBufferDesc chlg_desc;
+  SecBufferDesc resp_desc;
+  unsigned long attrs;
+  TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
+
+#if defined(CURL_DISABLE_VERBOSE_STRINGS)
+  (void) data;
+#endif
+
+  if(nego->context && nego->status == SEC_E_OK) {
+    /* We finished successfully our part of authentication, but server
+     * rejected it (since we're again here). Exit with an error since we
+     * can't invent anything better */
+    Curl_auth_spnego_cleanup(nego);
+    return CURLE_LOGIN_DENIED;
+  }
+
+  if(!nego->spn) {
+    /* Generate our SPN */
+    nego->spn = Curl_auth_build_spn(service, host, NULL);
+    if(!nego->spn)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  if(!nego->output_token) {
+    /* Query the security package for Negotiate */
+    nego->status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *)
+                                                      TEXT(SP_NAME_NEGOTIATE),
+                                                      &SecurityPackage);
+    if(nego->status != SEC_E_OK)
+      return CURLE_NOT_BUILT_IN;
+
+    nego->token_max = SecurityPackage->cbMaxToken;
+
+    /* Release the package buffer as it is not required anymore */
+    s_pSecFn->FreeContextBuffer(SecurityPackage);
+
+    /* Allocate our output buffer */
+    nego->output_token = malloc(nego->token_max);
+    if(!nego->output_token)
+      return CURLE_OUT_OF_MEMORY;
+ }
+
+  if(!nego->credentials) {
+    /* Do we have credientials to use or are we using single sign-on? */
+    if(user && *user) {
+      /* Populate our identity structure */
+      result = Curl_create_sspi_identity(user, password, &nego->identity);
+      if(result)
+        return result;
+
+      /* Allow proper cleanup of the identity structure */
+      nego->p_identity = &nego->identity;
+    }
+    else
+      /* Use the current Windows user */
+      nego->p_identity = NULL;
+
+    /* Allocate our credentials handle */
+    nego->credentials = malloc(sizeof(CredHandle));
+    if(!nego->credentials)
+      return CURLE_OUT_OF_MEMORY;
+
+    memset(nego->credentials, 0, sizeof(CredHandle));
+
+    /* Acquire our credentials handle */
+    nego->status =
+      s_pSecFn->AcquireCredentialsHandle(NULL,
+                                         (TCHAR *)TEXT(SP_NAME_NEGOTIATE),
+                                         SECPKG_CRED_OUTBOUND, NULL,
+                                         nego->p_identity, NULL, NULL,
+                                         nego->credentials, &expiry);
+    if(nego->status != SEC_E_OK)
+      return CURLE_LOGIN_DENIED;
+
+    /* Allocate our new context handle */
+    nego->context = malloc(sizeof(CtxtHandle));
+    if(!nego->context)
+      return CURLE_OUT_OF_MEMORY;
+
+    memset(nego->context, 0, sizeof(CtxtHandle));
+  }
+
+  if(chlg64 && *chlg64) {
+    /* Decode the base-64 encoded challenge message */
+    if(*chlg64 != '=') {
+      result = Curl_base64_decode(chlg64, &chlg, &chlglen);
+      if(result)
+        return result;
+    }
+
+    /* Ensure we have a valid challenge message */
+    if(!chlg) {
+      infof(data, "SPNEGO handshake failure (empty challenge message)\n");
+
+      return CURLE_BAD_CONTENT_ENCODING;
+    }
+
+    /* Setup the challenge "input" security buffer */
+    chlg_desc.ulVersion = SECBUFFER_VERSION;
+    chlg_desc.cBuffers  = 1;
+    chlg_desc.pBuffers  = &chlg_buf;
+    chlg_buf.BufferType = SECBUFFER_TOKEN;
+    chlg_buf.pvBuffer   = chlg;
+    chlg_buf.cbBuffer   = curlx_uztoul(chlglen);
+  }
+
+  /* Setup the response "output" security buffer */
+  resp_desc.ulVersion = SECBUFFER_VERSION;
+  resp_desc.cBuffers  = 1;
+  resp_desc.pBuffers  = &resp_buf;
+  resp_buf.BufferType = SECBUFFER_TOKEN;
+  resp_buf.pvBuffer   = nego->output_token;
+  resp_buf.cbBuffer   = curlx_uztoul(nego->token_max);
+
+  /* Generate our challenge-response message */
+  nego->status = s_pSecFn->InitializeSecurityContext(nego->credentials,
+                                                     chlg ? nego->context :
+                                                            NULL,
+                                                     nego->spn,
+                                                     ISC_REQ_CONFIDENTIALITY,
+                                                     0, SECURITY_NATIVE_DREP,
+                                                     chlg ? &chlg_desc : NULL,
+                                                     0, nego->context,
+                                                     &resp_desc, &attrs,
+                                                     &expiry);
+
+  /* Free the decoded challenge as it is not required anymore */
+  free(chlg);
+
+  if(GSS_ERROR(nego->status)) {
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  if(nego->status == SEC_I_COMPLETE_NEEDED ||
+     nego->status == SEC_I_COMPLETE_AND_CONTINUE) {
+    nego->status = s_pSecFn->CompleteAuthToken(nego->context, &resp_desc);
+    if(GSS_ERROR(nego->status)) {
+      return CURLE_RECV_ERROR;
+    }
+  }
+
+  nego->output_token_length = resp_buf.cbBuffer;
+
+  return result;
+}
+
+/*
+ * Curl_auth_create_spnego_message()
+ *
+ * This is used to generate an already encoded SPNEGO (Negotiate) response
+ * message ready for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data        [in]     - The session handle.
+ * nego        [in/out] - The Negotiate 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_spnego_message(struct Curl_easy *data,
+                                         struct negotiatedata *nego,
+                                         char **outptr, size_t *outlen)
+{
+  CURLcode result;
+
+  /* Base64 encode the already generated response */
+  result = Curl_base64_encode(data,
+                              (const char*) nego->output_token,
+                              nego->output_token_length,
+                              outptr, outlen);
+
+  if(result)
+    return result;
+
+  if(!*outptr || !*outlen)
+    return CURLE_REMOTE_ACCESS_DENIED;
+
+  return CURLE_OK;
+}
+
+/*
+ * Curl_auth_spnego_cleanup()
+ *
+ * This is used to clean up the SPNEGO (Negotiate) specific data.
+ *
+ * Parameters:
+ *
+ * nego     [in/out] - The Negotiate data struct being cleaned up.
+ *
+ */
+void Curl_auth_spnego_cleanup(struct negotiatedata *nego)
+{
+  /* Free our security context */
+  if(nego->context) {
+    s_pSecFn->DeleteSecurityContext(nego->context);
+    free(nego->context);
+    nego->context = NULL;
+  }
+
+  /* Free our credentials handle */
+  if(nego->credentials) {
+    s_pSecFn->FreeCredentialsHandle(nego->credentials);
+    free(nego->credentials);
+    nego->credentials = NULL;
+  }
+
+  /* Free our identity */
+  Curl_sspi_free_identity(nego->p_identity);
+  nego->p_identity = NULL;
+
+  /* Free the SPN and output token */
+  Curl_safefree(nego->spn);
+  Curl_safefree(nego->output_token);
+
+  /* Reset any variables */
+  nego->status = 0;
+  nego->token_max = 0;
+}
+
+#endif /* USE_WINDOWS_SSPI && USE_SPNEGO */
diff --git a/lib/vauth/vauth.c b/lib/vauth/vauth.c
new file mode 100644
index 0000000..702e2d4
--- /dev/null
+++ b/lib/vauth/vauth.c
@@ -0,0 +1,106 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2014 - 2016, Steve Holme, <steve_holme at hotmail.com>.
+ *
+ * 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"
+
+#include <curl/curl.h>
+
+#include "vauth.h"
+#include "curl_multibyte.h"
+#include "curl_printf.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Curl_auth_build_spn()
+ *
+ * This is used to build a SPN string in the following formats:
+ *
+ * service/host at realm (Not currently used)
+ * service/host       (Not used by GSS-API)
+ * service at realm      (Not used by Windows SSPI)
+ *
+ * Parameters:
+ *
+ * service  [in] - The service type such as http, smtp, pop or imap.
+ * host     [in] - The host name.
+ * realm    [in] - The realm.
+ *
+ * Returns a pointer to the newly allocated SPN.
+ */
+#if !defined(USE_WINDOWS_SSPI)
+char *Curl_auth_build_spn(const char *service, const char *host,
+                          const char *realm)
+{
+  char *spn = NULL;
+
+  /* Generate our SPN */
+  if(host && realm)
+    spn = aprintf("%s/%s@%s", service, host, realm);
+  else if(host)
+    spn = aprintf("%s/%s", service, host);
+  else if(realm)
+    spn = aprintf("%s@%s", service, realm);
+
+  /* Return our newly allocated SPN */
+  return spn;
+}
+#else
+TCHAR *Curl_auth_build_spn(const char *service, const char *host,
+                           const char *realm)
+{
+  char *utf8_spn = NULL;
+  TCHAR *tchar_spn = NULL;
+
+  (void) realm;
+
+  /* Note: We could use DsMakeSPN() or DsClientMakeSpnForTargetServer() rather
+     than doing this ourselves but the first is only available in Windows XP
+     and Windows Server 2003 and the latter is only available in Windows 2000
+     but not Windows95/98/ME or Windows NT4.0 unless the Active Directory
+     Client Extensions are installed. As such it is far simpler for us to
+     formulate the SPN instead. */
+
+  /* Generate our UTF8 based SPN */
+  utf8_spn = aprintf("%s/%s", service, host);
+  if(!utf8_spn) {
+    return NULL;
+  }
+
+  /* Allocate our TCHAR based SPN */
+  tchar_spn = Curl_convert_UTF8_to_tchar(utf8_spn);
+  if(!tchar_spn) {
+    free(utf8_spn);
+
+    return NULL;
+  }
+
+  /* Release the UTF8 variant when operating with Unicode */
+  Curl_unicodefree(utf8_spn);
+
+  /* Return our newly allocated SPN */
+  return tchar_spn;
+}
+#endif /* USE_WINDOWS_SSPI */
+
diff --git a/lib/vauth/vauth.h b/lib/vauth/vauth.h
new file mode 100644
index 0000000..38806ee
--- /dev/null
+++ b/lib/vauth/vauth.h
@@ -0,0 +1,189 @@
+#ifndef HEADER_CURL_VAUTH_H
+#define HEADER_CURL_VAUTH_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2014 - 2016, Steve Holme, <steve_holme at hotmail.com>.
+ *
+ * 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/curl.h>
+
+struct Curl_easy;
+
+#if !defined(CURL_DISABLE_CRYPTO_AUTH)
+struct digestdata;
+#endif
+
+#if defined(USE_NTLM)
+struct ntlmdata;
+#endif
+
+#if defined(USE_KERBEROS5)
+struct kerberos5data;
+#endif
+
+#if (defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)) && defined(USE_SPNEGO)
+struct negotiatedata;
+#endif
+
+#if defined(USE_WINDOWS_SSPI)
+#define GSS_ERROR(status) (status & 0x80000000)
+#endif
+
+/* This is used to build a SPN string */
+#if !defined(USE_WINDOWS_SSPI)
+char *Curl_auth_build_spn(const char *service, const char *host,
+                          const char *realm);
+#else
+TCHAR *Curl_auth_build_spn(const char *service, const char *host,
+                           const char *realm);
+#endif
+
+/* This is used to generate a base64 encoded PLAIN cleartext message */
+CURLcode Curl_auth_create_plain_message(struct Curl_easy *data,
+                                        const char *userp,
+                                        const char *passwdp,
+                                        char **outptr, size_t *outlen);
+
+/* This is used to generate a base64 encoded LOGIN cleartext message */
+CURLcode Curl_auth_create_login_message(struct Curl_easy *data,
+                                        const char *valuep, char **outptr,
+                                        size_t *outlen);
+
+/* This is used to generate a base64 encoded EXTERNAL cleartext message */
+CURLcode Curl_auth_create_external_message(struct Curl_easy *data,
+                                           const char *user, char **outptr,
+                                           size_t *outlen);
+
+#if !defined(CURL_DISABLE_CRYPTO_AUTH)
+/* This is used to decode a CRAM-MD5 challenge message */
+CURLcode Curl_auth_decode_cram_md5_message(const char *chlg64, char **outptr,
+                                           size_t *outlen);
+
+/* This is used to generate a CRAM-MD5 response message */
+CURLcode Curl_auth_create_cram_md5_message(struct Curl_easy *data,
+                                           const char *chlg,
+                                           const char *userp,
+                                           const char *passwdp,
+                                           char **outptr, size_t *outlen);
+
+/* This is used to generate a base64 encoded DIGEST-MD5 response message */
+CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
+                                             const char *chlg64,
+                                             const char *userp,
+                                             const char *passwdp,
+                                             const char *service,
+                                             char **outptr, size_t *outlen);
+
+/* This is used to decode a HTTP DIGEST challenge message */
+CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
+                                              struct digestdata *digest);
+
+/* This is used to generate a HTTP DIGEST response message */
+CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
+                                              const char *userp,
+                                              const char *passwdp,
+                                              const unsigned char *request,
+                                              const unsigned char *uri,
+                                              struct digestdata *digest,
+                                              char **outptr, size_t *outlen);
+
+/* This is used to clean up the digest specific data */
+void Curl_auth_digest_cleanup(struct digestdata *digest);
+#endif /* !CURL_DISABLE_CRYPTO_AUTH */
+
+#if defined(USE_NTLM)
+/* This is used to generate a base64 encoded NTLM type-1 message */
+CURLcode Curl_auth_create_ntlm_type1_message(const char *userp,
+                                             const char *passwdp,
+                                             struct ntlmdata *ntlm,
+                                             char **outptr,
+                                             size_t *outlen);
+
+/* This is used to decode a base64 encoded NTLM type-2 message */
+CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data,
+                                             const char *type2msg,
+                                             struct ntlmdata *ntlm);
+
+/* This is used to generate a base64 encoded NTLM type-3 message */
+CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
+                                             const char *userp,
+                                             const char *passwdp,
+                                             struct ntlmdata *ntlm,
+                                             char **outptr, size_t *outlen);
+
+/* This is used to clean up the NTLM specific data */
+void Curl_auth_ntlm_cleanup(struct ntlmdata *ntlm);
+#endif /* USE_NTLM */
+
+/* This is used to generate a base64 encoded OAuth 2.0 message */
+CURLcode Curl_auth_create_oauth_bearer_message(struct Curl_easy *data,
+                                               const char *user,
+                                               const char *host,
+                                               const long port,
+                                               const char *bearer,
+                                               char **outptr, size_t *outlen);
+#if defined(USE_KERBEROS5)
+/* This is used to generate a base64 encoded GSSAPI (Kerberos V5) user token
+   message */
+CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
+                                              const char *userp,
+                                              const char *passwdp,
+                                              const char *service,
+                                              const char *host,
+                                              const bool mutual,
+                                              const char *chlg64,
+                                              struct kerberos5data *krb5,
+                                              char **outptr, size_t *outlen);
+
+/* This is used to generate a base64 encoded GSSAPI (Kerberos V5) security
+   token message */
+CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
+                                                  const char *input,
+                                                  struct kerberos5data *krb5,
+                                                  char **outptr,
+                                                  size_t *outlen);
+
+/* This is used to clean up the GSSAPI specific data */
+void Curl_auth_gssapi_cleanup(struct kerberos5data *krb5);
+#endif /* USE_KERBEROS5 */
+
+#if defined(USE_SPNEGO)
+/* This is used to decode a base64 encoded SPNEGO (Negotiate) challenge
+   message */
+CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
+                                         const char *user,
+                                         const char *passwood,
+                                         const char *service,
+                                         const char *host,
+                                         const char *chlg64,
+                                         struct negotiatedata *nego);
+
+/* This is used to generate a base64 encoded SPNEGO (Negotiate) response
+   message */
+CURLcode Curl_auth_create_spnego_message(struct Curl_easy *data,
+                                         struct negotiatedata *nego,
+                                         char **outptr, size_t *outlen);
+
+/* This is used to clean up the SPNEGO specifiec data */
+void Curl_auth_spnego_cleanup(struct negotiatedata *nego);
+
+#endif /* USE_SPNEGO */
+
+#endif /* HEADER_CURL_VAUTH_H */
diff --git a/lib/version.c b/lib/version.c
index 1727c5a..1292445 100644
--- a/lib/version.c
+++ b/lib/version.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -40,6 +40,10 @@
 #include <stringprep.h>
 #endif
 
+#ifdef USE_LIBPSL
+#include <libpsl.h>
+#endif
+
 #if defined(HAVE_ICONV) && defined(CURL_DOES_CONVERSIONS)
 #include <iconv.h>
 #endif
@@ -60,13 +64,27 @@
 #define CURL_LIBSSH2_VERSION LIBSSH2_VERSION
 #endif
 
+void Curl_version_init(void);
+
+/* For thread safety purposes this function is called by global_init so that
+   the static data in both version functions is initialized. */
+void Curl_version_init(void)
+{
+  curl_version();
+  curl_version_info(CURLVERSION_NOW);
+}
+
 char *curl_version(void)
 {
+  static bool initialized;
   static char version[200];
   char *ptr = version;
   size_t len;
   size_t left = sizeof(version);
 
+  if(initialized)
+    return version;
+
   strcpy(ptr, LIBCURL_NAME "/" LIBCURL_VERSION);
   len = strlen(ptr);
   left -= len;
@@ -100,6 +118,11 @@ char *curl_version(void)
     ptr += len;
   }
 #endif
+#ifdef USE_LIBPSL
+  len = snprintf(ptr, left, " libpsl/%s", psl_get_version());
+  left -= len;
+  ptr += len;
+#endif
 #ifdef USE_WIN32_IDN
   len = snprintf(ptr, left, " WinIDN");
   left -= len;
@@ -151,6 +174,7 @@ char *curl_version(void)
   }
 #endif
 
+  initialized = true;
   return version;
 }
 
@@ -297,6 +321,9 @@ static curl_version_info_data version_info = {
 #if defined(USE_UNIX_SOCKETS)
   | CURL_VERSION_UNIX_SOCKETS
 #endif
+#if defined(USE_LIBPSL)
+  | CURL_VERSION_PSL
+#endif
   ,
   NULL, /* ssl_version */
   0,    /* ssl_version_num, this is kept at zero */
@@ -311,12 +338,18 @@ static curl_version_info_data version_info = {
 
 curl_version_info_data *curl_version_info(CURLversion stamp)
 {
+  static bool initialized;
 #ifdef USE_LIBSSH2
   static char ssh_buffer[80];
 #endif
-
 #ifdef USE_SSL
   static char ssl_buffer[80];
+#endif
+
+  if(initialized)
+    return &version_info;
+
+#ifdef USE_SSL
   Curl_ssl_version(ssl_buffer, sizeof(ssl_buffer));
   version_info.ssl_version = ssl_buffer;
 #endif
@@ -358,5 +391,6 @@ curl_version_info_data *curl_version_info(CURLversion stamp)
 
   (void)stamp; /* avoid compiler warnings, we don't use this */
 
+  initialized = true;
   return &version_info;
 }
diff --git a/lib/vtls/axtls.c b/lib/vtls/axtls.c
index 1038432..b6c69ad 100644
--- a/lib/vtls/axtls.c
+++ b/lib/vtls/axtls.c
@@ -6,11 +6,11 @@
  *                             \___|\___/|_| \_\_____|
  *
  * Copyright (C) 2010, DirecTV, Contact: Eric Hu, <ehu at directv.com>.
- * Copyright (C) 2010 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 2010 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -137,14 +137,12 @@ static void free_ssl_structs(struct ssl_connect_data *connssl)
  */
 static CURLcode connect_prep(struct connectdata *conn, int sockindex)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   SSL_CTX *ssl_ctx;
   SSL *ssl = NULL;
   int cert_types[] = {SSL_OBJ_X509_CERT, SSL_OBJ_PKCS12, 0};
   int key_types[] = {SSL_OBJ_RSA_KEY, SSL_OBJ_PKCS8, SSL_OBJ_PKCS12, 0};
   int i, ssl_fcn_return;
-  const uint8_t *ssl_sessionid;
-  size_t ssl_idsize;
 
   /* Assuming users will not compile in custom key/cert to axTLS.
   *  Also, even for blocking connects, use axTLS non-blocking feature.
@@ -258,14 +256,22 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex)
    * 2) setting up callbacks.  these seem gnutls specific
    */
 
-  /* In axTLS, handshaking happens inside ssl_client_new. */
-  if(!Curl_ssl_getsessionid(conn, (void **) &ssl_sessionid, &ssl_idsize)) {
-    /* we got a session id, use it! */
-    infof (data, "SSL re-using session ID\n");
-    ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex],
-                         ssl_sessionid, (uint8_t)ssl_idsize);
+  if(conn->ssl_config.sessionid) {
+    const uint8_t *ssl_sessionid;
+    size_t ssl_idsize;
+
+    /* In axTLS, handshaking happens inside ssl_client_new. */
+    Curl_ssl_sessionid_lock(conn);
+    if(!Curl_ssl_getsessionid(conn, (void **) &ssl_sessionid, &ssl_idsize)) {
+      /* we got a session id, use it! */
+      infof (data, "SSL re-using session ID\n");
+      ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex],
+                           ssl_sessionid, (uint8_t)ssl_idsize);
+    }
+    Curl_ssl_sessionid_unlock(conn);
   }
-  else
+
+  if(!ssl)
     ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex], NULL, 0);
 
   conn->ssl[sockindex].ssl = ssl;
@@ -278,10 +284,8 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex)
  */
 static CURLcode connect_finish(struct connectdata *conn, int sockindex)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   SSL *ssl = conn->ssl[sockindex].ssl;
-  const uint8_t *ssl_sessionid;
-  size_t ssl_idsize;
   const char *peer_CN;
   uint32_t dns_altname_index;
   const char *dns_altname;
@@ -379,11 +383,15 @@ static CURLcode connect_finish(struct connectdata *conn, int sockindex)
   conn->send[sockindex] = axtls_send;
 
   /* Put our freshly minted SSL session in cache */
-  ssl_idsize = ssl_get_session_id_size(ssl);
-  ssl_sessionid = ssl_get_session_id(ssl);
-  if(Curl_ssl_addsessionid(conn, (void *) ssl_sessionid, ssl_idsize)
-     != CURLE_OK)
-    infof (data, "failed to add session to cache\n");
+  if(conn->ssl_config.sessionid) {
+    const uint8_t *ssl_sessionid = ssl_get_session_id_size(ssl);
+    size_t ssl_idsize = ssl_get_session_id(ssl);
+    Curl_ssl_sessionid_lock(conn);
+    if(Curl_ssl_addsessionid(conn, (void *) ssl_sessionid, ssl_idsize)
+       != CURLE_OK)
+      infof (data, "failed to add session to cache\n");
+    Curl_ssl_sessionid_unlock(conn);
+  }
 
   return CURLE_OK;
 }
@@ -464,7 +472,7 @@ Curl_axtls_connect(struct connectdata *conn,
                   int sockindex)
 
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   CURLcode conn_step = connect_prep(conn, sockindex);
   int ssl_fcn_return;
   SSL *ssl = conn->ssl[sockindex].ssl;
@@ -493,7 +501,7 @@ Curl_axtls_connect(struct connectdata *conn,
       return map_error_to_curl(ssl_fcn_return);
     }
     /* TODO: avoid polling */
-    usleep(10000);
+    Curl_wait_ms(10);
   }
   infof (conn->data, "handshake completed successfully\n");
 
@@ -518,7 +526,7 @@ static ssize_t axtls_send(struct connectdata *conn,
 
   infof(conn->data, "  axtls_send\n");
 
-  if(rc < 0 ) {
+  if(rc < 0) {
     *err = map_error_to_curl(rc);
     rc = -1; /* generic error code for send failure */
   }
@@ -554,7 +562,7 @@ int Curl_axtls_shutdown(struct connectdata *conn, int sockindex)
    */
   int retval = 0;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   uint8_t *buf;
   ssize_t nread;
 
@@ -670,7 +678,7 @@ size_t Curl_axtls_version(char *buffer, size_t size)
   return snprintf(buffer, size, "axTLS/%s", ssl_version());
 }
 
-int Curl_axtls_random(struct SessionHandle *data,
+int Curl_axtls_random(struct Curl_easy *data,
                       unsigned char *entropy,
                       size_t length)
 {
diff --git a/lib/vtls/axtls.h b/lib/vtls/axtls.h
index 223ecb8..b16d051 100644
--- a/lib/vtls/axtls.h
+++ b/lib/vtls/axtls.h
@@ -12,7 +12,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -42,7 +42,7 @@ void Curl_axtls_session_free(void *ptr);
 size_t Curl_axtls_version(char *buffer, size_t size);
 int Curl_axtls_shutdown(struct connectdata *conn, int sockindex);
 int Curl_axtls_check_cxn(struct connectdata *conn);
-int Curl_axtls_random(struct SessionHandle *data,
+int Curl_axtls_random(struct Curl_easy *data,
                       unsigned char *entropy,
                       size_t length);
 
diff --git a/lib/vtls/cyassl.c b/lib/vtls/cyassl.c
index 3ded7f1..7994b3e 100644
--- a/lib/vtls/cyassl.c
+++ b/lib/vtls/cyassl.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -33,7 +33,7 @@
 #define WOLFSSL_OPTIONS_IGNORE_SYS
 /* CyaSSL's version.h, which should contain only the version, should come
 before all other CyaSSL includes and be immediately followed by build config
-aka options.h. http://curl.haxx.se/mail/lib-2015-04/0069.html */
+aka options.h. https://curl.haxx.se/mail/lib-2015-04/0069.html */
 #include <cyassl/version.h>
 #if defined(HAVE_CYASSL_OPTIONS_H) && (LIBCYASSL_VERSION_HEX > 0x03004008)
 #if defined(CYASSL_API) || defined(WOLFSSL_API)
@@ -51,7 +51,6 @@ and that's a problem since options.h hasn't been included yet. */
 #include "urldata.h"
 #include "sendf.h"
 #include "inet_pton.h"
-#include "cyassl.h"
 #include "vtls.h"
 #include "parsedate.h"
 #include "connect.h" /* for the connect timeout */
@@ -69,6 +68,8 @@ and that's a problem since options.h hasn't been included yet. */
 #include <cyassl/ctaocrypt/random.h>
 #include <cyassl/ctaocrypt/sha256.h>
 
+#include "cyassl.h"
+
 /* The last #include files should be: */
 #include "curl_memory.h"
 #include "memdebug.h"
@@ -77,6 +78,38 @@ and that's a problem since options.h hasn't been included yet. */
 #define CYASSL_MAX_ERROR_SZ 80
 #endif
 
+/* To determine what functions are available we rely on one or both of:
+   - the user's options.h generated by CyaSSL/wolfSSL
+   - the symbols detected by curl's configure
+   Since they are markedly different from one another, and one or the other may
+   not be available, we do some checking below to bring things in sync. */
+
+/* HAVE_ALPN is wolfSSL's build time symbol for enabling ALPN in options.h. */
+#ifndef HAVE_ALPN
+#ifdef HAVE_WOLFSSL_USEALPN
+#define HAVE_ALPN
+#endif
+#endif
+
+/* WOLFSSL_ALLOW_SSLV3 is wolfSSL's build time symbol for enabling SSLv3 in
+   options.h, but is only seen in >= 3.6.6 since that's when they started
+   disabling SSLv3 by default. */
+#ifndef WOLFSSL_ALLOW_SSLV3
+#if (LIBCYASSL_VERSION_HEX < 0x03006006) || \
+    defined(HAVE_WOLFSSLV3_CLIENT_METHOD)
+#define WOLFSSL_ALLOW_SSLV3
+#endif
+#endif
+
+/* HAVE_SUPPORTED_CURVES is wolfSSL's build time symbol for enabling the ECC
+   supported curve extension in options.h. Note ECC is enabled separately. */
+#ifndef HAVE_SUPPORTED_CURVES
+#if defined(HAVE_CYASSL_CTX_USESUPPORTEDCURVE) || \
+    defined(HAVE_WOLFSSL_CTX_USESUPPORTEDCURVE)
+#define HAVE_SUPPORTED_CURVES
+#endif
+#endif
+
 static Curl_recv cyassl_recv;
 static Curl_send cyassl_send;
 
@@ -101,10 +134,9 @@ cyassl_connect_step1(struct connectdata *conn,
                      int sockindex)
 {
   char error_buffer[CYASSL_MAX_ERROR_SZ];
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct ssl_connect_data* conssl = &conn->ssl[sockindex];
   SSL_METHOD* req_method = NULL;
-  void* ssl_sessionid = NULL;
   curl_socket_t sockfd = conn->sock[sockindex];
 #ifdef HAVE_SNI
   bool sni = FALSE;
@@ -143,8 +175,13 @@ cyassl_connect_step1(struct connectdata *conn,
     use_sni(TRUE);
     break;
   case CURL_SSLVERSION_SSLv3:
+#ifdef WOLFSSL_ALLOW_SSLV3
     req_method = SSLv3_client_method();
     use_sni(FALSE);
+#else
+    failf(data, "No support for SSLv3");
+    return CURLE_NOT_BUILT_IN;
+#endif
     break;
   case CURL_SSLVERSION_SSLv2:
     failf(data, "CyaSSL does not support SSLv2");
@@ -273,6 +310,16 @@ cyassl_connect_step1(struct connectdata *conn,
   }
 #endif
 
+#ifdef HAVE_SUPPORTED_CURVES
+  /* CyaSSL/wolfSSL does not send the supported ECC curves ext automatically:
+     https://github.com/wolfSSL/wolfssl/issues/366
+     The supported curves below are those also supported by OpenSSL 1.0.2 and
+     in the same order. */
+  CyaSSL_CTX_UseSupportedCurve(conssl->ctx, 0x17); /* secp256r1 */
+  CyaSSL_CTX_UseSupportedCurve(conssl->ctx, 0x19); /* secp521r1 */
+  CyaSSL_CTX_UseSupportedCurve(conssl->ctx, 0x18); /* secp384r1 */
+#endif
+
   /* give application a chance to interfere with SSL set up. */
   if(data->set.ssl.fsslctx) {
     CURLcode result = CURLE_OK;
@@ -302,16 +349,51 @@ cyassl_connect_step1(struct connectdata *conn,
     return CURLE_OUT_OF_MEMORY;
   }
 
-  /* Check if there's a cached ID we can/should use here! */
-  if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) {
-    /* we got a session id, use it! */
-    if(!SSL_set_session(conssl->handle, ssl_sessionid)) {
-      failf(data, "SSL: SSL_set_session failed: %s",
-            ERR_error_string(SSL_get_error(conssl->handle, 0), error_buffer));
+#ifdef HAVE_ALPN
+  if(conn->bits.tls_enable_alpn) {
+    char protocols[128];
+    *protocols = '\0';
+
+    /* wolfSSL's ALPN protocol name list format is a comma separated string of
+       protocols in descending order of preference, eg: "h2,http/1.1" */
+
+#ifdef USE_NGHTTP2
+    if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
+      strcpy(protocols + strlen(protocols), NGHTTP2_PROTO_VERSION_ID ",");
+      infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
+    }
+#endif
+
+    strcpy(protocols + strlen(protocols), ALPN_HTTP_1_1);
+    infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1);
+
+    if(wolfSSL_UseALPN(conssl->handle, protocols,
+                       (unsigned)strlen(protocols),
+                       WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) != SSL_SUCCESS) {
+      failf(data, "SSL: failed setting ALPN protocols");
       return CURLE_SSL_CONNECT_ERROR;
     }
-    /* Informational message */
-    infof (data, "SSL re-using session ID\n");
+  }
+#endif /* HAVE_ALPN */
+
+  /* Check if there's a cached ID we can/should use here! */
+  if(conn->ssl_config.sessionid) {
+    void *ssl_sessionid = NULL;
+
+    Curl_ssl_sessionid_lock(conn);
+    if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) {
+      /* we got a session id, use it! */
+      if(!SSL_set_session(conssl->handle, ssl_sessionid)) {
+        Curl_ssl_sessionid_unlock(conn);
+        failf(data, "SSL: SSL_set_session failed: %s",
+              ERR_error_string(SSL_get_error(conssl->handle, 0),
+              error_buffer));
+        return CURLE_SSL_CONNECT_ERROR;
+      }
+      /* Informational message */
+      infof (data, "SSL re-using session ID\n");
+    }
+    Curl_ssl_sessionid_unlock(conn);
   }
 
   /* pass the raw socket into the SSL layer */
@@ -330,7 +412,7 @@ cyassl_connect_step2(struct connectdata *conn,
                      int sockindex)
 {
   int ret = -1;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct ssl_connect_data* conssl = &conn->ssl[sockindex];
 
   conn->recv[sockindex] = cyassl_recv;
@@ -406,6 +488,7 @@ cyassl_connect_step2(struct connectdata *conn,
   }
 
   if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) {
+#ifdef KEEP_PEER_CERT
     X509 *x509;
     const char *x509_der;
     int x509_der_len;
@@ -434,14 +517,54 @@ cyassl_connect_step2(struct connectdata *conn,
       return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
     }
 
-    result = Curl_pin_peer_pubkey(data->set.str[STRING_SSL_PINNEDPUBLICKEY],
+    result = Curl_pin_peer_pubkey(data,
+                                  data->set.str[STRING_SSL_PINNEDPUBLICKEY],
                                   (const unsigned char *)pubkey->header,
                                   (size_t)(pubkey->end - pubkey->header));
     if(result) {
       failf(data, "SSL: public key does not match pinned public key!");
       return result;
     }
+#else
+    failf(data, "Library lacks pinning support built-in");
+    return CURLE_NOT_BUILT_IN;
+#endif
+  }
+
+#ifdef HAVE_ALPN
+  if(conn->bits.tls_enable_alpn) {
+    int rc;
+    char *protocol = NULL;
+    unsigned short protocol_len = 0;
+
+    rc = wolfSSL_ALPN_GetProtocol(conssl->handle, &protocol, &protocol_len);
+
+    if(rc == SSL_SUCCESS) {
+      infof(data, "ALPN, server accepted to use %.*s\n", protocol_len,
+            protocol);
+
+      if(protocol_len == ALPN_HTTP_1_1_LENGTH &&
+         !memcmp(protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH))
+        conn->negnpn = CURL_HTTP_VERSION_1_1;
+#ifdef USE_NGHTTP2
+      else if(data->set.httpversion >= CURL_HTTP_VERSION_2 &&
+              protocol_len == NGHTTP2_PROTO_VERSION_ID_LEN &&
+              !memcmp(protocol, NGHTTP2_PROTO_VERSION_ID,
+                      NGHTTP2_PROTO_VERSION_ID_LEN))
+        conn->negnpn = CURL_HTTP_VERSION_2;
+#endif
+      else
+        infof(data, "ALPN, unrecognized protocol %.*s\n", protocol_len,
+              protocol);
+    }
+    else if(rc == SSL_ALPN_NOT_FOUND)
+      infof(data, "ALPN, server did not agree to a protocol\n");
+    else {
+      failf(data, "ALPN, failure getting protocol, error %d", rc);
+      return CURLE_SSL_CONNECT_ERROR;
+    }
   }
+#endif /* HAVE_ALPN */
 
   conssl->connecting_state = ssl_connect_3;
   infof(data, "SSL connected\n");
@@ -455,32 +578,38 @@ cyassl_connect_step3(struct connectdata *conn,
                      int sockindex)
 {
   CURLcode result = CURLE_OK;
-  void *old_ssl_sessionid=NULL;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-  bool incache;
-  SSL_SESSION *our_ssl_sessionid;
 
   DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
 
-  our_ssl_sessionid = SSL_get_session(connssl->handle);
+  if(conn->ssl_config.sessionid) {
+    bool incache;
+    SSL_SESSION *our_ssl_sessionid;
+    void *old_ssl_sessionid = NULL;
+
+    our_ssl_sessionid = SSL_get_session(connssl->handle);
 
-  incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL));
-  if(incache) {
-    if(old_ssl_sessionid != our_ssl_sessionid) {
-      infof(data, "old SSL session ID is stale, removing\n");
-      Curl_ssl_delsessionid(conn, old_ssl_sessionid);
-      incache = FALSE;
+    Curl_ssl_sessionid_lock(conn);
+    incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL));
+    if(incache) {
+      if(old_ssl_sessionid != our_ssl_sessionid) {
+        infof(data, "old SSL session ID is stale, removing\n");
+        Curl_ssl_delsessionid(conn, old_ssl_sessionid);
+        incache = FALSE;
+      }
     }
-  }
 
-  if(!incache) {
-    result = Curl_ssl_addsessionid(conn, our_ssl_sessionid,
-                                   0 /* unknown size */);
-    if(result) {
-      failf(data, "failed to store ssl session");
-      return result;
+    if(!incache) {
+      result = Curl_ssl_addsessionid(conn, our_ssl_sessionid,
+                                     0 /* unknown size */);
+      if(result) {
+        Curl_ssl_sessionid_unlock(conn);
+        failf(data, "failed to store ssl session");
+        return result;
+      }
     }
+    Curl_ssl_sessionid_unlock(conn);
   }
 
   connssl->connecting_state = ssl_connect_done;
@@ -625,7 +754,7 @@ cyassl_connect_common(struct connectdata *conn,
                       bool *done)
 {
   CURLcode result;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   curl_socket_t sockfd = conn->sock[sockindex];
   long timeout_ms;
@@ -756,7 +885,7 @@ Curl_cyassl_connect(struct connectdata *conn,
   return CURLE_OK;
 }
 
-int Curl_cyassl_random(struct SessionHandle *data,
+int Curl_cyassl_random(struct Curl_easy *data,
                        unsigned char *entropy,
                        size_t length)
 {
@@ -779,7 +908,7 @@ void Curl_cyassl_sha256sum(const unsigned char *tmp, /* input */
   Sha256 SHA256pw;
   (void)unused;
   InitSha256(&SHA256pw);
-  Sha256Update(&SHA256pw, tmp, tmplen);
+  Sha256Update(&SHA256pw, tmp, (word32)tmplen);
   Sha256Final(&SHA256pw, sha256sum);
 }
 
diff --git a/lib/vtls/cyassl.h b/lib/vtls/cyassl.h
index 167de74..508dfaa 100644
--- a/lib/vtls/cyassl.h
+++ b/lib/vtls/cyassl.h
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -25,6 +25,18 @@
 
 #ifdef USE_CYASSL
 
+/* KEEP_PEER_CERT is a product of the presence of build time symbol
+   OPENSSL_EXTRA without NO_CERTS, depending on the version. KEEP_PEER_CERT is
+   in wolfSSL's settings.h, and the latter two are build time symbols in
+   options.h. */
+#ifndef KEEP_PEER_CERT
+#if defined(HAVE_CYASSL_GET_PEER_CERTIFICATE) || \
+    defined(HAVE_WOLFSSL_GET_PEER_CERTIFICATE) || \
+    (defined(OPENSSL_EXTRA) && !defined(NO_CERTS))
+#define KEEP_PEER_CERT
+#endif
+#endif
+
 CURLcode Curl_cyassl_connect(struct connectdata *conn, int sockindex);
 bool Curl_cyassl_data_pending(const struct connectdata* conn, int connindex);
 int Curl_cyassl_shutdown(struct connectdata* conn, int sockindex);
@@ -39,7 +51,7 @@ int Curl_cyassl_init(void);
 CURLcode Curl_cyassl_connect_nonblocking(struct connectdata *conn,
                                          int sockindex,
                                          bool *done);
-int Curl_cyassl_random(struct SessionHandle *data,
+int Curl_cyassl_random(struct Curl_easy *data,
                        unsigned char *entropy,
                        size_t length);
 void Curl_cyassl_sha256sum(const unsigned char *tmp, /* input */
@@ -53,6 +65,11 @@ void Curl_cyassl_sha256sum(const unsigned char *tmp, /* input */
 /* this backend supports CURLOPT_SSL_CTX_* */
 #define have_curlssl_ssl_ctx 1
 
+#ifdef KEEP_PEER_CERT
+/* this backend supports CURLOPT_PINNEDPUBLICKEY */
+#define have_curlssl_pinnedpubkey 1
+#endif
+
 /* API setup for CyaSSL */
 #define curlssl_init Curl_cyassl_init
 #define curlssl_cleanup() Curl_nop_stmt
diff --git a/lib/vtls/darwinssl.c b/lib/vtls/darwinssl.c
index 03adcef..ebb9e30 100644
--- a/lib/vtls/darwinssl.c
+++ b/lib/vtls/darwinssl.c
@@ -10,7 +10,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -28,7 +28,7 @@
 
 #include "curl_setup.h"
 
-#include "urldata.h" /* for the SessionHandle definition */
+#include "urldata.h" /* for the Curl_easy definition */
 #include "curl_base64.h"
 #include "strtok.h"
 
@@ -781,7 +781,7 @@ CF_INLINE void GetDarwinVersionNumber(int *major, int *minor)
   int mib[2];
   char *os_version;
   size_t os_version_len;
-  char *os_version_major, *os_version_minor/*, *os_version_point*/;
+  char *os_version_major, *os_version_minor;
   char *tok_buf;
 
   /* Get the Darwin kernel version from the kernel using sysctl(): */
@@ -800,7 +800,6 @@ CF_INLINE void GetDarwinVersionNumber(int *major, int *minor)
   /* Parse the version: */
   os_version_major = strtok_r(os_version, ".", &tok_buf);
   os_version_minor = strtok_r(NULL, ".", &tok_buf);
-  /*os_version_point = strtok_r(NULL, ".", &tok_buf);*/
   *major = atoi(os_version_major);
   *minor = atoi(os_version_minor);
   free(os_version);
@@ -1000,7 +999,7 @@ CF_INLINE bool is_file(const char *filename)
 static CURLcode darwinssl_connect_step1(struct connectdata *conn,
                                         int sockindex)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   curl_socket_t sockfd = conn->sock[sockindex];
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
 #ifdef ENABLE_IPV6
@@ -1010,8 +1009,6 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
 #endif /* ENABLE_IPV6 */
   size_t all_ciphers_count = 0UL, allowed_ciphers_count = 0UL, i;
   SSLCipherSuite *all_ciphers = NULL, *allowed_ciphers = NULL;
-  char *ssl_sessionid;
-  size_t ssl_sessionid_len;
   OSStatus err = noErr;
 #if CURL_BUILD_MAC
   int darwinver_maj = 0, darwinver_min = 0;
@@ -1282,14 +1279,21 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
 #if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS
   /* Snow Leopard introduced the SSLSetSessionOption() function, but due to
      a library bug with the way the kSSLSessionOptionBreakOnServerAuth flag
-     works, it doesn't work as expected under Snow Leopard or Lion.
+     works, it doesn't work as expected under Snow Leopard, Lion or
+     Mountain Lion.
      So we need to call SSLSetEnableCertVerify() on those older cats in order
      to disable certificate validation if the user turned that off.
      (SecureTransport will always validate the certificate chain by
-     default.) */
-  /* (Note: Darwin 12.x.x is Mountain Lion.) */
+     default.)
+  Note:
+  Darwin 11.x.x is Lion (10.7)
+  Darwin 12.x.x is Mountain Lion (10.8)
+  Darwin 13.x.x is Mavericks (10.9)
+  Darwin 14.x.x is Yosemite (10.10)
+  Darwin 15.x.x is El Capitan (10.11)
+  */
 #if CURL_BUILD_MAC
-  if(SSLSetSessionOption != NULL && darwinver_maj >= 12) {
+  if(SSLSetSessionOption != NULL && darwinver_maj >= 13) {
 #else
   if(SSLSetSessionOption != NULL) {
 #endif /* CURL_BUILD_MAC */
@@ -1468,37 +1472,46 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
 #endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */
 
   /* Check if there's a cached ID we can/should use here! */
-  if(!Curl_ssl_getsessionid(conn, (void **)&ssl_sessionid,
-                            &ssl_sessionid_len)) {
-    /* we got a session id, use it! */
-    err = SSLSetPeerID(connssl->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
-    if(err != noErr) {
-      failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err);
-      return CURLE_SSL_CONNECT_ERROR;
-    }
-    /* Informational message */
-    infof(data, "SSL re-using session ID\n");
-  }
-  /* If there isn't one, then let's make one up! This has to be done prior
-     to starting the handshake. */
-  else {
-    CURLcode result;
-    ssl_sessionid =
-      aprintf("%s:%d:%d:%s:%hu", data->set.str[STRING_SSL_CAFILE],
-              data->set.ssl.verifypeer, data->set.ssl.verifyhost,
-              conn->host.name, conn->remote_port);
-    ssl_sessionid_len = strlen(ssl_sessionid);
-
-    err = SSLSetPeerID(connssl->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
-    if(err != noErr) {
-      failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err);
-      return CURLE_SSL_CONNECT_ERROR;
+  if(conn->ssl_config.sessionid) {
+    char *ssl_sessionid;
+    size_t ssl_sessionid_len;
+
+    Curl_ssl_sessionid_lock(conn);
+    if(!Curl_ssl_getsessionid(conn, (void **)&ssl_sessionid,
+                              &ssl_sessionid_len)) {
+      /* we got a session id, use it! */
+      err = SSLSetPeerID(connssl->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
+      Curl_ssl_sessionid_unlock(conn);
+      if(err != noErr) {
+        failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err);
+        return CURLE_SSL_CONNECT_ERROR;
+      }
+      /* Informational message */
+      infof(data, "SSL re-using session ID\n");
     }
+    /* If there isn't one, then let's make one up! This has to be done prior
+       to starting the handshake. */
+    else {
+      CURLcode result;
+      ssl_sessionid =
+        aprintf("%s:%d:%d:%s:%hu", data->set.str[STRING_SSL_CAFILE],
+                data->set.ssl.verifypeer, data->set.ssl.verifyhost,
+                conn->host.name, conn->remote_port);
+      ssl_sessionid_len = strlen(ssl_sessionid);
+
+      err = SSLSetPeerID(connssl->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
+      if(err != noErr) {
+        Curl_ssl_sessionid_unlock(conn);
+        failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err);
+        return CURLE_SSL_CONNECT_ERROR;
+      }
 
-    result = Curl_ssl_addsessionid(conn, ssl_sessionid, ssl_sessionid_len);
-    if(result) {
-      failf(data, "failed to store ssl session");
-      return result;
+      result = Curl_ssl_addsessionid(conn, ssl_sessionid, ssl_sessionid_len);
+      Curl_ssl_sessionid_unlock(conn);
+      if(result) {
+        failf(data, "failed to store ssl session");
+        return result;
+      }
     }
   }
 
@@ -1620,7 +1633,7 @@ static int read_cert(const char *file, unsigned char **out, size_t *outlen)
   return 0;
 }
 
-static int sslerr_to_curlerr(struct SessionHandle *data, int err)
+static int sslerr_to_curlerr(struct Curl_easy *data, int err)
 {
   switch(err) {
     case errSSLXCertChainInvalid:
@@ -1649,7 +1662,7 @@ static int sslerr_to_curlerr(struct SessionHandle *data, int err)
   }
 }
 
-static int append_cert_to_array(struct SessionHandle *data,
+static int append_cert_to_array(struct Curl_easy *data,
                                 unsigned char *buf, size_t buflen,
                                 CFMutableArrayRef array)
 {
@@ -1694,7 +1707,7 @@ static int append_cert_to_array(struct SessionHandle *data,
     return CURLE_OK;
 }
 
-static int verify_cert(const char *cafile, struct SessionHandle *data,
+static int verify_cert(const char *cafile, struct Curl_easy *data,
                        SSLContextRef ctx)
 {
   int n = 0, rc;
@@ -1814,7 +1827,7 @@ static int verify_cert(const char *cafile, struct SessionHandle *data,
 static CURLcode
 darwinssl_connect_step2(struct connectdata *conn, int sockindex)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   OSStatus err;
   SSLCipherSuite cipher;
@@ -1954,7 +1967,7 @@ static CURLcode
 darwinssl_connect_step3(struct connectdata *conn,
                         int sockindex)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   CFStringRef server_cert_summary;
   char server_cert_summary_c[128];
@@ -2078,7 +2091,7 @@ darwinssl_connect_common(struct connectdata *conn,
                          bool *done)
 {
   CURLcode result;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   curl_socket_t sockfd = conn->sock[sockindex];
   long timeout_ms;
@@ -2233,7 +2246,7 @@ void Curl_darwinssl_close(struct connectdata *conn, int sockindex)
 int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex)
 {
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   ssize_t nread;
   int what;
   int rc;
@@ -2381,7 +2394,7 @@ static ssize_t darwinssl_send(struct connectdata *conn,
                               size_t len,
                               CURLcode *curlcode)
 {
-  /*struct SessionHandle *data = conn->data;*/
+  /*struct Curl_easy *data = conn->data;*/
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   size_t processed = 0UL;
   OSStatus err;
@@ -2447,7 +2460,7 @@ static ssize_t darwinssl_recv(struct connectdata *conn,
                               size_t buffersize,
                               CURLcode *curlcode)
 {
-  /*struct SessionHandle *data = conn->data;*/
+  /*struct Curl_easy *data = conn->data;*/
   struct ssl_connect_data *connssl = &conn->ssl[num];
   size_t processed = 0UL;
   OSStatus err = SSLRead(connssl->ssl_ctx, buf, buffersize, &processed);
diff --git a/lib/vtls/darwinssl.h b/lib/vtls/darwinssl.h
index 3bb69c0..8b185b6 100644
--- a/lib/vtls/darwinssl.h
+++ b/lib/vtls/darwinssl.h
@@ -12,7 +12,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/vtls/gskit.c b/lib/vtls/gskit.c
index d884bd4..55a55ef 100644
--- a/lib/vtls/gskit.c
+++ b/lib/vtls/gskit.c
@@ -9,7 +9,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -163,7 +163,7 @@ static bool is_separator(char c)
 }
 
 
-static CURLcode gskit_status(struct SessionHandle *data, int rc,
+static CURLcode gskit_status(struct Curl_easy *data, int rc,
                              const char *procname, CURLcode defcode)
 {
   /* Process GSKit status and map it to a CURLcode. */
@@ -206,7 +206,7 @@ static CURLcode gskit_status(struct SessionHandle *data, int rc,
 }
 
 
-static CURLcode set_enum(struct SessionHandle *data, gsk_handle h,
+static CURLcode set_enum(struct Curl_easy *data, gsk_handle h,
                 GSK_ENUM_ID id, GSK_ENUM_VALUE value, bool unsupported_ok)
 {
   int rc = gsk_attribute_set_enum(h, id, value);
@@ -228,7 +228,7 @@ static CURLcode set_enum(struct SessionHandle *data, gsk_handle h,
 }
 
 
-static CURLcode set_buffer(struct SessionHandle *data, gsk_handle h,
+static CURLcode set_buffer(struct Curl_easy *data, gsk_handle h,
                         GSK_BUF_ID id, const char *buffer, bool unsupported_ok)
 {
   int rc = gsk_attribute_set_buffer(h, id, buffer, 0);
@@ -250,7 +250,7 @@ static CURLcode set_buffer(struct SessionHandle *data, gsk_handle h,
 }
 
 
-static CURLcode set_numeric(struct SessionHandle *data,
+static CURLcode set_numeric(struct Curl_easy *data,
                             gsk_handle h, GSK_NUM_ID id, int value)
 {
   int rc = gsk_attribute_set_numeric_value(h, id, value);
@@ -270,7 +270,7 @@ static CURLcode set_numeric(struct SessionHandle *data,
 }
 
 
-static CURLcode set_callback(struct SessionHandle *data,
+static CURLcode set_callback(struct Curl_easy *data,
                              gsk_handle h, GSK_CALLBACK_ID id, void *info)
 {
   int rc = gsk_attribute_set_callback(h, id, info);
@@ -289,7 +289,7 @@ static CURLcode set_callback(struct SessionHandle *data,
 }
 
 
-static CURLcode set_ciphers(struct SessionHandle *data,
+static CURLcode set_ciphers(struct Curl_easy *data,
                                         gsk_handle h, unsigned int *protoflags)
 {
   const char *cipherlist = data->set.str[STRING_SSL_CIPHER_LIST];
@@ -436,7 +436,7 @@ void Curl_gskit_cleanup(void)
 }
 
 
-static CURLcode init_environment(struct SessionHandle *data,
+static CURLcode init_environment(struct Curl_easy *data,
                                  gsk_handle *envir, const char *appid,
                                  const char *file, const char *label,
                                  const char *password)
@@ -502,7 +502,7 @@ static void close_async_handshake(struct ssl_connect_data *connssl)
 
 
 static void close_one(struct ssl_connect_data *conn,
-                      struct SessionHandle *data)
+                      struct Curl_easy *data)
 {
   if(conn->handle) {
     gskit_status(data, gsk_secure_soc_close(&conn->handle),
@@ -517,7 +517,7 @@ static void close_one(struct ssl_connect_data *conn,
 static ssize_t gskit_send(struct connectdata *conn, int sockindex,
                            const void *mem, size_t len, CURLcode *curlcode)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   CURLcode cc;
   int written;
 
@@ -536,7 +536,7 @@ static ssize_t gskit_send(struct connectdata *conn, int sockindex,
 static ssize_t gskit_recv(struct connectdata *conn, int num, char *buf,
                            size_t buffersize, CURLcode *curlcode)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   int buffsize;
   int nread;
   CURLcode cc;
@@ -555,7 +555,7 @@ static ssize_t gskit_recv(struct connectdata *conn, int num, char *buf,
 
 static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   gsk_handle envir;
   CURLcode result;
@@ -750,7 +750,7 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
 static CURLcode gskit_connect_step2(struct connectdata *conn, int sockindex,
                                     bool nonblocking)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   Qso_OverlappedIO_t cstat;
   long timeout_ms;
@@ -801,7 +801,7 @@ static CURLcode gskit_connect_step2(struct connectdata *conn, int sockindex,
 
 static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   const gsk_cert_data_elem *cdev;
   int cdec;
@@ -874,7 +874,7 @@ static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex)
       return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
     Curl_parseX509(&x509, cert, certend);
     p = &x509.subjectPublicKeyInfo;
-    result = Curl_pin_peer_pubkey(ptr, p->header, p->end - p->header);
+    result = Curl_pin_peer_pubkey(data, ptr, p->header, p->end - p->header);
     if(result) {
       failf(data, "SSL: public key does not match pinned public key!");
       return result;
@@ -889,7 +889,7 @@ static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex)
 static CURLcode gskit_connect_common(struct connectdata *conn, int sockindex,
                                      bool nonblocking, bool *done)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   long timeout_ms;
   Qso_OverlappedIO_t cstat;
@@ -976,7 +976,7 @@ CURLcode Curl_gskit_connect(struct connectdata *conn, int sockindex)
 
 void Curl_gskit_close(struct connectdata *conn, int sockindex)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
 
   if(connssl->use)
@@ -987,7 +987,7 @@ void Curl_gskit_close(struct connectdata *conn, int sockindex)
 int Curl_gskit_shutdown(struct connectdata *conn, int sockindex)
 {
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   ssize_t nread;
   int what;
   int rc;
diff --git a/lib/vtls/gskit.h b/lib/vtls/gskit.h
index af31faf..41483cb 100644
--- a/lib/vtls/gskit.h
+++ b/lib/vtls/gskit.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c
index c54dfc1..1c3e6b1 100644
--- a/lib/vtls/gtls.c
+++ b/lib/vtls/gtls.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -62,7 +62,7 @@
 
 /*
  Some hackish cast macros based on:
- http://library.gnome.org/devel/glib/unstable/glib-Type-Conversion-Macros.html
+ https://developer.gnome.org/glib/unstable/glib-Type-Conversion-Macros.html
 */
 #ifndef GNUTLS_POINTER_TO_INT_CAST
 #define GNUTLS_POINTER_TO_INT_CAST(p) ((int) (long) (p))
@@ -201,7 +201,7 @@ int Curl_gtls_cleanup(void)
   return 1;
 }
 
-static void showtime(struct SessionHandle *data,
+static void showtime(struct Curl_easy *data,
                      const char *text,
                      time_t stamp)
 {
@@ -262,7 +262,7 @@ static CURLcode handshake(struct connectdata *conn,
                           bool duringconnect,
                           bool nonblocking)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   gnutls_session_t session = conn->ssl[sockindex].session;
   curl_socket_t sockfd = conn->sock[sockindex];
@@ -367,11 +367,9 @@ static CURLcode
 gtls_connect_step1(struct connectdata *conn,
                    int sockindex)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   gnutls_session_t session;
   int rc;
-  void *ssl_sessionid;
-  size_t ssl_idsize;
   bool sni = TRUE; /* default is SNI enabled */
 #ifdef ENABLE_IPV6
   struct in6_addr addr;
@@ -487,6 +485,14 @@ gtls_connect_step1(struct connectdata *conn,
   }
 #endif
 
+#ifdef CURL_CA_FALLBACK
+  /* use system ca certificate store as fallback */
+  if(data->set.ssl.verifypeer &&
+     !(data->set.ssl.CAfile || data->set.ssl.CApath)) {
+    gnutls_certificate_set_x509_system_trust(conn->ssl[sockindex].cred);
+  }
+#endif
+
   if(data->set.ssl.CRLfile) {
     /* set the CRL list file */
     rc = gnutls_certificate_set_x509_crl_file(conn->ssl[sockindex].cred,
@@ -633,12 +639,12 @@ gtls_connect_step1(struct connectdata *conn,
 #endif
 
 #ifdef HAS_ALPN
-  if(data->set.ssl_enable_alpn) {
+  if(conn->bits.tls_enable_alpn) {
     int cur = 0;
     gnutls_datum_t protocols[2];
 
 #ifdef USE_NGHTTP2
-    if(data->set.httpversion == CURL_HTTP_VERSION_2_0) {
+    if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
       protocols[cur].data = (unsigned char *)NGHTTP2_PROTO_VERSION_ID;
       protocols[cur].size = NGHTTP2_PROTO_VERSION_ID_LEN;
       cur++;
@@ -656,15 +662,44 @@ gtls_connect_step1(struct connectdata *conn,
 #endif
 
   if(data->set.str[STRING_CERT]) {
-    if(gnutls_certificate_set_x509_key_file(
-         conn->ssl[sockindex].cred,
-         data->set.str[STRING_CERT],
-         data->set.str[STRING_KEY] ?
-         data->set.str[STRING_KEY] : data->set.str[STRING_CERT],
-         do_file_type(data->set.str[STRING_CERT_TYPE]) ) !=
-       GNUTLS_E_SUCCESS) {
-      failf(data, "error reading X.509 key or certificate file");
+    if(data->set.str[STRING_KEY_PASSWD]) {
+#if HAVE_GNUTLS_CERTIFICATE_SET_X509_KEY_FILE2
+      const unsigned int supported_key_encryption_algorithms =
+        GNUTLS_PKCS_USE_PKCS12_3DES | GNUTLS_PKCS_USE_PKCS12_ARCFOUR |
+        GNUTLS_PKCS_USE_PKCS12_RC2_40 | GNUTLS_PKCS_USE_PBES2_3DES |
+        GNUTLS_PKCS_USE_PBES2_AES_128 | GNUTLS_PKCS_USE_PBES2_AES_192 |
+        GNUTLS_PKCS_USE_PBES2_AES_256;
+      rc = gnutls_certificate_set_x509_key_file2(
+           conn->ssl[sockindex].cred,
+           data->set.str[STRING_CERT],
+           data->set.str[STRING_KEY] ?
+           data->set.str[STRING_KEY] : data->set.str[STRING_CERT],
+           do_file_type(data->set.str[STRING_CERT_TYPE]),
+           data->set.str[STRING_KEY_PASSWD],
+           supported_key_encryption_algorithms);
+      if(rc != GNUTLS_E_SUCCESS) {
+        failf(data,
+              "error reading X.509 potentially-encrypted key file: %s",
+              gnutls_strerror(rc));
+        return CURLE_SSL_CONNECT_ERROR;
+      }
+#else
+      failf(data, "gnutls lacks support for encrypted key files");
       return CURLE_SSL_CONNECT_ERROR;
+#endif
+    }
+    else {
+      rc = gnutls_certificate_set_x509_key_file(
+           conn->ssl[sockindex].cred,
+           data->set.str[STRING_CERT],
+           data->set.str[STRING_KEY] ?
+           data->set.str[STRING_KEY] : data->set.str[STRING_CERT],
+           do_file_type(data->set.str[STRING_CERT_TYPE]) );
+      if(rc != GNUTLS_E_SUCCESS) {
+        failf(data, "error reading X.509 key or certificate file: %s",
+              gnutls_strerror(rc));
+        return CURLE_SSL_CONNECT_ERROR;
+      }
     }
   }
 
@@ -712,19 +747,26 @@ gtls_connect_step1(struct connectdata *conn,
 
   /* This might be a reconnect, so we check for a session ID in the cache
      to speed up things */
+  if(conn->ssl_config.sessionid) {
+    void *ssl_sessionid;
+    size_t ssl_idsize;
 
-  if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize)) {
-    /* we got a session id, use it! */
-    gnutls_session_set_data(session, ssl_sessionid, ssl_idsize);
+    Curl_ssl_sessionid_lock(conn);
+    if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize)) {
+      /* we got a session id, use it! */
+      gnutls_session_set_data(session, ssl_sessionid, ssl_idsize);
 
-    /* Informational message */
-    infof (data, "SSL re-using session ID\n");
+      /* Informational message */
+      infof (data, "SSL re-using session ID\n");
+    }
+    Curl_ssl_sessionid_unlock(conn);
   }
 
   return CURLE_OK;
 }
 
-static CURLcode pkp_pin_peer_pubkey(gnutls_x509_crt_t cert,
+static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
+                                    gnutls_x509_crt_t cert,
                                     const char *pinnedpubkey)
 {
   /* Scratch */
@@ -769,7 +811,7 @@ static CURLcode pkp_pin_peer_pubkey(gnutls_x509_crt_t cert,
     /* End Gyrations */
 
     /* The one good exit point */
-    result = Curl_pin_peer_pubkey(pinnedpubkey, buff1, len1);
+    result = Curl_pin_peer_pubkey(data, pinnedpubkey, buff1, len1);
   } while(0);
 
   if(NULL != key)
@@ -798,11 +840,9 @@ gtls_connect_step3(struct connectdata *conn,
   unsigned int bits;
   time_t certclock;
   const char *ptr;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   gnutls_session_t session = conn->ssl[sockindex].session;
   int rc;
-  bool incache;
-  void *ssl_sessionid;
 #ifdef HAS_ALPN
   gnutls_datum_t proto;
 #endif
@@ -1152,7 +1192,7 @@ gtls_connect_step3(struct connectdata *conn,
 
   ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
   if(ptr) {
-    result = pkp_pin_peer_pubkey(x509_cert, ptr);
+    result = pkp_pin_peer_pubkey(data, x509_cert, ptr);
     if(result != CURLE_OK) {
       failf(data, "SSL: public key does not match pinned public key!");
       gnutls_x509_crt_deinit(x509_cert);
@@ -1202,7 +1242,7 @@ gtls_connect_step3(struct connectdata *conn,
   infof(data, "\t compression: %s\n", ptr);
 
 #ifdef HAS_ALPN
-  if(data->set.ssl_enable_alpn) {
+  if(conn->bits.tls_enable_alpn) {
     rc = gnutls_alpn_get_selected_protocol(session, &proto);
     if(rc == 0) {
       infof(data, "ALPN, server accepted to use %.*s\n", proto.size,
@@ -1212,7 +1252,7 @@ gtls_connect_step3(struct connectdata *conn,
       if(proto.size == NGHTTP2_PROTO_VERSION_ID_LEN &&
          !memcmp(NGHTTP2_PROTO_VERSION_ID, proto.data,
                  NGHTTP2_PROTO_VERSION_ID_LEN)) {
-        conn->negnpn = CURL_HTTP_VERSION_2_0;
+        conn->negnpn = CURL_HTTP_VERSION_2;
       }
       else
 #endif
@@ -1230,11 +1270,13 @@ gtls_connect_step3(struct connectdata *conn,
   conn->recv[sockindex] = gtls_recv;
   conn->send[sockindex] = gtls_send;
 
-  {
+  if(conn->ssl_config.sessionid) {
     /* we always unconditionally get the session id here, as even if we
        already got it from the cache and asked to use it in the connection, it
        might've been rejected and then a new one is in use now and we need to
        detect that. */
+    bool incache;
+    void *ssl_sessionid;
     void *connect_sessionid;
     size_t connect_idsize = 0;
 
@@ -1246,6 +1288,7 @@ gtls_connect_step3(struct connectdata *conn,
       /* extract session ID to the allocated buffer */
       gnutls_session_get_data(session, connect_sessionid, &connect_idsize);
 
+      Curl_ssl_sessionid_lock(conn);
       incache = !(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL));
       if(incache) {
         /* there was one before in the cache, so instead of risking that the
@@ -1255,6 +1298,7 @@ gtls_connect_step3(struct connectdata *conn,
 
       /* store this session id */
       result = Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize);
+      Curl_ssl_sessionid_unlock(conn);
       if(result) {
         free(connect_sessionid);
         result = CURLE_OUT_OF_MEMORY;
@@ -1343,7 +1387,7 @@ static ssize_t gtls_send(struct connectdata *conn,
 {
   ssize_t rc = gnutls_record_send(conn->ssl[sockindex].session, mem, len);
 
-  if(rc < 0 ) {
+  if(rc < 0) {
     *curlcode = (rc == GNUTLS_E_AGAIN)
       ? CURLE_AGAIN
       : CURLE_SEND_ERROR;
@@ -1387,7 +1431,7 @@ int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
 {
   ssize_t result;
   int retval = 0;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   int done = 0;
   char buf[120];
 
@@ -1500,7 +1544,7 @@ size_t Curl_gtls_version(char *buffer, size_t size)
 }
 
 #ifndef USE_GNUTLS_NETTLE
-static int Curl_gtls_seed(struct SessionHandle *data)
+static int Curl_gtls_seed(struct Curl_easy *data)
 {
   /* we have the "SSL is seeded" boolean static to prevent multiple
      time-consuming seedings in vain */
@@ -1524,7 +1568,7 @@ static int Curl_gtls_seed(struct SessionHandle *data)
 #endif
 
 /* data might be NULL! */
-int Curl_gtls_random(struct SessionHandle *data,
+int Curl_gtls_random(struct Curl_easy *data,
                      unsigned char *entropy,
                      size_t length)
 {
diff --git a/lib/vtls/gtls.h b/lib/vtls/gtls.h
index 0afd9b9..e0a95a7 100644
--- a/lib/vtls/gtls.h
+++ b/lib/vtls/gtls.h
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -41,7 +41,7 @@ void Curl_gtls_close(struct connectdata *conn, int sockindex);
 void Curl_gtls_session_free(void *ptr);
 size_t Curl_gtls_version(char *buffer, size_t size);
 int Curl_gtls_shutdown(struct connectdata *conn, int sockindex);
-int Curl_gtls_random(struct SessionHandle *data,
+int Curl_gtls_random(struct Curl_easy *data,
                      unsigned char *entropy,
                      size_t length);
 void Curl_gtls_md5sum(unsigned char *tmp, /* input */
@@ -64,6 +64,9 @@ bool Curl_gtls_cert_status_request(void);
 /* this backend supports CURLOPT_CERTINFO */
 #define have_curlssl_certinfo 1
 
+/* this backend supports CURLOPT_PINNEDPUBLICKEY */
+#define have_curlssl_pinnedpubkey 1
+
 /* API setup for GnuTLS */
 #define curlssl_init Curl_gtls_init
 #define curlssl_cleanup Curl_gtls_cleanup
diff --git a/lib/vtls/mbedtls.c b/lib/vtls/mbedtls.c
new file mode 100644
index 0000000..a1e7d23
--- /dev/null
+++ b/lib/vtls/mbedtls.c
@@ -0,0 +1,871 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2010 - 2011, Hoi-Ho Chan, <hoiho.chan at gmail.com>
+ * Copyright (C) 2012 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.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.
+ *
+ ***************************************************************************/
+
+/*
+ * Source file for all mbedTLS-specific code for the TLS/SSL layer. No code
+ * but vtls.c should ever call or use these functions.
+ *
+ */
+
+#include "curl_setup.h"
+
+#ifdef USE_MBEDTLS
+
+#include <mbedtls/net.h>
+#include <mbedtls/ssl.h>
+#include <mbedtls/certs.h>
+#include <mbedtls/x509.h>
+#include <mbedtls/version.h>
+
+#include <mbedtls/error.h>
+#include <mbedtls/entropy.h>
+#include <mbedtls/ctr_drbg.h>
+#include <mbedtls/sha256.h>
+
+#include "urldata.h"
+#include "sendf.h"
+#include "inet_pton.h"
+#include "mbedtls.h"
+#include "vtls.h"
+#include "parsedate.h"
+#include "connect.h" /* for the connect timeout */
+#include "select.h"
+#include "rawstr.h"
+#include "polarssl_threadlock.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* apply threading? */
+#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
+#define THREADING_SUPPORT
+#endif
+
+#if defined(THREADING_SUPPORT)
+static mbedtls_entropy_context entropy;
+
+static int entropy_init_initialized = 0;
+
+/* start of entropy_init_mutex() */
+static void entropy_init_mutex(mbedtls_entropy_context *ctx)
+{
+  /* lock 0 = entropy_init_mutex() */
+  Curl_polarsslthreadlock_lock_function(0);
+  if(entropy_init_initialized == 0) {
+    mbedtls_entropy_init(ctx);
+    entropy_init_initialized = 1;
+  }
+  Curl_polarsslthreadlock_unlock_function(0);
+}
+/* end of entropy_init_mutex() */
+
+/* start of entropy_func_mutex() */
+static int entropy_func_mutex(void *data, unsigned char *output, size_t len)
+{
+  int ret;
+  /* lock 1 = entropy_func_mutex() */
+  Curl_polarsslthreadlock_lock_function(1);
+  ret = mbedtls_entropy_func(data, output, len);
+  Curl_polarsslthreadlock_unlock_function(1);
+
+  return ret;
+}
+/* end of entropy_func_mutex() */
+
+#endif /* THREADING_SUPPORT */
+
+/* Define this to enable lots of debugging for mbedTLS */
+#undef MBEDTLS_DEBUG
+
+#ifdef MBEDTLS_DEBUG
+static void mbed_debug(void *context, int level, const char *f_name,
+                       int line_nb, const char *line)
+{
+  struct Curl_easy *data = NULL;
+
+  if(!context)
+    return;
+
+  data = (struct Curl_easy *)context;
+
+  infof(data, "%s", line);
+  (void) level;
+}
+#else
+#endif
+
+/* ALPN for http2? */
+#ifdef USE_NGHTTP2
+#  undef HAS_ALPN
+#  ifdef MBEDTLS_SSL_ALPN
+#    define HAS_ALPN
+#  endif
+#endif
+
+
+/*
+ *  profile
+ */
+const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_fr =
+{
+  /* Hashes from SHA-1 and above */
+  MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA1) |
+  MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_RIPEMD160) |
+  MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA224) |
+  MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256) |
+  MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA384) |
+  MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA512),
+  0xFFFFFFF, /* Any PK alg    */
+  0xFFFFFFF, /* Any curve     */
+  1024,      /* RSA min key len */
+};
+
+/* See https://tls.mbed.org/discussions/generic/
+   howto-determine-exact-buffer-len-for-mbedtls_pk_write_pubkey_der
+*/
+#define RSA_PUB_DER_MAX_BYTES   (38 + 2 * MBEDTLS_MPI_MAX_SIZE)
+#define ECP_PUB_DER_MAX_BYTES   (30 + 2 * MBEDTLS_ECP_MAX_BYTES)
+
+#define PUB_DER_MAX_BYTES   (RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \
+                             RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES)
+
+static Curl_recv mbed_recv;
+static Curl_send mbed_send;
+
+static CURLcode
+mbed_connect_step1(struct connectdata *conn,
+                   int sockindex)
+{
+  struct Curl_easy *data = conn->data;
+  struct ssl_connect_data* connssl = &conn->ssl[sockindex];
+
+  int ret = -1;
+  char errorbuf[128];
+  errorbuf[0]=0;
+
+  /* mbedTLS only supports SSLv3 and TLSv1 */
+  if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) {
+    failf(data, "mbedTLS does not support SSLv2");
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+#ifdef THREADING_SUPPORT
+  entropy_init_mutex(&entropy);
+  mbedtls_ctr_drbg_init(&connssl->ctr_drbg);
+
+  ret = mbedtls_ctr_drbg_seed(&connssl->ctr_drbg, entropy_func_mutex,
+                              &entropy, NULL, 0);
+  if(ret) {
+#ifdef MBEDTLS_ERROR_C
+    mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+#endif /* MBEDTLS_ERROR_C */
+    failf(data, "Failed - mbedTLS: ctr_drbg_init returned (-0x%04X) %s\n",
+          -ret, errorbuf);
+  }
+#else
+  mbedtls_entropy_init(&connssl->entropy);
+  mbedtls_ctr_drbg_init(&connssl->ctr_drbg);
+
+  ret = mbedtls_ctr_drbg_seed(&connssl->ctr_drbg, mbedtls_entropy_func,
+                              &connssl->entropy, NULL, 0);
+  if(ret) {
+#ifdef MBEDTLS_ERROR_C
+    mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+#endif /* MBEDTLS_ERROR_C */
+    failf(data, "Failed - mbedTLS: ctr_drbg_init returned (-0x%04X) %s\n",
+          -ret, errorbuf);
+  }
+#endif /* THREADING_SUPPORT */
+
+  /* Load the trusted CA */
+  mbedtls_x509_crt_init(&connssl->cacert);
+
+  if(data->set.str[STRING_SSL_CAFILE]) {
+    ret = mbedtls_x509_crt_parse_file(&connssl->cacert,
+                                      data->set.str[STRING_SSL_CAFILE]);
+
+    if(ret<0) {
+#ifdef MBEDTLS_ERROR_C
+      mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+#endif /* MBEDTLS_ERROR_C */
+      failf(data, "Error reading ca cert file %s - mbedTLS: (-0x%04X) %s",
+            data->set.str[STRING_SSL_CAFILE], -ret, errorbuf);
+
+      if(data->set.ssl.verifypeer)
+        return CURLE_SSL_CACERT_BADFILE;
+    }
+  }
+
+  if(data->set.str[STRING_SSL_CAPATH]) {
+    ret = mbedtls_x509_crt_parse_path(&connssl->cacert,
+                                      data->set.str[STRING_SSL_CAPATH]);
+
+    if(ret<0) {
+#ifdef MBEDTLS_ERROR_C
+      mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+#endif /* MBEDTLS_ERROR_C */
+      failf(data, "Error reading ca cert path %s - mbedTLS: (-0x%04X) %s",
+            data->set.str[STRING_SSL_CAPATH], -ret, errorbuf);
+
+      if(data->set.ssl.verifypeer)
+        return CURLE_SSL_CACERT_BADFILE;
+    }
+  }
+
+  /* Load the client certificate */
+  mbedtls_x509_crt_init(&connssl->clicert);
+
+  if(data->set.str[STRING_CERT]) {
+    ret = mbedtls_x509_crt_parse_file(&connssl->clicert,
+                                      data->set.str[STRING_CERT]);
+
+    if(ret) {
+#ifdef MBEDTLS_ERROR_C
+      mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+#endif /* MBEDTLS_ERROR_C */
+      failf(data, "Error reading client cert file %s - mbedTLS: (-0x%04X) %s",
+            data->set.str[STRING_CERT], -ret, errorbuf);
+
+      return CURLE_SSL_CERTPROBLEM;
+    }
+  }
+
+  /* Load the client private key */
+  mbedtls_pk_init(&connssl->pk);
+
+  if(data->set.str[STRING_KEY]) {
+    ret = mbedtls_pk_parse_keyfile(&connssl->pk, data->set.str[STRING_KEY],
+                                   data->set.str[STRING_KEY_PASSWD]);
+    if(ret == 0 && !mbedtls_pk_can_do(&connssl->pk, MBEDTLS_PK_RSA))
+      ret = MBEDTLS_ERR_PK_TYPE_MISMATCH;
+
+    if(ret) {
+#ifdef MBEDTLS_ERROR_C
+      mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+#endif /* MBEDTLS_ERROR_C */
+      failf(data, "Error reading private key %s - mbedTLS: (-0x%04X) %s",
+            data->set.str[STRING_KEY], -ret, errorbuf);
+
+      return CURLE_SSL_CERTPROBLEM;
+    }
+  }
+
+  /* Load the CRL */
+  mbedtls_x509_crl_init(&connssl->crl);
+
+  if(data->set.str[STRING_SSL_CRLFILE]) {
+    ret = mbedtls_x509_crl_parse_file(&connssl->crl,
+                                      data->set.str[STRING_SSL_CRLFILE]);
+
+    if(ret) {
+#ifdef MBEDTLS_ERROR_C
+      mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+#endif /* MBEDTLS_ERROR_C */
+      failf(data, "Error reading CRL file %s - mbedTLS: (-0x%04X) %s",
+            data->set.str[STRING_SSL_CRLFILE], -ret, errorbuf);
+
+      return CURLE_SSL_CRL_BADFILE;
+    }
+  }
+
+  infof(data, "mbedTLS: Connecting to %s:%d\n",
+        conn->host.name, conn->remote_port);
+
+  mbedtls_ssl_config_init(&connssl->config);
+
+  mbedtls_ssl_init(&connssl->ssl);
+  if(mbedtls_ssl_setup(&connssl->ssl, &connssl->config)) {
+    failf(data, "mbedTLS: ssl_init failed");
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+  ret = mbedtls_ssl_config_defaults(&connssl->config,
+                                    MBEDTLS_SSL_IS_CLIENT,
+                                    MBEDTLS_SSL_TRANSPORT_STREAM,
+                                    MBEDTLS_SSL_PRESET_DEFAULT);
+  if(ret) {
+    failf(data, "mbedTLS: ssl_config failed");
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  /* new profile with RSA min key len = 1024 ... */
+  mbedtls_ssl_conf_cert_profile(&connssl->config,
+                                &mbedtls_x509_crt_profile_fr);
+
+  switch(data->set.ssl.version) {
+  case CURL_SSLVERSION_DEFAULT:
+  case CURL_SSLVERSION_TLSv1:
+    mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
+                                 MBEDTLS_SSL_MINOR_VERSION_1);
+    infof(data, "mbedTLS: Set min SSL version to TLS 1.0\n");
+    break;
+  case CURL_SSLVERSION_SSLv3:
+    mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
+                                 MBEDTLS_SSL_MINOR_VERSION_0);
+    mbedtls_ssl_conf_max_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
+                                 MBEDTLS_SSL_MINOR_VERSION_0);
+    infof(data, "mbedTLS: Set SSL version to SSLv3\n");
+    break;
+  case CURL_SSLVERSION_TLSv1_0:
+    mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
+                                 MBEDTLS_SSL_MINOR_VERSION_1);
+    mbedtls_ssl_conf_max_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
+                                 MBEDTLS_SSL_MINOR_VERSION_1);
+    infof(data, "mbedTLS: Set SSL version to TLS 1.0\n");
+    break;
+  case CURL_SSLVERSION_TLSv1_1:
+    mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
+                                 MBEDTLS_SSL_MINOR_VERSION_2);
+    mbedtls_ssl_conf_max_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
+                                 MBEDTLS_SSL_MINOR_VERSION_2);
+    infof(data, "mbedTLS: Set SSL version to TLS 1.1\n");
+    break;
+  case CURL_SSLVERSION_TLSv1_2:
+    mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
+                                 MBEDTLS_SSL_MINOR_VERSION_3);
+    mbedtls_ssl_conf_max_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
+                                 MBEDTLS_SSL_MINOR_VERSION_3);
+    infof(data, "mbedTLS: Set SSL version to TLS 1.2\n");
+    break;
+  default:
+    failf(data, "mbedTLS: Unsupported SSL protocol version");
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  mbedtls_ssl_conf_authmode(&connssl->config, MBEDTLS_SSL_VERIFY_OPTIONAL);
+
+  mbedtls_ssl_conf_rng(&connssl->config, mbedtls_ctr_drbg_random,
+                       &connssl->ctr_drbg);
+  mbedtls_ssl_set_bio(&connssl->ssl, &conn->sock[sockindex],
+                      mbedtls_net_send,
+                      mbedtls_net_recv,
+                      NULL /*  rev_timeout() */);
+
+  mbedtls_ssl_conf_ciphersuites(&connssl->config,
+                                mbedtls_ssl_list_ciphersuites());
+
+  /* Check if there's a cached ID we can/should use here! */
+  if(conn->ssl_config.sessionid) {
+    void *old_session = NULL;
+
+    Curl_ssl_sessionid_lock(conn);
+    if(!Curl_ssl_getsessionid(conn, &old_session, NULL)) {
+      ret = mbedtls_ssl_set_session(&connssl->ssl, old_session);
+      if(ret) {
+        Curl_ssl_sessionid_unlock(conn);
+        failf(data, "mbedtls_ssl_set_session returned -0x%x", -ret);
+        return CURLE_SSL_CONNECT_ERROR;
+      }
+      infof(data, "mbedTLS re-using session\n");
+    }
+    Curl_ssl_sessionid_unlock(conn);
+  }
+
+  mbedtls_ssl_conf_ca_chain(&connssl->config,
+                            &connssl->cacert,
+                            &connssl->crl);
+
+  if(data->set.str[STRING_KEY]) {
+    mbedtls_ssl_conf_own_cert(&connssl->config,
+                              &connssl->clicert, &connssl->pk);
+  }
+  if(mbedtls_ssl_set_hostname(&connssl->ssl, conn->host.name)) {
+    /* mbedtls_ssl_set_hostname() sets the name to use in CN/SAN checks *and*
+       the name to set in the SNI extension. So even if curl connects to a
+       host specified as an IP address, this function must be used. */
+    failf(data, "couldn't set hostname in mbedTLS");
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+#ifdef HAS_ALPN
+  if(conn->bits.tls_enable_alpn) {
+    const char **p = &connssl->protocols[0];
+#ifdef USE_NGHTTP2
+    if(data->set.httpversion >= CURL_HTTP_VERSION_2)
+      *p++ = NGHTTP2_PROTO_VERSION_ID;
+#endif
+    *p++ = ALPN_HTTP_1_1;
+    *p = NULL;
+    /* this function doesn't clone the protocols array, which is why we need
+       to keep it around */
+    if(mbedtls_ssl_conf_alpn_protocols(&connssl->config,
+                                       &connssl->protocols[0])) {
+      failf(data, "Failed setting ALPN protocols");
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+    for(p = &connssl->protocols[0]; *p; ++p)
+      infof(data, "ALPN, offering %s\n", *p);
+  }
+#endif
+
+#ifdef MBEDTLS_DEBUG
+  mbedtls_ssl_conf_dbg(&connssl->config, mbed_debug, data);
+#endif
+
+  connssl->connecting_state = ssl_connect_2;
+
+  return CURLE_OK;
+}
+
+static CURLcode
+mbed_connect_step2(struct connectdata *conn,
+                   int sockindex)
+{
+  int ret;
+  struct Curl_easy *data = conn->data;
+  struct ssl_connect_data* connssl = &conn->ssl[sockindex];
+  const mbedtls_x509_crt *peercert;
+
+#ifdef HAS_ALPN
+  const char* next_protocol;
+#endif
+
+  char errorbuf[128];
+  errorbuf[0] = 0;
+
+  conn->recv[sockindex] = mbed_recv;
+  conn->send[sockindex] = mbed_send;
+
+  ret = mbedtls_ssl_handshake(&connssl->ssl);
+
+  if(ret == MBEDTLS_ERR_SSL_WANT_READ) {
+    connssl->connecting_state = ssl_connect_2_reading;
+    return CURLE_OK;
+  }
+  else if(ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
+    connssl->connecting_state = ssl_connect_2_writing;
+    return CURLE_OK;
+  }
+  else if(ret) {
+#ifdef MBEDTLS_ERROR_C
+    mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+#endif /* MBEDTLS_ERROR_C */
+    failf(data, "ssl_handshake returned - mbedTLS: (-0x%04X) %s",
+          -ret, errorbuf);
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  infof(data, "mbedTLS: Handshake complete, cipher is %s\n",
+        mbedtls_ssl_get_ciphersuite(&conn->ssl[sockindex].ssl)
+    );
+
+  ret = mbedtls_ssl_get_verify_result(&conn->ssl[sockindex].ssl);
+
+  if(ret && data->set.ssl.verifypeer) {
+    if(ret & MBEDTLS_X509_BADCERT_EXPIRED)
+      failf(data, "Cert verify failed: BADCERT_EXPIRED");
+
+    if(ret & MBEDTLS_X509_BADCERT_REVOKED) {
+      failf(data, "Cert verify failed: BADCERT_REVOKED");
+      return CURLE_SSL_CACERT;
+    }
+
+    if(ret & MBEDTLS_X509_BADCERT_CN_MISMATCH)
+      failf(data, "Cert verify failed: BADCERT_CN_MISMATCH");
+
+    if(ret & MBEDTLS_X509_BADCERT_NOT_TRUSTED)
+      failf(data, "Cert verify failed: BADCERT_NOT_TRUSTED");
+
+    return CURLE_PEER_FAILED_VERIFICATION;
+  }
+
+  peercert = mbedtls_ssl_get_peer_cert(&connssl->ssl);
+
+  if(peercert && data->set.verbose) {
+    const size_t bufsize = 16384;
+    char *buffer = malloc(bufsize);
+
+    if(!buffer)
+      return CURLE_OUT_OF_MEMORY;
+
+    if(mbedtls_x509_crt_info(buffer, bufsize, "* ", peercert) > 0)
+      infof(data, "Dumping cert info:\n%s\n", buffer);
+    else
+      infof(data, "Unable to dump certificate information.\n");
+
+    free(buffer);
+  }
+
+  if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) {
+    int size;
+    CURLcode result;
+    mbedtls_x509_crt *p;
+    unsigned char pubkey[PUB_DER_MAX_BYTES];
+
+    if(!peercert || !peercert->raw.p || !peercert->raw.len) {
+      failf(data, "Failed due to missing peer certificate");
+      return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+    }
+
+    p = calloc(1, sizeof(*p));
+
+    if(!p)
+      return CURLE_OUT_OF_MEMORY;
+
+    mbedtls_x509_crt_init(p);
+
+    /* Make a copy of our const peercert because mbedtls_pk_write_pubkey_der
+       needs a non-const key, for now.
+       https://github.com/ARMmbed/mbedtls/issues/396 */
+    if(mbedtls_x509_crt_parse_der(p, peercert->raw.p, peercert->raw.len)) {
+      failf(data, "Failed copying peer certificate");
+      mbedtls_x509_crt_free(p);
+      free(p);
+      return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+    }
+
+    size = mbedtls_pk_write_pubkey_der(&p->pk, pubkey, PUB_DER_MAX_BYTES);
+
+    if(size <= 0) {
+      failf(data, "Failed copying public key from peer certificate");
+      mbedtls_x509_crt_free(p);
+      free(p);
+      return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+    }
+
+    /* mbedtls_pk_write_pubkey_der writes data at the end of the buffer. */
+    result = Curl_pin_peer_pubkey(data,
+                                  data->set.str[STRING_SSL_PINNEDPUBLICKEY],
+                                  &pubkey[PUB_DER_MAX_BYTES - size], size);
+    if(result) {
+      mbedtls_x509_crt_free(p);
+      free(p);
+      return result;
+    }
+
+    mbedtls_x509_crt_free(p);
+    free(p);
+  }
+
+#ifdef HAS_ALPN
+  if(conn->bits.tls_enable_alpn) {
+    next_protocol = mbedtls_ssl_get_alpn_protocol(&connssl->ssl);
+
+    if(next_protocol) {
+      infof(data, "ALPN, server accepted to use %s\n", next_protocol);
+#ifdef USE_NGHTTP2
+      if(!strncmp(next_protocol, NGHTTP2_PROTO_VERSION_ID,
+                  NGHTTP2_PROTO_VERSION_ID_LEN) &&
+         !next_protocol[NGHTTP2_PROTO_VERSION_ID_LEN]) {
+        conn->negnpn = CURL_HTTP_VERSION_2;
+      }
+      else
+#endif
+        if(!strncmp(next_protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH) &&
+           !next_protocol[ALPN_HTTP_1_1_LENGTH]) {
+          conn->negnpn = CURL_HTTP_VERSION_1_1;
+        }
+    }
+    else {
+      infof(data, "ALPN, server did not agree to a protocol\n");
+    }
+  }
+#endif
+
+  connssl->connecting_state = ssl_connect_3;
+  infof(data, "SSL connected\n");
+
+  return CURLE_OK;
+}
+
+static CURLcode
+mbed_connect_step3(struct connectdata *conn,
+                   int sockindex)
+{
+  CURLcode retcode = CURLE_OK;
+  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+  struct Curl_easy *data = conn->data;
+
+  DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
+
+  if(conn->ssl_config.sessionid) {
+    int ret;
+    mbedtls_ssl_session *our_ssl_sessionid;
+    void *old_ssl_sessionid = NULL;
+
+    our_ssl_sessionid = malloc(sizeof(mbedtls_ssl_session));
+    if(!our_ssl_sessionid)
+      return CURLE_OUT_OF_MEMORY;
+
+    mbedtls_ssl_session_init(our_ssl_sessionid);
+
+    ret = mbedtls_ssl_get_session(&connssl->ssl, our_ssl_sessionid);
+    if(ret) {
+      failf(data, "mbedtls_ssl_get_session returned -0x%x", -ret);
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+
+    /* If there's already a matching session in the cache, delete it */
+    Curl_ssl_sessionid_lock(conn);
+    if(!Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL))
+      Curl_ssl_delsessionid(conn, old_ssl_sessionid);
+
+    retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, 0);
+    Curl_ssl_sessionid_unlock(conn);
+    if(retcode) {
+      free(our_ssl_sessionid);
+      failf(data, "failed to store ssl session");
+      return retcode;
+    }
+  }
+
+  connssl->connecting_state = ssl_connect_done;
+
+  return CURLE_OK;
+}
+
+static ssize_t mbed_send(struct connectdata *conn, int sockindex,
+                         const void *mem, size_t len,
+                         CURLcode *curlcode)
+{
+  int ret = -1;
+
+  ret = mbedtls_ssl_write(&conn->ssl[sockindex].ssl,
+                          (unsigned char *)mem, len);
+
+  if(ret < 0) {
+    *curlcode = (ret == MBEDTLS_ERR_SSL_WANT_WRITE) ?
+      CURLE_AGAIN : CURLE_SEND_ERROR;
+    ret = -1;
+  }
+
+  return ret;
+}
+
+void Curl_mbedtls_close_all(struct Curl_easy *data)
+{
+  (void)data;
+}
+
+void Curl_mbedtls_close(struct connectdata *conn, int sockindex)
+{
+  mbedtls_pk_free(&conn->ssl[sockindex].pk);
+  mbedtls_x509_crt_free(&conn->ssl[sockindex].clicert);
+  mbedtls_x509_crt_free(&conn->ssl[sockindex].cacert);
+  mbedtls_x509_crl_free(&conn->ssl[sockindex].crl);
+  mbedtls_ssl_config_free(&conn->ssl[sockindex].config);
+  mbedtls_ssl_free(&conn->ssl[sockindex].ssl);
+  mbedtls_ctr_drbg_free(&conn->ssl[sockindex].ctr_drbg);
+#ifndef THREADING_SUPPORT
+  mbedtls_entropy_free(&conn->ssl[sockindex].entropy);
+#endif /* THREADING_SUPPORT */
+}
+
+static ssize_t mbed_recv(struct connectdata *conn, int num,
+                         char *buf, size_t buffersize,
+                         CURLcode *curlcode)
+{
+  int ret = -1;
+  ssize_t len = -1;
+
+  memset(buf, 0, buffersize);
+  ret = mbedtls_ssl_read(&conn->ssl[num].ssl, (unsigned char *)buf,
+                         buffersize);
+
+  if(ret <= 0) {
+    if(ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY)
+      return 0;
+
+    *curlcode = (ret == MBEDTLS_ERR_SSL_WANT_READ) ?
+      CURLE_AGAIN : CURLE_RECV_ERROR;
+    return -1;
+  }
+
+  len = ret;
+
+  return len;
+}
+
+void Curl_mbedtls_session_free(void *ptr)
+{
+  mbedtls_ssl_session_free(ptr);
+  free(ptr);
+}
+
+size_t Curl_mbedtls_version(char *buffer, size_t size)
+{
+  unsigned int version = mbedtls_version_get_number();
+  return snprintf(buffer, size, "mbedTLS/%d.%d.%d", version>>24,
+                  (version>>16)&0xff, (version>>8)&0xff);
+}
+
+static CURLcode
+mbed_connect_common(struct connectdata *conn,
+                    int sockindex,
+                    bool nonblocking,
+                    bool *done)
+{
+  CURLcode retcode;
+  struct Curl_easy *data = conn->data;
+  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+  curl_socket_t sockfd = conn->sock[sockindex];
+  long timeout_ms;
+  int what;
+
+  /* check if the connection has already been established */
+  if(ssl_connection_complete == connssl->state) {
+    *done = TRUE;
+    return CURLE_OK;
+  }
+
+  if(ssl_connect_1==connssl->connecting_state) {
+    /* Find out how much more time we're allowed */
+    timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+    if(timeout_ms < 0) {
+      /* no need to continue if time already is up */
+      failf(data, "SSL connection timeout");
+      return CURLE_OPERATION_TIMEDOUT;
+    }
+    retcode = mbed_connect_step1(conn, sockindex);
+    if(retcode)
+      return retcode;
+  }
+
+  while(ssl_connect_2 == connssl->connecting_state ||
+        ssl_connect_2_reading == connssl->connecting_state ||
+        ssl_connect_2_writing == connssl->connecting_state) {
+
+    /* check allowed time left */
+    timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+    if(timeout_ms < 0) {
+      /* no need to continue if time already is up */
+      failf(data, "SSL connection timeout");
+      return CURLE_OPERATION_TIMEDOUT;
+    }
+
+    /* if ssl is expecting something, check if it's available. */
+    if(connssl->connecting_state == ssl_connect_2_reading
+       || connssl->connecting_state == ssl_connect_2_writing) {
+
+      curl_socket_t writefd = ssl_connect_2_writing==
+        connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+      curl_socket_t readfd = ssl_connect_2_reading==
+        connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+
+      what = Curl_socket_ready(readfd, writefd, nonblocking ? 0 : timeout_ms);
+      if(what < 0) {
+        /* fatal error */
+        failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+        return CURLE_SSL_CONNECT_ERROR;
+      }
+      else if(0 == what) {
+        if(nonblocking) {
+          *done = FALSE;
+          return CURLE_OK;
+        }
+        else {
+          /* timeout */
+          failf(data, "SSL connection timeout");
+          return CURLE_OPERATION_TIMEDOUT;
+        }
+      }
+      /* socket is readable or writable */
+    }
+
+    /* Run transaction, and return to the caller if it failed or if
+     * this connection is part of a multi handle and this loop would
+     * execute again. This permits the owner of a multi handle to
+     * abort a connection attempt before step2 has completed while
+     * ensuring that a client using select() or epoll() will always
+     * have a valid fdset to wait on.
+     */
+    retcode = mbed_connect_step2(conn, sockindex);
+    if(retcode || (nonblocking &&
+                   (ssl_connect_2 == connssl->connecting_state ||
+                    ssl_connect_2_reading == connssl->connecting_state ||
+                    ssl_connect_2_writing == connssl->connecting_state)))
+      return retcode;
+
+  } /* repeat step2 until all transactions are done. */
+
+  if(ssl_connect_3==connssl->connecting_state) {
+    retcode = mbed_connect_step3(conn, sockindex);
+    if(retcode)
+      return retcode;
+  }
+
+  if(ssl_connect_done==connssl->connecting_state) {
+    connssl->state = ssl_connection_complete;
+    conn->recv[sockindex] = mbed_recv;
+    conn->send[sockindex] = mbed_send;
+    *done = TRUE;
+  }
+  else
+    *done = FALSE;
+
+  /* Reset our connect state machine */
+  connssl->connecting_state = ssl_connect_1;
+
+  return CURLE_OK;
+}
+
+CURLcode
+Curl_mbedtls_connect_nonblocking(struct connectdata *conn,
+                                 int sockindex,
+                                 bool *done)
+{
+  return mbed_connect_common(conn, sockindex, TRUE, done);
+}
+
+
+CURLcode
+Curl_mbedtls_connect(struct connectdata *conn,
+                     int sockindex)
+{
+  CURLcode retcode;
+  bool done = FALSE;
+
+  retcode = mbed_connect_common(conn, sockindex, FALSE, &done);
+  if(retcode)
+    return retcode;
+
+  DEBUGASSERT(done);
+
+  return CURLE_OK;
+}
+
+/*
+ * return 0 error initializing SSL
+ * return 1 SSL initialized successfully
+ */
+int Curl_mbedtls_init(void)
+{
+  return Curl_polarsslthreadlock_thread_setup();
+}
+
+void Curl_mbedtls_cleanup(void)
+{
+  (void)Curl_polarsslthreadlock_thread_cleanup();
+}
+
+int Curl_mbedtls_data_pending(const struct connectdata *conn, int sockindex)
+{
+  mbedtls_ssl_context *ssl =
+    (mbedtls_ssl_context *)&conn->ssl[sockindex].ssl;
+  return ssl->in_msglen != 0;
+}
+
+#endif /* USE_MBEDTLS */
diff --git a/lib/vtls/mbedtls.h b/lib/vtls/mbedtls.h
new file mode 100644
index 0000000..1021d54
--- /dev/null
+++ b/lib/vtls/mbedtls.h
@@ -0,0 +1,80 @@
+#ifndef HEADER_CURL_MBEDTLS_H
+#define HEADER_CURL_MBEDTLS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2012 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 2010, Hoi-Ho Chan, <hoiho.chan at gmail.com>
+ *
+ * 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 USE_MBEDTLS
+
+#include <mbedtls/sha256.h>
+
+/* Called on first use mbedTLS, setup threading if supported */
+int  Curl_mbedtls_init(void);
+void Curl_mbedtls_cleanup(void);
+int Curl_mbedtls_data_pending(const struct connectdata *conn, int sockindex);
+
+CURLcode Curl_mbedtls_connect(struct connectdata *conn, int sockindex);
+
+CURLcode Curl_mbedtls_connect_nonblocking(struct connectdata *conn,
+                                           int sockindex,
+                                           bool *done);
+
+/* tell mbedTLS to close down all open information regarding connections (and
+   thus session ID caching etc) */
+void Curl_mbedtls_close_all(struct Curl_easy *data);
+
+ /* close a SSL connection */
+void Curl_mbedtls_close(struct connectdata *conn, int sockindex);
+
+void Curl_mbedtls_session_free(void *ptr);
+size_t Curl_mbedtls_version(char *buffer, size_t size);
+int Curl_mbedtls_shutdown(struct connectdata *conn, int sockindex);
+
+/* this backends supports CURLOPT_PINNEDPUBLICKEY */
+#define have_curlssl_pinnedpubkey 1
+
+/* API setup for mbedTLS */
+#define curlssl_init() Curl_mbedtls_init()
+#define curlssl_cleanup() Curl_mbedtls_cleanup()
+#define curlssl_connect Curl_mbedtls_connect
+#define curlssl_connect_nonblocking Curl_mbedtls_connect_nonblocking
+#define curlssl_session_free(x)  Curl_mbedtls_session_free(x)
+#define curlssl_close_all Curl_mbedtls_close_all
+#define curlssl_close Curl_mbedtls_close
+#define curlssl_shutdown(x,y) 0
+#define curlssl_set_engine(x,y) (x=x, y=y, CURLE_NOT_BUILT_IN)
+#define curlssl_set_engine_default(x) (x=x, CURLE_NOT_BUILT_IN)
+#define curlssl_engines_list(x) (x=x, (struct curl_slist *)NULL)
+#define curlssl_version Curl_mbedtls_version
+#define curlssl_check_cxn(x) (x=x, -1)
+#define curlssl_data_pending(x,y) Curl_mbedtls_data_pending(x, y)
+#define CURL_SSL_BACKEND CURLSSLBACKEND_MBEDTLS
+#define curlssl_sha256sum(a,b,c,d) mbedtls_sha256(a,b,c,0)
+
+/* This might cause libcurl to use a weeker random!
+   TODO: implement proper use of Polarssl's CTR-DRBG or HMAC-DRBG and use that
+*/
+#define curlssl_random(x,y,z) (x=x, y=y, z=z, CURLE_NOT_BUILT_IN)
+
+#endif /* USE_MBEDTLS */
+#endif /* HEADER_CURL_MBEDTLS_H */
diff --git a/lib/vtls/nss.c b/lib/vtls/nss.c
index 91727c7..ad33f25 100644
--- a/lib/vtls/nss.c
+++ b/lib/vtls/nss.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -198,12 +198,12 @@ static const char* nss_error_to_name(PRErrorCode code)
   return "unknown error";
 }
 
-static void nss_print_error_message(struct SessionHandle *data, PRUint32 err)
+static void nss_print_error_message(struct Curl_easy *data, PRUint32 err)
 {
   failf(data, "%s", PR_ErrorToString(err, PR_LANGUAGE_I_DEFAULT));
 }
 
-static SECStatus set_ciphers(struct SessionHandle *data, PRFileDesc * model,
+static SECStatus set_ciphers(struct Curl_easy *data, PRFileDesc * model,
                              char *cipher_list)
 {
   unsigned int i;
@@ -211,16 +211,22 @@ static SECStatus set_ciphers(struct SessionHandle *data, PRFileDesc * model,
   PRBool found;
   char *cipher;
 
+  /* use accessors to avoid dynamic linking issues after an update of NSS */
+  const PRUint16 num_implemented_ciphers = SSL_GetNumImplementedCiphers();
+  const PRUint16 *implemented_ciphers = SSL_GetImplementedCiphers();
+  if(!implemented_ciphers)
+    return SECFailure;
+
   /* First disable all ciphers. This uses a different max value in case
    * NSS adds more ciphers later we don't want them available by
    * accident
    */
-  for(i=0; i<SSL_NumImplementedCiphers; i++) {
-    SSL_CipherPrefSet(model, SSL_ImplementedCiphers[i], PR_FALSE);
+  for(i = 0; i < num_implemented_ciphers; i++) {
+    SSL_CipherPrefSet(model, implemented_ciphers[i], PR_FALSE);
   }
 
   /* Set every entry in our list to false */
-  for(i=0; i<NUM_OF_CIPHERS; i++) {
+  for(i = 0; i < NUM_OF_CIPHERS; i++) {
     cipher_state[i] = PR_FALSE;
   }
 
@@ -269,21 +275,21 @@ static SECStatus set_ciphers(struct SessionHandle *data, PRFileDesc * model,
 }
 
 /*
- * Get the number of ciphers that are enabled. We use this to determine
+ * Return true if at least one cipher-suite is enabled. Used to determine
  * if we need to call NSS_SetDomesticPolicy() to enable the default ciphers.
  */
-static int num_enabled_ciphers(void)
+static bool any_cipher_enabled(void)
 {
-  PRInt32 policy = 0;
-  int count = 0;
   unsigned int i;
 
   for(i=0; i<NUM_OF_CIPHERS; i++) {
+    PRInt32 policy = 0;
     SSL_CipherPolicyGet(cipherlist[i].num, &policy);
     if(policy)
-      count++;
+      return TRUE;
   }
-  return count;
+
+  return FALSE;
 }
 
 /*
@@ -313,7 +319,7 @@ static int is_file(const char *filename)
  * should be later deallocated using free().  If the OOM failure occurs, we
  * return NULL, too.
  */
-static char* dup_nickname(struct SessionHandle *data, enum dupstring cert_kind)
+static char* dup_nickname(struct Curl_easy *data, enum dupstring cert_kind)
 {
   const char *str = data->set.str[cert_kind];
   const char *n;
@@ -322,8 +328,8 @@ static char* dup_nickname(struct SessionHandle *data, enum dupstring cert_kind)
     /* no such file exists, use the string as nickname */
     return strdup(str);
 
-  /* search the last slash; we require at least one slash in a file name */
-  n = strrchr(str, '/');
+  /* search the first slash; we require at least one slash in a file name */
+  n = strchr(str, '/');
   if(!n) {
     infof(data, "warning: certificate file name \"%s\" handled as nickname; "
           "please use \"./%s\" to force file name\n", str, str);
@@ -591,7 +597,7 @@ static int display_error(struct connectdata *conn, PRInt32 err,
 static CURLcode cert_stuff(struct connectdata *conn, int sockindex,
                            char *cert_file, char *key_file)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   CURLcode result;
 
   if(cert_file) {
@@ -690,7 +696,7 @@ static void HandshakeCallback(PRFileDesc *sock, void *arg)
   unsigned int buflen;
   SSLNextProtoState state;
 
-  if(!conn->data->set.ssl_enable_npn && !conn->data->set.ssl_enable_alpn) {
+  if(!conn->bits.tls_enable_npn && !conn->bits.tls_enable_alpn) {
     return;
   }
 
@@ -714,7 +720,7 @@ static void HandshakeCallback(PRFileDesc *sock, void *arg)
 #ifdef USE_NGHTTP2
     if(buflen == NGHTTP2_PROTO_VERSION_ID_LEN &&
        !memcmp(NGHTTP2_PROTO_VERSION_ID, buf, NGHTTP2_PROTO_VERSION_ID_LEN)) {
-      conn->negnpn = CURL_HTTP_VERSION_2_0;
+      conn->negnpn = CURL_HTTP_VERSION_2;
     }
     else
 #endif
@@ -730,7 +736,7 @@ static SECStatus CanFalseStartCallback(PRFileDesc *sock, void *client_data,
                                        PRBool *canFalseStart)
 {
   struct connectdata *conn = client_data;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   SSLChannelInfo channelInfo;
   SSLCipherSuiteInfo cipherInfo;
@@ -785,7 +791,7 @@ end:
 }
 #endif
 
-static void display_cert_info(struct SessionHandle *data,
+static void display_cert_info(struct Curl_easy *data,
                               CERTCertificate *cert)
 {
   char *subject, *issuer, *common_name;
@@ -886,7 +892,7 @@ static CURLcode display_conn_info(struct connectdata *conn, PRFileDesc *sock)
 static SECStatus BadCertHandler(void *arg, PRFileDesc *sock)
 {
   struct connectdata *conn = (struct connectdata *)arg;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   PRErrorCode err = PR_GetError();
   CERTCertificate *cert;
 
@@ -922,12 +928,6 @@ static SECStatus check_issuer_cert(PRFileDesc *sock,
   SECStatus res=SECSuccess;
   void *proto_win = NULL;
 
-  /*
-    PRArenaPool   *tmpArena = NULL;
-    CERTAuthKeyID *authorityKeyID = NULL;
-    SECITEM       *caname = NULL;
-  */
-
   cert = SSL_PeerCertificate(sock);
   cert_issuer = CERT_FindCertIssuer(cert, PR_Now(), certUsageObjectSigner);
 
@@ -950,7 +950,7 @@ static CURLcode cmp_peer_pubkey(struct ssl_connect_data *connssl,
                                 const char *pinnedpubkey)
 {
   CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
-  struct SessionHandle *data = connssl->data;
+  struct Curl_easy *data = connssl->data;
   CERTCertificate *cert;
 
   if(!pinnedpubkey)
@@ -967,8 +967,7 @@ static CURLcode cmp_peer_pubkey(struct ssl_connect_data *connssl,
       SECItem *cert_der = PK11_DEREncodePublicKey(pubkey);
       if(cert_der) {
         /* compare the public key with the pinned public key */
-        result = Curl_pin_peer_pubkey(pinnedpubkey,
-                                      cert_der->data,
+        result = Curl_pin_peer_pubkey(data, pinnedpubkey, cert_der->data,
                                       cert_der->len);
         SECITEM_FreeItem(cert_der, PR_TRUE);
       }
@@ -1003,7 +1002,7 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
                                   struct SECKEYPrivateKeyStr **pRetKey)
 {
   struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg;
-  struct SessionHandle *data = connssl->data;
+  struct Curl_easy *data = connssl->data;
   const char *nickname = connssl->client_nickname;
 
   if(connssl->obj_clicert) {
@@ -1135,7 +1134,7 @@ static PRStatus nspr_io_close(PRFileDesc *fd)
 }
 
 /* data might be NULL */
-static CURLcode nss_init_core(struct SessionHandle *data, const char *cert_dir)
+static CURLcode nss_init_core(struct Curl_easy *data, const char *cert_dir)
 {
   NSSInitParameters initparams;
 
@@ -1173,7 +1172,7 @@ static CURLcode nss_init_core(struct SessionHandle *data, const char *cert_dir)
 }
 
 /* data might be NULL */
-static CURLcode nss_init(struct SessionHandle *data)
+static CURLcode nss_init(struct Curl_easy *data)
 {
   char *cert_dir;
   struct_stat st;
@@ -1223,7 +1222,7 @@ static CURLcode nss_init(struct SessionHandle *data)
   if(result)
     return result;
 
-  if(num_enabled_ciphers() == 0)
+  if(!any_cipher_enabled())
     NSS_SetDomesticPolicy();
 
   initialized = 1;
@@ -1252,7 +1251,7 @@ int Curl_nss_init(void)
 }
 
 /* data might be NULL */
-CURLcode Curl_nss_force_init(struct SessionHandle *data)
+CURLcode Curl_nss_force_init(struct Curl_easy *data)
 {
   CURLcode result;
   if(!nss_initlock) {
@@ -1398,7 +1397,7 @@ static Curl_send nss_send;
 static CURLcode nss_load_ca_certificates(struct connectdata *conn,
                                          int sockindex)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   const char *cafile = data->set.ssl.CAfile;
   const char *capath = data->set.ssl.CApath;
 
@@ -1448,7 +1447,7 @@ static CURLcode nss_load_ca_certificates(struct connectdata *conn,
 }
 
 static CURLcode nss_init_sslver(SSLVersionRange *sslver,
-                                struct SessionHandle *data)
+                                struct Curl_easy *data)
 {
   switch(data->set.ssl.version) {
   default:
@@ -1501,7 +1500,7 @@ static CURLcode nss_init_sslver(SSLVersionRange *sslver,
 }
 
 static CURLcode nss_fail_connect(struct ssl_connect_data *connssl,
-                                 struct SessionHandle *data,
+                                 struct Curl_easy *data,
                                  CURLcode curlerr)
 {
   PRErrorCode err = 0;
@@ -1528,7 +1527,7 @@ static CURLcode nss_fail_connect(struct ssl_connect_data *connssl,
 
 /* Switch the SSL socket into non-blocking mode. */
 static CURLcode nss_set_nonblock(struct ssl_connect_data *connssl,
-                                 struct SessionHandle *data)
+                                 struct Curl_easy *data)
 {
   static PRSocketOptionData sock_opt;
   sock_opt.option = PR_SockOpt_Nonblocking;
@@ -1547,7 +1546,7 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
   PRFileDesc *nspr_io_stub = NULL;
   PRBool ssl_no_cache;
   PRBool ssl_cbc_random_iv;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   curl_socket_t sockfd = conn->sock[sockindex];
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   CURLcode result;
@@ -1745,14 +1744,14 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
 #endif
 
 #ifdef SSL_ENABLE_NPN
-  if(SSL_OptionSet(connssl->handle, SSL_ENABLE_NPN, data->set.ssl_enable_npn
-        ? PR_TRUE : PR_FALSE) != SECSuccess)
+  if(SSL_OptionSet(connssl->handle, SSL_ENABLE_NPN, conn->bits.tls_enable_npn
+                   ? PR_TRUE : PR_FALSE) != SECSuccess)
     goto error;
 #endif
 
 #ifdef SSL_ENABLE_ALPN
-  if(SSL_OptionSet(connssl->handle, SSL_ENABLE_ALPN, data->set.ssl_enable_alpn
-        ? PR_TRUE : PR_FALSE) != SECSuccess)
+  if(SSL_OptionSet(connssl->handle, SSL_ENABLE_ALPN, conn->bits.tls_enable_alpn
+                   ? PR_TRUE : PR_FALSE) != SECSuccess)
     goto error;
 #endif
 
@@ -1769,12 +1768,12 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
 #endif
 
 #if defined(SSL_ENABLE_NPN) || defined(SSL_ENABLE_ALPN)
-  if(data->set.ssl_enable_npn || data->set.ssl_enable_alpn) {
+  if(conn->bits.tls_enable_npn || conn->bits.tls_enable_alpn) {
     int cur = 0;
     unsigned char protocols[128];
 
 #ifdef USE_NGHTTP2
-    if(data->set.httpversion == CURL_HTTP_VERSION_2_0) {
+    if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
       protocols[cur++] = NGHTTP2_PROTO_VERSION_ID_LEN;
       memcpy(&protocols[cur], NGHTTP2_PROTO_VERSION_ID,
           NGHTTP2_PROTO_VERSION_ID_LEN);
@@ -1792,9 +1791,17 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
 
 
   /* Force handshake on next I/O */
-  SSL_ResetHandshake(connssl->handle, /* asServer */ PR_FALSE);
+  if(SSL_ResetHandshake(connssl->handle, /* asServer */ PR_FALSE)
+      != SECSuccess)
+    goto error;
 
-  SSL_SetURL(connssl->handle, conn->host.name);
+  /* propagate hostname to the TLS layer */
+  if(SSL_SetURL(connssl->handle, conn->host.name) != SECSuccess)
+    goto error;
+
+  /* prevent NSS from re-using the session for a different hostname */
+  if(SSL_SetSockPeerID(connssl->handle, conn->host.name) != SECSuccess)
+    goto error;
 
   return CURLE_OK;
 
@@ -1808,7 +1815,7 @@ error:
 static CURLcode nss_do_connect(struct connectdata *conn, int sockindex)
 {
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   CURLcode result = CURLE_SSL_CONNECT_ERROR;
   PRUint32 timeout;
 
@@ -1871,7 +1878,7 @@ static CURLcode nss_connect_common(struct connectdata *conn, int sockindex,
                                    bool *done)
 {
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   const bool blocking = (done == NULL);
   CURLcode result;
 
@@ -2008,14 +2015,14 @@ size_t Curl_nss_version(char *buffer, size_t size)
 }
 
 /* data might be NULL */
-int Curl_nss_seed(struct SessionHandle *data)
+int Curl_nss_seed(struct Curl_easy *data)
 {
   /* make sure that NSS is initialized */
   return !!Curl_nss_force_init(data);
 }
 
 /* data might be NULL */
-int Curl_nss_random(struct SessionHandle *data,
+int Curl_nss_random(struct Curl_easy *data,
                     unsigned char *entropy,
                     size_t length)
 {
diff --git a/lib/vtls/nssg.h b/lib/vtls/nssg.h
index 5fd7275..ac67e6a 100644
--- a/lib/vtls/nssg.h
+++ b/lib/vtls/nssg.h
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -42,12 +42,12 @@ void Curl_nss_cleanup(void);
 
 size_t Curl_nss_version(char *buffer, size_t size);
 int Curl_nss_check_cxn(struct connectdata *cxn);
-int Curl_nss_seed(struct SessionHandle *data);
+int Curl_nss_seed(struct Curl_easy *data);
 
 /* initialize NSS library if not already */
-CURLcode Curl_nss_force_init(struct SessionHandle *data);
+CURLcode Curl_nss_force_init(struct Curl_easy *data);
 
-int Curl_nss_random(struct SessionHandle *data,
+int Curl_nss_random(struct Curl_easy *data,
                     unsigned char *entropy,
                     size_t length);
 
@@ -74,6 +74,9 @@ bool Curl_nss_false_start(void);
 /* this backend supports CURLOPT_CERTINFO */
 #define have_curlssl_certinfo 1
 
+/* this backends supports CURLOPT_PINNEDPUBLICKEY */
+#define have_curlssl_pinnedpubkey 1
+
 /* API setup for NSS */
 #define curlssl_init Curl_nss_init
 #define curlssl_cleanup Curl_nss_cleanup
diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c
index 90e4c2b..3027ca3 100644
--- a/lib/vtls/openssl.c
+++ b/lib/vtls/openssl.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -68,7 +68,7 @@
 #include <openssl/pkcs12.h>
 #endif
 
-#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_IS_BORINGSSL)
+#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_OCSP)
 #include <openssl/ocsp.h>
 #endif
 
@@ -83,23 +83,8 @@
 #error "OPENSSL_VERSION_NUMBER not defined"
 #endif
 
-#if OPENSSL_VERSION_NUMBER >= 0x00907001L && !defined(OPENSSL_IS_BORINGSSL)
-/* ENGINE_load_private_key() takes four arguments */
-#define HAVE_ENGINE_LOAD_FOUR_ARGS
+#if defined(HAVE_OPENSSL_ENGINE_H)
 #include <openssl/ui.h>
-#else
-/* ENGINE_load_private_key() takes three arguments */
-#undef HAVE_ENGINE_LOAD_FOUR_ARGS
-#endif
-
-#if (OPENSSL_VERSION_NUMBER >= 0x00903001L) && \
-    defined(HAVE_OPENSSL_PKCS12_H) && \
-    !defined(OPENSSL_IS_BORINGSSL)
-/* OpenSSL has PKCS 12 support, BoringSSL does not */
-#define HAVE_PKCS12_SUPPORT
-#else
-/* OpenSSL does not have PKCS12 support */
-#undef HAVE_PKCS12_SUPPORT
 #endif
 
 #if OPENSSL_VERSION_NUMBER >= 0x00909000L
@@ -108,18 +93,13 @@
 #define SSL_METHOD_QUAL
 #endif
 
-#if OPENSSL_VERSION_NUMBER >= 0x00907000L
-/* 0.9.6 didn't have X509_STORE_set_flags() */
-#define HAVE_X509_STORE_SET_FLAGS 1
-#else
-#define X509_STORE_set_flags(x,y) Curl_nop_stmt
-#endif
-
-#ifdef OPENSSL_IS_BORINGSSL
-/* BoringSSL has no ERR_remove_state() */
-#define ERR_remove_state(x)
-#elif (OPENSSL_VERSION_NUMBER >= 0x10000000L)
+#if (OPENSSL_VERSION_NUMBER >= 0x10000000L)
 #define HAVE_ERR_REMOVE_THREAD_STATE 1
+#if (OPENSSL_VERSION_NUMBER >= 0x10100004L) && \
+  !defined(LIBRESSL_VERSION_NUMBER)
+/* OpenSSL 1.1.0 deprecates the function */
+#define HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED 1
+#endif
 #endif
 
 #if !defined(HAVE_SSLV2_CLIENT_METHOD) || \
@@ -128,19 +108,39 @@
 #define OPENSSL_NO_SSL2
 #endif
 
-#if defined(OPENSSL_IS_BORINGSSL)
-#define NO_RAND_SEED 1
-/* In BoringSSL OpenSSL_add_all_algorithms does nothing */
-#define OpenSSL_add_all_algorithms()
-/* BoringSSL does not have CONF_modules_load_file */
-#define CONF_modules_load_file(a,b,c)
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && /* OpenSSL 1.1.0+ */ \
+  !defined(LIBRESSL_VERSION_NUMBER)
+#define SSLeay_add_ssl_algorithms() SSL_library_init()
+#define SSLEAY_VERSION_NUMBER OPENSSL_VERSION_NUMBER
+#define HAVE_X509_GET0_EXTENSIONS 1 /* added in 1.1.0 -pre1 */
+#define HAVE_OPAQUE_EVP_PKEY 1 /* since 1.1.0 -pre3 */
+#define HAVE_OPAQUE_RSA_DSA_DH 1 /* since 1.1.0 -pre5 */
+#endif
+
+#if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) && /* 1.0.2 or later */ \
+  !defined(LIBRESSL_VERSION_NUMBER)
+#define HAVE_X509_GET0_SIGNATURE 1
 #endif
 
-#if (OPENSSL_VERSION_NUMBER < 0x0090808fL) || defined(OPENSSL_IS_BORINGSSL)
-/* not present in BoringSSL  or older OpenSSL */
+#if OPENSSL_VERSION_NUMBER >= 0x10002003L && \
+  OPENSSL_VERSION_NUMBER <= 0x10002FFFL && \
+  !defined(OPENSSL_NO_COMP)
+#define HAVE_SSL_COMP_FREE_COMPRESSION_METHODS 1
+#endif
+
+#if (OPENSSL_VERSION_NUMBER < 0x0090808fL)
+/* not present in older OpenSSL */
 #define OPENSSL_load_builtin_modules(x)
 #endif
 
+#if defined(LIBRESSL_VERSION_NUMBER)
+#define OSSL_PACKAGE "LibreSSL"
+#elif defined(OPENSSL_IS_BORINGSSL)
+#define OSSL_PACKAGE "BoringSSL"
+#else
+#define OSSL_PACKAGE "OpenSSL"
+#endif
+
 /*
  * Number of bytes to read from the random number seed file. This must be
  * a finite value (because some entropy "files" like /dev/urandom have
@@ -171,7 +171,6 @@ static int passwd_callback(char *buf, int num, int encrypting,
  * pass in an argument that is never used.
  */
 
-#ifndef NO_RAND_SEED
 #ifdef HAVE_RAND_STATUS
 #define seed_enough(x) rand_enough()
 static bool rand_enough(void)
@@ -187,7 +186,7 @@ static bool rand_enough(int nread)
 }
 #endif
 
-static int ossl_seed(struct SessionHandle *data)
+static int ossl_seed(struct Curl_easy *data)
 {
   char *buf = data->state.buffer; /* point to the big buffer */
   int nread=0;
@@ -256,7 +255,7 @@ static int ossl_seed(struct SessionHandle *data)
   return nread;
 }
 
-static void Curl_ossl_seed(struct SessionHandle *data)
+static void Curl_ossl_seed(struct Curl_easy *data)
 {
   /* we have the "SSL is seeded" boolean static to prevent multiple
      time-consuming seedings in vain */
@@ -268,11 +267,6 @@ static void Curl_ossl_seed(struct SessionHandle *data)
     ssl_seeded = TRUE;
   }
 }
-#else
-/* BoringSSL needs no seeding */
-#define Curl_ossl_seed(x)
-#endif
-
 
 #ifndef SSL_FILETYPE_ENGINE
 #define SSL_FILETYPE_ENGINE 42
@@ -295,7 +289,7 @@ static int do_file_type(const char *type)
   return -1;
 }
 
-#if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_LOAD_FOUR_ARGS)
+#if defined(HAVE_OPENSSL_ENGINE_H)
 /*
  * Supply default password to the engine user interface conversation.
  * The password is passed by OpenSSL engine from ENGINE_load_private_key()
@@ -345,7 +339,7 @@ int cert_stuff(struct connectdata *conn,
                char *key_file,
                const char *key_type)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   int file_type = do_file_type(cert_type);
 
@@ -369,7 +363,8 @@ int cert_stuff(struct connectdata *conn,
       if(SSL_CTX_use_certificate_chain_file(ctx,
                                             cert_file) != 1) {
         failf(data,
-              "could not load PEM client certificate, OpenSSL error %s, "
+              "could not load PEM client certificate, " OSSL_PACKAGE
+              " error %s, "
               "(no key found, wrong pass phrase, or wrong file format?)",
               ERR_error_string(ERR_get_error(), NULL) );
         return 0;
@@ -384,7 +379,8 @@ int cert_stuff(struct connectdata *conn,
                                       cert_file,
                                       file_type) != 1) {
         failf(data,
-              "could not load ASN1 client certificate, OpenSSL error %s, "
+              "could not load ASN1 client certificate, " OSSL_PACKAGE
+              " error %s, "
               "(no key found, wrong pass phrase, or wrong file format?)",
               ERR_error_string(ERR_get_error(), NULL) );
         return 0;
@@ -445,12 +441,11 @@ int cert_stuff(struct connectdata *conn,
 
     case SSL_FILETYPE_PKCS12:
     {
-#ifdef HAVE_PKCS12_SUPPORT
+#ifdef HAVE_OPENSSL_PKCS12_H
       FILE *f;
       PKCS12 *p12;
       EVP_PKEY *pri;
       STACK_OF(X509) *ca = NULL;
-      int i;
 
       f = fopen(cert_file, "rb");
       if(!f) {
@@ -470,7 +465,8 @@ int cert_stuff(struct connectdata *conn,
       if(!PKCS12_parse(p12, data->set.str[STRING_KEY_PASSWD], &pri, &x509,
                        &ca)) {
         failf(data,
-              "could not parse PKCS12 file, check password, OpenSSL error %s",
+              "could not parse PKCS12 file, check password, " OSSL_PACKAGE
+              " error %s",
               ERR_error_string(ERR_get_error(), NULL) );
         PKCS12_free(p12);
         return 0;
@@ -480,7 +476,8 @@ int cert_stuff(struct connectdata *conn,
 
       if(SSL_CTX_use_certificate(ctx, x509) != 1) {
         failf(data,
-              "could not load PKCS12 client certificate, OpenSSL error %s",
+              "could not load PKCS12 client certificate, " OSSL_PACKAGE
+              " error %s",
               ERR_error_string(ERR_get_error(), NULL) );
         goto fail;
       }
@@ -497,8 +494,8 @@ int cert_stuff(struct connectdata *conn,
         goto fail;
       }
       /* Set Certificate Verification chain */
-      if(ca && sk_X509_num(ca)) {
-        for(i = 0; i < sk_X509_num(ca); i++) {
+      if(ca) {
+        while(sk_X509_num(ca)) {
           /*
            * Note that sk_X509_pop() is used below to make sure the cert is
            * removed from the stack properly before getting passed to
@@ -508,6 +505,7 @@ int cert_stuff(struct connectdata *conn,
            */
           X509 *x = sk_X509_pop(ca);
           if(!SSL_CTX_add_extra_chain_cert(ctx, x)) {
+            X509_free(x);
             failf(data, "cannot add certificate to certificate chain");
             goto fail;
           }
@@ -561,28 +559,23 @@ int cert_stuff(struct connectdata *conn,
       {                         /* XXXX still needs some work */
         EVP_PKEY *priv_key = NULL;
         if(data->state.engine) {
-#ifdef HAVE_ENGINE_LOAD_FOUR_ARGS
           UI_METHOD *ui_method =
             UI_create_method((char *)"cURL user interface");
           if(!ui_method) {
-            failf(data, "unable do create OpenSSL user-interface method");
+            failf(data, "unable do create " OSSL_PACKAGE
+                  " user-interface method");
             return 0;
           }
           UI_method_set_opener(ui_method, UI_method_get_opener(UI_OpenSSL()));
           UI_method_set_closer(ui_method, UI_method_get_closer(UI_OpenSSL()));
           UI_method_set_reader(ui_method, ssl_ui_reader);
           UI_method_set_writer(ui_method, ssl_ui_writer);
-#endif
           /* the typecast below was added to please mingw32 */
           priv_key = (EVP_PKEY *)
             ENGINE_load_private_key(data->state.engine, key_file,
-#ifdef HAVE_ENGINE_LOAD_FOUR_ARGS
                                     ui_method,
-#endif
                                     data->set.str[STRING_KEY_PASSWD]);
-#ifdef HAVE_ENGINE_LOAD_FOUR_ARGS
           UI_destroy_method(ui_method);
-#endif
           if(!priv_key) {
             failf(data, "failed to load private key from crypto engine");
             return 0;
@@ -679,7 +672,7 @@ static int x509_name_oneline(X509_NAME *a, char *buf, size_t size)
 
 /* Return error string for last OpenSSL error
  */
-static char *SSL_strerror(unsigned long error, char *buf, size_t size)
+static char *ossl_strerror(unsigned long error, char *buf, size_t size)
 {
   /* OpenSSL 0.9.6 and later has a function named
      ERR_error_string_n() that takes the size of the buffer as a
@@ -702,16 +695,6 @@ int Curl_ossl_init(void)
   ENGINE_load_builtin_engines();
 #endif
 
-  /* Lets get nice error messages */
-  SSL_load_error_strings();
-
-  /* Init the global ciphers and digests */
-  if(!SSLeay_add_ssl_algorithms())
-    return 0;
-
-  OpenSSL_add_all_algorithms();
-
-
   /* OPENSSL_config(NULL); is "strongly recommended" to use but unfortunately
      that function makes an exit() call on wrongly formatted config files
      which makes it hard to use in some situations. OPENSSL_config() itself
@@ -728,6 +711,15 @@ int Curl_ossl_init(void)
                          CONF_MFLAGS_DEFAULT_SECTION|
                          CONF_MFLAGS_IGNORE_MISSING_FILE);
 
+  /* Lets get nice error messages */
+  SSL_load_error_strings();
+
+  /* Init the global ciphers and digests */
+  if(!SSLeay_add_ssl_algorithms())
+    return 0;
+
+  OpenSSL_add_all_algorithms();
+
   return 1;
 }
 
@@ -751,15 +743,24 @@ void Curl_ossl_cleanup(void)
   ERR_free_strings();
 
   /* Free thread local error state, destroying hash upon zero refcount */
-#ifdef HAVE_ERR_REMOVE_THREAD_STATE
+#ifdef HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED
+
+#elif defined(HAVE_ERR_REMOVE_THREAD_STATE)
   ERR_remove_thread_state(NULL);
 #else
   ERR_remove_state(0);
 #endif
+
+  /* Free all memory allocated by all configuration modules */
+  CONF_modules_free();
+
+#ifdef HAVE_SSL_COMP_FREE_COMPRESSION_METHODS
+  SSL_COMP_free_compression_methods();
+#endif
 }
 
 /*
- * This function uses SSL_peek to determine connection status.
+ * This function is used to determine connection status.
  *
  * Return codes:
  *     1 means the connection is still in place
@@ -768,22 +769,51 @@ void Curl_ossl_cleanup(void)
  */
 int Curl_ossl_check_cxn(struct connectdata *conn)
 {
-  int rc;
+  /* SSL_peek takes data out of the raw recv buffer without peeking so we use
+     recv MSG_PEEK instead. Bug #795 */
+#ifdef MSG_PEEK
   char buf;
-
-  rc = SSL_peek(conn->ssl[FIRSTSOCKET].handle, (void*)&buf, 1);
-  if(rc > 0)
-    return 1; /* connection still in place */
-
-  if(rc == 0)
+  ssize_t nread;
+  nread = recv((RECV_TYPE_ARG1)conn->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf,
+               (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK);
+  if(nread == 0)
     return 0; /* connection has been closed */
-
+  else if(nread == 1)
+    return 1; /* connection still in place */
+  else if(nread == -1) {
+      int err = SOCKERRNO;
+      if(err == EINPROGRESS ||
+#if defined(EAGAIN) && (EAGAIN != EWOULDBLOCK)
+         err == EAGAIN ||
+#endif
+         err == EWOULDBLOCK)
+        return 1; /* connection still in place */
+      if(err == ECONNRESET ||
+#ifdef ECONNABORTED
+         err == ECONNABORTED ||
+#endif
+#ifdef ENETDOWN
+         err == ENETDOWN ||
+#endif
+#ifdef ENETRESET
+         err == ENETRESET ||
+#endif
+#ifdef ESHUTDOWN
+         err == ESHUTDOWN ||
+#endif
+#ifdef ETIMEDOUT
+         err == ETIMEDOUT ||
+#endif
+         err == ENOTCONN)
+        return 0; /* connection has been closed */
+  }
+#endif
   return -1; /* connection status unknown */
 }
 
 /* Selects an OpenSSL crypto engine
  */
-CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine)
+CURLcode Curl_ossl_set_engine(struct Curl_easy *data, const char *engine)
 {
 #if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H)
   ENGINE *e;
@@ -814,7 +844,7 @@ CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine)
 
     ENGINE_free(e);
     failf(data, "Failed to initialise SSL Engine '%s':\n%s",
-          engine, SSL_strerror(ERR_get_error(), buf, sizeof(buf)));
+          engine, ossl_strerror(ERR_get_error(), buf, sizeof(buf)));
     return CURLE_SSL_ENGINE_INITFAILED;
   }
   data->state.engine = e;
@@ -828,7 +858,7 @@ CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine)
 
 /* Sets engine as default for all SSL operations
  */
-CURLcode Curl_ossl_set_engine_default(struct SessionHandle *data)
+CURLcode Curl_ossl_set_engine_default(struct Curl_easy *data)
 {
 #ifdef HAVE_OPENSSL_ENGINE_H
   if(data->state.engine) {
@@ -850,7 +880,7 @@ CURLcode Curl_ossl_set_engine_default(struct SessionHandle *data)
 
 /* Return list of OpenSSL crypto engine names.
  */
-struct curl_slist *Curl_ossl_engines_list(struct SessionHandle *data)
+struct curl_slist *Curl_ossl_engines_list(struct Curl_easy *data)
 {
   struct curl_slist *list = NULL;
 #if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H)
@@ -899,9 +929,9 @@ int Curl_ossl_shutdown(struct connectdata *conn, int sockindex)
 {
   int retval = 0;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-  struct SessionHandle *data = conn->data;
-  char buf[120]; /* We will use this for the OpenSSL error buffer, so it has
-                    to be at least 120 bytes long. */
+  struct Curl_easy *data = conn->data;
+  char buf[256]; /* We will use this for the OpenSSL error buffer, so it has
+                    to be at least 256 bytes long. */
   unsigned long sslerror;
   ssize_t nread;
   int buffsize;
@@ -949,8 +979,8 @@ int Curl_ossl_shutdown(struct connectdata *conn, int sockindex)
         default:
           /* openssl/ssl.h says "look at error stack/return value/errno" */
           sslerror = ERR_get_error();
-          failf(conn->data, "SSL read: %s, errno %d",
-                ERR_error_string(sslerror, buf),
+          failf(conn->data, OSSL_PACKAGE " SSL read: %s, errno %d",
+                ossl_strerror(sslerror, buf, sizeof(buf)),
                 SOCKERRNO);
           done = 1;
           break;
@@ -1002,7 +1032,7 @@ void Curl_ossl_session_free(void *ptr)
  * This function is called when the 'data' struct is going away. Close
  * down everything and free all resources!
  */
-void Curl_ossl_close_all(struct SessionHandle *data)
+void Curl_ossl_close_all(struct Curl_easy *data)
 {
 #ifdef HAVE_OPENSSL_ENGINE_H
   if(data->state.engine) {
@@ -1015,49 +1045,6 @@ void Curl_ossl_close_all(struct SessionHandle *data)
 #endif
 }
 
-static int asn1_output(const ASN1_UTCTIME *tm,
-                       char *buf,
-                       size_t sizeofbuf)
-{
-  const char *asn1_string;
-  int gmt=FALSE;
-  int i;
-  int year=0, month=0, day=0, hour=0, minute=0, second=0;
-
-  i=tm->length;
-  asn1_string=(const char *)tm->data;
-
-  if(i < 10)
-    return 1;
-  if(asn1_string[i-1] == 'Z')
-    gmt=TRUE;
-  for(i=0; i<10; i++)
-    if((asn1_string[i] > '9') || (asn1_string[i] < '0'))
-      return 2;
-
-  year= (asn1_string[0]-'0')*10+(asn1_string[1]-'0');
-  if(year < 50)
-    year+=100;
-
-  month= (asn1_string[2]-'0')*10+(asn1_string[3]-'0');
-  if((month > 12) || (month < 1))
-    return 3;
-
-  day= (asn1_string[4]-'0')*10+(asn1_string[5]-'0');
-  hour= (asn1_string[6]-'0')*10+(asn1_string[7]-'0');
-  minute=  (asn1_string[8]-'0')*10+(asn1_string[9]-'0');
-
-  if((asn1_string[10] >= '0') && (asn1_string[10] <= '9') &&
-     (asn1_string[11] >= '0') && (asn1_string[11] <= '9'))
-    second= (asn1_string[10]-'0')*10+(asn1_string[11]-'0');
-
-  snprintf(buf, sizeofbuf,
-           "%04d-%02d-%02d %02d:%02d:%02d %s",
-           year+1900, month, day, hour, minute, second, (gmt?"GMT":""));
-
-  return 0;
-}
-
 /* ====================================================== */
 
 
@@ -1084,11 +1071,10 @@ static int asn1_output(const ASN1_UTCTIME *tm,
 */
 static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert)
 {
-  int matched = -1; /* -1 is no alternative match yet, 1 means match and 0
-                       means mismatch */
+  bool matched = FALSE;
   int target = GEN_DNS; /* target type, GEN_DNS or GEN_IPADD */
   size_t addrlen = 0;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   STACK_OF(GENERAL_NAME) *altnames;
 #ifdef ENABLE_IPV6
   struct in6_addr addr;
@@ -1096,6 +1082,7 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert)
   struct in_addr addr;
 #endif
   CURLcode result = CURLE_OK;
+  bool dNSName = FALSE; /* if a dNSName field exists in the cert */
 
 #ifdef ENABLE_IPV6
   if(conn->bits.ipv6_ip &&
@@ -1116,16 +1103,23 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert)
   if(altnames) {
     int numalts;
     int i;
+    bool dnsmatched = FALSE;
+    bool ipmatched = FALSE;
 
     /* get amount of alternatives, RFC2459 claims there MUST be at least
        one, but we don't depend on it... */
     numalts = sk_GENERAL_NAME_num(altnames);
 
-    /* loop through all alternatives while none has matched */
-    for(i=0; (i<numalts) && (matched != 1); i++) {
+    /* loop through all alternatives - until a dnsmatch */
+    for(i=0; (i < numalts) && !dnsmatched; i++) {
       /* get a handle to alternative name number i */
       const GENERAL_NAME *check = sk_GENERAL_NAME_value(altnames, i);
 
+      /* If a subjectAltName extension of type dNSName is present, that MUST
+         be used as the identity. / RFC2818 section 3.1 */
+      if(check->type == GEN_DNS)
+        dNSName = TRUE;
+
       /* only check alternatives of the same type the target is */
       if(check->type == target) {
         /* get data and length */
@@ -1147,33 +1141,42 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert)
           if((altlen == strlen(altptr)) &&
              /* if this isn't true, there was an embedded zero in the name
                 string and we cannot match it. */
-             Curl_cert_hostcheck(altptr, conn->host.name))
-            matched = 1;
-          else
-            matched = 0;
+             Curl_cert_hostcheck(altptr, conn->host.name)) {
+            dnsmatched = TRUE;
+            infof(data,
+                  " subjectAltName: host \"%s\" matched cert's \"%s\"\n",
+                  conn->host.dispname, altptr);
+          }
           break;
 
         case GEN_IPADD: /* IP address comparison */
           /* compare alternative IP address if the data chunk is the same size
              our server IP address is */
-          if((altlen == addrlen) && !memcmp(altptr, &addr, altlen))
-            matched = 1;
-          else
-            matched = 0;
+          if((altlen == addrlen) && !memcmp(altptr, &addr, altlen)) {
+            ipmatched = TRUE;
+            infof(data,
+                  " subjectAltName: host \"%s\" matched cert's IP address!\n",
+                  conn->host.dispname);
+          }
           break;
         }
       }
     }
     GENERAL_NAMES_free(altnames);
+
+    if(dnsmatched || (!dNSName && ipmatched)) {
+      /* count as a match if the dnsname matched or if there was no dnsname
+         fields at all AND there was an IP field match */
+      matched = TRUE;
+    }
   }
 
-  if(matched == 1)
-    /* an alternative name matched the server hostname */
-    infof(data, "\t subjectAltName: %s matched\n", conn->host.dispname);
-  else if(matched == 0) {
-    /* an alternative name field existed, but didn't match and then
-       we MUST fail */
-    infof(data, "\t subjectAltName does not match %s\n", conn->host.dispname);
+  if(matched)
+    /* an alternative name matched */
+    ;
+  else if(dNSName) {
+    /* an dNSName field existed, but didn't match and then we MUST fail */
+    infof(data, " subjectAltName does not match %s\n", conn->host.dispname);
     failf(data, "SSL: no alternative certificate subject name matches "
           "target host name '%s'", conn->host.dispname);
     result = CURLE_PEER_FAILED_VERIFICATION;
@@ -1183,7 +1186,7 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert)
        distinguished one to get the most significant one. */
     int j, i=-1;
 
-/* The following is done because of a bug in 0.9.6b */
+    /* The following is done because of a bug in 0.9.6b */
 
     unsigned char *nulstr = (unsigned char *)"";
     unsigned char *peer_CN = nulstr;
@@ -1255,7 +1258,7 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert)
       result = CURLE_PEER_FAILED_VERIFICATION;
     }
     else {
-      infof(data, "\t common name: %s (matched)\n", peer_CN);
+      infof(data, " common name: %s (matched)\n", peer_CN);
     }
     if(peer_CN)
       OPENSSL_free(peer_CN);
@@ -1265,14 +1268,14 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert)
 }
 
 #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
-    !defined(OPENSSL_IS_BORINGSSL)
+    !defined(OPENSSL_NO_OCSP)
 static CURLcode verifystatus(struct connectdata *conn,
                              struct ssl_connect_data *connssl)
 {
   int i, ocsp_status;
   const unsigned char *p;
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
 
   OCSP_RESPONSE *rsp = NULL;
   OCSP_BASICRESP *br = NULL;
@@ -1351,7 +1354,8 @@ static CURLcode verifystatus(struct connectdata *conn,
 
     ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
 
-    if(!(single = OCSP_resp_get0(br, i)))
+    single = OCSP_resp_get0(br, i);
+    if(!single)
       continue;
 
     cert_status = OCSP_single_get0_status(single, &crl_reason, &rev,
@@ -1487,7 +1491,7 @@ static void ssl_tls_trace(int direction, int ssl_ver, int content_type,
                           const void *buf, size_t len, SSL *ssl,
                           void *userp)
 {
-  struct SessionHandle *data;
+  struct Curl_easy *data;
   const char *msg_name, *tls_rt_name;
   char ssl_buf[1024];
   char unknown[32];
@@ -1620,12 +1624,12 @@ select_next_proto_cb(SSL *ssl,
   (void)ssl;
 
 #ifdef USE_NGHTTP2
-  if(conn->data->set.httpversion == CURL_HTTP_VERSION_2_0 &&
+  if(conn->data->set.httpversion >= CURL_HTTP_VERSION_2 &&
      !select_next_protocol(out, outlen, in, inlen, NGHTTP2_PROTO_VERSION_ID,
                            NGHTTP2_PROTO_VERSION_ID_LEN)) {
     infof(conn->data, "NPN, negotiated HTTP2 (%s)\n",
           NGHTTP2_PROTO_VERSION_ID);
-    conn->negnpn = CURL_HTTP_VERSION_2_0;
+    conn->negnpn = CURL_HTTP_VERSION_2;
     return SSL_TLSEXT_ERR_OK;
   }
 #endif
@@ -1673,9 +1677,8 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
 {
   CURLcode result = CURLE_OK;
   char *ciphers;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   SSL_METHOD_QUAL SSL_METHOD *req_method = NULL;
-  void *ssl_sessionid = NULL;
   X509_LOOKUP *lookup = NULL;
   curl_socket_t sockfd = conn->sock[sockindex];
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
@@ -1707,7 +1710,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
   case CURL_SSLVERSION_TLSv1_2:
     /* it will be handled later with the context options */
 #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \
-    !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL)
+    !defined(LIBRESSL_VERSION_NUMBER)
     req_method = TLS_client_method();
 #else
     req_method = SSLv23_client_method();
@@ -1716,7 +1719,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
     break;
   case CURL_SSLVERSION_SSLv2:
 #ifdef OPENSSL_NO_SSL2
-    failf(data, "OpenSSL was built without SSLv2 support");
+    failf(data, OSSL_PACKAGE " was built without SSLv2 support");
     return CURLE_NOT_BUILT_IN;
 #else
 #ifdef USE_TLS_SRP
@@ -1729,7 +1732,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
 #endif
   case CURL_SSLVERSION_SSLv3:
 #ifdef OPENSSL_NO_SSL3_METHOD
-    failf(data, "OpenSSL was built without SSLv3 support");
+    failf(data, OSSL_PACKAGE " was built without SSLv3 support");
     return CURLE_NOT_BUILT_IN;
 #else
 #ifdef USE_TLS_SRP
@@ -1887,17 +1890,17 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
   SSL_CTX_set_options(connssl->ctx, ctx_options);
 
 #ifdef HAS_NPN
-  if(data->set.ssl_enable_npn)
+  if(conn->bits.tls_enable_npn)
     SSL_CTX_set_next_proto_select_cb(connssl->ctx, select_next_proto_cb, conn);
 #endif
 
 #ifdef HAS_ALPN
-  if(data->set.ssl_enable_alpn) {
+  if(conn->bits.tls_enable_alpn) {
     int cur = 0;
     unsigned char protocols[128];
 
 #ifdef USE_NGHTTP2
-    if(data->set.httpversion == CURL_HTTP_VERSION_2_0) {
+    if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
       protocols[cur++] = NGHTTP2_PROTO_VERSION_ID_LEN;
 
       memcpy(&protocols[cur], NGHTTP2_PROTO_VERSION_ID,
@@ -1997,6 +2000,13 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
           data->set.str[STRING_SSL_CAPATH] ? data->set.str[STRING_SSL_CAPATH]:
           "none");
   }
+#ifdef CURL_CA_FALLBACK
+  else if(data->set.ssl.verifypeer) {
+    /* verfying the peer without any CA certificates won't
+       work so use openssl's built in default as fallback */
+    SSL_CTX_set_default_verify_paths(connssl->ctx);
+  }
+#endif
 
   if(data->set.str[STRING_SSL_CRLFILE]) {
     /* tell SSL where to find CRL file that is used to check certificate
@@ -2063,7 +2073,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
   }
 
 #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
-    !defined(OPENSSL_IS_BORINGSSL)
+    !defined(OPENSSL_NO_OCSP)
   if(data->set.ssl.verifystatus)
     SSL_set_tlsext_status_type(connssl->handle, TLSEXT_STATUSTYPE_ocsp);
 #endif
@@ -2084,15 +2094,22 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
 #endif
 
   /* Check if there's a cached ID we can/should use here! */
-  if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) {
-    /* we got a session id, use it! */
-    if(!SSL_set_session(connssl->handle, ssl_sessionid)) {
-      failf(data, "SSL: SSL_set_session failed: %s",
-            ERR_error_string(ERR_get_error(), NULL));
-      return CURLE_SSL_CONNECT_ERROR;
+  if(conn->ssl_config.sessionid) {
+    void *ssl_sessionid = NULL;
+
+    Curl_ssl_sessionid_lock(conn);
+    if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) {
+      /* we got a session id, use it! */
+      if(!SSL_set_session(connssl->handle, ssl_sessionid)) {
+        Curl_ssl_sessionid_unlock(conn);
+        failf(data, "SSL: SSL_set_session failed: %s",
+              ERR_error_string(ERR_get_error(), NULL));
+        return CURLE_SSL_CONNECT_ERROR;
+      }
+      /* Informational message */
+      infof (data, "SSL re-using session ID\n");
     }
-    /* Informational message */
-    infof (data, "SSL re-using session ID\n");
+    Curl_ssl_sessionid_unlock(conn);
   }
 
   /* pass the raw socket into the SSL layers */
@@ -2109,7 +2126,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
 
 static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   int err;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   DEBUGASSERT(ssl_connect_2 == connssl->connecting_state
@@ -2141,27 +2158,22 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex)
                                     least 256 bytes long. */
       CURLcode result;
       long lerr;
+      int lib;
+      int reason;
 
-      connssl->connecting_state = ssl_connect_2; /* the connection failed,
-                                                    we're not waiting for
-                                                    anything else. */
-
-      errdetail = ERR_get_error(); /* Gets the earliest error code from the
-                                      thread's error queue and removes the
-                                      entry. */
-
-      switch(errdetail) {
-      case 0x1407E086:
-        /* 1407E086:
-           SSL routines:
-           SSL2_SET_CERTIFICATE:
-           certificate verify failed */
-        /* fall-through */
-      case 0x14090086:
-        /* 14090086:
-           SSL routines:
-           SSL3_GET_SERVER_CERTIFICATE:
-           certificate verify failed */
+      /* the connection failed, we're not waiting for anything else. */
+      connssl->connecting_state = ssl_connect_2;
+
+      /* Get the earliest error code from the thread's error queue and removes
+         the entry. */
+      errdetail = ERR_get_error();
+
+      /* Extract which lib and reason */
+      lib = ERR_GET_LIB(errdetail);
+      reason = ERR_GET_REASON(errdetail);
+
+      if((lib == ERR_LIB_SSL) &&
+         (reason == SSL_R_CERTIFICATE_VERIFY_FAILED)) {
         result = CURLE_SSL_CACERT;
 
         lerr = SSL_get_verify_result(connssl->handle);
@@ -2173,13 +2185,11 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex)
         else
           /* strcpy() is fine here as long as the string fits within
              error_buffer */
-          strcpy(error_buffer,
-                 "SSL certificate problem, check your CA cert");
-        break;
-      default:
+          strcpy(error_buffer, "SSL certificate verification failed");
+      }
+      else {
         result = CURLE_SSL_CONNECT_ERROR;
-        SSL_strerror(errdetail, error_buffer, sizeof(error_buffer));
-        break;
+        ossl_strerror(errdetail, error_buffer, sizeof(error_buffer));
       }
 
       /* detail is already set to the SSL error above */
@@ -2213,7 +2223,7 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex)
     /* Sets data and len to negotiated protocol, len is 0 if no protocol was
      * negotiated
      */
-    if(data->set.ssl_enable_alpn) {
+    if(conn->bits.tls_enable_alpn) {
       const unsigned char* neg_protocol;
       unsigned int len;
       SSL_get0_alpn_selected(connssl->handle, &neg_protocol, &len);
@@ -2223,7 +2233,7 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex)
 #ifdef USE_NGHTTP2
         if(len == NGHTTP2_PROTO_VERSION_ID_LEN &&
            !memcmp(NGHTTP2_PROTO_VERSION_ID, neg_protocol, len)) {
-          conn->negnpn = CURL_HTTP_VERSION_2_0;
+          conn->negnpn = CURL_HTTP_VERSION_2;
         }
         else
 #endif
@@ -2256,58 +2266,59 @@ static int asn1_object_dump(ASN1_OBJECT *a, char *buf, size_t len)
   return 0;
 }
 
-static void pubkey_show(struct SessionHandle *data,
+#define push_certinfo(_label, _num) \
+do {                              \
+  long info_len = BIO_get_mem_data(mem, &ptr); \
+  Curl_ssl_push_certinfo_len(data, _num, _label, ptr, info_len); \
+  if(1!=BIO_reset(mem))                                          \
+    break;                                                       \
+} WHILE_FALSE
+
+static void pubkey_show(struct Curl_easy *data,
+                        BIO *mem,
                         int num,
                         const char *type,
                         const char *name,
-                        unsigned char *raw,
-                        int len)
+#ifdef HAVE_OPAQUE_RSA_DSA_DH
+                        const
+#endif
+                        BIGNUM *bn)
 {
-  size_t left;
-  int i;
+  char *ptr;
   char namebuf[32];
-  char *buffer;
-
-  left = len*3 + 1;
-  buffer = malloc(left);
-  if(buffer) {
-    char *ptr=buffer;
-    snprintf(namebuf, sizeof(namebuf), "%s(%s)", type, name);
-    for(i=0; i< len; i++) {
-      snprintf(ptr, left, "%02x:", raw[i]);
-      ptr += 3;
-      left -= 3;
-    }
-    infof(data, "   %s: %s\n", namebuf, buffer);
-    Curl_ssl_push_certinfo(data, num, namebuf, buffer);
-    free(buffer);
-  }
+
+  snprintf(namebuf, sizeof(namebuf), "%s(%s)", type, name);
+
+  if(bn)
+    BN_print(mem, bn);
+  push_certinfo(namebuf, num);
 }
 
+#ifdef HAVE_OPAQUE_RSA_DSA_DH
+#define print_pubkey_BN(_type, _name, _num)              \
+  pubkey_show(data, mem, _num, #_type, #_name, _name)
+
+#else
 #define print_pubkey_BN(_type, _name, _num)    \
 do {                              \
-  if(pubkey->pkey._type->_name) { \
-    int len = BN_num_bytes(pubkey->pkey._type->_name);  \
-    if(len < CERTBUFFERSIZE) {                                    \
-      BN_bn2bin(pubkey->pkey._type->_name, (unsigned char*)bufp); \
-      bufp[len] = 0;                                                    \
-      pubkey_show(data, _num, #_type, #_name, (unsigned char*)bufp, len); \
-    } \
+  if(_type->_name) { \
+    pubkey_show(data, mem, _num, #_type, #_name, _type->_name); \
   } \
 } WHILE_FALSE
+#endif
 
-static int X509V3_ext(struct SessionHandle *data,
+static int X509V3_ext(struct Curl_easy *data,
                       int certnum,
                       STACK_OF(X509_EXTENSION) *exts)
 {
   int i;
   size_t j;
 
-  if(sk_X509_EXTENSION_num(exts) <= 0)
+  if((int)sk_X509_EXTENSION_num(exts) <= 0)
     /* no extensions, bail out */
     return 1;
 
-  for(i=0; i<sk_X509_EXTENSION_num(exts); i++) {
+  for(i=0; i < (int)sk_X509_EXTENSION_num(exts); i++) {
     ASN1_OBJECT *obj;
     X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i);
     BUF_MEM *biomem;
@@ -2323,18 +2334,12 @@ static int X509V3_ext(struct SessionHandle *data,
 
     asn1_object_dump(obj, namebuf, sizeof(namebuf));
 
-    infof(data, "%s: %s\n", namebuf,
-          X509_EXTENSION_get_critical(ext)?"(critical)":"");
-
     if(!X509V3_EXT_print(bio_out, ext, 0, 0))
       ASN1_STRING_print(bio_out, (ASN1_STRING *)X509_EXTENSION_get_data(ext));
 
     BIO_get_mem_ptr(bio_out, &biomem);
 
-    /* biomem->length bytes at biomem->data, this little loop here is only
-       done for the infof() call, we send the "raw" data to the certinfo
-       function */
-    for(j=0; j<(size_t)biomem->length; j++) {
+    for(j = 0; j < (size_t)biomem->length; j++) {
       const char *sep="";
       if(biomem->data[j] == '\n') {
         sep=", ";
@@ -2346,7 +2351,6 @@ static int X509V3_ext(struct SessionHandle *data,
         ptr+=snprintf(ptr, sizeof(buf)-(ptr-buf), "%s%c", sep,
                       biomem->data[j]);
     }
-    infof(data, "  %s\n", buf);
 
     Curl_ssl_push_certinfo(data, certnum, namebuf, buf);
 
@@ -2356,46 +2360,6 @@ static int X509V3_ext(struct SessionHandle *data,
   return 0; /* all is fine */
 }
 
-
-static void X509_signature(struct SessionHandle *data,
-                           int numcert,
-                           ASN1_STRING *sig)
-{
-  char buf[1024];
-  char *ptr = buf;
-  int i;
-
-  for(i=0; i<sig->length; i++)
-    ptr+=snprintf(ptr, sizeof(buf)-(ptr-buf), "%02x:", sig->data[i]);
-
-  infof(data, " Signature: %s\n", buf);
-  Curl_ssl_push_certinfo(data, numcert, "Signature", buf);
-}
-
-static void dumpcert(struct SessionHandle *data, X509 *x, int numcert)
-{
-  BIO *bio_out = BIO_new(BIO_s_mem());
-  BUF_MEM *biomem;
-
-  /* this outputs the cert in this 64 column wide style with newlines and
-     -----BEGIN CERTIFICATE----- texts and more */
-  PEM_write_bio_X509(bio_out, x);
-
-  BIO_get_mem_ptr(bio_out, &biomem);
-
-  Curl_ssl_push_certinfo_len(data, numcert,
-                             "Cert", biomem->data, biomem->length);
-
-  BIO_free(bio_out);
-}
-
-/*
- * This size was previously 512 which has been reported "too small" without
- * any specifics, so it was enlarged to allow more data to get shown uncut.
- * The "perfect" size is yet to figure out.
- */
-#define CERTBUFFERSIZE 8192
-
 static CURLcode get_cert_chain(struct connectdata *conn,
                                struct ssl_connect_data *connssl)
 
@@ -2403,17 +2367,12 @@ static CURLcode get_cert_chain(struct connectdata *conn,
   CURLcode result;
   STACK_OF(X509) *sk;
   int i;
-  char *bufp;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   int numcerts;
-
-  bufp = malloc(CERTBUFFERSIZE);
-  if(!bufp)
-    return CURLE_OUT_OF_MEMORY;
+  BIO *mem;
 
   sk = SSL_get_peer_cert_chain(connssl->handle);
   if(!sk) {
-    free(bufp);
     return CURLE_OUT_OF_MEMORY;
   }
 
@@ -2421,99 +2380,122 @@ static CURLcode get_cert_chain(struct connectdata *conn,
 
   result = Curl_ssl_init_certinfo(data, numcerts);
   if(result) {
-    free(bufp);
     return result;
   }
 
-  infof(data, "--- Certificate chain\n");
-  for(i=0; i<numcerts; i++) {
-    long value;
-    ASN1_INTEGER *num;
-    ASN1_TIME *certdate;
+  mem = BIO_new(BIO_s_mem());
 
-    /* get the certs in "importance order" */
-#if 0
-    X509 *x = sk_X509_value(sk, numcerts - i - 1);
-#else
+  for(i = 0; i < numcerts; i++) {
+    ASN1_INTEGER *num;
     X509 *x = sk_X509_value(sk, i);
-#endif
-
-    X509_CINF *cinf;
     EVP_PKEY *pubkey=NULL;
     int j;
     char *ptr;
+    ASN1_BIT_STRING *psig = NULL;
 
-    (void)x509_name_oneline(X509_get_subject_name(x), bufp, CERTBUFFERSIZE);
-    infof(data, "%2d Subject: %s\n", i, bufp);
-    Curl_ssl_push_certinfo(data, i, "Subject", bufp);
+    X509_NAME_print_ex(mem, X509_get_subject_name(x), 0, XN_FLAG_ONELINE);
+    push_certinfo("Subject", i);
 
-    (void)x509_name_oneline(X509_get_issuer_name(x), bufp, CERTBUFFERSIZE);
-    infof(data, "   Issuer: %s\n", bufp);
-    Curl_ssl_push_certinfo(data, i, "Issuer", bufp);
+    X509_NAME_print_ex(mem, X509_get_issuer_name(x), 0, XN_FLAG_ONELINE);
+    push_certinfo("Issuer", i);
 
-    value = X509_get_version(x);
-    infof(data, "   Version: %lu (0x%lx)\n", value+1, value);
-    snprintf(bufp, CERTBUFFERSIZE, "%lx", value);
-    Curl_ssl_push_certinfo(data, i, "Version", bufp); /* hex */
+    BIO_printf(mem, "%lx", X509_get_version(x));
+    push_certinfo("Version", i);
 
-    num=X509_get_serialNumber(x);
-    {
-      int left = CERTBUFFERSIZE;
+    num = X509_get_serialNumber(x);
+    if(num->type == V_ASN1_NEG_INTEGER)
+      BIO_puts(mem, "-");
+    for(j = 0; j < num->length; j++)
+      BIO_printf(mem, "%02x", num->data[j]);
+    push_certinfo("Serial Number", i);
 
-      ptr = bufp;
-      if(num->type == V_ASN1_NEG_INTEGER) {
-        *ptr++='-';
-        left--;
-      }
-
-      for(j=0; (j<num->length) && (left>=3); j++) {
-        snprintf(ptr, left, "%02x", num->data[j]);
-        ptr += 2;
-        left -= 2;
+#if defined(HAVE_X509_GET0_SIGNATURE) && defined(HAVE_X509_GET0_EXTENSIONS)
+    {
+      X509_ALGOR *palg = NULL;
+      ASN1_STRING *a = ASN1_STRING_new();
+      if(a) {
+        X509_get0_signature(&psig, &palg, x);
+        X509_signature_print(mem, palg, a);
+        ASN1_STRING_free(a);
+
+        if(palg) {
+          i2a_ASN1_OBJECT(mem, palg->algorithm);
+          push_certinfo("Public Key Algorithm", i);
+        }
       }
-      if(num->length)
-        infof(data, "   Serial Number: %s\n", bufp);
-      else
-        bufp[0]=0;
+      X509V3_ext(data, i, X509_get0_extensions(x));
     }
-    if(bufp[0])
-      Curl_ssl_push_certinfo(data, i, "Serial Number", bufp); /* hex */
-
-    cinf = x->cert_info;
+#else
+    {
+      /* before OpenSSL 1.0.2 */
+      X509_CINF *cinf = x->cert_info;
 
-    j = asn1_object_dump(cinf->signature->algorithm, bufp, CERTBUFFERSIZE);
-    if(!j) {
-      infof(data, "   Signature Algorithm: %s\n", bufp);
-      Curl_ssl_push_certinfo(data, i, "Signature Algorithm", bufp);
-    }
+      i2a_ASN1_OBJECT(mem, cinf->signature->algorithm);
+      push_certinfo("Signature Algorithm", i);
 
-    certdate = X509_get_notBefore(x);
-    asn1_output(certdate, bufp, CERTBUFFERSIZE);
-    infof(data, "   Start date: %s\n", bufp);
-    Curl_ssl_push_certinfo(data, i, "Start date", bufp);
+      i2a_ASN1_OBJECT(mem, cinf->key->algor->algorithm);
+      push_certinfo("Public Key Algorithm", i);
 
-    certdate = X509_get_notAfter(x);
-    asn1_output(certdate, bufp, CERTBUFFERSIZE);
-    infof(data, "   Expire date: %s\n", bufp);
-    Curl_ssl_push_certinfo(data, i, "Expire date", bufp);
+      X509V3_ext(data, i, cinf->extensions);
 
-    j = asn1_object_dump(cinf->key->algor->algorithm, bufp, CERTBUFFERSIZE);
-    if(!j) {
-      infof(data, "   Public Key Algorithm: %s\n", bufp);
-      Curl_ssl_push_certinfo(data, i, "Public Key Algorithm", bufp);
+      psig = x->signature;
     }
+#endif
+
+    ASN1_TIME_print(mem, X509_get_notBefore(x));
+    push_certinfo("Start date", i);
+
+    ASN1_TIME_print(mem, X509_get_notAfter(x));
+    push_certinfo("Expire date", i);
 
     pubkey = X509_get_pubkey(x);
     if(!pubkey)
       infof(data, "   Unable to load public key\n");
     else {
-      switch(pubkey->type) {
+      int pktype;
+#ifdef HAVE_OPAQUE_EVP_PKEY
+      pktype = EVP_PKEY_id(pubkey);
+#else
+      pktype = pubkey->type;
+#endif
+      switch(pktype) {
       case EVP_PKEY_RSA:
-        infof(data,  "   RSA Public Key (%d bits)\n",
-              BN_num_bits(pubkey->pkey.rsa->n));
-        snprintf(bufp, CERTBUFFERSIZE, "%d", BN_num_bits(pubkey->pkey.rsa->n));
-        Curl_ssl_push_certinfo(data, i, "RSA Public Key", bufp);
-
+      {
+        RSA *rsa;
+#ifdef HAVE_OPAQUE_EVP_PKEY
+        rsa = EVP_PKEY_get0_RSA(pubkey);
+#else
+        rsa = pubkey->pkey.rsa;
+#endif
+
+#ifdef HAVE_OPAQUE_RSA_DSA_DH
+        {
+          const BIGNUM *n;
+          const BIGNUM *e;
+          const BIGNUM *d;
+          const BIGNUM *p;
+          const BIGNUM *q;
+          const BIGNUM *dmp1;
+          const BIGNUM *dmq1;
+          const BIGNUM *iqmp;
+
+          RSA_get0_key(rsa, &n, &e, &d);
+          RSA_get0_factors(rsa, &p, &q);
+          RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp);
+          BN_print(mem, n);
+          push_certinfo("RSA Public Key", i);
+          print_pubkey_BN(rsa, n, i);
+          print_pubkey_BN(rsa, e, i);
+          print_pubkey_BN(rsa, d, i);
+          print_pubkey_BN(rsa, p, i);
+          print_pubkey_BN(rsa, q, i);
+          print_pubkey_BN(rsa, dmp1, i);
+          print_pubkey_BN(rsa, dmq1, i);
+          print_pubkey_BN(rsa, iqmp, i);
+        }
+#else
+        BIO_printf(mem, "%d", BN_num_bits(rsa->n));
+        push_certinfo("RSA Public Key", i);
         print_pubkey_BN(rsa, n, i);
         print_pubkey_BN(rsa, e, i);
         print_pubkey_BN(rsa, d, i);
@@ -2522,20 +2504,75 @@ static CURLcode get_cert_chain(struct connectdata *conn,
         print_pubkey_BN(rsa, dmp1, i);
         print_pubkey_BN(rsa, dmq1, i);
         print_pubkey_BN(rsa, iqmp, i);
+#endif
+
         break;
+      }
       case EVP_PKEY_DSA:
+      {
+        DSA *dsa;
+#ifdef HAVE_OPAQUE_EVP_PKEY
+        dsa = EVP_PKEY_get0_DSA(pubkey);
+#else
+        dsa = pubkey->pkey.dsa;
+#endif
+#ifdef HAVE_OPAQUE_RSA_DSA_DH
+        {
+          const BIGNUM *p;
+          const BIGNUM *q;
+          const BIGNUM *g;
+          const BIGNUM *priv_key;
+          const BIGNUM *pub_key;
+
+          DSA_get0_pqg(dsa, &p, &q, &g);
+          DSA_get0_key(dsa, &pub_key, &priv_key);
+
+          print_pubkey_BN(dsa, p, i);
+          print_pubkey_BN(dsa, q, i);
+          print_pubkey_BN(dsa, g, i);
+          print_pubkey_BN(dsa, priv_key, i);
+          print_pubkey_BN(dsa, pub_key, i);
+        }
+#else
         print_pubkey_BN(dsa, p, i);
         print_pubkey_BN(dsa, q, i);
         print_pubkey_BN(dsa, g, i);
         print_pubkey_BN(dsa, priv_key, i);
         print_pubkey_BN(dsa, pub_key, i);
+#endif
         break;
+      }
       case EVP_PKEY_DH:
+      {
+        DH *dh;
+#ifdef HAVE_OPAQUE_EVP_PKEY
+        dh = EVP_PKEY_get0_DH(pubkey);
+#else
+        dh = pubkey->pkey.dh;
+#endif
+#ifdef HAVE_OPAQUE_RSA_DSA_DH
+        {
+          const BIGNUM *p;
+          const BIGNUM *q;
+          const BIGNUM *g;
+          const BIGNUM *priv_key;
+          const BIGNUM *pub_key;
+          DH_get0_pqg(dh, &p, &q, &g);
+          DH_get0_key(dh, &pub_key, &priv_key);
+          print_pubkey_BN(dh, p, i);
+          print_pubkey_BN(dh, q, i);
+          print_pubkey_BN(dh, g, i);
+          print_pubkey_BN(dh, priv_key, i);
+          print_pubkey_BN(dh, pub_key, i);
+       }
+#else
         print_pubkey_BN(dh, p, i);
         print_pubkey_BN(dh, g, i);
         print_pubkey_BN(dh, priv_key, i);
         print_pubkey_BN(dh, pub_key, i);
+#endif
         break;
+      }
 #if 0
       case EVP_PKEY_EC: /* symbol not present in OpenSSL 0.9.6 */
         /* left TODO */
@@ -2545,14 +2582,17 @@ static CURLcode get_cert_chain(struct connectdata *conn,
       EVP_PKEY_free(pubkey);
     }
 
-    X509V3_ext(data, i, cinf->extensions);
-
-    X509_signature(data, i, x->signature);
+    if(psig) {
+      for(j = 0; j < psig->length; j++)
+        BIO_printf(mem, "%02x:", psig->data[j]);
+      push_certinfo("Signature", i);
+    }
 
-    dumpcert(data, x, i);
+    PEM_write_bio_X509(mem, x);
+    push_certinfo("Cert", i);
   }
 
-  free(bufp);
+  BIO_free(mem);
 
   return CURLE_OK;
 }
@@ -2561,7 +2601,8 @@ static CURLcode get_cert_chain(struct connectdata *conn,
  * Heavily modified from:
  * https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning#OpenSSL
  */
-static CURLcode pkp_pin_peer_pubkey(X509* cert, const char *pinnedpubkey)
+static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, X509* cert,
+                                    const char *pinnedpubkey)
 {
   /* Scratch */
   int len1 = 0, len2 = 0;
@@ -2606,7 +2647,7 @@ static CURLcode pkp_pin_peer_pubkey(X509* cert, const char *pinnedpubkey)
     /* End Gyrations */
 
     /* The one good exit point */
-    result = Curl_pin_peer_pubkey(pinnedpubkey, buff1, len1);
+    result = Curl_pin_peer_pubkey(data, pinnedpubkey, buff1, len1);
   } while(0);
 
   /* https://www.openssl.org/docs/crypto/buffer.html */
@@ -2630,13 +2671,13 @@ static CURLcode servercert(struct connectdata *conn,
 {
   CURLcode result = CURLE_OK;
   int rc;
-  long lerr;
-  ASN1_TIME *certdate;
-  struct SessionHandle *data = conn->data;
+  long lerr, len;
+  struct Curl_easy *data = conn->data;
   X509 *issuer;
   FILE *fp;
   char *buffer = data->state.buffer;
   const char *ptr;
+  BIO *mem = BIO_new(BIO_s_mem());
 
   if(data->set.ssl.certinfo)
     /* we've been asked to gather certificate info! */
@@ -2644,8 +2685,10 @@ static CURLcode servercert(struct connectdata *conn,
 
   connssl->server_cert = SSL_get_peer_certificate(connssl->handle);
   if(!connssl->server_cert) {
-    if(strict)
-      failf(data, "SSL: couldn't get peer certificate!");
+    if(!strict)
+      return CURLE_OK;
+
+    failf(data, "SSL: couldn't get peer certificate!");
     return CURLE_PEER_FAILED_VERIFICATION;
   }
 
@@ -2653,15 +2696,19 @@ static CURLcode servercert(struct connectdata *conn,
 
   rc = x509_name_oneline(X509_get_subject_name(connssl->server_cert),
                          buffer, BUFSIZE);
-  infof(data, "\t subject: %s\n", rc?"[NONE]":buffer);
+  infof(data, " subject: %s\n", rc?"[NONE]":buffer);
+
+  ASN1_TIME_print(mem, X509_get_notBefore(connssl->server_cert));
+  len = BIO_get_mem_data(mem, (char **) &ptr);
+  infof(data, " start date: %.*s\n", len, ptr);
+  rc = BIO_reset(mem);
 
-  certdate = X509_get_notBefore(connssl->server_cert);
-  asn1_output(certdate, buffer, BUFSIZE);
-  infof(data, "\t start date: %s\n", buffer);
+  ASN1_TIME_print(mem, X509_get_notAfter(connssl->server_cert));
+  len = BIO_get_mem_data(mem, (char **) &ptr);
+  infof(data, " expire date: %.*s\n", len, ptr);
+  rc = BIO_reset(mem);
 
-  certdate = X509_get_notAfter(connssl->server_cert);
-  asn1_output(certdate, buffer, BUFSIZE);
-  infof(data, "\t expire date: %s\n", buffer);
+  BIO_free(mem);
 
   if(data->set.ssl.verifyhost) {
     result = verifyhost(conn, connssl->server_cert);
@@ -2680,7 +2727,7 @@ static CURLcode servercert(struct connectdata *conn,
     result = CURLE_SSL_CONNECT_ERROR;
   }
   else {
-    infof(data, "\t issuer: %s\n", buffer);
+    infof(data, " issuer: %s\n", buffer);
 
     /* We could do all sorts of certificate verification stuff here before
        deallocating the certificate. */
@@ -2720,7 +2767,7 @@ static CURLcode servercert(struct connectdata *conn,
         return CURLE_SSL_ISSUER_ERROR;
       }
 
-      infof(data, "\t SSL certificate issuer check ok (%s)\n",
+      infof(data, " SSL certificate issuer check ok (%s)\n",
             data->set.str[STRING_SSL_ISSUERCERT]);
       X509_free(issuer);
     }
@@ -2738,16 +2785,16 @@ static CURLcode servercert(struct connectdata *conn,
         result = CURLE_PEER_FAILED_VERIFICATION;
       }
       else
-        infof(data, "\t SSL certificate verify result: %s (%ld),"
+        infof(data, " SSL certificate verify result: %s (%ld),"
               " continuing anyway.\n",
               X509_verify_cert_error_string(lerr), lerr);
     }
     else
-      infof(data, "\t SSL certificate verify ok.\n");
+      infof(data, " SSL certificate verify ok.\n");
   }
 
 #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
-    !defined(OPENSSL_IS_BORINGSSL)
+    !defined(OPENSSL_NO_OCSP)
   if(data->set.ssl.verifystatus) {
     result = verifystatus(conn, connssl);
     if(result) {
@@ -2764,7 +2811,7 @@ static CURLcode servercert(struct connectdata *conn,
 
   ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
   if(!result && ptr) {
-    result = pkp_pin_peer_pubkey(connssl->server_cert, ptr);
+    result = pkp_pin_peer_pubkey(data, connssl->server_cert, ptr);
     if(result)
       failf(data, "SSL: public key does not match pinned public key!");
   }
@@ -2779,43 +2826,49 @@ static CURLcode servercert(struct connectdata *conn,
 static CURLcode ossl_connect_step3(struct connectdata *conn, int sockindex)
 {
   CURLcode result = CURLE_OK;
-  void *old_ssl_sessionid = NULL;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-  bool incache;
-  SSL_SESSION *our_ssl_sessionid;
 
   DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
 
-  our_ssl_sessionid = SSL_get1_session(connssl->handle);
+  if(conn->ssl_config.sessionid) {
+    bool incache;
+    SSL_SESSION *our_ssl_sessionid;
+    void *old_ssl_sessionid = NULL;
 
-  /* SSL_get1_session() will increment the reference count and the session
-     will stay in memory until explicitly freed with SSL_SESSION_free(3),
-     regardless of its state. */
+    our_ssl_sessionid = SSL_get1_session(connssl->handle);
 
-  incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL));
-  if(incache) {
-    if(old_ssl_sessionid != our_ssl_sessionid) {
-      infof(data, "old SSL session ID is stale, removing\n");
-      Curl_ssl_delsessionid(conn, old_ssl_sessionid);
-      incache = FALSE;
+    /* SSL_get1_session() will increment the reference count and the session
+        will stay in memory until explicitly freed with SSL_SESSION_free(3),
+        regardless of its state. */
+
+    Curl_ssl_sessionid_lock(conn);
+    incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL));
+    if(incache) {
+      if(old_ssl_sessionid != our_ssl_sessionid) {
+        infof(data, "old SSL session ID is stale, removing\n");
+        Curl_ssl_delsessionid(conn, old_ssl_sessionid);
+        incache = FALSE;
+      }
     }
-  }
 
-  if(!incache) {
-    result = Curl_ssl_addsessionid(conn, our_ssl_sessionid,
-                                   0 /* unknown size */);
-    if(result) {
-      failf(data, "failed to store ssl session");
-      return result;
+    if(!incache) {
+      result = Curl_ssl_addsessionid(conn, our_ssl_sessionid,
+                                      0 /* unknown size */);
+      if(result) {
+        Curl_ssl_sessionid_unlock(conn);
+        failf(data, "failed to store ssl session");
+        return result;
+      }
     }
-  }
-  else {
-    /* Session was incache, so refcount already incremented earlier.
-     * Avoid further increments with each SSL_get1_session() call.
-     * This does not free the session as refcount remains > 0
-     */
-    SSL_SESSION_free(our_ssl_sessionid);
+    else {
+      /* Session was incache, so refcount already incremented earlier.
+        * Avoid further increments with each SSL_get1_session() call.
+        * This does not free the session as refcount remains > 0
+        */
+      SSL_SESSION_free(our_ssl_sessionid);
+    }
+    Curl_ssl_sessionid_unlock(conn);
   }
 
   /*
@@ -2843,7 +2896,7 @@ static CURLcode ossl_connect_common(struct connectdata *conn,
                                     bool *done)
 {
   CURLcode result;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   curl_socket_t sockfd = conn->sock[sockindex];
   long timeout_ms;
@@ -2987,7 +3040,7 @@ static ssize_t ossl_send(struct connectdata *conn,
   /* SSL_write() is said to return 'int' while write() and send() returns
      'size_t' */
   int err;
-  char error_buffer[120]; /* OpenSSL documents that this must be at least 120
+  char error_buffer[256]; /* OpenSSL documents that this must be at least 256
                              bytes long. */
   unsigned long sslerror;
   int memlen;
@@ -3019,7 +3072,7 @@ static ssize_t ossl_send(struct connectdata *conn,
           The OpenSSL error queue contains more information on the error. */
       sslerror = ERR_get_error();
       failf(conn->data, "SSL_write() error: %s",
-            ERR_error_string(sslerror, error_buffer));
+            ossl_strerror(sslerror, error_buffer, sizeof(error_buffer)));
       *curlcode = CURLE_SEND_ERROR;
       return -1;
     }
@@ -3038,8 +3091,8 @@ static ssize_t ossl_recv(struct connectdata *conn, /* connection data */
                          size_t buffersize,        /* max amount to read */
                          CURLcode *curlcode)
 {
-  char error_buffer[120]; /* OpenSSL documents that this must be at
-                             least 120 bytes long. */
+  char error_buffer[256]; /* OpenSSL documents that this must be at
+                             least 256 bytes long. */
   unsigned long sslerror;
   ssize_t nread;
   int buffsize;
@@ -3070,7 +3123,7 @@ static ssize_t ossl_recv(struct connectdata *conn, /* connection data */
         /* If the return code was negative or there actually is an error in the
            queue */
         failf(conn->data, "SSL read: %s, errno %d",
-              ERR_error_string(sslerror, error_buffer),
+              ossl_strerror(sslerror, error_buffer, sizeof(error_buffer)),
               SOCKERRNO);
         *curlcode = CURLE_RECV_ERROR;
         return -1;
@@ -3082,86 +3135,45 @@ static ssize_t ossl_recv(struct connectdata *conn, /* connection data */
 
 size_t Curl_ossl_version(char *buffer, size_t size)
 {
-#ifdef YASSL_VERSION
-  /* yassl provides an OpenSSL API compatibility layer so it looks identical
-     to OpenSSL in all other aspects */
-  return snprintf(buffer, size, "yassl/%s", YASSL_VERSION);
-#else /* YASSL_VERSION */
 #ifdef OPENSSL_IS_BORINGSSL
-  return snprintf(buffer, size, "BoringSSL");
+  return snprintf(buffer, size, OSSL_PACKAGE);
 #else /* OPENSSL_IS_BORINGSSL */
-
-#if(OPENSSL_VERSION_NUMBER >= 0x905000)
-  {
-    char sub[3];
-    unsigned long ssleay_value;
-    sub[2]='\0';
-    sub[1]='\0';
-    ssleay_value=SSLeay();
-    if(ssleay_value < 0x906000) {
-      ssleay_value=SSLEAY_VERSION_NUMBER;
-      sub[0]='\0';
-    }
-    else {
-      if(ssleay_value&0xff0) {
-        int minor_ver = (ssleay_value >> 4) & 0xff;
-        if(minor_ver > 26) {
-          /* handle extended version introduced for 0.9.8za */
-          sub[1] = (char) ((minor_ver - 1) % 26 + 'a' + 1);
-          sub[0] = 'z';
-        }
-        else {
-          sub[0]=(char)(((ssleay_value>>4)&0xff) + 'a' -1);
-        }
-      }
-      else
-        sub[0]='\0';
-    }
-
-    return snprintf(buffer, size, "%s/%lx.%lx.%lx%s",
-#ifdef LIBRESSL_VERSION_NUMBER
-                    "LibreSSL"
-#else
-                    "OpenSSL"
-#endif
-                    , (ssleay_value>>28)&0xf,
-                    (ssleay_value>>20)&0xff,
-                    (ssleay_value>>12)&0xff,
-                    sub);
+  char sub[3];
+  unsigned long ssleay_value;
+  sub[2]='\0';
+  sub[1]='\0';
+  ssleay_value=SSLeay();
+  if(ssleay_value < 0x906000) {
+    ssleay_value=SSLEAY_VERSION_NUMBER;
+    sub[0]='\0';
   }
-
-#else /* OPENSSL_VERSION_NUMBER is less than 0.9.5 */
-
-#if(OPENSSL_VERSION_NUMBER >= 0x900000)
-  return snprintf(buffer, size, "OpenSSL/%lx.%lx.%lx",
-                  (OPENSSL_VERSION_NUMBER>>28)&0xff,
-                  (OPENSSL_VERSION_NUMBER>>20)&0xff,
-                  (OPENSSL_VERSION_NUMBER>>12)&0xf);
-
-#else /* (OPENSSL_VERSION_NUMBER >= 0x900000) */
-  {
-    char sub[2];
-    sub[1]='\0';
-    if(OPENSSL_VERSION_NUMBER&0x0f) {
-      sub[0]=(OPENSSL_VERSION_NUMBER&0x0f) + 'a' -1;
+  else {
+    if(ssleay_value&0xff0) {
+      int minor_ver = (ssleay_value >> 4) & 0xff;
+      if(minor_ver > 26) {
+        /* handle extended version introduced for 0.9.8za */
+        sub[1] = (char) ((minor_ver - 1) % 26 + 'a' + 1);
+        sub[0] = 'z';
+      }
+      else {
+        sub[0]=(char)(((ssleay_value>>4)&0xff) + 'a' -1);
+      }
     }
     else
       sub[0]='\0';
-
-    return snprintf(buffer, size, "SSL/%x.%x.%x%s",
-                    (OPENSSL_VERSION_NUMBER>>12)&0xff,
-                    (OPENSSL_VERSION_NUMBER>>8)&0xf,
-                    (OPENSSL_VERSION_NUMBER>>4)&0xf, sub);
   }
-#endif /* (OPENSSL_VERSION_NUMBER >= 0x900000) */
-#endif /* OPENSSL_VERSION_NUMBER is less than 0.9.5 */
 
+  return snprintf(buffer, size, "%s/%lx.%lx.%lx%s",
+                  OSSL_PACKAGE,
+                  (ssleay_value>>28)&0xf,
+                  (ssleay_value>>20)&0xff,
+                  (ssleay_value>>12)&0xff,
+                  sub);
 #endif /* OPENSSL_IS_BORINGSSL */
-#endif /* YASSL_VERSION */
 }
 
 /* can be called with data == NULL */
-int Curl_ossl_random(struct SessionHandle *data, unsigned char *entropy,
+int Curl_ossl_random(struct Curl_easy *data, unsigned char *entropy,
                      size_t length)
 {
   if(data) {
@@ -3183,7 +3195,7 @@ void Curl_ossl_md5sum(unsigned char *tmp, /* input */
   MD5_Final(md5sum, &MD5pw);
 }
 
-#ifndef OPENSSL_NO_SHA256
+#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
 void Curl_ossl_sha256sum(const unsigned char *tmp, /* input */
                       size_t tmplen,
                       unsigned char *sha256sum /* output */,
@@ -3200,7 +3212,7 @@ void Curl_ossl_sha256sum(const unsigned char *tmp, /* input */
 bool Curl_ossl_cert_status_request(void)
 {
 #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
-    !defined(OPENSSL_IS_BORINGSSL)
+    !defined(OPENSSL_NO_OCSP)
   return TRUE;
 #else
   return FALSE;
diff --git a/lib/vtls/openssl.h b/lib/vtls/openssl.h
index a1f347a..ee18e71 100644
--- a/lib/vtls/openssl.h
+++ b/lib/vtls/openssl.h
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -41,20 +41,20 @@ void Curl_ossl_close(struct connectdata *conn, int sockindex);
 
 /* tell OpenSSL to close down all open information regarding connections (and
    thus session ID caching etc) */
-void Curl_ossl_close_all(struct SessionHandle *data);
+void Curl_ossl_close_all(struct Curl_easy *data);
 
 /* Sets an OpenSSL engine */
-CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine);
+CURLcode Curl_ossl_set_engine(struct Curl_easy *data, const char *engine);
 
 /* function provided for the generic SSL-layer, called when a session id
    should be freed */
 void Curl_ossl_session_free(void *ptr);
 
 /* Sets engine as default for all SSL operations */
-CURLcode Curl_ossl_set_engine_default(struct SessionHandle *data);
+CURLcode Curl_ossl_set_engine_default(struct Curl_easy *data);
 
 /* Build list of OpenSSL engines */
-struct curl_slist *Curl_ossl_engines_list(struct SessionHandle *data);
+struct curl_slist *Curl_ossl_engines_list(struct Curl_easy *data);
 
 int Curl_ossl_init(void);
 void Curl_ossl_cleanup(void);
@@ -66,7 +66,7 @@ bool Curl_ossl_data_pending(const struct connectdata *conn,
                             int connindex);
 
 /* return 0 if a find random is filled in */
-int Curl_ossl_random(struct SessionHandle *data, unsigned char *entropy,
+int Curl_ossl_random(struct Curl_easy *data, unsigned char *entropy,
                      size_t length);
 void Curl_ossl_md5sum(unsigned char *tmp, /* input */
                       size_t tmplen,
@@ -88,9 +88,12 @@ bool Curl_ossl_cert_status_request(void);
 /* this backend supports CURLOPT_CERTINFO */
 #define have_curlssl_certinfo 1
 
-/* this backend suppots CURLOPT_SSL_CTX_* */
+/* this backend supports CURLOPT_SSL_CTX_* */
 #define have_curlssl_ssl_ctx 1
 
+/* this backend supports CURLOPT_PINNEDPUBLICKEY */
+#define have_curlssl_pinnedpubkey 1
+
 /* API setup for OpenSSL */
 #define curlssl_init Curl_ossl_init
 #define curlssl_cleanup Curl_ossl_cleanup
@@ -108,7 +111,7 @@ bool Curl_ossl_cert_status_request(void);
 #define curlssl_data_pending(x,y) Curl_ossl_data_pending(x,y)
 #define curlssl_random(x,y,z) Curl_ossl_random(x,y,z)
 #define curlssl_md5sum(a,b,c,d) Curl_ossl_md5sum(a,b,c,d)
-#ifndef OPENSSL_NO_SHA256
+#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
 #define curlssl_sha256sum(a,b,c,d) Curl_ossl_sha256sum(a,b,c,d)
 #endif
 #define curlssl_cert_status_request() Curl_ossl_cert_status_request()
diff --git a/lib/vtls/polarssl.c b/lib/vtls/polarssl.c
index 066c055..d33f548 100644
--- a/lib/vtls/polarssl.c
+++ b/lib/vtls/polarssl.c
@@ -5,12 +5,12 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
+ * Copyright (C) 2012 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  * Copyright (C) 2010 - 2011, Hoi-Ho Chan, <hoiho.chan at gmail.com>
- * Copyright (C) 2012 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -36,6 +36,7 @@
 #include <polarssl/certs.h>
 #include <polarssl/x509.h>
 #include <polarssl/version.h>
+#include <polarssl/sha256.h>
 
 #if POLARSSL_VERSION_NUMBER < 0x01030000
 #error too old PolarSSL
@@ -60,6 +61,15 @@
 /* The last #include file should be: */
 #include "memdebug.h"
 
+/* See https://tls.mbed.org/discussions/generic/
+   howto-determine-exact-buffer-len-for-mbedtls_pk_write_pubkey_der
+*/
+#define RSA_PUB_DER_MAX_BYTES   (38 + 2 * POLARSSL_MPI_MAX_SIZE)
+#define ECP_PUB_DER_MAX_BYTES   (30 + 2 * POLARSSL_ECP_MAX_BYTES)
+
+#define PUB_DER_MAX_BYTES   (RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \
+                             RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES)
+
 /* apply threading? */
 #if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
 #define THREADING_SUPPORT
@@ -74,12 +84,12 @@ static int  entropy_init_initialized  = 0;
 static void entropy_init_mutex(entropy_context *ctx)
 {
   /* lock 0 = entropy_init_mutex() */
-  polarsslthreadlock_lock_function(0);
+  Curl_polarsslthreadlock_lock_function(0);
   if(entropy_init_initialized == 0) {
     entropy_init(ctx);
     entropy_init_initialized = 1;
   }
-  polarsslthreadlock_unlock_function(0);
+  Curl_polarsslthreadlock_unlock_function(0);
 }
 /* end of entropy_init_mutex() */
 
@@ -88,9 +98,9 @@ static int entropy_func_mutex(void *data, unsigned char *output, size_t len)
 {
     int ret;
     /* lock 1 = entropy_func_mutex() */
-    polarsslthreadlock_lock_function(1);
+    Curl_polarsslthreadlock_lock_function(1);
     ret = entropy_func(data, output, len);
-    polarsslthreadlock_unlock_function(1);
+    Curl_polarsslthreadlock_unlock_function(1);
 
     return ret;
 }
@@ -104,12 +114,12 @@ static int entropy_func_mutex(void *data, unsigned char *output, size_t len)
 #ifdef POLARSSL_DEBUG
 static void polarssl_debug(void *context, int level, const char *line)
 {
-  struct SessionHandle *data = NULL;
+  struct Curl_easy *data = NULL;
 
   if(!context)
     return;
 
-  data = (struct SessionHandle *)context;
+  data = (struct Curl_easy *)context;
 
   infof(data, "%s", line);
   (void) level;
@@ -130,7 +140,7 @@ static CURLcode
 polarssl_connect_step1(struct connectdata *conn,
                      int sockindex)
 {
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct ssl_connect_data* connssl = &conn->ssl[sockindex];
 
   bool sni = TRUE; /* default is SNI enabled */
@@ -140,8 +150,6 @@ polarssl_connect_step1(struct connectdata *conn,
 #else
   struct in_addr addr;
 #endif
-  void *old_session = NULL;
-  size_t old_session_size = 0;
   char errorbuf[128];
   errorbuf[0]=0;
 
@@ -157,7 +165,7 @@ polarssl_connect_step1(struct connectdata *conn,
   entropy_init_mutex(&entropy);
 
   if((ret = ctr_drbg_init(&connssl->ctr_drbg, entropy_func_mutex, &entropy,
-                               connssl->ssn.id, connssl->ssn.length)) != 0) {
+                          NULL, 0)) != 0) {
 #ifdef POLARSSL_ERROR_C
      error_strerror(ret, errorbuf, sizeof(errorbuf));
 #endif /* POLARSSL_ERROR_C */
@@ -168,7 +176,7 @@ polarssl_connect_step1(struct connectdata *conn,
   entropy_init(&connssl->entropy);
 
   if((ret = ctr_drbg_init(&connssl->ctr_drbg, entropy_func, &connssl->entropy,
-                                connssl->ssn.id, connssl->ssn.length)) != 0) {
+                          NULL, 0)) != 0) {
 #ifdef POLARSSL_ERROR_C
      error_strerror(ret, errorbuf, sizeof(errorbuf));
 #endif /* POLARSSL_ERROR_C */
@@ -328,13 +336,22 @@ polarssl_connect_step1(struct connectdata *conn,
               net_send, &conn->sock[sockindex]);
 
   ssl_set_ciphersuites(&connssl->ssl, ssl_list_ciphersuites());
-  if(!Curl_ssl_getsessionid(conn, &old_session, &old_session_size)) {
-    memcpy(&connssl->ssn, old_session, old_session_size);
-    infof(data, "PolarSSL re-using session\n");
-  }
 
-  ssl_set_session(&connssl->ssl,
-                  &connssl->ssn);
+  /* Check if there's a cached ID we can/should use here! */
+  if(conn->ssl_config.sessionid) {
+    void *old_session = NULL;
+
+    Curl_ssl_sessionid_lock(conn);
+    if(!Curl_ssl_getsessionid(conn, &old_session, NULL)) {
+      ret = ssl_set_session(&connssl->ssl, old_session);
+      Curl_ssl_sessionid_unlock(conn);
+      if(ret) {
+        failf(data, "ssl_set_session returned -0x%x", -ret);
+        return CURLE_SSL_CONNECT_ERROR;
+      }
+      infof(data, "PolarSSL re-using session\n");
+    }
+  }
 
   ssl_set_ca_chain(&connssl->ssl,
                    &connssl->cacert,
@@ -344,22 +361,21 @@ polarssl_connect_step1(struct connectdata *conn,
   ssl_set_own_cert_rsa(&connssl->ssl,
                        &connssl->clicert, &connssl->rsa);
 
-  if(!Curl_inet_pton(AF_INET, conn->host.name, &addr) &&
-#ifdef ENABLE_IPV6
-     !Curl_inet_pton(AF_INET6, conn->host.name, &addr) &&
-#endif
-     sni && ssl_set_hostname(&connssl->ssl, conn->host.name)) {
-     infof(data, "WARNING: failed to configure "
-                 "server name indication (SNI) TLS extension\n");
+  if(ssl_set_hostname(&connssl->ssl, conn->host.name)) {
+    /* ssl_set_hostname() sets the name to use in CN/SAN checks *and* the name
+       to set in the SNI extension. So even if curl connects to a host
+       specified as an IP address, this function must be used. */
+    failf(data, "couldn't set hostname in PolarSSL");
+    return CURLE_SSL_CONNECT_ERROR;
   }
 
 #ifdef HAS_ALPN
-  if(data->set.ssl_enable_alpn) {
+  if(conn->bits.tls_enable_alpn) {
     static const char* protocols[3];
     int cur = 0;
 
 #ifdef USE_NGHTTP2
-    if(data->set.httpversion == CURL_HTTP_VERSION_2_0) {
+    if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
       protocols[cur++] = NGHTTP2_PROTO_VERSION_ID;
       infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
     }
@@ -388,7 +404,7 @@ polarssl_connect_step2(struct connectdata *conn,
                      int sockindex)
 {
   int ret;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct ssl_connect_data* connssl = &conn->ssl[sockindex];
   char buffer[1024];
 
@@ -453,8 +469,63 @@ polarssl_connect_step2(struct connectdata *conn,
       infof(data, "Dumping cert info:\n%s\n", buffer);
   }
 
+  /* adapted from mbedtls.c */
+  if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) {
+    int size;
+    CURLcode result;
+    x509_crt *p;
+    unsigned char pubkey[PUB_DER_MAX_BYTES];
+    const x509_crt *peercert;
+
+    peercert = ssl_get_peer_cert(&connssl->ssl);
+
+    if(!peercert || !peercert->raw.p || !peercert->raw.len) {
+      failf(data, "Failed due to missing peer certificate");
+      return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+    }
+
+    p = calloc(1, sizeof(*p));
+
+    if(!p)
+      return CURLE_OUT_OF_MEMORY;
+
+    x509_crt_init(p);
+
+    /* Make a copy of our const peercert because pk_write_pubkey_der
+       needs a non-const key, for now.
+       https://github.com/ARMmbed/mbedtls/issues/396 */
+    if(x509_crt_parse_der(p, peercert->raw.p, peercert->raw.len)) {
+      failf(data, "Failed copying peer certificate");
+      x509_crt_free(p);
+      free(p);
+      return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+    }
+
+    size = pk_write_pubkey_der(&p->pk, pubkey, PUB_DER_MAX_BYTES);
+
+    if(size <= 0) {
+      failf(data, "Failed copying public key from peer certificate");
+      x509_crt_free(p);
+      free(p);
+      return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+    }
+
+    /* pk_write_pubkey_der writes data at the end of the buffer. */
+    result = Curl_pin_peer_pubkey(data,
+                                  data->set.str[STRING_SSL_PINNEDPUBLICKEY],
+                                  &pubkey[PUB_DER_MAX_BYTES - size], size);
+    if(result) {
+      x509_crt_free(p);
+      free(p);
+      return result;
+    }
+
+    x509_crt_free(p);
+    free(p);
+  }
+
 #ifdef HAS_ALPN
-  if(data->set.ssl_enable_alpn) {
+  if(conn->bits.tls_enable_alpn) {
     const char *next_protocol = ssl_get_alpn_protocol(&connssl->ssl);
 
     if(next_protocol != NULL) {
@@ -463,7 +534,7 @@ polarssl_connect_step2(struct connectdata *conn,
 #ifdef USE_NGHTTP2
       if(!strncmp(next_protocol, NGHTTP2_PROTO_VERSION_ID,
                   NGHTTP2_PROTO_VERSION_ID_LEN)) {
-        conn->negnpn = CURL_HTTP_VERSION_2_0;
+        conn->negnpn = CURL_HTTP_VERSION_2;
       }
       else
 #endif
@@ -486,39 +557,40 @@ static CURLcode
 polarssl_connect_step3(struct connectdata *conn,
                      int sockindex)
 {
-  CURLcode result = CURLE_OK;
+  CURLcode retcode = CURLE_OK;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-  struct SessionHandle *data = conn->data;
-  void *old_ssl_sessionid = NULL;
-  ssl_session *our_ssl_sessionid = &conn->ssl[sockindex].ssn;
-  bool incache;
+  struct Curl_easy *data = conn->data;
 
   DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
 
-  /* Save the current session data for possible re-use */
-  incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL));
-  if(incache) {
-    if(old_ssl_sessionid != our_ssl_sessionid) {
-      infof(data, "old SSL session ID is stale, removing\n");
-      Curl_ssl_delsessionid(conn, old_ssl_sessionid);
-      incache = FALSE;
-    }
-  }
+  if(conn->ssl_config.sessionid) {
+    int ret;
+    ssl_session *our_ssl_sessionid;
+    void *old_ssl_sessionid = NULL;
 
-  if(!incache) {
-    void *new_session = malloc(sizeof(ssl_session));
+    our_ssl_sessionid = malloc(sizeof(ssl_session));
+    if(!our_ssl_sessionid)
+      return CURLE_OUT_OF_MEMORY;
 
-    if(new_session) {
-      memcpy(new_session, our_ssl_sessionid, sizeof(ssl_session));
+    ssl_session_init(our_ssl_sessionid);
 
-      result = Curl_ssl_addsessionid(conn, new_session, sizeof(ssl_session));
+    ret = ssl_get_session(&connssl->ssl, our_ssl_sessionid);
+    if(ret) {
+      failf(data, "ssl_get_session returned -0x%x", -ret);
+      return CURLE_SSL_CONNECT_ERROR;
     }
-    else
-      result = CURLE_OUT_OF_MEMORY;
 
-    if(result) {
+    /* If there's already a matching session in the cache, delete it */
+    Curl_ssl_sessionid_lock(conn);
+    if(!Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL))
+      Curl_ssl_delsessionid(conn, old_ssl_sessionid);
+
+    retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, 0);
+    Curl_ssl_sessionid_unlock(conn);
+    if(retcode) {
+      free(our_ssl_sessionid);
       failf(data, "failed to store ssl session");
-      return result;
+      return retcode;
     }
   }
 
@@ -584,6 +656,7 @@ static ssize_t polarssl_recv(struct connectdata *conn,
 
 void Curl_polarssl_session_free(void *ptr)
 {
+  ssl_session_free(ptr);
   free(ptr);
 }
 
@@ -605,7 +678,7 @@ polarssl_connect_common(struct connectdata *conn,
                         bool *done)
 {
   CURLcode result;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   curl_socket_t sockfd = conn->sock[sockindex];
   long timeout_ms;
@@ -740,14 +813,14 @@ Curl_polarssl_connect(struct connectdata *conn,
  * return 0 error initializing SSL
  * return 1 SSL initialized successfully
  */
-int polarssl_init(void)
+int Curl_polarssl_init(void)
 {
-  return polarsslthreadlock_thread_setup();
+  return Curl_polarsslthreadlock_thread_setup();
 }
 
-void polarssl_cleanup(void)
+void Curl_polarssl_cleanup(void)
 {
-  (void)polarsslthreadlock_thread_cleanup();
+  (void)Curl_polarsslthreadlock_thread_cleanup();
 }
 
 #endif /* USE_POLARSSL */
diff --git a/lib/vtls/polarssl.h b/lib/vtls/polarssl.h
index f980dbb..7098b24 100644
--- a/lib/vtls/polarssl.h
+++ b/lib/vtls/polarssl.h
@@ -7,12 +7,12 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
+ * Copyright (C) 2012 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  * Copyright (C) 2010, Hoi-Ho Chan, <hoiho.chan at gmail.com>
- * Copyright (C) 2012 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -26,9 +26,11 @@
 
 #ifdef USE_POLARSSL
 
+#include <polarssl/sha256.h>
+
 /* Called on first use PolarSSL, setup threading if supported */
-int  polarssl_init(void);
-void polarssl_cleanup(void);
+int  Curl_polarssl_init(void);
+void Curl_polarssl_cleanup(void);
 
 
 CURLcode Curl_polarssl_connect(struct connectdata *conn, int sockindex);
@@ -50,9 +52,12 @@ int Curl_polarssl_shutdown(struct connectdata *conn, int sockindex);
 /* this backend supports the CAPATH option */
 #define have_curlssl_ca_path 1
 
+/* this backends supports CURLOPT_PINNEDPUBLICKEY */
+#define have_curlssl_pinnedpubkey 1
+
 /* API setup for PolarSSL */
-#define curlssl_init() polarssl_init()
-#define curlssl_cleanup() polarssl_cleanup()
+#define curlssl_init() Curl_polarssl_init()
+#define curlssl_cleanup() Curl_polarssl_cleanup()
 #define curlssl_connect Curl_polarssl_connect
 #define curlssl_connect_nonblocking Curl_polarssl_connect_nonblocking
 #define curlssl_session_free(x)  Curl_polarssl_session_free(x)
@@ -65,6 +70,7 @@ int Curl_polarssl_shutdown(struct connectdata *conn, int sockindex);
 #define curlssl_version Curl_polarssl_version
 #define curlssl_check_cxn(x) ((void)x, -1)
 #define curlssl_data_pending(x,y) ((void)x, (void)y, 0)
+#define curlssl_sha256sum(a,b,c,d) sha256(a,b,c,0)
 
 /* This might cause libcurl to use a weeker random!
    TODO: implement proper use of Polarssl's CTR-DRBG or HMAC-DRBG and use that
diff --git a/lib/vtls/polarssl_threadlock.c b/lib/vtls/polarssl_threadlock.c
index 62abf43..3b0ebf8 100644
--- a/lib/vtls/polarssl_threadlock.c
+++ b/lib/vtls/polarssl_threadlock.c
@@ -5,12 +5,12 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
+ * Copyright (C) 2013-2015, Daniel Stenberg, <daniel at haxx.se>, et al.
  * Copyright (C) 2010, 2011, Hoi-Ho Chan, <hoiho.chan at gmail.com>
- * Copyright (C) 2013, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -22,7 +22,7 @@
  ***************************************************************************/
 #include "curl_setup.h"
 
-#if defined(USE_POLARSSL) && \
+#if (defined(USE_POLARSSL) || defined(USE_MBEDTLS)) && \
     (defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32))
 
 #if defined(USE_THREADS_POSIX)
@@ -47,7 +47,7 @@
 /* This array will store all of the mutexes available to PolarSSL. */
 static POLARSSL_MUTEX_T *mutex_buf = NULL;
 
-int polarsslthreadlock_thread_setup(void)
+int Curl_polarsslthreadlock_thread_setup(void)
 {
   int i;
   int ret;
@@ -73,7 +73,7 @@ int polarsslthreadlock_thread_setup(void)
   return 1; /* OK */
 }
 
-int polarsslthreadlock_thread_cleanup(void)
+int Curl_polarsslthreadlock_thread_cleanup(void)
 {
   int i;
   int ret;
@@ -100,7 +100,7 @@ int polarsslthreadlock_thread_cleanup(void)
   return 1; /* OK */
 }
 
-int polarsslthreadlock_lock_function(int n)
+int Curl_polarsslthreadlock_lock_function(int n)
 {
   int ret;
 #ifdef HAVE_PTHREAD_H
@@ -125,7 +125,7 @@ int polarsslthreadlock_lock_function(int n)
   return 1; /* OK */
 }
 
-int polarsslthreadlock_unlock_function(int n)
+int Curl_polarsslthreadlock_unlock_function(int n)
 {
   int ret;
 #ifdef HAVE_PTHREAD_H
@@ -150,4 +150,4 @@ int polarsslthreadlock_unlock_function(int n)
   return 1; /* OK */
 }
 
-#endif /* USE_POLARSSL */
+#endif /* USE_POLARSSL || USE_MBEDTLS */
diff --git a/lib/vtls/polarssl_threadlock.h b/lib/vtls/polarssl_threadlock.h
index b67b3f9..dda5359 100644
--- a/lib/vtls/polarssl_threadlock.h
+++ b/lib/vtls/polarssl_threadlock.h
@@ -7,12 +7,12 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
+ * Copyright (C) 2013-2015, Daniel Stenberg, <daniel at haxx.se>, et al.
  * Copyright (C) 2010, Hoi-Ho Chan, <hoiho.chan at gmail.com>
- * Copyright (C) 2013, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -24,7 +24,7 @@
  ***************************************************************************/
 #include "curl_setup.h"
 
-#ifdef USE_POLARSSL
+#if (defined USE_POLARSSL) || (defined USE_MBEDTLS)
 
 #if defined(USE_THREADS_POSIX)
 #  define POLARSSL_MUTEX_T       pthread_mutex_t
@@ -34,17 +34,17 @@
 
 #if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
 
-int polarsslthreadlock_thread_setup(void);
-int polarsslthreadlock_thread_cleanup(void);
-int polarsslthreadlock_lock_function(int n);
-int polarsslthreadlock_unlock_function(int n);
+int Curl_polarsslthreadlock_thread_setup(void);
+int Curl_polarsslthreadlock_thread_cleanup(void);
+int Curl_polarsslthreadlock_lock_function(int n);
+int Curl_polarsslthreadlock_unlock_function(int n);
 
 #else
 
-#define polarsslthreadlock_thread_setup() 1
-#define polarsslthreadlock_thread_cleanup() 1
-#define polarsslthreadlock_lock_function(x) 1
-#define polarsslthreadlock_unlock_function(x) 1
+#define Curl_polarsslthreadlock_thread_setup() 1
+#define Curl_polarsslthreadlock_thread_cleanup() 1
+#define Curl_polarsslthreadlock_lock_function(x) 1
+#define Curl_polarsslthreadlock_unlock_function(x) 1
 
 #endif /* USE_THREADS_POSIX || USE_THREADS_WIN32 */
 
diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c
index 2174e21..f991ec9 100644
--- a/lib/vtls/schannel.c
+++ b/lib/vtls/schannel.c
@@ -5,13 +5,13 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2012 - 2015, Marc Hoersken, <info at marc-hoersken.de>
+ * Copyright (C) 2012 - 2016, Marc Hoersken, <info at marc-hoersken.de>
  * Copyright (C) 2012, Mark Salisbury, <mark.salisbury at hp.com>
- * Copyright (C) 2012 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 2012 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -56,11 +56,23 @@
 #include "inet_pton.h" /* for IP addr SNI check */
 #include "curl_multibyte.h"
 #include "warnless.h"
+#include "x509asn1.h"
 #include "curl_printf.h"
+#include "system_win32.h"
+
+ /* The last #include file should be: */
 #include "curl_memory.h"
-/* The last #include file should be: */
 #include "memdebug.h"
 
+/* ALPN requires version 8.1 of the Windows SDK, which was
+   shipped with Visual Studio 2013, aka _MSC_VER 1800:
+
+   https://technet.microsoft.com/en-us/library/hh831771%28v=ws.11%29.aspx
+*/
+#if defined(_MSC_VER) && (_MSC_VER >= 1800) && !defined(_USING_V110_SDK71_)
+#  define HAS_ALPN 1
+#endif
+
 /* Uncomment to force verbose output
  * #define infof(x, y, ...) printf(y, __VA_ARGS__)
  * #define failf(x, y, ...) printf(y, __VA_ARGS__)
@@ -93,10 +105,15 @@ static CURLcode
 schannel_connect_step1(struct connectdata *conn, int sockindex)
 {
   ssize_t written = -1;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   SecBuffer outbuf;
   SecBufferDesc outbuf_desc;
+  SecBuffer inbuf;
+  SecBufferDesc inbuf_desc;
+#ifdef HAS_ALPN
+  unsigned char alpn_buffer[128];
+#endif
   SCHANNEL_CRED schannel_cred;
   SECURITY_STATUS sspi_status = SEC_E_OK;
   struct curl_schannel_cred *old_cred = NULL;
@@ -110,12 +127,24 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
   infof(data, "schannel: SSL/TLS connection with %s port %hu (step 1/3)\n",
         conn->host.name, conn->remote_port);
 
+  connssl->cred = NULL;
+
   /* check for an existing re-usable credential handle */
-  if(!Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL)) {
-    connssl->cred = old_cred;
-    infof(data, "schannel: re-using existing credential handle\n");
+  if(conn->ssl_config.sessionid) {
+    Curl_ssl_sessionid_lock(conn);
+    if(!Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL)) {
+      connssl->cred = old_cred;
+      infof(data, "schannel: re-using existing credential handle\n");
+
+      /* increment the reference counter of the credential/session handle */
+      connssl->cred->refcount++;
+      infof(data, "schannel: incremented credential handle refcount = %d\n",
+            connssl->cred->refcount);
+    }
+    Curl_ssl_sessionid_unlock(conn);
   }
-  else {
+
+  if(!connssl->cred) {
     /* setup Schannel API options */
     memset(&schannel_cred, 0, sizeof(schannel_cred));
     schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
@@ -188,8 +217,10 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
       return CURLE_OUT_OF_MEMORY;
     }
     memset(connssl->cred, 0, sizeof(struct curl_schannel_cred));
+    connssl->cred->refcount = 1;
 
-    /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx */
+    /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx
+       */
     sspi_status =
       s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME,
                                          SECPKG_CRED_OUTBOUND, NULL,
@@ -218,6 +249,63 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
     infof(data, "schannel: using IP address, SNI is not supported by OS.\n");
   }
 
+#ifdef HAS_ALPN
+  /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above */
+  if(conn->bits.tls_enable_alpn &&
+     Curl_verify_windows_version(6, 3, PLATFORM_WINNT,
+                                 VERSION_GREATER_THAN_EQUAL)) {
+    int cur = 0;
+    int list_start_index = 0;
+    unsigned int* extension_len = NULL;
+    unsigned short* list_len = NULL;
+
+    /* The first four bytes will be an unsigned int indicating number
+       of bytes of data in the rest of the the buffer. */
+    extension_len = (unsigned int*)(&alpn_buffer[cur]);
+    cur += sizeof(unsigned int);
+
+    /* The next four bytes are an indicator that this buffer will contain
+       ALPN data, as opposed to NPN, for example. */
+    *(unsigned int*)&alpn_buffer[cur] =
+      SecApplicationProtocolNegotiationExt_ALPN;
+    cur += sizeof(unsigned int);
+
+    /* The next two bytes will be an unsigned short indicating the number
+       of bytes used to list the preferred protocols. */
+    list_len = (unsigned short*)(&alpn_buffer[cur]);
+    cur += sizeof(unsigned short);
+
+    list_start_index = cur;
+
+#ifdef USE_NGHTTP2
+    if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
+      memcpy(&alpn_buffer[cur], NGHTTP2_PROTO_ALPN, NGHTTP2_PROTO_ALPN_LEN);
+      cur += NGHTTP2_PROTO_ALPN_LEN;
+      infof(data, "schannel: ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
+    }
+#endif
+
+    alpn_buffer[cur++] = ALPN_HTTP_1_1_LENGTH;
+    memcpy(&alpn_buffer[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH);
+    cur += ALPN_HTTP_1_1_LENGTH;
+    infof(data, "schannel: ALPN, offering %s\n", ALPN_HTTP_1_1);
+
+    *list_len = curlx_uitous(cur - list_start_index);
+    *extension_len = *list_len + sizeof(unsigned int) + sizeof(unsigned short);
+
+    InitSecBuffer(&inbuf, SECBUFFER_APPLICATION_PROTOCOLS, alpn_buffer, cur);
+    InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
+  }
+  else
+  {
+    InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
+    InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
+  }
+#else /* HAS_ALPN */
+  InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
+  InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
+#endif
+
   /* setup output buffer */
   InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
   InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
@@ -240,11 +328,11 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
   if(!host_name)
     return CURLE_OUT_OF_MEMORY;
 
-  /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx */
+  /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx */
 
   sspi_status = s_pSecFn->InitializeSecurityContext(
     &connssl->cred->cred_handle, NULL, host_name,
-    connssl->req_flags, 0, 0, NULL, 0, &connssl->ctxt->ctxt_handle,
+    connssl->req_flags, 0, 0, &inbuf_desc, 0, &connssl->ctxt->ctxt_handle,
     &outbuf_desc, &connssl->ret_flags, &connssl->ctxt->time_stamp);
 
   Curl_unicodefree(host_name);
@@ -291,7 +379,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
 {
   int i;
   ssize_t nread = -1, written = -1;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   unsigned char *reallocated_buffer;
   size_t reallocated_length;
@@ -407,8 +495,8 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
     if(!host_name)
       return CURLE_OUT_OF_MEMORY;
 
-    /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx */
-
+    /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx
+       */
     sspi_status = s_pSecFn->InitializeSecurityContext(
       &connssl->cred->cred_handle, &connssl->ctxt->ctxt_handle,
       host_name, connssl->req_flags, 0, 0, &inbuf_desc, 0, NULL,
@@ -531,10 +619,13 @@ static CURLcode
 schannel_connect_step3(struct connectdata *conn, int sockindex)
 {
   CURLcode result = CURLE_OK;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-  struct curl_schannel_cred *old_cred = NULL;
-  bool incache;
+  SECURITY_STATUS sspi_status = SEC_E_OK;
+  CERT_CONTEXT *ccert_context = NULL;
+#ifdef HAS_ALPN
+  SecPkgContext_ApplicationProtocol alpn_result;
+#endif
 
   DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
 
@@ -559,34 +650,98 @@ schannel_connect_step3(struct connectdata *conn, int sockindex)
     return CURLE_SSL_CONNECT_ERROR;
   }
 
-  /* increment the reference counter of the credential/session handle */
-  if(connssl->cred && connssl->ctxt) {
-    connssl->cred->refcount++;
-    infof(data, "schannel: incremented credential handle refcount = %d\n",
-          connssl->cred->refcount);
+#ifdef HAS_ALPN
+  /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above */
+  if(conn->bits.tls_enable_alpn &&
+     Curl_verify_windows_version(6, 3, PLATFORM_WINNT,
+                                 VERSION_GREATER_THAN_EQUAL)) {
+    sspi_status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle,
+      SECPKG_ATTR_APPLICATION_PROTOCOL, &alpn_result);
+
+    if(sspi_status != SEC_E_OK) {
+      failf(data, "schannel: failed to retrieve ALPN result");
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+
+    if(alpn_result.ProtoNegoStatus ==
+       SecApplicationProtocolNegotiationStatus_Success) {
+
+      infof(data, "schannel: ALPN, server accepted to use %.*s\n",
+        alpn_result.ProtocolIdSize, alpn_result.ProtocolId);
+
+#ifdef USE_NGHTTP2
+      if(alpn_result.ProtocolIdSize == NGHTTP2_PROTO_VERSION_ID_LEN &&
+         !memcmp(NGHTTP2_PROTO_VERSION_ID, alpn_result.ProtocolId,
+          NGHTTP2_PROTO_VERSION_ID_LEN)) {
+        conn->negnpn = CURL_HTTP_VERSION_2;
+      }
+      else
+#endif
+      if(alpn_result.ProtocolIdSize == ALPN_HTTP_1_1_LENGTH &&
+         !memcmp(ALPN_HTTP_1_1, alpn_result.ProtocolId,
+           ALPN_HTTP_1_1_LENGTH)) {
+        conn->negnpn = CURL_HTTP_VERSION_1_1;
+      }
+    }
+    else
+      infof(data, "ALPN, server did not agree to a protocol\n");
   }
+#endif
 
   /* save the current session data for possible re-use */
-  incache = !(Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL));
-  if(incache) {
-    if(old_cred != connssl->cred) {
-      infof(data, "schannel: old credential handle is stale, removing\n");
-      Curl_ssl_delsessionid(conn, (void *)old_cred);
-      incache = FALSE;
+  if(conn->ssl_config.sessionid) {
+    bool incache;
+    struct curl_schannel_cred *old_cred = NULL;
+
+    Curl_ssl_sessionid_lock(conn);
+    incache = !(Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL));
+    if(incache) {
+      if(old_cred != connssl->cred) {
+        infof(data, "schannel: old credential handle is stale, removing\n");
+        /* we're not taking old_cred ownership here, no refcount++ is needed */
+        Curl_ssl_delsessionid(conn, (void *)old_cred);
+        incache = FALSE;
+      }
     }
+    if(!incache) {
+      result = Curl_ssl_addsessionid(conn, (void *)connssl->cred,
+                                     sizeof(struct curl_schannel_cred));
+      if(result) {
+        Curl_ssl_sessionid_unlock(conn);
+        failf(data, "schannel: failed to store credential handle");
+        return result;
+      }
+      else {
+        /* this cred session is now also referenced by sessionid cache */
+        connssl->cred->refcount++;
+        infof(data, "schannel: stored credential handle in session cache\n");
+      }
+    }
+    Curl_ssl_sessionid_unlock(conn);
   }
 
-  if(!incache) {
-    result = Curl_ssl_addsessionid(conn, (void *)connssl->cred,
-                                   sizeof(struct curl_schannel_cred));
-    if(result) {
-      failf(data, "schannel: failed to store credential handle");
-      return result;
+  if(data->set.ssl.certinfo) {
+    sspi_status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle,
+      SECPKG_ATTR_REMOTE_CERT_CONTEXT, &ccert_context);
+
+    if((sspi_status != SEC_E_OK) || (ccert_context == NULL)) {
+      failf(data, "schannel: failed to retrieve remote cert context");
+      return CURLE_SSL_CONNECT_ERROR;
     }
-    else {
-      connssl->cred->cached = TRUE;
-      infof(data, "schannel: stored credential handle in session cache\n");
+
+    result = Curl_ssl_init_certinfo(data, 1);
+    if(!result) {
+      if(((ccert_context->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
+         (ccert_context->cbCertEncoded > 0)) {
+
+        const char *beg = (const char *) ccert_context->pbCertEncoded;
+        const char *end = beg + ccert_context->cbCertEncoded;
+        result = Curl_extract_certinfo(conn, 0, beg, end);
+      }
     }
+    CertFreeCertificateContext(ccert_context);
+    if(result)
+      return result;
   }
 
   connssl->connecting_state = ssl_connect_done;
@@ -599,7 +754,7 @@ schannel_connect_common(struct connectdata *conn, int sockindex,
                         bool nonblocking, bool *done)
 {
   CURLcode result;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   curl_socket_t sockfd = conn->sock[sockindex];
   long timeout_ms;
@@ -759,7 +914,7 @@ schannel_send(struct connectdata *conn, int sockindex,
   /* copy data into output buffer */
   memcpy(outbuf[1].pvBuffer, buf, len);
 
-  /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */
+  /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */
   sspi_status = s_pSecFn->EncryptMessage(&connssl->ctxt->ctxt_handle, 0,
                                          &outbuf_desc, 0);
 
@@ -858,7 +1013,7 @@ schannel_recv(struct connectdata *conn, int sockindex,
 {
   size_t size = 0;
   ssize_t nread = -1;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   unsigned char *reallocated_buffer;
   size_t reallocated_length;
@@ -973,7 +1128,8 @@ schannel_recv(struct connectdata *conn, int sockindex,
     InitSecBuffer(&inbuf[3], SECBUFFER_EMPTY, NULL, 0);
     InitSecBufferDesc(&inbuf_desc, inbuf, 4);
 
-    /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx */
+    /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx
+       */
     sspi_status = s_pSecFn->DecryptMessage(&connssl->ctxt->ctxt_handle,
                                            &inbuf_desc, 0, NULL);
 
@@ -1120,23 +1276,8 @@ cleanup:
   */
   if(len && !connssl->decdata_offset && connssl->recv_connection_closed &&
      !connssl->recv_sspi_close_notify) {
-    BOOL isWin2k;
-    ULONGLONG cm;
-    OSVERSIONINFOEX osver;
-
-    memset(&osver, 0, sizeof(osver));
-    osver.dwOSVersionInfoSize = sizeof(osver);
-    osver.dwMajorVersion = 5;
-
-    cm = VerSetConditionMask(0, VER_MAJORVERSION, VER_EQUAL);
-    cm = VerSetConditionMask(cm, VER_MINORVERSION, VER_EQUAL);
-    cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
-    cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL);
-
-    isWin2k = VerifyVersionInfo(&osver,
-                                (VER_MAJORVERSION | VER_MINORVERSION |
-                                 VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR),
-                                cm);
+    bool isWin2k = Curl_verify_windows_version(5, 0, PLATFORM_WINNT,
+                                               VERSION_EQUAL);
 
     if(isWin2k && sspi_status == SEC_E_OK)
       connssl->recv_sspi_close_notify = true;
@@ -1204,7 +1345,7 @@ bool Curl_schannel_data_pending(const struct connectdata *conn, int sockindex)
 
   if(connssl->use) /* SSL/TLS is in use */
     return (connssl->encdata_offset > 0 ||
-            connssl->decdata_offset > 0 ) ? TRUE : FALSE;
+            connssl->decdata_offset > 0) ? TRUE : FALSE;
   else
     return FALSE;
 }
@@ -1218,10 +1359,10 @@ void Curl_schannel_close(struct connectdata *conn, int sockindex)
 
 int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
 {
-  /* See http://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx
+  /* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx
    * Shutting Down an Schannel Connection
    */
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
 
   infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu\n",
@@ -1294,19 +1435,10 @@ int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
 
   /* free SSPI Schannel API credential handle */
   if(connssl->cred) {
-    /* decrement the reference counter of the credential/session handle */
-    if(connssl->cred->refcount > 0) {
-      connssl->cred->refcount--;
-      infof(data, "schannel: decremented credential handle refcount = %d\n",
-            connssl->cred->refcount);
-    }
-
-    /* if the handle was not cached and the refcount is zero */
-    if(!connssl->cred->cached && connssl->cred->refcount == 0) {
-      infof(data, "schannel: clear credential handle\n");
-      s_pSecFn->FreeCredentialsHandle(&connssl->cred->cred_handle);
-      Curl_safefree(connssl->cred);
-    }
+    Curl_ssl_sessionid_lock(conn);
+    Curl_schannel_session_free(connssl->cred);
+    Curl_ssl_sessionid_unlock(conn);
+    connssl->cred = NULL;
   }
 
   /* free internal buffer for received encrypted data */
@@ -1328,16 +1460,13 @@ int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
 
 void Curl_schannel_session_free(void *ptr)
 {
+  /* this is expected to be called under sessionid lock */
   struct curl_schannel_cred *cred = ptr;
 
-  if(cred && cred->cached) {
-    if(cred->refcount == 0) {
-      s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
-      Curl_safefree(cred);
-    }
-    else {
-      cred->cached = FALSE;
-    }
+  cred->refcount--;
+  if(cred->refcount == 0) {
+    s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
+    Curl_safefree(cred);
   }
 }
 
@@ -1379,7 +1508,7 @@ int Curl_schannel_random(unsigned char *entropy, size_t length)
 static CURLcode verify_certificate(struct connectdata *conn, int sockindex)
 {
   SECURITY_STATUS status;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   CURLcode result = CURLE_OK;
   CERT_CONTEXT *pCertContextServer = NULL;
diff --git a/lib/vtls/schannel.h b/lib/vtls/schannel.h
index 5329584..8a4991e 100644
--- a/lib/vtls/schannel.h
+++ b/lib/vtls/schannel.h
@@ -12,7 +12,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -97,6 +97,9 @@ int Curl_schannel_random(unsigned char *entropy, size_t length);
 /* Set the API backend definition to Schannel */
 #define CURL_SSL_BACKEND CURLSSLBACKEND_SCHANNEL
 
+/* this backend supports CURLOPT_CERTINFO */
+#define have_curlssl_certinfo 1
+
 /* API setup for Schannel */
 #define curlssl_init Curl_schannel_init
 #define curlssl_cleanup Curl_schannel_cleanup
diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c
index 01bbc61..3863777 100644
--- a/lib/vtls/vtls.c
+++ b/lib/vtls/vtls.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -41,7 +41,7 @@
    defines/macros #defined by the lib-specific header files.
 
    "SSL/TLS Strong Encryption: An Introduction"
-   http://httpd.apache.org/docs-2.0/ssl/ssl_intro.html
+   https://httpd.apache.org/docs/2.0/ssl/ssl_intro.html
 */
 
 #include "curl_setup.h"
@@ -99,6 +99,7 @@ Curl_ssl_config_matches(struct ssl_config_data* data,
      (data->verifyhost == needle->verifyhost) &&
      safe_strequal(data->CApath, needle->CApath) &&
      safe_strequal(data->CAfile, needle->CAfile) &&
+     safe_strequal(data->clientcert, needle->clientcert) &&
      safe_strequal(data->random_file, needle->random_file) &&
      safe_strequal(data->egdsocket, needle->egdsocket) &&
      safe_strequal(data->cipher_list, needle->cipher_list))
@@ -156,6 +157,15 @@ Curl_clone_ssl_config(struct ssl_config_data *source,
   else
     dest->random_file = NULL;
 
+  if(source->clientcert) {
+    dest->clientcert = strdup(source->clientcert);
+    if(!dest->clientcert)
+      return FALSE;
+    dest->sessionid = FALSE;
+  }
+  else
+    dest->clientcert = NULL;
+
   return TRUE;
 }
 
@@ -166,6 +176,7 @@ void Curl_free_ssl_config(struct ssl_config_data* sslc)
   Curl_safefree(sslc->cipher_list);
   Curl_safefree(sslc->egdsocket);
   Curl_safefree(sslc->random_file);
+  Curl_safefree(sslc->clientcert);
 }
 
 
@@ -181,7 +192,7 @@ void Curl_free_ssl_config(struct ssl_config_data* sslc)
  *
  */
 
-unsigned int Curl_rand(struct SessionHandle *data)
+unsigned int Curl_rand(struct Curl_easy *data)
 {
   unsigned int r = 0;
   static unsigned int randseed;
@@ -276,7 +287,7 @@ void Curl_ssl_cleanup(void)
   }
 }
 
-static bool ssl_prefs_check(struct SessionHandle *data)
+static bool ssl_prefs_check(struct Curl_easy *data)
 {
   /* check for CURLOPT_SSLVERSION invalid parameter value */
   if((data->set.ssl.version < 0)
@@ -330,6 +341,25 @@ Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex,
 }
 
 /*
+ * Lock shared SSL session data
+ */
+void Curl_ssl_sessionid_lock(struct connectdata *conn)
+{
+  if(SSLSESSION_SHARED(conn->data))
+    Curl_share_lock(conn->data,
+                    CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE);
+}
+
+/*
+ * Unlock shared SSL session data
+ */
+void Curl_ssl_sessionid_unlock(struct connectdata *conn)
+{
+  if(SSLSESSION_SHARED(conn->data))
+    Curl_share_unlock(conn->data, CURL_LOCK_DATA_SSL_SESSION);
+}
+
+/*
  * Check if there's a session ID for the given connection in the cache, and if
  * there's one suitable, it is provided. Returns TRUE when no entry matched.
  */
@@ -338,22 +368,22 @@ bool Curl_ssl_getsessionid(struct connectdata *conn,
                            size_t *idsize) /* set 0 if unknown */
 {
   struct curl_ssl_session *check;
-  struct SessionHandle *data = conn->data;
+  struct Curl_easy *data = conn->data;
   size_t i;
   long *general_age;
   bool no_match = TRUE;
 
   *ssl_sessionid = NULL;
 
+  DEBUGASSERT(conn->ssl_config.sessionid);
+
   if(!conn->ssl_config.sessionid)
     /* session ID re-use is disabled */
     return TRUE;
 
   /* Lock if shared */
-  if(SSLSESSION_SHARED(data)) {
-    Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE);
+  if(SSLSESSION_SHARED(data))
     general_age = &data->share->sessionage;
-  }
   else
     general_age = &data->state.sessionage;
 
@@ -363,6 +393,12 @@ bool Curl_ssl_getsessionid(struct connectdata *conn,
       /* not session ID means blank entry */
       continue;
     if(Curl_raw_equal(conn->host.name, check->name) &&
+       ((!conn->bits.conn_to_host && !check->conn_to_host) ||
+         (conn->bits.conn_to_host && check->conn_to_host &&
+           Curl_raw_equal(conn->conn_to_host.name, check->conn_to_host))) &&
+       ((!conn->bits.conn_to_port && check->conn_to_port == -1) ||
+         (conn->bits.conn_to_port && check->conn_to_port != -1 &&
+           conn->conn_to_port == check->conn_to_port)) &&
        (conn->remote_port == check->remote_port) &&
        Curl_ssl_config_matches(&conn->ssl_config, &check->ssl_config)) {
       /* yes, we have a session ID! */
@@ -376,10 +412,6 @@ bool Curl_ssl_getsessionid(struct connectdata *conn,
     }
   }
 
-  /* Unlock */
-  if(SSLSESSION_SHARED(data))
-    Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION);
-
   return no_match;
 }
 
@@ -400,6 +432,7 @@ void Curl_ssl_kill_session(struct curl_ssl_session *session)
     Curl_free_ssl_config(&session->ssl_config);
 
     Curl_safefree(session->name);
+    Curl_safefree(session->conn_to_host);
   }
 }
 
@@ -409,10 +442,7 @@ void Curl_ssl_kill_session(struct curl_ssl_session *session)
 void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid)
 {
   size_t i;
-  struct SessionHandle *data=conn->data;
-
-  if(SSLSESSION_SHARED(data))
-    Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE);
+  struct Curl_easy *data=conn->data;
 
   for(i = 0; i < data->set.ssl.max_ssl_sessions; i++) {
     struct curl_ssl_session *check = &data->state.session[i];
@@ -422,9 +452,6 @@ void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid)
       break;
     }
   }
-
-  if(SSLSESSION_SHARED(data))
-    Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION);
 }
 
 /*
@@ -438,26 +465,40 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
                                size_t idsize)
 {
   size_t i;
-  struct SessionHandle *data=conn->data; /* the mother of all structs */
+  struct Curl_easy *data=conn->data; /* the mother of all structs */
   struct curl_ssl_session *store = &data->state.session[0];
   long oldest_age=data->state.session[0].age; /* zero if unused */
   char *clone_host;
+  char *clone_conn_to_host;
+  int conn_to_port;
   long *general_age;
 
-  /* Even though session ID re-use might be disabled, that only disables USING
-     IT. We still store it here in case the re-using is again enabled for an
-     upcoming transfer */
+  DEBUGASSERT(conn->ssl_config.sessionid);
 
   clone_host = strdup(conn->host.name);
   if(!clone_host)
     return CURLE_OUT_OF_MEMORY; /* bail out */
 
+  if(conn->bits.conn_to_host) {
+    clone_conn_to_host = strdup(conn->conn_to_host.name);
+    if(!clone_conn_to_host) {
+      free(clone_host);
+      return CURLE_OUT_OF_MEMORY; /* bail out */
+    }
+  }
+  else
+    clone_conn_to_host = NULL;
+
+  if(conn->bits.conn_to_port)
+    conn_to_port = conn->conn_to_port;
+  else
+    conn_to_port = -1;
+
   /* Now we should add the session ID and the host name to the cache, (remove
      the oldest if necessary) */
 
   /* If using shared SSL session, lock! */
   if(SSLSESSION_SHARED(data)) {
-    Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE);
     general_age = &data->share->sessionage;
   }
   else {
@@ -484,17 +525,16 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
   store->age = *general_age;    /* set current age */
     /* free it if there's one already present */
   free(store->name);
+  free(store->conn_to_host);
   store->name = clone_host;               /* clone host name */
+  store->conn_to_host = clone_conn_to_host; /* clone connect to host name */
+  store->conn_to_port = conn_to_port; /* connect to port number */
   store->remote_port = conn->remote_port; /* port number */
 
-
-  /* Unlock */
-  if(SSLSESSION_SHARED(data))
-    Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION);
-
   if(!Curl_clone_ssl_config(&conn->ssl_config, &store->ssl_config)) {
     store->sessionid = NULL; /* let caller free sessionid */
     free(clone_host);
+    free(clone_conn_to_host);
     return CURLE_OUT_OF_MEMORY;
   }
 
@@ -502,7 +542,7 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
 }
 
 
-void Curl_ssl_close_all(struct SessionHandle *data)
+void Curl_ssl_close_all(struct Curl_easy *data)
 {
   size_t i;
   /* kill the session ID cache if not shared */
@@ -540,20 +580,20 @@ CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex)
 
 /* Selects an SSL crypto engine
  */
-CURLcode Curl_ssl_set_engine(struct SessionHandle *data, const char *engine)
+CURLcode Curl_ssl_set_engine(struct Curl_easy *data, const char *engine)
 {
   return curlssl_set_engine(data, engine);
 }
 
 /* Selects the default SSL crypto engine
  */
-CURLcode Curl_ssl_set_engine_default(struct SessionHandle *data)
+CURLcode Curl_ssl_set_engine_default(struct Curl_easy *data)
 {
   return curlssl_set_engine_default(data);
 }
 
 /* Return list of OpenSSL crypto engine names. */
-struct curl_slist *Curl_ssl_engines_list(struct SessionHandle *data)
+struct curl_slist *Curl_ssl_engines_list(struct Curl_easy *data)
 {
   return curlssl_engines_list(data);
 }
@@ -562,7 +602,7 @@ struct curl_slist *Curl_ssl_engines_list(struct SessionHandle *data)
  * This sets up a session ID cache to the specified size. Make sure this code
  * is agnostic to what underlying SSL technology we use.
  */
-CURLcode Curl_ssl_initsessions(struct SessionHandle *data, size_t amount)
+CURLcode Curl_ssl_initsessions(struct Curl_easy *data, size_t amount)
 {
   struct curl_ssl_session *session;
 
@@ -605,7 +645,7 @@ bool Curl_ssl_data_pending(const struct connectdata *conn,
   return curlssl_data_pending(conn, connindex);
 }
 
-void Curl_ssl_free_certinfo(struct SessionHandle *data)
+void Curl_ssl_free_certinfo(struct Curl_easy *data)
 {
   int i;
   struct curl_certinfo *ci = &data->info.certs;
@@ -623,7 +663,7 @@ void Curl_ssl_free_certinfo(struct SessionHandle *data)
   }
 }
 
-CURLcode Curl_ssl_init_certinfo(struct SessionHandle *data, int num)
+CURLcode Curl_ssl_init_certinfo(struct Curl_easy *data, int num)
 {
   struct curl_certinfo *ci = &data->info.certs;
   struct curl_slist **table;
@@ -645,7 +685,7 @@ CURLcode Curl_ssl_init_certinfo(struct SessionHandle *data, int num)
 /*
  * 'value' is NOT a zero terminated string
  */
-CURLcode Curl_ssl_push_certinfo_len(struct SessionHandle *data,
+CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy *data,
                                     int certnum,
                                     const char *label,
                                     const char *value,
@@ -686,7 +726,7 @@ CURLcode Curl_ssl_push_certinfo_len(struct SessionHandle *data,
  * This is a convenience function for push_certinfo_len that takes a zero
  * terminated value.
  */
-CURLcode Curl_ssl_push_certinfo(struct SessionHandle *data,
+CURLcode Curl_ssl_push_certinfo(struct Curl_easy *data,
                                 int certnum,
                                 const char *label,
                                 const char *value)
@@ -696,7 +736,7 @@ CURLcode Curl_ssl_push_certinfo(struct SessionHandle *data,
   return Curl_ssl_push_certinfo_len(data, certnum, label, value, valuelen);
 }
 
-int Curl_ssl_random(struct SessionHandle *data,
+int Curl_ssl_random(struct Curl_easy *data,
                      unsigned char *entropy,
                      size_t length)
 {
@@ -765,7 +805,8 @@ static CURLcode pubkey_pem_to_der(const char *pem,
  * Generic pinned public key check.
  */
 
-CURLcode Curl_pin_peer_pubkey(const char *pinnedpubkey,
+CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
+                              const char *pinnedpubkey,
                               const unsigned char *pubkey, size_t pubkeylen)
 {
   FILE *fp;
@@ -775,9 +816,10 @@ CURLcode Curl_pin_peer_pubkey(const char *pinnedpubkey,
   CURLcode pem_read;
   CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
 #ifdef curlssl_sha256sum
-  size_t pinkeylen;
-  char *pinkeycopy, *begin_pos, *end_pos;
-  unsigned char *sha256sumdigest = NULL, *expectedsha256sumdigest = NULL;
+  CURLcode encode;
+  size_t encodedlen, pinkeylen;
+  char *encoded, *pinkeycopy, *begin_pos, *end_pos;
+  unsigned char *sha256sumdigest = NULL;
 #endif
 
   /* if a path wasn't specified, don't pin */
@@ -786,21 +828,29 @@ CURLcode Curl_pin_peer_pubkey(const char *pinnedpubkey,
   if(!pubkey || !pubkeylen)
     return result;
 
-#ifdef curlssl_sha256sum
   /* only do this if pinnedpubkey starts with "sha256//", length 8 */
   if(strncmp(pinnedpubkey, "sha256//", 8) == 0) {
+#ifdef curlssl_sha256sum
     /* compute sha256sum of public key */
     sha256sumdigest = malloc(SHA256_DIGEST_LENGTH);
     if(!sha256sumdigest)
       return CURLE_OUT_OF_MEMORY;
     curlssl_sha256sum(pubkey, pubkeylen,
                       sha256sumdigest, SHA256_DIGEST_LENGTH);
+    encode = Curl_base64_encode(data, (char *)sha256sumdigest,
+                                SHA256_DIGEST_LENGTH, &encoded, &encodedlen);
+    Curl_safefree(sha256sumdigest);
+
+    if(encode)
+      return encode;
+
+    infof(data, "\t public key hash: sha256//%s\n", encoded);
 
     /* it starts with sha256//, copy so we can modify it */
     pinkeylen = strlen(pinnedpubkey) + 1;
     pinkeycopy = malloc(pinkeylen);
     if(!pinkeycopy) {
-      Curl_safefree(sha256sumdigest);
+      Curl_safefree(encoded);
       return CURLE_OUT_OF_MEMORY;
     }
     memcpy(pinkeycopy, pinnedpubkey, pinkeylen);
@@ -815,20 +865,11 @@ CURLcode Curl_pin_peer_pubkey(const char *pinnedpubkey,
       if(end_pos)
         end_pos[0] = '\0';
 
-      /* decode base64 pinnedpubkey, 8 is length of "sha256//" */
-      pem_read = Curl_base64_decode(begin_pos + 8,
-                                    &expectedsha256sumdigest, &size);
-      /* if not valid base64, don't bother comparing or freeing */
-      if(!pem_read) {
-        /* compare sha256 digests directly */
-        if(SHA256_DIGEST_LENGTH == size &&
-           !memcmp(sha256sumdigest, expectedsha256sumdigest,
-                   SHA256_DIGEST_LENGTH)) {
-          result = CURLE_OK;
-          Curl_safefree(expectedsha256sumdigest);
-          break;
-        }
-        Curl_safefree(expectedsha256sumdigest);
+      /* compare base64 sha256 digests, 8 is the length of "sha256//" */
+      if(encodedlen == strlen(begin_pos + 8) &&
+         !memcmp(encoded, begin_pos + 8, encodedlen)) {
+        result = CURLE_OK;
+        break;
       }
 
       /*
@@ -840,11 +881,14 @@ CURLcode Curl_pin_peer_pubkey(const char *pinnedpubkey,
         begin_pos = strstr(end_pos, "sha256//");
       }
     } while(end_pos && begin_pos);
-    Curl_safefree(sha256sumdigest);
+    Curl_safefree(encoded);
     Curl_safefree(pinkeycopy);
+#else
+    /* without sha256 support, this cannot match */
+    (void)data;
+#endif
     return result;
   }
-#endif
 
   fp = fopen(pinnedpubkey, "rb");
   if(!fp)
diff --git a/lib/vtls/vtls.h b/lib/vtls/vtls.h
index 2349e5b..a41ecc3 100644
--- a/lib/vtls/vtls.h
+++ b/lib/vtls/vtls.h
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -32,6 +32,7 @@
 #include "cyassl.h"         /* CyaSSL versions */
 #include "schannel.h"       /* Schannel SSPI version */
 #include "darwinssl.h"      /* SecureTransport (Darwin) version */
+#include "mbedtls.h"        /* mbedTLS versions */
 
 #ifndef MAX_PINNED_PUBKEY_SIZE
 #define MAX_PINNED_PUBKEY_SIZE 1048576 /* 1MB */
@@ -45,7 +46,7 @@
 #define SHA256_DIGEST_LENGTH 32 /* fixed size */
 #endif
 
-/* see http://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg-04 */
+/* see https://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg-04 */
 #define ALPN_HTTP_1_1_LENGTH 8
 #define ALPN_HTTP_1_1 "http/1.1"
 
@@ -55,7 +56,7 @@ bool Curl_clone_ssl_config(struct ssl_config_data* source,
                            struct ssl_config_data* dest);
 void Curl_free_ssl_config(struct ssl_config_data* sslc);
 
-unsigned int Curl_rand(struct SessionHandle *);
+unsigned int Curl_rand(struct Curl_easy *);
 
 int Curl_ssl_backend(void);
 
@@ -68,16 +69,16 @@ CURLcode Curl_ssl_connect_nonblocking(struct connectdata *conn,
                                       bool *done);
 /* tell the SSL stuff to close down all open information regarding
    connections (and thus session ID caching etc) */
-void Curl_ssl_close_all(struct SessionHandle *data);
+void Curl_ssl_close_all(struct Curl_easy *data);
 void Curl_ssl_close(struct connectdata *conn, int sockindex);
 CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex);
-CURLcode Curl_ssl_set_engine(struct SessionHandle *data, const char *engine);
+CURLcode Curl_ssl_set_engine(struct Curl_easy *data, const char *engine);
 /* Sets engine as default for all SSL operations */
-CURLcode Curl_ssl_set_engine_default(struct SessionHandle *data);
-struct curl_slist *Curl_ssl_engines_list(struct SessionHandle *data);
+CURLcode Curl_ssl_set_engine_default(struct Curl_easy *data);
+struct curl_slist *Curl_ssl_engines_list(struct Curl_easy *data);
 
 /* init the SSL session ID cache */
-CURLcode Curl_ssl_initsessions(struct SessionHandle *, size_t);
+CURLcode Curl_ssl_initsessions(struct Curl_easy *, size_t);
 size_t Curl_ssl_version(char *buffer, size_t size);
 bool Curl_ssl_data_pending(const struct connectdata *conn,
                            int connindex);
@@ -85,39 +86,71 @@ int Curl_ssl_check_cxn(struct connectdata *conn);
 
 /* Certificate information list handling. */
 
-void Curl_ssl_free_certinfo(struct SessionHandle *data);
-CURLcode Curl_ssl_init_certinfo(struct SessionHandle * data, int num);
-CURLcode Curl_ssl_push_certinfo_len(struct SessionHandle * data, int certnum,
+void Curl_ssl_free_certinfo(struct Curl_easy *data);
+CURLcode Curl_ssl_init_certinfo(struct Curl_easy * data, int num);
+CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy * data, int certnum,
                                     const char * label, const char * value,
                                     size_t valuelen);
-CURLcode Curl_ssl_push_certinfo(struct SessionHandle * data, int certnum,
+CURLcode Curl_ssl_push_certinfo(struct Curl_easy * data, int certnum,
                                 const char * label, const char * value);
 
 /* Functions to be used by SSL library adaptation functions */
 
-/* extract a session ID */
+/* Lock session cache mutex.
+ * Call this before calling other Curl_ssl_*session* functions
+ * Caller should unlock this mutex as soon as possible, as it may block
+ * other SSL connection from making progress.
+ * The purpose of explicitly locking SSL session cache data is to allow
+ * individual SSL engines to manage session lifetime in their specific way.
+ */
+void Curl_ssl_sessionid_lock(struct connectdata *conn);
+
+/* Unlock session cache mutex */
+void Curl_ssl_sessionid_unlock(struct connectdata *conn);
+
+/* extract a session ID
+ * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
+ * Caller must make sure that the ownership of returned sessionid object
+ * is properly taken (e.g. its refcount is incremented
+ * under sessionid mutex).
+ */
 bool Curl_ssl_getsessionid(struct connectdata *conn,
                            void **ssl_sessionid,
-                           size_t *idsize) /* set 0 if unknown */;
-/* add a new session ID */
+                           size_t *idsize); /* set 0 if unknown */
+/* add a new session ID
+ * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
+ * Caller must ensure that it has properly shared ownership of this sessionid
+ * object with cache (e.g. incrementing refcount on success)
+ */
 CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
                                void *ssl_sessionid,
                                size_t idsize);
-/* Kill a single session ID entry in the cache */
+/* Kill a single session ID entry in the cache
+ * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
+ * This will call engine-specific curlssl_session_free function, which must
+ * take sessionid object ownership from sessionid cache
+ * (e.g. decrement refcount).
+ */
 void Curl_ssl_kill_session(struct curl_ssl_session *session);
-/* delete a session from the cache */
+/* delete a session from the cache
+ * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
+ * This will call engine-specific curlssl_session_free function, which must
+ * take sessionid object ownership from sessionid cache
+ * (e.g. decrement refcount).
+ */
 void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid);
 
 /* get N random bytes into the buffer, return 0 if a find random is filled
    in */
-int Curl_ssl_random(struct SessionHandle *data, unsigned char *buffer,
+int Curl_ssl_random(struct Curl_easy *data, unsigned char *buffer,
                     size_t length);
 CURLcode Curl_ssl_md5sum(unsigned char *tmp, /* input */
                          size_t tmplen,
                          unsigned char *md5sum, /* output */
                          size_t md5len);
 /* Check pinned public key. */
-CURLcode Curl_pin_peer_pubkey(const char *pinnedpubkey,
+CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
+                              const char *pinnedpubkey,
                               const unsigned char *pubkey, size_t pubkeylen);
 
 bool Curl_ssl_cert_status_request(void);
diff --git a/lib/warnless.c b/lib/warnless.c
index 8c130d3..0c4472e 100644
--- a/lib/warnless.c
+++ b/lib/warnless.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -379,6 +379,63 @@ int curlx_sztosi(ssize_t sznum)
 }
 
 /*
+** unsigned int to unsigned short
+*/
+
+unsigned short curlx_uitous(unsigned int uinum)
+{
+#ifdef __INTEL_COMPILER
+#  pragma warning(push)
+#  pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+  DEBUGASSERT(uinum <= (unsigned int) CURL_MASK_USHORT);
+  return (unsigned short) (uinum & (unsigned int) CURL_MASK_USHORT);
+
+#ifdef __INTEL_COMPILER
+#  pragma warning(pop)
+#endif
+}
+
+/*
+** unsigned int to unsigned char
+*/
+
+unsigned char curlx_uitouc(unsigned int uinum)
+{
+#ifdef __INTEL_COMPILER
+#  pragma warning(push)
+#  pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+  DEBUGASSERT(uinum <= (unsigned int) CURL_MASK_UCHAR);
+  return (unsigned char) (uinum & (unsigned int) CURL_MASK_UCHAR);
+
+#ifdef __INTEL_COMPILER
+#  pragma warning(pop)
+#endif
+}
+
+/*
+** unsigned int to signed int
+*/
+
+int curlx_uitosi(unsigned int uinum)
+{
+#ifdef __INTEL_COMPILER
+#  pragma warning(push)
+#  pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+  DEBUGASSERT(uinum <= (unsigned int) CURL_MASK_SINT);
+  return (int) (uinum & (unsigned int) CURL_MASK_SINT);
+
+#ifdef __INTEL_COMPILER
+#  pragma warning(pop)
+#endif
+}
+
+/*
 ** signed int to unsigned size_t
 */
 
diff --git a/lib/warnless.h b/lib/warnless.h
index ad77d3c..ab6d299 100644
--- a/lib/warnless.h
+++ b/lib/warnless.h
@@ -7,11 +7,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -52,6 +52,12 @@ size_t curlx_sotouz(curl_off_t sonum);
 
 int curlx_sztosi(ssize_t sznum);
 
+unsigned short curlx_uitous(unsigned int uinum);
+
+unsigned char curlx_uitouc(unsigned int uinum);
+
+int curlx_uitosi(unsigned int uinum);
+
 size_t curlx_sitouz(int sinum);
 
 #ifdef USE_WINSOCK
diff --git a/lib/wildcard.c b/lib/wildcard.c
index 6f55839..dbbe45f 100644
--- a/lib/wildcard.c
+++ b/lib/wildcard.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -25,9 +25,9 @@
 #include "wildcard.h"
 #include "llist.h"
 #include "fileinfo.h"
+/* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_memory.h"
-/* The last #include file should be: */
 #include "memdebug.h"
 
 CURLcode Curl_wildcard_init(struct WildcardData *wc)
diff --git a/lib/wildcard.h b/lib/wildcard.h
index 16c80ec..7f61cd1 100644
--- a/lib/wildcard.h
+++ b/lib/wildcard.h
@@ -11,7 +11,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -53,6 +53,6 @@ struct WildcardData {
 CURLcode Curl_wildcard_init(struct WildcardData *wc);
 void Curl_wildcard_dtor(struct WildcardData *wc);
 
-struct SessionHandle;
+struct Curl_easy;
 
 #endif /* HEADER_CURL_WILDCARD_H */
diff --git a/lib/x509asn1.c b/lib/x509asn1.c
index a3dfd64..e17bcd9 100644
--- a/lib/x509asn1.c
+++ b/lib/x509asn1.c
@@ -5,11 +5,11 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel at haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel at haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -23,7 +23,7 @@
 #include "curl_setup.h"
 
 #if defined(USE_GSKIT) || defined(USE_NSS) || defined(USE_GNUTLS) || \
-    defined(USE_CYASSL)
+    defined(USE_CYASSL) || defined(USE_SCHANNEL)
 
 #include <curl/curl.h>
 #include "urldata.h"
@@ -34,9 +34,10 @@
 #include "inet_pton.h"
 #include "curl_base64.h"
 #include "x509asn1.h"
+
+/* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_memory.h"
-/* The last #include file should be: */
 #include "memdebug.h"
 
 
@@ -783,7 +784,7 @@ static const char * dumpAlgo(curl_asn1Element * param,
   return OID2str(oid.beg, oid.end, TRUE);
 }
 
-static void do_pubkey_field(struct SessionHandle * data, int certnum,
+static void do_pubkey_field(struct Curl_easy * data, int certnum,
                             const char * label, curl_asn1Element * elem)
 {
   const char * output;
@@ -800,7 +801,7 @@ static void do_pubkey_field(struct SessionHandle * data, int certnum,
   }
 }
 
-static void do_pubkey(struct SessionHandle * data, int certnum,
+static void do_pubkey(struct Curl_easy * data, int certnum,
                       const char * algo, curl_asn1Element * param,
                       curl_asn1Element * pubkey)
 {
@@ -870,7 +871,7 @@ CURLcode Curl_extract_certinfo(struct connectdata * conn,
                                const char * end)
 {
   curl_X509certificate cert;
-  struct SessionHandle * data = conn->data;
+  struct Curl_easy * data = conn->data;
   curl_asn1Element param;
   const char * ccp;
   char * cp1;
@@ -1024,7 +1025,7 @@ CURLcode Curl_extract_certinfo(struct connectdata * conn,
   return CURLE_OK;
 }
 
-#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_CYASSL */
+#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_CYASSL or USE_SCHANNEL */
 
 #if defined(USE_GSKIT)
 
@@ -1055,13 +1056,12 @@ static const char * checkOID(const char * beg, const char * end,
 CURLcode Curl_verifyhost(struct connectdata * conn,
                          const char * beg, const char * end)
 {
-  struct SessionHandle * data = conn->data;
+  struct Curl_easy * data = conn->data;
   curl_X509certificate cert;
   curl_asn1Element dn;
   curl_asn1Element elem;
   curl_asn1Element ext;
   curl_asn1Element name;
-  int i;
   const char * p;
   const char * q;
   char * dnsname;
@@ -1110,16 +1110,13 @@ CURLcode Curl_verifyhost(struct connectdata * conn,
         q = Curl_getASN1Element(&name, q, elem.end);
         switch (name.tag) {
         case 2: /* DNS name. */
-          i = 0;
           len = utf8asn1str(&dnsname, CURL_ASN1_IA5_STRING,
                             name.beg, name.end);
-          if(len > 0)
-            if(strlen(dnsname) == (size_t) len)
-              i = Curl_cert_hostcheck((const char *) dnsname, conn->host.name);
+          if(len > 0 && (size_t)len == strlen(dnsname))
+            matched = Curl_cert_hostcheck(dnsname, conn->host.name);
+          else
+            matched = 0;
           free(dnsname);
-          if(!i)
-            return CURLE_PEER_FAILED_VERIFICATION;
-          matched = i;
           break;
 
         case 7: /* IP address. */
diff --git a/lib/x509asn1.h b/lib/x509asn1.h
index eb23e50..0f2b930 100644
--- a/lib/x509asn1.h
+++ b/lib/x509asn1.h
@@ -12,7 +12,7 @@
  *
  * 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -26,7 +26,7 @@
 #include "curl_setup.h"
 
 #if defined(USE_GSKIT) || defined(USE_NSS) || defined(USE_GNUTLS) || \
-    defined(USE_CYASSL)
+    defined(USE_CYASSL) || defined(USE_SCHANNEL)
 
 #include "urldata.h"
 
@@ -128,5 +128,5 @@ CURLcode Curl_extract_certinfo(struct connectdata * conn, int certnum,
 CURLcode Curl_verifyhost(struct connectdata * conn,
                          const char * beg, const char * end);
 
-#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_CYASSL */
+#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_CYASSL or USE_SCHANNEL */
 #endif /* HEADER_CURL_X509ASN1_H */

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=e1c11352f231ae310339cd539ed59cb302bd4dbe
commit e1c11352f231ae310339cd539ed59cb302bd4dbe
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Wed Aug 3 11:55:15 2016 -0400
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Wed Aug 3 14:26:02 2016 -0400

    curl: Update script to get curl 7.50.1

diff --git a/Utilities/Scripts/update-curl.bash b/Utilities/Scripts/update-curl.bash
index 17a4f2c..0e466cf 100755
--- a/Utilities/Scripts/update-curl.bash
+++ b/Utilities/Scripts/update-curl.bash
@@ -8,7 +8,7 @@ readonly name="curl"
 readonly ownership="Curl Upstream <curl-library at cool.haxx.se>"
 readonly subtree="Utilities/cmcurl"
 readonly repo="https://github.com/bagder/curl.git"
-readonly tag="curl-7_44_0"
+readonly tag="curl-7_50_1"
 readonly shortlog=false
 readonly paths="
   CMake/*
@@ -22,6 +22,8 @@ readonly paths="
   lib/Makefile.inc
   lib/curl_config.h.cmake
   lib/libcurl.rc
+  lib/vauth/*.c
+  lib/vauth/*.h
   lib/vtls/*.c
   lib/vtls/*.h
 "

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=a51c6c5394169f34480e7261ef666eb4bf898c67
commit a51c6c5394169f34480e7261ef666eb4bf898c67
Merge: 3e9b034 7ec709d
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Wed Aug 3 11:54:18 2016 -0400
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Wed Aug 3 11:54:18 2016 -0400

    Merge branch 'upstream-curl' into update-curl


https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=7ec709d3d7cc988d4cf6dc2c49713d4c55f09542
commit 7ec709d3d7cc988d4cf6dc2c49713d4c55f09542
Author:     Curl Upstream <curl-library at cool.haxx.se>
AuthorDate: Tue Aug 11 20:13:01 2015 +0200
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Wed Aug 3 11:52:06 2016 -0400

    curl 2015-08-11 (1a7f66a3)
    
    Code extracted from:
    
        https://github.com/bagder/curl.git
    
    at commit 1a7f66a3de2625d10f65415e6eb3e56067dc0555 (curl-7_44_0).

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=3e9b03439f6fa16abf555f37016e0f45f2073b78
commit 3e9b03439f6fa16abf555f37016e0f45f2073b78
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Wed Aug 3 11:50:27 2016 -0400
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Wed Aug 3 11:51:27 2016 -0400

    Add script to update curl from upstream

diff --git a/Utilities/Scripts/update-curl.bash b/Utilities/Scripts/update-curl.bash
new file mode 100755
index 0000000..17a4f2c
--- /dev/null
+++ b/Utilities/Scripts/update-curl.bash
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+
+set -e
+set -x
+shopt -s dotglob
+
+readonly name="curl"
+readonly ownership="Curl Upstream <curl-library at cool.haxx.se>"
+readonly subtree="Utilities/cmcurl"
+readonly repo="https://github.com/bagder/curl.git"
+readonly tag="curl-7_44_0"
+readonly shortlog=false
+readonly paths="
+  CMake/*
+  CMakeLists.txt
+  COPYING
+  include/curl/*.h
+  include/curl/curlbuild.h.cmake
+  lib/*.c
+  lib/*.h
+  lib/CMakeLists.txt
+  lib/Makefile.inc
+  lib/curl_config.h.cmake
+  lib/libcurl.rc
+  lib/vtls/*.c
+  lib/vtls/*.h
+"
+
+extract_source () {
+    git_archive
+    pushd "${extractdir}/${name}-reduced"
+    rm lib/config-*.h
+    popd
+}
+
+. "${BASH_SOURCE%/*}/update-third-party.bash"

-----------------------------------------------------------------------

Summary of changes:
 Utilities/Scripts/update-curl.bash                 |   38 +
 Utilities/cmcurl/CMake/CurlTests.c                 |    2 +-
 Utilities/cmcurl/CMake/OtherTests.cmake            |    2 +-
 Utilities/cmcurl/CMakeLists.txt                    |  182 +--
 Utilities/cmcurl/COPYING                           |    3 +-
 Utilities/cmcurl/README-CMake.txt                  |   66 -
 Utilities/cmcurl/include/curl/curl.h               |  243 ++--
 Utilities/cmcurl/include/curl/curlbuild.h.cmake    |    4 +-
 Utilities/cmcurl/include/curl/curlrules.h          |    4 +-
 Utilities/cmcurl/include/curl/curlver.h            |   14 +-
 Utilities/cmcurl/include/curl/easy.h               |    2 +-
 Utilities/cmcurl/include/curl/mprintf.h            |   30 +-
 Utilities/cmcurl/include/curl/multi.h              |    8 +-
 Utilities/cmcurl/include/curl/stdcheaders.h        |    2 +-
 Utilities/cmcurl/include/curl/typecheck-gcc.h      |  124 +-
 Utilities/cmcurl/lib/Makefile.inc                  |   41 +-
 Utilities/cmcurl/lib/amigaos.c                     |    6 +-
 Utilities/cmcurl/lib/amigaos.h                     |    2 +-
 Utilities/cmcurl/lib/arpa_telnet.h                 |    2 +-
 Utilities/cmcurl/lib/asyn-ares.c                   |   24 +-
 Utilities/cmcurl/lib/asyn-thread.c                 |   31 +-
 Utilities/cmcurl/lib/asyn.h                        |    4 +-
 Utilities/cmcurl/lib/base64.c                      |   44 +-
 Utilities/cmcurl/lib/conncache.c                   |   24 +-
 Utilities/cmcurl/lib/conncache.h                   |    2 +-
 Utilities/cmcurl/lib/connect.c                     |  133 +-
 Utilities/cmcurl/lib/connect.h                     |   14 +-
 Utilities/cmcurl/lib/content_encoding.c            |    6 +-
 Utilities/cmcurl/lib/content_encoding.h            |    2 +-
 Utilities/cmcurl/lib/cookie.c                      |  122 +-
 Utilities/cmcurl/lib/cookie.h                      |   14 +-
 Utilities/cmcurl/lib/curl_addrinfo.c               |   44 +-
 Utilities/cmcurl/lib/curl_addrinfo.h               |   15 +-
 Utilities/cmcurl/lib/curl_base64.h                 |    6 +-
 Utilities/cmcurl/lib/curl_config.h.cmake           |   27 +
 Utilities/cmcurl/lib/curl_des.c                    |    6 +-
 Utilities/cmcurl/lib/curl_des.h                    |    6 +-
 Utilities/cmcurl/lib/curl_endian.c                 |    2 +-
 Utilities/cmcurl/lib/curl_endian.h                 |    2 +-
 Utilities/cmcurl/lib/curl_fnmatch.c                |    6 +-
 Utilities/cmcurl/lib/curl_fnmatch.h                |    2 +-
 Utilities/cmcurl/lib/curl_gethostname.c            |    2 +-
 Utilities/cmcurl/lib/curl_gethostname.h            |    2 +-
 Utilities/cmcurl/lib/curl_gssapi.c                 |   65 +-
 Utilities/cmcurl/lib/curl_gssapi.h                 |    8 +-
 Utilities/cmcurl/lib/curl_hmac.h                   |    2 +-
 Utilities/cmcurl/lib/curl_ldap.h                   |    2 +-
 Utilities/cmcurl/lib/curl_md4.h                    |    2 +-
 Utilities/cmcurl/lib/curl_md5.h                    |    2 +-
 Utilities/cmcurl/lib/curl_memory.h                 |   19 +-
 Utilities/cmcurl/lib/curl_memrchr.c                |    7 +-
 Utilities/cmcurl/lib/curl_memrchr.h                |    2 +-
 Utilities/cmcurl/lib/curl_multibyte.c              |    4 +-
 Utilities/cmcurl/lib/curl_multibyte.h              |    2 +-
 Utilities/cmcurl/lib/curl_ntlm_core.c              |   34 +-
 Utilities/cmcurl/lib/curl_ntlm_core.h              |    6 +-
 Utilities/cmcurl/lib/curl_ntlm_wb.c                |   15 +-
 Utilities/cmcurl/lib/curl_ntlm_wb.h                |    2 +-
 Utilities/cmcurl/lib/curl_printf.h                 |    2 +-
 Utilities/cmcurl/lib/curl_rtmp.c                   |    4 +-
 Utilities/cmcurl/lib/curl_rtmp.h                   |    2 +-
 Utilities/cmcurl/lib/curl_sasl.c                   | 1332 ++----------------
 Utilities/cmcurl/lib/curl_sasl.h                   |  143 +-
 Utilities/cmcurl/lib/curl_sasl_sspi.c              | 1281 -----------------
 Utilities/cmcurl/lib/curl_sec.h                    |    2 +-
 Utilities/cmcurl/lib/curl_setup.h                  |   49 +-
 Utilities/cmcurl/lib/curl_setup_once.h             |    2 +-
 Utilities/cmcurl/lib/curl_sspi.c                   |   52 +-
 Utilities/cmcurl/lib/curl_sspi.h                   |    6 +-
 Utilities/cmcurl/lib/curl_threads.c                |    6 +-
 Utilities/cmcurl/lib/curl_threads.h                |    2 +-
 Utilities/cmcurl/lib/curlx.h                       |    2 +-
 Utilities/cmcurl/lib/dict.c                        |    6 +-
 Utilities/cmcurl/lib/dict.h                        |    2 +-
 Utilities/cmcurl/lib/dotdot.c                      |   17 +-
 Utilities/cmcurl/lib/dotdot.h                      |    2 +-
 Utilities/cmcurl/lib/easy.c                        |  181 +--
 Utilities/cmcurl/lib/easyif.h                      |    6 +-
 Utilities/cmcurl/lib/escape.c                      |   24 +-
 Utilities/cmcurl/lib/escape.h                      |    4 +-
 Utilities/cmcurl/lib/file.c                        |   93 +-
 Utilities/cmcurl/lib/file.h                        |    2 +-
 Utilities/cmcurl/lib/fileinfo.c                    |    2 +-
 Utilities/cmcurl/lib/fileinfo.h                    |    2 +-
 Utilities/cmcurl/lib/formdata.c                    |  121 +-
 Utilities/cmcurl/lib/formdata.h                    |   12 +-
 Utilities/cmcurl/lib/ftp.c                         |  181 +--
 Utilities/cmcurl/lib/ftp.h                         |    6 +-
 Utilities/cmcurl/lib/ftplistparser.c               |   36 +-
 Utilities/cmcurl/lib/ftplistparser.h               |    2 +-
 Utilities/cmcurl/lib/getenv.c                      |    2 +-
 Utilities/cmcurl/lib/getinfo.c                     |  128 +-
 Utilities/cmcurl/lib/getinfo.h                     |    6 +-
 Utilities/cmcurl/lib/gopher.c                      |   12 +-
 Utilities/cmcurl/lib/gopher.h                      |    2 +-
 Utilities/cmcurl/lib/hash.c                        |   30 +-
 Utilities/cmcurl/lib/hash.h                        |    2 +-
 Utilities/cmcurl/lib/hmac.c                        |    7 +-
 Utilities/cmcurl/lib/hostasyn.c                    |    4 +-
 Utilities/cmcurl/lib/hostcheck.c                   |    4 +-
 Utilities/cmcurl/lib/hostcheck.h                   |    2 +-
 Utilities/cmcurl/lib/hostip.c                      |   29 +-
 Utilities/cmcurl/lib/hostip.h                      |   24 +-
 Utilities/cmcurl/lib/hostip4.c                     |    6 +-
 Utilities/cmcurl/lib/hostip6.c                     |   31 +-
 Utilities/cmcurl/lib/hostsyn.c                     |   10 +-
 Utilities/cmcurl/lib/http.c                        |  361 ++---
 Utilities/cmcurl/lib/http.h                        |   12 +-
 Utilities/cmcurl/lib/http2.c                       |  800 ++++++++---
 Utilities/cmcurl/lib/http2.h                       |   10 +-
 Utilities/cmcurl/lib/http_chunks.c                 |    8 +-
 Utilities/cmcurl/lib/http_chunks.h                 |    2 +-
 Utilities/cmcurl/lib/http_digest.c                 |   25 +-
 Utilities/cmcurl/lib/http_digest.h                 |    4 +-
 Utilities/cmcurl/lib/http_negotiate.c              |  193 +--
 Utilities/cmcurl/lib/http_negotiate.h              |    8 +-
 Utilities/cmcurl/lib/http_negotiate_sspi.c         |  300 ----
 Utilities/cmcurl/lib/{curl_ntlm.c => http_ntlm.c}  |   27 +-
 Utilities/cmcurl/lib/{curl_ntlm.h => http_ntlm.h}  |    2 +-
 Utilities/cmcurl/lib/http_proxy.c                  |   45 +-
 Utilities/cmcurl/lib/http_proxy.h                  |    2 +-
 Utilities/cmcurl/lib/idn_win32.c                   |   63 +-
 Utilities/cmcurl/lib/if2ip.c                       |   19 +-
 Utilities/cmcurl/lib/if2ip.h                       |    2 +-
 Utilities/cmcurl/lib/imap.c                        |  148 +-
 Utilities/cmcurl/lib/imap.h                        |    6 +-
 Utilities/cmcurl/lib/inet_ntop.c                   |   11 +-
 Utilities/cmcurl/lib/inet_ntop.h                   |    2 +-
 Utilities/cmcurl/lib/inet_pton.c                   |    8 +-
 Utilities/cmcurl/lib/inet_pton.h                   |    2 +-
 Utilities/cmcurl/lib/krb5.c                        |   28 +-
 Utilities/cmcurl/lib/ldap.c                        |   13 +-
 Utilities/cmcurl/lib/libcurl.rc                    |    6 +-
 Utilities/cmcurl/lib/llist.c                       |    6 +-
 Utilities/cmcurl/lib/llist.h                       |    2 +-
 Utilities/cmcurl/lib/md5.c                         |    6 +-
 Utilities/cmcurl/lib/memdebug.c                    |   15 +-
 Utilities/cmcurl/lib/memdebug.h                    |   17 +-
 Utilities/cmcurl/lib/mprintf.c                     |  184 +--
 Utilities/cmcurl/lib/multi.c                       |  709 +++++++---
 Utilities/cmcurl/lib/multihandle.h                 |   10 +-
 Utilities/cmcurl/lib/multiif.h                     |   14 +-
 Utilities/cmcurl/lib/netrc.c                       |    8 +-
 Utilities/cmcurl/lib/netrc.h                       |    2 +-
 Utilities/cmcurl/lib/non-ascii.c                   |   24 +-
 Utilities/cmcurl/lib/non-ascii.h                   |   18 +-
 Utilities/cmcurl/lib/nonblock.c                    |    6 +-
 Utilities/cmcurl/lib/nonblock.h                    |    2 +-
 Utilities/cmcurl/lib/nwlib.c                       |   50 +-
 Utilities/cmcurl/lib/nwos.c                        |   12 +-
 Utilities/cmcurl/lib/openldap.c                    |  109 +-
 Utilities/cmcurl/lib/parsedate.c                   |    2 +-
 Utilities/cmcurl/lib/parsedate.h                   |    2 +-
 Utilities/cmcurl/lib/pingpong.c                    |   18 +-
 Utilities/cmcurl/lib/pingpong.h                    |    2 +-
 Utilities/cmcurl/lib/pipeline.c                    |   46 +-
 Utilities/cmcurl/lib/pipeline.h                    |   20 +-
 Utilities/cmcurl/lib/pop3.c                        |   74 +-
 Utilities/cmcurl/lib/pop3.h                        |    6 +-
 Utilities/cmcurl/lib/progress.c                    |   20 +-
 Utilities/cmcurl/lib/progress.h                    |   16 +-
 Utilities/cmcurl/lib/rawstr.c                      |   12 +-
 Utilities/cmcurl/lib/rawstr.h                      |    2 +-
 Utilities/cmcurl/lib/rtsp.c                        |   48 +-
 Utilities/cmcurl/lib/rtsp.h                        |    2 +-
 Utilities/cmcurl/lib/security.c                    |    2 +-
 Utilities/cmcurl/lib/select.c                      |   22 +-
 Utilities/cmcurl/lib/select.h                      |    2 +-
 Utilities/cmcurl/lib/sendf.c                       |  154 ++-
 Utilities/cmcurl/lib/sendf.h                       |    8 +-
 Utilities/cmcurl/lib/setup-os400.h                 |    2 +-
 Utilities/cmcurl/lib/setup-vms.h                   |    2 +-
 Utilities/cmcurl/lib/share.c                       |   23 +-
 Utilities/cmcurl/lib/share.h                       |    6 +-
 Utilities/cmcurl/lib/sigpipe.h                     |    6 +-
 Utilities/cmcurl/lib/slist.c                       |    6 +-
 Utilities/cmcurl/lib/slist.h                       |    2 +-
 Utilities/cmcurl/lib/smb.c                         |   13 +-
 Utilities/cmcurl/lib/smb.h                         |    2 +-
 Utilities/cmcurl/lib/smtp.c                        |   85 +-
 Utilities/cmcurl/lib/smtp.h                        |    6 +-
 Utilities/cmcurl/lib/sockaddr.h                    |    2 +-
 Utilities/cmcurl/lib/socks.c                       |   44 +-
 Utilities/cmcurl/lib/socks.h                       |    2 +-
 Utilities/cmcurl/lib/socks_gssapi.c                |   14 +-
 Utilities/cmcurl/lib/socks_sspi.c                  |   17 +-
 Utilities/cmcurl/lib/speedcheck.c                  |    6 +-
 Utilities/cmcurl/lib/speedcheck.h                  |    6 +-
 Utilities/cmcurl/lib/splay.c                       |    2 +-
 Utilities/cmcurl/lib/splay.h                       |    6 +-
 Utilities/cmcurl/lib/ssh.c                         |  173 ++-
 Utilities/cmcurl/lib/ssh.h                         |    7 +-
 Utilities/cmcurl/lib/strdup.c                      |    8 +-
 Utilities/cmcurl/lib/strdup.h                      |    2 +-
 Utilities/cmcurl/lib/strequal.c                    |    2 +-
 Utilities/cmcurl/lib/strequal.h                    |    2 +-
 Utilities/cmcurl/lib/strerror.c                    |   20 +-
 Utilities/cmcurl/lib/strerror.h                    |    2 +-
 Utilities/cmcurl/lib/strtok.c                      |    2 +-
 Utilities/cmcurl/lib/strtok.h                      |    2 +-
 Utilities/cmcurl/lib/strtoofft.c                   |    2 +-
 Utilities/cmcurl/lib/strtoofft.h                   |    2 +-
 Utilities/cmcurl/lib/system_win32.c                |  294 ++++
 Utilities/cmcurl/lib/system_win32.h                |   61 +
 Utilities/cmcurl/lib/telnet.c                      |   46 +-
 Utilities/cmcurl/lib/telnet.h                      |    2 +-
 Utilities/cmcurl/lib/tftp.c                        |   99 +-
 Utilities/cmcurl/lib/tftp.h                        |    2 +-
 Utilities/cmcurl/lib/timeval.c                     |   14 +-
 Utilities/cmcurl/lib/timeval.h                     |    2 +-
 Utilities/cmcurl/lib/transfer.c                    |  219 ++-
 Utilities/cmcurl/lib/transfer.h                    |   17 +-
 Utilities/cmcurl/lib/url.c                         | 1449 ++++++++++++--------
 Utilities/cmcurl/lib/url.h                         |   40 +-
 Utilities/cmcurl/lib/urldata.h                     |  187 ++-
 Utilities/cmcurl/lib/vauth/cleartext.c             |  157 +++
 Utilities/cmcurl/lib/vauth/cram.c                  |  138 ++
 Utilities/cmcurl/lib/vauth/digest.c                |  883 ++++++++++++
 .../cmcurl/lib/{strequal.h => vauth/digest.h}      |   26 +-
 Utilities/cmcurl/lib/vauth/digest_sspi.c           |  533 +++++++
 .../{curl_sasl_gssapi.c => vauth/krb5_gssapi.c}    |  175 ++-
 Utilities/cmcurl/lib/vauth/krb5_sspi.c             |  496 +++++++
 .../cmcurl/lib/{curl_ntlm_msgs.c => vauth/ntlm.c}  |   65 +-
 .../cmcurl/lib/{curl_ntlm_msgs.h => vauth/ntlm.h}  |   10 +-
 Utilities/cmcurl/lib/vauth/ntlm_sspi.c             |  314 +++++
 Utilities/cmcurl/lib/vauth/oauth2.c                |   86 ++
 Utilities/cmcurl/lib/vauth/spnego_gssapi.c         |  260 ++++
 Utilities/cmcurl/lib/vauth/spnego_sspi.c           |  297 ++++
 Utilities/cmcurl/lib/vauth/vauth.c                 |  106 ++
 Utilities/cmcurl/lib/vauth/vauth.h                 |  189 +++
 Utilities/cmcurl/lib/version.c                     |   40 +-
 Utilities/cmcurl/lib/vtls/axtls.c                  |   58 +-
 Utilities/cmcurl/lib/vtls/axtls.h                  |    4 +-
 Utilities/cmcurl/lib/vtls/cyassl.c                 |  203 ++-
 Utilities/cmcurl/lib/vtls/cyassl.h                 |   23 +-
 Utilities/cmcurl/lib/vtls/darwinssl.c              |  111 +-
 Utilities/cmcurl/lib/vtls/darwinssl.h              |    2 +-
 Utilities/cmcurl/lib/vtls/gskit.c                  |   36 +-
 Utilities/cmcurl/lib/vtls/gskit.h                  |    2 +-
 Utilities/cmcurl/lib/vtls/gtls.c                   |  116 +-
 Utilities/cmcurl/lib/vtls/gtls.h                   |    9 +-
 Utilities/cmcurl/lib/vtls/mbedtls.c                |  871 ++++++++++++
 Utilities/cmcurl/lib/vtls/mbedtls.h                |   80 ++
 Utilities/cmcurl/lib/vtls/nss.c                    |  113 +-
 Utilities/cmcurl/lib/vtls/nssg.h                   |   13 +-
 Utilities/cmcurl/lib/vtls/openssl.c                |  998 +++++++-------
 Utilities/cmcurl/lib/vtls/openssl.h                |   21 +-
 Utilities/cmcurl/lib/vtls/polarssl.c               |  191 ++-
 Utilities/cmcurl/lib/vtls/polarssl.h               |   18 +-
 Utilities/cmcurl/lib/vtls/polarssl_threadlock.c    |   16 +-
 Utilities/cmcurl/lib/vtls/polarssl_threadlock.h    |   22 +-
 Utilities/cmcurl/lib/vtls/schannel.c               |  297 ++--
 Utilities/cmcurl/lib/vtls/schannel.h               |    5 +-
 Utilities/cmcurl/lib/vtls/vtls.c                   |  168 ++-
 Utilities/cmcurl/lib/vtls/vtls.h                   |   73 +-
 Utilities/cmcurl/lib/warnless.c                    |   61 +-
 Utilities/cmcurl/lib/warnless.h                    |   10 +-
 Utilities/cmcurl/lib/wildcard.c                    |    6 +-
 Utilities/cmcurl/lib/wildcard.h                    |    4 +-
 Utilities/cmcurl/lib/x509asn1.c                    |   31 +-
 Utilities/cmcurl/lib/x509asn1.h                    |    6 +-
 261 files changed, 11892 insertions(+), 7488 deletions(-)
 create mode 100755 Utilities/Scripts/update-curl.bash
 delete mode 100644 Utilities/cmcurl/README-CMake.txt
 delete mode 100644 Utilities/cmcurl/lib/curl_sasl_sspi.c
 delete mode 100644 Utilities/cmcurl/lib/http_negotiate_sspi.c
 rename Utilities/cmcurl/lib/{curl_ntlm.c => http_ntlm.c} (91%)
 rename Utilities/cmcurl/lib/{curl_ntlm.h => http_ntlm.h} (95%)
 create mode 100644 Utilities/cmcurl/lib/system_win32.c
 create mode 100644 Utilities/cmcurl/lib/system_win32.h
 create mode 100644 Utilities/cmcurl/lib/vauth/cleartext.c
 create mode 100644 Utilities/cmcurl/lib/vauth/cram.c
 create mode 100644 Utilities/cmcurl/lib/vauth/digest.c
 copy Utilities/cmcurl/lib/{strequal.h => vauth/digest.h} (59%)
 create mode 100644 Utilities/cmcurl/lib/vauth/digest_sspi.c
 rename Utilities/cmcurl/lib/{curl_sasl_gssapi.c => vauth/krb5_gssapi.c} (66%)
 create mode 100644 Utilities/cmcurl/lib/vauth/krb5_sspi.c
 rename Utilities/cmcurl/lib/{curl_ntlm_msgs.c => vauth/ntlm.c} (94%)
 rename Utilities/cmcurl/lib/{curl_ntlm_msgs.h => vauth/ntlm.h} (95%)
 create mode 100644 Utilities/cmcurl/lib/vauth/ntlm_sspi.c
 create mode 100644 Utilities/cmcurl/lib/vauth/oauth2.c
 create mode 100644 Utilities/cmcurl/lib/vauth/spnego_gssapi.c
 create mode 100644 Utilities/cmcurl/lib/vauth/spnego_sspi.c
 create mode 100644 Utilities/cmcurl/lib/vauth/vauth.c
 create mode 100644 Utilities/cmcurl/lib/vauth/vauth.h
 create mode 100644 Utilities/cmcurl/lib/vtls/mbedtls.c
 create mode 100644 Utilities/cmcurl/lib/vtls/mbedtls.h


hooks/post-receive
-- 
CMake


More information about the Cmake-commits mailing list