Browse Source

Merge branch 'upstream-curl' into update-curl

* upstream-curl:
  curl 2017-10-04 (3ea76790)
Brad King 8 years ago
parent
commit
9e3ef40edb
100 changed files with 4663 additions and 3405 deletions
  1. 29 0
      Utilities/cmcurl/CMake/Macros.cmake
  2. 6 6
      Utilities/cmcurl/CMake/OtherTests.cmake
  3. 26 0
      Utilities/cmcurl/CMake/cmake_uninstall.cmake.in
  4. 103 82
      Utilities/cmcurl/CMakeLists.txt
  5. 217 30
      Utilities/cmcurl/include/curl/curl.h
  6. 0 218
      Utilities/cmcurl/include/curl/curlbuild.h.cmake
  7. 0 239
      Utilities/cmcurl/include/curl/curlrules.h
  8. 4 4
      Utilities/cmcurl/include/curl/curlver.h
  9. 1 1
      Utilities/cmcurl/include/curl/multi.h
  10. 301 314
      Utilities/cmcurl/include/curl/system.h
  11. 18 3
      Utilities/cmcurl/include/curl/typecheck-gcc.h
  12. 8 3
      Utilities/cmcurl/lib/CMakeLists.txt
  13. 3 2
      Utilities/cmcurl/lib/Makefile.inc
  14. 4 4
      Utilities/cmcurl/lib/asyn-ares.c
  15. 33 22
      Utilities/cmcurl/lib/asyn-thread.c
  16. 1 1
      Utilities/cmcurl/lib/conncache.h
  17. 37 45
      Utilities/cmcurl/lib/connect.c
  18. 2 2
      Utilities/cmcurl/lib/connect.h
  19. 3 3
      Utilities/cmcurl/lib/content_encoding.c
  20. 88 58
      Utilities/cmcurl/lib/cookie.c
  21. 7 4
      Utilities/cmcurl/lib/cookie.h
  22. 3 3
      Utilities/cmcurl/lib/curl_addrinfo.c
  23. 3 9
      Utilities/cmcurl/lib/curl_config.h.cmake
  24. 6 6
      Utilities/cmcurl/lib/curl_fnmatch.c
  25. 58 34
      Utilities/cmcurl/lib/curl_ntlm_core.c
  26. 10 4
      Utilities/cmcurl/lib/curl_ntlm_core.h
  27. 10 16
      Utilities/cmcurl/lib/curl_ntlm_wb.c
  28. 7 1
      Utilities/cmcurl/lib/curl_rtmp.c
  29. 4 2
      Utilities/cmcurl/lib/curl_sasl.c
  30. 23 19
      Utilities/cmcurl/lib/curl_setup.h
  31. 0 14
      Utilities/cmcurl/lib/curl_setup_once.h
  32. 11 4
      Utilities/cmcurl/lib/curl_threads.c
  33. 8 7
      Utilities/cmcurl/lib/dict.c
  34. 15 15
      Utilities/cmcurl/lib/dotdot.c
  35. 14 12
      Utilities/cmcurl/lib/easy.c
  36. 13 13
      Utilities/cmcurl/lib/escape.c
  37. 24 18
      Utilities/cmcurl/lib/file.c
  38. 146 741
      Utilities/cmcurl/lib/formdata.c
  39. 3 51
      Utilities/cmcurl/lib/formdata.h
  40. 107 171
      Utilities/cmcurl/lib/ftp.c
  41. 3 1
      Utilities/cmcurl/lib/ftp.h
  42. 15 23
      Utilities/cmcurl/lib/ftplistparser.c
  43. 53 34
      Utilities/cmcurl/lib/getinfo.c
  44. 6 5
      Utilities/cmcurl/lib/gopher.c
  45. 2 2
      Utilities/cmcurl/lib/hash.c
  46. 7 7
      Utilities/cmcurl/lib/hostcheck.c
  47. 6 6
      Utilities/cmcurl/lib/hostip.c
  48. 2 2
      Utilities/cmcurl/lib/hostip4.c
  49. 2 2
      Utilities/cmcurl/lib/hostip6.c
  50. 240 204
      Utilities/cmcurl/lib/http.c
  51. 10 7
      Utilities/cmcurl/lib/http.h
  52. 58 7
      Utilities/cmcurl/lib/http2.c
  53. 4 3
      Utilities/cmcurl/lib/http2.h
  54. 12 14
      Utilities/cmcurl/lib/http_chunks.c
  55. 8 5
      Utilities/cmcurl/lib/http_ntlm.c
  56. 154 124
      Utilities/cmcurl/lib/http_proxy.c
  57. 10 0
      Utilities/cmcurl/lib/http_proxy.h
  58. 9 7
      Utilities/cmcurl/lib/if2ip.c
  59. 3 2
      Utilities/cmcurl/lib/if2ip.h
  60. 78 117
      Utilities/cmcurl/lib/imap.c
  61. 2 1
      Utilities/cmcurl/lib/imap.h
  62. 7 7
      Utilities/cmcurl/lib/inet_ntop.c
  63. 3 3
      Utilities/cmcurl/lib/inet_pton.c
  64. 4 1
      Utilities/cmcurl/lib/inet_pton.h
  65. 1 1
      Utilities/cmcurl/lib/krb5.c
  66. 5 4
      Utilities/cmcurl/lib/ldap.c
  67. 12 11
      Utilities/cmcurl/lib/memdebug.c
  68. 1860 0
      Utilities/cmcurl/lib/mime.c
  69. 135 0
      Utilities/cmcurl/lib/mime.h
  70. 17 21
      Utilities/cmcurl/lib/mprintf.c
  71. 75 64
      Utilities/cmcurl/lib/multi.c
  72. 1 1
      Utilities/cmcurl/lib/multihandle.h
  73. 24 20
      Utilities/cmcurl/lib/netrc.c
  74. 44 60
      Utilities/cmcurl/lib/non-ascii.c
  75. 1 3
      Utilities/cmcurl/lib/non-ascii.h
  76. 8 6
      Utilities/cmcurl/lib/openldap.c
  77. 37 37
      Utilities/cmcurl/lib/parsedate.c
  78. 14 14
      Utilities/cmcurl/lib/pingpong.c
  79. 1 1
      Utilities/cmcurl/lib/pingpong.h
  80. 15 22
      Utilities/cmcurl/lib/pipeline.c
  81. 2 77
      Utilities/cmcurl/lib/pop3.c
  82. 71 61
      Utilities/cmcurl/lib/progress.c
  83. 4 4
      Utilities/cmcurl/lib/progress.h
  84. 1 1
      Utilities/cmcurl/lib/rand.c
  85. 39 4
      Utilities/cmcurl/lib/rtsp.c
  86. 0 2
      Utilities/cmcurl/lib/rtsp.h
  87. 2 2
      Utilities/cmcurl/lib/security.c
  88. 5 5
      Utilities/cmcurl/lib/select.c
  89. 3 2
      Utilities/cmcurl/lib/select.h
  90. 10 10
      Utilities/cmcurl/lib/sendf.c
  91. 27 4
      Utilities/cmcurl/lib/smb.c
  92. 39 79
      Utilities/cmcurl/lib/smtp.c
  93. 49 39
      Utilities/cmcurl/lib/socks.c
  94. 30 29
      Utilities/cmcurl/lib/socks_gssapi.c
  95. 12 12
      Utilities/cmcurl/lib/socks_sspi.c
  96. 2 2
      Utilities/cmcurl/lib/speedcheck.c
  97. 2 2
      Utilities/cmcurl/lib/speedcheck.h
  98. 15 11
      Utilities/cmcurl/lib/splay.c
  99. 9 8
      Utilities/cmcurl/lib/splay.h
  100. 37 21
      Utilities/cmcurl/lib/ssh.c

+ 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()
 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(NOT DEFINED curl_cv_func_recv_args OR "${curl_cv_func_recv_args}" STREQUAL "unknown")
     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")
               if(NOT curl_cv_func_recv_done)
                 unset(curl_cv_func_recv_test CACHE)
@@ -96,9 +96,9 @@ int main(void) {
 if(curl_cv_send)
   if(NOT DEFINED curl_cv_func_send_args OR "${curl_cv_func_send_args}" STREQUAL "unknown")
     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")
               if(NOT curl_cv_func_send_done)
                 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)

+ 103 - 82
Utilities/cmcurl/CMakeLists.txt

@@ -88,7 +88,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
 # you should have received as part of this distribution. The terms
@@ -126,6 +126,7 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake;${CMAKE_MODULE_PATH}")
 include(Utilities)
 include(Macros)
 include(CMakeDependentOption)
+include(CheckCCompilerFlag)
 
 project( CURL C )
 
@@ -159,20 +160,36 @@ set(OS "\"${CMAKE_SYSTEM_NAME}\"")
 include_directories(${PROJECT_BINARY_DIR}/include/curl)
 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(CURL_STATICLIB "Set to ON to build libcurl with static linking." OFF)
 option(ENABLE_ARES "Set to ON to enable c-ares support" OFF)
 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()
+
+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_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)
   # DEBUGBUILD will be defined only for Debug builds
   if(NOT CMAKE_VERSION VERSION_LESS 3.0)
@@ -187,13 +204,12 @@ if (ENABLE_CURLDEBUG)
   set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS CURLDEBUG)
 endif()
 
+# For debug libs and exes, add "-d" postfix
+set(CMAKE_DEBUG_POSTFIX "-d" CACHE STRING "Set debug library postfix")
+
 # initialize CURL_LIBS
 set(CURL_LIBS "")
 
-if(ENABLE_THREADED_RESOLVER AND ENABLE_ARES)
-  message(FATAL_ERROR "Options ENABLE_THREADED_RESOLVER and ENABLE_ARES are mutually exclusive")
-endif()
-
 if(ENABLE_ARES)
   set(USE_ARES 1)
   find_package(CARES REQUIRED)
@@ -201,11 +217,6 @@ if(ENABLE_ARES)
   set(CURL_LIBS ${CURL_LIBS} ${CARES_LIBRARY})
 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.
 include(CurlSymbolHiding)
 endif()
@@ -265,8 +276,6 @@ option(CURL_DISABLE_CRYPTO_AUTH "to disable cryptographic authentication" OFF)
 mark_as_advanced(CURL_DISABLE_CRYPTO_AUTH)
 option(CURL_DISABLE_VERBOSE_STRINGS "to disable verbose strings" OFF)
 mark_as_advanced(CURL_DISABLE_VERBOSE_STRINGS)
-option(DISABLED_THREADSAFE "Set to explicitly specify we don't want to use thread-safe functions" OFF)
-mark_as_advanced(DISABLED_THREADSAFE)
 option(ENABLE_IPV6 "Define if you want to enable IPv6 support" ON)
 mark_as_advanced(ENABLE_IPV6)
 if(ENABLE_IPV6 AND NOT WIN32)
@@ -283,51 +292,48 @@ if(ENABLE_IPV6 AND NOT WIN32)
   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.
+CURL_NROFF_CHECK()
 # 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()
 
 # We need ansi c-flags, especially on HP
 set(CMAKE_C_FLAGS "${CMAKE_ANSI_CFLAGS} ${CMAKE_C_FLAGS}")
 set(CMAKE_REQUIRED_FLAGS ${CMAKE_ANSI_CFLAGS})
 
+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.
 if(BORLAND)
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w-")
 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(${CMAKE_SYSTEM_NAME} MATCHES AIX)
   set(_ALL_SOURCE 1)
@@ -349,19 +355,14 @@ if(WIN32)
 endif(WIN32)
 
 if(ENABLE_THREADED_RESOLVER)
+  find_package(Threads REQUIRED)
   if(WIN32)
     set(USE_THREADS_WIN32 ON)
   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()
+  set(CURL_LIBS ${CURL_LIBS} ${CMAKE_THREAD_LIBS_INIT})
 endif()
 
 # Check for all needed libraries
@@ -911,11 +912,6 @@ check_type_size("int"  SIZEOF_INT)
 check_type_size("__int64"  SIZEOF___INT64)
 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)
   set(HAVE_LONGLONG 1)
   set(HAVE_LL 1)
@@ -1003,7 +999,18 @@ check_symbol_exists(ioctl          "${CURL_INCLUDES}" HAVE_IOCTL)
 check_symbol_exists(setsockopt     "${CURL_INCLUDES}" HAVE_SETSOCKOPT)
 
 # symbol exists in win32, but function does not.
-check_function_exists(inet_pton HAVE_INET_PTON)
+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)
 if(HAVE_FSETXATTR)
@@ -1075,6 +1082,13 @@ if(HAVE_FILE_OFFSET_BITS)
   set(CMAKE_REQUIRED_FLAGS "-D_FILE_OFFSET_BITS=64")
 endif(HAVE_FILE_OFFSET_BITS)
 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)
 
 foreach(CURL_TEST
@@ -1190,7 +1204,7 @@ else()
   set(CURL_HAVE_SOCKLEN_T 0)
 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)
   set(CURL_PULL_WS2TCPIP_H ${HAVE_WS2TCPIP_H})
 else()
@@ -1205,11 +1219,6 @@ include(CMake/OtherTests.cmake)
 
 add_definitions(-DHAVE_CONFIG_H)
 
-# For windows, do not allow the compiler to use default target (Vista).
-if(WIN32)
-  add_definitions(-D_WIN32_WINNT=0x0501)
-endif(WIN32)
-
 # For windows, all compilers used by cmake should support large files
 if(WIN32)
   set(USE_WIN32_LARGE_FILES ON)
@@ -1217,6 +1226,11 @@ endif(WIN32)
 
 if(MSVC)
   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)
 
 # Ugly (but functional) way to include "Makefile.inc" by transforming it (= regenerate it).
@@ -1235,10 +1249,12 @@ function(TRANSFORM_MAKEFILE_INC INPUT_FILE OUTPUT_FILE)
 
 endfunction()
 
-if(0) # This code not needed for building within CMake.
-add_subdirectory(docs)
+if(USE_MANUAL)
+  add_subdirectory(docs)
 endif()
+
 add_subdirectory(lib)
+
 if(BUILD_CURL_EXE)
   add_subdirectory(src)
 endif()
@@ -1355,7 +1371,7 @@ set(LDFLAGS                 "${CMAKE_SHARED_LINKER_FLAGS}")
 set(LIBCURL_LIBS            "")
 set(libdir                  "${CMAKE_INSTALL_PREFIX}/lib")
 foreach(_lib ${CMAKE_C_IMPLICIT_LINK_LIBRARIES} ${CURL_LIBS})
-  if(_lib MATCHES ".*/.*")
+  if(_lib MATCHES ".*/.*" OR _lib MATCHES "^-")
     set(LIBCURL_LIBS          "${LIBCURL_LIBS} ${_lib}")
   else()
     set(LIBCURL_LIBS          "${LIBCURL_LIBS} -l${_lib}")
@@ -1391,16 +1407,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")
 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"
     DESTINATION include
-    FILES_MATCHING PATTERN "*.h"
-    PATTERN "curlbuild.h" EXCLUDE)
-
+    FILES_MATCHING PATTERN "*.h")
 
 # Workaround for MSVS10 to avoid the Dialog Hell
 # FIXME: This could be removed with future version of CMake.
@@ -1410,4 +1420,15 @@ if(MSVC_VERSION EQUAL 1600)
     file(APPEND "${CURL_SLN_FILENAME}" "\n# This should be regenerated!\n")
   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()

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

@@ -36,8 +36,6 @@
 
 #include "curlver.h"         /* libcurl version defines   */
 #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
@@ -76,6 +74,7 @@
 #if defined(_AIX) || defined(__NOVELL_LIBC__) || defined(__NetBSD__) || \
     defined(__minix) || defined(__SYMBIAN32__) || defined(__INTEGRITY) || \
     defined(ANDROID) || defined(__ANDROID__) || defined(__OpenBSD__) || \
+    defined(__CYGWIN__) || \
    (defined(__FreeBSD_version) && (__FreeBSD_version < 800000))
 #include <sys/select.h>
 #endif
@@ -134,6 +133,27 @@ typedef int curl_socket_t;
 #define 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 *next;       /* next entry in the list */
   char *name;                       /* pointer to allocated name */
@@ -337,7 +357,7 @@ typedef size_t (*curl_read_callback)(char *buffer,
                                       size_t nitems,
                                       void *instream);
 
