浏览代码

Merge topic 'update-curl'

bb759148 curl: Update build within CMake to account for 7.56 changes
9e3ef40e Merge branch 'upstream-curl' into update-curl
de7c21d6 curl 2017-10-04 (3ea76790)
2fad0e20 curl: Update script to get curl 7.56.0

Acked-by: Kitware Robot <[email protected]>
Merge-request: !1372
Brad King 8 年之前
父节点
当前提交
48a58e91a6
共有 100 个文件被更改,包括 4640 次插入3386 次删除
  1. 10 2
      Utilities/Scripts/update-curl.bash
  2. 29 0
      Utilities/cmcurl/CMake/Macros.cmake
  3. 6 6
      Utilities/cmcurl/CMake/OtherTests.cmake
  4. 26 0
      Utilities/cmcurl/CMake/cmake_uninstall.cmake.in
  5. 107 82
      Utilities/cmcurl/CMakeLists.txt
  6. 217 30
      Utilities/cmcurl/include/curl/curl.h
  7. 0 218
      Utilities/cmcurl/include/curl/curlbuild.h.cmake
  8. 0 239
      Utilities/cmcurl/include/curl/curlrules.h
  9. 4 4
      Utilities/cmcurl/include/curl/curlver.h
  10. 1 1
      Utilities/cmcurl/include/curl/multi.h
  11. 301 314
      Utilities/cmcurl/include/curl/system.h
  12. 18 3
      Utilities/cmcurl/include/curl/typecheck-gcc.h
  13. 8 3
      Utilities/cmcurl/lib/CMakeLists.txt
  14. 3 2
      Utilities/cmcurl/lib/Makefile.inc
  15. 4 4
      Utilities/cmcurl/lib/asyn-ares.c
  16. 33 22
      Utilities/cmcurl/lib/asyn-thread.c
  17. 1 1
      Utilities/cmcurl/lib/conncache.h
  18. 37 45
      Utilities/cmcurl/lib/connect.c
  19. 2 2
      Utilities/cmcurl/lib/connect.h
  20. 3 3
      Utilities/cmcurl/lib/content_encoding.c
  21. 88 58
      Utilities/cmcurl/lib/cookie.c
  22. 7 4
      Utilities/cmcurl/lib/cookie.h
  23. 3 3
      Utilities/cmcurl/lib/curl_addrinfo.c
  24. 3 9
      Utilities/cmcurl/lib/curl_config.h.cmake
  25. 6 6
      Utilities/cmcurl/lib/curl_fnmatch.c
  26. 58 34
      Utilities/cmcurl/lib/curl_ntlm_core.c
  27. 10 4
      Utilities/cmcurl/lib/curl_ntlm_core.h
  28. 10 16
      Utilities/cmcurl/lib/curl_ntlm_wb.c
  29. 7 1
      Utilities/cmcurl/lib/curl_rtmp.c
  30. 4 2
      Utilities/cmcurl/lib/curl_sasl.c
  31. 23 19
      Utilities/cmcurl/lib/curl_setup.h
  32. 0 14
      Utilities/cmcurl/lib/curl_setup_once.h
  33. 11 4
      Utilities/cmcurl/lib/curl_threads.c
  34. 8 7
      Utilities/cmcurl/lib/dict.c
  35. 15 15
      Utilities/cmcurl/lib/dotdot.c
  36. 14 12
      Utilities/cmcurl/lib/easy.c
  37. 13 13
      Utilities/cmcurl/lib/escape.c
  38. 24 18
      Utilities/cmcurl/lib/file.c
  39. 146 741
      Utilities/cmcurl/lib/formdata.c
  40. 3 51
      Utilities/cmcurl/lib/formdata.h
  41. 107 171
      Utilities/cmcurl/lib/ftp.c
  42. 3 1
      Utilities/cmcurl/lib/ftp.h
  43. 15 23
      Utilities/cmcurl/lib/ftplistparser.c
  44. 53 34
      Utilities/cmcurl/lib/getinfo.c
  45. 6 5
      Utilities/cmcurl/lib/gopher.c
  46. 2 2
      Utilities/cmcurl/lib/hash.c
  47. 7 7
      Utilities/cmcurl/lib/hostcheck.c
  48. 6 6
      Utilities/cmcurl/lib/hostip.c
  49. 2 2
      Utilities/cmcurl/lib/hostip4.c
  50. 2 2
      Utilities/cmcurl/lib/hostip6.c
  51. 240 204
      Utilities/cmcurl/lib/http.c
  52. 10 7
      Utilities/cmcurl/lib/http.h
  53. 58 7
      Utilities/cmcurl/lib/http2.c
  54. 4 3
      Utilities/cmcurl/lib/http2.h
  55. 12 14
      Utilities/cmcurl/lib/http_chunks.c
  56. 8 5
      Utilities/cmcurl/lib/http_ntlm.c
  57. 154 124
      Utilities/cmcurl/lib/http_proxy.c
  58. 10 0
      Utilities/cmcurl/lib/http_proxy.h
  59. 9 7
      Utilities/cmcurl/lib/if2ip.c
  60. 3 2
      Utilities/cmcurl/lib/if2ip.h
  61. 78 117
      Utilities/cmcurl/lib/imap.c
  62. 2 1
      Utilities/cmcurl/lib/imap.h
  63. 7 7
      Utilities/cmcurl/lib/inet_ntop.c
  64. 3 3
      Utilities/cmcurl/lib/inet_pton.c
  65. 4 1
      Utilities/cmcurl/lib/inet_pton.h
  66. 1 1
      Utilities/cmcurl/lib/krb5.c
  67. 5 4
      Utilities/cmcurl/lib/ldap.c
  68. 12 11
      Utilities/cmcurl/lib/memdebug.c
  69. 1860 0
      Utilities/cmcurl/lib/mime.c
  70. 135 0
      Utilities/cmcurl/lib/mime.h
  71. 17 21
      Utilities/cmcurl/lib/mprintf.c
  72. 75 64
      Utilities/cmcurl/lib/multi.c
  73. 1 1
      Utilities/cmcurl/lib/multihandle.h
  74. 24 20
      Utilities/cmcurl/lib/netrc.c
  75. 44 60
      Utilities/cmcurl/lib/non-ascii.c
  76. 1 3
      Utilities/cmcurl/lib/non-ascii.h
  77. 8 6
      Utilities/cmcurl/lib/openldap.c
  78. 37 37
      Utilities/cmcurl/lib/parsedate.c
  79. 14 14
      Utilities/cmcurl/lib/pingpong.c
  80. 1 1
      Utilities/cmcurl/lib/pingpong.h
  81. 15 22
      Utilities/cmcurl/lib/pipeline.c
  82. 2 77
      Utilities/cmcurl/lib/pop3.c
  83. 71 61
      Utilities/cmcurl/lib/progress.c
  84. 4 4
      Utilities/cmcurl/lib/progress.h
  85. 1 1
      Utilities/cmcurl/lib/rand.c
  86. 39 4
      Utilities/cmcurl/lib/rtsp.c
  87. 0 2
      Utilities/cmcurl/lib/rtsp.h
  88. 2 2
      Utilities/cmcurl/lib/security.c
  89. 5 5
      Utilities/cmcurl/lib/select.c
  90. 3 2
      Utilities/cmcurl/lib/select.h
  91. 10 10
      Utilities/cmcurl/lib/sendf.c
  92. 27 4
      Utilities/cmcurl/lib/smb.c
  93. 39 79
      Utilities/cmcurl/lib/smtp.c
  94. 49 39
      Utilities/cmcurl/lib/socks.c
  95. 30 29
      Utilities/cmcurl/lib/socks_gssapi.c
  96. 12 12
      Utilities/cmcurl/lib/socks_sspi.c
  97. 2 2
      Utilities/cmcurl/lib/speedcheck.c
  98. 2 2
      Utilities/cmcurl/lib/speedcheck.h
  99. 15 11
      Utilities/cmcurl/lib/splay.c
  100. 9 8
      Utilities/cmcurl/lib/splay.h

+ 10 - 2
Utilities/Scripts/update-curl.bash

@@ -8,14 +8,13 @@ readonly name="curl"
 readonly ownership="Curl Upstream <[email protected]>"
 readonly ownership="Curl Upstream <[email protected]>"
 readonly subtree="Utilities/cmcurl"
 readonly subtree="Utilities/cmcurl"
 readonly repo="https://github.com/curl/curl.git"
 readonly repo="https://github.com/curl/curl.git"
-readonly tag="curl-7_54_1"
+readonly tag="curl-7_56_0"
 readonly shortlog=false
 readonly shortlog=false
 readonly paths="
 readonly paths="
   CMake/*
   CMake/*
   CMakeLists.txt
   CMakeLists.txt
   COPYING
   COPYING
   include/curl/*.h
   include/curl/*.h
-  include/curl/curlbuild.h.cmake
   lib/*.c
   lib/*.c
   lib/*.h
   lib/*.h
   lib/CMakeLists.txt
   lib/CMakeLists.txt
@@ -32,6 +31,15 @@ extract_source () {
     git_archive
     git_archive
     pushd "${extractdir}/${name}-reduced"
     pushd "${extractdir}/${name}-reduced"
     rm lib/config-*.h
     rm lib/config-*.h
+    chmod a-x lib/connect.c
+    for f in \
+      lib/cookie.c \
+      lib/krb5.c \
+      lib/security.c \
+      ; do
+        iconv -f LATIN1 -t UTF8 $f -o $f.utf-8
+        mv $f.utf-8 $f
+    done
     echo "* -whitespace" > .gitattributes
     echo "* -whitespace" > .gitattributes
     popd
     popd
 }
 }

+ 29 - 0
Utilities/cmcurl/CMake/Macros.cmake

@@ -93,3 +93,32 @@ macro(CURL_INTERNAL_TEST_RUN CURL_TEST)
     endif(${CURL_TEST}_COMPILE AND NOT ${CURL_TEST})
     endif(${CURL_TEST}_COMPILE AND NOT ${CURL_TEST})
   endif()
   endif()
 endmacro(CURL_INTERNAL_TEST_RUN)
 endmacro(CURL_INTERNAL_TEST_RUN)
+
+macro(CURL_NROFF_CHECK)
+  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(NROFF_USEFUL ON)
+        break()
+      endif()
+    endforeach()
+    # No need for the temporary file
+    file(REMOVE "${CMAKE_CURRENT_BINARY_DIR}/nroff-input.txt")
+    if(NOT NROFF_USEFUL)
+      message(WARNING "Found no *nroff option to get plaintext from man pages")
+    endif()
+  else()
+    message(WARNING "Found no *nroff program")
+  endif()
+endmacro(CURL_NROFF_CHECK)

+ 6 - 6
Utilities/cmcurl/CMake/OtherTests.cmake

@@ -32,9 +32,9 @@ int main(void) {
 if(curl_cv_recv)
 if(curl_cv_recv)
   if(NOT DEFINED curl_cv_func_recv_args OR "${curl_cv_func_recv_args}" STREQUAL "unknown")
   if(NOT DEFINED curl_cv_func_recv_args OR "${curl_cv_func_recv_args}" STREQUAL "unknown")
     foreach(recv_retv "int" "ssize_t" )
     foreach(recv_retv "int" "ssize_t" )
-      foreach(recv_arg1 "int" "ssize_t" "SOCKET")
-        foreach(recv_arg2 "void *" "char *")
-          foreach(recv_arg3 "size_t" "int" "socklen_t" "unsigned int")
+      foreach(recv_arg1 "SOCKET" "int" )
+        foreach(recv_arg2 "char *" "void *" )
+          foreach(recv_arg3 "int" "size_t" "socklen_t" "unsigned int")
             foreach(recv_arg4 "int" "unsigned int")
             foreach(recv_arg4 "int" "unsigned int")
               if(NOT curl_cv_func_recv_done)
               if(NOT curl_cv_func_recv_done)
                 unset(curl_cv_func_recv_test CACHE)
                 unset(curl_cv_func_recv_test CACHE)
@@ -96,9 +96,9 @@ int main(void) {
 if(curl_cv_send)
 if(curl_cv_send)
   if(NOT DEFINED curl_cv_func_send_args OR "${curl_cv_func_send_args}" STREQUAL "unknown")
   if(NOT DEFINED curl_cv_func_send_args OR "${curl_cv_func_send_args}" STREQUAL "unknown")
     foreach(send_retv "int" "ssize_t" )
     foreach(send_retv "int" "ssize_t" )
-      foreach(send_arg1 "int" "ssize_t" "SOCKET")
-        foreach(send_arg2 "const void *" "void *" "char *" "const char *")
-          foreach(send_arg3 "size_t" "int" "socklen_t" "unsigned int")
+      foreach(send_arg1 "SOCKET" "int" "ssize_t" )
+        foreach(send_arg2 "const char *" "const void *" "void *" "char *")
+          foreach(send_arg3 "int" "size_t" "socklen_t" "unsigned int")
             foreach(send_arg4 "int" "unsigned int")
             foreach(send_arg4 "int" "unsigned int")
               if(NOT curl_cv_func_send_done)
               if(NOT curl_cv_func_send_done)
                 unset(curl_cv_func_send_test CACHE)
                 unset(curl_cv_func_send_test CACHE)

+ 26 - 0
Utilities/cmcurl/CMake/cmake_uninstall.cmake.in

@@ -0,0 +1,26 @@
+if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+  message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+
+if (NOT DEFINED CMAKE_INSTALL_PREFIX)
+  set (CMAKE_INSTALL_PREFIX "@CMAKE_INSTALL_PREFIX@")
+endif ()
+ message(${CMAKE_INSTALL_PREFIX})
+
+file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
+string(REGEX REPLACE "\n" ";" files "${files}")
+foreach(file ${files})
+  message(STATUS "Uninstalling $ENV{DESTDIR}${file}")
+  if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
+    exec_program(
+      "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
+      OUTPUT_VARIABLE rm_out
+      RETURN_VALUE rm_retval
+      )
+    if(NOT "${rm_retval}" STREQUAL 0)
+      message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}")
+    endif(NOT "${rm_retval}" STREQUAL 0)
+  else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
+    message(STATUS "File $ENV{DESTDIR}${file} does not exist.")
+  endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
+endforeach(file)

+ 107 - 82
Utilities/cmcurl/CMakeLists.txt

@@ -24,6 +24,7 @@ set(CURL_DISABLE_TFTP ON CACHE INTERNAL "Disable curl tftp protocol?")
 set(CURL_DISABLE_VERBOSE_STRINGS OFF CACHE INTERNAL "Do not disable curl verbosity")
 set(CURL_DISABLE_VERBOSE_STRINGS OFF CACHE INTERNAL "Do not disable curl verbosity")
 set(CURL_HIDDEN_SYMBOLS OFF CACHE INTERNAL "No curl hidden symbols")
 set(CURL_HIDDEN_SYMBOLS OFF CACHE INTERNAL "No curl hidden symbols")
 set(CURL_STATICLIB ON CACHE INTERNAL "Static curl")
 set(CURL_STATICLIB ON CACHE INTERNAL "Static curl")
+set(CURL_WERROR OFF CACHE INTERNAL "Turn compiler warnings into errors")
 set(DISABLED_THREADSAFE OFF CACHE INTERNAL "Curl can use thread-safe functions")
 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_ARES OFF CACHE INTERNAL "No curl c-ares support")
 set(ENABLE_CURLDEBUG OFF CACHE INTERNAL "No curl TrackMemory features")
 set(ENABLE_CURLDEBUG OFF CACHE INTERNAL "No curl TrackMemory features")
@@ -33,6 +34,7 @@ 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_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(ENABLE_UNIX_SOCKETS OFF CACHE INTERNAL "No curl Unix domain sockets support")
 set(HTTP_ONLY OFF CACHE INTERNAL "Curl is not http-only")
 set(HTTP_ONLY OFF CACHE INTERNAL "Curl is not http-only")
+set(PICKY_COMPILER OFF CACHE INTERNAL "Enable picky compiler options")
 set(USE_WIN32_LDAP OFF CACHE INTERNAL "No curl Windows LDAP")
 set(USE_WIN32_LDAP OFF CACHE INTERNAL "No curl Windows LDAP")
 if(CMAKE_USE_OPENSSL)
 if(CMAKE_USE_OPENSSL)
 elseif(WIN32)
 elseif(WIN32)
@@ -88,7 +90,7 @@ endif()
 #                            | (__| |_| |  _ <| |___
 #                            | (__| |_| |  _ <| |___
 #                             \___|\___/|_| \_\_____|
 #                             \___|\___/|_| \_\_____|
 #
 #
-# Copyright (C) 1998 - 2016, Daniel Stenberg, <[email protected]>, et al.
+# Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, et al.
 #
 #
 # This software is licensed as described in the file COPYING, which
 # This software is licensed as described in the file COPYING, which
 # you should have received as part of this distribution. The terms
 # you should have received as part of this distribution. The terms
@@ -126,6 +128,7 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake;${CMAKE_MODULE_PATH}")
 include(Utilities)
 include(Utilities)
 include(Macros)
 include(Macros)
 include(CMakeDependentOption)
 include(CMakeDependentOption)
+include(CheckCCompilerFlag)
 
 
 project( CURL C )
 project( CURL C )
 
 
@@ -159,20 +162,36 @@ set(OS "\"${CMAKE_SYSTEM_NAME}\"")
 include_directories(${PROJECT_BINARY_DIR}/include/curl)
 include_directories(${PROJECT_BINARY_DIR}/include/curl)
 include_directories( ${CURL_SOURCE_DIR}/include )
 include_directories( ${CURL_SOURCE_DIR}/include )
 
 
+option(CURL_WERROR "Turn compiler warnings into errors" OFF)
+option(PICKY_COMPILER "Enable picky compiler options" ON)
 option(BUILD_CURL_EXE "Set to ON to build curl executable." ON)
 option(BUILD_CURL_EXE "Set to ON to build curl executable." ON)
 option(CURL_STATICLIB "Set to ON to build libcurl with static linking." OFF)
 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_ARES "Set to ON to enable c-ares support" OFF)
 if(WIN32)
 if(WIN32)
-  CMAKE_DEPENDENT_OPTION(ENABLE_THREADED_RESOLVER
-                         "Set to ON to enable threaded DNS lookup"
-                         ON "NOT ENABLE_ARES"
-                         OFF)
-else()
-  option(ENABLE_THREADED_RESOLVER "Set to ON to enable POSIX threaded DNS lookup" OFF)
+  option(CURL_STATIC_CRT "Set to ON to build libcurl with static CRT on Windows (/MT)." OFF)
+  option(ENABLE_INET_PTON "Set to OFF to prevent usage of inet_pton when building against modern SDKs while still requiring compatibility with older Windows versions, such as Windows XP, Windows Server 2003 etc." ON)
 endif()
 endif()
+
+CMAKE_DEPENDENT_OPTION(ENABLE_THREADED_RESOLVER "Set to ON to enable threaded DNS lookup"
+        ON "NOT ENABLE_ARES"
+        OFF)
+
 option(ENABLE_DEBUG "Set to ON to enable curl debug features" 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)
 option(ENABLE_CURLDEBUG "Set to ON to build with TrackMemory feature enabled" OFF)
 
 
+if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANG)
+  if (PICKY_COMPILER)
+    foreach (_CCOPT -pedantic -Wall -W -Wpointer-arith -Wwrite-strings -Wunused -Wshadow -Winline -Wnested-externs -Wmissing-declarations -Wmissing-prototypes -Wno-long-long -Wfloat-equal -Wno-multichar -Wsign-compare -Wundef -Wno-format-nonliteral -Wendif-labels -Wstrict-prototypes -Wdeclaration-after-statement -Wstrict-aliasing=3 -Wcast-align -Wtype-limits -Wold-style-declaration -Wmissing-parameter-type -Wempty-body -Wclobbered -Wignored-qualifiers -Wconversion -Wno-sign-conversion -Wvla -Wdouble-promotion -Wno-system-headers)
+      # surprisingly, CHECK_C_COMPILER_FLAG needs a new variable to store each new
+      # test result in.
+      CHECK_C_COMPILER_FLAG(${_CCOPT} OPT${_CCOPT})
+      if(OPT${_CCOPT})
+        set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${_CCOPT}")
+      endif()
+    endforeach()
+  endif(PICKY_COMPILER)
+endif(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANG)
+
 if (ENABLE_DEBUG)
 if (ENABLE_DEBUG)
   # DEBUGBUILD will be defined only for Debug builds
   # DEBUGBUILD will be defined only for Debug builds
   if(NOT CMAKE_VERSION VERSION_LESS 3.0)
   if(NOT CMAKE_VERSION VERSION_LESS 3.0)
@@ -187,13 +206,14 @@ if (ENABLE_CURLDEBUG)
   set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS CURLDEBUG)
   set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS CURLDEBUG)
 endif()
 endif()
 
 
+if(0) # This code not needed for building within CMake.
+# For debug libs and exes, add "-d" postfix
+set(CMAKE_DEBUG_POSTFIX "-d" CACHE STRING "Set debug library postfix")
+endif()
+
 # initialize CURL_LIBS
 # initialize CURL_LIBS
 set(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)
 if(ENABLE_ARES)
   set(USE_ARES 1)
   set(USE_ARES 1)
   find_package(CARES REQUIRED)
   find_package(CARES REQUIRED)
@@ -201,11 +221,6 @@ if(ENABLE_ARES)
   set(CURL_LIBS ${CURL_LIBS} ${CARES_LIBRARY})
   set(CURL_LIBS ${CURL_LIBS} ${CARES_LIBRARY})
 endif()
 endif()
 
 
-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()
-
 if(0) # This code not needed for building within CMake.
 if(0) # This code not needed for building within CMake.
 include(CurlSymbolHiding)
 include(CurlSymbolHiding)
 endif()
 endif()
@@ -265,8 +280,6 @@ option(CURL_DISABLE_CRYPTO_AUTH "to disable cryptographic authentication" OFF)
 mark_as_advanced(CURL_DISABLE_CRYPTO_AUTH)
 mark_as_advanced(CURL_DISABLE_CRYPTO_AUTH)
 option(CURL_DISABLE_VERBOSE_STRINGS "to disable verbose strings" OFF)
 option(CURL_DISABLE_VERBOSE_STRINGS "to disable verbose strings" OFF)
 mark_as_advanced(CURL_DISABLE_VERBOSE_STRINGS)
 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)
 option(ENABLE_IPV6 "Define if you want to enable IPv6 support" ON)
 mark_as_advanced(ENABLE_IPV6)
 mark_as_advanced(ENABLE_IPV6)
 if(ENABLE_IPV6 AND NOT WIN32)
 if(ENABLE_IPV6 AND NOT WIN32)
@@ -283,51 +296,48 @@ if(ENABLE_IPV6 AND NOT WIN32)
   endif()
   endif()
 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()
-
 if(0) # This code not needed for building within CMake.
 if(0) # This code not needed for building within CMake.
+CURL_NROFF_CHECK()
 # Required for building manual, docs, tests
 # Required for building manual, docs, tests
-find_package(Perl REQUIRED)
+find_package(Perl)
+
+CMAKE_DEPENDENT_OPTION(ENABLE_MANUAL "to provide the built-in manual"
+    ON "NROFF_USEFUL;PERL_FOUND"
+    OFF)
+
+if(NOT PERL_FOUND)
+  message(STATUS "Perl not found, testing disabled.")
+  set(BUILD_TESTING OFF)
+endif()
+if(ENABLE_MANUAL)
+  set(USE_MANUAL ON)
+endif()
 endif()
 endif()
 
 
 # We need ansi c-flags, especially on HP
 # We need ansi c-flags, especially on HP
 set(CMAKE_C_FLAGS "${CMAKE_ANSI_CFLAGS} ${CMAKE_C_FLAGS}")
 set(CMAKE_C_FLAGS "${CMAKE_ANSI_CFLAGS} ${CMAKE_C_FLAGS}")
 set(CMAKE_REQUIRED_FLAGS ${CMAKE_ANSI_CFLAGS})
 set(CMAKE_REQUIRED_FLAGS ${CMAKE_ANSI_CFLAGS})
 
 
+if(CURL_STATIC_CRT)
+  set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MT")
+  set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MTd")
+endif()
+
 # Disable warnings on Borland to avoid changing 3rd party code.
 # Disable warnings on Borland to avoid changing 3rd party code.
 if(BORLAND)
 if(BORLAND)
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w-")
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w-")
 endif(BORLAND)
 endif(BORLAND)
 
 
+if(CURL_WERROR)
+  if(MSVC_VERSION)
+    set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /WX")
+    set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /WX")
+  else()
+    # this assumes clang or gcc style options
+    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
+  endif()
+endif(CURL_WERROR)
+
 # If we are on AIX, do the _ALL_SOURCE magic
 # If we are on AIX, do the _ALL_SOURCE magic
 if(${CMAKE_SYSTEM_NAME} MATCHES AIX)
 if(${CMAKE_SYSTEM_NAME} MATCHES AIX)
   set(_ALL_SOURCE 1)
   set(_ALL_SOURCE 1)
@@ -349,19 +359,14 @@ if(WIN32)
 endif(WIN32)
 endif(WIN32)
 
 
 if(ENABLE_THREADED_RESOLVER)
 if(ENABLE_THREADED_RESOLVER)
+  find_package(Threads REQUIRED)
   if(WIN32)
   if(WIN32)
     set(USE_THREADS_WIN32 ON)
     set(USE_THREADS_WIN32 ON)
   else()
   else()
-    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()
+    set(USE_THREADS_POSIX ${CMAKE_USE_PTHREADS_INIT})
+    set(HAVE_PTHREAD_H ${CMAKE_USE_PTHREADS_INIT})
   endif()
   endif()
+  set(CURL_LIBS ${CURL_LIBS} ${CMAKE_THREAD_LIBS_INIT})
 endif()
 endif()
 
 
 # Check for all needed libraries
 # Check for all needed libraries
@@ -911,11 +916,6 @@ check_type_size("int"  SIZEOF_INT)
 check_type_size("__int64"  SIZEOF___INT64)
 check_type_size("__int64"  SIZEOF___INT64)
 check_type_size("time_t"  SIZEOF_TIME_T)
 check_type_size("time_t"  SIZEOF_TIME_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)
 if(HAVE_SIZEOF_LONG_LONG)
   set(HAVE_LONGLONG 1)
   set(HAVE_LONGLONG 1)
   set(HAVE_LL 1)
   set(HAVE_LL 1)
@@ -1003,7 +1003,18 @@ check_symbol_exists(ioctl          "${CURL_INCLUDES}" HAVE_IOCTL)
 check_symbol_exists(setsockopt     "${CURL_INCLUDES}" HAVE_SETSOCKOPT)
 check_symbol_exists(setsockopt     "${CURL_INCLUDES}" HAVE_SETSOCKOPT)
 
 
 # symbol exists in win32, but function does not.
 # symbol exists in win32, but function does not.
-check_function_exists(inet_pton HAVE_INET_PTON)
+if(WIN32)
+  if(ENABLE_INET_PTON)
+    check_function_exists(inet_pton HAVE_INET_PTON)
+    # _WIN32_WINNT_VISTA (0x0600)
+    add_definitions(-D_WIN32_WINNT=0x0600)
+  else()
+    # _WIN32_WINNT_WINXP (0x0501)
+    add_definitions(-D_WIN32_WINNT=0x0501)
+  endif()
+else()
+    check_function_exists(inet_pton HAVE_INET_PTON)
+endif()
 
 
 check_symbol_exists(fsetxattr "${CURL_INCLUDES}" HAVE_FSETXATTR)
 check_symbol_exists(fsetxattr "${CURL_INCLUDES}" HAVE_FSETXATTR)
 if(HAVE_FSETXATTR)
 if(HAVE_FSETXATTR)
@@ -1075,6 +1086,13 @@ if(HAVE_FILE_OFFSET_BITS)
   set(CMAKE_REQUIRED_FLAGS "-D_FILE_OFFSET_BITS=64")
   set(CMAKE_REQUIRED_FLAGS "-D_FILE_OFFSET_BITS=64")
 endif(HAVE_FILE_OFFSET_BITS)
 endif(HAVE_FILE_OFFSET_BITS)
 check_type_size("off_t"  SIZEOF_OFF_T)
 check_type_size("off_t"  SIZEOF_OFF_T)
+
+# include this header to get the type
+set(CMAKE_REQUIRED_INCLUDES "${CURL_SOURCE_DIR}/include")
+set(CMAKE_EXTRA_INCLUDE_FILES "curl/system.h")
+check_type_size("curl_off_t"  SIZEOF_CURL_OFF_T)
+set(CMAKE_EXTRA_INCLUDE_FILES "")
+
 set(CMAKE_REQUIRED_FLAGS)
 set(CMAKE_REQUIRED_FLAGS)
 
 
 foreach(CURL_TEST
 foreach(CURL_TEST
@@ -1190,7 +1208,7 @@ else()
   set(CURL_HAVE_SOCKLEN_T 0)
   set(CURL_HAVE_SOCKLEN_T 0)
 endif()
 endif()
 
 
-# TODO test which of these headers are required for the typedefs used in curlbuild.h
+# TODO test which of these headers are required
 if(WIN32)
 if(WIN32)
   set(CURL_PULL_WS2TCPIP_H ${HAVE_WS2TCPIP_H})
   set(CURL_PULL_WS2TCPIP_H ${HAVE_WS2TCPIP_H})
 else()
 else()
@@ -1205,11 +1223,6 @@ include(CMake/OtherTests.cmake)
 
 
 add_definitions(-DHAVE_CONFIG_H)
 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)
-
 # For windows, all compilers used by cmake should support large files
 # For windows, all compilers used by cmake should support large files
 if(WIN32)
 if(WIN32)
   set(USE_WIN32_LARGE_FILES ON)
   set(USE_WIN32_LARGE_FILES ON)
@@ -1217,6 +1230,11 @@ endif(WIN32)
 
 
 if(MSVC)
 if(MSVC)
   add_definitions(-D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE)
   add_definitions(-D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE)
+  if(CMAKE_C_FLAGS MATCHES "/W[0-4]")
+    string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
+  else(CMAKE_C_FLAGS MATCHES "/W[0-4]")
+    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W4")
+  endif(CMAKE_C_FLAGS MATCHES "/W[0-4]")
 endif(MSVC)
 endif(MSVC)
 
 
 # Ugly (but functional) way to include "Makefile.inc" by transforming it (= regenerate it).
 # Ugly (but functional) way to include "Makefile.inc" by transforming it (= regenerate it).
@@ -1235,10 +1253,12 @@ function(TRANSFORM_MAKEFILE_INC INPUT_FILE OUTPUT_FILE)
 
 
 endfunction()
 endfunction()
 
 
-if(0) # This code not needed for building within CMake.
-add_subdirectory(docs)
+if(USE_MANUAL)
+  add_subdirectory(docs)
 endif()
 endif()
+
 add_subdirectory(lib)
 add_subdirectory(lib)
+
 if(BUILD_CURL_EXE)
 if(BUILD_CURL_EXE)
   add_subdirectory(src)
   add_subdirectory(src)
 endif()
 endif()
@@ -1355,7 +1375,7 @@ set(LDFLAGS                 "${CMAKE_SHARED_LINKER_FLAGS}")
 set(LIBCURL_LIBS            "")
 set(LIBCURL_LIBS            "")
 set(libdir                  "${CMAKE_INSTALL_PREFIX}/lib")
 set(libdir                  "${CMAKE_INSTALL_PREFIX}/lib")
 foreach(_lib ${CMAKE_C_IMPLICIT_LINK_LIBRARIES} ${CURL_LIBS})
 foreach(_lib ${CMAKE_C_IMPLICIT_LINK_LIBRARIES} ${CURL_LIBS})
-  if(_lib MATCHES ".*/.*")
+  if(_lib MATCHES ".*/.*" OR _lib MATCHES "^-")
     set(LIBCURL_LIBS          "${LIBCURL_LIBS} ${_lib}")
     set(LIBCURL_LIBS          "${LIBCURL_LIBS} ${_lib}")
   else()
   else()
     set(LIBCURL_LIBS          "${LIBCURL_LIBS} -l${_lib}")
     set(LIBCURL_LIBS          "${LIBCURL_LIBS} -l${_lib}")
@@ -1391,16 +1411,10 @@ 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")
   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()
 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 headers
 install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/curl"
 install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/curl"
     DESTINATION include
     DESTINATION include
-    FILES_MATCHING PATTERN "*.h"
-    PATTERN "curlbuild.h" EXCLUDE)
-
+    FILES_MATCHING PATTERN "*.h")
 
 
 # Workaround for MSVS10 to avoid the Dialog Hell
 # Workaround for MSVS10 to avoid the Dialog Hell
 # FIXME: This could be removed with future version of CMake.
 # FIXME: This could be removed with future version of CMake.
@@ -1410,4 +1424,15 @@ if(MSVC_VERSION EQUAL 1600)
     file(APPEND "${CURL_SLN_FILENAME}" "\n# This should be regenerated!\n")
     file(APPEND "${CURL_SLN_FILENAME}" "\n# This should be regenerated!\n")
   endif()
   endif()
 endif()
 endif()
+
+if(NOT TARGET uninstall)
+  configure_file(
+      ${CMAKE_CURRENT_SOURCE_DIR}/CMake/cmake_uninstall.cmake.in
+      ${CMAKE_CURRENT_BINARY_DIR}/CMake/cmake_uninstall.cmake
+      IMMEDIATE @ONLY)
+
+  add_custom_target(uninstall
+      COMMAND ${CMAKE_COMMAND} -P
+      ${CMAKE_CURRENT_BINARY_DIR}/CMake/cmake_uninstall.cmake)
+endif()
 endif()
 endif()

+ 217 - 30
Utilities/cmcurl/include/curl/curl.h

@@ -36,8 +36,6 @@
 
 
 #include "curlver.h"         /* libcurl version defines   */
 #include "curlver.h"         /* libcurl version defines   */
 #include "system.h"          /* determine things run-time */
 #include "system.h"          /* determine things run-time */
-#include "cmcurl/include/curl/curlbuild.h" /* libcurl build definitions */
-#include "curlrules.h"       /* libcurl rules enforcement */
 
 
 /*
 /*
  * Define WIN32 when build target is Win32 API
  * Define WIN32 when build target is Win32 API
@@ -76,6 +74,7 @@
 #if defined(_AIX) || defined(__NOVELL_LIBC__) || defined(__NetBSD__) || \
 #if defined(_AIX) || defined(__NOVELL_LIBC__) || defined(__NetBSD__) || \
     defined(__minix) || defined(__SYMBIAN32__) || defined(__INTEGRITY) || \
     defined(__minix) || defined(__SYMBIAN32__) || defined(__INTEGRITY) || \
     defined(ANDROID) || defined(__ANDROID__) || defined(__OpenBSD__) || \
     defined(ANDROID) || defined(__ANDROID__) || defined(__OpenBSD__) || \
+    defined(__CYGWIN__) || \
    (defined(__FreeBSD_version) && (__FreeBSD_version < 800000))
    (defined(__FreeBSD_version) && (__FreeBSD_version < 800000))
 #include <sys/select.h>
 #include <sys/select.h>
 #endif
 #endif
@@ -134,6 +133,27 @@ typedef int curl_socket_t;
 #define curl_socket_typedef
 #define curl_socket_typedef
 #endif /* curl_socket_typedef */
 #endif /* curl_socket_typedef */
 
 
+/* 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_WOLFSSL = 7,
+  CURLSSLBACKEND_SCHANNEL = 8,
+  CURLSSLBACKEND_DARWINSSL = 9,
+  CURLSSLBACKEND_AXTLS = 10,
+  CURLSSLBACKEND_MBEDTLS = 11
+} curl_sslbackend;
+
+/* aliases for library clones and renames */
+#define CURLSSLBACKEND_LIBRESSL CURLSSLBACKEND_OPENSSL
+#define CURLSSLBACKEND_BORINGSSL CURLSSLBACKEND_OPENSSL
+#define CURLSSLBACKEND_CYASSL CURLSSLBACKEND_WOLFSSL
+
 struct curl_httppost {
 struct curl_httppost {
   struct curl_httppost *next;       /* next entry in the list */
   struct curl_httppost *next;       /* next entry in the list */
   char *name;                       /* pointer to allocated name */
   char *name;                       /* pointer to allocated name */
@@ -337,7 +357,7 @@ typedef size_t (*curl_read_callback)(char *buffer,
                                       size_t nitems,
                                       size_t nitems,
                                       void *instream);
                                       void *instream);
 
 
-typedef enum  {
+typedef enum {
   CURLSOCKTYPE_IPCXN,  /* socket created for a specific IP connection */
   CURLSOCKTYPE_IPCXN,  /* socket created for a specific IP connection */
   CURLSOCKTYPE_ACCEPT, /* socket created by accept() call */
   CURLSOCKTYPE_ACCEPT, /* socket created by accept() call */
   CURLSOCKTYPE_LAST    /* never use */
   CURLSOCKTYPE_LAST    /* never use */
@@ -379,7 +399,7 @@ typedef enum {
   CURLIOE_LAST           /* never use */
   CURLIOE_LAST           /* never use */
 } curlioerr;
 } curlioerr;
 
 
-typedef enum  {
+typedef enum {
   CURLIOCMD_NOP,         /* no operation */
   CURLIOCMD_NOP,         /* no operation */
   CURLIOCMD_RESTARTREAD, /* restart the read stream from start */
   CURLIOCMD_RESTARTREAD, /* restart the read stream from start */
   CURLIOCMD_LAST         /* never use */
   CURLIOCMD_LAST         /* never use */
@@ -679,6 +699,8 @@ typedef enum {
 #define CURLAUTH_NEGOTIATE    (((unsigned long)1)<<2)
 #define CURLAUTH_NEGOTIATE    (((unsigned long)1)<<2)
 /* Deprecated since the advent of CURLAUTH_NEGOTIATE */
 /* Deprecated since the advent of CURLAUTH_NEGOTIATE */
 #define CURLAUTH_GSSNEGOTIATE CURLAUTH_NEGOTIATE
 #define CURLAUTH_GSSNEGOTIATE CURLAUTH_NEGOTIATE
+/* Used for CURLOPT_SOCKS5_AUTH to stay terminologically correct */
+#define CURLAUTH_GSSAPI CURLAUTH_NEGOTIATE
 #define CURLAUTH_NTLM         (((unsigned long)1)<<3)
 #define CURLAUTH_NTLM         (((unsigned long)1)<<3)
 #define CURLAUTH_DIGEST_IE    (((unsigned long)1)<<4)
 #define CURLAUTH_DIGEST_IE    (((unsigned long)1)<<4)
 #define CURLAUTH_NTLM_WB      (((unsigned long)1)<<5)
 #define CURLAUTH_NTLM_WB      (((unsigned long)1)<<5)
@@ -1782,6 +1804,18 @@ typedef enum {
   /* Suppress proxy CONNECT response headers from user callbacks */
   /* Suppress proxy CONNECT response headers from user callbacks */
   CINIT(SUPPRESS_CONNECT_HEADERS, LONG, 265),
   CINIT(SUPPRESS_CONNECT_HEADERS, LONG, 265),
 
 
+  /* The request target, instead of extracted from the URL */
+  CINIT(REQUEST_TARGET, STRINGPOINT, 266),
+
+  /* bitmask of allowed auth methods for connections to SOCKS5 proxies */
+  CINIT(SOCKS5_AUTH, LONG, 267),
+
+  /* Enable/disable SSH compression */
+  CINIT(SSH_COMPRESSION, LONG, 268),
+
+  /* Post MIME data. */
+  CINIT(MIMEPOST, OBJECTPOINT, 269),
+
   CURLOPT_LASTENTRY /* the last unused */
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
 } CURLoption;
 
 
@@ -1928,15 +1962,140 @@ typedef enum {
   CURL_TIMECOND_LAST
   CURL_TIMECOND_LAST
 } curl_TimeCond;
 } curl_TimeCond;
 
 
+/* Special size_t value signaling a zero-terminated string. */
+#define CURL_ZERO_TERMINATED ((size_t) -1)
 
 
 /* curl_strequal() and curl_strnequal() are subject for removal in a future
 /* curl_strequal() and curl_strnequal() are subject for removal in a future
-   libcurl, see lib/README.curlx for details
+   release */
+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);
+
+/* Mime/form handling support. */
+typedef struct curl_mime_s      curl_mime;      /* Mime context. */
+typedef struct curl_mimepart_s  curl_mimepart;  /* Mime part context. */
+
+/*
+ * NAME curl_mime_init()
+ *
+ * DESCRIPTION
+ *
+ * Create a mime context and return its handle. The easy parameter is the
+ * target handle.
+ */
+CURL_EXTERN curl_mime *curl_mime_init(CURL *easy);
+
+/*
+ * NAME curl_mime_free()
+ *
+ * DESCRIPTION
+ *
+ * release a mime handle and its substructures.
+ */
+CURL_EXTERN void curl_mime_free(curl_mime *mime);
+
+/*
+ * NAME curl_mime_addpart()
+ *
+ * DESCRIPTION
+ *
+ * Append a new empty part to the given mime context and return a handle to
+ * the created part.
+ */
+CURL_EXTERN curl_mimepart *curl_mime_addpart(curl_mime *mime);
+
+/*
+ * NAME curl_mime_name()
+ *
+ * DESCRIPTION
+ *
+ * Set mime/form part name.
+ */
+CURL_EXTERN CURLcode curl_mime_name(curl_mimepart *part, const char *name);
+
+/*
+ * NAME curl_mime_filename()
+ *
+ * DESCRIPTION
+ *
+ * Set mime part remote file name.
+ */
+CURL_EXTERN CURLcode curl_mime_filename(curl_mimepart *part,
+                                        const char *filename);
+
+/*
+ * NAME curl_mime_type()
+ *
+ * DESCRIPTION
+ *
+ * Set mime part type.
+ */
+CURL_EXTERN CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype);
+
+/*
+ * NAME curl_mime_encoder()
+ *
+ * DESCRIPTION
+ *
+ * Set mime data transfer encoder.
+ */
+CURL_EXTERN CURLcode curl_mime_encoder(curl_mimepart *part,
+                                       const char *encoding);
+
+/*
+ * NAME curl_mime_data()
+ *
+ * DESCRIPTION
+ *
+ * Set mime part data source from memory data,
+ */
+CURL_EXTERN CURLcode curl_mime_data(curl_mimepart *part,
+                                    const char *data, size_t datasize);
+
+/*
+ * NAME curl_mime_filedata()
+ *
+ * DESCRIPTION
+ *
+ * Set mime part data source from named file.
+ */
+CURL_EXTERN CURLcode curl_mime_filedata(curl_mimepart *part,
+                                        const char *filename);
+
+/*
+ * NAME curl_mime_data_cb()
+ *
+ * DESCRIPTION
+ *
+ * Set mime part data source from callback function.
+ */
+CURL_EXTERN CURLcode curl_mime_data_cb(curl_mimepart *part,
+                                       curl_off_t datasize,
+                                       curl_read_callback readfunc,
+                                       curl_seek_callback seekfunc,
+                                       curl_free_callback freefunc,
+                                       void *arg);
 
 
-   !checksrc! disable SPACEBEFOREPAREN 2
-*/
-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 curl_mime_subparts()
+ *
+ * DESCRIPTION
+ *
+ * Set mime part data source from subparts.
+ */
+CURL_EXTERN CURLcode curl_mime_subparts(curl_mimepart *part,
+                                        curl_mime *subparts);
+/*
+ * NAME curl_mime_headers()
+ *
+ * DESCRIPTION
+ *
+ * Set mime part headers.
+ */
+CURL_EXTERN CURLcode curl_mime_headers(curl_mimepart *part,
+                                       struct curl_slist *headers,
+                                       int take_ownership);
 
 
+/* Old form API. */
 /* name is uppercase CURLFORM_<name> */
 /* name is uppercase CURLFORM_<name> */
 #ifdef CFINIT
 #ifdef CFINIT
 #undef CFINIT
 #undef CFINIT
@@ -2178,6 +2337,47 @@ struct curl_slist {
   struct curl_slist *next;
   struct curl_slist *next;
 };
 };
 
 
+/*
+ * NAME curl_global_sslset()
+ *
+ * DESCRIPTION
+ *
+ * When built with multiple SSL backends, curl_global_sslset() allows to
+ * choose one. This function can only be called once, and it must be called
+ * *before* curl_global_init().
+ *
+ * The backend can be identified by the id (e.g. CURLSSLBACKEND_OPENSSL). The
+ * backend can also be specified via the name parameter (passing -1 as id).
+ * If both id and name are specified, the name will be ignored. If neither id
+ * nor name are specified, the function will fail with
+ * CURLSSLSET_UNKNOWN_BACKEND and set the "avail" pointer to the
+ * NULL-terminated list of available backends.
+ *
+ * Upon success, the function returns CURLSSLSET_OK.
+ *
+ * If the specified SSL backend is not available, the function returns
+ * CURLSSLSET_UNKNOWN_BACKEND and sets the "avail" pointer to a NULL-terminated
+ * list of available SSL backends.
+ *
+ * The SSL backend can be set only once. If it has already been set, a
+ * subsequent attempt to change it will result in a CURLSSLSET_TOO_LATE.
+ */
+
+typedef struct {
+  curl_sslbackend id;
+  const char *name;
+} curl_ssl_backend;
+
+typedef enum {
+  CURLSSLSET_OK = 0,
+  CURLSSLSET_UNKNOWN_BACKEND,
+  CURLSSLSET_TOO_LATE,
+  CURLSSLSET_NO_BACKENDS /* libcurl was built without any SSL support */
+} CURLsslset;
+
+CURL_EXTERN CURLsslset curl_global_sslset(curl_sslbackend id, const char *name,
+                                          const curl_ssl_backend ***avail);
+
 /*
 /*
  * NAME curl_slist_append()
  * NAME curl_slist_append()
  *
  *
@@ -2218,27 +2418,6 @@ struct curl_certinfo {
                                    format "name: value" */
                                    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_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
 /* Information about the SSL library used and the respective internal SSL
    handle, which can be used to obtain further information regarding the
    handle, which can be used to obtain further information regarding the
    connection. Asked for with CURLINFO_TLS_SSL_PTR or CURLINFO_TLS_SESSION. */
    connection. Asked for with CURLINFO_TLS_SSL_PTR or CURLINFO_TLS_SESSION. */
@@ -2253,6 +2432,7 @@ struct curl_tlssessioninfo {
 #define CURLINFO_SLIST    0x400000
 #define CURLINFO_SLIST    0x400000
 #define CURLINFO_PTR      0x400000 /* same as SLIST */
 #define CURLINFO_PTR      0x400000 /* same as SLIST */
 #define CURLINFO_SOCKET   0x500000
 #define CURLINFO_SOCKET   0x500000
+#define CURLINFO_OFF_T    0x600000
 #define CURLINFO_MASK     0x0fffff
 #define CURLINFO_MASK     0x0fffff
 #define CURLINFO_TYPEMASK 0xf00000
 #define CURLINFO_TYPEMASK 0xf00000
 
 
@@ -2265,15 +2445,21 @@ typedef enum {
   CURLINFO_CONNECT_TIME     = CURLINFO_DOUBLE + 5,
   CURLINFO_CONNECT_TIME     = CURLINFO_DOUBLE + 5,
   CURLINFO_PRETRANSFER_TIME = CURLINFO_DOUBLE + 6,
   CURLINFO_PRETRANSFER_TIME = CURLINFO_DOUBLE + 6,
   CURLINFO_SIZE_UPLOAD      = CURLINFO_DOUBLE + 7,
   CURLINFO_SIZE_UPLOAD      = CURLINFO_DOUBLE + 7,
+  CURLINFO_SIZE_UPLOAD_T    = CURLINFO_OFF_T  + 7,
   CURLINFO_SIZE_DOWNLOAD    = CURLINFO_DOUBLE + 8,
   CURLINFO_SIZE_DOWNLOAD    = CURLINFO_DOUBLE + 8,
+  CURLINFO_SIZE_DOWNLOAD_T  = CURLINFO_OFF_T  + 8,
   CURLINFO_SPEED_DOWNLOAD   = CURLINFO_DOUBLE + 9,
   CURLINFO_SPEED_DOWNLOAD   = CURLINFO_DOUBLE + 9,
+  CURLINFO_SPEED_DOWNLOAD_T = CURLINFO_OFF_T  + 9,
   CURLINFO_SPEED_UPLOAD     = CURLINFO_DOUBLE + 10,
   CURLINFO_SPEED_UPLOAD     = CURLINFO_DOUBLE + 10,
+  CURLINFO_SPEED_UPLOAD_T   = CURLINFO_OFF_T  + 10,
   CURLINFO_HEADER_SIZE      = CURLINFO_LONG   + 11,
   CURLINFO_HEADER_SIZE      = CURLINFO_LONG   + 11,
   CURLINFO_REQUEST_SIZE     = CURLINFO_LONG   + 12,
   CURLINFO_REQUEST_SIZE     = CURLINFO_LONG   + 12,
   CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG   + 13,
   CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG   + 13,
   CURLINFO_FILETIME         = CURLINFO_LONG   + 14,
   CURLINFO_FILETIME         = CURLINFO_LONG   + 14,
   CURLINFO_CONTENT_LENGTH_DOWNLOAD   = CURLINFO_DOUBLE + 15,
   CURLINFO_CONTENT_LENGTH_DOWNLOAD   = CURLINFO_DOUBLE + 15,
+  CURLINFO_CONTENT_LENGTH_DOWNLOAD_T = CURLINFO_OFF_T  + 15,
   CURLINFO_CONTENT_LENGTH_UPLOAD     = CURLINFO_DOUBLE + 16,
   CURLINFO_CONTENT_LENGTH_UPLOAD     = CURLINFO_DOUBLE + 16,
+  CURLINFO_CONTENT_LENGTH_UPLOAD_T   = CURLINFO_OFF_T  + 16,
   CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17,
   CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17,
   CURLINFO_CONTENT_TYPE     = CURLINFO_STRING + 18,
   CURLINFO_CONTENT_TYPE     = CURLINFO_STRING + 18,
   CURLINFO_REDIRECT_TIME    = CURLINFO_DOUBLE + 19,
   CURLINFO_REDIRECT_TIME    = CURLINFO_DOUBLE + 19,
@@ -2471,6 +2657,7 @@ typedef struct {
 #define CURL_VERSION_PSL          (1<<20) /* Mozilla's Public Suffix List, used
 #define CURL_VERSION_PSL          (1<<20) /* Mozilla's Public Suffix List, used
                                              for cookie domain verification */
                                              for cookie domain verification */
 #define CURL_VERSION_HTTPS_PROXY  (1<<21) /* HTTPS-proxy support built-in */
 #define CURL_VERSION_HTTPS_PROXY  (1<<21) /* HTTPS-proxy support built-in */
+#define CURL_VERSION_MULTI_SSL    (1<<22) /* Multiple SSL backends available */
 
 
  /*
  /*
  * NAME curl_version_info()
  * NAME curl_version_info()

+ 0 - 218
Utilities/cmcurl/include/curl/curlbuild.h.cmake

@@ -1,218 +0,0 @@
-#ifndef __CURL_CURLBUILD_H
-#define __CURL_CURLBUILD_H
-/***************************************************************************
- *                                  _   _ ____  _
- *  Project                     ___| | | |  _ \| |
- *                             / __| | | | |_) | |
- *                            | (__| |_| |  _ <| |___
- *                             \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2008, Daniel Stenberg, <[email protected]>, 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.
- *
- ***************************************************************************/
-
-/* ================================================================ */
-/*               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: 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. */
-@CURL_SIZEOF_INT_CODE@
-
-/* The size of `long', as computed by sizeof. */
-@CURL_SIZEOF_LONG_CODE@
-
-/* The size of `long long', as computed by sizeof. */
-@CURL_SIZEOF_LONG_LONG_CODE@
-
-/* The size of `ssize_t', as computed by sizeof. */
-@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. */
-@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 */

+ 0 - 239
Utilities/cmcurl/include/curl/curlrules.h

@@ -1,239 +0,0 @@
-#ifndef __CURL_CURLRULES_H
-#define __CURL_CURLRULES_H
-/***************************************************************************
- *                                  _   _ ____  _
- *  Project                     ___| | | |  _ \| |
- *                             / __| | | | |_) | |
- *                            | (__| |_| |  _ <| |___
- *                             \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, 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.
- *
- ***************************************************************************/
-
-/* ================================================================ */
-/*                    COMPILE TIME SANITY CHECKS                    */
-/* ================================================================ */
-
-/*
- * NOTE 1:
- * -------
- *
- * All checks done in this file are intentionally placed in a public
- * header file which is pulled by curl/curl.h when an application is
- * being built using an already built libcurl library. Additionally
- * this file is also included and used when building the library.
- *
- * If compilation fails on this file it is certainly sure that the
- * problem is elsewhere. It could be a problem in the curlbuild.h
- * header file, or simply that you are using different compilation
- * settings than those used to build the library.
- *
- * Nothing in this file is intended to be modified or adjusted by the
- * curl library user nor by the curl library builder.
- *
- * Do not deactivate any check, these are done to make sure that the
- * library is properly built and used.
- *
- * You can find further help on the libcurl development mailing list:
- * https://cool.haxx.se/mailman/listinfo/curl-library/
- *
- * NOTE 2
- * ------
- *
- * Some of the following compile time checks are based on the fact
- * that the dimension of a constant array can not be a negative one.
- * In this way if the compile time verification fails, the compilation
- * will fail issuing an error. The error description wording is compiler
- * dependent but it will be quite similar to one of the following:
- *
- *   "negative subscript or subscript is too large"
- *   "array must have at least one element"
- *   "-1 is an illegal array size"
- *   "size of array is negative"
- *
- * If you are building an application which tries to use an already
- * built libcurl library and you are getting this kind of errors on
- * this file, it is a clear indication that there is a mismatch between
- * how the library was built and how you are trying to use it for your
- * application. Your already compiled or binary library provider is the
- * only one who can give you the details you need to properly use it.
- */
-
-/*
- * Verify that some macros are actually defined.
- */
-
-#ifndef CURL_SIZEOF_LONG
-#  error "CURL_SIZEOF_LONG definition is missing!"
-   Error Compilation_aborted_CURL_SIZEOF_LONG_is_missing
-#endif
-
-#ifndef CURL_TYPEOF_CURL_SOCKLEN_T
-#  error "CURL_TYPEOF_CURL_SOCKLEN_T definition is missing!"
-   Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_is_missing
-#endif
-
-#ifndef CURL_SIZEOF_CURL_SOCKLEN_T
-#  error "CURL_SIZEOF_CURL_SOCKLEN_T definition is missing!"
-   Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_is_missing
-#endif
-
-#ifndef CURL_TYPEOF_CURL_OFF_T
-#  error "CURL_TYPEOF_CURL_OFF_T definition is missing!"
-   Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_is_missing
-#endif
-
-#ifndef CURL_FORMAT_CURL_OFF_T
-#  error "CURL_FORMAT_CURL_OFF_T definition is missing!"
-   Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_is_missing
-#endif
-
-#ifndef CURL_FORMAT_CURL_OFF_TU
-#  error "CURL_FORMAT_CURL_OFF_TU definition is missing!"
-   Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_is_missing
-#endif
-
-#ifndef CURL_SIZEOF_CURL_OFF_T
-#  error "CURL_SIZEOF_CURL_OFF_T definition is missing!"
-   Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_is_missing
-#endif
-
-#ifndef CURL_SUFFIX_CURL_OFF_T
-#  error "CURL_SUFFIX_CURL_OFF_T definition is missing!"
-   Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_is_missing
-#endif
-
-#ifndef CURL_SUFFIX_CURL_OFF_TU
-#  error "CURL_SUFFIX_CURL_OFF_TU definition is missing!"
-   Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_is_missing
-#endif
-
-/*
- * Macros private to this header file.
- */
-
-#define CurlchkszEQ(t, s) sizeof(t) == s ? 1 : -1
-
-#define CurlchkszGE(t1, t2) sizeof(t1) >= sizeof(t2) ? 1 : -1
-
-/*
- * Verify that the size previously defined and expected for long
- * is the same as the one reported by sizeof() at compile time.
- */
-
-typedef char
-  __curl_rule_01__
-    [CurlchkszEQ(long, CURL_SIZEOF_LONG)];
-
-/*
- * Verify that the size previously defined and expected for
- * curl_off_t is actually the the same as the one reported
- * by sizeof() at compile time.
- */
-
-typedef char
-  __curl_rule_02__
-    [CurlchkszEQ(curl_off_t, CURL_SIZEOF_CURL_OFF_T)];
-
-/*
- * Verify at compile time that the size of curl_off_t as reported
- * by sizeof() is greater or equal than the one reported for long
- * for the current compilation.
- */
-
-typedef char
-  __curl_rule_03__
-    [CurlchkszGE(curl_off_t, long)];
-
-/*
- * Verify that the size previously defined and expected for
- * curl_socklen_t is actually the the same as the one reported
- * by sizeof() at compile time.
- */
-
-typedef char
-  __curl_rule_04__
-    [CurlchkszEQ(curl_socklen_t, CURL_SIZEOF_CURL_SOCKLEN_T)];
-
-/*
- * Verify at compile time that the size of curl_socklen_t as reported
- * by sizeof() is greater or equal than the one reported for int for
- * the current compilation.
- */
-
-typedef char
-  __curl_rule_05__
-    [CurlchkszGE(curl_socklen_t, int)];
-
-/* ================================================================ */
-/*          EXTERNALLY AND INTERNALLY VISIBLE DEFINITIONS           */
-/* ================================================================ */
-
-/*
- * CURL_ISOCPP and CURL_OFF_T_C definitions are done here in order to allow
- * these to be visible and exported by the external libcurl interface API,
- * while also making them visible to the library internals, simply including
- * curl_setup.h, without actually needing to include curl.h internally.
- * If some day this section would grow big enough, all this should be moved
- * to its own header file.
- */
-
-/*
- * Figure out if we can use the ## preprocessor operator, which is supported
- * by ISO/ANSI C and C++. Some compilers support it without setting __STDC__
- * or  __cplusplus so we need to carefully check for them too.
- */
-
-#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \
-  defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \
-  defined(__POCC__) || defined(__SALFORDC__) || defined(__HIGHC__) || \
-  defined(__ILEC400__)
-  /* This compiler is believed to have an ISO compatible preprocessor */
-#define CURL_ISOCPP
-#else
-  /* This compiler is believed NOT to have an ISO compatible preprocessor */
-#undef CURL_ISOCPP
-#endif
-
-/*
- * Macros for minimum-width signed and unsigned curl_off_t integer constants.
- */
-
-#if defined(__BORLANDC__) && (__BORLANDC__ == 0x0551)
-#  define __CURL_OFF_T_C_HLPR2(x) x
-#  define __CURL_OFF_T_C_HLPR1(x) __CURL_OFF_T_C_HLPR2(x)
-#  define CURL_OFF_T_C(Val)  __CURL_OFF_T_C_HLPR1(Val) ## \
-                             __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_T)
-#  define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \
-                             __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_TU)
-#else
-#  ifdef CURL_ISOCPP
-#    define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val ## Suffix
-#  else
-#    define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val/**/Suffix
-#  endif
-#  define __CURL_OFF_T_C_HLPR1(Val,Suffix) __CURL_OFF_T_C_HLPR2(Val,Suffix)
-#  define CURL_OFF_T_C(Val)  __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_T)
-#  define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_TU)
-#endif
-
-/*
- * Get rid of macros private to this header file.
- */
-
-#undef CurlchkszEQ
-#undef CurlchkszGE
-
-#endif /* __CURL_CURLRULES_H */

+ 4 - 4
Utilities/cmcurl/include/curl/curlver.h

@@ -30,13 +30,13 @@
 
 
 /* This is the version number of the libcurl package from which this header
 /* This is the version number of the libcurl package from which this header
    file origins: */
    file origins: */
-#define LIBCURL_VERSION "7.54.1"
+#define LIBCURL_VERSION "7.56.0"
 
 
 /* The numeric version number is also available "in parts" by using these
 /* The numeric version number is also available "in parts" by using these
    defines: */
    defines: */
 #define LIBCURL_VERSION_MAJOR 7
 #define LIBCURL_VERSION_MAJOR 7
-#define LIBCURL_VERSION_MINOR 54
-#define LIBCURL_VERSION_PATCH 1
+#define LIBCURL_VERSION_MINOR 56
+#define LIBCURL_VERSION_PATCH 0
 
 
 /* This is the numeric version of the libcurl version number, meant for easier
 /* This is the numeric version of the libcurl version number, meant for easier
    parsing and comparions by programs. The LIBCURL_VERSION_NUM define will
    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
    CURL_VERSION_BITS() macro since curl's own configure script greps for it
    and needs it to contain the full number.
    and needs it to contain the full number.
 */
 */
-#define LIBCURL_VERSION_NUM 0x073601
+#define LIBCURL_VERSION_NUM 0x073800
 
 
 /*
 /*
  * This is the date and time when the full source package was created. The
  * This is the date and time when the full source package was created. The

+ 1 - 1
Utilities/cmcurl/include/curl/multi.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms

+ 301 - 314
Utilities/cmcurl/include/curl/system.h

@@ -22,14 +22,6 @@
  *
  *
  ***************************************************************************/
  ***************************************************************************/
 
 
-/*
- * This header is supposed to eventually replace curlbuild.h. This little one
- * is still learning.  During the experimental phase, this header files
- * defines symbols using the prefixes CURLSYS_ or curlsys_. When we feel
- * confident enough, we replace curlbuild.h with this file and rename all
- * prefixes to CURL_ and curl_.
- */
-
 /*
 /*
  * Try to keep one section per platform, compiler and architecture, otherwise,
  * Try to keep one section per platform, compiler and architecture, otherwise,
  * if an existing section is reused for a different one and later on the
  * if an existing section is reused for a different one and later on the
@@ -60,323 +52,271 @@
 
 
 #if defined(__DJGPP__) || defined(__GO32__)
 #if defined(__DJGPP__) || defined(__GO32__)
 #  if defined(__DJGPP__) && (__DJGPP__ > 1)
 #  if defined(__DJGPP__) && (__DJGPP__ > 1)
-#    define CURLSYS_SIZEOF_LONG           4
-#    define CURLSYS_TYPEOF_CURL_OFF_T     long long
-#    define CURLSYS_FORMAT_CURL_OFF_T     "lld"
-#    define CURLSYS_FORMAT_CURL_OFF_TU    "llu"
-#    define CURLSYS_SIZEOF_CURL_OFF_T     8
-#    define CURLSYS_SUFFIX_CURL_OFF_T     LL
-#    define CURLSYS_SUFFIX_CURL_OFF_TU    ULL
+#    define CURL_TYPEOF_CURL_OFF_T     long long
+#    define CURL_FORMAT_CURL_OFF_T     "lld"
+#    define CURL_FORMAT_CURL_OFF_TU    "llu"
+#    define CURL_SUFFIX_CURL_OFF_T     LL
+#    define CURL_SUFFIX_CURL_OFF_TU    ULL
 #  else
 #  else
-#    define CURLSYS_SIZEOF_LONG           4
-#    define CURLSYS_TYPEOF_CURL_OFF_T     long
-#    define CURLSYS_FORMAT_CURL_OFF_T     "ld"
-#    define CURLSYS_FORMAT_CURL_OFF_TU    "lu"
-#    define CURLSYS_SIZEOF_CURL_OFF_T     4
-#    define CURLSYS_SUFFIX_CURL_OFF_T     L
-#    define CURLSYS_SUFFIX_CURL_OFF_TU    UL
+#    define CURL_TYPEOF_CURL_OFF_T     long
+#    define CURL_FORMAT_CURL_OFF_T     "ld"
+#    define CURL_FORMAT_CURL_OFF_TU    "lu"
+#    define CURL_SUFFIX_CURL_OFF_T     L
+#    define CURL_SUFFIX_CURL_OFF_TU    UL
 #  endif
 #  endif
-#  define CURLSYS_TYPEOF_CURL_SOCKLEN_T int
-#  define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
+#  define CURL_TYPEOF_CURL_SOCKLEN_T int
 
 
 #elif defined(__SALFORDC__)
 #elif defined(__SALFORDC__)
-#  define CURLSYS_SIZEOF_LONG           4
-#  define CURLSYS_TYPEOF_CURL_OFF_T     long
-#  define CURLSYS_FORMAT_CURL_OFF_T     "ld"
-#  define CURLSYS_FORMAT_CURL_OFF_TU    "lu"
-#  define CURLSYS_SIZEOF_CURL_OFF_T     4
-#  define CURLSYS_SUFFIX_CURL_OFF_T     L
-#  define CURLSYS_SUFFIX_CURL_OFF_TU    UL
-#  define CURLSYS_TYPEOF_CURL_SOCKLEN_T int
-#  define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
+#  define CURL_TYPEOF_CURL_OFF_T     long
+#  define CURL_FORMAT_CURL_OFF_T     "ld"
+#  define CURL_FORMAT_CURL_OFF_TU    "lu"
+#  define CURL_SUFFIX_CURL_OFF_T     L
+#  define CURL_SUFFIX_CURL_OFF_TU    UL
+#  define CURL_TYPEOF_CURL_SOCKLEN_T int
 
 
 #elif defined(__BORLANDC__)
 #elif defined(__BORLANDC__)
 #  if (__BORLANDC__ < 0x520)
 #  if (__BORLANDC__ < 0x520)
-#    define CURLSYS_SIZEOF_LONG           4
-#    define CURLSYS_TYPEOF_CURL_OFF_T     long
-#    define CURLSYS_FORMAT_CURL_OFF_T     "ld"
-#    define CURLSYS_FORMAT_CURL_OFF_TU    "lu"
-#    define CURLSYS_SIZEOF_CURL_OFF_T     4
-#    define CURLSYS_SUFFIX_CURL_OFF_T     L
-#    define CURLSYS_SUFFIX_CURL_OFF_TU    UL
+#    define CURL_TYPEOF_CURL_OFF_T     long
+#    define CURL_FORMAT_CURL_OFF_T     "ld"
+#    define CURL_FORMAT_CURL_OFF_TU    "lu"
+#    define CURL_SUFFIX_CURL_OFF_T     L
+#    define CURL_SUFFIX_CURL_OFF_TU    UL
 #  else
 #  else
-#    define CURLSYS_SIZEOF_LONG           4
-#    define CURLSYS_TYPEOF_CURL_OFF_T     __int64
-#    define CURLSYS_FORMAT_CURL_OFF_T     "I64d"
-#    define CURLSYS_FORMAT_CURL_OFF_TU    "I64u"
-#    define CURLSYS_SIZEOF_CURL_OFF_T     8
-#    define CURLSYS_SUFFIX_CURL_OFF_T     i64
-#    define CURLSYS_SUFFIX_CURL_OFF_TU    ui64
+#    define CURL_TYPEOF_CURL_OFF_T     __int64
+#    define CURL_FORMAT_CURL_OFF_T     "I64d"
+#    define CURL_FORMAT_CURL_OFF_TU    "I64u"
+#    define CURL_SUFFIX_CURL_OFF_T     i64
+#    define CURL_SUFFIX_CURL_OFF_TU    ui64
 #  endif
 #  endif
-#  define CURLSYS_TYPEOF_CURL_SOCKLEN_T int
-#  define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
+#  define CURL_TYPEOF_CURL_SOCKLEN_T int
 
 
 #elif defined(__TURBOC__)
 #elif defined(__TURBOC__)
-#  define CURLSYS_SIZEOF_LONG           4
-#  define CURLSYS_TYPEOF_CURL_OFF_T     long
-#  define CURLSYS_FORMAT_CURL_OFF_T     "ld"
-#  define CURLSYS_FORMAT_CURL_OFF_TU    "lu"
-#  define CURLSYS_SIZEOF_CURL_OFF_T     4
-#  define CURLSYS_SUFFIX_CURL_OFF_T     L
-#  define CURLSYS_SUFFIX_CURL_OFF_TU    UL
-#  define CURLSYS_TYPEOF_CURL_SOCKLEN_T int
-#  define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
+#  define CURL_TYPEOF_CURL_OFF_T     long
+#  define CURL_FORMAT_CURL_OFF_T     "ld"
+#  define CURL_FORMAT_CURL_OFF_TU    "lu"
+#  define CURL_SUFFIX_CURL_OFF_T     L
+#  define CURL_SUFFIX_CURL_OFF_TU    UL
+#  define CURL_TYPEOF_CURL_SOCKLEN_T int
 
 
 #elif defined(__WATCOMC__)
 #elif defined(__WATCOMC__)
 #  if defined(__386__)
 #  if defined(__386__)
-#    define CURLSYS_SIZEOF_LONG           4
-#    define CURLSYS_TYPEOF_CURL_OFF_T     __int64
-#    define CURLSYS_FORMAT_CURL_OFF_T     "I64d"
-#    define CURLSYS_FORMAT_CURL_OFF_TU    "I64u"
-#    define CURLSYS_SIZEOF_CURL_OFF_T     8
-#    define CURLSYS_SUFFIX_CURL_OFF_T     i64
-#    define CURLSYS_SUFFIX_CURL_OFF_TU    ui64
+#    define CURL_TYPEOF_CURL_OFF_T     __int64
+#    define CURL_FORMAT_CURL_OFF_T     "I64d"
+#    define CURL_FORMAT_CURL_OFF_TU    "I64u"
+#    define CURL_SUFFIX_CURL_OFF_T     i64
+#    define CURL_SUFFIX_CURL_OFF_TU    ui64
 #  else
 #  else
-#    define CURLSYS_SIZEOF_LONG           4
-#    define CURLSYS_TYPEOF_CURL_OFF_T     long
-#    define CURLSYS_FORMAT_CURL_OFF_T     "ld"
-#    define CURLSYS_FORMAT_CURL_OFF_TU    "lu"
-#    define CURLSYS_SIZEOF_CURL_OFF_T     4
-#    define CURLSYS_SUFFIX_CURL_OFF_T     L
-#    define CURLSYS_SUFFIX_CURL_OFF_TU    UL
+#    define CURL_TYPEOF_CURL_OFF_T     long
+#    define CURL_FORMAT_CURL_OFF_T     "ld"
+#    define CURL_FORMAT_CURL_OFF_TU    "lu"
+#    define CURL_SUFFIX_CURL_OFF_T     L
+#    define CURL_SUFFIX_CURL_OFF_TU    UL
 #  endif
 #  endif
-#  define CURLSYS_TYPEOF_CURL_SOCKLEN_T int
-#  define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
+#  define CURL_TYPEOF_CURL_SOCKLEN_T int
 
 
 #elif defined(__POCC__)
 #elif defined(__POCC__)
 #  if (__POCC__ < 280)
 #  if (__POCC__ < 280)
-#    define CURLSYS_SIZEOF_LONG           4
-#    define CURLSYS_TYPEOF_CURL_OFF_T     long
-#    define CURLSYS_FORMAT_CURL_OFF_T     "ld"
-#    define CURLSYS_FORMAT_CURL_OFF_TU    "lu"
-#    define CURLSYS_SIZEOF_CURL_OFF_T     4
-#    define CURLSYS_SUFFIX_CURL_OFF_T     L
-#    define CURLSYS_SUFFIX_CURL_OFF_TU    UL
+#    define CURL_TYPEOF_CURL_OFF_T     long
+#    define CURL_FORMAT_CURL_OFF_T     "ld"
+#    define CURL_FORMAT_CURL_OFF_TU    "lu"
+#    define CURL_SUFFIX_CURL_OFF_T     L
+#    define CURL_SUFFIX_CURL_OFF_TU    UL
 #  elif defined(_MSC_VER)
 #  elif defined(_MSC_VER)
-#    define CURLSYS_SIZEOF_LONG           4
-#    define CURLSYS_TYPEOF_CURL_OFF_T     __int64
-#    define CURLSYS_FORMAT_CURL_OFF_T     "I64d"
-#    define CURLSYS_FORMAT_CURL_OFF_TU    "I64u"
-#    define CURLSYS_SIZEOF_CURL_OFF_T     8
-#    define CURLSYS_SUFFIX_CURL_OFF_T     i64
-#    define CURLSYS_SUFFIX_CURL_OFF_TU    ui64
+#    define CURL_TYPEOF_CURL_OFF_T     __int64
+#    define CURL_FORMAT_CURL_OFF_T     "I64d"
+#    define CURL_FORMAT_CURL_OFF_TU    "I64u"
+#    define CURL_SUFFIX_CURL_OFF_T     i64
+#    define CURL_SUFFIX_CURL_OFF_TU    ui64
 #  else
 #  else
-#    define CURLSYS_SIZEOF_LONG           4
-#    define CURLSYS_TYPEOF_CURL_OFF_T     long long
-#    define CURLSYS_FORMAT_CURL_OFF_T     "lld"
-#    define CURLSYS_FORMAT_CURL_OFF_TU    "llu"
-#    define CURLSYS_SIZEOF_CURL_OFF_T     8
-#    define CURLSYS_SUFFIX_CURL_OFF_T     LL
-#    define CURLSYS_SUFFIX_CURL_OFF_TU    ULL
+#    define CURL_TYPEOF_CURL_OFF_T     long long
+#    define CURL_FORMAT_CURL_OFF_T     "lld"
+#    define CURL_FORMAT_CURL_OFF_TU    "llu"
+#    define CURL_SUFFIX_CURL_OFF_T     LL
+#    define CURL_SUFFIX_CURL_OFF_TU    ULL
 #  endif
 #  endif
-#  define CURLSYS_TYPEOF_CURL_SOCKLEN_T int
-#  define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
+#  define CURL_TYPEOF_CURL_SOCKLEN_T int
 
 
 #elif defined(__LCC__)
 #elif defined(__LCC__)
-#  define CURLSYS_SIZEOF_LONG           4
-#  define CURLSYS_TYPEOF_CURL_OFF_T     long
-#  define CURLSYS_FORMAT_CURL_OFF_T     "ld"
-#  define CURLSYS_FORMAT_CURL_OFF_TU    "lu"
-#  define CURLSYS_SIZEOF_CURL_OFF_T     4
-#  define CURLSYS_SUFFIX_CURL_OFF_T     L
-#  define CURLSYS_SUFFIX_CURL_OFF_TU    UL
-#  define CURLSYS_TYPEOF_CURL_SOCKLEN_T int
-#  define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
+#  define CURL_TYPEOF_CURL_OFF_T     long
+#  define CURL_FORMAT_CURL_OFF_T     "ld"
+#  define CURL_FORMAT_CURL_OFF_TU    "lu"
+#  define CURL_SUFFIX_CURL_OFF_T     L
+#  define CURL_SUFFIX_CURL_OFF_TU    UL
+#  define CURL_TYPEOF_CURL_SOCKLEN_T int
 
 
 #elif defined(__SYMBIAN32__)
 #elif defined(__SYMBIAN32__)
 #  if defined(__EABI__)  /* Treat all ARM compilers equally */
 #  if defined(__EABI__)  /* Treat all ARM compilers equally */
-#    define CURLSYS_SIZEOF_LONG           4
-#    define CURLSYS_TYPEOF_CURL_OFF_T     long long
-#    define CURLSYS_FORMAT_CURL_OFF_T     "lld"
-#    define CURLSYS_FORMAT_CURL_OFF_TU    "llu"
-#    define CURLSYS_SIZEOF_CURL_OFF_T     8
-#    define CURLSYS_SUFFIX_CURL_OFF_T     LL
-#    define CURLSYS_SUFFIX_CURL_OFF_TU    ULL
+#    define CURL_TYPEOF_CURL_OFF_T     long long
+#    define CURL_FORMAT_CURL_OFF_T     "lld"
+#    define CURL_FORMAT_CURL_OFF_TU    "llu"
+#    define CURL_SUFFIX_CURL_OFF_T     LL
+#    define CURL_SUFFIX_CURL_OFF_TU    ULL
 #  elif defined(__CW32__)
 #  elif defined(__CW32__)
 #    pragma longlong on
 #    pragma longlong on
-#    define CURLSYS_SIZEOF_LONG           4
-#    define CURLSYS_TYPEOF_CURL_OFF_T     long long
-#    define CURLSYS_FORMAT_CURL_OFF_T     "lld"
-#    define CURLSYS_FORMAT_CURL_OFF_TU    "llu"
-#    define CURLSYS_SIZEOF_CURL_OFF_T     8
-#    define CURLSYS_SUFFIX_CURL_OFF_T     LL
-#    define CURLSYS_SUFFIX_CURL_OFF_TU    ULL
+#    define CURL_TYPEOF_CURL_OFF_T     long long
+#    define CURL_FORMAT_CURL_OFF_T     "lld"
+#    define CURL_FORMAT_CURL_OFF_TU    "llu"
+#    define CURL_SUFFIX_CURL_OFF_T     LL
+#    define CURL_SUFFIX_CURL_OFF_TU    ULL
 #  elif defined(__VC32__)
 #  elif defined(__VC32__)
-#    define CURLSYS_SIZEOF_LONG           4
-#    define CURLSYS_TYPEOF_CURL_OFF_T     __int64
-#    define CURLSYS_FORMAT_CURL_OFF_T     "lld"
-#    define CURLSYS_FORMAT_CURL_OFF_TU    "llu"
-#    define CURLSYS_SIZEOF_CURL_OFF_T     8
-#    define CURLSYS_SUFFIX_CURL_OFF_T     LL
-#    define CURLSYS_SUFFIX_CURL_OFF_TU    ULL
+#    define CURL_TYPEOF_CURL_OFF_T     __int64
+#    define CURL_FORMAT_CURL_OFF_T     "lld"
+#    define CURL_FORMAT_CURL_OFF_TU    "llu"
+#    define CURL_SUFFIX_CURL_OFF_T     LL
+#    define CURL_SUFFIX_CURL_OFF_TU    ULL
 #  endif
 #  endif
-#  define CURLSYS_TYPEOF_CURL_SOCKLEN_T unsigned int
-#  define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
+#  define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int
 
 
 #elif defined(__MWERKS__)
 #elif defined(__MWERKS__)
-#  define CURLSYS_SIZEOF_LONG           4
-#  define CURLSYS_TYPEOF_CURL_OFF_T     long long
-#  define CURLSYS_FORMAT_CURL_OFF_T     "lld"
-#  define CURLSYS_FORMAT_CURL_OFF_TU    "llu"
-#  define CURLSYS_SIZEOF_CURL_OFF_T     8
-#  define CURLSYS_SUFFIX_CURL_OFF_T     LL
-#  define CURLSYS_SUFFIX_CURL_OFF_TU    ULL
-#  define CURLSYS_TYPEOF_CURL_SOCKLEN_T int
-#  define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
+#  define CURL_TYPEOF_CURL_OFF_T     long long
+#  define CURL_FORMAT_CURL_OFF_T     "lld"
+#  define CURL_FORMAT_CURL_OFF_TU    "llu"
+#  define CURL_SUFFIX_CURL_OFF_T     LL
+#  define CURL_SUFFIX_CURL_OFF_TU    ULL
+#  define CURL_TYPEOF_CURL_SOCKLEN_T int
 
 
 #elif defined(_WIN32_WCE)
 #elif defined(_WIN32_WCE)
-#  define CURLSYS_SIZEOF_LONG           4
-#  define CURLSYS_TYPEOF_CURL_OFF_T     __int64
-#  define CURLSYS_FORMAT_CURL_OFF_T     "I64d"
-#  define CURLSYS_FORMAT_CURL_OFF_TU    "I64u"
-#  define CURLSYS_SIZEOF_CURL_OFF_T     8
-#  define CURLSYS_SUFFIX_CURL_OFF_T     i64
-#  define CURLSYS_SUFFIX_CURL_OFF_TU    ui64
-#  define CURLSYS_TYPEOF_CURL_SOCKLEN_T int
-#  define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
+#  define CURL_TYPEOF_CURL_OFF_T     __int64
+#  define CURL_FORMAT_CURL_OFF_T     "I64d"
+#  define CURL_FORMAT_CURL_OFF_TU    "I64u"
+#  define CURL_SUFFIX_CURL_OFF_T     i64
+#  define CURL_SUFFIX_CURL_OFF_TU    ui64
+#  define CURL_TYPEOF_CURL_SOCKLEN_T int
 
 
 #elif defined(__MINGW32__)
 #elif defined(__MINGW32__)
-#  define CURLSYS_SIZEOF_LONG           4
-#  define CURLSYS_TYPEOF_CURL_OFF_T     long long
-#  define CURLSYS_FORMAT_CURL_OFF_T     "I64d"
-#  define CURLSYS_FORMAT_CURL_OFF_TU    "I64u"
-#  define CURLSYS_SIZEOF_CURL_OFF_T     8
-#  define CURLSYS_SUFFIX_CURL_OFF_T     LL
-#  define CURLSYS_SUFFIX_CURL_OFF_TU    ULL
-#  define CURLSYS_TYPEOF_CURL_SOCKLEN_T socklen_t
-#  define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
-#  define CURLSYS_PULL_SYS_TYPES_H      1
-#  define CURLSYS_PULL_WS2TCPIP_H       1
+#  define CURL_TYPEOF_CURL_OFF_T     long long
+#  define CURL_FORMAT_CURL_OFF_T     "I64d"
+#  define CURL_FORMAT_CURL_OFF_TU    "I64u"
+#  define CURL_SUFFIX_CURL_OFF_T     LL
+#  define CURL_SUFFIX_CURL_OFF_TU    ULL
+#  define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
+#  define CURL_PULL_SYS_TYPES_H      1
+#  define CURL_PULL_WS2TCPIP_H       1
 
 
 #elif defined(__VMS)
 #elif defined(__VMS)
 #  if defined(__VAX)
 #  if defined(__VAX)
-#    define CURLSYS_SIZEOF_LONG           4
-#    define CURLSYS_TYPEOF_CURL_OFF_T     long
-#    define CURLSYS_FORMAT_CURL_OFF_T     "ld"
-#    define CURLSYS_FORMAT_CURL_OFF_TU    "lu"
-#    define CURLSYS_SIZEOF_CURL_OFF_T     4
-#    define CURLSYS_SUFFIX_CURL_OFF_T     L
-#    define CURLSYS_SUFFIX_CURL_OFF_TU    UL
+#    define CURL_TYPEOF_CURL_OFF_T     long
+#    define CURL_FORMAT_CURL_OFF_T     "ld"
+#    define CURL_FORMAT_CURL_OFF_TU    "lu"
+#    define CURL_SUFFIX_CURL_OFF_T     L
+#    define CURL_SUFFIX_CURL_OFF_TU    UL
 #  else
 #  else
-#    define CURLSYS_SIZEOF_LONG           4
-#    define CURLSYS_TYPEOF_CURL_OFF_T     long long
-#    define CURLSYS_FORMAT_CURL_OFF_T     "lld"
-#    define CURLSYS_FORMAT_CURL_OFF_TU    "llu"
-#    define CURLSYS_SIZEOF_CURL_OFF_T     8
-#    define CURLSYS_SUFFIX_CURL_OFF_T     LL
-#    define CURLSYS_SUFFIX_CURL_OFF_TU    ULL
+#    define CURL_TYPEOF_CURL_OFF_T     long long
+#    define CURL_FORMAT_CURL_OFF_T     "lld"
+#    define CURL_FORMAT_CURL_OFF_TU    "llu"
+#    define CURL_SUFFIX_CURL_OFF_T     LL
+#    define CURL_SUFFIX_CURL_OFF_TU    ULL
 #  endif
 #  endif
-#  define CURLSYS_TYPEOF_CURL_SOCKLEN_T unsigned int
-#  define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
+#  define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int
 
 
 #elif defined(__OS400__)
 #elif defined(__OS400__)
 #  if defined(__ILEC400__)
 #  if defined(__ILEC400__)
-#    define CURLSYS_SIZEOF_LONG           4
-#    define CURLSYS_TYPEOF_CURL_OFF_T     long long
-#    define CURLSYS_FORMAT_CURL_OFF_T     "lld"
-#    define CURLSYS_FORMAT_CURL_OFF_TU    "llu"
-#    define CURLSYS_SIZEOF_CURL_OFF_T     8
-#    define CURLSYS_SUFFIX_CURL_OFF_T     LL
-#    define CURLSYS_SUFFIX_CURL_OFF_TU    ULL
-#    define CURLSYS_TYPEOF_CURL_SOCKLEN_T socklen_t
-#    define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
-#    define CURLSYS_PULL_SYS_TYPES_H      1
-#    define CURLSYS_PULL_SYS_SOCKET_H     1
+#    define CURL_TYPEOF_CURL_OFF_T     long long
+#    define CURL_FORMAT_CURL_OFF_T     "lld"
+#    define CURL_FORMAT_CURL_OFF_TU    "llu"
+#    define CURL_SUFFIX_CURL_OFF_T     LL
+#    define CURL_SUFFIX_CURL_OFF_TU    ULL
+#    define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
+#    define CURL_PULL_SYS_TYPES_H      1
+#    define CURL_PULL_SYS_SOCKET_H     1
 #  endif
 #  endif
 
 
 #elif defined(__MVS__)
 #elif defined(__MVS__)
 #  if defined(__IBMC__) || defined(__IBMCPP__)
 #  if defined(__IBMC__) || defined(__IBMCPP__)
 #    if defined(_ILP32)
 #    if defined(_ILP32)
-#      define CURLSYS_SIZEOF_LONG           4
 #    elif defined(_LP64)
 #    elif defined(_LP64)
-#      define CURLSYS_SIZEOF_LONG           8
 #    endif
 #    endif
 #    if defined(_LONG_LONG)
 #    if defined(_LONG_LONG)
-#      define CURLSYS_TYPEOF_CURL_OFF_T     long long
-#      define CURLSYS_FORMAT_CURL_OFF_T     "lld"
-#      define CURLSYS_FORMAT_CURL_OFF_TU    "llu"
-#      define CURLSYS_SIZEOF_CURL_OFF_T     8
-#      define CURLSYS_SUFFIX_CURL_OFF_T     LL
-#      define CURLSYS_SUFFIX_CURL_OFF_TU    ULL
+#      define CURL_TYPEOF_CURL_OFF_T     long long
+#      define CURL_FORMAT_CURL_OFF_T     "lld"
+#      define CURL_FORMAT_CURL_OFF_TU    "llu"
+#      define CURL_SUFFIX_CURL_OFF_T     LL
+#      define CURL_SUFFIX_CURL_OFF_TU    ULL
 #    elif defined(_LP64)
 #    elif defined(_LP64)
-#      define CURLSYS_TYPEOF_CURL_OFF_T     long
-#      define CURLSYS_FORMAT_CURL_OFF_T     "ld"
-#      define CURLSYS_FORMAT_CURL_OFF_TU    "lu"
-#      define CURLSYS_SIZEOF_CURL_OFF_T     8
-#      define CURLSYS_SUFFIX_CURL_OFF_T     L
-#      define CURLSYS_SUFFIX_CURL_OFF_TU    UL
+#      define CURL_TYPEOF_CURL_OFF_T     long
+#      define CURL_FORMAT_CURL_OFF_T     "ld"
+#      define CURL_FORMAT_CURL_OFF_TU    "lu"
+#      define CURL_SUFFIX_CURL_OFF_T     L
+#      define CURL_SUFFIX_CURL_OFF_TU    UL
 #    else
 #    else
-#      define CURLSYS_TYPEOF_CURL_OFF_T     long
-#      define CURLSYS_FORMAT_CURL_OFF_T     "ld"
-#      define CURLSYS_FORMAT_CURL_OFF_TU    "lu"
-#      define CURLSYS_SIZEOF_CURL_OFF_T     4
-#      define CURLSYS_SUFFIX_CURL_OFF_T     L
-#      define CURLSYS_SUFFIX_CURL_OFF_TU    UL
+#      define CURL_TYPEOF_CURL_OFF_T     long
+#      define CURL_FORMAT_CURL_OFF_T     "ld"
+#      define CURL_FORMAT_CURL_OFF_TU    "lu"
+#      define CURL_SUFFIX_CURL_OFF_T     L
+#      define CURL_SUFFIX_CURL_OFF_TU    UL
 #    endif
 #    endif
-#    define CURLSYS_TYPEOF_CURL_SOCKLEN_T socklen_t
-#    define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
-#    define CURLSYS_PULL_SYS_TYPES_H      1
-#    define CURLSYS_PULL_SYS_SOCKET_H     1
+#    define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
+#    define CURL_PULL_SYS_TYPES_H      1
+#    define CURL_PULL_SYS_SOCKET_H     1
 #  endif
 #  endif
 
 
 #elif defined(__370__)
 #elif defined(__370__)
 #  if defined(__IBMC__) || defined(__IBMCPP__)
 #  if defined(__IBMC__) || defined(__IBMCPP__)
 #    if defined(_ILP32)
 #    if defined(_ILP32)
-#      define CURLSYS_SIZEOF_LONG           4
 #    elif defined(_LP64)
 #    elif defined(_LP64)
-#      define CURLSYS_SIZEOF_LONG           8
 #    endif
 #    endif
 #    if defined(_LONG_LONG)
 #    if defined(_LONG_LONG)
-#      define CURLSYS_TYPEOF_CURL_OFF_T     long long
-#      define CURLSYS_FORMAT_CURL_OFF_T     "lld"
-#      define CURLSYS_FORMAT_CURL_OFF_TU    "llu"
-#      define CURLSYS_SIZEOF_CURL_OFF_T     8
-#      define CURLSYS_SUFFIX_CURL_OFF_T     LL
-#      define CURLSYS_SUFFIX_CURL_OFF_TU    ULL
+#      define CURL_TYPEOF_CURL_OFF_T     long long
+#      define CURL_FORMAT_CURL_OFF_T     "lld"
+#      define CURL_FORMAT_CURL_OFF_TU    "llu"
+#      define CURL_SUFFIX_CURL_OFF_T     LL
+#      define CURL_SUFFIX_CURL_OFF_TU    ULL
 #    elif defined(_LP64)
 #    elif defined(_LP64)
-#      define CURLSYS_TYPEOF_CURL_OFF_T     long
-#      define CURLSYS_FORMAT_CURL_OFF_T     "ld"
-#      define CURLSYS_FORMAT_CURL_OFF_TU    "lu"
-#      define CURLSYS_SIZEOF_CURL_OFF_T     8
-#      define CURLSYS_SUFFIX_CURL_OFF_T     L
-#      define CURLSYS_SUFFIX_CURL_OFF_TU    UL
+#      define CURL_TYPEOF_CURL_OFF_T     long
+#      define CURL_FORMAT_CURL_OFF_T     "ld"
+#      define CURL_FORMAT_CURL_OFF_TU    "lu"
+#      define CURL_SUFFIX_CURL_OFF_T     L
+#      define CURL_SUFFIX_CURL_OFF_TU    UL
 #    else
 #    else
-#      define CURLSYS_TYPEOF_CURL_OFF_T     long
-#      define CURLSYS_FORMAT_CURL_OFF_T     "ld"
-#      define CURLSYS_FORMAT_CURL_OFF_TU    "lu"
-#      define CURLSYS_SIZEOF_CURL_OFF_T     4
-#      define CURLSYS_SUFFIX_CURL_OFF_T     L
-#      define CURLSYS_SUFFIX_CURL_OFF_TU    UL
+#      define CURL_TYPEOF_CURL_OFF_T     long
+#      define CURL_FORMAT_CURL_OFF_T     "ld"
+#      define CURL_FORMAT_CURL_OFF_TU    "lu"
+#      define CURL_SUFFIX_CURL_OFF_T     L
+#      define CURL_SUFFIX_CURL_OFF_TU    UL
 #    endif
 #    endif
-#    define CURLSYS_TYPEOF_CURL_SOCKLEN_T socklen_t
-#    define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
-#    define CURLSYS_PULL_SYS_TYPES_H      1
-#    define CURLSYS_PULL_SYS_SOCKET_H     1
+#    define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
+#    define CURL_PULL_SYS_TYPES_H      1
+#    define CURL_PULL_SYS_SOCKET_H     1
 #  endif
 #  endif
 
 
 #elif defined(TPF)
 #elif defined(TPF)
-#  define CURLSYS_SIZEOF_LONG           8
-#  define CURLSYS_TYPEOF_CURL_OFF_T     long
-#  define CURLSYS_FORMAT_CURL_OFF_T     "ld"
-#  define CURLSYS_FORMAT_CURL_OFF_TU    "lu"
-#  define CURLSYS_SIZEOF_CURL_OFF_T     8
-#  define CURLSYS_SUFFIX_CURL_OFF_T     L
-#  define CURLSYS_SUFFIX_CURL_OFF_TU    UL
-#  define CURLSYS_TYPEOF_CURL_SOCKLEN_T int
-#  define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
+#  define CURL_TYPEOF_CURL_OFF_T     long
+#  define CURL_FORMAT_CURL_OFF_T     "ld"
+#  define CURL_FORMAT_CURL_OFF_TU    "lu"
+#  define CURL_SUFFIX_CURL_OFF_T     L
+#  define CURL_SUFFIX_CURL_OFF_TU    UL
+#  define CURL_TYPEOF_CURL_SOCKLEN_T int
 
 
 #elif defined(__TINYC__) /* also known as tcc */
 #elif defined(__TINYC__) /* also known as tcc */
 
 
-#  define CURLSYS_SIZEOF_LONG           4
-#  define CURLSYS_TYPEOF_CURL_OFF_T     long long
-#  define CURLSYS_FORMAT_CURL_OFF_T     "lld"
-#  define CURLSYS_FORMAT_CURL_OFF_TU    "llu"
-#  define CURLSYS_SIZEOF_CURL_OFF_T     8
-#  define CURLSYS_SUFFIX_CURL_OFF_T     LL
-#  define CURLSYS_SUFFIX_CURL_OFF_TU    ULL
-#  define CURLSYS_TYPEOF_CURL_SOCKLEN_T socklen_t
-#  define CURLSYS_PULL_SYS_TYPES_H      1
-#  define CURLSYS_PULL_SYS_SOCKET_H     1
+#  define CURL_TYPEOF_CURL_OFF_T     long long
+#  define CURL_FORMAT_CURL_OFF_T     "lld"
+#  define CURL_FORMAT_CURL_OFF_TU    "llu"
+#  define CURL_SUFFIX_CURL_OFF_T     LL
+#  define CURL_SUFFIX_CURL_OFF_TU    ULL
+#  define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
+#  define CURL_PULL_SYS_TYPES_H      1
+#  define CURL_PULL_SYS_SOCKET_H     1
+
+#elif defined(__SUNPRO_C) /* Oracle Solaris Studio */
+#  if !defined(__LP64) && (defined(__ILP32) ||                          \
+                           defined(__i386) || defined(__sparcv8))
+#    define CURL_TYPEOF_CURL_OFF_T     long long
+#    define CURL_FORMAT_CURL_OFF_T     "lld"
+#    define CURL_FORMAT_CURL_OFF_TU    "llu"
+#    define CURL_SUFFIX_CURL_OFF_T     LL
+#    define CURL_SUFFIX_CURL_OFF_TU    ULL
+#  elif defined(__LP64) || \
+        defined(__amd64) || defined(__sparcv9)
+#    define CURL_TYPEOF_CURL_OFF_T     long
+#    define CURL_FORMAT_CURL_OFF_T     "ld"
+#    define CURL_FORMAT_CURL_OFF_TU    "lu"
+#    define CURL_SUFFIX_CURL_OFF_T     L
+#    define CURL_SUFFIX_CURL_OFF_TU    UL
+#  endif
+#  define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
+#  define CURL_PULL_SYS_TYPES_H      1
+#  define CURL_PULL_SYS_SOCKET_H     1
 
 
 /* ===================================== */
 /* ===================================== */
 /*    KEEP MSVC THE PENULTIMATE ENTRY    */
 /*    KEEP MSVC THE PENULTIMATE ENTRY    */
@@ -384,101 +324,148 @@
 
 
 #elif defined(_MSC_VER)
 #elif defined(_MSC_VER)
 #  if (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64)
 #  if (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64)
-#    define CURLSYS_SIZEOF_LONG           4
-#    define CURLSYS_TYPEOF_CURL_OFF_T     __int64
-#    define CURLSYS_FORMAT_CURL_OFF_T     "I64d"
-#    define CURLSYS_FORMAT_CURL_OFF_TU    "I64u"
-#    define CURLSYS_SIZEOF_CURL_OFF_T     8
-#    define CURLSYS_SUFFIX_CURL_OFF_T     i64
-#    define CURLSYS_SUFFIX_CURL_OFF_TU    ui64
+#    define CURL_TYPEOF_CURL_OFF_T     __int64
+#    define CURL_FORMAT_CURL_OFF_T     "I64d"
+#    define CURL_FORMAT_CURL_OFF_TU    "I64u"
+#    define CURL_SUFFIX_CURL_OFF_T     i64
+#    define CURL_SUFFIX_CURL_OFF_TU    ui64
 #  else
 #  else
-#    define CURLSYS_SIZEOF_LONG           4
-#    define CURLSYS_TYPEOF_CURL_OFF_T     long
-#    define CURLSYS_FORMAT_CURL_OFF_T     "ld"
-#    define CURLSYS_FORMAT_CURL_OFF_TU    "lu"
-#    define CURLSYS_SIZEOF_CURL_OFF_T     4
-#    define CURLSYS_SUFFIX_CURL_OFF_T     L
-#    define CURLSYS_SUFFIX_CURL_OFF_TU    UL
+#    define CURL_TYPEOF_CURL_OFF_T     long
+#    define CURL_FORMAT_CURL_OFF_T     "ld"
+#    define CURL_FORMAT_CURL_OFF_TU    "lu"
+#    define CURL_SUFFIX_CURL_OFF_T     L
+#    define CURL_SUFFIX_CURL_OFF_TU    UL
 #  endif
 #  endif
-#  define CURLSYS_TYPEOF_CURL_SOCKLEN_T int
-#  define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
+#  define CURL_TYPEOF_CURL_SOCKLEN_T int
 
 
 /* ===================================== */
 /* ===================================== */
 /*    KEEP GENERIC GCC THE LAST ENTRY    */
 /*    KEEP GENERIC GCC THE LAST ENTRY    */
 /* ===================================== */
 /* ===================================== */
 
 
 #elif defined(__GNUC__)
 #elif defined(__GNUC__)
-#  if !defined(__LP64__) && (defined(__ILP32__) || \
-      defined(__i386__) || defined(__ppc__) || defined(__arm__) || \
-      defined(__sparc__) || defined(__mips__) || defined(__sh__))
-#    define CURLSYS_SIZEOF_LONG           4
-#    define CURLSYS_TYPEOF_CURL_OFF_T     long long
-#    define CURLSYS_FORMAT_CURL_OFF_T     "lld"
-#    define CURLSYS_FORMAT_CURL_OFF_TU    "llu"
-#    define CURLSYS_SIZEOF_CURL_OFF_T     8
-#    define CURLSYS_SUFFIX_CURL_OFF_T     LL
-#    define CURLSYS_SUFFIX_CURL_OFF_TU    ULL
+#  if !defined(__LP64__) &&                                             \
+  (defined(__ILP32__) || defined(__i386__) || defined(__hppa__) ||      \
+   defined(__ppc__) || defined(__powerpc__) || defined(__arm__) ||      \
+   defined(__sparc__) || defined(__mips__) || defined(__sh__) ||        \
+   defined(__XTENSA__) ||                                               \
+   (defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 4))
+#    define CURL_TYPEOF_CURL_OFF_T     long long
+#    define CURL_FORMAT_CURL_OFF_T     "lld"
+#    define CURL_FORMAT_CURL_OFF_TU    "llu"
+#    define CURL_SUFFIX_CURL_OFF_T     LL
+#    define CURL_SUFFIX_CURL_OFF_TU    ULL
 #  elif defined(__LP64__) || \
 #  elif defined(__LP64__) || \
-        defined(__x86_64__) || defined(__ppc64__) || defined(__sparc64__)
-#    define CURLSYS_SIZEOF_LONG           8
-#    define CURLSYS_TYPEOF_CURL_OFF_T     long
-#    define CURLSYS_FORMAT_CURL_OFF_T     "ld"
-#    define CURLSYS_FORMAT_CURL_OFF_TU    "lu"
-#    define CURLSYS_SIZEOF_CURL_OFF_T     8
-#    define CURLSYS_SUFFIX_CURL_OFF_T     L
-#    define CURLSYS_SUFFIX_CURL_OFF_TU    UL
+        defined(__x86_64__) || defined(__ppc64__) || defined(__sparc64__) || \
+        (defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 8)
+#    define CURL_TYPEOF_CURL_OFF_T     long
+#    define CURL_FORMAT_CURL_OFF_T     "ld"
+#    define CURL_FORMAT_CURL_OFF_TU    "lu"
+#    define CURL_SUFFIX_CURL_OFF_T     L
+#    define CURL_SUFFIX_CURL_OFF_TU    UL
 #  endif
 #  endif
-#  define CURLSYS_TYPEOF_CURL_SOCKLEN_T socklen_t
-#  define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
-#  define CURLSYS_PULL_SYS_TYPES_H      1
-#  define CURLSYS_PULL_SYS_SOCKET_H     1
+#  define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
+#  define CURL_PULL_SYS_TYPES_H      1
+#  define CURL_PULL_SYS_SOCKET_H     1
 
 
 #else
 #else
 /* generic "safe guess" on old 32 bit style */
 /* generic "safe guess" on old 32 bit style */
-# define CURLSYS_SIZEOF_LONG 4
-# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
-# define CURLSYS_SIZEOF_CURL_OFF_T 4
-# define CURLSYS_TYPEOF_CURL_OFF_T     long
-# define CURLSYS_FORMAT_CURL_OFF_T     "ld"
-# define CURLSYS_FORMAT_CURL_OFF_TU    "lu"
-# define CURLSYS_SUFFIX_CURL_OFF_T     L
-# define CURLSYS_SUFFIX_CURL_OFF_TU    UL
-# define CURLSYS_TYPEOF_CURL_SOCKLEN_T int
+# define CURL_TYPEOF_CURL_OFF_T     long
+# define CURL_FORMAT_CURL_OFF_T     "ld"
+# define CURL_FORMAT_CURL_OFF_TU    "lu"
+# define CURL_SUFFIX_CURL_OFF_T     L
+# define CURL_SUFFIX_CURL_OFF_TU    UL
+# define CURL_TYPEOF_CURL_SOCKLEN_T int
 #endif
 #endif
 
 
-/* CURLSYS_PULL_WS2TCPIP_H is defined above when inclusion of header file  */
+#ifdef _AIX
+/* AIX needs <sys/poll.h> */
+#define CURL_PULL_SYS_POLL_H
+#endif
+
+
+/* CURL_PULL_WS2TCPIP_H is defined above when inclusion of header file  */
 /* ws2tcpip.h is required here to properly make type definitions below. */
 /* ws2tcpip.h is required here to properly make type definitions below. */
-#ifdef CURLSYS_PULL_WS2TCPIP_H
-#  ifndef WIN32_LEAN_AND_MEAN
-#    define WIN32_LEAN_AND_MEAN
-#  endif
-#  include <windows.h>
+#ifdef CURL_PULL_WS2TCPIP_H
 #  include <winsock2.h>
 #  include <winsock2.h>
+#  include <windows.h>
 #  include <ws2tcpip.h>
 #  include <ws2tcpip.h>
 #endif
 #endif
 
 
-/* CURLSYS_PULL_SYS_TYPES_H is defined above when inclusion of header file  */
+/* CURL_PULL_SYS_TYPES_H is defined above when inclusion of header file  */
 /* sys/types.h is required here to properly make type definitions below. */
 /* sys/types.h is required here to properly make type definitions below. */
-#ifdef CURLSYS_PULL_SYS_TYPES_H
+#ifdef CURL_PULL_SYS_TYPES_H
 #  include <sys/types.h>
 #  include <sys/types.h>
 #endif
 #endif
 
 
-/* CURLSYS_PULL_SYS_SOCKET_H is defined above when inclusion of header file  */
+/* CURL_PULL_SYS_SOCKET_H is defined above when inclusion of header file  */
 /* sys/socket.h is required here to properly make type definitions below. */
 /* sys/socket.h is required here to properly make type definitions below. */
-#ifdef CURLSYS_PULL_SYS_SOCKET_H
+#ifdef CURL_PULL_SYS_SOCKET_H
 #  include <sys/socket.h>
 #  include <sys/socket.h>
 #endif
 #endif
 
 
+/* CURL_PULL_SYS_POLL_H is defined above when inclusion of header file    */
+/* sys/poll.h is required here to properly make type definitions below.   */
+#ifdef CURL_PULL_SYS_POLL_H
+#  include <sys/poll.h>
+#endif
+
 /* Data type definition of curl_socklen_t. */
 /* Data type definition of curl_socklen_t. */
-#ifdef CURLSYS_TYPEOF_CURL_SOCKLEN_T
-  typedef CURLSYS_TYPEOF_CURL_SOCKLEN_T curlsys_socklen_t;
+#ifdef CURL_TYPEOF_CURL_SOCKLEN_T
+  typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t;
 #endif
 #endif
 
 
 /* Data type definition of curl_off_t. */
 /* Data type definition of curl_off_t. */
 
 
-#ifdef CURLSYS_TYPEOF_CURL_OFF_T
-  typedef CURLSYS_TYPEOF_CURL_OFF_T curlsys_off_t;
+#ifdef CURL_TYPEOF_CURL_OFF_T
+  typedef CURL_TYPEOF_CURL_OFF_T curl_off_t;
 #endif
 #endif
 
 
-#endif /* __CURL_SYSTEM_H */
+/*
+ * CURL_ISOCPP and CURL_OFF_T_C definitions are done here in order to allow
+ * these to be visible and exported by the external libcurl interface API,
+ * while also making them visible to the library internals, simply including
+ * curl_setup.h, without actually needing to include curl.h internally.
+ * If some day this section would grow big enough, all this should be moved
+ * to its own header file.
+ */
 
 
+/*
+ * Figure out if we can use the ## preprocessor operator, which is supported
+ * by ISO/ANSI C and C++. Some compilers support it without setting __STDC__
+ * or  __cplusplus so we need to carefully check for them too.
+ */
+
+#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \
+  defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \
+  defined(__POCC__) || defined(__SALFORDC__) || defined(__HIGHC__) || \
+  defined(__ILEC400__)
+  /* This compiler is believed to have an ISO compatible preprocessor */
+#define CURL_ISOCPP
+#else
+  /* This compiler is believed NOT to have an ISO compatible preprocessor */
+#undef CURL_ISOCPP
+#endif
+
+/*
+ * Macros for minimum-width signed and unsigned curl_off_t integer constants.
+ */
+
+#if defined(__BORLANDC__) && (__BORLANDC__ == 0x0551)
+#  define __CURL_OFF_T_C_HLPR2(x) x
+#  define __CURL_OFF_T_C_HLPR1(x) __CURL_OFF_T_C_HLPR2(x)
+#  define CURL_OFF_T_C(Val)  __CURL_OFF_T_C_HLPR1(Val) ## \
+                             __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_T)
+#  define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \
+                             __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_TU)
+#else
+#  ifdef CURL_ISOCPP
+#    define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val ## Suffix
+#  else
+#    define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val/**/Suffix
+#  endif
+#  define __CURL_OFF_T_C_HLPR1(Val,Suffix) __CURL_OFF_T_C_HLPR2(Val,Suffix)
+#  define CURL_OFF_T_C(Val)  __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_T)
+#  define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_TU)
+#endif
+
+#endif /* __CURL_SYSTEM_H */

+ 18 - 3
Utilities/cmcurl/include/curl/typecheck-gcc.h

@@ -96,6 +96,9 @@ __extension__ ({                                                              \
     if((_curl_opt) == CURLOPT_HTTPPOST)                                       \
     if((_curl_opt) == CURLOPT_HTTPPOST)                                       \
       if(!_curl_is_arr((value), struct curl_httppost))                        \
       if(!_curl_is_arr((value), struct curl_httppost))                        \
         _curl_easy_setopt_err_curl_httpost();                                 \
         _curl_easy_setopt_err_curl_httpost();                                 \
+    if((_curl_opt) == CURLOPT_MIMEPOST)                                       \
+      if(!_curl_is_ptr((value), curl_mime))                                   \
+        _curl_easy_setopt_err_curl_mimepost();                                \
     if(_curl_is_slist_option(_curl_opt))                                      \
     if(_curl_is_slist_option(_curl_opt))                                      \
       if(!_curl_is_arr((value), struct curl_slist))                           \
       if(!_curl_is_arr((value), struct curl_slist))                           \
         _curl_easy_setopt_err_curl_slist();                                   \
         _curl_easy_setopt_err_curl_slist();                                   \
@@ -110,7 +113,7 @@ __extension__ ({                                                              \
 /* FIXME: don't allow const pointers */
 /* FIXME: don't allow const pointers */
 #define curl_easy_getinfo(handle, info, arg)                                  \
 #define curl_easy_getinfo(handle, info, arg)                                  \
 __extension__ ({                                                              \
 __extension__ ({                                                              \
-  __typeof__(info) _curl_info = info;                                        \
+  __typeof__(info) _curl_info = info;                                         \
   if(__builtin_constant_p(_curl_info)) {                                      \
   if(__builtin_constant_p(_curl_info)) {                                      \
     if(_curl_is_string_info(_curl_info))                                      \
     if(_curl_is_string_info(_curl_info))                                      \
       if(!_curl_is_arr((arg), char *))                                        \
       if(!_curl_is_arr((arg), char *))                                        \
@@ -130,9 +133,12 @@ __extension__ ({                                                              \
     if(_curl_is_certinfo_info(_curl_info))                                    \
     if(_curl_is_certinfo_info(_curl_info))                                    \
       if(!_curl_is_arr((arg), struct curl_certinfo *))                        \
       if(!_curl_is_arr((arg), struct curl_certinfo *))                        \
         _curl_easy_getinfo_err_curl_certinfo();                               \
         _curl_easy_getinfo_err_curl_certinfo();                               \
-   if(_curl_is_socket_info(_curl_info))                                       \
+    if(_curl_is_socket_info(_curl_info))                                      \
       if(!_curl_is_arr((arg), curl_socket_t))                                 \
       if(!_curl_is_arr((arg), curl_socket_t))                                 \
         _curl_easy_getinfo_err_curl_socket();                                 \
         _curl_easy_getinfo_err_curl_socket();                                 \
+    if(_curl_is_off_t_info(_curl_info))                                       \
+      if(!_curl_is_arr((arg), curl_off_t))                                    \
+        _curl_easy_getinfo_err_curl_off_t();                                  \
   }                                                                           \
   }                                                                           \
   curl_easy_getinfo(handle, _curl_info, arg);                                 \
   curl_easy_getinfo(handle, _curl_info, arg);                                 \
 })
 })
@@ -197,6 +203,9 @@ _CURL_WARNING(_curl_easy_setopt_err_postfields,
 _CURL_WARNING(_curl_easy_setopt_err_curl_httpost,
 _CURL_WARNING(_curl_easy_setopt_err_curl_httpost,
               "curl_easy_setopt expects a 'struct curl_httppost *' "
               "curl_easy_setopt expects a 'struct curl_httppost *' "
               "argument for this option")
               "argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_curl_mimepost,
+              "curl_easy_setopt expects a 'curl_mime *' "
+              "argument for this option")
 _CURL_WARNING(_curl_easy_setopt_err_curl_slist,
 _CURL_WARNING(_curl_easy_setopt_err_curl_slist,
   "curl_easy_setopt expects a 'struct curl_slist *' argument for this option")
   "curl_easy_setopt expects a 'struct curl_slist *' argument for this option")
 _CURL_WARNING(_curl_easy_setopt_err_CURLSH,
 _CURL_WARNING(_curl_easy_setopt_err_CURLSH,
@@ -218,6 +227,8 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_certinfo,
               "'struct curl_certinfo *' for this info")
               "'struct curl_certinfo *' for this info")
 _CURL_WARNING(_curl_easy_getinfo_err_curl_socket,
 _CURL_WARNING(_curl_easy_getinfo_err_curl_socket,
   "curl_easy_getinfo expects a pointer to curl_socket_t for this info")
   "curl_easy_getinfo expects a pointer to curl_socket_t for this info")
+_CURL_WARNING(_curl_easy_getinfo_err_curl_off_t,
+  "curl_easy_getinfo expects a pointer to curl_off_t for this info")
 
 
 /* groups of curl_easy_setops options that take the same type of argument */
 /* groups of curl_easy_setops options that take the same type of argument */
 
 
@@ -391,7 +402,11 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_socket,
 
 
 /* true if info expects a pointer to struct curl_socket_t argument */
 /* true if info expects a pointer to struct curl_socket_t argument */
 #define _curl_is_socket_info(info)                                            \
 #define _curl_is_socket_info(info)                                            \
-  (CURLINFO_SOCKET < (info))
+  (CURLINFO_SOCKET < (info) && (info) < CURLINFO_OFF_T)
+
+/* true if info expects a pointer to curl_off_t argument */
+#define _curl_is_off_t_info(info)                                             \
+  (CURLINFO_OFF_T < (info))
 
 
 
 
 /* typecheck helpers -- check whether given expression has requested type*/
 /* typecheck helpers -- check whether given expression has requested type*/

+ 8 - 3
Utilities/cmcurl/lib/CMakeLists.txt

@@ -1,7 +1,5 @@
 set(LIB_NAME cmcurl)
 set(LIB_NAME cmcurl)
 
 
-configure_file(${CURL_SOURCE_DIR}/include/curl/curlbuild.h.cmake
-  ${CURL_BINARY_DIR}/include/curl/curlbuild.h)
 configure_file(curl_config.h.cmake
 configure_file(curl_config.h.cmake
   ${CMAKE_CURRENT_BINARY_DIR}/curl_config.h)
   ${CMAKE_CURRENT_BINARY_DIR}/curl_config.h)
 
 
@@ -10,11 +8,11 @@ include(${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake)
 
 
 list(APPEND HHEADERS
 list(APPEND HHEADERS
   ${CMAKE_CURRENT_BINARY_DIR}/curl_config.h
   ${CMAKE_CURRENT_BINARY_DIR}/curl_config.h
-  ${CURL_BINARY_DIR}/include/curl/curlbuild.h
   )
   )
 
 
 if(MSVC AND NOT CURL_STATICLIB)
 if(MSVC AND NOT CURL_STATICLIB)
   list(APPEND CSOURCES libcurl.rc)
   list(APPEND CSOURCES libcurl.rc)
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4127")
 endif()
 endif()
 
 
 # SET(CSOURCES
 # SET(CSOURCES
@@ -124,6 +122,13 @@ if(WIN32)
   if(NOT CURL_STATICLIB)
   if(NOT CURL_STATICLIB)
     # Add "_imp" as a suffix before the extension to avoid conflicting with the statically linked "libcurl.lib"
     # Add "_imp" as a suffix before the extension to avoid conflicting with the statically linked "libcurl.lib"
     set_target_properties(${LIB_NAME} PROPERTIES IMPORT_SUFFIX "_imp.lib")
     set_target_properties(${LIB_NAME} PROPERTIES IMPORT_SUFFIX "_imp.lib")
+
+    set_target_properties (${LIB_NAME} PROPERTIES
+       DEBUG_POSTFIX "-d"
+       # Note: no postfix for release variants, let user choose what style of release he wants
+       # MINSIZEREL_POSTFIX "-z"
+       # RELWITHDEBINFO_POSTFIX "-g"
+       )
   endif()
   endif()
 endif()
 endif()
 
 

+ 3 - 2
Utilities/cmcurl/lib/Makefile.inc

@@ -53,7 +53,8 @@ LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c   \
   http_proxy.c non-ascii.c asyn-ares.c asyn-thread.c curl_gssapi.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 rand.c        \
   http_ntlm.c curl_ntlm_wb.c curl_ntlm_core.c curl_sasl.c rand.c        \
   curl_multibyte.c hostcheck.c conncache.c pipeline.c dotdot.c          \
   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
+  x509asn1.c http2.c smb.c curl_endian.c curl_des.c system_win32.c      \
+  mime.c
 
 
 LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \
 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         \
   formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h if2ip.h         \
@@ -72,7 +73,7 @@ LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \
   curl_sasl.h curl_multibyte.h hostcheck.h conncache.h                  \
   curl_sasl.h curl_multibyte.h hostcheck.h conncache.h                  \
   curl_setup_once.h multihandle.h setup-vms.h pipeline.h dotdot.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           \
   x509asn1.h http2.h sigpipe.h smb.h curl_endian.h curl_des.h           \
-  curl_printf.h system_win32.h rand.h
+  curl_printf.h system_win32.h rand.h mime.h
 
 
 LIB_RCFILES = libcurl.rc
 LIB_RCFILES = libcurl.rc
 
 

+ 4 - 4
Utilities/cmcurl/lib/asyn-ares.c

@@ -260,7 +260,7 @@ static int waitperform(struct connectdata *conn, int timeout_ms)
   bitmask = ares_getsock((ares_channel)data->state.resolver, socks,
   bitmask = ares_getsock((ares_channel)data->state.resolver, socks,
                          ARES_GETSOCK_MAXNUM);
                          ARES_GETSOCK_MAXNUM);
 
 
-  for(i=0; i < ARES_GETSOCK_MAXNUM; i++) {
+  for(i = 0; i < ARES_GETSOCK_MAXNUM; i++) {
     pfd[i].events = 0;
     pfd[i].events = 0;
     pfd[i].revents = 0;
     pfd[i].revents = 0;
     if(ARES_GETSOCK_READABLE(bitmask, i)) {
     if(ARES_GETSOCK_READABLE(bitmask, i)) {
@@ -289,7 +289,7 @@ static int waitperform(struct connectdata *conn, int timeout_ms)
                     ARES_SOCKET_BAD);
                     ARES_SOCKET_BAD);
   else {
   else {
     /* move through the descriptors and ask for processing on them */
     /* move through the descriptors and ask for processing on them */
-    for(i=0; i < num; i++)
+    for(i = 0; i < num; i++)
       ares_process_fd((ares_channel)data->state.resolver,
       ares_process_fd((ares_channel)data->state.resolver,
                       pfd[i].revents & (POLLRDNORM|POLLIN)?
                       pfd[i].revents & (POLLRDNORM|POLLIN)?
                       pfd[i].fd:ARES_SOCKET_BAD,
                       pfd[i].fd:ARES_SOCKET_BAD,
@@ -355,7 +355,7 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
   struct Curl_easy *data = conn->data;
   struct Curl_easy *data = conn->data;
   long timeout;
   long timeout;
-  struct timeval now = Curl_tvnow();
+  struct curltime now = Curl_tvnow();
   struct Curl_dns_entry *temp_entry;
   struct Curl_dns_entry *temp_entry;
 
 
   if(entry)
   if(entry)
@@ -400,7 +400,7 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
     if(Curl_pgrsUpdate(conn))
     if(Curl_pgrsUpdate(conn))
       result = CURLE_ABORTED_BY_CALLBACK;
       result = CURLE_ABORTED_BY_CALLBACK;
     else {
     else {
-      struct timeval now2 = Curl_tvnow();
+      struct curltime now2 = Curl_tvnow();
       time_t timediff = Curl_tvdiff(now2, now); /* spent time */
       time_t timediff = Curl_tvdiff(now2, now); /* spent time */
       if(timediff <= 0)
       if(timediff <= 0)
         timeout -= 1; /* always deduct at least 1 */
         timeout -= 1; /* always deduct at least 1 */

+ 33 - 22
Utilities/cmcurl/lib/asyn-thread.c

@@ -210,6 +210,10 @@ int init_thread_sync_data(struct thread_data * td,
 
 
   tsd->td = td;
   tsd->td = td;
   tsd->port = port;
   tsd->port = port;
+  /* Treat the request as done until the thread actually starts so any early
+   * cleanup gets done properly.
+   */
+  tsd->done = 1;
 #ifdef HAVE_GETADDRINFO
 #ifdef HAVE_GETADDRINFO
   DEBUGASSERT(hints);
   DEBUGASSERT(hints);
   tsd->hints = *hints;
   tsd->hints = *hints;
@@ -380,11 +384,11 @@ static bool init_resolve_thread(struct connectdata *conn,
                                 const struct addrinfo *hints)
                                 const struct addrinfo *hints)
 {
 {
   struct thread_data *td = calloc(1, sizeof(struct thread_data));
   struct thread_data *td = calloc(1, sizeof(struct thread_data));
-  int err = RESOLVER_ENOMEM;
+  int err = ENOMEM;
 
 
   conn->async.os_specific = (void *)td;
   conn->async.os_specific = (void *)td;
   if(!td)
   if(!td)
-    goto err_exit;
+    goto errno_exit;
 
 
   conn->async.port = port;
   conn->async.port = port;
   conn->async.done = FALSE;
   conn->async.done = FALSE;
@@ -392,14 +396,20 @@ static bool init_resolve_thread(struct connectdata *conn,
   conn->async.dns = NULL;
   conn->async.dns = NULL;
   td->thread_hnd = curl_thread_t_null;
   td->thread_hnd = curl_thread_t_null;
 
 
-  if(!init_thread_sync_data(td, hostname, port, hints))
-    goto err_exit;
+  if(!init_thread_sync_data(td, hostname, port, hints)) {
+    conn->async.os_specific = NULL;
+    free(td);
+    goto errno_exit;
+  }
 
 
   free(conn->async.hostname);
   free(conn->async.hostname);
   conn->async.hostname = strdup(hostname);
   conn->async.hostname = strdup(hostname);
   if(!conn->async.hostname)
   if(!conn->async.hostname)
     goto err_exit;
     goto err_exit;
 
 
+  /* The thread will set this to 1 when complete. */
+  td->tsd.done = 0;
+
 #ifdef HAVE_GETADDRINFO
 #ifdef HAVE_GETADDRINFO
   td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd);
   td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd);
 #else
 #else
@@ -407,9 +417,9 @@ static bool init_resolve_thread(struct connectdata *conn,
 #endif
 #endif
 
 
   if(!td->thread_hnd) {
   if(!td->thread_hnd) {
-#ifndef _WIN32_WCE
+    /* The thread never started, so mark it as done here for proper cleanup. */
+    td->tsd.done = 1;
     err = errno;
     err = errno;
-#endif
     goto err_exit;
     goto err_exit;
   }
   }
 
 
@@ -418,8 +428,8 @@ static bool init_resolve_thread(struct connectdata *conn,
  err_exit:
  err_exit:
   destroy_async_data(&conn->async);
   destroy_async_data(&conn->async);
 
 
-  SET_ERRNO(err);
-
+ errno_exit:
+  errno = err;
   return FALSE;
   return FALSE;
 }
 }
 
 
@@ -594,28 +604,29 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
                                          int *waitp)
                                          int *waitp)
 {
 {
   struct addrinfo hints;
   struct addrinfo hints;
-  struct in_addr in;
   Curl_addrinfo *res;
   Curl_addrinfo *res;
   int error;
   int error;
   char sbuf[12];
   char sbuf[12];
   int pf = PF_INET;
   int pf = PF_INET;
-#ifdef CURLRES_IPV6
-  struct in6_addr in6;
-#endif /* CURLRES_IPV6 */
 
 
   *waitp = 0; /* default to synchronous response */
   *waitp = 0; /* default to synchronous response */
 
 
 #ifndef USE_RESOLVE_ON_IPS
 #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 */
-    return Curl_ip2addr(AF_INET, &in, hostname, port);
-
+  {
+    struct in_addr in;
+    /* 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 */
+      return Curl_ip2addr(AF_INET, &in, hostname, port);
+  }
 #ifdef CURLRES_IPV6
 #ifdef CURLRES_IPV6
-  /* check if this is an IPv6 address string */
-  if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0)
-    /* This is an IPv6 address literal */
-    return Curl_ip2addr(AF_INET6, &in6, hostname, port);
+  {
+    struct in6_addr in6;
+    /* check if this is an IPv6 address string */
+    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 /* CURLRES_IPV6 */
 #endif /* !USE_RESOLVE_ON_IPS */
 #endif /* !USE_RESOLVE_ON_IPS */
 
 
@@ -654,7 +665,7 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
 
 
   /* fall-back to blocking version */
   /* fall-back to blocking version */
   infof(conn->data, "init_resolve_thread() failed for %s; %s\n",
   infof(conn->data, "init_resolve_thread() failed for %s; %s\n",
-        hostname, Curl_strerror(conn, ERRNO));
+        hostname, Curl_strerror(conn, errno));
 
 
   error = Curl_getaddrinfo_ex(hostname, sbuf, &hints, &res);
   error = Curl_getaddrinfo_ex(hostname, sbuf, &hints, &res);
   if(error) {
   if(error) {

+ 1 - 1
Utilities/cmcurl/lib/conncache.h

@@ -27,7 +27,7 @@ struct conncache {
   struct curl_hash hash;
   struct curl_hash hash;
   size_t num_connections;
   size_t num_connections;
   long next_connection_id;
   long next_connection_id;
-  struct timeval last_cleanup;
+  struct curltime last_cleanup;
 };
 };
 
 
 #define BUNDLE_NO_MULTIUSE -1
 #define BUNDLE_NO_MULTIUSE -1

+ 37 - 45
Utilities/cmcurl/lib/connect.c

@@ -180,12 +180,12 @@ singleipconnect(struct connectdata *conn,
  * @unittest: 1303
  * @unittest: 1303
  */
  */
 time_t Curl_timeleft(struct Curl_easy *data,
 time_t Curl_timeleft(struct Curl_easy *data,
-                     struct timeval *nowp,
+                     struct curltime *nowp,
                      bool duringconnect)
                      bool duringconnect)
 {
 {
   int timeout_set = 0;
   int timeout_set = 0;
   time_t timeout_ms = duringconnect?DEFAULT_CONNECT_TIMEOUT:0;
   time_t timeout_ms = duringconnect?DEFAULT_CONNECT_TIMEOUT:0;
-  struct timeval now;
+  struct curltime now;
 
 
   /* if a timeout is set, use the most restrictive one */
   /* if a timeout is set, use the most restrictive one */
 
 
@@ -249,7 +249,7 @@ static CURLcode bindlocal(struct connectdata *conn,
   struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
   struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
 #endif
 #endif
 
 
-  struct Curl_dns_entry *h=NULL;
+  struct Curl_dns_entry *h = NULL;
   unsigned short port = data->set.localport; /* use this port number, 0 for
   unsigned short port = data->set.localport; /* use this port number, 0 for
                                                 "random" */
                                                 "random" */
   /* how many port numbers to try to bind to, increasing one at a time */
   /* how many port numbers to try to bind to, increasing one at a time */
@@ -319,7 +319,7 @@ static CURLcode bindlocal(struct connectdata *conn,
            * as a hostname or ip address.
            * as a hostname or ip address.
            */
            */
           if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
           if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
-                        dev, (curl_socklen_t)strlen(dev)+1) != 0) {
+                        dev, (curl_socklen_t)strlen(dev) + 1) != 0) {
             error = SOCKERRNO;
             error = SOCKERRNO;
             infof(data, "SO_BINDTODEVICE %s failed with errno %d: %s;"
             infof(data, "SO_BINDTODEVICE %s failed with errno %d: %s;"
                   " will do regular bind\n",
                   " will do regular bind\n",
@@ -607,7 +607,8 @@ void Curl_persistconninfo(struct connectdata *conn)
   conn->data->info.conn_local_port = conn->local_port;
   conn->data->info.conn_local_port = conn->local_port;
 }
 }
 
 
-/* retrieves ip address and port from a sockaddr structure */
+/* retrieves ip address and port from a sockaddr structure.
+   note it calls Curl_inet_ntop which sets errno on fail, not SOCKERRNO. */
 static bool getaddressinfo(struct sockaddr *sa, char *addr,
 static bool getaddressinfo(struct sockaddr *sa, char *addr,
                            long *port)
                            long *port)
 {
 {
@@ -654,7 +655,7 @@ static bool getaddressinfo(struct sockaddr *sa, char *addr,
 
 
   addr[0] = '\0';
   addr[0] = '\0';
   *port = 0;
   *port = 0;
-
+  errno = EAFNOSUPPORT;
   return FALSE;
   return FALSE;
 }
 }
 
 
@@ -672,11 +673,9 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
     return;
     return;
 
 
   if(!conn->bits.reuse && !conn->bits.tcp_fastopen) {
   if(!conn->bits.reuse && !conn->bits.tcp_fastopen) {
-    int error;
-
     len = sizeof(struct Curl_sockaddr_storage);
     len = sizeof(struct Curl_sockaddr_storage);
     if(getpeername(sockfd, (struct sockaddr*) &ssrem, &len)) {
     if(getpeername(sockfd, (struct sockaddr*) &ssrem, &len)) {
-      error = SOCKERRNO;
+      int error = SOCKERRNO;
       failf(data, "getpeername() failed with errno %d: %s",
       failf(data, "getpeername() failed with errno %d: %s",
             error, Curl_strerror(conn, error));
             error, Curl_strerror(conn, error));
       return;
       return;
@@ -685,7 +684,7 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
     len = sizeof(struct Curl_sockaddr_storage);
     len = sizeof(struct Curl_sockaddr_storage);
     memset(&ssloc, 0, sizeof(ssloc));
     memset(&ssloc, 0, sizeof(ssloc));
     if(getsockname(sockfd, (struct sockaddr*) &ssloc, &len)) {
     if(getsockname(sockfd, (struct sockaddr*) &ssloc, &len)) {
-      error = SOCKERRNO;
+      int error = SOCKERRNO;
       failf(data, "getsockname() failed with errno %d: %s",
       failf(data, "getsockname() failed with errno %d: %s",
             error, Curl_strerror(conn, error));
             error, Curl_strerror(conn, error));
       return;
       return;
@@ -693,18 +692,16 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
 
 
     if(!getaddressinfo((struct sockaddr*)&ssrem,
     if(!getaddressinfo((struct sockaddr*)&ssrem,
                         conn->primary_ip, &conn->primary_port)) {
                         conn->primary_ip, &conn->primary_port)) {
-      error = ERRNO;
       failf(data, "ssrem inet_ntop() failed with errno %d: %s",
       failf(data, "ssrem inet_ntop() failed with errno %d: %s",
-            error, Curl_strerror(conn, error));
+            errno, Curl_strerror(conn, errno));
       return;
       return;
     }
     }
     memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN);
     memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN);
 
 
     if(!getaddressinfo((struct sockaddr*)&ssloc,
     if(!getaddressinfo((struct sockaddr*)&ssloc,
                        conn->local_ip, &conn->local_port)) {
                        conn->local_ip, &conn->local_port)) {
-      error = ERRNO;
       failf(data, "ssloc inet_ntop() failed with errno %d: %s",
       failf(data, "ssloc inet_ntop() failed with errno %d: %s",
-            error, Curl_strerror(conn, error));
+            errno, Curl_strerror(conn, errno));
       return;
       return;
     }
     }
 
 
@@ -726,7 +723,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
   time_t allow;
   time_t allow;
   int error = 0;
   int error = 0;
-  struct timeval now;
+  struct curltime now;
   int rc;
   int rc;
   int i;
   int i;
 
 
@@ -751,7 +748,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
     return CURLE_OPERATION_TIMEDOUT;
     return CURLE_OPERATION_TIMEDOUT;
   }
   }
 
 
-  for(i=0; i<2; i++) {
+  for(i = 0; i<2; i++) {
     const int other = i ^ 1;
     const int other = i ^ 1;
     if(conn->tempsock[i] == CURL_SOCKET_BAD)
     if(conn->tempsock[i] == CURL_SOCKET_BAD)
       continue;
       continue;
@@ -879,19 +876,6 @@ void Curl_tcpnodelay(struct connectdata *conn, curl_socket_t sockfd)
   curl_socklen_t onoff = (curl_socklen_t) 1;
   curl_socklen_t onoff = (curl_socklen_t) 1;
   int level = IPPROTO_TCP;
   int level = IPPROTO_TCP;
 
 
-#if 0
-  /* The use of getprotobyname() is disabled since it isn't thread-safe on
-     numerous systems. On these getprotobyname_r() should be used instead, but
-     that exists in at least one 4 arg version and one 5 arg version, and
-     since the proto number rarely changes anyway we now just use the hard
-     coded number. The "proper" fix would need a configure check for the
-     correct function much in the same style the gethostbyname_r versions are
-     detected. */
-  struct protoent *pe = getprotobyname("tcp");
-  if(pe)
-    level = pe->p_proto;
-#endif
-
 #if defined(CURL_DISABLE_VERBOSE_STRINGS)
 #if defined(CURL_DISABLE_VERBOSE_STRINGS)
   (void) conn;
   (void) conn;
 #endif
 #endif
@@ -916,7 +900,7 @@ void Curl_tcpnodelay(struct connectdata *conn, curl_socket_t sockfd)
 static void nosigpipe(struct connectdata *conn,
 static void nosigpipe(struct connectdata *conn,
                       curl_socket_t sockfd)
                       curl_socket_t sockfd)
 {
 {
-  struct Curl_easy *data= conn->data;
+  struct Curl_easy *data = conn->data;
   int onoff = 1;
   int onoff = 1;
   if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
   if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
                 sizeof(onoff)) < 0)
                 sizeof(onoff)) < 0)
@@ -1008,9 +992,8 @@ static CURLcode singleipconnect(struct connectdata *conn,
   if(!getaddressinfo((struct sockaddr*)&addr.sa_addr,
   if(!getaddressinfo((struct sockaddr*)&addr.sa_addr,
                      ipaddress, &port)) {
                      ipaddress, &port)) {
     /* malformed address or bug in inet_ntop, try next address */
     /* malformed address or bug in inet_ntop, try next address */
-    error = ERRNO;
     failf(data, "sa_addr inet_ntop() failed with errno %d: %s",
     failf(data, "sa_addr inet_ntop() failed with errno %d: %s",
-          error, Curl_strerror(conn, error));
+          errno, Curl_strerror(conn, errno));
     Curl_closesocket(conn, sockfd);
     Curl_closesocket(conn, sockfd);
     return CURLE_OK;
     return CURLE_OK;
   }
   }
@@ -1076,16 +1059,25 @@ static CURLcode singleipconnect(struct connectdata *conn,
   if(!isconnected && (conn->socktype == SOCK_STREAM)) {
   if(!isconnected && (conn->socktype == SOCK_STREAM)) {
     if(conn->bits.tcp_fastopen) {
     if(conn->bits.tcp_fastopen) {
 #if defined(CONNECT_DATA_IDEMPOTENT) /* OS X */
 #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);
+#ifdef HAVE_BUILTIN_AVAILABLE
+      if(__builtin_available(macOS 10.11, iOS 9.0, tvOS 9.0, watchOS 2.0, *)) {
+#endif /* HAVE_BUILTIN_AVAILABLE */
+        sa_endpoints_t endpoints;
+        endpoints.sae_srcif = 0;
+        endpoints.sae_srcaddr = NULL;
+        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);
+#ifdef HAVE_BUILTIN_AVAILABLE
+      }
+      else {
+        rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
+      }
+#endif /* HAVE_BUILTIN_AVAILABLE */
 #elif defined(MSG_FASTOPEN) /* Linux */
 #elif defined(MSG_FASTOPEN) /* Linux */
       if(conn->given->flags & PROTOPT_SSL)
       if(conn->given->flags & PROTOPT_SSL)
         rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
         rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
@@ -1153,7 +1145,7 @@ CURLcode Curl_connecthost(struct connectdata *conn,  /* context */
                           const struct Curl_dns_entry *remotehost)
                           const struct Curl_dns_entry *remotehost)
 {
 {
   struct Curl_easy *data = conn->data;
   struct Curl_easy *data = conn->data;
-  struct timeval before = Curl_tvnow();
+  struct curltime before = Curl_tvnow();
   CURLcode result = CURLE_COULDNT_CONNECT;
   CURLcode result = CURLE_COULDNT_CONNECT;
 
 
   time_t timeout_ms = Curl_timeleft(data, &before, TRUE);
   time_t timeout_ms = Curl_timeleft(data, &before, TRUE);
@@ -1169,7 +1161,6 @@ CURLcode Curl_connecthost(struct connectdata *conn,  /* context */
   conn->tempaddr[1] = NULL;
   conn->tempaddr[1] = NULL;
   conn->tempsock[0] = CURL_SOCKET_BAD;
   conn->tempsock[0] = CURL_SOCKET_BAD;
   conn->tempsock[1] = CURL_SOCKET_BAD;
   conn->tempsock[1] = CURL_SOCKET_BAD;
-  Curl_expire(conn->data, HAPPY_EYEBALLS_TIMEOUT, EXPIRE_HAPPY_EYEBALLS);
 
 
   /* Max time for the next connection attempt */
   /* Max time for the next connection attempt */
   conn->timeoutms_per_addr =
   conn->timeoutms_per_addr =
@@ -1190,6 +1181,7 @@ CURLcode Curl_connecthost(struct connectdata *conn,  /* context */
   }
   }
 
 
   data->info.numconnects++; /* to track the number of connections made */
   data->info.numconnects++; /* to track the number of connections made */
+  Curl_expire(conn->data, HAPPY_EYEBALLS_TIMEOUT, EXPIRE_HAPPY_EYEBALLS);
 
 
   return CURLE_OK;
   return CURLE_OK;
 }
 }
@@ -1341,7 +1333,7 @@ CURLcode Curl_socket(struct connectdata *conn,
 
 
   addr->family = ai->ai_family;
   addr->family = ai->ai_family;
   addr->socktype = conn->socktype;
   addr->socktype = conn->socktype;
-  addr->protocol = conn->socktype==SOCK_DGRAM?IPPROTO_UDP:ai->ai_protocol;
+  addr->protocol = conn->socktype == SOCK_DGRAM?IPPROTO_UDP:ai->ai_protocol;
   addr->addrlen = ai->ai_addrlen;
   addr->addrlen = ai->ai_addrlen;
 
 
   if(addr->addrlen > sizeof(struct Curl_sockaddr_storage))
   if(addr->addrlen > sizeof(struct Curl_sockaddr_storage))

+ 2 - 2
Utilities/cmcurl/lib/connect.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -36,7 +36,7 @@ CURLcode Curl_connecthost(struct connectdata *conn,
 /* generic function that returns how much time there's left to run, according
 /* generic function that returns how much time there's left to run, according
    to the timeouts set */
    to the timeouts set */
 time_t Curl_timeleft(struct Curl_easy *data,
 time_t Curl_timeleft(struct Curl_easy *data,
-                     struct timeval *nowp,
+                     struct curltime *nowp,
                      bool duringconnect);
                      bool duringconnect);
 
 
 #define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */
 #define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */

+ 3 - 3
Utilities/cmcurl/lib/content_encoding.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -227,7 +227,7 @@ static enum {
 
 
     extra_len = (data[1] << 8) | data[0];
     extra_len = (data[1] << 8) | data[0];
 
 
-    if(len < (extra_len+2))
+    if(len < (extra_len + 2))
       return GZIP_UNDERFLOW;
       return GZIP_UNDERFLOW;
 
 
     len -= (extra_len + 2);
     len -= (extra_len + 2);
@@ -288,7 +288,7 @@ Curl_unencode_gzip_write(struct connectdata *conn,
 
 
     if(strcmp(zlibVersion(), "1.2.0.4") >= 0) {
     if(strcmp(zlibVersion(), "1.2.0.4") >= 0) {
       /* zlib ver. >= 1.2.0.4 supports transparent gzip decompressing */
       /* zlib ver. >= 1.2.0.4 supports transparent gzip decompressing */
-      if(inflateInit2(z, MAX_WBITS+32) != Z_OK) {
+      if(inflateInit2(z, MAX_WBITS + 32) != Z_OK) {
         return process_zlib_error(conn, z);
         return process_zlib_error(conn, z);
       }
       }
       k->zlib_init = ZLIB_INIT_GZIP; /* Transparent gzip decompress state */
       k->zlib_init = ZLIB_INIT_GZIP; /* Transparent gzip decompress state */

+ 88 - 58
Utilities/cmcurl/lib/cookie.c

@@ -125,7 +125,7 @@ static bool tailmatch(const char *cooke_domain, const char *hostname)
   if(hostname_len < cookie_domain_len)
   if(hostname_len < cookie_domain_len)
     return FALSE;
     return FALSE;
 
 
-  if(!strcasecompare(cooke_domain, hostname+hostname_len-cookie_domain_len))
+  if(!strcasecompare(cooke_domain, hostname + hostname_len-cookie_domain_len))
     return FALSE;
     return FALSE;
 
 
   /* A lead char of cookie_domain is not '.'.
   /* A lead char of cookie_domain is not '.'.
@@ -375,9 +375,8 @@ Curl_cookie_add(struct Curl_easy *data,
                                        unless set */
                                        unless set */
 {
 {
   struct Cookie *clist;
   struct Cookie *clist;
-  char name[MAX_NAME];
   struct Cookie *co;
   struct Cookie *co;
-  struct Cookie *lastc=NULL;
+  struct Cookie *lastc = NULL;
   time_t now = time(NULL);
   time_t now = time(NULL);
   bool replace_old = FALSE;
   bool replace_old = FALSE;
   bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */
   bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */
@@ -397,17 +396,19 @@ Curl_cookie_add(struct Curl_easy *data,
 
 
   if(httpheader) {
   if(httpheader) {
     /* This line was read off a HTTP-header */
     /* This line was read off a HTTP-header */
+    char name[MAX_NAME];
+    char what[MAX_NAME];
     const char *ptr;
     const char *ptr;
     const char *semiptr;
     const char *semiptr;
-    char *what;
 
 
-    what = malloc(MAX_COOKIE_LINE);
-    if(!what) {
+    size_t linelength = strlen(lineptr);
+    if(linelength > MAX_COOKIE_LINE) {
+      /* discard overly long lines at once */
       free(co);
       free(co);
       return NULL;
       return NULL;
     }
     }
 
 
-    semiptr=strchr(lineptr, ';'); /* first, find a semicolon */
+    semiptr = strchr(lineptr, ';'); /* first, find a semicolon */
 
 
     while(*lineptr && ISBLANK(*lineptr))
     while(*lineptr && ISBLANK(*lineptr))
       lineptr++;
       lineptr++;
@@ -415,9 +416,9 @@ Curl_cookie_add(struct Curl_easy *data,
     ptr = lineptr;
     ptr = lineptr;
     do {
     do {
       /* we have a <what>=<this> pair or a stand-alone word here */
       /* we have a <what>=<this> pair or a stand-alone word here */
-      name[0]=what[0]=0; /* init the buffers */
+      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]",
+                     MAX_NAME_TXT "[^;\r\n]",
                      name, what)) {
                      name, what)) {
         /* Use strstore() below to properly deal with received cookie
         /* Use strstore() below to properly deal with received cookie
            headers that have the same string property set more than once,
            headers that have the same string property set more than once,
@@ -425,10 +426,24 @@ Curl_cookie_add(struct Curl_easy *data,
         const char *whatptr;
         const char *whatptr;
         bool done = FALSE;
         bool done = FALSE;
         bool sep;
         bool sep;
-        size_t len=strlen(what);
+        size_t len = strlen(what);
         size_t nlen = strlen(name);
         size_t nlen = strlen(name);
         const char *endofn = &ptr[ nlen ];
         const char *endofn = &ptr[ nlen ];
 
 
+        infof(data, "cookie size: name/val %d + %d bytes\n",
+              nlen, len);
+
+        if(nlen >= (MAX_NAME-1) || len >= (MAX_NAME-1) ||
+           ((nlen + len) > MAX_NAME)) {
+          /* too long individual name or contents, or too long combination of
+             name + contents. Chrome and Firefox support 4095 or 4096 bytes
+             combo. */
+          freecookie(co);
+          infof(data, "oversized cookie dropped, name/val %d + %d bytes\n",
+                nlen, len);
+          return NULL;
+        }
+
         /* name ends with a '=' ? */
         /* name ends with a '=' ? */
         sep = (*endofn == '=')?TRUE:FALSE;
         sep = (*endofn == '=')?TRUE:FALSE;
 
 
@@ -440,18 +455,18 @@ Curl_cookie_add(struct Curl_easy *data,
               endofn--;
               endofn--;
               nlen--;
               nlen--;
             }
             }
-            name[nlen]=0; /* new end of name */
+            name[nlen] = 0; /* new end of name */
           }
           }
         }
         }
 
 
         /* Strip off trailing whitespace from the 'what' */
         /* Strip off trailing whitespace from the 'what' */
         while(len && ISBLANK(what[len-1])) {
         while(len && ISBLANK(what[len-1])) {
-          what[len-1]=0;
+          what[len-1] = 0;
           len--;
           len--;
         }
         }
 
 
         /* Skip leading whitespace from the 'what' */
         /* Skip leading whitespace from the 'what' */
-        whatptr=what;
+        whatptr = what;
         while(*whatptr && ISBLANK(*whatptr))
         while(*whatptr && ISBLANK(*whatptr))
           whatptr++;
           whatptr++;
 
 
@@ -484,6 +499,7 @@ Curl_cookie_add(struct Curl_easy *data,
             badcookie = TRUE; /* out of memory bad */
             badcookie = TRUE; /* out of memory bad */
             break;
             break;
           }
           }
+          free(co->spath); /* if this is set again */
           co->spath = sanitize_cookie_path(co->path);
           co->spath = sanitize_cookie_path(co->path);
           if(!co->spath) {
           if(!co->spath) {
             badcookie = TRUE; /* out of memory bad */
             badcookie = TRUE; /* out of memory bad */
@@ -510,7 +526,7 @@ Curl_cookie_add(struct Curl_easy *data,
             /* check for more dots */
             /* check for more dots */
             dotp = strchr(whatptr, '.');
             dotp = strchr(whatptr, '.');
             if(!dotp && !strcasecompare("localhost", whatptr))
             if(!dotp && !strcasecompare("localhost", whatptr))
-              domain=":";
+              domain = ":";
           }
           }
 #endif
 #endif
 
 
@@ -525,14 +541,14 @@ Curl_cookie_add(struct Curl_easy *data,
               break;
               break;
             }
             }
             if(!is_ip)
             if(!is_ip)
-              co->tailmatch=TRUE; /* we always do that if the domain name was
-                                     given */
+              co->tailmatch = TRUE; /* we always do that if the domain name was
+                                       given */
           }
           }
           else {
           else {
             /* we did not get a tailmatch and then the attempted set domain
             /* we did not get a tailmatch and then the attempted set domain
                is not a domain to which the current host belongs. Mark as
                is not a domain to which the current host belongs. Mark as
                bad. */
                bad. */
-            badcookie=TRUE;
+            badcookie = TRUE;
             infof(data, "skipped cookie with bad tailmatch domain: %s\n",
             infof(data, "skipped cookie with bad tailmatch domain: %s\n",
                   whatptr);
                   whatptr);
           }
           }
@@ -581,26 +597,32 @@ Curl_cookie_add(struct Curl_easy *data,
         continue;
         continue;
       }
       }
 
 
-      ptr=semiptr+1;
+      ptr = semiptr + 1;
       while(*ptr && ISBLANK(*ptr))
       while(*ptr && ISBLANK(*ptr))
         ptr++;
         ptr++;
-      semiptr=strchr(ptr, ';'); /* now, find the next semicolon */
+      semiptr = strchr(ptr, ';'); /* now, find the next semicolon */
 
 
       if(!semiptr && *ptr)
       if(!semiptr && *ptr)
         /* There are no more semicolons, but there's a final name=value pair
         /* There are no more semicolons, but there's a final name=value pair
            coming up */
            coming up */
-        semiptr=strchr(ptr, '\0');
+        semiptr = strchr(ptr, '\0');
     } while(semiptr);
     } while(semiptr);
 
 
     if(co->maxage) {
     if(co->maxage) {
-      co->expires =
-        curlx_strtoofft((*co->maxage=='\"')?
-                        &co->maxage[1]:&co->maxage[0], NULL, 10);
-      if(CURL_OFF_T_MAX - now < co->expires)
-        /* avoid overflow */
+      CURLofft offt;
+      offt = curlx_strtoofft((*co->maxage == '\"')?
+                             &co->maxage[1]:&co->maxage[0], NULL, 10,
+                             &co->expires);
+      if(offt == CURL_OFFT_FLOW)
+        /* overflow, used max value */
         co->expires = CURL_OFF_T_MAX;
         co->expires = CURL_OFF_T_MAX;
-      else
-        co->expires += now;
+      else if(!offt) {
+        if(CURL_OFF_T_MAX - now < co->expires)
+          /* would overflow */
+          co->expires = CURL_OFF_T_MAX;
+        else
+          co->expires += now;
+      }
     }
     }
     else if(co->expirestr) {
     else if(co->expirestr) {
       /* Note that if the date couldn't get parsed for whatever reason,
       /* Note that if the date couldn't get parsed for whatever reason,
@@ -619,7 +641,7 @@ Curl_cookie_add(struct Curl_easy *data,
     if(!badcookie && !co->domain) {
     if(!badcookie && !co->domain) {
       if(domain) {
       if(domain) {
         /* no domain was given in the header line, set the default */
         /* no domain was given in the header line, set the default */
-        co->domain=strdup(domain);
+        co->domain = strdup(domain);
         if(!co->domain)
         if(!co->domain)
           badcookie = TRUE;
           badcookie = TRUE;
       }
       }
@@ -639,11 +661,11 @@ Curl_cookie_add(struct Curl_easy *data,
       else
       else
         endslash = memrchr(path, '/', (size_t)(queryp - path));
         endslash = memrchr(path, '/', (size_t)(queryp - path));
       if(endslash) {
       if(endslash) {
-        size_t pathlen = (size_t)(endslash-path+1); /* include ending slash */
-        co->path=malloc(pathlen+1); /* one extra for the zero byte */
+        size_t pathlen = (size_t)(endslash-path + 1); /* include end slash */
+        co->path = malloc(pathlen + 1); /* one extra for the zero byte */
         if(co->path) {
         if(co->path) {
           memcpy(co->path, path, pathlen);
           memcpy(co->path, path, pathlen);
-          co->path[pathlen]=0; /* zero terminate */
+          co->path[pathlen] = 0; /* zero terminate */
           co->spath = sanitize_cookie_path(co->path);
           co->spath = sanitize_cookie_path(co->path);
           if(!co->spath)
           if(!co->spath)
             badcookie = TRUE; /* out of memory bad */
             badcookie = TRUE; /* out of memory bad */
@@ -653,8 +675,6 @@ Curl_cookie_add(struct Curl_easy *data,
       }
       }
     }
     }
 
 
-    free(what);
-
     if(badcookie || !co->name) {
     if(badcookie || !co->name) {
       /* we didn't get a cookie name or a bad one,
       /* we didn't get a cookie name or a bad one,
          this is an illegal line, bail out */
          this is an illegal line, bail out */
@@ -668,7 +688,7 @@ Curl_cookie_add(struct Curl_easy *data,
        reading the odd netscape cookies-file format here */
        reading the odd netscape cookies-file format here */
     char *ptr;
     char *ptr;
     char *firstptr;
     char *firstptr;
-    char *tok_buf=NULL;
+    char *tok_buf = NULL;
     int fields;
     int fields;
 
 
     /* IE introduced HTTP-only cookies to prevent XSS attacks. Cookies
     /* IE introduced HTTP-only cookies to prevent XSS attacks. Cookies
@@ -689,19 +709,19 @@ Curl_cookie_add(struct Curl_easy *data,
       return NULL;
       return NULL;
     }
     }
     /* strip off the possible end-of-line characters */
     /* strip off the possible end-of-line characters */
-    ptr=strchr(lineptr, '\r');
+    ptr = strchr(lineptr, '\r');
     if(ptr)
     if(ptr)
-      *ptr=0; /* clear it */
-    ptr=strchr(lineptr, '\n');
+      *ptr = 0; /* clear it */
+    ptr = strchr(lineptr, '\n');
     if(ptr)
     if(ptr)
-      *ptr=0; /* clear it */
+      *ptr = 0; /* clear it */
 
 
-    firstptr=strtok_r(lineptr, "\t", &tok_buf); /* tokenize it on the TAB */
+    firstptr = strtok_r(lineptr, "\t", &tok_buf); /* tokenize it on the TAB */
 
 
     /* Now loop through the fields and init the struct we already have
     /* Now loop through the fields and init the struct we already have
        allocated */
        allocated */
-    for(ptr=firstptr, fields=0; ptr && !badcookie;
-        ptr=strtok_r(NULL, "\t", &tok_buf), fields++) {
+    for(ptr = firstptr, fields = 0; ptr && !badcookie;
+        ptr = strtok_r(NULL, "\t", &tok_buf), fields++) {
       switch(fields) {
       switch(fields) {
       case 0:
       case 0:
         if(ptr[0]=='.') /* skip preceding dots */
         if(ptr[0]=='.') /* skip preceding dots */
@@ -712,7 +732,7 @@ Curl_cookie_add(struct Curl_easy *data,
         break;
         break;
       case 1:
       case 1:
         /* This field got its explanation on the 23rd of May 2001 by
         /* This field got its explanation on the 23rd of May 2001 by
-           Andrés García:
+           Andrés García:
 
 
            flag: A TRUE/FALSE value indicating if all machines within a given
            flag: A TRUE/FALSE value indicating if all machines within a given
            domain can access the variable. This value is set automatically by
            domain can access the variable. This value is set automatically by
@@ -726,7 +746,7 @@ Curl_cookie_add(struct Curl_easy *data,
       case 2:
       case 2:
         /* It turns out, that sometimes the file format allows the path
         /* It turns out, that sometimes the file format allows the path
            field to remain not filled in, we try to detect this and work
            field to remain not filled in, we try to detect this and work
-           around it! Andrés García made us aware of this... */
+           around it! Andrés García made us aware of this... */
         if(strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) {
         if(strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) {
           /* only if the path doesn't look like a boolean option! */
           /* only if the path doesn't look like a boolean option! */
           co->path = strdup(ptr);
           co->path = strdup(ptr);
@@ -753,7 +773,8 @@ Curl_cookie_add(struct Curl_easy *data,
         co->secure = strcasecompare(ptr, "TRUE")?TRUE:FALSE;
         co->secure = strcasecompare(ptr, "TRUE")?TRUE:FALSE;
         break;
         break;
       case 4:
       case 4:
-        co->expires = curlx_strtoofft(ptr, NULL, 10);
+        if(curlx_strtoofft(ptr, NULL, 10, &co->expires))
+          badcookie = TRUE;
         break;
         break;
       case 5:
       case 5:
         co->name = strdup(ptr);
         co->name = strdup(ptr);
@@ -828,7 +849,7 @@ Curl_cookie_add(struct Curl_easy *data,
         if(strcasecompare(clist->domain, co->domain) &&
         if(strcasecompare(clist->domain, co->domain) &&
           (clist->tailmatch == co->tailmatch))
           (clist->tailmatch == co->tailmatch))
           /* The domains are identical */
           /* The domains are identical */
-          replace_old=TRUE;
+          replace_old = TRUE;
       }
       }
       else if(!clist->domain && !co->domain)
       else if(!clist->domain && !co->domain)
         replace_old = TRUE;
         replace_old = TRUE;
@@ -957,7 +978,7 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
 {
 {
   struct CookieInfo *c;
   struct CookieInfo *c;
   FILE *fp = NULL;
   FILE *fp = NULL;
-  bool fromfile=TRUE;
+  bool fromfile = TRUE;
   char *line = NULL;
   char *line = NULL;
 
 
   if(NULL == inc) {
   if(NULL == inc) {
@@ -977,7 +998,7 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
 
 
   if(file && !strcmp(file, "-")) {
   if(file && !strcmp(file, "-")) {
     fp = stdin;
     fp = stdin;
-    fromfile=FALSE;
+    fromfile = FALSE;
   }
   }
   else if(file && !*file) {
   else if(file && !*file) {
     /* points to a "" string */
     /* points to a "" string */
@@ -998,12 +1019,12 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
     while(get_line(line, MAX_COOKIE_LINE, fp)) {
     while(get_line(line, MAX_COOKIE_LINE, fp)) {
       if(checkprefix("Set-Cookie:", line)) {
       if(checkprefix("Set-Cookie:", line)) {
         /* This is a cookie line, get it! */
         /* This is a cookie line, get it! */
-        lineptr=&line[11];
-        headerline=TRUE;
+        lineptr = &line[11];
+        headerline = TRUE;
       }
       }
       else {
       else {
-        lineptr=line;
-        headerline=FALSE;
+        lineptr = line;
+        headerline = FALSE;
       }
       }
       while(*lineptr && ISBLANK(*lineptr))
       while(*lineptr && ISBLANK(*lineptr))
         lineptr++;
         lineptr++;
@@ -1113,7 +1134,7 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
   struct Cookie *newco;
   struct Cookie *newco;
   struct Cookie *co;
   struct Cookie *co;
   time_t now = time(NULL);
   time_t now = time(NULL);
-  struct Cookie *mainco=NULL;
+  struct Cookie *mainco = NULL;
   size_t matches = 0;
   size_t matches = 0;
   bool is_ip;
   bool is_ip;
 
 
@@ -1185,7 +1206,7 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
 
 
     co = mainco;
     co = mainco;
 
 
-    for(i=0; co; co = co->next)
+    for(i = 0; co; co = co->next)
       array[i++] = co;
       array[i++] = co;
 
 
     /* now sort the cookie pointers in path length order */
     /* now sort the cookie pointers in path length order */
@@ -1194,8 +1215,8 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
     /* remake the linked list order according to the new order */
     /* remake the linked list order according to the new order */
 
 
     mainco = array[0]; /* start here */
     mainco = array[0]; /* start here */
-    for(i=0; i<matches-1; i++)
-      array[i]->next = array[i+1];
+    for(i = 0; i<matches-1; i++)
+      array[i]->next = array[i + 1];
     array[matches-1]->next = NULL; /* terminate the list */
     array[matches-1]->next = NULL; /* terminate the list */
 
 
     free(array); /* remove the temporary data again */
     free(array); /* remove the temporary data again */
@@ -1335,7 +1356,7 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere)
 {
 {
   struct Cookie *co;
   struct Cookie *co;
   FILE *out;
   FILE *out;
-  bool use_stdout=FALSE;
+  bool use_stdout = FALSE;
   char *format_ptr;
   char *format_ptr;
 
 
   if((NULL == c) || (0 == c->numcookies))
   if((NULL == c) || (0 == c->numcookies))
@@ -1349,7 +1370,7 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere)
   if(!strcmp("-", dumphere)) {
   if(!strcmp("-", dumphere)) {
     /* use stdout */
     /* use stdout */
     out = stdout;
     out = stdout;
-    use_stdout=TRUE;
+    use_stdout = TRUE;
   }
   }
   else {
   else {
     out = fopen(dumphere, FOPEN_WRITETEXT);
     out = fopen(dumphere, FOPEN_WRITETEXT);
@@ -1382,7 +1403,7 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere)
   return 0;
   return 0;
 }
 }
 
 
-struct curl_slist *Curl_cookie_list(struct Curl_easy *data)
+static struct curl_slist *cookie_list(struct Curl_easy *data)
 {
 {
   struct curl_slist *list = NULL;
   struct curl_slist *list = NULL;
   struct curl_slist *beg;
   struct curl_slist *beg;
@@ -1413,6 +1434,15 @@ struct curl_slist *Curl_cookie_list(struct Curl_easy *data)
   return list;
   return list;
 }
 }
 
 
+struct curl_slist *Curl_cookie_list(struct Curl_easy *data)
+{
+  struct curl_slist *list;
+  Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
+  list = cookie_list(data);
+  Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+  return list;
+}
+
 void Curl_flush_cookies(struct Curl_easy *data, int cleanup)
 void Curl_flush_cookies(struct Curl_easy *data, int cleanup)
 {
 {
   if(data->set.str[STRING_COOKIEJAR]) {
   if(data->set.str[STRING_COOKIEJAR]) {

+ 7 - 4
Utilities/cmcurl/lib/cookie.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -62,13 +62,16 @@ struct CookieInfo {
    that comprise the cookie non-terminal in the syntax description of the
    that comprise the cookie non-terminal in the syntax description of the
    Set-Cookie header)"
    Set-Cookie header)"
 
 
+   We allow max 5000 bytes cookie header. Max 4095 bytes length per cookie
+   name and value. Name + value may not exceed 4096 bytes.
+
 */
 */
 #define MAX_COOKIE_LINE 5000
 #define MAX_COOKIE_LINE 5000
 #define MAX_COOKIE_LINE_TXT "4999"
 #define MAX_COOKIE_LINE_TXT "4999"
 
 
-/* This is the maximum length of a cookie name we deal with: */
-#define MAX_NAME 1024
-#define MAX_NAME_TXT "1023"
+/* This is the maximum length of a cookie name or content we deal with: */
+#define MAX_NAME 4096
+#define MAX_NAME_TXT "4095"
 
 
 struct Curl_easy;
 struct Curl_easy;
 /*
 /*

+ 3 - 3
Utilities/cmcurl/lib/curl_addrinfo.c

@@ -286,7 +286,7 @@ Curl_he2ai(const struct hostent *he, int port)
 
 
   DEBUGASSERT((he->h_name != NULL) && (he->h_addr_list != NULL));
   DEBUGASSERT((he->h_name != NULL) && (he->h_addr_list != NULL));
 
 
-  for(i=0; (curr = he->h_addr_list[i]) != NULL; i++) {
+  for(i = 0; (curr = he->h_addr_list[i]) != NULL; i++) {
 
 
     size_t ss_size;
     size_t ss_size;
 #ifdef ENABLE_IPV6
 #ifdef ENABLE_IPV6
@@ -570,9 +570,9 @@ curl_dogetaddrinfo(const char *hostname,
                    int line, const char *source)
                    int line, const char *source)
 {
 {
 #ifdef USE_LWIPSOCK
 #ifdef USE_LWIPSOCK
-  int res=lwip_getaddrinfo(hostname, service, hints, result);
+  int res = lwip_getaddrinfo(hostname, service, hints, result);
 #else
 #else
-  int res=(getaddrinfo)(hostname, service, hints, result);
+  int res = (getaddrinfo)(hostname, service, hints, result);
 #endif
 #endif
   if(0 == res)
   if(0 == res)
     /* success */
     /* success */

+ 3 - 9
Utilities/cmcurl/lib/curl_config.h.cmake

@@ -42,9 +42,6 @@
 /* to disable RTSP */
 /* to disable RTSP */
 #cmakedefine CURL_DISABLE_RTSP 1
 #cmakedefine CURL_DISABLE_RTSP 1
 
 
-/* to disable RTMP */
-#cmakedefine CURL_DISABLE_RTMP 1
-
 /* to disable SMB */
 /* to disable SMB */
 #cmakedefine CURL_DISABLE_SMB 1
 #cmakedefine CURL_DISABLE_SMB 1
 
 
@@ -73,9 +70,6 @@
 /* when not building a shared library */
 /* when not building a shared library */
 #cmakedefine CURL_STATICLIB 1
 #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 */
 /* your Entropy Gathering Daemon socket pathname */
 #cmakedefine EGD_SOCKET ${EGD_SOCKET}
 #cmakedefine EGD_SOCKET ${EGD_SOCKET}
 
 
@@ -885,6 +879,9 @@
 /* The size of `off_t', as computed by sizeof. */
 /* The size of `off_t', as computed by sizeof. */
 @SIZEOF_OFF_T_CODE@
 @SIZEOF_OFF_T_CODE@
 
 
+/* The size of `curl_off_t', as computed by sizeof. */
+@SIZEOF_CURL_OFF_T_CODE@
+
 /* The size of `size_t', as computed by sizeof. */
 /* The size of `size_t', as computed by sizeof. */
 @SIZEOF_SIZE_T_CODE@
 @SIZEOF_SIZE_T_CODE@
 
 
@@ -960,9 +957,6 @@
 /* Version number of package */
 /* Version number of package */
 #cmakedefine VERSION ${VERSION}
 #cmakedefine VERSION ${VERSION}
 
 
-/* Define to avoid automatic inclusion of winsock.h */
-#cmakedefine WIN32_LEAN_AND_MEAN 1
-
 /* Define to 1 if OS is AIX. */
 /* Define to 1 if OS is AIX. */
 #ifndef _ALL_SOURCE
 #ifndef _ALL_SOURCE
 #  undef _ALL_SOURCE
 #  undef _ALL_SOURCE

+ 6 - 6
Utilities/cmcurl/lib/curl_fnmatch.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -151,7 +151,7 @@ static int setcharset(unsigned char **p, unsigned char *charset)
         (*p)++;
         (*p)++;
       }
       }
       else if(c == '[') {
       else if(c == '[') {
-        char c2 = *((*p)+1);
+        char c2 = *((*p) + 1);
         if(c2 == ':') { /* there has to be a keyword */
         if(c2 == ':') { /* there has to be a keyword */
           (*p) += 2;
           (*p) += 2;
           if(parsekeyword(p, charset)) {
           if(parsekeyword(p, charset)) {
@@ -319,9 +319,9 @@ static int loop(const unsigned char *pattern, const unsigned char *string)
     switch(state) {
     switch(state) {
     case CURLFNM_LOOP_DEFAULT:
     case CURLFNM_LOOP_DEFAULT:
       if(*p == '*') {
       if(*p == '*') {
-        while(*(p+1) == '*') /* eliminate multiple stars */
+        while(*(p + 1) == '*') /* eliminate multiple stars */
           p++;
           p++;
-        if(*s == '\0' && *(p+1) == '\0')
+        if(*s == '\0' && *(p + 1) == '\0')
           return CURL_FNMATCH_MATCH;
           return CURL_FNMATCH_MATCH;
         rc = loop(p + 1, s); /* *.txt matches .txt <=> .txt matches .txt */
         rc = loop(p + 1, s); /* *.txt matches .txt <=> .txt matches .txt */
         if(rc == CURL_FNMATCH_MATCH)
         if(rc == CURL_FNMATCH_MATCH)
@@ -351,7 +351,7 @@ static int loop(const unsigned char *pattern, const unsigned char *string)
         p++;
         p++;
       }
       }
       else if(*p == '[') {
       else if(*p == '[') {
-        unsigned char *pp = p+1; /* cannot handle with pointer to register */
+        unsigned char *pp = p + 1; /* cannot handle with pointer to register */
         if(setcharset(&pp, charset)) {
         if(setcharset(&pp, charset)) {
           int found = FALSE;
           int found = FALSE;
           if(charset[(unsigned int)*s])
           if(charset[(unsigned int)*s])
@@ -381,7 +381,7 @@ static int loop(const unsigned char *pattern, const unsigned char *string)
             found = !found;
             found = !found;
 
 
           if(found) {
           if(found) {
-            p = pp+1;
+            p = pp + 1;
             s++;
             s++;
             memset(charset, 0, CURLFNM_CHSET_SIZE);
             memset(charset, 0, CURLFNM_CHSET_SIZE);
           }
           }

+ 58 - 34
Utilities/cmcurl/lib/curl_ntlm_core.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -31,6 +31,25 @@
  * https://www.innovation.ch/java/ntlm.html
  * https://www.innovation.ch/java/ntlm.html
  */
  */
 
 
+/* Please keep the SSL backend-specific #if branches in this order:
+
+   1. USE_OPENSSL
+   2. USE_GNUTLS_NETTLE
+   3. USE_GNUTLS
+   4. USE_NSS
+   5. USE_MBEDTLS
+   6. USE_DARWINSSL
+   7. USE_OS400CRYPTO
+   8. USE_WIN32_CRYPTO
+
+   This ensures that:
+   - the same SSL branch gets activated throughout this source
+     file even if multiple backends are enabled at the same time.
+   - OpenSSL and NSS have higher priority than Windows Crypt, due
+     to issues with the latter supporting NTLM2Session responses
+     in NTLM type-3 messages.
+ */
+
 #if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO)
 #if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO)
 
 
 #ifdef USE_OPENSSL
 #ifdef USE_OPENSSL
@@ -76,14 +95,6 @@
 #  define MD5_DIGEST_LENGTH 16
 #  define MD5_DIGEST_LENGTH 16
 #  define MD4_DIGEST_LENGTH 16
 #  define MD4_DIGEST_LENGTH 16
 
 
-#elif defined(USE_MBEDTLS)
-
-#  include <mbedtls/des.h>
-#  include <mbedtls/md4.h>
-#  if !defined(MBEDTLS_MD4_C)
-#    include "curl_md4.h"
-#  endif
-
 #elif defined(USE_NSS)
 #elif defined(USE_NSS)
 
 
 #  include <nss.h>
 #  include <nss.h>
@@ -92,6 +103,14 @@
 #  include "curl_md4.h"
 #  include "curl_md4.h"
 #  define MD5_DIGEST_LENGTH MD5_LENGTH
 #  define MD5_DIGEST_LENGTH MD5_LENGTH
 
 
+#elif defined(USE_MBEDTLS)
+
+#  include <mbedtls/des.h>
+#  include <mbedtls/md4.h>
+#  if !defined(MBEDTLS_MD4_C)
+#    include "curl_md4.h"
+#  endif
+
 #elif defined(USE_DARWINSSL)
 #elif defined(USE_DARWINSSL)
 
 
 #  include <CommonCrypto/CommonCryptor.h>
 #  include <CommonCrypto/CommonCryptor.h>
@@ -196,26 +215,6 @@ static void setup_des_key(const unsigned char *key_56,
   gcry_cipher_setkey(*des, key, sizeof(key));
   gcry_cipher_setkey(*des, key, sizeof(key));
 }
 }
 
 
-#elif defined(USE_MBEDTLS)
-
-static bool encrypt_des(const unsigned char *in, unsigned char *out,
-                        const unsigned char *key_56)
-{
-  mbedtls_des_context ctx;
-  char key[8];
-
-  /* Expand the 56-bit key to 64-bits */
-  extend_key_56_to_64(key_56, key);
-
-  /* Set the key parity to odd */
-  mbedtls_des_key_set_parity((unsigned char *) key);
-
-  /* Perform the encryption */
-  mbedtls_des_init(&ctx);
-  mbedtls_des_setkey_enc(&ctx, (unsigned char *) key);
-  return mbedtls_des_crypt_ecb(&ctx, in, out) == 0;
-}
-
 #elif defined(USE_NSS)
 #elif defined(USE_NSS)
 
 
 /*
 /*
@@ -281,6 +280,26 @@ fail:
   return rv;
   return rv;
 }
 }
 
 
+#elif defined(USE_MBEDTLS)
+
+static bool encrypt_des(const unsigned char *in, unsigned char *out,
+                        const unsigned char *key_56)
+{
+  mbedtls_des_context ctx;
+  char key[8];
+
+  /* Expand the 56-bit key to 64-bits */
+  extend_key_56_to_64(key_56, key);
+
+  /* Set the key parity to odd */
+  mbedtls_des_key_set_parity((unsigned char *) key);
+
+  /* Perform the encryption */
+  mbedtls_des_init(&ctx);
+  mbedtls_des_setkey_enc(&ctx, (unsigned char *) key);
+  return mbedtls_des_crypt_ecb(&ctx, in, out) == 0;
+}
+
 #elif defined(USE_DARWINSSL)
 #elif defined(USE_DARWINSSL)
 
 
 static bool encrypt_des(const unsigned char *in, unsigned char *out,
 static bool encrypt_des(const unsigned char *in, unsigned char *out,
@@ -428,7 +447,7 @@ void Curl_ntlm_core_lm_resp(const unsigned char *keys,
   setup_des_key(keys + 14, &des);
   setup_des_key(keys + 14, &des);
   gcry_cipher_encrypt(des, results + 16, 8, plaintext, 8);
   gcry_cipher_encrypt(des, results + 16, 8, plaintext, 8);
   gcry_cipher_close(des);
   gcry_cipher_close(des);
-#elif defined(USE_MBEDTLS) || defined(USE_NSS) || defined(USE_DARWINSSL) \
+#elif defined(USE_NSS) || defined(USE_MBEDTLS) || defined(USE_DARWINSSL) \
   || defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO)
   || defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO)
   encrypt_des(plaintext, results, keys);
   encrypt_des(plaintext, results, keys);
   encrypt_des(plaintext, results + 8, keys + 7);
   encrypt_des(plaintext, results + 8, keys + 7);
@@ -492,7 +511,7 @@ CURLcode Curl_ntlm_core_mk_lm_hash(struct Curl_easy *data,
     setup_des_key(pw + 7, &des);
     setup_des_key(pw + 7, &des);
     gcry_cipher_encrypt(des, lmbuffer + 8, 8, magic, 8);
     gcry_cipher_encrypt(des, lmbuffer + 8, 8, magic, 8);
     gcry_cipher_close(des);
     gcry_cipher_close(des);
-#elif defined(USE_MBEDTLS) || defined(USE_NSS) || defined(USE_DARWINSSL) \
+#elif defined(USE_NSS) || defined(USE_MBEDTLS) || defined(USE_DARWINSSL) \
   || defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO)
   || defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO)
     encrypt_des(magic, lmbuffer, pw);
     encrypt_des(magic, lmbuffer, pw);
     encrypt_des(magic, lmbuffer + 8, pw + 7);
     encrypt_des(magic, lmbuffer + 8, pw + 7);
@@ -571,13 +590,18 @@ CURLcode Curl_ntlm_core_mk_nt_hash(struct Curl_easy *data,
     gcry_md_write(MD4pw, pw, 2 * len);
     gcry_md_write(MD4pw, pw, 2 * len);
     memcpy(ntbuffer, gcry_md_read(MD4pw, 0), MD4_DIGEST_LENGTH);
     memcpy(ntbuffer, gcry_md_read(MD4pw, 0), MD4_DIGEST_LENGTH);
     gcry_md_close(MD4pw);
     gcry_md_close(MD4pw);
-#elif defined(USE_NSS) || defined(USE_OS400CRYPTO) || \
-    (defined(USE_MBEDTLS) && !defined(MBEDTLS_MD4_C))
+#elif defined(USE_NSS)
     Curl_md4it(ntbuffer, pw, 2 * len);
     Curl_md4it(ntbuffer, pw, 2 * len);
 #elif defined(USE_MBEDTLS)
 #elif defined(USE_MBEDTLS)
+#if defined(MBEDTLS_MD4_C)
     mbedtls_md4(pw, 2 * len, ntbuffer);
     mbedtls_md4(pw, 2 * len, ntbuffer);
+#else
+    Curl_md4it(ntbuffer, pw, 2 * len);
+#endif
 #elif defined(USE_DARWINSSL)
 #elif defined(USE_DARWINSSL)
     (void)CC_MD4(pw, (CC_LONG)(2 * len), ntbuffer);
     (void)CC_MD4(pw, (CC_LONG)(2 * len), ntbuffer);
+#elif defined(USE_OS400CRYPTO)
+    Curl_md4it(ntbuffer, pw, 2 * len);
 #elif defined(USE_WIN32_CRYPTO)
 #elif defined(USE_WIN32_CRYPTO)
     HCRYPTPROV hprov;
     HCRYPTPROV hprov;
     if(CryptAcquireContext(&hprov, NULL, NULL, PROV_RSA_FULL,
     if(CryptAcquireContext(&hprov, NULL, NULL, PROV_RSA_FULL,
@@ -780,7 +804,7 @@ CURLcode  Curl_ntlm_core_mk_lmv2_resp(unsigned char *ntlmv2hash,
 
 
   /* Concatenate the HMAC MD5 output  with the client nonce */
   /* Concatenate the HMAC MD5 output  with the client nonce */
   memcpy(lmresp, hmac_output, 16);
   memcpy(lmresp, hmac_output, 16);
-  memcpy(lmresp+16, challenge_client, 8);
+  memcpy(lmresp + 16, challenge_client, 8);
 
 
   return result;
   return result;
 }
 }

+ 10 - 4
Utilities/cmcurl/lib/curl_ntlm_core.h

@@ -26,13 +26,19 @@
 
 
 #if defined(USE_NTLM)
 #if defined(USE_NTLM)
 
 
+/* If NSS is the first available SSL backend (see order in curl_ntlm_core.c)
+   then it must be initialized to be used by NTLM. */
+#if !defined(USE_OPENSSL) && \
+    !defined(USE_GNUTLS_NETTLE) && \
+    !defined(USE_GNUTLS) && \
+    defined(USE_NSS)
+#define NTLM_NEEDS_NSS_INIT
+#endif
+
 #if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO)
 #if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO)
 
 
 #ifdef USE_OPENSSL
 #ifdef USE_OPENSSL
-#  if !defined(OPENSSL_VERSION_NUMBER) && \
-      !defined(HEADER_SSL_H) && !defined(HEADER_MD5_H)
-#    error "curl_ntlm_core.h shall not be included before OpenSSL headers."
-#  endif
+#  include <openssl/ssl.h>
 #endif
 #endif
 
 
 /* Define USE_NTRESPONSES in order to make the type-3 message include
 /* Define USE_NTRESPONSES in order to make the type-3 message include

+ 10 - 16
Utilities/cmcurl/lib/curl_ntlm_wb.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -48,6 +48,7 @@
 #include "sendf.h"
 #include "sendf.h"
 #include "select.h"
 #include "select.h"
 #include "vauth/ntlm.h"
 #include "vauth/ntlm.h"
+#include "curl_ntlm_core.h"
 #include "curl_ntlm_wb.h"
 #include "curl_ntlm_wb.h"
 #include "url.h"
 #include "url.h"
 #include "strerror.h"
 #include "strerror.h"
@@ -123,7 +124,6 @@ static CURLcode ntlm_wb_init(struct connectdata *conn, const char *userp)
   struct passwd pw, *pw_res;
   struct passwd pw, *pw_res;
   char pwbuf[1024];
   char pwbuf[1024];
 #endif
 #endif
-  int error;
 
 
   /* Return if communication with ntlm_auth already set up */
   /* Return if communication with ntlm_auth already set up */
   if(conn->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD ||
   if(conn->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD ||
@@ -178,26 +178,23 @@ static CURLcode ntlm_wb_init(struct connectdata *conn, const char *userp)
     ntlm_auth = NTLM_WB_FILE;
     ntlm_auth = NTLM_WB_FILE;
 
 
   if(access(ntlm_auth, X_OK) != 0) {
   if(access(ntlm_auth, X_OK) != 0) {
-    error = ERRNO;
     failf(conn->data, "Could not access ntlm_auth: %s errno %d: %s",
     failf(conn->data, "Could not access ntlm_auth: %s errno %d: %s",
-          ntlm_auth, error, Curl_strerror(conn, error));
+          ntlm_auth, errno, Curl_strerror(conn, errno));
     goto done;
     goto done;
   }
   }
 
 
   if(socketpair(AF_UNIX, SOCK_STREAM, 0, sockfds)) {
   if(socketpair(AF_UNIX, SOCK_STREAM, 0, sockfds)) {
-    error = ERRNO;
     failf(conn->data, "Could not open socket pair. errno %d: %s",
     failf(conn->data, "Could not open socket pair. errno %d: %s",
-          error, Curl_strerror(conn, error));
+          errno, Curl_strerror(conn, errno));
     goto done;
     goto done;
   }
   }
 
 
   child_pid = fork();
   child_pid = fork();
   if(child_pid == -1) {
   if(child_pid == -1) {
-    error = ERRNO;
     sclose(sockfds[0]);
     sclose(sockfds[0]);
     sclose(sockfds[1]);
     sclose(sockfds[1]);
     failf(conn->data, "Could not fork. errno %d: %s",
     failf(conn->data, "Could not fork. errno %d: %s",
-          error, Curl_strerror(conn, error));
+          errno, Curl_strerror(conn, errno));
     goto done;
     goto done;
   }
   }
   else if(!child_pid) {
   else if(!child_pid) {
@@ -208,16 +205,14 @@ static CURLcode ntlm_wb_init(struct connectdata *conn, const char *userp)
     /* Don't use sclose in the child since it fools the socket leak detector */
     /* Don't use sclose in the child since it fools the socket leak detector */
     sclose_nolog(sockfds[0]);
     sclose_nolog(sockfds[0]);
     if(dup2(sockfds[1], STDIN_FILENO) == -1) {
     if(dup2(sockfds[1], STDIN_FILENO) == -1) {
-      error = ERRNO;
       failf(conn->data, "Could not redirect child stdin. errno %d: %s",
       failf(conn->data, "Could not redirect child stdin. errno %d: %s",
-            error, Curl_strerror(conn, error));
+            errno, Curl_strerror(conn, errno));
       exit(1);
       exit(1);
     }
     }
 
 
     if(dup2(sockfds[1], STDOUT_FILENO) == -1) {
     if(dup2(sockfds[1], STDOUT_FILENO) == -1) {
-      error = ERRNO;
       failf(conn->data, "Could not redirect child stdout. errno %d: %s",
       failf(conn->data, "Could not redirect child stdout. errno %d: %s",
-            error, Curl_strerror(conn, error));
+            errno, Curl_strerror(conn, errno));
       exit(1);
       exit(1);
     }
     }
 
 
@@ -235,10 +230,9 @@ static CURLcode ntlm_wb_init(struct connectdata *conn, const char *userp)
             "--username", username,
             "--username", username,
             NULL);
             NULL);
 
 
-    error = ERRNO;
     sclose_nolog(sockfds[1]);
     sclose_nolog(sockfds[1]);
     failf(conn->data, "Could not execl(). errno %d: %s",
     failf(conn->data, "Could not execl(). errno %d: %s",
-          error, Curl_strerror(conn, error));
+          errno, Curl_strerror(conn, errno));
     exit(1);
     exit(1);
   }
   }
 
 
@@ -364,7 +358,7 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn,
 
 
   /* not set means empty */
   /* not set means empty */
   if(!userp)
   if(!userp)
-    userp="";
+    userp = "";
 
 
   switch(ntlm->state) {
   switch(ntlm->state) {
   case NTLMSTATE_TYPE1:
   case NTLMSTATE_TYPE1:
@@ -420,7 +414,7 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn,
     /* connection is already authenticated,
     /* connection is already authenticated,
      * don't send a header in future requests */
      * don't send a header in future requests */
     free(*allocuserpwd);
     free(*allocuserpwd);
-    *allocuserpwd=NULL;
+    *allocuserpwd = NULL;
     authp->done = TRUE;
     authp->done = TRUE;
     break;
     break;
   }
   }

+ 7 - 1
Utilities/cmcurl/lib/curl_rtmp.c

@@ -74,6 +74,7 @@ const struct Curl_handler Curl_handler_rtmp = {
   ZERO_NULL,                            /* perform_getsock */
   ZERO_NULL,                            /* perform_getsock */
   rtmp_disconnect,                      /* disconnect */
   rtmp_disconnect,                      /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
   PORT_RTMP,                            /* defport */
   PORT_RTMP,                            /* defport */
   CURLPROTO_RTMP,                       /* protocol */
   CURLPROTO_RTMP,                       /* protocol */
   PROTOPT_NONE                          /* flags*/
   PROTOPT_NONE                          /* flags*/
@@ -94,6 +95,7 @@ const struct Curl_handler Curl_handler_rtmpt = {
   ZERO_NULL,                            /* perform_getsock */
   ZERO_NULL,                            /* perform_getsock */
   rtmp_disconnect,                      /* disconnect */
   rtmp_disconnect,                      /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
   PORT_RTMPT,                           /* defport */
   PORT_RTMPT,                           /* defport */
   CURLPROTO_RTMPT,                      /* protocol */
   CURLPROTO_RTMPT,                      /* protocol */
   PROTOPT_NONE                          /* flags*/
   PROTOPT_NONE                          /* flags*/
@@ -114,6 +116,7 @@ const struct Curl_handler Curl_handler_rtmpe = {
   ZERO_NULL,                            /* perform_getsock */
   ZERO_NULL,                            /* perform_getsock */
   rtmp_disconnect,                      /* disconnect */
   rtmp_disconnect,                      /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
   PORT_RTMP,                            /* defport */
   PORT_RTMP,                            /* defport */
   CURLPROTO_RTMPE,                      /* protocol */
   CURLPROTO_RTMPE,                      /* protocol */
   PROTOPT_NONE                          /* flags*/
   PROTOPT_NONE                          /* flags*/
@@ -134,6 +137,7 @@ const struct Curl_handler Curl_handler_rtmpte = {
   ZERO_NULL,                            /* perform_getsock */
   ZERO_NULL,                            /* perform_getsock */
   rtmp_disconnect,                      /* disconnect */
   rtmp_disconnect,                      /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
   PORT_RTMPT,                           /* defport */
   PORT_RTMPT,                           /* defport */
   CURLPROTO_RTMPTE,                     /* protocol */
   CURLPROTO_RTMPTE,                     /* protocol */
   PROTOPT_NONE                          /* flags*/
   PROTOPT_NONE                          /* flags*/
@@ -154,6 +158,7 @@ const struct Curl_handler Curl_handler_rtmps = {
   ZERO_NULL,                            /* perform_getsock */
   ZERO_NULL,                            /* perform_getsock */
   rtmp_disconnect,                      /* disconnect */
   rtmp_disconnect,                      /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
   PORT_RTMPS,                           /* defport */
   PORT_RTMPS,                           /* defport */
   CURLPROTO_RTMPS,                      /* protocol */
   CURLPROTO_RTMPS,                      /* protocol */
   PROTOPT_NONE                          /* flags*/
   PROTOPT_NONE                          /* flags*/
@@ -174,6 +179,7 @@ const struct Curl_handler Curl_handler_rtmpts = {
   ZERO_NULL,                            /* perform_getsock */
   ZERO_NULL,                            /* perform_getsock */
   rtmp_disconnect,                      /* disconnect */
   rtmp_disconnect,                      /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
   PORT_RTMPS,                           /* defport */
   PORT_RTMPS,                           /* defport */
   CURLPROTO_RTMPTS,                     /* protocol */
   CURLPROTO_RTMPTS,                     /* protocol */
   PROTOPT_NONE                          /* flags*/
   PROTOPT_NONE                          /* flags*/
@@ -200,7 +206,7 @@ static CURLcode rtmp_connect(struct connectdata *conn, bool *done)
   RTMP *r = conn->proto.generic;
   RTMP *r = conn->proto.generic;
   SET_RCVTIMEO(tv, 10);
   SET_RCVTIMEO(tv, 10);
 
 
-  r->m_sb.sb_socket = conn->sock[FIRSTSOCKET];
+  r->m_sb.sb_socket = (int)conn->sock[FIRSTSOCKET];
 
 
   /* We have to know if it's a write before we send the
   /* We have to know if it's a write before we send the
    * connect request packet
    * connect request packet

+ 4 - 2
Utilities/cmcurl/lib/curl_sasl.c

@@ -331,7 +331,8 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
       sasl->authused = SASL_MECH_NTLM;
       sasl->authused = SASL_MECH_NTLM;
 
 
       if(force_ir || data->set.sasl_ir)
       if(force_ir || data->set.sasl_ir)
-        result = Curl_auth_create_ntlm_type1_message(conn->user, conn->passwd,
+        result = Curl_auth_create_ntlm_type1_message(data,
+                                                     conn->user, conn->passwd,
                                                      &conn->ntlm, &resp, &len);
                                                      &conn->ntlm, &resp, &len);
       }
       }
     else
     else
@@ -493,7 +494,8 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
 #ifdef USE_NTLM
 #ifdef USE_NTLM
   case SASL_NTLM:
   case SASL_NTLM:
     /* Create the type-1 message */
     /* Create the type-1 message */
-    result = Curl_auth_create_ntlm_type1_message(conn->user, conn->passwd,
+    result = Curl_auth_create_ntlm_type1_message(data,
+                                                 conn->user, conn->passwd,
                                                  &conn->ntlm, &resp, &len);
                                                  &conn->ntlm, &resp, &len);
     newstate = SASL_NTLM_TYPE2MSG;
     newstate = SASL_NTLM_TYPE2MSG;
     break;
     break;

+ 23 - 19
Utilities/cmcurl/lib/curl_setup.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -22,6 +22,10 @@
  *
  *
  ***************************************************************************/
  ***************************************************************************/
 
 
+#if defined(BUILDING_LIBCURL) && !defined(CURL_NO_OLDIES)
+#define CURL_NO_OLDIES
+#endif
+
 /*
 /*
  * Define WIN32 when build target is Win32 API
  * Define WIN32 when build target is Win32 API
  */
  */
@@ -31,6 +35,17 @@
 #define WIN32
 #define WIN32
 #endif
 #endif
 
 
+#ifdef WIN32
+/*
+ * Don't include unneeded stuff in Windows headers to avoid compiler
+ * warnings and macro clashes.
+ * Make sure to define this macro before including any Windows headers.
+ */
+#  ifndef WIN32_LEAN_AND_MEAN
+#    define WIN32_LEAN_AND_MEAN
+#  endif
+#endif
+
 /*
 /*
  * Include configuration script results or hand-crafted
  * Include configuration script results or hand-crafted
  * configuration file for platforms which lack config tool.
  * configuration file for platforms which lack config tool.
@@ -130,14 +145,7 @@
 
 
 #include <curl/curl.h>
 #include <curl/curl.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
+#define CURL_SIZEOF_CURL_OFF_T SIZEOF_CURL_OFF_T
 
 
 /*
 /*
  * Disable other protocols when http is the only one desired.
  * Disable other protocols when http is the only one desired.
@@ -174,9 +182,6 @@
 #  ifndef CURL_DISABLE_SMTP
 #  ifndef CURL_DISABLE_SMTP
 #    define CURL_DISABLE_SMTP
 #    define CURL_DISABLE_SMTP
 #  endif
 #  endif
-#  ifndef CURL_DISABLE_RTMP
-#    define CURL_DISABLE_RTMP
-#  endif
 #  ifndef CURL_DISABLE_GOPHER
 #  ifndef CURL_DISABLE_GOPHER
 #    define CURL_DISABLE_GOPHER
 #    define CURL_DISABLE_GOPHER
 #  endif
 #  endif
@@ -195,7 +200,7 @@
 
 
 /* ================================================================ */
 /* ================================================================ */
 /* No system header file shall be included in this file before this */
 /* No system header file shall be included in this file before this */
-/* point. The only allowed ones are those included from curlbuild.h */
+/* point. The only allowed ones are those included from curl/system.h */
 /* ================================================================ */
 /* ================================================================ */
 
 
 /*
 /*
@@ -241,9 +246,6 @@
 #  if defined(_UNICODE) && !defined(UNICODE)
 #  if defined(_UNICODE) && !defined(UNICODE)
 #    define UNICODE
 #    define UNICODE
 #  endif
 #  endif
-#  ifndef WIN32_LEAN_AND_MEAN
-#    define WIN32_LEAN_AND_MEAN
-#  endif
 #  include <windows.h>
 #  include <windows.h>
 #  ifdef HAVE_WINSOCK2_H
 #  ifdef HAVE_WINSOCK2_H
 #    include <winsock2.h>
 #    include <winsock2.h>
@@ -655,9 +657,8 @@ int netware_init(void);
 #endif
 #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")
+#ifdef CURL_WANTS_CA_BUNDLE_ENV
+#error "No longer supported. Set CURLOPT_CAINFO at runtime instead."
 #endif
 #endif
 
 
 /*
 /*
@@ -731,6 +732,7 @@ Therefore we specify it explicitly. https://github.com/curl/curl/pull/258
 #if defined(WIN32) || defined(MSDOS)
 #if defined(WIN32) || defined(MSDOS)
 #define FOPEN_READTEXT "rt"
 #define FOPEN_READTEXT "rt"
 #define FOPEN_WRITETEXT "wt"
 #define FOPEN_WRITETEXT "wt"
+#define FOPEN_APPENDTEXT "at"
 #elif defined(__CYGWIN__)
 #elif defined(__CYGWIN__)
 /* Cygwin has specific behavior we need to address when WIN32 is not defined.
 /* Cygwin has specific behavior we need to address when WIN32 is not defined.
 https://cygwin.com/cygwin-ug-net/using-textbinary.html
 https://cygwin.com/cygwin-ug-net/using-textbinary.html
@@ -740,9 +742,11 @@ endings either CRLF or LF so 't' is appropriate.
 */
 */
 #define FOPEN_READTEXT "rt"
 #define FOPEN_READTEXT "rt"
 #define FOPEN_WRITETEXT "w"
 #define FOPEN_WRITETEXT "w"
+#define FOPEN_APPENDTEXT "a"
 #else
 #else
 #define FOPEN_READTEXT "r"
 #define FOPEN_READTEXT "r"
 #define FOPEN_WRITETEXT "w"
 #define FOPEN_WRITETEXT "w"
+#define FOPEN_APPENDTEXT "a"
 #endif
 #endif
 
 
 /* WinSock destroys recv() buffer when send() failed.
 /* WinSock destroys recv() buffer when send() failed.

+ 0 - 14
Utilities/cmcurl/lib/curl_setup_once.h

@@ -435,20 +435,6 @@ typedef int sig_atomic_t;
 #endif
 #endif
 
 
 
 
-/*
- * Macro ERRNO / SET_ERRNO() returns / sets the NOT *socket-related* errno
- * (or equivalent) on this platform to hide platform details to code using it.
- */
-
-#if defined(WIN32) && !defined(USE_LWIPSOCK)
-#define ERRNO         ((int)GetLastError())
-#define SET_ERRNO(x)  (SetLastError((DWORD)(x)))
-#else
-#define ERRNO         (errno)
-#define SET_ERRNO(x)  (errno = (x))
-#endif
-
-
 /*
 /*
  * Portable error number symbolic names defined to Winsock error codes.
  * Portable error number symbolic names defined to Winsock error codes.
  */
  */

+ 11 - 4
Utilities/cmcurl/lib/curl_threads.c

@@ -104,15 +104,22 @@ int Curl_thread_join(curl_thread_t *hnd)
 curl_thread_t Curl_thread_create(unsigned int (CURL_STDCALL *func) (void *),
 curl_thread_t Curl_thread_create(unsigned int (CURL_STDCALL *func) (void *),
                                  void *arg)
                                  void *arg)
 {
 {
+  curl_thread_t t;
 #ifdef _WIN32_WCE
 #ifdef _WIN32_WCE
-  return CreateThread(NULL, 0, func, arg, 0, NULL);
+  t = CreateThread(NULL, 0, func, arg, 0, NULL);
 #else
 #else
-  curl_thread_t t;
   t = (curl_thread_t)_beginthreadex(NULL, 0, func, arg, 0, NULL);
   t = (curl_thread_t)_beginthreadex(NULL, 0, func, arg, 0, NULL);
-  if((t == 0) || (t == (curl_thread_t)-1L))
+#endif
+  if((t == 0) || (t == LongToHandle(-1L))) {
+#ifdef _WIN32_WCE
+    DWORD gle = GetLastError();
+    errno = ((gle == ERROR_ACCESS_DENIED ||
+              gle == ERROR_NOT_ENOUGH_MEMORY) ?
+             EACCES : EINVAL);
+#endif
     return curl_thread_t_null;
     return curl_thread_t_null;
+  }
   return t;
   return t;
-#endif
 }
 }
 
 
 void Curl_thread_destroy(curl_thread_t hnd)
 void Curl_thread_destroy(curl_thread_t hnd)

+ 8 - 7
Utilities/cmcurl/lib/dict.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -85,6 +85,7 @@ const struct Curl_handler Curl_handler_dict = {
   ZERO_NULL,                            /* perform_getsock */
   ZERO_NULL,                            /* perform_getsock */
   ZERO_NULL,                            /* disconnect */
   ZERO_NULL,                            /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
   PORT_DICT,                            /* defport */
   PORT_DICT,                            /* defport */
   CURLPROTO_DICT,                       /* protocol */
   CURLPROTO_DICT,                       /* protocol */
   PROTOPT_NONE | PROTOPT_NOURLQUERY      /* flags */
   PROTOPT_NONE | PROTOPT_NOURLQUERY      /* flags */
@@ -97,7 +98,7 @@ static char *unescape_word(struct Curl_easy *data, const char *inputbuff)
   char *ptr;
   char *ptr;
   size_t len;
   size_t len;
   char ch;
   char ch;
-  int olen=0;
+  int olen = 0;
 
 
   CURLcode result = Curl_urldecode(data, inputbuff, 0, &newp, &len, FALSE);
   CURLcode result = Curl_urldecode(data, inputbuff, 0, &newp, &len, FALSE);
   if(!newp || result)
   if(!newp || result)
@@ -116,7 +117,7 @@ static char *unescape_word(struct Curl_easy *data, const char *inputbuff)
       }
       }
       dictp[olen++] = ch;
       dictp[olen++] = ch;
     }
     }
-    dictp[olen]=0;
+    dictp[olen] = 0;
   }
   }
   free(newp);
   free(newp);
   return dictp;
   return dictp;
@@ -131,8 +132,8 @@ static CURLcode dict_do(struct connectdata *conn, bool *done)
   char *strategy = NULL;
   char *strategy = NULL;
   char *nthdef = NULL; /* This is not part of the protocol, but required
   char *nthdef = NULL; /* This is not part of the protocol, but required
                           by RFC 2229 */
                           by RFC 2229 */
-  CURLcode result=CURLE_OK;
-  struct Curl_easy *data=conn->data;
+  CURLcode result = CURLE_OK;
+  struct Curl_easy *data = conn->data;
   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
 
 
   char *path = data->state.path;
   char *path = data->state.path;
@@ -167,7 +168,7 @@ static CURLcode dict_do(struct connectdata *conn, bool *done)
 
 
     if((word == NULL) || (*word == (char)0)) {
     if((word == NULL) || (*word == (char)0)) {
       infof(data, "lookup word is missing\n");
       infof(data, "lookup word is missing\n");
-      word=(char *)"default";
+      word = (char *)"default";
     }
     }
     if((database == NULL) || (*database == (char)0)) {
     if((database == NULL) || (*database == (char)0)) {
       database = (char *)"!";
       database = (char *)"!";
@@ -221,7 +222,7 @@ static CURLcode dict_do(struct connectdata *conn, bool *done)
 
 
     if((word == NULL) || (*word == (char)0)) {
     if((word == NULL) || (*word == (char)0)) {
       infof(data, "lookup word is missing\n");
       infof(data, "lookup word is missing\n");
-      word=(char *)"default";
+      word = (char *)"default";
     }
     }
     if((database == NULL) || (*database == (char)0)) {
     if((database == NULL) || (*database == (char)0)) {
       database = (char *)"!";
       database = (char *)"!";

+ 15 - 15
Utilities/cmcurl/lib/dotdot.c

@@ -55,7 +55,7 @@ char *Curl_dedotdotify(const char *input)
   size_t inlen = strlen(input);
   size_t inlen = strlen(input);
   char *clone;
   char *clone;
   size_t clen = inlen; /* the length of the cloned input */
   size_t clen = inlen; /* the length of the cloned input */
-  char *out = malloc(inlen+1);
+  char *out = malloc(inlen + 1);
   char *outptr;
   char *outptr;
   char *orgclone;
   char *orgclone;
   char *queryp;
   char *queryp;
@@ -92,25 +92,25 @@ char *Curl_dedotdotify(const char *input)
         remove that prefix from the input buffer; otherwise, */
         remove that prefix from the input buffer; otherwise, */
 
 
     if(!strncmp("./", clone, 2)) {
     if(!strncmp("./", clone, 2)) {
-      clone+=2;
-      clen-=2;
+      clone += 2;
+      clen -= 2;
     }
     }
     else if(!strncmp("../", clone, 3)) {
     else if(!strncmp("../", clone, 3)) {
-      clone+=3;
-      clen-=3;
+      clone += 3;
+      clen -= 3;
     }
     }
 
 
     /*  B.  if the input buffer begins with a prefix of "/./" or "/.", where
     /*  B.  if the input buffer begins with a prefix of "/./" or "/.", where
         "."  is a complete path segment, then replace that prefix with "/" in
         "."  is a complete path segment, then replace that prefix with "/" in
         the input buffer; otherwise, */
         the input buffer; otherwise, */
     else if(!strncmp("/./", clone, 3)) {
     else if(!strncmp("/./", clone, 3)) {
-      clone+=2;
-      clen-=2;
+      clone += 2;
+      clen -= 2;
     }
     }
     else if(!strcmp("/.", clone)) {
     else if(!strcmp("/.", clone)) {
       clone[1]='/';
       clone[1]='/';
       clone++;
       clone++;
-      clen-=1;
+      clen -= 1;
     }
     }
 
 
     /*  C.  if the input buffer begins with a prefix of "/../" or "/..", where
     /*  C.  if the input buffer begins with a prefix of "/../" or "/..", where
@@ -119,8 +119,8 @@ char *Curl_dedotdotify(const char *input)
         any) from the output buffer; otherwise, */
         any) from the output buffer; otherwise, */
 
 
     else if(!strncmp("/../", clone, 4)) {
     else if(!strncmp("/../", clone, 4)) {
-      clone+=3;
-      clen-=3;
+      clone += 3;
+      clen -= 3;
       /* remove the last segment from the output buffer */
       /* remove the last segment from the output buffer */
       while(outptr > out) {
       while(outptr > out) {
         outptr--;
         outptr--;
@@ -131,8 +131,8 @@ char *Curl_dedotdotify(const char *input)
     }
     }
     else if(!strcmp("/..", clone)) {
     else if(!strcmp("/..", clone)) {
       clone[2]='/';
       clone[2]='/';
-      clone+=2;
-      clen-=2;
+      clone += 2;
+      clen -= 2;
       /* remove the last segment from the output buffer */
       /* remove the last segment from the output buffer */
       while(outptr > out) {
       while(outptr > out) {
         outptr--;
         outptr--;
@@ -146,8 +146,8 @@ char *Curl_dedotdotify(const char *input)
         that from the input buffer; otherwise, */
         that from the input buffer; otherwise, */
 
 
     else if(!strcmp(".", clone) || !strcmp("..", clone)) {
     else if(!strcmp(".", clone) || !strcmp("..", clone)) {
-      *clone=0;
-      *out=0;
+      *clone = 0;
+      *out = 0;
     }
     }
 
 
     else {
     else {
@@ -172,7 +172,7 @@ char *Curl_dedotdotify(const char *input)
        from the correct index. */
        from the correct index. */
     size_t oindex = queryp - orgclone;
     size_t oindex = queryp - orgclone;
     qlen = strlen(&input[oindex]);
     qlen = strlen(&input[oindex]);
-    memcpy(outptr, &input[oindex], qlen+1); /* include the ending zero byte */
+    memcpy(outptr, &input[oindex], qlen + 1); /* include the end zero byte */
   }
   }
 
 
   free(orgclone);
   free(orgclone);

+ 14 - 12
Utilities/cmcurl/lib/easy.c

@@ -433,7 +433,7 @@ static int events_timer(struct Curl_multi *multi,    /* multi handle */
  */
  */
 static int poll2cselect(int pollmask)
 static int poll2cselect(int pollmask)
 {
 {
-  int omask=0;
+  int omask = 0;
   if(pollmask & POLLIN)
   if(pollmask & POLLIN)
     omask |= CURL_CSELECT_IN;
     omask |= CURL_CSELECT_IN;
   if(pollmask & POLLOUT)
   if(pollmask & POLLOUT)
@@ -450,7 +450,7 @@ static int poll2cselect(int pollmask)
  */
  */
 static short socketcb2poll(int pollmask)
 static short socketcb2poll(int pollmask)
 {
 {
-  short omask=0;
+  short omask = 0;
   if(pollmask & CURL_POLL_IN)
   if(pollmask & CURL_POLL_IN)
     omask |= POLLIN;
     omask |= POLLIN;
   if(pollmask & CURL_POLL_OUT)
   if(pollmask & CURL_POLL_OUT)
@@ -473,7 +473,7 @@ static int events_socket(struct Curl_easy *easy,      /* easy handle */
 {
 {
   struct events *ev = userp;
   struct events *ev = userp;
   struct socketmonitor *m;
   struct socketmonitor *m;
-  struct socketmonitor *prev=NULL;
+  struct socketmonitor *prev = NULL;
 
 
 #if defined(CURL_DISABLE_VERBOSE_STRINGS)
 #if defined(CURL_DISABLE_VERBOSE_STRINGS)
   (void) easy;
   (void) easy;
@@ -569,14 +569,14 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
     struct socketmonitor *m;
     struct socketmonitor *m;
     struct pollfd *f;
     struct pollfd *f;
     struct pollfd fds[4];
     struct pollfd fds[4];
-    int numfds=0;
+    int numfds = 0;
     int pollrc;
     int pollrc;
     int i;
     int i;
-    struct timeval before;
-    struct timeval after;
+    struct curltime before;
+    struct curltime after;
 
 
     /* populate the fds[] array */
     /* populate the fds[] array */
-    for(m = ev->list, f=&fds[0]; m; m = m->next) {
+    for(m = ev->list, f = &fds[0]; m; m = m->next) {
       f->fd = m->socket.fd;
       f->fd = m->socket.fd;
       f->events = m->socket.events;
       f->events = m->socket.events;
       f->revents = 0;
       f->revents = 0;
@@ -653,7 +653,9 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
  */
  */
 static CURLcode easy_events(struct Curl_multi *multi)
 static CURLcode easy_events(struct Curl_multi *multi)
 {
 {
-  struct events evs= {2, FALSE, 0, NULL, 0};
+  /* this struct is made static to allow it to be used after this function
+     returns and curl_multi_remove_handle() is called */
+  static struct events evs = {2, FALSE, 0, NULL, 0};
 
 
   /* if running event-based, do some further multi inits */
   /* if running event-based, do some further multi inits */
   events_setup(multi, &evs);
   events_setup(multi, &evs);
@@ -670,7 +672,7 @@ static CURLcode easy_transfer(struct Curl_multi *multi)
   bool done = FALSE;
   bool done = FALSE;
   CURLMcode mcode = CURLM_OK;
   CURLMcode mcode = CURLM_OK;
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
-  struct timeval before;
+  struct curltime before;
   int without_fds = 0;  /* count number of consecutive returns from
   int without_fds = 0;  /* count number of consecutive returns from
                            curl_multi_wait() without any filedescriptors */
                            curl_multi_wait() without any filedescriptors */
 
 
@@ -683,7 +685,7 @@ static CURLcode easy_transfer(struct Curl_multi *multi)
 
 
     if(!mcode) {
     if(!mcode) {
       if(!rc) {
       if(!rc) {
-        struct timeval after = curlx_tvnow();
+        struct curltime after = curlx_tvnow();
 
 
         /* If it returns without any filedescriptor instantly, we need to
         /* If it returns without any filedescriptor instantly, we need to
            avoid busy-looping during periods where it has nothing particular
            avoid busy-looping during periods where it has nothing particular
@@ -1025,13 +1027,13 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action)
     struct tempbuf writebuf[3]; /* there can only be three */
     struct tempbuf writebuf[3]; /* there can only be three */
 
 
     /* copy the structs to allow for immediate re-pausing */
     /* copy the structs to allow for immediate re-pausing */
-    for(i=0; i < data->state.tempcount; i++) {
+    for(i = 0; i < data->state.tempcount; i++) {
       writebuf[i] = data->state.tempwrite[i];
       writebuf[i] = data->state.tempwrite[i];
       data->state.tempwrite[i].buf = NULL;
       data->state.tempwrite[i].buf = NULL;
     }
     }
     data->state.tempcount = 0;
     data->state.tempcount = 0;
 
 
-    for(i=0; i < count; i++) {
+    for(i = 0; i < count; i++) {
       /* even if one function returns error, this loops through and frees all
       /* even if one function returns error, this loops through and frees all
          buffers */
          buffers */
       if(!result)
       if(!result)

+ 13 - 13
Utilities/cmcurl/lib/escape.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -84,14 +84,14 @@ char *curl_easy_escape(struct Curl_easy *data, const char *string,
   char *testing_ptr = NULL;
   char *testing_ptr = NULL;
   unsigned char in; /* we need to treat the characters unsigned */
   unsigned char in; /* we need to treat the characters unsigned */
   size_t newlen;
   size_t newlen;
-  size_t strindex=0;
+  size_t strindex = 0;
   size_t length;
   size_t length;
   CURLcode result;
   CURLcode result;
 
 
   if(inlength < 0)
   if(inlength < 0)
     return NULL;
     return NULL;
 
 
-  alloc = (inlength?(size_t)inlength:strlen(string))+1;
+  alloc = (inlength?(size_t)inlength:strlen(string)) + 1;
   newlen = alloc;
   newlen = alloc;
 
 
   ns = malloc(alloc);
   ns = malloc(alloc);
@@ -104,7 +104,7 @@ char *curl_easy_escape(struct Curl_easy *data, const char *string,
 
 
     if(Curl_isunreserved(in))
     if(Curl_isunreserved(in))
       /* just copy this */
       /* just copy this */
-      ns[strindex++]=in;
+      ns[strindex++] = in;
     else {
     else {
       /* encode it */
       /* encode it */
       newlen += 2; /* the size grows with two, since this'll become a %XX */
       newlen += 2; /* the size grows with two, since this'll become a %XX */
@@ -116,7 +116,7 @@ char *curl_easy_escape(struct Curl_easy *data, const char *string,
         ns = testing_ptr;
         ns = testing_ptr;
       }
       }
 
 
-      result = Curl_convert_to_network(data, &in, 1);
+      result = Curl_convert_to_network(data, (char *)&in, 1);
       if(result) {
       if(result) {
         /* Curl_convert_to_network calls failf if unsuccessful */
         /* Curl_convert_to_network calls failf if unsuccessful */
         free(ns);
         free(ns);
@@ -125,11 +125,11 @@ char *curl_easy_escape(struct Curl_easy *data, const char *string,
 
 
       snprintf(&ns[strindex], 4, "%%%02X", in);
       snprintf(&ns[strindex], 4, "%%%02X", in);
 
 
-      strindex+=3;
+      strindex += 3;
     }
     }
     string++;
     string++;
   }
   }
-  ns[strindex]=0; /* terminate it */
+  ns[strindex] = 0; /* terminate it */
   return ns;
   return ns;
 }
 }
 
 
@@ -148,10 +148,10 @@ CURLcode Curl_urldecode(struct Curl_easy *data,
                         char **ostring, size_t *olen,
                         char **ostring, size_t *olen,
                         bool reject_ctrl)
                         bool reject_ctrl)
 {
 {
-  size_t alloc = (length?length:strlen(string))+1;
+  size_t alloc = (length?length:strlen(string)) + 1;
   char *ns = malloc(alloc);
   char *ns = malloc(alloc);
   unsigned char in;
   unsigned char in;
-  size_t strindex=0;
+  size_t strindex = 0;
   unsigned long hex;
   unsigned long hex;
   CURLcode result;
   CURLcode result;
 
 
@@ -173,15 +173,15 @@ CURLcode Curl_urldecode(struct Curl_easy *data,
 
 
       in = curlx_ultouc(hex); /* this long is never bigger than 255 anyway */
       in = curlx_ultouc(hex); /* this long is never bigger than 255 anyway */
 
 
-      result = Curl_convert_from_network(data, &in, 1);
+      result = Curl_convert_from_network(data, (char *)&in, 1);
       if(result) {
       if(result) {
         /* Curl_convert_from_network calls failf if unsuccessful */
         /* Curl_convert_from_network calls failf if unsuccessful */
         free(ns);
         free(ns);
         return result;
         return result;
       }
       }
 
 
-      string+=2;
-      alloc-=2;
+      string += 2;
+      alloc -= 2;
     }
     }
 
 
     if(reject_ctrl && (in < 0x20)) {
     if(reject_ctrl && (in < 0x20)) {
@@ -192,7 +192,7 @@ CURLcode Curl_urldecode(struct Curl_easy *data,
     ns[strindex++] = in;
     ns[strindex++] = in;
     string++;
     string++;
   }
   }
-  ns[strindex]=0; /* terminate it */
+  ns[strindex] = 0; /* terminate it */
 
 
   if(olen)
   if(olen)
     /* store output size */
     /* store output size */

+ 24 - 18
Utilities/cmcurl/lib/file.c

@@ -108,6 +108,7 @@ const struct Curl_handler Curl_handler_file = {
   ZERO_NULL,                            /* perform_getsock */
   ZERO_NULL,                            /* perform_getsock */
   file_disconnect,                      /* disconnect */
   file_disconnect,                      /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
   0,                                    /* defport */
   0,                                    /* defport */
   CURLPROTO_FILE,                       /* protocol */
   CURLPROTO_FILE,                       /* protocol */
   PROTOPT_NONETWORK | PROTOPT_NOURLQUERY /* flags */
   PROTOPT_NONETWORK | PROTOPT_NOURLQUERY /* flags */
@@ -132,37 +133,42 @@ static CURLcode file_setup_connection(struct connectdata *conn)
 static CURLcode file_range(struct connectdata *conn)
 static CURLcode file_range(struct connectdata *conn)
 {
 {
   curl_off_t from, to;
   curl_off_t from, to;
-  curl_off_t totalsize=-1;
+  curl_off_t totalsize = -1;
   char *ptr;
   char *ptr;
   char *ptr2;
   char *ptr2;
   struct Curl_easy *data = conn->data;
   struct Curl_easy *data = conn->data;
 
 
   if(data->state.use_range && data->state.range) {
   if(data->state.use_range && data->state.range) {
-    from=curlx_strtoofft(data->state.range, &ptr, 0);
-    while(*ptr && (ISSPACE(*ptr) || (*ptr=='-')))
+    CURLofft from_t;
+    CURLofft to_t;
+    from_t = curlx_strtoofft(data->state.range, &ptr, 0, &from);
+    if(from_t == CURL_OFFT_FLOW)
+      return CURLE_RANGE_ERROR;
+    while(*ptr && (ISSPACE(*ptr) || (*ptr == '-')))
       ptr++;
       ptr++;
-    to=curlx_strtoofft(ptr, &ptr2, 0);
-    if(ptr == ptr2) {
-      /* we didn't get any digit */
-      to=-1;
-    }
-    if((-1 == to) && (from>=0)) {
+    to_t = curlx_strtoofft(ptr, &ptr2, 0, &to);
+    if(to_t == CURL_OFFT_FLOW)
+      return CURLE_RANGE_ERROR;
+    if((to_t == CURL_OFFT_INVAL) && !from_t) {
       /* X - */
       /* X - */
       data->state.resume_from = from;
       data->state.resume_from = from;
       DEBUGF(infof(data, "RANGE %" CURL_FORMAT_CURL_OFF_T " to end of file\n",
       DEBUGF(infof(data, "RANGE %" CURL_FORMAT_CURL_OFF_T " to end of file\n",
                    from));
                    from));
     }
     }
-    else if(from < 0) {
+    else if((from_t == CURL_OFFT_INVAL) && !to_t) {
       /* -Y */
       /* -Y */
-      data->req.maxdownload = -from;
-      data->state.resume_from = from;
+      data->req.maxdownload = to;
+      data->state.resume_from = -to;
       DEBUGF(infof(data, "RANGE the last %" CURL_FORMAT_CURL_OFF_T " bytes\n",
       DEBUGF(infof(data, "RANGE the last %" CURL_FORMAT_CURL_OFF_T " bytes\n",
-                   -from));
+                   to));
     }
     }
     else {
     else {
       /* X-Y */
       /* X-Y */
       totalsize = to-from;
       totalsize = to-from;
-      data->req.maxdownload = totalsize+1; /* include last byte */
+      if(totalsize == CURL_OFF_T_MAX)
+        /* this is too big to increase, so bail out */
+        return CURLE_RANGE_ERROR;
+      data->req.maxdownload = totalsize + 1; /* include last byte */
       data->state.resume_from = from;
       data->state.resume_from = from;
       DEBUGF(infof(data, "RANGE from %" CURL_FORMAT_CURL_OFF_T
       DEBUGF(infof(data, "RANGE from %" CURL_FORMAT_CURL_OFF_T
                    " getting %" CURL_FORMAT_CURL_OFF_T " bytes\n",
                    " getting %" CURL_FORMAT_CURL_OFF_T " bytes\n",
@@ -225,7 +231,7 @@ static CURLcode file_connect(struct connectdata *conn, bool *done)
   }
   }
 
 
   /* change path separators from '/' to '\\' for DOS, Windows and OS/2 */
   /* change path separators from '/' to '\\' for DOS, Windows and OS/2 */
-  for(i=0; i < real_path_len; ++i)
+  for(i = 0; i < real_path_len; ++i)
     if(actual_path[i] == '/')
     if(actual_path[i] == '/')
       actual_path[i] = '\\';
       actual_path[i] = '\\';
     else if(!actual_path[i]) { /* binary zero */
     else if(!actual_path[i]) { /* binary zero */
@@ -427,9 +433,9 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
   struct_stat statbuf; /* struct_stat instead of struct stat just to allow the
   struct_stat statbuf; /* struct_stat instead of struct stat just to allow the
                           Windows version to have a different struct without
                           Windows version to have a different struct without
                           having to redefine the simple word 'stat' */
                           having to redefine the simple word 'stat' */
-  curl_off_t expected_size=0;
+  curl_off_t expected_size = 0;
   bool size_known;
   bool size_known;
-  bool fstated=FALSE;
+  bool fstated = FALSE;
   ssize_t nread;
   ssize_t nread;
   struct Curl_easy *data = conn->data;
   struct Curl_easy *data = conn->data;
   char *buf = data->state.buffer;
   char *buf = data->state.buffer;
@@ -500,7 +506,7 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
              tm->tm_hour,
              tm->tm_hour,
              tm->tm_min,
              tm->tm_min,
              tm->tm_sec);
              tm->tm_sec);
-    result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
+    result = Curl_client_write(conn, CLIENTWRITE_BOTH, header, 0);
     if(!result)
     if(!result)
       /* set the file size to make it available post transfer */
       /* set the file size to make it available post transfer */
       Curl_pgrsSetDownloadSize(data, expected_size);
       Curl_pgrsSetDownloadSize(data, expected_size);

+ 146 - 741
Utilities/cmcurl/lib/formdata.c

@@ -32,6 +32,8 @@
 
 
 #include "urldata.h" /* for struct Curl_easy */
 #include "urldata.h" /* for struct Curl_easy */
 #include "formdata.h"
 #include "formdata.h"
+#include "mime.h"
+#include "non-ascii.h"
 #include "vtls/vtls.h"
 #include "vtls/vtls.h"
 #include "strcase.h"
 #include "strcase.h"
 #include "sendf.h"
 #include "sendf.h"
@@ -42,13 +44,6 @@
 #include "curl_memory.h"
 #include "curl_memory.h"
 #include "memdebug.h"
 #include "memdebug.h"
 
 
-#ifndef HAVE_BASENAME
-static char *Curl_basename(char *path);
-#define basename(x)  Curl_basename((x))
-#endif
-
-static size_t readfromfile(struct Form *form, char *buffer, size_t size);
-static CURLcode formboundary(struct Curl_easy *data, char *buffer, size_t len);
 
 
 /* What kind of Content-Type to use on un-specified files with unrecognized
 /* What kind of Content-Type to use on un-specified files with unrecognized
    extensions. */
    extensions. */
@@ -197,7 +192,7 @@ static const char *ContentTypeForFilename(const char *filename,
     contenttype = HTTPPOST_CONTENTTYPE_DEFAULT;
     contenttype = HTTPPOST_CONTENTTYPE_DEFAULT;
 
 
   if(filename) { /* in case a NULL was passed in */
   if(filename) { /* in case a NULL was passed in */
-    for(i=0; i<sizeof(ctts)/sizeof(ctts[0]); i++) {
+    for(i = 0; i<sizeof(ctts)/sizeof(ctts[0]); i++) {
       if(strlen(filename) >= strlen(ctts[i].extension)) {
       if(strlen(filename) >= strlen(ctts[i].extension)) {
         if(strcasecompare(filename +
         if(strcasecompare(filename +
                           strlen(filename) - strlen(ctts[i].extension),
                           strlen(filename) - strlen(ctts[i].extension),
@@ -272,7 +267,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
   struct curl_httppost *post = NULL;
   struct curl_httppost *post = NULL;
   CURLformoption option;
   CURLformoption option;
   struct curl_forms *forms = NULL;
   struct curl_forms *forms = NULL;
-  char *array_value=NULL; /* value read from an array */
+  char *array_value = NULL; /* value read from an array */
 
 
   /* This is a state variable, that if TRUE means that we're parsing an
   /* This is a state variable, that if TRUE means that we're parsing an
      array that we got passed to us. If FALSE we're parsing the input
      array that we got passed to us. If FALSE we're parsing the input
@@ -641,15 +636,26 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
         }
         }
         form->contenttype_alloc = TRUE;
         form->contenttype_alloc = TRUE;
       }
       }
+      if(form->name && form->namelength) {
+        /* Name should not contain nul bytes. */
+        size_t i;
+        for(i = 0; i < form->namelength; i++)
+          if(!form->name[i]) {
+            return_value = CURL_FORMADD_NULL;
+            break;
+          }
+        if(return_value != CURL_FORMADD_OK)
+          break;
+      }
       if(!(form->flags & HTTPPOST_PTRNAME) &&
       if(!(form->flags & HTTPPOST_PTRNAME) &&
          (form == first_form) ) {
          (form == first_form) ) {
         /* Note that there's small risk that form->name is NULL here if the
         /* Note that there's small risk that form->name is NULL here if the
            app passed in a bad combo, so we better check for that first. */
            app passed in a bad combo, so we better check for that first. */
         if(form->name) {
         if(form->name) {
-          /* copy name (without strdup; possibly contains null characters) */
+          /* copy name (without strdup; possibly not nul-terminated) */
           form->name = Curl_memdup(form->name, form->namelength?
           form->name = Curl_memdup(form->name, form->namelength?
                                    form->namelength:
                                    form->namelength:
-                                   strlen(form->name)+1);
+                                   strlen(form->name) + 1);
         }
         }
         if(!form->name) {
         if(!form->name) {
           return_value = CURL_FORMADD_MEMORY;
           return_value = CURL_FORMADD_MEMORY;
@@ -663,7 +669,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
         /* copy value (without strdup; possibly contains null characters) */
         /* copy value (without strdup; possibly contains null characters) */
         size_t clen  = (size_t) form->contentslength;
         size_t clen  = (size_t) form->contentslength;
         if(!clen)
         if(!clen)
-          clen = strlen(form->value)+1;
+          clen = strlen(form->value) + 1;
 
 
         form->value = Curl_memdup(form->value, clen);
         form->value = Curl_memdup(form->value, clen);
 
 
@@ -746,211 +752,6 @@ CURLFORMcode curl_formadd(struct curl_httppost **httppost,
   return result;
   return result;
 }
 }
 
 
-#ifdef __VMS
-#include <fabdef.h>
-/*
- * get_vms_file_size does what it takes to get the real size of the file
- *
- * For fixed files, find out the size of the EOF block and adjust.
- *
- * For all others, have to read the entire file in, discarding the contents.
- * Most posted text files will be small, and binary files like zlib archives
- * and CD/DVD images should be either a STREAM_LF format or a fixed format.
- *
- */
-curl_off_t VmsRealFileSize(const char *name,
-                           const struct_stat *stat_buf)
-{
-  char buffer[8192];
-  curl_off_t count;
-  int ret_stat;
-  FILE * file;
-
-  file = fopen(name, FOPEN_READTEXT); /* VMS */
-  if(file == NULL)
-    return 0;
-
-  count = 0;
-  ret_stat = 1;
-  while(ret_stat > 0) {
-    ret_stat = fread(buffer, 1, sizeof(buffer), file);
-    if(ret_stat != 0)
-      count += ret_stat;
-  }
-  fclose(file);
-
-  return count;
-}
-
-/*
- *
- *  VmsSpecialSize checks to see if the stat st_size can be trusted and
- *  if not to call a routine to get the correct size.
- *
- */
-static curl_off_t VmsSpecialSize(const char *name,
-                                 const struct_stat *stat_buf)
-{
-  switch(stat_buf->st_fab_rfm) {
-  case FAB$C_VAR:
-  case FAB$C_VFC:
-    return VmsRealFileSize(name, stat_buf);
-    break;
-  default:
-    return stat_buf->st_size;
-  }
-}
-
-#endif
-
-#ifndef __VMS
-#define filesize(name, stat_data) (stat_data.st_size)
-#else
-    /* Getting the expected file size needs help on VMS */
-#define filesize(name, stat_data) VmsSpecialSize(name, &stat_data)
-#endif
-
-/*
- * AddFormData() adds a chunk of data to the FormData linked list.
- *
- * size is incremented by the chunk length, unless it is NULL
- */
-static CURLcode AddFormData(struct FormData **formp,
-                            enum formtype type,
-                            const void *line,
-                            curl_off_t length,
-                            curl_off_t *size)
-{
-  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;
-
-  if(type <= FORM_CONTENT) {
-    /* 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
-    if(type != FORM_DATAMEM) {
-      newform->line = malloc((size_t)length+1);
-      if(!newform->line) {
-        result = CURLE_OUT_OF_MEMORY;
-        goto error;
-      }
-      alloc2 = newform->line;
-      memcpy(newform->line, line, (size_t)length);
-
-      /* zero terminate for easier debugging */
-      newform->line[(size_t)length]=0;
-    }
-    else {
-      newform->line = (char *)line;
-      type = FORM_DATA; /* in all other aspects this is just FORM_DATA */
-    }
-    newform->length = (size_t)length;
-  }
-  else
-    /* For callbacks and files we don't have any actual data so we just keep a
-       pointer to whatever this points to */
-    newform->line = (char *)line;
-
-  newform->type = type;
-
-  if(size) {
-    if(type != FORM_FILE)
-      /* for static content as well as callback data we add the size given
-         as input argument */
-      *size += length;
-    else {
-      /* Since this is a file to be uploaded here, add the size of the actual
-         file */
-      if(strcmp("-", newform->line)) {
-        struct_stat file;
-        if(!stat(newform->line, &file) && !S_ISDIR(file.st_mode))
-          *size += filesize(newform->line, file);
-        else {
-          result = CURLE_BAD_FUNCTION_ARGUMENT;
-          goto error;
-        }
-      }
-    }
-  }
-
-  if(*formp) {
-    (*formp)->next = newform;
-    *formp = newform;
-  }
-  else
-    *formp = newform;
-
-  return CURLE_OK;
-  error:
-  if(newform)
-    free(newform);
-  if(alloc2)
-    free(alloc2);
-  return result;
-}
-
-/*
- * AddFormDataf() adds printf()-style formatted data to the formdata chain.
- */
-
-static CURLcode AddFormDataf(struct FormData **formp,
-                             curl_off_t *size,
-                             const char *fmt, ...)
-{
-  char *s;
-  CURLcode result;
-  va_list ap;
-  va_start(ap, fmt);
-  s = curl_mvaprintf(fmt, ap);
-  va_end(ap);
-
-  if(!s)
-    return CURLE_OUT_OF_MEMORY;
-
-  result = AddFormData(formp, FORM_DATAMEM, s, 0, size);
-  if(result)
-    free(s);
-
-  return result;
-}
-
-/*
- * Curl_formclean() is used from http.c, this cleans a built FormData linked
- * list
- */
-void Curl_formclean(struct FormData **form_ptr)
-{
-  struct FormData *next, *form;
-
-  form = *form_ptr;
-  if(!form)
-    return;
-
-  do {
-    next=form->next;  /* the following form line */
-    if(form->type <= FORM_CONTENT)
-      free(form->line); /* free the line */
-    free(form);       /* free the struct */
-    form = next;
-  } while(form); /* continue */
-
-  *form_ptr = NULL;
-}
-
 /*
 /*
  * curl_formget()
  * curl_formget()
  * Serialize a curl_httppost struct.
  * Serialize a curl_httppost struct.
@@ -962,42 +763,34 @@ int curl_formget(struct curl_httppost *form, void *arg,
                  curl_formget_callback append)
                  curl_formget_callback append)
 {
 {
   CURLcode result;
   CURLcode result;
-  curl_off_t size;
-  struct FormData *data, *ptr;
+  curl_mimepart toppart;
 
 
-  result = Curl_getformdata(NULL, &data, form, NULL, &size);
-  if(result)
-    return (int)result;
-
-  for(ptr = data; ptr; ptr = ptr->next) {
-    if((ptr->type == FORM_FILE) || (ptr->type == FORM_CALLBACK)) {
-      char buffer[8192];
-      size_t nread;
-      struct Form temp;
-
-      Curl_FormInit(&temp, ptr);
-
-      do {
-        nread = readfromfile(&temp, buffer, sizeof(buffer));
-        if((nread == (size_t) -1) ||
-           (nread > sizeof(buffer)) ||
-           (nread != append(arg, buffer, nread))) {
-          if(temp.fp)
-            fclose(temp.fp);
-          Curl_formclean(&data);
-          return -1;
-        }
-      } while(nread);
-    }
-    else {
-      if(ptr->length != append(arg, ptr->line, ptr->length)) {
-        Curl_formclean(&data);
-        return -1;
-      }
+  Curl_mime_initpart(&toppart, NULL); /* default form is empty */
+  result = Curl_getformdata(NULL, &toppart, form, NULL);
+  if(!result)
+    result = Curl_mime_prepare_headers(&toppart, "multipart/form-data",
+                                       NULL, MIMESTRATEGY_FORM);
+
+  while(!result) {
+    char buffer[8192];
+    size_t nread = Curl_mime_read(buffer, 1, sizeof buffer, &toppart);
+
+    if(!nread)
+      break;
+
+    switch(nread) {
+    default:
+      if(append(arg, buffer, nread) != nread)
+        result = CURLE_READ_ERROR;
+      break;
+    case CURL_READFUNC_ABORT:
+    case CURL_READFUNC_PAUSE:
+      break;
     }
     }
   }
   }
-  Curl_formclean(&data);
-  return 0;
+
+  Curl_mime_cleanpart(&toppart);
+  return (int) result;
 }
 }
 
 
 /*
 /*
@@ -1013,7 +806,7 @@ void curl_formfree(struct curl_httppost *form)
     return;
     return;
 
 
   do {
   do {
-    next=form->next;  /* the following form line */
+    next = form->next;  /* the following form line */
 
 
     /* recurse to sub-contents */
     /* recurse to sub-contents */
     curl_formfree(form->more);
     curl_formfree(form->more);
@@ -1031,118 +824,29 @@ void curl_formfree(struct curl_httppost *form)
   } while(form); /* continue */
   } while(form); /* continue */
 }
 }
 
 
-#ifndef HAVE_BASENAME
-/*
-  (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004
-  Edition)
-
-  The basename() function shall take the pathname pointed to by path and
-  return a pointer to the final component of the pathname, deleting any
-  trailing '/' characters.
-
-  If the string pointed to by path consists entirely of the '/' character,
-  basename() shall return a pointer to the string "/". If the string pointed
-  to by path is exactly "//", it is implementation-defined whether '/' or "//"
-  is returned.
 
 
-  If path is a null pointer or points to an empty string, basename() shall
-  return a pointer to the string ".".
-
-  The basename() function may modify the string pointed to by path, and may
-  return a pointer to static storage that may then be overwritten by a
-  subsequent call to basename().
-
-  The basename() function need not be reentrant. A function that is not
-  required to be reentrant is not required to be thread-safe.
-
-*/
-static char *Curl_basename(char *path)
+/* Set mime part name, taking care of non nul-terminated name string. */
+static CURLcode setname(curl_mimepart *part, const char *name, size_t len)
 {
 {
-  /* Ignore all the details above for now and make a quick and simple
-     implementaion here */
-  char *s1;
-  char *s2;
-
-  s1=strrchr(path, '/');
-  s2=strrchr(path, '\\');
+  char *zname;
+  CURLcode res;
 
 
-  if(s1 && s2) {
-    path = (s1 > s2? s1 : s2)+1;
-  }
-  else if(s1)
-    path = s1 + 1;
-  else if(s2)
-    path = s2 + 1;
-
-  return path;
-}
-#endif
-
-static char *strippath(const char *fullfile)
-{
-  char *filename;
-  char *base;
-  filename = strdup(fullfile); /* duplicate since basename() may ruin the
-                                  buffer it works on */
-  if(!filename)
-    return NULL;
-  base = strdup(basename(filename));
-
-  free(filename); /* free temporary buffer */
-
-  return base; /* returns an allocated string or NULL ! */
-}
-
-static CURLcode formdata_add_filename(const struct curl_httppost *file,
-                                      struct FormData **form,
-                                      curl_off_t *size)
-{
-  CURLcode result = CURLE_OK;
-  char *filename = file->showfilename;
-  char *filebasename = NULL;
-  char *filename_escaped = NULL;
-
-  if(!filename) {
-    filebasename = strippath(file->contents);
-    if(!filebasename)
-      return CURLE_OUT_OF_MEMORY;
-    filename = filebasename;
-  }
-
-  if(strchr(filename, '\\') || strchr(filename, '"')) {
-    char *p0, *p1;
-
-    /* filename need be escaped */
-    filename_escaped = malloc(strlen(filename)*2+1);
-    if(!filename_escaped) {
-      free(filebasename);
-      return CURLE_OUT_OF_MEMORY;
-    }
-    p0 = filename_escaped;
-    p1 = filename;
-    while(*p1) {
-      if(*p1 == '\\' || *p1 == '"')
-        *p0++ = '\\';
-      *p0++ = *p1++;
-    }
-    *p0 = '\0';
-    filename = filename_escaped;
-  }
-  result = AddFormDataf(form, size,
-                        "; filename=\"%s\"",
-                        filename);
-  free(filename_escaped);
-  free(filebasename);
-  return result;
+  if(!name || !len)
+    return curl_mime_name(part, name);
+  zname = malloc(len + 1);
+  if(!zname)
+    return CURLE_OUT_OF_MEMORY;
+  memcpy(zname, name, len);
+  zname[len] = '\0';
+  res = curl_mime_name(part, zname);
+  free(zname);
+  return res;
 }
 }
 
 
 /*
 /*
- * Curl_getformdata() converts a linked list of "meta data" into a complete
- * (possibly huge) multipart formdata. The input list is in 'post', while the
- * output resulting linked lists gets stored in '*finalform'. *sizep will get
- * the total size of the whole POST.
- * A multipart/form_data content-type is built, unless a custom content-type
- * is passed in 'custom_content_type'.
+ * Curl_getformdata() converts a linked list of "meta data" into a mime
+ * structure. The input list is in 'post', while the output is stored in
+ * mime part at '*finalform'.
  *
  *
  * This function will not do a failf() for the potential memory failures but
  * This function will not do a failf() for the potential memory failures but
  * should for all other errors it spots. Just note that this function MAY get
  * should for all other errors it spots. Just note that this function MAY get
@@ -1150,422 +854,123 @@ static CURLcode formdata_add_filename(const struct curl_httppost *file,
  */
  */
 
 
 CURLcode Curl_getformdata(struct Curl_easy *data,
 CURLcode Curl_getformdata(struct Curl_easy *data,
-                          struct FormData **finalform,
+                          curl_mimepart *finalform,
                           struct curl_httppost *post,
                           struct curl_httppost *post,
-                          const char *custom_content_type,
-                          curl_off_t *sizep)
+                          curl_read_callback fread_func)
 {
 {
-  struct FormData *form = NULL;
-  struct FormData *firstform;
-  struct curl_httppost *file;
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
-  curl_off_t size = 0; /* support potentially ENORMOUS formposts */
-  char fileboundary[42];
-  struct curl_slist *curList;
-  char boundary[42];
+  curl_mime *form = NULL;
+  curl_mime *multipart;
+  curl_mimepart *part;
+  struct curl_httppost *file;
 
 
-  *finalform = NULL; /* default form is empty */
+  Curl_mime_cleanpart(finalform); /* default form is empty */
 
 
   if(!post)
   if(!post)
     return result; /* no input => no output! */
     return result; /* no input => no output! */
 
 
-  result = formboundary(data, boundary, sizeof(boundary));
-  if(result)
-    return result;
-
-  /* Make the first line of the output */
-  result = AddFormDataf(&form, NULL,
-                        "%s; boundary=%s\r\n",
-                        custom_content_type?custom_content_type:
-                        "Content-Type: multipart/form-data",
-                        boundary);
-
-  if(result) {
-    return result;
-  }
-  /* we DO NOT include that line in the total size of the POST, since it'll be
-     part of the header! */
-
-  firstform = form;
-
-  do {
-
-    if(size) {
-      result = AddFormDataf(&form, &size, "\r\n");
-      if(result)
-        break;
-    }
-
-    /* boundary */
-    result = AddFormDataf(&form, &size, "--%s\r\n", boundary);
-    if(result)
-      break;
-
-    /* Maybe later this should be disabled when a custom_content_type is
-       passed, since Content-Disposition is not meaningful for all multipart
-       types.
-    */
-    result = AddFormDataf(&form, &size,
-                          "Content-Disposition: form-data; name=\"");
-    if(result)
-      break;
-
-    result = AddFormData(&form, FORM_DATA, post->name, post->namelength,
-                         &size);
-    if(result)
-      break;
+  form = curl_mime_init(data);
+  if(!form)
+    result = CURLE_OUT_OF_MEMORY;
 
 
-    result = AddFormDataf(&form, &size, "\"");
-    if(result)
-      break;
+  if(!result)
+    result = curl_mime_subparts(finalform, form);
 
 
+  /* Process each top part. */
+  for(; !result && post; post = post->next) {
+    /* If we have more than a file here, create a mime subpart and fill it. */
+    multipart = form;
     if(post->more) {
     if(post->more) {
-      /* If used, this is a link to more file names, we must then do
-         the magic to include several files with the same field name */
-
-      result = formboundary(data, fileboundary, sizeof(fileboundary));
-      if(result) {
-        break;
+      part = curl_mime_addpart(form);
+      if(!part)
+        result = CURLE_OUT_OF_MEMORY;
+      if(!result)
+        result = setname(part, post->name, post->namelength);
+      if(!result) {
+        multipart = curl_mime_init(data);
+        if(!multipart)
+          result = CURLE_OUT_OF_MEMORY;
       }
       }
-
-      result = AddFormDataf(&form, &size,
-                            "\r\nContent-Type: multipart/mixed;"
-                            " boundary=%s\r\n",
-                            fileboundary);
-      if(result)
-        break;
+      if(!result)
+        result = curl_mime_subparts(part, multipart);
     }
     }
 
 
-    file = post;
-
-    do {
-
-      /* If 'showfilename' is set, that is a faked name passed on to us
-         to use to in the formpost. If that is not set, the actually used
-         local file name should be added. */
-
-      if(post->more) {
-        /* if multiple-file */
-        result = AddFormDataf(&form, &size,
-                              "\r\n--%s\r\nContent-Disposition: "
-                              "attachment",
-                              fileboundary);
-        if(result)
-          break;
-        result = formdata_add_filename(file, &form, &size);
-        if(result)
-          break;
-      }
-      else if(post->flags & (HTTPPOST_FILENAME|HTTPPOST_BUFFER|
-                             HTTPPOST_CALLBACK)) {
-        /* it should be noted that for the HTTPPOST_FILENAME and
-           HTTPPOST_CALLBACK cases the ->showfilename struct member is always
-           assigned at this point */
-        if(post->showfilename || (post->flags & HTTPPOST_FILENAME)) {
-          result = formdata_add_filename(post, &form, &size);
-        }
+    /* Generate all the part contents. */
+    for(file = post; !result && file; file = file->more) {
+      /* Create the part. */
+      part = curl_mime_addpart(multipart);
+      if(!part)
+        result = CURLE_OUT_OF_MEMORY;
 
 
-        if(result)
-          break;
-      }
+      /* Set the headers. */
+      if(!result)
+        result = curl_mime_headers(part, file->contentheader, 0);
 
 
-      if(file->contenttype) {
-        /* we have a specified type */
-        result = AddFormDataf(&form, &size,
-                              "\r\nContent-Type: %s",
-                              file->contenttype);
-        if(result)
-          break;
-      }
+      /* Set the content type. */
+      if(!result &&file->contenttype)
+        result = curl_mime_type(part, file->contenttype);
 
 
-      curList = file->contentheader;
-      while(curList) {
-        /* Process the additional headers specified for this form */
-        result = AddFormDataf(&form, &size, "\r\n%s", curList->data);
-        if(result)
-          break;
-        curList = curList->next;
-      }
-      if(result)
-        break;
+      /* Set field name. */
+      if(!result && !post->more)
+        result = setname(part, post->name, post->namelength);
 
 
-      result = AddFormDataf(&form, &size, "\r\n\r\n");
-      if(result)
-        break;
+      /* Process contents. */
+      if(!result) {
+        curl_off_t clen = post->contentslength;
 
 
-      if((post->flags & HTTPPOST_FILENAME) ||
-         (post->flags & HTTPPOST_READFILE)) {
-        /* we should include the contents from the specified file */
-        FILE *fileread;
-
-        fileread = !strcmp("-", file->contents)?
-          stdin:fopen(file->contents, "rb"); /* binary read for win32  */
-
-        /*
-         * VMS: This only allows for stream files on VMS.  Stream files are
-         * OK, as are FIXED & VAR files WITHOUT implied CC For implied CC,
-         * every record needs to have a \n appended & 1 added to SIZE
-         */
-
-        if(fileread) {
-          if(fileread != stdin) {
-            /* close the file */
-            fclose(fileread);
-            /* add the file name only - for later reading from this */
-            result = AddFormData(&form, FORM_FILE, file->contents, 0, &size);
-          }
-          else {
-            /* When uploading from stdin, we can't know the size of the file,
-             * thus must read the full file as before. We *could* use chunked
-             * transfer-encoding, but that only works for HTTP 1.1 and we
-             * can't be sure we work with such a server.
-             */
-            size_t nread;
-            char buffer[512];
-            while((nread = fread(buffer, 1, sizeof(buffer), fileread)) != 0) {
-              result = AddFormData(&form, FORM_CONTENT, buffer, nread, &size);
-              if(result || feof(fileread) || ferror(fileread))
-                break;
-            }
+        if(post->flags & CURL_HTTPPOST_LARGE)
+          clen = post->contentlen;
+        if(!clen)
+          clen = -1;
+
+        if(post->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE)) {
+          if(!strcmp(file->contents, "-")) {
+            /* There are a few cases where the code below won't work; in
+               particular, freopen(stdin) by the caller is not guaranteed
+               to result as expected. This feature has been kept for backward
+               compatibility: use of "-" pseudo file name should be avoided. */
+            result = curl_mime_data_cb(part, (curl_off_t) -1,
+                                       (curl_read_callback) fread,
+                                       (curl_seek_callback) fseek,
+                                       NULL, (void *) stdin);
           }
           }
+          else
+            result = curl_mime_filedata(part, file->contents);
+          if(!result && (post->flags & HTTPPOST_READFILE))
+            result = curl_mime_filename(part, NULL);
         }
         }
+        else if(post->flags & HTTPPOST_BUFFER)
+          result = curl_mime_data(part, post->buffer,
+                                  post->bufferlength? post->bufferlength: -1);
+        else if(post->flags & HTTPPOST_CALLBACK)
+          /* the contents should be read with the callback and the size is set
+             with the contentslength */
+          result = curl_mime_data_cb(part, clen,
+                                     fread_func, NULL, NULL, post->userp);
         else {
         else {
-          if(data)
-            failf(data, "couldn't open file \"%s\"", file->contents);
-          *finalform = NULL;
-          result = CURLE_READ_ERROR;
+          result = curl_mime_data(part, post->contents, (ssize_t) clen);
+#ifdef CURL_DOES_CONVERSIONS
+          /* Convert textual contents now. */
+          if(!result && data && part->datasize)
+            result = Curl_convert_to_network(data, part->data, part->datasize);
+#endif
         }
         }
       }
       }
-      else if(post->flags & HTTPPOST_BUFFER)
-        /* include contents of buffer */
-        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 */
-        result = AddFormData(&form, FORM_CALLBACK, post->userp,
-                             post->flags&CURL_HTTPPOST_LARGE?
-                             post->contentlen:post->contentslength, &size);
-      else
-        /* include the contents we got */
-        result = AddFormData(&form, FORM_CONTENT, post->contents,
-                             post->flags&CURL_HTTPPOST_LARGE?
-                             post->contentlen:post->contentslength, &size);
-      file = file->more;
-    } while(file && !result); /* for each specified file for this field */
-
-    if(result)
-      break;
 
 
-    if(post->more) {
-      /* this was a multiple-file inclusion, make a termination file
-         boundary: */
-      result = AddFormDataf(&form, &size,
-                           "\r\n--%s--",
-                           fileboundary);
-      if(result)
-        break;
+      /* Set fake file name. */
+      if(!result && post->showfilename)
+        if(post->more || (post->flags & (HTTPPOST_FILENAME | HTTPPOST_BUFFER |
+                                        HTTPPOST_CALLBACK)))
+          result = curl_mime_filename(part, post->showfilename);
     }
     }
-    post = post->next;
-  } while(post); /* for each field */
-
-  /* end-boundary for everything */
-  if(!result)
-    result = AddFormDataf(&form, &size, "\r\n--%s--\r\n", boundary);
-
-  if(result) {
-    Curl_formclean(&firstform);
-    return result;
   }
   }
 
 
-  *sizep = size;
-  *finalform = firstform;
+  if(result)
+    Curl_mime_cleanpart(finalform);
 
 
   return result;
   return result;
 }
 }
 
 
-/*
- * 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)
-{
-  if(!formdata)
-    return 1; /* error */
-
-  form->data = formdata;
-  form->sent = 0;
-  form->fp = NULL;
-  form->fread_func = ZERO_NULL;
-
-  return 0;
-}
-
-#ifndef __VMS
-# define fopen_read fopen
-#else
-  /*
-   * vmsfopenread
-   *
-   * For upload to work as expected on VMS, different optional
-   * parameters must be added to the fopen command based on
-   * record format of the file.
-   *
-   */
-# define fopen_read vmsfopenread
-static FILE * vmsfopenread(const char *file, const char *mode)
-{
-  struct_stat statbuf;
-  int result;
-
-  result = stat(file, &statbuf);
-
-  switch(statbuf.st_fab_rfm) {
-  case FAB$C_VAR:
-  case FAB$C_VFC:
-  case FAB$C_STMCR:
-    return fopen(file, FOPEN_READTEXT); /* VMS */
-    break;
-  default:
-    return fopen(file, FOPEN_READTEXT, "rfm=stmlf", "ctx=stm");
-  }
-}
-#endif
-
-/*
- * readfromfile()
- *
- * The read callback that this function may use can return a value larger than
- * 'size' (which then this function returns) that indicates a problem and it
- * must be properly dealt with
- */
-static size_t readfromfile(struct Form *form, char *buffer,
-                           size_t size)
-{
-  size_t nread;
-  bool callback = (form->data->type == FORM_CALLBACK)?TRUE:FALSE;
-
-  if(callback) {
-    if(form->fread_func == ZERO_NULL)
-      return 0;
-    nread = form->fread_func(buffer, 1, size, form->data->line);
-  }
-  else {
-    if(!form->fp) {
-      /* this file hasn't yet been opened */
-      form->fp = fopen_read(form->data->line, "rb"); /* b is for binary */
-      if(!form->fp)
-        return (size_t)-1; /* failure */
-    }
-    nread = fread(buffer, 1, size, form->fp);
-  }
-  if(!nread) {
-    /* this is the last chunk from the file, move on */
-    if(form->fp) {
-      fclose(form->fp);
-      form->fp = NULL;
-    }
-    form->data = form->data->next;
-  }
-
-  return nread;
-}
-
-/*
- * Curl_FormReader() is the fread() emulation function that will be used to
- * deliver the formdata to the transfer loop and then sent away to the peer.
- */
-size_t Curl_FormReader(char *buffer,
-                       size_t size,
-                       size_t nitems,
-                       FILE *mydata)
-{
-  struct Form *form;
-  size_t wantedsize;
-  size_t gotsize = 0;
-
-  form=(struct Form *)mydata;
-
-  wantedsize = size * nitems;
-
-  if(!form->data)
-    return 0; /* nothing, error, empty */
-
-  if((form->data->type == FORM_FILE) ||
-     (form->data->type == FORM_CALLBACK)) {
-    gotsize = readfromfile(form, buffer, wantedsize);
-
-    if(gotsize)
-      /* If positive or -1, return. If zero, continue! */
-      return gotsize;
-  }
-  do {
-
-    if((form->data->length - form->sent) > wantedsize - gotsize) {
-
-      memcpy(buffer + gotsize, form->data->line + form->sent,
-             wantedsize - gotsize);
-
-      form->sent += wantedsize-gotsize;
-
-      return wantedsize;
-    }
-
-    memcpy(buffer+gotsize,
-           form->data->line + form->sent,
-           (form->data->length - form->sent) );
-    gotsize += form->data->length - form->sent;
-
-    form->sent = 0;
-
-    form->data = form->data->next; /* advance */
-
-  } while(form->data && (form->data->type < FORM_CALLBACK));
-  /* If we got an empty line and we have more data, we proceed to the next
-     line immediately to avoid returning zero before we've reached the end. */
-
-  return gotsize;
-}
-
-/*
- * Curl_formpostheader() returns the first line of the formpost, the
- * request-header part (which is not part of the request-body like the rest of
- * the post).
- */
-char *Curl_formpostheader(void *formp, size_t *len)
-{
-  char *header;
-  struct Form *form=(struct Form *)formp;
-
-  if(!form->data)
-    return NULL; /* nothing, ERROR! */
-
-  header = form->data->line;
-  *len = form->data->length;
-
-  form->data = form->data->next; /* advance */
-
-  return header;
-}
-
-/*
- * formboundary() creates a suitable boundary string and returns an allocated
- * one.
- */
-static CURLcode formboundary(struct Curl_easy *data,
-                             char *buffer, size_t buflen)
-{
-  /* 24 dashes and 16 hexadecimal digits makes 64 bit (18446744073709551615)
-     combinations */
-  if(buflen < 41)
-    return CURLE_BAD_FUNCTION_ARGUMENT;
-
-  memset(buffer, '-', 24);
-  Curl_rand_hex(data, (unsigned char *)&buffer[24], 17);
-
-  return CURLE_OK;
-}
-
 #else  /* CURL_DISABLE_HTTP */
 #else  /* CURL_DISABLE_HTTP */
 CURLFORMcode curl_formadd(struct curl_httppost **httppost,
 CURLFORMcode curl_formadd(struct curl_httppost **httppost,
                           struct curl_httppost **last_post,
                           struct curl_httppost **last_post,

+ 3 - 51
Utilities/cmcurl/lib/formdata.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -22,32 +22,6 @@
  *
  *
  ***************************************************************************/
  ***************************************************************************/
 
 
-enum formtype {
-  FORM_DATAMEM, /* already allocated FORM_DATA memory */
-  FORM_DATA,    /* form metadata (convert to network encoding if necessary) */
-  FORM_CONTENT, /* form content  (never convert) */
-  FORM_CALLBACK, /* 'line' points to the custom pointer we pass to the callback
-                  */
-  FORM_FILE     /* 'line' points to a file name we should read from
-                   to create the form data (never convert) */
-};
-
-/* plain and simple linked list with lines to send */
-struct FormData {
-  struct FormData *next;
-  enum formtype type;
-  char *line;
-  size_t length;
-};
-
-struct Form {
-  struct FormData *data; /* current form line to send */
-  size_t sent;           /* number of bytes of the current line that has
-                            already been sent in a previous invoke */
-  FILE *fp;              /* file to read from */
-  curl_read_callback fread_func; /* fread callback pointer */
-};
-
 /* used by FormAdd for temporary storage */
 /* used by FormAdd for temporary storage */
 typedef struct FormInfo {
 typedef struct FormInfo {
   char *name;
   char *name;
@@ -69,31 +43,9 @@ typedef struct FormInfo {
   struct FormInfo *more;
   struct FormInfo *more;
 } FormInfo;
 } FormInfo;
 
 
-int Curl_FormInit(struct Form *form, struct FormData *formdata);
-
 CURLcode Curl_getformdata(struct Curl_easy *data,
 CURLcode Curl_getformdata(struct Curl_easy *data,
-                          struct FormData **,
+                          curl_mimepart *,
                           struct curl_httppost *post,
                           struct curl_httppost *post,
-                          const char *custom_contenttype,
-                          curl_off_t *size);
-
-/* fread() emulation */
-size_t Curl_FormReader(char *buffer,
-                       size_t size,
-                       size_t nitems,
-                       FILE *mydata);
-
-/*
- * Curl_formpostheader() returns the first line of the formpost, the
- * request-header part (which is not part of the request-body like the rest of
- * the post).
- */
-char *Curl_formpostheader(void *formp, size_t *len);
-
-char *Curl_FormBoundary(void);
-
-void Curl_formclean(struct FormData **);
-
-CURLcode Curl_formconvert(struct Curl_easy *, struct FormData *);
+                          curl_read_callback fread_func);
 
 
 #endif /* HEADER_CURL_FORMDATA_H */
 #endif /* HEADER_CURL_FORMDATA_H */

+ 107 - 171
Utilities/cmcurl/lib/ftp.c

@@ -178,10 +178,11 @@ const struct Curl_handler Curl_handler_ftp = {
   ZERO_NULL,                       /* perform_getsock */
   ZERO_NULL,                       /* perform_getsock */
   ftp_disconnect,                  /* disconnect */
   ftp_disconnect,                  /* disconnect */
   ZERO_NULL,                       /* readwrite */
   ZERO_NULL,                       /* readwrite */
+  ZERO_NULL,                       /* connection_check */
   PORT_FTP,                        /* defport */
   PORT_FTP,                        /* defport */
   CURLPROTO_FTP,                   /* protocol */
   CURLPROTO_FTP,                   /* protocol */
-  PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD
-  | PROTOPT_NOURLQUERY /* flags */
+  PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD |
+  PROTOPT_NOURLQUERY | PROTOPT_PROXY_AS_HTTP /* flags */
 };
 };
 
 
 
 
@@ -205,6 +206,7 @@ const struct Curl_handler Curl_handler_ftps = {
   ZERO_NULL,                       /* perform_getsock */
   ZERO_NULL,                       /* perform_getsock */
   ftp_disconnect,                  /* disconnect */
   ftp_disconnect,                  /* disconnect */
   ZERO_NULL,                       /* readwrite */
   ZERO_NULL,                       /* readwrite */
+  ZERO_NULL,                       /* connection_check */
   PORT_FTPS,                       /* defport */
   PORT_FTPS,                       /* defport */
   CURLPROTO_FTPS,                  /* protocol */
   CURLPROTO_FTPS,                  /* protocol */
   PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION |
   PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION |
@@ -212,59 +214,6 @@ const struct Curl_handler Curl_handler_ftps = {
 };
 };
 #endif
 #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)
 static void close_secondarysocket(struct connectdata *conn)
 {
 {
   if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
   if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
@@ -272,7 +221,6 @@ static void close_secondarysocket(struct connectdata *conn)
     conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
     conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
   }
   }
   conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
   conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
-  conn->tunnel_state[SECONDARYSOCKET] = TUNNEL_INIT;
 }
 }
 
 
 /*
 /*
@@ -291,9 +239,9 @@ static void freedirs(struct ftp_conn *ftpc)
 {
 {
   int i;
   int i;
   if(ftpc->dirs) {
   if(ftpc->dirs) {
-    for(i=0; i < ftpc->dirdepth; i++) {
+    for(i = 0; i < ftpc->dirdepth; i++) {
       free(ftpc->dirs[i]);
       free(ftpc->dirs[i]);
-      ftpc->dirs[i]=NULL;
+      ftpc->dirs[i] = NULL;
     }
     }
     free(ftpc->dirs);
     free(ftpc->dirs);
     ftpc->dirs = NULL;
     ftpc->dirs = NULL;
@@ -340,7 +288,7 @@ static CURLcode AcceptServerConnect(struct connectdata *conn)
   if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) {
   if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) {
     size = sizeof(add);
     size = sizeof(add);
 
 
-    s=accept(sock, (struct sockaddr *) &add, &size);
+    s = accept(sock, (struct sockaddr *) &add, &size);
   }
   }
   Curl_closesocket(conn, sock); /* close the first socket */
   Curl_closesocket(conn, sock); /* close the first socket */
 
 
@@ -388,7 +336,7 @@ static time_t ftp_timeleft_accept(struct Curl_easy *data)
 {
 {
   time_t timeout_ms = DEFAULT_ACCEPT_TIMEOUT;
   time_t timeout_ms = DEFAULT_ACCEPT_TIMEOUT;
   time_t other;
   time_t other;
-  struct timeval now;
+  struct curltime now;
 
 
   if(data->set.accepttimeout > 0)
   if(data->set.accepttimeout > 0)
     timeout_ms = data->set.accepttimeout;
     timeout_ms = data->set.accepttimeout;
@@ -509,7 +457,7 @@ static CURLcode InitiateTransfer(struct connectdata *conn)
   }
   }
 
 
   if(conn->proto.ftpc.state_saved == FTP_STOR) {
   if(conn->proto.ftpc.state_saved == FTP_STOR) {
-    *(ftp->bytecountp)=0;
+    *(ftp->bytecountp) = 0;
 
 
     /* When we know we're uploading a specified file, we can get the file
     /* When we know we're uploading a specified file, we can get the file
        size prior to the actual upload. */
        size prior to the actual upload. */
@@ -644,7 +592,7 @@ static CURLcode ftp_readresp(curl_socket_t sockfd,
 #endif
 #endif
 
 
   /* store the latest code for later retrieval */
   /* store the latest code for later retrieval */
-  data->info.httpcode=code;
+  data->info.httpcode = code;
 
 
   if(ftpcode)
   if(ftpcode)
     *ftpcode = code;
     *ftpcode = code;
@@ -692,8 +640,8 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   struct pingpong *pp = &ftpc->pp;
   struct pingpong *pp = &ftpc->pp;
   size_t nread;
   size_t nread;
-  int cache_skip=0;
-  int value_to_be_ignored=0;
+  int cache_skip = 0;
+  int value_to_be_ignored = 0;
 
 
   if(ftpcode)
   if(ftpcode)
     *ftpcode = 0; /* 0 for errors */
     *ftpcode = 0; /* 0 for errors */
@@ -701,13 +649,13 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
     /* make the pointer point to something for the rest of this function */
     /* make the pointer point to something for the rest of this function */
     ftpcode = &value_to_be_ignored;
     ftpcode = &value_to_be_ignored;
 
 
-  *nreadp=0;
+  *nreadp = 0;
 
 
   while(!*ftpcode && !result) {
   while(!*ftpcode && !result) {
     /* check and reset timeout value every lap */
     /* check and reset timeout value every lap */
     timeout = Curl_pp_state_timeout(pp);
     timeout = Curl_pp_state_timeout(pp);
 
 
-    if(timeout <=0) {
+    if(timeout <= 0) {
       failf(data, "FTP response timeout");
       failf(data, "FTP response timeout");
       return CURLE_OPERATION_TIMEDOUT; /* already too little time */
       return CURLE_OPERATION_TIMEDOUT; /* already too little time */
     }
     }
@@ -765,7 +713,7 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
     else
     else
       /* when we got data or there is no cache left, we reset the cache skip
       /* when we got data or there is no cache left, we reset the cache skip
          counter */
          counter */
-      cache_skip=0;
+      cache_skip = 0;
 
 
     *nreadp += nread;
     *nreadp += nread;
 
 
@@ -900,7 +848,7 @@ static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
       int i;
       int i;
       /* PORT is used to tell the server to connect to us, and during that we
       /* 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 */
          don't do happy eyeballs, but we do if we connect to the server */
-      for(s=1, i=0; i<2; i++) {
+      for(s = 1, i = 0; i<2; i++) {
         if(conn->tempsock[i] != CURL_SOCKET_BAD) {
         if(conn->tempsock[i] != CURL_SOCKET_BAD) {
           socks[s] = conn->tempsock[i];
           socks[s] = conn->tempsock[i];
           bits |= GETSOCK_WRITESOCK(s++);
           bits |= GETSOCK_WRITESOCK(s++);
@@ -937,23 +885,26 @@ static CURLcode ftp_state_cwd(struct connectdata *conn)
     /* count3 is set to allow a MKD to fail once. In the case when first CWD
     /* 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
        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 */
        dir) this then allows for a second try to CWD to it */
-    ftpc->count3 = (conn->data->set.ftp_create_missing_dirs==2)?1:0;
+    ftpc->count3 = (conn->data->set.ftp_create_missing_dirs == 2)?1:0;
 
 
-    if(conn->bits.reuse && ftpc->entrypath) {
+    if((conn->data->set.ftp_filemethod == FTPFILE_NOCWD) && !ftpc->cwdcount)
+      /* No CWD necessary */
+      result = ftp_state_mdtm(conn);
+    else if(conn->bits.reuse && ftpc->entrypath) {
       /* This is a re-used connection. Since we change directory to where the
       /* 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
          transfer is taking place, we must first get back to the original dir
          where we ended up after login: */
          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 */
+      ftpc->cwdcount = 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);
       PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->entrypath);
       state(conn, FTP_CWD);
       state(conn, FTP_CWD);
     }
     }
     else {
     else {
       if(ftpc->dirdepth) {
       if(ftpc->dirdepth) {
-        ftpc->count1 = 1;
+        ftpc->cwdcount = 1;
         /* issue the first CWD, the rest is sent when the CWD responses are
         /* issue the first CWD, the rest is sent when the CWD responses are
            received... */
            received... */
-        PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->dirs[ftpc->count1 -1]);
+        PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->dirs[ftpc->cwdcount -1]);
         state(conn, FTP_CWD);
         state(conn, FTP_CWD);
       }
       }
       else {
       else {
@@ -977,15 +928,15 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
 {
 {
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
-  struct Curl_easy *data=conn->data;
-  curl_socket_t portsock= CURL_SOCKET_BAD;
+  struct Curl_easy *data = conn->data;
+  curl_socket_t portsock = CURL_SOCKET_BAD;
   char myhost[256] = "";
   char myhost[256] = "";
 
 
   struct Curl_sockaddr_storage ss;
   struct Curl_sockaddr_storage ss;
   Curl_addrinfo *res, *ai;
   Curl_addrinfo *res, *ai;
   curl_socklen_t sslen;
   curl_socklen_t sslen;
   char hbuf[NI_MAXHOST];
   char hbuf[NI_MAXHOST];
-  struct sockaddr *sa=(struct sockaddr *)&ss;
+  struct sockaddr *sa = (struct sockaddr *)&ss;
   struct sockaddr_in * const sa4 = (void *)sa;
   struct sockaddr_in * const sa4 = (void *)sa;
 #ifdef ENABLE_IPV6
 #ifdef ENABLE_IPV6
   struct sockaddr_in6 * const sa6 = (void *)sa;
   struct sockaddr_in6 * const sa6 = (void *)sa;
@@ -996,7 +947,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
   int error;
   int error;
   char *host = NULL;
   char *host = NULL;
   char *string_ftpport = data->set.str[STRING_FTPPORT];
   char *string_ftpport = data->set.str[STRING_FTPPORT];
-  struct Curl_dns_entry *h=NULL;
+  struct Curl_dns_entry *h = NULL;
   unsigned short port_min = 0;
   unsigned short port_min = 0;
   unsigned short port_max = 0;
   unsigned short port_max = 0;
   unsigned short port;
   unsigned short port;
@@ -1024,7 +975,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
     char *port_start = NULL;
     char *port_start = NULL;
     char *port_sep = NULL;
     char *port_sep = NULL;
 
 
-    addr = calloc(addrlen+1, 1);
+    addr = calloc(addrlen + 1, 1);
     if(!addr)
     if(!addr)
       return CURLE_OUT_OF_MEMORY;
       return CURLE_OUT_OF_MEMORY;
 
 
@@ -1067,7 +1018,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
     if(ip_end != NULL) {
     if(ip_end != NULL) {
       port_start = strchr(ip_end, ':');
       port_start = strchr(ip_end, ':');
       if(port_start) {
       if(port_start) {
-        port_min = curlx_ultous(strtoul(port_start+1, NULL, 10));
+        port_min = curlx_ultous(strtoul(port_start + 1, NULL, 10));
         port_sep = strchr(port_start, '-');
         port_sep = strchr(port_start, '-');
         if(port_sep) {
         if(port_sep) {
           port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10));
           port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10));
@@ -1311,7 +1262,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
       /* translate x.x.x.x to x,x,x,x */
       /* translate x.x.x.x to x,x,x,x */
       while(source && *source) {
       while(source && *source) {
         if(*source == '.')
         if(*source == '.')
-          *dest=',';
+          *dest = ',';
         else
         else
           *dest = *source;
           *dest = *source;
         dest++;
         dest++;
@@ -1518,12 +1469,12 @@ static CURLcode ftp_state_list(struct connectdata *conn)
       return CURLE_OUT_OF_MEMORY;
       return CURLE_OUT_OF_MEMORY;
 
 
     /* Check if path does not end with /, as then we cut off the file part */
     /* Check if path does not end with /, as then we cut off the file part */
-    if(lstArg[strlen(lstArg) - 1] != '/')  {
+    if(lstArg[strlen(lstArg) - 1] != '/') {
 
 
       /* chop off the file part if format is dir/dir/file */
       /* chop off the file part if format is dir/dir/file */
       slashPos = strrchr(lstArg, '/');
       slashPos = strrchr(lstArg, '/');
       if(slashPos)
       if(slashPos)
-        *(slashPos+1) = '\0';
+        *(slashPos + 1) = '\0';
     }
     }
   }
   }
 
 
@@ -1671,7 +1622,7 @@ static CURLcode ftp_state_ul_setup(struct connectdata *conn,
     }
     }
 
 
     if(seekerr != CURL_SEEKFUNC_OK) {
     if(seekerr != CURL_SEEKFUNC_OK) {
-      curl_off_t passed=0;
+      curl_off_t passed = 0;
       if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
       if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
         failf(data, "Could not seek stream");
         failf(data, "Could not seek stream");
         return CURLE_FTP_COULDNT_USE_REST;
         return CURLE_FTP_COULDNT_USE_REST;
@@ -1733,7 +1684,7 @@ static CURLcode ftp_state_quote(struct connectdata *conn,
   struct Curl_easy *data = conn->data;
   struct Curl_easy *data = conn->data;
   struct FTP *ftp = data->req.protop;
   struct FTP *ftp = data->req.protop;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
-  bool quote=FALSE;
+  bool quote = FALSE;
   struct curl_slist *item;
   struct curl_slist *item;
 
 
   switch(instate) {
   switch(instate) {
@@ -1870,11 +1821,11 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
 {
 {
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   CURLcode result;
   CURLcode result;
-  struct Curl_easy *data=conn->data;
-  struct Curl_dns_entry *addr=NULL;
+  struct Curl_easy *data = conn->data;
+  struct Curl_dns_entry *addr = NULL;
   int rc;
   int rc;
   unsigned short connectport; /* the local port connect() should use! */
   unsigned short connectport; /* the local port connect() should use! */
-  char *str=&data->state.buffer[4];  /* start on the first letter */
+  char *str = &data->state.buffer[4];  /* start on the first letter */
 
 
   /* if we come here again, make sure the former name is cleared */
   /* if we come here again, make sure the former name is cleared */
   Curl_safefree(ftpc->newhost);
   Curl_safefree(ftpc->newhost);
@@ -1898,9 +1849,9 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
 
 
         /* The four separators should be identical, or else this is an oddly
         /* The four separators should be identical, or else this is an oddly
            formatted reply and we bail out immediately. */
            formatted reply and we bail out immediately. */
-        for(i=1; i<4; i++) {
+        for(i = 1; i<4; i++) {
           if(separator[i] != sep1) {
           if(separator[i] != sep1) {
-            ptr=NULL; /* set to NULL to signal error */
+            ptr = NULL; /* set to NULL to signal error */
             break;
             break;
           }
           }
         }
         }
@@ -1916,7 +1867,7 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
         }
         }
       }
       }
       else
       else
-        ptr=NULL;
+        ptr = NULL;
     }
     }
     if(!ptr) {
     if(!ptr) {
       failf(data, "Weirdly formatted EPSV reply");
       failf(data, "Weirdly formatted EPSV reply");
@@ -2090,7 +2041,7 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
                                     int ftpcode)
                                     int ftpcode)
 {
 {
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data=conn->data;
+  struct Curl_easy *data = conn->data;
   struct FTP *ftp = data->req.protop;
   struct FTP *ftp = data->req.protop;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
 
 
@@ -2104,7 +2055,7 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
                      &year, &month, &day, &hour, &minute, &second)) {
                      &year, &month, &day, &hour, &minute, &second)) {
         /* we have a time, reformat it */
         /* we have a time, reformat it */
         char timebuf[24];
         char timebuf[24];
-        time_t secs=time(NULL);
+        time_t secs = time(NULL);
 
 
         snprintf(timebuf, sizeof(timebuf),
         snprintf(timebuf, sizeof(timebuf),
                  "%04d%02d%02d %02d:%02d:%02d GMT",
                  "%04d%02d%02d %02d:%02d:%02d GMT",
@@ -2120,7 +2071,7 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
       if(data->set.opt_no_body &&
       if(data->set.opt_no_body &&
          ftpc->file &&
          ftpc->file &&
          data->set.get_filetime &&
          data->set.get_filetime &&
-         (data->info.filetime>=0) ) {
+         (data->info.filetime >= 0) ) {
         char headerbuf[128];
         char headerbuf[128];
         time_t filetime = (time_t)data->info.filetime;
         time_t filetime = (time_t)data->info.filetime;
         struct tm buffer;
         struct tm buffer;
@@ -2196,7 +2147,7 @@ static CURLcode ftp_state_type_resp(struct connectdata *conn,
                                     ftpstate instate)
                                     ftpstate instate)
 {
 {
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data=conn->data;
+  struct Curl_easy *data = conn->data;
 
 
   if(ftpcode/100 != 2) {
   if(ftpcode/100 != 2) {
     /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a
     /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a
@@ -2225,7 +2176,7 @@ static CURLcode ftp_state_retr(struct connectdata *conn,
                                          curl_off_t filesize)
                                          curl_off_t filesize)
 {
 {
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data=conn->data;
+  struct Curl_easy *data = conn->data;
   struct FTP *ftp = data->req.protop;
   struct FTP *ftp = data->req.protop;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
 
 
@@ -2308,12 +2259,14 @@ static CURLcode ftp_state_size_resp(struct connectdata *conn,
                                     ftpstate instate)
                                     ftpstate instate)
 {
 {
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data=conn->data;
-  curl_off_t filesize;
+  struct Curl_easy *data = conn->data;
+  curl_off_t filesize = -1;
   char *buf = data->state.buffer;
   char *buf = data->state.buffer;
 
 
   /* get the size from the ascii string: */
   /* get the size from the ascii string: */
-  filesize = (ftpcode == 213)?curlx_strtoofft(buf+4, NULL, 0):-1;
+  if(ftpcode == 213)
+    /* ignores parsing errors, which will make the size remain unknown */
+    (void)curlx_strtoofft(buf + 4, NULL, 0, &filesize);
 
 
   if(instate == FTP_SIZE) {
   if(instate == FTP_SIZE) {
 #ifdef CURL_FTP_HTTPSTYLE_HEAD
 #ifdef CURL_FTP_HTTPSTYLE_HEAD
@@ -2383,7 +2336,7 @@ static CURLcode ftp_state_stor_resp(struct connectdata *conn,
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
   struct Curl_easy *data = conn->data;
   struct Curl_easy *data = conn->data;
 
 
-  if(ftpcode>=400) {
+  if(ftpcode >= 400) {
     failf(data, "Failed FTP upload: %0d", ftpcode);
     failf(data, "Failed FTP upload: %0d", ftpcode);
     state(conn, FTP_STOP);
     state(conn, FTP_STOP);
     /* oops, we never close the sockets! */
     /* oops, we never close the sockets! */
@@ -2441,7 +2394,7 @@ static CURLcode ftp_state_get_resp(struct connectdata *conn,
       E:
       E:
       125 Data connection already open; Transfer starting. */
       125 Data connection already open; Transfer starting. */
 
 
-    curl_off_t size=-1; /* default unknown size */
+    curl_off_t size = -1; /* default unknown size */
 
 
 
 
     /*
     /*
@@ -2465,9 +2418,9 @@ static CURLcode ftp_state_get_resp(struct connectdata *conn,
        * Example D above makes this parsing a little tricky */
        * Example D above makes this parsing a little tricky */
       char *bytes;
       char *bytes;
       char *buf = data->state.buffer;
       char *buf = data->state.buffer;
-      bytes=strstr(buf, " bytes");
+      bytes = strstr(buf, " bytes");
       if(bytes--) {
       if(bytes--) {
-        long in=(long)(bytes-buf);
+        long in = (long)(bytes-buf);
         /* this is a hint there is size information in there! ;-) */
         /* this is a hint there is size information in there! ;-) */
         while(--in) {
         while(--in) {
           /* scan for the left parenthesis and break there */
           /* scan for the left parenthesis and break there */
@@ -2475,7 +2428,7 @@ static CURLcode ftp_state_get_resp(struct connectdata *conn,
             break;
             break;
           /* skip only digits */
           /* skip only digits */
           if(!ISDIGIT(*bytes)) {
           if(!ISDIGIT(*bytes)) {
-            bytes=NULL;
+            bytes = NULL;
             break;
             break;
           }
           }
           /* one more estep backwards */
           /* one more estep backwards */
@@ -2484,7 +2437,7 @@ static CURLcode ftp_state_get_resp(struct connectdata *conn,
         /* if we have nothing but digits: */
         /* if we have nothing but digits: */
         if(bytes++) {
         if(bytes++) {
           /* get the number! */
           /* get the number! */
-          size = curlx_strtoofft(bytes, NULL, 0);
+          (void)curlx_strtoofft(bytes, NULL, 0, &size);
         }
         }
       }
       }
     }
     }
@@ -2647,7 +2600,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
 {
 {
   CURLcode result;
   CURLcode result;
   curl_socket_t sock = conn->sock[FIRSTSOCKET];
   curl_socket_t sock = conn->sock[FIRSTSOCKET];
-  struct Curl_easy *data=conn->data;
+  struct Curl_easy *data = conn->data;
   int ftpcode;
   int ftpcode;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   struct pingpong *pp = &ftpc->pp;
   struct pingpong *pp = &ftpc->pp;
@@ -2699,7 +2652,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
         /* We don't have a SSL/TLS connection yet, but FTPS is
         /* We don't have a SSL/TLS connection yet, but FTPS is
            requested. Try a FTPS connection now */
            requested. Try a FTPS connection now */
 
 
-        ftpc->count3=0;
+        ftpc->count3 = 0;
         switch(data->set.ftpsslauth) {
         switch(data->set.ftpsslauth) {
         case CURLFTPAUTH_DEFAULT:
         case CURLFTPAUTH_DEFAULT:
         case CURLFTPAUTH_SSL:
         case CURLFTPAUTH_SSL:
@@ -2822,10 +2775,11 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
 
 
     case FTP_PWD:
     case FTP_PWD:
       if(ftpcode == 257) {
       if(ftpcode == 257) {
-        char *ptr=&data->state.buffer[4];  /* start on the first letter */
+        char *ptr = &data->state.buffer[4];  /* start on the first letter */
         const size_t buf_size = data->set.buffer_size;
         const size_t buf_size = data->set.buffer_size;
         char *dir;
         char *dir;
         char *store;
         char *store;
+        bool entry_extracted = FALSE;
 
 
         dir = malloc(nread + 1);
         dir = malloc(nread + 1);
         if(!dir)
         if(!dir)
@@ -2857,7 +2811,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
               }
               }
               else {
               else {
                 /* end of path */
                 /* end of path */
-                *store = '\0'; /* zero terminate */
+                entry_extracted = TRUE;
                 break; /* get out of this loop */
                 break; /* get out of this loop */
               }
               }
             }
             }
@@ -2866,7 +2820,9 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
             store++;
             store++;
             ptr++;
             ptr++;
           }
           }
-
+          *store = '\0'; /* zero terminate */
+        }
+        if(entry_extracted) {
           /* If the path name does not look like an absolute path (i.e.: it
           /* 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
              does not start with a '/'), we probably need some server-dependent
              adjustments. For example, this is the case when connecting to
              adjustments. For example, this is the case when connecting to
@@ -2913,7 +2869,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
 
 
     case FTP_SYST:
     case FTP_SYST:
       if(ftpcode == 215) {
       if(ftpcode == 215) {
-        char *ptr=&data->state.buffer[4];  /* start on the first letter */
+        char *ptr = &data->state.buffer[4];  /* start on the first letter */
         char *os;
         char *os;
         char *store;
         char *store;
 
 
@@ -2988,10 +2944,10 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
       if(ftpcode/100 != 2) {
       if(ftpcode/100 != 2) {
         /* failure to CWD there */
         /* failure to CWD there */
         if(conn->data->set.ftp_create_missing_dirs &&
         if(conn->data->set.ftp_create_missing_dirs &&
-           ftpc->count1 && !ftpc->count2) {
+           ftpc->cwdcount && !ftpc->count2) {
           /* try making it */
           /* try making it */
           ftpc->count2++; /* counter to prevent CWD-MKD loops */
           ftpc->count2++; /* counter to prevent CWD-MKD loops */
-          PPSENDF(&ftpc->pp, "MKD %s", ftpc->dirs[ftpc->count1 - 1]);
+          PPSENDF(&ftpc->pp, "MKD %s", ftpc->dirs[ftpc->cwdcount - 1]);
           state(conn, FTP_MKD);
           state(conn, FTP_MKD);
         }
         }
         else {
         else {
@@ -3004,10 +2960,10 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
       }
       }
       else {
       else {
         /* success */
         /* success */
-        ftpc->count2=0;
-        if(++ftpc->count1 <= ftpc->dirdepth) {
+        ftpc->count2 = 0;
+        if(++ftpc->cwdcount <= ftpc->dirdepth) {
           /* send next CWD */
           /* send next CWD */
-          PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
+          PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->cwdcount - 1]);
         }
         }
         else {
         else {
           result = ftp_state_mdtm(conn);
           result = ftp_state_mdtm(conn);
@@ -3025,7 +2981,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
       }
       }
       state(conn, FTP_CWD);
       state(conn, FTP_CWD);
       /* send CWD */
       /* send CWD */
-      PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
+      PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->cwdcount - 1]);
       break;
       break;
 
 
     case FTP_MDTM:
     case FTP_MDTM:
@@ -3244,15 +3200,16 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
     size_t flen = ftpc->file?strlen(ftpc->file):0; /* file is "raw" already */
     size_t flen = ftpc->file?strlen(ftpc->file):0; /* file is "raw" already */
     size_t dlen = strlen(path)-flen;
     size_t dlen = strlen(path)-flen;
     if(!ftpc->cwdfail) {
     if(!ftpc->cwdfail) {
+      ftpc->prevmethod = data->set.ftp_filemethod;
       if(dlen && (data->set.ftp_filemethod != FTPFILE_NOCWD)) {
       if(dlen && (data->set.ftp_filemethod != FTPFILE_NOCWD)) {
         ftpc->prevpath = path;
         ftpc->prevpath = path;
         if(flen)
         if(flen)
           /* if 'path' is not the whole string */
           /* if 'path' is not the whole string */
-          ftpc->prevpath[dlen]=0; /* terminate */
+          ftpc->prevpath[dlen] = 0; /* terminate */
       }
       }
       else {
       else {
         /* we never changed dir */
         /* we never changed dir */
-        ftpc->prevpath=strdup("");
+        ftpc->prevpath = strdup("");
         free(path);
         free(path);
       }
       }
       if(ftpc->prevpath)
       if(ftpc->prevpath)
@@ -3515,35 +3472,36 @@ static CURLcode ftp_range(struct connectdata *conn)
 {
 {
   curl_off_t from, to;
   curl_off_t from, to;
   char *ptr;
   char *ptr;
-  char *ptr2;
   struct Curl_easy *data = conn->data;
   struct Curl_easy *data = conn->data;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
 
 
   if(data->state.use_range && data->state.range) {
   if(data->state.use_range && data->state.range) {
-    from=curlx_strtoofft(data->state.range, &ptr, 0);
-    while(*ptr && (ISSPACE(*ptr) || (*ptr=='-')))
+    CURLofft from_t;
+    CURLofft to_t;
+    from_t = curlx_strtoofft(data->state.range, &ptr, 0, &from);
+    if(from_t == CURL_OFFT_FLOW)
+      return CURLE_RANGE_ERROR;
+    while(*ptr && (ISSPACE(*ptr) || (*ptr == '-')))
       ptr++;
       ptr++;
-    to=curlx_strtoofft(ptr, &ptr2, 0);
-    if(ptr == ptr2) {
-      /* we didn't get any digit */
-      to=-1;
-    }
-    if((-1 == to) && (from>=0)) {
+    to_t = curlx_strtoofft(ptr, NULL, 0, &to);
+    if(to_t == CURL_OFFT_FLOW)
+      return CURLE_RANGE_ERROR;
+    if((to_t == CURL_OFFT_INVAL) && !from_t) {
       /* X - */
       /* X - */
       data->state.resume_from = from;
       data->state.resume_from = from;
       DEBUGF(infof(conn->data, "FTP RANGE %" CURL_FORMAT_CURL_OFF_T
       DEBUGF(infof(conn->data, "FTP RANGE %" CURL_FORMAT_CURL_OFF_T
                    " to end of file\n", from));
                    " to end of file\n", from));
     }
     }
-    else if(from < 0) {
+    else if(!to_t && (from_t == CURL_OFFT_INVAL)) {
       /* -Y */
       /* -Y */
-      data->req.maxdownload = -from;
-      data->state.resume_from = from;
+      data->req.maxdownload = to;
+      data->state.resume_from = -to;
       DEBUGF(infof(conn->data, "FTP RANGE the last %" CURL_FORMAT_CURL_OFF_T
       DEBUGF(infof(conn->data, "FTP RANGE the last %" CURL_FORMAT_CURL_OFF_T
-                   " bytes\n", -from));
+                   " bytes\n", to));
     }
     }
     else {
     else {
       /* X-Y */
       /* X-Y */
-      data->req.maxdownload = (to-from)+1; /* include last byte */
+      data->req.maxdownload = (to - from) + 1; /* include last byte */
       data->state.resume_from = from;
       data->state.resume_from = from;
       DEBUGF(infof(conn->data, "FTP RANGE from %" CURL_FORMAT_CURL_OFF_T
       DEBUGF(infof(conn->data, "FTP RANGE from %" CURL_FORMAT_CURL_OFF_T
                    " getting %" CURL_FORMAT_CURL_OFF_T " bytes\n",
                    " getting %" CURL_FORMAT_CURL_OFF_T " bytes\n",
@@ -3574,7 +3532,7 @@ static CURLcode ftp_range(struct connectdata *conn)
 
 
 static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
 static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
 {
 {
-  struct Curl_easy *data=conn->data;
+  struct Curl_easy *data = conn->data;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
   bool connected = FALSE;
   bool connected = FALSE;
@@ -3585,7 +3543,7 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
 
 
   /* if the second connection isn't done yet, wait for it */
   /* if the second connection isn't done yet, wait for it */
   if(!conn->bits.tcpconnect[SECONDARYSOCKET]) {
   if(!conn->bits.tcpconnect[SECONDARYSOCKET]) {
-    if(conn->tunnel_state[SECONDARYSOCKET] == TUNNEL_CONNECT) {
+    if(Curl_connect_ongoing(conn)) {
       /* As we're in TUNNEL_CONNECT state now, we know the proxy name and port
       /* 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 */
          aren't used so we blank their arguments. TODO: make this nicer */
       result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0);
       result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0);
@@ -3617,7 +3575,7 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
     return result;
     return result;
 
 
   if(conn->bits.tunnel_proxy && conn->bits.httpproxy &&
   if(conn->bits.tunnel_proxy && conn->bits.httpproxy &&
-     conn->tunnel_state[SECONDARYSOCKET] != TUNNEL_COMPLETE)
+     Curl_connect_ongoing(conn))
     return result;
     return result;
 
 
 
 
@@ -3741,7 +3699,7 @@ CURLcode ftp_perform(struct connectdata *conn,
                      bool *dophase_done)
                      bool *dophase_done)
 {
 {
   /* this is FTP and no proxy */
   /* this is FTP and no proxy */
-  CURLcode result=CURLE_OK;
+  CURLcode result = CURLE_OK;
 
 
   DEBUGF(infof(conn->data, "DO phase starts\n"));
   DEBUGF(infof(conn->data, "DO phase starts\n"));
 
 
@@ -4035,7 +3993,7 @@ CURLcode Curl_ftpsend(struct connectdata *conn, const char *cmd)
 #define SBUF_SIZE 1024
 #define SBUF_SIZE 1024
   char s[SBUF_SIZE];
   char s[SBUF_SIZE];
   size_t write_len;
   size_t write_len;
-  char *sptr=s;
+  char *sptr = s;
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
 #ifdef HAVE_GSSAPI
 #ifdef HAVE_GSSAPI
   enum protection_level data_sec = conn->data_prot;
   enum protection_level data_sec = conn->data_prot;
@@ -4046,9 +4004,8 @@ CURLcode Curl_ftpsend(struct connectdata *conn, const char *cmd)
     return CURLE_BAD_FUNCTION_ARGUMENT;
     return CURLE_BAD_FUNCTION_ARGUMENT;
 
 
   strcpy(&s[write_len], "\r\n"); /* append a trailing CRLF */
   strcpy(&s[write_len], "\r\n"); /* append a trailing CRLF */
-  write_len +=2;
-
-  bytes_written=0;
+  write_len += 2;
+  bytes_written = 0;
 
 
   result = Curl_convert_to_network(conn->data, s, write_len);
   result = Curl_convert_to_network(conn->data, s, write_len);
   /* Curl_convert_to_network calls failf if unsuccessful */
   /* Curl_convert_to_network calls failf if unsuccessful */
@@ -4126,7 +4083,7 @@ static CURLcode ftp_quit(struct connectdata *conn)
  */
  */
 static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection)
 static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection)
 {
 {
-  struct ftp_conn *ftpc= &conn->proto.ftpc;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
   struct pingpong *pp = &ftpc->pp;
   struct pingpong *pp = &ftpc->pp;
 
 
   /* We cannot send quit unconditionally. If this connection is stale or
   /* We cannot send quit unconditionally. If this connection is stale or
@@ -4222,7 +4179,7 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
       ftpc->dirdepth = 0;
       ftpc->dirdepth = 0;
       break;
       break;
     }
     }
-    slash_pos=strrchr(cur_pos, '/');
+    slash_pos = strrchr(cur_pos, '/');
     if(slash_pos || !*cur_pos) {
     if(slash_pos || !*cur_pos) {
       size_t dirlen = slash_pos-cur_pos;
       size_t dirlen = slash_pos-cur_pos;
       CURLcode result;
       CURLcode result;
@@ -4243,7 +4200,7 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
         return result;
         return result;
       }
       }
       ftpc->dirdepth = 1; /* we consider it to be a single dir */
       ftpc->dirdepth = 1; /* we consider it to be a single dir */
-      filename = slash_pos ? slash_pos+1 : cur_pos; /* rest is file name */
+      filename = slash_pos ? slash_pos + 1 : cur_pos; /* rest is file name */
     }
     }
     else
     else
       filename = cur_pos;  /* this is a file name only */
       filename = cur_pos;  /* this is a file name only */
@@ -4327,8 +4284,8 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
     }
     }
   }
   }
   else
   else
-    ftpc->file=NULL; /* instead of point to a zero byte, we make it a NULL
-                       pointer */
+    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)) {
   if(data->set.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) {
     /* We need a file name when uploading. Return error! */
     /* We need a file name when uploading. Return error! */
@@ -4352,7 +4309,8 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
 
 
     dlen -= ftpc->file?strlen(ftpc->file):0;
     dlen -= ftpc->file?strlen(ftpc->file):0;
     if((dlen == strlen(ftpc->prevpath)) &&
     if((dlen == strlen(ftpc->prevpath)) &&
-       !strncmp(path, ftpc->prevpath, dlen)) {
+       !strncmp(path, ftpc->prevpath, dlen) &&
+       (ftpc->prevmethod == data->set.ftp_filemethod)) {
       infof(data, "Request has same path as previous transfer\n");
       infof(data, "Request has same path as previous transfer\n");
       ftpc->cwddone = TRUE;
       ftpc->cwddone = TRUE;
     }
     }
@@ -4423,8 +4381,8 @@ static
 CURLcode ftp_regular_transfer(struct connectdata *conn,
 CURLcode ftp_regular_transfer(struct connectdata *conn,
                               bool *dophase_done)
                               bool *dophase_done)
 {
 {
-  CURLcode result=CURLE_OK;
-  bool connected=FALSE;
+  CURLcode result = CURLE_OK;
+  bool connected = FALSE;
   struct Curl_easy *data = conn->data;
   struct Curl_easy *data = conn->data;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   data->req.size = -1; /* make sure this is unknown at this point */
   data->req.size = -1; /* make sure this is unknown at this point */
@@ -4464,28 +4422,6 @@ static CURLcode ftp_setup_connection(struct connectdata *conn)
   char command;
   char command;
   struct FTP *ftp;
   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));
   conn->data->req.protop = ftp = malloc(sizeof(struct FTP));
   if(NULL == ftp)
   if(NULL == ftp)
     return CURLE_OUT_OF_MEMORY;
     return CURLE_OUT_OF_MEMORY;

+ 3 - 1
Utilities/cmcurl/lib/ftp.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -130,10 +130,12 @@ struct ftp_conn {
                        should be FALSE when it gets to Curl_ftp_quit() */
                        should be FALSE when it gets to Curl_ftp_quit() */
   bool cwddone;     /* if it has been determined that the proper CWD combo
   bool cwddone;     /* if it has been determined that the proper CWD combo
                        already has been done */
                        already has been done */
+  int cwdcount;     /* number of CWD commands issued */
   bool cwdfail;     /* set TRUE if a CWD command fails, as then we must prevent
   bool cwdfail;     /* set TRUE if a CWD command fails, as then we must prevent
                        caching the current directory */
                        caching the current directory */
   bool wait_data_conn; /* this is set TRUE if data connection is waited */
   bool wait_data_conn; /* this is set TRUE if data connection is waited */
   char *prevpath;   /* conn->path from the previous transfer */
   char *prevpath;   /* conn->path from the previous transfer */
+  curl_ftpfile prevmethod; /* ftp method in previous transfer  */
   char transfertype; /* set by ftp_transfertype for use by Curl_client_write()a
   char transfertype; /* set by ftp_transfertype for use by Curl_client_write()a
                         and others (A/I or zero) */
                         and others (A/I or zero) */
   int count1; /* general purpose counter for the state machine */
   int count1; /* general purpose counter for the state machine */

+ 15 - 23
Utilities/cmcurl/lib/ftplistparser.c

@@ -421,7 +421,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
           else if(c == '\n') {
           else if(c == '\n') {
             finfo->b_data[parser->item_length - 1] = 0;
             finfo->b_data[parser->item_length - 1] = 0;
             if(strncmp("total ", finfo->b_data, 6) == 0) {
             if(strncmp("total ", finfo->b_data, 6) == 0) {
-              char *endptr = finfo->b_data+6;
+              char *endptr = finfo->b_data + 6;
               /* here we can deal with directory size, pass the leading white
               /* here we can deal with directory size, pass the leading white
                  spaces and then the digits */
                  spaces and then the digits */
               while(ISSPACE(*endptr))
               while(ISSPACE(*endptr))
@@ -609,16 +609,18 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
             char *p;
             char *p;
             curl_off_t fsize;
             curl_off_t fsize;
             finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
             finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
-            fsize = curlx_strtoofft(finfo->b_data+parser->item_offset, &p, 10);
-            if(p[0] == '\0' && fsize != CURL_OFF_T_MAX &&
-                               fsize != CURL_OFF_T_MIN) {
-              parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE;
-              parser->file_data->info.size = fsize;
+            if(!curlx_strtoofft(finfo->b_data + parser->item_offset,
+                                &p, 10, &fsize)) {
+              if(p[0] == '\0' && fsize != CURL_OFF_T_MAX &&
+                 fsize != CURL_OFF_T_MIN) {
+                parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE;
+                parser->file_data->info.size = fsize;
+              }
+              parser->item_length = 0;
+              parser->item_offset = 0;
+              parser->state.UNIX.main = PL_UNIX_TIME;
+              parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART1;
             }
             }
-            parser->item_length = 0;
-            parser->item_offset = 0;
-            parser->state.UNIX.main = PL_UNIX_TIME;
-            parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART1;
           }
           }
           else if(!ISDIGIT(c)) {
           else if(!ISDIGIT(c)) {
             PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
             PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
@@ -935,19 +937,9 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
             }
             }
             else {
             else {
               char *endptr;
               char *endptr;
-              finfo->size = curlx_strtoofft(finfo->b_data +
-                                            parser->item_offset,
-                                            &endptr, 10);
-              if(!*endptr) {
-                if(finfo->size == CURL_OFF_T_MAX ||
-                   finfo->size == CURL_OFF_T_MIN) {
-                  if(errno == ERANGE) {
-                    PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
-                    return bufflen;
-                  }
-                }
-              }
-              else {
+              if(curlx_strtoofft(finfo->b_data +
+                                 parser->item_offset,
+                                 &endptr, 10, &finfo->size)) {
                 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
                 PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
                 return bufflen;
                 return bufflen;
               }
               }

+ 53 - 34
Utilities/cmcurl/lib/getinfo.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -54,6 +54,7 @@ CURLcode Curl_initinfo(struct Curl_easy *data)
   pro->t_starttransfer = 0;
   pro->t_starttransfer = 0;
   pro->timespent = 0;
   pro->timespent = 0;
   pro->t_redirect = 0;
   pro->t_redirect = 0;
+  pro->is_t_startransfer_set = false;
 
 
   info->httpcode = 0;
   info->httpcode = 0;
   info->httpproxycode = 0;
   info->httpproxycode = 0;
@@ -246,27 +247,60 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
   return CURLE_OK;
   return CURLE_OK;
 }
 }
 
 
+#define DOUBLE_SECS(x) (double)(x)/1000000
+
+static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info,
+                             curl_off_t *param_offt)
+{
+  switch(info) {
+  case CURLINFO_SIZE_UPLOAD_T:
+    *param_offt = data->progress.uploaded;
+    break;
+  case CURLINFO_SIZE_DOWNLOAD_T:
+    *param_offt = data->progress.downloaded;
+    break;
+  case CURLINFO_SPEED_DOWNLOAD_T:
+    *param_offt =  data->progress.dlspeed;
+    break;
+  case CURLINFO_SPEED_UPLOAD_T:
+    *param_offt = data->progress.ulspeed;
+    break;
+  case CURLINFO_CONTENT_LENGTH_DOWNLOAD_T:
+    *param_offt = (data->progress.flags & PGRS_DL_SIZE_KNOWN)?
+      data->progress.size_dl:-1;
+    break;
+  case CURLINFO_CONTENT_LENGTH_UPLOAD_T:
+    *param_offt = (data->progress.flags & PGRS_UL_SIZE_KNOWN)?
+      data->progress.size_ul:-1;
+    break;
+  default:
+    return CURLE_UNKNOWN_OPTION;
+  }
+
+  return CURLE_OK;
+}
+
 static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info,
 static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info,
                                double *param_doublep)
                                double *param_doublep)
 {
 {
   switch(info) {
   switch(info) {
   case CURLINFO_TOTAL_TIME:
   case CURLINFO_TOTAL_TIME:
-    *param_doublep = data->progress.timespent;
+    *param_doublep = DOUBLE_SECS(data->progress.timespent);
     break;
     break;
   case CURLINFO_NAMELOOKUP_TIME:
   case CURLINFO_NAMELOOKUP_TIME:
-    *param_doublep = data->progress.t_nslookup;
+    *param_doublep = DOUBLE_SECS(data->progress.t_nslookup);
     break;
     break;
   case CURLINFO_CONNECT_TIME:
   case CURLINFO_CONNECT_TIME:
-    *param_doublep = data->progress.t_connect;
+    *param_doublep = DOUBLE_SECS(data->progress.t_connect);
     break;
     break;
   case CURLINFO_APPCONNECT_TIME:
   case CURLINFO_APPCONNECT_TIME:
-    *param_doublep = data->progress.t_appconnect;
+    *param_doublep = DOUBLE_SECS(data->progress.t_appconnect);
     break;
     break;
   case CURLINFO_PRETRANSFER_TIME:
   case CURLINFO_PRETRANSFER_TIME:
-    *param_doublep =  data->progress.t_pretransfer;
+    *param_doublep = DOUBLE_SECS(data->progress.t_pretransfer);
     break;
     break;
   case CURLINFO_STARTTRANSFER_TIME:
   case CURLINFO_STARTTRANSFER_TIME:
-    *param_doublep = data->progress.t_starttransfer;
+    *param_doublep = DOUBLE_SECS(data->progress.t_starttransfer);
     break;
     break;
   case CURLINFO_SIZE_UPLOAD:
   case CURLINFO_SIZE_UPLOAD:
     *param_doublep =  (double)data->progress.uploaded;
     *param_doublep =  (double)data->progress.uploaded;
@@ -289,7 +323,7 @@ static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info,
       (double)data->progress.size_ul:-1;
       (double)data->progress.size_ul:-1;
     break;
     break;
   case CURLINFO_REDIRECT_TIME:
   case CURLINFO_REDIRECT_TIME:
-    *param_doublep =  data->progress.t_redirect;
+    *param_doublep = DOUBLE_SECS(data->progress.t_redirect);
     break;
     break;
 
 
   default:
   default:
@@ -326,46 +360,25 @@ static CURLcode getinfo_slist(struct Curl_easy *data, CURLINFO info,
       struct curl_tlssessioninfo **tsip = (struct curl_tlssessioninfo **)
       struct curl_tlssessioninfo **tsip = (struct curl_tlssessioninfo **)
                                           param_slistp;
                                           param_slistp;
       struct curl_tlssessioninfo *tsi = &data->tsi;
       struct curl_tlssessioninfo *tsi = &data->tsi;
+#ifdef USE_SSL
       struct connectdata *conn = data->easy_conn;
       struct connectdata *conn = data->easy_conn;
+#endif
 
 
       *tsip = tsi;
       *tsip = tsi;
       tsi->backend = Curl_ssl_backend();
       tsi->backend = Curl_ssl_backend();
       tsi->internals = NULL;
       tsi->internals = NULL;
 
 
+#ifdef USE_SSL
       if(conn && tsi->backend != CURLSSLBACKEND_NONE) {
       if(conn && tsi->backend != CURLSSLBACKEND_NONE) {
         unsigned int i;
         unsigned int i;
         for(i = 0; i < (sizeof(conn->ssl) / sizeof(conn->ssl[0])); ++i) {
         for(i = 0; i < (sizeof(conn->ssl) / sizeof(conn->ssl[0])); ++i) {
           if(conn->ssl[i].use) {
           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
+            tsi->internals = Curl_ssl->get_internals(&conn->ssl[i], info);
             break;
             break;
           }
           }
         }
         }
       }
       }
+#endif
     }
     }
     break;
     break;
   default:
   default:
@@ -394,6 +407,7 @@ CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...)
   va_list arg;
   va_list arg;
   long *param_longp = NULL;
   long *param_longp = NULL;
   double *param_doublep = NULL;
   double *param_doublep = NULL;
+  curl_off_t *param_offt = NULL;
   const char **param_charp = NULL;
   const char **param_charp = NULL;
   struct curl_slist **param_slistp = NULL;
   struct curl_slist **param_slistp = NULL;
   curl_socket_t *param_socketp = NULL;
   curl_socket_t *param_socketp = NULL;
@@ -422,6 +436,11 @@ CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...)
     if(param_doublep)
     if(param_doublep)
       result = getinfo_double(data, info, param_doublep);
       result = getinfo_double(data, info, param_doublep);
     break;
     break;
+  case CURLINFO_OFF_T:
+    param_offt = va_arg(arg, curl_off_t *);
+    if(param_offt)
+      result = getinfo_offt(data, info, param_offt);
+    break;
   case CURLINFO_SLIST:
   case CURLINFO_SLIST:
     param_slistp = va_arg(arg, struct curl_slist **);
     param_slistp = va_arg(arg, struct curl_slist **);
     if(param_slistp)
     if(param_slistp)

+ 6 - 5
Utilities/cmcurl/lib/gopher.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -65,6 +65,7 @@ const struct Curl_handler Curl_handler_gopher = {
   ZERO_NULL,                            /* perform_getsock */
   ZERO_NULL,                            /* perform_getsock */
   ZERO_NULL,                            /* disconnect */
   ZERO_NULL,                            /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
   PORT_GOPHER,                          /* defport */
   PORT_GOPHER,                          /* defport */
   CURLPROTO_GOPHER,                     /* protocol */
   CURLPROTO_GOPHER,                     /* protocol */
   PROTOPT_NONE                          /* flags */
   PROTOPT_NONE                          /* flags */
@@ -72,8 +73,8 @@ const struct Curl_handler Curl_handler_gopher = {
 
 
 static CURLcode gopher_do(struct connectdata *conn, bool *done)
 static CURLcode gopher_do(struct connectdata *conn, bool *done)
 {
 {
-  CURLcode result=CURLE_OK;
-  struct Curl_easy *data=conn->data;
+  CURLcode result = CURLE_OK;
+  struct Curl_easy *data = conn->data;
   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
 
 
   curl_off_t *bytecount = &data->req.bytecount;
   curl_off_t *bytecount = &data->req.bytecount;
@@ -96,11 +97,11 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done)
 
 
     /* Otherwise, drop / and the first character (i.e., item type) ... */
     /* Otherwise, drop / and the first character (i.e., item type) ... */
     newp = path;
     newp = path;
-    newp+=2;
+    newp += 2;
 
 
     /* ... then turn ? into TAB for search servers, Veronica, etc. ... */
     /* ... then turn ? into TAB for search servers, Veronica, etc. ... */
     j = strlen(newp);
     j = strlen(newp);
-    for(i=0; i<j; i++)
+    for(i = 0; i<j; i++)
       if(newp[i] == '?')
       if(newp[i] == '?')
         newp[i] = '\x09';
         newp[i] = '\x09';
 
 

+ 2 - 2
Utilities/cmcurl/lib/hash.c

@@ -300,10 +300,10 @@ Curl_hash_next_element(struct curl_hash_iterator *iter)
 
 
   /* If we have reached the end of the list, find the next one */
   /* If we have reached the end of the list, find the next one */
   if(!iter->current_element) {
   if(!iter->current_element) {
-    for(i = iter->slot_index;i < h->slots;i++) {
+    for(i = iter->slot_index; i < h->slots; i++) {
       if(h->table[i].head) {
       if(h->table[i].head) {
         iter->current_element = h->table[i].head;
         iter->current_element = h->table[i].head;
-        iter->slot_index = i+1;
+        iter->slot_index = i + 1;
         break;
         break;
       }
       }
     }
     }

+ 7 - 7
Utilities/cmcurl/lib/hostcheck.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -73,10 +73,10 @@ static int hostmatch(char *hostname, char *pattern)
   /* normalize pattern and hostname by stripping off trailing dots */
   /* normalize pattern and hostname by stripping off trailing dots */
   size_t len = strlen(hostname);
   size_t len = strlen(hostname);
   if(hostname[len-1]=='.')
   if(hostname[len-1]=='.')
-    hostname[len-1]=0;
+    hostname[len-1] = 0;
   len = strlen(pattern);
   len = strlen(pattern);
   if(pattern[len-1]=='.')
   if(pattern[len-1]=='.')
-    pattern[len-1]=0;
+    pattern[len-1] = 0;
 
 
   pattern_wildcard = strchr(pattern, '*');
   pattern_wildcard = strchr(pattern, '*');
   if(pattern_wildcard == NULL)
   if(pattern_wildcard == NULL)
@@ -95,7 +95,7 @@ static int hostmatch(char *hostname, char *pattern)
      match. */
      match. */
   wildcard_enabled = 1;
   wildcard_enabled = 1;
   pattern_label_end = strchr(pattern, '.');
   pattern_label_end = strchr(pattern, '.');
-  if(pattern_label_end == NULL || strchr(pattern_label_end+1, '.') == NULL ||
+  if(pattern_label_end == NULL || strchr(pattern_label_end + 1, '.') == NULL ||
      pattern_wildcard > pattern_label_end ||
      pattern_wildcard > pattern_label_end ||
      strncasecompare(pattern, "xn--", 4)) {
      strncasecompare(pattern, "xn--", 4)) {
     wildcard_enabled = 0;
     wildcard_enabled = 0;
@@ -116,9 +116,9 @@ static int hostmatch(char *hostname, char *pattern)
     return CURL_HOST_NOMATCH;
     return CURL_HOST_NOMATCH;
 
 
   prefixlen = pattern_wildcard - pattern;
   prefixlen = pattern_wildcard - pattern;
-  suffixlen = pattern_label_end - (pattern_wildcard+1);
+  suffixlen = pattern_label_end - (pattern_wildcard + 1);
   return strncasecompare(pattern, hostname, prefixlen) &&
   return strncasecompare(pattern, hostname, prefixlen) &&
-    strncasecompare(pattern_wildcard+1, hostname_label_end - suffixlen,
+    strncasecompare(pattern_wildcard + 1, hostname_label_end - suffixlen,
                     suffixlen) ?
                     suffixlen) ?
     CURL_HOST_MATCH : CURL_HOST_NOMATCH;
     CURL_HOST_MATCH : CURL_HOST_NOMATCH;
 }
 }
@@ -137,7 +137,7 @@ int Curl_cert_hostcheck(const char *match_pattern, const char *hostname)
       hostp = strdup(hostname);
       hostp = strdup(hostname);
       if(hostp) {
       if(hostp) {
         if(hostmatch(hostp, matchp) == CURL_HOST_MATCH)
         if(hostmatch(hostp, matchp) == CURL_HOST_MATCH)
-          res= 1;
+          res = 1;
         free(hostp);
         free(hostp);
       }
       }
       free(matchp);
       free(matchp);

+ 6 - 6
Utilities/cmcurl/lib/hostip.c

@@ -304,9 +304,9 @@ fetch_addr(struct connectdata *conn,
   entry_len = strlen(entry_id);
   entry_len = strlen(entry_id);
 
 
   /* See if its already in our dns cache */
   /* See if its already in our dns cache */
-  dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1);
+  dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
 
 
-  if(dns && (data->set.dns_cache_timeout != -1))  {
+  if(dns && (data->set.dns_cache_timeout != -1)) {
     /* See whether the returned entry is stale. Done before we release lock */
     /* See whether the returned entry is stale. Done before we release lock */
     struct hostcache_prune_data user;
     struct hostcache_prune_data user;
 
 
@@ -316,7 +316,7 @@ fetch_addr(struct connectdata *conn,
     if(hostcache_timestamp_remove(&user, dns)) {
     if(hostcache_timestamp_remove(&user, dns)) {
       infof(data, "Hostname in DNS cache was stale, zapped\n");
       infof(data, "Hostname in DNS cache was stale, zapped\n");
       dns = NULL; /* the memory deallocation is being handled by the hash */
       dns = NULL; /* the memory deallocation is being handled by the hash */
-      Curl_hash_delete(data->dns.hostcache, entry_id, entry_len+1);
+      Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1);
     }
     }
   }
   }
 
 
@@ -403,7 +403,7 @@ Curl_cache_addr(struct Curl_easy *data,
     dns->timestamp = 1;   /* zero indicates CURLOPT_RESOLVE entry */
     dns->timestamp = 1;   /* zero indicates CURLOPT_RESOLVE entry */
 
 
   /* Store the resolved data in our DNS cache. */
   /* Store the resolved data in our DNS cache. */
-  dns2 = Curl_hash_add(data->dns.hostcache, entry_id, entry_len+1,
+  dns2 = Curl_hash_add(data->dns.hostcache, entry_id, entry_len + 1,
                        (void *)dns);
                        (void *)dns);
   if(!dns2) {
   if(!dns2) {
     free(dns);
     free(dns);
@@ -807,7 +807,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
         Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
         Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
 
 
       /* delete entry, ignore if it didn't exist */
       /* delete entry, ignore if it didn't exist */
-      Curl_hash_delete(data->dns.hostcache, entry_id, entry_len+1);
+      Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1);
 
 
       if(data->share)
       if(data->share)
         Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
         Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
@@ -848,7 +848,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
         Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
         Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
 
 
       /* See if its already in our dns cache */
       /* See if its already in our dns cache */
-      dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1);
+      dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
 
 
       /* free the allocated entry_id again */
       /* free the allocated entry_id again */
       free(entry_id);
       free(entry_id);

+ 2 - 2
Utilities/cmcurl/lib/hostip4.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -249,7 +249,7 @@ Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
      */
      */
 
 
     if(CURL_HOSTENT_SIZE >=
     if(CURL_HOSTENT_SIZE >=
-       (sizeof(struct hostent)+sizeof(struct hostent_data))) {
+       (sizeof(struct hostent) + sizeof(struct hostent_data))) {
 
 
       /* August 22nd, 2000: Albert Chin-A-Young brought an updated version
       /* August 22nd, 2000: Albert Chin-A-Young brought an updated version
        * that should work! September 20: Richard Prescott worked on the buffer
        * that should work! September 20: Richard Prescott worked on the buffer

+ 2 - 2
Utilities/cmcurl/lib/hostip6.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -212,7 +212,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
 
 
   if(port) {
   if(port) {
     snprintf(sbuf, sizeof(sbuf), "%d", port);
     snprintf(sbuf, sizeof(sbuf), "%d", port);
-    sbufptr=sbuf;
+    sbufptr = sbuf;
   }
   }
 
 
   error = Curl_getaddrinfo_ex(hostname, sbufptr, &hints, &res);
   error = Curl_getaddrinfo_ex(hostname, sbufptr, &hints, &res);

+ 240 - 204
Utilities/cmcurl/lib/http.c

@@ -50,6 +50,7 @@
 #include "transfer.h"
 #include "transfer.h"
 #include "sendf.h"
 #include "sendf.h"
 #include "formdata.h"
 #include "formdata.h"
+#include "mime.h"
 #include "progress.h"
 #include "progress.h"
 #include "curl_base64.h"
 #include "curl_base64.h"
 #include "cookie.h"
 #include "cookie.h"
@@ -119,6 +120,7 @@ const struct Curl_handler Curl_handler_http = {
   ZERO_NULL,                            /* perform_getsock */
   ZERO_NULL,                            /* perform_getsock */
   ZERO_NULL,                            /* disconnect */
   ZERO_NULL,                            /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
   PORT_HTTP,                            /* defport */
   PORT_HTTP,                            /* defport */
   CURLPROTO_HTTP,                       /* protocol */
   CURLPROTO_HTTP,                       /* protocol */
   PROTOPT_CREDSPERREQUEST               /* flags */
   PROTOPT_CREDSPERREQUEST               /* flags */
@@ -143,6 +145,7 @@ const struct Curl_handler Curl_handler_https = {
   ZERO_NULL,                            /* perform_getsock */
   ZERO_NULL,                            /* perform_getsock */
   ZERO_NULL,                            /* disconnect */
   ZERO_NULL,                            /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
   PORT_HTTPS,                           /* defport */
   PORT_HTTPS,                           /* defport */
   CURLPROTO_HTTPS,                      /* protocol */
   CURLPROTO_HTTPS,                      /* protocol */
   PROTOPT_SSL | PROTOPT_CREDSPERREQUEST | PROTOPT_ALPN_NPN /* flags */
   PROTOPT_SSL | PROTOPT_CREDSPERREQUEST | PROTOPT_ALPN_NPN /* flags */
@@ -160,6 +163,7 @@ CURLcode Curl_http_setup_conn(struct connectdata *conn)
   if(!http)
   if(!http)
     return CURLE_OUT_OF_MEMORY;
     return CURLE_OUT_OF_MEMORY;
 
 
+  Curl_mime_initpart(&http->form, conn->data);
   conn->data->req.protop = http;
   conn->data->req.protop = http;
 
 
   Curl_http2_setup_conn(conn);
   Curl_http2_setup_conn(conn);
@@ -168,26 +172,6 @@ CURLcode Curl_http_setup_conn(struct connectdata *conn)
   return CURLE_OK;
   return CURLE_OK;
 }
 }
 
 
-/*
- * checkheaders() checks the linked list of custom HTTP headers for a
- * particular header (prefix).
- *
- * Returns a pointer to the first matching header or NULL if none matched.
- */
-char *Curl_checkheaders(const struct connectdata *conn,
-                        const char *thisheader)
-{
-  struct curl_slist *head;
-  size_t thislen = strlen(thisheader);
-  struct Curl_easy *data = conn->data;
-
-  for(head = data->set.headers;head; head=head->next) {
-    if(strncasecompare(head->data, thisheader, thislen))
-      return head->data;
-  }
-
-  return NULL;
-}
 
 
 /*
 /*
  * checkProxyHeaders() checks the linked list of custom proxy headers
  * checkProxyHeaders() checks the linked list of custom proxy headers
@@ -207,7 +191,7 @@ char *Curl_checkProxyheaders(const struct connectdata *conn,
 
 
   for(head = (conn->bits.proxy && data->set.sep_headers) ?
   for(head = (conn->bits.proxy && data->set.sep_headers) ?
         data->set.proxyheaders : data->set.headers;
         data->set.proxyheaders : data->set.headers;
-      head; head=head->next) {
+      head; head = head->next) {
     if(strncasecompare(head->data, thisheader, thislen))
     if(strncasecompare(head->data, thisheader, thislen))
       return head->data;
       return head->data;
   }
   }
@@ -425,6 +409,7 @@ static CURLcode http_perhapsrewind(struct connectdata *conn)
         expectsend = data->state.infilesize;
         expectsend = data->state.infilesize;
       break;
       break;
     case HTTPREQ_POST_FORM:
     case HTTPREQ_POST_FORM:
+    case HTTPREQ_POST_MIME:
       expectsend = http->postsize;
       expectsend = http->postsize;
       break;
       break;
     default:
     default:
@@ -608,7 +593,7 @@ output_auth_headers(struct connectdata *conn,
 #endif
 #endif
 #if defined(USE_NTLM) && defined(NTLM_WB_ENABLED)
 #if defined(USE_NTLM) && defined(NTLM_WB_ENABLED)
   if(authstatus->picked == CURLAUTH_NTLM_WB) {
   if(authstatus->picked == CURLAUTH_NTLM_WB) {
-    auth="NTLM_WB";
+    auth = "NTLM_WB";
     result = Curl_output_ntlm_wb(conn, proxy);
     result = Curl_output_ntlm_wb(conn, proxy);
     if(result)
     if(result)
       return result;
       return result;
@@ -1020,7 +1005,7 @@ static size_t readmoredata(char *buffer,
 
 
       http->sending++; /* move one step up */
       http->sending++; /* move one step up */
 
 
-      http->backup.postsize=0;
+      http->backup.postsize = 0;
     }
     }
     else
     else
       http->postsize = 0;
       http->postsize = 0;
@@ -1148,7 +1133,7 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
         /* there was body data sent beyond the initial header part, pass that
         /* there was body data sent beyond the initial header part, pass that
            on to the debug callback too */
            on to the debug callback too */
         Curl_debug(conn->data, CURLINFO_DATA_OUT,
         Curl_debug(conn->data, CURLINFO_DATA_OUT,
-                   ptr+headlen, bodylen, conn);
+                   ptr + headlen, bodylen, conn);
       }
       }
     }
     }
 
 
@@ -1260,7 +1245,7 @@ CURLcode Curl_add_buffer(Curl_send_buffer *in, const void *inptr, size_t size)
        (~(size * 2) < (in->size_used * 2)))
        (~(size * 2) < (in->size_used * 2)))
       new_size = (size_t)-1;
       new_size = (size_t)-1;
     else
     else
-      new_size = (in->size_used+size) * 2;
+      new_size = (in->size_used + size) * 2;
 
 
     if(in->buffer)
     if(in->buffer)
       /* we have a buffer, enlarge the existing one */
       /* we have a buffer, enlarge the existing one */
@@ -1337,7 +1322,7 @@ Curl_compareheader(const char *headerline, /* line to check */
   clen = strlen(content); /* length of the word to find */
   clen = strlen(content); /* length of the word to find */
 
 
   /* find the content string in the rest of the line */
   /* find the content string in the rest of the line */
-  for(;len>=clen;len--, start++) {
+  for(; len >= clen; len--, start++) {
     if(strncasecompare(start, content, clen))
     if(strncasecompare(start, content, clen))
       return TRUE; /* match! */
       return TRUE; /* match! */
   }
   }
@@ -1369,7 +1354,7 @@ CURLcode Curl_http_connect(struct connectdata *conn, bool *done)
   if(CONNECT_FIRSTSOCKET_PROXY_SSL())
   if(CONNECT_FIRSTSOCKET_PROXY_SSL())
     return CURLE_OK; /* wait for HTTPS proxy SSL initialization to complete */
     return CURLE_OK; /* wait for HTTPS proxy SSL initialization to complete */
 
 
-  if(conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)
+  if(Curl_connect_ongoing(conn))
     /* nothing else to do except wait right now - we're not done here. */
     /* nothing else to do except wait right now - we're not done here. */
     return CURLE_OK;
     return CURLE_OK;
 
 
@@ -1468,18 +1453,17 @@ CURLcode Curl_http_done(struct connectdata *conn,
 
 
   Curl_http2_done(conn, premature);
   Curl_http2_done(conn, premature);
 
 
-  if(HTTPREQ_POST_FORM == data->set.httpreq) {
-    data->req.bytecount = http->readbytecount + http->writebytecount;
+  Curl_mime_cleanpart(&http->form);
 
 
-    Curl_formclean(&http->sendit); /* Now free that whole lot */
-    if(http->form.fp) {
-      /* a file being uploaded was left opened, close it! */
-      fclose(http->form.fp);
-      http->form.fp = NULL;
-    }
-  }
-  else if(HTTPREQ_PUT == data->set.httpreq)
+  switch(data->set.httpreq) {
+  case HTTPREQ_PUT:
+  case HTTPREQ_POST_FORM:
+  case HTTPREQ_POST_MIME:
     data->req.bytecount = http->readbytecount + http->writebytecount;
     data->req.bytecount = http->readbytecount + http->writebytecount;
+    break;
+  default:
+    break;
+  }
 
 
   if(status)
   if(status)
     return status;
     return status;
@@ -1579,7 +1563,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
   char *ptr;
   char *ptr;
   struct curl_slist *h[2];
   struct curl_slist *h[2];
   struct curl_slist *headers;
   struct curl_slist *headers;
-  int numlists=1; /* by default */
+  int numlists = 1; /* by default */
   struct Curl_easy *data = conn->data;
   struct Curl_easy *data = conn->data;
   int i;
   int i;
 
 
@@ -1611,7 +1595,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
   }
   }
 
 
   /* loop through one or two lists */
   /* loop through one or two lists */
-  for(i=0; i < numlists; i++) {
+  for(i = 0; i < numlists; i++) {
     headers = h[i];
     headers = h[i];
 
 
     while(headers) {
     while(headers) {
@@ -1635,15 +1619,19 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
                   /* this header (extended by formdata.c) is sent later */
                   /* this header (extended by formdata.c) is sent later */
                   checkprefix("Content-Type:", headers->data))
                   checkprefix("Content-Type:", headers->data))
             ;
             ;
+          else if(data->set.httpreq == HTTPREQ_POST_MIME &&
+                  /* this header is sent later */
+                  checkprefix("Content-Type:", headers->data))
+            ;
           else if(conn->bits.authneg &&
           else if(conn->bits.authneg &&
                   /* while doing auth neg, don't allow the custom length since
                   /* while doing auth neg, don't allow the custom length since
                      we will force length zero then */
                      we will force length zero then */
-                  checkprefix("Content-Length", headers->data))
+                  checkprefix("Content-Length:", headers->data))
             ;
             ;
           else if(conn->allocptr.te &&
           else if(conn->allocptr.te &&
                   /* when asking for Transfer-Encoding, don't pass on a custom
                   /* when asking for Transfer-Encoding, don't pass on a custom
                      Connection: */
                      Connection: */
-                  checkprefix("Connection", headers->data))
+                  checkprefix("Connection:", headers->data))
             ;
             ;
           else if((conn->httpversion == 20) &&
           else if((conn->httpversion == 20) &&
                   checkprefix("Transfer-Encoding:", headers->data))
                   checkprefix("Transfer-Encoding:", headers->data))
@@ -1676,6 +1664,10 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
               *ptr = ':';
               *ptr = ':';
               result = Curl_add_bufferf(req_buffer, "%s\r\n",
               result = Curl_add_bufferf(req_buffer, "%s\r\n",
                                         headers->data);
                                         headers->data);
+
+              /* restore the previous value */
+              *ptr = ';';
+
               if(result)
               if(result)
                 return result;
                 return result;
             }
             }
@@ -1773,7 +1765,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
   const char *httpstring;
   const char *httpstring;
   Curl_send_buffer *req_buffer;
   Curl_send_buffer *req_buffer;
   curl_off_t postsize = 0; /* curl_off_t to handle large file sizes */
   curl_off_t postsize = 0; /* curl_off_t to handle large file sizes */
-  int seekerr = CURL_SEEKFUNC_OK;
+  int seekerr = CURL_SEEKFUNC_CANTSEEK;
 
 
   /* Always consider the DO phase done after this function call, even if there
   /* Always consider the DO phase done after this function call, even if there
      may be parts of the request that is not yet sent, since we can deal with
      may be parts of the request that is not yet sent, since we can deal with
@@ -1846,11 +1838,15 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
       switch(httpreq) {
       switch(httpreq) {
       case HTTPREQ_POST:
       case HTTPREQ_POST:
       case HTTPREQ_POST_FORM:
       case HTTPREQ_POST_FORM:
+      case HTTPREQ_POST_MIME:
         request = "POST";
         request = "POST";
         break;
         break;
       case HTTPREQ_PUT:
       case HTTPREQ_PUT:
         request = "PUT";
         request = "PUT";
         break;
         break;
+      case HTTPREQ_OPTIONS:
+        request = "OPTIONS";
+        break;
       default: /* this should never happen */
       default: /* this should never happen */
       case HTTPREQ_GET:
       case HTTPREQ_GET:
         request = "GET";
         request = "GET";
@@ -1868,7 +1864,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
      here. */
      here. */
   if(Curl_checkheaders(conn, "User-Agent:")) {
   if(Curl_checkheaders(conn, "User-Agent:")) {
     free(conn->allocptr.uagent);
     free(conn->allocptr.uagent);
-    conn->allocptr.uagent=NULL;
+    conn->allocptr.uagent = NULL;
   }
   }
 
 
   /* setup the authentication headers */
   /* setup the authentication headers */
@@ -1937,6 +1933,48 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
   }
   }
 #endif
 #endif
 
 
+  switch(httpreq) {
+  case HTTPREQ_POST_MIME:
+    http->sendit = &data->set.mimepost;
+    break;
+  case HTTPREQ_POST_FORM:
+    /* Convert the form structure into a mime structure. */
+    Curl_mime_cleanpart(&http->form);
+    result = Curl_getformdata(data, &http->form, data->set.httppost,
+                              data->state.fread_func);
+    if(result)
+      return result;
+    http->sendit = &http->form;
+    break;
+  default:
+    http->sendit = NULL;
+  }
+
+  if(http->sendit) {
+    const char *cthdr = Curl_checkheaders(conn, "Content-Type:");
+
+    /* Read and seek body only. */
+    http->sendit->flags |= MIME_BODY_ONLY;
+
+    /* Prepare the mime structure headers & set content type. */
+
+    if(cthdr)
+      for(cthdr += 13; *cthdr == ' '; cthdr++)
+        ;
+    else if(http->sendit->kind == MIMEKIND_MULTIPART)
+      cthdr = "multipart/form-data";
+
+    curl_mime_headers(http->sendit, data->set.headers, 0);
+    result = Curl_mime_prepare_headers(http->sendit, cthdr,
+                                       NULL, MIMESTRATEGY_FORM);
+    curl_mime_headers(http->sendit, NULL, 0);
+    if(!result)
+      result = Curl_mime_rewind(http->sendit);
+    if(result)
+      return result;
+    http->postsize = Curl_mime_size(http->sendit);
+  }
+
   ptr = Curl_checkheaders(conn, "Transfer-Encoding:");
   ptr = Curl_checkheaders(conn, "Transfer-Encoding:");
   if(ptr) {
   if(ptr) {
     /* Some kind of TE is requested, check if 'chunked' is chosen */
     /* Some kind of TE is requested, check if 'chunked' is chosen */
@@ -1944,9 +1982,10 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
       Curl_compareheader(ptr, "Transfer-Encoding:", "chunked");
       Curl_compareheader(ptr, "Transfer-Encoding:", "chunked");
   }
   }
   else {
   else {
-    if((conn->handler->protocol&PROTO_FAMILY_HTTP) &&
-       data->set.upload &&
-       (data->state.infilesize == -1)) {
+    if((conn->handler->protocol & PROTO_FAMILY_HTTP) &&
+       (((httpreq == HTTPREQ_POST_MIME || httpreq == HTTPREQ_POST_FORM) &&
+       http->postsize < 0) ||
+       (data->set.upload && data->state.infilesize == -1))) {
       if(conn->bits.authneg)
       if(conn->bits.authneg)
         /* don't enable chunked during auth neg */
         /* don't enable chunked during auth neg */
         ;
         ;
@@ -2044,7 +2083,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
   }
   }
 
 
 #ifndef CURL_DISABLE_PROXY
 #ifndef CURL_DISABLE_PROXY
-  if(conn->bits.httpproxy && !conn->bits.tunnel_proxy)  {
+  if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
     /* Using a proxy but does not tunnel through it */
     /* Using a proxy but does not tunnel through it */
 
 
     /* The path sent to the proxy is in fact the entire URL. But if the remote
     /* The path sent to the proxy is in fact the entire URL. But if the remote
@@ -2118,21 +2157,9 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
   }
   }
 #endif /* CURL_DISABLE_PROXY */
 #endif /* CURL_DISABLE_PROXY */
 
 
-  if(HTTPREQ_POST_FORM == httpreq) {
-    /* we must build the whole post sequence first, so that we have a size of
-       the whole transfer before we start to send it */
-    result = Curl_getformdata(data, &http->sendit, data->set.httppost,
-                              Curl_checkheaders(conn, "Content-Type:"),
-                              &http->postsize);
-    if(result)
-      return result;
-  }
-
   http->p_accept = Curl_checkheaders(conn, "Accept:")?NULL:"Accept: */*\r\n";
   http->p_accept = Curl_checkheaders(conn, "Accept:")?NULL:"Accept: */*\r\n";
 
 
-  if(( (HTTPREQ_POST == httpreq) ||
-       (HTTPREQ_POST_FORM == httpreq) ||
-       (HTTPREQ_PUT == httpreq) ) &&
+  if((HTTPREQ_POST == httpreq || HTTPREQ_PUT == httpreq) &&
      data->state.resume_from) {
      data->state.resume_from) {
     /**********************************************************************
     /**********************************************************************
      * Resuming upload in HTTP means that we PUT or POST and that we have
      * Resuming upload in HTTP means that we PUT or POST and that we have
@@ -2140,6 +2167,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
      * a Range: header that will be passed along. We need to "fast forward"
      * a Range: header that will be passed along. We need to "fast forward"
      * the file the given number of bytes and decrease the assume upload
      * the file the given number of bytes and decrease the assume upload
      * file size before we continue this venture in the dark lands of HTTP.
      * file size before we continue this venture in the dark lands of HTTP.
+     * Resuming mime/form posting at an offset > 0 has no sense and is ignored.
      *********************************************************************/
      *********************************************************************/
 
 
     if(data->state.resume_from < 0) {
     if(data->state.resume_from < 0) {
@@ -2161,7 +2189,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
       }
       }
 
 
       if(seekerr != CURL_SEEKFUNC_OK) {
       if(seekerr != CURL_SEEKFUNC_OK) {
-        curl_off_t passed=0;
+        curl_off_t passed = 0;
 
 
         if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
         if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
           failf(data, "Could not seek stream");
           failf(data, "Could not seek stream");
@@ -2214,7 +2242,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
       conn->allocptr.rangeline = aprintf("Range: bytes=%s\r\n",
       conn->allocptr.rangeline = aprintf("Range: bytes=%s\r\n",
                                          data->state.range);
                                          data->state.range);
     }
     }
-    else if((httpreq != HTTPREQ_GET) &&
+    else if((httpreq == HTTPREQ_POST || httpreq == HTTPREQ_PUT) &&
             !Curl_checkheaders(conn, "Content-Range:")) {
             !Curl_checkheaders(conn, "Content-Range:")) {
 
 
       /* if a line like this was already allocated, free the previous one */
       /* if a line like this was already allocated, free the previous one */
@@ -2232,7 +2260,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
       }
       }
       else if(data->state.resume_from) {
       else if(data->state.resume_from) {
         /* This is because "resume" was selected */
         /* This is because "resume" was selected */
-        curl_off_t total_expected_size=
+        curl_off_t total_expected_size =
           data->state.resume_from + data->state.infilesize;
           data->state.resume_from + data->state.infilesize;
         conn->allocptr.rangeline =
         conn->allocptr.rangeline =
           aprintf("Content-Range: bytes %s%" CURL_FORMAT_CURL_OFF_T
           aprintf("Content-Range: bytes %s%" CURL_FORMAT_CURL_OFF_T
@@ -2266,6 +2294,9 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
   if(result)
   if(result)
     return result;
     return result;
 
 
+  if(data->set.str[STRING_TARGET])
+    ppath = data->set.str[STRING_TARGET];
+
   /* url */
   /* url */
   if(paste_ftp_userpwd)
   if(paste_ftp_userpwd)
     result = Curl_add_bufferf(req_buffer, "ftp://%s:%s@%s",
     result = Curl_add_bufferf(req_buffer, "ftp://%s:%s@%s",
@@ -2339,8 +2370,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
 
 
 #if !defined(CURL_DISABLE_COOKIES)
 #if !defined(CURL_DISABLE_COOKIES)
   if(data->cookies || addcookies) {
   if(data->cookies || addcookies) {
-    struct Cookie *co=NULL; /* no cookies from start */
-    int count=0;
+    struct Cookie *co = NULL; /* no cookies from start */
+    int count = 0;
 
 
     if(data->cookies) {
     if(data->cookies) {
       Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
       Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
@@ -2353,7 +2384,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
       Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
       Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
     }
     }
     if(co) {
     if(co) {
-      struct Cookie *store=co;
+      struct Cookie *store = co;
       /* now loop through all cookies that matched */
       /* now loop through all cookies that matched */
       while(co) {
       while(co) {
         if(co->value) {
         if(co->value) {
@@ -2407,117 +2438,79 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
 
 
   switch(httpreq) {
   switch(httpreq) {
 
 
-  case HTTPREQ_POST_FORM:
-    if(!http->sendit || conn->bits.authneg) {
-      /* nothing to post! */
-      result = Curl_add_bufferf(req_buffer, "Content-Length: 0\r\n\r\n");
-      if(result)
-        return result;
-
-      result = Curl_add_buffer_send(req_buffer, conn,
-                                    &data->info.request_size, 0, FIRSTSOCKET);
-      if(result)
-        failf(data, "Failed sending POST request");
-      else
-        /* setup variables for the upcoming transfer */
-        Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, &http->readbytecount,
-                            -1, NULL);
-      break;
-    }
-
-    if(Curl_FormInit(&http->form, http->sendit)) {
-      failf(data, "Internal HTTP POST error!");
-      return CURLE_HTTP_POST_ERROR;
-    }
-
-    /* Get the currently set callback function pointer and store that in the
-       form struct since we might want the actual user-provided callback later
-       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->state.fread_func;
-
-    /* Set the read function to read from the generated form data */
-    data->state.fread_func = (curl_read_callback)Curl_FormReader;
-    data->state.in = &http->form;
+  case HTTPREQ_PUT: /* Let's PUT the data to the server! */
 
 
-    http->sending = HTTPSEND_BODY;
+    if(conn->bits.authneg)
+      postsize = 0;
+    else
+      postsize = data->state.infilesize;
 
 
-    if(!data->req.upload_chunky &&
-       !Curl_checkheaders(conn, "Content-Length:")) {
+    if((postsize != -1) && !data->req.upload_chunky &&
+       (conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length:"))) {
       /* only add Content-Length if not uploading chunked */
       /* only add Content-Length if not uploading chunked */
       result = Curl_add_bufferf(req_buffer,
       result = Curl_add_bufferf(req_buffer,
                                 "Content-Length: %" CURL_FORMAT_CURL_OFF_T
                                 "Content-Length: %" CURL_FORMAT_CURL_OFF_T
-                                "\r\n", http->postsize);
+                                "\r\n", postsize);
       if(result)
       if(result)
         return result;
         return result;
     }
     }
 
 
-    result = expect100(data, conn, req_buffer);
-    if(result)
-      return result;
-
-    {
-
-      /* Get Content-Type: line from Curl_formpostheader.
-       */
-      char *contentType;
-      size_t linelength=0;
-      contentType = Curl_formpostheader((void *)&http->form,
-                                        &linelength);
-      if(!contentType) {
-        failf(data, "Could not get Content-Type header line!");
-        return CURLE_HTTP_POST_ERROR;
-      }
-
-      result = Curl_add_buffer(req_buffer, contentType, linelength);
+    if(postsize != 0) {
+      result = expect100(data, conn, req_buffer);
       if(result)
       if(result)
         return result;
         return result;
     }
     }
 
 
-    /* make the request end in a true CRLF */
-    result = Curl_add_buffer(req_buffer, "\r\n", 2);
+    result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers */
     if(result)
     if(result)
       return result;
       return result;
 
 
-    /* set upload size to the progress meter */
-    Curl_pgrsSetUploadSize(data, http->postsize);
+    /* set the upload size to the progress meter */
+    Curl_pgrsSetUploadSize(data, postsize);
 
 
-    /* fire away the whole request to the server */
+    /* this sends the buffer and frees all the buffer resources */
     result = Curl_add_buffer_send(req_buffer, conn,
     result = Curl_add_buffer_send(req_buffer, conn,
                                   &data->info.request_size, 0, FIRSTSOCKET);
                                   &data->info.request_size, 0, FIRSTSOCKET);
     if(result)
     if(result)
-      failf(data, "Failed sending POST request");
+      failf(data, "Failed sending PUT request");
     else
     else
-      /* setup variables for the upcoming transfer */
+      /* prepare for transfer */
       Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
       Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
-                          &http->readbytecount, FIRSTSOCKET,
-                          &http->writebytecount);
-
-    if(result) {
-      Curl_formclean(&http->sendit); /* free that whole lot */
-      return result;
-    }
-
-    /* convert the form data */
-    result = Curl_convert_form(data, http->sendit);
-    if(result) {
-      Curl_formclean(&http->sendit); /* free that whole lot */
+                          &http->readbytecount, postsize?FIRSTSOCKET:-1,
+                          postsize?&http->writebytecount:NULL);
+    if(result)
       return result;
       return result;
-    }
-
     break;
     break;
 
 
-  case HTTPREQ_PUT: /* Let's PUT the data to the server! */
+  case HTTPREQ_POST_FORM:
+  case HTTPREQ_POST_MIME:
+    /* This is form posting using mime data. */
+    if(conn->bits.authneg) {
+      /* nothing to post! */
+      result = Curl_add_bufferf(req_buffer, "Content-Length: 0\r\n\r\n");
+      if(result)
+        return result;
 
 
-    if(conn->bits.authneg)
-      postsize = 0;
-    else
-      postsize = data->state.infilesize;
+      result = Curl_add_buffer_send(req_buffer, conn,
+                                    &data->info.request_size, 0, FIRSTSOCKET);
+      if(result)
+        failf(data, "Failed sending POST request");
+      else
+        /* setup variables for the upcoming transfer */
+        Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, &http->readbytecount,
+                            -1, NULL);
+      break;
+    }
 
 
-    if((postsize != -1) && !data->req.upload_chunky &&
+    postsize = http->postsize;
+
+    /* We only set Content-Length and allow a custom Content-Length if
+       we don't upload data chunked, as RFC2616 forbids us to set both
+       kinds of headers (Transfer-Encoding: chunked and Content-Length) */
+    if(postsize != -1 && !data->req.upload_chunky &&
        (conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length:"))) {
        (conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length:"))) {
-      /* only add Content-Length if not uploading chunked */
+      /* we allow replacing this header if not during auth negotiation,
+         although it isn't very wise to actually set your own */
       result = Curl_add_bufferf(req_buffer,
       result = Curl_add_bufferf(req_buffer,
                                 "Content-Length: %" CURL_FORMAT_CURL_OFF_T
                                 "Content-Length: %" CURL_FORMAT_CURL_OFF_T
                                 "\r\n", postsize);
                                 "\r\n", postsize);
@@ -2525,24 +2518,52 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
         return result;
         return result;
     }
     }
 
 
-    if(postsize != 0) {
+    /* Output mime-generated headers. */
+    {
+      struct curl_slist *hdr;
+
+      for(hdr = http->sendit->curlheaders; hdr; hdr = hdr->next) {
+        result = Curl_add_bufferf(req_buffer, "%s\r\n", hdr->data);
+        if(result)
+          return result;
+      }
+    }
+
+    /* For really small posts we don't use Expect: headers at all, and for
+       the somewhat bigger ones we allow the app to disable it. Just make
+       sure that the expect100header is always set to the preferred value
+       here. */
+    ptr = Curl_checkheaders(conn, "Expect:");
+    if(ptr) {
+      data->state.expect100header =
+        Curl_compareheader(ptr, "Expect:", "100-continue");
+    }
+    else if(postsize > EXPECT_100_THRESHOLD || postsize < 0) {
       result = expect100(data, conn, req_buffer);
       result = expect100(data, conn, req_buffer);
       if(result)
       if(result)
         return result;
         return result;
     }
     }
+    else
+      data->state.expect100header = FALSE;
 
 
-    result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers */
+    /* make the request end in a true CRLF */
+    result = Curl_add_buffer(req_buffer, "\r\n", 2);
     if(result)
     if(result)
       return result;
       return result;
 
 
     /* set the upload size to the progress meter */
     /* set the upload size to the progress meter */
     Curl_pgrsSetUploadSize(data, postsize);
     Curl_pgrsSetUploadSize(data, postsize);
 
 
+    /* Read from mime structure. */
+    data->state.fread_func = (curl_read_callback) Curl_mime_read;
+    data->state.in = (void *) http->sendit;
+    http->sending = HTTPSEND_BODY;
+
     /* this sends the buffer and frees all the buffer resources */
     /* this sends the buffer and frees all the buffer resources */
     result = Curl_add_buffer_send(req_buffer, conn,
     result = Curl_add_buffer_send(req_buffer, conn,
                                   &data->info.request_size, 0, FIRSTSOCKET);
                                   &data->info.request_size, 0, FIRSTSOCKET);
     if(result)
     if(result)
-      failf(data, "Failed sending PUT request");
+      failf(data, "Failed sending POST request");
     else
     else
       /* prepare for transfer */
       /* prepare for transfer */
       Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
       Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
@@ -2550,6 +2571,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
                           postsize?&http->writebytecount:NULL);
                           postsize?&http->writebytecount:NULL);
     if(result)
     if(result)
       return result;
       return result;
+
     break;
     break;
 
 
   case HTTPREQ_POST:
   case HTTPREQ_POST:
@@ -2592,7 +2614,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
       data->state.expect100header =
       data->state.expect100header =
         Curl_compareheader(ptr, "Expect:", "100-continue");
         Curl_compareheader(ptr, "Expect:", "100-continue");
     }
     }
-    else if(postsize > TINY_INITIAL_POST_SIZE || postsize < 0) {
+    else if(postsize > EXPECT_100_THRESHOLD || postsize < 0) {
       result = expect100(data, conn, req_buffer);
       result = expect100(data, conn, req_buffer);
       if(result)
       if(result)
         return result;
         return result;
@@ -2606,7 +2628,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
          its size. */
          its size. */
       if(conn->httpversion != 20 &&
       if(conn->httpversion != 20 &&
          !data->state.expect100header &&
          !data->state.expect100header &&
-         (postsize < MAX_INITIAL_POST_SIZE))  {
+         (postsize < MAX_INITIAL_POST_SIZE)) {
         /* if we don't use expect: 100  AND
         /* if we don't use expect: 100  AND
            postsize is less than MAX_INITIAL_POST_SIZE
            postsize is less than MAX_INITIAL_POST_SIZE
 
 
@@ -2771,7 +2793,7 @@ checkhttpprefix(struct Curl_easy *data,
     failf(data, "Failed to allocate memory for conversion!");
     failf(data, "Failed to allocate memory for conversion!");
     return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */
     return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */
   }
   }
-  if(CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s)+1)) {
+  if(CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s) + 1)) {
     /* Curl_convert_from_network calls failf if unsuccessful */
     /* Curl_convert_from_network calls failf if unsuccessful */
     free(scratch);
     free(scratch);
     return FALSE; /* can't return CURLE_foobar so return FALSE */
     return FALSE; /* can't return CURLE_foobar so return FALSE */
@@ -2801,6 +2823,7 @@ static bool
 checkrtspprefix(struct Curl_easy *data,
 checkrtspprefix(struct Curl_easy *data,
                 const char *s)
                 const char *s)
 {
 {
+  bool result = FALSE;
 
 
 #ifdef CURL_DOES_CONVERSIONS
 #ifdef CURL_DOES_CONVERSIONS
   /* convert from the network encoding using a scratch area */
   /* convert from the network encoding using a scratch area */
@@ -2809,18 +2832,19 @@ checkrtspprefix(struct Curl_easy *data,
     failf(data, "Failed to allocate memory for conversion!");
     failf(data, "Failed to allocate memory for conversion!");
     return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */
     return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */
   }
   }
-  if(CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s)+1)) {
+  if(CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s) + 1)) {
     /* Curl_convert_from_network calls failf if unsuccessful */
     /* Curl_convert_from_network calls failf if unsuccessful */
-    free(scratch);
-    return FALSE; /* can't return CURLE_foobar so return FALSE */
+    result = FALSE; /* can't return CURLE_foobar so return FALSE */
   }
   }
-  s = scratch;
+  else
+    result = checkprefix("RTSP/", scratch)? TRUE: FALSE;
+  free(scratch);
 #else
 #else
   (void)data; /* unused */
   (void)data; /* unused */
+  result = checkprefix("RTSP/", s)? TRUE: FALSE;
 #endif /* CURL_DOES_CONVERSIONS */
 #endif /* CURL_DOES_CONVERSIONS */
-  if(checkprefix("RTSP/", s))
-    return TRUE;
-  return FALSE;
+
+  return result;
 }
 }
 #endif /* CURL_DISABLE_RTSP */
 #endif /* CURL_DISABLE_RTSP */
 
 
@@ -2862,14 +2886,14 @@ static CURLcode header_append(struct Curl_easy *data,
       return CURLE_OUT_OF_MEMORY;
       return CURLE_OUT_OF_MEMORY;
     }
     }
 
 
-    newsize=CURLMAX((k->hbuflen+ length)*3/2, data->state.headersize*2);
+    newsize = CURLMAX((k->hbuflen + length) * 3 / 2, data->state.headersize*2);
     hbufp_index = k->hbufp - data->state.headerbuff;
     hbufp_index = k->hbufp - data->state.headerbuff;
     newbuff = realloc(data->state.headerbuff, newsize);
     newbuff = realloc(data->state.headerbuff, newsize);
     if(!newbuff) {
     if(!newbuff) {
       failf(data, "Failed to alloc memory for big header!");
       failf(data, "Failed to alloc memory for big header!");
       return CURLE_OUT_OF_MEMORY;
       return CURLE_OUT_OF_MEMORY;
     }
     }
-    data->state.headersize=newsize;
+    data->state.headersize = newsize;
     data->state.headerbuff = newbuff;
     data->state.headerbuff = newbuff;
     k->hbufp = data->state.headerbuff + hbufp_index;
     k->hbufp = data->state.headerbuff + hbufp_index;
   }
   }
@@ -2962,7 +2986,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
     }
     }
 
 
     /* decrease the size of the remaining (supposed) header line */
     /* decrease the size of the remaining (supposed) header line */
-    rest_length = (k->end_ptr - k->str)+1;
+    rest_length = (k->end_ptr - k->str) + 1;
     *nread -= (ssize_t)rest_length;
     *nread -= (ssize_t)rest_length;
 
 
     k->str = k->end_ptr + 1; /* move past new line */
     k->str = k->end_ptr + 1; /* move past new line */
@@ -3161,6 +3185,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
           case HTTPREQ_PUT:
           case HTTPREQ_PUT:
           case HTTPREQ_POST:
           case HTTPREQ_POST:
           case HTTPREQ_POST_FORM:
           case HTTPREQ_POST_FORM:
+          case HTTPREQ_POST_MIME:
             /* We got an error response. If this happened before the whole
             /* We got an error response. If this happened before the whole
              * request body has been sent we stop sending and mark the
              * request body has been sent we stop sending and mark the
              * connection for closure after we've read the entire response.
              * connection for closure after we've read the entire response.
@@ -3288,7 +3313,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
 #define HEADER1 scratch
 #define HEADER1 scratch
 #define SCRATCHSIZE 21
 #define SCRATCHSIZE 21
       CURLcode res;
       CURLcode res;
-      char scratch[SCRATCHSIZE+1]; /* "HTTP/major.minor 123" */
+      char scratch[SCRATCHSIZE + 1]; /* "HTTP/major.minor 123" */
       /* We can't really convert this yet because we
       /* We can't really convert this yet because we
          don't know if it's the 1st header line or the body.
          don't know if it's the 1st header line or the body.
          So we do a partial conversion into a scratch area,
          So we do a partial conversion into a scratch area,
@@ -3314,19 +3339,22 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
          * says. We try to allow any number here, but we cannot make
          * says. We try to allow any number here, but we cannot make
          * guarantees on future behaviors since it isn't within the protocol.
          * guarantees on future behaviors since it isn't within the protocol.
          */
          */
+        char separator;
         nc = sscanf(HEADER1,
         nc = sscanf(HEADER1,
-                    " HTTP/%d.%d %d",
+                    " HTTP/%1d.%1d%c%3d",
                     &httpversion_major,
                     &httpversion_major,
                     &conn->httpversion,
                     &conn->httpversion,
+                    &separator,
                     &k->httpcode);
                     &k->httpcode);
 
 
         if(nc == 1 && httpversion_major == 2 &&
         if(nc == 1 && httpversion_major == 2 &&
            1 == sscanf(HEADER1, " HTTP/2 %d", &k->httpcode)) {
            1 == sscanf(HEADER1, " HTTP/2 %d", &k->httpcode)) {
           conn->httpversion = 0;
           conn->httpversion = 0;
-          nc = 3;
+          nc = 4;
+          separator = ' ';
         }
         }
 
 
-        if(nc==3) {
+        if((nc == 4) && (' ' == separator)) {
           conn->httpversion += 10 * httpversion_major;
           conn->httpversion += 10 * httpversion_major;
 
 
           if(k->upgr101 == UPGR101_RECEIVED) {
           if(k->upgr101 == UPGR101_RECEIVED) {
@@ -3335,11 +3363,11 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
               infof(data, "Lying server, not serving HTTP/2\n");
               infof(data, "Lying server, not serving HTTP/2\n");
           }
           }
         }
         }
-        else {
+        else if(!nc) {
           /* this is the real world, not a Nirvana
           /* this is the real world, not a Nirvana
              NCSA 1.5.x returns this crap when asked for HTTP/1.1
              NCSA 1.5.x returns this crap when asked for HTTP/1.1
           */
           */
-          nc=sscanf(HEADER1, " HTTP %3d", &k->httpcode);
+          nc = sscanf(HEADER1, " HTTP %3d", &k->httpcode);
           conn->httpversion = 10;
           conn->httpversion = 10;
 
 
           /* If user has set option HTTP200ALIASES,
           /* If user has set option HTTP200ALIASES,
@@ -3353,6 +3381,10 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
             }
             }
           }
           }
         }
         }
+        else {
+          failf(data, "Unsupported HTTP version in response\n");
+          return CURLE_UNSUPPORTED_PROTOCOL;
+        }
       }
       }
       else if(conn->handler->protocol & CURLPROTO_RTSP) {
       else if(conn->handler->protocol & CURLPROTO_RTSP) {
         nc = sscanf(HEADER1,
         nc = sscanf(HEADER1,
@@ -3360,7 +3392,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
                     &rtspversion_major,
                     &rtspversion_major,
                     &conn->rtspversion,
                     &conn->rtspversion,
                     &k->httpcode);
                     &k->httpcode);
-        if(nc==3) {
+        if(nc == 3) {
           conn->rtspversion += 10 * rtspversion_major;
           conn->rtspversion += 10 * rtspversion_major;
           conn->httpversion = 11; /* For us, RTSP acts like HTTP 1.1 */
           conn->httpversion = 11; /* For us, RTSP acts like HTTP 1.1 */
         }
         }
@@ -3392,7 +3424,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
            ((k->httpcode != 407) || !conn->bits.proxy_user_passwd) ) {
            ((k->httpcode != 407) || !conn->bits.proxy_user_passwd) ) {
 
 
           if(data->state.resume_from &&
           if(data->state.resume_from &&
-             (data->set.httpreq==HTTPREQ_GET) &&
+             (data->set.httpreq == HTTPREQ_GET) &&
              (k->httpcode == 416)) {
              (k->httpcode == 416)) {
             /* "Requested Range Not Satisfiable", just proceed and
             /* "Requested Range Not Satisfiable", just proceed and
                pretend this is no error */
                pretend this is no error */
@@ -3448,8 +3480,8 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
            * fields.  */
            * fields.  */
           if(data->set.timecondition)
           if(data->set.timecondition)
             data->info.timecond = TRUE;
             data->info.timecond = TRUE;
-          k->size=0;
-          k->maxdownload=0;
+          k->size = 0;
+          k->maxdownload = 0;
           k->ignorecl = TRUE; /* ignore Content-Length headers */
           k->ignorecl = TRUE; /* ignore Content-Length headers */
           break;
           break;
         default:
         default:
@@ -3471,28 +3503,32 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
     /* Check for Content-Length: header lines to get size */
     /* Check for Content-Length: header lines to get size */
     if(!k->ignorecl && !data->set.ignorecl &&
     if(!k->ignorecl && !data->set.ignorecl &&
        checkprefix("Content-Length:", k->p)) {
        checkprefix("Content-Length:", k->p)) {
-      curl_off_t contentlength = curlx_strtoofft(k->p+15, NULL, 10);
-      if(data->set.max_filesize &&
-         contentlength > data->set.max_filesize) {
-        failf(data, "Maximum file size exceeded");
-        return CURLE_FILESIZE_EXCEEDED;
-      }
-      if(contentlength >= 0) {
-        k->size = contentlength;
-        k->maxdownload = k->size;
-        /* we set the progress download size already at this point
-           just to make it easier for apps/callbacks to extract this
-           info as soon as possible */
-        Curl_pgrsSetDownloadSize(data, k->size);
-      }
-      else {
-        /* Negative Content-Length is really odd, and we know it
-           happens for example when older Apache servers send large
-           files */
-        streamclose(conn, "negative content-length");
-        infof(data, "Negative content-length: %" CURL_FORMAT_CURL_OFF_T
-              ", closing after transfer\n", contentlength);
+      curl_off_t contentlength;
+      if(!curlx_strtoofft(k->p + 15, NULL, 10, &contentlength)) {
+        if(data->set.max_filesize &&
+           contentlength > data->set.max_filesize) {
+          failf(data, "Maximum file size exceeded");
+          return CURLE_FILESIZE_EXCEEDED;
+        }
+        if(contentlength >= 0) {
+          k->size = contentlength;
+          k->maxdownload = k->size;
+          /* we set the progress download size already at this point
+             just to make it easier for apps/callbacks to extract this
+             info as soon as possible */
+          Curl_pgrsSetDownloadSize(data, k->size);
+        }
+        else {
+          /* Negative Content-Length is really odd, and we know it
+             happens for example when older Apache servers send large
+             files */
+          streamclose(conn, "negative content-length");
+          infof(data, "Negative content-length: %" CURL_FORMAT_CURL_OFF_T
+                ", closing after transfer\n", contentlength);
+        }
       }
       }
+      else
+        infof(data, "Illegal Content-Length: header\n");
     }
     }
     /* check for Content-Type: header lines to get the MIME-type */
     /* check for Content-Type: header lines to get the MIME-type */
     else if(checkprefix("Content-Type:", k->p)) {
     else if(checkprefix("Content-Type:", k->p)) {
@@ -3667,11 +3703,11 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
 
 
       /* if it truly stopped on a digit */
       /* if it truly stopped on a digit */
       if(ISDIGIT(*ptr)) {
       if(ISDIGIT(*ptr)) {
-        k->offset = curlx_strtoofft(ptr, NULL, 10);
-
-        if(data->state.resume_from == k->offset)
-          /* we asked for a resume and we got it */
-          k->content_range = TRUE;
+        if(!curlx_strtoofft(ptr, NULL, 10, &k->offset)) {
+          if(data->state.resume_from == k->offset)
+            /* we asked for a resume and we got it */
+            k->content_range = TRUE;
+        }
       }
       }
       else
       else
         data->state.resume_from = 0; /* get everything */
         data->state.resume_from = 0; /* get everything */
@@ -3682,7 +3718,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
       Curl_share_lock(data, CURL_LOCK_DATA_COOKIE,
       Curl_share_lock(data, CURL_LOCK_DATA_COOKIE,
                       CURL_LOCK_ACCESS_SINGLE);
                       CURL_LOCK_ACCESS_SINGLE);
       Curl_cookie_add(data,
       Curl_cookie_add(data,
-                      data->cookies, TRUE, k->p+11,
+                      data->cookies, TRUE, k->p + 11,
                       /* If there is a custom-set Host: name, use it
                       /* If there is a custom-set Host: name, use it
                          here, or else use real peer host name. */
                          here, or else use real peer host name. */
                       conn->allocptr.cookiehost?
                       conn->allocptr.cookiehost?
@@ -3693,8 +3729,8 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
 #endif
 #endif
     else if(checkprefix("Last-Modified:", k->p) &&
     else if(checkprefix("Last-Modified:", k->p) &&
             (data->set.timecondition || data->set.get_filetime) ) {
             (data->set.timecondition || data->set.get_filetime) ) {
-      time_t secs=time(NULL);
-      k->timeofdoc = curl_getdate(k->p+strlen("Last-Modified:"),
+      time_t secs = time(NULL);
+      k->timeofdoc = curl_getdate(k->p + strlen("Last-Modified:"),
                                   &secs);
                                   &secs);
       if(data->set.get_filetime)
       if(data->set.get_filetime)
         data->info.filetime = (long)k->timeofdoc;
         data->info.filetime = (long)k->timeofdoc;

+ 10 - 7
Utilities/cmcurl/lib/http.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -40,8 +40,6 @@ bool Curl_compareheader(const char *headerline,  /* line to check */
                         const char *header,   /* header keyword _with_ colon */
                         const char *header,   /* header keyword _with_ colon */
                         const char *content); /* content string to find */
                         const char *content); /* content string to find */
 
 
-char *Curl_checkheaders(const struct connectdata *conn,
-                        const char *thisheader);
 char *Curl_copy_header_value(const char *header);
 char *Curl_copy_header_value(const char *header);
 
 
 char *Curl_checkProxyheaders(const struct connectdata *conn,
 char *Curl_checkProxyheaders(const struct connectdata *conn,
@@ -115,8 +113,13 @@ CURLcode Curl_http_perhapsrewind(struct connectdata *conn);
 #define MAX_INITIAL_POST_SIZE (64*1024)
 #define MAX_INITIAL_POST_SIZE (64*1024)
 #endif
 #endif
 
 
-#ifndef TINY_INITIAL_POST_SIZE
-#define TINY_INITIAL_POST_SIZE 1024
+/* EXPECT_100_THRESHOLD is the request body size limit for when libcurl will
+ * automatically add an "Expect: 100-continue" header in HTTP requests. When
+ * the size is unknown, it will always add it.
+ *
+ */
+#ifndef EXPECT_100_THRESHOLD
+#define EXPECT_100_THRESHOLD 1024
 #endif
 #endif
 
 
 #endif /* CURL_DISABLE_HTTP */
 #endif /* CURL_DISABLE_HTTP */
@@ -125,7 +128,7 @@ CURLcode Curl_http_perhapsrewind(struct connectdata *conn);
  * HTTP unique setup
  * HTTP unique setup
  ***************************************************************************/
  ***************************************************************************/
 struct HTTP {
 struct HTTP {
-  struct FormData *sendit;
+  curl_mimepart *sendit;
   curl_off_t postsize; /* off_t to handle large file sizes */
   curl_off_t postsize; /* off_t to handle large file sizes */
   const char *postdata;
   const char *postdata;
 
 
@@ -135,7 +138,7 @@ struct HTTP {
   curl_off_t writebytecount;
   curl_off_t writebytecount;
 
 
   /* For FORM posting */
   /* For FORM posting */
-  struct Form form;
+  curl_mimepart form;
 
 
   struct back {
   struct back {
     curl_read_callback fread_func; /* backup storage for fread pointer */
     curl_read_callback fread_func; /* backup storage for fread pointer */

+ 58 - 7
Utilities/cmcurl/lib/http2.c

@@ -28,6 +28,7 @@
 #include "http2.h"
 #include "http2.h"
 #include "http.h"
 #include "http.h"
 #include "sendf.h"
 #include "sendf.h"
+#include "select.h"
 #include "curl_base64.h"
 #include "curl_base64.h"
 #include "strcase.h"
 #include "strcase.h"
 #include "multiif.h"
 #include "multiif.h"
@@ -151,6 +152,49 @@ static CURLcode http2_disconnect(struct connectdata *conn,
   return CURLE_OK;
   return CURLE_OK;
 }
 }
 
 
+/*
+ * The server may send us data at any point (e.g. PING frames). Therefore,
+ * we cannot assume that an HTTP/2 socket is dead just because it is readable.
+ *
+ * Instead, if it is readable, run Curl_connalive() to peek at the socket
+ * and distinguish between closed and data.
+ */
+static bool http2_connisdead(struct connectdata *check)
+{
+  int sval;
+  bool ret_val = TRUE;
+
+  sval = SOCKET_READABLE(check->sock[FIRSTSOCKET], 0);
+  if(sval == 0) {
+    /* timeout */
+    ret_val = FALSE;
+  }
+  else if(sval & CURL_CSELECT_ERR) {
+    /* socket is in an error state */
+    ret_val = TRUE;
+  }
+  else if(sval & CURL_CSELECT_IN) {
+    /* readable with no error. could still be closed */
+    ret_val = !Curl_connalive(check);
+  }
+
+  return ret_val;
+}
+
+
+static unsigned int http2_conncheck(struct connectdata *check,
+                                    unsigned int checks_to_perform)
+{
+  unsigned int ret_val = CONNRESULT_NONE;
+
+  if(checks_to_perform & CONNCHECK_ISDEAD) {
+    if(http2_connisdead(check))
+      ret_val |= CONNRESULT_DEAD;
+  }
+
+  return ret_val;
+}
+
 /* called from Curl_http_setup_conn */
 /* called from Curl_http_setup_conn */
 void Curl_http2_setup_req(struct Curl_easy *data)
 void Curl_http2_setup_req(struct Curl_easy *data)
 {
 {
@@ -196,6 +240,7 @@ static const struct Curl_handler Curl_handler_http2 = {
   http2_perform_getsock,                /* perform_getsock */
   http2_perform_getsock,                /* perform_getsock */
   http2_disconnect,                     /* disconnect */
   http2_disconnect,                     /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
+  http2_conncheck,                      /* connection_check */
   PORT_HTTP,                            /* defport */
   PORT_HTTP,                            /* defport */
   CURLPROTO_HTTP,                       /* protocol */
   CURLPROTO_HTTP,                       /* protocol */
   PROTOPT_STREAM                        /* flags */
   PROTOPT_STREAM                        /* flags */
@@ -216,6 +261,7 @@ static const struct Curl_handler Curl_handler_http2_ssl = {
   http2_perform_getsock,                /* perform_getsock */
   http2_perform_getsock,                /* perform_getsock */
   http2_disconnect,                     /* disconnect */
   http2_disconnect,                     /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
+  http2_conncheck,                      /* connection_check */
   PORT_HTTP,                            /* defport */
   PORT_HTTP,                            /* defport */
   CURLPROTO_HTTPS,                      /* protocol */
   CURLPROTO_HTTPS,                      /* protocol */
   PROTOPT_SSL | PROTOPT_STREAM          /* flags */
   PROTOPT_SSL | PROTOPT_STREAM          /* flags */
@@ -338,12 +384,12 @@ char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header)
     struct HTTP *stream = h->data->req.protop;
     struct HTTP *stream = h->data->req.protop;
     size_t len = strlen(header);
     size_t len = strlen(header);
     size_t i;
     size_t i;
-    for(i=0; i<stream->push_headers_used; i++) {
+    for(i = 0; i<stream->push_headers_used; i++) {
       if(!strncmp(header, stream->push_headers[i], len)) {
       if(!strncmp(header, stream->push_headers[i], len)) {
         /* sub-match, make sure that it is followed by a colon */
         /* sub-match, make sure that it is followed by a colon */
         if(stream->push_headers[i][len] != ':')
         if(stream->push_headers[i][len] != ':')
           continue;
           continue;
-        return &stream->push_headers[i][len+1];
+        return &stream->push_headers[i][len + 1];
       }
       }
     }
     }
   }
   }
@@ -418,7 +464,7 @@ static int push_promise(struct Curl_easy *data,
                               data->multi->push_userp);
                               data->multi->push_userp);
 
 
     /* free the headers again */
     /* free the headers again */
-    for(i=0; i<stream->push_headers_used; i++)
+    for(i = 0; i<stream->push_headers_used; i++)
       free(stream->push_headers[i]);
       free(stream->push_headers[i]);
     free(stream->push_headers);
     free(stream->push_headers);
     stream->push_headers = NULL;
     stream->push_headers = NULL;
@@ -1536,7 +1582,7 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
       failf(data, "nghttp2_session_mem_recv() returned %d:%s\n",
       failf(data, "nghttp2_session_mem_recv() returned %d:%s\n",
             rv, nghttp2_strerror((int)rv));
             rv, nghttp2_strerror((int)rv));
       *err = CURLE_RECV_ERROR;
       *err = CURLE_RECV_ERROR;
-      return 0;
+      return -1;
     }
     }
     DEBUGF(infof(data, "nghttp2_session_mem_recv() returns %zd\n", rv));
     DEBUGF(infof(data, "nghttp2_session_mem_recv() returns %zd\n", rv));
     if(nread == rv) {
     if(nread == rv) {
@@ -1554,7 +1600,7 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
     rv = h2_session_send(data, httpc->h2);
     rv = h2_session_send(data, httpc->h2);
     if(rv != 0) {
     if(rv != 0) {
       *err = CURLE_SEND_ERROR;
       *err = CURLE_SEND_ERROR;
-      return 0;
+      return -1;
     }
     }
 
 
     if(should_close_session(httpc)) {
     if(should_close_session(httpc)) {
@@ -1909,6 +1955,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
   switch(conn->data->set.httpreq) {
   switch(conn->data->set.httpreq) {
   case HTTPREQ_POST:
   case HTTPREQ_POST:
   case HTTPREQ_POST_FORM:
   case HTTPREQ_POST_FORM:
+  case HTTPREQ_POST_MIME:
   case HTTPREQ_PUT:
   case HTTPREQ_PUT:
     if(conn->data->state.infilesize != -1)
     if(conn->data->state.infilesize != -1)
       stream->upload_left = conn->data->state.infilesize;
       stream->upload_left = conn->data->state.infilesize;
@@ -2134,12 +2181,15 @@ CURLcode Curl_http2_switched(struct connectdata *conn,
   return CURLE_OK;
   return CURLE_OK;
 }
 }
 
 
-void Curl_http2_add_child(struct Curl_easy *parent, struct Curl_easy *child,
-                          bool exclusive)
+CURLcode Curl_http2_add_child(struct Curl_easy *parent,
+                              struct Curl_easy *child,
+                              bool exclusive)
 {
 {
   if(parent) {
   if(parent) {
     struct Curl_http2_dep **tail;
     struct Curl_http2_dep **tail;
     struct Curl_http2_dep *dep = calloc(1, sizeof(struct Curl_http2_dep));
     struct Curl_http2_dep *dep = calloc(1, sizeof(struct Curl_http2_dep));
+    if(!dep)
+      return CURLE_OUT_OF_MEMORY;
     dep->data = child;
     dep->data = child;
 
 
     if(parent->set.stream_dependents && exclusive) {
     if(parent->set.stream_dependents && exclusive) {
@@ -2170,6 +2220,7 @@ void Curl_http2_add_child(struct Curl_easy *parent, struct Curl_easy *child,
 
 
   child->set.stream_depends_on = parent;
   child->set.stream_depends_on = parent;
   child->set.stream_depends_e = exclusive;
   child->set.stream_depends_e = exclusive;
+  return CURLE_OK;
 }
 }
 
 
 void Curl_http2_remove_child(struct Curl_easy *parent, struct Curl_easy *child)
 void Curl_http2_remove_child(struct Curl_easy *parent, struct Curl_easy *child)

+ 4 - 3
Utilities/cmcurl/lib/http2.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -53,8 +53,9 @@ void Curl_http2_setup_conn(struct connectdata *conn);
 void Curl_http2_setup_req(struct Curl_easy *data);
 void Curl_http2_setup_req(struct Curl_easy *data);
 void Curl_http2_done(struct connectdata *conn, bool premature);
 void Curl_http2_done(struct connectdata *conn, bool premature);
 CURLcode Curl_http2_done_sending(struct connectdata *conn);
 CURLcode Curl_http2_done_sending(struct connectdata *conn);
-void Curl_http2_add_child(struct Curl_easy *parent, struct Curl_easy *child,
-                          bool exclusive);
+CURLcode Curl_http2_add_child(struct Curl_easy *parent,
+                              struct Curl_easy *child,
+                              bool exclusive);
 void Curl_http2_remove_child(struct Curl_easy *parent,
 void Curl_http2_remove_child(struct Curl_easy *parent,
                              struct Curl_easy *child);
                              struct Curl_easy *child);
 void Curl_http2_cleanup_dependencies(struct Curl_easy *data);
 void Curl_http2_cleanup_dependencies(struct Curl_easy *data);

+ 12 - 14
Utilities/cmcurl/lib/http_chunks.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -86,8 +86,8 @@ static bool Curl_isxdigit(char digit)
 void Curl_httpchunk_init(struct connectdata *conn)
 void Curl_httpchunk_init(struct connectdata *conn)
 {
 {
   struct Curl_chunker *chunk = &conn->chunk;
   struct Curl_chunker *chunk = &conn->chunk;
-  chunk->hexindex=0;        /* start at 0 */
-  chunk->dataleft=0;        /* no data left yet! */
+  chunk->hexindex = 0;      /* start at 0 */
+  chunk->dataleft = 0;      /* no data left yet! */
   chunk->state = CHUNK_HEX; /* we get hex first! */
   chunk->state = CHUNK_HEX; /* we get hex first! */
 }
 }
 
 
@@ -107,7 +107,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
                               ssize_t datalen,
                               ssize_t datalen,
                               ssize_t *wrotep)
                               ssize_t *wrotep)
 {
 {
-  CURLcode result=CURLE_OK;
+  CURLcode result = CURLE_OK;
   struct Curl_easy *data = conn->data;
   struct Curl_easy *data = conn->data;
   struct Curl_chunker *ch = &conn->chunk;
   struct Curl_chunker *ch = &conn->chunk;
   struct SingleRequest *k = &data->req;
   struct SingleRequest *k = &data->req;
@@ -147,7 +147,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
           return CHUNKE_ILLEGAL_HEX;
           return CHUNKE_ILLEGAL_HEX;
 
 
         /* length and datap are unmodified */
         /* length and datap are unmodified */
-        ch->hexbuffer[ch->hexindex]=0;
+        ch->hexbuffer[ch->hexindex] = 0;
 
 
         /* convert to host encoding before calling strtoul */
         /* convert to host encoding before calling strtoul */
         result = Curl_convert_from_network(conn->data, ch->hexbuffer,
         result = Curl_convert_from_network(conn->data, ch->hexbuffer,
@@ -158,9 +158,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
           return CHUNKE_ILLEGAL_HEX;
           return CHUNKE_ILLEGAL_HEX;
         }
         }
 
 
-        ch->datasize=curlx_strtoofft(ch->hexbuffer, &endptr, 16);
-        if((ch->datasize == CURL_OFF_T_MAX) && (errno == ERANGE))
-          /* overflow is an error */
+        if(curlx_strtoofft(ch->hexbuffer, &endptr, 16, &ch->datasize))
           return CHUNKE_ILLEGAL_HEX;
           return CHUNKE_ILLEGAL_HEX;
         ch->state = CHUNK_LF; /* now wait for the CRLF */
         ch->state = CHUNK_LF; /* now wait for the CRLF */
       }
       }
@@ -172,7 +170,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
         /* we're now expecting data to come, unless size was zero! */
         /* we're now expecting data to come, unless size was zero! */
         if(0 == ch->datasize) {
         if(0 == ch->datasize) {
           ch->state = CHUNK_TRAILER; /* now check for trailers */
           ch->state = CHUNK_TRAILER; /* now check for trailers */
-          conn->trlPos=0;
+          conn->trlPos = 0;
         }
         }
         else
         else
           ch->state = CHUNK_DATA;
           ch->state = CHUNK_DATA;
@@ -259,9 +257,9 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
 
 
         if(conn->trlPos) {
         if(conn->trlPos) {
           /* we allocate trailer with 3 bytes extra room to fit this */
           /* we allocate trailer with 3 bytes extra room to fit this */
-          conn->trailer[conn->trlPos++]=0x0d;
-          conn->trailer[conn->trlPos++]=0x0a;
-          conn->trailer[conn->trlPos]=0;
+          conn->trailer[conn->trlPos++] = 0x0d;
+          conn->trailer[conn->trlPos++] = 0x0a;
+          conn->trailer[conn->trlPos] = 0;
 
 
           /* Convert to host encoding before calling Curl_client_write */
           /* Convert to host encoding before calling Curl_client_write */
           result = Curl_convert_from_network(conn->data, conn->trailer,
           result = Curl_convert_from_network(conn->data, conn->trailer,
@@ -277,7 +275,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
             if(result)
             if(result)
               return CHUNKE_WRITE_ERROR;
               return CHUNKE_WRITE_ERROR;
           }
           }
-          conn->trlPos=0;
+          conn->trlPos = 0;
           ch->state = CHUNK_TRAILER_CR;
           ch->state = CHUNK_TRAILER_CR;
           if(*datap == 0x0a)
           if(*datap == 0x0a)
             /* already on the LF */
             /* already on the LF */
@@ -301,7 +299,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
             ptr = realloc(conn->trailer, conn->trlMax + 3);
             ptr = realloc(conn->trailer, conn->trlMax + 3);
           }
           }
           else {
           else {
-            conn->trlMax=128;
+            conn->trlMax = 128;
             ptr = malloc(conn->trlMax + 3);
             ptr = malloc(conn->trlMax + 3);
           }
           }
           if(!ptr)
           if(!ptr)

+ 8 - 5
Utilities/cmcurl/lib/http_ntlm.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -37,11 +37,14 @@
 #include "sendf.h"
 #include "sendf.h"
 #include "strcase.h"
 #include "strcase.h"
 #include "http_ntlm.h"
 #include "http_ntlm.h"
+#include "curl_ntlm_core.h"
 #include "curl_ntlm_wb.h"
 #include "curl_ntlm_wb.h"
 #include "vauth/vauth.h"
 #include "vauth/vauth.h"
 #include "url.h"
 #include "url.h"
 
 
-#if defined(USE_NSS)
+/* SSL backend-specific #if branches in this file must be kept in the order
+   documented in curl_ntlm_core. */
+#if defined(NTLM_NEEDS_NSS_INIT)
 #include "vtls/nssg.h"
 #include "vtls/nssg.h"
 #elif defined(USE_WINDOWS_SSPI)
 #elif defined(USE_WINDOWS_SSPI)
 #include "curl_sspi.h"
 #include "curl_sspi.h"
@@ -129,7 +132,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
   DEBUGASSERT(conn);
   DEBUGASSERT(conn);
   DEBUGASSERT(conn->data);
   DEBUGASSERT(conn->data);
 
 
-#ifdef USE_NSS
+#if defined(NTLM_NEEDS_NSS_INIT)
   if(CURLE_OK != Curl_nss_force_init(conn->data))
   if(CURLE_OK != Curl_nss_force_init(conn->data))
     return CURLE_OUT_OF_MEMORY;
     return CURLE_OUT_OF_MEMORY;
 #endif
 #endif
@@ -170,8 +173,8 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
   case NTLMSTATE_TYPE1:
   case NTLMSTATE_TYPE1:
   default: /* for the weird cases we (re)start here */
   default: /* for the weird cases we (re)start here */
     /* Create a type-1 message */
     /* Create a type-1 message */
-    result = Curl_auth_create_ntlm_type1_message(userp, passwdp, ntlm, &base64,
-                                                 &len);
+    result = Curl_auth_create_ntlm_type1_message(conn->data, userp, passwdp,
+                                                 ntlm, &base64, &len);
     if(result)
     if(result)
       return result;
       return result;
 
 

+ 154 - 124
Utilities/cmcurl/lib/http_proxy.c

@@ -22,11 +22,11 @@
 
 
 #include "curl_setup.h"
 #include "curl_setup.h"
 
 
+#include "http_proxy.h"
+
 #if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP)
 #if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP)
 
 
-#include "urldata.h"
 #include <curl/curl.h>
 #include <curl/curl.h>
-#include "http_proxy.h"
 #include "sendf.h"
 #include "sendf.h"
 #include "http.h"
 #include "http.h"
 #include "url.h"
 #include "url.h"
@@ -135,35 +135,73 @@ CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex)
   return CURLE_OK;
   return CURLE_OK;
 }
 }
 
 
-#define CONNECT_BUFFER_SIZE 16384
+bool Curl_connect_complete(struct connectdata *conn)
+{
+  return !conn->connect_state ||
+    (conn->connect_state->tunnel_state == TUNNEL_COMPLETE);
+}
+
+bool Curl_connect_ongoing(struct connectdata *conn)
+{
+  return conn->connect_state &&
+    (conn->connect_state->tunnel_state != TUNNEL_COMPLETE);
+}
+
+static CURLcode connect_init(struct connectdata *conn, bool reinit)
+{
+  struct http_connect_state *s;
+  if(!reinit) {
+    DEBUGASSERT(!conn->connect_state);
+    s = calloc(1, sizeof(struct http_connect_state));
+    if(!s)
+      return CURLE_OUT_OF_MEMORY;
+    infof(conn->data, "allocate connect buffer!\n");
+    conn->connect_state = s;
+  }
+  else {
+    DEBUGASSERT(conn->connect_state);
+    s = conn->connect_state;
+  }
+  s->tunnel_state = TUNNEL_INIT;
+  s->keepon = TRUE;
+  s->line_start = s->connect_buffer;
+  s->ptr = s->line_start;
+  s->cl = 0;
+  return CURLE_OK;
+}
+
+static void connect_done(struct connectdata *conn)
+{
+  struct http_connect_state *s = conn->connect_state;
+  s->tunnel_state = TUNNEL_COMPLETE;
+  infof(conn->data, "CONNECT phase completed!\n");
+}
 
 
 static CURLcode CONNECT(struct connectdata *conn,
 static CURLcode CONNECT(struct connectdata *conn,
                         int sockindex,
                         int sockindex,
                         const char *hostname,
                         const char *hostname,
                         int remote_port)
                         int remote_port)
 {
 {
-  int subversion=0;
-  struct Curl_easy *data=conn->data;
+  int subversion = 0;
+  struct Curl_easy *data = conn->data;
   struct SingleRequest *k = &data->req;
   struct SingleRequest *k = &data->req;
   CURLcode result;
   CURLcode result;
   curl_socket_t tunnelsocket = conn->sock[sockindex];
   curl_socket_t tunnelsocket = conn->sock[sockindex];
-  curl_off_t cl=0;
   bool closeConnection = FALSE;
   bool closeConnection = FALSE;
-  bool chunked_encoding = FALSE;
   time_t check;
   time_t check;
+  struct http_connect_state *s = conn->connect_state;
 
 
 #define SELECT_OK      0
 #define SELECT_OK      0
 #define SELECT_ERROR   1
 #define SELECT_ERROR   1
 #define SELECT_TIMEOUT 2
 #define SELECT_TIMEOUT 2
-  int error = SELECT_OK;
 
 
-  if(conn->tunnel_state[sockindex] == TUNNEL_COMPLETE)
+  if(Curl_connect_complete(conn))
     return CURLE_OK; /* CONNECT is already completed */
     return CURLE_OK; /* CONNECT is already completed */
 
 
   conn->bits.proxy_connect_closed = FALSE;
   conn->bits.proxy_connect_closed = FALSE;
 
 
   do {
   do {
-    if(TUNNEL_INIT == conn->tunnel_state[sockindex]) {
+    if(TUNNEL_INIT == s->tunnel_state) {
       /* BEGIN CONNECT PHASE */
       /* BEGIN CONNECT PHASE */
       char *host_port;
       char *host_port;
       Curl_send_buffer *req_buffer;
       Curl_send_buffer *req_buffer;
@@ -196,8 +234,8 @@ static CURLcode CONNECT(struct connectdata *conn,
 
 
       if(!result) {
       if(!result) {
         char *host = NULL;
         char *host = NULL;
-        const char *proxyconn="";
-        const char *useragent="";
+        const char *proxyconn = "";
+        const char *useragent = "";
         const char *http = (conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) ?
         const char *http = (conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) ?
           "1.0" : "1.1";
           "1.0" : "1.1";
         bool ipv6_ip = conn->bits.ipv6_ip;
         bool ipv6_ip = conn->bits.ipv6_ip;
@@ -206,7 +244,7 @@ static CURLcode CONNECT(struct connectdata *conn,
         /* the hostname may be different */
         /* the hostname may be different */
         if(hostname != conn->host.name)
         if(hostname != conn->host.name)
           ipv6_ip = (strchr(hostname, ':') != NULL);
           ipv6_ip = (strchr(hostname, ':') != NULL);
-        hostheader= /* host:port with IPv6 support */
+        hostheader = /* host:port with IPv6 support */
           aprintf("%s%s%s:%hu", ipv6_ip?"[":"", hostname, ipv6_ip?"]":"",
           aprintf("%s%s%s:%hu", ipv6_ip?"[":"", hostname, ipv6_ip?"]":"",
                   remote_port);
                   remote_port);
         if(!hostheader) {
         if(!hostheader) {
@@ -271,65 +309,46 @@ static CURLcode CONNECT(struct connectdata *conn,
       if(result)
       if(result)
         return result;
         return result;
 
 
-      conn->tunnel_state[sockindex] = TUNNEL_CONNECT;
+      s->tunnel_state = TUNNEL_CONNECT;
+      s->perline = 0;
     } /* END CONNECT PHASE */
     } /* END CONNECT PHASE */
 
 
     check = Curl_timeleft(data, NULL, TRUE);
     check = Curl_timeleft(data, NULL, TRUE);
     if(check <= 0) {
     if(check <= 0) {
       failf(data, "Proxy CONNECT aborted due to timeout");
       failf(data, "Proxy CONNECT aborted due to timeout");
-      return CURLE_RECV_ERROR;
+      return CURLE_OPERATION_TIMEDOUT;
     }
     }
 
 
     if(!Curl_conn_data_pending(conn, sockindex))
     if(!Curl_conn_data_pending(conn, sockindex))
       /* return so we'll be called again polling-style */
       /* return so we'll be called again polling-style */
       return CURLE_OK;
       return CURLE_OK;
-    DEBUGF(infof(data, "Read response immediately from proxy CONNECT\n"));
 
 
     /* at this point, the tunnel_connecting phase is over. */
     /* at this point, the tunnel_connecting phase is over. */
 
 
     { /* READING RESPONSE PHASE */
     { /* READING RESPONSE PHASE */
-      size_t nread;   /* total size read */
-      int perline; /* count bytes per line */
-      int keepon=TRUE;
-      ssize_t gotbytes;
-      char *ptr;
-      char *line_start;
+      int error = SELECT_OK;
 
 
-      ptr = conn->connect_buffer;
-      line_start = ptr;
+      while(s->keepon && !error) {
+        ssize_t gotbytes;
 
 
-      nread = 0;
-      perline = 0;
-
-      while(nread < (size_t)CONNECT_BUFFER_SIZE && keepon && !error) {
-        if(Curl_pgrsUpdate(conn))
-          return CURLE_ABORTED_BY_CALLBACK;
-
-        if(ptr >= &conn->connect_buffer[CONNECT_BUFFER_SIZE]) {
+        /* make sure we have space to read more data */
+        if(s->ptr >= &s->connect_buffer[CONNECT_BUFFER_SIZE]) {
           failf(data, "CONNECT response too large!");
           failf(data, "CONNECT response too large!");
           return CURLE_RECV_ERROR;
           return CURLE_RECV_ERROR;
         }
         }
 
 
-        check = Curl_timeleft(data, NULL, TRUE);
-        if(check <= 0) {
-          failf(data, "Proxy CONNECT aborted due to timeout");
-          error = SELECT_TIMEOUT; /* already too little time */
-          break;
-        }
-
         /* Read one byte at a time to avoid a race condition. Wait at most one
         /* Read one byte at a time to avoid a race condition. Wait at most one
            second before looping to ensure continuous pgrsUpdates. */
            second before looping to ensure continuous pgrsUpdates. */
-        result = Curl_read(conn, tunnelsocket, ptr, 1, &gotbytes);
-        if(result == CURLE_AGAIN) {
-          if(SOCKET_READABLE(tunnelsocket, check<1000L?check:1000) == -1) {
-            error = SELECT_ERROR;
-            failf(data, "Proxy CONNECT aborted due to select/poll error");
-            break;
-          }
-          continue;
-        }
+        result = Curl_read(conn, tunnelsocket, s->ptr, 1, &gotbytes);
+        if(result == CURLE_AGAIN)
+          /* socket buffer drained, return */
+          return CURLE_OK;
+
+        if(Curl_pgrsUpdate(conn))
+          return CURLE_ABORTED_BY_CALLBACK;
+
         if(result) {
         if(result) {
-          keepon = FALSE;
+          s->keepon = FALSE;
           break;
           break;
         }
         }
         else if(gotbytes <= 0) {
         else if(gotbytes <= 0) {
@@ -343,24 +362,22 @@ static CURLcode CONNECT(struct connectdata *conn,
             error = SELECT_ERROR;
             error = SELECT_ERROR;
             failf(data, "Proxy CONNECT aborted");
             failf(data, "Proxy CONNECT aborted");
           }
           }
-          keepon = FALSE;
+          s->keepon = FALSE;
           break;
           break;
         }
         }
 
 
-        /* We got a byte of data */
-        nread++;
 
 
-        if(keepon > TRUE) {
+        if(s->keepon > TRUE) {
           /* This means we are currently ignoring a response-body */
           /* This means we are currently ignoring a response-body */
 
 
-          nread = 0; /* make next read start over in the read buffer */
-          ptr = conn->connect_buffer;
-          if(cl) {
+          s->ptr = s->connect_buffer;
+          if(s->cl) {
             /* A Content-Length based body: simply count down the counter
             /* A Content-Length based body: simply count down the counter
                and make sure to break out of the loop when we're done! */
                and make sure to break out of the loop when we're done! */
-            cl--;
-            if(cl <= 0) {
-              keepon = FALSE;
+            s->cl--;
+            if(s->cl <= 0) {
+              s->keepon = FALSE;
+              s->tunnel_state = TUNNEL_COMPLETE;
               break;
               break;
             }
             }
           }
           }
@@ -372,28 +389,29 @@ static CURLcode CONNECT(struct connectdata *conn,
 
 
             /* now parse the chunked piece of data so that we can
             /* now parse the chunked piece of data so that we can
                properly tell when the stream ends */
                properly tell when the stream ends */
-            r = Curl_httpchunk_read(conn, ptr, 1, &tookcareof);
+            r = Curl_httpchunk_read(conn, s->ptr, 1, &tookcareof);
             if(r == CHUNKE_STOP) {
             if(r == CHUNKE_STOP) {
               /* we're done reading chunks! */
               /* we're done reading chunks! */
               infof(data, "chunk reading DONE\n");
               infof(data, "chunk reading DONE\n");
-              keepon = FALSE;
+              s->keepon = FALSE;
               /* we did the full CONNECT treatment, go COMPLETE */
               /* we did the full CONNECT treatment, go COMPLETE */
-              conn->tunnel_state[sockindex] = TUNNEL_COMPLETE;
+              s->tunnel_state = TUNNEL_COMPLETE;
             }
             }
           }
           }
           continue;
           continue;
         }
         }
 
 
-        perline++; /* amount of bytes in this line so far */
+        s->perline++; /* amount of bytes in this line so far */
 
 
         /* if this is not the end of a header line then continue */
         /* if this is not the end of a header line then continue */
-        if(*ptr != 0x0a) {
-          ptr++;
+        if(*s->ptr != 0x0a) {
+          s->ptr++;
           continue;
           continue;
         }
         }
 
 
         /* convert from the network encoding */
         /* convert from the network encoding */
-        result = Curl_convert_from_network(data, line_start, perline);
+        result = Curl_convert_from_network(data, s->line_start,
+                                           (size_t)s->perline);
         /* Curl_convert_from_network calls failf if unsuccessful */
         /* Curl_convert_from_network calls failf if unsuccessful */
         if(result)
         if(result)
           return result;
           return result;
@@ -401,7 +419,7 @@ static CURLcode CONNECT(struct connectdata *conn,
         /* output debug if that is requested */
         /* output debug if that is requested */
         if(data->set.verbose)
         if(data->set.verbose)
           Curl_debug(data, CURLINFO_HEADER_IN,
           Curl_debug(data, CURLINFO_HEADER_IN,
-                     line_start, (size_t)perline, conn);
+                     s->line_start, (size_t)s->perline, conn);
 
 
         if(!data->set.suppress_connect_headers) {
         if(!data->set.suppress_connect_headers) {
           /* send the header to the callback */
           /* send the header to the callback */
@@ -409,35 +427,34 @@ static CURLcode CONNECT(struct connectdata *conn,
           if(data->set.include_header)
           if(data->set.include_header)
             writetype |= CLIENTWRITE_BODY;
             writetype |= CLIENTWRITE_BODY;
 
 
-          result = Curl_client_write(conn, writetype, line_start, perline);
+          result = Curl_client_write(conn, writetype,
+                                     s->line_start, s->perline);
           if(result)
           if(result)
             return result;
             return result;
         }
         }
 
 
-        data->info.header_size += (long)perline;
-        data->req.headerbytecount += (long)perline;
+        data->info.header_size += (long)s->perline;
+        data->req.headerbytecount += (long)s->perline;
 
 
         /* Newlines are CRLF, so the CR is ignored as the line isn't
         /* Newlines are CRLF, so the CR is ignored as the line isn't
            really terminated until the LF comes. Treat a following CR
            really terminated until the LF comes. Treat a following CR
            as end-of-headers as well.*/
            as end-of-headers as well.*/
 
 
-        if(('\r' == line_start[0]) ||
-           ('\n' == line_start[0])) {
+        if(('\r' == s->line_start[0]) ||
+           ('\n' == s->line_start[0])) {
           /* end of response-headers from the proxy */
           /* end of response-headers from the proxy */
-          nread = 0; /* make next read start over in the read
-                        buffer */
-          ptr = conn->connect_buffer;
+          s->ptr = s->connect_buffer;
           if((407 == k->httpcode) && !data->state.authproblem) {
           if((407 == k->httpcode) && !data->state.authproblem) {
             /* If we get a 407 response code with content length
             /* If we get a 407 response code with content length
                when we have no auth problem, we must ignore the
                when we have no auth problem, we must ignore the
                whole response-body */
                whole response-body */
-            keepon = 2;
+            s->keepon = 2;
 
 
-            if(cl) {
+            if(s->cl) {
               infof(data, "Ignore %" CURL_FORMAT_CURL_OFF_T
               infof(data, "Ignore %" CURL_FORMAT_CURL_OFF_T
-                    " bytes of response-body\n", cl);
+                    " bytes of response-body\n", s->cl);
             }
             }
-            else if(chunked_encoding) {
+            else if(s->chunked_encoding) {
               CHUNKcode r;
               CHUNKcode r;
 
 
               infof(data, "Ignore chunked response-body\n");
               infof(data, "Ignore chunked response-body\n");
@@ -448,46 +465,46 @@ static CURLcode CONNECT(struct connectdata *conn,
                  function returns! */
                  function returns! */
               k->ignorebody = TRUE;
               k->ignorebody = TRUE;
 
 
-              if(line_start[1] == '\n') {
+              if(s->line_start[1] == '\n') {
                 /* this can only be a LF if the letter at index 0
                 /* this can only be a LF if the letter at index 0
                    was a CR */
                    was a CR */
-                line_start++;
+                s->line_start++;
               }
               }
 
 
               /* now parse the chunked piece of data so that we can
               /* now parse the chunked piece of data so that we can
                  properly tell when the stream ends */
                  properly tell when the stream ends */
-              r = Curl_httpchunk_read(conn, line_start + 1, 1, &gotbytes);
+              r = Curl_httpchunk_read(conn, s->line_start + 1, 1, &gotbytes);
               if(r == CHUNKE_STOP) {
               if(r == CHUNKE_STOP) {
                 /* we're done reading chunks! */
                 /* we're done reading chunks! */
                 infof(data, "chunk reading DONE\n");
                 infof(data, "chunk reading DONE\n");
-                keepon = FALSE;
-                /* we did the full CONNECT treatment, go to
-                   COMPLETE */
-                conn->tunnel_state[sockindex] = TUNNEL_COMPLETE;
+                s->keepon = FALSE;
+                /* we did the full CONNECT treatment, go to COMPLETE */
+                s->tunnel_state = TUNNEL_COMPLETE;
               }
               }
             }
             }
             else {
             else {
               /* without content-length or chunked encoding, we
               /* without content-length or chunked encoding, we
                  can't keep the connection alive since the close is
                  can't keep the connection alive since the close is
                  the end signal so we bail out at once instead */
                  the end signal so we bail out at once instead */
-              keepon = FALSE;
+              s->keepon = FALSE;
             }
             }
           }
           }
           else
           else
-            keepon = FALSE;
-          /* we did the full CONNECT treatment, go to COMPLETE */
-          conn->tunnel_state[sockindex] = TUNNEL_COMPLETE;
+            s->keepon = FALSE;
+          if(!s->cl)
+            /* we did the full CONNECT treatment, go to COMPLETE */
+            s->tunnel_state = TUNNEL_COMPLETE;
           continue;
           continue;
         }
         }
 
 
-        line_start[perline] = 0; /* zero terminate the buffer */
-        if((checkprefix("WWW-Authenticate:", line_start) &&
+        s->line_start[s->perline] = 0; /* zero terminate the buffer */
+        if((checkprefix("WWW-Authenticate:", s->line_start) &&
             (401 == k->httpcode)) ||
             (401 == k->httpcode)) ||
-           (checkprefix("Proxy-authenticate:", line_start) &&
+           (checkprefix("Proxy-authenticate:", s->line_start) &&
             (407 == k->httpcode))) {
             (407 == k->httpcode))) {
 
 
           bool proxy = (k->httpcode == 407) ? TRUE : FALSE;
           bool proxy = (k->httpcode == 407) ? TRUE : FALSE;
-          char *auth = Curl_copy_header_value(line_start);
+          char *auth = Curl_copy_header_value(s->line_start);
           if(!auth)
           if(!auth)
             return CURLE_OUT_OF_MEMORY;
             return CURLE_OUT_OF_MEMORY;
 
 
@@ -498,7 +515,7 @@ static CURLcode CONNECT(struct connectdata *conn,
           if(result)
           if(result)
             return result;
             return result;
         }
         }
-        else if(checkprefix("Content-Length:", line_start)) {
+        else if(checkprefix("Content-Length:", s->line_start)) {
           if(k->httpcode/100 == 2) {
           if(k->httpcode/100 == 2) {
             /* A client MUST ignore any Content-Length or Transfer-Encoding
             /* A client MUST ignore any Content-Length or Transfer-Encoding
                header fields received in a successful response to CONNECT.
                header fields received in a successful response to CONNECT.
@@ -507,13 +524,13 @@ static CURLcode CONNECT(struct connectdata *conn,
                   k->httpcode);
                   k->httpcode);
           }
           }
           else {
           else {
-            cl = curlx_strtoofft(line_start +
-                                 strlen("Content-Length:"), NULL, 10);
+            (void)curlx_strtoofft(s->line_start +
+                                  strlen("Content-Length:"), NULL, 10, &s->cl);
           }
           }
         }
         }
-        else if(Curl_compareheader(line_start, "Connection:", "close"))
+        else if(Curl_compareheader(s->line_start, "Connection:", "close"))
           closeConnection = TRUE;
           closeConnection = TRUE;
-        else if(checkprefix("Transfer-Encoding:", line_start)) {
+        else if(checkprefix("Transfer-Encoding:", s->line_start)) {
           if(k->httpcode/100 == 2) {
           if(k->httpcode/100 == 2) {
             /* A client MUST ignore any Content-Length or Transfer-Encoding
             /* A client MUST ignore any Content-Length or Transfer-Encoding
                header fields received in a successful response to CONNECT.
                header fields received in a successful response to CONNECT.
@@ -521,26 +538,27 @@ static CURLcode CONNECT(struct connectdata *conn,
             infof(data, "Ignoring Transfer-Encoding in "
             infof(data, "Ignoring Transfer-Encoding in "
                   "CONNECT %03d response\n", k->httpcode);
                   "CONNECT %03d response\n", k->httpcode);
           }
           }
-          else if(Curl_compareheader(line_start,
+          else if(Curl_compareheader(s->line_start,
                                      "Transfer-Encoding:", "chunked")) {
                                      "Transfer-Encoding:", "chunked")) {
             infof(data, "CONNECT responded chunked\n");
             infof(data, "CONNECT responded chunked\n");
-            chunked_encoding = TRUE;
+            s->chunked_encoding = TRUE;
             /* init our chunky engine */
             /* init our chunky engine */
             Curl_httpchunk_init(conn);
             Curl_httpchunk_init(conn);
           }
           }
         }
         }
-        else if(Curl_compareheader(line_start, "Proxy-Connection:", "close"))
+        else if(Curl_compareheader(s->line_start,
+                                   "Proxy-Connection:", "close"))
           closeConnection = TRUE;
           closeConnection = TRUE;
-        else if(2 == sscanf(line_start, "HTTP/1.%d %d",
+        else if(2 == sscanf(s->line_start, "HTTP/1.%d %d",
                             &subversion,
                             &subversion,
                             &k->httpcode)) {
                             &k->httpcode)) {
           /* store the HTTP code from the proxy */
           /* store the HTTP code from the proxy */
           data->info.httpproxycode = k->httpcode;
           data->info.httpproxycode = k->httpcode;
         }
         }
 
 
-        perline = 0; /* line starts over here */
-        ptr = conn->connect_buffer;
-        line_start = ptr;
+        s->perline = 0; /* line starts over here */
+        s->ptr = s->connect_buffer;
+        s->line_start = s->ptr;
       } /* while there's buffer left and loop is requested */
       } /* while there's buffer left and loop is requested */
 
 
       if(Curl_pgrsUpdate(conn))
       if(Curl_pgrsUpdate(conn))
@@ -549,7 +567,7 @@ static CURLcode CONNECT(struct connectdata *conn,
       if(error)
       if(error)
         return CURLE_RECV_ERROR;
         return CURLE_RECV_ERROR;
 
 
-      if(data->info.httpproxycode != 200) {
+      if(data->info.httpproxycode/100 != 2) {
         /* Deal with the possibly already received authenticate
         /* Deal with the possibly already received authenticate
            headers. 'newurl' is set to a new URL if we must loop. */
            headers. 'newurl' is set to a new URL if we must loop. */
         result = Curl_http_auth_act(conn);
         result = Curl_http_auth_act(conn);
@@ -574,19 +592,17 @@ static CURLcode CONNECT(struct connectdata *conn,
     /* If we are supposed to continue and request a new URL, which basically
     /* If we are supposed to continue and request a new URL, which basically
      * means the HTTP authentication is still going on so if the tunnel
      * means the HTTP authentication is still going on so if the tunnel
      * is complete we start over in INIT state */
      * is complete we start over in INIT state */
-    if(data->req.newurl &&
-       (TUNNEL_COMPLETE == conn->tunnel_state[sockindex])) {
-      conn->tunnel_state[sockindex] = TUNNEL_INIT;
-      infof(data, "TUNNEL_STATE switched to: %d\n",
-            conn->tunnel_state[sockindex]);
+    if(data->req.newurl && (TUNNEL_COMPLETE == s->tunnel_state)) {
+      connect_init(conn, TRUE); /* reinit */
     }
     }
 
 
   } while(data->req.newurl);
   } while(data->req.newurl);
 
 
-  if(200 != data->req.httpcode) {
+  if(data->info.httpproxycode/100 != 2) {
     if(closeConnection && data->req.newurl) {
     if(closeConnection && data->req.newurl) {
       conn->bits.proxy_connect_closed = TRUE;
       conn->bits.proxy_connect_closed = TRUE;
       infof(data, "Connect me again please\n");
       infof(data, "Connect me again please\n");
+      connect_done(conn);
     }
     }
     else {
     else {
       free(data->req.newurl);
       free(data->req.newurl);
@@ -598,7 +614,7 @@ static CURLcode CONNECT(struct connectdata *conn,
     }
     }
 
 
     /* to back to init state */
     /* to back to init state */
-    conn->tunnel_state[sockindex] = TUNNEL_INIT;
+    s->tunnel_state = TUNNEL_INIT;
 
 
     if(conn->bits.proxy_connect_closed)
     if(conn->bits.proxy_connect_closed)
       /* this is not an error, just part of the connection negotiation */
       /* this is not an error, just part of the connection negotiation */
@@ -608,7 +624,7 @@ static CURLcode CONNECT(struct connectdata *conn,
     return CURLE_RECV_ERROR;
     return CURLE_RECV_ERROR;
   }
   }
 
 
-  conn->tunnel_state[sockindex] = TUNNEL_COMPLETE;
+  s->tunnel_state = TUNNEL_COMPLETE;
 
 
   /* If a proxy-authorization header was used for the proxy, then we should
   /* If a proxy-authorization header was used for the proxy, then we should
      make sure that it isn't accidentally used for the document request
      make sure that it isn't accidentally used for the document request
@@ -618,13 +634,24 @@ static CURLcode CONNECT(struct connectdata *conn,
 
 
   data->state.authproxy.done = TRUE;
   data->state.authproxy.done = TRUE;
 
 
-  infof(data, "Proxy replied OK to CONNECT request\n");
+  infof(data, "Proxy replied %d to CONNECT request\n",
+        data->info.httpproxycode);
   data->req.ignorebody = FALSE; /* put it (back) to non-ignore state */
   data->req.ignorebody = FALSE; /* put it (back) to non-ignore state */
   conn->bits.rewindaftersend = FALSE; /* make sure this isn't set for the
   conn->bits.rewindaftersend = FALSE; /* make sure this isn't set for the
                                          document request  */
                                          document request  */
   return CURLE_OK;
   return CURLE_OK;
 }
 }
 
 
+void Curl_connect_free(struct Curl_easy *data)
+{
+  struct connectdata *conn = data->easy_conn;
+  struct http_connect_state *s = conn->connect_state;
+  if(s) {
+    free(s);
+    conn->connect_state = NULL;
+  }
+}
+
 /*
 /*
  * Curl_proxyCONNECT() requires that we're connected to a HTTP proxy. This
  * Curl_proxyCONNECT() requires that we're connected to a HTTP proxy. This
  * function will issue the necessary commands to get a seamless tunnel through
  * function will issue the necessary commands to get a seamless tunnel through
@@ -637,20 +664,23 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
                            int remote_port)
                            int remote_port)
 {
 {
   CURLcode result;
   CURLcode result;
-  if(TUNNEL_INIT == conn->tunnel_state[sockindex]) {
-    if(!conn->connect_buffer) {
-      conn->connect_buffer = malloc(CONNECT_BUFFER_SIZE);
-      if(!conn->connect_buffer)
-        return CURLE_OUT_OF_MEMORY;
-    }
+  if(!conn->connect_state) {
+    result = connect_init(conn, FALSE);
+    if(result)
+      return result;
   }
   }
   result = CONNECT(conn, sockindex, hostname, remote_port);
   result = CONNECT(conn, sockindex, hostname, remote_port);
 
 
-  if(result || (TUNNEL_COMPLETE == conn->tunnel_state[sockindex]))
-    Curl_safefree(conn->connect_buffer);
+  if(result || Curl_connect_complete(conn))
+    connect_done(conn);
 
 
   return result;
   return result;
 }
 }
 
 
+#else
+void Curl_connect_free(struct Curl_easy *data)
+{
+  (void)data;
+}
 
 
 #endif /* CURL_DISABLE_PROXY */
 #endif /* CURL_DISABLE_PROXY */

+ 10 - 0
Utilities/cmcurl/lib/http_proxy.h

@@ -22,6 +22,9 @@
  *
  *
  ***************************************************************************/
  ***************************************************************************/
 
 
+#include "curl_setup.h"
+#include "urldata.h"
+
 #if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP)
 #if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP)
 /* ftp can use this as well */
 /* ftp can use this as well */
 CURLcode Curl_proxyCONNECT(struct connectdata *conn,
 CURLcode Curl_proxyCONNECT(struct connectdata *conn,
@@ -33,9 +36,16 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
 
 
 CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex);
 CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex);
 
 
+bool Curl_connect_complete(struct connectdata *conn);
+bool Curl_connect_ongoing(struct connectdata *conn);
+
 #else
 #else
 #define Curl_proxyCONNECT(x,y,z,w) CURLE_NOT_BUILT_IN
 #define Curl_proxyCONNECT(x,y,z,w) CURLE_NOT_BUILT_IN
 #define Curl_proxy_connect(x,y) CURLE_OK
 #define Curl_proxy_connect(x,y) CURLE_OK
+#define Curl_connect_complete(x) CURLE_OK
+#define Curl_connect_ongoing(x) FALSE
 #endif
 #endif
 
 
+void Curl_connect_free(struct Curl_easy *data);
+
 #endif /* HEADER_CURL_HTTP_PROXY_H */
 #endif /* HEADER_CURL_HTTP_PROXY_H */

+ 9 - 7
Utilities/cmcurl/lib/if2ip.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -71,6 +71,8 @@ unsigned int Curl_ipv6_scope(const struct sockaddr *sa)
     const unsigned char *b = sa6->sin6_addr.s6_addr;
     const unsigned char *b = sa6->sin6_addr.s6_addr;
     unsigned short w = (unsigned short) ((b[0] << 8) | b[1]);
     unsigned short w = (unsigned short) ((b[0] << 8) | b[1]);
 
 
+    if((b[0] & 0xFE) == 0xFC) /* Handle ULAs */
+      return IPV6_SCOPE_UNIQUELOCAL;
     switch(w & 0xFFC0) {
     switch(w & 0xFFC0) {
     case 0xFE80:
     case 0xFE80:
       return IPV6_SCOPE_LINKLOCAL;
       return IPV6_SCOPE_LINKLOCAL;
@@ -101,7 +103,7 @@ bool Curl_if_is_interface_name(const char *interf)
   struct ifaddrs *iface, *head;
   struct ifaddrs *iface, *head;
 
 
   if(getifaddrs(&head) >= 0) {
   if(getifaddrs(&head) >= 0) {
-    for(iface=head; iface != NULL; iface=iface->ifa_next) {
+    for(iface = head; iface != NULL; iface = iface->ifa_next) {
       if(strcasecompare(iface->ifa_name, interf)) {
       if(strcasecompare(iface->ifa_name, interf)) {
         result = TRUE;
         result = TRUE;
         break;
         break;
@@ -121,15 +123,15 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
 
 
 #ifndef ENABLE_IPV6
 #ifndef ENABLE_IPV6
   (void) remote_scope;
   (void) remote_scope;
-
-#ifndef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
-  (void) remote_scope_id;
 #endif
 #endif
 
 
+#if !defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID) || \
+    !defined(ENABLE_IPV6)
+  (void) remote_scope_id;
 #endif
 #endif
 
 
   if(getifaddrs(&head) >= 0) {
   if(getifaddrs(&head) >= 0) {
-    for(iface = head; iface != NULL; iface=iface->ifa_next) {
+    for(iface = head; iface != NULL; iface = iface->ifa_next) {
       if(iface->ifa_addr != NULL) {
       if(iface->ifa_addr != NULL) {
         if(iface->ifa_addr->sa_family == af) {
         if(iface->ifa_addr->sa_family == af) {
           if(strcasecompare(iface->ifa_name, interf)) {
           if(strcasecompare(iface->ifa_name, interf)) {
@@ -228,7 +230,7 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
     return IF2IP_NOT_FOUND;
     return IF2IP_NOT_FOUND;
 
 
   memset(&req, 0, sizeof(req));
   memset(&req, 0, sizeof(req));
-  memcpy(req.ifr_name, interf, len+1);
+  memcpy(req.ifr_name, interf, len + 1);
   req.ifr_addr.sa_family = AF_INET;
   req.ifr_addr.sa_family = AF_INET;
 
 
   if(ioctl(dummy, SIOCGIFADDR, &req) < 0) {
   if(ioctl(dummy, SIOCGIFADDR, &req) < 0) {

+ 3 - 2
Utilities/cmcurl/lib/if2ip.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -27,7 +27,8 @@
 #define IPV6_SCOPE_GLOBAL       0       /* Global scope. */
 #define IPV6_SCOPE_GLOBAL       0       /* Global scope. */
 #define IPV6_SCOPE_LINKLOCAL    1       /* Link-local scope. */
 #define IPV6_SCOPE_LINKLOCAL    1       /* Link-local scope. */
 #define IPV6_SCOPE_SITELOCAL    2       /* Site-local scope (deprecated). */
 #define IPV6_SCOPE_SITELOCAL    2       /* Site-local scope (deprecated). */
-#define IPV6_SCOPE_NODELOCAL    3       /* Loopback. */
+#define IPV6_SCOPE_UNIQUELOCAL  3       /* Unique local */
+#define IPV6_SCOPE_NODELOCAL    4       /* Loopback. */
 
 
 unsigned int Curl_ipv6_scope(const struct sockaddr *sa);
 unsigned int Curl_ipv6_scope(const struct sockaddr *sa);
 
 

+ 78 - 117
Utilities/cmcurl/lib/imap.c

@@ -68,6 +68,7 @@
 #include "http.h" /* for HTTP proxy tunnel stuff */
 #include "http.h" /* for HTTP proxy tunnel stuff */
 #include "socks.h"
 #include "socks.h"
 #include "imap.h"
 #include "imap.h"
+#include "mime.h"
 #include "strtoofft.h"
 #include "strtoofft.h"
 #include "strcase.h"
 #include "strcase.h"
 #include "vtls/vtls.h"
 #include "vtls/vtls.h"
@@ -128,6 +129,7 @@ const struct Curl_handler Curl_handler_imap = {
   ZERO_NULL,                        /* perform_getsock */
   ZERO_NULL,                        /* perform_getsock */
   imap_disconnect,                  /* disconnect */
   imap_disconnect,                  /* disconnect */
   ZERO_NULL,                        /* readwrite */
   ZERO_NULL,                        /* readwrite */
+  ZERO_NULL,                        /* connection_check */
   PORT_IMAP,                        /* defport */
   PORT_IMAP,                        /* defport */
   CURLPROTO_IMAP,                   /* protocol */
   CURLPROTO_IMAP,                   /* protocol */
   PROTOPT_CLOSEACTION|              /* flags */
   PROTOPT_CLOSEACTION|              /* flags */
@@ -154,69 +156,22 @@ const struct Curl_handler Curl_handler_imaps = {
   ZERO_NULL,                        /* perform_getsock */
   ZERO_NULL,                        /* perform_getsock */
   imap_disconnect,                  /* disconnect */
   imap_disconnect,                  /* disconnect */
   ZERO_NULL,                        /* readwrite */
   ZERO_NULL,                        /* readwrite */
+  ZERO_NULL,                        /* connection_check */
   PORT_IMAPS,                       /* defport */
   PORT_IMAPS,                       /* defport */
   CURLPROTO_IMAPS,                  /* protocol */
   CURLPROTO_IMAPS,                  /* protocol */
   PROTOPT_CLOSEACTION | PROTOPT_SSL /* flags */
   PROTOPT_CLOSEACTION | PROTOPT_SSL /* flags */
 };
 };
 #endif
 #endif
 
 
-#ifndef CURL_DISABLE_HTTP
-/*
- * HTTP-proxyed IMAP protocol handler.
- */
-
-static const struct Curl_handler Curl_handler_imap_proxy = {
-  "IMAP",                               /* 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_IMAP,                            /* defport */
-  CURLPROTO_HTTP,                       /* protocol */
-  PROTOPT_NONE                          /* flags */
-};
-
-#ifdef USE_SSL
-/*
- * HTTP-proxyed IMAPS protocol handler.
- */
-
-static const struct Curl_handler Curl_handler_imaps_proxy = {
-  "IMAPS",                              /* 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_IMAPS,                           /* defport */
-  CURLPROTO_HTTP,                       /* protocol */
-  PROTOPT_NONE                          /* flags */
-};
-#endif
-#endif
+#define IMAP_RESP_OK       1
+#define IMAP_RESP_NOT_OK   2
+#define IMAP_RESP_PREAUTH  3
 
 
 /* SASL parameters for the imap protocol */
 /* SASL parameters for the imap protocol */
 static const struct SASLproto saslimap = {
 static const struct SASLproto saslimap = {
   "imap",                     /* The service name */
   "imap",                     /* The service name */
   '+',                        /* Code received when continuation is expected */
   '+',                        /* Code received when continuation is expected */
-  'O',                        /* Code to receive upon authentication success */
+  IMAP_RESP_OK,               /* Code to receive upon authentication success */
   0,                          /* Maximum initial response length (no max) */
   0,                          /* Maximum initial response length (no max) */
   imap_perform_authenticate,  /* Send authentication command */
   imap_perform_authenticate,  /* Send authentication command */
   imap_continue_authenticate, /* Send authentication continuation */
   imap_continue_authenticate, /* Send authentication continuation */
@@ -299,15 +254,11 @@ static bool imap_endofresp(struct connectdata *conn, char *line, size_t len,
     len -= id_len + 1;
     len -= id_len + 1;
 
 
     if(len >= 2 && !memcmp(line, "OK", 2))
     if(len >= 2 && !memcmp(line, "OK", 2))
-      *resp = 'O';
-    else if(len >= 2 && !memcmp(line, "NO", 2))
-      *resp = 'N';
-    else if(len >= 3 && !memcmp(line, "BAD", 3))
-      *resp = 'B';
-    else {
-      failf(conn->data, "Bad tagged response");
-      *resp = -1;
-    }
+      *resp = IMAP_RESP_OK;
+    else if(len >= 7 && !memcmp(line, "PREAUTH", 7))
+      *resp = IMAP_RESP_PREAUTH;
+    else
+      *resp = IMAP_RESP_NOT_OK;
 
 
     return TRUE;
     return TRUE;
   }
   }
@@ -613,9 +564,10 @@ static CURLcode imap_perform_authentication(struct connectdata *conn)
   struct imap_conn *imapc = &conn->proto.imapc;
   struct imap_conn *imapc = &conn->proto.imapc;
   saslprogress progress;
   saslprogress progress;
 
 
-  /* Check we have enough data to authenticate with and end the
-     connect phase if we don't */
-  if(!Curl_sasl_can_authenticate(&imapc->sasl, conn)) {
+  /* Check if already authenticated OR if there is enough data to authenticate
+     with and end the connect phase if we don't */
+  if(imapc->preauth ||
+     !Curl_sasl_can_authenticate(&imapc->sasl, conn)) {
     state(conn, IMAP_STOP);
     state(conn, IMAP_STOP);
     return result;
     return result;
   }
   }
@@ -757,18 +709,48 @@ static CURLcode imap_perform_fetch(struct connectdata *conn)
 static CURLcode imap_perform_append(struct connectdata *conn)
 static CURLcode imap_perform_append(struct connectdata *conn)
 {
 {
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
-  struct IMAP *imap = conn->data->req.protop;
+  struct Curl_easy *data = conn->data;
+  struct IMAP *imap = data->req.protop;
   char *mailbox;
   char *mailbox;
 
 
   /* Check we have a mailbox */
   /* Check we have a mailbox */
   if(!imap->mailbox) {
   if(!imap->mailbox) {
-    failf(conn->data, "Cannot APPEND without a mailbox.");
+    failf(data, "Cannot APPEND without a mailbox.");
     return CURLE_URL_MALFORMAT;
     return CURLE_URL_MALFORMAT;
   }
   }
 
 
+  /* Prepare the mime data if some. */
+  if(data->set.mimepost.kind != MIMEKIND_NONE) {
+    /* Use the whole structure as data. */
+    data->set.mimepost.flags &= ~MIME_BODY_ONLY;
+
+    /* Add external headers and mime version. */
+    curl_mime_headers(&data->set.mimepost, data->set.headers, 0);
+    result = Curl_mime_prepare_headers(&data->set.mimepost, NULL,
+                                       NULL, MIMESTRATEGY_MAIL);
+
+    if(!result)
+      if(!Curl_checkheaders(conn, "Mime-Version"))
+        result = Curl_mime_add_header(&data->set.mimepost.curlheaders,
+                                      "Mime-Version: 1.0");
+
+    /* Make sure we will read the entire mime structure. */
+    if(!result)
+      result = Curl_mime_rewind(&data->set.mimepost);
+
+    if(result)
+      return result;
+
+    data->state.infilesize = Curl_mime_size(&data->set.mimepost);
+
+    /* Read from mime structure. */
+    data->state.fread_func = (curl_read_callback) Curl_mime_read;
+    data->state.in = (void *) &data->set.mimepost;
+  }
+
   /* Check we know the size of the upload */
   /* Check we know the size of the upload */
-  if(conn->data->state.infilesize < 0) {
-    failf(conn->data, "Cannot APPEND with unknown input file size\n");
+  if(data->state.infilesize < 0) {
+    failf(data, "Cannot APPEND with unknown input file size\n");
     return CURLE_UPLOAD_FAILED;
     return CURLE_UPLOAD_FAILED;
   }
   }
 
 
@@ -779,7 +761,7 @@ static CURLcode imap_perform_append(struct connectdata *conn)
 
 
   /* Send the APPEND command */
   /* Send the APPEND command */
   result = imap_sendf(conn, "APPEND %s (\\Seen) {%" CURL_FORMAT_CURL_OFF_T "}",
   result = imap_sendf(conn, "APPEND %s (\\Seen) {%" CURL_FORMAT_CURL_OFF_T "}",
-                      mailbox, conn->data->state.infilesize);
+                      mailbox, data->state.infilesize);
 
 
   free(mailbox);
   free(mailbox);
 
 
@@ -839,19 +821,21 @@ static CURLcode imap_state_servergreet_resp(struct connectdata *conn,
                                             int imapcode,
                                             int imapcode,
                                             imapstate instate)
                                             imapstate instate)
 {
 {
-  CURLcode result = CURLE_OK;
   struct Curl_easy *data = conn->data;
   struct Curl_easy *data = conn->data;
-
   (void)instate; /* no use for this yet */
   (void)instate; /* no use for this yet */
 
 
-  if(imapcode != 'O') {
+  if(imapcode == IMAP_RESP_PREAUTH) {
+    /* PREAUTH */
+    struct imap_conn *imapc = &conn->proto.imapc;
+    imapc->preauth = TRUE;
+    infof(data, "PREAUTH connection, already authenticated!\n");
+  }
+  else if(imapcode != IMAP_RESP_OK) {
     failf(data, "Got unexpected imap-server response");
     failf(data, "Got unexpected imap-server response");
-    result = CURLE_WEIRD_SERVER_REPLY;
+    return CURLE_WEIRD_SERVER_REPLY;
   }
   }
-  else
-    result = imap_perform_capability(conn);
 
 
-  return result;
+  return imap_perform_capability(conn);
 }
 }
 
 
 /* For CAPABILITY responses */
 /* For CAPABILITY responses */
@@ -918,7 +902,7 @@ static CURLcode imap_state_capability_resp(struct connectdata *conn,
       line += wordlen;
       line += wordlen;
     }
     }
   }
   }
-  else if(imapcode == 'O') {
+  else if(imapcode == IMAP_RESP_OK) {
     if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
     if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
       /* We don't have a SSL/TLS connection yet, but SSL is requested */
       /* We don't have a SSL/TLS connection yet, but SSL is requested */
       if(imapc->tls_supported)
       if(imapc->tls_supported)
@@ -951,7 +935,7 @@ static CURLcode imap_state_starttls_resp(struct connectdata *conn,
 
 
   (void)instate; /* no use for this yet */
   (void)instate; /* no use for this yet */
 
 
-  if(imapcode != 'O') {
+  if(imapcode != IMAP_RESP_OK) {
     if(data->set.use_ssl != CURLUSESSL_TRY) {
     if(data->set.use_ssl != CURLUSESSL_TRY) {
       failf(data, "STARTTLS denied");
       failf(data, "STARTTLS denied");
       result = CURLE_USE_SSL_FAILED;
       result = CURLE_USE_SSL_FAILED;
@@ -1009,7 +993,7 @@ static CURLcode imap_state_login_resp(struct connectdata *conn,
 
 
   (void)instate; /* no use for this yet */
   (void)instate; /* no use for this yet */
 
 
-  if(imapcode != 'O') {
+  if(imapcode != IMAP_RESP_OK) {
     failf(data, "Access denied. %c", imapcode);
     failf(data, "Access denied. %c", imapcode);
     result = CURLE_LOGIN_DENIED;
     result = CURLE_LOGIN_DENIED;
   }
   }
@@ -1037,7 +1021,7 @@ static CURLcode imap_state_listsearch_resp(struct connectdata *conn,
     result = Curl_client_write(conn, CLIENTWRITE_BODY, line, len + 1);
     result = Curl_client_write(conn, CLIENTWRITE_BODY, line, len + 1);
     line[len] = '\0';
     line[len] = '\0';
   }
   }
-  else if(imapcode != 'O')
+  else if(imapcode != IMAP_RESP_OK)
     result = CURLE_QUOTE_ERROR; /* TODO: Fix error code */
     result = CURLE_QUOTE_ERROR; /* TODO: Fix error code */
   else
   else
     /* End of DO phase */
     /* End of DO phase */
@@ -1066,7 +1050,7 @@ static CURLcode imap_state_select_resp(struct connectdata *conn, int imapcode,
       imapc->mailbox_uidvalidity = strdup(tmp);
       imapc->mailbox_uidvalidity = strdup(tmp);
     }
     }
   }
   }
-  else if(imapcode == 'O') {
+  else if(imapcode == IMAP_RESP_OK) {
     /* Check if the UIDVALIDITY has been specified and matches */
     /* Check if the UIDVALIDITY has been specified and matches */
     if(imap->uidvalidity && imapc->mailbox_uidvalidity &&
     if(imap->uidvalidity && imapc->mailbox_uidvalidity &&
        strcmp(imap->uidvalidity, imapc->mailbox_uidvalidity)) {
        strcmp(imap->uidvalidity, imapc->mailbox_uidvalidity)) {
@@ -1120,10 +1104,11 @@ static CURLcode imap_state_fetch_resp(struct connectdata *conn, int imapcode,
 
 
   if(*ptr == '{') {
   if(*ptr == '{') {
     char *endptr;
     char *endptr;
-    size = curlx_strtoofft(ptr + 1, &endptr, 10);
-    if(endptr - ptr > 1 && endptr[0] == '}' &&
-       endptr[1] == '\r' && endptr[2] == '\0')
-      parsed = TRUE;
+    if(!curlx_strtoofft(ptr + 1, &endptr, 10, &size)) {
+      if(endptr - ptr > 1 && endptr[0] == '}' &&
+         endptr[1] == '\r' && endptr[2] == '\0')
+        parsed = TRUE;
+    }
   }
   }
 
 
   if(parsed) {
   if(parsed) {
@@ -1197,7 +1182,7 @@ static CURLcode imap_state_fetch_final_resp(struct connectdata *conn,
 
 
   (void)instate; /* No use for this yet */
   (void)instate; /* No use for this yet */
 
 
-  if(imapcode != 'O')
+  if(imapcode != IMAP_RESP_OK)
     result = CURLE_WEIRD_SERVER_REPLY;
     result = CURLE_WEIRD_SERVER_REPLY;
   else
   else
     /* End of DONE phase */
     /* End of DONE phase */
@@ -1241,7 +1226,7 @@ static CURLcode imap_state_append_final_resp(struct connectdata *conn,
 
 
   (void)instate; /* No use for this yet */
   (void)instate; /* No use for this yet */
 
 
-  if(imapcode != 'O')
+  if(imapcode != IMAP_RESP_OK)
     result = CURLE_UPLOAD_FAILED;
     result = CURLE_UPLOAD_FAILED;
   else
   else
     /* End of DONE phase */
     /* End of DONE phase */
@@ -1469,9 +1454,10 @@ static CURLcode imap_done(struct connectdata *conn, CURLcode status,
     result = status;         /* use the already set error code */
     result = status;         /* use the already set error code */
   }
   }
   else if(!data->set.connect_only && !imap->custom &&
   else if(!data->set.connect_only && !imap->custom &&
-          (imap->uid || data->set.upload)) {
+          (imap->uid || data->set.upload ||
+          data->set.mimepost.kind != MIMEKIND_NONE)) {
     /* Handle responses after FETCH or APPEND transfer has finished */
     /* Handle responses after FETCH or APPEND transfer has finished */
-    if(!data->set.upload)
+    if(!data->set.upload && data->set.mimepost.kind == MIMEKIND_NONE)
       state(conn, IMAP_FETCH_FINAL);
       state(conn, IMAP_FETCH_FINAL);
     else {
     else {
       /* End the APPEND command first by sending an empty line */
       /* End the APPEND command first by sending an empty line */
@@ -1541,7 +1527,7 @@ static CURLcode imap_perform(struct connectdata *conn, bool *connected,
     selected = TRUE;
     selected = TRUE;
 
 
   /* Start the first command in the DO phase */
   /* Start the first command in the DO phase */
-  if(conn->data->set.upload)
+  if(conn->data->set.upload || data->set.mimepost.kind != MIMEKIND_NONE)
     /* APPEND can be executed directly */
     /* APPEND can be executed directly */
     result = imap_perform_append(conn);
     result = imap_perform_append(conn);
   else if(imap->custom && (selected || !imap->mailbox))
   else if(imap->custom && (selected || !imap->mailbox))
@@ -1715,31 +1701,6 @@ static CURLcode imap_setup_connection(struct connectdata *conn)
 
 
   /* Clear the TLS upgraded flag */
   /* Clear the TLS upgraded flag */
   conn->tls_upgraded = FALSE;
   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 */
-#ifndef CURL_DISABLE_HTTP
-    if(conn->handler == &Curl_handler_imap)
-      conn->handler = &Curl_handler_imap_proxy;
-    else {
-#ifdef USE_SSL
-      conn->handler = &Curl_handler_imaps_proxy;
-#else
-      failf(data, "IMAPS not supported!");
-      return CURLE_UNSUPPORTED_PROTOCOL;
-#endif
-    }
-
-    /* set it up as an HTTP connection instead */
-    return conn->handler->setup_connection(conn);
-#else
-    failf(data, "IMAP over http proxy requires HTTP support built-in!");
-    return CURLE_UNSUPPORTED_PROTOCOL;
-#endif
-  }
-
   data->state.path++;   /* don't include the initial slash */
   data->state.path++;   /* don't include the initial slash */
 
 
   return CURLE_OK;
   return CURLE_OK;
@@ -1836,7 +1797,7 @@ static char *imap_atom(const char *str, bool escape_only)
     return strdup(str);
     return strdup(str);
 
 
   /* Calculate the new string length */
   /* Calculate the new string length */
-  newlen = strlen(str) + backsp_count + quote_count + (others_exists ? 2 : 0);
+  newlen = strlen(str) + backsp_count + quote_count + (escape_only ? 0 : 2);
 
 
   /* Allocate the new string */
   /* Allocate the new string */
   newstr = (char *) malloc((newlen + 1) * sizeof(char));
   newstr = (char *) malloc((newlen + 1) * sizeof(char));
@@ -1845,7 +1806,7 @@ static char *imap_atom(const char *str, bool escape_only)
 
 
   /* Surround the string in quotes if necessary */
   /* Surround the string in quotes if necessary */
   p2 = newstr;
   p2 = newstr;
-  if(others_exists) {
+  if(!escape_only) {
     newstr[0] = '"';
     newstr[0] = '"';
     newstr[newlen - 1] = '"';
     newstr[newlen - 1] = '"';
     p2++;
     p2++;

+ 2 - 1
Utilities/cmcurl/lib/imap.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 2009 - 2015, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2009 - 2017, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -71,6 +71,7 @@ struct imap_conn {
   struct pingpong pp;
   struct pingpong pp;
   imapstate state;            /* Always use imap.c:state() to change state! */
   imapstate state;            /* Always use imap.c:state() to change state! */
   bool ssldone;               /* Is connect() over SSL done? */
   bool ssldone;               /* Is connect() over SSL done? */
+  bool preauth;               /* Is this connection PREAUTH? */
   struct SASL sasl;           /* SASL-related parameters */
   struct SASL sasl;           /* SASL-related parameters */
   unsigned int preftype;      /* Preferred authentication type */
   unsigned int preftype;      /* Preferred authentication type */
   int cmdid;                  /* Last used command ID */
   int cmdid;                  /* Last used command ID */

+ 7 - 7
Utilities/cmcurl/lib/inet_ntop.c

@@ -63,7 +63,7 @@ static char *inet_ntop4 (const unsigned char *src, char *dst, size_t size)
 
 
   len = strlen(tmp);
   len = strlen(tmp);
   if(len == 0 || len >= size) {
   if(len == 0 || len >= size) {
-    SET_ERRNO(ENOSPC);
+    errno = ENOSPC;
     return (NULL);
     return (NULL);
   }
   }
   strcpy(dst, tmp);
   strcpy(dst, tmp);
@@ -141,8 +141,8 @@ static char *inet_ntop6 (const unsigned char *src, char *dst, size_t size)
      */
      */
     if(i == 6 && best.base == 0 &&
     if(i == 6 && best.base == 0 &&
         (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
         (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
-      if(!inet_ntop4(src+12, tp, sizeof(tmp) - (tp - tmp))) {
-        SET_ERRNO(ENOSPC);
+      if(!inet_ntop4(src + 12, tp, sizeof(tmp) - (tp - tmp))) {
+        errno = ENOSPC;
         return (NULL);
         return (NULL);
       }
       }
       tp += strlen(tp);
       tp += strlen(tp);
@@ -160,7 +160,7 @@ static char *inet_ntop6 (const unsigned char *src, char *dst, size_t size)
   /* Check for overflow, copy, and we're done.
   /* Check for overflow, copy, and we're done.
    */
    */
   if((size_t)(tp - tmp) > size) {
   if((size_t)(tp - tmp) > size) {
-    SET_ERRNO(ENOSPC);
+    errno = ENOSPC;
     return (NULL);
     return (NULL);
   }
   }
   strcpy(dst, tmp);
   strcpy(dst, tmp);
@@ -177,8 +177,8 @@ static char *inet_ntop6 (const unsigned char *src, char *dst, size_t size)
  *
  *
  * On Windows we store the error in the thread errno, not
  * On Windows we store the error in the thread errno, not
  * in the winsock error code. This is to avoid losing the
  * in the winsock error code. This is to avoid losing the
- * actual last winsock error. So use macro ERRNO to fetch the
- * errno this function sets when returning NULL, not SOCKERRNO.
+ * actual last winsock error. So when this function returns
+ * NULL, check errno not SOCKERRNO.
  */
  */
 char *Curl_inet_ntop(int af, const void *src, char *buf, size_t size)
 char *Curl_inet_ntop(int af, const void *src, char *buf, size_t size)
 {
 {
@@ -190,7 +190,7 @@ char *Curl_inet_ntop(int af, const void *src, char *buf, size_t size)
     return inet_ntop6((const unsigned char *)src, buf, size);
     return inet_ntop6((const unsigned char *)src, buf, size);
 #endif
 #endif
   default:
   default:
-    SET_ERRNO(EAFNOSUPPORT);
+    errno = EAFNOSUPPORT;
     return NULL;
     return NULL;
   }
   }
 }
 }

+ 3 - 3
Utilities/cmcurl/lib/inet_pton.c

@@ -57,8 +57,8 @@ static int      inet_pton6(const char *src, unsigned char *dst);
  * notice:
  * notice:
  *      On Windows we store the error in the thread errno, not
  *      On Windows we store the error in the thread errno, not
  *      in the winsock error code. This is to avoid losing the
  *      in the winsock error code. This is to avoid losing the
- *      actual last winsock error. So use macro ERRNO to fetch the
- *      errno this function sets when returning (-1), not SOCKERRNO.
+ *      actual last winsock error. So when this function returns
+ *      -1, check errno not SOCKERRNO.
  * author:
  * author:
  *      Paul Vixie, 1996.
  *      Paul Vixie, 1996.
  */
  */
@@ -73,7 +73,7 @@ Curl_inet_pton(int af, const char *src, void *dst)
     return (inet_pton6(src, (unsigned char *)dst));
     return (inet_pton6(src, (unsigned char *)dst));
 #endif
 #endif
   default:
   default:
-    SET_ERRNO(EAFNOSUPPORT);
+    errno = EAFNOSUPPORT;
     return (-1);
     return (-1);
   }
   }
   /* NOTREACHED */
   /* NOTREACHED */

+ 4 - 1
Utilities/cmcurl/lib/inet_pton.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2005, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -29,6 +29,9 @@ int Curl_inet_pton(int, const char *, void *);
 #ifdef HAVE_INET_PTON
 #ifdef HAVE_INET_PTON
 #ifdef HAVE_ARPA_INET_H
 #ifdef HAVE_ARPA_INET_H
 #include <arpa/inet.h>
 #include <arpa/inet.h>
+#elif defined(HAVE_WS2TCPIP_H)
+/* inet_pton() exists in Vista or later */
+#include <ws2tcpip.h>
 #endif
 #endif
 #define Curl_inet_pton(x,y,z) inet_pton(x,y,z)
 #define Curl_inet_pton(x,y,z) inet_pton(x,y,z)
 #endif
 #endif

+ 1 - 1
Utilities/cmcurl/lib/krb5.c

@@ -1,6 +1,6 @@
 /* GSSAPI/krb5 support for FTP - loosely based on old krb4.c
 /* GSSAPI/krb5 support for FTP - loosely based on old krb4.c
  *
  *
- * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan
  * (Royal Institute of Technology, Stockholm, Sweden).
  * (Royal Institute of Technology, Stockholm, Sweden).
  * Copyright (c) 2004 - 2016 Daniel Stenberg
  * Copyright (c) 2004 - 2016 Daniel Stenberg
  * All rights reserved.
  * All rights reserved.

+ 5 - 4
Utilities/cmcurl/lib/ldap.c

@@ -5,7 +5,7 @@
  *                | (__| |_| |  _ <| |___
  *                | (__| |_| |  _ <| |___
  *                 \___|\___/|_| \_\_____|
  *                 \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -150,6 +150,7 @@ const struct Curl_handler Curl_handler_ldap = {
   ZERO_NULL,                            /* perform_getsock */
   ZERO_NULL,                            /* perform_getsock */
   ZERO_NULL,                            /* disconnect */
   ZERO_NULL,                            /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
   PORT_LDAP,                            /* defport */
   PORT_LDAP,                            /* defport */
   CURLPROTO_LDAP,                       /* protocol */
   CURLPROTO_LDAP,                       /* protocol */
   PROTOPT_NONE                          /* flags */
   PROTOPT_NONE                          /* flags */
@@ -175,6 +176,7 @@ const struct Curl_handler Curl_handler_ldaps = {
   ZERO_NULL,                            /* perform_getsock */
   ZERO_NULL,                            /* perform_getsock */
   ZERO_NULL,                            /* disconnect */
   ZERO_NULL,                            /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
   PORT_LDAPS,                           /* defport */
   PORT_LDAPS,                           /* defport */
   CURLPROTO_LDAPS,                      /* protocol */
   CURLPROTO_LDAPS,                      /* protocol */
   PROTOPT_SSL                           /* flags */
   PROTOPT_SSL                           /* flags */
@@ -233,7 +235,6 @@ static int ldap_win_bind(struct connectdata *conn, LDAP *server,
                          const char *user, const char *passwd)
                          const char *user, const char *passwd)
 {
 {
   int rc = LDAP_INVALID_CREDENTIALS;
   int rc = LDAP_INVALID_CREDENTIALS;
-  ULONG method = LDAP_AUTH_SIMPLE;
 
 
   PTCHAR inuser = NULL;
   PTCHAR inuser = NULL;
   PTCHAR inpass = NULL;
   PTCHAR inpass = NULL;
@@ -242,7 +243,7 @@ static int ldap_win_bind(struct connectdata *conn, LDAP *server,
     inuser = Curl_convert_UTF8_to_tchar((char *) user);
     inuser = Curl_convert_UTF8_to_tchar((char *) user);
     inpass = Curl_convert_UTF8_to_tchar((char *) passwd);
     inpass = Curl_convert_UTF8_to_tchar((char *) passwd);
 
 
-    rc = ldap_bind_s(server, inuser, inpass, method);
+    rc = ldap_simple_bind_s(server, inuser, inpass);
 
 
     Curl_unicodefree(inuser);
     Curl_unicodefree(inuser);
     Curl_unicodefree(inpass);
     Curl_unicodefree(inpass);
@@ -266,7 +267,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
   LDAPMessage *ldapmsg = NULL;
   LDAPMessage *ldapmsg = NULL;
   LDAPMessage *entryIterator;
   LDAPMessage *entryIterator;
   int num = 0;
   int num = 0;
-  struct Curl_easy *data=conn->data;
+  struct Curl_easy *data = conn->data;
   int ldap_proto = LDAP_VERSION3;
   int ldap_proto = LDAP_VERSION3;
   int ldap_ssl = 0;
   int ldap_ssl = 0;
   char *val_b64 = NULL;
   char *val_b64 = NULL;

+ 12 - 11
Utilities/cmcurl/lib/memdebug.c

@@ -115,7 +115,8 @@ void curl_memdebug(const char *logname)
       logfile = stderr;
       logfile = stderr;
 #ifdef MEMDEBUG_LOG_SYNC
 #ifdef MEMDEBUG_LOG_SYNC
     /* Flush the log file after every line so the log isn't lost in a crash */
     /* Flush the log file after every line so the log isn't lost in a crash */
-    setbuf(logfile, (char *)NULL);
+    if(logfile)
+      setbuf(logfile, (char *)NULL);
 #endif
 #endif
   }
   }
 }
 }
@@ -146,7 +147,7 @@ static bool countcheck(const char *func, int line, const char *source)
                 source, line, func);
                 source, line, func);
         fflush(logfile); /* because it might crash now */
         fflush(logfile); /* because it might crash now */
       }
       }
-      SET_ERRNO(ENOMEM);
+      errno = ENOMEM;
       return TRUE; /* RETURN ERROR! */
       return TRUE; /* RETURN ERROR! */
     }
     }
     else
     else
@@ -169,7 +170,7 @@ void *curl_domalloc(size_t wantedsize, int line, const char *source)
     return NULL;
     return NULL;
 
 
   /* alloc at least 64 bytes */
   /* alloc at least 64 bytes */
-  size = sizeof(struct memdebug)+wantedsize;
+  size = sizeof(struct memdebug) + wantedsize;
 
 
   mem = (Curl_cmalloc)(size);
   mem = (Curl_cmalloc)(size);
   if(mem) {
   if(mem) {
@@ -224,9 +225,9 @@ char *curl_dostrdup(const char *str, int line, const char *source)
   if(countcheck("strdup", line, source))
   if(countcheck("strdup", line, source))
     return NULL;
     return NULL;
 
 
-  len=strlen(str)+1;
+  len = strlen(str) + 1;
 
 
-  mem=curl_domalloc(len, 0, NULL); /* NULL prevents logging */
+  mem = curl_domalloc(len, 0, NULL); /* NULL prevents logging */
   if(mem)
   if(mem)
     memcpy(mem, str, len);
     memcpy(mem, str, len);
 
 
@@ -268,9 +269,9 @@ wchar_t *curl_dowcsdup(const wchar_t *str, int line, const char *source)
 void *curl_dorealloc(void *ptr, size_t wantedsize,
 void *curl_dorealloc(void *ptr, size_t wantedsize,
                      int line, const char *source)
                      int line, const char *source)
 {
 {
-  struct memdebug *mem=NULL;
+  struct memdebug *mem = NULL;
 
 
-  size_t size = sizeof(struct memdebug)+wantedsize;
+  size_t size = sizeof(struct memdebug) + wantedsize;
 
 
   DEBUGASSERT(wantedsize != 0);
   DEBUGASSERT(wantedsize != 0);
 
 
@@ -406,7 +407,7 @@ void curl_mark_sclose(curl_socket_t sockfd, int line, const char *source)
 /* this is our own defined way to close sockets on *ALL* platforms */
 /* this is our own defined way to close sockets on *ALL* platforms */
 int curl_sclose(curl_socket_t sockfd, int line, const char *source)
 int curl_sclose(curl_socket_t sockfd, int line, const char *source)
 {
 {
-  int res=sclose(sockfd);
+  int res = sclose(sockfd);
   curl_mark_sclose(sockfd, line, source);
   curl_mark_sclose(sockfd, line, source);
   return res;
   return res;
 }
 }
@@ -414,7 +415,7 @@ int curl_sclose(curl_socket_t sockfd, int line, const char *source)
 FILE *curl_fopen(const char *file, const char *mode,
 FILE *curl_fopen(const char *file, const char *mode,
                  int line, const char *source)
                  int line, const char *source)
 {
 {
-  FILE *res=fopen(file, mode);
+  FILE *res = fopen(file, mode);
 
 
   if(source)
   if(source)
     curl_memlog("FILE %s:%d fopen(\"%s\",\"%s\") = %p\n",
     curl_memlog("FILE %s:%d fopen(\"%s\",\"%s\") = %p\n",
@@ -427,7 +428,7 @@ FILE *curl_fopen(const char *file, const char *mode,
 FILE *curl_fdopen(int filedes, const char *mode,
 FILE *curl_fdopen(int filedes, const char *mode,
                   int line, const char *source)
                   int line, const char *source)
 {
 {
-  FILE *res=fdopen(filedes, mode);
+  FILE *res = fdopen(filedes, mode);
 
 
   if(source)
   if(source)
     curl_memlog("FILE %s:%d fdopen(\"%d\",\"%s\") = %p\n",
     curl_memlog("FILE %s:%d fdopen(\"%d\",\"%s\") = %p\n",
@@ -443,7 +444,7 @@ int curl_fclose(FILE *file, int line, const char *source)
 
 
   DEBUGASSERT(file != NULL);
   DEBUGASSERT(file != NULL);
 
 
-  res=fclose(file);
+  res = fclose(file);
 
 
   if(source)
   if(source)
     curl_memlog("FILE %s:%d fclose(%p)\n",
     curl_memlog("FILE %s:%d fclose(%p)\n",

+ 1860 - 0
Utilities/cmcurl/lib/mime.c

@@ -0,0 +1,1860 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, 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"
+
+#include <curl/curl.h>
+
+#include "mime.h"
+#include "non-ascii.h"
+
+#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_SMTP) || \
+    !defined(CURL_DISABLE_IMAP)
+
+#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
+#include <libgen.h>
+#endif
+
+#include "rand.h"
+#include "slist.h"
+#include "strcase.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#ifdef WIN32
+# ifndef R_OK
+#  define R_OK 4
+# endif
+#endif
+
+
+#define FILE_CONTENTTYPE_DEFAULT        "application/octet-stream"
+#define MULTIPART_CONTENTTYPE_DEFAULT   "multipart/mixed"
+#define DISPOSITION_DEFAULT             "attachment"
+
+#define READ_ERROR                      ((size_t) -1)
+
+/* Encoders. */
+static size_t encoder_nop_read(char *buffer, size_t size, bool ateof,
+                                curl_mimepart *part);
+static curl_off_t encoder_nop_size(curl_mimepart *part);
+static size_t encoder_7bit_read(char *buffer, size_t size, bool ateof,
+                                curl_mimepart *part);
+static size_t encoder_base64_read(char *buffer, size_t size, bool ateof,
+                                curl_mimepart *part);
+static curl_off_t encoder_base64_size(curl_mimepart *part);
+static size_t encoder_qp_read(char *buffer, size_t size, bool ateof,
+                              curl_mimepart *part);
+static curl_off_t encoder_qp_size(curl_mimepart *part);
+
+static const mime_encoder encoders[] = {
+  {"binary", encoder_nop_read, encoder_nop_size},
+  {"8bit", encoder_nop_read, encoder_nop_size},
+  {"7bit", encoder_7bit_read, encoder_nop_size},
+  {"base64", encoder_base64_read, encoder_base64_size},
+  {"quoted-printable", encoder_qp_read, encoder_qp_size},
+  {ZERO_NULL, ZERO_NULL, ZERO_NULL}
+};
+
+/* Base64 encoding table */
+static const char base64[] =
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+/* Quoted-printable character class table.
+ *
+ * We cannot rely on ctype functions since quoted-printable input data
+ * is assumed to be ascii-compatible, even on non-ascii platforms. */
+#define QP_OK           1       /* Can be represented by itself. */
+#define QP_SP           2       /* Space or tab. */
+#define QP_CR           3       /* Carriage return. */
+#define QP_LF           4       /* Line-feed. */
+static const unsigned char qp_class[] = {
+ 0,     0,     0,     0,     0,     0,     0,     0,            /* 00 - 07 */
+ 0,     QP_SP, QP_LF, 0,     0,     QP_CR, 0,     0,            /* 08 - 0F */
+ 0,     0,     0,     0,     0,     0,     0,     0,            /* 10 - 17 */
+ 0,     0,     0,     0,     0,     0,     0,     0,            /* 18 - 1F */
+ QP_SP, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 20 - 27 */
+ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 28 - 2F */
+ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 30 - 37 */
+ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, 0    , QP_OK, QP_OK,        /* 38 - 3F */
+ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 40 - 47 */
+ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 48 - 4F */
+ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 50 - 57 */
+ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 58 - 5F */
+ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 60 - 67 */
+ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 68 - 6F */
+ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 70 - 77 */
+ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, 0,            /* 78 - 7F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                /* 80 - 8F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                /* 90 - 9F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                /* A0 - AF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                /* B0 - BF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                /* C0 - CF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                /* D0 - DF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                /* E0 - EF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0                 /* F0 - FF */
+};
+
+
+/* Binary --> hexadecimal ASCII table. */
+static const char aschex[] =
+  "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x41\x42\x43\x44\x45\x46";
+
+
+
+#ifndef __VMS
+#define filesize(name, stat_data) (stat_data.st_size)
+#define fopen_read fopen
+
+#else
+
+#include <fabdef.h>
+/*
+ * get_vms_file_size does what it takes to get the real size of the file
+ *
+ * For fixed files, find out the size of the EOF block and adjust.
+ *
+ * For all others, have to read the entire file in, discarding the contents.
+ * Most posted text files will be small, and binary files like zlib archives
+ * and CD/DVD images should be either a STREAM_LF format or a fixed format.
+ *
+ */
+curl_off_t VmsRealFileSize(const char *name,
+                           const struct_stat *stat_buf)
+{
+  char buffer[8192];
+  curl_off_t count;
+  int ret_stat;
+  FILE * file;
+
+  file = fopen(name, FOPEN_READTEXT); /* VMS */
+  if(file == NULL)
+    return 0;
+
+  count = 0;
+  ret_stat = 1;
+  while(ret_stat > 0) {
+    ret_stat = fread(buffer, 1, sizeof(buffer), file);
+    if(ret_stat != 0)
+      count += ret_stat;
+  }
+  fclose(file);
+
+  return count;
+}
+
+/*
+ *
+ *  VmsSpecialSize checks to see if the stat st_size can be trusted and
+ *  if not to call a routine to get the correct size.
+ *
+ */
+static curl_off_t VmsSpecialSize(const char *name,
+                                 const struct_stat *stat_buf)
+{
+  switch(stat_buf->st_fab_rfm) {
+  case FAB$C_VAR:
+  case FAB$C_VFC:
+    return VmsRealFileSize(name, stat_buf);
+    break;
+  default:
+    return stat_buf->st_size;
+  }
+}
+
+#define filesize(name, stat_data) VmsSpecialSize(name, &stat_data)
+
+/*
+ * vmsfopenread
+ *
+ * For upload to work as expected on VMS, different optional
+ * parameters must be added to the fopen command based on
+ * record format of the file.
+ *
+ */
+static FILE * vmsfopenread(const char *file, const char *mode)
+{
+  struct_stat statbuf;
+  int result;
+
+  result = stat(file, &statbuf);
+
+  switch(statbuf.st_fab_rfm) {
+  case FAB$C_VAR:
+  case FAB$C_VFC:
+  case FAB$C_STMCR:
+    return fopen(file, FOPEN_READTEXT); /* VMS */
+    break;
+  default:
+    return fopen(file, FOPEN_READTEXT, "rfm=stmlf", "ctx=stm");
+  }
+}
+
+#define fopen_read vmsfopenread
+#endif
+
+
+#ifndef HAVE_BASENAME
+/*
+  (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004
+  Edition)
+
+  The basename() function shall take the pathname pointed to by path and
+  return a pointer to the final component of the pathname, deleting any
+  trailing '/' characters.
+
+  If the string pointed to by path consists entirely of the '/' character,
+  basename() shall return a pointer to the string "/". If the string pointed
+  to by path is exactly "//", it is implementation-defined whether '/' or "//"
+  is returned.
+
+  If path is a null pointer or points to an empty string, basename() shall
+  return a pointer to the string ".".
+
+  The basename() function may modify the string pointed to by path, and may
+  return a pointer to static storage that may then be overwritten by a
+  subsequent call to basename().
+
+  The basename() function need not be reentrant. A function that is not
+  required to be reentrant is not required to be thread-safe.
+
+*/
+static char *Curl_basename(char *path)
+{
+  /* Ignore all the details above for now and make a quick and simple
+     implementaion here */
+  char *s1;
+  char *s2;
+
+  s1 = strrchr(path, '/');
+  s2 = strrchr(path, '\\');
+
+  if(s1 && s2) {
+    path = (s1 > s2? s1 : s2) + 1;
+  }
+  else if(s1)
+    path = s1 + 1;
+  else if(s2)
+    path = s2 + 1;
+
+  return path;
+}
+
+#define basename(x)  Curl_basename((x))
+#endif
+
+
+/* Set readback state. */
+static void mimesetstate(mime_state *state, enum mimestate tok, void *ptr)
+{
+  state->state = tok;
+  state->ptr = ptr;
+  state->offset = 0;
+}
+
+
+/* Escape header string into allocated memory. */
+static char *escape_string(const char *src)
+{
+  size_t bytecount = 0;
+  size_t i;
+  char *dst;
+
+  for(i = 0; src[i]; i++)
+    if(src[i] == '"' || src[i] == '\\')
+      bytecount++;
+
+  bytecount += i;
+  dst = malloc(bytecount + 1);
+  if(!dst)
+    return NULL;
+
+  for(i = 0; *src; src++) {
+    if(*src == '"' || *src == '\\')
+      dst[i++] = '\\';
+    dst[i++] = *src;
+  }
+
+  dst[i] = '\0';
+  return dst;
+}
+
+/* Check if header matches. */
+static char *match_header(struct curl_slist *hdr, const char *lbl, size_t len)
+{
+  char *value = NULL;
+
+  if(strncasecompare(hdr->data, lbl, len) && hdr->data[len] == ':')
+    for(value = hdr->data + len + 1; *value == ' '; value++)
+      ;
+  return value;
+}
+
+/* Get a header from an slist. */
+static char *search_header(struct curl_slist *hdrlist, const char *hdr)
+{
+  size_t len = strlen(hdr);
+  char *value = NULL;
+
+  for(; !value && hdrlist; hdrlist = hdrlist->next)
+    value = match_header(hdrlist, hdr, len);
+
+  return value;
+}
+
+static char *strippath(const char *fullfile)
+{
+  char *filename;
+  char *base;
+  filename = strdup(fullfile); /* duplicate since basename() may ruin the
+                                  buffer it works on */
+  if(!filename)
+    return NULL;
+  base = strdup(basename(filename));
+
+  free(filename); /* free temporary buffer */
+
+  return base; /* returns an allocated string or NULL ! */
+}
+
+/* Initialize data encoder state. */
+static void cleanup_encoder_state(mime_encoder_state *p)
+{
+  p->pos = 0;
+  p->bufbeg = 0;
+  p->bufend = 0;
+}
+
+
+/* Dummy encoder. This is used for 8bit and binary content encodings. */
+static size_t encoder_nop_read(char *buffer, size_t size, bool ateof,
+                               curl_mimepart *part)
+{
+  mime_encoder_state *st = &part->encstate;
+  size_t insize = st->bufend - st->bufbeg;
+
+  (void) ateof;
+
+  if(size > insize)
+    size = insize;
+  if(size)
+    memcpy(buffer, st->buf, size);
+  st->bufbeg += size;
+  return size;
+}
+
+static curl_off_t encoder_nop_size(curl_mimepart *part)
+{
+  return part->datasize;
+}
+
+
+/* 7bit encoder: the encoder is just a data validity check. */
+static size_t encoder_7bit_read(char *buffer, size_t size, bool ateof,
+                                curl_mimepart *part)
+{
+  mime_encoder_state *st = &part->encstate;
+  size_t cursize = st->bufend - st->bufbeg;
+
+  (void) ateof;
+
+  if(size > cursize)
+    size = cursize;
+
+  for(cursize = 0; cursize < size; cursize++) {
+    *buffer = st->buf[st->bufbeg];
+    if(*buffer++ & 0x80)
+      return cursize? cursize: READ_ERROR;
+    st->bufbeg++;
+  }
+
+  return cursize;
+}
+
+
+/* Base64 content encoder. */
+static size_t encoder_base64_read(char *buffer, size_t size, bool ateof,
+                                curl_mimepart *part)
+{
+  mime_encoder_state *st = &part->encstate;
+  size_t cursize = 0;
+  int i;
+  char *ptr = buffer;
+
+  while(st->bufbeg < st->bufend) {
+    /* Line full ? */
+    if(st->pos >= MAX_ENCODED_LINE_LENGTH - 4) {
+      /* Yes, we need 2 characters for CRLF. */
+      if(size < 2)
+        break;
+      *ptr++ = '\r';
+      *ptr++ = '\n';
+      st->pos = 0;
+      cursize += 2;
+      size -= 2;
+    }
+
+    /* Be sure there is enough space and input data for a base64 group. */
+    if(size < 4 || st->bufend - st->bufbeg < 3)
+      break;
+
+    /* Encode three bytes a four characters. */
+    i = st->buf[st->bufbeg++] & 0xFF;
+    i = (i << 8) | (st->buf[st->bufbeg++] & 0xFF);
+    i = (i << 8) | (st->buf[st->bufbeg++] & 0xFF);
+    *ptr++ = base64[(i >> 18) & 0x3F];
+    *ptr++ = base64[(i >> 12) & 0x3F];
+    *ptr++ = base64[(i >> 6) & 0x3F];
+    *ptr++ = base64[i & 0x3F];
+    cursize += 4;
+    st->pos += 4;
+    size -= 4;
+  }
+
+  /* If at eof, we have to flush the buffered data. */
+  if(ateof && size >= 4) {
+    /* Buffered data size can only be 0, 1 or 2. */
+    ptr[2] = ptr[3] = '=';
+    i = 0;
+    switch(st->bufend - st->bufbeg) {
+    case 2:
+      i = (st->buf[st->bufbeg + 1] & 0xFF) << 8;
+      /* FALLTHROUGH */
+    case 1:
+      i |= (st->buf[st->bufbeg] & 0xFF) << 16;
+      ptr[0] = base64[(i >> 18) & 0x3F];
+      ptr[1] = base64[(i >> 12) & 0x3F];
+      if(++st->bufbeg != st->bufend) {
+        ptr[2] = base64[(i >> 6) & 0x3F];
+        st->bufbeg++;
+      }
+      cursize += 4;
+      st->pos += 4;
+      break;
+    }
+  }
+
+#ifdef CURL_DOES_CONVERSIONS
+  /* This is now textual data, Convert character codes. */
+  if(part->easy && cursize) {
+    CURLcode result = Curl_convert_to_network(part->easy, buffer, cursize);
+    if(result)
+      return READ_ERROR;
+  }
+#endif
+
+  return cursize;
+}
+
+static curl_off_t encoder_base64_size(curl_mimepart *part)
+{
+  curl_off_t size = part->datasize;
+
+  if(size <= 0)
+    return size;    /* Unknown size or no data. */
+
+  /* Compute base64 character count. */
+  size = 4 * (1 + (size - 1) / 3);
+
+  /* Effective character count must include CRLFs. */
+  return size + 2 * ((size - 1) / MAX_ENCODED_LINE_LENGTH);
+}
+
+
+/* Quoted-printable lookahead.
+ *
+ * Check if a CRLF or end of data is in input buffer at current position + n.
+ * Return -1 if more data needed, 1 if CRLF or end of data, else 0.
+ */
+static int qp_lookahead_eol(mime_encoder_state *st, int ateof, size_t n)
+{
+  n += st->bufbeg;
+  if(n >= st->bufend && ateof)
+    return 1;
+  if(n + 2 > st->bufend)
+    return ateof? 0: -1;
+  if(qp_class[st->buf[n] & 0xFF] == QP_CR &&
+     qp_class[st->buf[n + 1] & 0xFF] == QP_LF)
+    return 1;
+  return 0;
+}
+
+/* Quoted-printable encoder. */
+static size_t encoder_qp_read(char *buffer, size_t size, bool ateof,
+                              curl_mimepart *part)
+{
+  mime_encoder_state *st = &part->encstate;
+  char *ptr = buffer;
+  size_t cursize = 0;
+  int i;
+  size_t len;
+  size_t consumed;
+  int softlinebreak;
+  char buf[4];
+
+  /* On all platforms, input is supposed to be ASCII compatible: for this
+     reason, we use hexadecimal ASCII codes in this function rather than
+     character constants that can be interpreted as non-ascii on some
+     platforms. Preserve ASCII encoding on output too. */
+  while(st->bufbeg < st->bufend) {
+    len = 1;
+    consumed = 1;
+    i = st->buf[st->bufbeg];
+    buf[0] = (char) i;
+    buf[1] = aschex[(i >> 4) & 0xF];
+    buf[2] = aschex[i & 0xF];
+
+    switch(qp_class[st->buf[st->bufbeg] & 0xFF]) {
+    case QP_OK:          /* Not a special character. */
+      break;
+    case QP_SP:          /* Space or tab. */
+      /* Spacing must be escaped if followed by CRLF. */
+      switch(qp_lookahead_eol(st, ateof, 1)) {
+      case -1:          /* More input data needed. */
+        return cursize;
+      case 0:           /* No encoding needed. */
+        break;
+      default:          /* CRLF after space or tab. */
+        buf[0] = '\x3D';    /* '=' */
+        len = 3;
+        break;
+      }
+      break;
+    case QP_CR:         /* Carriage return. */
+      /* If followed by a line-feed, output the CRLF pair.
+         Else escape it. */
+      switch(qp_lookahead_eol(st, ateof, 0)) {
+      case -1:          /* Need more data. */
+        return cursize;
+      case 1:           /* CRLF found. */
+        buf[len++] = '\x0A';    /* Append '\n'. */
+        consumed = 2;
+        break;
+      default:          /* Not followed by LF: escape. */
+        buf[0] = '\x3D';    /* '=' */
+        len = 3;
+        break;
+      }
+      break;
+    default:            /* Character must be escaped. */
+      buf[0] = '\x3D';    /* '=' */
+      len = 3;
+      break;
+    }
+
+    /* Be sure the encoded character fits within maximum line length. */
+    if(buf[len - 1] != '\x0A') {    /* '\n' */
+      softlinebreak = st->pos + len > MAX_ENCODED_LINE_LENGTH;
+      if(!softlinebreak && st->pos + len == MAX_ENCODED_LINE_LENGTH) {
+        /* We may use the current line only if end of data or followed by
+           a CRLF. */
+        switch(qp_lookahead_eol(st, ateof, consumed)) {
+        case -1:        /* Need more data. */
+          return cursize;
+          break;
+        case 0:         /* Not followed by a CRLF. */
+          softlinebreak = 1;
+          break;
+        }
+      }
+      if(softlinebreak) {
+        strcpy(buf, "\x3D\x0D\x0A");    /* "=\r\n" */
+        len = 3;
+        consumed = 0;
+      }
+    }
+
+    /* If the output buffer would overflow, do not store. */
+    if(len > size)
+      break;
+
+    /* Append to output buffer. */
+    memcpy(ptr, buf, len);
+    cursize += len;
+    ptr += len;
+    size -= len;
+    st->pos += len;
+    if(buf[len - 1] == '\x0A')    /* '\n' */
+      st->pos = 0;
+    st->bufbeg += consumed;
+  }
+
+  return cursize;
+}
+
+static curl_off_t encoder_qp_size(curl_mimepart *part)
+{
+  /* Determining the size can only be done by reading the data: unless the
+     data size is 0, we return it as unknown (-1). */
+  return part->datasize? -1: 0;
+}
+
+
+/* In-memory data callbacks. */
+/* Argument is a pointer to the mime part. */
+static size_t mime_mem_read(char *buffer, size_t size, size_t nitems,
+                            void *instream)
+{
+  curl_mimepart *part = (curl_mimepart *) instream;
+  size_t sz = (size_t) part->datasize - part->state.offset;
+
+  (void) size;   /* Always 1.*/
+
+  if(sz > nitems)
+    sz = nitems;
+
+  if(sz)
+    memcpy(buffer, (char *) part->data, sz);
+
+  part->state.offset += sz;
+  return sz;
+}
+
+static int mime_mem_seek(void *instream, curl_off_t offset, int whence)
+{
+  curl_mimepart *part = (curl_mimepart *) instream;
+
+  switch(whence) {
+  case SEEK_CUR:
+    offset += part->state.offset;
+    break;
+  case SEEK_END:
+    offset += part->datasize;
+    break;
+  }
+
+  if(offset < 0 || offset > part->datasize)
+    return CURL_SEEKFUNC_FAIL;
+
+  part->state.offset = (size_t) offset;
+  return CURL_SEEKFUNC_OK;
+}
+
+static void mime_mem_free(void *ptr)
+{
+  Curl_safefree(((curl_mimepart *) ptr)->data);
+}
+
+
+/* Named file callbacks. */
+/* Argument is a pointer to the mime part. */
+static int mime_open_file(curl_mimepart * part)
+{
+  /* Open a MIMEKIND_FILE part. */
+
+  if(part->fp)
+    return 0;
+  part->fp = fopen_read(part->data, "rb");
+  return part->fp? 0: -1;
+}
+
+static size_t mime_file_read(char *buffer, size_t size, size_t nitems,
+                             void *instream)
+{
+  curl_mimepart *part = (curl_mimepart *) instream;
+
+  if(mime_open_file(part))
+    return READ_ERROR;
+
+  return fread(buffer, size, nitems, part->fp);
+}
+
+static int mime_file_seek(void *instream, curl_off_t offset, int whence)
+{
+  curl_mimepart *part = (curl_mimepart *) instream;
+
+  if(whence == SEEK_SET && !offset && !part->fp)
+    return CURL_SEEKFUNC_OK;   /* Not open: implicitly already at BOF. */
+
+  if(mime_open_file(part))
+    return CURL_SEEKFUNC_FAIL;
+
+  return fseek(part->fp, (long) offset, whence)?
+               CURL_SEEKFUNC_CANTSEEK: CURL_SEEKFUNC_OK;
+}
+
+static void mime_file_free(void *ptr)
+{
+  curl_mimepart *part = (curl_mimepart *) ptr;
+
+  if(part->fp) {
+    fclose(part->fp);
+    part->fp = NULL;
+  }
+  Curl_safefree(part->data);
+  part->data = NULL;
+}
+
+
+/* Subparts callbacks. */
+/* Argument is a pointer to the mime structure. */
+
+/* Readback a byte string segment. */
+static size_t readback_bytes(mime_state *state,
+                             char *buffer, size_t bufsize,
+                             const char *bytes, size_t numbytes,
+                             const char *trail)
+{
+  size_t sz;
+
+  sz = numbytes - state->offset;
+
+  if(numbytes > state->offset) {
+    sz = numbytes - state->offset;
+    bytes += state->offset;
+  }
+  else {
+    size_t tsz = strlen(trail);
+
+    sz = state->offset - numbytes;
+    if(sz >= tsz)
+      return 0;
+    bytes = trail + sz;
+    sz = tsz - sz;
+  }
+
+  if(sz > bufsize)
+    sz = bufsize;
+
+  memcpy(buffer, bytes, sz);
+  state->offset += sz;
+  return sz;
+}
+
+/* Read a non-encoded part content. */
+static size_t read_part_content(curl_mimepart *part,
+                                char *buffer, size_t bufsize)
+{
+  size_t sz = 0;
+
+  if(part->readfunc)
+    sz = part->readfunc(buffer, 1, bufsize, part->arg);
+  return sz;
+}
+
+/* Read and encode part content. */
+static size_t read_encoded_part_content(curl_mimepart *part,
+                                        char *buffer, size_t bufsize)
+{
+  mime_encoder_state *st = &part->encstate;
+  size_t cursize = 0;
+  size_t sz;
+  bool ateof = FALSE;
+
+  while(bufsize) {
+    if(st->bufbeg < st->bufend || ateof) {
+      /* Encode buffered data. */
+      sz = part->encoder->encodefunc(buffer, bufsize, ateof, part);
+      switch(sz) {
+      case 0:
+        if(ateof)
+          return cursize;
+        break;
+      case CURL_READFUNC_ABORT:
+      case CURL_READFUNC_PAUSE:
+      case READ_ERROR:
+        return cursize? cursize: sz;
+      default:
+        cursize += sz;
+        buffer += sz;
+        bufsize -= sz;
+        continue;
+      }
+    }
+
+    /* We need more data in input buffer. */
+    if(st->bufbeg) {
+      size_t len = st->bufend - st->bufbeg;
+
+      if(len)
+        memmove(st->buf, st->buf + st->bufbeg, len);
+      st->bufbeg = 0;
+      st->bufend = len;
+    }
+    if(st->bufend >= sizeof st->buf)
+      return cursize? cursize: READ_ERROR;    /* Buffer full. */
+    sz = read_part_content(part, st->buf + st->bufend,
+                           sizeof st->buf - st->bufend);
+    switch(sz) {
+    case 0:
+      ateof = TRUE;
+      break;
+    case CURL_READFUNC_ABORT:
+    case CURL_READFUNC_PAUSE:
+    case READ_ERROR:
+      return cursize? cursize: sz;
+    default:
+      st->bufend += sz;
+      break;
+    }
+  }
+
+  return cursize;
+}
+
+/* Readback a mime part. */
+static size_t readback_part(curl_mimepart *part,
+                            char *buffer, size_t bufsize)
+{
+  size_t cursize = 0;
+  size_t sz;
+  struct curl_slist *hdr;
+#ifdef CURL_DOES_CONVERSIONS
+  char *convbuf = buffer;
+#endif
+
+  /* Readback from part. */
+
+  while(bufsize) {
+    sz = 0;
+    hdr = (struct curl_slist *) part->state.ptr;
+    switch(part->state.state) {
+    case MIMESTATE_BEGIN:
+      mimesetstate(&part->state, part->flags & MIME_BODY_ONLY? MIMESTATE_BODY:
+                                 MIMESTATE_CURLHEADERS, part->curlheaders);
+      break;
+    case MIMESTATE_USERHEADERS:
+      if(!hdr) {
+        mimesetstate(&part->state, MIMESTATE_EOH, NULL);
+        break;
+      }
+      if(match_header(hdr, "Content-Type", 12)) {
+        mimesetstate(&part->state, MIMESTATE_USERHEADERS, hdr->next);
+        break;
+      }
+      /* FALLTHROUGH */
+    case MIMESTATE_CURLHEADERS:
+      if(!hdr)
+        mimesetstate(&part->state, MIMESTATE_USERHEADERS, part->userheaders);
+      else {
+        sz = readback_bytes(&part->state, buffer, bufsize,
+                            hdr->data, strlen(hdr->data), "\r\n");
+        if(!sz)
+          mimesetstate(&part->state, part->state.state, hdr->next);
+      }
+      break;
+    case MIMESTATE_EOH:
+      sz = readback_bytes(&part->state, buffer, bufsize, "\r\n", 2, "");
+      if(!sz)
+        mimesetstate(&part->state, MIMESTATE_BODY, NULL);
+      break;
+    case MIMESTATE_BODY:
+#ifdef CURL_DOES_CONVERSIONS
+      if(part->easy && convbuf < buffer) {
+        CURLcode result = Curl_convert_to_network(part->easy, convbuf,
+                                                  buffer - convbuf);
+        if(result)
+          return READ_ERROR;
+        convbuf = buffer;
+      }
+#endif
+      cleanup_encoder_state(&part->encstate);
+      mimesetstate(&part->state, MIMESTATE_CONTENT, NULL);
+      break;
+    case MIMESTATE_CONTENT:
+      if(part->encoder)
+        sz = read_encoded_part_content(part, buffer, bufsize);
+      else
+        sz = read_part_content(part, buffer, bufsize);
+      switch(sz) {
+      case 0:
+        mimesetstate(&part->state, MIMESTATE_END, NULL);
+        /* Try sparing open file descriptors. */
+        if(part->kind == MIMEKIND_FILE && part->fp) {
+          fclose(part->fp);
+          part->fp = NULL;
+        }
+        /* FALLTHROUGH */
+      case CURL_READFUNC_ABORT:
+      case CURL_READFUNC_PAUSE:
+      case READ_ERROR:
+        return cursize? cursize: sz;
+      }
+      break;
+    case MIMESTATE_END:
+      return cursize;
+    default:
+      break;    /* Other values not in part state. */
+    }
+
+    /* Bump buffer and counters according to read size. */
+    cursize += sz;
+    buffer += sz;
+    bufsize -= sz;
+  }
+
+#ifdef CURL_DOES_CONVERSIONS
+      if(part->easy && convbuf < buffer &&
+         part->state.state < MIMESTATE_BODY) {
+        CURLcode result = Curl_convert_to_network(part->easy, convbuf,
+                                                  buffer - convbuf);
+        if(result)
+          return READ_ERROR;
+      }
+#endif
+
+  return cursize;
+}
+
+/* Readback from mime. */
+static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems,
+                                 void *instream)
+{
+  curl_mime *mime = (curl_mime *) instream;
+  size_t cursize = 0;
+  size_t sz;
+  curl_mimepart *part;
+#ifdef CURL_DOES_CONVERSIONS
+  char *convbuf = buffer;
+#endif
+
+  (void) size;   /* Always 1. */
+
+  while(nitems) {
+    sz = 0;
+    part = mime->state.ptr;
+    switch(mime->state.state) {
+    case MIMESTATE_BEGIN:
+    case MIMESTATE_BODY:
+#ifdef CURL_DOES_CONVERSIONS
+      convbuf = buffer;
+#endif
+      mimesetstate(&mime->state, MIMESTATE_BOUNDARY1, mime->firstpart);
+      /* The first boundary always follows the header termination empty line,
+         so is always preceded by a CRLK. We can then spare 2 characters
+         by skipping the leading CRLF in boundary. */
+      mime->state.offset += 2;
+      break;
+    case MIMESTATE_BOUNDARY1:
+      sz = readback_bytes(&mime->state, buffer, nitems, "\r\n--", 4, "");
+      if(!sz)
+        mimesetstate(&mime->state, MIMESTATE_BOUNDARY2, part);
+      break;
+    case MIMESTATE_BOUNDARY2:
+      sz = readback_bytes(&mime->state, buffer, nitems, mime->boundary,
+                          strlen(mime->boundary), part? "\r\n": "--\r\n");
+      if(!sz) {
+#ifdef CURL_DOES_CONVERSIONS
+        if(mime->easy && convbuf < buffer) {
+          CURLcode result = Curl_convert_to_network(mime->easy, convbuf,
+                                                    buffer - convbuf);
+          if(result)
+            return READ_ERROR;
+          convbuf = buffer;
+        }
+#endif
+        mimesetstate(&mime->state, MIMESTATE_CONTENT, part);
+      }
+      break;
+    case MIMESTATE_CONTENT:
+      if(!part) {
+        mimesetstate(&mime->state, MIMESTATE_END, NULL);
+        break;
+      }
+      sz = readback_part(part, buffer, nitems);
+      switch(sz) {
+      case CURL_READFUNC_ABORT:
+      case CURL_READFUNC_PAUSE:
+      case READ_ERROR:
+        return cursize? cursize: sz;
+      case 0:
+#ifdef CURL_DOES_CONVERSIONS
+        convbuf = buffer;
+#endif
+        mimesetstate(&mime->state, MIMESTATE_BOUNDARY1, part->nextpart);
+        break;
+      }
+      break;
+    case MIMESTATE_END:
+      return cursize;
+    default:
+      break;    /* other values not used in mime state. */
+    }
+
+    /* Bump buffer and counters according to read size. */
+    cursize += sz;
+    buffer += sz;
+    nitems -= sz;
+  }
+
+#ifdef CURL_DOES_CONVERSIONS
+      if(mime->easy && convbuf < buffer &&
+         mime->state.state <= MIMESTATE_CONTENT) {
+        CURLcode result = Curl_convert_to_network(mime->easy, convbuf,
+                                                  buffer - convbuf);
+        if(result)
+          return READ_ERROR;
+      }
+#endif
+
+  return cursize;
+}
+
+static int mime_part_rewind(curl_mimepart *part)
+{
+  int res = CURL_SEEKFUNC_OK;
+  enum mimestate targetstate = MIMESTATE_BEGIN;
+
+  if(part->flags & MIME_BODY_ONLY)
+    targetstate = MIMESTATE_BODY;
+  cleanup_encoder_state(&part->encstate);
+  if(part->state.state > targetstate) {
+    res = CURL_SEEKFUNC_CANTSEEK;
+    if(part->seekfunc) {
+      res = part->seekfunc(part->arg, (curl_off_t) 0, SEEK_SET);
+      switch(res) {
+      case CURL_SEEKFUNC_OK:
+      case CURL_SEEKFUNC_FAIL:
+      case CURL_SEEKFUNC_CANTSEEK:
+        break;
+      case -1:    /* For fseek() error. */
+        res = CURL_SEEKFUNC_CANTSEEK;
+        break;
+      default:
+        res = CURL_SEEKFUNC_FAIL;
+        break;
+      }
+    }
+  }
+
+  if(res == CURL_SEEKFUNC_OK)
+    mimesetstate(&part->state, targetstate, NULL);
+
+  return res;
+}
+
+static int mime_subparts_seek(void *instream, curl_off_t offset, int whence)
+{
+  curl_mime *mime = (curl_mime *) instream;
+  curl_mimepart *part;
+  int result = CURL_SEEKFUNC_OK;
+  int res;
+
+  if(whence != SEEK_SET || offset)
+    return CURL_SEEKFUNC_CANTSEEK;    /* Only support full rewind. */
+
+  if(mime->state.state == MIMESTATE_BEGIN)
+   return CURL_SEEKFUNC_OK;           /* Already rewound. */
+
+  for(part = mime->firstpart; part; part = part->nextpart) {
+    res = mime_part_rewind(part);
+    if(res != CURL_SEEKFUNC_OK)
+      result = res;
+  }
+
+  if(result == CURL_SEEKFUNC_OK)
+    mimesetstate(&mime->state, MIMESTATE_BEGIN, NULL);
+
+  return result;
+}
+
+static void mime_subparts_free(void *ptr)
+{
+  curl_mime *mime = (curl_mime *) ptr;
+  curl_mime_free(mime);
+}
+
+
+/* Release part content. */
+static void cleanup_part_content(curl_mimepart *part)
+{
+  if(part->freefunc)
+    part->freefunc(part->arg);
+
+  part->readfunc = NULL;
+  part->seekfunc = NULL;
+  part->freefunc = NULL;
+  part->arg = (void *) part;          /* Defaults to part itself. */
+  part->data = NULL;
+  part->fp = NULL;
+  part->datasize = (curl_off_t) 0;    /* No size yet. */
+  part->encoder = NULL;
+  cleanup_encoder_state(&part->encstate);
+  part->kind = MIMEKIND_NONE;
+}
+
+void Curl_mime_cleanpart(curl_mimepart *part)
+{
+  cleanup_part_content(part);
+  curl_slist_free_all(part->curlheaders);
+  if(part->flags & MIME_USERHEADERS_OWNER)
+    curl_slist_free_all(part->userheaders);
+  Curl_safefree(part->mimetype);
+  Curl_safefree(part->name);
+  Curl_safefree(part->filename);
+  Curl_mime_initpart(part, part->easy);
+}
+
+/* Recursively delete a mime handle and its parts. */
+void curl_mime_free(curl_mime *mime)
+{
+  curl_mimepart *part;
+
+  if(mime) {
+    while(mime->firstpart) {
+      part = mime->firstpart;
+      mime->firstpart = part->nextpart;
+      Curl_mime_cleanpart(part);
+      free(part);
+    }
+
+    free(mime->boundary);
+    free(mime);
+  }
+}
+
+/*
+ * Mime build functions.
+ */
+
+/* Create a mime handle. */
+curl_mime *curl_mime_init(struct Curl_easy *easy)
+{
+  curl_mime *mime;
+
+  mime = (curl_mime *) malloc(sizeof *mime);
+
+  if(mime) {
+    mime->easy = easy;
+    mime->parent = NULL;
+    mime->firstpart = NULL;
+    mime->lastpart = NULL;
+
+    /* Get a part boundary. */
+    mime->boundary = malloc(24 + MIME_RAND_BOUNDARY_CHARS + 1);
+    if(!mime->boundary) {
+      free(mime);
+      return NULL;
+    }
+
+    memset(mime->boundary, '-', 24);
+    Curl_rand_hex(easy, (unsigned char *) mime->boundary + 24,
+                  MIME_RAND_BOUNDARY_CHARS + 1);
+    mimesetstate(&mime->state, MIMESTATE_BEGIN, NULL);
+  }
+
+  return mime;
+}
+
+/* Initialize a mime part. */
+void Curl_mime_initpart(curl_mimepart *part, struct Curl_easy *easy)
+{
+  memset((char *) part, 0, sizeof *part);
+  part->easy = easy;
+  mimesetstate(&part->state, MIMESTATE_BEGIN, NULL);
+}
+
+/* Create a mime part and append it to a mime handle's part list. */
+curl_mimepart *curl_mime_addpart(curl_mime *mime)
+{
+  curl_mimepart *part;
+
+  if(!mime)
+    return NULL;
+
+  part = (curl_mimepart *) malloc(sizeof *part);
+
+  if(part) {
+    Curl_mime_initpart(part, mime->easy);
+    part->parent = mime;
+
+    if(mime->lastpart)
+      mime->lastpart->nextpart = part;
+    else
+      mime->firstpart = part;
+
+    mime->lastpart = part;
+  }
+
+  return part;
+}
+
+/* Set mime part name. */
+CURLcode curl_mime_name(curl_mimepart *part, const char *name)
+{
+  if(!part)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  Curl_safefree(part->name);
+  part->name = NULL;
+
+  if(name) {
+    part->name = strdup(name);
+    if(!part->name)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  return CURLE_OK;
+}
+
+/* Set mime part remote file name. */
+CURLcode curl_mime_filename(curl_mimepart *part, const char *filename)
+{
+  if(!part)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  Curl_safefree(part->filename);
+  part->filename = NULL;
+
+  if(filename) {
+    part->filename = strdup(filename);
+    if(!part->filename)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  return CURLE_OK;
+}
+
+/* Set mime part content from memory data. */
+CURLcode curl_mime_data(curl_mimepart *part,
+                        const char *data, size_t datasize)
+{
+  if(!part)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  cleanup_part_content(part);
+
+  if(data) {
+    if(datasize == CURL_ZERO_TERMINATED)
+      datasize = strlen(data);
+
+    part->data = malloc(datasize + 1);
+    if(!part->data)
+      return CURLE_OUT_OF_MEMORY;
+
+    part->datasize = datasize;
+
+    if(datasize)
+      memcpy(part->data, data, datasize);
+    part->data[datasize] = '\0';    /* Set a nul terminator as sentinel. */
+
+    part->readfunc = mime_mem_read;
+    part->seekfunc = mime_mem_seek;
+    part->freefunc = mime_mem_free;
+    part->kind = MIMEKIND_DATA;
+  }
+
+  return CURLE_OK;
+}
+
+/* Set mime part content from named local file. */
+CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename)
+{
+  CURLcode result = CURLE_OK;
+  char *base;
+
+  if(!part)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  cleanup_part_content(part);
+
+  if(filename) {
+    struct_stat sbuf;
+
+    if(stat(filename, &sbuf) || access(filename, R_OK))
+      result = CURLE_READ_ERROR;
+
+    part->data = strdup(filename);
+    if(!part->data)
+      result = CURLE_OUT_OF_MEMORY;
+
+    part->datasize = -1;
+    if(!result && S_ISREG(sbuf.st_mode)) {
+      part->datasize = filesize(filename, sbuf);
+      part->seekfunc = mime_file_seek;
+    }
+
+    part->readfunc = mime_file_read;
+    part->freefunc = mime_file_free;
+    part->kind = MIMEKIND_FILE;
+
+    /* As a side effect, set the filename to the current file's base name.
+       It is possible to withdraw this by explicitly calling
+       curl_mime_filename() with a NULL filename argument after the current
+       call. */
+    base = strippath(filename);
+    if(!base)
+      result = CURLE_OUT_OF_MEMORY;
+    else {
+      CURLcode res = curl_mime_filename(part, base);
+
+      if(res)
+        result = res;
+      free(base);
+    }
+  }
+  return result;
+}
+
+/* Set mime part type. */
+CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype)
+{
+  if(!part)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  Curl_safefree(part->mimetype);
+  part->mimetype = NULL;
+
+  if(mimetype) {
+    part->mimetype = strdup(mimetype);
+    if(!part->mimetype)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  return CURLE_OK;
+}
+
+/* Set mime data transfer encoder. */
+CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding)
+{
+  CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
+  const mime_encoder *mep;
+
+  if(!part)
+    return result;
+
+  part->encoder = NULL;
+
+  if(!encoding)
+    return CURLE_OK;    /* Removing current encoder. */
+
+  for(mep = encoders; mep->name; mep++)
+    if(strcasecompare(encoding, mep->name)) {
+      part->encoder = mep;
+      result = CURLE_OK;
+    }
+
+  return result;
+}
+
+/* Set mime part headers. */
+CURLcode curl_mime_headers(curl_mimepart *part,
+                           struct curl_slist *headers, int take_ownership)
+{
+  if(!part)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  if(part->flags & MIME_USERHEADERS_OWNER) {
+    curl_slist_free_all(part->userheaders);
+    part->flags &= ~MIME_USERHEADERS_OWNER;
+  }
+  part->userheaders = headers;
+  if(headers && take_ownership)
+    part->flags |= MIME_USERHEADERS_OWNER;
+  return CURLE_OK;
+}
+
+/* Set mime part content from callback. */
+CURLcode curl_mime_data_cb(curl_mimepart *part, curl_off_t datasize,
+                           curl_read_callback readfunc,
+                           curl_seek_callback seekfunc,
+                           curl_free_callback freefunc, void *arg)
+{
+  if(!part)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  cleanup_part_content(part);
+
+  if(readfunc) {
+    part->readfunc = readfunc;
+    part->seekfunc = seekfunc;
+    part->freefunc = freefunc;
+    part->arg = arg;
+    part->datasize = datasize;
+    part->kind = MIMEKIND_CALLBACK;
+  }
+
+  return CURLE_OK;
+}
+
+/* Set mime part content from subparts. */
+CURLcode curl_mime_subparts(curl_mimepart *part,
+                            curl_mime *subparts)
+{
+  if(!part)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  /* Accept setting twice the same subparts. */
+  if(part->kind == MIMEKIND_MULTIPART && part->arg == subparts)
+    return CURLE_OK;
+
+  cleanup_part_content(part);
+
+  if(subparts) {
+    /* Must belong to the same data handle. */
+    if(part->easy && subparts->easy && part->easy != subparts->easy)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+
+    /* Should not have been attached already. */
+    if(subparts->parent)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+
+    subparts->parent = part;
+    part->readfunc = mime_subparts_read;
+    part->seekfunc = mime_subparts_seek;
+    part->freefunc = mime_subparts_free;
+    part->arg = subparts;
+    part->datasize = -1;
+    part->kind = MIMEKIND_MULTIPART;
+  }
+
+  return CURLE_OK;
+}
+
+
+/* Readback from top mime. */
+/* Argument is the dummy top part. */
+size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, void *instream)
+{
+  curl_mimepart *part = (curl_mimepart *) instream;
+
+  (void) size;   /* Always 1. */
+  return readback_part(part, buffer, nitems);
+}
+
+/* Rewind mime stream. */
+CURLcode Curl_mime_rewind(curl_mimepart *part)
+{
+  return mime_part_rewind(part) == CURL_SEEKFUNC_OK?
+         CURLE_OK: CURLE_SEND_FAIL_REWIND;
+}
+
+/* Compute header list size. */
+static size_t slist_size(struct curl_slist *s,
+                         size_t overhead, const char *skip)
+{
+  size_t size = 0;
+  size_t skiplen = skip? strlen(skip): 0;
+
+  for(; s; s = s->next)
+    if(!skip || !match_header(s, skip, skiplen))
+      size += strlen(s->data) + overhead;
+  return size;
+}
+
+/* Get/compute multipart size. */
+static curl_off_t multipart_size(curl_mime *mime)
+{
+  curl_off_t size;
+  curl_off_t sz;
+  size_t boundarysize;
+  curl_mimepart *part;
+
+  if(!mime)
+    return 0;           /* Not present -> empty. */
+
+  boundarysize = 4 + strlen(mime->boundary) + 2;
+  size = boundarysize;  /* Final boundary - CRLF after headers. */
+
+  for(part = mime->firstpart; part; part = part->nextpart) {
+    sz = Curl_mime_size(part);
+
+    if(sz < 0)
+      size = sz;
+
+    if(size >= 0)
+      size += boundarysize + sz;
+  }
+
+  return size;
+}
+
+/* Get/compute mime size. */
+curl_off_t Curl_mime_size(curl_mimepart *part)
+{
+  curl_off_t size;
+
+  if(part->datasize < 0 && part->kind == MIMEKIND_MULTIPART)
+    part->datasize = multipart_size(part->arg);
+
+  size = part->datasize;
+
+  if(part->encoder)
+    size = part->encoder->sizefunc(part);
+
+  if(size >= 0 && !(part->flags & MIME_BODY_ONLY)) {
+    /* Compute total part size. */
+    size += slist_size(part->curlheaders, 2, NULL);
+    size += slist_size(part->userheaders, 2, "Content-Type");
+    size += 2;    /* CRLF after headers. */
+  }
+  return size;
+}
+
+/* Add a header. */
+/* VARARGS2 */
+CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...)
+{
+  struct curl_slist *hdr = NULL;
+  char *s = NULL;
+  va_list ap;
+
+  va_start(ap, fmt);
+  s = curl_mvaprintf(fmt, ap);
+  va_end(ap);
+
+  if(s) {
+    hdr = Curl_slist_append_nodup(*slp, s);
+    if(hdr)
+      *slp = hdr;
+    else
+      free(s);
+  }
+
+  return hdr? CURLE_OK: CURLE_OUT_OF_MEMORY;
+}
+
+/* Add a content type header. */
+static CURLcode add_content_type(struct curl_slist **slp,
+                                 const char *type, const char *boundary)
+{
+  return Curl_mime_add_header(slp, "Content-Type: %s%s%s", type,
+                              boundary? "; boundary=": "",
+                              boundary? boundary: "");
+}
+
+
+static const char *ContentTypeForFilename(const char *filename)
+{
+  unsigned int i;
+
+  /*
+   * If no content type was specified, we scan through a few well-known
+   * extensions and pick the first we match!
+   */
+  struct ContentType {
+    const char *extension;
+    const char *type;
+  };
+  static const struct ContentType ctts[] = {
+    {".gif",  "image/gif"},
+    {".jpg",  "image/jpeg"},
+    {".jpeg", "image/jpeg"},
+    {".png",  "image/png"},
+    {".svg",  "image/svg+xml"},
+    {".txt",  "text/plain"},
+    {".htm",  "text/html"},
+    {".html", "text/html"},
+    {".pdf",  "application/pdf"},
+    {".xml",  "application/xml"}
+  };
+
+  if(filename) {
+    size_t len1 = strlen(filename);
+    const char *nameend = filename + len1;
+
+    for(i = 0; i < sizeof ctts / sizeof ctts[0]; i++) {
+      size_t len2 = strlen(ctts[i].extension);
+
+      if(len1 >= len2 && strcasecompare(nameend - len2, ctts[i].extension))
+          return ctts[i].type;
+    }
+  }
+  return NULL;
+}
+
+CURLcode Curl_mime_prepare_headers(curl_mimepart *part,
+                                   const char *contenttype,
+                                   const char *disposition,
+                                   enum mimestrategy strategy)
+{
+  curl_mime *mime = NULL;
+  const char *boundary = NULL;
+  char *s;
+  const char *cte = NULL;
+  CURLcode ret = CURLE_OK;
+
+  /* Get rid of previously prepared headers. */
+  curl_slist_free_all(part->curlheaders);
+  part->curlheaders = NULL;
+
+  /* Be sure we won't access old headers later. */
+  if(part->state.state == MIMESTATE_CURLHEADERS)
+    mimesetstate(&part->state, MIMESTATE_CURLHEADERS, NULL);
+
+  /* Build the content-type header. */
+  s = search_header(part->userheaders, "Content-Type");
+  if(s)
+    contenttype = s;
+  if(part->mimetype)
+    contenttype = part->mimetype;
+  if(!contenttype) {
+    switch(part->kind) {
+    case MIMEKIND_MULTIPART:
+      contenttype = MULTIPART_CONTENTTYPE_DEFAULT;
+      break;
+    case MIMEKIND_FILE:
+      contenttype = ContentTypeForFilename(part->filename);
+      if(!contenttype)
+        contenttype = ContentTypeForFilename(part->data);
+      if(!contenttype && part->filename)
+        contenttype = FILE_CONTENTTYPE_DEFAULT;
+      break;
+    default:
+      contenttype = ContentTypeForFilename(part->filename);
+      break;
+    }
+  }
+
+  if(part->kind == MIMEKIND_MULTIPART) {
+    mime = (curl_mime *) part->arg;
+    if(mime)
+      boundary = mime->boundary;
+  }
+  else if(contenttype && strcasecompare(contenttype, "text/plain"))
+    if(strategy == MIMESTRATEGY_MAIL || !part->filename)
+      contenttype = NULL;
+
+  /* Issue content-disposition header only if not already set by caller. */
+  if(!search_header(part->userheaders, "Content-Disposition")) {
+    if(!disposition)
+      if(part->filename || part->name ||
+        (contenttype && !strncasecompare(contenttype, "multipart/", 10)))
+          disposition = DISPOSITION_DEFAULT;
+    if(disposition && curl_strequal(disposition, "attachment") &&
+     !part->name && !part->filename)
+      disposition = NULL;
+    if(disposition) {
+      char *name = NULL;
+      char *filename = NULL;
+
+      if(part->name) {
+        name = escape_string(part->name);
+        if(!name)
+          ret = CURLE_OUT_OF_MEMORY;
+      }
+      if(!ret && part->filename) {
+        filename = escape_string(part->filename);
+        if(!filename)
+          ret = CURLE_OUT_OF_MEMORY;
+      }
+      if(!ret)
+        ret = Curl_mime_add_header(&part->curlheaders,
+                                   "Content-Disposition: %s%s%s%s%s%s%s",
+                                   disposition,
+                                   name? "; name=\"": "",
+                                   name? name: "",
+                                   name? "\"": "",
+                                   filename? "; filename=\"": "",
+                                   filename? filename: "",
+                                   filename? "\"": "");
+      Curl_safefree(name);
+      Curl_safefree(filename);
+      if(ret)
+        return ret;
+      }
+    }
+
+  /* Issue Content-Type header. */
+  if(contenttype) {
+    ret = add_content_type(&part->curlheaders, contenttype, boundary);
+    if(ret)
+      return ret;
+  }
+
+  /* Content-Transfer-Encoding header. */
+  if(!search_header(part->userheaders, "Content-Transfer-Encoding")) {
+    if(part->encoder)
+      cte = part->encoder->name;
+    else if(contenttype && strategy == MIMESTRATEGY_MAIL &&
+     part->kind != MIMEKIND_MULTIPART)
+      cte = "8bit";
+    if(cte) {
+      ret = Curl_mime_add_header(&part->curlheaders,
+                                 "Content-Transfer-Encoding: %s", cte);
+      if(ret)
+        return ret;
+    }
+  }
+
+  /* If we were reading curl-generated headers, restart with new ones (this
+     should not occur). */
+  if(part->state.state == MIMESTATE_CURLHEADERS)
+    mimesetstate(&part->state, MIMESTATE_CURLHEADERS, part->curlheaders);
+
+  /* Process subparts. */
+  if(part->kind == MIMEKIND_MULTIPART && mime) {
+    curl_mimepart *subpart;
+
+    disposition = NULL;
+    if(strcasecompare(contenttype, "multipart/form-data"))
+      disposition = "form-data";
+    for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart) {
+      ret = Curl_mime_prepare_headers(subpart, NULL, disposition, strategy);
+      if(ret)
+        return ret;
+    }
+  }
+  return ret;
+}
+
+#else /* !CURL_DISABLE_HTTP || !CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP */
+
+/* Mime not compiled in: define stubs for externally-referenced functions. */
+curl_mime *curl_mime_init(CURL *easy)
+{
+  (void) easy;
+  return NULL;
+}
+
+void curl_mime_free(curl_mime *mime)
+{
+  (void) mime;
+}
+
+curl_mimepart *curl_mime_addpart(curl_mime *mime)
+{
+  (void) mime;
+  return NULL;
+}
+
+CURLcode curl_mime_name(curl_mimepart *part, const char *name)
+{
+  (void) part;
+  (void) name;
+  return CURLE_NOT_BUILT_IN;
+}
+
+CURLcode curl_mime_filename(curl_mimepart *part, const char *filename)
+{
+  (void) part;
+  (void) filename;
+  return CURLE_NOT_BUILT_IN;
+}
+
+CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype)
+{
+  (void) part;
+  (void) mimetype;
+  return CURLE_NOT_BUILT_IN;
+}
+
+CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding)
+{
+  (void) part;
+  (void) encoding;
+  return CURLE_NOT_BUILT_IN;
+}
+
+CURLcode curl_mime_data(curl_mimepart *part,
+                        const char *data, size_t datasize)
+{
+  (void) part;
+  (void) data;
+  (void) datasize;
+  return CURLE_NOT_BUILT_IN;
+}
+
+CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename)
+{
+  (void) part;
+  (void) filename;
+  return CURLE_NOT_BUILT_IN;
+}
+
+CURLcode curl_mime_data_cb(curl_mimepart *part,
+                           curl_off_t datasize,
+                           curl_read_callback readfunc,
+                           curl_seek_callback seekfunc,
+                           curl_free_callback freefunc,
+                           void *arg)
+{
+  (void) part;
+  (void) datasize;
+  (void) readfunc;
+  (void) seekfunc;
+  (void) freefunc;
+  (void) arg;
+  return CURLE_NOT_BUILT_IN;
+}
+
+CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts)
+{
+  (void) part;
+  (void) subparts;
+  return CURLE_NOT_BUILT_IN;
+}
+
+CURLcode curl_mime_headers(curl_mimepart *part,
+                           struct curl_slist *headers, int take_ownership)
+{
+  (void) part;
+  (void) headers;
+  (void) take_ownership;
+  return CURLE_NOT_BUILT_IN;
+}
+
+void Curl_mime_initpart(curl_mimepart *part, struct Curl_easy *easy)
+{
+  (void) part;
+  (void) easy;
+}
+
+void Curl_mime_cleanpart(curl_mimepart *part)
+{
+  (void) part;
+}
+
+CURLcode Curl_mime_prepare_headers(curl_mimepart *part,
+                                   const char *contenttype,
+                                   const char *disposition,
+                                   enum mimestrategy strategy)
+{
+  (void) part;
+  (void) contenttype;
+  (void) disposition;
+  (void) strategy;
+  return CURLE_NOT_BUILT_IN;
+}
+
+curl_off_t Curl_mime_size(curl_mimepart *part)
+{
+  (void) part;
+  return (curl_off_t) -1;
+}
+
+size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, void *instream)
+{
+  (void) buffer;
+  (void) size;
+  (void) nitems;
+  (void) instream;
+  return 0;
+}
+
+CURLcode Curl_mime_rewind(curl_mimepart *part)
+{
+  (void) part;
+  return CURLE_NOT_BUILT_IN;
+}
+
+/* VARARGS2 */
+CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...)
+{
+  (void) slp;
+  (void) fmt;
+  return CURLE_NOT_BUILT_IN;
+}
+
+#endif /* !CURL_DISABLE_HTTP || !CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP */

+ 135 - 0
Utilities/cmcurl/lib/mime.h

@@ -0,0 +1,135 @@
+#ifndef HEADER_CURL_MIME_H
+#define HEADER_CURL_MIME_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, 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.
+ *
+ ***************************************************************************/
+
+#define MIME_RAND_BOUNDARY_CHARS        16  /* Nb. of random boundary chars. */
+#define MAX_ENCODED_LINE_LENGTH         76  /* Maximum encoded line length. */
+#define ENCODING_BUFFER_SIZE            256 /* Encoding temp buffers size. */
+
+/* Part flags. */
+#define MIME_USERHEADERS_OWNER  (1 << 0)
+#define MIME_BODY_ONLY          (1 << 1)
+
+/* Part source kinds. */
+enum mimekind {
+  MIMEKIND_NONE = 0,            /* Part not set. */
+  MIMEKIND_DATA,                /* Allocated mime data. */
+  MIMEKIND_FILE,                /* Data from file. */
+  MIMEKIND_CALLBACK,            /* Data from `read' callback. */
+  MIMEKIND_MULTIPART,           /* Data is a mime subpart. */
+  MIMEKIND_LAST
+};
+
+/* Readback state tokens. */
+enum mimestate {
+  MIMESTATE_BEGIN,              /* Readback has not yet started. */
+  MIMESTATE_CURLHEADERS,        /* In curl-generated headers. */
+  MIMESTATE_USERHEADERS,        /* In caller's supplied headers. */
+  MIMESTATE_EOH,                /* End of headers. */
+  MIMESTATE_BODY,               /* Placeholder. */
+  MIMESTATE_BOUNDARY1,          /* In boundary prefix. */
+  MIMESTATE_BOUNDARY2,          /* In boundary. */
+  MIMESTATE_CONTENT,            /* In content. */
+  MIMESTATE_END,                /* End of part reached. */
+  MIMESTATE_LAST
+};
+
+/* Mime headers strategies. */
+enum mimestrategy {
+  MIMESTRATEGY_MAIL,            /* Mime mail. */
+  MIMESTRATEGY_FORM,            /* HTTP post form. */
+  MIMESTRATEGY_LAST
+};
+
+/* Content transfer encoder. */
+typedef struct {
+  const char *   name;          /* Encoding name. */
+  size_t         (*encodefunc)(char *buffer, size_t size, bool ateof,
+                             curl_mimepart *part);  /* Encoded read. */
+  curl_off_t     (*sizefunc)(curl_mimepart *part);  /* Encoded size. */
+}  mime_encoder;
+
+/* Content transfer encoder state. */
+typedef struct {
+  size_t         pos;           /* Position on output line. */
+  size_t         bufbeg;        /* Next data index in input buffer. */
+  size_t         bufend;        /* First unused byte index in input buffer. */
+  char           buf[ENCODING_BUFFER_SIZE]; /* Input buffer. */
+}  mime_encoder_state;
+
+/* Mime readback state. */
+typedef struct {
+  enum mimestate state;       /* Current state token. */
+  void *ptr;                  /* State-dependent pointer. */
+  size_t offset;              /* State-dependent offset. */
+}  mime_state;
+
+/* A mime multipart. */
+struct curl_mime_s {
+  struct Curl_easy *easy;          /* The associated easy handle. */
+  curl_mimepart *parent;           /* Parent part. */
+  curl_mimepart *firstpart;        /* First part. */
+  curl_mimepart *lastpart;         /* Last part. */
+  char *boundary;                  /* The part boundary. */
+  mime_state state;                /* Current readback state. */
+};
+
+/* A mime part. */
+struct curl_mimepart_s {
+  struct Curl_easy *easy;          /* The associated easy handle. */
+  curl_mime *parent;               /* Parent mime structure. */
+  curl_mimepart *nextpart;         /* Forward linked list. */
+  enum mimekind kind;              /* The part kind. */
+  char *data;                      /* Memory data or file name. */
+  curl_read_callback readfunc;     /* Read function. */
+  curl_seek_callback seekfunc;     /* Seek function. */
+  curl_free_callback freefunc;     /* Argument free function. */
+  void *arg;                       /* Argument to callback functions. */
+  FILE *fp;                        /* File pointer. */
+  struct curl_slist *curlheaders;  /* Part headers. */
+  struct curl_slist *userheaders;  /* Part headers. */
+  char *mimetype;                  /* Part mime type. */
+  char *filename;                  /* Remote file name. */
+  char *name;                      /* Data name. */
+  curl_off_t datasize;             /* Expected data size. */
+  unsigned int flags;              /* Flags. */
+  mime_state state;                /* Current readback state. */
+  const mime_encoder *encoder;     /* Content data encoder. */
+  mime_encoder_state encstate;     /* Data encoder state. */
+};
+
+
+/* Prototypes. */
+void Curl_mime_initpart(curl_mimepart *part, struct Curl_easy *easy);
+void Curl_mime_cleanpart(curl_mimepart *part);
+CURLcode Curl_mime_prepare_headers(curl_mimepart *part,
+                                   const char *contenttype,
+                                   const char *disposition,
+                                   enum mimestrategy strategy);
+curl_off_t Curl_mime_size(curl_mimepart *part);
+size_t Curl_mime_read(char *buffer, size_t size, size_t nitems,
+                      void *instream);
+CURLcode Curl_mime_rewind(curl_mimepart *part);
+CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...);
+
+#endif /* HEADER_CURL_MIME_H */

+ 17 - 21
Utilities/cmcurl/lib/mprintf.c

@@ -46,10 +46,6 @@
  * If SIZEOF_SIZE_T has not been defined, default to the size of long.
  * 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
 #ifdef HAVE_LONGLONG
 #  define LONG_LONG_TYPE long long
 #  define LONG_LONG_TYPE long long
 #  define HAVE_LONG_LONG_TYPE
 #  define HAVE_LONG_LONG_TYPE
@@ -111,7 +107,7 @@ static const char upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
   } WHILE_FALSE
   } WHILE_FALSE
 
 
 /* Data type to read from the arglist */
 /* Data type to read from the arglist */
-typedef enum  {
+typedef enum {
   FORMAT_UNKNOWN = 0,
   FORMAT_UNKNOWN = 0,
   FORMAT_STRING,
   FORMAT_STRING,
   FORMAT_PTR,
   FORMAT_PTR,
@@ -181,7 +177,7 @@ struct asprintf {
 
 
 static long dprintf_DollarString(char *input, char **end)
 static long dprintf_DollarString(char *input, char **end)
 {
 {
-  int number=0;
+  int number = 0;
   while(ISDIGIT(*input)) {
   while(ISDIGIT(*input)) {
     number *= 10;
     number *= 10;
     number += *input-'0';
     number += *input-'0';
@@ -237,7 +233,7 @@ static int dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos,
   long width;
   long width;
   long precision;
   long precision;
   int flags;
   int flags;
-  long max_param=0;
+  long max_param = 0;
   long i;
   long i;
 
 
   while(*fmt) {
   while(*fmt) {
@@ -326,7 +322,7 @@ static int dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos,
           break;
           break;
 #if defined(MP_HAVE_INT_EXTENSIONS)
 #if defined(MP_HAVE_INT_EXTENSIONS)
         case 'I':
         case 'I':
-#if (CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG)
+#if (SIZEOF_CURL_OFF_T > SIZEOF_LONG)
           flags |= FLAGS_LONGLONG;
           flags |= FLAGS_LONGLONG;
 #else
 #else
           flags |= FLAGS_LONG;
           flags |= FLAGS_LONG;
@@ -348,14 +344,14 @@ static int dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos,
         case 'z':
         case 'z':
           /* the code below generates a warning if -Wunreachable-code is
           /* the code below generates a warning if -Wunreachable-code is
              used */
              used */
-#if (SIZEOF_SIZE_T > CURL_SIZEOF_LONG)
+#if (SIZEOF_SIZE_T > SIZEOF_LONG)
           flags |= FLAGS_LONGLONG;
           flags |= FLAGS_LONGLONG;
 #else
 #else
           flags |= FLAGS_LONG;
           flags |= FLAGS_LONG;
 #endif
 #endif
           break;
           break;
         case 'O':
         case 'O':
-#if (CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG)
+#if (SIZEOF_CURL_OFF_T > SIZEOF_LONG)
           flags |= FLAGS_LONGLONG;
           flags |= FLAGS_LONGLONG;
 #else
 #else
           flags |= FLAGS_LONG;
           flags |= FLAGS_LONG;
@@ -380,7 +376,7 @@ static int dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos,
           else
           else
             width = param_num;
             width = param_num;
           if(width > max_param)
           if(width > max_param)
-            max_param=width;
+            max_param = width;
           break;
           break;
         default:
         default:
           break;
           break;
@@ -486,7 +482,7 @@ static int dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos,
   }
   }
 
 
   /* Read the arg list parameters into our data list */
   /* Read the arg list parameters into our data list */
-  for(i=0; i<max_param; i++) {
+  for(i = 0; i<max_param; i++) {
     /* Width/precision arguments must be read before the main argument
     /* Width/precision arguments must be read before the main argument
        they are attached to */
        they are attached to */
     if(vto[i].flags & FLAGS_WIDTHPARAM) {
     if(vto[i].flags & FLAGS_WIDTHPARAM) {
@@ -573,7 +569,7 @@ static int dprintf_formatf(
   int done = 0;
   int done = 0;
 
 
   long param; /* current parameter to read */
   long param; /* current parameter to read */
-  long param_num=0; /* parameter counter */
+  long param_num = 0; /* parameter counter */
 
 
   va_stack_t vto[MAX_PARAMETERS];
   va_stack_t vto[MAX_PARAMETERS];
   char *endpos[MAX_PARAMETERS];
   char *endpos[MAX_PARAMETERS];
@@ -643,7 +639,7 @@ static int dprintf_formatf(
 
 
     /* If this is a positional parameter, the position must follow immediately
     /* If this is a positional parameter, the position must follow immediately
        after the %, thus create a %<num>$ sequence */
        after the %, thus create a %<num>$ sequence */
-    param=dprintf_DollarString(f, &f);
+    param = dprintf_DollarString(f, &f);
 
 
     if(!param)
     if(!param)
       param = param_num;
       param = param_num;
@@ -952,7 +948,7 @@ static int dprintf_formatf(
            output characters */
            output characters */
         (sprintf)(work, formatbuf, p->data.dnum);
         (sprintf)(work, formatbuf, p->data.dnum);
         DEBUGASSERT(strlen(work) <= sizeof(work));
         DEBUGASSERT(strlen(work) <= sizeof(work));
-        for(fptr=work; *fptr; fptr++)
+        for(fptr = work; *fptr; fptr++)
           OUTCHAR(*fptr);
           OUTCHAR(*fptr);
       }
       }
       break;
       break;
@@ -984,7 +980,7 @@ static int dprintf_formatf(
 /* fputc() look-alike */
 /* fputc() look-alike */
 static int addbyter(int output, FILE *data)
 static int addbyter(int output, FILE *data)
 {
 {
-  struct nsprintf *infop=(struct nsprintf *)data;
+  struct nsprintf *infop = (struct nsprintf *)data;
   unsigned char outc = (unsigned char)output;
   unsigned char outc = (unsigned char)output;
 
 
   if(infop->length < infop->max) {
   if(infop->length < infop->max) {
@@ -1032,7 +1028,7 @@ int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...)
 /* fputc() look-alike */
 /* fputc() look-alike */
 static int alloc_addbyter(int output, FILE *data)
 static int alloc_addbyter(int output, FILE *data)
 {
 {
-  struct asprintf *infop=(struct asprintf *)data;
+  struct asprintf *infop = (struct asprintf *)data;
   unsigned char outc = (unsigned char)output;
   unsigned char outc = (unsigned char)output;
 
 
   if(!infop->buffer) {
   if(!infop->buffer) {
@@ -1042,9 +1038,9 @@ static int alloc_addbyter(int output, FILE *data)
       return -1; /* fail */
       return -1; /* fail */
     }
     }
     infop->alloc = 32;
     infop->alloc = 32;
-    infop->len =0;
+    infop->len = 0;
   }
   }
-  else if(infop->len+1 >= infop->alloc) {
+  else if(infop->len + 1 >= infop->alloc) {
     char *newptr = NULL;
     char *newptr = NULL;
     size_t newsize = infop->alloc*2;
     size_t newsize = infop->alloc*2;
 
 
@@ -1133,7 +1129,7 @@ int curl_msprintf(char *buffer, const char *format, ...)
   va_start(ap_save, format);
   va_start(ap_save, format);
   retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save);
   retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save);
   va_end(ap_save);
   va_end(ap_save);
-  *buffer=0; /* we terminate this with a zero byte */
+  *buffer = 0; /* we terminate this with a zero byte */
   return retcode;
   return retcode;
 }
 }
 
 
@@ -1162,7 +1158,7 @@ int curl_mvsprintf(char *buffer, const char *format, va_list ap_save)
 {
 {
   int retcode;
   int retcode;
   retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save);
   retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save);
-  *buffer=0; /* we terminate this with a zero byte */
+  *buffer = 0; /* we terminate this with a zero byte */
   return retcode;
   return retcode;
 }
 }
 
 

+ 75 - 64
Utilities/cmcurl/lib/multi.c

@@ -44,6 +44,7 @@
 #include "sigpipe.h"
 #include "sigpipe.h"
 #include "vtls/vtls.h"
 #include "vtls/vtls.h"
 #include "connect.h"
 #include "connect.h"
+#include "http_proxy.h"
 /* The last 3 #include files should be in this order */
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_printf.h"
 #include "curl_memory.h"
 #include "curl_memory.h"
@@ -69,7 +70,7 @@ static void singlesocket(struct Curl_multi *multi,
                          struct Curl_easy *data);
                          struct Curl_easy *data);
 static int update_timer(struct Curl_multi *multi);
 static int update_timer(struct Curl_multi *multi);
 
 
-static CURLMcode add_next_timeout(struct timeval now,
+static CURLMcode add_next_timeout(struct curltime now,
                                   struct Curl_multi *multi,
                                   struct Curl_multi *multi,
                                   struct Curl_easy *d);
                                   struct Curl_easy *d);
 static CURLMcode multi_timeout(struct Curl_multi *multi,
 static CURLMcode multi_timeout(struct Curl_multi *multi,
@@ -114,6 +115,13 @@ static void mstate(struct Curl_easy *data, CURLMstate state
     NULL,
     NULL,
     NULL,
     NULL,
     Curl_init_CONNECT, /* CONNECT */
     Curl_init_CONNECT, /* CONNECT */
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    Curl_connect_free /* DO */
     /* the rest is NULL too */
     /* the rest is NULL too */
   };
   };
 
 
@@ -584,7 +592,7 @@ static CURLcode multi_done(struct connectdata **connp,
 
 
   /* if the transfer was completed in a paused state there can be buffered
   /* if the transfer was completed in a paused state there can be buffered
      data left to free */
      data left to free */
-  for(i=0; i < data->state.tempcount; i++) {
+  for(i = 0; i < data->state.tempcount; i++) {
     free(data->state.tempwrite[i].buf);
     free(data->state.tempwrite[i].buf);
   }
   }
   data->state.tempcount = 0;
   data->state.tempcount = 0;
@@ -794,8 +802,8 @@ static int waitconnect_getsock(struct connectdata *conn,
                                int numsocks)
                                int numsocks)
 {
 {
   int i;
   int i;
-  int s=0;
-  int rc=0;
+  int s = 0;
+  int rc = 0;
 
 
   if(!numsocks)
   if(!numsocks)
     return GETSOCK_BLANK;
     return GETSOCK_BLANK;
@@ -805,7 +813,7 @@ static int waitconnect_getsock(struct connectdata *conn,
     return Curl_ssl_getsock(conn, sock, numsocks);
     return Curl_ssl_getsock(conn, sock, numsocks);
 #endif
 #endif
 
 
-  for(i=0; i<2; i++) {
+  for(i = 0; i<2; i++) {
     if(conn->tempsock[i] != CURL_SOCKET_BAD) {
     if(conn->tempsock[i] != CURL_SOCKET_BAD) {
       sock[s] = conn->tempsock[i];
       sock[s] = conn->tempsock[i];
       rc |= GETSOCK_WRITESOCK(s++);
       rc |= GETSOCK_WRITESOCK(s++);
@@ -826,7 +834,7 @@ static int waitproxyconnect_getsock(struct connectdata *conn,
 
 
   /* when we've sent a CONNECT to a proxy, we should rather wait for the
   /* when we've sent a CONNECT to a proxy, we should rather wait for the
      socket to become readable to be able to get the response headers */
      socket to become readable to be able to get the response headers */
-  if(conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)
+  if(conn->connect_state)
     return GETSOCK_READSOCK(0);
     return GETSOCK_READSOCK(0);
 
 
   return GETSOCK_WRITESOCK(0);
   return GETSOCK_WRITESOCK(0);
@@ -916,7 +924,7 @@ CURLMcode curl_multi_fdset(struct Curl_multi *multi,
      Some easy handles may not have connected to the remote host yet,
      Some easy handles may not have connected to the remote host yet,
      and then we must make sure that is done. */
      and then we must make sure that is done. */
   struct Curl_easy *data;
   struct Curl_easy *data;
-  int this_max_fd=-1;
+  int this_max_fd = -1;
   curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE];
   curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE];
   int bitmap;
   int bitmap;
   int i;
   int i;
@@ -925,11 +933,11 @@ CURLMcode curl_multi_fdset(struct Curl_multi *multi,
   if(!GOOD_MULTI_HANDLE(multi))
   if(!GOOD_MULTI_HANDLE(multi))
     return CURLM_BAD_HANDLE;
     return CURLM_BAD_HANDLE;
 
 
-  data=multi->easyp;
+  data = multi->easyp;
   while(data) {
   while(data) {
     bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE);
     bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE);
 
 
-    for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) {
+    for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) {
       curl_socket_t s = CURL_SOCKET_BAD;
       curl_socket_t s = CURL_SOCKET_BAD;
 
 
       if((bitmap & GETSOCK_READSOCK(i)) && VALID_SOCK((sockbunch[i]))) {
       if((bitmap & GETSOCK_READSOCK(i)) && VALID_SOCK((sockbunch[i]))) {
@@ -986,11 +994,11 @@ CURLMcode curl_multi_wait(struct Curl_multi *multi,
     timeout_ms = (int)timeout_internal;
     timeout_ms = (int)timeout_internal;
 
 
   /* Count up how many fds we have from the multi handle */
   /* Count up how many fds we have from the multi handle */
-  data=multi->easyp;
+  data = multi->easyp;
   while(data) {
   while(data) {
     bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE);
     bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE);
 
 
-    for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) {
+    for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) {
       curl_socket_t s = CURL_SOCKET_BAD;
       curl_socket_t s = CURL_SOCKET_BAD;
 
 
       if(bitmap & GETSOCK_READSOCK(i)) {
       if(bitmap & GETSOCK_READSOCK(i)) {
@@ -1014,6 +1022,10 @@ CURLMcode curl_multi_wait(struct Curl_multi *multi,
 
 
   if(nfds) {
   if(nfds) {
     if(nfds > NUM_POLLS_ON_STACK) {
     if(nfds > NUM_POLLS_ON_STACK) {
+      /* 'nfds' is a 32 bit value and 'struct pollfd' is typically 8 bytes
+         big, so at 2^29 sockets this value might wrap. When a process gets
+         the capability to actually handle over 500 million sockets this
+         calculation needs a integer overflow check. */
       ufds = malloc(nfds * sizeof(struct pollfd));
       ufds = malloc(nfds * sizeof(struct pollfd));
       if(!ufds)
       if(!ufds)
         return CURLM_OUT_OF_MEMORY;
         return CURLM_OUT_OF_MEMORY;
@@ -1029,11 +1041,11 @@ CURLMcode curl_multi_wait(struct Curl_multi *multi,
 
 
   if(curlfds) {
   if(curlfds) {
     /* Add the curl handles to our pollfds first */
     /* Add the curl handles to our pollfds first */
-    data=multi->easyp;
+    data = multi->easyp;
     while(data) {
     while(data) {
       bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE);
       bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE);
 
 
-      for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) {
+      for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) {
         curl_socket_t s = CURL_SOCKET_BAD;
         curl_socket_t s = CURL_SOCKET_BAD;
 
 
         if(bitmap & GETSOCK_READSOCK(i)) {
         if(bitmap & GETSOCK_READSOCK(i)) {
@@ -1217,15 +1229,15 @@ static CURLcode multi_reconnect_request(struct connectdata **connp)
  */
  */
 static void do_complete(struct connectdata *conn)
 static void do_complete(struct connectdata *conn)
 {
 {
-  conn->data->req.chunk=FALSE;
+  conn->data->req.chunk = FALSE;
   conn->data->req.maxfd = (conn->sockfd>conn->writesockfd?
   conn->data->req.maxfd = (conn->sockfd>conn->writesockfd?
-                           conn->sockfd:conn->writesockfd)+1;
+                           conn->sockfd:conn->writesockfd) + 1;
   Curl_pgrsTime(conn->data, TIMER_PRETRANSFER);
   Curl_pgrsTime(conn->data, TIMER_PRETRANSFER);
 }
 }
 
 
 static CURLcode multi_do(struct connectdata **connp, bool *done)
 static CURLcode multi_do(struct connectdata **connp, bool *done)
 {
 {
-  CURLcode result=CURLE_OK;
+  CURLcode result = CURLE_OK;
   struct connectdata *conn = *connp;
   struct connectdata *conn = *connp;
   struct Curl_easy *data = conn->data;
   struct Curl_easy *data = conn->data;
 
 
@@ -1274,7 +1286,7 @@ static CURLcode multi_do(struct connectdata **connp, bool *done)
 
 
 static CURLcode multi_do_more(struct connectdata *conn, int *complete)
 static CURLcode multi_do_more(struct connectdata *conn, int *complete)
 {
 {
-  CURLcode result=CURLE_OK;
+  CURLcode result = CURLE_OK;
 
 
   *complete = 0;
   *complete = 0;
 
 
@@ -1289,7 +1301,7 @@ static CURLcode multi_do_more(struct connectdata *conn, int *complete)
 }
 }
 
 
 static CURLMcode multi_runsingle(struct Curl_multi *multi,
 static CURLMcode multi_runsingle(struct Curl_multi *multi,
-                                 struct timeval now,
+                                 struct curltime now,
                                  struct Curl_easy *data)
                                  struct Curl_easy *data)
 {
 {
   struct Curl_message *msg = NULL;
   struct Curl_message *msg = NULL;
@@ -1403,7 +1415,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
     switch(data->mstate) {
     switch(data->mstate) {
     case CURLM_STATE_INIT:
     case CURLM_STATE_INIT:
       /* init this transfer. */
       /* init this transfer. */
-      result=Curl_pretransfer(data);
+      result = Curl_pretransfer(data);
 
 
       if(!result) {
       if(!result) {
         /* after init, go CONNECT */
         /* after init, go CONNECT */
@@ -1455,7 +1467,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
                          CURLM_STATE_WAITDO:CURLM_STATE_DO);
                          CURLM_STATE_WAITDO:CURLM_STATE_DO);
             else {
             else {
 #ifndef CURL_DISABLE_HTTP
 #ifndef CURL_DISABLE_HTTP
-              if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)
+              if(Curl_connect_ongoing(data->easy_conn))
                 multistate(data, CURLM_STATE_WAITPROXYCONNECT);
                 multistate(data, CURLM_STATE_WAITPROXYCONNECT);
               else
               else
 #endif
 #endif
@@ -1520,7 +1532,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
                        CURLM_STATE_WAITDO:CURLM_STATE_DO);
                        CURLM_STATE_WAITDO:CURLM_STATE_DO);
           else {
           else {
 #ifndef CURL_DISABLE_HTTP
 #ifndef CURL_DISABLE_HTTP
-            if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)
+            if(Curl_connect_ongoing(data->easy_conn))
               multistate(data, CURLM_STATE_WAITPROXYCONNECT);
               multistate(data, CURLM_STATE_WAITPROXYCONNECT);
             else
             else
 #endif
 #endif
@@ -1552,7 +1564,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
       else if(!result) {
       else if(!result) {
         if((data->easy_conn->http_proxy.proxytype != CURLPROXY_HTTPS ||
         if((data->easy_conn->http_proxy.proxytype != CURLPROXY_HTTPS ||
            data->easy_conn->bits.proxy_ssl_connected[FIRSTSOCKET]) &&
            data->easy_conn->bits.proxy_ssl_connected[FIRSTSOCKET]) &&
-           (data->easy_conn->tunnel_state[FIRSTSOCKET] != TUNNEL_CONNECT)) {
+           Curl_connect_complete(data->easy_conn)) {
           rc = CURLM_CALL_MULTI_PERFORM;
           rc = CURLM_CALL_MULTI_PERFORM;
           /* initiate protocol connect phase */
           /* initiate protocol connect phase */
           multistate(data, CURLM_STATE_SENDPROTOCONNECT);
           multistate(data, CURLM_STATE_SENDPROTOCONNECT);
@@ -1568,7 +1580,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
 #ifndef CURL_DISABLE_HTTP
 #ifndef CURL_DISABLE_HTTP
         if((data->easy_conn->http_proxy.proxytype == CURLPROXY_HTTPS &&
         if((data->easy_conn->http_proxy.proxytype == CURLPROXY_HTTPS &&
             !data->easy_conn->bits.proxy_ssl_connected[FIRSTSOCKET]) ||
             !data->easy_conn->bits.proxy_ssl_connected[FIRSTSOCKET]) ||
-            (data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)) {
+           Curl_connect_ongoing(data->easy_conn)) {
           multistate(data, CURLM_STATE_WAITPROXYCONNECT);
           multistate(data, CURLM_STATE_WAITPROXYCONNECT);
           break;
           break;
         }
         }
@@ -1685,7 +1697,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
            * back to the CONNECT phase so we can try again.
            * back to the CONNECT phase so we can try again.
            */
            */
           char *newurl = NULL;
           char *newurl = NULL;
-          followtype follow=FOLLOW_NONE;
+          followtype follow = FOLLOW_NONE;
           CURLcode drc;
           CURLcode drc;
           bool retry = FALSE;
           bool retry = FALSE;
 
 
@@ -1771,7 +1783,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
         if(control) {
         if(control) {
           /* if positive, advance to DO_DONE
           /* if positive, advance to DO_DONE
              if negative, go back to DOING */
              if negative, go back to DOING */
-          multistate(data, control==1?
+          multistate(data, control == 1?
                      CURLM_STATE_DO_DONE:
                      CURLM_STATE_DO_DONE:
                      CURLM_STATE_DOING);
                      CURLM_STATE_DOING);
           rc = CURLM_CALL_MULTI_PERFORM;
           rc = CURLM_CALL_MULTI_PERFORM;
@@ -1926,7 +1938,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
         multi_done(&data->easy_conn, result, TRUE);
         multi_done(&data->easy_conn, result, TRUE);
       }
       }
       else if(done) {
       else if(done) {
-        followtype follow=FOLLOW_NONE;
+        followtype follow = FOLLOW_NONE;
 
 
         /* call this even if the readwrite function returned error */
         /* call this even if the readwrite function returned error */
         Curl_posttransfer(data);
         Curl_posttransfer(data);
@@ -2132,14 +2144,14 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
 CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles)
 CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles)
 {
 {
   struct Curl_easy *data;
   struct Curl_easy *data;
-  CURLMcode returncode=CURLM_OK;
+  CURLMcode returncode = CURLM_OK;
   struct Curl_tree *t;
   struct Curl_tree *t;
-  struct timeval now = Curl_tvnow();
+  struct curltime now = Curl_tvnow();
 
 
   if(!GOOD_MULTI_HANDLE(multi))
   if(!GOOD_MULTI_HANDLE(multi))
     return CURLM_BAD_HANDLE;
     return CURLM_BAD_HANDLE;
 
 
-  data=multi->easyp;
+  data = multi->easyp;
   while(data) {
   while(data) {
     CURLMcode result;
     CURLMcode result;
     SIGPIPE_VARIABLE(pipe_st);
     SIGPIPE_VARIABLE(pipe_st);
@@ -2234,7 +2246,7 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
     /* remove all easy handles */
     /* remove all easy handles */
     data = multi->easyp;
     data = multi->easyp;
     while(data) {
     while(data) {
-      nextdata=data->next;
+      nextdata = data->next;
       if(data->dns.hostcachetype == HCACHE_MULTI) {
       if(data->dns.hostcachetype == HCACHE_MULTI) {
         /* clear out the usage of the shared DNS cache */
         /* clear out the usage of the shared DNS cache */
         Curl_hostcache_clean(data, data->dns.hostcache);
         Curl_hostcache_clean(data, data->dns.hostcache);
@@ -2314,7 +2326,7 @@ static void singlesocket(struct Curl_multi *multi,
   int num;
   int num;
   unsigned int curraction;
   unsigned int curraction;
 
 
-  for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++)
+  for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++)
     socks[i] = CURL_SOCKET_BAD;
     socks[i] = CURL_SOCKET_BAD;
 
 
   /* Fill in the 'current' struct with the state as it is now: what sockets to
   /* Fill in the 'current' struct with the state as it is now: what sockets to
@@ -2326,7 +2338,7 @@ static void singlesocket(struct Curl_multi *multi,
      longer supervised ones and add new ones */
      longer supervised ones and add new ones */
 
 
   /* walk over the sockets we got right now */
   /* walk over the sockets we got right now */
-  for(i=0; (i< MAX_SOCKSPEREASYHANDLE) &&
+  for(i = 0; (i< MAX_SOCKSPEREASYHANDLE) &&
         (curraction & (GETSOCK_READSOCK(i) | GETSOCK_WRITESOCK(i)));
         (curraction & (GETSOCK_READSOCK(i) | GETSOCK_WRITESOCK(i)));
       i++) {
       i++) {
     int action = CURL_POLL_NONE;
     int action = CURL_POLL_NONE;
@@ -2370,10 +2382,10 @@ static void singlesocket(struct Curl_multi *multi,
 
 
   /* when we've walked over all the sockets we should have right now, we must
   /* when we've walked over all the sockets we should have right now, we must
      make sure to detect sockets that are removed */
      make sure to detect sockets that are removed */
-  for(i=0; i< data->numsocks; i++) {
+  for(i = 0; i< data->numsocks; i++) {
     int j;
     int j;
     s = data->sockets[i];
     s = data->sockets[i];
-    for(j=0; j<num; j++) {
+    for(j = 0; j<num; j++) {
       if(s == socks[j]) {
       if(s == socks[j]) {
         /* this is still supervised */
         /* this is still supervised */
         s = CURL_SOCKET_BAD;
         s = CURL_SOCKET_BAD;
@@ -2484,11 +2496,11 @@ void Curl_multi_closed(struct connectdata *conn, curl_socket_t s)
  * The splay tree only has each sessionhandle as a single node and the nearest
  * The splay tree only has each sessionhandle as a single node and the nearest
  * timeout is used to sort it on.
  * timeout is used to sort it on.
  */
  */
-static CURLMcode add_next_timeout(struct timeval now,
+static CURLMcode add_next_timeout(struct curltime now,
                                   struct Curl_multi *multi,
                                   struct Curl_multi *multi,
                                   struct Curl_easy *d)
                                   struct Curl_easy *d)
 {
 {
-  struct timeval *tv = &d->state.expiretime;
+  struct curltime *tv = &d->state.expiretime;
   struct curl_llist *list = &d->state.timeoutlist;
   struct curl_llist *list = &d->state.timeoutlist;
   struct curl_llist_element *e;
   struct curl_llist_element *e;
   struct time_node *node = NULL;
   struct time_node *node = NULL;
@@ -2520,10 +2532,8 @@ static CURLMcode add_next_timeout(struct timeval now,
     /* copy the first entry to 'tv' */
     /* copy the first entry to 'tv' */
     memcpy(tv, &node->time, sizeof(*tv));
     memcpy(tv, &node->time, sizeof(*tv));
 
 
-    /* remove first entry from list */
-    Curl_llist_remove(list, e, NULL);
-
-    /* insert this node again into the splay */
+    /* Insert this node again into the splay.  Keep the timer in the list in
+       case we need to recompute future timers. */
     multi->timetree = Curl_splayinsert(*tv, multi->timetree,
     multi->timetree = Curl_splayinsert(*tv, multi->timetree,
                                        &d->state.timenode);
                                        &d->state.timenode);
   }
   }
@@ -2539,7 +2549,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
   CURLMcode result = CURLM_OK;
   CURLMcode result = CURLM_OK;
   struct Curl_easy *data = NULL;
   struct Curl_easy *data = NULL;
   struct Curl_tree *t;
   struct Curl_tree *t;
-  struct timeval now = Curl_tvnow();
+  struct curltime now = Curl_tvnow();
 
 
   if(checkall) {
   if(checkall) {
     /* *perform() deals with running_handles on its own */
     /* *perform() deals with running_handles on its own */
@@ -2548,7 +2558,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
     /* walk through each easy handle and do the socket state change magic
     /* walk through each easy handle and do the socket state change magic
        and callbacks */
        and callbacks */
     if(result != CURLM_BAD_HANDLE) {
     if(result != CURLM_BAD_HANDLE) {
-      data=multi->easyp;
+      data = multi->easyp;
       while(data) {
       while(data) {
         singlesocket(multi, data);
         singlesocket(multi, data);
         data = data->next;
         data = data->next;
@@ -2765,11 +2775,11 @@ CURLMcode curl_multi_socket_all(struct Curl_multi *multi, int *running_handles)
 static CURLMcode multi_timeout(struct Curl_multi *multi,
 static CURLMcode multi_timeout(struct Curl_multi *multi,
                                long *timeout_ms)
                                long *timeout_ms)
 {
 {
-  static struct timeval tv_zero = {0, 0};
+  static struct curltime tv_zero = {0, 0};
 
 
   if(multi->timetree) {
   if(multi->timetree) {
     /* we have a tree of expire times */
     /* we have a tree of expire times */
-    struct timeval now = Curl_tvnow();
+    struct curltime now = Curl_tvnow();
 
 
     /* splay the lowest to the bottom */
     /* splay the lowest to the bottom */
     multi->timetree = Curl_splay(tv_zero, multi->timetree);
     multi->timetree = Curl_splay(tv_zero, multi->timetree);
@@ -2785,7 +2795,7 @@ static CURLMcode multi_timeout(struct Curl_multi *multi,
          * processors while the diff is still present but less than one
          * processors while the diff is still present but less than one
          * millisecond! instead we return 1 until the time is ripe.
          * millisecond! instead we return 1 until the time is ripe.
          */
          */
-        *timeout_ms=1;
+        *timeout_ms = 1;
     }
     }
     else
     else
       /* 0 means immediately */
       /* 0 means immediately */
@@ -2821,7 +2831,7 @@ static int update_timer(struct Curl_multi *multi)
     return -1;
     return -1;
   }
   }
   if(timeout_ms < 0) {
   if(timeout_ms < 0) {
-    static const struct timeval none={0, 0};
+    static const struct curltime none = {0, 0};
     if(Curl_splaycomparekeys(none, multi->timer_lastcall)) {
     if(Curl_splaycomparekeys(none, multi->timer_lastcall)) {
       multi->timer_lastcall = none;
       multi->timer_lastcall = none;
       /* there's no timeout now but there was one previously, tell the app to
       /* there's no timeout now but there was one previously, tell the app to
@@ -2872,7 +2882,7 @@ multi_deltimeout(struct Curl_easy *data, expire_id eid)
  */
  */
 static CURLMcode
 static CURLMcode
 multi_addtimeout(struct Curl_easy *data,
 multi_addtimeout(struct Curl_easy *data,
-                 struct timeval *stamp,
+                 struct curltime *stamp,
                  expire_id eid)
                  expire_id eid)
 {
 {
   struct curl_llist_element *e;
   struct curl_llist_element *e;
@@ -2920,9 +2930,9 @@ multi_addtimeout(struct Curl_easy *data,
 void Curl_expire(struct Curl_easy *data, time_t milli, expire_id id)
 void Curl_expire(struct Curl_easy *data, time_t milli, expire_id id)
 {
 {
   struct Curl_multi *multi = data->multi;
   struct Curl_multi *multi = data->multi;
-  struct timeval *nowp = &data->state.expiretime;
+  struct curltime *nowp = &data->state.expiretime;
   int rc;
   int rc;
-  struct timeval set;
+  struct curltime set;
 
 
   /* this is only interesting while there is still an associated multi struct
   /* this is only interesting while there is still an associated multi struct
      remaining! */
      remaining! */
@@ -2932,34 +2942,33 @@ void Curl_expire(struct Curl_easy *data, time_t milli, expire_id id)
   DEBUGASSERT(id < EXPIRE_LAST);
   DEBUGASSERT(id < EXPIRE_LAST);
 
 
   set = Curl_tvnow();
   set = Curl_tvnow();
-  set.tv_sec += (long)(milli/1000);
-  set.tv_usec += (long)(milli%1000)*1000;
+  set.tv_sec += milli/1000;
+  set.tv_usec += (unsigned int)(milli%1000)*1000;
 
 
   if(set.tv_usec >= 1000000) {
   if(set.tv_usec >= 1000000) {
     set.tv_sec++;
     set.tv_sec++;
     set.tv_usec -= 1000000;
     set.tv_usec -= 1000000;
   }
   }
 
 
+  /* Remove any timer with the same id just in case. */
+  multi_deltimeout(data, id);
+
+  /* Add it to the timer list.  It must stay in the list until it has expired
+     in case we need to recompute the minimum timer later. */
+  multi_addtimeout(data, &set, id);
+
   if(nowp->tv_sec || nowp->tv_usec) {
   if(nowp->tv_sec || nowp->tv_usec) {
     /* This means that the struct is added as a node in the splay tree.
     /* This means that the struct is added as a node in the splay tree.
        Compare if the new time is earlier, and only remove-old/add-new if it
        Compare if the new time is earlier, and only remove-old/add-new if it
        is. */
        is. */
     time_t diff = curlx_tvdiff(set, *nowp);
     time_t diff = curlx_tvdiff(set, *nowp);
 
 
-    /* remove the previous timer first, if there */
-    multi_deltimeout(data, id);
-
     if(diff > 0) {
     if(diff > 0) {
-      /* the new expire time was later so just add it to the queue
-         and get out */
-      multi_addtimeout(data, &set, id);
+      /* The current splay tree entry is sooner than this new expiry time.
+         We don't need to update our splay tree entry. */
       return;
       return;
     }
     }
 
 
-    /* the new time is newer than the presently set one, so add the current
-       to the queue and update the head */
-    multi_addtimeout(data, nowp, id);
-
     /* Since this is an updated time, we must remove the previous entry from
     /* Since this is an updated time, we must remove the previous entry from
        the splay tree first and then re-add the new value */
        the splay tree first and then re-add the new value */
     rc = Curl_splayremovebyaddr(multi->timetree,
     rc = Curl_splayremovebyaddr(multi->timetree,
@@ -2969,6 +2978,8 @@ void Curl_expire(struct Curl_easy *data, time_t milli, expire_id id)
       infof(data, "Internal error removing splay node = %d\n", rc);
       infof(data, "Internal error removing splay node = %d\n", rc);
   }
   }
 
 
+  /* Indicate that we are in the splay tree and insert the new timer expiry
+     value since it is our local minimum. */
   *nowp = set;
   *nowp = set;
   data->state.timenode.payload = data;
   data->state.timenode.payload = data;
   multi->timetree = Curl_splayinsert(*nowp, multi->timetree,
   multi->timetree = Curl_splayinsert(*nowp, multi->timetree,
@@ -2995,7 +3006,7 @@ void Curl_expire_done(struct Curl_easy *data, expire_id id)
 void Curl_expire_clear(struct Curl_easy *data)
 void Curl_expire_clear(struct Curl_easy *data)
 {
 {
   struct Curl_multi *multi = data->multi;
   struct Curl_multi *multi = data->multi;
-  struct timeval *nowp = &data->state.expiretime;
+  struct curltime *nowp = &data->state.expiretime;
   int rc;
   int rc;
 
 
   /* this is only interesting while there is still an associated multi struct
   /* this is only interesting while there is still an associated multi struct
@@ -3104,13 +3115,13 @@ void Curl_multi_dump(struct Curl_multi *multi)
   int i;
   int i;
   fprintf(stderr, "* Multi status: %d handles, %d alive\n",
   fprintf(stderr, "* Multi status: %d handles, %d alive\n",
           multi->num_easy, multi->num_alive);
           multi->num_easy, multi->num_alive);
-  for(data=multi->easyp; data; data = data->next) {
+  for(data = multi->easyp; data; data = data->next) {
     if(data->mstate < CURLM_STATE_COMPLETED) {
     if(data->mstate < CURLM_STATE_COMPLETED) {
       /* only display handles that are not completed */
       /* only display handles that are not completed */
       fprintf(stderr, "handle %p, state %s, %d sockets\n",
       fprintf(stderr, "handle %p, state %s, %d sockets\n",
               (void *)data,
               (void *)data,
               statename[data->mstate], data->numsocks);
               statename[data->mstate], data->numsocks);
-      for(i=0; i < data->numsocks; i++) {
+      for(i = 0; i < data->numsocks; i++) {
         curl_socket_t s = data->sockets[i];
         curl_socket_t s = data->sockets[i];
         struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);
         struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);
 
 

+ 1 - 1
Utilities/cmcurl/lib/multihandle.h

@@ -148,7 +148,7 @@ struct Curl_multi {
   /* timer callback and user data pointer for the *socket() API */
   /* timer callback and user data pointer for the *socket() API */
   curl_multi_timer_callback timer_cb;
   curl_multi_timer_callback timer_cb;
   void *timer_userp;
   void *timer_userp;
-  struct timeval timer_lastcall; /* the fixed time for the timeout for the
+  struct curltime timer_lastcall; /* the fixed time for the timeout for the
                                     previous callback */
                                     previous callback */
 };
 };
 
 

+ 24 - 20
Utilities/cmcurl/lib/netrc.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -56,14 +56,15 @@ int Curl_parsenetrc(const char *host,
                     char *netrcfile)
                     char *netrcfile)
 {
 {
   FILE *file;
   FILE *file;
-  int retcode=1;
+  int retcode = 1;
   int specific_login = (*loginp && **loginp != 0);
   int specific_login = (*loginp && **loginp != 0);
   bool netrc_alloc = FALSE;
   bool netrc_alloc = FALSE;
-  enum host_lookup_state state=NOTHING;
+  enum host_lookup_state state = NOTHING;
 
 
-  char state_login=0;      /* Found a login keyword */
-  char state_password=0;   /* Found a password keyword */
-  int state_our_login=FALSE;  /* With specific_login, found *our* login name */
+  char state_login = 0;      /* Found a login keyword */
+  char state_password = 0;   /* Found a password keyword */
+  int state_our_login = FALSE;  /* With specific_login, found *our* login
+                                   name */
 
 
 #define NETRC DOT_CHAR "netrc"
 #define NETRC DOT_CHAR "netrc"
 
 
@@ -88,7 +89,7 @@ int Curl_parsenetrc(const char *host,
     }
     }
     else {
     else {
       struct passwd *pw;
       struct passwd *pw;
-      pw= getpwuid(geteuid());
+      pw = getpwuid(geteuid());
       if(pw) {
       if(pw) {
         home = pw->pw_dir;
         home = pw->pw_dir;
       }
       }
@@ -113,16 +114,19 @@ int Curl_parsenetrc(const char *host,
   if(file) {
   if(file) {
     char *tok;
     char *tok;
     char *tok_buf;
     char *tok_buf;
-    bool done=FALSE;
+    bool done = FALSE;
     char netrcbuffer[256];
     char netrcbuffer[256];
     int  netrcbuffsize = (int)sizeof(netrcbuffer);
     int  netrcbuffsize = (int)sizeof(netrcbuffer);
 
 
     while(!done && fgets(netrcbuffer, netrcbuffsize, file)) {
     while(!done && fgets(netrcbuffer, netrcbuffsize, file)) {
-      tok=strtok_r(netrcbuffer, " \t\n", &tok_buf);
+      tok = strtok_r(netrcbuffer, " \t\n", &tok_buf);
+      if(tok && *tok == '#')
+        /* treat an initial hash as a comment line */
+        continue;
       while(!done && tok) {
       while(!done && tok) {
 
 
         if((*loginp && **loginp) && (*passwordp && **passwordp)) {
         if((*loginp && **loginp) && (*passwordp && **passwordp)) {
-          done=TRUE;
+          done = TRUE;
           break;
           break;
         }
         }
 
 
@@ -133,22 +137,22 @@ int Curl_parsenetrc(const char *host,
                delimiter that starts the stuff entered for this machine,
                delimiter that starts the stuff entered for this machine,
                after this we need to search for 'login' and
                after this we need to search for 'login' and
                'password'. */
                'password'. */
-            state=HOSTFOUND;
+            state = HOSTFOUND;
           }
           }
           else if(strcasecompare("default", tok)) {
           else if(strcasecompare("default", tok)) {
-            state=HOSTVALID;
-            retcode=0; /* we did find our host */
+            state = HOSTVALID;
+            retcode = 0; /* we did find our host */
           }
           }
           break;
           break;
         case HOSTFOUND:
         case HOSTFOUND:
           if(strcasecompare(host, tok)) {
           if(strcasecompare(host, tok)) {
             /* and yes, this is our host! */
             /* and yes, this is our host! */
-            state=HOSTVALID;
-            retcode=0; /* we did find our host */
+            state = HOSTVALID;
+            retcode = 0; /* we did find our host */
           }
           }
           else
           else
             /* not our host */
             /* not our host */
-            state=NOTHING;
+            state = NOTHING;
           break;
           break;
         case HOSTVALID:
         case HOSTVALID:
           /* we are now parsing sub-keywords concerning "our" host */
           /* we are now parsing sub-keywords concerning "our" host */
@@ -164,7 +168,7 @@ int Curl_parsenetrc(const char *host,
                 goto out;
                 goto out;
               }
               }
             }
             }
-            state_login=0;
+            state_login = 0;
           }
           }
           else if(state_password) {
           else if(state_password) {
             if(state_our_login || !specific_login) {
             if(state_our_login || !specific_login) {
@@ -175,12 +179,12 @@ int Curl_parsenetrc(const char *host,
                 goto out;
                 goto out;
               }
               }
             }
             }
-            state_password=0;
+            state_password = 0;
           }
           }
           else if(strcasecompare("login", tok))
           else if(strcasecompare("login", tok))
-            state_login=1;
+            state_login = 1;
           else if(strcasecompare("password", tok))
           else if(strcasecompare("password", tok))
-            state_password=1;
+            state_password = 1;
           else if(strcasecompare("machine", tok)) {
           else if(strcasecompare("machine", tok)) {
             /* ok, there's machine here go => */
             /* ok, there's machine here go => */
             state = HOSTFOUND;
             state = HOSTFOUND;

+ 44 - 60
Utilities/cmcurl/lib/non-ascii.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -82,7 +82,7 @@ CURLcode Curl_convert_clone(struct Curl_easy *data,
 CURLcode Curl_convert_to_network(struct Curl_easy *data,
 CURLcode Curl_convert_to_network(struct Curl_easy *data,
                                  char *buffer, size_t length)
                                  char *buffer, size_t length)
 {
 {
-  if(data->set.convtonetwork) {
+  if(data && data->set.convtonetwork) {
     /* use translation callback */
     /* use translation callback */
     CURLcode result = data->set.convtonetwork(buffer, length);
     CURLcode result = data->set.convtonetwork(buffer, length);
     if(result) {
     if(result) {
@@ -96,34 +96,37 @@ CURLcode Curl_convert_to_network(struct Curl_easy *data,
   else {
   else {
 #ifdef HAVE_ICONV
 #ifdef HAVE_ICONV
     /* do the translation ourselves */
     /* do the translation ourselves */
+    iconv_t tmpcd = (iconv_t) -1;
+    iconv_t *cd = &tmpcd;
     char *input_ptr, *output_ptr;
     char *input_ptr, *output_ptr;
     size_t in_bytes, out_bytes, rc;
     size_t in_bytes, out_bytes, rc;
-    int error;
 
 
     /* open an iconv conversion descriptor if necessary */
     /* open an iconv conversion descriptor if necessary */
-    if(data->outbound_cd == (iconv_t)-1) {
-      data->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
-                                     CURL_ICONV_CODESET_OF_HOST);
-      if(data->outbound_cd == (iconv_t)-1) {
-        error = ERRNO;
+    if(data)
+      cd = &data->outbound_cd;
+    if(*cd == (iconv_t)-1) {
+      *cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
+                       CURL_ICONV_CODESET_OF_HOST);
+      if(*cd == (iconv_t)-1) {
         failf(data,
         failf(data,
               "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
               "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
               CURL_ICONV_CODESET_OF_NETWORK,
               CURL_ICONV_CODESET_OF_NETWORK,
               CURL_ICONV_CODESET_OF_HOST,
               CURL_ICONV_CODESET_OF_HOST,
-              error, strerror(error));
+              errno, strerror(errno));
         return CURLE_CONV_FAILED;
         return CURLE_CONV_FAILED;
       }
       }
     }
     }
     /* call iconv */
     /* call iconv */
     input_ptr = output_ptr = buffer;
     input_ptr = output_ptr = buffer;
     in_bytes = out_bytes = length;
     in_bytes = out_bytes = length;
-    rc = iconv(data->outbound_cd, (const char **)&input_ptr, &in_bytes,
+    rc = iconv(*cd, &input_ptr, &in_bytes,
                &output_ptr, &out_bytes);
                &output_ptr, &out_bytes);
+    if(!data)
+      iconv_close(tmpcd);
     if((rc == ICONV_ERROR) || (in_bytes != 0)) {
     if((rc == ICONV_ERROR) || (in_bytes != 0)) {
-      error = ERRNO;
       failf(data,
       failf(data,
             "The Curl_convert_to_network iconv call failed with errno %i: %s",
             "The Curl_convert_to_network iconv call failed with errno %i: %s",
-            error, strerror(error));
+            errno, strerror(errno));
       return CURLE_CONV_FAILED;
       return CURLE_CONV_FAILED;
     }
     }
 #else
 #else
@@ -142,7 +145,7 @@ CURLcode Curl_convert_to_network(struct Curl_easy *data,
 CURLcode Curl_convert_from_network(struct Curl_easy *data,
 CURLcode Curl_convert_from_network(struct Curl_easy *data,
                                    char *buffer, size_t length)
                                    char *buffer, size_t length)
 {
 {
-  if(data->set.convfromnetwork) {
+  if(data && data->set.convfromnetwork) {
     /* use translation callback */
     /* use translation callback */
     CURLcode result = data->set.convfromnetwork(buffer, length);
     CURLcode result = data->set.convfromnetwork(buffer, length);
     if(result) {
     if(result) {
@@ -156,34 +159,37 @@ CURLcode Curl_convert_from_network(struct Curl_easy *data,
   else {
   else {
 #ifdef HAVE_ICONV
 #ifdef HAVE_ICONV
     /* do the translation ourselves */
     /* do the translation ourselves */
+    iconv_t tmpcd = (iconv_t) -1;
+    iconv_t *cd = &tmpcd;
     char *input_ptr, *output_ptr;
     char *input_ptr, *output_ptr;
     size_t in_bytes, out_bytes, rc;
     size_t in_bytes, out_bytes, rc;
-    int error;
 
 
     /* open an iconv conversion descriptor if necessary */
     /* open an iconv conversion descriptor if necessary */
-    if(data->inbound_cd == (iconv_t)-1) {
-      data->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
-                                    CURL_ICONV_CODESET_OF_NETWORK);
-      if(data->inbound_cd == (iconv_t)-1) {
-        error = ERRNO;
+    if(data)
+      cd = &data->inbound_cd;
+    if(*cd == (iconv_t)-1) {
+      *cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
+                       CURL_ICONV_CODESET_OF_NETWORK);
+      if(*cd == (iconv_t)-1) {
         failf(data,
         failf(data,
               "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
               "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
               CURL_ICONV_CODESET_OF_HOST,
               CURL_ICONV_CODESET_OF_HOST,
               CURL_ICONV_CODESET_OF_NETWORK,
               CURL_ICONV_CODESET_OF_NETWORK,
-              error, strerror(error));
+              errno, strerror(errno));
         return CURLE_CONV_FAILED;
         return CURLE_CONV_FAILED;
       }
       }
     }
     }
     /* call iconv */
     /* call iconv */
     input_ptr = output_ptr = buffer;
     input_ptr = output_ptr = buffer;
     in_bytes = out_bytes = length;
     in_bytes = out_bytes = length;
-    rc = iconv(data->inbound_cd, (const char **)&input_ptr, &in_bytes,
+    rc = iconv(*cd, &input_ptr, &in_bytes,
                &output_ptr, &out_bytes);
                &output_ptr, &out_bytes);
+    if(!data)
+      iconv_close(tmpcd);
     if((rc == ICONV_ERROR) || (in_bytes != 0)) {
     if((rc == ICONV_ERROR) || (in_bytes != 0)) {
-      error = ERRNO;
       failf(data,
       failf(data,
             "Curl_convert_from_network iconv call failed with errno %i: %s",
             "Curl_convert_from_network iconv call failed with errno %i: %s",
-            error, strerror(error));
+            errno, strerror(errno));
       return CURLE_CONV_FAILED;
       return CURLE_CONV_FAILED;
     }
     }
 #else
 #else
@@ -202,7 +208,7 @@ CURLcode Curl_convert_from_network(struct Curl_easy *data,
 CURLcode Curl_convert_from_utf8(struct Curl_easy *data,
 CURLcode Curl_convert_from_utf8(struct Curl_easy *data,
                                 char *buffer, size_t length)
                                 char *buffer, size_t length)
 {
 {
-  if(data->set.convfromutf8) {
+  if(data && data->set.convfromutf8) {
     /* use translation callback */
     /* use translation callback */
     CURLcode result = data->set.convfromutf8(buffer, length);
     CURLcode result = data->set.convfromutf8(buffer, length);
     if(result) {
     if(result) {
@@ -216,35 +222,38 @@ CURLcode Curl_convert_from_utf8(struct Curl_easy *data,
   else {
   else {
 #ifdef HAVE_ICONV
 #ifdef HAVE_ICONV
     /* do the translation ourselves */
     /* do the translation ourselves */
-    const char *input_ptr;
+    iconv_t tmpcd = (iconv_t) -1;
+    iconv_t *cd = &tmpcd;
+    char *input_ptr;
     char *output_ptr;
     char *output_ptr;
     size_t in_bytes, out_bytes, rc;
     size_t in_bytes, out_bytes, rc;
-    int error;
 
 
     /* open an iconv conversion descriptor if necessary */
     /* open an iconv conversion descriptor if necessary */
-    if(data->utf8_cd == (iconv_t)-1) {
-      data->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
-                                 CURL_ICONV_CODESET_FOR_UTF8);
-      if(data->utf8_cd == (iconv_t)-1) {
-        error = ERRNO;
+    if(data)
+      cd = &data->utf8_cd;
+    if(*cd == (iconv_t)-1) {
+      *cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
+                       CURL_ICONV_CODESET_FOR_UTF8);
+      if(*cd == (iconv_t)-1) {
         failf(data,
         failf(data,
               "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
               "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
               CURL_ICONV_CODESET_OF_HOST,
               CURL_ICONV_CODESET_OF_HOST,
               CURL_ICONV_CODESET_FOR_UTF8,
               CURL_ICONV_CODESET_FOR_UTF8,
-              error, strerror(error));
+              errno, strerror(errno));
         return CURLE_CONV_FAILED;
         return CURLE_CONV_FAILED;
       }
       }
     }
     }
     /* call iconv */
     /* call iconv */
     input_ptr = output_ptr = buffer;
     input_ptr = output_ptr = buffer;
     in_bytes = out_bytes = length;
     in_bytes = out_bytes = length;
-    rc = iconv(data->utf8_cd, &input_ptr, &in_bytes,
+    rc = iconv(*cd, &input_ptr, &in_bytes,
                &output_ptr, &out_bytes);
                &output_ptr, &out_bytes);
+    if(!data)
+      iconv_close(tmpcd);
     if((rc == ICONV_ERROR) || (in_bytes != 0)) {
     if((rc == ICONV_ERROR) || (in_bytes != 0)) {
-      error = ERRNO;
       failf(data,
       failf(data,
             "The Curl_convert_from_utf8 iconv call failed with errno %i: %s",
             "The Curl_convert_from_utf8 iconv call failed with errno %i: %s",
-            error, strerror(error));
+            errno, strerror(errno));
       return CURLE_CONV_FAILED;
       return CURLE_CONV_FAILED;
     }
     }
     if(output_ptr < input_ptr) {
     if(output_ptr < input_ptr) {
@@ -310,29 +319,4 @@ void Curl_convert_close(struct Curl_easy *data)
 #endif /* HAVE_ICONV */
 #endif /* HAVE_ICONV */
 }
 }
 
 
-/*
- * 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 Curl_easy *data, struct FormData *form)
-{
-  CURLcode result;
-
-  if(!data)
-    return CURLE_BAD_FUNCTION_ARGUMENT;
-
-  while(form) {
-    if(form->type == FORM_DATA) {
-      result = Curl_convert_to_network(data, form->line, form->length);
-      /* Curl_convert_to_network calls failf if unsuccessful */
-      if(result)
-        return result;
-    }
-
-    form = form->next;
-  }
-
-  return CURLE_OK;
-}
-
 #endif /* CURL_DOES_CONVERSIONS */
 #endif /* CURL_DOES_CONVERSIONS */

+ 1 - 3
Utilities/cmcurl/lib/non-ascii.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2011, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -48,7 +48,6 @@ CURLcode Curl_convert_from_network(struct Curl_easy *data,
                                  char *buffer, size_t length);
                                  char *buffer, size_t length);
 CURLcode Curl_convert_from_utf8(struct Curl_easy *data,
 CURLcode Curl_convert_from_utf8(struct Curl_easy *data,
                                  char *buffer, size_t length);
                                  char *buffer, size_t length);
-CURLcode Curl_convert_form(struct Curl_easy *data, struct FormData *form);
 #else
 #else
 #define Curl_convert_clone(a,b,c,d) ((void)a, CURLE_OK)
 #define Curl_convert_clone(a,b,c,d) ((void)a, CURLE_OK)
 #define Curl_convert_init(x) Curl_nop_stmt
 #define Curl_convert_init(x) Curl_nop_stmt
@@ -57,7 +56,6 @@ CURLcode Curl_convert_form(struct Curl_easy *data, struct FormData *form);
 #define Curl_convert_to_network(a,b,c) ((void)a, CURLE_OK)
 #define Curl_convert_to_network(a,b,c) ((void)a, CURLE_OK)
 #define Curl_convert_from_network(a,b,c) ((void)a, CURLE_OK)
 #define Curl_convert_from_network(a,b,c) ((void)a, CURLE_OK)
 #define Curl_convert_from_utf8(a,b,c) ((void)a, CURLE_OK)
 #define Curl_convert_from_utf8(a,b,c) ((void)a, CURLE_OK)
-#define Curl_convert_form(a,b) CURLE_OK
 #endif
 #endif
 
 
 #endif /* HEADER_CURL_NON_ASCII_H */
 #endif /* HEADER_CURL_NON_ASCII_H */

+ 8 - 6
Utilities/cmcurl/lib/openldap.c

@@ -5,7 +5,7 @@
  *                | (__| |_| |  _ <| |___
  *                | (__| |_| |  _ <| |___
  *                 \___|\___/|_| \_\_____|
  *                 \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 2010, Howard Chu, <[email protected]>
+ * Copyright (C) 2010, 2017, Howard Chu, <[email protected]>
  * Copyright (C) 2011 - 2016, Daniel Stenberg, <[email protected]>, et al.
  * Copyright (C) 2011 - 2016, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
@@ -85,6 +85,7 @@ const struct Curl_handler Curl_handler_ldap = {
   ZERO_NULL,                            /* perform_getsock */
   ZERO_NULL,                            /* perform_getsock */
   ldap_disconnect,                      /* disconnect */
   ldap_disconnect,                      /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
   PORT_LDAP,                            /* defport */
   PORT_LDAP,                            /* defport */
   CURLPROTO_LDAP,                       /* protocol */
   CURLPROTO_LDAP,                       /* protocol */
   PROTOPT_NONE                          /* flags */
   PROTOPT_NONE                          /* flags */
@@ -110,6 +111,7 @@ const struct Curl_handler Curl_handler_ldaps = {
   ZERO_NULL,                            /* perform_getsock */
   ZERO_NULL,                            /* perform_getsock */
   ldap_disconnect,                      /* disconnect */
   ldap_disconnect,                      /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
   PORT_LDAPS,                           /* defport */
   PORT_LDAPS,                           /* defport */
   CURLPROTO_LDAP,                       /* protocol */
   CURLPROTO_LDAP,                       /* protocol */
   PROTOPT_SSL                           /* flags */
   PROTOPT_SSL                           /* flags */
@@ -150,7 +152,7 @@ static CURLcode ldap_setup_connection(struct connectdata *conn)
 {
 {
   ldapconninfo *li;
   ldapconninfo *li;
   LDAPURLDesc *lud;
   LDAPURLDesc *lud;
-  struct Curl_easy *data=conn->data;
+  struct Curl_easy *data = conn->data;
   int rc, proto;
   int rc, proto;
   CURLcode status;
   CURLcode status;
 
 
@@ -196,7 +198,7 @@ static CURLcode ldap_connect(struct connectdata *conn, bool *done)
   (void)done;
   (void)done;
 
 
   strcpy(hosturl, "ldap");
   strcpy(hosturl, "ldap");
-  ptr = hosturl+4;
+  ptr = hosturl + 4;
   if(conn->handler->flags & PROTOPT_SSL)
   if(conn->handler->flags & PROTOPT_SSL)
     *ptr++ = 's';
     *ptr++ = 's';
   snprintf(ptr, sizeof(hosturl)-(ptr-hosturl), "://%s:%d",
   snprintf(ptr, sizeof(hosturl)-(ptr-hosturl), "://%s:%d",
@@ -352,7 +354,7 @@ static CURLcode ldap_do(struct connectdata *conn, bool *done)
   int rc = 0;
   int rc = 0;
   LDAPURLDesc *ludp = NULL;
   LDAPURLDesc *ludp = NULL;
   int msgid;
   int msgid;
-  struct Curl_easy *data=conn->data;
+  struct Curl_easy *data = conn->data;
 
 
   connkeep(conn, "OpenLDAP do");
   connkeep(conn, "OpenLDAP do");
 
 
@@ -517,7 +519,7 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
       else
       else
         binary = 0;
         binary = 0;
 
 
-      for(i=0; bvals[i].bv_val != NULL; i++) {
+      for(i = 0; bvals[i].bv_val != NULL; i++) {
         int binval = 0;
         int binval = 0;
         writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1);
         writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1);
         if(writeerr) {
         if(writeerr) {
@@ -547,7 +549,7 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
           else {
           else {
             /* check for unprintable characters */
             /* check for unprintable characters */
             unsigned int j;
             unsigned int j;
-            for(j=0; j<bvals[i].bv_len; j++)
+            for(j = 0; j<bvals[i].bv_len; j++)
               if(!ISPRINT(bvals[i].bv_val[j])) {
               if(!ISPRINT(bvals[i].bv_val[j])) {
                 binval = 1;
                 binval = 1;
                 break;
                 break;

+ 37 - 37
Utilities/cmcurl/lib/parsedate.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -167,20 +167,20 @@ static const struct tzinfo tz[]= {
      RFC 1123) had their signs wrong. Here we use the correct signs to match
      RFC 1123) had their signs wrong. Here we use the correct signs to match
      actual military usage.
      actual military usage.
    */
    */
-  {"A",  +1 * 60},         /* Alpha */
-  {"B",  +2 * 60},         /* Bravo */
-  {"C",  +3 * 60},         /* Charlie */
-  {"D",  +4 * 60},         /* Delta */
-  {"E",  +5 * 60},         /* Echo */
-  {"F",  +6 * 60},         /* Foxtrot */
-  {"G",  +7 * 60},         /* Golf */
-  {"H",  +8 * 60},         /* Hotel */
-  {"I",  +9 * 60},         /* India */
+  {"A",  1 * 60},         /* Alpha */
+  {"B",  2 * 60},         /* Bravo */
+  {"C",  3 * 60},         /* Charlie */
+  {"D",  4 * 60},         /* Delta */
+  {"E",  5 * 60},         /* Echo */
+  {"F",  6 * 60},         /* Foxtrot */
+  {"G",  7 * 60},         /* Golf */
+  {"H",  8 * 60},         /* Hotel */
+  {"I",  9 * 60},         /* India */
   /* "J", Juliet is not used as a timezone, to indicate the observer's local
   /* "J", Juliet is not used as a timezone, to indicate the observer's local
      time */
      time */
-  {"K", +10 * 60},         /* Kilo */
-  {"L", +11 * 60},         /* Lima */
-  {"M", +12 * 60},         /* Mike */
+  {"K", 10 * 60},         /* Kilo */
+  {"L", 11 * 60},         /* Lima */
+  {"M", 12 * 60},         /* Mike */
   {"N",  -1 * 60},         /* November */
   {"N",  -1 * 60},         /* November */
   {"O",  -2 * 60},         /* Oscar */
   {"O",  -2 * 60},         /* Oscar */
   {"P",  -3 * 60},         /* Papa */
   {"P",  -3 * 60},         /* Papa */
@@ -205,14 +205,14 @@ static int checkday(const char *check, size_t len)
 {
 {
   int i;
   int i;
   const char * const *what;
   const char * const *what;
-  bool found= FALSE;
+  bool found = FALSE;
   if(len > 3)
   if(len > 3)
     what = &weekday[0];
     what = &weekday[0];
   else
   else
     what = &Curl_wkday[0];
     what = &Curl_wkday[0];
-  for(i=0; i<7; i++) {
+  for(i = 0; i<7; i++) {
     if(strcasecompare(check, what[0])) {
     if(strcasecompare(check, what[0])) {
-      found=TRUE;
+      found = TRUE;
       break;
       break;
     }
     }
     what++;
     what++;
@@ -224,12 +224,12 @@ static int checkmonth(const char *check)
 {
 {
   int i;
   int i;
   const char * const *what;
   const char * const *what;
-  bool found= FALSE;
+  bool found = FALSE;
 
 
   what = &Curl_month[0];
   what = &Curl_month[0];
-  for(i=0; i<12; i++) {
+  for(i = 0; i<12; i++) {
     if(strcasecompare(check, what[0])) {
     if(strcasecompare(check, what[0])) {
-      found=TRUE;
+      found = TRUE;
       break;
       break;
     }
     }
     what++;
     what++;
@@ -244,12 +244,12 @@ static int checktz(const char *check)
 {
 {
   unsigned int i;
   unsigned int i;
   const struct tzinfo *what;
   const struct tzinfo *what;
-  bool found= FALSE;
+  bool found = FALSE;
 
 
   what = tz;
   what = tz;
-  for(i=0; i< sizeof(tz)/sizeof(tz[0]); i++) {
+  for(i = 0; i< sizeof(tz)/sizeof(tz[0]); i++) {
     if(strcasecompare(check, what->name)) {
     if(strcasecompare(check, what->name)) {
-      found=TRUE;
+      found = TRUE;
       break;
       break;
     }
     }
     what++;
     what++;
@@ -331,21 +331,21 @@ static time_t my_timegm(struct my_tm *tm)
 static int parsedate(const char *date, time_t *output)
 static int parsedate(const char *date, time_t *output)
 {
 {
   time_t t = 0;
   time_t t = 0;
-  int wdaynum=-1;  /* day of the week number, 0-6 (mon-sun) */
-  int monnum=-1;   /* month of the year number, 0-11 */
-  int mdaynum=-1; /* day of month, 1 - 31 */
-  int hournum=-1;
-  int minnum=-1;
-  int secnum=-1;
-  int yearnum=-1;
-  int tzoff=-1;
+  int wdaynum = -1;  /* day of the week number, 0-6 (mon-sun) */
+  int monnum = -1;   /* month of the year number, 0-11 */
+  int mdaynum = -1; /* day of month, 1 - 31 */
+  int hournum = -1;
+  int minnum = -1;
+  int secnum = -1;
+  int yearnum = -1;
+  int tzoff = -1;
   struct my_tm tm;
   struct my_tm tm;
   enum assume dignext = DATE_MDAY;
   enum assume dignext = DATE_MDAY;
   const char *indate = date; /* save the original pointer */
   const char *indate = date; /* save the original pointer */
   int part = 0; /* max 6 parts */
   int part = 0; /* max 6 parts */
 
 
   while(*date && (part < 6)) {
   while(*date && (part < 6)) {
-    bool found=FALSE;
+    bool found = FALSE;
 
 
     skip(&date);
     skip(&date);
 
 
@@ -386,7 +386,7 @@ static int parsedate(const char *date, time_t *output)
       /* a digit */
       /* a digit */
       int val;
       int val;
       char *end;
       char *end;
-      int len=0;
+      int len = 0;
       if((secnum == -1) &&
       if((secnum == -1) &&
          (3 == sscanf(date, "%02d:%02d:%02d%n",
          (3 == sscanf(date, "%02d:%02d:%02d%n",
                       &hournum, &minnum, &secnum, &len))) {
                       &hournum, &minnum, &secnum, &len))) {
@@ -404,12 +404,12 @@ static int parsedate(const char *date, time_t *output)
         int error;
         int error;
         int old_errno;
         int old_errno;
 
 
-        old_errno = ERRNO;
-        SET_ERRNO(0);
+        old_errno = errno;
+        errno = 0;
         lval = strtol(date, &end, 10);
         lval = strtol(date, &end, 10);
-        error = ERRNO;
-        if(error != old_errno)
-          SET_ERRNO(old_errno);
+        error = errno;
+        if(errno != old_errno)
+          errno = old_errno;
 
 
         if(error)
         if(error)
           return PARSEDATE_FAIL;
           return PARSEDATE_FAIL;

+ 14 - 14
Utilities/cmcurl/lib/pingpong.c

@@ -47,10 +47,10 @@
 time_t Curl_pp_state_timeout(struct pingpong *pp)
 time_t Curl_pp_state_timeout(struct pingpong *pp)
 {
 {
   struct connectdata *conn = pp->conn;
   struct connectdata *conn = pp->conn;
-  struct Curl_easy *data=conn->data;
+  struct Curl_easy *data = conn->data;
   time_t timeout_ms; /* in milliseconds */
   time_t timeout_ms; /* in milliseconds */
   time_t timeout2_ms; /* in milliseconds */
   time_t timeout2_ms; /* in milliseconds */
-  long response_time= (data->set.server_response_timeout)?
+  long response_time = (data->set.server_response_timeout)?
     data->set.server_response_timeout: pp->response_time;
     data->set.server_response_timeout: pp->response_time;
 
 
   /* if CURLOPT_SERVER_RESPONSE_TIMEOUT is set, use that to determine
   /* if CURLOPT_SERVER_RESPONSE_TIMEOUT is set, use that to determine
@@ -85,10 +85,10 @@ CURLcode Curl_pp_statemach(struct pingpong *pp, bool block)
   int rc;
   int rc;
   time_t interval_ms;
   time_t interval_ms;
   time_t timeout_ms = Curl_pp_state_timeout(pp);
   time_t timeout_ms = Curl_pp_state_timeout(pp);
-  struct Curl_easy *data=conn->data;
+  struct Curl_easy *data = conn->data;
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
 
 
-  if(timeout_ms <=0) {
+  if(timeout_ms <= 0) {
     failf(data, "server response timeout");
     failf(data, "server response timeout");
     return CURLE_OPERATION_TIMEDOUT; /* already too little time */
     return CURLE_OPERATION_TIMEDOUT; /* already too little time */
   }
   }
@@ -270,7 +270,7 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd,
                           size_t *size) /* size of the response */
                           size_t *size) /* size of the response */
 {
 {
   ssize_t perline; /* count bytes per line */
   ssize_t perline; /* count bytes per line */
-  bool keepon=TRUE;
+  bool keepon = TRUE;
   ssize_t gotbytes;
   ssize_t gotbytes;
   char *ptr;
   char *ptr;
   struct connectdata *conn = pp->conn;
   struct connectdata *conn = pp->conn;
@@ -281,7 +281,7 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd,
   *code = 0; /* 0 for errors or not done */
   *code = 0; /* 0 for errors or not done */
   *size = 0;
   *size = 0;
 
 
-  ptr=buf + pp->nread_resp;
+  ptr = buf + pp->nread_resp;
 
 
   /* number of bytes in the current line, so far */
   /* number of bytes in the current line, so far */
   perline = (ssize_t)(ptr-pp->linestart_resp);
   perline = (ssize_t)(ptr-pp->linestart_resp);
@@ -297,7 +297,7 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd,
        * it would have been populated with something of size int to begin
        * it would have been populated with something of size int to begin
        * with, even though its datatype may be larger than an int.
        * with, even though its datatype may be larger than an int.
        */
        */
-      DEBUGASSERT((ptr+pp->cache_size) <= (buf+data->set.buffer_size+1));
+      DEBUGASSERT((ptr + pp->cache_size) <= (buf + data->set.buffer_size + 1));
       memcpy(ptr, pp->cache, pp->cache_size);
       memcpy(ptr, pp->cache, pp->cache_size);
       gotbytes = (ssize_t)pp->cache_size;
       gotbytes = (ssize_t)pp->cache_size;
       free(pp->cache);    /* free the cache */
       free(pp->cache);    /* free the cache */
@@ -351,7 +351,7 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd,
       pp->nread_resp += gotbytes;
       pp->nread_resp += gotbytes;
       for(i = 0; i < gotbytes; ptr++, i++) {
       for(i = 0; i < gotbytes; ptr++, i++) {
         perline++;
         perline++;
-        if(*ptr=='\n') {
+        if(*ptr == '\n') {
           /* a newline is CRLF in pp-talk, so the CR is ignored as
           /* a newline is CRLF in pp-talk, so the CR is ignored as
              the line isn't really terminated until the LF comes */
              the line isn't really terminated until the LF comes */
 
 
@@ -378,17 +378,17 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd,
                start of the buffer and zero terminate, for old times sake */
                start of the buffer and zero terminate, for old times sake */
             size_t n = ptr - pp->linestart_resp;
             size_t n = ptr - pp->linestart_resp;
             memmove(buf, pp->linestart_resp, n);
             memmove(buf, pp->linestart_resp, n);
-            buf[n]=0; /* zero terminate */
-            keepon=FALSE;
-            pp->linestart_resp = ptr+1; /* advance pointer */
+            buf[n] = 0; /* zero terminate */
+            keepon = FALSE;
+            pp->linestart_resp = ptr + 1; /* advance pointer */
             i++; /* skip this before getting out */
             i++; /* skip this before getting out */
 
 
             *size = pp->nread_resp; /* size of the response */
             *size = pp->nread_resp; /* size of the response */
             pp->nread_resp = 0; /* restart */
             pp->nread_resp = 0; /* restart */
             break;
             break;
           }
           }
-          perline=0; /* line starts over here */
-          pp->linestart_resp = ptr+1;
+          perline = 0; /* line starts over here */
+          pp->linestart_resp = ptr + 1;
         }
         }
       }
       }
 
 
@@ -490,7 +490,7 @@ CURLcode Curl_pp_flushsend(struct pingpong *pp)
   }
   }
   else {
   else {
     free(pp->sendthis);
     free(pp->sendthis);
-    pp->sendthis=NULL;
+    pp->sendthis = NULL;
     pp->sendleft = pp->sendsize = 0;
     pp->sendleft = pp->sendsize = 0;
     pp->response = Curl_tvnow();
     pp->response = Curl_tvnow();
   }
   }

+ 1 - 1
Utilities/cmcurl/lib/pingpong.h

@@ -58,7 +58,7 @@ struct pingpong {
                      server */
                      server */
   size_t sendleft; /* number of bytes left to send from the sendthis buffer */
   size_t sendleft; /* number of bytes left to send from the sendthis buffer */
   size_t sendsize; /* total size of the sendthis buffer */
   size_t sendsize; /* total size of the sendthis buffer */
-  struct timeval response; /* set to Curl_tvnow() when a command has been sent
+  struct curltime response; /* set to Curl_tvnow() when a command has been sent
                               off, used to time-out response reading */
                               off, used to time-out response reading */
   long response_time; /* When no timeout is given, this is the amount of
   long response_time; /* When no timeout is given, this is the amount of
                          milliseconds we await for a server response. */
                          milliseconds we await for a server response. */

+ 15 - 22
Utilities/cmcurl/lib/pipeline.c

@@ -230,28 +230,27 @@ CURLMcode Curl_pipeline_set_site_blacklist(char **sites,
   return CURLM_OK;
   return CURLM_OK;
 }
 }
 
 
+struct blacklist_node {
+  struct curl_llist_element list;
+  char server_name[1];
+};
+
 bool Curl_pipeline_server_blacklisted(struct Curl_easy *handle,
 bool Curl_pipeline_server_blacklisted(struct Curl_easy *handle,
                                       char *server_name)
                                       char *server_name)
 {
 {
   if(handle->multi && server_name) {
   if(handle->multi && server_name) {
-    struct curl_llist *blacklist =
+    struct curl_llist *list =
       Curl_multi_pipelining_server_bl(handle->multi);
       Curl_multi_pipelining_server_bl(handle->multi);
 
 
-    if(blacklist) {
-      struct curl_llist_element *curr;
-
-      curr = blacklist->head;
-      while(curr) {
-        char *bl_server_name;
-
-        bl_server_name = curr->ptr;
-        if(strncasecompare(bl_server_name, server_name,
-                           strlen(bl_server_name))) {
-          infof(handle, "Server %s is blacklisted\n", server_name);
-          return TRUE;
-        }
-        curr = curr->next;
+    struct curl_llist_element *e = list->head;
+    while(e) {
+      struct blacklist_node *bl = (struct blacklist_node *)e;
+      if(strncasecompare(bl->server_name, server_name,
+                         strlen(bl->server_name))) {
+        infof(handle, "Server %s is blacklisted\n", server_name);
+        return TRUE;
       }
       }
+      e = e->next;
     }
     }
 
 
     DEBUGF(infof(handle, "Server %s is not blacklisted\n", server_name));
     DEBUGF(infof(handle, "Server %s is not blacklisted\n", server_name));
@@ -259,11 +258,6 @@ bool Curl_pipeline_server_blacklisted(struct Curl_easy *handle,
   return FALSE;
   return FALSE;
 }
 }
 
 
-struct blacklist_node {
-  struct curl_llist_element list;
-  char server_name[1];
-};
-
 CURLMcode Curl_pipeline_set_server_blacklist(char **servers,
 CURLMcode Curl_pipeline_set_server_blacklist(char **servers,
                                              struct curl_llist *list)
                                              struct curl_llist *list)
 {
 {
@@ -286,8 +280,7 @@ CURLMcode Curl_pipeline_set_server_blacklist(char **servers,
       }
       }
       strcpy(n->server_name, *servers);
       strcpy(n->server_name, *servers);
 
 
-      Curl_llist_insert_next(list, list->tail, n->server_name,
-                             &n->list);
+      Curl_llist_insert_next(list, list->tail, n, &n->list);
       servers++;
       servers++;
     }
     }
   }
   }

+ 2 - 77
Utilities/cmcurl/lib/pop3.c

@@ -125,6 +125,7 @@ const struct Curl_handler Curl_handler_pop3 = {
   ZERO_NULL,                        /* perform_getsock */
   ZERO_NULL,                        /* perform_getsock */
   pop3_disconnect,                  /* disconnect */
   pop3_disconnect,                  /* disconnect */
   ZERO_NULL,                        /* readwrite */
   ZERO_NULL,                        /* readwrite */
+  ZERO_NULL,                        /* connection_check */
   PORT_POP3,                        /* defport */
   PORT_POP3,                        /* defport */
   CURLPROTO_POP3,                   /* protocol */
   CURLPROTO_POP3,                   /* protocol */
   PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */
   PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */
@@ -151,6 +152,7 @@ const struct Curl_handler Curl_handler_pop3s = {
   ZERO_NULL,                        /* perform_getsock */
   ZERO_NULL,                        /* perform_getsock */
   pop3_disconnect,                  /* disconnect */
   pop3_disconnect,                  /* disconnect */
   ZERO_NULL,                        /* readwrite */
   ZERO_NULL,                        /* readwrite */
+  ZERO_NULL,                        /* connection_check */
   PORT_POP3S,                       /* defport */
   PORT_POP3S,                       /* defport */
   CURLPROTO_POP3S,                  /* protocol */
   CURLPROTO_POP3S,                  /* protocol */
   PROTOPT_CLOSEACTION | PROTOPT_SSL
   PROTOPT_CLOSEACTION | PROTOPT_SSL
@@ -158,58 +160,6 @@ const struct Curl_handler Curl_handler_pop3s = {
 };
 };
 #endif
 #endif
 
 
-#ifndef CURL_DISABLE_HTTP
-/*
- * HTTP-proxyed POP3 protocol handler.
- */
-
-static const struct Curl_handler Curl_handler_pop3_proxy = {
-  "POP3",                               /* 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_POP3,                            /* defport */
-  CURLPROTO_HTTP,                       /* protocol */
-  PROTOPT_NONE                          /* flags */
-};
-
-#ifdef USE_SSL
-/*
- * HTTP-proxyed POP3S protocol handler.
- */
-
-static const struct Curl_handler Curl_handler_pop3s_proxy = {
-  "POP3S",                              /* 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_POP3S,                           /* defport */
-  CURLPROTO_HTTP,                       /* protocol */
-  PROTOPT_NONE                          /* flags */
-};
-#endif
-#endif
-
 /* SASL parameters for the pop3 protocol */
 /* SASL parameters for the pop3 protocol */
 static const struct SASLproto saslpop3 = {
 static const struct SASLproto saslpop3 = {
   "pop",                      /* The service name */
   "pop",                      /* The service name */
@@ -1355,31 +1305,6 @@ static CURLcode pop3_setup_connection(struct connectdata *conn)
 
 
   /* Clear the TLS upgraded flag */
   /* Clear the TLS upgraded flag */
   conn->tls_upgraded = FALSE;
   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 */
-#ifndef CURL_DISABLE_HTTP
-    if(conn->handler == &Curl_handler_pop3)
-      conn->handler = &Curl_handler_pop3_proxy;
-    else {
-#ifdef USE_SSL
-      conn->handler = &Curl_handler_pop3s_proxy;
-#else
-      failf(data, "POP3S not supported!");
-      return CURLE_UNSUPPORTED_PROTOCOL;
-#endif
-    }
-
-    /* set it up as an HTTP connection instead */
-    return conn->handler->setup_connection(conn);
-#else
-    failf(data, "POP3 over http proxy requires HTTP support built-in!");
-    return CURLE_UNSUPPORTED_PROTOCOL;
-#endif
-  }
-
   data->state.path++;   /* don't include the initial slash */
   data->state.path++;   /* don't include the initial slash */
 
 
   return CURLE_OK;
   return CURLE_OK;

+ 71 - 61
Utilities/cmcurl/lib/progress.c

@@ -134,7 +134,7 @@ int Curl_pgrsDone(struct connectdata *conn)
 {
 {
   int rc;
   int rc;
   struct Curl_easy *data = conn->data;
   struct Curl_easy *data = conn->data;
-  data->progress.lastshow=0;
+  data->progress.lastshow = 0;
   rc = Curl_pgrsUpdate(conn); /* the final (forced) update */
   rc = Curl_pgrsUpdate(conn); /* the final (forced) update */
   if(rc)
   if(rc)
     return rc;
     return rc;
@@ -149,21 +149,20 @@ int Curl_pgrsDone(struct connectdata *conn)
   return 0;
   return 0;
 }
 }
 
 
-/* reset all times except redirect, and reset the known transfer sizes */
-void Curl_pgrsResetTimesSizes(struct Curl_easy *data)
+/* reset the known transfer sizes */
+void Curl_pgrsResetTransferSizes(struct Curl_easy *data)
 {
 {
-  data->progress.t_nslookup = 0.0;
-  data->progress.t_connect = 0.0;
-  data->progress.t_pretransfer = 0.0;
-  data->progress.t_starttransfer = 0.0;
-
   Curl_pgrsSetDownloadSize(data, -1);
   Curl_pgrsSetDownloadSize(data, -1);
   Curl_pgrsSetUploadSize(data, -1);
   Curl_pgrsSetUploadSize(data, -1);
 }
 }
 
 
+/*
+ * @unittest: 1399
+ */
 void Curl_pgrsTime(struct Curl_easy *data, timerid timer)
 void Curl_pgrsTime(struct Curl_easy *data, timerid timer)
 {
 {
-  struct timeval now = Curl_tvnow();
+  struct curltime now = Curl_tvnow();
+  time_t *delta = NULL;
 
 
   switch(timer) {
   switch(timer) {
   default:
   default:
@@ -177,45 +176,58 @@ void Curl_pgrsTime(struct Curl_easy *data, timerid timer)
   case TIMER_STARTSINGLE:
   case TIMER_STARTSINGLE:
     /* This is set at the start of each single fetch */
     /* This is set at the start of each single fetch */
     data->progress.t_startsingle = now;
     data->progress.t_startsingle = now;
+    data->progress.is_t_startransfer_set = false;
     break;
     break;
-
   case TIMER_STARTACCEPT:
   case TIMER_STARTACCEPT:
-    data->progress.t_acceptdata = Curl_tvnow();
+    data->progress.t_acceptdata = now;
     break;
     break;
-
   case TIMER_NAMELOOKUP:
   case TIMER_NAMELOOKUP:
-    data->progress.t_nslookup =
-      Curl_tvdiff_secs(now, data->progress.t_startsingle);
+    delta = &data->progress.t_nslookup;
     break;
     break;
   case TIMER_CONNECT:
   case TIMER_CONNECT:
-    data->progress.t_connect =
-      Curl_tvdiff_secs(now, data->progress.t_startsingle);
+    delta = &data->progress.t_connect;
     break;
     break;
   case TIMER_APPCONNECT:
   case TIMER_APPCONNECT:
-    data->progress.t_appconnect =
-      Curl_tvdiff_secs(now, data->progress.t_startsingle);
+    delta = &data->progress.t_appconnect;
     break;
     break;
   case TIMER_PRETRANSFER:
   case TIMER_PRETRANSFER:
-    data->progress.t_pretransfer =
-      Curl_tvdiff_secs(now, data->progress.t_startsingle);
+    delta = &data->progress.t_pretransfer;
     break;
     break;
   case TIMER_STARTTRANSFER:
   case TIMER_STARTTRANSFER:
-    data->progress.t_starttransfer =
-      Curl_tvdiff_secs(now, data->progress.t_startsingle);
-    break;
+    delta = &data->progress.t_starttransfer;
+    /* prevent updating t_starttransfer unless:
+     *   1) this is the first time we're setting t_starttransfer
+     *   2) a redirect has occurred since the last time t_starttransfer was set
+     * This prevents repeated invocations of the function from incorrectly
+     * changing the t_starttransfer time.
+     */
+    if(data->progress.is_t_startransfer_set) {
+      return;
+    }
+    else {
+      data->progress.is_t_startransfer_set = true;
+      break;
+    }
   case TIMER_POSTRANSFER:
   case TIMER_POSTRANSFER:
     /* this is the normal end-of-transfer thing */
     /* this is the normal end-of-transfer thing */
     break;
     break;
   case TIMER_REDIRECT:
   case TIMER_REDIRECT:
-    data->progress.t_redirect = Curl_tvdiff_secs(now, data->progress.start);
+    data->progress.t_redirect = Curl_tvdiff_us(now, data->progress.start);
     break;
     break;
   }
   }
+  if(delta) {
+    time_t us = Curl_tvdiff_us(now, data->progress.t_startsingle);
+    if(!us)
+      us++; /* make sure at least one microsecond passed */
+    *delta += us;
+  }
 }
 }
 
 
 void Curl_pgrsStartNow(struct Curl_easy *data)
 void Curl_pgrsStartNow(struct Curl_easy *data)
 {
 {
   data->progress.speeder_c = 0; /* reset the progress meter display */
   data->progress.speeder_c = 0; /* reset the progress meter display */
   data->progress.start = Curl_tvnow();
   data->progress.start = Curl_tvnow();
+  data->progress.is_t_startransfer_set = false;
   data->progress.ul_limit_start.tv_sec = 0;
   data->progress.ul_limit_start.tv_sec = 0;
   data->progress.ul_limit_start.tv_usec = 0;
   data->progress.ul_limit_start.tv_usec = 0;
   data->progress.dl_limit_start.tv_sec = 0;
   data->progress.dl_limit_start.tv_sec = 0;
@@ -246,8 +258,8 @@ void Curl_pgrsStartNow(struct Curl_easy *data)
 long Curl_pgrsLimitWaitTime(curl_off_t cursize,
 long Curl_pgrsLimitWaitTime(curl_off_t cursize,
                             curl_off_t startsize,
                             curl_off_t startsize,
                             curl_off_t limit,
                             curl_off_t limit,
-                            struct timeval start,
-                            struct timeval now)
+                            struct curltime start,
+                            struct curltime now)
 {
 {
   curl_off_t size = cursize - startsize;
   curl_off_t size = cursize - startsize;
   time_t minimum;
   time_t minimum;
@@ -273,7 +285,7 @@ long Curl_pgrsLimitWaitTime(curl_off_t cursize,
 
 
 void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size)
 void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size)
 {
 {
-  struct timeval now = Curl_tvnow();
+  struct curltime now = Curl_tvnow();
 
 
   data->progress.downloaded = size;
   data->progress.downloaded = size;
 
 
@@ -291,7 +303,7 @@ void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size)
 
 
 void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size)
 void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size)
 {
 {
-  struct timeval now = Curl_tvnow();
+  struct curltime now = Curl_tvnow();
 
 
   data->progress.uploaded = size;
   data->progress.uploaded = size;
 
 
@@ -337,12 +349,12 @@ void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size)
  */
  */
 int Curl_pgrsUpdate(struct connectdata *conn)
 int Curl_pgrsUpdate(struct connectdata *conn)
 {
 {
-  struct timeval now;
+  struct curltime now;
   int result;
   int result;
   char max5[6][10];
   char max5[6][10];
-  curl_off_t dlpercen=0;
-  curl_off_t ulpercen=0;
-  curl_off_t total_percen=0;
+  curl_off_t dlpercen = 0;
+  curl_off_t ulpercen = 0;
+  curl_off_t total_percen = 0;
   curl_off_t total_transfer;
   curl_off_t total_transfer;
   curl_off_t total_expected_transfer;
   curl_off_t total_expected_transfer;
   curl_off_t timespent;
   curl_off_t timespent;
@@ -353,26 +365,26 @@ int Curl_pgrsUpdate(struct connectdata *conn)
   char time_left[10];
   char time_left[10];
   char time_total[10];
   char time_total[10];
   char time_spent[10];
   char time_spent[10];
-  curl_off_t ulestimate=0;
-  curl_off_t dlestimate=0;
+  curl_off_t ulestimate = 0;
+  curl_off_t dlestimate = 0;
   curl_off_t total_estimate;
   curl_off_t total_estimate;
-  bool shownow=FALSE;
+  bool shownow = FALSE;
 
 
   now = Curl_tvnow(); /* what time is it */
   now = Curl_tvnow(); /* what time is it */
 
 
   /* The time spent so far (from the start) */
   /* The time spent so far (from the start) */
-  data->progress.timespent = curlx_tvdiff_secs(now, data->progress.start);
-  timespent = (curl_off_t)data->progress.timespent;
+  data->progress.timespent = Curl_tvdiff_us(now, data->progress.start);
+  timespent = (curl_off_t)data->progress.timespent/1000000; /* seconds */
 
 
   /* The average download speed this far */
   /* The average download speed this far */
   data->progress.dlspeed = (curl_off_t)
   data->progress.dlspeed = (curl_off_t)
-    ((double)data->progress.downloaded/
-     (data->progress.timespent>0?data->progress.timespent:1));
+    (data->progress.downloaded/
+     (timespent>0?timespent:1));
 
 
   /* The average upload speed this far */
   /* The average upload speed this far */
   data->progress.ulspeed = (curl_off_t)
   data->progress.ulspeed = (curl_off_t)
-    ((double)data->progress.uploaded/
-     (data->progress.timespent>0?data->progress.timespent:1));
+    (data->progress.uploaded/
+     (timespent>0?timespent:1));
 
 
   /* Calculations done at most once a second, unless end is reached */
   /* Calculations done at most once a second, unless end is reached */
   if(data->progress.lastshow != now.tv_sec) {
   if(data->progress.lastshow != now.tv_sec) {
@@ -380,11 +392,10 @@ int Curl_pgrsUpdate(struct connectdata *conn)
 
 
     data->progress.lastshow = now.tv_sec;
     data->progress.lastshow = now.tv_sec;
 
 
-    /* Let's do the "current speed" thing, which should use the fastest
-       of the dl/ul speeds. Store the faster speed at entry 'nowindex'. */
+    /* Let's do the "current speed" thing, with the dl + ul speeds
+       combined. Store the speed at entry 'nowindex'. */
     data->progress.speeder[ nowindex ] =
     data->progress.speeder[ nowindex ] =
-      data->progress.downloaded>data->progress.uploaded?
-      data->progress.downloaded:data->progress.uploaded;
+      data->progress.downloaded + data->progress.uploaded;
 
 
     /* remember the exact time for this moment */
     /* remember the exact time for this moment */
     data->progress.speeder_time [ nowindex ] = now;
     data->progress.speeder_time [ nowindex ] = now;
@@ -397,7 +408,7 @@ int Curl_pgrsUpdate(struct connectdata *conn)
        array. With N_ENTRIES filled in, we have about N_ENTRIES-1 seconds of
        array. With N_ENTRIES filled in, we have about N_ENTRIES-1 seconds of
        transfer. Imagine, after one second we have filled in two entries,
        transfer. Imagine, after one second we have filled in two entries,
        after two seconds we've filled in three entries etc. */
        after two seconds we've filled in three entries etc. */
-    countindex = ((data->progress.speeder_c>=CURR_TIME)?
+    countindex = ((data->progress.speeder_c >= CURR_TIME)?
                   CURR_TIME:data->progress.speeder_c) - 1;
                   CURR_TIME:data->progress.speeder_c) - 1;
 
 
     /* first of all, we don't do this if there's no counted seconds yet */
     /* first of all, we don't do this if there's no counted seconds yet */
@@ -407,14 +418,14 @@ int Curl_pgrsUpdate(struct connectdata *conn)
       /* Get the index position to compare with the 'nowindex' position.
       /* Get the index position to compare with the 'nowindex' position.
          Get the oldest entry possible. While we have less than CURR_TIME
          Get the oldest entry possible. While we have less than CURR_TIME
          entries, the first entry will remain the oldest. */
          entries, the first entry will remain the oldest. */
-      checkindex = (data->progress.speeder_c>=CURR_TIME)?
+      checkindex = (data->progress.speeder_c >= CURR_TIME)?
         data->progress.speeder_c%CURR_TIME:0;
         data->progress.speeder_c%CURR_TIME:0;
 
 
       /* Figure out the exact time for the time span */
       /* Figure out the exact time for the time span */
       span_ms = Curl_tvdiff(now,
       span_ms = Curl_tvdiff(now,
                             data->progress.speeder_time[checkindex]);
                             data->progress.speeder_time[checkindex]);
       if(0 == span_ms)
       if(0 == span_ms)
-        span_ms=1; /* at least one millisecond MUST have passed */
+        span_ms = 1; /* at least one millisecond MUST have passed */
 
 
       /* Calculate the average speed the last 'span_ms' milliseconds */
       /* Calculate the average speed the last 'span_ms' milliseconds */
       {
       {
@@ -433,10 +444,9 @@ int Curl_pgrsUpdate(struct connectdata *conn)
       }
       }
     }
     }
     else
     else
-      /* the first second we use the main average */
+      /* the first second we use the average */
       data->progress.current_speed =
       data->progress.current_speed =
-        (data->progress.ulspeed>data->progress.dlspeed)?
-        data->progress.ulspeed:data->progress.dlspeed;
+        data->progress.ulspeed + data->progress.dlspeed;
 
 
   } /* Calculations end */
   } /* Calculations end */
 
 
@@ -445,22 +455,22 @@ int Curl_pgrsUpdate(struct connectdata *conn)
 
 
     if(data->set.fxferinfo) {
     if(data->set.fxferinfo) {
       /* There's a callback set, call that */
       /* There's a callback set, call that */
-      result= data->set.fxferinfo(data->set.progress_client,
-                                  data->progress.size_dl,
-                                  data->progress.downloaded,
-                                  data->progress.size_ul,
-                                  data->progress.uploaded);
+      result = data->set.fxferinfo(data->set.progress_client,
+                                   data->progress.size_dl,
+                                   data->progress.downloaded,
+                                   data->progress.size_ul,
+                                   data->progress.uploaded);
       if(result)
       if(result)
         failf(data, "Callback aborted");
         failf(data, "Callback aborted");
       return result;
       return result;
     }
     }
     if(data->set.fprogress) {
     if(data->set.fprogress) {
       /* The older deprecated callback is set, call that */
       /* The older deprecated callback is set, call that */
-      result= data->set.fprogress(data->set.progress_client,
-                                  (double)data->progress.size_dl,
-                                  (double)data->progress.downloaded,
-                                  (double)data->progress.size_ul,
-                                  (double)data->progress.uploaded);
+      result = data->set.fprogress(data->set.progress_client,
+                                   (double)data->progress.size_dl,
+                                   (double)data->progress.downloaded,
+                                   (double)data->progress.size_ul,
+                                   (double)data->progress.uploaded);
       if(result)
       if(result)
         failf(data, "Callback aborted");
         failf(data, "Callback aborted");
       return result;
       return result;

+ 4 - 4
Utilities/cmcurl/lib/progress.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -47,13 +47,13 @@ void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size);
 void Curl_pgrsSetDownloadCounter(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);
 void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size);
 int Curl_pgrsUpdate(struct connectdata *);
 int Curl_pgrsUpdate(struct connectdata *);
-void Curl_pgrsResetTimesSizes(struct Curl_easy *data);
+void Curl_pgrsResetTransferSizes(struct Curl_easy *data);
 void Curl_pgrsTime(struct Curl_easy *data, timerid timer);
 void Curl_pgrsTime(struct Curl_easy *data, timerid timer);
 long Curl_pgrsLimitWaitTime(curl_off_t cursize,
 long Curl_pgrsLimitWaitTime(curl_off_t cursize,
                             curl_off_t startsize,
                             curl_off_t startsize,
                             curl_off_t limit,
                             curl_off_t limit,
-                            struct timeval start,
-                            struct timeval now);
+                            struct curltime start,
+                            struct curltime now);
 
 
 /* Don't show progress for sizes smaller than: */
 /* Don't show progress for sizes smaller than: */
 #define LEAST_SIZE_PROGRESS BUFSIZE
 #define LEAST_SIZE_PROGRESS BUFSIZE

+ 1 - 1
Utilities/cmcurl/lib/rand.c

@@ -86,7 +86,7 @@ static CURLcode randit(struct Curl_easy *data, unsigned int *rnd)
 #endif
 #endif
 
 
   if(!seeded) {
   if(!seeded) {
-    struct timeval now = curlx_tvnow();
+    struct curltime now = curlx_tvnow();
     infof(data, "WARNING: Using weak random seed\n");
     infof(data, "WARNING: Using weak random seed\n");
     randseed += (unsigned int)now.tv_usec + (unsigned int)now.tv_sec;
     randseed += (unsigned int)now.tv_usec + (unsigned int)now.tv_sec;
     randseed = randseed * 1103515245 + 12345;
     randseed = randseed * 1103515245 + 12345;

+ 39 - 4
Utilities/cmcurl/lib/rtsp.c

@@ -81,6 +81,9 @@ static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data,
 
 
 static CURLcode rtsp_setup_connection(struct connectdata *conn);
 static CURLcode rtsp_setup_connection(struct connectdata *conn);
 
 
+bool rtsp_connisdead(struct connectdata *check);
+static unsigned int rtsp_conncheck(struct connectdata *check,
+                                   unsigned int checks_to_perform);
 
 
 /* this returns the socket to wait for in the DO and DOING state for the multi
 /* this returns the socket to wait for in the DO and DOING state for the multi
    interface and then we're always _sending_ a request and thus we wait for
    interface and then we're always _sending_ a request and thus we wait for
@@ -117,6 +120,7 @@ const struct Curl_handler Curl_handler_rtsp = {
   ZERO_NULL,                            /* perform_getsock */
   ZERO_NULL,                            /* perform_getsock */
   rtsp_disconnect,                      /* disconnect */
   rtsp_disconnect,                      /* disconnect */
   rtsp_rtp_readwrite,                   /* readwrite */
   rtsp_rtp_readwrite,                   /* readwrite */
+  rtsp_conncheck,                       /* connection_check */
   PORT_RTSP,                            /* defport */
   PORT_RTSP,                            /* defport */
   CURLPROTO_RTSP,                       /* protocol */
   CURLPROTO_RTSP,                       /* protocol */
   PROTOPT_NONE                          /* flags */
   PROTOPT_NONE                          /* flags */
@@ -143,7 +147,7 @@ static CURLcode rtsp_setup_connection(struct connectdata *conn)
  * Instead, if it is readable, run Curl_connalive() to peek at the socket
  * Instead, if it is readable, run Curl_connalive() to peek at the socket
  * and distinguish between closed and data.
  * and distinguish between closed and data.
  */
  */
-bool Curl_rtsp_connisdead(struct connectdata *check)
+bool rtsp_connisdead(struct connectdata *check)
 {
 {
   int sval;
   int sval;
   bool ret_val = TRUE;
   bool ret_val = TRUE;
@@ -165,6 +169,23 @@ bool Curl_rtsp_connisdead(struct connectdata *check)
   return ret_val;
   return ret_val;
 }
 }
 
 
+/*
+ * Function to check on various aspects of a connection.
+ */
+static unsigned int rtsp_conncheck(struct connectdata *check,
+                                   unsigned int checks_to_perform)
+{
+  unsigned int ret_val = CONNRESULT_NONE;
+
+  if(checks_to_perform & CONNCHECK_ISDEAD) {
+    if(rtsp_connisdead(check))
+      ret_val |= CONNRESULT_DEAD;
+  }
+
+  return ret_val;
+}
+
+
 static CURLcode rtsp_connect(struct connectdata *conn, bool *done)
 static CURLcode rtsp_connect(struct connectdata *conn, bool *done)
 {
 {
   CURLcode httpStatus;
   CURLcode httpStatus;
@@ -229,7 +250,7 @@ static CURLcode rtsp_done(struct connectdata *conn,
 static CURLcode rtsp_do(struct connectdata *conn, bool *done)
 static CURLcode rtsp_do(struct connectdata *conn, bool *done)
 {
 {
   struct Curl_easy *data = conn->data;
   struct Curl_easy *data = conn->data;
-  CURLcode result=CURLE_OK;
+  CURLcode result = CURLE_OK;
   Curl_RtspReq rtspreq = data->set.rtspreq;
   Curl_RtspReq rtspreq = data->set.rtspreq;
   struct RTSP *rtsp = data->req.protop;
   struct RTSP *rtsp = data->req.protop;
   struct HTTP *http;
   struct HTTP *http;
@@ -728,14 +749,28 @@ CURLcode rtp_client_write(struct connectdata *conn, char *ptr, size_t len)
   struct Curl_easy *data = conn->data;
   struct Curl_easy *data = conn->data;
   size_t wrote;
   size_t wrote;
   curl_write_callback writeit;
   curl_write_callback writeit;
+  void *user_ptr;
 
 
   if(len == 0) {
   if(len == 0) {
     failf(data, "Cannot write a 0 size RTP packet.");
     failf(data, "Cannot write a 0 size RTP packet.");
     return CURLE_WRITE_ERROR;
     return CURLE_WRITE_ERROR;
   }
   }
 
 
-  writeit = data->set.fwrite_rtp?data->set.fwrite_rtp:data->set.fwrite_func;
-  wrote = writeit(ptr, 1, len, data->set.rtp_out);
+  /* If the user has configured CURLOPT_INTERLEAVEFUNCTION then use that
+     function and any configured CURLOPT_INTERLEAVEDATA to write out the RTP
+     data. Otherwise, use the CURLOPT_WRITEFUNCTION with the CURLOPT_WRITEDATA
+     pointer to write out the RTP data. */
+  if(data->set.fwrite_rtp) {
+    writeit = data->set.fwrite_rtp;
+    user_ptr = data->set.rtp_out;
+  }
+  else
+  {
+    writeit = data->set.fwrite_func;
+    user_ptr = data->set.out;
+  }
+
+  wrote = writeit(ptr, 1, len, user_ptr);
 
 
   if(CURL_WRITEFUNC_PAUSE == wrote) {
   if(CURL_WRITEFUNC_PAUSE == wrote) {
     failf(data, "Cannot pause RTP");
     failf(data, "Cannot pause RTP");

+ 0 - 2
Utilities/cmcurl/lib/rtsp.h

@@ -25,13 +25,11 @@
 
 
 extern const struct Curl_handler Curl_handler_rtsp;
 extern const struct Curl_handler Curl_handler_rtsp;
 
 
-bool Curl_rtsp_connisdead(struct connectdata *check);
 CURLcode Curl_rtsp_parseheader(struct connectdata *conn, char *header);
 CURLcode Curl_rtsp_parseheader(struct connectdata *conn, char *header);
 
 
 #else
 #else
 /* disabled */
 /* disabled */
 #define Curl_rtsp_parseheader(x,y) CURLE_NOT_BUILT_IN
 #define Curl_rtsp_parseheader(x,y) CURLE_NOT_BUILT_IN
-#define Curl_rtsp_connisdead(x) TRUE
 
 
 #endif /* CURL_DISABLE_RTSP */
 #endif /* CURL_DISABLE_RTSP */
 
 

+ 2 - 2
Utilities/cmcurl/lib/security.c

@@ -7,7 +7,7 @@
  * rewrite to work around the paragraph 2 in the BSD licenses as explained
  * rewrite to work around the paragraph 2 in the BSD licenses as explained
  * below.
  * below.
  *
  *
- * Copyright (c) 1998, 1999 Kungliga Tekniska Högskolan
+ * Copyright (c) 1998, 1999, 2017 Kungliga Tekniska Högskolan
  * (Royal Institute of Technology, Stockholm, Sweden).
  * (Royal Institute of Technology, Stockholm, Sweden).
  *
  *
  * Copyright (C) 2001 - 2015, Daniel Stenberg, <[email protected]>, et al.
  * Copyright (C) 2001 - 2015, Daniel Stenberg, <[email protected]>, et al.
@@ -115,7 +115,7 @@ static char level_to_char(int level)
 static int ftp_send_command(struct connectdata *conn, const char *message, ...)
 static int ftp_send_command(struct connectdata *conn, const char *message, ...)
 {
 {
   int ftp_code;
   int ftp_code;
-  ssize_t nread=0;
+  ssize_t nread = 0;
   va_list args;
   va_list args;
   char print_buffer[50];
   char print_buffer[50];
 
 

+ 5 - 5
Utilities/cmcurl/lib/select.c

@@ -78,7 +78,7 @@ int Curl_wait_ms(int timeout_ms)
 #ifndef HAVE_POLL_FINE
 #ifndef HAVE_POLL_FINE
   struct timeval pending_tv;
   struct timeval pending_tv;
 #endif
 #endif
-  struct timeval initial_tv;
+  struct curltime initial_tv;
   int pending_ms;
   int pending_ms;
   int error;
   int error;
 #endif
 #endif
@@ -158,7 +158,7 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */
   fd_set fds_err;
   fd_set fds_err;
   curl_socket_t maxfd;
   curl_socket_t maxfd;
 #endif
 #endif
-  struct timeval initial_tv = {0, 0};
+  struct curltime initial_tv = {0, 0};
   int pending_ms = 0;
   int pending_ms = 0;
   int error;
   int error;
   int r;
   int r;
@@ -398,7 +398,7 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms)
   fd_set fds_err;
   fd_set fds_err;
   curl_socket_t maxfd;
   curl_socket_t maxfd;
 #endif
 #endif
-  struct timeval initial_tv = {0, 0};
+  struct curltime initial_tv = {0, 0};
   bool fds_none = TRUE;
   bool fds_none = TRUE;
   unsigned int i;
   unsigned int i;
   int pending_ms = 0;
   int pending_ms = 0;
@@ -571,8 +571,8 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms)
  *
  *
  * Return values are the same as select's.
  * 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 tpf_select_libcurl(int maxfds, fd_set *reads, fd_set *writes,
+                       fd_set *excepts, struct timeval *tv)
 {
 {
    int rc;
    int rc;
 
 

+ 3 - 2
Utilities/cmcurl/lib/select.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -36,7 +36,8 @@
 
 
 #if !defined(HAVE_STRUCT_POLLFD) && \
 #if !defined(HAVE_STRUCT_POLLFD) && \
     !defined(HAVE_SYS_POLL_H) && \
     !defined(HAVE_SYS_POLL_H) && \
-    !defined(HAVE_POLL_H)
+    !defined(HAVE_POLL_H) && \
+    !defined(POLLIN)
 
 
 #define POLLIN      0x01
 #define POLLIN      0x01
 #define POLLPRI     0x02
 #define POLLPRI     0x02

+ 10 - 10
Utilities/cmcurl/lib/sendf.c

@@ -63,7 +63,7 @@ static size_t convert_lineends(struct Curl_easy *data,
     if(*startPtr == '\n') {
     if(*startPtr == '\n') {
       /* This block of incoming data starts with the
       /* This block of incoming data starts with the
          previous block's LF so get rid of it */
          previous block's LF so get rid of it */
-      memmove(startPtr, startPtr+1, size-1);
+      memmove(startPtr, startPtr + 1, size-1);
       size--;
       size--;
       /* and it wasn't a bare CR but a CRLF conversion instead */
       /* and it wasn't a bare CR but a CRLF conversion instead */
       data->state.crlf_conversions++;
       data->state.crlf_conversions++;
@@ -75,7 +75,7 @@ static size_t convert_lineends(struct Curl_easy *data,
   inPtr = outPtr = memchr(startPtr, '\r', size);
   inPtr = outPtr = memchr(startPtr, '\r', size);
   if(inPtr) {
   if(inPtr) {
     /* at least one CR, now look for CRLF */
     /* at least one CR, now look for CRLF */
-    while(inPtr < (startPtr+size-1)) {
+    while(inPtr < (startPtr + size-1)) {
       /* note that it's size-1, so we'll never look past the last byte */
       /* note that it's size-1, so we'll never look past the last byte */
       if(memcmp(inPtr, "\r\n", 2) == 0) {
       if(memcmp(inPtr, "\r\n", 2) == 0) {
         /* CRLF found, bump past the CR and copy the NL */
         /* CRLF found, bump past the CR and copy the NL */
@@ -98,7 +98,7 @@ static size_t convert_lineends(struct Curl_easy *data,
       inPtr++;
       inPtr++;
     } /* end of while loop */
     } /* end of while loop */
 
 
-    if(inPtr < startPtr+size) {
+    if(inPtr < startPtr + size) {
       /* handle last byte */
       /* handle last byte */
       if(*inPtr == '\r') {
       if(*inPtr == '\r') {
         /* deal with a CR at the end of the buffer */
         /* deal with a CR at the end of the buffer */
@@ -112,7 +112,7 @@ static size_t convert_lineends(struct Curl_easy *data,
       }
       }
       outPtr++;
       outPtr++;
     }
     }
-    if(outPtr < startPtr+size)
+    if(outPtr < startPtr + size)
       /* tidy up by null terminating the now shorter data */
       /* tidy up by null terminating the now shorter data */
       *outPtr = '\0';
       *outPtr = '\0';
 
 
@@ -279,7 +279,7 @@ CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn,
   if(!s)
   if(!s)
     return CURLE_OUT_OF_MEMORY; /* failure */
     return CURLE_OUT_OF_MEMORY; /* failure */
 
 
-  bytes_written=0;
+  bytes_written = 0;
   write_len = strlen(s);
   write_len = strlen(s);
   sptr = s;
   sptr = s;
 
 
@@ -387,7 +387,7 @@ ssize_t Curl_send_plain(struct connectdata *conn, int num,
 #endif
 #endif
       ) {
       ) {
       /* this is just a case of EWOULDBLOCK */
       /* this is just a case of EWOULDBLOCK */
-      bytes_written=0;
+      bytes_written = 0;
       *code = CURLE_AGAIN;
       *code = CURLE_AGAIN;
     }
     }
     else {
     else {
@@ -480,7 +480,7 @@ static CURLcode pausewrite(struct Curl_easy *data,
   bool newtype = TRUE;
   bool newtype = TRUE;
 
 
   if(s->tempcount) {
   if(s->tempcount) {
-    for(i=0; i< s->tempcount; i++) {
+    for(i = 0; i< s->tempcount; i++) {
       if(s->tempwrite[i].type == type) {
       if(s->tempwrite[i].type == type) {
         /* data for this type exists */
         /* data for this type exists */
         newtype = FALSE;
         newtype = FALSE;
@@ -704,7 +704,7 @@ CURLcode Curl_read(struct connectdata *conn, /* connection data */
      us use the correct ssl handle. */
      us use the correct ssl handle. */
   int num = (sockfd == conn->sock[SECONDARYSOCKET]);
   int num = (sockfd == conn->sock[SECONDARYSOCKET]);
 
 
-  *n=0; /* reset amount to zero */
+  *n = 0; /* reset amount to zero */
 
 
   /* If session can pipeline, check connection buffer  */
   /* If session can pipeline, check connection buffer  */
   if(pipelining) {
   if(pipelining) {
@@ -823,8 +823,8 @@ int Curl_debug(struct Curl_easy *data, curl_infotype type,
   int rc;
   int rc;
   if(data->set.printhost && conn && conn->host.dispname) {
   if(data->set.printhost && conn && conn->host.dispname) {
     char buffer[160];
     char buffer[160];
-    const char *t=NULL;
-    const char *w="Data";
+    const char *t = NULL;
+    const char *w = "Data";
     switch(type) {
     switch(type) {
     case CURLINFO_HEADER_IN:
     case CURLINFO_HEADER_IN:
       w = "Header";
       w = "Header";

+ 27 - 4
Utilities/cmcurl/lib/smb.c

@@ -34,7 +34,7 @@
 #include <process.h>
 #include <process.h>
 #ifdef CURL_WINDOWS_APP
 #ifdef CURL_WINDOWS_APP
 #define getpid GetCurrentProcessId
 #define getpid GetCurrentProcessId
-#else
+#elif !defined(MSDOS)
 #define getpid _getpid
 #define getpid _getpid
 #endif
 #endif
 #endif
 #endif
@@ -85,6 +85,7 @@ const struct Curl_handler Curl_handler_smb = {
   ZERO_NULL,                            /* perform_getsock */
   ZERO_NULL,                            /* perform_getsock */
   smb_disconnect,                       /* disconnect */
   smb_disconnect,                       /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
   PORT_SMB,                             /* defport */
   PORT_SMB,                             /* defport */
   CURLPROTO_SMB,                        /* protocol */
   CURLPROTO_SMB,                        /* protocol */
   PROTOPT_NONE                          /* flags */
   PROTOPT_NONE                          /* flags */
@@ -109,6 +110,7 @@ const struct Curl_handler Curl_handler_smbs = {
   ZERO_NULL,                            /* perform_getsock */
   ZERO_NULL,                            /* perform_getsock */
   smb_disconnect,                       /* disconnect */
   smb_disconnect,                       /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
   PORT_SMBS,                            /* defport */
   PORT_SMBS,                            /* defport */
   CURLPROTO_SMBS,                       /* protocol */
   CURLPROTO_SMBS,                       /* protocol */
   PROTOPT_SSL                           /* flags */
   PROTOPT_SSL                           /* flags */
@@ -713,6 +715,23 @@ static CURLcode smb_connection_state(struct connectdata *conn, bool *done)
   return CURLE_OK;
   return CURLE_OK;
 }
 }
 
 
+/*
+ * Convert a timestamp from the Windows world (100 nsec units from
+ * 1 Jan 1601) to Posix time.
+ */
+static void get_posix_time(long *_out, const void *_in)
+{
+#ifdef HAVE_LONGLONG
+  long long timestamp = *(long long *) _in;
+#else
+  unsigned __int64 timestamp = *(unsigned __int64 *) _in;
+#endif
+
+  timestamp -= 116444736000000000ULL;
+  timestamp /= 10000000;
+  *_out = (long) timestamp;
+}
+
 static CURLcode smb_request_state(struct connectdata *conn, bool *done)
 static CURLcode smb_request_state(struct connectdata *conn, bool *done)
 {
 {
   struct smb_request *req = conn->data->req.protop;
   struct smb_request *req = conn->data->req.protop;
@@ -723,6 +742,7 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done)
   unsigned short off;
   unsigned short off;
   CURLcode result;
   CURLcode result;
   void *msg = NULL;
   void *msg = NULL;
+  const struct smb_nt_create_response *smb_m;
 
 
   /* Start the request */
   /* Start the request */
   if(req->state == SMB_REQUESTING) {
   if(req->state == SMB_REQUESTING) {
@@ -765,7 +785,8 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done)
       next_state = SMB_TREE_DISCONNECT;
       next_state = SMB_TREE_DISCONNECT;
       break;
       break;
     }
     }
-    req->fid = smb_swap16(((struct smb_nt_create_response *)msg)->fid);
+    smb_m = (const struct smb_nt_create_response*) msg;
+    req->fid = smb_swap16(smb_m->fid);
     conn->data->req.offset = 0;
     conn->data->req.offset = 0;
     if(conn->data->set.upload) {
     if(conn->data->set.upload) {
       conn->data->req.size = conn->data->state.infilesize;
       conn->data->req.size = conn->data->state.infilesize;
@@ -773,9 +794,11 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done)
       next_state = SMB_UPLOAD;
       next_state = SMB_UPLOAD;
     }
     }
     else {
     else {
-      conn->data->req.size =
-        smb_swap64(((struct smb_nt_create_response *)msg)->end_of_file);
+      smb_m = (const struct smb_nt_create_response*) msg;
+      conn->data->req.size = smb_swap64(smb_m->end_of_file);
       Curl_pgrsSetDownloadSize(conn->data, conn->data->req.size);
       Curl_pgrsSetDownloadSize(conn->data, conn->data->req.size);
+      if(conn->data->set.get_filetime)
+        get_posix_time(&conn->data->info.filetime, &smb_m->last_change_time);
       next_state = SMB_DOWNLOAD;
       next_state = SMB_DOWNLOAD;
     }
     }
     break;
     break;

+ 39 - 79
Utilities/cmcurl/lib/smtp.c

@@ -67,6 +67,7 @@
 #include "transfer.h"
 #include "transfer.h"
 #include "escape.h"
 #include "escape.h"
 #include "http.h" /* for HTTP proxy tunnel stuff */
 #include "http.h" /* for HTTP proxy tunnel stuff */
+#include "mime.h"
 #include "socks.h"
 #include "socks.h"
 #include "smtp.h"
 #include "smtp.h"
 #include "strtoofft.h"
 #include "strtoofft.h"
@@ -124,6 +125,7 @@ const struct Curl_handler Curl_handler_smtp = {
   ZERO_NULL,                        /* perform_getsock */
   ZERO_NULL,                        /* perform_getsock */
   smtp_disconnect,                  /* disconnect */
   smtp_disconnect,                  /* disconnect */
   ZERO_NULL,                        /* readwrite */
   ZERO_NULL,                        /* readwrite */
+  ZERO_NULL,                        /* connection_check */
   PORT_SMTP,                        /* defport */
   PORT_SMTP,                        /* defport */
   CURLPROTO_SMTP,                   /* protocol */
   CURLPROTO_SMTP,                   /* protocol */
   PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */
   PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */
@@ -150,6 +152,7 @@ const struct Curl_handler Curl_handler_smtps = {
   ZERO_NULL,                        /* perform_getsock */
   ZERO_NULL,                        /* perform_getsock */
   smtp_disconnect,                  /* disconnect */
   smtp_disconnect,                  /* disconnect */
   ZERO_NULL,                        /* readwrite */
   ZERO_NULL,                        /* readwrite */
+  ZERO_NULL,                        /* connection_check */
   PORT_SMTPS,                       /* defport */
   PORT_SMTPS,                       /* defport */
   CURLPROTO_SMTPS,                  /* protocol */
   CURLPROTO_SMTPS,                  /* protocol */
   PROTOPT_CLOSEACTION | PROTOPT_SSL
   PROTOPT_CLOSEACTION | PROTOPT_SSL
@@ -157,58 +160,6 @@ const struct Curl_handler Curl_handler_smtps = {
 };
 };
 #endif
 #endif
 
 
-#ifndef CURL_DISABLE_HTTP
-/*
- * HTTP-proxyed SMTP protocol handler.
- */
-
-static const struct Curl_handler Curl_handler_smtp_proxy = {
-  "SMTP",                               /* 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_SMTP,                            /* defport */
-  CURLPROTO_HTTP,                       /* protocol */
-  PROTOPT_NONE                          /* flags */
-};
-
-#ifdef USE_SSL
-/*
- * HTTP-proxyed SMTPS protocol handler.
- */
-
-static const struct Curl_handler Curl_handler_smtps_proxy = {
-  "SMTPS",                              /* 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_SMTPS,                           /* defport */
-  CURLPROTO_HTTP,                       /* protocol */
-  PROTOPT_NONE                          /* flags */
-};
-#endif
-#endif
-
 /* SASL parameters for the smtp protocol */
 /* SASL parameters for the smtp protocol */
 static const struct SASLproto saslsmtp = {
 static const struct SASLproto saslsmtp = {
   "smtp",                     /* The service name */
   "smtp",                     /* The service name */
@@ -580,8 +531,40 @@ static CURLcode smtp_perform_mail(struct connectdata *conn)
     }
     }
   }
   }
 
 
+  /* Prepare the mime data if some. */
+  if(data->set.mimepost.kind != MIMEKIND_NONE) {
+    /* Use the whole structure as data. */
+    data->set.mimepost.flags &= ~MIME_BODY_ONLY;
+
+    /* Add external headers and mime version. */
+    curl_mime_headers(&data->set.mimepost, data->set.headers, 0);
+    result = Curl_mime_prepare_headers(&data->set.mimepost, NULL,
+                                       NULL, MIMESTRATEGY_MAIL);
+
+    if(!result)
+      if(!Curl_checkheaders(conn, "Mime-Version"))
+        result = Curl_mime_add_header(&data->set.mimepost.curlheaders,
+                                      "Mime-Version: 1.0");
+
+    /* Make sure we will read the entire mime structure. */
+    if(!result)
+      result = Curl_mime_rewind(&data->set.mimepost);
+
+    if(result) {
+      free(from);
+      free(auth);
+      return result;
+    }
+
+    data->state.infilesize = Curl_mime_size(&data->set.mimepost);
+
+    /* Read from mime structure. */
+    data->state.fread_func = (curl_read_callback) Curl_mime_read;
+    data->state.in = (void *) &data->set.mimepost;
+  }
+
   /* Calculate the optional SIZE parameter */
   /* Calculate the optional SIZE parameter */
-  if(conn->proto.smtpc.size_supported && conn->data->state.infilesize > 0) {
+  if(conn->proto.smtpc.size_supported && data->state.infilesize > 0) {
     size = aprintf("%" CURL_FORMAT_CURL_OFF_T, data->state.infilesize);
     size = aprintf("%" CURL_FORMAT_CURL_OFF_T, data->state.infilesize);
 
 
     if(!size) {
     if(!size) {
@@ -1209,7 +1192,8 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
     connclose(conn, "SMTP done with bad status"); /* marked for closure */
     connclose(conn, "SMTP done with bad status"); /* marked for closure */
     result = status;         /* use the already set error code */
     result = status;         /* use the already set error code */
   }
   }
-  else if(!data->set.connect_only && data->set.upload && data->set.mail_rcpt) {
+  else if(!data->set.connect_only && data->set.mail_rcpt &&
+          (data->set.upload || data->set.mimepost.kind)) {
     /* Calculate the EOB taking into account any terminating CRLF from the
     /* Calculate the EOB taking into account any terminating CRLF from the
        previous line of the email or the CRLF of the DATA command when there
        previous line of the email or the CRLF of the DATA command when there
        is "no mail data". RFC-5321, sect. 4.1.1.4.
        is "no mail data". RFC-5321, sect. 4.1.1.4.
@@ -1299,7 +1283,7 @@ static CURLcode smtp_perform(struct connectdata *conn, bool *connected,
   smtp->rcpt = data->set.mail_rcpt;
   smtp->rcpt = data->set.mail_rcpt;
 
 
   /* Start the first command in the DO phase */
   /* Start the first command in the DO phase */
-  if(data->set.upload && data->set.mail_rcpt)
+  if((data->set.upload || data->set.mimepost.kind) && data->set.mail_rcpt)
     /* MAIL transfer */
     /* MAIL transfer */
     result = smtp_perform_mail(conn);
     result = smtp_perform_mail(conn);
   else
   else
@@ -1451,30 +1435,6 @@ static CURLcode smtp_setup_connection(struct connectdata *conn)
   /* Clear the TLS upgraded flag */
   /* Clear the TLS upgraded flag */
   conn->tls_upgraded = FALSE;
   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 */
-#ifndef CURL_DISABLE_HTTP
-    if(conn->handler == &Curl_handler_smtp)
-      conn->handler = &Curl_handler_smtp_proxy;
-    else {
-#ifdef USE_SSL
-      conn->handler = &Curl_handler_smtps_proxy;
-#else
-      failf(data, "SMTPS not supported!");
-      return CURLE_UNSUPPORTED_PROTOCOL;
-#endif
-    }
-    /* set it up as a HTTP connection instead */
-    return conn->handler->setup_connection(conn);
-
-#else
-    failf(data, "SMTP over http proxy requires HTTP support built-in!");
-    return CURLE_UNSUPPORTED_PROTOCOL;
-#endif
-  }
-
   /* Initialise the SMTP layer */
   /* Initialise the SMTP layer */
   result = smtp_init(conn);
   result = smtp_init(conn);
   if(result)
   if(result)

+ 49 - 39
Utilities/cmcurl/lib/socks.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -105,7 +105,7 @@ int Curl_blockread_all(struct connectdata *conn, /* connection data */
 *   Set protocol4a=true for  "SOCKS 4A (Simple Extension to SOCKS 4 Protocol)"
 *   Set protocol4a=true for  "SOCKS 4A (Simple Extension to SOCKS 4 Protocol)"
 *   Nonsupport "Identification Protocol (RFC1413)"
 *   Nonsupport "Identification Protocol (RFC1413)"
 */
 */
-CURLcode Curl_SOCKS4(const char *proxy_name,
+CURLcode Curl_SOCKS4(const char *proxy_user,
                      const char *hostname,
                      const char *hostname,
                      int remote_port,
                      int remote_port,
                      int sockindex,
                      int sockindex,
@@ -154,7 +154,7 @@ CURLcode Curl_SOCKS4(const char *proxy_name,
   /* DNS resolve only for SOCKS4, not SOCKS4a */
   /* DNS resolve only for SOCKS4, not SOCKS4a */
   if(!protocol4a) {
   if(!protocol4a) {
     struct Curl_dns_entry *dns;
     struct Curl_dns_entry *dns;
-    Curl_addrinfo *hp=NULL;
+    Curl_addrinfo *hp = NULL;
     int rc;
     int rc;
 
 
     rc = Curl_resolv(conn, hostname, remote_port, &dns);
     rc = Curl_resolv(conn, hostname, remote_port, &dns);
@@ -171,7 +171,7 @@ CURLcode Curl_SOCKS4(const char *proxy_name,
      * returns a Curl_addrinfo pointer that may not always look the same.
      * returns a Curl_addrinfo pointer that may not always look the same.
      */
      */
     if(dns)
     if(dns)
-      hp=dns->addr;
+      hp = dns->addr;
     if(hp) {
     if(hp) {
       char buf[64];
       char buf[64];
       Curl_printable_address(hp, buf, sizeof(buf));
       Curl_printable_address(hp, buf, sizeof(buf));
@@ -206,14 +206,14 @@ CURLcode Curl_SOCKS4(const char *proxy_name,
    * This is currently not supporting "Identification Protocol (RFC1413)".
    * This is currently not supporting "Identification Protocol (RFC1413)".
    */
    */
   socksreq[8] = 0; /* ensure empty userid is NUL-terminated */
   socksreq[8] = 0; /* ensure empty userid is NUL-terminated */
-  if(proxy_name) {
-    size_t plen = strlen(proxy_name);
+  if(proxy_user) {
+    size_t plen = strlen(proxy_user);
     if(plen >= sizeof(socksreq) - 8) {
     if(plen >= sizeof(socksreq) - 8) {
       failf(data, "Too long SOCKS proxy name, can't use!\n");
       failf(data, "Too long SOCKS proxy name, can't use!\n");
       return CURLE_COULDNT_CONNECT;
       return CURLE_COULDNT_CONNECT;
     }
     }
     /* copy the proxy name WITH trailing zero */
     /* copy the proxy name WITH trailing zero */
-    memcpy(socksreq + 8, proxy_name, plen+1);
+    memcpy(socksreq + 8, proxy_user, plen + 1);
   }
   }
 
 
   /*
   /*
@@ -306,7 +306,7 @@ CURLcode Curl_SOCKS4(const char *proxy_name,
             ", request rejected or failed.",
             ", request rejected or failed.",
             (unsigned char)socksreq[4], (unsigned char)socksreq[5],
             (unsigned char)socksreq[4], (unsigned char)socksreq[5],
             (unsigned char)socksreq[6], (unsigned char)socksreq[7],
             (unsigned char)socksreq[6], (unsigned char)socksreq[7],
-            (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]),
+            (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
             (unsigned char)socksreq[1]);
             (unsigned char)socksreq[1]);
       return CURLE_COULDNT_CONNECT;
       return CURLE_COULDNT_CONNECT;
     case 92:
     case 92:
@@ -316,7 +316,7 @@ CURLcode Curl_SOCKS4(const char *proxy_name,
             "identd on the client.",
             "identd on the client.",
             (unsigned char)socksreq[4], (unsigned char)socksreq[5],
             (unsigned char)socksreq[4], (unsigned char)socksreq[5],
             (unsigned char)socksreq[6], (unsigned char)socksreq[7],
             (unsigned char)socksreq[6], (unsigned char)socksreq[7],
-            (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]),
+            (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
             (unsigned char)socksreq[1]);
             (unsigned char)socksreq[1]);
       return CURLE_COULDNT_CONNECT;
       return CURLE_COULDNT_CONNECT;
     case 93:
     case 93:
@@ -326,7 +326,7 @@ CURLcode Curl_SOCKS4(const char *proxy_name,
             "report different user-ids.",
             "report different user-ids.",
             (unsigned char)socksreq[4], (unsigned char)socksreq[5],
             (unsigned char)socksreq[4], (unsigned char)socksreq[5],
             (unsigned char)socksreq[6], (unsigned char)socksreq[7],
             (unsigned char)socksreq[6], (unsigned char)socksreq[7],
-            (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]),
+            (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
             (unsigned char)socksreq[1]);
             (unsigned char)socksreq[1]);
       return CURLE_COULDNT_CONNECT;
       return CURLE_COULDNT_CONNECT;
     default:
     default:
@@ -335,7 +335,7 @@ CURLcode Curl_SOCKS4(const char *proxy_name,
             ", Unknown.",
             ", Unknown.",
             (unsigned char)socksreq[4], (unsigned char)socksreq[5],
             (unsigned char)socksreq[4], (unsigned char)socksreq[5],
             (unsigned char)socksreq[6], (unsigned char)socksreq[7],
             (unsigned char)socksreq[6], (unsigned char)socksreq[7],
-            (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]),
+            (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
             (unsigned char)socksreq[1]);
             (unsigned char)socksreq[1]);
       return CURLE_COULDNT_CONNECT;
       return CURLE_COULDNT_CONNECT;
     }
     }
@@ -350,7 +350,7 @@ CURLcode Curl_SOCKS4(const char *proxy_name,
  * This function logs in to a SOCKS5 proxy and sends the specifics to the final
  * This function logs in to a SOCKS5 proxy and sends the specifics to the final
  * destination server.
  * destination server.
  */
  */
-CURLcode Curl_SOCKS5(const char *proxy_name,
+CURLcode Curl_SOCKS5(const char *proxy_user,
                      const char *proxy_password,
                      const char *proxy_password,
                      const char *hostname,
                      const char *hostname,
                      int remote_port,
                      int remote_port,
@@ -375,6 +375,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name,
   */
   */
 
 
   unsigned char socksreq[600]; /* room for large user/pw (255 max each) */
   unsigned char socksreq[600]; /* room for large user/pw (255 max each) */
+  int idx;
   ssize_t actualread;
   ssize_t actualread;
   ssize_t written;
   ssize_t written;
   int result;
   int result;
@@ -386,6 +387,8 @@ CURLcode Curl_SOCKS5(const char *proxy_name,
     (conn->socks_proxy.proxytype == CURLPROXY_SOCKS5) ? TRUE : FALSE;
     (conn->socks_proxy.proxytype == CURLPROXY_SOCKS5) ? TRUE : FALSE;
   const size_t hostname_len = strlen(hostname);
   const size_t hostname_len = strlen(hostname);
   ssize_t len = 0;
   ssize_t len = 0;
+  const unsigned long auth = data->set.socks5auth;
+  bool allow_gssapi = FALSE;
 
 
   if(conn->bits.httpproxy)
   if(conn->bits.httpproxy)
     infof(conn->data, "SOCKS5: connecting to HTTP proxy %s port %d\n",
     infof(conn->data, "SOCKS5: connecting to HTTP proxy %s port %d\n",
@@ -426,18 +429,29 @@ CURLcode Curl_SOCKS5(const char *proxy_name,
     return CURLE_COULDNT_CONNECT;
     return CURLE_COULDNT_CONNECT;
   }
   }
 
 
-  socksreq[0] = 5; /* version */
+  if(auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI))
+    infof(conn->data,
+        "warning: unsupported value passed to CURLOPT_SOCKS5_AUTH: %lu\n",
+        auth);
+  if(!(auth & CURLAUTH_BASIC))
+    /* disable username/password auth */
+    proxy_user = NULL;
 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
-  socksreq[1] = (char)(proxy_name ? 3 : 2); /* number of methods (below) */
-  socksreq[2] = 0; /* no authentication */
-  socksreq[3] = 1; /* GSS-API */
-  socksreq[4] = 2; /* username/password */
-#else
-  socksreq[1] = (char)(proxy_name ? 2 : 1); /* number of methods (below) */
-  socksreq[2] = 0; /* no authentication */
-  socksreq[3] = 2; /* username/password */
+  if(auth & CURLAUTH_GSSAPI)
+    allow_gssapi = TRUE;
 #endif
 #endif
 
 
+  idx = 0;
+  socksreq[idx++] = 5;   /* version */
+  idx++;                 /* reserve for the number of authentication methods */
+  socksreq[idx++] = 0;   /* no authentication */
+  if(allow_gssapi)
+    socksreq[idx++] = 1; /* GSS-API */
+  if(proxy_user)
+    socksreq[idx++] = 2; /* username/password */
+  /* write the number of authentication methods */
+  socksreq[1] = (unsigned char) (idx - 2);
+
   (void)curlx_nonblock(sock, FALSE);
   (void)curlx_nonblock(sock, FALSE);
 
 
   infof(data, "SOCKS5 communication to %s:%d\n", hostname, remote_port);
   infof(data, "SOCKS5 communication to %s:%d\n", hostname, remote_port);
@@ -469,7 +483,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name,
 
 
   (void)curlx_nonblock(sock, FALSE);
   (void)curlx_nonblock(sock, FALSE);
 
 
-  result=Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread);
+  result = Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread);
   if(result || (actualread != 2)) {
   if(result || (actualread != 2)) {
     failf(data, "Unable to receive initial SOCKS5 response.");
     failf(data, "Unable to receive initial SOCKS5 response.");
     return CURLE_COULDNT_CONNECT;
     return CURLE_COULDNT_CONNECT;
@@ -484,7 +498,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name,
     ;
     ;
   }
   }
 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
-  else if(socksreq[1] == 1) {
+  else if(allow_gssapi && (socksreq[1] == 1)) {
     code = Curl_SOCKS5_gssapi_negotiate(sockindex, conn);
     code = Curl_SOCKS5_gssapi_negotiate(sockindex, conn);
     if(code) {
     if(code) {
       failf(data, "Unable to negotiate SOCKS5 GSS-API context.");
       failf(data, "Unable to negotiate SOCKS5 GSS-API context.");
@@ -494,13 +508,13 @@ CURLcode Curl_SOCKS5(const char *proxy_name,
 #endif
 #endif
   else if(socksreq[1] == 2) {
   else if(socksreq[1] == 2) {
     /* Needs user name and password */
     /* Needs user name and password */
-    size_t proxy_name_len, proxy_password_len;
-    if(proxy_name && proxy_password) {
-      proxy_name_len = strlen(proxy_name);
+    size_t proxy_user_len, proxy_password_len;
+    if(proxy_user && proxy_password) {
+      proxy_user_len = strlen(proxy_user);
       proxy_password_len = strlen(proxy_password);
       proxy_password_len = strlen(proxy_password);
     }
     }
     else {
     else {
-      proxy_name_len = 0;
+      proxy_user_len = 0;
       proxy_password_len = 0;
       proxy_password_len = 0;
     }
     }
 
 
@@ -513,10 +527,10 @@ CURLcode Curl_SOCKS5(const char *proxy_name,
      */
      */
     len = 0;
     len = 0;
     socksreq[len++] = 1;    /* username/pw subnegotiation version */
     socksreq[len++] = 1;    /* username/pw subnegotiation version */
-    socksreq[len++] = (unsigned char) proxy_name_len;
-    if(proxy_name && proxy_name_len)
-      memcpy(socksreq + len, proxy_name, proxy_name_len);
-    len += proxy_name_len;
+    socksreq[len++] = (unsigned char) proxy_user_len;
+    if(proxy_user && proxy_user_len)
+      memcpy(socksreq + len, proxy_user, proxy_user_len);
+    len += proxy_user_len;
     socksreq[len++] = (unsigned char) proxy_password_len;
     socksreq[len++] = (unsigned char) proxy_password_len;
     if(proxy_password && proxy_password_len)
     if(proxy_password && proxy_password_len)
       memcpy(socksreq + len, proxy_password, proxy_password_len);
       memcpy(socksreq + len, proxy_password, proxy_password_len);
@@ -528,7 +542,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name,
       return CURLE_COULDNT_CONNECT;
       return CURLE_COULDNT_CONNECT;
     }
     }
 
 
-    result=Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread);
+    result = Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread);
     if(result || (actualread != 2)) {
     if(result || (actualread != 2)) {
       failf(data, "Unable to receive SOCKS5 sub-negotiation response.");
       failf(data, "Unable to receive SOCKS5 sub-negotiation response.");
       return CURLE_COULDNT_CONNECT;
       return CURLE_COULDNT_CONNECT;
@@ -545,17 +559,13 @@ CURLcode Curl_SOCKS5(const char *proxy_name,
   }
   }
   else {
   else {
     /* error */
     /* error */
-#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
-    if(socksreq[1] == 255) {
-#else
-    if(socksreq[1] == 1) {
+    if(!allow_gssapi && (socksreq[1] == 1)) {
       failf(data,
       failf(data,
             "SOCKS5 GSSAPI per-message authentication is not supported.");
             "SOCKS5 GSSAPI per-message authentication is not supported.");
       return CURLE_COULDNT_CONNECT;
       return CURLE_COULDNT_CONNECT;
     }
     }
     if(socksreq[1] == 255) {
     if(socksreq[1] == 255) {
-#endif
-      if(!proxy_name || !*proxy_name) {
+      if(!proxy_user || !*proxy_user) {
         failf(data,
         failf(data,
               "No authentication method was acceptable. (It is quite likely"
               "No authentication method was acceptable. (It is quite likely"
               " that the SOCKS5 server wanted a username/password, since none"
               " that the SOCKS5 server wanted a username/password, since none"
@@ -605,7 +615,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name,
      * returns a Curl_addrinfo pointer that may not always look the same.
      * returns a Curl_addrinfo pointer that may not always look the same.
      */
      */
     if(dns)
     if(dns)
-      hp=dns->addr;
+      hp = dns->addr;
     if(hp) {
     if(hp) {
       int i;
       int i;
       char buf[64];
       char buf[64];

+ 30 - 29
Utilities/cmcurl/lib/socks_gssapi.c

@@ -5,8 +5,8 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 2009, 2011, Markus Moeller, <[email protected]>
- * Copyright (C) 2012 - 2016, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2009, Markus Moeller, <[email protected]>
+ * Copyright (C) 2012 - 2017, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -65,7 +65,7 @@ static int check_gss_err(struct Curl_easy *data,
                                     &msg_ctx, &status_string);
                                     &msg_ctx, &status_string);
       if(maj_stat == GSS_S_COMPLETE) {
       if(maj_stat == GSS_S_COMPLETE) {
         if(sizeof(buf) > len + status_string.length + 1) {
         if(sizeof(buf) > len + status_string.length + 1) {
-          strcpy(buf+len, (char *) status_string.value);
+          strcpy(buf + len, (char *) status_string.value);
           len += status_string.length;
           len += status_string.length;
         }
         }
         gss_release_buffer(&min_stat, &status_string);
         gss_release_buffer(&min_stat, &status_string);
@@ -74,7 +74,7 @@ static int check_gss_err(struct Curl_easy *data,
       gss_release_buffer(&min_stat, &status_string);
       gss_release_buffer(&min_stat, &status_string);
     }
     }
     if(sizeof(buf) > len + 3) {
     if(sizeof(buf) > len + 3) {
-      strcpy(buf+len, ".\n");
+      strcpy(buf + len, ".\n");
       len += 2;
       len += 2;
     }
     }
     msg_ctx = 0;
     msg_ctx = 0;
@@ -86,7 +86,7 @@ static int check_gss_err(struct Curl_easy *data,
                                     &msg_ctx, &status_string);
                                     &msg_ctx, &status_string);
       if(maj_stat == GSS_S_COMPLETE) {
       if(maj_stat == GSS_S_COMPLETE) {
         if(sizeof(buf) > len + status_string.length)
         if(sizeof(buf) > len + status_string.length)
-          strcpy(buf+len, (char *) status_string.value);
+          strcpy(buf + len, (char *) status_string.value);
         gss_release_buffer(&min_stat, &status_string);
         gss_release_buffer(&min_stat, &status_string);
         break;
         break;
       }
       }
@@ -119,7 +119,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
   gss_name_t       server = GSS_C_NO_NAME;
   gss_name_t       server = GSS_C_NO_NAME;
   gss_name_t       gss_client_name = GSS_C_NO_NAME;
   gss_name_t       gss_client_name = GSS_C_NO_NAME;
   unsigned short   us_length;
   unsigned short   us_length;
-  char             *user=NULL;
+  char             *user = NULL;
   unsigned char socksreq[4]; /* room for GSS-API exchange header only */
   unsigned char socksreq[4]; /* room for GSS-API exchange header only */
   const char *serviceptr = data->set.str[STRING_PROXY_SERVICE_NAME] ?
   const char *serviceptr = data->set.str[STRING_PROXY_SERVICE_NAME] ?
                            data->set.str[STRING_PROXY_SERVICE_NAME] : "rcmd";
                            data->set.str[STRING_PROXY_SERVICE_NAME] : "rcmd";
@@ -146,11 +146,12 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
   }
   }
   else {
   else {
     service.value = malloc(serviceptr_length +
     service.value = malloc(serviceptr_length +
-                           strlen(conn->socks_proxy.host.name)+2);
+                           strlen(conn->socks_proxy.host.name) + 2);
     if(!service.value)
     if(!service.value)
       return CURLE_OUT_OF_MEMORY;
       return CURLE_OUT_OF_MEMORY;
-    service.length = serviceptr_length + strlen(conn->socks_proxy.host.name)+1;
-    snprintf(service.value, service.length+1, "%s@%s",
+    service.length = serviceptr_length +
+      strlen(conn->socks_proxy.host.name) + 1;
+    snprintf(service.value, service.length + 1, "%s@%s",
              serviceptr, conn->socks_proxy.host.name);
              serviceptr, conn->socks_proxy.host.name);
 
 
     gss_major_status = gss_import_name(&gss_minor_status, &service,
     gss_major_status = gss_import_name(&gss_minor_status, &service,
@@ -196,7 +197,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
       socksreq[0] = 1;    /* GSS-API subnegotiation version */
       socksreq[0] = 1;    /* GSS-API subnegotiation version */
       socksreq[1] = 1;    /* authentication message type */
       socksreq[1] = 1;    /* authentication message type */
       us_length = htons((short)gss_send_token.length);
       us_length = htons((short)gss_send_token.length);
-      memcpy(socksreq+2, &us_length, sizeof(short));
+      memcpy(socksreq + 2, &us_length, sizeof(short));
 
 
       code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
       code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
       if(code || (4 != written)) {
       if(code || (4 != written)) {
@@ -236,7 +237,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
      * +----+------+-----+----------------+
      * +----+------+-----+----------------+
      */
      */
 
 
-    result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread);
+    result = Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread);
     if(result || (actualread != 4)) {
     if(result || (actualread != 4)) {
       failf(data, "Failed to receive GSS-API authentication response.");
       failf(data, "Failed to receive GSS-API authentication response.");
       gss_release_name(&gss_status, &server);
       gss_release_name(&gss_status, &server);
@@ -261,11 +262,11 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
       return CURLE_COULDNT_CONNECT;
       return CURLE_COULDNT_CONNECT;
     }
     }
 
 
-    memcpy(&us_length, socksreq+2, sizeof(short));
+    memcpy(&us_length, socksreq + 2, sizeof(short));
     us_length = ntohs(us_length);
     us_length = ntohs(us_length);
 
 
-    gss_recv_token.length=us_length;
-    gss_recv_token.value=malloc(us_length);
+    gss_recv_token.length = us_length;
+    gss_recv_token.value = malloc(us_length);
     if(!gss_recv_token.value) {
     if(!gss_recv_token.value) {
       failf(data,
       failf(data,
             "Could not allocate memory for GSS-API authentication "
             "Could not allocate memory for GSS-API authentication "
@@ -275,8 +276,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
       return CURLE_OUT_OF_MEMORY;
       return CURLE_OUT_OF_MEMORY;
     }
     }
 
 
-    result=Curl_blockread_all(conn, sock, (char *)gss_recv_token.value,
-                              gss_recv_token.length, &actualread);
+    result = Curl_blockread_all(conn, sock, (char *)gss_recv_token.value,
+                                gss_recv_token.length, &actualread);
 
 
     if(result || (actualread != us_length)) {
     if(result || (actualread != us_length)) {
       failf(data, "Failed to receive GSS-API authentication token.");
       failf(data, "Failed to receive GSS-API authentication token.");
@@ -312,7 +313,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
     failf(data, "Failed to determine user name.");
     failf(data, "Failed to determine user name.");
     return CURLE_COULDNT_CONNECT;
     return CURLE_COULDNT_CONNECT;
   }
   }
-  user=malloc(gss_send_token.length+1);
+  user = malloc(gss_send_token.length + 1);
   if(!user) {
   if(!user) {
     gss_delete_sec_context(&gss_status, &gss_context, NULL);
     gss_delete_sec_context(&gss_status, &gss_context, NULL);
     gss_release_name(&gss_status, &gss_client_name);
     gss_release_name(&gss_status, &gss_client_name);
@@ -326,7 +327,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
   gss_release_buffer(&gss_status, &gss_send_token);
   gss_release_buffer(&gss_status, &gss_send_token);
   infof(data, "SOCKS5 server authencticated user %s with GSS-API.\n",user);
   infof(data, "SOCKS5 server authencticated user %s with GSS-API.\n",user);
   free(user);
   free(user);
-  user=NULL;
+  user = NULL;
 
 
   /* Do encryption */
   /* Do encryption */
   socksreq[0] = 1;    /* GSS-API subnegotiation version */
   socksreq[0] = 1;    /* GSS-API subnegotiation version */
@@ -341,7 +342,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
     gss_enc = 1;
     gss_enc = 1;
 
 
   infof(data, "SOCKS5 server supports GSS-API %s data protection.\n",
   infof(data, "SOCKS5 server supports GSS-API %s data protection.\n",
-        (gss_enc==0)?"no":((gss_enc==1)?"integrity":"confidentiality"));
+        (gss_enc == 0)?"no":((gss_enc==1)?"integrity":"confidentiality"));
   /* force for the moment to no data protection */
   /* force for the moment to no data protection */
   gss_enc = 0;
   gss_enc = 0;
   /*
   /*
@@ -376,7 +377,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
    */
    */
   if(data->set.socks5_gssapi_nec) {
   if(data->set.socks5_gssapi_nec) {
     us_length = htons((short)1);
     us_length = htons((short)1);
-    memcpy(socksreq+2, &us_length, sizeof(short));
+    memcpy(socksreq + 2, &us_length, sizeof(short));
   }
   }
   else {
   else {
     gss_send_token.length = 1;
     gss_send_token.length = 1;
@@ -401,7 +402,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
     gss_release_buffer(&gss_status, &gss_send_token);
     gss_release_buffer(&gss_status, &gss_send_token);
 
 
     us_length = htons((short)gss_w_token.length);
     us_length = htons((short)gss_w_token.length);
-    memcpy(socksreq+2, &us_length, sizeof(short));
+    memcpy(socksreq + 2, &us_length, sizeof(short));
   }
   }
 
 
   code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
   code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
@@ -433,7 +434,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
     gss_release_buffer(&gss_status, &gss_w_token);
     gss_release_buffer(&gss_status, &gss_w_token);
   }
   }
 
 
-  result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread);
+  result = Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread);
   if(result || (actualread != 4)) {
   if(result || (actualread != 4)) {
     failf(data, "Failed to receive GSS-API encryption response.");
     failf(data, "Failed to receive GSS-API encryption response.");
     gss_delete_sec_context(&gss_status, &gss_context, NULL);
     gss_delete_sec_context(&gss_status, &gss_context, NULL);
@@ -455,17 +456,17 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
     return CURLE_COULDNT_CONNECT;
     return CURLE_COULDNT_CONNECT;
   }
   }
 
 
-  memcpy(&us_length, socksreq+2, sizeof(short));
+  memcpy(&us_length, socksreq + 2, sizeof(short));
   us_length = ntohs(us_length);
   us_length = ntohs(us_length);
 
 
-  gss_recv_token.length= us_length;
-  gss_recv_token.value=malloc(gss_recv_token.length);
+  gss_recv_token.length = us_length;
+  gss_recv_token.value = malloc(gss_recv_token.length);
   if(!gss_recv_token.value) {
   if(!gss_recv_token.value) {
     gss_delete_sec_context(&gss_status, &gss_context, NULL);
     gss_delete_sec_context(&gss_status, &gss_context, NULL);
     return CURLE_OUT_OF_MEMORY;
     return CURLE_OUT_OF_MEMORY;
   }
   }
-  result=Curl_blockread_all(conn, sock, (char *)gss_recv_token.value,
-                            gss_recv_token.length, &actualread);
+  result = Curl_blockread_all(conn, sock, (char *)gss_recv_token.value,
+                              gss_recv_token.length, &actualread);
 
 
   if(result || (actualread != us_length)) {
   if(result || (actualread != us_length)) {
     failf(data, "Failed to receive GSS-API encryptrion type.");
     failf(data, "Failed to receive GSS-API encryptrion type.");
@@ -513,8 +514,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
   }
   }
 
 
   infof(data, "SOCKS5 access with%s protection granted.\n",
   infof(data, "SOCKS5 access with%s protection granted.\n",
-        (socksreq[0]==0)?"out GSS-API data":
-        ((socksreq[0]==1)?" GSS-API integrity":" GSS-API confidentiality"));
+        (socksreq[0] == 0)?"out GSS-API data":
+        ((socksreq[0] == 1)?" GSS-API integrity":" GSS-API confidentiality"));
 
 
   conn->socks5_gssapi_enctype = socksreq[0];
   conn->socks5_gssapi_enctype = socksreq[0];
   if(socksreq[0] == 0)
   if(socksreq[0] == 0)

+ 12 - 12
Utilities/cmcurl/lib/socks_sspi.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 2012 - 2016, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2012 - 2017, Daniel Stenberg, <[email protected]>, et al.
  * Copyright (C) 2009, 2011, Markus Moeller, <[email protected]>
  * Copyright (C) 2009, 2011, Markus Moeller, <[email protected]>
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
@@ -108,7 +108,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
     if(!service_name)
     if(!service_name)
       return CURLE_OUT_OF_MEMORY;
       return CURLE_OUT_OF_MEMORY;
     snprintf(service_name, service_length +
     snprintf(service_name, service_length +
-             strlen(conn->socks_proxy.host.name)+2, "%s/%s",
+             strlen(conn->socks_proxy.host.name) + 2, "%s/%s",
              service, conn->socks_proxy.host.name);
              service, conn->socks_proxy.host.name);
   }
   }
 
 
@@ -199,7 +199,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
       socksreq[0] = 1;    /* GSS-API subnegotiation version */
       socksreq[0] = 1;    /* GSS-API subnegotiation version */
       socksreq[1] = 1;    /* authentication message type */
       socksreq[1] = 1;    /* authentication message type */
       us_length = htons((short)sspi_send_token.cbBuffer);
       us_length = htons((short)sspi_send_token.cbBuffer);
-      memcpy(socksreq+2, &us_length, sizeof(short));
+      memcpy(socksreq + 2, &us_length, sizeof(short));
 
 
       code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
       code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
       if(code || (4 != written)) {
       if(code || (4 != written)) {
@@ -283,7 +283,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
       return CURLE_COULDNT_CONNECT;
       return CURLE_COULDNT_CONNECT;
     }
     }
 
 
-    memcpy(&us_length, socksreq+2, sizeof(short));
+    memcpy(&us_length, socksreq + 2, sizeof(short));
     us_length = ntohs(us_length);
     us_length = ntohs(us_length);
 
 
     sspi_recv_token.cbBuffer = us_length;
     sspi_recv_token.cbBuffer = us_length;
@@ -341,7 +341,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
     gss_enc = 1;
     gss_enc = 1;
 
 
   infof(data, "SOCKS5 server supports GSS-API %s data protection.\n",
   infof(data, "SOCKS5 server supports GSS-API %s data protection.\n",
-        (gss_enc==0)?"no":((gss_enc==1)?"integrity":"confidentiality") );
+        (gss_enc == 0)?"no":((gss_enc == 1)?"integrity":"confidentiality") );
   /* force to no data protection, avoid encryption/decryption for now */
   /* force to no data protection, avoid encryption/decryption for now */
   gss_enc = 0;
   gss_enc = 0;
   /*
   /*
@@ -377,7 +377,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
 
 
   if(data->set.socks5_gssapi_nec) {
   if(data->set.socks5_gssapi_nec) {
     us_length = htons((short)1);
     us_length = htons((short)1);
-    memcpy(socksreq+2, &us_length, sizeof(short));
+    memcpy(socksreq + 2, &us_length, sizeof(short));
   }
   }
   else {
   else {
     status = s_pSecFn->QueryContextAttributes(&sspi_context,
     status = s_pSecFn->QueryContextAttributes(&sspi_context,
@@ -445,8 +445,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
     memcpy((PUCHAR) sspi_send_token.pvBuffer +(int)sspi_w_token[0].cbBuffer,
     memcpy((PUCHAR) sspi_send_token.pvBuffer +(int)sspi_w_token[0].cbBuffer,
            sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer);
            sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer);
     memcpy((PUCHAR) sspi_send_token.pvBuffer
     memcpy((PUCHAR) sspi_send_token.pvBuffer
-           +sspi_w_token[0].cbBuffer
-           +sspi_w_token[1].cbBuffer,
+           + sspi_w_token[0].cbBuffer
+           + sspi_w_token[1].cbBuffer,
            sspi_w_token[2].pvBuffer, sspi_w_token[2].cbBuffer);
            sspi_w_token[2].pvBuffer, sspi_w_token[2].cbBuffer);
 
 
     s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
     s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
@@ -460,7 +460,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
     sspi_w_token[2].cbBuffer = 0;
     sspi_w_token[2].cbBuffer = 0;
 
 
     us_length = htons((short)sspi_send_token.cbBuffer);
     us_length = htons((short)sspi_send_token.cbBuffer);
-    memcpy(socksreq+2, &us_length, sizeof(short));
+    memcpy(socksreq + 2, &us_length, sizeof(short));
   }
   }
 
 
   code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
   code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
@@ -517,7 +517,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
     return CURLE_COULDNT_CONNECT;
     return CURLE_COULDNT_CONNECT;
   }
   }
 
 
-  memcpy(&us_length, socksreq+2, sizeof(short));
+  memcpy(&us_length, socksreq + 2, sizeof(short));
   us_length = ntohs(us_length);
   us_length = ntohs(us_length);
 
 
   sspi_w_token[0].cbBuffer = us_length;
   sspi_w_token[0].cbBuffer = us_length;
@@ -588,8 +588,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
   }
   }
 
 
   infof(data, "SOCKS5 access with%s protection granted.\n",
   infof(data, "SOCKS5 access with%s protection granted.\n",
-        (socksreq[0]==0)?"out GSS-API data":
-        ((socksreq[0]==1)?" GSS-API integrity":" GSS-API confidentiality"));
+        (socksreq[0] == 0)?"out GSS-API data":
+        ((socksreq[0] == 1)?" GSS-API integrity":" GSS-API confidentiality"));
 
 
   /* For later use if encryption is required
   /* For later use if encryption is required
      conn->socks5_gssapi_enctype = socksreq[0];
      conn->socks5_gssapi_enctype = socksreq[0];

+ 2 - 2
Utilities/cmcurl/lib/speedcheck.c

@@ -30,14 +30,14 @@
 
 
 void Curl_speedinit(struct Curl_easy *data)
 void Curl_speedinit(struct Curl_easy *data)
 {
 {
-  memset(&data->state.keeps_speed, 0, sizeof(struct timeval));
+  memset(&data->state.keeps_speed, 0, sizeof(struct curltime));
 }
 }
 
 
 /*
 /*
  * @unittest: 1606
  * @unittest: 1606
  */
  */
 CURLcode Curl_speedcheck(struct Curl_easy *data,
 CURLcode Curl_speedcheck(struct Curl_easy *data,
-                         struct timeval now)
+                         struct curltime now)
 {
 {
   if((data->progress.current_speed >= 0) && data->set.low_speed_time) {
   if((data->progress.current_speed >= 0) && data->set.low_speed_time) {
     if(data->progress.current_speed < data->set.low_speed_limit) {
     if(data->progress.current_speed < data->set.low_speed_limit) {

+ 2 - 2
Utilities/cmcurl/lib/speedcheck.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2010, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -28,6 +28,6 @@
 
 
 void Curl_speedinit(struct Curl_easy *data);
 void Curl_speedinit(struct Curl_easy *data);
 CURLcode Curl_speedcheck(struct Curl_easy *data,
 CURLcode Curl_speedcheck(struct Curl_easy *data,
-                         struct timeval now);
+                         struct curltime now);
 
 
 #endif /* HEADER_CURL_SPEEDCHECK_H */
 #endif /* HEADER_CURL_SPEEDCHECK_H */

+ 15 - 11
Utilities/cmcurl/lib/splay.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1997 - 2015, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1997 - 2017, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -37,7 +37,7 @@
  * Splay using the key i (which may or may not be in the tree.) The starting
  * Splay using the key i (which may or may not be in the tree.) The starting
  * root is t.
  * root is t.
  */
  */
-struct Curl_tree *Curl_splay(struct timeval i,
+struct Curl_tree *Curl_splay(struct curltime i,
                              struct Curl_tree *t)
                              struct Curl_tree *t)
 {
 {
   struct Curl_tree N, *l, *r, *y;
   struct Curl_tree N, *l, *r, *y;
@@ -97,24 +97,26 @@ struct Curl_tree *Curl_splay(struct timeval i,
  *
  *
  * @unittest: 1309
  * @unittest: 1309
  */
  */
-struct Curl_tree *Curl_splayinsert(struct timeval i,
+struct Curl_tree *Curl_splayinsert(struct curltime i,
                                    struct Curl_tree *t,
                                    struct Curl_tree *t,
                                    struct Curl_tree *node)
                                    struct Curl_tree *node)
 {
 {
-  static const struct timeval KEY_NOTUSED = {-1, -1}; /* will *NEVER* appear */
+  static const struct curltime KEY_NOTUSED = {
+    (time_t)-1, (unsigned int)-1
+  }; /* will *NEVER* appear */
 
 
   if(node == NULL)
   if(node == NULL)
     return t;
     return t;
 
 
   if(t != NULL) {
   if(t != NULL) {
     t = Curl_splay(i, t);
     t = Curl_splay(i, t);
-    if(compare(i, t->key)==0) {
+    if(compare(i, t->key) == 0) {
       /* There already exists a node in the tree with the very same key. Build
       /* There already exists a node in the tree with the very same key. Build
          a doubly-linked circular list of nodes. We add the new 'node' struct
          a doubly-linked circular list of nodes. We add the new 'node' struct
          to the end of this list. */
          to the end of this list. */
 
 
       node->key = KEY_NOTUSED; /* we set the key in the sub node to NOTUSED
       node->key = KEY_NOTUSED; /* we set the key in the sub node to NOTUSED
-                               to quickly identify this node as a subnode */
+                                  to quickly identify this node as a subnode */
       node->samen = t;
       node->samen = t;
       node->samep = t->samep;
       node->samep = t->samep;
       t->samep->samen = node;
       t->samep->samen = node;
@@ -149,11 +151,11 @@ struct Curl_tree *Curl_splayinsert(struct timeval i,
 /* Finds and deletes the best-fit node from the tree. Return a pointer to the
 /* Finds and deletes the best-fit node from the tree. Return a pointer to the
    resulting tree.  best-fit means the smallest node if it is not larger than
    resulting tree.  best-fit means the smallest node if it is not larger than
    the key */
    the key */
-struct Curl_tree *Curl_splaygetbest(struct timeval i,
-                                       struct Curl_tree *t,
-                                       struct Curl_tree **removed)
+struct Curl_tree *Curl_splaygetbest(struct curltime i,
+                                    struct Curl_tree *t,
+                                    struct Curl_tree **removed)
 {
 {
-  static struct timeval tv_zero = {0, 0};
+  static struct curltime tv_zero = {0, 0};
   struct Curl_tree *x;
   struct Curl_tree *x;
 
 
   if(!t) {
   if(!t) {
@@ -209,7 +211,9 @@ int Curl_splayremovebyaddr(struct Curl_tree *t,
                            struct Curl_tree *removenode,
                            struct Curl_tree *removenode,
                            struct Curl_tree **newroot)
                            struct Curl_tree **newroot)
 {
 {
-  static const struct timeval KEY_NOTUSED = {-1, -1}; /* will *NEVER* appear */
+  static const struct curltime KEY_NOTUSED = {
+    (time_t)-1, (unsigned int)-1
+  }; /* will *NEVER* appear */
   struct Curl_tree *x;
   struct Curl_tree *x;
 
 
   if(!t || !removenode)
   if(!t || !removenode)

+ 9 - 8
Utilities/cmcurl/lib/splay.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1997 - 2016, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1997 - 2017, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -22,30 +22,31 @@
  *
  *
  ***************************************************************************/
  ***************************************************************************/
 #include "curl_setup.h"
 #include "curl_setup.h"
+#include "timeval.h"
 
 
 struct Curl_tree {
 struct Curl_tree {
   struct Curl_tree *smaller; /* smaller node */
   struct Curl_tree *smaller; /* smaller node */
   struct Curl_tree *larger;  /* larger node */
   struct Curl_tree *larger;  /* larger node */
   struct Curl_tree *samen;   /* points to the next node with identical key */
   struct Curl_tree *samen;   /* points to the next node with identical key */
   struct Curl_tree *samep;   /* points to the prev node with identical key */
   struct Curl_tree *samep;   /* points to the prev node with identical key */
-  struct timeval key;        /* this node's "sort" key */
+  struct curltime key;        /* this node's "sort" key */
   void *payload;             /* data the splay code doesn't care about */
   void *payload;             /* data the splay code doesn't care about */
 };
 };
 
 
-struct Curl_tree *Curl_splay(struct timeval i,
+struct Curl_tree *Curl_splay(struct curltime i,
                              struct Curl_tree *t);
                              struct Curl_tree *t);
 
 
-struct Curl_tree *Curl_splayinsert(struct timeval key,
+struct Curl_tree *Curl_splayinsert(struct curltime key,
                                    struct Curl_tree *t,
                                    struct Curl_tree *t,
                                    struct Curl_tree *newnode);
                                    struct Curl_tree *newnode);
 
 
 #if 0
 #if 0
-struct Curl_tree *Curl_splayremove(struct timeval key,
+struct Curl_tree *Curl_splayremove(struct curltime key,
                                    struct Curl_tree *t,
                                    struct Curl_tree *t,
                                    struct Curl_tree **removed);
                                    struct Curl_tree **removed);
 #endif
 #endif
 
 
-struct Curl_tree *Curl_splaygetbest(struct timeval key,
+struct Curl_tree *Curl_splaygetbest(struct curltime key,
                                     struct Curl_tree *t,
                                     struct Curl_tree *t,
                                     struct Curl_tree **removed);
                                     struct Curl_tree **removed);
 
 
@@ -53,8 +54,8 @@ int Curl_splayremovebyaddr(struct Curl_tree *t,
                            struct Curl_tree *removenode,
                            struct Curl_tree *removenode,
                            struct Curl_tree **newroot);
                            struct Curl_tree **newroot);
 
 
-#define Curl_splaycomparekeys(i,j) ( ((i.tv_sec)  < (j.tv_sec))  ? -1 : \
-                                   ( ((i.tv_sec)  > (j.tv_sec))  ?  1 : \
+#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 : \
                                    ( ((i.tv_usec) > (j.tv_usec)) ?  1 : 0))))
                                    ( ((i.tv_usec) > (j.tv_usec)) ?  1 : 0))))
 
 

部分文件因为文件数量过多而无法显示