-typedef enum  {
+typedef enum {
   CURLSOCKTYPE_IPCXN,  /* socket created for a specific IP connection */
   CURLSOCKTYPE_ACCEPT, /* socket created by accept() call */
   CURLSOCKTYPE_LAST    /* never use */
@@ -379,7 +399,7 @@ typedef enum {
   CURLIOE_LAST           /* never use */
 } curlioerr;
 
-typedef enum  {
+typedef enum {
   CURLIOCMD_NOP,         /* no operation */
   CURLIOCMD_RESTARTREAD, /* restart the read stream from start */
   CURLIOCMD_LAST         /* never use */
@@ -679,6 +699,8 @@ typedef enum {
 #define CURLAUTH_NEGOTIATE    (((unsigned long)1)<<2)
 /* Deprecated since the advent of 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_DIGEST_IE    (((unsigned long)1)<<4)
 #define CURLAUTH_NTLM_WB      (((unsigned long)1)<<5)
@@ -1782,6 +1804,18 @@ typedef enum {
   /* Suppress proxy CONNECT response headers from user callbacks */
   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 */
 } CURLoption;
 
@@ -1928,15 +1962,140 @@ typedef enum {
   CURL_TIMECOND_LAST
 } 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
-   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> */
 #ifdef CFINIT
 #undef CFINIT
@@ -2178,6 +2337,47 @@ struct curl_slist {
   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()
  *
@@ -2218,27 +2418,6 @@ struct curl_certinfo {
                                    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
    handle, which can be used to obtain further information regarding the
    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_PTR      0x400000 /* same as SLIST */
 #define CURLINFO_SOCKET   0x500000
+#define CURLINFO_OFF_T    0x600000
 #define CURLINFO_MASK     0x0fffff
 #define CURLINFO_TYPEMASK 0xf00000
 
@@ -2265,15 +2445,21 @@ typedef enum {
   CURLINFO_CONNECT_TIME     = CURLINFO_DOUBLE + 5,
   CURLINFO_PRETRANSFER_TIME = CURLINFO_DOUBLE + 6,
   CURLINFO_SIZE_UPLOAD      = CURLINFO_DOUBLE + 7,
+  CURLINFO_SIZE_UPLOAD_T    = CURLINFO_OFF_T  + 7,
   CURLINFO_SIZE_DOWNLOAD    = CURLINFO_DOUBLE + 8,
+  CURLINFO_SIZE_DOWNLOAD_T  = CURLINFO_OFF_T  + 8,
   CURLINFO_SPEED_DOWNLOAD   = CURLINFO_DOUBLE + 9,
+  CURLINFO_SPEED_DOWNLOAD_T = CURLINFO_OFF_T  + 9,
   CURLINFO_SPEED_UPLOAD     = CURLINFO_DOUBLE + 10,
+  CURLINFO_SPEED_UPLOAD_T   = CURLINFO_OFF_T  + 10,
   CURLINFO_HEADER_SIZE      = CURLINFO_LONG   + 11,
   CURLINFO_REQUEST_SIZE     = CURLINFO_LONG   + 12,
   CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG   + 13,
   CURLINFO_FILETIME         = CURLINFO_LONG   + 14,
   CURLINFO_CONTENT_LENGTH_DOWNLOAD   = CURLINFO_DOUBLE + 15,
+  CURLINFO_CONTENT_LENGTH_DOWNLOAD_T = CURLINFO_OFF_T  + 15,
   CURLINFO_CONTENT_LENGTH_UPLOAD     = CURLINFO_DOUBLE + 16,
+  CURLINFO_CONTENT_LENGTH_UPLOAD_T   = CURLINFO_OFF_T  + 16,
   CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17,
   CURLINFO_CONTENT_TYPE     = CURLINFO_STRING + 18,
   CURLINFO_REDIRECT_TIME    = CURLINFO_DOUBLE + 19,
@@ -2471,6 +2657,7 @@ typedef struct {
 #define CURL_VERSION_PSL          (1<<20) /* Mozilla's Public Suffix List, used
                                              for cookie domain verification */
 #define CURL_VERSION_HTTPS_PROXY  (1<<21) /* HTTPS-proxy support built-in */
+#define CURL_VERSION_MULTI_SSL    (1<<22) /* Multiple SSL backends available */
 
  /*
  * 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
    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
    defines: */
 #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
    parsing and comparions by programs. The LIBCURL_VERSION_NUM define will
@@ -57,7 +57,7 @@
    CURL_VERSION_BITS() macro since curl's own configure script greps for it
    and needs it to contain the full number.
 */
-#define LIBCURL_VERSION_NUM 0x073601
+#define LIBCURL_VERSION_NUM 0x073800
 
 /*
  * 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
  * 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,
  * 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__) && (__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
-#    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
-#  define CURLSYS_TYPEOF_CURL_SOCKLEN_T int
-#  define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
+#  define CURL_TYPEOF_CURL_SOCKLEN_T int
 
 #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__)
 #  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
-#    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
-#  define CURLSYS_TYPEOF_CURL_SOCKLEN_T int
-#  define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
+#  define CURL_TYPEOF_CURL_SOCKLEN_T int
 
 #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__)
 #  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
-#    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
-#  define CURLSYS_TYPEOF_CURL_SOCKLEN_T int
-#  define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
+#  define CURL_TYPEOF_CURL_SOCKLEN_T int
 
 #elif defined(__POCC__)
 #  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)
-#    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
-#    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
-#  define CURLSYS_TYPEOF_CURL_SOCKLEN_T int
-#  define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
+#  define CURL_TYPEOF_CURL_SOCKLEN_T int
 
 #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__)
 #  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__)
 #    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__)
-#    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
-#  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__)
-#  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)
-#  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__)
-#  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)
 #  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
-#    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
-#  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__)
 #  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
 
 #elif defined(__MVS__)
 #  if defined(__IBMC__) || defined(__IBMCPP__)
 #    if defined(_ILP32)
-#      define CURLSYS_SIZEOF_LONG           4
 #    elif defined(_LP64)
-#      define CURLSYS_SIZEOF_LONG           8
 #    endif
 #    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)
-#      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
-#      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
-#    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
 
 #elif defined(__370__)
 #  if defined(__IBMC__) || defined(__IBMCPP__)
 #    if defined(_ILP32)
-#      define CURLSYS_SIZEOF_LONG           4
 #    elif defined(_LP64)
-#      define CURLSYS_SIZEOF_LONG           8
 #    endif
 #    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)
-#      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
-#      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
-#    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
 
 #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 */
 
-#  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    */
@@ -384,101 +324,148 @@
 
 #elif defined(_MSC_VER)
 #  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
-#    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
-#  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    */
 /* ===================================== */
 
 #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__) || \
-        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
-#  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
 /* 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
 
-/* 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. */
-#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 <windows.h>
 #  include <ws2tcpip.h>
 #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. */
-#ifdef CURLSYS_PULL_SYS_TYPES_H
+#ifdef CURL_PULL_SYS_TYPES_H
 #  include <sys/types.h>
 #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. */
-#ifdef CURLSYS_PULL_SYS_SOCKET_H
+#ifdef CURL_PULL_SYS_SOCKET_H
 #  include <sys/socket.h>
 #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. */
-#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
 
 /* 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 /* __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_is_arr((value), struct curl_httppost))                        \
         _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_arr((value), struct curl_slist))                           \
         _curl_easy_setopt_err_curl_slist();                                   \
@@ -110,7 +113,7 @@ __extension__ ({                                                              \
 /* FIXME: don't allow const pointers */
 #define curl_easy_getinfo(handle, info, arg)                                  \
 __extension__ ({                                                              \
-  __typeof__(info) _curl_info = info;                                        \
+  __typeof__(info) _curl_info = info;                                         \
   if(__builtin_constant_p(_curl_info)) {                                      \
     if(_curl_is_string_info(_curl_info))                                      \
       if(!_curl_is_arr((arg), char *))                                        \
@@ -130,9 +133,12 @@ __extension__ ({                                                              \
     if(_curl_is_certinfo_info(_curl_info))                                    \
       if(!_curl_is_arr((arg), struct 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))                                 \
         _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);                                 \
 })
@@ -197,6 +203,9 @@ _CURL_WARNING(_curl_easy_setopt_err_postfields,
 _CURL_WARNING(_curl_easy_setopt_err_curl_httpost,
               "curl_easy_setopt expects a 'struct curl_httppost *' "
               "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_easy_setopt expects a 'struct curl_slist *' argument for this option")
 _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")
 _CURL_WARNING(_curl_easy_getinfo_err_curl_socket,
   "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 */
 
@@ -391,7 +402,11 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_socket,
 
 /* true if info expects a pointer to struct curl_socket_t argument */
 #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*/

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

@@ -1,7 +1,5 @@
 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
   ${CMAKE_CURRENT_BINARY_DIR}/curl_config.h)
 
@@ -10,11 +8,11 @@ include(${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake)
 
 list(APPEND HHEADERS
   ${CMAKE_CURRENT_BINARY_DIR}/curl_config.h
-  ${CURL_BINARY_DIR}/include/curl/curlbuild.h
   )
 
 if(MSVC AND NOT CURL_STATICLIB)
   list(APPEND CSOURCES libcurl.rc)
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4127")
 endif()
 
 # SET(CSOURCES
@@ -124,6 +122,13 @@ if(WIN32)
   if(NOT CURL_STATICLIB)
     # 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
+       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()
 

+ 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_ntlm.c curl_ntlm_wb.c curl_ntlm_core.c curl_sasl.c rand.c        \
   curl_multibyte.c hostcheck.c conncache.c pipeline.c dotdot.c          \
-  x509asn1.c http2.c smb.c curl_endian.c curl_des.c system_win32.c
+  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 \
   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_setup_once.h multihandle.h setup-vms.h pipeline.h dotdot.h       \
   x509asn1.h http2.h sigpipe.h smb.h curl_endian.h curl_des.h           \
-  curl_printf.h system_win32.h rand.h
+  curl_printf.h system_win32.h rand.h mime.h
 
 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,
                          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].revents = 0;
     if(ARES_GETSOCK_READABLE(bitmask, i)) {
@@ -289,7 +289,7 @@ static int waitperform(struct connectdata *conn, int timeout_ms)
                     ARES_SOCKET_BAD);
   else {
     /* 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,
                       pfd[i].revents & (POLLRDNORM|POLLIN)?
                       pfd[i].fd:ARES_SOCKET_BAD,
@@ -355,7 +355,7 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
   CURLcode result = CURLE_OK;
   struct Curl_easy *data = conn->data;
   long timeout;
-  struct timeval now = Curl_tvnow();
+  struct curltime now = Curl_tvnow();
   struct Curl_dns_entry *temp_entry;
 
   if(entry)
@@ -400,7 +400,7 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
     if(Curl_pgrsUpdate(conn))
       result = CURLE_ABORTED_BY_CALLBACK;
     else {
-      struct timeval now2 = Curl_tvnow();
+      struct curltime now2 = Curl_tvnow();
       time_t timediff = Curl_tvdiff(now2, now); /* spent time */
       if(timediff <= 0)
         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->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
   DEBUGASSERT(hints);
   tsd->hints = *hints;
@@ -380,11 +384,11 @@ static bool init_resolve_thread(struct connectdata *conn,
                                 const struct addrinfo *hints)
 {
   struct thread_data *td = calloc(1, sizeof(struct thread_data));
-  int err = RESOLVER_ENOMEM;
+  int err = ENOMEM;
 
   conn->async.os_specific = (void *)td;
   if(!td)
-    goto err_exit;
+    goto errno_exit;
 
   conn->async.port = port;
   conn->async.done = FALSE;
@@ -392,14 +396,20 @@ static bool init_resolve_thread(struct connectdata *conn,
   conn->async.dns = 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);
   conn->async.hostname = strdup(hostname);
   if(!conn->async.hostname)
     goto err_exit;
 
+  /* The thread will set this to 1 when complete. */
+  td->tsd.done = 0;
+
 #ifdef HAVE_GETADDRINFO
   td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd);
 #else
@@ -407,9 +417,9 @@ static bool init_resolve_thread(struct connectdata *conn,
 #endif
 
   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;
-#endif
     goto err_exit;
   }
 
@@ -418,8 +428,8 @@ static bool init_resolve_thread(struct connectdata *conn,
  err_exit:
   destroy_async_data(&conn->async);
 
-  SET_ERRNO(err);
-
+ errno_exit:
+  errno = err;
   return FALSE;
 }
 
@@ -594,28 +604,29 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
                                          int *waitp)
 {
   struct addrinfo hints;
-  struct in_addr in;
   Curl_addrinfo *res;
   int error;
   char sbuf[12];
   int pf = PF_INET;
-#ifdef CURLRES_IPV6
-  struct in6_addr in6;
-#endif /* CURLRES_IPV6 */
 
   *waitp = 0; /* default to synchronous response */
 
 #ifndef USE_RESOLVE_ON_IPS
-  /* First check if this is an IPv4 address string */
-  if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
-    /* This is a dotted IP address 123.123.123.123-style */
-    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
-  /* 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 /* !USE_RESOLVE_ON_IPS */
 
@@ -654,7 +665,7 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
 
   /* fall-back to blocking version */
   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);
   if(error) {

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

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

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

@@ -180,12 +180,12 @@ singleipconnect(struct connectdata *conn,
  * @unittest: 1303
  */
 time_t Curl_timeleft(struct Curl_easy *data,
-                     struct timeval *nowp,
+                     struct curltime *nowp,
                      bool duringconnect)
 {
   int timeout_set = 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 */
 
@@ -249,7 +249,7 @@ static CURLcode bindlocal(struct connectdata *conn,
   struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
 #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
                                                 "random" */
   /* 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.
            */
           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;
             infof(data, "SO_BINDTODEVICE %s failed with errno %d: %s;"
                   " will do regular bind\n",
@@ -607,7 +607,8 @@ void Curl_persistconninfo(struct connectdata *conn)
   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,
                            long *port)
 {
@@ -654,7 +655,7 @@ static bool getaddressinfo(struct sockaddr *sa, char *addr,
 
   addr[0] = '\0';
   *port = 0;
-
+  errno = EAFNOSUPPORT;
   return FALSE;
 }
 
@@ -672,11 +673,9 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
     return;
 
   if(!conn->bits.reuse && !conn->bits.tcp_fastopen) {
-    int error;
-
     len = sizeof(struct Curl_sockaddr_storage);
     if(getpeername(sockfd, (struct sockaddr*) &ssrem, &len)) {
-      error = SOCKERRNO;
+      int error = SOCKERRNO;
       failf(data, "getpeername() failed with errno %d: %s",
             error, Curl_strerror(conn, error));
       return;
@@ -685,7 +684,7 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
     len = sizeof(struct Curl_sockaddr_storage);
     memset(&ssloc, 0, sizeof(ssloc));
     if(getsockname(sockfd, (struct sockaddr*) &ssloc, &len)) {
-      error = SOCKERRNO;
+      int error = SOCKERRNO;
       failf(data, "getsockname() failed with errno %d: %s",
             error, Curl_strerror(conn, error));
       return;
@@ -693,18 +692,16 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
 
     if(!getaddressinfo((struct sockaddr*)&ssrem,
                         conn->primary_ip, &conn->primary_port)) {
-      error = ERRNO;
       failf(data, "ssrem inet_ntop() failed with errno %d: %s",
-            error, Curl_strerror(conn, error));
+            errno, Curl_strerror(conn, errno));
       return;
     }
     memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN);
 
     if(!getaddressinfo((struct sockaddr*)&ssloc,
                        conn->local_ip, &conn->local_port)) {
-      error = ERRNO;
       failf(data, "ssloc inet_ntop() failed with errno %d: %s",
-            error, Curl_strerror(conn, error));
+            errno, Curl_strerror(conn, errno));
       return;
     }
 
@@ -726,7 +723,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
   CURLcode result = CURLE_OK;
   time_t allow;
   int error = 0;
-  struct timeval now;
+  struct curltime now;
   int rc;
   int i;
 
@@ -751,7 +748,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
     return CURLE_OPERATION_TIMEDOUT;
   }
 
-  for(i=0; i<2; i++) {
+  for(i = 0; i<2; i++) {
     const int other = i ^ 1;
     if(conn->tempsock[i] == CURL_SOCKET_BAD)
       continue;
@@ -879,19 +876,6 @@ void Curl_tcpnodelay(struct connectdata *conn, curl_socket_t sockfd)
   curl_socklen_t onoff = (curl_socklen_t) 1;
   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)
   (void) conn;
 #endif
@@ -916,7 +900,7 @@ void Curl_tcpnodelay(struct connectdata *conn, curl_socket_t sockfd)
 static void nosigpipe(struct connectdata *conn,
                       curl_socket_t sockfd)
 {
-  struct Curl_easy *data= conn->data;
+  struct Curl_easy *data = conn->data;
   int onoff = 1;
   if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
                 sizeof(onoff)) < 0)
@@ -1008,9 +992,8 @@ static CURLcode singleipconnect(struct connectdata *conn,
   if(!getaddressinfo((struct sockaddr*)&addr.sa_addr,
                      ipaddress, &port)) {
     /* malformed address or bug in inet_ntop, try next address */
-    error = ERRNO;
     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);
     return CURLE_OK;
   }
@@ -1076,16 +1059,25 @@ static CURLcode singleipconnect(struct connectdata *conn,
   if(!isconnected && (conn->socktype == SOCK_STREAM)) {
     if(conn->bits.tcp_fastopen) {
 #if defined(CONNECT_DATA_IDEMPOTENT) /* OS X */
-      sa_endpoints_t endpoints;
-      endpoints.sae_srcif = 0;
-      endpoints.sae_srcaddr = NULL;
-      endpoints.sae_srcaddrlen = 0;
-      endpoints.sae_dstaddr = &addr.sa_addr;
-      endpoints.sae_dstaddrlen = addr.addrlen;
-
-      rc = connectx(sockfd, &endpoints, SAE_ASSOCID_ANY,
-                    CONNECT_RESUME_ON_READ_WRITE | CONNECT_DATA_IDEMPOTENT,
-                    NULL, 0, NULL, NULL);
+#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 */
       if(conn->given->flags & PROTOPT_SSL)
         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)
 {
   struct Curl_easy *data = conn->data;
-  struct timeval before = Curl_tvnow();
+  struct curltime before = Curl_tvnow();
   CURLcode result = CURLE_COULDNT_CONNECT;
 
   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->tempsock[0] = 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 */
   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 */
+  Curl_expire(conn->data, HAPPY_EYEBALLS_TIMEOUT, EXPIRE_HAPPY_EYEBALLS);
 
   return CURLE_OK;
 }
@@ -1341,7 +1333,7 @@ CURLcode Curl_socket(struct connectdata *conn,
 
   addr->family = ai->ai_family;
   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;
 
   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
  * 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
    to the timeouts set */
 time_t Curl_timeleft(struct Curl_easy *data,
-                     struct timeval *nowp,
+                     struct curltime *nowp,
                      bool duringconnect);
 
 #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
  * you should have received as part of this distribution. The terms
@@ -227,7 +227,7 @@ static enum {
 
     extra_len = (data[1] << 8) | data[0];
 
-    if(len < (extra_len+2))
+    if(len < (extra_len + 2))
       return GZIP_UNDERFLOW;
 
     len -= (extra_len + 2);
@@ -288,7 +288,7 @@ Curl_unencode_gzip_write(struct connectdata *conn,
 
     if(strcmp(zlibVersion(), "1.2.0.4") >= 0) {
       /* zlib ver. >= 1.2.0.4 supports transparent gzip decompressing */
-      if(inflateInit2(z, MAX_WBITS+32) != Z_OK) {
+      if(inflateInit2(z, MAX_WBITS + 32) != Z_OK) {
         return process_zlib_error(conn, z);
       }
       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)
     return FALSE;
 
-  if(!strcasecompare(cooke_domain, hostname+hostname_len-cookie_domain_len))
+  if(!strcasecompare(cooke_domain, hostname + hostname_len-cookie_domain_len))
     return FALSE;
 
   /* A lead char of cookie_domain is not '.'.
@@ -375,9 +375,8 @@ Curl_cookie_add(struct Curl_easy *data,
                                        unless set */
 {
   struct Cookie *clist;
-  char name[MAX_NAME];
   struct Cookie *co;
-  struct Cookie *lastc=NULL;
+  struct Cookie *lastc = NULL;
   time_t now = time(NULL);
   bool replace_old = FALSE;
   bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */
@@ -397,17 +396,19 @@ Curl_cookie_add(struct Curl_easy *data,
 
   if(httpheader) {
     /* This line was read off a HTTP-header */
+    char name[MAX_NAME];
+    char what[MAX_NAME];
     const char *ptr;
     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);
       return NULL;
     }
 
-    semiptr=strchr(lineptr, ';'); /* first, find a semicolon */
+    semiptr = strchr(lineptr, ';'); /* first, find a semicolon */
 
     while(*lineptr && ISBLANK(*lineptr))
       lineptr++;
@@ -415,9 +416,9 @@ Curl_cookie_add(struct Curl_easy *data,
     ptr = lineptr;
     do {
       /* 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=] =%"
-                     MAX_COOKIE_LINE_TXT "[^;\r\n]",
+                     MAX_NAME_TXT "[^;\r\n]",
                      name, what)) {
         /* Use strstore() below to properly deal with received cookie
            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;
         bool done = FALSE;
         bool sep;
-        size_t len=strlen(what);
+        size_t len = strlen(what);
         size_t nlen = strlen(name);
         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 '=' ? */
         sep = (*endofn == '=')?TRUE:FALSE;
 
@@ -440,18 +455,18 @@ Curl_cookie_add(struct Curl_easy *data,
               endofn--;
               nlen--;
             }
-            name[nlen]=0; /* new end of name */
+            name[nlen] = 0; /* new end of name */
           }
         }
 
         /* Strip off trailing whitespace from the 'what' */
         while(len && ISBLANK(what[len-1])) {
-          what[len-1]=0;
+          what[len-1] = 0;
           len--;
         }
 
         /* Skip leading whitespace from the 'what' */
-        whatptr=what;
+        whatptr = what;
         while(*whatptr && ISBLANK(*whatptr))
           whatptr++;
 
@@ -484,6 +499,7 @@ Curl_cookie_add(struct Curl_easy *data,
             badcookie = TRUE; /* out of memory bad */
             break;
           }
+          free(co->spath); /* if this is set again */
           co->spath = sanitize_cookie_path(co->path);
           if(!co->spath) {
             badcookie = TRUE; /* out of memory bad */
@@ -510,7 +526,7 @@ Curl_cookie_add(struct Curl_easy *data,
             /* check for more dots */
             dotp = strchr(whatptr, '.');
             if(!dotp && !strcasecompare("localhost", whatptr))
-              domain=":";
+              domain = ":";
           }
 #endif
 
@@ -525,14 +541,14 @@ Curl_cookie_add(struct Curl_easy *data,
               break;
             }
             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 {
             /* we did not get a tailmatch and then the attempted set domain
                is not a domain to which the current host belongs. Mark as
                bad. */
-            badcookie=TRUE;
+            badcookie = TRUE;
             infof(data, "skipped cookie with bad tailmatch domain: %s\n",
                   whatptr);
           }
@@ -581,26 +597,32 @@ Curl_cookie_add(struct Curl_easy *data,
         continue;
       }
 
-      ptr=semiptr+1;
+      ptr = semiptr + 1;
       while(*ptr && ISBLANK(*ptr))
         ptr++;
-      semiptr=strchr(ptr, ';'); /* now, find the next semicolon */
+      semiptr = strchr(ptr, ';'); /* now, find the next semicolon */
 
       if(!semiptr && *ptr)
         /* There are no more semicolons, but there's a final name=value pair
            coming up */
-        semiptr=strchr(ptr, '\0');
+        semiptr = strchr(ptr, '\0');
     } while(semiptr);
 
     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;
-      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) {
       /* 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(domain) {
         /* no domain was given in the header line, set the default */
-        co->domain=strdup(domain);
+        co->domain = strdup(domain);
         if(!co->domain)
           badcookie = TRUE;
       }
@@ -639,11 +661,11 @@ Curl_cookie_add(struct Curl_easy *data,
       else
         endslash = memrchr(path, '/', (size_t)(queryp - path));
       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) {
           memcpy(co->path, path, pathlen);
-          co->path[pathlen]=0; /* zero terminate */
+          co->path[pathlen] = 0; /* zero terminate */
           co->spath = sanitize_cookie_path(co->path);
           if(!co->spath)
             badcookie = TRUE; /* out of memory bad */
@@ -653,8 +675,6 @@ Curl_cookie_add(struct Curl_easy *data,
       }
     }
 
-    free(what);
-
     if(badcookie || !co->name) {
       /* we didn't get a cookie name or a bad one,
          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 */
     char *ptr;
     char *firstptr;
-    char *tok_buf=NULL;
+    char *tok_buf = NULL;
     int fields;
 
     /* IE introduced HTTP-only cookies to prevent XSS attacks. Cookies
@@ -689,19 +709,19 @@ Curl_cookie_add(struct Curl_easy *data,
       return NULL;
     }
     /* strip off the possible end-of-line characters */
-    ptr=strchr(lineptr, '\r');
+    ptr = strchr(lineptr, '\r');
     if(ptr)
-      *ptr=0; /* clear it */
-    ptr=strchr(lineptr, '\n');
+      *ptr = 0; /* clear it */
+    ptr = strchr(lineptr, '\n');
     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
        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) {
       case 0:
         if(ptr[0]=='.') /* skip preceding dots */
@@ -712,7 +732,7 @@ Curl_cookie_add(struct Curl_easy *data,
         break;
       case 1:
         /* 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
            domain can access the variable. This value is set automatically by
@@ -726,7 +746,7 @@ Curl_cookie_add(struct Curl_easy *data,
       case 2:
         /* It turns out, that sometimes the file format allows the path
            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)) {
           /* only if the path doesn't look like a boolean option! */
           co->path = strdup(ptr);
@@ -753,7 +773,8 @@ Curl_cookie_add(struct Curl_easy *data,
         co->secure = strcasecompare(ptr, "TRUE")?TRUE:FALSE;
         break;
       case 4:
-        co->expires = curlx_strtoofft(ptr, NULL, 10);
+        if(curlx_strtoofft(ptr, NULL, 10, &co->expires))
+          badcookie = TRUE;
         break;
       case 5:
         co->name = strdup(ptr);
@@ -828,7 +849,7 @@ Curl_cookie_add(struct Curl_easy *data,
         if(strcasecompare(clist->domain, co->domain) &&
           (clist->tailmatch == co->tailmatch))
           /* The domains are identical */
-          replace_old=TRUE;
+          replace_old = TRUE;
       }
       else if(!clist->domain && !co->domain)
         replace_old = TRUE;
@@ -957,7 +978,7 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
 {
   struct CookieInfo *c;
   FILE *fp = NULL;
-  bool fromfile=TRUE;
+  bool fromfile = TRUE;
   char *line = NULL;
 
   if(NULL == inc) {
@@ -977,7 +998,7 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
 
   if(file && !strcmp(file, "-")) {
     fp = stdin;
-    fromfile=FALSE;
+    fromfile = FALSE;
   }
   else if(file && !*file) {
     /* 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)) {
       if(checkprefix("Set-Cookie:", line)) {
         /* This is a cookie line, get it! */
-        lineptr=&line[11];
-        headerline=TRUE;
+        lineptr = &line[11];
+        headerline = TRUE;
       }
       else {
-        lineptr=line;
-        headerline=FALSE;
+        lineptr = line;
+        headerline = FALSE;
       }
       while(*lineptr && ISBLANK(*lineptr))
         lineptr++;
@@ -1113,7 +1134,7 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
   struct Cookie *newco;
   struct Cookie *co;
   time_t now = time(NULL);
-  struct Cookie *mainco=NULL;
+  struct Cookie *mainco = NULL;
   size_t matches = 0;
   bool is_ip;
 
@@ -1185,7 +1206,7 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
 
     co = mainco;
 
-    for(i=0; co; co = co->next)
+    for(i = 0; co; co = co->next)
       array[i++] = co;
 
     /* 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 */
 
     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 */
 
     free(array); /* remove the temporary data again */
@@ -1335,7 +1356,7 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere)
 {
   struct Cookie *co;
   FILE *out;
-  bool use_stdout=FALSE;
+  bool use_stdout = FALSE;
   char *format_ptr;
 
   if((NULL == c) || (0 == c->numcookies))
@@ -1349,7 +1370,7 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere)
   if(!strcmp("-", dumphere)) {
     /* use stdout */
     out = stdout;
-    use_stdout=TRUE;
+    use_stdout = TRUE;
   }
   else {
     out = fopen(dumphere, FOPEN_WRITETEXT);
@@ -1382,7 +1403,7 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere)
   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 *beg;
@@ -1413,6 +1434,15 @@ struct curl_slist *Curl_cookie_list(struct Curl_easy *data)
   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)
 {
   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
  * 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
    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_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;
 /*

+ 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));
 
-  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;
 #ifdef ENABLE_IPV6
@@ -570,9 +570,9 @@ curl_dogetaddrinfo(const char *hostname,
                    int line, const char *source)
 {
 #ifdef USE_LWIPSOCK
-  int res=lwip_getaddrinfo(hostname, service, hints, result);
+  int res = lwip_getaddrinfo(hostname, service, hints, result);
 #else
-  int res=(getaddrinfo)(hostname, service, hints, result);
+  int res = (getaddrinfo)(hostname, service, hints, result);
 #endif
   if(0 == res)
     /* success */

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

@@ -42,9 +42,6 @@
 /* to disable RTSP */
 #cmakedefine CURL_DISABLE_RTSP 1
 
-/* to disable RTMP */
-#cmakedefine CURL_DISABLE_RTMP 1
-
 /* to disable SMB */
 #cmakedefine CURL_DISABLE_SMB 1
 
@@ -73,9 +70,6 @@
 /* when not building a shared library */
 #cmakedefine CURL_STATICLIB 1
 
-/* Set to explicitly specify we don't want to use thread-safe functions */
-#cmakedefine DISABLED_THREADSAFE 1
-
 /* your Entropy Gathering Daemon socket pathname */
 #cmakedefine EGD_SOCKET ${EGD_SOCKET}
 
@@ -885,6 +879,9 @@
 /* The size of `off_t', as computed by sizeof. */
 @SIZEOF_OFF_T_CODE@
 
+/* The size of `curl_off_t', as computed by sizeof. */
+#cmakedefine SIZEOF_CURL_OFF_T ${SIZEOF_CURL_OFF_T}
+
 /* The size of `size_t', as computed by sizeof. */
 @SIZEOF_SIZE_T_CODE@
 
@@ -960,9 +957,6 @@
 /* Version number of package */
 #cmakedefine VERSION ${VERSION}
 
-/* Define to avoid automatic inclusion of winsock.h */
-#cmakedefine WIN32_LEAN_AND_MEAN 1
-
 /* Define to 1 if OS is AIX. */
 #ifndef _ALL_SOURCE
 #  undef _ALL_SOURCE

+ 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
  * 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)++;
       }
       else if(c == '[') {
-        char c2 = *((*p)+1);
+        char c2 = *((*p) + 1);
         if(c2 == ':') { /* there has to be a keyword */
           (*p) += 2;
           if(parsekeyword(p, charset)) {
@@ -319,9 +319,9 @@ static int loop(const unsigned char *pattern, const unsigned char *string)
     switch(state) {
     case CURLFNM_LOOP_DEFAULT:
       if(*p == '*') {
-        while(*(p+1) == '*') /* eliminate multiple stars */
+        while(*(p + 1) == '*') /* eliminate multiple stars */
           p++;
-        if(*s == '\0' && *(p+1) == '\0')
+        if(*s == '\0' && *(p + 1) == '\0')
           return CURL_FNMATCH_MATCH;
         rc = loop(p + 1, s); /* *.txt matches .txt <=> .txt matches .txt */
         if(rc == CURL_FNMATCH_MATCH)
@@ -351,7 +351,7 @@ static int loop(const unsigned char *pattern, const unsigned char *string)
         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)) {
           int found = FALSE;
           if(charset[(unsigned int)*s])
@@ -381,7 +381,7 @@ static int loop(const unsigned char *pattern, const unsigned char *string)
             found = !found;
 
           if(found) {
-            p = pp+1;
+            p = pp + 1;
             s++;
             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
  * you should have received as part of this distribution. The terms
@@ -31,6 +31,25 @@
  * 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)
 
 #ifdef USE_OPENSSL
@@ -76,14 +95,6 @@
 #  define MD5_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)
 
 #  include <nss.h>
@@ -92,6 +103,14 @@
 #  include "curl_md4.h"
 #  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)
 
 #  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));
 }
 
-#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)
 
 /*
@@ -281,6 +280,26 @@ fail:
   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)
 
 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);
   gcry_cipher_encrypt(des, results + 16, 8, plaintext, 8);
   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)
   encrypt_des(plaintext, results, keys);
   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);
     gcry_cipher_encrypt(des, lmbuffer + 8, 8, magic, 8);
     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)
     encrypt_des(magic, lmbuffer, pw);
     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);
     memcpy(ntbuffer, gcry_md_read(MD4pw, 0), MD4_DIGEST_LENGTH);
     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);
 #elif defined(USE_MBEDTLS)
+#if defined(MBEDTLS_MD4_C)
     mbedtls_md4(pw, 2 * len, ntbuffer);
+#else
+    Curl_md4it(ntbuffer, pw, 2 * len);
+#endif
 #elif defined(USE_DARWINSSL)
     (void)CC_MD4(pw, (CC_LONG)(2 * len), ntbuffer);
+#elif defined(USE_OS400CRYPTO)
+    Curl_md4it(ntbuffer, pw, 2 * len);
 #elif defined(USE_WIN32_CRYPTO)
     HCRYPTPROV hprov;
     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 */
   memcpy(lmresp, hmac_output, 16);
-  memcpy(lmresp+16, challenge_client, 8);
+  memcpy(lmresp + 16, challenge_client, 8);
 
   return result;
 }

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

@@ -26,13 +26,19 @@
 
 #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)
 
 #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
 
 /* 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
  * you should have received as part of this distribution. The terms
@@ -48,6 +48,7 @@
 #include "sendf.h"
 #include "select.h"
 #include "vauth/ntlm.h"
+#include "curl_ntlm_core.h"
 #include "curl_ntlm_wb.h"
 #include "url.h"
 #include "strerror.h"
@@ -123,7 +124,6 @@ static CURLcode ntlm_wb_init(struct connectdata *conn, const char *userp)
   struct passwd pw, *pw_res;
   char pwbuf[1024];
 #endif
-  int error;
 
   /* Return if communication with ntlm_auth already set up */
   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;
 
   if(access(ntlm_auth, X_OK) != 0) {
-    error = ERRNO;
     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;
   }
 
   if(socketpair(AF_UNIX, SOCK_STREAM, 0, sockfds)) {
-    error = ERRNO;
     failf(conn->data, "Could not open socket pair. errno %d: %s",
-          error, Curl_strerror(conn, error));
+          errno, Curl_strerror(conn, errno));
     goto done;
   }
 
   child_pid = fork();
   if(child_pid == -1) {
-    error = ERRNO;
     sclose(sockfds[0]);
     sclose(sockfds[1]);
     failf(conn->data, "Could not fork. errno %d: %s",
-          error, Curl_strerror(conn, error));
+          errno, Curl_strerror(conn, errno));
     goto done;
   }
   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 */
     sclose_nolog(sockfds[0]);
     if(dup2(sockfds[1], STDIN_FILENO) == -1) {
-      error = ERRNO;
       failf(conn->data, "Could not redirect child stdin. errno %d: %s",
-            error, Curl_strerror(conn, error));
+            errno, Curl_strerror(conn, errno));
       exit(1);
     }
 
     if(dup2(sockfds[1], STDOUT_FILENO) == -1) {
-      error = ERRNO;
       failf(conn->data, "Could not redirect child stdout. errno %d: %s",
-            error, Curl_strerror(conn, error));
+            errno, Curl_strerror(conn, errno));
       exit(1);
     }
 
@@ -235,10 +230,9 @@ static CURLcode ntlm_wb_init(struct connectdata *conn, const char *userp)
             "--username", username,
             NULL);
 
-    error = ERRNO;
     sclose_nolog(sockfds[1]);
     failf(conn->data, "Could not execl(). errno %d: %s",
-          error, Curl_strerror(conn, error));
+          errno, Curl_strerror(conn, errno));
     exit(1);
   }
 
@@ -364,7 +358,7 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn,
 
   /* not set means empty */
   if(!userp)
-    userp="";
+    userp = "";
 
   switch(ntlm->state) {
   case NTLMSTATE_TYPE1:
@@ -420,7 +414,7 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn,
     /* connection is already authenticated,
      * don't send a header in future requests */
     free(*allocuserpwd);
-    *allocuserpwd=NULL;
+    *allocuserpwd = NULL;
     authp->done = TRUE;
     break;
   }

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

@@ -74,6 +74,7 @@ const struct Curl_handler Curl_handler_rtmp = {
   ZERO_NULL,                            /* perform_getsock */
   rtmp_disconnect,                      /* disconnect */
   ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
   PORT_RTMP,                            /* defport */
   CURLPROTO_RTMP,                       /* protocol */
   PROTOPT_NONE                          /* flags*/
@@ -94,6 +95,7 @@ const struct Curl_handler Curl_handler_rtmpt = {
   ZERO_NULL,                            /* perform_getsock */
   rtmp_disconnect,                      /* disconnect */
   ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
   PORT_RTMPT,                           /* defport */
   CURLPROTO_RTMPT,                      /* protocol */
   PROTOPT_NONE                          /* flags*/
@@ -114,6 +116,7 @@ const struct Curl_handler Curl_handler_rtmpe = {
   ZERO_NULL,                            /* perform_getsock */
   rtmp_disconnect,                      /* disconnect */
   ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
   PORT_RTMP,                            /* defport */
   CURLPROTO_RTMPE,                      /* protocol */
   PROTOPT_NONE                          /* flags*/
@@ -134,6 +137,7 @@ const struct Curl_handler Curl_handler_rtmpte = {
   ZERO_NULL,                            /* perform_getsock */
   rtmp_disconnect,                      /* disconnect */
   ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
   PORT_RTMPT,                           /* defport */
   CURLPROTO_RTMPTE,                     /* protocol */
   PROTOPT_NONE                          /* flags*/
@@ -154,6 +158,7 @@ const struct Curl_handler Curl_handler_rtmps = {
   ZERO_NULL,                            /* perform_getsock */
   rtmp_disconnect,                      /* disconnect */
   ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
   PORT_RTMPS,                           /* defport */
   CURLPROTO_RTMPS,                      /* protocol */
   PROTOPT_NONE                          /* flags*/
@@ -174,6 +179,7 @@ const struct Curl_handler Curl_handler_rtmpts = {
   ZERO_NULL,                            /* perform_getsock */
   rtmp_disconnect,                      /* disconnect */
   ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
   PORT_RTMPS,                           /* defport */
   CURLPROTO_RTMPTS,                     /* protocol */
   PROTOPT_NONE                          /* flags*/
@@ -200,7 +206,7 @@ static CURLcode rtmp_connect(struct connectdata *conn, bool *done)
   RTMP *r = conn->proto.generic;
   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
    * 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;
 
       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);
       }
     else
@@ -493,7 +494,8 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
 #ifdef USE_NTLM
   case SASL_NTLM:
     /* 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);
     newstate = SASL_NTLM_TYPE2MSG;
     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
  * 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
  */
@@ -31,6 +35,17 @@
 #define WIN32
 #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
  * configuration file for platforms which lack config tool.
@@ -130,14 +145,7 @@
 
 #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.
@@ -174,9 +182,6 @@
 #  ifndef CURL_DISABLE_SMTP
 #    define CURL_DISABLE_SMTP
 #  endif
-#  ifndef CURL_DISABLE_RTMP
-#    define CURL_DISABLE_RTMP
-#  endif
 #  ifndef CURL_DISABLE_GOPHER
 #    define CURL_DISABLE_GOPHER
 #  endif
@@ -195,7 +200,7 @@
 
 /* ================================================================ */
 /* 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)
 #    define UNICODE
 #  endif
-#  ifndef WIN32_LEAN_AND_MEAN
-#    define WIN32_LEAN_AND_MEAN
-#  endif
 #  include <windows.h>
 #  ifdef HAVE_WINSOCK2_H
 #    include <winsock2.h>
@@ -655,9 +657,8 @@ int netware_init(void);
 #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
 
 /*
@@ -731,6 +732,7 @@ Therefore we specify it explicitly. https://github.com/curl/curl/pull/258
 #if defined(WIN32) || defined(MSDOS)
 #define FOPEN_READTEXT "rt"
 #define FOPEN_WRITETEXT "wt"
+#define FOPEN_APPENDTEXT "at"
 #elif defined(__CYGWIN__)
 /* Cygwin has specific behavior we need to address when WIN32 is not defined.
 https://cygwin.com/cygwin-ug-net/using-textbinary.html
@@ -740,9 +742,11 @@ endings either CRLF or LF so 't' is appropriate.
 */
 #define FOPEN_READTEXT "rt"
 #define FOPEN_WRITETEXT "w"
+#define FOPEN_APPENDTEXT "a"
 #else
 #define FOPEN_READTEXT "r"
 #define FOPEN_WRITETEXT "w"
+#define FOPEN_APPENDTEXT "a"
 #endif
 
 /* 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
 
 
-/*
- * 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.
  */

+ 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 *),
                                  void *arg)
 {
+  curl_thread_t t;
 #ifdef _WIN32_WCE
-  return CreateThread(NULL, 0, func, arg, 0, NULL);
+  t = CreateThread(NULL, 0, func, arg, 0, NULL);
 #else
-  curl_thread_t t;
   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 t;
-#endif
 }
 
 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
  * 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,                            /* disconnect */
   ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
   PORT_DICT,                            /* defport */
   CURLPROTO_DICT,                       /* protocol */
   PROTOPT_NONE | PROTOPT_NOURLQUERY      /* flags */
@@ -97,7 +98,7 @@ static char *unescape_word(struct Curl_easy *data, const char *inputbuff)
   char *ptr;
   size_t len;
   char ch;
-  int olen=0;
+  int olen = 0;
 
   CURLcode result = Curl_urldecode(data, inputbuff, 0, &newp, &len, FALSE);
   if(!newp || result)
@@ -116,7 +117,7 @@ static char *unescape_word(struct Curl_easy *data, const char *inputbuff)
       }
       dictp[olen++] = ch;
     }
-    dictp[olen]=0;
+    dictp[olen] = 0;
   }
   free(newp);
   return dictp;
@@ -131,8 +132,8 @@ static CURLcode dict_do(struct connectdata *conn, bool *done)
   char *strategy = NULL;
   char *nthdef = NULL; /* This is not part of the protocol, but required
                           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];
 
   char *path = data->state.path;
@@ -167,7 +168,7 @@ static CURLcode dict_do(struct connectdata *conn, bool *done)
 
     if((word == NULL) || (*word == (char)0)) {
       infof(data, "lookup word is missing\n");
-      word=(char *)"default";
+      word = (char *)"default";
     }
     if((database == NULL) || (*database == (char)0)) {
       database = (char *)"!";
@@ -221,7 +222,7 @@ static CURLcode dict_do(struct connectdata *conn, bool *done)
 
     if((word == NULL) || (*word == (char)0)) {
       infof(data, "lookup word is missing\n");
-      word=(char *)"default";
+      word = (char *)"default";
     }
     if((database == NULL) || (*database == (char)0)) {
       database = (char *)"!";

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

@@ -55,7 +55,7 @@ char *Curl_dedotdotify(const char *input)
   size_t inlen = strlen(input);
   char *clone;
   size_t clen = inlen; /* the length of the cloned input */
-  char *out = malloc(inlen+1);
+  char *out = malloc(inlen + 1);
   char *outptr;
   char *orgclone;
   char *queryp;
@@ -92,25 +92,25 @@ char *Curl_dedotdotify(const char *input)
         remove that prefix from the input buffer; otherwise, */
 
     if(!strncmp("./", clone, 2)) {
-      clone+=2;
-      clen-=2;
+      clone += 2;
+      clen -= 2;
     }
     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
         "."  is a complete path segment, then replace that prefix with "/" in
         the input buffer; otherwise, */
     else if(!strncmp("/./", clone, 3)) {
-      clone+=2;
-      clen-=2;
+      clone += 2;
+      clen -= 2;
     }
     else if(!strcmp("/.", clone)) {
       clone[1]='/';
       clone++;
-      clen-=1;
+      clen -= 1;
     }
 
     /*  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, */
 
     else if(!strncmp("/../", clone, 4)) {
-      clone+=3;
-      clen-=3;
+      clone += 3;
+      clen -= 3;
       /* remove the last segment from the output buffer */
       while(outptr > out) {
         outptr--;
@@ -131,8 +131,8 @@ char *Curl_dedotdotify(const char *input)
     }
     else if(!strcmp("/..", clone)) {
       clone[2]='/';
-      clone+=2;
-      clen-=2;
+      clone += 2;
+      clen -= 2;
       /* remove the last segment from the output buffer */
       while(outptr > out) {
         outptr--;
@@ -146,8 +146,8 @@ char *Curl_dedotdotify(const char *input)
         that from the input buffer; otherwise, */
 
     else if(!strcmp(".", clone) || !strcmp("..", clone)) {
-      *clone=0;
-      *out=0;
+      *clone = 0;
+      *out = 0;
     }
 
     else {
@@ -172,7 +172,7 @@ char *Curl_dedotdotify(const char *input)
        from the correct index. */
     size_t oindex = queryp - orgclone;
     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);

+ 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)
 {
-  int omask=0;
+  int omask = 0;
   if(pollmask & POLLIN)
     omask |= CURL_CSELECT_IN;
   if(pollmask & POLLOUT)
@@ -450,7 +450,7 @@ static int poll2cselect(int pollmask)
  */
 static short socketcb2poll(int pollmask)
 {
-  short omask=0;
+  short omask = 0;
   if(pollmask & CURL_POLL_IN)
     omask |= POLLIN;
   if(pollmask & CURL_POLL_OUT)
@@ -473,7 +473,7 @@ static int events_socket(struct Curl_easy *easy,      /* easy handle */
 {
   struct events *ev = userp;
   struct socketmonitor *m;
-  struct socketmonitor *prev=NULL;
+  struct socketmonitor *prev = NULL;
 
 #if defined(CURL_DISABLE_VERBOSE_STRINGS)
   (void) easy;
@@ -569,14 +569,14 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
     struct socketmonitor *m;
     struct pollfd *f;
     struct pollfd fds[4];
-    int numfds=0;
+    int numfds = 0;
     int pollrc;
     int i;
-    struct timeval before;
-    struct timeval after;
+    struct curltime before;
+    struct curltime after;
 
     /* 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->events = m->socket.events;
       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)
 {
-  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 */
   events_setup(multi, &evs);
@@ -670,7 +672,7 @@ static CURLcode easy_transfer(struct Curl_multi *multi)
   bool done = FALSE;
   CURLMcode mcode = CURLM_OK;
   CURLcode result = CURLE_OK;
-  struct timeval before;
+  struct curltime before;
   int without_fds = 0;  /* count number of consecutive returns from
                            curl_multi_wait() without any filedescriptors */
 
@@ -683,7 +685,7 @@ static CURLcode easy_transfer(struct Curl_multi *multi)
 
     if(!mcode) {
       if(!rc) {
-        struct timeval after = curlx_tvnow();
+        struct curltime after = curlx_tvnow();
 
         /* If it returns without any filedescriptor instantly, we need to
            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 */
 
     /* 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];
       data->state.tempwrite[i].buf = NULL;
     }
     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
          buffers */
       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
  * 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;
   unsigned char in; /* we need to treat the characters unsigned */
   size_t newlen;
-  size_t strindex=0;
+  size_t strindex = 0;
   size_t length;
   CURLcode result;
 
   if(inlength < 0)
     return NULL;
 
-  alloc = (inlength?(size_t)inlength:strlen(string))+1;
+  alloc = (inlength?(size_t)inlength:strlen(string)) + 1;
   newlen = alloc;
 
   ns = malloc(alloc);
@@ -104,7 +104,7 @@ char *curl_easy_escape(struct Curl_easy *data, const char *string,
 
     if(Curl_isunreserved(in))
       /* just copy this */
-      ns[strindex++]=in;
+      ns[strindex++] = in;
     else {
       /* encode it */
       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;
       }
 
-      result = Curl_convert_to_network(data, &in, 1);
+      result = Curl_convert_to_network(data, (char *)&in, 1);
       if(result) {
         /* Curl_convert_to_network calls failf if unsuccessful */
         free(ns);
@@ -125,11 +125,11 @@ char *curl_easy_escape(struct Curl_easy *data, const char *string,
 
       snprintf(&ns[strindex], 4, "%%%02X", in);
 
-      strindex+=3;
+      strindex += 3;
     }
     string++;
   }
-  ns[strindex]=0; /* terminate it */
+  ns[strindex] = 0; /* terminate it */
   return ns;
 }
 
@@ -148,10 +148,10 @@ CURLcode Curl_urldecode(struct Curl_easy *data,
                         char **ostring, size_t *olen,
                         bool reject_ctrl)
 {
-  size_t alloc = (length?length:strlen(string))+1;
+  size_t alloc = (length?length:strlen(string)) + 1;
   char *ns = malloc(alloc);
   unsigned char in;
-  size_t strindex=0;
+  size_t strindex = 0;
   unsigned long hex;
   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 */
 
-      result = Curl_convert_from_network(data, &in, 1);
+      result = Curl_convert_from_network(data, (char *)&in, 1);
       if(result) {
         /* Curl_convert_from_network calls failf if unsuccessful */
         free(ns);
         return result;
       }
 
-      string+=2;
-      alloc-=2;
+      string += 2;
+      alloc -= 2;
     }
 
     if(reject_ctrl && (in < 0x20)) {
@@ -192,7 +192,7 @@ CURLcode Curl_urldecode(struct Curl_easy *data,
     ns[strindex++] = in;
     string++;
   }
-  ns[strindex]=0; /* terminate it */
+  ns[strindex] = 0; /* terminate it */
 
   if(olen)
     /* 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 */
   file_disconnect,                      /* disconnect */
   ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
   0,                                    /* defport */
   CURLPROTO_FILE,                       /* protocol */
   PROTOPT_NONETWORK | PROTOPT_NOURLQUERY /* flags */
@@ -132,37 +133,42 @@ static CURLcode file_setup_connection(struct connectdata *conn)
 static CURLcode file_range(struct connectdata *conn)
 {
   curl_off_t from, to;
-  curl_off_t totalsize=-1;
+  curl_off_t totalsize = -1;
   char *ptr;
   char *ptr2;
   struct Curl_easy *data = conn->data;
 
   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++;
-    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 - */
       data->state.resume_from = from;
       DEBUGF(infof(data, "RANGE %" CURL_FORMAT_CURL_OFF_T " to end of file\n",
                    from));
     }
-    else if(from < 0) {
+    else if((from_t == CURL_OFFT_INVAL) && !to_t) {
       /* -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",
-                   -from));
+                   to));
     }
     else {
       /* X-Y */
       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;
       DEBUGF(infof(data, "RANGE from %" CURL_FORMAT_CURL_OFF_T
                    " 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 */
-  for(i=0; i < real_path_len; ++i)
+  for(i = 0; i < real_path_len; ++i)
     if(actual_path[i] == '/')
       actual_path[i] = '\\';
     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
                           Windows version to have a different struct without
                           having to redefine the simple word 'stat' */
-  curl_off_t expected_size=0;
+  curl_off_t expected_size = 0;
   bool size_known;
-  bool fstated=FALSE;
+  bool fstated = FALSE;
   ssize_t nread;
   struct Curl_easy *data = conn->data;
   char *buf = data->state.buffer;
@@ -500,7 +506,7 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
              tm->tm_hour,
              tm->tm_min,
              tm->tm_sec);
-    result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
+    result = Curl_client_write(conn, CLIENTWRITE_BOTH, header, 0);
     if(!result)
       /* set the file size to make it available post transfer */
       Curl_pgrsSetDownloadSize(data, expected_size);

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

@@ -32,6 +32,8 @@
 
 #include "urldata.h" /* for struct Curl_easy */
 #include "formdata.h"
+#include "mime.h"
+#include "non-ascii.h"
 #include "vtls/vtls.h"
 #include "strcase.h"
 #include "sendf.h"
@@ -42,13 +44,6 @@
 #include "curl_memory.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
    extensions. */
@@ -197,7 +192,7 @@ static const char *ContentTypeForFilename(const char *filename,
     contenttype = HTTPPOST_CONTENTTYPE_DEFAULT;
 
   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(strcasecompare(filename +
                           strlen(filename) - strlen(ctts[i].extension),
@@ -272,7 +267,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
   struct curl_httppost *post = NULL;
   CURLformoption option;
   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
      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;
       }
+      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) &&
          (form == first_form) ) {
         /* 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. */
         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->namelength:
-                                   strlen(form->name)+1);
+                                   strlen(form->name) + 1);
         }
         if(!form->name) {
           return_value = CURL_FORMADD_MEMORY;
@@ -663,7 +669,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
         /* copy value (without strdup; possibly contains null characters) */
         size_t clen  = (size_t) form->contentslength;
         if(!clen)
-          clen = strlen(form->value)+1;
+          clen = strlen(form->value) + 1;
 
         form->value = Curl_memdup(form->value, clen);
 
@@ -746,211 +752,6 @@ CURLFORMcode curl_formadd(struct curl_httppost **httppost,
   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()
  * Serialize a curl_httppost struct.
@@ -962,42 +763,34 @@ int curl_formget(struct curl_httppost *form, void *arg,
                  curl_formget_callback append)
 {
   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;
 
   do {
-    next=form->next;  /* the following form line */
+    next = form->next;  /* the following form line */
 
     /* recurse to sub-contents */
     curl_formfree(form->more);
@@ -1031,118 +824,29 @@ void curl_formfree(struct curl_httppost *form)
   } 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
  * 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,
-                          struct FormData **finalform,
+                          curl_mimepart *finalform,
                           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;
-  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)
     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 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 {
-          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;
 }
 
-/*
- * 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 */
 CURLFORMcode curl_formadd(struct curl_httppost **httppost,
                           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
  * 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 */
 typedef struct FormInfo {
   char *name;
@@ -69,31 +43,9 @@ typedef struct FormInfo {
   struct FormInfo *more;
 } FormInfo;
 
-int Curl_FormInit(struct Form *form, struct FormData *formdata);
-
 CURLcode Curl_getformdata(struct Curl_easy *data,
-                          struct FormData **,
+                          curl_mimepart *,
                           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 */

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

@@ -178,10 +178,11 @@ const struct Curl_handler Curl_handler_ftp = {
   ZERO_NULL,                       /* perform_getsock */
   ftp_disconnect,                  /* disconnect */
   ZERO_NULL,                       /* readwrite */
+  ZERO_NULL,                       /* connection_check */
   PORT_FTP,                        /* defport */
   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 */
   ftp_disconnect,                  /* disconnect */
   ZERO_NULL,                       /* readwrite */
+  ZERO_NULL,                       /* connection_check */
   PORT_FTPS,                       /* defport */
   CURLPROTO_FTPS,                  /* protocol */
   PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION |
@@ -212,59 +214,6 @@ const struct Curl_handler Curl_handler_ftps = {
 };
 #endif
 
-#ifndef CURL_DISABLE_HTTP
-/*
- * HTTP-proxyed FTP protocol handler.
- */
-
-static const struct Curl_handler Curl_handler_ftp_proxy = {
-  "FTP",                                /* scheme */
-  Curl_http_setup_conn,                 /* setup_connection */
-  Curl_http,                            /* do_it */
-  Curl_http_done,                       /* done */
-  ZERO_NULL,                            /* do_more */
-  ZERO_NULL,                            /* connect_it */
-  ZERO_NULL,                            /* connecting */
-  ZERO_NULL,                            /* doing */
-  ZERO_NULL,                            /* proto_getsock */
-  ZERO_NULL,                            /* doing_getsock */
-  ZERO_NULL,                            /* domore_getsock */
-  ZERO_NULL,                            /* perform_getsock */
-  ZERO_NULL,                            /* disconnect */
-  ZERO_NULL,                            /* readwrite */
-  PORT_FTP,                             /* defport */
-  CURLPROTO_HTTP,                       /* protocol */
-  PROTOPT_NONE                          /* flags */
-};
-
-
-#ifdef USE_SSL
-/*
- * HTTP-proxyed FTPS protocol handler.
- */
-
-static const struct Curl_handler Curl_handler_ftps_proxy = {
-  "FTPS",                               /* scheme */
-  Curl_http_setup_conn,                 /* setup_connection */
-  Curl_http,                            /* do_it */
-  Curl_http_done,                       /* done */
-  ZERO_NULL,                            /* do_more */
-  ZERO_NULL,                            /* connect_it */
-  ZERO_NULL,                            /* connecting */
-  ZERO_NULL,                            /* doing */
-  ZERO_NULL,                            /* proto_getsock */
-  ZERO_NULL,                            /* doing_getsock */
-  ZERO_NULL,                            /* domore_getsock */
-  ZERO_NULL,                            /* perform_getsock */
-  ZERO_NULL,                            /* disconnect */
-  ZERO_NULL,                            /* readwrite */
-  PORT_FTPS,                            /* defport */
-  CURLPROTO_HTTP,                       /* protocol */
-  PROTOPT_NONE                          /* flags */
-};
-#endif
-#endif
-
 static void close_secondarysocket(struct connectdata *conn)
 {
   if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
@@ -272,7 +221,6 @@ static void close_secondarysocket(struct connectdata *conn)
     conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
   }
   conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
-  conn->tunnel_state[SECONDARYSOCKET] = TUNNEL_INIT;
 }
 
 /*
@@ -291,9 +239,9 @@ static void freedirs(struct ftp_conn *ftpc)
 {
   int i;
   if(ftpc->dirs) {
-    for(i=0; i < ftpc->dirdepth; i++) {
+    for(i = 0; i < ftpc->dirdepth; i++) {
       free(ftpc->dirs[i]);
-      ftpc->dirs[i]=NULL;
+      ftpc->dirs[i] = NULL;
     }
     free(ftpc->dirs);
     ftpc->dirs = NULL;
@@ -340,7 +288,7 @@ static CURLcode AcceptServerConnect(struct connectdata *conn)
   if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) {
     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 */
 
@@ -388,7 +336,7 @@ static time_t ftp_timeleft_accept(struct Curl_easy *data)
 {
   time_t timeout_ms = DEFAULT_ACCEPT_TIMEOUT;
   time_t other;
-  struct timeval now;
+  struct curltime now;
 
   if(data->set.accepttimeout > 0)
     timeout_ms = data->set.accepttimeout;
@@ -509,7 +457,7 @@ static CURLcode InitiateTransfer(struct connectdata *conn)
   }
 
   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
        size prior to the actual upload. */
@@ -644,7 +592,7 @@ static CURLcode ftp_readresp(curl_socket_t sockfd,
 #endif
 
   /* store the latest code for later retrieval */
-  data->info.httpcode=code;
+  data->info.httpcode = code;
 
   if(ftpcode)
     *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 pingpong *pp = &ftpc->pp;
   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)
     *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 */
     ftpcode = &value_to_be_ignored;
 
-  *nreadp=0;
+  *nreadp = 0;
 
   while(!*ftpcode && !result) {
     /* check and reset timeout value every lap */
     timeout = Curl_pp_state_timeout(pp);
 
-    if(timeout <=0) {
+    if(timeout <= 0) {
       failf(data, "FTP response timeout");
       return CURLE_OPERATION_TIMEDOUT; /* already too little time */
     }
@@ -765,7 +713,7 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
     else
       /* when we got data or there is no cache left, we reset the cache skip
          counter */
-      cache_skip=0;
+      cache_skip = 0;
 
     *nreadp += nread;
 
@@ -900,7 +848,7 @@ static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
       int i;
       /* PORT is used to tell the server to connect to us, and during that we
          don't do happy eyeballs, but we do if we connect to the server */
-      for(s=1, i=0; i<2; i++) {
+      for(s = 1, i = 0; i<2; i++) {
         if(conn->tempsock[i] != CURL_SOCKET_BAD) {
           socks[s] = conn->tempsock[i];
           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
        fails and then MKD fails (due to another session raced it to create the
        dir) this then allows for a second try to CWD to it */
-    ftpc->count3 = (conn->data->set.ftp_create_missing_dirs==2)?1:0;
+    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
          transfer is taking place, we must first get back to the original dir
          where we ended up after login: */
-      ftpc->count1 = 0; /* we count this as the first path, then we add one
-                          for all upcoming ones in the ftp->dirs[] array */
+      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);
       state(conn, FTP_CWD);
     }
     else {
       if(ftpc->dirdepth) {
-        ftpc->count1 = 1;
+        ftpc->cwdcount = 1;
         /* issue the first CWD, the rest is sent when the CWD responses are
            received... */
-        PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->dirs[ftpc->count1 -1]);
+        PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->dirs[ftpc->cwdcount -1]);
         state(conn, FTP_CWD);
       }
       else {
@@ -977,15 +928,15 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
 {
   CURLcode result = CURLE_OK;
   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] = "";
 
   struct Curl_sockaddr_storage ss;
   Curl_addrinfo *res, *ai;
   curl_socklen_t sslen;
   char hbuf[NI_MAXHOST];
-  struct sockaddr *sa=(struct sockaddr *)&ss;
+  struct sockaddr *sa = (struct sockaddr *)&ss;
   struct sockaddr_in * const sa4 = (void *)sa;
 #ifdef ENABLE_IPV6
   struct sockaddr_in6 * const sa6 = (void *)sa;
@@ -996,7 +947,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
   int error;
   char *host = NULL;
   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_max = 0;
   unsigned short port;
@@ -1024,7 +975,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
     char *port_start = NULL;
     char *port_sep = NULL;
 
-    addr = calloc(addrlen+1, 1);
+    addr = calloc(addrlen + 1, 1);
     if(!addr)
       return CURLE_OUT_OF_MEMORY;
 
@@ -1067,7 +1018,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
     if(ip_end != NULL) {
       port_start = strchr(ip_end, ':');
       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, '-');
         if(port_sep) {
           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 */
       while(source && *source) {
         if(*source == '.')
-          *dest=',';
+          *dest = ',';
         else
           *dest = *source;
         dest++;
@@ -1518,12 +1469,12 @@ static CURLcode ftp_state_list(struct connectdata *conn)
       return CURLE_OUT_OF_MEMORY;
 
     /* Check if path does not end with /, as then we cut off the file part */
-    if(lstArg[strlen(lstArg) - 1] != '/')  {
+    if(lstArg[strlen(lstArg) - 1] != '/') {
 
       /* chop off the file part if format is dir/dir/file */
       slashPos = strrchr(lstArg, '/');
       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) {
-      curl_off_t passed=0;
+      curl_off_t passed = 0;
       if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
         failf(data, "Could not seek stream");
         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 FTP *ftp = data->req.protop;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
-  bool quote=FALSE;
+  bool quote = FALSE;
   struct curl_slist *item;
 
   switch(instate) {
@@ -1870,11 +1821,11 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
 {
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   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;
   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 */
   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
            formatted reply and we bail out immediately. */
-        for(i=1; i<4; i++) {
+        for(i = 1; i<4; i++) {
           if(separator[i] != sep1) {
-            ptr=NULL; /* set to NULL to signal error */
+            ptr = NULL; /* set to NULL to signal error */
             break;
           }
         }
@@ -1916,7 +1867,7 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
         }
       }
       else
-        ptr=NULL;
+        ptr = NULL;
     }
     if(!ptr) {
       failf(data, "Weirdly formatted EPSV reply");
@@ -2090,7 +2041,7 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
                                     int ftpcode)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data=conn->data;
+  struct Curl_easy *data = conn->data;
   struct FTP *ftp = data->req.protop;
   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)) {
         /* we have a time, reformat it */
         char timebuf[24];
-        time_t secs=time(NULL);
+        time_t secs = time(NULL);
 
         snprintf(timebuf, sizeof(timebuf),
                  "%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 &&
          ftpc->file &&
          data->set.get_filetime &&
-         (data->info.filetime>=0) ) {
+         (data->info.filetime >= 0) ) {
         char headerbuf[128];
         time_t filetime = (time_t)data->info.filetime;
         struct tm buffer;
@@ -2196,7 +2147,7 @@ static CURLcode ftp_state_type_resp(struct connectdata *conn,
                                     ftpstate instate)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data=conn->data;
+  struct Curl_easy *data = conn->data;
 
   if(ftpcode/100 != 2) {
     /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a
@@ -2225,7 +2176,7 @@ static CURLcode ftp_state_retr(struct connectdata *conn,
                                          curl_off_t filesize)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data=conn->data;
+  struct Curl_easy *data = conn->data;
   struct FTP *ftp = data->req.protop;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
 
@@ -2308,12 +2259,14 @@ static CURLcode ftp_state_size_resp(struct connectdata *conn,
                                     ftpstate instate)
 {
   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;
 
   /* 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) {
 #ifdef CURL_FTP_HTTPSTYLE_HEAD
@@ -2383,7 +2336,7 @@ static CURLcode ftp_state_stor_resp(struct connectdata *conn,
   CURLcode result = CURLE_OK;
   struct Curl_easy *data = conn->data;
 
-  if(ftpcode>=400) {
+  if(ftpcode >= 400) {
     failf(data, "Failed FTP upload: %0d", ftpcode);
     state(conn, FTP_STOP);
     /* oops, we never close the sockets! */
@@ -2441,7 +2394,7 @@ static CURLcode ftp_state_get_resp(struct connectdata *conn,
       E:
       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 */
       char *bytes;
       char *buf = data->state.buffer;
-      bytes=strstr(buf, " bytes");
+      bytes = strstr(buf, " bytes");
       if(bytes--) {
-        long in=(long)(bytes-buf);
+        long in = (long)(bytes-buf);
         /* this is a hint there is size information in there! ;-) */
         while(--in) {
           /* scan for the left parenthesis and break there */
@@ -2475,7 +2428,7 @@ static CURLcode ftp_state_get_resp(struct connectdata *conn,
             break;
           /* skip only digits */
           if(!ISDIGIT(*bytes)) {
-            bytes=NULL;
+            bytes = NULL;
             break;
           }
           /* one more estep backwards */
@@ -2484,7 +2437,7 @@ static CURLcode ftp_state_get_resp(struct connectdata *conn,
         /* if we have nothing but digits: */
         if(bytes++) {
           /* 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;
   curl_socket_t sock = conn->sock[FIRSTSOCKET];
-  struct Curl_easy *data=conn->data;
+  struct Curl_easy *data = conn->data;
   int ftpcode;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   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
            requested. Try a FTPS connection now */
 
-        ftpc->count3=0;
+        ftpc->count3 = 0;
         switch(data->set.ftpsslauth) {
         case CURLFTPAUTH_DEFAULT:
         case CURLFTPAUTH_SSL:
@@ -2822,10 +2775,11 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
 
     case FTP_PWD:
       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;
         char *dir;
         char *store;
+        bool entry_extracted = FALSE;
 
         dir = malloc(nread + 1);
         if(!dir)
@@ -2857,7 +2811,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
               }
               else {
                 /* end of path */
-                *store = '\0'; /* zero terminate */
+                entry_extracted = TRUE;
                 break; /* get out of this loop */
               }
             }
@@ -2866,7 +2820,9 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
             store++;
             ptr++;
           }
-
+          *store = '\0'; /* zero terminate */
+        }
+        if(entry_extracted) {
           /* If the path name does not look like an absolute path (i.e.: it
              does not start with a '/'), we probably need some server-dependent
              adjustments. For example, this is the case when connecting to
@@ -2913,7 +2869,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
 
     case FTP_SYST:
       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 *store;
 
@@ -2988,10 +2944,10 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
       if(ftpcode/100 != 2) {
         /* failure to CWD there */
         if(conn->data->set.ftp_create_missing_dirs &&
-           ftpc->count1 && !ftpc->count2) {
+           ftpc->cwdcount && !ftpc->count2) {
           /* try making it */
           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);
         }
         else {
@@ -3004,10 +2960,10 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
       }
       else {
         /* success */
-        ftpc->count2=0;
-        if(++ftpc->count1 <= ftpc->dirdepth) {
+        ftpc->count2 = 0;
+        if(++ftpc->cwdcount <= ftpc->dirdepth) {
           /* send next CWD */
-          PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
+          PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->cwdcount - 1]);
         }
         else {
           result = ftp_state_mdtm(conn);
@@ -3025,7 +2981,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
       }
       state(conn, FTP_CWD);
       /* send CWD */
-      PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
+      PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->cwdcount - 1]);
       break;
 
     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 dlen = strlen(path)-flen;
     if(!ftpc->cwdfail) {
+      ftpc->prevmethod = data->set.ftp_filemethod;
       if(dlen && (data->set.ftp_filemethod != FTPFILE_NOCWD)) {
         ftpc->prevpath = path;
         if(flen)
           /* if 'path' is not the whole string */
-          ftpc->prevpath[dlen]=0; /* terminate */
+          ftpc->prevpath[dlen] = 0; /* terminate */
       }
       else {
         /* we never changed dir */
-        ftpc->prevpath=strdup("");
+        ftpc->prevpath = strdup("");
         free(path);
       }
       if(ftpc->prevpath)
@@ -3515,35 +3472,36 @@ static CURLcode ftp_range(struct connectdata *conn)
 {
   curl_off_t from, to;
   char *ptr;
-  char *ptr2;
   struct Curl_easy *data = conn->data;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
 
   if(data->state.use_range && data->state.range) {
-    from=curlx_strtoofft(data->state.range, &ptr, 0);
-    while(*ptr && (ISSPACE(*ptr) || (*ptr=='-')))
+    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++;
-    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 - */
       data->state.resume_from = from;
       DEBUGF(infof(conn->data, "FTP RANGE %" CURL_FORMAT_CURL_OFF_T
                    " to end of file\n", from));
     }
-    else if(from < 0) {
+    else if(!to_t && (from_t == CURL_OFFT_INVAL)) {
       /* -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
-                   " bytes\n", -from));
+                   " bytes\n", to));
     }
     else {
       /* 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;
       DEBUGF(infof(conn->data, "FTP RANGE from %" CURL_FORMAT_CURL_OFF_T
                    " 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)
 {
-  struct Curl_easy *data=conn->data;
+  struct Curl_easy *data = conn->data;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   CURLcode result = CURLE_OK;
   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(!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
          aren't used so we blank their arguments. TODO: make this nicer */
       result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0);
@@ -3617,7 +3575,7 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
     return result;
 
   if(conn->bits.tunnel_proxy && conn->bits.httpproxy &&
-     conn->tunnel_state[SECONDARYSOCKET] != TUNNEL_COMPLETE)
+     Curl_connect_ongoing(conn))
     return result;
 
 
@@ -3741,7 +3699,7 @@ CURLcode ftp_perform(struct connectdata *conn,
                      bool *dophase_done)
 {
   /* this is FTP and no proxy */
-  CURLcode result=CURLE_OK;
+  CURLcode result = CURLE_OK;
 
   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
   char s[SBUF_SIZE];
   size_t write_len;
-  char *sptr=s;
+  char *sptr = s;
   CURLcode result = CURLE_OK;
 #ifdef HAVE_GSSAPI
   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;
 
   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);
   /* 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)
 {
-  struct ftp_conn *ftpc= &conn->proto.ftpc;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
   struct pingpong *pp = &ftpc->pp;
 
   /* 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;
       break;
     }
-    slash_pos=strrchr(cur_pos, '/');
+    slash_pos = strrchr(cur_pos, '/');
     if(slash_pos || !*cur_pos) {
       size_t dirlen = slash_pos-cur_pos;
       CURLcode result;
@@ -4243,7 +4200,7 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
         return result;
       }
       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
       filename = cur_pos;  /* this is a file name only */
@@ -4327,8 +4284,8 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
     }
   }
   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)) {
     /* 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;
     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");
       ftpc->cwddone = TRUE;
     }
@@ -4423,8 +4381,8 @@ static
 CURLcode ftp_regular_transfer(struct connectdata *conn,
                               bool *dophase_done)
 {
-  CURLcode result=CURLE_OK;
-  bool connected=FALSE;
+  CURLcode result = CURLE_OK;
+  bool connected = FALSE;
   struct Curl_easy *data = conn->data;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   data->req.size = -1; /* make sure this is unknown at this point */
@@ -4464,28 +4422,6 @@ static CURLcode ftp_setup_connection(struct connectdata *conn)
   char command;
   struct FTP *ftp;
 
-  if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
-    /* Unless we have asked to tunnel ftp operations through the proxy, we
-       switch and use HTTP operations only */
-#ifndef CURL_DISABLE_HTTP
-    if(conn->handler == &Curl_handler_ftp)
-      conn->handler = &Curl_handler_ftp_proxy;
-    else {
-#ifdef USE_SSL
-      conn->handler = &Curl_handler_ftps_proxy;
-#else
-      failf(data, "FTPS not supported!");
-      return CURLE_UNSUPPORTED_PROTOCOL;
-#endif
-    }
-    /* set it up as a HTTP connection instead */
-    return conn->handler->setup_connection(conn);
-#else
-    failf(data, "FTP over http proxy requires HTTP support built-in!");
-    return CURLE_UNSUPPORTED_PROTOCOL;
-#endif
-  }
-
   conn->data->req.protop = ftp = malloc(sizeof(struct FTP));
   if(NULL == ftp)
     return CURLE_OUT_OF_MEMORY;

+ 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
  * 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() */
   bool cwddone;     /* if it has been determined that the proper CWD combo
                        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
                        caching the current directory */
   bool wait_data_conn; /* this is set TRUE if data connection is waited */
   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
                         and others (A/I or zero) */
   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') {
             finfo->b_data[parser->item_length - 1] = 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
                  spaces and then the digits */
               while(ISSPACE(*endptr))
@@ -609,16 +609,18 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
             char *p;
             curl_off_t fsize;
             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)) {
             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 {
               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);
                 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
  * 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->timespent = 0;
   pro->t_redirect = 0;
+  pro->is_t_startransfer_set = false;
 
   info->httpcode = 0;
   info->httpproxycode = 0;
@@ -246,27 +247,60 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
   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,
                                double *param_doublep)
 {
   switch(info) {
   case CURLINFO_TOTAL_TIME:
-    *param_doublep = data->progress.timespent;
+    *param_doublep = DOUBLE_SECS(data->progress.timespent);
     break;
   case CURLINFO_NAMELOOKUP_TIME:
-    *param_doublep = data->progress.t_nslookup;
+    *param_doublep = DOUBLE_SECS(data->progress.t_nslookup);
     break;
   case CURLINFO_CONNECT_TIME:
-    *param_doublep = data->progress.t_connect;
+    *param_doublep = DOUBLE_SECS(data->progress.t_connect);
     break;
   case CURLINFO_APPCONNECT_TIME:
-    *param_doublep = data->progress.t_appconnect;
+    *param_doublep = DOUBLE_SECS(data->progress.t_appconnect);
     break;
   case CURLINFO_PRETRANSFER_TIME:
-    *param_doublep =  data->progress.t_pretransfer;
+    *param_doublep = DOUBLE_SECS(data->progress.t_pretransfer);
     break;
   case CURLINFO_STARTTRANSFER_TIME:
-    *param_doublep = data->progress.t_starttransfer;
+    *param_doublep = DOUBLE_SECS(data->progress.t_starttransfer);
     break;
   case CURLINFO_SIZE_UPLOAD:
     *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;
     break;
   case CURLINFO_REDIRECT_TIME:
-    *param_doublep =  data->progress.t_redirect;
+    *param_doublep = DOUBLE_SECS(data->progress.t_redirect);
     break;
 
   default:
@@ -326,46 +360,25 @@ static CURLcode getinfo_slist(struct Curl_easy *data, CURLINFO info,
       struct curl_tlssessioninfo **tsip = (struct curl_tlssessioninfo **)
                                           param_slistp;
       struct curl_tlssessioninfo *tsi = &data->tsi;
+#ifdef USE_SSL
       struct connectdata *conn = data->easy_conn;
+#endif
 
       *tsip = tsi;
       tsi->backend = Curl_ssl_backend();
       tsi->internals = NULL;
 
+#ifdef USE_SSL
       if(conn && tsi->backend != CURLSSLBACKEND_NONE) {
         unsigned int i;
         for(i = 0; i < (sizeof(conn->ssl) / sizeof(conn->ssl[0])); ++i) {
           if(conn->ssl[i].use) {
-#if defined(USE_AXTLS)
-            tsi->internals = (void *)conn->ssl[i].ssl;
-#elif defined(USE_CYASSL)
-            tsi->internals = (void *)conn->ssl[i].handle;
-#elif defined(USE_DARWINSSL)
-            tsi->internals = (void *)conn->ssl[i].ssl_ctx;
-#elif defined(USE_GNUTLS)
-            tsi->internals = (void *)conn->ssl[i].session;
-#elif defined(USE_GSKIT)
-            tsi->internals = (void *)conn->ssl[i].handle;
-#elif defined(USE_MBEDTLS)
-            tsi->internals = (void *)&conn->ssl[i].ssl;
-#elif defined(USE_NSS)
-            tsi->internals = (void *)conn->ssl[i].handle;
-#elif defined(USE_OPENSSL)
-            /* Legacy: CURLINFO_TLS_SESSION must return an SSL_CTX pointer. */
-            tsi->internals = ((info == CURLINFO_TLS_SESSION) ?
-                              (void *)conn->ssl[i].ctx :
-                              (void *)conn->ssl[i].handle);
-#elif defined(USE_POLARSSL)
-            tsi->internals = (void *)&conn->ssl[i].ssl;
-#elif defined(USE_SCHANNEL)
-            tsi->internals = (void *)&conn->ssl[i].ctxt->ctxt_handle;
-#elif defined(USE_SSL)
-#error "SSL backend specific information missing for CURLINFO_TLS_SSL_PTR"
-#endif
+            tsi->internals = Curl_ssl->get_internals(&conn->ssl[i], info);
             break;
           }
         }
       }
+#endif
     }
     break;
   default:
@@ -394,6 +407,7 @@ CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...)
   va_list arg;
   long *param_longp = NULL;
   double *param_doublep = NULL;
+  curl_off_t *param_offt = NULL;
   const char **param_charp = NULL;
   struct curl_slist **param_slistp = NULL;
   curl_socket_t *param_socketp = NULL;
@@ -422,6 +436,11 @@ CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...)
     if(param_doublep)
       result = getinfo_double(data, info, param_doublep);
     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:
     param_slistp = va_arg(arg, struct curl_slist **);
     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
  * 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,                            /* disconnect */
   ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
   PORT_GOPHER,                          /* defport */
   CURLPROTO_GOPHER,                     /* protocol */
   PROTOPT_NONE                          /* flags */
@@ -72,8 +73,8 @@ const struct Curl_handler Curl_handler_gopher = {
 
 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_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) ... */
     newp = path;
-    newp+=2;
+    newp += 2;
 
     /* ... then turn ? into TAB for search servers, Veronica, etc. ... */
     j = strlen(newp);
-    for(i=0; i<j; i++)
+    for(i = 0; i<j; i++)
       if(newp[i] == '?')
         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(!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) {
         iter->current_element = h->table[i].head;
-        iter->slot_index = i+1;
+        iter->slot_index = i + 1;
         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
  * 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 */
   size_t len = strlen(hostname);
   if(hostname[len-1]=='.')
-    hostname[len-1]=0;
+    hostname[len-1] = 0;
   len = strlen(pattern);
   if(pattern[len-1]=='.')
-    pattern[len-1]=0;
+    pattern[len-1] = 0;
 
   pattern_wildcard = strchr(pattern, '*');
   if(pattern_wildcard == NULL)
@@ -95,7 +95,7 @@ static int hostmatch(char *hostname, char *pattern)
      match. */
   wildcard_enabled = 1;
   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 ||
      strncasecompare(pattern, "xn--", 4)) {
     wildcard_enabled = 0;
@@ -116,9 +116,9 @@ static int hostmatch(char *hostname, char *pattern)
     return CURL_HOST_NOMATCH;
 
   prefixlen = pattern_wildcard - pattern;
-  suffixlen = pattern_label_end - (pattern_wildcard+1);
+  suffixlen = pattern_label_end - (pattern_wildcard + 1);
   return strncasecompare(pattern, hostname, prefixlen) &&
-    strncasecompare(pattern_wildcard+1, hostname_label_end - suffixlen,
+    strncasecompare(pattern_wildcard + 1, hostname_label_end - suffixlen,
                     suffixlen) ?
     CURL_HOST_MATCH : CURL_HOST_NOMATCH;
 }
@@ -137,7 +137,7 @@ int Curl_cert_hostcheck(const char *match_pattern, const char *hostname)
       hostp = strdup(hostname);
       if(hostp) {
         if(hostmatch(hostp, matchp) == CURL_HOST_MATCH)
-          res= 1;
+          res = 1;
         free(hostp);
       }
       free(matchp);

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

@@ -304,9 +304,9 @@ fetch_addr(struct connectdata *conn,
   entry_len = strlen(entry_id);
 
   /* 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 */
     struct hostcache_prune_data user;
 
@@ -316,7 +316,7 @@ fetch_addr(struct connectdata *conn,
     if(hostcache_timestamp_remove(&user, dns)) {
       infof(data, "Hostname in DNS cache was stale, zapped\n");
       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 */
 
   /* 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);
   if(!dns2) {
     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);
 
       /* 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)
         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);
 
       /* 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(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
  * 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 >=
-       (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
        * 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
  * you should have received as part of this distribution. The terms
@@ -212,7 +212,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
 
   if(port) {
     snprintf(sbuf, sizeof(sbuf), "%d", port);
-    sbufptr=sbuf;
+    sbufptr = sbuf;
   }
 
   error = Curl_getaddrinfo_ex(hostname, sbufptr, &hints, &res);

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

@@ -50,6 +50,7 @@
 #include "transfer.h"
 #include "sendf.h"
 #include "formdata.h"
+#include "mime.h"
 #include "progress.h"
 #include "curl_base64.h"
 #include "cookie.h"
@@ -119,6 +120,7 @@ const struct Curl_handler Curl_handler_http = {
   ZERO_NULL,                            /* perform_getsock */
   ZERO_NULL,                            /* disconnect */
   ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
   PORT_HTTP,                            /* defport */
   CURLPROTO_HTTP,                       /* protocol */
   PROTOPT_CREDSPERREQUEST               /* flags */
@@ -143,6 +145,7 @@ const struct Curl_handler Curl_handler_https = {
   ZERO_NULL,                            /* perform_getsock */
   ZERO_NULL,                            /* disconnect */
   ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
   PORT_HTTPS,                           /* defport */
   CURLPROTO_HTTPS,                      /* protocol */
   PROTOPT_SSL | PROTOPT_CREDSPERREQUEST | PROTOPT_ALPN_NPN /* flags */
@@ -160,6 +163,7 @@ CURLcode Curl_http_setup_conn(struct connectdata *conn)
   if(!http)
     return CURLE_OUT_OF_MEMORY;
 
+  Curl_mime_initpart(&http->form, conn->data);
   conn->data->req.protop = http;
 
   Curl_http2_setup_conn(conn);
@@ -168,26 +172,6 @@ CURLcode Curl_http_setup_conn(struct connectdata *conn)
   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
@@ -207,7 +191,7 @@ char *Curl_checkProxyheaders(const struct connectdata *conn,
 
   for(head = (conn->bits.proxy && data->set.sep_headers) ?
         data->set.proxyheaders : data->set.headers;
-      head; head=head->next) {
+      head; head = head->next) {
     if(strncasecompare(head->data, thisheader, thislen))
       return head->data;
   }
@@ -425,6 +409,7 @@ static CURLcode http_perhapsrewind(struct connectdata *conn)
         expectsend = data->state.infilesize;
       break;
     case HTTPREQ_POST_FORM:
+    case HTTPREQ_POST_MIME:
       expectsend = http->postsize;
       break;
     default:
@@ -608,7 +593,7 @@ output_auth_headers(struct connectdata *conn,
 #endif
 #if defined(USE_NTLM) && defined(NTLM_WB_ENABLED)
   if(authstatus->picked == CURLAUTH_NTLM_WB) {
-    auth="NTLM_WB";
+    auth = "NTLM_WB";
     result = Curl_output_ntlm_wb(conn, proxy);
     if(result)
       return result;
@@ -1020,7 +1005,7 @@ static size_t readmoredata(char *buffer,
 
       http->sending++; /* move one step up */
 
-      http->backup.postsize=0;
+      http->backup.postsize = 0;
     }
     else
       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
            on to the debug callback too */
         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)))
       new_size = (size_t)-1;
     else
-      new_size = (in->size_used+size) * 2;
+      new_size = (in->size_used + size) * 2;
 
     if(in->buffer)
       /* we have a buffer, enlarge the existing one */
@@ -1337,7 +1322,7 @@ Curl_compareheader(const char *headerline, /* line to check */
   clen = strlen(content); /* length of the word to find */
 
   /* 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))
       return TRUE; /* match! */
   }
@@ -1369,7 +1354,7 @@ CURLcode Curl_http_connect(struct connectdata *conn, bool *done)
   if(CONNECT_FIRSTSOCKET_PROXY_SSL())
     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. */
     return CURLE_OK;
 
@@ -1468,18 +1453,17 @@ CURLcode Curl_http_done(struct connectdata *conn,
 
   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;
+    break;
+  default:
+    break;
+  }
 
   if(status)
     return status;
@@ -1579,7 +1563,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
   char *ptr;
   struct curl_slist *h[2];
   struct curl_slist *headers;
-  int numlists=1; /* by default */
+  int numlists = 1; /* by default */
   struct Curl_easy *data = conn->data;
   int i;
 
@@ -1611,7 +1595,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
   }
 
   /* loop through one or two lists */
-  for(i=0; i < numlists; i++) {
+  for(i = 0; i < numlists; i++) {
     headers = h[i];
 
     while(headers) {
@@ -1635,15 +1619,19 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
                   /* this header (extended by formdata.c) is sent later */
                   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 &&
                   /* while doing auth neg, don't allow the custom length since
                      we will force length zero then */
-                  checkprefix("Content-Length", headers->data))
+                  checkprefix("Content-Length:", headers->data))
             ;
           else if(conn->allocptr.te &&
                   /* when asking for Transfer-Encoding, don't pass on a custom
                      Connection: */
-                  checkprefix("Connection", headers->data))
+                  checkprefix("Connection:", headers->data))
             ;
           else if((conn->httpversion == 20) &&
                   checkprefix("Transfer-Encoding:", headers->data))
@@ -1676,6 +1664,10 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
               *ptr = ':';
               result = Curl_add_bufferf(req_buffer, "%s\r\n",
                                         headers->data);
+
+              /* restore the previous value */
+              *ptr = ';';
+
               if(result)
                 return result;
             }
@@ -1773,7 +1765,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
   const char *httpstring;
   Curl_send_buffer *req_buffer;
   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
      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) {
       case HTTPREQ_POST:
       case HTTPREQ_POST_FORM:
+      case HTTPREQ_POST_MIME:
         request = "POST";
         break;
       case HTTPREQ_PUT:
         request = "PUT";
         break;
+      case HTTPREQ_OPTIONS:
+        request = "OPTIONS";
+        break;
       default: /* this should never happen */
       case HTTPREQ_GET:
         request = "GET";
@@ -1868,7 +1864,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
      here. */
   if(Curl_checkheaders(conn, "User-Agent:")) {
     free(conn->allocptr.uagent);
-    conn->allocptr.uagent=NULL;
+    conn->allocptr.uagent = NULL;
   }
 
   /* setup the authentication headers */
@@ -1937,6 +1933,48 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
   }
 #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:");
   if(ptr) {
     /* 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");
   }
   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)
         /* don't enable chunked during auth neg */
         ;
@@ -2044,7 +2083,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
   }
 
 #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 */
 
     /* 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 */
 
-  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";
 
-  if(( (HTTPREQ_POST == httpreq) ||
-       (HTTPREQ_POST_FORM == httpreq) ||
-       (HTTPREQ_PUT == httpreq) ) &&
+  if((HTTPREQ_POST == httpreq || HTTPREQ_PUT == httpreq) &&
      data->state.resume_from) {
     /**********************************************************************
      * 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"
      * 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.
+     * Resuming mime/form posting at an offset > 0 has no sense and is ignored.
      *********************************************************************/
 
     if(data->state.resume_from < 0) {
@@ -2161,7 +2189,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
       }
 
       if(seekerr != CURL_SEEKFUNC_OK) {
-        curl_off_t passed=0;
+        curl_off_t passed = 0;
 
         if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
           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",
                                          data->state.range);
     }
-    else if((httpreq != HTTPREQ_GET) &&
+    else if((httpreq == HTTPREQ_POST || httpreq == HTTPREQ_PUT) &&
             !Curl_checkheaders(conn, "Content-Range:")) {
 
       /* 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) {
         /* 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;
         conn->allocptr.rangeline =
           aprintf("Content-Range: bytes %s%" CURL_FORMAT_CURL_OFF_T
@@ -2266,6 +2294,9 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
   if(result)
     return result;
 
+  if(data->set.str[STRING_TARGET])
+    ppath = data->set.str[STRING_TARGET];
+
   /* url */
   if(paste_ftp_userpwd)
     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(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) {
       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);
     }
     if(co) {
-      struct Cookie *store=co;
+      struct Cookie *store = co;
       /* now loop through all cookies that matched */
       while(co) {
         if(co->value) {
@@ -2407,117 +2438,79 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
 
   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 */
       result = Curl_add_bufferf(req_buffer,
                                 "Content-Length: %" CURL_FORMAT_CURL_OFF_T
-                                "\r\n", http->postsize);
+                                "\r\n", postsize);
       if(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)
         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)
       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,
                                   &data->info.request_size, 0, FIRSTSOCKET);
     if(result)
-      failf(data, "Failed sending POST request");
+      failf(data, "Failed sending PUT request");
     else
-      /* setup variables for the upcoming transfer */
+      /* prepare for transfer */
       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;
-    }
-
     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:"))) {
-      /* 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,
                                 "Content-Length: %" CURL_FORMAT_CURL_OFF_T
                                 "\r\n", postsize);
@@ -2525,24 +2518,52 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
         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);
       if(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)
       return result;
 
     /* set the upload size to the progress meter */
     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 */
     result = Curl_add_buffer_send(req_buffer, conn,
                                   &data->info.request_size, 0, FIRSTSOCKET);
     if(result)
-      failf(data, "Failed sending PUT request");
+      failf(data, "Failed sending POST request");
     else
       /* prepare for transfer */
       Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
@@ -2550,6 +2571,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
                           postsize?&http->writebytecount:NULL);
     if(result)
       return result;
+
     break;
 
   case HTTPREQ_POST:
@@ -2592,7 +2614,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
       data->state.expect100header =
         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);
       if(result)
         return result;
@@ -2606,7 +2628,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
          its size. */
       if(conn->httpversion != 20 &&
          !data->state.expect100header &&
-         (postsize < MAX_INITIAL_POST_SIZE))  {
+         (postsize < MAX_INITIAL_POST_SIZE)) {
         /* if we don't use expect: 100  AND
            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!");
     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 */
     free(scratch);
     return FALSE; /* can't return CURLE_foobar so return FALSE */
@@ -2801,6 +2823,7 @@ static bool
 checkrtspprefix(struct Curl_easy *data,
                 const char *s)
 {
+  bool result = FALSE;
 
 #ifdef CURL_DOES_CONVERSIONS
   /* 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!");
     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 */
-    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
   (void)data; /* unused */
+  result = checkprefix("RTSP/", s)? TRUE: FALSE;
 #endif /* CURL_DOES_CONVERSIONS */
-  if(checkprefix("RTSP/", s))
-    return TRUE;
-  return FALSE;
+
+  return result;
 }
 #endif /* CURL_DISABLE_RTSP */
 
@@ -2862,14 +2886,14 @@ static CURLcode header_append(struct Curl_easy *data,
       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;
     newbuff = realloc(data->state.headerbuff, newsize);
     if(!newbuff) {
       failf(data, "Failed to alloc memory for big header!");
       return CURLE_OUT_OF_MEMORY;
     }
-    data->state.headersize=newsize;
+    data->state.headersize = newsize;
     data->state.headerbuff = newbuff;
     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 */
-    rest_length = (k->end_ptr - k->str)+1;
+    rest_length = (k->end_ptr - k->str) + 1;
     *nread -= (ssize_t)rest_length;
 
     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_POST:
           case HTTPREQ_POST_FORM:
+          case HTTPREQ_POST_MIME:
             /* We got an error response. If this happened before the whole
              * request body has been sent we stop sending and mark the
              * connection for closure after we've read the entire response.
@@ -3288,7 +3313,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
 #define HEADER1 scratch
 #define SCRATCHSIZE 21
       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
          don't know if it's the 1st header line or the body.
          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
          * guarantees on future behaviors since it isn't within the protocol.
          */
+        char separator;
         nc = sscanf(HEADER1,
-                    " HTTP/%d.%d %d",
+                    " HTTP/%1d.%1d%c%3d",
                     &httpversion_major,
                     &conn->httpversion,
+                    &separator,
                     &k->httpcode);
 
         if(nc == 1 && httpversion_major == 2 &&
            1 == sscanf(HEADER1, " HTTP/2 %d", &k->httpcode)) {
           conn->httpversion = 0;
-          nc = 3;
+          nc = 4;
+          separator = ' ';
         }
 
-        if(nc==3) {
+        if((nc == 4) && (' ' == separator)) {
           conn->httpversion += 10 * httpversion_major;
 
           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");
           }
         }
-        else {
+        else if(!nc) {
           /* this is the real world, not a Nirvana
              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;
 
           /* 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) {
         nc = sscanf(HEADER1,
@@ -3360,7 +3392,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
                     &rtspversion_major,
                     &conn->rtspversion,
                     &k->httpcode);
-        if(nc==3) {
+        if(nc == 3) {
           conn->rtspversion += 10 * rtspversion_major;
           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) ) {
 
           if(data->state.resume_from &&
-             (data->set.httpreq==HTTPREQ_GET) &&
+             (data->set.httpreq == HTTPREQ_GET) &&
              (k->httpcode == 416)) {
             /* "Requested Range Not Satisfiable", just proceed and
                pretend this is no error */
@@ -3448,8 +3480,8 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
            * fields.  */
           if(data->set.timecondition)
             data->info.timecond = TRUE;
-          k->size=0;
-          k->maxdownload=0;
+          k->size = 0;
+          k->maxdownload = 0;
           k->ignorecl = TRUE; /* ignore Content-Length headers */
           break;
         default:
@@ -3471,28 +3503,32 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
     /* Check for Content-Length: header lines to get size */
     if(!k->ignorecl && !data->set.ignorecl &&
        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 */
     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(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
         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_LOCK_ACCESS_SINGLE);
       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
                          here, or else use real peer host name. */
                       conn->allocptr.cookiehost?
@@ -3693,8 +3729,8 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
 #endif
     else if(checkprefix("Last-Modified:", k->p) &&
             (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);
       if(data->set.get_filetime)
         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
  * 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 *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_checkProxyheaders(const struct connectdata *conn,
@@ -115,8 +113,13 @@ CURLcode Curl_http_perhapsrewind(struct connectdata *conn);
 #define MAX_INITIAL_POST_SIZE (64*1024)
 #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 /* CURL_DISABLE_HTTP */
@@ -125,7 +128,7 @@ CURLcode Curl_http_perhapsrewind(struct connectdata *conn);
  * HTTP unique setup
  ***************************************************************************/
 struct HTTP {
-  struct FormData *sendit;
+  curl_mimepart *sendit;
   curl_off_t postsize; /* off_t to handle large file sizes */
   const char *postdata;
 
@@ -135,7 +138,7 @@ struct HTTP {
   curl_off_t writebytecount;
 
   /* For FORM posting */
-  struct Form form;
+  curl_mimepart form;
 
   struct back {
     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 "http.h"
 #include "sendf.h"
+#include "select.h"
 #include "curl_base64.h"
 #include "strcase.h"
 #include "multiif.h"
@@ -151,6 +152,49 @@ static CURLcode http2_disconnect(struct connectdata *conn,
   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 */
 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_disconnect,                     /* disconnect */
   ZERO_NULL,                            /* readwrite */
+  http2_conncheck,                      /* connection_check */
   PORT_HTTP,                            /* defport */
   CURLPROTO_HTTP,                       /* protocol */
   PROTOPT_STREAM                        /* flags */
@@ -216,6 +261,7 @@ static const struct Curl_handler Curl_handler_http2_ssl = {
   http2_perform_getsock,                /* perform_getsock */
   http2_disconnect,                     /* disconnect */
   ZERO_NULL,                            /* readwrite */
+  http2_conncheck,                      /* connection_check */
   PORT_HTTP,                            /* defport */
   CURLPROTO_HTTPS,                      /* protocol */
   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;
     size_t len = strlen(header);
     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)) {
         /* sub-match, make sure that it is followed by a colon */
         if(stream->push_headers[i][len] != ':')
           continue;
-        return &stream->push_headers[i][len+1];
+        return &stream->push_headers[i][len + 1];
       }
     }
   }
@@ -418,7 +464,7 @@ static int push_promise(struct Curl_easy *data,
                               data->multi->push_userp);
 
     /* 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);
     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",
             rv, nghttp2_strerror((int)rv));
       *err = CURLE_RECV_ERROR;
-      return 0;
+      return -1;
     }
     DEBUGF(infof(data, "nghttp2_session_mem_recv() returns %zd\n", 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);
     if(rv != 0) {
       *err = CURLE_SEND_ERROR;
-      return 0;
+      return -1;
     }
 
     if(should_close_session(httpc)) {
@@ -1909,6 +1955,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
   switch(conn->data->set.httpreq) {
   case HTTPREQ_POST:
   case HTTPREQ_POST_FORM:
+  case HTTPREQ_POST_MIME:
   case HTTPREQ_PUT:
     if(conn->data->state.infilesize != -1)
       stream->upload_left = conn->data->state.infilesize;
@@ -2134,12 +2181,15 @@ CURLcode Curl_http2_switched(struct connectdata *conn,
   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) {
     struct Curl_http2_dep **tail;
     struct Curl_http2_dep *dep = calloc(1, sizeof(struct Curl_http2_dep));
+    if(!dep)
+      return CURLE_OUT_OF_MEMORY;
     dep->data = child;
 
     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_e = exclusive;
+  return CURLE_OK;
 }
 
 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
  * 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_done(struct connectdata *conn, bool premature);
 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,
                              struct Curl_easy *child);
 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
  * 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)
 {
   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! */
 }
 
@@ -107,7 +107,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
                               ssize_t datalen,
                               ssize_t *wrotep)
 {
-  CURLcode result=CURLE_OK;
+  CURLcode result = CURLE_OK;
   struct Curl_easy *data = conn->data;
   struct Curl_chunker *ch = &conn->chunk;
   struct SingleRequest *k = &data->req;
@@ -147,7 +147,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
           return CHUNKE_ILLEGAL_HEX;
 
         /* length and datap are unmodified */
-        ch->hexbuffer[ch->hexindex]=0;
+        ch->hexbuffer[ch->hexindex] = 0;
 
         /* convert to host encoding before calling strtoul */
         result = Curl_convert_from_network(conn->data, ch->hexbuffer,
@@ -158,9 +158,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
           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;
         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! */
         if(0 == ch->datasize) {
           ch->state = CHUNK_TRAILER; /* now check for trailers */
-          conn->trlPos=0;
+          conn->trlPos = 0;
         }
         else
           ch->state = CHUNK_DATA;
@@ -259,9 +257,9 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
 
         if(conn->trlPos) {
           /* 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 */
           result = Curl_convert_from_network(conn->data, conn->trailer,
@@ -277,7 +275,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
             if(result)
               return CHUNKE_WRITE_ERROR;
           }
-          conn->trlPos=0;
+          conn->trlPos = 0;
           ch->state = CHUNK_TRAILER_CR;
           if(*datap == 0x0a)
             /* already on the LF */
@@ -301,7 +299,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
             ptr = realloc(conn->trailer, conn->trlMax + 3);
           }
           else {
-            conn->trlMax=128;
+            conn->trlMax = 128;
             ptr = malloc(conn->trlMax + 3);
           }
           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
  * you should have received as part of this distribution. The terms
@@ -37,11 +37,14 @@
 #include "sendf.h"
 #include "strcase.h"
 #include "http_ntlm.h"
+#include "curl_ntlm_core.h"
 #include "curl_ntlm_wb.h"
 #include "vauth/vauth.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"
 #elif defined(USE_WINDOWS_SSPI)
 #include "curl_sspi.h"
@@ -129,7 +132,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
   DEBUGASSERT(conn);
   DEBUGASSERT(conn->data);
 
-#ifdef USE_NSS
+#if defined(NTLM_NEEDS_NSS_INIT)
   if(CURLE_OK != Curl_nss_force_init(conn->data))
     return CURLE_OUT_OF_MEMORY;
 #endif
@@ -170,8 +173,8 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
   case NTLMSTATE_TYPE1:
   default: /* for the weird cases we (re)start here */
     /* Create a type-1 message */
-    result = Curl_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)
       return result;
 

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

@@ -22,11 +22,11 @@
 
 #include "curl_setup.h"
 
+#include "http_proxy.h"
+
 #if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP)
 
-#include "urldata.h"
 #include <curl/curl.h>
-#include "http_proxy.h"
 #include "sendf.h"
 #include "http.h"
 #include "url.h"
@@ -135,35 +135,73 @@ CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex)
   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,
                         int sockindex,
                         const char *hostname,
                         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;
   CURLcode result;
   curl_socket_t tunnelsocket = conn->sock[sockindex];
-  curl_off_t cl=0;
   bool closeConnection = FALSE;
-  bool chunked_encoding = FALSE;
   time_t check;
+  struct http_connect_state *s = conn->connect_state;
 
 #define SELECT_OK      0
 #define SELECT_ERROR   1
 #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 */
 
   conn->bits.proxy_connect_closed = FALSE;
 
   do {
-    if(TUNNEL_INIT == conn->tunnel_state[sockindex]) {
+    if(TUNNEL_INIT == s->tunnel_state) {
       /* BEGIN CONNECT PHASE */
       char *host_port;
       Curl_send_buffer *req_buffer;
@@ -196,8 +234,8 @@ static CURLcode CONNECT(struct connectdata *conn,
 
       if(!result) {
         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) ?
           "1.0" : "1.1";
         bool ipv6_ip = conn->bits.ipv6_ip;
@@ -206,7 +244,7 @@ static CURLcode CONNECT(struct connectdata *conn,
         /* the hostname may be different */
         if(hostname != conn->host.name)
           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?"]":"",
                   remote_port);
         if(!hostheader) {
@@ -271,65 +309,46 @@ static CURLcode CONNECT(struct connectdata *conn,
       if(result)
         return result;
 
-      conn->tunnel_state[sockindex] = TUNNEL_CONNECT;
+      s->tunnel_state = TUNNEL_CONNECT;
+      s->perline = 0;
     } /* END CONNECT PHASE */
 
     check = Curl_timeleft(data, NULL, TRUE);
     if(check <= 0) {
       failf(data, "Proxy CONNECT aborted due to timeout");
-      return CURLE_RECV_ERROR;
+      return CURLE_OPERATION_TIMEDOUT;
     }
 
     if(!Curl_conn_data_pending(conn, sockindex))
       /* return so we'll be called again polling-style */
       return CURLE_OK;
-    DEBUGF(infof(data, "Read response immediately from proxy CONNECT\n"));
 
     /* at this point, the tunnel_connecting phase is over. */
 
     { /* 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!");
           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
            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) {
-          keepon = FALSE;
+          s->keepon = FALSE;
           break;
         }
         else if(gotbytes <= 0) {
@@ -343,24 +362,22 @@ static CURLcode CONNECT(struct connectdata *conn,
             error = SELECT_ERROR;
             failf(data, "Proxy CONNECT aborted");
           }
-          keepon = FALSE;
+          s->keepon = FALSE;
           break;
         }
 
-        /* We got a byte of data */
-        nread++;
 
-        if(keepon > TRUE) {
+        if(s->keepon > TRUE) {
           /* 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
                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;
             }
           }
@@ -372,28 +389,29 @@ static CURLcode CONNECT(struct connectdata *conn,
 
             /* now parse the chunked piece of data so that we can
                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) {
               /* we're done reading chunks! */
               infof(data, "chunk reading DONE\n");
-              keepon = FALSE;
+              s->keepon = FALSE;
               /* we did the full CONNECT treatment, go COMPLETE */
-              conn->tunnel_state[sockindex] = TUNNEL_COMPLETE;
+              s->tunnel_state = TUNNEL_COMPLETE;
             }
           }
           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(*ptr != 0x0a) {
-          ptr++;
+        if(*s->ptr != 0x0a) {
+          s->ptr++;
           continue;
         }
 
         /* 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 */
         if(result)
           return result;
@@ -401,7 +419,7 @@ static CURLcode CONNECT(struct connectdata *conn,
         /* output debug if that is requested */
         if(data->set.verbose)
           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) {
           /* send the header to the callback */
@@ -409,35 +427,34 @@ static CURLcode CONNECT(struct connectdata *conn,
           if(data->set.include_header)
             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)
             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
            really terminated until the LF comes. Treat a following CR
            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 */
-          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 we get a 407 response code with content length
                when we have no auth problem, we must ignore the
                whole response-body */
-            keepon = 2;
+            s->keepon = 2;
 
-            if(cl) {
+            if(s->cl) {
               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;
 
               infof(data, "Ignore chunked response-body\n");
@@ -448,46 +465,46 @@ static CURLcode CONNECT(struct connectdata *conn,
                  function returns! */
               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
                    was a CR */
-                line_start++;
+                s->line_start++;
               }
 
               /* now parse the chunked piece of data so that we can
                  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) {
                 /* we're done reading chunks! */
                 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 {
               /* without content-length or chunked encoding, we
                  can't keep the connection alive since the close is
                  the end signal so we bail out at once instead */
-              keepon = FALSE;
+              s->keepon = FALSE;
             }
           }
           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;
         }
 
-        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)) ||
-           (checkprefix("Proxy-authenticate:", line_start) &&
+           (checkprefix("Proxy-authenticate:", s->line_start) &&
             (407 == k->httpcode))) {
 
           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)
             return CURLE_OUT_OF_MEMORY;
 
@@ -498,7 +515,7 @@ static CURLcode CONNECT(struct connectdata *conn,
           if(result)
             return result;
         }
-        else if(checkprefix("Content-Length:", line_start)) {
+        else if(checkprefix("Content-Length:", s->line_start)) {
           if(k->httpcode/100 == 2) {
             /* A client MUST ignore any Content-Length or Transfer-Encoding
                header fields received in a successful response to CONNECT.
@@ -507,13 +524,13 @@ static CURLcode CONNECT(struct connectdata *conn,
                   k->httpcode);
           }
           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;
-        else if(checkprefix("Transfer-Encoding:", line_start)) {
+        else if(checkprefix("Transfer-Encoding:", s->line_start)) {
           if(k->httpcode/100 == 2) {
             /* A client MUST ignore any Content-Length or Transfer-Encoding
                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 "
                   "CONNECT %03d response\n", k->httpcode);
           }
-          else if(Curl_compareheader(line_start,
+          else if(Curl_compareheader(s->line_start,
                                      "Transfer-Encoding:", "chunked")) {
             infof(data, "CONNECT responded chunked\n");
-            chunked_encoding = TRUE;
+            s->chunked_encoding = TRUE;
             /* init our chunky engine */
             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;
-        else if(2 == sscanf(line_start, "HTTP/1.%d %d",
+        else if(2 == sscanf(s->line_start, "HTTP/1.%d %d",
                             &subversion,
                             &k->httpcode)) {
           /* store the HTTP code from the proxy */
           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 */
 
       if(Curl_pgrsUpdate(conn))
@@ -549,7 +567,7 @@ static CURLcode CONNECT(struct connectdata *conn,
       if(error)
         return CURLE_RECV_ERROR;
 
-      if(data->info.httpproxycode != 200) {
+      if(data->info.httpproxycode/100 != 2) {
         /* Deal with the possibly already received authenticate
            headers. 'newurl' is set to a new URL if we must loop. */
         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
      * means the HTTP authentication is still going on so if the tunnel
      * 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);
 
-  if(200 != data->req.httpcode) {
+  if(data->info.httpproxycode/100 != 2) {
     if(closeConnection && data->req.newurl) {
       conn->bits.proxy_connect_closed = TRUE;
       infof(data, "Connect me again please\n");
+      connect_done(conn);
     }
     else {
       free(data->req.newurl);
@@ -598,7 +614,7 @@ static CURLcode CONNECT(struct connectdata *conn,
     }
 
     /* to back to init state */
-    conn->tunnel_state[sockindex] = TUNNEL_INIT;
+    s->tunnel_state = TUNNEL_INIT;
 
     if(conn->bits.proxy_connect_closed)
       /* 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;
   }
 
-  conn->tunnel_state[sockindex] = TUNNEL_COMPLETE;
+  s->tunnel_state = TUNNEL_COMPLETE;
 
   /* 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
@@ -618,13 +634,24 @@ static CURLcode CONNECT(struct connectdata *conn,
 
   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 */
   conn->bits.rewindaftersend = FALSE; /* make sure this isn't set for the
                                          document request  */
   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
  * 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)
 {
   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);
 
-  if(result || (TUNNEL_COMPLETE == conn->tunnel_state[sockindex]))
-    Curl_safefree(conn->connect_buffer);
+  if(result || Curl_connect_complete(conn))
+    connect_done(conn);
 
   return result;
 }
 
+#else
+void Curl_connect_free(struct Curl_easy *data)
+{
+  (void)data;
+}
 
 #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)
 /* ftp can use this as well */
 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);
 
+bool Curl_connect_complete(struct connectdata *conn);
+bool Curl_connect_ongoing(struct connectdata *conn);
+
 #else
 #define Curl_proxyCONNECT(x,y,z,w) CURLE_NOT_BUILT_IN
 #define Curl_proxy_connect(x,y) CURLE_OK
+#define Curl_connect_complete(x) CURLE_OK
+#define Curl_connect_ongoing(x) FALSE
 #endif
 
+void Curl_connect_free(struct Curl_easy *data);
+
 #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
  * 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;
     unsigned short w = (unsigned short) ((b[0] << 8) | b[1]);
 
+    if((b[0] & 0xFE) == 0xFC) /* Handle ULAs */
+      return IPV6_SCOPE_UNIQUELOCAL;
     switch(w & 0xFFC0) {
     case 0xFE80:
       return IPV6_SCOPE_LINKLOCAL;
@@ -101,7 +103,7 @@ bool Curl_if_is_interface_name(const char *interf)
   struct ifaddrs *iface, *head;
 
   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)) {
         result = TRUE;
         break;
@@ -121,15 +123,15 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
 
 #ifndef ENABLE_IPV6
   (void) remote_scope;
-
-#ifndef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
-  (void) remote_scope_id;
 #endif
 
+#if !defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID) || \
+    !defined(ENABLE_IPV6)
+  (void) remote_scope_id;
 #endif
 
   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->sa_family == af) {
           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;
 
   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;
 
   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
  * 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_LINKLOCAL    1       /* Link-local scope. */
 #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);
 

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

@@ -68,6 +68,7 @@
 #include "http.h" /* for HTTP proxy tunnel stuff */
 #include "socks.h"
 #include "imap.h"
+#include "mime.h"
 #include "strtoofft.h"
 #include "strcase.h"
 #include "vtls/vtls.h"
@@ -128,6 +129,7 @@ const struct Curl_handler Curl_handler_imap = {
   ZERO_NULL,                        /* perform_getsock */
   imap_disconnect,                  /* disconnect */
   ZERO_NULL,                        /* readwrite */
+  ZERO_NULL,                        /* connection_check */
   PORT_IMAP,                        /* defport */
   CURLPROTO_IMAP,                   /* protocol */
   PROTOPT_CLOSEACTION|              /* flags */
@@ -154,69 +156,22 @@ const struct Curl_handler Curl_handler_imaps = {
   ZERO_NULL,                        /* perform_getsock */
   imap_disconnect,                  /* disconnect */
   ZERO_NULL,                        /* readwrite */
+  ZERO_NULL,                        /* connection_check */
   PORT_IMAPS,                       /* defport */
   CURLPROTO_IMAPS,                  /* protocol */
   PROTOPT_CLOSEACTION | PROTOPT_SSL /* flags */
 };
 #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 */
 static const struct SASLproto saslimap = {
   "imap",                     /* The service name */
   '+',                        /* 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) */
   imap_perform_authenticate,  /* Send authentication command */
   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;
 
     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;
   }
@@ -613,9 +564,10 @@ static CURLcode imap_perform_authentication(struct connectdata *conn)
   struct imap_conn *imapc = &conn->proto.imapc;
   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);
     return result;
   }
@@ -757,18 +709,48 @@ static CURLcode imap_perform_fetch(struct connectdata *conn)
 static CURLcode imap_perform_append(struct connectdata *conn)
 {
   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;
 
   /* Check we have a mailbox */
   if(!imap->mailbox) {
-    failf(conn->data, "Cannot APPEND without a mailbox.");
+    failf(data, "Cannot APPEND without a mailbox.");
     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 */
-  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;
   }
 
@@ -779,7 +761,7 @@ static CURLcode imap_perform_append(struct connectdata *conn)
 
   /* Send the APPEND command */
   result = imap_sendf(conn, "APPEND %s (\\Seen) {%" CURL_FORMAT_CURL_OFF_T "}",
-                      mailbox, conn->data->state.infilesize);
+                      mailbox, data->state.infilesize);
 
   free(mailbox);
 
@@ -839,19 +821,21 @@ static CURLcode imap_state_servergreet_resp(struct connectdata *conn,
                                             int imapcode,
                                             imapstate instate)
 {
-  CURLcode result = CURLE_OK;
   struct Curl_easy *data = conn->data;
-
   (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");
-    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 */
@@ -918,7 +902,7 @@ static CURLcode imap_state_capability_resp(struct connectdata *conn,
       line += wordlen;
     }
   }
-  else if(imapcode == 'O') {
+  else if(imapcode == IMAP_RESP_OK) {
     if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
       /* We don't have a SSL/TLS connection yet, but SSL is requested */
       if(imapc->tls_supported)
@@ -951,7 +935,7 @@ static CURLcode imap_state_starttls_resp(struct connectdata *conn,
 
   (void)instate; /* no use for this yet */
 
-  if(imapcode != 'O') {
+  if(imapcode != IMAP_RESP_OK) {
     if(data->set.use_ssl != CURLUSESSL_TRY) {
       failf(data, "STARTTLS denied");
       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 */
 
-  if(imapcode != 'O') {
+  if(imapcode != IMAP_RESP_OK) {
     failf(data, "Access denied. %c", imapcode);
     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);
     line[len] = '\0';
   }
-  else if(imapcode != 'O')
+  else if(imapcode != IMAP_RESP_OK)
     result = CURLE_QUOTE_ERROR; /* TODO: Fix error code */
   else
     /* End of DO phase */
@@ -1066,7 +1050,7 @@ static CURLcode imap_state_select_resp(struct connectdata *conn, int imapcode,
       imapc->mailbox_uidvalidity = strdup(tmp);
     }
   }
-  else if(imapcode == 'O') {
+  else if(imapcode == IMAP_RESP_OK) {
     /* Check if the UIDVALIDITY has been specified and matches */
     if(imap->uidvalidity && imapc->mailbox_uidvalidity &&
        strcmp(imap->uidvalidity, imapc->mailbox_uidvalidity)) {
@@ -1120,10 +1104,11 @@ static CURLcode imap_state_fetch_resp(struct connectdata *conn, int imapcode,
 
   if(*ptr == '{') {
     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) {
@@ -1197,7 +1182,7 @@ static CURLcode imap_state_fetch_final_resp(struct connectdata *conn,
 
   (void)instate; /* No use for this yet */
 
-  if(imapcode != 'O')
+  if(imapcode != IMAP_RESP_OK)
     result = CURLE_WEIRD_SERVER_REPLY;
   else
     /* 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 */
 
-  if(imapcode != 'O')
+  if(imapcode != IMAP_RESP_OK)
     result = CURLE_UPLOAD_FAILED;
   else
     /* 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 */
   }
   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 */
-    if(!data->set.upload)
+    if(!data->set.upload && data->set.mimepost.kind == MIMEKIND_NONE)
       state(conn, IMAP_FETCH_FINAL);
     else {
       /* 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;
 
   /* 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 */
     result = imap_perform_append(conn);
   else if(imap->custom && (selected || !imap->mailbox))
@@ -1715,31 +1701,6 @@ static CURLcode imap_setup_connection(struct connectdata *conn)
 
   /* Clear the TLS upgraded flag */
   conn->tls_upgraded = FALSE;
-
-  /* Set up the proxy if necessary */
-  if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
-    /* Unless we have asked to tunnel IMAP operations through the proxy, we
-       switch and use HTTP operations only */
-#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 */
 
   return CURLE_OK;
@@ -1836,7 +1797,7 @@ static char *imap_atom(const char *str, bool escape_only)
     return strdup(str);
 
   /* 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 */
   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 */
   p2 = newstr;
-  if(others_exists) {
+  if(!escape_only) {
     newstr[0] = '"';
     newstr[newlen - 1] = '"';
     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
  * you should have received as part of this distribution. The terms
@@ -71,6 +71,7 @@ struct imap_conn {
   struct pingpong pp;
   imapstate state;            /* Always use imap.c:state() to change state! */
   bool ssldone;               /* Is connect() over SSL done? */
+  bool preauth;               /* Is this connection PREAUTH? */
   struct SASL sasl;           /* SASL-related parameters */
   unsigned int preftype;      /* Preferred authentication type */
   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);
   if(len == 0 || len >= size) {
-    SET_ERRNO(ENOSPC);
+    errno = ENOSPC;
     return (NULL);
   }
   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 &&
         (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);
       }
       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.
    */
   if((size_t)(tp - tmp) > size) {
-    SET_ERRNO(ENOSPC);
+    errno = ENOSPC;
     return (NULL);
   }
   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
  * 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)
 {
@@ -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);
 #endif
   default:
-    SET_ERRNO(EAFNOSUPPORT);
+    errno = EAFNOSUPPORT;
     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:
  *      On Windows we store the error in the thread errno, not
  *      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:
  *      Paul Vixie, 1996.
  */
@@ -73,7 +73,7 @@ Curl_inet_pton(int af, const char *src, void *dst)
     return (inet_pton6(src, (unsigned char *)dst));
 #endif
   default:
-    SET_ERRNO(EAFNOSUPPORT);
+    errno = EAFNOSUPPORT;
     return (-1);
   }
   /* 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
  * 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_ARPA_INET_H
 #include <arpa/inet.h>
+#elif defined(HAVE_WS2TCPIP_H)
+/* inet_pton() exists in Vista or later */
+#include <ws2tcpip.h>
 #endif
 #define Curl_inet_pton(x,y,z) inet_pton(x,y,z)
 #endif

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

@@ -1,6 +1,6 @@
 /* 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).
  * Copyright (c) 2004 - 2016 Daniel Stenberg
  * 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
  * 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,                            /* disconnect */
   ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
   PORT_LDAP,                            /* defport */
   CURLPROTO_LDAP,                       /* protocol */
   PROTOPT_NONE                          /* flags */
@@ -175,6 +176,7 @@ const struct Curl_handler Curl_handler_ldaps = {
   ZERO_NULL,                            /* perform_getsock */
   ZERO_NULL,                            /* disconnect */
   ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
   PORT_LDAPS,                           /* defport */
   CURLPROTO_LDAPS,                      /* protocol */
   PROTOPT_SSL                           /* flags */
@@ -233,7 +235,6 @@ static int ldap_win_bind(struct connectdata *conn, LDAP *server,
                          const char *user, const char *passwd)
 {
   int rc = LDAP_INVALID_CREDENTIALS;
-  ULONG method = LDAP_AUTH_SIMPLE;
 
   PTCHAR inuser = 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);
     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(inpass);
@@ -266,7 +267,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
   LDAPMessage *ldapmsg = NULL;
   LDAPMessage *entryIterator;
   int num = 0;
-  struct Curl_easy *data=conn->data;
+  struct Curl_easy *data = conn->data;
   int ldap_proto = LDAP_VERSION3;
   int ldap_ssl = 0;
   char *val_b64 = NULL;

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

@@ -115,7 +115,8 @@ void curl_memdebug(const char *logname)
       logfile = stderr;
 #ifdef MEMDEBUG_LOG_SYNC
     /* Flush the log file after every line so the log isn't lost in a crash */
-    setbuf(logfile, (char *)NULL);
+    if(logfile)
+      setbuf(logfile, (char *)NULL);
 #endif
   }
 }
@@ -146,7 +147,7 @@ static bool countcheck(const char *func, int line, const char *source)
                 source, line, func);
         fflush(logfile); /* because it might crash now */
       }
-      SET_ERRNO(ENOMEM);
+      errno = ENOMEM;
       return TRUE; /* RETURN ERROR! */
     }
     else
@@ -169,7 +170,7 @@ void *curl_domalloc(size_t wantedsize, int line, const char *source)
     return NULL;
 
   /* alloc at least 64 bytes */
-  size = sizeof(struct memdebug)+wantedsize;
+  size = sizeof(struct memdebug) + wantedsize;
 
   mem = (Curl_cmalloc)(size);
   if(mem) {
@@ -224,9 +225,9 @@ char *curl_dostrdup(const char *str, int line, const char *source)
   if(countcheck("strdup", line, source))
     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)
     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,
                      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);
 
@@ -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 */
 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);
   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,
                  int line, const char *source)
 {
-  FILE *res=fopen(file, mode);
+  FILE *res = fopen(file, mode);
 
   if(source)
     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,
                   int line, const char *source)
 {
-  FILE *res=fdopen(filedes, mode);
+  FILE *res = fdopen(filedes, mode);
 
   if(source)
     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);
 
-  res=fclose(file);
+  res = fclose(file);
 
   if(source)
     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.
  */
 
-#ifndef SIZEOF_SIZE_T
-#  define SIZEOF_SIZE_T CURL_SIZEOF_LONG
-#endif
-
 #ifdef HAVE_LONGLONG
 #  define LONG_LONG_TYPE long long
 #  define HAVE_LONG_LONG_TYPE
@@ -111,7 +107,7 @@ static const char upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
   } WHILE_FALSE
 
 /* Data type to read from the arglist */
-typedef enum  {
+typedef enum {
   FORMAT_UNKNOWN = 0,
   FORMAT_STRING,
   FORMAT_PTR,
@@ -181,7 +177,7 @@ struct asprintf {
 
 static long dprintf_DollarString(char *input, char **end)
 {
-  int number=0;
+  int number = 0;
   while(ISDIGIT(*input)) {
     number *= 10;
     number += *input-'0';
@@ -237,7 +233,7 @@ static int dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos,
   long width;
   long precision;
   int flags;
-  long max_param=0;
+  long max_param = 0;
   long i;
 
   while(*fmt) {
@@ -326,7 +322,7 @@ static int dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos,
           break;
 #if defined(MP_HAVE_INT_EXTENSIONS)
         case 'I':
-#if (CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG)
+#if (SIZEOF_CURL_OFF_T > SIZEOF_LONG)
           flags |= FLAGS_LONGLONG;
 #else
           flags |= FLAGS_LONG;
@@ -348,14 +344,14 @@ static int dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos,
         case 'z':
           /* the code below generates a warning if -Wunreachable-code is
              used */
-#if (SIZEOF_SIZE_T > CURL_SIZEOF_LONG)
+#if (SIZEOF_SIZE_T > SIZEOF_LONG)
           flags |= FLAGS_LONGLONG;
 #else
           flags |= FLAGS_LONG;
 #endif
           break;
         case 'O':
-#if (CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG)
+#if (SIZEOF_CURL_OFF_T > SIZEOF_LONG)
           flags |= FLAGS_LONGLONG;
 #else
           flags |= FLAGS_LONG;
@@ -380,7 +376,7 @@ static int dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos,
           else
             width = param_num;
           if(width > max_param)
-            max_param=width;
+            max_param = width;
           break;
         default:
           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 */
-  for(i=0; i<max_param; i++) {
+  for(i = 0; i<max_param; i++) {
     /* Width/precision arguments must be read before the main argument
        they are attached to */
     if(vto[i].flags & FLAGS_WIDTHPARAM) {
@@ -573,7 +569,7 @@ static int dprintf_formatf(
   int done = 0;
 
   long param; /* current parameter to read */
-  long param_num=0; /* parameter counter */
+  long param_num = 0; /* parameter counter */
 
   va_stack_t vto[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
        after the %, thus create a %<num>$ sequence */
-    param=dprintf_DollarString(f, &f);
+    param = dprintf_DollarString(f, &f);
 
     if(!param)
       param = param_num;
@@ -952,7 +948,7 @@ static int dprintf_formatf(
            output characters */
         (sprintf)(work, formatbuf, p->data.dnum);
         DEBUGASSERT(strlen(work) <= sizeof(work));
-        for(fptr=work; *fptr; fptr++)
+        for(fptr = work; *fptr; fptr++)
           OUTCHAR(*fptr);
       }
       break;
@@ -984,7 +980,7 @@ static int dprintf_formatf(
 /* fputc() look-alike */
 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;
 
   if(infop->length < infop->max) {
@@ -1032,7 +1028,7 @@ int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...)
 /* fputc() look-alike */
 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;
 
   if(!infop->buffer) {
@@ -1042,9 +1038,9 @@ static int alloc_addbyter(int output, FILE *data)
       return -1; /* fail */
     }
     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;
     size_t newsize = infop->alloc*2;
 
@@ -1133,7 +1129,7 @@ int curl_msprintf(char *buffer, const char *format, ...)
   va_start(ap_save, format);
   retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save);
   va_end(ap_save);
-  *buffer=0; /* we terminate this with a zero byte */
+  *buffer = 0; /* we terminate this with a zero byte */
   return retcode;
 }
 
@@ -1162,7 +1158,7 @@ int curl_mvsprintf(char *buffer, const char *format, va_list ap_save)
 {
   int retcode;
   retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save);
-  *buffer=0; /* we terminate this with a zero byte */
+  *buffer = 0; /* we terminate this with a zero byte */
   return retcode;
 }
 

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

@@ -44,6 +44,7 @@
 #include "sigpipe.h"
 #include "vtls/vtls.h"
 #include "connect.h"
+#include "http_proxy.h"
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_memory.h"
@@ -69,7 +70,7 @@ static void singlesocket(struct Curl_multi *multi,
                          struct Curl_easy *data);
 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_easy *d);
 static CURLMcode multi_timeout(struct Curl_multi *multi,
@@ -114,6 +115,13 @@ static void mstate(struct Curl_easy *data, CURLMstate state
     NULL,
     NULL,
     Curl_init_CONNECT, /* CONNECT */
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    Curl_connect_free /* DO */
     /* 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
      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);
   }
   data->state.tempcount = 0;
@@ -794,8 +802,8 @@ static int waitconnect_getsock(struct connectdata *conn,
                                int numsocks)
 {
   int i;
-  int s=0;
-  int rc=0;
+  int s = 0;
+  int rc = 0;
 
   if(!numsocks)
     return GETSOCK_BLANK;
@@ -805,7 +813,7 @@ static int waitconnect_getsock(struct connectdata *conn,
     return Curl_ssl_getsock(conn, sock, numsocks);
 #endif
 
-  for(i=0; i<2; i++) {
+  for(i = 0; i<2; i++) {
     if(conn->tempsock[i] != CURL_SOCKET_BAD) {
       sock[s] = conn->tempsock[i];
       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
      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_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,
      and then we must make sure that is done. */
   struct Curl_easy *data;
-  int this_max_fd=-1;
+  int this_max_fd = -1;
   curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE];
   int bitmap;
   int i;
@@ -925,11 +933,11 @@ CURLMcode curl_multi_fdset(struct Curl_multi *multi,
   if(!GOOD_MULTI_HANDLE(multi))
     return CURLM_BAD_HANDLE;
 
-  data=multi->easyp;
+  data = multi->easyp;
   while(data) {
     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;
 
       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;
 
   /* Count up how many fds we have from the multi handle */
-  data=multi->easyp;
+  data = multi->easyp;
   while(data) {
     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;
 
       if(bitmap & GETSOCK_READSOCK(i)) {
@@ -1014,6 +1022,10 @@ CURLMcode curl_multi_wait(struct Curl_multi *multi,
 
   if(nfds) {
     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));
       if(!ufds)
         return CURLM_OUT_OF_MEMORY;
@@ -1029,11 +1041,11 @@ CURLMcode curl_multi_wait(struct Curl_multi *multi,
 
   if(curlfds) {
     /* Add the curl handles to our pollfds first */
-    data=multi->easyp;
+    data = multi->easyp;
     while(data) {
       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;
 
         if(bitmap & GETSOCK_READSOCK(i)) {
@@ -1217,15 +1229,15 @@ static CURLcode multi_reconnect_request(struct connectdata **connp)
  */
 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->sockfd:conn->writesockfd)+1;
+                           conn->sockfd:conn->writesockfd) + 1;
   Curl_pgrsTime(conn->data, TIMER_PRETRANSFER);
 }
 
 static CURLcode multi_do(struct connectdata **connp, bool *done)
 {
-  CURLcode result=CURLE_OK;
+  CURLcode result = CURLE_OK;
   struct connectdata *conn = *connp;
   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)
 {
-  CURLcode result=CURLE_OK;
+  CURLcode result = CURLE_OK;
 
   *complete = 0;
 
@@ -1289,7 +1301,7 @@ static CURLcode multi_do_more(struct connectdata *conn, int *complete)
 }
 
 static CURLMcode multi_runsingle(struct Curl_multi *multi,
-                                 struct timeval now,
+                                 struct curltime now,
                                  struct Curl_easy *data)
 {
   struct Curl_message *msg = NULL;
@@ -1403,7 +1415,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
     switch(data->mstate) {
     case CURLM_STATE_INIT:
       /* init this transfer. */
-      result=Curl_pretransfer(data);
+      result = Curl_pretransfer(data);
 
       if(!result) {
         /* after init, go CONNECT */
@@ -1455,7 +1467,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
                          CURLM_STATE_WAITDO:CURLM_STATE_DO);
             else {
 #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);
               else
 #endif
@@ -1520,7 +1532,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
                        CURLM_STATE_WAITDO:CURLM_STATE_DO);
           else {
 #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);
             else
 #endif
@@ -1552,7 +1564,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
       else if(!result) {
         if((data->easy_conn->http_proxy.proxytype != CURLPROXY_HTTPS ||
            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;
           /* initiate protocol connect phase */
           multistate(data, CURLM_STATE_SENDPROTOCONNECT);
@@ -1568,7 +1580,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
 #ifndef CURL_DISABLE_HTTP
         if((data->easy_conn->http_proxy.proxytype == CURLPROXY_HTTPS &&
             !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);
           break;
         }
@@ -1685,7 +1697,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
            * back to the CONNECT phase so we can try again.
            */
           char *newurl = NULL;
-          followtype follow=FOLLOW_NONE;
+          followtype follow = FOLLOW_NONE;
           CURLcode drc;
           bool retry = FALSE;
 
@@ -1771,7 +1783,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
         if(control) {
           /* if positive, advance to DO_DONE
              if negative, go back to DOING */
-          multistate(data, control==1?
+          multistate(data, control == 1?
                      CURLM_STATE_DO_DONE:
                      CURLM_STATE_DOING);
           rc = CURLM_CALL_MULTI_PERFORM;
@@ -1926,7 +1938,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
         multi_done(&data->easy_conn, result, TRUE);
       }
       else if(done) {
-        followtype follow=FOLLOW_NONE;
+        followtype follow = FOLLOW_NONE;
 
         /* call this even if the readwrite function returned error */
         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)
 {
   struct Curl_easy *data;
-  CURLMcode returncode=CURLM_OK;
+  CURLMcode returncode = CURLM_OK;
   struct Curl_tree *t;
-  struct timeval now = Curl_tvnow();
+  struct curltime now = Curl_tvnow();
 
   if(!GOOD_MULTI_HANDLE(multi))
     return CURLM_BAD_HANDLE;
 
-  data=multi->easyp;
+  data = multi->easyp;
   while(data) {
     CURLMcode result;
     SIGPIPE_VARIABLE(pipe_st);
@@ -2234,7 +2246,7 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
     /* remove all easy handles */
     data = multi->easyp;
     while(data) {
-      nextdata=data->next;
+      nextdata = data->next;
       if(data->dns.hostcachetype == HCACHE_MULTI) {
         /* clear out the usage of the shared DNS cache */
         Curl_hostcache_clean(data, data->dns.hostcache);
@@ -2314,7 +2326,7 @@ static void singlesocket(struct Curl_multi *multi,
   int num;
   unsigned int curraction;
 
-  for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++)
+  for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++)
     socks[i] = CURL_SOCKET_BAD;
 
   /* 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 */
 
   /* 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)));
       i++) {
     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
      make sure to detect sockets that are removed */
-  for(i=0; i< data->numsocks; i++) {
+  for(i = 0; i< data->numsocks; i++) {
     int j;
     s = data->sockets[i];
-    for(j=0; j<num; j++) {
+    for(j = 0; j<num; j++) {
       if(s == socks[j]) {
         /* this is still supervised */
         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
  * 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_easy *d)
 {
-  struct timeval *tv = &d->state.expiretime;
+  struct curltime *tv = &d->state.expiretime;
   struct curl_llist *list = &d->state.timeoutlist;
   struct curl_llist_element *e;
   struct time_node *node = NULL;
@@ -2520,10 +2532,8 @@ static CURLMcode add_next_timeout(struct timeval now,
     /* copy the first entry to '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,
                                        &d->state.timenode);
   }
@@ -2539,7 +2549,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
   CURLMcode result = CURLM_OK;
   struct Curl_easy *data = NULL;
   struct Curl_tree *t;
-  struct timeval now = Curl_tvnow();
+  struct curltime now = Curl_tvnow();
 
   if(checkall) {
     /* *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
        and callbacks */
     if(result != CURLM_BAD_HANDLE) {
-      data=multi->easyp;
+      data = multi->easyp;
       while(data) {
         singlesocket(multi, data);
         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,
                                long *timeout_ms)
 {
-  static struct timeval tv_zero = {0, 0};
+  static struct curltime tv_zero = {0, 0};
 
   if(multi->timetree) {
     /* we have a tree of expire times */
-    struct timeval now = Curl_tvnow();
+    struct curltime now = Curl_tvnow();
 
     /* splay the lowest to the bottom */
     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
          * millisecond! instead we return 1 until the time is ripe.
          */
-        *timeout_ms=1;
+        *timeout_ms = 1;
     }
     else
       /* 0 means immediately */
@@ -2821,7 +2831,7 @@ static int update_timer(struct Curl_multi *multi)
     return -1;
   }
   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)) {
       multi->timer_lastcall = none;
       /* 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
 multi_addtimeout(struct Curl_easy *data,
-                 struct timeval *stamp,
+                 struct curltime *stamp,
                  expire_id eid)
 {
   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)
 {
   struct Curl_multi *multi = data->multi;
-  struct timeval *nowp = &data->state.expiretime;
+  struct curltime *nowp = &data->state.expiretime;
   int rc;
-  struct timeval set;
+  struct curltime set;
 
   /* this is only interesting while there is still an associated multi struct
      remaining! */
@@ -2932,34 +2942,33 @@ void Curl_expire(struct Curl_easy *data, time_t milli, expire_id id)
   DEBUGASSERT(id < EXPIRE_LAST);
 
   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) {
     set.tv_sec++;
     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) {
     /* This means that the struct is added as a node in the splay tree.
        Compare if the new time is earlier, and only remove-old/add-new if it
        is. */
     time_t diff = curlx_tvdiff(set, *nowp);
 
-    /* remove the previous timer first, if there */
-    multi_deltimeout(data, id);
-
     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;
     }
 
-    /* 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
        the splay tree first and then re-add the new value */
     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);
   }
 
+  /* Indicate that we are in the splay tree and insert the new timer expiry
+     value since it is our local minimum. */
   *nowp = set;
   data->state.timenode.payload = data;
   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)
 {
   struct Curl_multi *multi = data->multi;
-  struct timeval *nowp = &data->state.expiretime;
+  struct curltime *nowp = &data->state.expiretime;
   int rc;
 
   /* 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;
   fprintf(stderr, "* Multi status: %d handles, %d alive\n",
           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) {
       /* only display handles that are not completed */
       fprintf(stderr, "handle %p, state %s, %d sockets\n",
               (void *)data,
               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];
         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 */
   curl_multi_timer_callback timer_cb;
   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 */
 };
 

+ 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
  * you should have received as part of this distribution. The terms
@@ -56,14 +56,15 @@ int Curl_parsenetrc(const char *host,
                     char *netrcfile)
 {
   FILE *file;
-  int retcode=1;
+  int retcode = 1;
   int specific_login = (*loginp && **loginp != 0);
   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"
 
@@ -88,7 +89,7 @@ int Curl_parsenetrc(const char *host,
     }
     else {
       struct passwd *pw;
-      pw= getpwuid(geteuid());
+      pw = getpwuid(geteuid());
       if(pw) {
         home = pw->pw_dir;
       }
@@ -113,16 +114,19 @@ int Curl_parsenetrc(const char *host,
   if(file) {
     char *tok;
     char *tok_buf;
-    bool done=FALSE;
+    bool done = FALSE;
     char netrcbuffer[256];
     int  netrcbuffsize = (int)sizeof(netrcbuffer);
 
     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) {
 
         if((*loginp && **loginp) && (*passwordp && **passwordp)) {
-          done=TRUE;
+          done = TRUE;
           break;
         }
 
@@ -133,22 +137,22 @@ int Curl_parsenetrc(const char *host,
                delimiter that starts the stuff entered for this machine,
                after this we need to search for 'login' and
                'password'. */
-            state=HOSTFOUND;
+            state = HOSTFOUND;
           }
           else if(strcasecompare("default", tok)) {
-            state=HOSTVALID;
-            retcode=0; /* we did find our host */
+            state = HOSTVALID;
+            retcode = 0; /* we did find our host */
           }
           break;
         case HOSTFOUND:
           if(strcasecompare(host, tok)) {
             /* 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
             /* not our host */
-            state=NOTHING;
+            state = NOTHING;
           break;
         case HOSTVALID:
           /* we are now parsing sub-keywords concerning "our" host */
@@ -164,7 +168,7 @@ int Curl_parsenetrc(const char *host,
                 goto out;
               }
             }
-            state_login=0;
+            state_login = 0;
           }
           else if(state_password) {
             if(state_our_login || !specific_login) {
@@ -175,12 +179,12 @@ int Curl_parsenetrc(const char *host,
                 goto out;
               }
             }
-            state_password=0;
+            state_password = 0;
           }
           else if(strcasecompare("login", tok))
-            state_login=1;
+            state_login = 1;
           else if(strcasecompare("password", tok))
-            state_password=1;
+            state_password = 1;
           else if(strcasecompare("machine", tok)) {
             /* ok, there's machine here go => */
             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
  * 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,
                                  char *buffer, size_t length)
 {
-  if(data->set.convtonetwork) {
+  if(data && data->set.convtonetwork) {
     /* use translation callback */
     CURLcode result = data->set.convtonetwork(buffer, length);
     if(result) {
@@ -96,34 +96,37 @@ CURLcode Curl_convert_to_network(struct Curl_easy *data,
   else {
 #ifdef HAVE_ICONV
     /* do the translation ourselves */
+    iconv_t tmpcd = (iconv_t) -1;
+    iconv_t *cd = &tmpcd;
     char *input_ptr, *output_ptr;
     size_t in_bytes, out_bytes, rc;
-    int error;
 
     /* 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,
               "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
               CURL_ICONV_CODESET_OF_NETWORK,
               CURL_ICONV_CODESET_OF_HOST,
-              error, strerror(error));
+              errno, strerror(errno));
         return CURLE_CONV_FAILED;
       }
     }
     /* call iconv */
     input_ptr = output_ptr = buffer;
     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);
+    if(!data)
+      iconv_close(tmpcd);
     if((rc == ICONV_ERROR) || (in_bytes != 0)) {
-      error = ERRNO;
       failf(data,
             "The Curl_convert_to_network iconv call failed with errno %i: %s",
-            error, strerror(error));
+            errno, strerror(errno));
       return CURLE_CONV_FAILED;
     }
 #else
@@ -142,7 +145,7 @@ CURLcode Curl_convert_to_network(struct Curl_easy *data,
 CURLcode Curl_convert_from_network(struct Curl_easy *data,
                                    char *buffer, size_t length)
 {
-  if(data->set.convfromnetwork) {
+  if(data && data->set.convfromnetwork) {
     /* use translation callback */
     CURLcode result = data->set.convfromnetwork(buffer, length);
     if(result) {
@@ -156,34 +159,37 @@ CURLcode Curl_convert_from_network(struct Curl_easy *data,
   else {
 #ifdef HAVE_ICONV
     /* do the translation ourselves */
+    iconv_t tmpcd = (iconv_t) -1;
+    iconv_t *cd = &tmpcd;
     char *input_ptr, *output_ptr;
     size_t in_bytes, out_bytes, rc;
-    int error;
 
     /* 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,
               "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
               CURL_ICONV_CODESET_OF_HOST,
               CURL_ICONV_CODESET_OF_NETWORK,
-              error, strerror(error));
+              errno, strerror(errno));
         return CURLE_CONV_FAILED;
       }
     }
     /* call iconv */
     input_ptr = output_ptr = buffer;
     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);
+    if(!data)
+      iconv_close(tmpcd);
     if((rc == ICONV_ERROR) || (in_bytes != 0)) {
-      error = ERRNO;
       failf(data,
             "Curl_convert_from_network iconv call failed with errno %i: %s",
-            error, strerror(error));
+            errno, strerror(errno));
       return CURLE_CONV_FAILED;
     }
 #else
@@ -202,7 +208,7 @@ CURLcode Curl_convert_from_network(struct Curl_easy *data,
 CURLcode Curl_convert_from_utf8(struct Curl_easy *data,
                                 char *buffer, size_t length)
 {
-  if(data->set.convfromutf8) {
+  if(data && data->set.convfromutf8) {
     /* use translation callback */
     CURLcode result = data->set.convfromutf8(buffer, length);
     if(result) {
@@ -216,35 +222,38 @@ CURLcode Curl_convert_from_utf8(struct Curl_easy *data,
   else {
 #ifdef HAVE_ICONV
     /* do the translation ourselves */
-    const char *input_ptr;
+    iconv_t tmpcd = (iconv_t) -1;
+    iconv_t *cd = &tmpcd;
+    char *input_ptr;
     char *output_ptr;
     size_t in_bytes, out_bytes, rc;
-    int error;
 
     /* 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,
               "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
               CURL_ICONV_CODESET_OF_HOST,
               CURL_ICONV_CODESET_FOR_UTF8,
-              error, strerror(error));
+              errno, strerror(errno));
         return CURLE_CONV_FAILED;
       }
     }
     /* call iconv */
     input_ptr = output_ptr = buffer;
     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);
+    if(!data)
+      iconv_close(tmpcd);
     if((rc == ICONV_ERROR) || (in_bytes != 0)) {
-      error = ERRNO;
       failf(data,
             "The Curl_convert_from_utf8 iconv call failed with errno %i: %s",
-            error, strerror(error));
+            errno, strerror(errno));
       return CURLE_CONV_FAILED;
     }
     if(output_ptr < input_ptr) {
@@ -310,29 +319,4 @@ void Curl_convert_close(struct Curl_easy *data)
 #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 */

+ 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
  * 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);
 CURLcode Curl_convert_from_utf8(struct Curl_easy *data,
                                  char *buffer, size_t length);
-CURLcode Curl_convert_form(struct Curl_easy *data, struct FormData *form);
 #else
 #define Curl_convert_clone(a,b,c,d) ((void)a, CURLE_OK)
 #define Curl_convert_init(x) Curl_nop_stmt
@@ -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_from_network(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 /* 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.
  *
  * 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 */
   ldap_disconnect,                      /* disconnect */
   ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
   PORT_LDAP,                            /* defport */
   CURLPROTO_LDAP,                       /* protocol */
   PROTOPT_NONE                          /* flags */
@@ -110,6 +111,7 @@ const struct Curl_handler Curl_handler_ldaps = {
   ZERO_NULL,                            /* perform_getsock */
   ldap_disconnect,                      /* disconnect */
   ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
   PORT_LDAPS,                           /* defport */
   CURLPROTO_LDAP,                       /* protocol */
   PROTOPT_SSL                           /* flags */
@@ -150,7 +152,7 @@ static CURLcode ldap_setup_connection(struct connectdata *conn)
 {
   ldapconninfo *li;
   LDAPURLDesc *lud;
-  struct Curl_easy *data=conn->data;
+  struct Curl_easy *data = conn->data;
   int rc, proto;
   CURLcode status;
 
@@ -196,7 +198,7 @@ static CURLcode ldap_connect(struct connectdata *conn, bool *done)
   (void)done;
 
   strcpy(hosturl, "ldap");
-  ptr = hosturl+4;
+  ptr = hosturl + 4;
   if(conn->handler->flags & PROTOPT_SSL)
     *ptr++ = 's';
   snprintf(ptr, sizeof(hosturl)-(ptr-hosturl), "://%s:%d",
@@ -352,7 +354,7 @@ static CURLcode ldap_do(struct connectdata *conn, bool *done)
   int rc = 0;
   LDAPURLDesc *ludp = NULL;
   int msgid;
-  struct Curl_easy *data=conn->data;
+  struct Curl_easy *data = conn->data;
 
   connkeep(conn, "OpenLDAP do");
 
@@ -517,7 +519,7 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
       else
         binary = 0;
 
-      for(i=0; bvals[i].bv_val != NULL; i++) {
+      for(i = 0; bvals[i].bv_val != NULL; i++) {
         int binval = 0;
         writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1);
         if(writeerr) {
@@ -547,7 +549,7 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
           else {
             /* check for unprintable characters */
             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])) {
                 binval = 1;
                 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
  * 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
      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
      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 */
   {"O",  -2 * 60},         /* Oscar */
   {"P",  -3 * 60},         /* Papa */
@@ -205,14 +205,14 @@ static int checkday(const char *check, size_t len)
 {
   int i;
   const char * const *what;
-  bool found= FALSE;
+  bool found = FALSE;
   if(len > 3)
     what = &weekday[0];
   else
     what = &Curl_wkday[0];
-  for(i=0; i<7; i++) {
+  for(i = 0; i<7; i++) {
     if(strcasecompare(check, what[0])) {
-      found=TRUE;
+      found = TRUE;
       break;
     }
     what++;
@@ -224,12 +224,12 @@ static int checkmonth(const char *check)
 {
   int i;
   const char * const *what;
-  bool found= FALSE;
+  bool found = FALSE;
 
   what = &Curl_month[0];
-  for(i=0; i<12; i++) {
+  for(i = 0; i<12; i++) {
     if(strcasecompare(check, what[0])) {
-      found=TRUE;
+      found = TRUE;
       break;
     }
     what++;
@@ -244,12 +244,12 @@ static int checktz(const char *check)
 {
   unsigned int i;
   const struct tzinfo *what;
-  bool found= FALSE;
+  bool found = FALSE;
 
   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)) {
-      found=TRUE;
+      found = TRUE;
       break;
     }
     what++;
@@ -331,21 +331,21 @@ static time_t my_timegm(struct my_tm *tm)
 static int parsedate(const char *date, time_t *output)
 {
   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;
   enum assume dignext = DATE_MDAY;
   const char *indate = date; /* save the original pointer */
   int part = 0; /* max 6 parts */
 
   while(*date && (part < 6)) {
-    bool found=FALSE;
+    bool found = FALSE;
 
     skip(&date);
 
@@ -386,7 +386,7 @@ static int parsedate(const char *date, time_t *output)
       /* a digit */
       int val;
       char *end;
-      int len=0;
+      int len = 0;
       if((secnum == -1) &&
          (3 == sscanf(date, "%02d:%02d:%02d%n",
                       &hournum, &minnum, &secnum, &len))) {
@@ -404,12 +404,12 @@ static int parsedate(const char *date, time_t *output)
         int error;
         int old_errno;
 
-        old_errno = ERRNO;
-        SET_ERRNO(0);
+        old_errno = errno;
+        errno = 0;
         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)
           return PARSEDATE_FAIL;

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

@@ -47,10 +47,10 @@
 time_t Curl_pp_state_timeout(struct pingpong *pp)
 {
   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 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;
 
   /* 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;
   time_t interval_ms;
   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;
 
-  if(timeout_ms <=0) {
+  if(timeout_ms <= 0) {
     failf(data, "server response timeout");
     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 */
 {
   ssize_t perline; /* count bytes per line */
-  bool keepon=TRUE;
+  bool keepon = TRUE;
   ssize_t gotbytes;
   char *ptr;
   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 */
   *size = 0;
 
-  ptr=buf + pp->nread_resp;
+  ptr = buf + pp->nread_resp;
 
   /* number of bytes in the current line, so far */
   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
        * 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);
       gotbytes = (ssize_t)pp->cache_size;
       free(pp->cache);    /* free the cache */
@@ -351,7 +351,7 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd,
       pp->nread_resp += gotbytes;
       for(i = 0; i < gotbytes; ptr++, i++) {
         perline++;
-        if(*ptr=='\n') {
+        if(*ptr == '\n') {
           /* a newline is CRLF in pp-talk, so the CR is ignored as
              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 */
             size_t n = ptr - pp->linestart_resp;
             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 */
 
             *size = pp->nread_resp; /* size of the response */
             pp->nread_resp = 0; /* restart */
             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 {
     free(pp->sendthis);
-    pp->sendthis=NULL;
+    pp->sendthis = NULL;
     pp->sendleft = pp->sendsize = 0;
     pp->response = Curl_tvnow();
   }

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

@@ -58,7 +58,7 @@ struct pingpong {
                      server */
   size_t sendleft; /* number of bytes left to send from the sendthis buffer */
   size_t sendsize; /* total size of the sendthis buffer */
-  struct 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 */
   long response_time; /* When no timeout is given, this is the amount of
                          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;
 }
 
+struct blacklist_node {
+  struct curl_llist_element list;
+  char server_name[1];
+};
+
 bool Curl_pipeline_server_blacklisted(struct Curl_easy *handle,
                                       char *server_name)
 {
   if(handle->multi && server_name) {
-    struct curl_llist *blacklist =
+    struct curl_llist *list =
       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));
@@ -259,11 +258,6 @@ bool Curl_pipeline_server_blacklisted(struct Curl_easy *handle,
   return FALSE;
 }
 
-struct blacklist_node {
-  struct curl_llist_element list;
-  char server_name[1];
-};
-
 CURLMcode Curl_pipeline_set_server_blacklist(char **servers,
                                              struct curl_llist *list)
 {
@@ -286,8 +280,7 @@ CURLMcode Curl_pipeline_set_server_blacklist(char **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++;
     }
   }

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

@@ -125,6 +125,7 @@ const struct Curl_handler Curl_handler_pop3 = {
   ZERO_NULL,                        /* perform_getsock */
   pop3_disconnect,                  /* disconnect */
   ZERO_NULL,                        /* readwrite */
+  ZERO_NULL,                        /* connection_check */
   PORT_POP3,                        /* defport */
   CURLPROTO_POP3,                   /* protocol */
   PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */
@@ -151,6 +152,7 @@ const struct Curl_handler Curl_handler_pop3s = {
   ZERO_NULL,                        /* perform_getsock */
   pop3_disconnect,                  /* disconnect */
   ZERO_NULL,                        /* readwrite */
+  ZERO_NULL,                        /* connection_check */
   PORT_POP3S,                       /* defport */
   CURLPROTO_POP3S,                  /* protocol */
   PROTOPT_CLOSEACTION | PROTOPT_SSL
@@ -158,58 +160,6 @@ const struct Curl_handler Curl_handler_pop3s = {
 };
 #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 */
 static const struct SASLproto saslpop3 = {
   "pop",                      /* The service name */
@@ -1355,31 +1305,6 @@ static CURLcode pop3_setup_connection(struct connectdata *conn)
 
   /* Clear the TLS upgraded flag */
   conn->tls_upgraded = FALSE;
-
-  /* Set up the proxy if necessary */
-  if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
-    /* Unless we have asked to tunnel POP3 operations through the proxy, we
-       switch and use HTTP operations only */
-#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 */
 
   return CURLE_OK;

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

@@ -134,7 +134,7 @@ int Curl_pgrsDone(struct connectdata *conn)
 {
   int rc;
   struct Curl_easy *data = conn->data;
-  data->progress.lastshow=0;
+  data->progress.lastshow = 0;
   rc = Curl_pgrsUpdate(conn); /* the final (forced) update */
   if(rc)
     return rc;
@@ -149,21 +149,20 @@ int Curl_pgrsDone(struct connectdata *conn)
   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_pgrsSetUploadSize(data, -1);
 }
 
+/*
+ * @unittest: 1399
+ */
 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) {
   default:
@@ -177,45 +176,58 @@ void Curl_pgrsTime(struct Curl_easy *data, timerid timer)
   case TIMER_STARTSINGLE:
     /* This is set at the start of each single fetch */
     data->progress.t_startsingle = now;
+    data->progress.is_t_startransfer_set = false;
     break;
-
   case TIMER_STARTACCEPT:
-    data->progress.t_acceptdata = Curl_tvnow();
+    data->progress.t_acceptdata = now;
     break;
-
   case TIMER_NAMELOOKUP:
-    data->progress.t_nslookup =
-      Curl_tvdiff_secs(now, data->progress.t_startsingle);
+    delta = &data->progress.t_nslookup;
     break;
   case TIMER_CONNECT:
-    data->progress.t_connect =
-      Curl_tvdiff_secs(now, data->progress.t_startsingle);
+    delta = &data->progress.t_connect;
     break;
   case TIMER_APPCONNECT:
-    data->progress.t_appconnect =
-      Curl_tvdiff_secs(now, data->progress.t_startsingle);
+    delta = &data->progress.t_appconnect;
     break;
   case TIMER_PRETRANSFER:
-    data->progress.t_pretransfer =
-      Curl_tvdiff_secs(now, data->progress.t_startsingle);
+    delta = &data->progress.t_pretransfer;
     break;
   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:
     /* this is the normal end-of-transfer thing */
     break;
   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;
   }
+  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)
 {
   data->progress.speeder_c = 0; /* reset the progress meter display */
   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_usec = 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,
                             curl_off_t startsize,
                             curl_off_t limit,
-                            struct timeval start,
-                            struct timeval now)
+                            struct curltime start,
+                            struct curltime now)
 {
   curl_off_t size = cursize - startsize;
   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)
 {
-  struct timeval now = Curl_tvnow();
+  struct curltime now = Curl_tvnow();
 
   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)
 {
-  struct timeval now = Curl_tvnow();
+  struct curltime now = Curl_tvnow();
 
   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)
 {
-  struct timeval now;
+  struct curltime now;
   int result;
   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_expected_transfer;
   curl_off_t timespent;
@@ -353,26 +365,26 @@ int Curl_pgrsUpdate(struct connectdata *conn)
   char time_left[10];
   char time_total[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;
-  bool shownow=FALSE;
+  bool shownow = FALSE;
 
   now = Curl_tvnow(); /* what time is it */
 
   /* 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 */
   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 */
   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 */
   if(data->progress.lastshow != now.tv_sec) {
@@ -380,11 +392,10 @@ int Curl_pgrsUpdate(struct connectdata *conn)
 
     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.downloaded>data->progress.uploaded?
-      data->progress.downloaded:data->progress.uploaded;
+      data->progress.downloaded + data->progress.uploaded;
 
     /* remember the exact time for this moment */
     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
        transfer. Imagine, after one second we have filled in two entries,
        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;
 
     /* 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 oldest entry possible. While we have less than CURR_TIME
          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;
 
       /* Figure out the exact time for the time span */
       span_ms = Curl_tvdiff(now,
                             data->progress.speeder_time[checkindex]);
       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 */
       {
@@ -433,10 +444,9 @@ int Curl_pgrsUpdate(struct connectdata *conn)
       }
     }
     else
-      /* the first second we use the main average */
+      /* the first second we use the average */
       data->progress.current_speed =
-        (data->progress.ulspeed>data->progress.dlspeed)?
-        data->progress.ulspeed:data->progress.dlspeed;
+        data->progress.ulspeed + data->progress.dlspeed;
 
   } /* Calculations end */
 
@@ -445,22 +455,22 @@ int Curl_pgrsUpdate(struct connectdata *conn)
 
     if(data->set.fxferinfo) {
       /* 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)
         failf(data, "Callback aborted");
       return result;
     }
     if(data->set.fprogress) {
       /* 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)
         failf(data, "Callback aborted");
       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
  * 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_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size);
 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);
 long Curl_pgrsLimitWaitTime(curl_off_t cursize,
                             curl_off_t startsize,
                             curl_off_t limit,
-                            struct timeval start,
-                            struct timeval now);
+                            struct curltime start,
+                            struct curltime now);
 
 /* Don't show progress for sizes smaller than: */
 #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
 
   if(!seeded) {
-    struct timeval now = curlx_tvnow();
+    struct curltime now = curlx_tvnow();
     infof(data, "WARNING: Using weak random seed\n");
     randseed += (unsigned int)now.tv_usec + (unsigned int)now.tv_sec;
     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);
 
+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
    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 */
   rtsp_disconnect,                      /* disconnect */
   rtsp_rtp_readwrite,                   /* readwrite */
+  rtsp_conncheck,                       /* connection_check */
   PORT_RTSP,                            /* defport */
   CURLPROTO_RTSP,                       /* protocol */
   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
  * and distinguish between closed and data.
  */
-bool Curl_rtsp_connisdead(struct connectdata *check)
+bool rtsp_connisdead(struct connectdata *check)
 {
   int sval;
   bool ret_val = TRUE;
@@ -165,6 +169,23 @@ bool Curl_rtsp_connisdead(struct connectdata *check)
   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)
 {
   CURLcode httpStatus;
@@ -229,7 +250,7 @@ static CURLcode rtsp_done(struct connectdata *conn,
 static CURLcode rtsp_do(struct connectdata *conn, bool *done)
 {
   struct Curl_easy *data = conn->data;
-  CURLcode result=CURLE_OK;
+  CURLcode result = CURLE_OK;
   Curl_RtspReq rtspreq = data->set.rtspreq;
   struct RTSP *rtsp = data->req.protop;
   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;
   size_t wrote;
   curl_write_callback writeit;
+  void *user_ptr;
 
   if(len == 0) {
     failf(data, "Cannot write a 0 size RTP packet.");
     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) {
     failf(data, "Cannot pause RTP");

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

@@ -25,13 +25,11 @@
 
 extern const struct Curl_handler Curl_handler_rtsp;
 
-bool Curl_rtsp_connisdead(struct connectdata *check);
 CURLcode Curl_rtsp_parseheader(struct connectdata *conn, char *header);
 
 #else
 /* disabled */
 #define Curl_rtsp_parseheader(x,y) CURLE_NOT_BUILT_IN
-#define Curl_rtsp_connisdead(x) TRUE
 
 #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
  * below.
  *
- * Copyright (c) 1998, 1999 Kungliga Tekniska Högskolan
+ * Copyright (c) 1998, 1999, 2017 Kungliga Tekniska Högskolan
  * (Royal Institute of Technology, Stockholm, Sweden).
  *
  * 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, ...)
 {
   int ftp_code;
-  ssize_t nread=0;
+  ssize_t nread = 0;
   va_list args;
   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
   struct timeval pending_tv;
 #endif
-  struct timeval initial_tv;
+  struct curltime initial_tv;
   int pending_ms;
   int error;
 #endif
@@ -158,7 +158,7 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */
   fd_set fds_err;
   curl_socket_t maxfd;
 #endif
-  struct timeval initial_tv = {0, 0};
+  struct curltime initial_tv = {0, 0};
   int pending_ms = 0;
   int error;
   int r;
@@ -398,7 +398,7 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms)
   fd_set fds_err;
   curl_socket_t maxfd;
 #endif
-  struct timeval initial_tv = {0, 0};
+  struct curltime initial_tv = {0, 0};
   bool fds_none = TRUE;
   unsigned int i;
   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.
  */
-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;
 

+ 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
  * you should have received as part of this distribution. The terms
@@ -36,7 +36,8 @@
 
 #if !defined(HAVE_STRUCT_POLLFD) && \
     !defined(HAVE_SYS_POLL_H) && \
-    !defined(HAVE_POLL_H)
+    !defined(HAVE_POLL_H) && \
+    !defined(POLLIN)
 
 #define POLLIN      0x01
 #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') {
       /* This block of incoming data starts with the
          previous block's LF so get rid of it */
-      memmove(startPtr, startPtr+1, size-1);
+      memmove(startPtr, startPtr + 1, size-1);
       size--;
       /* and it wasn't a bare CR but a CRLF conversion instead */
       data->state.crlf_conversions++;
@@ -75,7 +75,7 @@ static size_t convert_lineends(struct Curl_easy *data,
   inPtr = outPtr = memchr(startPtr, '\r', size);
   if(inPtr) {
     /* 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 */
       if(memcmp(inPtr, "\r\n", 2) == 0) {
         /* CRLF found, bump past the CR and copy the NL */
@@ -98,7 +98,7 @@ static size_t convert_lineends(struct Curl_easy *data,
       inPtr++;
     } /* end of while loop */
 
-    if(inPtr < startPtr+size) {
+    if(inPtr < startPtr + size) {
       /* handle last byte */
       if(*inPtr == '\r') {
         /* deal with a CR at the end of the buffer */
@@ -112,7 +112,7 @@ static size_t convert_lineends(struct Curl_easy *data,
       }
       outPtr++;
     }
-    if(outPtr < startPtr+size)
+    if(outPtr < startPtr + size)
       /* tidy up by null terminating the now shorter data */
       *outPtr = '\0';
 
@@ -279,7 +279,7 @@ CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn,
   if(!s)
     return CURLE_OUT_OF_MEMORY; /* failure */
 
-  bytes_written=0;
+  bytes_written = 0;
   write_len = strlen(s);
   sptr = s;
 
@@ -387,7 +387,7 @@ ssize_t Curl_send_plain(struct connectdata *conn, int num,
 #endif
       ) {
       /* this is just a case of EWOULDBLOCK */
-      bytes_written=0;
+      bytes_written = 0;
       *code = CURLE_AGAIN;
     }
     else {
@@ -480,7 +480,7 @@ static CURLcode pausewrite(struct Curl_easy *data,
   bool newtype = TRUE;
 
   if(s->tempcount) {
-    for(i=0; i< s->tempcount; i++) {
+    for(i = 0; i< s->tempcount; i++) {
       if(s->tempwrite[i].type == type) {
         /* data for this type exists */
         newtype = FALSE;
@@ -704,7 +704,7 @@ CURLcode Curl_read(struct connectdata *conn, /* connection data */
      us use the correct ssl handle. */
   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(pipelining) {
@@ -823,8 +823,8 @@ int Curl_debug(struct Curl_easy *data, curl_infotype type,
   int rc;
   if(data->set.printhost && conn && conn->host.dispname) {
     char buffer[160];
-    const char *t=NULL;
-    const char *w="Data";
+    const char *t = NULL;
+    const char *w = "Data";
     switch(type) {
     case CURLINFO_HEADER_IN:
       w = "Header";

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

@@ -34,7 +34,7 @@
 #include <process.h>
 #ifdef CURL_WINDOWS_APP
 #define getpid GetCurrentProcessId
-#else
+#elif !defined(MSDOS)
 #define getpid _getpid
 #endif
 #endif
@@ -85,6 +85,7 @@ const struct Curl_handler Curl_handler_smb = {
   ZERO_NULL,                            /* perform_getsock */
   smb_disconnect,                       /* disconnect */
   ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
   PORT_SMB,                             /* defport */
   CURLPROTO_SMB,                        /* protocol */
   PROTOPT_NONE                          /* flags */
@@ -109,6 +110,7 @@ const struct Curl_handler Curl_handler_smbs = {
   ZERO_NULL,                            /* perform_getsock */
   smb_disconnect,                       /* disconnect */
   ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
   PORT_SMBS,                            /* defport */
   CURLPROTO_SMBS,                       /* protocol */
   PROTOPT_SSL                           /* flags */
@@ -713,6 +715,23 @@ static CURLcode smb_connection_state(struct connectdata *conn, bool *done)
   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)
 {
   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;
   CURLcode result;
   void *msg = NULL;
+  const struct smb_nt_create_response *smb_m;
 
   /* Start the request */
   if(req->state == SMB_REQUESTING) {
@@ -765,7 +785,8 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done)
       next_state = SMB_TREE_DISCONNECT;
       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;
     if(conn->data->set.upload) {
       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;
     }
     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);
+      if(conn->data->set.get_filetime)
+        get_posix_time(&conn->data->info.filetime, &smb_m->last_change_time);
       next_state = SMB_DOWNLOAD;
     }
     break;

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

@@ -67,6 +67,7 @@
 #include "transfer.h"
 #include "escape.h"
 #include "http.h" /* for HTTP proxy tunnel stuff */
+#include "mime.h"
 #include "socks.h"
 #include "smtp.h"
 #include "strtoofft.h"
@@ -124,6 +125,7 @@ const struct Curl_handler Curl_handler_smtp = {
   ZERO_NULL,                        /* perform_getsock */
   smtp_disconnect,                  /* disconnect */
   ZERO_NULL,                        /* readwrite */
+  ZERO_NULL,                        /* connection_check */
   PORT_SMTP,                        /* defport */
   CURLPROTO_SMTP,                   /* protocol */
   PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */
@@ -150,6 +152,7 @@ const struct Curl_handler Curl_handler_smtps = {
   ZERO_NULL,                        /* perform_getsock */
   smtp_disconnect,                  /* disconnect */
   ZERO_NULL,                        /* readwrite */
+  ZERO_NULL,                        /* connection_check */
   PORT_SMTPS,                       /* defport */
   CURLPROTO_SMTPS,                  /* protocol */
   PROTOPT_CLOSEACTION | PROTOPT_SSL
@@ -157,58 +160,6 @@ const struct Curl_handler Curl_handler_smtps = {
 };
 #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 */
 static const struct SASLproto saslsmtp = {
   "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 */
-  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);
 
     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 */
     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
        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.
@@ -1299,7 +1283,7 @@ static CURLcode smtp_perform(struct connectdata *conn, bool *connected,
   smtp->rcpt = data->set.mail_rcpt;
 
   /* 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 */
     result = smtp_perform_mail(conn);
   else
@@ -1451,30 +1435,6 @@ static CURLcode smtp_setup_connection(struct connectdata *conn)
   /* Clear the TLS upgraded flag */
   conn->tls_upgraded = FALSE;
 
-  /* Set up the proxy if necessary */
-  if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
-    /* Unless we have asked to tunnel SMTP operations through the proxy, we
-       switch and use HTTP operations only */
-#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 */
   result = smtp_init(conn);
   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
  * 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)"
 *   Nonsupport "Identification Protocol (RFC1413)"
 */
-CURLcode Curl_SOCKS4(const char *proxy_name,
+CURLcode Curl_SOCKS4(const char *proxy_user,
                      const char *hostname,
                      int remote_port,
                      int sockindex,
@@ -154,7 +154,7 @@ CURLcode Curl_SOCKS4(const char *proxy_name,
   /* DNS resolve only for SOCKS4, not SOCKS4a */
   if(!protocol4a) {
     struct Curl_dns_entry *dns;
-    Curl_addrinfo *hp=NULL;
+    Curl_addrinfo *hp = NULL;
     int rc;
 
     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.
      */
     if(dns)
-      hp=dns->addr;
+      hp = dns->addr;
     if(hp) {
       char buf[64];
       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)".
    */
   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) {
       failf(data, "Too long SOCKS proxy name, can't use!\n");
       return CURLE_COULDNT_CONNECT;
     }
     /* 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.",
             (unsigned char)socksreq[4], (unsigned char)socksreq[5],
             (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]);
       return CURLE_COULDNT_CONNECT;
     case 92:
@@ -316,7 +316,7 @@ CURLcode Curl_SOCKS4(const char *proxy_name,
             "identd on the client.",
             (unsigned char)socksreq[4], (unsigned char)socksreq[5],
             (unsigned char)socksreq[6], (unsigned char)socksreq[7],
-            (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]),
+            (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
             (unsigned char)socksreq[1]);
       return CURLE_COULDNT_CONNECT;
     case 93:
@@ -326,7 +326,7 @@ CURLcode Curl_SOCKS4(const char *proxy_name,
             "report different user-ids.",
             (unsigned char)socksreq[4], (unsigned char)socksreq[5],
             (unsigned char)socksreq[6], (unsigned char)socksreq[7],
-            (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]),
+            (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
             (unsigned char)socksreq[1]);
       return CURLE_COULDNT_CONNECT;
     default:
@@ -335,7 +335,7 @@ CURLcode Curl_SOCKS4(const char *proxy_name,
             ", Unknown.",
             (unsigned char)socksreq[4], (unsigned char)socksreq[5],
             (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]);
       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
  * destination server.
  */
-CURLcode Curl_SOCKS5(const char *proxy_name,
+CURLcode Curl_SOCKS5(const char *proxy_user,
                      const char *proxy_password,
                      const char *hostname,
                      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) */
+  int idx;
   ssize_t actualread;
   ssize_t written;
   int result;
@@ -386,6 +387,8 @@ CURLcode Curl_SOCKS5(const char *proxy_name,
     (conn->socks_proxy.proxytype == CURLPROXY_SOCKS5) ? TRUE : FALSE;
   const size_t hostname_len = strlen(hostname);
   ssize_t len = 0;
+  const unsigned long auth = data->set.socks5auth;
+  bool allow_gssapi = FALSE;
 
   if(conn->bits.httpproxy)
     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;
   }
 
-  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)
-  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
 
+  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);
 
   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);
 
-  result=Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread);
+  result = Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread);
   if(result || (actualread != 2)) {
     failf(data, "Unable to receive initial SOCKS5 response.");
     return CURLE_COULDNT_CONNECT;
@@ -484,7 +498,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name,
     ;
   }
 #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);
     if(code) {
       failf(data, "Unable to negotiate SOCKS5 GSS-API context.");
@@ -494,13 +508,13 @@ CURLcode Curl_SOCKS5(const char *proxy_name,
 #endif
   else if(socksreq[1] == 2) {
     /* 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);
     }
     else {
-      proxy_name_len = 0;
+      proxy_user_len = 0;
       proxy_password_len = 0;
     }
 
@@ -513,10 +527,10 @@ CURLcode Curl_SOCKS5(const char *proxy_name,
      */
     len = 0;
     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;
     if(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;
     }
 
-    result=Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread);
+    result = Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread);
     if(result || (actualread != 2)) {
       failf(data, "Unable to receive SOCKS5 sub-negotiation response.");
       return CURLE_COULDNT_CONNECT;
@@ -545,17 +559,13 @@ CURLcode Curl_SOCKS5(const char *proxy_name,
   }
   else {
     /* 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,
             "SOCKS5 GSSAPI per-message authentication is not supported.");
       return CURLE_COULDNT_CONNECT;
     }
     if(socksreq[1] == 255) {
-#endif
-      if(!proxy_name || !*proxy_name) {
+      if(!proxy_user || !*proxy_user) {
         failf(data,
               "No authentication method was acceptable. (It is quite likely"
               " 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.
      */
     if(dns)
-      hp=dns->addr;
+      hp = dns->addr;
     if(hp) {
       int i;
       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
  * 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);
       if(maj_stat == GSS_S_COMPLETE) {
         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;
         }
         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);
     }
     if(sizeof(buf) > len + 3) {
-      strcpy(buf+len, ".\n");
+      strcpy(buf + len, ".\n");
       len += 2;
     }
     msg_ctx = 0;
@@ -86,7 +86,7 @@ static int check_gss_err(struct Curl_easy *data,
                                     &msg_ctx, &status_string);
       if(maj_stat == GSS_S_COMPLETE) {
         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);
         break;
       }
@@ -119,7 +119,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
   gss_name_t       server = GSS_C_NO_NAME;
   gss_name_t       gss_client_name = GSS_C_NO_NAME;
   unsigned short   us_length;
-  char             *user=NULL;
+  char             *user = NULL;
   unsigned char socksreq[4]; /* room for GSS-API exchange header only */
   const char *serviceptr = data->set.str[STRING_PROXY_SERVICE_NAME] ?
                            data->set.str[STRING_PROXY_SERVICE_NAME] : "rcmd";
@@ -146,11 +146,12 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
   }
   else {
     service.value = malloc(serviceptr_length +
-                           strlen(conn->socks_proxy.host.name)+2);
+                           strlen(conn->socks_proxy.host.name) + 2);
     if(!service.value)
       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);
 
     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[1] = 1;    /* authentication message type */
       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);
       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)) {
       failf(data, "Failed to receive GSS-API authentication response.");
       gss_release_name(&gss_status, &server);
@@ -261,11 +262,11 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
       return CURLE_COULDNT_CONNECT;
     }
 
-    memcpy(&us_length, socksreq+2, sizeof(short));
+    memcpy(&us_length, socksreq + 2, sizeof(short));
     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) {
       failf(data,
             "Could not allocate memory for GSS-API authentication "
@@ -275,8 +276,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
       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)) {
       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.");
     return CURLE_COULDNT_CONNECT;
   }
-  user=malloc(gss_send_token.length+1);
+  user = malloc(gss_send_token.length + 1);
   if(!user) {
     gss_delete_sec_context(&gss_status, &gss_context, NULL);
     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);
   infof(data, "SOCKS5 server authencticated user %s with GSS-API.\n",user);
   free(user);
-  user=NULL;
+  user = NULL;
 
   /* Do encryption */
   socksreq[0] = 1;    /* GSS-API subnegotiation version */
@@ -341,7 +342,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
     gss_enc = 1;
 
   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 */
   gss_enc = 0;
   /*
@@ -376,7 +377,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
    */
   if(data->set.socks5_gssapi_nec) {
     us_length = htons((short)1);
-    memcpy(socksreq+2, &us_length, sizeof(short));
+    memcpy(socksreq + 2, &us_length, sizeof(short));
   }
   else {
     gss_send_token.length = 1;
@@ -401,7 +402,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
     gss_release_buffer(&gss_status, &gss_send_token);
 
     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);
@@ -433,7 +434,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
     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)) {
     failf(data, "Failed to receive GSS-API encryption response.");
     gss_delete_sec_context(&gss_status, &gss_context, NULL);
@@ -455,17 +456,17 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
     return CURLE_COULDNT_CONNECT;
   }
 
-  memcpy(&us_length, socksreq+2, sizeof(short));
+  memcpy(&us_length, socksreq + 2, sizeof(short));
   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) {
     gss_delete_sec_context(&gss_status, &gss_context, NULL);
     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)) {
     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",
-        (socksreq[0]==0)?"out GSS-API data":
-        ((socksreq[0]==1)?" GSS-API integrity":" GSS-API confidentiality"));
+        (socksreq[0] == 0)?"out GSS-API data":
+        ((socksreq[0] == 1)?" GSS-API integrity":" GSS-API confidentiality"));
 
   conn->socks5_gssapi_enctype = socksreq[0];
   if(socksreq[0] == 0)

+ 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]>
  *
  * 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)
       return CURLE_OUT_OF_MEMORY;
     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);
   }
 
@@ -199,7 +199,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
       socksreq[0] = 1;    /* GSS-API subnegotiation version */
       socksreq[1] = 1;    /* authentication message type */
       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);
       if(code || (4 != written)) {
@@ -283,7 +283,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
       return CURLE_COULDNT_CONNECT;
     }
 
-    memcpy(&us_length, socksreq+2, sizeof(short));
+    memcpy(&us_length, socksreq + 2, sizeof(short));
     us_length = ntohs(us_length);
 
     sspi_recv_token.cbBuffer = us_length;
@@ -341,7 +341,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
     gss_enc = 1;
 
   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 */
   gss_enc = 0;
   /*
@@ -377,7 +377,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
 
   if(data->set.socks5_gssapi_nec) {
     us_length = htons((short)1);
-    memcpy(socksreq+2, &us_length, sizeof(short));
+    memcpy(socksreq + 2, &us_length, sizeof(short));
   }
   else {
     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,
            sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer);
     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);
 
     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;
 
     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);
@@ -517,7 +517,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
     return CURLE_COULDNT_CONNECT;
   }
 
-  memcpy(&us_length, socksreq+2, sizeof(short));
+  memcpy(&us_length, socksreq + 2, sizeof(short));
   us_length = ntohs(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",
-        (socksreq[0]==0)?"out GSS-API data":
-        ((socksreq[0]==1)?" GSS-API integrity":" GSS-API confidentiality"));
+        (socksreq[0] == 0)?"out GSS-API data":
+        ((socksreq[0] == 1)?" GSS-API integrity":" GSS-API confidentiality"));
 
   /* For later use if encryption is required
      conn->socks5_gssapi_enctype = socksreq[0];

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

@@ -30,14 +30,14 @@
 
 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
  */
 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 < 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
  * you should have received as part of this distribution. The terms
@@ -28,6 +28,6 @@
 
 void Curl_speedinit(struct Curl_easy *data);
 CURLcode Curl_speedcheck(struct Curl_easy *data,
-                         struct timeval now);
+                         struct curltime now);
 
 #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
  * 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
  * 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 N, *l, *r, *y;
@@ -97,24 +97,26 @@ struct Curl_tree *Curl_splay(struct timeval i,
  *
  * @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 *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)
     return t;
 
   if(t != NULL) {
     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
          a doubly-linked circular list of nodes. We add the new 'node' struct
          to the end of this list. */
 
       node->key = KEY_NOTUSED; /* we set the key in the sub node to NOTUSED
-                               to quickly identify this node as a subnode */
+                                  to quickly identify this node as a subnode */
       node->samen = t;
       node->samep = t->samep;
       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
    resulting tree.  best-fit means the smallest node if it is not larger than
    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;
 
   if(!t) {
@@ -209,7 +211,9 @@ int Curl_splayremovebyaddr(struct Curl_tree *t,
                            struct Curl_tree *removenode,
                            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;
 
   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
  * you should have received as part of this distribution. The terms
@@ -22,30 +22,31 @@
  *
  ***************************************************************************/
 #include "curl_setup.h"
+#include "timeval.h"
 
 struct Curl_tree {
   struct Curl_tree *smaller; /* smaller node */
   struct Curl_tree *larger;  /* larger node */
   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 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 */
 };
 
-struct Curl_tree *Curl_splay(struct timeval i,
+struct Curl_tree *Curl_splay(struct curltime i,
                              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 *newnode);
 
 #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 **removed);
 #endif
 
-struct Curl_tree *Curl_splaygetbest(struct timeval key,
+struct Curl_tree *Curl_splaygetbest(struct curltime key,
                                     struct Curl_tree *t,
                                     struct Curl_tree **removed);
 
@@ -53,8 +54,8 @@ int Curl_splayremovebyaddr(struct Curl_tree *t,
                            struct Curl_tree *removenode,
                            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 : 0))))
 

+ 37 - 21
Utilities/cmcurl/lib/ssh.c

@@ -177,6 +177,7 @@ const struct Curl_handler Curl_handler_scp = {
   ssh_perform_getsock,                  /* perform_getsock */
   scp_disconnect,                       /* disconnect */
   ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
   PORT_SSH,                             /* defport */
   CURLPROTO_SCP,                        /* protocol */
   PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
@@ -203,6 +204,7 @@ const struct Curl_handler Curl_handler_sftp = {
   ssh_perform_getsock,                  /* perform_getsock */
   sftp_disconnect,                      /* disconnect */
   ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
   PORT_SSH,                             /* defport */
   CURLPROTO_SFTP,                       /* protocol */
   PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
@@ -426,14 +428,14 @@ static CURLcode ssh_getworkingpath(struct connectdata *conn,
 
   /* Check for /~/, indicating relative to the user's home directory */
   if(conn->handler->protocol & CURLPROTO_SCP) {
-    real_path = malloc(working_path_len+1);
+    real_path = malloc(working_path_len + 1);
     if(real_path == NULL) {
       free(working_path);
       return CURLE_OUT_OF_MEMORY;
     }
     if((working_path_len > 3) && (!memcmp(working_path, "/~/", 3)))
       /* It is referenced to the home directory, so strip the leading '/~/' */
-      memcpy(real_path, working_path+3, 4 + working_path_len-3);
+      memcpy(real_path, working_path + 3, 4 + working_path_len-3);
     else
       memcpy(real_path, working_path, 1 + working_path_len);
   }
@@ -449,19 +451,19 @@ static CURLcode ssh_getworkingpath(struct connectdata *conn,
          leading '/' */
       memcpy(real_path, homedir, homelen);
       real_path[homelen] = '/';
-      real_path[homelen+1] = '\0';
+      real_path[homelen + 1] = '\0';
       if(working_path_len > 3) {
-        memcpy(real_path+homelen+1, working_path + 3,
+        memcpy(real_path + homelen + 1, working_path + 3,
                1 + working_path_len -3);
       }
     }
     else {
-      real_path = malloc(working_path_len+1);
+      real_path = malloc(working_path_len + 1);
       if(real_path == NULL) {
         free(working_path);
         return CURLE_OUT_OF_MEMORY;
       }
-      memcpy(real_path, working_path, 1+working_path_len);
+      memcpy(real_path, working_path, 1 + working_path_len);
     }
   }
 
@@ -1811,7 +1813,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
              zero even though libssh2_sftp_open() failed previously! We need
              to work around that! */
           sshc->actualcode = CURLE_SSH;
-          err=-1;
+          err = -1;
         }
         failf(data, "Upload failed: %s (%d/%d)",
               err>= LIBSSH2_FX_OK?sftp_libssh2_strerror(err):"ssh error",
@@ -1829,7 +1831,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
         }
 
         if(seekerr != CURL_SEEKFUNC_OK) {
-          curl_off_t passed=0;
+          curl_off_t passed = 0;
 
           if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
             failf(data, "Could not seek stream");
@@ -1981,13 +1983,13 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
         sshc->actualcode = result?result:CURLE_SSH;
         break;
       }
-      sshc->readdir_filename = malloc(PATH_MAX+1);
+      sshc->readdir_filename = malloc(PATH_MAX + 1);
       if(!sshc->readdir_filename) {
         state(conn, SSH_SFTP_CLOSE);
         sshc->actualcode = CURLE_OUT_OF_MEMORY;
         break;
       }
-      sshc->readdir_longentry = malloc(PATH_MAX+1);
+      sshc->readdir_longentry = malloc(PATH_MAX + 1);
       if(!sshc->readdir_longentry) {
         Curl_safefree(sshc->readdir_filename);
         state(conn, SSH_SFTP_CLOSE);
@@ -2021,7 +2023,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
             break;
           }
           result = Curl_client_write(conn, CLIENTWRITE_BODY,
-                                     tmpLine, sshc->readdir_len+1);
+                                     tmpLine, sshc->readdir_len + 1);
           free(tmpLine);
 
           if(result) {
@@ -2030,7 +2032,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
           }
           /* since this counts what we send to the client, we include the
              newline in this counter */
-          data->req.bytecount += sshc->readdir_len+1;
+          data->req.bytecount += sshc->readdir_len + 1;
 
           /* output debug output if that is requested */
           if(data->set.verbose) {
@@ -2231,18 +2233,25 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
           curl_off_t from, to;
           char *ptr;
           char *ptr2;
+          CURLofft to_t;
+          CURLofft from_t;
 
-          from=curlx_strtoofft(conn->data->state.range, &ptr, 0);
-          while(*ptr && (ISSPACE(*ptr) || (*ptr=='-')))
+          from_t = curlx_strtoofft(conn->data->state.range, &ptr, 0, &from);
+          if(from_t == CURL_OFFT_FLOW)
+            return CURLE_RANGE_ERROR;
+          while(*ptr && (ISSPACE(*ptr) || (*ptr == '-')))
             ptr++;
-          to=curlx_strtoofft(ptr, &ptr2, 0);
-          if((ptr == ptr2) /* no "to" value given */
+          to_t = curlx_strtoofft(ptr, &ptr2, 0, &to);
+          if(to_t == CURL_OFFT_FLOW)
+            return CURLE_RANGE_ERROR;
+          if((to_t == CURL_OFFT_INVAL) /* no "to" value given */
              || (to >= size)) {
             to = size - 1;
           }
-          if(from < 0) {
+          if(from_t) {
             /* from is relative to end of file */
-            from += size;
+            from = size - to;
+            to = size - 1;
           }
           if(from > size) {
             failf(data, "Offset (%"
@@ -2825,7 +2834,7 @@ static CURLcode ssh_block_statemach(struct connectdata *conn,
   while((sshc->state != SSH_STOP) && !result) {
     bool block;
     time_t left = 1000;
-    struct timeval now = Curl_tvnow();
+    struct curltime now = Curl_tvnow();
 
     result = ssh_statemach_act(conn, &block);
     if(result)
@@ -2933,6 +2942,13 @@ static CURLcode ssh_connect(struct connectdata *conn, bool *done)
     return CURLE_FAILED_INIT;
   }
 
+  if(data->set.ssh_compression) {
+#if LIBSSH2_VERSION_NUM >= 0x010208
+    if(libssh2_session_flag(ssh->ssh_session, LIBSSH2_FLAG_COMPRESS, 1) < 0)
+#endif
+      infof(data, "Failed to enable compression for ssh session\n");
+  }
+
 #ifdef HAVE_LIBSSH2_KNOWNHOST_API
   if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
     int rc;
@@ -3029,8 +3045,8 @@ static CURLcode ssh_do(struct connectdata *conn, bool *done)
   data->req.size = -1; /* make sure this is unknown at this point */
 
   sshc->actualcode = CURLE_OK; /* reset error code */
-  sshc->secondCreateDirs =0;   /* reset the create dir attempt state
-                                  variable */
+  sshc->secondCreateDirs = 0;   /* reset the create dir attempt state
+                                   variable */
 
   Curl_pgrsSetUploadCounter(data, 0);
   Curl_pgrsSetDownloadCounter(data, 0);

Some files were not shown because too many files changed in this diff