summaryrefslogtreecommitdiffstats
path: root/Source/CTest
diff options
context:
space:
mode:
authorAndy Cedilnik <andy.cedilnik@kitware.com>2004-10-05 13:34:20 (GMT)
committerAndy Cedilnik <andy.cedilnik@kitware.com>2004-10-05 13:34:20 (GMT)
commit609801fe67c95f9959468df8316a8f4a26943842 (patch)
treebe2cf804edae61b76806c95bf0965985e4f45aed /Source/CTest
parent50da0328472ad0f318f64a20876c474ad968fef3 (diff)
downloadCMake-609801fe67c95f9959468df8316a8f4a26943842.zip
CMake-609801fe67c95f9959468df8316a8f4a26943842.tar.gz
CMake-609801fe67c95f9959468df8316a8f4a26943842.tar.bz2
ENH: Update Curl to 7.12.1
Diffstat (limited to 'Source/CTest')
-rw-r--r--Source/CTest/Curl/CMake/CheckSymbolExists.cmake58
-rw-r--r--Source/CTest/Curl/CMakeLists.txt188
-rw-r--r--Source/CTest/Curl/amigaos.c49
-rw-r--r--Source/CTest/Curl/amigaos.h52
-rw-r--r--Source/CTest/Curl/arpa_telnet.h70
-rw-r--r--Source/CTest/Curl/base64.c166
-rw-r--r--Source/CTest/Curl/base64.h6
-rw-r--r--Source/CTest/Curl/ca-bundle.h32
-rw-r--r--Source/CTest/Curl/config.h.in467
-rw-r--r--Source/CTest/Curl/connect.c803
-rw-r--r--Source/CTest/Curl/connect.h26
-rw-r--r--Source/CTest/Curl/content_encoding.c301
-rw-r--r--Source/CTest/Curl/content_encoding.h25
-rw-r--r--Source/CTest/Curl/cookie.c453
-rw-r--r--Source/CTest/Curl/cookie.h48
-rw-r--r--Source/CTest/Curl/curl.copyright36
-rw-r--r--Source/CTest/Curl/curl/curl.h703
-rw-r--r--Source/CTest/Curl/curl/curlver.h55
-rw-r--r--Source/CTest/Curl/curl/easy.h25
-rw-r--r--Source/CTest/Curl/curl/mprintf.h69
-rw-r--r--Source/CTest/Curl/curl/multi.h41
-rw-r--r--Source/CTest/Curl/curl/stdcheaders.h4
-rw-r--r--Source/CTest/Curl/curl/types.h29
-rw-r--r--Source/CTest/Curl/curlx.h95
-rw-r--r--Source/CTest/Curl/dict.c43
-rw-r--r--Source/CTest/Curl/dict.h2
-rw-r--r--Source/CTest/Curl/dllinit.c96
-rw-r--r--Source/CTest/Curl/easy.c464
-rw-r--r--Source/CTest/Curl/escape.c96
-rw-r--r--Source/CTest/Curl/escape.h2
-rw-r--r--Source/CTest/Curl/file.c258
-rw-r--r--Source/CTest/Curl/file.h7
-rw-r--r--Source/CTest/Curl/formdata.c1013
-rw-r--r--Source/CTest/Curl/formdata.h62
-rw-r--r--Source/CTest/Curl/ftp.c1615
-rw-r--r--Source/CTest/Curl/ftp.h6
-rw-r--r--Source/CTest/Curl/getdate.c2286
-rw-r--r--Source/CTest/Curl/getenv.c18
-rw-r--r--Source/CTest/Curl/getinfo.c46
-rw-r--r--Source/CTest/Curl/getinfo.h2
-rw-r--r--Source/CTest/Curl/getpass.c236
-rw-r--r--Source/CTest/Curl/hash.c263
-rw-r--r--Source/CTest/Curl/hash.h24
-rw-r--r--Source/CTest/Curl/hostares.c301
-rw-r--r--Source/CTest/Curl/hostasyn.c170
-rw-r--r--Source/CTest/Curl/hostip.c865
-rw-r--r--Source/CTest/Curl/hostip.h213
-rw-r--r--Source/CTest/Curl/hostip4.c449
-rw-r--r--Source/CTest/Curl/hostip6.c263
-rw-r--r--Source/CTest/Curl/hostsyn.c149
-rw-r--r--Source/CTest/Curl/hostthre.c550
-rw-r--r--Source/CTest/Curl/http.c1653
-rw-r--r--Source/CTest/Curl/http.h29
-rw-r--r--Source/CTest/Curl/http_chunks.c53
-rw-r--r--Source/CTest/Curl/http_chunks.h2
-rw-r--r--Source/CTest/Curl/http_digest.c482
-rw-r--r--Source/CTest/Curl/http_digest.h53
-rw-r--r--Source/CTest/Curl/http_negotiate.c332
-rw-r--r--Source/CTest/Curl/http_negotiate.h39
-rw-r--r--Source/CTest/Curl/http_ntlm.c585
-rw-r--r--Source/CTest/Curl/http_ntlm.h143
-rw-r--r--Source/CTest/Curl/if2ip.c55
-rw-r--r--Source/CTest/Curl/if2ip.h19
-rw-r--r--Source/CTest/Curl/inet_ntop.c198
-rw-r--r--Source/CTest/Curl/inet_ntop.h37
-rw-r--r--Source/CTest/Curl/inet_pton.c240
-rw-r--r--Source/CTest/Curl/inet_pton.h (renamed from Source/CTest/Curl/getpass.h)24
-rw-r--r--Source/CTest/Curl/krb4.c209
-rw-r--r--Source/CTest/Curl/krb4.h2
-rw-r--r--Source/CTest/Curl/ldap.c643
-rw-r--r--Source/CTest/Curl/ldap.h3
-rw-r--r--Source/CTest/Curl/llist.c92
-rw-r--r--Source/CTest/Curl/llist.h10
-rw-r--r--Source/CTest/Curl/md5.c348
-rw-r--r--Source/CTest/Curl/md5.h29
-rw-r--r--Source/CTest/Curl/memdebug.c178
-rw-r--r--Source/CTest/Curl/memdebug.h38
-rw-r--r--Source/CTest/Curl/memory.h50
-rw-r--r--Source/CTest/Curl/mprintf.c360
-rw-r--r--Source/CTest/Curl/multi.c426
-rw-r--r--Source/CTest/Curl/netrc.c133
-rw-r--r--Source/CTest/Curl/netrc.h5
-rw-r--r--Source/CTest/Curl/nwlib.c300
-rw-r--r--Source/CTest/Curl/progress.c317
-rw-r--r--Source/CTest/Curl/progress.h10
-rw-r--r--Source/CTest/Curl/security.c97
-rw-r--r--Source/CTest/Curl/security.h2
-rw-r--r--Source/CTest/Curl/sendf.c239
-rw-r--r--Source/CTest/Curl/sendf.h12
-rw-r--r--Source/CTest/Curl/setup.h230
-rw-r--r--Source/CTest/Curl/share.c219
-rw-r--r--Source/CTest/Curl/share.h29
-rw-r--r--Source/CTest/Curl/speedcheck.c13
-rw-r--r--Source/CTest/Curl/speedcheck.h2
-rw-r--r--Source/CTest/Curl/ssluse.c1031
-rw-r--r--Source/CTest/Curl/ssluse.h4
-rw-r--r--Source/CTest/Curl/strequal.c57
-rw-r--r--Source/CTest/Curl/strequal.h15
-rw-r--r--Source/CTest/Curl/strerror.c558
-rw-r--r--Source/CTest/Curl/strerror.h30
-rw-r--r--Source/CTest/Curl/strtok.c12
-rw-r--r--Source/CTest/Curl/strtok.h2
-rw-r--r--Source/CTest/Curl/strtoofft.c157
-rw-r--r--Source/CTest/Curl/strtoofft.h62
-rw-r--r--Source/CTest/Curl/telnet.c1027
-rw-r--r--Source/CTest/Curl/telnet.h4
-rw-r--r--Source/CTest/Curl/timeval.c81
-rw-r--r--Source/CTest/Curl/timeval.h38
-rw-r--r--Source/CTest/Curl/transfer.c1184
-rw-r--r--Source/CTest/Curl/transfer.h32
-rw-r--r--Source/CTest/Curl/url.c2284
-rw-r--r--Source/CTest/Curl/url.h27
-rw-r--r--Source/CTest/Curl/urldata.h461
-rw-r--r--Source/CTest/Curl/version.c155
114 files changed, 19761 insertions, 8700 deletions
diff --git a/Source/CTest/Curl/CMake/CheckSymbolExists.cmake b/Source/CTest/Curl/CMake/CheckSymbolExists.cmake
deleted file mode 100644
index 0ec34a1..0000000
--- a/Source/CTest/Curl/CMake/CheckSymbolExists.cmake
+++ /dev/null
@@ -1,58 +0,0 @@
-#
-# Check if the symbol exists in include files
-#
-# CHECK_SYMBOL_EXISTS - macro which checks the symbol exists in include files.
-# SYMBOL - symbol
-# FILES - include files to check
-# VARIABLE - variable to return result
-#
-
-MACRO(CHECK_SYMBOL_EXISTS SYMBOL FILES VARIABLE)
- IF("${VARIABLE}" MATCHES "^${VARIABLE}$")
- SET(CHECK_SYMBOL_EXISTS_CONTENT "/* */\n")
- SET(MACRO_CHECK_SYMBOL_EXISTS_FLAGS ${CMAKE_REQUIRED_FLAGS})
- STRING(ASCII 35 POUND)
- STRING(ASCII 40 OPEN_PARENT)
- STRING(ASCII 41 CLOSE_PARENT)
- SET(PARENTS "${OPEN_PARENT}${CLOSE_PARENT}")
- IF(CMAKE_REQUIRED_LIBRARIES)
- SET(CHECK_SYMBOL_EXISTS_LIBS
- "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}")
- ENDIF(CMAKE_REQUIRED_LIBRARIES)
- FOREACH(FILE ${FILES})
- SET(CHECK_SYMBOL_EXISTS_CONTENT
- "${CHECK_SYMBOL_EXISTS_CONTENT}${POUND}include <${FILE}>\n")
- ENDFOREACH(FILE)
- SET(CHECK_SYMBOL_EXISTS_CONTENT
- "${CHECK_SYMBOL_EXISTS_CONTENT}\nvoid cmakeRequireSymbol${OPEN_PARENT}int dummy,...${CLOSE_PARENT}{${OPEN_PARENT}void${CLOSE_PARENT}dummy;}\nint main${PARENTS}\n{\n${POUND}ifndef ${SYMBOL}\n cmakeRequireSymbol${OPEN_PARENT}0,&${SYMBOL}${CLOSE_PARENT};\n${POUND}endif\n return 0;\n}\n")
-
- WRITE_FILE(${CMAKE_BINARY_DIR}/CMakeTmp/CheckSymbolExists.c
- "${CHECK_SYMBOL_EXISTS_CONTENT}")
-
- MESSAGE(STATUS "Looking for ${SYMBOL}")
- TRY_COMPILE(${VARIABLE}
- ${CMAKE_BINARY_DIR}
- ${CMAKE_BINARY_DIR}/CMakeTmp/CheckSymbolExists.c
- CMAKE_FLAGS
- -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_SYMBOL_EXISTS_FLAGS}
- "${CHECK_SYMBOL_EXISTS_LIBS}"
- OUTPUT_VARIABLE OUTPUT)
- IF(${VARIABLE})
- MESSAGE(STATUS "Looking for ${SYMBOL} - found")
- SET(${VARIABLE} 1 CACHE INTERNAL "Have symbol ${SYMBOL}")
- WRITE_FILE(${CMAKE_BINARY_DIR}/CMakeOutput.log
- "Determining if the ${SYMBOL} "
- "exist passed with the following output:\n"
- "${OUTPUT}\nFile ${CMAKE_BINARY_DIR}/CMakeTmp/CheckSymbolExists.c:\n"
- "${CHECK_SYMBOL_EXISTS_CONTENT}" APPEND)
- ELSE(${VARIABLE})
- MESSAGE(STATUS "Looking for ${SYMBOL} - not found.")
- SET(${VARIABLE} "" CACHE INTERNAL "Have symbol ${SYMBOL}")
- WRITE_FILE(${CMAKE_BINARY_DIR}/CMakeError.log
- "Determining if the ${SYMBOL} "
- "exist failed with the following output:\n"
- "${OUTPUT}\nFile ${CMAKE_BINARY_DIR}/CMakeTmp/CheckSymbolExists.c:\n"
- "${CHECK_SYMBOL_EXISTS_CONTENT}" APPEND)
- ENDIF(${VARIABLE})
- ENDIF("${VARIABLE}" MATCHES "^${VARIABLE}$")
-ENDMACRO(CHECK_SYMBOL_EXISTS)
diff --git a/Source/CTest/Curl/CMakeLists.txt b/Source/CTest/Curl/CMakeLists.txt
index 7a54f72..61a174d 100644
--- a/Source/CTest/Curl/CMakeLists.txt
+++ b/Source/CTest/Curl/CMakeLists.txt
@@ -1,17 +1,18 @@
-CMAKE_MINIMUM_REQUIRED(VERSION 1.5)
+CMAKE_MINIMUM_REQUIRED(VERSION 2.0)
PROJECT(LIBCURL C)
INCLUDE_REGULAR_EXPRESSION("^.*\\.h$")
# Setup package meta-data
SET(PACKAGE "curl")
-SET(VERSION "7.10.3")
-SET(PACKAGE_TARNAME " ")
+SET(VERSION "7.12.1")
+SET(PACKAGE_TARNAME "curl")
SET(PACKAGE_BUGREPORT " ")
-SET(PACKAGE_NAME " ")
-SET(PACKAGE_VERSION " ")
-SET(PACKAGE_STRING " ")
-SET(OPERATING_SYSTEM ${CMAKE_SYSTEM_NAME})
+SET(PACKAGE_NAME "curl")
+SET(PACKAGE_VERSION "-")
+SET(PACKAGE_STRING "curl-")
+SET(PACKAGE_BUGREPORT "a suitable curl mailing list => http://curl.haxx.se/mail/")
+SET(OPERATING_SYSTEM "${CMAKE_SYSTEM_NAME}")
# We need ansi c-flags, especially on HP
SET(CMAKE_C_FLAGS "${CMAKE_ANSI_CFLAGS} ${CMAKE_C_FLAGS}")
@@ -23,60 +24,79 @@ IF(${CMAKE_SYSTEM_NAME} MATCHES AIX)
ENDIF(${CMAKE_SYSTEM_NAME} MATCHES AIX)
# Include all the necessary files for macros
-INCLUDE (${CMAKE_ROOT}/Modules/CheckFunctionExists.cmake)
-INCLUDE (${CMAKE_ROOT}/Modules/CheckIncludeFile.cmake)
-INCLUDE (${CMAKE_ROOT}/Modules/CheckIncludeFiles.cmake)
-INCLUDE (${CMAKE_ROOT}/Modules/CheckLibraryExists.cmake)
-INCLUDE (${LIBCURL_SOURCE_DIR}/CMake/CheckSymbolExists.cmake)
-INCLUDE (${CMAKE_ROOT}/Modules/CheckTypeSize.cmake)
+SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake")
+INCLUDE (CheckFunctionExists)
+INCLUDE (CheckIncludeFile)
+INCLUDE (CheckIncludeFiles)
+INCLUDE (CheckLibraryExists)
+INCLUDE (CheckSymbolExists)
+INCLUDE (CheckTypeSize)
SET(libCurl_SRCS
- file.c
- timeval.c
base64.c
- hostip.c
- progress.c
- formdata.c
+ connect.c
+ content_encoding.c
cookie.c
- http.c
- sendf.c
- ftp.c
- url.c
dict.c
- if2ip.c
- speedcheck.c
+ easy.c
+ escape.c
+ file.c
+ formdata.c
+ ftp.c
getdate.c
- ldap.c
- ssluse.c
- version.c
getenv.c
- escape.c
- mprintf.c
- telnet.c
- getpass.c
- netrc.c
getinfo.c
- transfer.c
- strequal.c
- easy.c
+ hash.c
+ hostares.c
+ hostasyn.c
+ hostip.c
+ hostip4.c
+ hostip6.c
+ hostsyn.c
+ hostthre.c
+ http.c
http_chunks.c
- connect.c
+ http_digest.c
+ http_negotiate.c
+ http_ntlm.c
+ if2ip.c
+ inet_ntop.c
+ inet_pton.c
+ krb4.c
+ ldap.c
llist.c
- hash.c
+ md5.c
+ memdebug.c
+ mprintf.c
multi.c
+ netrc.c
+ progress.c
+ security.c
+ sendf.c
+ share.c
+ speedcheck.c
+ ssluse.c
+ strequal.c
+ strerror.c
+ strtok.c
+ strtoofft.c
+ telnet.c
+ timeval.c
+ transfer.c
+ url.c
+ version.c
)
-
-
# if we have Kerberos 4, right now this is never on
-IF(KRB4)
+#OPTION(CURL_KRB4 "Use Kerberos 4" OFF)
+IF(CURL_KRB4)
SET(libCurl_SRCS ${libCurl_SRCS}
krb4.c
security.c
)
-ENDIF(KRB4)
+ENDIF(CURL_KRB4)
-OPTION(CURL_MALLOC_DEBUG "Debug mallocs in Curl" OFF)
+#OPTION(CURL_MALLOC_DEBUG "Debug mallocs in Curl" OFF)
MARK_AS_ADVANCED(CURL_MALLOC_DEBUG)
IF(CURL_MALLOC_DEBUG)
SET(libCurl_SRCS ${libCurl_SRCS}
@@ -84,7 +104,6 @@ IF(CURL_MALLOC_DEBUG)
)
ENDIF(CURL_MALLOC_DEBUG)
-
# On windows preload settings
IF(WIN32)
INCLUDE(${LIBCURL_SOURCE_DIR}/Platforms/WindowsCache.cmake)
@@ -114,9 +133,11 @@ ENDIF(NOT NOT_NEED_LIBNSL)
CHECK_LIBRARY_EXISTS_CONCAT("ws2_32" getch HAVE_LIBWS2_32)
CHECK_LIBRARY_EXISTS_CONCAT("winmm" getch HAVE_LIBWINMM)
CHECK_LIBRARY_EXISTS_CONCAT("z" inflateEnd HAVE_LIBZ)
-CHECK_LIBRARY_EXISTS_CONCAT("crypto" CRYPTO_lock HAVE_LIBCRYPTO)
+#OPTION(CMAKE_USE_OPENSSL "Use OpenSSL code. Experimental" OFF)
+MARK_AS_ADVANCED(CMAKE_USE_OPENSSL)
IF(CMAKE_USE_OPENSSL)
+ CHECK_LIBRARY_EXISTS_CONCAT("crypto" CRYPTO_lock HAVE_LIBCRYPTO)
CHECK_LIBRARY_EXISTS_CONCAT("ssl" SSL_connect HAVE_LIBSSL)
ENDIF(CMAKE_USE_OPENSSL)
@@ -155,6 +176,8 @@ MACRO(CHECK_INCLUDE_FILE_CONCAT FILE VARIABLE)
ENDMACRO(CHECK_INCLUDE_FILE_CONCAT)
# Check for header files
+CHECK_INCLUDE_FILE_CONCAT("stdio.h" HAVE_STDIO_H)
+CHECK_INCLUDE_FILE_CONCAT("stddef.h" HAVE_STDDEF_H)
CHECK_INCLUDE_FILE_CONCAT("sys/types.h" HAVE_SYS_TYPES_H)
CHECK_INCLUDE_FILE_CONCAT("inttypes.h" HAVE_INTTYPES_H)
CHECK_INCLUDE_FILE_CONCAT("alloca.h" HAVE_ALLOCA_H)
@@ -164,8 +187,9 @@ CHECK_INCLUDE_FILE_CONCAT("fcntl.h" HAVE_FCNTL_H)
CHECK_INCLUDE_FILE_CONCAT("malloc.h" HAVE_MALLOC_H)
CHECK_INCLUDE_FILE_CONCAT("memory.h" HAVE_MEMORY_H)
CHECK_INCLUDE_FILE_CONCAT("netdb.h" HAVE_NETDB_H)
-CHECK_INCLUDE_FILE_CONCAT("zlib.h" HAVE_ZLIB_H)
CHECK_INCLUDE_FILE_CONCAT("sys/poll.h" HAVE_SYS_POLL_H)
+CHECK_INCLUDE_FILE_CONCAT("assert.h" HAVE_ASSERT_H)
+CHECK_INCLUDE_FILE_CONCAT("limits.h" HAVE_LIMITS_H)
IF(CMAKE_USE_OPENSSL)
CHECK_INCLUDE_FILE_CONCAT("openssl/x509.h" HAVE_OPENSSL_X509_H)
@@ -175,13 +199,17 @@ IF(CMAKE_USE_OPENSSL)
CHECK_INCLUDE_FILE_CONCAT("openssl/pem.h" HAVE_OPENSSL_PEM_H)
CHECK_INCLUDE_FILE_CONCAT("openssl/ssl.h" HAVE_OPENSSL_SSL_H)
CHECK_INCLUDE_FILE_CONCAT("openssl/err.h" HAVE_OPENSSL_ERR_H)
+ CHECK_INCLUDE_FILE_CONCAT("openssl/rand.h" HAVE_OPENSSL_RAND_H)
ENDIF(CMAKE_USE_OPENSSL)
+CHECK_INCLUDE_FILE_CONCAT("zlib.h" HAVE_ZLIB_H)
CHECK_INCLUDE_FILE_CONCAT("sys/socket.h" HAVE_SYS_SOCKET_H)
CHECK_INCLUDE_FILE_CONCAT("netinet/in.h" HAVE_NETINET_IN_H)
CHECK_INCLUDE_FILE_CONCAT("net/if.h" HAVE_NET_IF_H)
CHECK_INCLUDE_FILE_CONCAT("netinet/if_ether.h"
HAVE_NETINET_IF_ETHER_H)
+CHECK_INCLUDE_FILE_CONCAT("netinet/tcp.h"
+ HAVE_NETINET_TCP_H)
CHECK_INCLUDE_FILE_CONCAT("sys/select.h" HAVE_SYS_SELECT_H)
CHECK_INCLUDE_FILE_CONCAT("utime.h" HAVE_UTIME_H)
CHECK_INCLUDE_FILE_CONCAT("netinet/in.h" HAVE_NETINET_IN_H)
@@ -206,12 +234,19 @@ CHECK_INCLUDE_FILE_CONCAT("sys/sockio.h" HAVE_SYS_SOCKIO_H)
CHECK_INCLUDE_FILE_CONCAT("x509.h" HAVE_X509_H)
CHECK_INCLUDE_FILE_CONCAT("setjmp.h" HAVE_SETJMP_H)
CHECK_INCLUDE_FILE_CONCAT("signal.h" HAVE_SIGNAL_H)
+CHECK_INCLUDE_FILE_CONCAT("sys/ioctl.h" HAVE_SYS_IOCTL_H)
+CHECK_INCLUDE_FILE_CONCAT("sys/utsname.h" HAVE_SYS_UTSNAME_H)
+CHECK_TYPE_SIZE(size_t SIZEOF_SIZE_T)
CHECK_TYPE_SIZE(ssize_t SIZEOF_SSIZE_T)
+CHECK_TYPE_SIZE("long long" SIZEOF_LONG_LONG)
CHECK_TYPE_SIZE("long double" SIZEOF_LONG_DOUBLE)
IF(NOT HAVE_SIZEOF_SSIZE_T)
SET(ssize_t int)
ENDIF(NOT HAVE_SIZEOF_SSIZE_T)
+IF(HAVE_SIZEOF_LONG_LONG)
+ SET(HAVE_LONGLONG 1)
+ENDIF(HAVE_SIZEOF_LONG_LONG)
FIND_FILE(RANDOM_FILE urandom /dev)
MARK_AS_ADVANCED(RANDOM_FILE)
@@ -231,6 +266,7 @@ CHECK_SYMBOL_EXISTS(strcmpi "${CURL_INCLUDES}" HAVE_STRCMPI)
CHECK_SYMBOL_EXISTS(gethostbyaddr "${CURL_INCLUDES}" HAVE_GETHOSTBYADDR)
CHECK_SYMBOL_EXISTS(gettimeofday "${CURL_INCLUDES}" HAVE_GETTIMEOFDAY)
CHECK_SYMBOL_EXISTS(inet_addr "${CURL_INCLUDES}" HAVE_INET_ADDR)
+CHECK_SYMBOL_EXISTS(inet_pton "${CURL_INCLUDES}" HAVE_INET_PTON)
CHECK_SYMBOL_EXISTS(inet_ntoa "${CURL_INCLUDES}" HAVE_INET_NTOA)
CHECK_SYMBOL_EXISTS(inet_ntoa_r "${CURL_INCLUDES}" HAVE_INET_NTOA_R)
CHECK_SYMBOL_EXISTS(tcsetattr "${CURL_INCLUDES}" HAVE_TCSETATTR)
@@ -244,20 +280,30 @@ CHECK_SYMBOL_EXISTS(strlcat "${CURL_INCLUDES}" HAVE_STRLCAT)
CHECK_SYMBOL_EXISTS(getpwuid "${CURL_INCLUDES}" HAVE_GETPWUID)
CHECK_SYMBOL_EXISTS(geteuid "${CURL_INCLUDES}" HAVE_GETEUID)
CHECK_SYMBOL_EXISTS(utime "${CURL_INCLUDES}" HAVE_UTIME)
-CHECK_SYMBOL_EXISTS(RAND_status "${CURL_INCLUDES}" HAVE_RAND_STATUS)
-CHECK_SYMBOL_EXISTS(RAND_screen "${CURL_INCLUDES}" HAVE_RAND_SCREEN)
-CHECK_SYMBOL_EXISTS(RAND_egd "${CURL_INCLUDES}" HAVE_RAND_EGD)
+IF(CMAKE_USE_OPENSSL)
+ CHECK_SYMBOL_EXISTS(RAND_status "${CURL_INCLUDES}" HAVE_RAND_STATUS)
+ CHECK_SYMBOL_EXISTS(RAND_screen "${CURL_INCLUDES}" HAVE_RAND_SCREEN)
+ CHECK_SYMBOL_EXISTS(RAND_egd "${CURL_INCLUDES}" HAVE_RAND_EGD)
+ CHECK_SYMBOL_EXISTS(CRYPTO_cleanup_all_ex_data "${CURL_INCLUDES}"
+ HAVE_CRYPTO_CLEANUP_ALL_EX_DATA)
+ENDIF(CMAKE_USE_OPENSSL)
CHECK_SYMBOL_EXISTS(gmtime_r "${CURL_INCLUDES}" HAVE_GMTIME_R)
CHECK_SYMBOL_EXISTS(localtime_r "${CURL_INCLUDES}" HAVE_LOCALTIME_R)
-CHECK_SYMBOL_EXISTS(gethostbyname_r "${CURL_INCLUDES};netdb.h" HAVE_GETHOSTBYNAME_R)
-CHECK_SYMBOL_EXISTS(gethostbyaddr_r "${CURL_INCLUDES};netdb.h" HAVE_GETHOSTBYADDR_R)
+CHECK_SYMBOL_EXISTS(gethostbyname "${CURL_INCLUDES}" HAVE_GETHOSTBYNAME)
+CHECK_SYMBOL_EXISTS(gethostbyname_r "${CURL_INCLUDES}" HAVE_GETHOSTBYNAME_R)
+CHECK_SYMBOL_EXISTS(gethostbyaddr_r "${CURL_INCLUDES}" HAVE_GETHOSTBYADDR_R)
CHECK_SYMBOL_EXISTS(signal "${CURL_INCLUDES}" HAVE_SIGNAL_FUNC)
CHECK_SYMBOL_EXISTS(SIGALRM "${CURL_INCLUDES}" HAVE_SIGNAL_MACRO)
IF(HAVE_SIGNAL_FUNC AND HAVE_SIGNAL_MACRO)
SET(HAVE_SIGNAL 1)
ENDIF(HAVE_SIGNAL_FUNC AND HAVE_SIGNAL_MACRO)
+CHECK_SYMBOL_EXISTS(uname "${CURL_INCLUDES}" HAVE_UNAME)
+CHECK_SYMBOL_EXISTS(strtoll "${CURL_INCLUDES}" HAVE_STRTOLL)
+CHECK_SYMBOL_EXISTS(strerror_r "${CURL_INCLUDES}" HAVE_STRERROR_R)
+CHECK_SYMBOL_EXISTS(siginterrupt "${CURL_INCLUDES}" HAVE_SIGINTERRUPT)
+CHECK_SYMBOL_EXISTS(perror "${CURL_INCLUDES}" HAVE_PERROR)
# only build compat strtok if we need to
IF (NOT HAVE_STRTOK_R)
@@ -334,6 +380,7 @@ FOREACH(CURL_TEST
HAVE_INET_NTOA_R_DECL
HAVE_INET_NTOA_R_DECL_REENTRANT
HAVE_GETADDRINFO
+ _FILE_OFFSET_BITS
)
CURL_INTERNAL_TEST(${CURL_TEST})
ENDFOREACH(CURL_TEST)
@@ -398,21 +445,34 @@ IF(HAVE_LIBZ)
SET(libCurl_SRCS ${libCurl_SRCS} content_encoding.c)
ENDIF(HAVE_LIBZ)
-# Check for nonblocking
+IF(_FILE_OFFSET_BITS)
+ SET(_FILE_OFFSET_BITS 64)
+ENDIF(_FILE_OFFSET_BITS)
+SET(CMAKE_REQUIRED_FLAGS "-D_FILE_OFFSET_BITS=64")
+SET(CMAKE_EXTRA_INCLUDE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/curl/curl.h")
+CHECK_TYPE_SIZE("curl_off_t" SIZEOF_CURL_OFF_T)
+SET(CMAKE_EXTRA_INCLUDE_FILES)
+SET(CMAKE_REQUIRED_FLAGS)
-SET(HAVE_SOME_NONBLOCK 0)
-FOREACH(CURL_TEST
- HAVE_FIONBIO
- HAVE_IOCTLSOCKET
- HAVE_IOCTLSOCKET_CASE
- HAVE_O_NONBLOCK)
- IF(${CURL_TEST})
- SET(HAVE_SOME_NONBLOCK 1)
- ENDIF(${CURL_TEST})
-ENDFOREACH(CURL_TEST)
-IF(NOT HAVE_SOME_NONBLOCK)
- SET(HAVE_DISABLED_NONBLOCKING 1)
-ENDIF(NOT HAVE_SOME_NONBLOCK)
+
+# Check for nonblocking
+#OPTION(CURL_HAVE_DISABLED_NONBLOCKING "Disable non-blocking socket detection" OFF)
+SET(HAVE_DISABLED_NONBLOCKING)
+IF(CURL_HAVE_DISABLED_NONBLOCKING)
+ SET(HAVE_SOME_NONBLOCK 0)
+ FOREACH(CURL_TEST
+ HAVE_FIONBIO
+ HAVE_IOCTLSOCKET
+ HAVE_IOCTLSOCKET_CASE
+ HAVE_O_NONBLOCK)
+ IF(${CURL_TEST})
+ SET(HAVE_SOME_NONBLOCK 1)
+ ENDIF(${CURL_TEST})
+ ENDFOREACH(CURL_TEST)
+ IF(NOT HAVE_SOME_NONBLOCK)
+ SET(HAVE_DISABLED_NONBLOCKING 1)
+ ENDIF(NOT HAVE_SOME_NONBLOCK)
+ENDIF(CURL_HAVE_DISABLED_NONBLOCKING)
IF(RETSIGTYPE_TEST)
SET(RETSIGTYPE void)
diff --git a/Source/CTest/Curl/amigaos.c b/Source/CTest/Curl/amigaos.c
new file mode 100644
index 0000000..16a7d5e
--- /dev/null
+++ b/Source/CTest/Curl/amigaos.c
@@ -0,0 +1,49 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "amigaos.h"
+#include <stdio.h> /* for stderr */
+
+struct Library *SocketBase = NULL;
+
+void amiga_cleanup()
+{
+ if(SocketBase)
+ CloseLibrary(SocketBase);
+
+ SocketBase = NULL;
+}
+
+BOOL amiga_init()
+{
+ if(!SocketBase)
+ SocketBase = OpenLibrary("bsdsocket.library", 4);
+
+ if(!SocketBase) {
+ fprintf(stderr, "No TCP/IP Stack running!\n\a");
+ return FALSE;
+ }
+
+ atexit(amiga_cleanup);
+ return TRUE;
+}
diff --git a/Source/CTest/Curl/amigaos.h b/Source/CTest/Curl/amigaos.h
new file mode 100644
index 0000000..0196eec
--- /dev/null
+++ b/Source/CTest/Curl/amigaos.h
@@ -0,0 +1,52 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#ifndef LIBCURL_AMIGAOS_H
+#define LIBCURL_AMIGAOS_H
+
+#ifndef __ixemul__
+
+#include <exec/types.h>
+#include <exec/execbase.h>
+
+#include <proto/exec.h>
+#include <proto/dos.h>
+
+#include <bsdsocket.h>
+
+#include "config-amigaos.h"
+
+#define select(args...) WaitSelect( args, NULL)
+#define inet_ntoa(x) Inet_NtoA( x ## .s_addr)
+#define ioctl(a,b,c,d) IoctlSocket( (LONG)a, (ULONG)b, (char*)c)
+#define _AMIGASF 1
+
+extern void amiga_cleanup();
+extern BOOL amiga_init();
+
+#else /* __ixemul__ */
+
+#warning compiling with ixemul...
+
+#endif /* __ixemul__ */
+#endif /* LIBCURL_AMIGAOS_H */
diff --git a/Source/CTest/Curl/arpa_telnet.h b/Source/CTest/Curl/arpa_telnet.h
index 378b7c0..5359ff1 100644
--- a/Source/CTest/Curl/arpa_telnet.h
+++ b/Source/CTest/Curl/arpa_telnet.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -26,15 +26,15 @@
/*
* Telnet option defines. Add more here if in need.
*/
-#define TELOPT_BINARY 0 /* binary 8bit data */
-#define TELOPT_SGA 3 /* Supress Go Ahead */
-#define TELOPT_EXOPL 255 /* EXtended OPtions List */
-#define TELOPT_TTYPE 24 /* Terminal TYPE */
-#define TELOPT_XDISPLOC 35 /* X DISPlay LOCation */
+#define CURL_TELOPT_BINARY 0 /* binary 8bit data */
+#define CURL_TELOPT_SGA 3 /* Supress Go Ahead */
+#define CURL_TELOPT_EXOPL 255 /* EXtended OPtions List */
+#define CURL_TELOPT_TTYPE 24 /* Terminal TYPE */
+#define CURL_TELOPT_XDISPLOC 35 /* X DISPlay LOCation */
-#define TELOPT_NEW_ENVIRON 39 /* NEW ENVIRONment variables */
-#define NEW_ENV_VAR 0
-#define NEW_ENV_VALUE 1
+#define CURL_TELOPT_NEW_ENVIRON 39 /* NEW ENVIRONment variables */
+#define CURL_NEW_ENV_VAR 0
+#define CURL_NEW_ENV_VALUE 1
/*
* The telnet options represented as strings
@@ -53,31 +53,27 @@ static const char *telnetoptions[]=
"OLD-ENVIRON", "AUTHENTICATION", "ENCRYPT", "NEW-ENVIRON"
};
-#define TELOPT_MAXIMUM TELOPT_NEW_ENVIRON
+#define CURL_TELOPT_MAXIMUM CURL_TELOPT_NEW_ENVIRON
-#define TELOPT_OK(x) ((x) <= TELOPT_MAXIMUM)
-#define TELOPT(x) telnetoptions[x]
+#define CURL_TELOPT_OK(x) ((x) <= CURL_TELOPT_MAXIMUM)
+#define CURL_TELOPT(x) telnetoptions[x]
-#define NTELOPTS 40
-
-#ifdef SE
-# undef SE
-#endif
+#define CURL_NTELOPTS 40
/*
* First some defines
*/
-#define xEOF 236 /* End Of File */
-#define SE 240 /* Sub negotiation End */
-#define NOP 241 /* No OPeration */
-#define DM 242 /* Data Mark */
-#define GA 249 /* Go Ahead, reverse the line */
-#define SB 250 /* SuBnegotiation */
-#define WILL 251 /* Our side WILL use this option */
-#define WONT 252 /* Our side WON'T use this option */
-#define DO 253 /* DO use this option! */
-#define DONT 254 /* DON'T use this option! */
-#define IAC 255 /* Interpret As Command */
+#define CURL_xEOF 236 /* End Of File */
+#define CURL_SE 240 /* Sub negotiation End */
+#define CURL_NOP 241 /* No OPeration */
+#define CURL_DM 242 /* Data Mark */
+#define CURL_GA 249 /* Go Ahead, reverse the line */
+#define CURL_SB 250 /* SuBnegotiation */
+#define CURL_WILL 251 /* Our side WILL use this option */
+#define CURL_WONT 252 /* Our side WON'T use this option */
+#define CURL_DO 253 /* DO use this option! */
+#define CURL_DONT 254 /* DON'T use this option! */
+#define CURL_IAC 255 /* Interpret As Command */
/*
* Then those numbers represented as strings:
@@ -90,16 +86,16 @@ static const char *telnetcmds[]=
"WILL", "WONT", "DO", "DONT", "IAC"
};
-#define TELCMD_MINIMUM xEOF /* the first one */
-#define TELCMD_MAXIMUM IAC /* surprise, 255 is the last one! ;-) */
+#define CURL_TELCMD_MINIMUM CURL_xEOF /* the first one */
+#define CURL_TELCMD_MAXIMUM CURL_IAC /* surprise, 255 is the last one! ;-) */
-#define TELQUAL_IS 0
-#define TELQUAL_SEND 1
-#define TELQUAL_INFO 2
-#define TELQUAL_NAME 3
+#define CURL_TELQUAL_IS 0
+#define CURL_TELQUAL_SEND 1
+#define CURL_TELQUAL_INFO 2
+#define CURL_TELQUAL_NAME 3
-#define TELCMD_OK(x) ( ((unsigned int)(x) >= TELCMD_MINIMUM) && \
- ((unsigned int)(x) <= TELCMD_MAXIMUM) )
-#define TELCMD(x) telnetcmds[(x)-TELCMD_MINIMUM]
+#define CURL_TELCMD_OK(x) ( ((unsigned int)(x) >= CURL_TELCMD_MINIMUM) && \
+ ((unsigned int)(x) <= CURL_TELCMD_MAXIMUM) )
+#define CURL_TELCMD(x) telnetcmds[(x)-CURL_TELCMD_MINIMUM]
#endif
#endif
diff --git a/Source/CTest/Curl/base64.c b/Source/CTest/Curl/base64.c
index 1e8da91..2416bca 100644
--- a/Source/CTest/Curl/base64.c
+++ b/Source/CTest/Curl/base64.c
@@ -1,16 +1,16 @@
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -28,7 +28,7 @@
* a base64-encoded version to stdout, and the length returned by the
* encoding function to stderr. Compile with -DTEST_DECODE for a program that
* will go the other way.
- *
+ *
* This code will break if int is smaller than 32 bits
*/
@@ -41,12 +41,13 @@
#include <curl/mprintf.h>
#include "base64.h"
+#include "memory.h"
-#ifdef MALLOCDEBUG
+/* include memdebug.h last */
#include "memdebug.h"
-#endif
-static void decodeQuantum(unsigned char *dest, char *src)
+
+static void decodeQuantum(unsigned char *dest, const char *src)
{
unsigned int x = 0;
int i;
@@ -55,7 +56,7 @@ static void decodeQuantum(unsigned char *dest, char *src)
x = (x << 6) + (unsigned int)(src[i] - 'A' + 0);
else if(src[i] >= 'a' && src[i] <= 'z')
x = (x << 6) + (unsigned int)(src[i] - 'a' + 26);
- else if(src[i] >= '0' && src[i] <= '9')
+ else if(src[i] >= '0' && src[i] <= '9')
x = (x << 6) + (unsigned int)(src[i] - '0' + 52);
else if(src[i] == '+')
x = (x << 6) + 62;
@@ -65,48 +66,53 @@ static void decodeQuantum(unsigned char *dest, char *src)
x = (x << 6);
}
- dest[2] = (unsigned char)(x & 255); x >>= 8;
- dest[1] = (unsigned char)(x & 255); x >>= 8;
- dest[0] = (unsigned char)(x & 255); x >>= 8;
+ dest[2] = (unsigned char)(x & 255);
+ x >>= 8;
+ dest[1] = (unsigned char)(x & 255);
+ x >>= 8;
+ dest[0] = (unsigned char)(x & 255);
}
-/* base64Decode
- * Given a base64 string at src, decode it into the memory pointed
- * to by dest. If rawLength points to a valid address (ie not NULL),
- * store the length of the decoded data to it.
+/*
+ * Curl_base64_decode()
+ *
+ * Given a base64 string at src, decode it into the memory pointed to by
+ * dest. Returns the length of the decoded data.
*/
-static void base64Decode(unsigned char *dest, char *src, int *rawLength)
+size_t Curl_base64_decode(const char *src, char *dest)
{
int length = 0;
int equalsTerm = 0;
int i;
int numQuantums;
unsigned char lastQuantum[3];
-
+ size_t rawlen=0;
+
while((src[length] != '=') && src[length])
length++;
while(src[length+equalsTerm] == '=')
equalsTerm++;
-
+
numQuantums = (length + equalsTerm) / 4;
- if(rawLength)
- *rawLength = (numQuantums * 3) - equalsTerm;
-
+
+ rawlen = (numQuantums * 3) - equalsTerm;
+
for(i = 0; i < numQuantums - 1; i++) {
- decodeQuantum(dest, src);
+ decodeQuantum((unsigned char *)dest, src);
dest += 3; src += 4;
}
decodeQuantum(lastQuantum, src);
for(i = 0; i < 3 - equalsTerm; i++)
dest[i] = lastQuantum[i];
-
+
+ return rawlen;
}
/* ---- Base64 Encoding --- */
static char table64[]=
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
+
/*
* Curl_base64_encode()
*
@@ -115,7 +121,7 @@ static char table64[]=
* went wrong, -1 is returned.
*
*/
-int Curl_base64_encode(const void *inp, int insize, char **outptr)
+size_t Curl_base64_encode(const char *inp, size_t insize, char **outptr)
{
unsigned char ibuf[3];
unsigned char obuf[4];
@@ -126,16 +132,18 @@ int Curl_base64_encode(const void *inp, int insize, char **outptr)
char *indata = (char *)inp;
+ *outptr = NULL; /* set to NULL in case of failure before we reach the end */
+
if(0 == insize)
- insize = (int)strlen(indata);
+ insize = strlen(indata);
base64data = output = (char*)malloc(insize*4/3+4);
if(NULL == output)
- return -1;
+ return 0;
while(insize > 0) {
- for (i = inputparts = 0; i < 3; i++) {
- if(*indata) {
+ for (i = inputparts = 0; i < 3; i++) {
+ if(insize > 0) {
inputparts++;
ibuf[i] = *indata;
indata++;
@@ -144,32 +152,30 @@ int Curl_base64_encode(const void *inp, int insize, char **outptr)
else
ibuf[i] = 0;
}
-
- obuf [0] = (unsigned char)((ibuf [0] & 0xFC) >> 2);
- obuf [1] = (unsigned char)(((ibuf [0] & 0x03) << 4) |
- ((ibuf [1] & 0xF0) >> 4));
- obuf [2] = (unsigned char)(((ibuf [1] & 0x0F) << 2) |
- ((ibuf [2] & 0xC0) >> 6));
- obuf [3] = (unsigned char)(ibuf [2] & 0x3F);
+
+ obuf [0] = (ibuf [0] & 0xFC) >> 2;
+ obuf [1] = ((ibuf [0] & 0x03) << 4) | ((ibuf [1] & 0xF0) >> 4);
+ obuf [2] = ((ibuf [1] & 0x0F) << 2) | ((ibuf [2] & 0xC0) >> 6);
+ obuf [3] = ibuf [2] & 0x3F;
switch(inputparts) {
case 1: /* only one byte read */
- sprintf(output, "%c%c==",
- table64[obuf[0]],
- table64[obuf[1]]);
+ snprintf(output, 5, "%c%c==",
+ table64[obuf[0]],
+ table64[obuf[1]]);
break;
case 2: /* two bytes read */
- sprintf(output, "%c%c%c=",
- table64[obuf[0]],
- table64[obuf[1]],
- table64[obuf[2]]);
+ snprintf(output, 5, "%c%c%c=",
+ table64[obuf[0]],
+ table64[obuf[1]],
+ table64[obuf[2]]);
break;
default:
- sprintf(output, "%c%c%c%c",
- table64[obuf[0]],
- table64[obuf[1]],
- table64[obuf[2]],
- table64[obuf[3]] );
+ snprintf(output, 5, "%c%c%c%c",
+ table64[obuf[0]],
+ table64[obuf[1]],
+ table64[obuf[2]],
+ table64[obuf[3]] );
break;
}
output += 4;
@@ -177,18 +183,10 @@ int Curl_base64_encode(const void *inp, int insize, char **outptr)
*output=0;
*outptr = base64data; /* make it return the actual data memory */
- return (int)strlen(base64data); /* return the length of the new data */
+ return strlen(base64data); /* return the length of the new data */
}
/* ---- End of Base64 Encoding ---- */
-int Curl_base64_decode(const char *str, void *data)
-{
- int ret;
-
- base64Decode((unsigned char *)data, (char *)str, &ret);
- return ret;
-}
-
/************* TEST HARNESS STUFF ****************/
@@ -204,24 +202,26 @@ void *suck(int *);
int main(int argc, char **argv, char **envp)
{
char *base64;
- int base64Len;
+ size_t base64Len;
unsigned char *data;
int dataLen;
-
+
data = (unsigned char *)suck(&dataLen);
base64Len = Curl_base64_encode(data, dataLen, &base64);
fprintf(stderr, "%d\n", base64Len);
fprintf(stdout, "%s", base64);
-
+
free(base64); free(data);
return 0;
}
#endif
#ifdef TEST_DECODE
-/* decoding test harness. Read in a base64 string from stdin and write out the
+/* decoding test harness. Read in a base64 string from stdin and write out the
* length returned by Curl_base64_decode, followed by the decoded data itself
+ *
+ * gcc -DTEST_DECODE base64.c -o base64 mprintf.o memdebug.o
*/
#include <stdio.h>
@@ -234,14 +234,32 @@ int main(int argc, char **argv, char **envp)
int base64Len;
unsigned char *data;
int dataLen;
-
+ int i, j;
+
base64 = (char *)suck(&base64Len);
data = (unsigned char *)malloc(base64Len * 3/4 + 8);
dataLen = Curl_base64_decode(base64, data);
-
+
fprintf(stderr, "%d\n", dataLen);
- fwrite(data,1,dataLen,stdout);
-
+
+ for(i=0; i < dataLen; i+=0x10) {
+ printf("0x%02x: ", i);
+ for(j=0; j < 0x10; j++)
+ if((j+i) < dataLen)
+ printf("%02x ", data[i+j]);
+ else
+ printf(" ");
+
+ printf(" | ");
+
+ for(j=0; j < 0x10; j++)
+ if((j+i) < dataLen)
+ printf("%c", isgraph(data[i+j])?data[i+j]:'.');
+ else
+ break;
+ puts("");
+ }
+
free(base64); free(data);
return 0;
}
@@ -255,7 +273,7 @@ void *suck(int *lenptr)
unsigned char *buf = NULL;
int lastread;
int len = 0;
-
+
do {
cursize *= 2;
buf = (unsigned char *)realloc(buf, cursize);
@@ -263,16 +281,8 @@ void *suck(int *lenptr)
lastread = fread(buf + len, 1, cursize - len, stdin);
len += lastread;
} while(!feof(stdin));
-
+
lenptr[0] = len;
return (void *)buf;
}
#endif
-
-/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
- */
diff --git a/Source/CTest/Curl/base64.h b/Source/CTest/Curl/base64.h
index 5bda7d6..307148e 100644
--- a/Source/CTest/Curl/base64.h
+++ b/Source/CTest/Curl/base64.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -22,6 +22,6 @@
*
* $Id$
***************************************************************************/
-int Curl_base64_encode(const void *data, int size, char **str);
-int Curl_base64_decode(const char *str, void *data);
+size_t Curl_base64_encode(const char *input, size_t size, char **str);
+size_t Curl_base64_decode(const char *source, char *dest);
#endif
diff --git a/Source/CTest/Curl/ca-bundle.h b/Source/CTest/Curl/ca-bundle.h
index 1545372..12390bc 100644
--- a/Source/CTest/Curl/ca-bundle.h
+++ b/Source/CTest/Curl/ca-bundle.h
@@ -1,31 +1 @@
-#ifndef __CA_BUNDLE_H
-#define __CA_BUNDLE_H
-/*****************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * In order to be useful for every potential user, curl and libcurl are
- * dual-licensed under the MPL and the MIT/X-derivate licenses.
- *
- * You 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 MPL or the MIT/X-derivate
- * licenses. You may pick one of these licenses.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- *****************************************************************************/
-
-#ifndef CURL_CA_BUNDLE
-/* Set this to the full path file name of the ca cert bundle */
-#undef CURL_CA_BUNDLE
-#endif
-
-#endif /* __CA_BUNDLE_H */
+/* ca bundle path set in here*/
diff --git a/Source/CTest/Curl/config.h.in b/Source/CTest/Curl/config.h.in
index 122a272..5b554cc 100644
--- a/Source/CTest/Curl/config.h.in
+++ b/Source/CTest/Curl/config.h.in
@@ -1,427 +1,424 @@
/* lib/config.h.in. Generated from configure.in by autoheader. */
-/* Name of this package! */
-#cmakedefine PACKAGE "${PACKAGE}"
-/* Version number of this archive. */
-#cmakedefine VERSION "${VERSION}"
-
-/* Define if you have the getpass function. */
-#cmakedefine HAVE_GETPASS ${HAVE_GETPASS}
-
-/* Define cpu-machine-OS */
-#define OS "${OPERATING_SYSTEM}"
-
-/* Define if you have the gethostbyaddr_r() function with 5 arguments */
-#cmakedefine HAVE_GETHOSTBYADDR_R_5 ${HAVE_GETHOSTBYADDR_R_5}
-
-/* Define if you have the gethostbyaddr_r() function with 7 arguments */
-#cmakedefine HAVE_GETHOSTBYADDR_R_7 ${HAVE_GETHOSTBYADDR_R_7}
-
-/* Define if you have the gethostbyaddr_r() function with 8 arguments */
-#cmakedefine HAVE_GETHOSTBYADDR_R_8 ${HAVE_GETHOSTBYADDR_R_8}
-
-/* Define if you have the gethostbyname_r() function with 3 arguments */
-#cmakedefine HAVE_GETHOSTBYNAME_R_3 ${HAVE_GETHOSTBYNAME_R_3}
-
-/* Define if you have the gethostbyname_r() function with 5 arguments */
-#cmakedefine HAVE_GETHOSTBYNAME_R_5 ${HAVE_GETHOSTBYNAME_R_5}
-
-/* Define if you have the gethostbyname_r() function with 6 arguments */
-#cmakedefine HAVE_GETHOSTBYNAME_R_6 ${HAVE_GETHOSTBYNAME_R_6}
-
-/* Define if you have the inet_ntoa_r function declared. */
-#cmakedefine HAVE_INET_NTOA_R_DECL ${HAVE_INET_NTOA_R_DECL}
-
-/* Define if you need the _REENTRANT define for some functions */
-#cmakedefine NEED_REENTRANT ${NEED_REENTRANT}
-
-/* Define if you have the Kerberos4 libraries (including -ldes) */
-#cmakedefine KRB4 ${KRB4}
-
-/* Define if you want to enable IPv6 support */
-#cmakedefine ENABLE_IPV6 ${ENABLE_IPV6}
-
-/* Define this to 'int' if ssize_t is not an available typedefed type */
-#cmakedefine ssize_t ${ssize_t}
-
-/* Define this to 'int' if socklen_t is not an available typedefed type */
-#cmakedefine socklen_t ${socklen_t}
-
-/* Define this as a suitable file to read random data from */
-#cmakedefine RANDOM_FILE "${RANDOM_FILE}"
-
-/* Define this to your Entropy Gathering Daemon socket pathname */
-#cmakedefine EGD_SOCKET ${EGD_SOCKET}
-
-/* Define if you have a working OpenSSL installation */
-#cmakedefine OPENSSL_ENABLED ${OPENSSL_ENABLED}
-
-/* Define the one correct non-blocking socket method below */
-#cmakedefine HAVE_FIONBIO ${HAVE_FIONBIO}
-#cmakedefine HAVE_IOCTLSOCKET ${HAVE_IOCTLSOCKET}
-#cmakedefine HAVE_IOCTLSOCKET_CASE ${HAVE_IOCTLSOCKET_CASE}
-#cmakedefine HAVE_O_NONBLOCK ${HAVE_O_NONBLOCK}
-#cmakedefine HAVE_DISABLED_NONBLOCKING ${HAVE_DISABLED_NONBLOCKING}
-
-/* Define this to 'int' if in_addr_t is not an available typedefed type */
-#cmakedefine in_addr_t ${in_addr_t}
-
-/* Define to disable DICT */
-#cmakedefine CURL_DISABLE_DICT ${CURL_DISABLE_DICT}
-
-/* Define to disable FILE */
-#cmakedefine CURL_DISABLE_FILE ${CURL_DISABLE_FILE}
-
-/* Define to disable FTP */
-#cmakedefine CURL_DISABLE_FTP ${CURL_DISABLE_FTP}
-
-/* Define to disable GOPHER */
-#cmakedefine CURL_DISABLE_GOPHER ${CURL_DISABLE_GOPHER}
-
-/* Define to disable HTTP */
-#cmakedefine CURL_DISABLE_HTTP ${CURL_DISABLE_HTTP}
-
-/* Define to disable LDAP */
-#cmakedefine CURL_DISABLE_LDAP ${CURL_DISABLE_LDAP}
-
-/* Define to disable TELNET */
-#cmakedefine CURL_DISABLE_TELNET ${CURL_DISABLE_TELNET}
-
-/* Define if you have zlib present */
-#cmakedefine HAVE_LIBZ ${HAVE_LIBZ}
-
-/* CA bundle full path name */
-#cmakedefine CURL_CA_BUNDLE ${CURL_CA_BUNDLE}
+/* to disable DICT */
+#cmakedefine CURL_DISABLE_DICT ${CURL_DISABLE_DICT}
/* to disable FILE */
-#cmakedefine CURL_DISABLE_FILE ${CURL_DISABLE_FILE}
+#cmakedefine CURL_DISABLE_FILE ${CURL_DISABLE_FILE}
/* to disable FTP */
-#cmakedefine CURL_DISABLE_FTP ${CURL_DISABLE_FTP}
+#cmakedefine CURL_DISABLE_FTP ${CURL_DISABLE_FTP}
/* to disable GOPHER */
-#cmakedefine CURL_DISABLE_GOPHER ${CURL_DISABLE_GOPHER}
+#cmakedefine CURL_DISABLE_GOPHER ${CURL_DISABLE_GOPHER}
/* to disable HTTP */
-#cmakedefine CURL_DISABLE_HTTP ${CURL_DISABLE_HTTP}
+#cmakedefine CURL_DISABLE_HTTP ${CURL_DISABLE_HTTP}
/* to disable LDAP */
-#cmakedefine CURL_DISABLE_LDAP ${CURL_DISABLE_LDAP}
+#cmakedefine CURL_DISABLE_LDAP ${CURL_DISABLE_LDAP}
/* to disable TELNET */
-#cmakedefine CURL_DISABLE_TELNET ${CURL_DISABLE_TELNET}
+#cmakedefine CURL_DISABLE_TELNET ${CURL_DISABLE_TELNET}
/* Set to explicitly specify we don't want to use thread-safe functions */
-#cmakedefine DISABLED_THREADSAFE ${DISABLED_THREADSAFE}
+#cmakedefine DISABLED_THREADSAFE ${DISABLED_THREADSAFE}
/* your Entropy Gathering Daemon socket pathname */
-#cmakedefine EGD_SOCKET ${EGD_SOCKET}
+#cmakedefine EGD_SOCKET ${EGD_SOCKET}
/* Define if you want to enable IPv6 support */
-#cmakedefine ENABLE_IPV6 ${ENABLE_IPV6}
+#cmakedefine ENABLE_IPV6 ${ENABLE_IPV6}
/* Define to 1 if you have the <alloca.h> header file. */
-#cmakedefine HAVE_ALLOCA_H ${HAVE_ALLOCA_H}
+#cmakedefine HAVE_ALLOCA_H ${HAVE_ALLOCA_H}
/* Define to 1 if you have the <arpa/inet.h> header file. */
-#cmakedefine HAVE_ARPA_INET_H ${HAVE_ARPA_INET_H}
+#cmakedefine HAVE_ARPA_INET_H ${HAVE_ARPA_INET_H}
+
+/* Define to 1 if you have the <assert.h> header file. */
+#cmakedefine HAVE_ASSERT_H ${HAVE_ASSERT_H}
/* Define to 1 if you have the `closesocket' function. */
-#cmakedefine HAVE_CLOSESOCKET ${HAVE_CLOSESOCKET}
+#cmakedefine HAVE_CLOSESOCKET ${HAVE_CLOSESOCKET}
+
+/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */
+#cmakedefine HAVE_CRYPTO_CLEANUP_ALL_EX_DATA ${HAVE_CRYPTO_CLEANUP_ALL_EX_DATA}
/* Define to 1 if you have the <crypto.h> header file. */
-#cmakedefine HAVE_CRYPTO_H ${HAVE_CRYPTO_H}
+#cmakedefine HAVE_CRYPTO_H ${HAVE_CRYPTO_H}
/* Define to 1 if you have the <des.h> header file. */
-#cmakedefine HAVE_DES_H ${HAVE_DES_H}
+#cmakedefine HAVE_DES_H ${HAVE_DES_H}
-/* to disable NON-BLOCKING connections */
-#cmakedefine HAVE_DISABLED_NONBLOCKING ${HAVE_DISABLED_NONBLOCKING}
+/* disabled non-blocking sockets */
+#cmakedefine HAVE_DISABLED_NONBLOCKING ${HAVE_DISABLED_NONBLOCKING}
/* Define to 1 if you have the <dlfcn.h> header file. */
-#cmakedefine HAVE_DLFCN_H ${HAVE_DLFCN_H}
+#cmakedefine HAVE_DLFCN_H ${HAVE_DLFCN_H}
/* Define to 1 if you have the `dlopen' function. */
-#cmakedefine HAVE_DLOPEN ${HAVE_DLOPEN}
+#cmakedefine HAVE_DLOPEN ${HAVE_DLOPEN}
/* Define to 1 if you have the <err.h> header file. */
-#cmakedefine HAVE_ERR_H ${HAVE_ERR_H}
+#cmakedefine HAVE_ERR_H ${HAVE_ERR_H}
/* Define to 1 if you have the <fcntl.h> header file. */
-#cmakedefine HAVE_FCNTL_H ${HAVE_FCNTL_H}
+#cmakedefine HAVE_FCNTL_H ${HAVE_FCNTL_H}
+
+/* use FIONBIO for non-blocking sockets */
+#cmakedefine HAVE_FIONBIO ${HAVE_FIONBIO}
/* Define if getaddrinfo exists and works */
-#cmakedefine HAVE_GETADDRINFO ${HAVE_GETADDRINFO}
+#cmakedefine HAVE_GETADDRINFO ${HAVE_GETADDRINFO}
/* Define to 1 if you have the `geteuid' function. */
-#cmakedefine HAVE_GETEUID ${HAVE_GETEUID}
+#cmakedefine HAVE_GETEUID ${HAVE_GETEUID}
/* Define to 1 if you have the `gethostbyaddr' function. */
-#cmakedefine HAVE_GETHOSTBYADDR ${HAVE_GETHOSTBYADDR}
+#cmakedefine HAVE_GETHOSTBYADDR ${HAVE_GETHOSTBYADDR}
-/* Define to 1 if you have the `gethostbyaddr_r' function. */
-#cmakedefine HAVE_GETHOSTBYADDR_R ${HAVE_GETHOSTBYADDR_R}
+/* If you have gethostbyname */
+#cmakedefine HAVE_GETHOSTBYNAME ${HAVE_GETHOSTBYNAME}
/* Define to 1 if you have the `gethostbyname_r' function. */
-#cmakedefine HAVE_GETHOSTBYNAME_R ${HAVE_GETHOSTBYNAME_R}
+#cmakedefine HAVE_GETHOSTBYNAME_R ${HAVE_GETHOSTBYNAME_R}
+
+/* gethostbyname_r() takes 3 args */
+#cmakedefine HAVE_GETHOSTBYNAME_R_3 ${HAVE_GETHOSTBYNAME_R_3}
+
+/* gethostbyname_r() takes 5 args */
+#cmakedefine HAVE_GETHOSTBYNAME_R_5 ${HAVE_GETHOSTBYNAME_R_5}
+
+/* gethostbyname_r() takes 6 args */
+#cmakedefine HAVE_GETHOSTBYNAME_R_6 ${HAVE_GETHOSTBYNAME_R_6}
/* Define to 1 if you have the `getpass_r' function. */
-#cmakedefine HAVE_GETPASS_R ${HAVE_GETPASS_R}
+#cmakedefine HAVE_GETPASS_R ${HAVE_GETPASS_R}
/* Define to 1 if you have the `getpwuid' function. */
-#cmakedefine HAVE_GETPWUID ${HAVE_GETPWUID}
+#cmakedefine HAVE_GETPWUID ${HAVE_GETPWUID}
/* Define to 1 if you have the `gettimeofday' function. */
-#cmakedefine HAVE_GETTIMEOFDAY ${HAVE_GETTIMEOFDAY}
+#cmakedefine HAVE_GETTIMEOFDAY ${HAVE_GETTIMEOFDAY}
+
+/* we have a glibc-style strerror_r() */
+#cmakedefine HAVE_GLIBC_STRERROR_R ${HAVE_GLIBC_STRERROR_R}
/* Define to 1 if you have the `gmtime_r' function. */
-#cmakedefine HAVE_GMTIME_R ${HAVE_GMTIME_R}
+#cmakedefine HAVE_GMTIME_R ${HAVE_GMTIME_R}
+
+/* if you have the gssapi libraries */
+#cmakedefine HAVE_GSSAPI ${HAVE_GSSAPI}
+
+/* if you have the Heimdal gssapi libraries */
+#cmakedefine HAVE_GSSHEIMDAL ${HAVE_GSSHEIMDAL}
+
+/* if you have the MIT gssapi libraries */
+#cmakedefine HAVE_GSSMIT ${HAVE_GSSMIT}
+
+/* Define to 1 if you have the `idn_free' function. */
+#cmakedefine HAVE_IDN_FREE ${HAVE_IDN_FREE}
+
+/* Define to 1 if you have the <idn-free.h> header file. */
+#cmakedefine HAVE_IDN_FREE_H ${HAVE_IDN_FREE_H}
/* Define to 1 if you have the `inet_addr' function. */
-#cmakedefine HAVE_INET_ADDR ${HAVE_INET_ADDR}
+#cmakedefine HAVE_INET_ADDR ${HAVE_INET_ADDR}
/* Define to 1 if you have the `inet_ntoa' function. */
-#cmakedefine HAVE_INET_NTOA ${HAVE_INET_NTOA}
+#cmakedefine HAVE_INET_NTOA ${HAVE_INET_NTOA}
/* Define to 1 if you have the `inet_ntoa_r' function. */
-#cmakedefine HAVE_INET_NTOA_R ${HAVE_INET_NTOA_R}
+#cmakedefine HAVE_INET_NTOA_R ${HAVE_INET_NTOA_R}
+
+/* inet_ntoa_r() is declared */
+#cmakedefine HAVE_INET_NTOA_R_DECL ${HAVE_INET_NTOA_R_DECL}
+
+/* Define to 1 if you have the `inet_pton' function. */
+#cmakedefine HAVE_INET_PTON ${HAVE_INET_PTON}
/* Define to 1 if you have the <inttypes.h> header file. */
-#cmakedefine HAVE_INTTYPES_H ${HAVE_INTTYPES_H}
+#cmakedefine HAVE_INTTYPES_H ${HAVE_INTTYPES_H}
+
+/* use ioctlsocket() for non-blocking sockets */
+#cmakedefine HAVE_IOCTLSOCKET ${HAVE_IOCTLSOCKET}
+
+/* use Ioctlsocket() for non-blocking sockets */
+#cmakedefine HAVE_IOCTLSOCKET_CASE ${HAVE_IOCTLSOCKET_CASE}
/* Define to 1 if you have the <io.h> header file. */
-#cmakedefine HAVE_IO_H ${HAVE_IO_H}
+#cmakedefine HAVE_IO_H ${HAVE_IO_H}
+
+/* if you have the Kerberos4 libraries (including -ldes) */
+#cmakedefine HAVE_KRB4 ${HAVE_KRB4}
/* Define to 1 if you have the `krb_get_our_ip_for_realm' function. */
-#cmakedefine HAVE_KRB_GET_OUR_IP_FOR_REALM ${HAVE_KRB_GET_OUR_IP_FOR_REALM}
+#cmakedefine HAVE_KRB_GET_OUR_IP_FOR_REALM ${HAVE_KRB_GET_OUR_IP_FOR_REALM}
/* Define to 1 if you have the <krb.h> header file. */
-#cmakedefine HAVE_KRB_H ${HAVE_KRB_H}
+#cmakedefine HAVE_KRB_H ${HAVE_KRB_H}
/* Define to 1 if you have the `crypto' library (-lcrypto). */
-#cmakedefine HAVE_LIBCRYPTO ${HAVE_LIBCRYPTO}
+#cmakedefine HAVE_LIBCRYPTO ${HAVE_LIBCRYPTO}
/* Define to 1 if you have the `dl' library (-ldl). */
-#cmakedefine HAVE_LIBDL ${HAVE_LIBDL}
+#cmakedefine HAVE_LIBDL ${HAVE_LIBDL}
-/* Define to 1 if you have the `nsl' library (-lnsl). */
-#cmakedefine HAVE_LIBNSL ${HAVE_LIBNSL}
+/* Define to 1 if you have the `idn' library (-lidn). */
+#cmakedefine HAVE_LIBIDN ${HAVE_LIBIDN}
/* Define to 1 if you have the `resolv' library (-lresolv). */
-#cmakedefine HAVE_LIBRESOLV ${HAVE_LIBRESOLV}
+#cmakedefine HAVE_LIBRESOLV ${HAVE_LIBRESOLV}
/* Define to 1 if you have the `resolve' library (-lresolve). */
-#cmakedefine HAVE_LIBRESOLVE ${HAVE_LIBRESOLVE}
+#cmakedefine HAVE_LIBRESOLVE ${HAVE_LIBRESOLVE}
/* Define to 1 if you have the `socket' library (-lsocket). */
-#cmakedefine HAVE_LIBSOCKET ${HAVE_LIBSOCKET}
+#cmakedefine HAVE_LIBSOCKET ${HAVE_LIBSOCKET}
/* Define to 1 if you have the `ssl' library (-lssl). */
-#cmakedefine HAVE_LIBSSL ${HAVE_LIBSSL}
+#cmakedefine HAVE_LIBSSL ${HAVE_LIBSSL}
-/* Define to 1 if you have the `ucb' library (-lucb). */
-#cmakedefine HAVE_LIBUCB ${HAVE_LIBUCB}
+/* if zlib is available */
+#cmakedefine HAVE_LIBZ ${HAVE_LIBZ}
-/* If zlib is available */
-#cmakedefine HAVE_LIBZ ${HAVE_LIBZ}
+/* Define to 1 if you have the <limits.h> header file. */
+#cmakedefine HAVE_LIMITS_H ${HAVE_LIMITS_H}
/* Define to 1 if you have the `localtime_r' function. */
-#cmakedefine HAVE_LOCALTIME_R ${HAVE_LOCALTIME_R}
+#cmakedefine HAVE_LOCALTIME_R ${HAVE_LOCALTIME_R}
+
+/* if your compiler supports 'long long' */
+#cmakedefine HAVE_LONGLONG ${HAVE_LONGLONG}
/* Define to 1 if you have the <malloc.h> header file. */
-#cmakedefine HAVE_MALLOC_H ${HAVE_MALLOC_H}
+#cmakedefine HAVE_MALLOC_H ${HAVE_MALLOC_H}
/* Define to 1 if you have the <memory.h> header file. */
-#cmakedefine HAVE_MEMORY_H ${HAVE_MEMORY_H}
+#cmakedefine HAVE_MEMORY_H ${HAVE_MEMORY_H}
/* Define to 1 if you have the <netdb.h> header file. */
-#cmakedefine HAVE_NETDB_H ${HAVE_NETDB_H}
-
-/* Define to 1 if you have the <netinet/if_ether.h> header file. */
-#cmakedefine HAVE_NETINET_IF_ETHER_H ${HAVE_NETINET_IF_ETHER_H}
+#cmakedefine HAVE_NETDB_H ${HAVE_NETDB_H}
/* Define to 1 if you have the <netinet/in.h> header file. */
-#cmakedefine HAVE_NETINET_IN_H ${HAVE_NETINET_IN_H}
+#cmakedefine HAVE_NETINET_IN_H ${HAVE_NETINET_IN_H}
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#cmakedefine HAVE_NETINET_TCP_H ${HAVE_NETINET_TCP_H}
/* Define to 1 if you have the <net/if.h> header file. */
-#cmakedefine HAVE_NET_IF_H ${HAVE_NET_IF_H}
+#cmakedefine HAVE_NET_IF_H ${HAVE_NET_IF_H}
+
+/* Define if NI_WITHSCOPEID exists and works */
+#cmakedefine HAVE_NI_WITHSCOPEID ${HAVE_NI_WITHSCOPEID}
+
+/* we have no strerror_r() proto */
+#cmakedefine HAVE_NO_STRERROR_R_DECL ${HAVE_NO_STRERROR_R_DECL}
/* Define to 1 if you have the <openssl/crypto.h> header file. */
-#cmakedefine HAVE_OPENSSL_CRYPTO_H ${HAVE_OPENSSL_CRYPTO_H}
+#cmakedefine HAVE_OPENSSL_CRYPTO_H ${HAVE_OPENSSL_CRYPTO_H}
/* Define to 1 if you have the <openssl/engine.h> header file. */
-#cmakedefine HAVE_OPENSSL_ENGINE_H ${HAVE_OPENSSL_ENGINE_H}
+#cmakedefine HAVE_OPENSSL_ENGINE_H ${HAVE_OPENSSL_ENGINE_H}
/* Define to 1 if you have the <openssl/err.h> header file. */
-#cmakedefine HAVE_OPENSSL_ERR_H ${HAVE_OPENSSL_ERR_H}
+#cmakedefine HAVE_OPENSSL_ERR_H ${HAVE_OPENSSL_ERR_H}
/* Define to 1 if you have the <openssl/pem.h> header file. */
-#cmakedefine HAVE_OPENSSL_PEM_H ${HAVE_OPENSSL_PEM_H}
+#cmakedefine HAVE_OPENSSL_PEM_H ${HAVE_OPENSSL_PEM_H}
/* Define to 1 if you have the <openssl/rsa.h> header file. */
-#cmakedefine HAVE_OPENSSL_RSA_H ${HAVE_OPENSSL_RSA_H}
+#cmakedefine HAVE_OPENSSL_RSA_H ${HAVE_OPENSSL_RSA_H}
/* Define to 1 if you have the <openssl/ssl.h> header file. */
-#cmakedefine HAVE_OPENSSL_SSL_H ${HAVE_OPENSSL_SSL_H}
+#cmakedefine HAVE_OPENSSL_SSL_H ${HAVE_OPENSSL_SSL_H}
/* Define to 1 if you have the <openssl/x509.h> header file. */
-#cmakedefine HAVE_OPENSSL_X509_H ${HAVE_OPENSSL_X509_H}
+#cmakedefine HAVE_OPENSSL_X509_H ${HAVE_OPENSSL_X509_H}
+
+/* use O_NONBLOCK for non-blocking sockets */
+#cmakedefine HAVE_O_NONBLOCK ${HAVE_O_NONBLOCK}
/* Define to 1 if you have the <pem.h> header file. */
-#cmakedefine HAVE_PEM_H ${HAVE_PEM_H}
+#cmakedefine HAVE_PEM_H ${HAVE_PEM_H}
/* Define to 1 if you have the `perror' function. */
-#cmakedefine HAVE_PERROR ${HAVE_PERROR}
+#cmakedefine HAVE_PERROR ${HAVE_PERROR}
/* Define to 1 if you have the `poll' function. */
-#cmakedefine HAVE_POLL ${HAVE_POLL}
+#cmakedefine HAVE_POLL ${HAVE_POLL}
+
+/* If you have a fine poll */
+#cmakedefine HAVE_POLL_FINE ${HAVE_POLL_FINE}
+
+/* we have a POSIX-style strerror_r() */
+#cmakedefine HAVE_POSIX_STRERROR_R ${HAVE_POSIX_STRERROR_R}
/* Define to 1 if you have the <pwd.h> header file. */
-#cmakedefine HAVE_PWD_H ${HAVE_PWD_H}
+#cmakedefine HAVE_PWD_H ${HAVE_PWD_H}
/* Define to 1 if you have the `RAND_egd' function. */
-#cmakedefine HAVE_RAND_EGD ${HAVE_RAND_EGD}
+#cmakedefine HAVE_RAND_EGD ${HAVE_RAND_EGD}
/* Define to 1 if you have the `RAND_screen' function. */
-#cmakedefine HAVE_RAND_SCREEN ${HAVE_RAND_SCREEN}
+#cmakedefine HAVE_RAND_SCREEN ${HAVE_RAND_SCREEN}
/* Define to 1 if you have the `RAND_status' function. */
-#cmakedefine HAVE_RAND_STATUS ${HAVE_RAND_STATUS}
+#cmakedefine HAVE_RAND_STATUS ${HAVE_RAND_STATUS}
/* Define to 1 if you have the <rsa.h> header file. */
-#cmakedefine HAVE_RSA_H ${HAVE_RSA_H}
+#cmakedefine HAVE_RSA_H ${HAVE_RSA_H}
/* Define to 1 if you have the `select' function. */
-#cmakedefine HAVE_SELECT ${HAVE_SELECT}
+#cmakedefine HAVE_SELECT ${HAVE_SELECT}
/* Define to 1 if you have the <setjmp.h> header file. */
-#cmakedefine HAVE_SETJMP_H ${HAVE_SETJMP_H}
-
-/* Define to 1 if you have the `setvbuf' function. */
-#cmakedefine HAVE_SETVBUF ${HAVE_SETVBUF}
+#cmakedefine HAVE_SETJMP_H ${HAVE_SETJMP_H}
/* Define to 1 if you have the <sgtty.h> header file. */
-#cmakedefine HAVE_SGTTY_H ${HAVE_SGTTY_H}
+#cmakedefine HAVE_SGTTY_H ${HAVE_SGTTY_H}
/* Define to 1 if you have the `sigaction' function. */
-#cmakedefine HAVE_SIGACTION ${HAVE_SIGACTION}
+#cmakedefine HAVE_SIGACTION ${HAVE_SIGACTION}
+
+/* Define to 1 if you have the `siginterrupt' function. */
+#cmakedefine HAVE_SIGINTERRUPT ${HAVE_SIGINTERRUPT}
/* Define to 1 if you have the `signal' function. */
-#cmakedefine HAVE_SIGNAL ${HAVE_SIGNAL}
+#cmakedefine HAVE_SIGNAL ${HAVE_SIGNAL}
/* If you have sigsetjmp */
-#cmakedefine HAVE_SIGSETJMP ${HAVE_SIGSETJMP}
+#cmakedefine HAVE_SIGSETJMP ${HAVE_SIGSETJMP}
/* Define to 1 if you have the `socket' function. */
-#cmakedefine HAVE_SOCKET ${HAVE_SOCKET}
+#cmakedefine HAVE_SOCKET ${HAVE_SOCKET}
+
+/* use SO_NONBLOCK for non-blocking sockets */
+#cmakedefine HAVE_SO_NONBLOCK ${HAVE_SO_NONBLOCK}
+
+/* Define this if you have the SPNEGO library fbopenssl */
+#cmakedefine HAVE_SPNEGO ${HAVE_SPNEGO}
/* Define to 1 if you have the <ssl.h> header file. */
-#cmakedefine HAVE_SSL_H ${HAVE_SSL_H}
+#cmakedefine HAVE_SSL_H ${HAVE_SSL_H}
/* Define to 1 if you have the <stdint.h> header file. */
-#cmakedefine HAVE_STDINT_H ${HAVE_STDINT_H}
+#cmakedefine HAVE_STDINT_H ${HAVE_STDINT_H}
/* Define to 1 if you have the <stdlib.h> header file. */
-#cmakedefine HAVE_STDLIB_H ${HAVE_STDLIB_H}
+#cmakedefine HAVE_STDLIB_H ${HAVE_STDLIB_H}
/* Define to 1 if you have the `strcasecmp' function. */
-#cmakedefine HAVE_STRCASECMP ${HAVE_STRCASECMP}
+#cmakedefine HAVE_STRCASECMP ${HAVE_STRCASECMP}
/* Define to 1 if you have the `strcmpi' function. */
-#cmakedefine HAVE_STRCMPI ${HAVE_STRCMPI}
+#cmakedefine HAVE_STRCMPI ${HAVE_STRCMPI}
/* Define to 1 if you have the `strdup' function. */
-#cmakedefine HAVE_STRDUP ${HAVE_STRDUP}
+#cmakedefine HAVE_STRDUP ${HAVE_STRDUP}
+
+/* Define to 1 if you have the `strerror_r' function. */
+#cmakedefine HAVE_STRERROR_R ${HAVE_STRERROR_R}
/* Define to 1 if you have the `strftime' function. */
-#cmakedefine HAVE_STRFTIME ${HAVE_STRFTIME}
+#cmakedefine HAVE_STRFTIME ${HAVE_STRFTIME}
/* Define to 1 if you have the `stricmp' function. */
-#cmakedefine HAVE_STRICMP ${HAVE_STRICMP}
+#cmakedefine HAVE_STRICMP ${HAVE_STRICMP}
/* Define to 1 if you have the <strings.h> header file. */
-#cmakedefine HAVE_STRINGS_H ${HAVE_STRINGS_H}
+#cmakedefine HAVE_STRINGS_H ${HAVE_STRINGS_H}
/* Define to 1 if you have the <string.h> header file. */
-#cmakedefine HAVE_STRING_H ${HAVE_STRING_H}
+#cmakedefine HAVE_STRING_H ${HAVE_STRING_H}
/* Define to 1 if you have the `strlcat' function. */
-#cmakedefine HAVE_STRLCAT ${HAVE_STRLCAT}
+#cmakedefine HAVE_STRLCAT ${HAVE_STRLCAT}
/* Define to 1 if you have the `strlcpy' function. */
-#cmakedefine HAVE_STRLCPY ${HAVE_STRLCPY}
+#cmakedefine HAVE_STRLCPY ${HAVE_STRLCPY}
/* Define to 1 if you have the `strstr' function. */
-#cmakedefine HAVE_STRSTR ${HAVE_STRSTR}
+#cmakedefine HAVE_STRSTR ${HAVE_STRSTR}
/* Define to 1 if you have the `strtok_r' function. */
-#cmakedefine HAVE_STRTOK_R ${HAVE_STRTOK_R}
+#cmakedefine HAVE_STRTOK_R ${HAVE_STRTOK_R}
+
+/* Define to 1 if you have the `strtoll' function. */
+#cmakedefine HAVE_STRTOLL ${HAVE_STRTOLL}
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#cmakedefine HAVE_SYS_IOCTL_H ${HAVE_SYS_IOCTL_H}
/* Define to 1 if you have the <sys/param.h> header file. */
-#cmakedefine HAVE_SYS_PARAM_H ${HAVE_SYS_PARAM_H}
+#cmakedefine HAVE_SYS_PARAM_H ${HAVE_SYS_PARAM_H}
/* Define to 1 if you have the <sys/poll.h> header file. */
-#cmakedefine HAVE_SYS_POLL_H ${HAVE_SYS_POLL_H}
+#cmakedefine HAVE_SYS_POLL_H ${HAVE_SYS_POLL_H}
/* Define to 1 if you have the <sys/select.h> header file. */
-#cmakedefine HAVE_SYS_SELECT_H ${HAVE_SYS_SELECT_H}
+#cmakedefine HAVE_SYS_SELECT_H ${HAVE_SYS_SELECT_H}
/* Define to 1 if you have the <sys/socket.h> header file. */
-#cmakedefine HAVE_SYS_SOCKET_H ${HAVE_SYS_SOCKET_H}
+#cmakedefine HAVE_SYS_SOCKET_H ${HAVE_SYS_SOCKET_H}
/* Define to 1 if you have the <sys/sockio.h> header file. */
-#cmakedefine HAVE_SYS_SOCKIO_H ${HAVE_SYS_SOCKIO_H}
+#cmakedefine HAVE_SYS_SOCKIO_H ${HAVE_SYS_SOCKIO_H}
/* Define to 1 if you have the <sys/stat.h> header file. */
-#cmakedefine HAVE_SYS_STAT_H ${HAVE_SYS_STAT_H}
+#cmakedefine HAVE_SYS_STAT_H ${HAVE_SYS_STAT_H}
/* Define to 1 if you have the <sys/time.h> header file. */
-#cmakedefine HAVE_SYS_TIME_H ${HAVE_SYS_TIME_H}
+#cmakedefine HAVE_SYS_TIME_H ${HAVE_SYS_TIME_H}
/* Define to 1 if you have the <sys/types.h> header file. */
-#cmakedefine HAVE_SYS_TYPES_H ${HAVE_SYS_TYPES_H}
+#cmakedefine HAVE_SYS_TYPES_H ${HAVE_SYS_TYPES_H}
/* Define to 1 if you have the <sys/utime.h> header file. */
-#cmakedefine HAVE_SYS_UTIME_H ${HAVE_SYS_UTIME_H}
+#cmakedefine HAVE_SYS_UTIME_H ${HAVE_SYS_UTIME_H}
/* Define to 1 if you have the `tcgetattr' function. */
-#cmakedefine HAVE_TCGETATTR ${HAVE_TCGETATTR}
+#cmakedefine HAVE_TCGETATTR ${HAVE_TCGETATTR}
/* Define to 1 if you have the `tcsetattr' function. */
-#cmakedefine HAVE_TCSETATTR ${HAVE_TCSETATTR}
+#cmakedefine HAVE_TCSETATTR ${HAVE_TCSETATTR}
/* Define to 1 if you have the <termios.h> header file. */
-#cmakedefine HAVE_TERMIOS_H ${HAVE_TERMIOS_H}
+#cmakedefine HAVE_TERMIOS_H ${HAVE_TERMIOS_H}
/* Define to 1 if you have the <termio.h> header file. */
-#cmakedefine HAVE_TERMIO_H ${HAVE_TERMIO_H}
+#cmakedefine HAVE_TERMIO_H ${HAVE_TERMIO_H}
/* Define to 1 if you have the <time.h> header file. */
-#cmakedefine HAVE_TIME_H ${HAVE_TIME_H}
+#cmakedefine HAVE_TIME_H ${HAVE_TIME_H}
/* Define to 1 if you have the `uname' function. */
-#cmakedefine HAVE_UNAME ${HAVE_UNAME}
+#cmakedefine HAVE_UNAME ${HAVE_UNAME}
/* Define to 1 if you have the <unistd.h> header file. */
-#cmakedefine HAVE_UNISTD_H ${HAVE_UNISTD_H}
+#cmakedefine HAVE_UNISTD_H ${HAVE_UNISTD_H}
/* Define to 1 if you have the `utime' function. */
-#cmakedefine HAVE_UTIME ${HAVE_UTIME}
+#cmakedefine HAVE_UTIME ${HAVE_UTIME}
/* Define to 1 if you have the <utime.h> header file. */
-#cmakedefine HAVE_UTIME_H ${HAVE_UTIME_H}
+#cmakedefine HAVE_UTIME_H ${HAVE_UTIME_H}
/* Define to 1 if you have the <winsock.h> header file. */
-#cmakedefine HAVE_WINSOCK_H ${HAVE_WINSOCK_H}
+#cmakedefine HAVE_WINSOCK_H ${HAVE_WINSOCK_H}
+
+/* Define this symbol if your OS supports changing the contents of argv */
+#cmakedefine HAVE_WRITABLE_ARGV ${HAVE_WRITABLE_ARGV}
/* Define to 1 if you have the <x509.h> header file. */
-#cmakedefine HAVE_X509_H ${HAVE_X509_H}
+#cmakedefine HAVE_X509_H ${HAVE_X509_H}
/* if you have the zlib.h header file */
-#cmakedefine HAVE_ZLIB_H ${HAVE_ZLIB_H}
+#cmakedefine HAVE_ZLIB_H ${HAVE_ZLIB_H}
-/* if you have the Kerberos4 libraries (including -ldes) */
-#cmakedefine KRB4 ${KRB4}
+/* need REENTRANT defined */
+#cmakedefine NEED_REENTRANT ${NEED_REENTRANT}
/* cpu-machine-OS */
#define OS "${OPERATING_SYSTEM}"
@@ -448,13 +445,34 @@
#cmakedefine RANDOM_FILE "${RANDOM_FILE}"
/* Define as the return type of signal handlers (`int' or `void'). */
-#cmakedefine RETSIGTYPE ${RETSIGTYPE}
+#cmakedefine RETSIGTYPE ${RETSIGTYPE}
+
+/* Define to the type of arg 1 for `select'. */
+#cmakedefine SELECT_TYPE_ARG1 ${SELECT_TYPE_ARG1}
+
+/* Define to the type of args 2, 3 and 4 for `select'. */
+#cmakedefine SELECT_TYPE_ARG234 ${SELECT_TYPE_ARG234}
+
+/* Define to the type of arg 5 for `select'. */
+#cmakedefine SELECT_TYPE_ARG5 ${SELECT_TYPE_ARG5}
+
+/* The size of a `curl_off_t', as computed by sizeof. */
+#cmakedefine SIZEOF_CURL_OFF_T ${SIZEOF_CURL_OFF_T}
+
+/* The size of a `size_t', as computed by sizeof. */
+#cmakedefine SIZEOF_SIZE_T ${SIZEOF_SIZE_T}
/* Define to 1 if you have the ANSI C header files. */
-#cmakedefine STDC_HEADERS ${STDC_HEADERS}
+#cmakedefine STDC_HEADERS ${STDC_HEADERS}
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
-#cmakedefine TIME_WITH_SYS_TIME ${TIME_WITH_SYS_TIME}
+#cmakedefine TIME_WITH_SYS_TIME ${TIME_WITH_SYS_TIME}
+
+/* Define if you want to enable ares support */
+#cmakedefine USE_ARES ${USE_ARES}
+
+/* If you want to build curl with the built-in manual */
+#cmakedefine USE_MANUAL ${USE_MANUAL}
/* Version number of package */
#cmakedefine VERSION "${VERSION}"
@@ -467,25 +485,22 @@
#endif
/* Number of bits in a file offset, on hosts where this is settable. */
-#cmakedefine _FILE_OFFSET_BITS ${_FILE_OFFSET_BITS}
+#cmakedefine _FILE_OFFSET_BITS ${_FILE_OFFSET_BITS}
/* Define for large files, on AIX-style hosts. */
-#cmakedefine _LARGE_FILES ${_LARGE_FILES}
+#cmakedefine _LARGE_FILES ${_LARGE_FILES}
/* Define to empty if `const' does not conform to ANSI C. */
-#cmakedefine const ${const}
+#cmakedefine const ${const}
/* type to use in place of in_addr_t if not defined */
-#cmakedefine in_addr_t ${in_addr_t}
+#cmakedefine in_addr_t ${in_addr_t}
/* Define to `unsigned' if <sys/types.h> does not define. */
-#cmakedefine size_t ${size_t}
+#cmakedefine size_t ${size_t}
/* type to use in place of socklen_t if not defined */
-#cmakedefine socklen_t ${socklen_t}
-
-/* Define to `int' if <sys/types.h> does not define. */
-#cmakedefine ssize_t ${ssize_t}
+#cmakedefine socklen_t ${socklen_t}
-/* The number of bytes in a long double. */
-#cmakedefine SIZEOF_LONG_DOUBLE ${SIZEOF_LONG_DOUBLE}
+/* the signed version of size_t */
+#cmakedefine ssize_t ${ssize_t}
diff --git a/Source/CTest/Curl/connect.c b/Source/CTest/Curl/connect.c
index 221a727..d19c5e7 100644
--- a/Source/CTest/Curl/connect.c
+++ b/Source/CTest/Curl/connect.c
@@ -1,16 +1,16 @@
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -26,9 +26,21 @@
#ifndef WIN32
/* headers for non-win32 */
#include <sys/time.h>
-#include <sys/socket.h>
+#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h> /* <netinet/tcp.h> may need it */
+#endif
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h> /* for TCP_NODELAY */
+#endif
+#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
+#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
@@ -48,6 +60,13 @@
#include <stdlib.h> /* required for free() prototype, without it, this crashes
on macos 68K */
#endif
+#if (defined(HAVE_FIONBIO) && defined(__NOVELL_LIBC__))
+#include <sys/filio.h>
+#endif
+#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
#ifdef VMS
#include <in.h>
#include <inet.h>
@@ -64,26 +83,37 @@
#endif
#ifdef WIN32
-#define HAVE_IOCTLSOCKET
#include <windows.h>
-#include <winsock.h>
#define EINPROGRESS WSAEINPROGRESS
#define EWOULDBLOCK WSAEWOULDBLOCK
#define EISCONN WSAEISCONN
-#undef HAVE_DISABLED_NONBLOCKING
+#define ENOTSOCK WSAENOTSOCK
+#define ECONNREFUSED WSAECONNREFUSED
#endif
#include "urldata.h"
#include "sendf.h"
#include "if2ip.h"
+#include "strerror.h"
+#include "connect.h"
+#include "memory.h"
/* The last #include file should be: */
-#ifdef MALLOCDEBUG
#include "memdebug.h"
-#endif
-static
-int geterrno(void)
+static bool verifyconnect(curl_socket_t sockfd, int *error);
+
+static curl_socket_t
+singleipconnect(struct connectdata *conn,
+ Curl_addrinfo *ai, /* start connecting to this */
+ long timeout_ms,
+ bool *connected);
+
+/*
+ * Curl_ourerrno() returns the errno (or equivalent) on this platform to
+ * hide platform specific for the function that calls this.
+ */
+int Curl_ourerrno(void)
{
#ifdef WIN32
return (int)GetLastError();
@@ -92,53 +122,60 @@ int geterrno(void)
#endif
}
-/*************************************************************************
- * Curl_nonblock
- *
- * Description:
- * Set the socket to either blocking or non-blocking mode.
+/*
+ * Curl_nonblock() set the given socket to either blocking or non-blocking
+ * mode based on the 'nonblock' boolean argument. This function is highly
+ * portable.
*/
-
-int Curl_nonblock(int socket, /* operate on this */
+int Curl_nonblock(curl_socket_t sockfd, /* operate on this */
int nonblock /* TRUE or FALSE */)
{
#undef SETBLOCK
#ifdef HAVE_O_NONBLOCK
+ /* most recent unix versions */
int flags;
- flags = fcntl(socket, F_GETFL, 0);
+ flags = fcntl(sockfd, F_GETFL, 0);
if (TRUE == nonblock)
- return fcntl(socket, F_SETFL, flags | O_NONBLOCK);
+ return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
else
- return fcntl(socket, F_SETFL, flags & (~O_NONBLOCK));
+ return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK));
#define SETBLOCK 1
#endif
#ifdef HAVE_FIONBIO
+ /* older unix versions */
int flags;
flags = nonblock;
- return ioctl(socket, FIONBIO, &flags);
+ return ioctl(sockfd, FIONBIO, &flags);
#define SETBLOCK 2
#endif
#ifdef HAVE_IOCTLSOCKET
- int flags;
+ /* Windows? */
+ unsigned long flags;
flags = nonblock;
- return ioctlsocket(socket, FIONBIO, (unsigned long*)&flags);
+ return ioctlsocket(sockfd, FIONBIO, &flags);
#define SETBLOCK 3
#endif
#ifdef HAVE_IOCTLSOCKET_CASE
- return IoctlSocket(socket, FIONBIO, (long)nonblock);
+ /* presumably for Amiga */
+ return IoctlSocket(sockfd, FIONBIO, (long)nonblock);
#define SETBLOCK 4
#endif
+#ifdef HAVE_SO_NONBLOCK
+ /* BeOS */
+ long b = nonblock ? 1 : 0;
+ return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b));
+#define SETBLOCK 5
+#endif
+
#ifdef HAVE_DISABLED_NONBLOCKING
- (void)socket;
- (void)nonblock;
return 0; /* returns success */
-#define SETBLOCK 5
+#define SETBLOCK 6
#endif
#ifndef SETBLOCK
@@ -147,16 +184,33 @@ int Curl_nonblock(int socket, /* operate on this */
}
/*
- * Return 0 on fine connect, -1 on error and 1 on timeout.
+ * waitconnect() waits for a TCP connect on the given socket for the specified
+ * number if milliseconds. It returns:
+ * 0 fine connect
+ * -1 select() error
+ * 1 select() timeout
+ * 2 select() returned with an error condition fd_set
*/
+
+#define WAITCONN_CONNECTED 0
+#define WAITCONN_SELECT_ERROR -1
+#define WAITCONN_TIMEOUT 1
+#define WAITCONN_FDSET_ERROR 2
+
static
-int waitconnect(int sockfd, /* socket */
- int timeout_msec)
+int waitconnect(curl_socket_t sockfd, /* socket */
+ long timeout_msec)
{
fd_set fd;
fd_set errfd;
struct timeval interval;
int rc;
+#ifdef mpeix
+ /* Call this function once now, and ignore the results. We do this to
+ "clear" the error state on the socket so that we can later read it
+ reliably. This is reported necessary on the MPE/iX operating system. */
+ verifyconnect(sockfd, NULL);
+#endif
/* now select() until we get connect or timeout */
FD_ZERO(&fd);
@@ -165,7 +219,7 @@ int waitconnect(int sockfd, /* socket */
FD_ZERO(&errfd);
FD_SET(sockfd, &errfd);
- interval.tv_sec = timeout_msec/1000;
+ interval.tv_sec = (int)(timeout_msec/1000);
timeout_msec -= interval.tv_sec*1000;
interval.tv_usec = timeout_msec*1000;
@@ -173,63 +227,66 @@ int waitconnect(int sockfd, /* socket */
rc = select(sockfd+1, NULL, &fd, &errfd, &interval);
if(-1 == rc)
/* error, no connect here, try next */
- return -1;
-
+ return WAITCONN_SELECT_ERROR;
+
else if(0 == rc)
/* timeout, no connect today */
- return 1;
+ return WAITCONN_TIMEOUT;
if(FD_ISSET(sockfd, &errfd))
/* error condition caught */
- return 2;
+ return WAITCONN_FDSET_ERROR;
/* we have a connect! */
- return 0;
+ return WAITCONN_CONNECTED;
}
static CURLcode bindlocal(struct connectdata *conn,
- int sockfd)
+ curl_socket_t sockfd)
{
-#if !defined(WIN32)||defined(__CYGWIN32__)
- /* We don't generally like checking for OS-versions, we should make this
- HAVE_XXXX based, although at the moment I don't have a decent test for
- this! */
-
#ifdef HAVE_INET_NTOA
-
-#ifndef INADDR_NONE
-#define INADDR_NONE (in_addr_t) ~0
-#endif
-
+ bool bindworked = FALSE;
struct SessionHandle *data = conn->data;
/*************************************************************
* Select device to bind socket to
*************************************************************/
if (strlen(data->set.device)<255) {
- struct sockaddr_in sa;
struct Curl_dns_entry *h=NULL;
+ size_t size;
char myhost[256] = "";
in_addr_t in;
+ int rc;
+ bool was_iface = FALSE;
- if(Curl_if2ip(data->set.device, myhost, sizeof(myhost))) {
+ /* First check if the given name is an IP address */
+ in=inet_addr(data->set.device);
+
+ if((in == CURL_INADDR_NONE) &&
+ Curl_if2ip(data->set.device, myhost, sizeof(myhost))) {
/*
* We now have the numerical IPv4-style x.y.z.w in the 'myhost' buffer
*/
- h = Curl_resolv(data, myhost, 0);
+ rc = Curl_resolv(conn, myhost, 0, &h);
+ if(rc == CURLRESOLV_PENDING)
+ (void)Curl_wait_for_resolv(conn, &h);
+
+ if(h)
+ was_iface = TRUE;
}
- else {
- if(strlen(data->set.device)>1) {
- /*
- * This was not an interface, resolve the name as a host name
- * or IP number
- */
- h = Curl_resolv(data, data->set.device, 0);
- if(h) {
- /* we know data->set.device is shorter than the myhost array */
- strcpy(myhost, data->set.device);
- }
- }
+
+ if(!was_iface) {
+ /*
+ * This was not an interface, resolve the name as a host name
+ * or IP number
+ */
+ rc = Curl_resolv(conn, data->set.device, 0, &h);
+ if(rc == CURLRESOLV_PENDING)
+ (void)Curl_wait_for_resolv(conn, &h);
+
+ if(h)
+ /* we know data->set.device is shorter than the myhost array */
+ strcpy(myhost, data->set.device);
}
if(! *myhost) {
@@ -239,79 +296,69 @@ static CURLcode bindlocal(struct connectdata *conn,
hostent_buf,
sizeof(hostent_buf));
*/
+ failf(data, "Couldn't bind to '%s'", data->set.device);
return CURLE_HTTP_PORT_FAILED;
}
infof(data, "We bind local end to %s\n", myhost);
+#ifdef SO_BINDTODEVICE
+ /* I am not sure any other OSs than Linux that provide this feature, and
+ * at the least I cannot test. --Ben
+ *
+ * This feature allows one to tightly bind the local socket to a
+ * particular interface. This will force even requests to other local
+ * interfaces to go out the external interface.
+ *
+ */
+ if (was_iface) {
+ /* Only bind to the interface when specified as interface, not just as a
+ * hostname or ip address.
+ */
+ if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
+ data->set.device, strlen(data->set.device)+1) != 0) {
+ /* printf("Failed to BINDTODEVICE, socket: %d device: %s error: %s\n",
+ sockfd, data->set.device, Curl_strerror(Curl_ourerrno())); */
+ infof(data, "SO_BINDTODEVICE %s failed\n",
+ data->set.device);
+ /* This is typically "errno 1, error: Operation not permitted" if
+ you're not running as root or another suitable privileged user */
+ }
+ }
+#endif
+
in=inet_addr(myhost);
- if (INADDR_NONE != in) {
+ if (CURL_INADDR_NONE != in) {
if ( h ) {
Curl_addrinfo *addr = h->addr;
- Curl_resolv_unlock(h);
+ Curl_resolv_unlock(data, h);
/* we don't need it anymore after this function has returned */
- memset((char *)&sa, 0, sizeof(sa));
+ if( bind(sockfd, addr->ai_addr, (socklen_t)addr->ai_addrlen) >= 0) {
+ /* we succeeded to bind */
#ifdef ENABLE_IPV6
- memcpy((char *)&sa.sin_addr, addr->ai_addr, addr->ai_addrlen);
- sa.sin_family = addr->ai_family;
+ struct sockaddr_in6 add;
#else
- memcpy((char *)&sa.sin_addr, addr->h_addr, addr->h_length);
- sa.sin_family = AF_INET;
-#endif
- sa.sin_addr.s_addr = in;
- sa.sin_port = 0; /* get any port */
-
- if( bind(sockfd, (struct sockaddr *)&sa, sizeof(sa)) >= 0) {
- /* we succeeded to bind */
struct sockaddr_in add;
-
-#ifdef __hpux
- int gsize = sizeof(add);
-#else
- socklen_t gsize = sizeof(add);
#endif
+
+ bindworked = TRUE;
+
+ size = sizeof(add);
if(getsockname(sockfd, (struct sockaddr *) &add,
- &gsize)<0) {
+ (socklen_t *)&size)<0) {
failf(data, "getsockname() failed");
return CURLE_HTTP_PORT_FAILED;
}
}
- else {
- switch(errno) {
- case EBADF:
- failf(data, "Invalid descriptor: %d", errno);
- break;
- case EINVAL:
- failf(data, "Invalid request: %d", errno);
- break;
- case EACCES:
- failf(data, "Address is protected, user not superuser: %d", errno);
- break;
- case ENOTSOCK:
- failf(data,
- "Argument is a descriptor for a file, not a socket: %d",
- errno);
- break;
- case EFAULT:
- failf(data, "Inaccessable memory error: %d", errno);
- break;
- case ENAMETOOLONG:
- failf(data, "Address too long: %d", errno);
- break;
- case ENOMEM:
- failf(data, "Insufficient kernel memory was available: %d", errno);
- break;
- default:
- failf(data, "errno %d", errno);
- break;
- } /* end of switch(errno) */
-
+
+ if(!bindworked) {
+ failf(data, "%s", Curl_strerror(conn, Curl_ourerrno()));
return CURLE_HTTP_PORT_FAILED;
- } /* end of else */
-
+ }
+
} /* end of if h */
else {
failf(data,"could't find my own IP address (%s)", myhost);
@@ -328,29 +375,85 @@ static CURLcode bindlocal(struct connectdata *conn,
} /* end of device selection support */
#endif /* end of HAVE_INET_NTOA */
-#endif /* end of not WIN32 */
- (void)conn;
- (void)sockfd;
return CURLE_HTTP_PORT_FAILED;
}
-
-static
-int socketerror(int sockfd)
+/*
+ * verifyconnect() returns TRUE if the connect really has happened.
+ */
+static bool verifyconnect(curl_socket_t sockfd, int *error)
{
+ bool rc = TRUE;
+#ifdef SO_ERROR
int err = 0;
-#ifdef __hpux
- int errSize = sizeof(err);
-#else
socklen_t errSize = sizeof(err);
+
+#ifdef WIN32
+ /*
+ * In October 2003 we effectively nullified this function on Windows due to
+ * problems with it using all CPU in multi-threaded cases.
+ *
+ * In May 2004, we bring it back to offer more info back on connect failures.
+ * Gisle Vanem could reproduce the former problems with this function, but
+ * could avoid them by adding this SleepEx() call below:
+ *
+ * "I don't have Rational Quantify, but the hint from his post was
+ * ntdll::NtRemoveIoCompletion(). So I'd assume the SleepEx (or maybe
+ * just Sleep(0) would be enough?) would release whatever
+ * mutex/critical-section the ntdll call is waiting on.
+ *
+ * Someone got to verify this on Win-NT 4.0, 2000."
+ */
+ SleepEx(0, FALSE);
#endif
if( -1 == getsockopt(sockfd, SOL_SOCKET, SO_ERROR,
(void *)&err, &errSize))
- err = geterrno();
-
- return err;
+ err = Curl_ourerrno();
+
+ if ((0 == err) || (EISCONN == err))
+ /* we are connected, awesome! */
+ rc = TRUE;
+ else
+ /* This wasn't a successful connect */
+ rc = FALSE;
+ if (error)
+ *error = err;
+#else
+ (void)sockfd;
+ if (error)
+ *error = Curl_ourerrno();
+#endif
+ return rc;
+}
+
+/* Used within the multi interface. Try next IP address, return TRUE if no
+ more address exists */
+static bool trynextip(struct connectdata *conn,
+ int sockindex,
+ bool *connected)
+{
+ curl_socket_t sockfd;
+ Curl_addrinfo *ai;
+
+ if(sockindex != FIRSTSOCKET)
+ return TRUE; /* no next */
+
+ /* try the next address */
+ ai = conn->ip_addr->ai_next;
+
+ while (ai) {
+ sockfd = singleipconnect(conn, ai, 0L, connected);
+ if(sockfd != CURL_SOCKET_BAD) {
+ /* store the new socket descriptor */
+ conn->sock[sockindex] = sockfd;
+ conn->ip_addr = ai;
+ return FALSE;
+ }
+ ai = ai->ai_next;
+ }
+ return TRUE;
}
/*
@@ -359,37 +462,41 @@ int socketerror(int sockfd)
*/
CURLcode Curl_is_connected(struct connectdata *conn,
- int sockfd,
+ int sockindex,
bool *connected)
{
int rc;
struct SessionHandle *data = conn->data;
+ CURLcode code = CURLE_OK;
+ curl_socket_t sockfd = conn->sock[sockindex];
+ long allow = DEFAULT_CONNECT_TIMEOUT;
+ long has_passed;
- *connected = FALSE; /* a very negative world view is best */
+ curlassert(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);
- if(data->set.timeout || data->set.connecttimeout) {
- /* there is a timeout set */
+ *connected = FALSE; /* a very negative world view is best */
- /* Evaluate in milliseconds how much time that has passed */
- long has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.start);
+ /* Evaluate in milliseconds how much time that has passed */
+ has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.start);
- /* subtract the most strict timeout of the ones */
- if(data->set.timeout && data->set.connecttimeout) {
- if (data->set.timeout < data->set.connecttimeout)
- has_passed -= data->set.timeout*1000;
- else
- has_passed -= data->set.connecttimeout*1000;
- }
- else if(data->set.timeout)
- has_passed -= data->set.timeout*1000;
+ /* subtract the most strict timeout of the ones */
+ if(data->set.timeout && data->set.connecttimeout) {
+ if (data->set.timeout < data->set.connecttimeout)
+ allow = data->set.timeout*1000;
else
- has_passed -= data->set.connecttimeout*1000;
+ allow = data->set.connecttimeout*1000;
+ }
+ else if(data->set.timeout) {
+ allow = data->set.timeout*1000;
+ }
+ else if(data->set.connecttimeout) {
+ allow = data->set.connecttimeout*1000;
+ }
- if(has_passed > 0 ) {
- /* time-out, bail out, go home */
- failf(data, "Connection time-out");
- return CURLE_OPERATION_TIMEOUTED;
- }
+ if(has_passed > allow ) {
+ /* time-out, bail out, go home */
+ failf(data, "Connection time-out after %ld ms", has_passed);
+ return CURLE_OPERATION_TIMEOUTED;
}
if(conn->bits.tcpconnect) {
/* we are connected already! */
@@ -400,29 +507,142 @@ CURLcode Curl_is_connected(struct connectdata *conn,
/* check for connect without timeout as we want to return immediately */
rc = waitconnect(sockfd, 0);
- if(0 == rc) {
- int err = socketerror(sockfd);
- if ((0 == err) || (EISCONN == err)) {
+ if(WAITCONN_CONNECTED == rc) {
+ if (verifyconnect(sockfd, NULL)) {
/* we are connected, awesome! */
*connected = TRUE;
return CURLE_OK;
}
/* nope, not connected for real */
- if(err)
- return CURLE_COULDNT_CONNECT;
+ infof(data, "Connection failed\n");
+ if(trynextip(conn, sockindex, connected)) {
+ code = CURLE_COULDNT_CONNECT;
+ }
+ }
+ else if(WAITCONN_TIMEOUT != rc) {
+ /* nope, not connected */
+ infof(data, "Connection failed\n");
+ if(trynextip(conn, sockindex, connected)) {
+ int error = Curl_ourerrno();
+ failf(data, "Failed connect to %s:%d; %s",
+ conn->host.name, conn->port, Curl_strerror(conn,error));
+ code = CURLE_COULDNT_CONNECT;
+ }
}
-
/*
- * If the connection phase is "done" here, we should attempt to connect
- * to the "next address" in the Curl_hostaddr structure that we resolved
- * before. But we don't have that struct around anymore and we can't just
- * keep a pointer since the cache might in fact have gotten pruned by the
- * time we want to read this... Alas, we don't do this yet.
+ * If the connection failed here, we should attempt to connect to the "next
+ * address" for the given host.
*/
- return CURLE_OK;
+ return code;
+}
+
+static void tcpnodelay(struct connectdata *conn,
+ curl_socket_t sockfd)
+{
+#ifdef TCP_NODELAY
+ struct SessionHandle *data= conn->data;
+ socklen_t onoff = (socklen_t) data->set.tcp_nodelay;
+ if(setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (void *)&onoff,
+ sizeof(onoff)) < 0)
+ infof(data, "Could not set TCP_NODELAY: %s\n",
+ Curl_strerror(conn, Curl_ourerrno()));
+ else
+ infof(data,"TCP_NODELAY set\n");
+#else
+ (void)conn;
+ (void)sockfd;
+#endif
}
+/* singleipconnect() connects to the given IP only, and it may return without
+ having connected if used from the multi interface. */
+static curl_socket_t
+singleipconnect(struct connectdata *conn,
+ Curl_addrinfo *ai,
+ long timeout_ms,
+ bool *connected)
+{
+ char addr_buf[128];
+ int rc;
+ int error;
+ bool conected;
+ struct SessionHandle *data = conn->data;
+ curl_socket_t sockfd = socket(ai->ai_family, ai->ai_socktype,
+ ai->ai_protocol);
+ if (sockfd == CURL_SOCKET_BAD)
+ return CURL_SOCKET_BAD;
+
+ *connected = FALSE; /* default is not connected */
+
+ Curl_printable_address(ai, addr_buf, sizeof(addr_buf));
+ infof(data, " Trying %s... ", addr_buf);
+
+ if(data->set.tcp_nodelay)
+ tcpnodelay(conn, sockfd);
+
+ if(conn->data->set.device) {
+ /* user selected to bind the outgoing socket to a specified "device"
+ before doing connect */
+ CURLcode res = bindlocal(conn, sockfd);
+ if(res)
+ return res;
+ }
+
+ /* set socket non-blocking */
+ Curl_nonblock(sockfd, TRUE);
+
+ rc = connect(sockfd, ai->ai_addr, ai->ai_addrlen);
+
+ if(-1 == rc) {
+ error = Curl_ourerrno();
+
+ switch (error) {
+ case EINPROGRESS:
+ case EWOULDBLOCK:
+#if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
+ /* On some platforms EAGAIN and EWOULDBLOCK are the
+ * same value, and on others they are different, hence
+ * the odd #if
+ */
+ case EAGAIN:
+#endif
+ rc = waitconnect(sockfd, timeout_ms);
+ break;
+ default:
+ /* unknown error, fallthrough and try another address! */
+ failf(data, "Failed to connect to %s: %s",
+ addr_buf, Curl_strerror(conn,error));
+ break;
+ }
+ }
+
+ /* The 'WAITCONN_TIMEOUT == rc' comes from the waitconnect(), and not from
+ connect(). We can be sure of this since connect() cannot return 1. */
+ if((WAITCONN_TIMEOUT == rc) &&
+ (data->state.used_interface == Curl_if_multi)) {
+ /* Timeout when running the multi interface */
+ return sockfd;
+ }
+
+ conected = verifyconnect(sockfd, &error);
+
+ if(!rc && conected) {
+ /* we are connected, awesome! */
+ *connected = TRUE; /* this is a true connect */
+ infof(data, "connected\n");
+ return sockfd;
+ }
+ else if(WAITCONN_TIMEOUT == rc)
+ infof(data, "Timeout\n");
+ else
+ infof(data, "%s\n", Curl_strerror(conn, error));
+
+ /* connect failed or timed out */
+ sclose(sockfd);
+
+ return CURL_SOCKET_BAD;
+}
/*
* TCP connect to the given host with timeout, proxy or remote doesn't matter.
@@ -432,16 +652,16 @@ CURLcode Curl_is_connected(struct connectdata *conn,
CURLcode Curl_connecthost(struct connectdata *conn, /* context */
struct Curl_dns_entry *remotehost, /* use this one */
- int port, /* connect to this */
- int *sockconn, /* the connected socket */
- Curl_ipconnect **addr, /* the one we used */
+ curl_socket_t *sockconn, /* the connected socket */
+ Curl_addrinfo **addr, /* the one we used */
bool *connected) /* really connected? */
{
struct SessionHandle *data = conn->data;
- int rc;
- int sockfd=-1;
- int aliasindex=0;
- char *hostname;
+ curl_socket_t sockfd = CURL_SOCKET_BAD;
+ int aliasindex;
+ int num_addr;
+ Curl_addrinfo *ai;
+ Curl_addrinfo *curr_addr;
struct timeval after;
struct timeval before = Curl_tvnow();
@@ -449,12 +669,13 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
/*************************************************************
* Figure out what maximum time we have left
*************************************************************/
- long timeout_ms=300000; /* milliseconds, default to five minutes */
+ long timeout_ms= DEFAULT_CONNECT_TIMEOUT;
+ long timeout_per_addr;
*connected = FALSE; /* default to not connected */
if(data->set.timeout || data->set.connecttimeout) {
- double has_passed;
+ long has_passed;
/* Evaluate in milliseconds how much time that has passed */
has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.start);
@@ -467,7 +688,7 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
if(data->set.timeout && data->set.connecttimeout) {
if (data->set.timeout < data->set.connecttimeout)
timeout_ms = data->set.timeout*1000;
- else
+ else
timeout_ms = data->set.connecttimeout*1000;
}
else if(data->set.timeout)
@@ -476,7 +697,7 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
timeout_ms = data->set.connecttimeout*1000;
/* subtract the passed time */
- timeout_ms -= (long)has_passed;
+ timeout_ms -= has_passed;
if(timeout_ms < 0) {
/* a precaution, no need to continue if time already is up */
@@ -485,232 +706,53 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
}
}
- hostname = data->change.proxy?conn->proxyhost:conn->hostname;
- infof(data, "About to connect() to %s%s%s:%d\n",
- conn->bits.ipv6_ip?"[":"",
- hostname,
- conn->bits.ipv6_ip?"]":"",
- port);
+ /* Max time for each address */
+ num_addr = Curl_num_addresses(remotehost->addr);
+ timeout_per_addr = timeout_ms / num_addr;
-#ifdef ENABLE_IPV6
- /*
- * Connecting with IPv6 support is so much easier and cleanly done
- */
- {
- struct addrinfo *ai;
- port =0; /* prevent compiler warning */
-
- for (ai = remotehost->addr; ai; ai = ai->ai_next, aliasindex++) {
- sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
- if (sockfd < 0)
- continue;
-
- if(conn->data->set.device) {
- /* user selected to bind the outgoing socket to a specified "device"
- before doing connect */
- CURLcode res = bindlocal(conn, sockfd);
- if(res)
- return res;
- }
-
- /* set socket non-blocking */
- Curl_nonblock(sockfd, TRUE);
-
- rc = connect(sockfd, ai->ai_addr, ai->ai_addrlen);
-
- if(-1 == rc) {
- int error=geterrno();
+ ai = remotehost->addr;
- switch (error) {
- case EINPROGRESS:
- case EWOULDBLOCK:
-#if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
- /* On some platforms EAGAIN and EWOULDBLOCK are the
- * same value, and on others they are different, hence
- * the odd #if
- */
- case EAGAIN:
-#endif
- case EINTR:
- /* asynchronous connect, wait for connect or timeout */
- if(data->state.used_interface == Curl_if_multi)
- /* don't hang when doing multi */
- timeout_ms = 0;
-
- rc = waitconnect(sockfd, timeout_ms);
- break;
- case ECONNREFUSED: /* no one listening */
- default:
- /* unknown error, fallthrough and try another address! */
- failf(data, "Failed connect to %s: %d", hostname, error);
- break;
- }
- }
-
- if(0 == rc) {
- /* we might be connected, if the socket says it is OK! Ask it! */
- int err;
-
- err = socketerror(sockfd);
- if ((0 == err) || (EISCONN == err)) {
- /* we are connected, awesome! */
- *connected = TRUE; /* this is truly a connect */
- break;
- }
- failf(data, "socket error: %d", err);
- /* we are _not_ connected, it was a false alert, continue please */
- }
- else if(data->state.used_interface == Curl_if_multi) {
- /* When running the multi interface, we bail out here */
- rc = 0;
- break;
- }
-
- /* connect failed or timed out */
- sclose(sockfd);
- sockfd = -1;
-
- /* get a new timeout for next attempt */
- after = Curl_tvnow();
- timeout_ms -= Curl_tvdiff(after, before);
- if(timeout_ms < 0) {
- failf(data, "connect() timed out!");
- return CURLE_OPERATION_TIMEOUTED;
- }
- before = after;
- continue;
- }
- if (sockfd < 0)
- return CURLE_COULDNT_CONNECT;
+ /* Below is the loop that attempts to connect to all IP-addresses we
+ * know for the given host. One by one until one IP succeeds.
+ */
- /* leave the socket in non-blocking mode */
+ if(data->state.used_interface == Curl_if_multi)
+ /* don't hang when doing multi */
+ timeout_per_addr = timeout_ms = 0;
- if(addr)
- *addr = ai; /* the address we ended up connected to */
- }
-#else
/*
- * Connecting with IPv4-only support
+ * Connecting with a Curl_addrinfo chain
*/
- if(!remotehost->addr->h_addr_list[0]) {
- /* If there is no addresses in the address list, then we return
- error right away */
- failf(data, "no address available");
- return CURLE_COULDNT_CONNECT;
- }
- /* create an IPv4 TCP socket */
- sockfd = (int)socket(AF_INET, SOCK_STREAM, 0);
- if(-1 == sockfd) {
- failf(data, "couldn't create socket");
- return CURLE_COULDNT_CONNECT; /* big time error */
- }
-
- if(conn->data->set.device) {
- /* user selected to bind the outgoing socket to a specified "device"
- before doing connect */
- CURLcode res = bindlocal(conn, sockfd);
- if(res)
- return res;
- }
+ for (curr_addr = ai, aliasindex=0; curr_addr;
+ curr_addr = curr_addr->ai_next, aliasindex++) {
- /* Convert socket to non-blocking type */
- Curl_nonblock(sockfd, TRUE);
+ /* start connecting to the IP curr_addr points to */
+ sockfd = singleipconnect(conn, curr_addr, timeout_per_addr, connected);
- /* This is the loop that attempts to connect to all IP-addresses we
- know for the given host. One by one. */
- for(rc=-1, aliasindex=0;
- rc && (void *)remotehost->addr->h_addr_list[aliasindex];
- aliasindex++) {
- struct sockaddr_in serv_addr;
-
- /* do this nasty work to do the connect */
- memset((char *) &serv_addr, '\0', sizeof(serv_addr));
- memcpy(&(serv_addr.sin_addr),
- remotehost->addr->h_addr_list[aliasindex],
- sizeof(struct in_addr));
- serv_addr.sin_family = remotehost->addr->h_addrtype;
- serv_addr.sin_port = htons((unsigned short)port);
-
- rc = connect(sockfd, (struct sockaddr *)&serv_addr,
- sizeof(serv_addr));
-
- if(-1 == rc) {
- int error=geterrno();
-
- switch (error) {
- case EINPROGRESS:
- case EWOULDBLOCK:
-#if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
- /* On some platforms EAGAIN and EWOULDBLOCK are the
- * same value, and on others they are different, hence
- * the odd #if
- */
- case EAGAIN:
-#endif
- /* asynchronous connect, wait for connect or timeout */
- if(data->state.used_interface == Curl_if_multi)
- /* don't hang when doing multi */
- timeout_ms = 0;
-
- rc = waitconnect(sockfd, timeout_ms);
- break;
- default:
- /* unknown error, fallthrough and try another address! */
- failf(data, "Failed to connect to %s IP number %d: %d",
- hostname, aliasindex+1, error);
- break;
- }
- }
-
- /* The '1 == rc' comes from the waitconnect(), and not from connect().
- We can be sure of this since connect() cannot return 1. */
- if((1 == rc) && (data->state.used_interface == Curl_if_multi)) {
- /* Timeout when running the multi interface, we return here with a
- CURLE_OK return code. */
- rc = 0;
+ if(sockfd != CURL_SOCKET_BAD)
break;
- }
- if(0 == rc) {
- int err = socketerror(sockfd);
- if ((0 == err) || (EISCONN == err)) {
- /* we are connected, awesome! */
- *connected = TRUE; /* this is a true connect */
- break;
- }
- /* nope, not connected for real */
- rc = -1;
+ /* get a new timeout for next attempt */
+ after = Curl_tvnow();
+ timeout_ms -= Curl_tvdiff(after, before);
+ if(timeout_ms < 0) {
+ failf(data, "connect() timed out!");
+ return CURLE_OPERATION_TIMEOUTED;
}
+ before = after;
+ } /* end of connect-to-each-address loop */
- if(0 != rc) {
- /* get a new timeout for next attempt */
- after = Curl_tvnow();
- timeout_ms -= Curl_tvdiff(after, before);
- if(timeout_ms < 0) {
- failf(data, "Connect timeout on IP number %d", aliasindex+1);
- break;
- }
- before = after;
- continue; /* try next address */
- }
- break;
- }
- if(0 != rc) {
+ if (sockfd == CURL_SOCKET_BAD) {
/* no good connect was made */
- sclose(sockfd);
- *sockconn = -1;
- failf(data, "Connect failed");
+ *sockconn = CURL_SOCKET_BAD;
return CURLE_COULDNT_CONNECT;
}
/* leave the socket in non-blocking mode */
+ /* store the address we use */
if(addr)
- {
- /* this is the address we've connected to */
- memcpy(addr, &remotehost->addr->h_addr_list[aliasindex], sizeof(struct in_addr*));
- }
-#endif
+ *addr = curr_addr;
/* allow NULL-pointers to get passed in */
if(sockconn)
@@ -718,4 +760,3 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
return CURLE_OK;
}
-
diff --git a/Source/CTest/Curl/connect.h b/Source/CTest/Curl/connect.h
index fdbecec..d39495c 100644
--- a/Source/CTest/Curl/connect.h
+++ b/Source/CTest/Curl/connect.h
@@ -1,18 +1,18 @@
#ifndef __CONNECT_H
#define __CONNECT_H
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -23,18 +23,22 @@
* $Id$
***************************************************************************/
-int Curl_nonblock(int socket, /* operate on this */
+int Curl_nonblock(curl_socket_t sockfd, /* operate on this */
int nonblock /* TRUE or FALSE */);
CURLcode Curl_is_connected(struct connectdata *conn,
- int sockfd,
+ int sockindex,
bool *connected);
CURLcode Curl_connecthost(struct connectdata *conn,
struct Curl_dns_entry *host, /* connect to this */
- int port, /* connect to this port number */
- int *sockconn, /* not set if error is returned */
- Curl_ipconnect **addr, /* the one we used */
+ curl_socket_t *sockconn, /* not set if error */
+ Curl_addrinfo **addr, /* the one we used */
bool *connected /* truly connected? */
);
+
+int Curl_ourerrno(void);
+
+#define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */
+
#endif
diff --git a/Source/CTest/Curl/content_encoding.c b/Source/CTest/Curl/content_encoding.c
index e20e26e..b786e3f 100644
--- a/Source/CTest/Curl/content_encoding.c
+++ b/Source/CTest/Curl/content_encoding.c
@@ -1,16 +1,16 @@
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -25,13 +25,29 @@
#ifdef HAVE_LIBZ
+#include <stdlib.h>
+#include <string.h>
+
#include "urldata.h"
#include <curl/curl.h>
-#include <curl/types.h>
#include "sendf.h"
+#include "content_encoding.h"
+#include "memory.h"
+
+#include "memdebug.h"
-#define DSIZ 4096 /* buffer size for decompressed data */
+#define DSIZ 0x10000 /* buffer size for decompressed data */
+#define GZIP_MAGIC_0 0x1f
+#define GZIP_MAGIC_1 0x8b
+
+/* gzip flag byte */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
+#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define COMMENT 0x10 /* bit 4 set: file comment present */
+#define RESERVED 0xE0 /* bits 5..7: reserved */
static CURLcode
process_zlib_error(struct SessionHandle *data, z_stream *z)
@@ -55,28 +71,30 @@ exit_zlib(z_stream *z, bool *zlib_init, CURLcode result)
}
CURLcode
-Curl_unencode_deflate_write(struct SessionHandle *data,
+Curl_unencode_deflate_write(struct SessionHandle *data,
struct Curl_transfer_keeper *k,
ssize_t nread)
{
int status; /* zlib status */
- int result; /* Curl_client_write status */
+ CURLcode result = CURLE_OK; /* Curl_client_write status */
char decomp[DSIZ]; /* Put the decompressed data here. */
z_stream *z = &k->z; /* zlib state structure */
-
+
/* Initialize zlib? */
if (!k->zlib_init) {
z->zalloc = (alloc_func)Z_NULL;
z->zfree = (free_func)Z_NULL;
- z->opaque = 0; /* of dubious use 08/27/02 jhrg */
+ z->opaque = 0;
+ z->next_in = NULL;
+ z->avail_in = 0;
if (inflateInit(z) != Z_OK)
return process_zlib_error(data, z);
k->zlib_init = 1;
}
- /* Set the compressed input when this fucntion is called */
+ /* Set the compressed input when this function is called */
z->next_in = (Bytef *)k->str;
- z->avail_in = nread;
+ z->avail_in = (uInt)nread;
/* because the buffer size is fixed, iteratively decompress
and transfer to the client via client_write. */
@@ -87,36 +105,259 @@ Curl_unencode_deflate_write(struct SessionHandle *data,
status = inflate(z, Z_SYNC_FLUSH);
if (status == Z_OK || status == Z_STREAM_END) {
- result = Curl_client_write(data, CLIENTWRITE_BODY, decomp,
- DSIZ - z->avail_out);
- /* if !CURLE_OK, clean up, return */
- if (result) {
- return exit_zlib(z, &k->zlib_init, (CURLcode)result);
+ if (DSIZ - z->avail_out) {
+ result = Curl_client_write(data, CLIENTWRITE_BODY, decomp,
+ DSIZ - z->avail_out);
+ /* if !CURLE_OK, clean up, return */
+ if (result)
+ return exit_zlib(z, &k->zlib_init, result);
}
/* Done?; clean up, return */
if (status == Z_STREAM_END) {
if (inflateEnd(z) == Z_OK)
- return exit_zlib(z, &k->zlib_init, (CURLcode)result);
+ return exit_zlib(z, &k->zlib_init, result);
else
return exit_zlib(z, &k->zlib_init, process_zlib_error(data, z));
}
/* Done with these bytes, exit */
- if (status == Z_OK && z->avail_in == 0 && z->avail_out > 0)
- return (CURLcode)result;
+ if (status == Z_OK && z->avail_in == 0 && z->avail_out > 0)
+ return result;
}
else { /* Error; exit loop, handle below */
return exit_zlib(z, &k->zlib_init, process_zlib_error(data, z));
}
}
}
-#endif /* HAVE_LIBZ */
-/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
- */
+/* Skip over the gzip header */
+static enum {
+ GZIP_OK,
+ GZIP_BAD,
+ GZIP_UNDERFLOW
+} check_gzip_header(unsigned char const *data, ssize_t len, ssize_t *headerlen)
+{
+ int method, flags;
+ const ssize_t totallen = len;
+
+ /* The shortest header is 10 bytes */
+ if (len < 10)
+ return GZIP_UNDERFLOW;
+
+ if ((data[0] != GZIP_MAGIC_0) || (data[1] != GZIP_MAGIC_1))
+ return GZIP_BAD;
+
+ method = data[2];
+ flags = data[3];
+
+ if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
+ /* Can't handle this compression method or unknown flag */
+ return GZIP_BAD;
+ }
+
+ /* Skip over time, xflags, OS code and all previous bytes */
+ len -= 10;
+ data += 10;
+
+ if (flags & EXTRA_FIELD) {
+ ssize_t extra_len;
+
+ if (len < 2)
+ return GZIP_UNDERFLOW;
+
+ extra_len = (data[1] << 8) | data[0];
+
+ if (len < (extra_len+2))
+ return GZIP_UNDERFLOW;
+
+ len -= (extra_len + 2);
+ }
+
+ if (flags & ORIG_NAME) {
+ /* Skip over NUL-terminated file name */
+ while (len && *data) {
+ --len;
+ ++data;
+ }
+ if (!len || *data)
+ return GZIP_UNDERFLOW;
+
+ /* Skip over the NUL */
+ --len;
+ ++data;
+ }
+
+ if (flags & COMMENT) {
+ /* Skip over NUL-terminated comment */
+ while (len && *data) {
+ --len;
+ ++data;
+ }
+ if (!len || *data)
+ return GZIP_UNDERFLOW;
+
+ /* Skip over the NUL */
+ --len;
+ ++data;
+ }
+
+ if (flags & HEAD_CRC) {
+ if (len < 2)
+ return GZIP_UNDERFLOW;
+
+ len -= 2;
+ data += 2;
+ }
+
+ *headerlen = totallen - len;
+ return GZIP_OK;
+}
+
+CURLcode
+Curl_unencode_gzip_write(struct SessionHandle *data,
+ struct Curl_transfer_keeper *k,
+ ssize_t nread)
+{
+ int status; /* zlib status */
+ CURLcode result = CURLE_OK; /* Curl_client_write status */
+ char decomp[DSIZ]; /* Put the decompressed data here. */
+ z_stream *z = &k->z; /* zlib state structure */
+
+ /* Initialize zlib? */
+ if (!k->zlib_init) {
+ z->zalloc = (alloc_func)Z_NULL;
+ z->zfree = (free_func)Z_NULL;
+ z->opaque = 0;
+ z->next_in = NULL;
+ z->avail_in = 0;
+ if (inflateInit2(z, -MAX_WBITS) != Z_OK)
+ return process_zlib_error(data, z);
+ k->zlib_init = 1; /* Initial call state */
+ }
+
+ /* This next mess is to get around the potential case where there isn't
+ * enough data passed in to skip over the gzip header. If that happens, we
+ * malloc a block and copy what we have then wait for the next call. If
+ * there still isn't enough (this is definitely a worst-case scenario), we
+ * make the block bigger, copy the next part in and keep waiting.
+ */
+
+ /* Skip over gzip header? */
+ if (k->zlib_init == 1) {
+ /* Initial call state */
+ ssize_t hlen;
+
+ switch (check_gzip_header((unsigned char *)k->str, nread, &hlen)) {
+ case GZIP_OK:
+ z->next_in = (Bytef *)k->str + hlen;
+ z->avail_in = (uInt)(nread - hlen);
+ k->zlib_init = 3; /* Inflating stream state */
+ break;
+
+ case GZIP_UNDERFLOW:
+ /* We need more data so we can find the end of the gzip header. It's
+ * possible that the memory block we malloc here will never be freed if
+ * the transfer abruptly aborts after this point. Since it's unlikely
+ * that circumstances will be right for this code path to be followed in
+ * the first place, and it's even more unlikely for a transfer to fail
+ * immediately afterwards, it should seldom be a problem.
+ */
+ z->avail_in = (uInt)nread;
+ z->next_in = malloc(z->avail_in);
+ if (z->next_in == NULL) {
+ return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY);
+ }
+ memcpy(z->next_in, k->str, z->avail_in);
+ k->zlib_init = 2; /* Need more gzip header data state */
+ /* We don't have any data to inflate yet */
+ return CURLE_OK;
+
+ case GZIP_BAD:
+ default:
+ return exit_zlib(z, &k->zlib_init, process_zlib_error(data, z));
+ }
+
+ }
+ else if (k->zlib_init == 2) {
+ /* Need more gzip header data state */
+ ssize_t hlen;
+ unsigned char *oldblock = z->next_in;
+
+ z->avail_in += nread;
+ z->next_in = realloc(z->next_in, z->avail_in);
+ if (z->next_in == NULL) {
+ free(oldblock);
+ return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY);
+ }
+ /* Append the new block of data to the previous one */
+ memcpy(z->next_in + z->avail_in - nread, k->str, nread);
+
+ switch (check_gzip_header(z->next_in, z->avail_in, &hlen)) {
+ case GZIP_OK:
+ /* This is the zlib stream data */
+ free(z->next_in);
+ /* Don't point into the malloced block since we just freed it */
+ z->next_in = (Bytef *)k->str + hlen + nread - z->avail_in;
+ z->avail_in = (uInt)(z->avail_in - hlen);
+ k->zlib_init = 3; /* Inflating stream state */
+ break;
+
+ case GZIP_UNDERFLOW:
+ /* We still don't have any data to inflate! */
+ return CURLE_OK;
+
+ case GZIP_BAD:
+ default:
+ free(z->next_in);
+ return exit_zlib(z, &k->zlib_init, process_zlib_error(data, z));
+ }
+
+ }
+ else {
+ /* Inflating stream state */
+ z->next_in = (Bytef *)k->str;
+ z->avail_in = (uInt)nread;
+ }
+
+ if (z->avail_in == 0) {
+ /* We don't have any data to inflate; wait until next time */
+ return CURLE_OK;
+ }
+
+ /* because the buffer size is fixed, iteratively decompress and transfer to
+ the client via client_write. */
+ for (;;) {
+ /* (re)set buffer for decompressed output for every iteration */
+ z->next_out = (Bytef *)&decomp[0];
+ z->avail_out = DSIZ;
+
+ status = inflate(z, Z_SYNC_FLUSH);
+ if (status == Z_OK || status == Z_STREAM_END) {
+ if(DSIZ - z->avail_out) {
+ result = Curl_client_write(data, CLIENTWRITE_BODY, decomp,
+ DSIZ - z->avail_out);
+ /* if !CURLE_OK, clean up, return */
+ if (result)
+ return exit_zlib(z, &k->zlib_init, result);
+ }
+
+ /* Done?; clean up, return */
+ /* We should really check the gzip CRC here */
+ if (status == Z_STREAM_END) {
+ if (inflateEnd(z) == Z_OK)
+ return exit_zlib(z, &k->zlib_init, result);
+ else
+ return exit_zlib(z, &k->zlib_init, process_zlib_error(data, z));
+ }
+
+ /* Done with these bytes, exit */
+ if (status == Z_OK && z->avail_in == 0 && z->avail_out > 0)
+ return result;
+ }
+ else { /* Error; exit loop, handle below */
+ return exit_zlib(z, &k->zlib_init, process_zlib_error(data, z));
+ }
+ }
+}
+#endif /* HAVE_LIBZ */
diff --git a/Source/CTest/Curl/content_encoding.h b/Source/CTest/Curl/content_encoding.h
index 2e7676b..a65dbd2 100644
--- a/Source/CTest/Curl/content_encoding.h
+++ b/Source/CTest/Curl/content_encoding.h
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -20,15 +20,22 @@
*
* $Id$
***************************************************************************/
+#include "setup.h"
+
+/*
+ * Comma-separated list all supported Content-Encodings ('identity' is implied)
+ */
+#ifdef HAVE_LIBZ
+#define ALL_CONTENT_ENCODINGS "deflate, gzip"
+#else
+#define ALL_CONTENT_ENCODINGS "identity"
+#endif
CURLcode Curl_unencode_deflate_write(struct SessionHandle *data,
struct Curl_transfer_keeper *k,
ssize_t nread);
-
-/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
- */
+
+CURLcode
+Curl_unencode_gzip_write(struct SessionHandle *data,
+ struct Curl_transfer_keeper *k,
+ ssize_t nread);
diff --git a/Source/CTest/Curl/cookie.c b/Source/CTest/Curl/cookie.c
index 4a2b83e..5037314 100644
--- a/Source/CTest/Curl/cookie.c
+++ b/Source/CTest/Curl/cookie.c
@@ -1,16 +1,16 @@
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -28,7 +28,7 @@ RECEIVING COOKIE INFORMATION
============================
struct CookieInfo *cookie_init(char *file);
-
+
Inits a cookie struct to store data in a local file. This is always
called before any cookies are set.
@@ -58,9 +58,9 @@ struct Cookies *cookie_getlist(struct CookieInfo *cookie,
It shall only return cookies that haven't expired.
-
+
Example set of cookies:
-
+
Set-cookie: PRODUCTINFO=webxpress; domain=.fidelity.com; path=/; secure
Set-cookie: PERSONALIZE=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
domain=.fidelity.com; path=/ftgw; secure
@@ -77,6 +77,7 @@ Example set of cookies:
13-Jun-1988 03:04:55 GMT; domain=.fidelity.com; path=/; secure
****/
+
#include "setup.h"
#ifndef CURL_DISABLE_HTTP
@@ -85,19 +86,23 @@ Example set of cookies:
#include <string.h>
#include <ctype.h>
+#include "urldata.h"
#include "cookie.h"
#include "getdate.h"
#include "strequal.h"
#include "strtok.h"
+#include "sendf.h"
+#include "memory.h"
/* The last #include file should be: */
-#ifdef MALLOCDEBUG
+#ifdef CURLDEBUG
#include "memdebug.h"
#endif
-static void
-free_cookiemess(struct Cookie *co)
+static void freecookie(struct Cookie *co)
{
+ if(co->expirestr)
+ free(co->expirestr);
if(co->domain)
free(co->domain);
if(co->path)
@@ -110,6 +115,17 @@ free_cookiemess(struct Cookie *co)
free(co);
}
+static bool tailmatch(const char *little, const char *bigone)
+{
+ size_t littlelen = strlen(little);
+ size_t biglen = strlen(bigone);
+
+ if(littlelen > biglen)
+ return FALSE;
+
+ return (bool)strequal(little, bigone+biglen-littlelen);
+}
+
/****************************************************************************
*
* Curl_cookie_add()
@@ -119,13 +135,21 @@ free_cookiemess(struct Cookie *co)
***************************************************************************/
struct Cookie *
-Curl_cookie_add(struct CookieInfo *c,
+Curl_cookie_add(struct SessionHandle *data,
+ /* The 'data' pointer here may be NULL at times, and thus
+ must only be used very carefully for things that can deal
+ with data being NULL. Such as infof() and similar */
+
+ struct CookieInfo *c,
bool httpheader, /* TRUE if HTTP header-style line */
char *lineptr, /* first character of the line */
- char *domain) /* default domain */
+ char *domain, /* default domain */
+ char *path) /* full path used when this cookie is set,
+ used to get default path for the cookie
+ unless set */
{
struct Cookie *clist;
- char what[MAX_COOKIE_LINE];
+ char *what;
char name[MAX_NAME];
char *ptr;
char *semiptr;
@@ -133,18 +157,23 @@ Curl_cookie_add(struct CookieInfo *c,
struct Cookie *lastc=NULL;
time_t now = time(NULL);
bool replace_old = FALSE;
+ bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */
/* First, alloc and init a new struct for it */
- co = (struct Cookie *)malloc(sizeof(struct Cookie));
+ co = (struct Cookie *)calloc(sizeof(struct Cookie), 1);
if(!co)
return NULL; /* bail out if we're this low on memory */
- /* clear the whole struct first */
- memset(co, 0, sizeof(struct Cookie));
-
if(httpheader) {
/* This line was read off a HTTP-header */
char *sep;
+
+ what = malloc(MAX_COOKIE_LINE);
+ if(!what) {
+ free(co);
+ return NULL;
+ }
+
semiptr=strchr(lineptr, ';'); /* first, find a semicolon */
while(*lineptr && isspace((int)*lineptr))
@@ -183,13 +212,82 @@ Curl_cookie_add(struct CookieInfo *c,
if(strequal("path", name)) {
co->path=strdup(whatptr);
+ if(!co->path) {
+ badcookie = TRUE; /* out of memory bad */
+ break;
+ }
}
else if(strequal("domain", name)) {
- co->domain=strdup(whatptr);
- co->field1= (char)((whatptr[0]=='.')?2:1);
+ /* note that this name may or may not have a preceeding dot, but
+ we don't care about that, we treat the names the same anyway */
+
+ const char *domptr=whatptr;
+ int dotcount=1;
+
+ /* Count the dots, we need to make sure that there are enough
+ of them. */
+
+ if('.' == whatptr[0])
+ /* don't count the initial dot, assume it */
+ domptr++;
+
+ do {
+ domptr = strchr(domptr, '.');
+ if(domptr) {
+ domptr++;
+ dotcount++;
+ }
+ } while(domptr);
+
+ /* The original Netscape cookie spec defined that this domain name
+ MUST have three dots (or two if one of the seven holy TLDs),
+ but it seems that these kinds of cookies are in use "out there"
+ so we cannot be that strict. I've therefore lowered the check
+ to not allow less than two dots. */
+
+ if(dotcount < 2) {
+ /* Received and skipped a cookie with a domain using too few
+ dots. */
+ badcookie=TRUE; /* mark this as a bad cookie */
+ infof(data, "skipped cookie with illegal dotcount domain: %s\n",
+ whatptr);
+ }
+ else {
+ /* Now, we make sure that our host is within the given domain,
+ or the given domain is not valid and thus cannot be set. */
+
+ if('.' == whatptr[0])
+ whatptr++; /* ignore preceeding dot */
+
+ if(!domain || tailmatch(whatptr, domain)) {
+ const char *tailptr=whatptr;
+ if(tailptr[0] == '.')
+ tailptr++;
+ co->domain=strdup(tailptr); /* don't prefix w/dots
+ internally */
+ if(!co->domain) {
+ badcookie = TRUE;
+ break;
+ }
+ co->tailmatch=TRUE; /* we always do that if the domain name was
+ given */
+ }
+ else {
+ /* we did not get a tailmatch and then the attempted set domain
+ is not a domain to which the current host belongs. Mark as
+ bad. */
+ badcookie=TRUE;
+ infof(data, "skipped cookie with bad tailmatch domain: %s\n",
+ whatptr);
+ }
+ }
}
else if(strequal("version", name)) {
co->version=strdup(whatptr);
+ if(!co->version) {
+ badcookie = TRUE;
+ break;
+ }
}
else if(strequal("max-age", name)) {
/* Defined in RFC2109:
@@ -202,16 +300,28 @@ Curl_cookie_add(struct CookieInfo *c,
*/
co->maxage = strdup(whatptr);
+ if(!co->maxage) {
+ badcookie = TRUE;
+ break;
+ }
co->expires =
- atoi((*co->maxage=='\"')?&co->maxage[1]:&co->maxage[0]) + (long)now;
+ atoi((*co->maxage=='\"')?&co->maxage[1]:&co->maxage[0]) + now;
}
else if(strequal("expires", name)) {
co->expirestr=strdup(whatptr);
- co->expires = (long)curl_getdate(what, &now);
+ if(!co->expirestr) {
+ badcookie = TRUE;
+ break;
+ }
+ co->expires = curl_getdate(what, &now);
}
else if(!co->name) {
co->name = strdup(name);
co->value = strdup(whatptr);
+ if(!co->name || !co->value) {
+ badcookie = TRUE;
+ break;
+ }
}
/*
else this is the second (or more) name we don't know
@@ -248,23 +358,39 @@ Curl_cookie_add(struct CookieInfo *c,
semiptr=strchr(ptr, '\0');
} while(semiptr);
- if(NULL == co->name) {
- /* we didn't get a cookie name, this is an illegal line, bail out */
- if(co->domain)
- free(co->domain);
- if(co->path)
- free(co->path);
- if(co->name)
- free(co->name);
- if(co->value)
- free(co->value);
- free(co);
+ if(!badcookie && !co->domain) {
+ if(domain) {
+ /* no domain was given in the header line, set the default */
+ co->domain=strdup(domain);
+ if(!co->domain)
+ badcookie = TRUE;
+ }
+ }
+
+ if(!badcookie && !co->path && path) {
+ /* no path was given in the header line, set the default */
+ char *endslash = strrchr(path, '/');
+ if(endslash) {
+ size_t pathlen = endslash-path+1; /* include the ending 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 */
+ }
+ else
+ badcookie = TRUE;
+ }
+ }
+
+ free(what);
+
+ if(badcookie || !co->name) {
+ /* we didn't get a cookie name or a bad one,
+ this is an illegal line, bail out */
+ freecookie(co);
return NULL;
}
- if(NULL == co->domain)
- /* no domain given in the header line, set the default now */
- co->domain=domain?strdup(domain):NULL;
}
else {
/* This line is NOT a HTTP header style line, we do offer support for
@@ -286,7 +412,7 @@ Curl_cookie_add(struct CookieInfo *c,
if(ptr)
*ptr=0; /* clear it */
- firstptr=strtok_r(lineptr, "\t", &tok_buf); /* first tokenize it on the TAB */
+ firstptr=strtok_r(lineptr, "\t", &tok_buf); /* tokenize it on the TAB */
/* Here's a quick check to eliminate normal HTTP-headers from this */
if(!firstptr || strchr(firstptr, ':')) {
@@ -296,10 +422,15 @@ Curl_cookie_add(struct CookieInfo *c,
/* Now loop through the fields and init the struct we already have
allocated */
- for(ptr=firstptr, fields=0; ptr; 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 preceeding dots */
+ ptr++;
co->domain = strdup(ptr);
+ if(!co->domain)
+ badcookie = TRUE;
break;
case 1:
/* This field got its explanation on the 23rd of May 2001 by
@@ -311,10 +442,8 @@ Curl_cookie_add(struct CookieInfo *c,
As far as I can see, it is set to true when the cookie says
.domain.com and to false when the domain is complete www.domain.com
-
- We don't currently take advantage of this knowledge.
*/
- co->field1=(char)(strequal(ptr, "TRUE")+1); /* store information */
+ co->tailmatch=(bool)strequal(ptr, "TRUE"); /* store information */
break;
case 2:
/* It turns out, that sometimes the file format allows the path
@@ -323,10 +452,14 @@ Curl_cookie_add(struct CookieInfo *c,
if (strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) {
/* only if the path doesn't look like a boolean option! */
co->path = strdup(ptr);
+ if(!co->path)
+ badcookie = TRUE;
break;
}
/* this doesn't look like a path, make one up! */
co->path = strdup("/");
+ if(!co->path)
+ badcookie = TRUE;
fields++; /* add a field and fall down to secure */
/* FALLTHROUGH */
case 3:
@@ -337,17 +470,31 @@ Curl_cookie_add(struct CookieInfo *c,
break;
case 5:
co->name = strdup(ptr);
+ if(!co->name)
+ badcookie = TRUE;
break;
case 6:
co->value = strdup(ptr);
+ if(!co->value)
+ badcookie = TRUE;
break;
}
}
+ if(6 == fields) {
+ /* we got a cookie with blank contents, fix it */
+ co->value = strdup("");
+ if(!co->value)
+ badcookie = TRUE;
+ else
+ fields++;
+ }
- if(7 != fields) {
- /* we did not find the sufficient number of fields to recognize this
- as a valid line, abort and go home */
- free_cookiemess(co);
+ if(!badcookie && (7 != fields))
+ /* we did not find the sufficient number of fields */
+ badcookie = TRUE;
+
+ if(badcookie) {
+ freecookie(co);
return NULL;
}
@@ -356,7 +503,7 @@ Curl_cookie_add(struct CookieInfo *c,
if(!c->running && /* read from a file */
c->newsession && /* clean session cookies */
!co->expires) { /* this is a session cookie since it doesn't expire! */
- free_cookiemess(co);
+ freecookie(co);
return NULL;
}
@@ -373,13 +520,8 @@ Curl_cookie_add(struct CookieInfo *c,
/* the names are identical */
if(clist->domain && co->domain) {
- if(strequal(clist->domain, co->domain) ||
- (clist->domain[0]=='.' &&
- strequal(&(clist->domain[1]), co->domain)) ||
- (co->domain[0]=='.' &&
- strequal(clist->domain, &(co->domain[1]))) )
- /* The domains are identical, or at least identical if you skip the
- preceeding dot */
+ if(strequal(clist->domain, co->domain))
+ /* The domains are identical */
replace_old=TRUE;
}
else if(!clist->domain && !co->domain)
@@ -399,7 +541,7 @@ Curl_cookie_add(struct CookieInfo *c,
replace_old = TRUE;
else
replace_old = FALSE;
-
+
}
if(replace_old && !co->livecookie && clist->livecookie) {
@@ -409,16 +551,7 @@ Curl_cookie_add(struct CookieInfo *c,
live cookies stay alive */
/* Free the newcomer and get out of here! */
- if(co->domain)
- free(co->domain);
- if(co->path)
- free(co->path);
- if(co->name)
- free(co->name);
- if(co->value)
- free(co->value);
-
- free(co);
+ freecookie(co);
return NULL;
}
@@ -460,6 +593,12 @@ Curl_cookie_add(struct CookieInfo *c,
clist = clist->next;
}
+ if(c->running)
+ /* Only show this when NOT reading the cookies from a file */
+ infof(data, "%s cookie %s=\"%s\" for domain %s, path %s, expire %d\n",
+ replace_old?"Replaced":"Added", co->name, co->value,
+ co->domain, co->path, co->expires);
+
if(!replace_old) {
/* then make the last item point on this new one */
if(lastc)
@@ -469,7 +608,6 @@ Curl_cookie_add(struct CookieInfo *c,
}
c->numcookies++; /* one more cookie in the jar */
-
return co;
}
@@ -483,21 +621,20 @@ Curl_cookie_add(struct CookieInfo *c,
* If 'newsession' is TRUE, discard all "session cookies" on read from file.
*
****************************************************************************/
-struct CookieInfo *Curl_cookie_init(char *file,
+struct CookieInfo *Curl_cookie_init(struct SessionHandle *data,
+ char *file,
struct CookieInfo *inc,
bool newsession)
{
- char line[MAX_COOKIE_LINE];
struct CookieInfo *c;
FILE *fp;
bool fromfile=TRUE;
-
+
if(NULL == inc) {
/* we didn't get a struct, create one */
- c = (struct CookieInfo *)malloc(sizeof(struct CookieInfo));
+ c = (struct CookieInfo *)calloc(1, sizeof(struct CookieInfo));
if(!c)
return NULL; /* failed to get memory */
- memset(c, 0, sizeof(struct CookieInfo));
c->filename = strdup(file?file:"none"); /* copy the name just in case */
}
else {
@@ -518,20 +655,25 @@ struct CookieInfo *Curl_cookie_init(char *file,
if(fp) {
char *lineptr;
bool headerline;
- while(fgets(line, MAX_COOKIE_LINE, fp)) {
- if(checkprefix("Set-Cookie:", line)) {
- /* This is a cookie line, get it! */
- lineptr=&line[11];
- headerline=TRUE;
- }
- else {
- lineptr=line;
- headerline=FALSE;
- }
- while(*lineptr && isspace((int)*lineptr))
- lineptr++;
- Curl_cookie_add(c, headerline, lineptr, NULL);
+ char *line = (char *)malloc(MAX_COOKIE_LINE);
+ if(line) {
+ while(fgets(line, MAX_COOKIE_LINE, fp)) {
+ if(checkprefix("Set-Cookie:", line)) {
+ /* This is a cookie line, get it! */
+ lineptr=&line[11];
+ headerline=TRUE;
+ }
+ else {
+ lineptr=line;
+ headerline=FALSE;
+ }
+ while(*lineptr && isspace((int)*lineptr))
+ lineptr++;
+
+ Curl_cookie_add(data, c, headerline, lineptr, NULL, NULL);
+ }
+ free(line); /* free the line buffer */
}
if(fromfile)
fclose(fp);
@@ -560,9 +702,6 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
struct Cookie *newco;
struct Cookie *co;
time_t now = time(NULL);
- int hostlen=(int)strlen(host);
- int domlen;
-
struct Cookie *mainco=NULL;
if(!c || !c->cookies)
@@ -571,43 +710,52 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
co = c->cookies;
while(co) {
- /* only process this cookie if it is not expired or had no expire
- date AND that if the cookie requires we're secure we must only
- continue if we are! */
+ /* only process this cookie if it is not expired or had no expire
+ date AND that if the cookie requires we're secure we must only
+ continue if we are! */
if( (co->expires<=0 || (co->expires> now)) &&
(co->secure?secure:TRUE) ) {
- /* now check if the domain is correct */
- domlen=co->domain?(int)strlen(co->domain):0;
- if(!co->domain ||
- ((domlen<=hostlen) &&
- strequal(host+(hostlen-domlen), co->domain)) ) {
- /* the right part of the host matches the domain stuff in the
- cookie data */
-
- /* now check the left part of the path with the cookies path
- requirement */
- if(!co->path ||
- checkprefix(co->path, path) ) {
-
- /* and now, we know this is a match and we should create an
- entry for the return-linked-list */
-
- newco = (struct Cookie *)malloc(sizeof(struct Cookie));
- if(newco) {
- /* first, copy the whole source cookie: */
- memcpy(newco, co, sizeof(struct Cookie));
-
- /* then modify our next */
- newco->next = mainco;
-
- /* point the main to us */
- mainco = newco;
- }
- }
+ /* now check if the domain is correct */
+ if(!co->domain ||
+ (co->tailmatch && tailmatch(co->domain, host)) ||
+ (!co->tailmatch && strequal(host, co->domain)) ) {
+ /* the right part of the host matches the domain stuff in the
+ cookie data */
+
+ /* now check the left part of the path with the cookies path
+ requirement */
+ if(!co->path ||
+ checkprefix(co->path, path) ) {
+
+ /* and now, we know this is a match and we should create an
+ entry for the return-linked-list */
+
+ newco = (struct Cookie *)malloc(sizeof(struct Cookie));
+ if(newco) {
+ /* first, copy the whole source cookie: */
+ memcpy(newco, co, sizeof(struct Cookie));
+
+ /* then modify our next */
+ newco->next = mainco;
+
+ /* point the main to us */
+ mainco = newco;
+ }
+ else {
+ /* failure, clear up the allocated chain and return NULL */
+ while(mainco) {
+ co = mainco->next;
+ free(mainco);
+ mainco = co;
+ }
+
+ return NULL;
+ }
}
- }
- co = co->next;
+ }
+ }
+ co = co->next;
}
return mainco; /* return the new list */
@@ -652,24 +800,8 @@ void Curl_cookie_cleanup(struct CookieInfo *c)
co = c->cookies;
while(co) {
- if(co->name)
- free(co->name);
- if(co->value)
- free(co->value);
- if(co->domain)
- free(co->domain);
- if(co->path)
- free(co->path);
- if(co->expirestr)
- free(co->expirestr);
-
- if(co->version)
- free(co->version);
- if(co->maxage)
- free(co->maxage);
-
next = co->next;
- free(co);
+ freecookie(co);
co = next;
}
free(c); /* free the base struct as well */
@@ -712,18 +844,22 @@ int Curl_cookie_output(struct CookieInfo *c, char *dumphere)
"# This file was generated by libcurl! Edit at your own risk.\n\n",
out);
co = c->cookies;
-
+
while(co) {
fprintf(out,
- "%s\t" /* domain */
- "%s\t" /* field1 */
+ "%s%s\t" /* domain */
+ "%s\t" /* tailmatch */
"%s\t" /* path */
"%s\t" /* secure */
"%u\t" /* expires */
"%s\t" /* name */
"%s\n", /* value */
+
+ /* Make sure all domains are prefixed with a dot if they allow
+ tailmatching. This is Mozilla-style. */
+ (co->tailmatch && co->domain && co->domain[0] != '.')? ".":"",
co->domain?co->domain:"unknown",
- co->field1==2?"TRUE":"FALSE",
+ co->tailmatch?"TRUE":"FALSE",
co->path?co->path:"/",
co->secure?"TRUE":"FALSE",
(unsigned int)co->expires,
@@ -740,39 +876,4 @@ int Curl_cookie_output(struct CookieInfo *c, char *dumphere)
return 0;
}
-#ifdef CURL_COOKIE_DEBUG
-
-/*
- * On my Solaris box, this command line builds this test program:
- *
- * gcc -g -o cooktest -DCURL_COOKIE_DEBUG -DHAVE_CONFIG_H -I.. -I../include cookie.c strequal.o getdate.o memdebug.o mprintf.o strtok.o -lnsl -lsocket
- *
- */
-
-int main(int argc, char **argv)
-{
- struct CookieInfo *c=NULL;
- if(argc>1) {
- c = Curl_cookie_init(argv[1], c);
- Curl_cookie_add(c, TRUE, "PERSONALIZE=none;expires=Monday, 13-Jun-1988 03:04:55 GMT; domain=.fidelity.com; path=/ftgw; secure");
- Curl_cookie_add(c, TRUE, "foobar=yes; domain=.haxx.se; path=/looser;");
- c = Curl_cookie_init(argv[1], c);
-
- Curl_cookie_output(c);
- Curl_cookie_cleanup(c);
- return 0;
- }
- return 1;
-}
-
-#endif
-
#endif /* CURL_DISABLE_HTTP */
-
-/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
- */
diff --git a/Source/CTest/Curl/cookie.h b/Source/CTest/Curl/cookie.h
index 77ac059..6f8e8e5 100644
--- a/Source/CTest/Curl/cookie.h
+++ b/Source/CTest/Curl/cookie.h
@@ -1,18 +1,18 @@
#ifndef __COOKIE_H
#define __COOKIE_H
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -40,13 +40,12 @@ struct Cookie {
char *domain; /* domain = <this> */
long expires; /* expires = <this> */
char *expirestr; /* the plain text version */
+ bool tailmatch; /* weather we do tail-matchning of the domain name */
- char field1; /* read from a cookie file, 1 => FALSE, 2=> TRUE */
-
/* RFC 2109 keywords. Version=1 means 2109-compliant cookie sending */
char *version; /* Version = <value> */
char *maxage; /* Max-Age = <value> */
-
+
bool secure; /* whether the 'secure' keyword was used */
bool livecookie; /* updated from a server, not a stored file */
};
@@ -61,22 +60,33 @@ struct CookieInfo {
bool newsession; /* new session, discard session cookies on load */
};
-/* This is the maximum line length we accept for a cookie line */
-#define MAX_COOKIE_LINE 2048
-#define MAX_COOKIE_LINE_TXT "2047"
+/* This is the maximum line length we accept for a cookie line. RFC 2109
+ section 6.3 says:
+
+ "at least 4096 bytes per cookie (as measured by the size of the characters
+ that comprise the cookie non-terminal in the syntax description of the
+ Set-Cookie header)"
+
+*/
+#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 256
-#define MAX_NAME_TXT "255"
+#define MAX_NAME 1024
+#define MAX_NAME_TXT "1023"
+struct SessionHandle;
/*
- * Add a cookie to the internal list of cookies. The domain argument is only
- * used if the header boolean is TRUE.
+ * Add a cookie to the internal list of cookies. The domain and path arguments
+ * are only used if the header boolean is TRUE.
*/
-struct Cookie *Curl_cookie_add(struct CookieInfo *, bool header, char *line,
- char *domain);
-struct CookieInfo *Curl_cookie_init(char *, struct CookieInfo *, bool);
+struct Cookie *Curl_cookie_add(struct SessionHandle *data,
+ struct CookieInfo *, bool header, char *line,
+ char *domain, char *path);
+
+struct CookieInfo *Curl_cookie_init(struct SessionHandle *data,
+ char *, struct CookieInfo *, bool);
struct Cookie *Curl_cookie_getlist(struct CookieInfo *, char *, char *, bool);
void Curl_cookie_freelist(struct Cookie *);
void Curl_cookie_cleanup(struct CookieInfo *);
diff --git a/Source/CTest/Curl/curl.copyright b/Source/CTest/Curl/curl.copyright
index a2ed2ef..16ea773 100644
--- a/Source/CTest/Curl/curl.copyright
+++ b/Source/CTest/Curl/curl.copyright
@@ -2,28 +2,24 @@ This package was cmakified by Andy Cedilnik <andy . cedilnik @ kitware.com>
It was downloaded from http://curl.haxx.se
-Upstream Authors: Daniel Stenberg <daniel@haxx.se>
+COPYRIGHT AND PERMISSION NOTICE
-Copyright:
+Copyright (c) 1996 - 2004, Daniel Stenberg, <daniel@haxx.se>.
- COPYRIGHT AND PERMISSION NOTICE
+All rights reserved.
- Copyright (c) 1996 - 2002, Daniel Stenberg, <daniel@haxx.se>.
+Permission to use, copy, modify, and distribute this software for any purpose
+with or without fee is hereby granted, provided that the above copyright
+notice and this permission notice appear in all copies.
- All rights reserved.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN
+NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
- Permission to use, copy, modify, and distribute this software for any purpose
- with or without fee is hereby granted, provided that the above copyright
- notice and this permission notice appear in all copies.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN
- NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
- DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
- OR OTHER DEALINGS IN THE SOFTWARE.
-
- Except as contained in this notice, the name of a copyright holder shall not
- be used in advertising or otherwise to promote the sale, use or other dealings
- in this Software without prior written authorization of the copyright holder.
+Except as contained in this notice, the name of a copyright holder shall not
+be used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization of the copyright holder.
diff --git a/Source/CTest/Curl/curl/curl.h b/Source/CTest/Curl/curl/curl.h
index 689b585..96c8fcc 100644
--- a/Source/CTest/Curl/curl/curl.h
+++ b/Source/CTest/Curl/curl/curl.h
@@ -1,18 +1,18 @@
#ifndef __CURL_CURL_H
#define __CURL_CURL_H
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -23,71 +23,109 @@
* $Id$
***************************************************************************/
+/* If you have problems, all libcurl docs and details are found here:
+ http://curl.haxx.se/libcurl/
+*/
+
+#include "curlver.h" /* the libcurl version defines */
+
#include <stdio.h>
-/* The include stuff here is mainly for time_t! */
+#include <limits.h>
+
+/* The include stuff here below is mainly for time_t! */
#ifdef vms
# include <types.h>
# include <time.h>
#else
# include <sys/types.h>
-# ifdef TIME_WITH_SYS_TIME
-# include <sys/time.h>
-# include <time.h>
-# else
-# ifdef HAVE_SYS_TIME_H
-# include <sys/time.h>
-# else
-# include <time.h>
-# endif
-# endif
+# include <time.h>
#endif /* defined (vms) */
-#ifndef TRUE
-#define TRUE 1
-#endif
-#ifndef FALSE
-#define FALSE 0
-#endif
-
-#include "types.h"
+typedef void CURL;
#ifdef __cplusplus
extern "C" {
#endif
-/* stupid #define trick to preserve functionality with older code, but
- making it use our name space for the future */
-#define HttpPost curl_httppost
+/*
+ * We want the typedef curl_off_t setup for large file support on all
+ * platforms. We also provide a CURL_FORMAT_OFF_T define to use in *printf
+ * format strings when outputting a variable of type curl_off_t.
+ */
+#if defined(_MSC_VER) || defined(__LCC__)
+/* MSVC */
+ typedef signed __int64 curl_off_t;
+#define CURL_FORMAT_OFF_T "%I64d"
+#else /* _MSC_VER || __LCC__ */
+#if (defined(__GNUC__) && defined(WIN32)) || defined(__WATCOMC__)
+/* gcc on windows or Watcom */
+ typedef long long curl_off_t;
+#define CURL_FORMAT_OFF_T "%I64d"
+#else /* GCC or Watcom on Windows */
+
+/* "normal" POSIX approach, do note that this does not necessarily mean that
+ the type is >32 bits, see the SIZEOF_CURL_OFF_T define for that! */
+ typedef off_t curl_off_t;
+
+/* Check a range of defines to detect large file support. On Linux it seems
+ none of these are set by default, so if you don't explicitly switches on
+ large file support, this define will be made for "small file" support. */
+#ifndef _FILE_OFFSET_BITS
+#define _FILE_OFFSET_BITS 0 /* to prevent warnings in the check below */
+#define UNDEF_FILE_OFFSET_BITS
+#endif
+#ifndef FILESIZEBITS
+#define FILESIZEBITS 0 /* to prevent warnings in the check below */
+#define UNDEF_FILESIZEBITS
+#endif
-struct curl_httppost {
- struct curl_httppost *next; /* next entry in the list */
- char *name; /* pointer to allocated name */
- long namelength; /* length of name length */
- char *contents; /* pointer to allocated data contents */
- long contentslength; /* length of contents field */
+#if defined(_LARGE_FILES) || (_FILE_OFFSET_BITS > 32) || (FILESIZEBITS > 32) \
+ || defined(_LARGEFILE_SOURCE) || defined(_LARGEFILE64_SOURCE)
+ /* For now, we assume at least one of these to be set for large files to
+ work! */
+#define CURL_FORMAT_OFF_T "%lld"
+#else /* LARGE_FILE support */
+#define CURL_FORMAT_OFF_T "%ld"
+#endif
+#endif /* GCC or Watcom on Windows */
+#endif /* _MSC_VER || __LCC__ */
+
+#ifdef UNDEF_FILE_OFFSET_BITS
+/* this was defined above for our checks, undefine it again */
+#undef _FILE_OFFSET_BITS
+#endif
- /* CMC: Added support for buffer uploads */
- char *buffer; /* pointer to allocated buffer contents */
- long bufferlength; /* length of buffer field */
+#ifdef UNDEF_FILESIZEBITS
+/* this was defined above for our checks, undefine it again */
+#undef FILESIZEBITS
+#endif
- char *contenttype; /* Content-Type */
+struct curl_httppost {
+ struct curl_httppost *next; /* next entry in the list */
+ char *name; /* pointer to allocated name */
+ long namelength; /* length of name length */
+ char *contents; /* pointer to allocated data contents */
+ long contentslength; /* length of contents field */
+ char *buffer; /* pointer to allocated buffer contents */
+ long bufferlength; /* length of buffer field */
+ char *contenttype; /* Content-Type */
struct curl_slist* contentheader; /* list of extra headers for this form */
- struct curl_httppost *more; /* if one field name has more than one file, this
- link should link to following files */
- long flags; /* as defined below */
-#define HTTPPOST_FILENAME (1<<0) /* specified content is a file name */
-#define HTTPPOST_READFILE (1<<1) /* specified content is a file name */
-#define HTTPPOST_PTRNAME (1<<2) /* name is only stored pointer
- do not free in formfree */
+ struct curl_httppost *more; /* if one field name has more than one
+ file, this link should link to following
+ files */
+ long flags; /* as defined below */
+#define HTTPPOST_FILENAME (1<<0) /* specified content is a file name */
+#define HTTPPOST_READFILE (1<<1) /* specified content is a file name */
+#define HTTPPOST_PTRNAME (1<<2) /* name is only stored pointer
+ do not free in formfree */
#define HTTPPOST_PTRCONTENTS (1<<3) /* contents is only stored pointer
do not free in formfree */
+#define HTTPPOST_BUFFER (1<<4) /* upload file from buffer */
+#define HTTPPOST_PTRBUFFER (1<<5) /* upload file from pointer contents */
-/* CMC: Added support for buffer uploads */
-#define HTTPPOST_BUFFER (1<<4) /* upload file from buffer */
-#define HTTPPOST_PTRBUFFER (1<<5) /* upload file from pointer contents */
-
- char *showfilename; /* The file name to show. If not set, the actual
- file name will be used (if this is a file part) */
+ char *showfilename; /* The file name to show. If not set, the
+ actual file name will be used (if this
+ is a file part) */
};
typedef int (*curl_progress_callback)(void *clientp,
@@ -105,16 +143,32 @@ typedef size_t (*curl_write_callback)(char *buffer,
size_t nitems,
void *outstream);
+/* This is a brand new return code for the read callback that will signal
+ the caller to immediately abort the current transfer. */
+#define CURL_READFUNC_ABORT 0x10000000
typedef size_t (*curl_read_callback)(char *buffer,
size_t size,
size_t nitems,
void *instream);
+ /* not used since 7.10.8, will be removed in a future release */
typedef int (*curl_passwd_callback)(void *clientp,
const char *prompt,
char *buffer,
int buflen);
+/*
+ * The following typedef's are signatures of malloc, free, realloc, strdup and
+ * calloc respectively. Function pointers of these types can be passed to the
+ * curl_global_init_mem() function to set user defined memory management
+ * callback routines.
+ */
+typedef void *(*curl_malloc_callback)(size_t size);
+typedef void (*curl_free_callback)(void *ptr);
+typedef void *(*curl_realloc_callback)(void *ptr, size_t size);
+typedef char *(*curl_strdup_callback)(const char *str);
+typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size);
+
/* the kind of data that is passed to information_callback*/
typedef enum {
CURLINFO_TEXT = 0,
@@ -122,6 +176,8 @@ typedef enum {
CURLINFO_HEADER_OUT, /* 2 */
CURLINFO_DATA_IN, /* 3 */
CURLINFO_DATA_OUT, /* 4 */
+ CURLINFO_SSL_DATA_IN, /* 5 */
+ CURLINFO_SSL_DATA_OUT, /* 6 */
CURLINFO_END
} curl_infotype;
@@ -130,8 +186,8 @@ typedef int (*curl_debug_callback)
curl_infotype type, /* what kind of data */
char *data, /* points to the data */
size_t size, /* size of the data pointed to */
- void *userp); /* whatever the user please */
-
+ void *userptr); /* whatever the user please */
+
/* All possible error codes from all sorts of curl functions. Future versions
may return other values, stay prepared.
@@ -144,7 +200,7 @@ typedef enum {
CURLE_UNSUPPORTED_PROTOCOL, /* 1 */
CURLE_FAILED_INIT, /* 2 */
CURLE_URL_MALFORMAT, /* 3 */
- CURLE_URL_MALFORMAT_USER, /* 4 */
+ CURLE_URL_MALFORMAT_USER, /* 4 (NOT USED) */
CURLE_COULDNT_RESOLVE_PROXY, /* 5 */
CURLE_COULDNT_RESOLVE_HOST, /* 6 */
CURLE_COULDNT_CONNECT, /* 7 */
@@ -164,7 +220,7 @@ typedef enum {
CURLE_FTP_QUOTE_ERROR, /* 21 */
CURLE_HTTP_RETURNED_ERROR, /* 22 */
CURLE_WRITE_ERROR, /* 23 */
- CURLE_MALFORMAT_USER, /* 24 - user name is illegally specified */
+ CURLE_MALFORMAT_USER, /* 24 - NOT USED */
CURLE_FTP_COULDNT_STOR_FILE, /* 25 - failed FTP upload */
CURLE_READ_ERROR, /* 26 - could open/read from file */
CURLE_OUT_OF_MEMORY, /* 27 */
@@ -184,13 +240,13 @@ typedef enum {
CURLE_FUNCTION_NOT_FOUND, /* 41 */
CURLE_ABORTED_BY_CALLBACK, /* 42 */
CURLE_BAD_FUNCTION_ARGUMENT, /* 43 */
- CURLE_BAD_CALLING_ORDER, /* 44 */
- CURLE_HTTP_PORT_FAILED, /* 45 - HTTP Interface operation failed */
- CURLE_BAD_PASSWORD_ENTERED, /* 46 - my_getpass() returns fail */
+ CURLE_BAD_CALLING_ORDER, /* 44 - NOT USED */
+ CURLE_INTERFACE_FAILED, /* 45 - CURLOPT_INTERFACE failed */
+ CURLE_BAD_PASSWORD_ENTERED, /* 46 - NOT USED */
CURLE_TOO_MANY_REDIRECTS , /* 47 - catch endless re-direct loops */
CURLE_UNKNOWN_TELNET_OPTION, /* 48 - User specified an unknown option */
CURLE_TELNET_OPTION_SYNTAX , /* 49 - Malformed telnet option */
- CURLE_OBSOLETE, /* 50 - removed after 7.7.3 */
+ CURLE_OBSOLETE, /* 50 - NOT USED */
CURLE_SSL_PEER_CERTIFICATE, /* 51 - peer's certificate wasn't ok */
CURLE_GOT_NOTHING, /* 52 - when this is a specific error */
CURLE_SSL_ENGINE_NOTFOUND, /* 53 - SSL crypto engine not found */
@@ -203,13 +259,24 @@ typedef enum {
CURLE_SSL_CIPHER, /* 59 - couldn't use specified cipher */
CURLE_SSL_CACERT, /* 60 - problem with the CA cert (path?) */
CURLE_BAD_CONTENT_ENCODING, /* 61 - Unrecognized transfer encoding */
+ CURLE_LDAP_INVALID_URL, /* 62 - Invalid LDAP URL */
+ CURLE_FILESIZE_EXCEEDED, /* 63 - Maximum file size exceeded */
+ CURLE_FTP_SSL_FAILED, /* 64 - Requested FTP SSL level failed */
CURL_LAST /* never use! */
} CURLcode;
+typedef CURLcode (*curl_ssl_ctx_callback)(CURL *curl, /* easy handle */
+ void *ssl_ctx, /* actually an
+ OpenSSL SSL_CTX */
+ void *userptr);
+
/* Make a spelling correction for the operation timed-out define */
#define CURLE_OPERATION_TIMEDOUT CURLE_OPERATION_TIMEOUTED
+
+/* backwards compatibility with older names */
#define CURLE_HTTP_NOT_FOUND CURLE_HTTP_RETURNED_ERROR
+#define CURLE_HTTP_PORT_FAILED CURLE_INTERFACE_FAILED
typedef enum {
CURLPROXY_HTTP = 0,
@@ -217,6 +284,14 @@ typedef enum {
CURLPROXY_SOCKS5 = 5
} curl_proxytype;
+#define CURLAUTH_NONE 0 /* nothing */
+#define CURLAUTH_BASIC (1<<0) /* Basic (default) */
+#define CURLAUTH_DIGEST (1<<1) /* Digest */
+#define CURLAUTH_GSSNEGOTIATE (1<<2) /* GSS-Negotiate */
+#define CURLAUTH_NTLM (1<<3) /* NTLM */
+#define CURLAUTH_ANY ~0 /* all types set */
+#define CURLAUTH_ANYSAFE (~CURLAUTH_BASIC)
+
/* this was the error code 50 in 7.7.3 and a few earlier versions, this
is no longer used by libcurl but is instead #defined here only to not
make programs break */
@@ -228,11 +303,20 @@ typedef enum {
#define CURL_ERROR_SIZE 256
+typedef enum {
+ CURLFTPSSL_NONE, /* do not attempt to use SSL */
+ CURLFTPSSL_TRY, /* try using SSL, proceed anyway otherwise */
+ CURLFTPSSL_CONTROL, /* SSL for the control connection or fail */
+ CURLFTPSSL_ALL, /* SSL for all communication or fail */
+ CURLFTPSSL_LAST /* not an option, never use */
+} curl_ftpssl;
+
/* long may be 32 or 64 bits, but we should never depend on anything else
but 32 */
#define CURLOPTTYPE_LONG 0
#define CURLOPTTYPE_OBJECTPOINT 10000
#define CURLOPTTYPE_FUNCTIONPOINT 20000
+#define CURLOPTTYPE_OFF_T 30000
/* name is uppercase CURLOPT_<name>,
type is one of the defined CURLOPTTYPE_<type>
@@ -248,7 +332,7 @@ typedef enum {
* platforms.
*/
#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \
- defined(__HP_aCC) || defined(__BORLANDC__)
+ defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__)
/* This compiler is believed to have an ISO compatible preprocessor */
#define CURL_ISOCPP
#else
@@ -263,36 +347,36 @@ typedef enum {
#define LONG CURLOPTTYPE_LONG
#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT
#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT
+#define OFF_T CURLOPTTYPE_OFF_T
#define CINIT(name,type,number) CURLOPT_/**/name = type + number
#endif
+/*
+ * This macro-mania below setups the CURLOPT_[what] enum, to be used with
+ * curl_easy_setopt(). The first argument in the CINIT() macro is the [what]
+ * word.
+ */
+
typedef enum {
- CINIT(NOTHING, LONG, 0), /********* the first one is unused ************/
-
/* This is the FILE * or void * the regular output should be written to. */
CINIT(FILE, OBJECTPOINT, 1),
/* The full URL to get/put */
CINIT(URL, OBJECTPOINT, 2),
- /* Port number to connect to, if other than default. Specify the CONF_PORT
- flag in the CURLOPT_FLAGS to activate this */
+ /* Port number to connect to, if other than default. */
CINIT(PORT, LONG, 3),
- /* Name of proxy to use. Specify the CONF_PROXY flag in the CURLOPT_FLAGS to
- activate this */
+ /* Name of proxy to use. */
CINIT(PROXY, OBJECTPOINT, 4),
-
- /* Name and password to use when fetching. Specify the CONF_USERPWD flag in
- the CURLOPT_FLAGS to activate this */
+
+ /* "name:password" to use when fetching. */
CINIT(USERPWD, OBJECTPOINT, 5),
- /* Name and password to use with Proxy. Specify the CONF_PROXYUSERPWD
- flag in the CURLOPT_FLAGS to activate this */
+ /* "name:password" to use with proxy. */
CINIT(PROXYUSERPWD, OBJECTPOINT, 6),
- /* Range to get, specified as an ASCII string. Specify the CONF_RANGE flag
- in the CURLOPT_FLAGS to activate this */
+ /* Range to get, specified as an ASCII string. */
CINIT(RANGE, OBJECTPOINT, 7),
/* not used */
@@ -318,7 +402,12 @@ typedef enum {
/* If the CURLOPT_INFILE is used, this can be used to inform libcurl about
* how large the file being sent really is. That allows better error
* checking and better verifies that the upload was succcessful. -1 means
- * unknown size. */
+ * unknown size.
+ *
+ * For large file support, there is also a _LARGE version of the key
+ * which takes an off_t type, allowing platforms with larger off_t
+ * sizes to handle larger files. See below for INFILESIZE_LARGE.
+ */
CINIT(INFILESIZE, LONG, 14),
/* POST input fields. */
@@ -337,7 +426,7 @@ typedef enum {
/* If the download receives less than "low speed limit" bytes/second
* during "low speed time" seconds, the operations is aborted.
* You could i.e if you have a pretty high speed connection, abort if
- * it is less than 2000 bytes/sec during 20 seconds.
+ * it is less than 2000 bytes/sec during 20 seconds.
*/
/* Set the "low speed limit" */
@@ -346,7 +435,12 @@ typedef enum {
/* Set the "low speed time" */
CINIT(LOW_SPEED_TIME, LONG, 20),
- /* Set the continuation offset */
+ /* Set the continuation offset.
+ *
+ * Note there is also a _LARGE version of this key which uses
+ * off_t types, allowing for large file offsets on platforms which
+ * use larger-than-32-bit off_t's. Look below for RESUME_FROM_LARGE.
+ */
CINIT(RESUME_FROM, LONG, 21),
/* Set cookie in request: */
@@ -365,7 +459,7 @@ typedef enum {
CINIT(SSLCERTPASSWD, OBJECTPOINT, 26),
/* password for the SSL private key */
CINIT(SSLKEYPASSWD, OBJECTPOINT, 26),
-
+
/* send TYPE parameter? */
CINIT(CRLF, LONG, 27),
@@ -391,9 +485,7 @@ typedef enum {
since 1 Jan 1970 */
CINIT(TIMEVALUE, LONG, 34),
- /* HTTP request, for odd commands like DELETE, TRACE and others */
- /* OBSOLETE DEFINE, left for tradition only */
- CINIT(HTTPREQUEST, OBJECTPOINT, 35),
+ /* 35 = OBSOLETE */
/* Custom request, for customizing the get command like
HTTP: DELETE, TRACE and others
@@ -413,7 +505,6 @@ typedef enum {
as described elsewhere. */
CINIT(WRITEINFO, OBJECTPOINT, 40),
- /* Previous FLAG bits */
CINIT(VERBOSE, LONG, 41), /* talk a lot */
CINIT(HEADER, LONG, 42), /* throw the header out too */
CINIT(NOPROGRESS, LONG, 43), /* shut off the progress meter */
@@ -431,14 +522,10 @@ typedef enum {
CINIT(FOLLOWLOCATION, LONG, 52), /* use Location: Luke! */
- /* This FTPASCII name is now obsolete, to be removed, use the TRANSFERTEXT
- instead. It goes for more protocols than just ftp... */
- CINIT(FTPASCII, LONG, 53), /* use TYPE A for transfer */
-
CINIT(TRANSFERTEXT, LONG, 53), /* transfer data in text/ASCII format */
- CINIT(PUT, LONG, 54), /* PUT the input file */
+ CINIT(PUT, LONG, 54), /* HTTP PUT */
- CINIT(MUTE, LONG, 55), /* OBSOLETE OPTION, removed in 7.8 */
+ /* 55 = OBSOLETE */
/* Function that will be called instead of the internal progress display
* function. This function should be defined as the curl_progress_callback
@@ -471,24 +558,20 @@ typedef enum {
/* Set if we should verify the peer in ssl handshake, set 1 to verify. */
CINIT(SSL_VERIFYPEER, LONG, 64),
-
+
/* The CApath or CAfile used to validate the peer certificate
this option is used only if SSL_VERIFYPEER is true */
CINIT(CAINFO, OBJECTPOINT, 65),
- /* Function pointer to replace the internal password prompt */
- CINIT(PASSWDFUNCTION, FUNCTIONPOINT, 66),
+ /* 66 = OBSOLETE */
+ /* 67 = OBSOLETE */
- /* Custom pointer that gets passed as first argument to the password
- function */
- CINIT(PASSWDDATA, OBJECTPOINT, 67),
-
/* Maximum number of http redirects to follow */
CINIT(MAXREDIRS, LONG, 68),
- /* Pass a pointer to a time_t to get a possible date of the requested
- document! Pass a NULL to shut it off. */
- CINIT(FILETIME, OBJECTPOINT, 69),
+ /* Pass a long set to 1 to get the date of the requested document (if
+ possible)! Pass a zero to shut it off. */
+ CINIT(FILETIME, LONG, 69),
/* This points to a linked list of telnet options */
CINIT(TELNETOPTIONS, OBJECTPOINT, 70),
@@ -500,8 +583,7 @@ typedef enum {
up */
CINIT(CLOSEPOLICY, LONG, 72),
- /* Callback to use when CURLCLOSEPOLICY_CALLBACK is set */
- CINIT(CLOSEFUNCTION, FUNCTIONPOINT, 73),
+ /* 73 = OBSOLETE */
/* Set to explicitly use a new connection for the upcoming transfer.
Do not use this unless you're absolutely sure of this, as it makes the
@@ -552,7 +634,7 @@ typedef enum {
/* Specificly switch on or off the FTP engine's use of the EPSV command. By
default, that one will always be attempted before the more traditional
- PASV command. */
+ PASV command. */
CINIT(FTP_USE_EPSV, LONG, 85),
/* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") */
@@ -573,7 +655,7 @@ typedef enum {
CINIT(SSLENGINE_DEFAULT, LONG, 90),
/* Non-zero value means to use the global dns cache */
- CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91),
+ CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91), /* To become OBSOLETE soon */
/* DNS cache timeout */
CINIT(DNS_CACHE_TIMEOUT, LONG, 92),
@@ -601,7 +683,7 @@ typedef enum {
timeouts. This option is useful for multi-threaded applications.
See libcurl-the-guide for more background information. */
CINIT(NOSIGNAL, LONG, 99),
-
+
/* Provide a CURLShare for mutexing non-ts data */
CINIT(SHARE, OBJECTPOINT, 100),
@@ -612,21 +694,155 @@ typedef enum {
/* Set the Accept-Encoding string. Use this to tell a server you would like
the response to be compressed. */
CINIT(ENCODING, OBJECTPOINT, 102),
-
+
/* Set pointer to private data */
CINIT(PRIVATE, OBJECTPOINT, 103),
/* Set aliases for HTTP 200 in the HTTP Response header */
CINIT(HTTP200ALIASES, OBJECTPOINT, 104),
+ /* Continue to send authentication (user+password) when following locations,
+ even when hostname changed. This can potentionally send off the name
+ and password to whatever host the server decides. */
+ CINIT(UNRESTRICTED_AUTH, LONG, 105),
+
+ /* Specificly switch on or off the FTP engine's use of the EPRT command ( it
+ also disables the LPRT attempt). By default, those ones will always be
+ attempted before the good old traditional PORT command. */
+ CINIT(FTP_USE_EPRT, LONG, 106),
+
+ /* Set this to a bitmask value to enable the particular authentications
+ methods you like. Use this in combination with CURLOPT_USERPWD.
+ Note that setting multiple bits may cause extra network round-trips. */
+ CINIT(HTTPAUTH, LONG, 107),
+
+ /* Set the ssl context callback function, currently only for OpenSSL ssl_ctx
+ in second argument. The function must be matching the
+ curl_ssl_ctx_callback proto. */
+ CINIT(SSL_CTX_FUNCTION, FUNCTIONPOINT, 108),
+
+ /* Set the userdata for the ssl context callback function's third
+ argument */
+ CINIT(SSL_CTX_DATA, OBJECTPOINT, 109),
+
+ /* FTP Option that causes missing dirs to be created on the remote server */
+ CINIT(FTP_CREATE_MISSING_DIRS, LONG, 110),
+
+ /* Set this to a bitmask value to enable the particular authentications
+ methods you like. Use this in combination with CURLOPT_PROXYUSERPWD.
+ Note that setting multiple bits may cause extra network round-trips. */
+ CINIT(PROXYAUTH, LONG, 111),
+
+ /* FTP option that changes the timeout, in seconds, associated with
+ getting a response. This is different from transfer timeout time and
+ essentially places a demand on the FTP server to acknowledge commands
+ in a timely manner. */
+ CINIT(FTP_RESPONSE_TIMEOUT, LONG , 112),
+
+ /* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to
+ tell libcurl to resolve names to those IP versions only. This only has
+ affect on systems with support for more than one, i.e IPv4 _and_ IPv6. */
+ CINIT(IPRESOLVE, LONG, 113),
+
+ /* Set this option to limit the size of a file that will be downloaded from
+ an HTTP or FTP server.
+
+ Note there is also _LARGE version which adds large file support for
+ platforms which have larger off_t sizes. See MAXFILESIZE_LARGE below. */
+ CINIT(MAXFILESIZE, LONG, 114),
+
+ /* See the comment for INFILESIZE above, but in short, specifies
+ * the size of the file being uploaded. -1 means unknown.
+ */
+ CINIT(INFILESIZE_LARGE, OFF_T, 115),
+
+ /* Sets the continuation offset. There is also a LONG version of this;
+ * look above for RESUME_FROM.
+ */
+ CINIT(RESUME_FROM_LARGE, OFF_T, 116),
+
+ /* Sets the maximum size of data that will be downloaded from
+ * an HTTP or FTP server. See MAXFILESIZE above for the LONG version.
+ */
+ CINIT(MAXFILESIZE_LARGE, OFF_T, 117),
+
+ /* Set this option to the file name of your .netrc file you want libcurl
+ to parse (using the CURLOPT_NETRC option). If not set, libcurl will do
+ a poor attempt to find the user's home directory and check for a .netrc
+ file in there. */
+ CINIT(NETRC_FILE, OBJECTPOINT, 118),
+
+ /* Enable SSL/TLS for FTP, pick one of:
+ CURLFTPSSL_TRY - try using SSL, proceed anyway otherwise
+ CURLFTPSSL_CONTROL - SSL for the control connection or fail
+ CURLFTPSSL_ALL - SSL for all communication or fail
+ */
+ CINIT(FTP_SSL, LONG, 119),
+
+ /* The _LARGE version of the standard POSTFIELDSIZE option */
+ CINIT(POSTFIELDSIZE_LARGE, OFF_T, 120),
+
+ /* Enable/disable the TCP Nagle algorithm */
+ CINIT(TCP_NODELAY, LONG, 121),
+
+ /* When doing 3rd party transfer, set the source host name with this */
+ CINIT(SOURCE_HOST, OBJECTPOINT, 122),
+
+ /* When doing 3rd party transfer, set the source user and password with
+ this */
+ CINIT(SOURCE_USERPWD, OBJECTPOINT, 123),
+
+ /* When doing 3rd party transfer, set the source file path with this */
+ CINIT(SOURCE_PATH, OBJECTPOINT, 124),
+
+ /* When doing 3rd party transfer, set the source server's port number
+ with this */
+ CINIT(SOURCE_PORT, LONG, 125),
+
+ /* When doing 3rd party transfer, decide which server that should get the
+ PASV command (and the other gets the PORT).
+ 0 (default) - The target host issues PASV.
+ 1 - The source host issues PASV */
+ CINIT(PASV_HOST, LONG, 126),
+
+ /* When doing 3rd party transfer, set the source pre-quote linked list
+ of commands with this */
+ CINIT(SOURCE_PREQUOTE, OBJECTPOINT, 127),
+
+ /* When doing 3rd party transfer, set the source post-quote linked list
+ of commands with this */
+ CINIT(SOURCE_POSTQUOTE, OBJECTPOINT, 128),
+
CURLOPT_LASTENTRY /* the last unused */
} CURLoption;
- /* two convenient "aliases" that follow the name scheme better */
+ /* Below here follows defines for the CURLOPT_IPRESOLVE option. If a host
+ name resolves addresses using more than one IP protocol version, this
+ option might be handy to force libcurl to use a specific IP version. */
+#define CURL_IPRESOLVE_WHATEVER 0 /* default, resolves addresses to all IP
+ versions that your system allows */
+#define CURL_IPRESOLVE_V4 1 /* resolve to ipv4 addresses */
+#define CURL_IPRESOLVE_V6 2 /* resolve to ipv6 addresses */
+
+ /* three convenient "aliases" that follow the name scheme better */
#define CURLOPT_WRITEDATA CURLOPT_FILE
-#define CURLOPT_READDATA CURLOPT_INFILE
+#define CURLOPT_READDATA CURLOPT_INFILE
#define CURLOPT_HEADERDATA CURLOPT_WRITEHEADER
+#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
+ the obsolete stuff removed! */
+#define CURLOPT_HTTPREQUEST -1
+#define CURLOPT_FTPASCII CURLOPT_TRANSFERTEXT
+#define CURLOPT_MUTE -2
+#define CURLOPT_PASSWDFUNCTION -3
+#define CURLOPT_PASSWDDATA -4
+#define CURLOPT_CLOSEFUNCTION -5
+
+#else
+/* This is set if CURL_NO_OLDIES is defined at compile-time */
+#undef CURLOPT_DNS_USE_GLOBAL_CACHE /* soon obsolete */
+#endif
+
/* These enums are for use with the CURLOPT_HTTP_VERSION option. */
enum {
@@ -635,7 +851,7 @@ enum {
for us! */
CURL_HTTP_VERSION_1_0, /* please use HTTP 1.0 in the request */
CURL_HTTP_VERSION_1_1, /* please use HTTP 1.1 in the request */
-
+
CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */
};
@@ -671,37 +887,15 @@ typedef enum {
CURL_TIMECOND_LAST
} curl_TimeCond;
-/* for backwards compatibility */
-#ifndef TIMECOND_IFMODSINCE
-#define TIMECOND_IFMODSINCE CURL_TIMECOND_IFMODSINCE
-#endif
-#ifndef TIMECOND_IFUNMODSINCE
-#define TIMECOND_IFUNMODSINCE CURL_TIMECOND_IFUNMODSINCE
-#endif
-#ifndef TIMECOND_LASTMOD
-#define TIMECOND_LASTMOD CURL_TIMECOND_LASTMOD
-#endif
-
#ifdef __BEOS__
#include <support/SupportDefs.h>
#endif
-/* These functions are in the libcurl, they're here for portable reasons and
- they are used by the 'curl' client. They really should be moved to some kind
- of "portability library" since it has nothing to do with file transfers and
- might be usable to other programs...
-
- NOTE: they return TRUE if the strings match *case insensitively*.
- */
+/* curl_strequal() and curl_strnequal() are subject for removal in a future
+ libcurl, see lib/README.curlx for details */
extern int (curl_strequal)(const char *s1, const char *s2);
extern int (curl_strnequal)(const char *s1, const char *s2, size_t n);
-#define strequal(a,b) curl_strequal(a,b)
-#define strnequal(a,b,c) curl_strnequal(a,b,c)
-
-/* DEPRECATED function to build formdata */
-int curl_formparse(char *, struct curl_httppost **,
- struct curl_httppost **_post);
/* name is uppercase CURLFORM_<name> */
#ifdef CFINIT
@@ -717,7 +911,7 @@ int curl_formparse(char *, struct curl_httppost **,
typedef enum {
CFINIT(NOTHING), /********* the first one is unused ************/
-
+
/* */
CFINIT(COPYNAME),
CFINIT(PTRNAME),
@@ -747,13 +941,13 @@ typedef enum {
/* structure to be used as parameter for CURLFORM_ARRAY */
struct curl_forms {
- CURLformoption option;
- const char *value;
+ CURLformoption option;
+ const char *value;
};
/* use this for multipart formpost building */
/* Returns code for curl_formadd()
- *
+ *
* Returns:
* CURL_FORMADD_OK on success
* CURL_FORMADD_MEMORY if the FormInfo allocation fails
@@ -776,51 +970,147 @@ typedef enum {
CURL_FORMADD_UNKNOWN_OPTION,
CURL_FORMADD_INCOMPLETE,
CURL_FORMADD_ILLEGAL_ARRAY,
+ CURL_FORMADD_DISABLED, /* libcurl was built with this disabled */
CURL_FORMADD_LAST /* last */
} CURLFORMcode;
+/*
+ * NAME curl_formadd()
+ *
+ * DESCRIPTION
+ *
+ * Pretty advanved function for building multi-part formposts. Each invoke
+ * adds one part that together construct a full post. Then use
+ * CURLOPT_HTTPPOST to send it off to libcurl.
+ */
CURLFORMcode curl_formadd(struct curl_httppost **httppost,
- struct curl_httppost **last_post,
- ...);
+ struct curl_httppost **last_post,
+ ...);
-/* cleanup a form: */
+/*
+ * NAME curl_formfree()
+ *
+ * DESCRIPTION
+ *
+ * Free a multipart formpost previously built with curl_formadd().
+ */
void curl_formfree(struct curl_httppost *form);
-/* Unix and Win32 getenv function call, this returns a malloc()'ed string that
- MUST be free()ed after usage is complete. */
+/*
+ * NAME curl_getenv()
+ *
+ * DESCRIPTION
+ *
+ * Returns a malloc()'ed string that MUST be curl_free()ed after usage is
+ * complete. DEPRECATED - see lib/README.curlx
+ */
char *curl_getenv(const char *variable);
-/* Returns a static ascii string of the libcurl version. */
+/*
+ * NAME curl_version()
+ *
+ * DESCRIPTION
+ *
+ * Returns a static ascii string of the libcurl version.
+ */
char *curl_version(void);
-/* Escape and unescape URL encoding in strings. The functions return a new
- * allocated string or NULL if an error occurred. */
+/*
+ * NAME curl_escape()
+ *
+ * DESCRIPTION
+ *
+ * Escapes URL strings (converts all letters consider illegal in URLs to their
+ * %XX versions). This function returns a new allocated string or NULL if an
+ * error occurred.
+ */
char *curl_escape(const char *string, int length);
+
+/*
+ * NAME curl_unescape()
+ *
+ * DESCRIPTION
+ *
+ * Unescapes URL encoding in strings (converts all %XX codes to their 8bit
+ * versions). This function returns a new allocated string or NULL if an error
+ * occurred.
+ */
char *curl_unescape(const char *string, int length);
-/* 20020912 WJM. Provide for a de-allocation in the same translation unit
- that did the allocation. Added in libcurl 7.10 */
+
+/*
+ * NAME curl_free()
+ *
+ * DESCRIPTION
+ *
+ * Provided for de-allocation in the same translation unit that did the
+ * allocation. Added in libcurl 7.10
+ */
void curl_free(void *p);
-/* curl_global_init() should be invoked exactly once for each application that
- uses libcurl */
+/*
+ * NAME curl_global_init()
+ *
+ * DESCRIPTION
+ *
+ * curl_global_init() should be invoked exactly once for each application that
+ * uses libcurl
+ */
CURLcode curl_global_init(long flags);
-/* curl_global_cleanup() should be invoked exactly once for each application
- that uses libcurl */
-void curl_global_cleanup(void);
+/*
+ * NAME curl_global_init_mem()
+ *
+ * DESCRIPTION
+ *
+ * curl_global_init() or curl_global_init_mem() should be invoked exactly once
+ * for each application that uses libcurl. This function can be used to
+ * initialize libcurl and set user defined memory management callback
+ * functions. Users can implement memory management routines to check for
+ * memory leaks, check for mis-use of the curl library etc. User registered
+ * callback routines with be invoked by this library instead of the system
+ * memory management routines like malloc, free etc.
+ */
+CURLcode curl_global_init_mem(long flags,
+ curl_malloc_callback m,
+ curl_free_callback f,
+ curl_realloc_callback r,
+ curl_strdup_callback s,
+ curl_calloc_callback c);
-/* This is the version number */
-#define LIBCURL_VERSION "7.10.3"
-#define LIBCURL_VERSION_NUM 0x070a03
+/*
+ * NAME curl_global_cleanup()
+ *
+ * DESCRIPTION
+ *
+ * curl_global_cleanup() should be invoked exactly once for each application
+ * that uses libcurl
+ */
+void curl_global_cleanup(void);
/* linked-list structure for the CURLOPT_QUOTE option (and other) */
struct curl_slist {
- char *data;
- struct curl_slist *next;
+ char *data;
+ struct curl_slist *next;
};
+/*
+ * NAME curl_slist_append()
+ *
+ * DESCRIPTION
+ *
+ * Appends a string to a linked list. If no list exists, it will be created
+ * first. Returns the new list, after appending.
+ */
struct curl_slist *curl_slist_append(struct curl_slist *, const char *);
+
+/*
+ * NAME curl_slist_free_all()
+ *
+ * DESCRIPTION
+ *
+ * free a previously built curl_slist.
+ */
void curl_slist_free_all(struct curl_slist *);
/*
@@ -835,7 +1125,6 @@ void curl_slist_free_all(struct curl_slist *);
*/
time_t curl_getdate(const char *p, const time_t *now);
-
#define CURLINFO_STRING 0x100000
#define CURLINFO_LONG 0x200000
#define CURLINFO_DOUBLE 0x300000
@@ -845,7 +1134,7 @@ time_t curl_getdate(const char *p, const time_t *now);
typedef enum {
CURLINFO_NONE, /* first, never use this */
CURLINFO_EFFECTIVE_URL = CURLINFO_STRING + 1,
- CURLINFO_HTTP_CODE = CURLINFO_LONG + 2,
+ CURLINFO_RESPONSE_CODE = CURLINFO_LONG + 2,
CURLINFO_TOTAL_TIME = CURLINFO_DOUBLE + 3,
CURLINFO_NAMELOOKUP_TIME = CURLINFO_DOUBLE + 4,
CURLINFO_CONNECT_TIME = CURLINFO_DOUBLE + 5,
@@ -858,24 +1147,25 @@ typedef enum {
CURLINFO_REQUEST_SIZE = CURLINFO_LONG + 12,
CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG + 13,
CURLINFO_FILETIME = CURLINFO_LONG + 14,
-
CURLINFO_CONTENT_LENGTH_DOWNLOAD = CURLINFO_DOUBLE + 15,
CURLINFO_CONTENT_LENGTH_UPLOAD = CURLINFO_DOUBLE + 16,
-
CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17,
-
- CURLINFO_CONTENT_TYPE = CURLINFO_STRING + 18,
-
- CURLINFO_REDIRECT_TIME = CURLINFO_DOUBLE + 19,
- CURLINFO_REDIRECT_COUNT = CURLINFO_LONG + 20,
-
- CURLINFO_PRIVATE = CURLINFO_STRING + 21,
-
- /* Fill in new entries here! */
-
- CURLINFO_LASTONE = 22
+ CURLINFO_CONTENT_TYPE = CURLINFO_STRING + 18,
+ CURLINFO_REDIRECT_TIME = CURLINFO_DOUBLE + 19,
+ CURLINFO_REDIRECT_COUNT = CURLINFO_LONG + 20,
+ CURLINFO_PRIVATE = CURLINFO_STRING + 21,
+ CURLINFO_HTTP_CONNECTCODE = CURLINFO_LONG + 22,
+ CURLINFO_HTTPAUTH_AVAIL = CURLINFO_LONG + 23,
+ CURLINFO_PROXYAUTH_AVAIL = CURLINFO_LONG + 24,
+ /* Fill in new entries below here! */
+
+ CURLINFO_LASTONE = 23
} CURLINFO;
+/* CURLINFO_RESPONSE_CODE is the new name for the option previously known as
+ CURLINFO_HTTP_CODE */
+#define CURLINFO_HTTP_CODE CURLINFO_RESPONSE_CODE
+
typedef enum {
CURLCLOSEPOLICY_NONE, /* first, never use this */
@@ -884,7 +1174,7 @@ typedef enum {
CURLCLOSEPOLICY_LEAST_TRAFFIC,
CURLCLOSEPOLICY_SLOWEST,
CURLCLOSEPOLICY_CALLBACK,
-
+
CURLCLOSEPOLICY_LAST /* last, never use this */
} curl_closepolicy;
@@ -902,10 +1192,15 @@ typedef enum {
/* Different data locks for a single share */
typedef enum {
CURL_LOCK_DATA_NONE = 0,
- CURL_LOCK_DATA_COOKIE = 1,
- CURL_LOCK_DATA_DNS = 2,
- CURL_LOCK_DATA_SSL_SESSION = 3,
- CURL_LOCK_DATA_CONNECT = 4,
+ /* CURL_LOCK_DATA_SHARE is used internaly to say that
+ * the locking is just made to change the internal state of the share
+ * itself.
+ */
+ CURL_LOCK_DATA_SHARE,
+ CURL_LOCK_DATA_COOKIE,
+ CURL_LOCK_DATA_DNS,
+ CURL_LOCK_DATA_SSL_SESSION,
+ CURL_LOCK_DATA_CONNECT,
CURL_LOCK_DATA_LAST
} curl_lock_data;
@@ -919,7 +1214,7 @@ typedef enum {
typedef void (*curl_lock_function)(CURL *handle,
curl_lock_data data,
- curl_lock_access access,
+ curl_lock_access locktype,
void *userptr);
typedef void (*curl_unlock_function)(CURL *handle,
curl_lock_data data,
@@ -932,6 +1227,7 @@ typedef enum {
CURLSHE_BAD_OPTION, /* 1 */
CURLSHE_IN_USE, /* 2 */
CURLSHE_INVALID, /* 3 */
+ CURLSHE_NOMEM, /* out of memory */
CURLSHE_LAST /* never use */
} CURLSHcode;
@@ -956,6 +1252,8 @@ CURLSHcode curl_share_cleanup(CURLSH *);
typedef enum {
CURLVERSION_FIRST,
+ CURLVERSION_SECOND,
+ CURLVERSION_THIRD,
CURLVERSION_LAST /* never actually use this */
} CURLversion;
@@ -964,7 +1262,7 @@ typedef enum {
meant to be a built-in version number for what kind of struct the caller
expects. If the struct ever changes, we redfine the NOW to another enum
from above. */
-#define CURLVERSION_NOW CURLVERSION_FIRST
+#define CURLVERSION_NOW CURLVERSION_THIRD
typedef struct {
CURLversion age; /* age of the returned struct */
@@ -977,16 +1275,59 @@ typedef struct {
const char *libz_version; /* human readable string */
/* protocols is terminated by an entry with a NULL protoname */
const char **protocols;
+
+ /* The fields below this were added in CURLVERSION_SECOND */
+ const char *ares;
+ int ares_num;
+
+ /* This field was aded in CURLVERSION_THIRD */
+ const char *libidn;
} curl_version_info_data;
-#define CURL_VERSION_IPV6 (1<<0)
-#define CURL_VERSION_KERBEROS4 (1<<1)
-#define CURL_VERSION_SSL (1<<2)
-#define CURL_VERSION_LIBZ (1<<3)
+#define CURL_VERSION_IPV6 (1<<0) /* IPv6-enabled */
+#define CURL_VERSION_KERBEROS4 (1<<1) /* kerberos auth is supported */
+#define CURL_VERSION_SSL (1<<2) /* SSL options are present */
+#define CURL_VERSION_LIBZ (1<<3) /* libz features are present */
+#define CURL_VERSION_NTLM (1<<4) /* NTLM auth is supported */
+#define CURL_VERSION_GSSNEGOTIATE (1<<5) /* Negotiate auth support */
+#define CURL_VERSION_DEBUG (1<<6) /* built with debug capabilities */
+#define CURL_VERSION_ASYNCHDNS (1<<7) /* asynchronous dns resolves */
+#define CURL_VERSION_SPNEGO (1<<8) /* SPNEGO auth */
+#define CURL_VERSION_LARGEFILE (1<<9) /* supports files bigger than 2GB */
+#define CURL_VERSION_IDN (1<<10) /* International Domain Names support */
-/* returns a pointer to a static copy of the version info struct */
+/*
+ * NAME curl_version_info()
+ *
+ * DESCRIPTION
+ *
+ * This function returns a pointer to a static copy of the version info
+ * struct. See above.
+ */
curl_version_info_data *curl_version_info(CURLversion);
+/*
+ * NAME curl_easy_strerror()
+ *
+ * DESCRIPTION
+ *
+ * The curl_easy_strerror function may be used to turn a CURLcode value
+ * into the equivalent human readable error string. This is useful
+ * for printing meaningful error messages.
+ */
+const char *curl_easy_strerror(CURLcode);
+
+/*
+ * NAME curl_share_strerror()
+ *
+ * DESCRIPTION
+ *
+ * The curl_share_strerror function may be used to turn a CURLSHcode value
+ * into the equivalent human readable error string. This is useful
+ * for printing meaningful error messages.
+ */
+const char *curl_share_strerror(CURLSHcode);
+
#ifdef __cplusplus
}
#endif
diff --git a/Source/CTest/Curl/curl/curlver.h b/Source/CTest/Curl/curl/curlver.h
new file mode 100644
index 0000000..ef0a4c5
--- /dev/null
+++ b/Source/CTest/Curl/curl/curlver.h
@@ -0,0 +1,55 @@
+#ifndef __CURL_CURLVER_H
+#define __CURL_CURLVER_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+/* This header file contains nothing but libcurl version info, generated by
+ a script at release-time. This was made its own header file in 7.11.2 */
+
+/* This is the version number of the libcurl package from which this header
+ file origins: */
+#define LIBCURL_VERSION "7.12.1"
+
+/* This is the numeric version of the libcurl version number, meant for easier
+ parsing and comparions by programs. The LIBCURL_VERSION_NUM define will
+ always follow this syntax:
+
+ 0xXXYYZZ
+
+ Where XX, YY and ZZ are the main version, release and patch numbers in
+ hexadecimal. All three numbers are always represented using two digits. 1.2
+ would appear as "0x010200" while version 9.11.7 appears as "0x090b07".
+
+ This 6-digit hexadecimal number does not show pre-release number, and it is
+ always a greater number in a more recent release. It makes comparisons with
+ greater than and less than work.
+*/
+#define LIBCURL_VERSION_NUM 0x70C01
+
+/* The numeric version number is also available "in parts" by using these
+ defines: */
+#define LIBCURL_VERSION_MAJOR 7
+#define LIBCURL_VERSION_MINOR 12
+#define LIBCURL_VERSION_PATCH 1
+
+#endif /* __CURL_CURLVER_H */
diff --git a/Source/CTest/Curl/curl/easy.h b/Source/CTest/Curl/curl/easy.h
index 47f4e96..336e542 100644
--- a/Source/CTest/Curl/curl/easy.h
+++ b/Source/CTest/Curl/curl/easy.h
@@ -1,18 +1,18 @@
#ifndef __CURL_EASY_H
#define __CURL_EASY_H
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -61,6 +61,19 @@ CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...);
*/
CURL* curl_easy_duphandle(CURL *curl);
+/*
+ * NAME curl_easy_reset()
+ *
+ * DESCRIPTION
+ *
+ * Re-initializes a CURL handle to the default values. This puts back the
+ * handle to the same state as it was in when it was just created.
+ *
+ * It does keep: live connections, the Session ID cache, the DNS cache and the
+ * cookies.
+ */
+void curl_easy_reset(CURL *curl);
+
#ifdef __cplusplus
}
#endif
diff --git a/Source/CTest/Curl/curl/mprintf.h b/Source/CTest/Curl/curl/mprintf.h
index 30c4d44..65dc114 100644
--- a/Source/CTest/Curl/curl/mprintf.h
+++ b/Source/CTest/Curl/curl/mprintf.h
@@ -1,54 +1,25 @@
-/*************************************************************************
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
*
* $Id$
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
- * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
- * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
- *
- *************************************************************************
- *
- * Preliminary documentation
- *
- * printf conversions:
- *
- * conversion ::= '%%' | '%' [position] ( number | float | string )
- * position ::= digits '$'
- * number ::= [number-flags] ( 'd' | 'i' | 'o' | 'x' | 'X' | 'u')
- * number-flags ::= 'h' | 'l' | 'L' ...
- * float ::= [float-flags] ( 'f' | 'e' | 'E' | 'g' | 'G' )
- * string ::= [string-flags] 's'
- * string-flags ::= padding | '#'
- * digits ::= (digit)+
- * digit ::= 0-9
- *
- * c
- * p
- * n
- *
- * qualifiers
- *
- * - : left adjustment
- * + : show sign
- * SPACE : padding
- * # : alterative
- * . : precision
- * * : width
- * 0 : padding / size
- * 1-9 : size
- * h : short
- * l : long
- * ll : longlong
- * L : long double
- * Z : long / longlong
- * q : longlong
- *
- ************************************************************************/
+ ***************************************************************************/
#ifndef H_MPRINTF
#define H_MPRINTF
diff --git a/Source/CTest/Curl/curl/multi.h b/Source/CTest/Curl/curl/multi.h
index 40dd01e..3a867ab 100644
--- a/Source/CTest/Curl/curl/multi.h
+++ b/Source/CTest/Curl/curl/multi.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -44,19 +44,35 @@
o Enable the application to select() on its own file descriptors and curl's
file descriptors simultaneous easily.
- Example sources using this interface is here: ../multi/
-
*/
+#if defined(_WIN32) && !defined(WIN32)
+/* Chris Lewis mentioned that he doesn't get WIN32 defined, only _WIN32 so we
+ make this adjustment to catch this. */
+#define WIN32 1
+#endif
#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
-#include <winsock.h>
+#include <winsock2.h>
#else
+
+/* HP-UX systems version 9, 10 and 11 lack sys/select.h and so does oldish
+ libc5-based Linux systems. Only include it on system that are known to
+ require it! */
+#if defined(_AIX) || defined(NETWARE)
+#include <sys/select.h>
+#endif
+
#include <sys/socket.h>
#include <sys/time.h>
+#include <sys/types.h>
#endif
#include "curl.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
typedef void CURLM;
typedef enum {
@@ -71,7 +87,7 @@ typedef enum {
typedef enum {
CURLMSG_NONE, /* first, not used */
- CURLMSG_DONE, /* This easy handle has completed. 'whatever' points to
+ CURLMSG_DONE, /* This easy handle has completed. 'result' contains
the CURLcode of the transfer */
CURLMSG_LAST /* last, not used */
} CURLMSG;
@@ -187,4 +203,19 @@ CURLMcode curl_multi_cleanup(CURLM *multi_handle);
CURLMsg *curl_multi_info_read(CURLM *multi_handle,
int *msgs_in_queue);
+/*
+ * NAME curl_multi_strerror()
+ *
+ * DESCRIPTION
+ *
+ * The curl_multi_strerror function may be used to turn a CURLMcode value
+ * into the equivalent human readable error string. This is useful
+ * for printing meaningful error messages.
+ */
+const char *curl_multi_strerror(CURLMcode);
+
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif
+
#endif
diff --git a/Source/CTest/Curl/curl/stdcheaders.h b/Source/CTest/Curl/curl/stdcheaders.h
index 35648b5..11c1e2f 100644
--- a/Source/CTest/Curl/curl/stdcheaders.h
+++ b/Source/CTest/Curl/curl/stdcheaders.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -23,9 +23,7 @@
* $Id$
***************************************************************************/
-#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
-#endif
size_t fread (void *, size_t, size_t, FILE *);
size_t fwrite (const void *, size_t, size_t, FILE *);
diff --git a/Source/CTest/Curl/curl/types.h b/Source/CTest/Curl/curl/types.h
index 5598880..d37d6ae 100644
--- a/Source/CTest/Curl/curl/types.h
+++ b/Source/CTest/Curl/curl/types.h
@@ -1,28 +1 @@
-#ifndef __CURL_TYPES_H
-#define __CURL_TYPES_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-typedef void CURL;
-typedef void CURLconnect;
-
-#endif /* __CURL_TYPES_H */
+/* not used */
diff --git a/Source/CTest/Curl/curlx.h b/Source/CTest/Curl/curlx.h
new file mode 100644
index 0000000..0dd9a09
--- /dev/null
+++ b/Source/CTest/Curl/curlx.h
@@ -0,0 +1,95 @@
+#ifndef __CURLX_H
+#define __CURLX_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+/*
+ * Defines protos and includes all header files that provide the curlx_*
+ * functions. The curlx_* functions are not part of the libcurl API, but are
+ * stand-alone functions whose sources can be built and linked by apps if need
+ * be.
+ */
+
+#include <curl/mprintf.h>
+/* this is still a public header file that provides the curl_mprintf()
+ functions while they still are offered publicly. They will be made library-
+ private one day */
+
+#include "strequal.h"
+/* "strequal.h" provides the strequal protos */
+
+#include "strtoofft.h"
+/* "strtoofft.h" provides this function: curlx_strtoofft(), returns a
+ curl_off_t number from a given string.
+*/
+
+#include "timeval.h"
+/*
+ "timeval.h" sets up a 'struct timeval' even for platforms that otherwise
+ don't have one and has protos for these functions:
+
+ curlx_tvnow()
+ curlx_tvdiff()
+ curlx_tvdiff_secs()
+*/
+
+/* Now setup curlx_ * names for the functions that are to become curlx_ and
+ be removed from a future libcurl official API:
+ curlx_getenv
+ curlx_mprintf (and its variations)
+ curlx_strequal
+ curlx_strnequal
+
+*/
+
+#define curlx_getenv curl_getenv
+#define curlx_strequal curl_strequal
+#define curlx_strnequal curl_strnequal
+#define curlx_mvsnprintf curl_mvsnprintf
+#define curlx_msnprintf curl_msnprintf
+#define curlx_maprintf curl_maprintf
+#define curlx_mvaprintf curl_mvaprintf
+#define curlx_msprintf curl_msprintf
+#define curlx_mprintf curl_mprintf
+#define curlx_mfprintf curl_mfprintf
+#define curlx_mvsprintf curl_mvsprintf
+#define curlx_mvprintf curl_mvprintf
+#define curlx_mvfprintf curl_mvfprintf
+
+#ifdef ENABLE_CURLX_PRINTF
+/* If this define is set, we define all "standard" printf() functions to use
+ the curlx_* version instead. It makes the source code transparant and
+ easier to understand/patch. */
+# define printf curlx_mprintf
+# define fprintf curlx_mfprintf
+# define sprintf curlx_msprintf
+# define snprintf curlx_msnprintf
+# define vprintf curlx_mvprintf
+# define vfprintf curlx_mvfprintf
+# define vsprintf curlx_mvsprintf
+# define vsnprintf curlx_mvsnprintf
+# define aprintf curlx_maprintf
+# define vaprintf curlx_mvaprintf
+#endif /* ENABLE_CURLX_PRINTF */
+
+#endif /* __CURLX_H */
diff --git a/Source/CTest/Curl/dict.c b/Source/CTest/Curl/dict.c
index df8c5b5..c5e2c04 100644
--- a/Source/CTest/Curl/dict.c
+++ b/Source/CTest/Curl/dict.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -35,7 +35,6 @@
#include <errno.h>
#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
-#include <winsock.h>
#include <time.h>
#include <io.h>
#else
@@ -44,7 +43,6 @@
#endif
#include <netinet/in.h>
#include <sys/time.h>
-#include <sys/resource.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
@@ -76,13 +74,13 @@
#include "progress.h"
#include "strequal.h"
+#include "dict.h"
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
CURLcode Curl_dict(struct connectdata *conn)
{
- int nth;
char *word;
char *ppath;
char *database = NULL;
@@ -91,9 +89,10 @@ CURLcode Curl_dict(struct connectdata *conn)
by RFC 2229 */
CURLcode result=CURLE_OK;
struct SessionHandle *data=conn->data;
+ curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
char *path = conn->path;
- long *bytecount = &conn->bytecount;
+ curl_off_t *bytecount = &conn->bytecount;
if(conn->bits.user_passwd) {
/* AUTH is missing */
@@ -129,14 +128,8 @@ CURLcode Curl_dict(struct connectdata *conn)
if ((strategy == NULL) || (*strategy == (char)0)) {
strategy = (char *)".";
}
- if ((nthdef == NULL) || (*nthdef == (char)0)) {
- nth = 0;
- }
- else {
- nth = atoi(nthdef);
- }
- result = Curl_sendf(conn->firstsocket, conn,
+ result = Curl_sendf(sockfd, conn,
"CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\n"
"MATCH "
"%s " /* database */
@@ -151,7 +144,7 @@ CURLcode Curl_dict(struct connectdata *conn)
if(result)
failf(data, "Failed sending DICT request");
else
- result = Curl_Transfer(conn, conn->firstsocket, -1, FALSE, bytecount,
+ result = Curl_Transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
-1, NULL); /* no upload */
if(result)
return result;
@@ -179,14 +172,8 @@ CURLcode Curl_dict(struct connectdata *conn)
if ((database == NULL) || (*database == (char)0)) {
database = (char *)"!";
}
- if ((nthdef == NULL) || (*nthdef == (char)0)) {
- nth = 0;
- }
- else {
- nth = atoi(nthdef);
- }
- result = Curl_sendf(conn->firstsocket, conn,
+ result = Curl_sendf(sockfd, conn,
"CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\n"
"DEFINE "
"%s " /* database */
@@ -197,7 +184,7 @@ CURLcode Curl_dict(struct connectdata *conn)
if(result)
failf(data, "Failed sending DICT request");
else
- result = Curl_Transfer(conn, conn->firstsocket, -1, FALSE, bytecount,
+ result = Curl_Transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
-1, NULL); /* no upload */
if(result)
@@ -215,27 +202,19 @@ CURLcode Curl_dict(struct connectdata *conn)
if (ppath[i] == ':')
ppath[i] = ' ';
}
- result = Curl_sendf(conn->firstsocket, conn,
+ result = Curl_sendf(sockfd, conn,
"CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\n"
"%s\n"
"QUIT\n", ppath);
if(result)
failf(data, "Failed sending DICT request");
else
- result = Curl_Transfer(conn, conn->firstsocket, -1, FALSE, bytecount,
+ result = Curl_Transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
-1, NULL);
if(result)
return result;
}
}
- (void)nth;
+
return CURLE_OK;
}
-
-/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
- */
diff --git a/Source/CTest/Curl/dict.h b/Source/CTest/Curl/dict.h
index 537e486..4301f01 100644
--- a/Source/CTest/Curl/dict.h
+++ b/Source/CTest/Curl/dict.h
@@ -8,7 +8,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
diff --git a/Source/CTest/Curl/dllinit.c b/Source/CTest/Curl/dllinit.c
deleted file mode 100644
index 71b28bd..0000000
--- a/Source/CTest/Curl/dllinit.c
+++ /dev/null
@@ -1,96 +0,0 @@
-#ifdef WIN32
-/* dllinit.c -- Portable DLL initialization.
- Copyright (C) 1998, 1999 Free Software Foundation, Inc.
- Contributed by Mumit Khan (khan@xraylith.wisc.edu).
-
- I've used DllMain as the DLL "main" since that's the most common
- usage. MSVC and Mingw32 both default to DllMain as the standard
- callback from the linker entry point. Cygwin, as of b20.1, also
- uses DllMain as the default callback from the entry point.
-
- The real entry point is typically always defined by the runtime
- library, and usually never overridden by (casual) user. What you can
- override however is the callback routine that the entry point calls,
- and this file provides such a callback function, DllMain.
-
- Mingw32: The default entry point for mingw32 is DllMainCRTStartup
- which is defined in libmingw32.a This in turn calls DllMain which is
- defined here. If not defined, there is a stub in libmingw32.a which
- does nothing.
-
- Cygwin: The default entry point for Cygwin b20.1 or newer is
- __cygwin_dll_entry which is defined in libcygwin.a. This in turn
- calls the routine DllMain. If not defined, there is a stub in
- libcygwin.a which does nothing.
-
- MSVC: MSVC runtime calls DllMain, just like Mingw32.
-
- Summary: If you need to do anything special in DllMain, just add it
- here. Otherwise, the default setup should be just fine for 99%+ of
- the time. I strongly suggest that you *not* change the entry point,
- but rather change DllMain as appropriate.
-
- */
-
-
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#undef WIN32_LEAN_AND_MEAN
-#include <stdio.h>
-
-BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason,
- LPVOID reserved /* Not used. */ );
-
-/*
- *----------------------------------------------------------------------
- *
- * DllMain --
- *
- * This routine is called by the Mingw32, Cygwin32 or VC++ C run
- * time library init code, or the Borland DllEntryPoint routine. It
- * is responsible for initializing various dynamically loaded
- * libraries.
- *
- * Results:
- * TRUE on sucess, FALSE on failure.
- *
- * Side effects:
- *
- *----------------------------------------------------------------------
- */
-BOOL APIENTRY
-DllMain (
- HINSTANCE hInst /* Library instance handle. */ ,
- DWORD reason /* Reason this function is being called. */ ,
- LPVOID reserved /* Not used. */ )
-{
-
- switch (reason)
- {
- case DLL_PROCESS_ATTACH:
- break;
-
- case DLL_PROCESS_DETACH:
- break;
-
- case DLL_THREAD_ATTACH:
- break;
-
- case DLL_THREAD_DETACH:
- break;
- }
- return TRUE;
-}
-#else
-#ifdef VMS
-int VOID_VAR_DLLINIT;
-#endif
-#endif
-
-/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
- */
diff --git a/Source/CTest/Curl/easy.c b/Source/CTest/Curl/easy.c
index 145db5a..53bd13b 100644
--- a/Source/CTest/Curl/easy.c
+++ b/Source/CTest/Curl/easy.c
@@ -1,16 +1,16 @@
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -37,7 +37,6 @@
#include "strequal.h"
#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
-#include <winsock.h>
#include <time.h>
#include <io.h>
#else
@@ -46,7 +45,6 @@
#endif
#include <netinet/in.h>
#include <sys/time.h>
-#include <sys/resource.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
@@ -68,7 +66,7 @@
#include <sys/select.h>
#endif
-#endif
+#endif /* WIN32 ... */
#include "urldata.h"
#include <curl/curl.h>
@@ -77,70 +75,120 @@
#include "url.h"
#include "getinfo.h"
#include "hostip.h"
+#include "share.h"
+#include "memory.h"
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
-
-/* Silly win32 socket initialization functions */
+/* The last #include file should be: */
+#include "memdebug.h"
#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
+/* win32_cleanup() is for win32 socket cleanup functionality, the opposite
+ of win32_init() */
static void win32_cleanup(void)
{
WSACleanup();
}
+/* win32_init() performs win32 socket initialization to properly setup the
+ stack to allow networking */
static CURLcode win32_init(void)
{
- WORD wVersionRequested;
- WSADATA wsaData;
- int err;
- wVersionRequested = MAKEWORD(2, 0);
-
- err = WSAStartup(wVersionRequested, &wsaData);
-
- if (err != 0)
- /* Tell the user that we couldn't find a useable */
- /* winsock.dll. */
- return CURLE_FAILED_INIT;
-
- /* Confirm that the Windows Sockets DLL supports 2.0.*/
- /* Note that if the DLL supports versions greater */
- /* than 2.0 in addition to 2.0, it will still return */
- /* 2.0 in wVersion since that is the version we */
- /* requested. */
-
- if ( LOBYTE( wsaData.wVersion ) != 2 ||
- HIBYTE( wsaData.wVersion ) != 0 ) {
- /* Tell the user that we couldn't find a useable */
-
- /* winsock.dll. */
- WSACleanup();
- return CURLE_FAILED_INIT;
+ WORD wVersionRequested;
+ WSADATA wsaData;
+ int err;
+
+#ifdef ENABLE_IPV6
+ wVersionRequested = MAKEWORD(2, 0);
+#else
+ wVersionRequested = MAKEWORD(1, 1);
+#endif
+
+ err = WSAStartup(wVersionRequested, &wsaData);
+
+ if (err != 0)
+ /* Tell the user that we couldn't find a useable */
+ /* winsock.dll. */
+ return CURLE_FAILED_INIT;
+
+ /* Confirm that the Windows Sockets DLL supports what we need.*/
+ /* Note that if the DLL supports versions greater */
+ /* than wVersionRequested, it will still return */
+ /* wVersionRequested in wVersion. wHighVersion contains the */
+ /* highest supported version. */
+
+ if ( LOBYTE( wsaData.wVersion ) != LOBYTE(wVersionRequested) ||
+ HIBYTE( wsaData.wVersion ) != HIBYTE(wVersionRequested) ) {
+ /* Tell the user that we couldn't find a useable */
+
+ /* winsock.dll. */
+ WSACleanup();
+ return CURLE_FAILED_INIT;
}
+ /* The Windows Sockets DLL is acceptable. Proceed. */
return CURLE_OK;
}
-/* The Windows Sockets DLL is acceptable. Proceed. */
+
#else
/* These functions exist merely to prevent compiler warnings */
static CURLcode win32_init(void) { return CURLE_OK; }
static void win32_cleanup(void) { }
#endif
+#ifdef USE_LIBIDN
+/*
+ * Initialise use of IDNA library.
+ * It falls back to ASCII if $CHARSET isn't defined. This doesn't work for
+ * idna_to_ascii_lz().
+ */
+static void idna_init (void)
+{
+#ifdef WIN32
+ char buf[60];
+ UINT cp = GetACP();
+
+ if (!getenv("CHARSET") && cp > 0) {
+ snprintf(buf, sizeof(buf), "CHARSET=cp%u", cp);
+ putenv(buf);
+ }
+#else
+ /* to do? */
+#endif
+}
+#endif /* USE_LIBIDN */
/* true globals -- for curl_global_init() and curl_global_cleanup() */
static unsigned int initialized = 0;
static long init_flags = 0;
+/*
+ * If a memory-using function (like curl_getenv) is used before
+ * curl_global_init() is called, we need to have these pointers set already.
+ */
+curl_malloc_callback Curl_cmalloc = (curl_malloc_callback)malloc;
+curl_free_callback Curl_cfree = (curl_free_callback)free;
+curl_realloc_callback Curl_crealloc = (curl_realloc_callback)realloc;
+curl_strdup_callback Curl_cstrdup = (curl_strdup_callback)strdup;
+curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc;
+
/**
- * Globally initializes cURL given a bitwise set of
- * the different features to initialize.
+ * curl_global_init() globally initializes cURL given a bitwise set of the
+ * different features of what to initialize.
*/
CURLcode curl_global_init(long flags)
{
if (initialized)
return CURLE_OK;
+ /* Setup the default memory functions here (again) */
+ Curl_cmalloc = (curl_malloc_callback)malloc;
+ Curl_cfree = (curl_free_callback)free;
+ Curl_crealloc = (curl_realloc_callback)realloc;
+ Curl_cstrdup = (curl_strdup_callback)strdup;
+ Curl_ccalloc = (curl_calloc_callback)calloc;
+
if (flags & CURL_GLOBAL_SSL)
Curl_SSL_init();
@@ -148,15 +196,55 @@ CURLcode curl_global_init(long flags)
if (win32_init() != CURLE_OK)
return CURLE_FAILED_INIT;
+#ifdef _AMIGASF
+ if(!amiga_init())
+ return CURLE_FAILED_INIT;
+#endif
+
+#ifdef USE_LIBIDN
+ idna_init();
+#endif
+
initialized = 1;
init_flags = flags;
-
+
return CURLE_OK;
}
+/*
+ * curl_global_init_mem() globally initializes cURL and also registers the
+ * user provided callback routines.
+ */
+CURLcode curl_global_init_mem(long flags, curl_malloc_callback m,
+ curl_free_callback f, curl_realloc_callback r,
+ curl_strdup_callback s, curl_calloc_callback c)
+{
+ CURLcode code = CURLE_OK;
+
+ /* Invalid input, return immediately */
+ if (!m || !f || !r || !s || !c)
+ return CURLE_FAILED_INIT;
+
+ /* Already initialized, don't do it again */
+ if ( initialized )
+ return CURLE_OK;
+
+ /* Call the actual init function first */
+ code = curl_global_init(flags);
+ if (code == CURLE_OK) {
+ Curl_cmalloc = m;
+ Curl_cfree = f;
+ Curl_cstrdup = s;
+ Curl_crealloc = r;
+ Curl_ccalloc = c;
+ }
+
+ return code;
+}
+
/**
- * Globally cleanup cURL, uses the value of "init_flags" to determine
- * what needs to be cleaned up and what doesn't
+ * curl_global_cleanup() globally cleanups cURL, uses the value of
+ * "init_flags" to determine what needs to be cleaned up and what doesn't.
*/
void curl_global_cleanup(void)
{
@@ -171,18 +259,30 @@ void curl_global_cleanup(void)
if (init_flags & CURL_GLOBAL_WIN32)
win32_cleanup();
+#ifdef _AMIGASF
+ amiga_cleanup();
+#endif
+
initialized = 0;
init_flags = 0;
}
+/*
+ * curl_easy_init() is the external interface to alloc, setup and init an
+ * easy handle that is returned. If anything goes wrong, NULL is returned.
+ */
CURL *curl_easy_init(void)
{
CURLcode res;
struct SessionHandle *data;
/* Make sure we inited the global SSL stuff */
- if (!initialized)
- curl_global_init(CURL_GLOBAL_DEFAULT);
+ if (!initialized) {
+ res = curl_global_init(CURL_GLOBAL_DEFAULT);
+ if(res)
+ /* something in the global init failed, return nothing */
+ return NULL;
+ }
/* We use curl_open() with undefined URL so far */
res = Curl_open(&data);
@@ -192,6 +292,10 @@ CURL *curl_easy_init(void)
return data;
}
+/*
+ * curl_easy_setopt() is the external interface for setting options on an
+ * easy handle.
+ */
typedef int (*func_T)(void);
CURLcode curl_easy_setopt(CURL *curl, CURLoption tag, ...)
{
@@ -199,7 +303,12 @@ CURLcode curl_easy_setopt(CURL *curl, CURLoption tag, ...)
func_T param_func = (func_T)0;
long param_long = 0;
void *param_obj = NULL;
+ curl_off_t param_offset = 0;
struct SessionHandle *data = curl;
+ CURLcode ret=CURLE_FAILED_INIT;
+
+ if(!curl)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
va_start(arg, tag);
@@ -213,49 +322,86 @@ CURLcode curl_easy_setopt(CURL *curl, CURLoption tag, ...)
if(tag < CURLOPTTYPE_OBJECTPOINT) {
/* This is a LONG type */
param_long = va_arg(arg, long);
- Curl_setopt(data, tag, param_long);
+ ret = Curl_setopt(data, tag, param_long);
}
else if(tag < CURLOPTTYPE_FUNCTIONPOINT) {
/* This is a object pointer type */
param_obj = va_arg(arg, void *);
- Curl_setopt(data, tag, param_obj);
+ ret = Curl_setopt(data, tag, param_obj);
}
- else {
+ else if(tag < CURLOPTTYPE_OFF_T) {
+ /* This is a function pointer type */
param_func = va_arg(arg, func_T );
- Curl_setopt(data, tag, param_func);
+ ret = Curl_setopt(data, tag, param_func);
+ }
+ else {
+ /* This is a curl_off_t type */
+ param_offset = va_arg(arg, curl_off_t);
+ ret = Curl_setopt(data, tag, param_offset);
}
va_end(arg);
- return CURLE_OK;
+ return ret;
}
+/*
+ * curl_easy_perform() is the external interface that performs a transfer
+ * previously setup.
+ */
CURLcode curl_easy_perform(CURL *curl)
{
struct SessionHandle *data = (struct SessionHandle *)curl;
- if (Curl_global_host_cache_use(data) && data->hostcache != Curl_global_host_cache_get()) {
- if (data->hostcache) {
- Curl_hash_destroy(data->hostcache);
+ if(!data)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
+ if ( ! (data->share && data->share->hostcache) ) {
+
+ if (Curl_global_host_cache_use(data) &&
+ data->hostcache != Curl_global_host_cache_get()) {
+ if (data->hostcache)
+ Curl_hash_destroy(data->hostcache);
+ data->hostcache = Curl_global_host_cache_get();
+ }
+
+ if (!data->hostcache) {
+ data->hostcache = Curl_mk_dnscache();
+
+ if(!data->hostcache)
+ /* While we possibly could survive and do good without a host cache,
+ the fact that creating it failed indicates that things are truly
+ screwed up and we should bail out! */
+ return CURLE_OUT_OF_MEMORY;
}
- data->hostcache = Curl_global_host_cache_get();
- }
- if (!data->hostcache) {
- data->hostcache = Curl_hash_alloc(7, Curl_freednsinfo);
}
-
+
return Curl_perform(data);
}
+/*
+ * curl_easy_cleanup() is the external interface to cleaning/freeing the given
+ * easy handle.
+ */
void curl_easy_cleanup(CURL *curl)
{
struct SessionHandle *data = (struct SessionHandle *)curl;
- if (!Curl_global_host_cache_use(data)) {
- Curl_hash_destroy(data->hostcache);
+
+ if(!data)
+ return;
+
+ if ( ! (data->share && data->share->hostcache) ) {
+ if ( !Curl_global_host_cache_use(data)) {
+ Curl_hash_destroy(data->hostcache);
+ }
}
Curl_close(data);
}
+/*
+ * curl_easy_getinfo() is an external interface that allows an app to retrieve
+ * information from a performed transfer and similar.
+ */
CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...)
{
va_list arg;
@@ -268,76 +414,170 @@ CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...)
return Curl_getinfo(data, info, paramp);
}
+/*
+ * curl_easy_duphandle() is an external interface to allow duplication of a
+ * given input easy handle. The returned handle will be a new working handle
+ * with all options set exactly as the input source handle.
+ */
CURL *curl_easy_duphandle(CURL *incurl)
{
+ bool fail = TRUE;
struct SessionHandle *data=(struct SessionHandle *)incurl;
struct SessionHandle *outcurl = (struct SessionHandle *)
- malloc(sizeof(struct SessionHandle));
+ calloc(sizeof(struct SessionHandle), 1);
if(NULL == outcurl)
return NULL; /* failure */
- /* start with clearing the entire new struct */
- memset(outcurl, 0, sizeof(struct SessionHandle));
+ do {
- /*
- * We setup a few buffers we need. We should probably make them
- * get setup on-demand in the code, as that would probably decrease
- * the likeliness of us forgetting to init a buffer here in the future.
- */
- outcurl->state.headerbuff=(char*)malloc(HEADERSIZE);
- if(!outcurl->state.headerbuff) {
- free(outcurl); /* free the memory again */
- return NULL;
- }
- outcurl->state.headersize=HEADERSIZE;
+ /*
+ * We setup a few buffers we need. We should probably make them
+ * get setup on-demand in the code, as that would probably decrease
+ * the likeliness of us forgetting to init a buffer here in the future.
+ */
+ outcurl->state.headerbuff=(char*)malloc(HEADERSIZE);
+ if(!outcurl->state.headerbuff) {
+ break;
+ }
+ outcurl->state.headersize=HEADERSIZE;
- /* copy all userdefined values */
- outcurl->set = data->set;
- outcurl->state.numconnects = data->state.numconnects;
- outcurl->state.connects = (struct connectdata **)
+ /* copy all userdefined values */
+ outcurl->set = data->set;
+ outcurl->state.numconnects = data->state.numconnects;
+ outcurl->state.connects = (struct connectdata **)
malloc(sizeof(struct connectdata *) * outcurl->state.numconnects);
- if(!outcurl->state.connects) {
- free(outcurl->state.headerbuff);
- free(outcurl);
- return NULL;
- }
- memset(outcurl->state.connects, 0,
- sizeof(struct connectdata *)*outcurl->state.numconnects);
-
- outcurl->progress.flags = data->progress.flags;
- outcurl->progress.callback = data->progress.callback;
-
- if(data->cookies)
- /* If cookies are enabled in the parent handle, we enable them
- in the clone as well! */
- outcurl->cookies = Curl_cookie_init(data->cookies->filename,
- outcurl->cookies,
- data->set.cookiesession);
-
- /* duplicate all values in 'change' */
- if(data->change.url) {
- outcurl->change.url = strdup(data->change.url);
- outcurl->change.url_alloc = TRUE;
- }
- if(data->change.proxy) {
- outcurl->change.proxy = strdup(data->change.proxy);
- outcurl->change.proxy_alloc = TRUE;
- }
- if(data->change.referer) {
- outcurl->change.referer = strdup(data->change.referer);
- outcurl->change.referer_alloc = TRUE;
+ if(!outcurl->state.connects) {
+ break;
+ }
+
+ memset(outcurl->state.connects, 0,
+ sizeof(struct connectdata *)*outcurl->state.numconnects);
+
+ outcurl->progress.flags = data->progress.flags;
+ outcurl->progress.callback = data->progress.callback;
+
+#ifndef CURL_DISABLE_HTTP
+ if(data->cookies) {
+ /* If cookies are enabled in the parent handle, we enable them
+ in the clone as well! */
+ outcurl->cookies = Curl_cookie_init(data,
+ data->cookies->filename,
+ outcurl->cookies,
+ data->set.cookiesession);
+ if(!outcurl->cookies) {
+ break;
+ }
+ }
+#endif /* CURL_DISABLE_HTTP */
+
+ /* duplicate all values in 'change' */
+ if(data->change.url) {
+ outcurl->change.url = strdup(data->change.url);
+ if(!outcurl->change.url)
+ break;
+ outcurl->change.url_alloc = TRUE;
+ }
+ if(data->change.proxy) {
+ outcurl->change.proxy = strdup(data->change.proxy);
+ if(!outcurl->change.proxy)
+ break;
+ outcurl->change.proxy_alloc = TRUE;
+ }
+ if(data->change.referer) {
+ outcurl->change.referer = strdup(data->change.referer);
+ if(!outcurl->change.referer)
+ break;
+ outcurl->change.referer_alloc = TRUE;
+ }
+
+#ifdef USE_ARES
+ /* If we use ares, we setup a new ares channel for the new handle */
+ if(ARES_SUCCESS != ares_init(&outcurl->state.areschannel))
+ break;
+#endif
+
+ fail = FALSE; /* we reach this point and thus we are OK */
+
+ } while(0);
+
+ if(fail) {
+ if(outcurl) {
+ if(outcurl->state.connects)
+ free(outcurl->state.connects);
+ if(outcurl->state.headerbuff)
+ free(outcurl->state.headerbuff);
+ if(outcurl->change.proxy)
+ free(outcurl->change.proxy);
+ if(outcurl->change.url)
+ free(outcurl->change.url);
+ if(outcurl->change.referer)
+ free(outcurl->change.referer);
+ free(outcurl); /* free the memory again */
+ outcurl = NULL;
+ }
}
return outcurl;
}
/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
+ * curl_easy_reset() is an external interface that allows an app to re-
+ * initialize a session handle to the default values.
*/
+void curl_easy_reset(CURL *curl)
+{
+ struct SessionHandle *data = (struct SessionHandle *)curl;
+
+ /* zero out UserDefined data: */
+ memset(&data->set, 0, sizeof(struct UserDefined));
+
+ /* zero out Progress data: */
+ memset(&data->progress, 0, sizeof(struct Progress));
+
+ /* The remainder of these calls have been taken from Curl_open() */
+
+ data->set.out = stdout; /* default output to stdout */
+ data->set.in = stdin; /* default input from stdin */
+ data->set.err = stderr; /* default stderr to stderr */
+
+ /* use fwrite as default function to store output */
+ data->set.fwrite = (curl_write_callback)fwrite;
+
+ /* use fread as default function to read input */
+ data->set.fread = (curl_read_callback)fread;
+
+ data->set.infilesize = -1; /* we don't know any size */
+
+ data->state.current_speed = -1; /* init to negative == impossible */
+
+ data->set.httpreq = HTTPREQ_GET; /* Default HTTP request */
+ data->set.ftp_use_epsv = TRUE; /* FTP defaults to EPSV operations */
+ data->set.ftp_use_eprt = TRUE; /* FTP defaults to EPRT operations */
+
+ data->set.dns_cache_timeout = 60; /* Timeout every 60 seconds by default */
+
+ /* make libcurl quiet by default: */
+ data->set.hide_progress = TRUE; /* CURLOPT_NOPROGRESS changes these */
+
+ /* Set the default size of the SSL session ID cache */
+ data->set.ssl.numsessions = 5;
+
+ data->set.proxyport = 1080;
+ data->set.proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */
+ data->set.httpauth = CURLAUTH_BASIC; /* defaults to basic */
+ data->set.proxyauth = CURLAUTH_BASIC; /* defaults to basic */
+
+ /*
+ * libcurl 7.10 introduced SSL verification *by default*! This needs to be
+ * switched off unless wanted.
+ */
+ data->set.ssl.verifypeer = TRUE;
+ data->set.ssl.verifyhost = 2;
+#ifdef CURL_CA_BUNDLE
+ /* This is our prefered CA cert bundle since install time */
+ data->set.ssl.CAfile = (char *)CURL_CA_BUNDLE;
+#endif
+}
diff --git a/Source/CTest/Curl/escape.c b/Source/CTest/Curl/escape.c
index fbe4b2c..4466d4c 100644
--- a/Source/CTest/Curl/escape.c
+++ b/Source/CTest/Curl/escape.c
@@ -1,16 +1,16 @@
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -31,20 +31,27 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include "memory.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
/* The last #include file should be: */
-#ifdef MALLOCDEBUG
#include "memdebug.h"
-#endif
-char *curl_escape(const char *string, int length)
+char *curl_escape(const char *string, int inlength)
{
- int alloc = (length?length:(int)strlen(string))+1;
- char *ns = malloc(alloc);
+ size_t alloc = (inlength?(size_t)inlength:strlen(string))+1;
+ char *ns;
char *testing_ptr = NULL;
unsigned char in;
- int newlen = alloc;
- int index=0;
+ size_t newlen = alloc;
+ int strindex=0;
+ size_t length;
+
+ ns = malloc(alloc);
+ if(!ns)
+ return NULL;
length = alloc-1;
while(length--) {
@@ -65,59 +72,64 @@ char *curl_escape(const char *string, int length)
ns = testing_ptr;
}
}
- sprintf(&ns[index], "%%%02X", in);
+ snprintf(&ns[strindex], 4, "%%%02X", in);
- index+=3;
+ strindex+=3;
}
else {
/* just copy this */
- ns[index++]=in;
+ ns[strindex++]=in;
}
string++;
}
- ns[index]=0; /* terminate it */
+ ns[strindex]=0; /* terminate it */
return ns;
}
+#define ishex(in) ((in >= 'a' && in <= 'f') || \
+ (in >= 'A' && in <= 'F') || \
+ (in >= '0' && in <= '9'))
+
char *curl_unescape(const char *string, int length)
{
int alloc = (length?length:(int)strlen(string))+1;
char *ns = malloc(alloc);
unsigned char in;
- int index=0;
- unsigned int hex;
-
- if( !ns ) {
+ int strindex=0;
+ long hex;
+
+ if( !ns )
return NULL;
- }
-
+
while(--alloc > 0) {
in = *string;
- if('%' == in) {
- /* encoded part */
- if(sscanf(string+1, "%02X", &hex)) {
- in = (unsigned char)hex;
- string+=2;
- alloc-=2;
- }
+ if(('%' == in) && ishex(string[1]) && ishex(string[2])) {
+ /* this is two hexadecimal digits following a '%' */
+ char hexstr[3];
+ char *ptr;
+ hexstr[0] = string[1];
+ hexstr[1] = string[2];
+ hexstr[2] = 0;
+
+ hex = strtol(hexstr, &ptr, 16);
+
+ in = (unsigned char)hex; /* this long is never bigger than 255 anyway */
+ string+=2;
+ alloc-=2;
}
-
- ns[index++] = in;
+
+ ns[strindex++] = in;
string++;
}
- ns[index]=0; /* terminate it */
+ ns[strindex]=0; /* terminate it */
return ns;
}
+/* For operating systems/environments that use different malloc/free
+ ssystems for the app and for this library, we provide a free that uses
+ the library's memory system */
void curl_free(void *p)
{
- free(p);
+ if(p)
+ free(p);
}
-
-/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
- */
diff --git a/Source/CTest/Curl/escape.h b/Source/CTest/Curl/escape.h
index 5808207..4d29236 100644
--- a/Source/CTest/Curl/escape.h
+++ b/Source/CTest/Curl/escape.h
@@ -8,7 +8,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
diff --git a/Source/CTest/Curl/file.c b/Source/CTest/Curl/file.c
index 3dedbbc..7cfbf6f 100644
--- a/Source/CTest/Curl/file.c
+++ b/Source/CTest/Curl/file.c
@@ -1,16 +1,16 @@
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -36,7 +36,6 @@
#include <errno.h>
#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
-#include <winsock.h>
#include <time.h>
#include <io.h>
#include <fcntl.h>
@@ -48,7 +47,6 @@
#include <netinet/in.h>
#endif
#include <sys/time.h>
-#include <sys/resource.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
@@ -75,7 +73,6 @@
#include <fcntl.h>
#endif
-
#endif
#include "urldata.h"
@@ -83,46 +80,85 @@
#include "progress.h"
#include "sendf.h"
#include "escape.h"
+#include "file.h"
+#include "speedcheck.h"
+#include "getinfo.h"
+#include "transfer.h"
+#include "url.h"
+#include "memory.h"
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
/* The last #include file should be: */
-#ifdef MALLOCDEBUG
#include "memdebug.h"
-#endif
-/* Emulate a connect-then-transfer protocol. We connect to the file here */
+/*
+ * Curl_file_connect() gets called from Curl_protocol_connect() to allow us to
+ * do protocol-specific actions at connect-time. We emulate a
+ * connect-then-transfer protocol and "connect" to the file here
+ */
CURLcode Curl_file_connect(struct connectdata *conn)
{
- char *actual_path = curl_unescape(conn->path, 0);
- struct FILE *file;
+ char *real_path = curl_unescape(conn->path, 0);
+ struct FILEPROTO *file;
int fd;
#if defined(WIN32) || defined(__EMX__)
int i;
+ char *actual_path;
#endif
- file = (struct FILE *)malloc(sizeof(struct FILE));
- if(!file)
+ if(!real_path)
+ return CURLE_OUT_OF_MEMORY;
+
+ file = (struct FILEPROTO *)calloc(sizeof(struct FILEPROTO), 1);
+ if(!file) {
+ free(real_path);
return CURLE_OUT_OF_MEMORY;
+ }
- memset(file, 0, sizeof(struct FILE));
conn->proto.file = file;
#if defined(WIN32) || defined(__EMX__)
+ /* If the first character is a slash, and there's
+ something that looks like a drive at the beginning of
+ the path, skip the slash. If we remove the initial
+ slash in all cases, paths without drive letters end up
+ relative to the current directory which isn't how
+ browsers work.
+
+ Some browsers accept | instead of : as the drive letter
+ separator, so we do too.
+
+ On other platforms, we need the slash to indicate an
+ absolute pathname. On Windows, absolute paths start
+ with a drive letter.
+ */
+ actual_path = real_path;
+ if ((actual_path[0] == '/') &&
+ actual_path[1] &&
+ (actual_path[2] == ':' || actual_path[2] == '|'))
+ {
+ actual_path[2] = ':';
+ actual_path++;
+ }
+
/* change path separators from '/' to '\\' for Windows and OS/2 */
for (i=0; actual_path[i] != '\0'; ++i)
if (actual_path[i] == '/')
actual_path[i] = '\\';
fd = open(actual_path, O_RDONLY | O_BINARY); /* no CR/LF translation! */
+ file->path = actual_path;
#else
- fd = open(actual_path, O_RDONLY);
+ fd = open(real_path, O_RDONLY);
+ file->path = real_path;
#endif
- free(actual_path);
+ file->freepath = real_path; /* free this when done */
- if(fd == -1) {
+ if(!conn->data->set.upload && (fd == -1)) {
failf(conn->data, "Couldn't open file %s", conn->path);
+ Curl_file_done(conn, CURLE_FILE_COULDNT_READ_FILE);
return CURLE_FILE_COULDNT_READ_FILE;
}
file->fd = fd;
@@ -130,35 +166,174 @@ CURLcode Curl_file_connect(struct connectdata *conn)
return CURLE_OK;
}
-/* This is the do-phase, separated from the connect-phase above */
+#if defined(WIN32) && (SIZEOF_CURL_OFF_T > 4)
+#define lseek(x,y,z) _lseeki64(x, y, z)
+#endif
+
+CURLcode Curl_file_done(struct connectdata *conn,
+ CURLcode status)
+{
+ struct FILEPROTO *file = conn->proto.file;
+ (void)status; /* not used */
+ Curl_safefree(file->freepath);
+
+ return CURLE_OK;
+}
+
+#if defined(WIN32) || defined(__EMX__)
+#define DIRSEP '\\'
+#else
+#define DIRSEP '/'
+#endif
+
+static CURLcode file_upload(struct connectdata *conn)
+{
+ struct FILEPROTO *file = conn->proto.file;
+ char *dir = strchr(file->path, DIRSEP);
+ FILE *fp;
+ CURLcode res=CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ char *buf = data->state.buffer;
+ size_t nread;
+ size_t nwrite;
+ curl_off_t bytecount = 0;
+ struct timeval now = Curl_tvnow();
+
+ /*
+ * Since FILE: doesn't do the full init, we need to provide some extra
+ * assignments here.
+ */
+ conn->fread = data->set.fread;
+ conn->fread_in = data->set.in;
+ conn->upload_fromhere = buf;
+
+ if(!dir)
+ return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */
+
+ if(!dir[1])
+ return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */
+
+ fp = fopen(file->path, "wb");
+ if(!fp) {
+ failf(data, "Can't open %s for writing", file->path);
+ return CURLE_WRITE_ERROR;
+ }
+
+ if(-1 != data->set.infilesize)
+ /* known size of data to "upload" */
+ Curl_pgrsSetUploadSize(data, data->set.infilesize);
+
+ while (res == CURLE_OK) {
+ int readcount;
+ res = Curl_fillreadbuffer(conn, BUFSIZE, &readcount);
+ if(res)
+ return res;
+
+ nread = (size_t)readcount;
+
+ if (nread <= 0)
+ break;
+
+ /* write the data to the target */
+ nwrite = fwrite(buf, 1, nread, fp);
+ if(nwrite != nread) {
+ res = CURLE_SEND_ERROR;
+ break;
+ }
+
+ bytecount += nread;
+
+ Curl_pgrsSetUploadCounter(data, bytecount);
+
+ if(Curl_pgrsUpdate(conn))
+ res = CURLE_ABORTED_BY_CALLBACK;
+ else
+ res = Curl_speedcheck(data, now);
+ }
+ if(!res && Curl_pgrsUpdate(conn))
+ res = CURLE_ABORTED_BY_CALLBACK;
+
+ fclose(fp);
+ return res;
+}
+
+/*
+ * Curl_file() is the protocol-specific function for the do-phase, separated
+ * from the connect-phase above. Other protocols merely setup the transfer in
+ * the do-phase, to have it done in the main transfer loop but since some
+ * platforms we support don't allow select()ing etc on file handles (as
+ * opposed to sockets) we instead perform the whole do-operation in this
+ * function.
+ */
CURLcode Curl_file(struct connectdata *conn)
{
- /* This implementation ignores the host name in conformance with
+ /* This implementation ignores the host name in conformance with
RFC 1738. Only local files (reachable via the standard file system)
are supported. This means that files on remotely mounted directories
(via NFS, Samba, NT sharing) can be accessed through a file:// URL
*/
CURLcode res = CURLE_OK;
struct stat statbuf;
- double expected_size=-1;
+ curl_off_t expected_size=0;
+ bool fstated=FALSE;
ssize_t nread;
struct SessionHandle *data = conn->data;
char *buf = data->state.buffer;
- int bytecount = 0;
- struct timeval start = Curl_tvnow();
- struct timeval now = start;
+ curl_off_t bytecount = 0;
int fd;
+ struct timeval now = Curl_tvnow();
- (void)now;
+ Curl_readwrite_init(conn);
+ Curl_initinfo(data);
+ Curl_pgrsStartNow(data);
+
+ if(data->set.upload)
+ return file_upload(conn);
/* get the fd from the connection phase */
fd = conn->proto.file->fd;
-/*VMS?? -- This only works reliable for STREAMLF files */
+ /* VMS: This only works reliable for STREAMLF files */
if( -1 != fstat(fd, &statbuf)) {
/* we could stat it, then read out the size */
- expected_size = (double)statbuf.st_size;
+ expected_size = statbuf.st_size;
+ fstated = TRUE;
+ }
+
+ /* If we have selected NOBODY and HEADER, it means that we only want file
+ information. Which for FILE can't be much more than the file size and
+ date. */
+ if(conn->bits.no_body && data->set.include_header && fstated) {
+ CURLcode result;
+ snprintf(buf, sizeof(data->state.buffer),
+ "Content-Length: %" FORMAT_OFF_T "\r\n", expected_size);
+ result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
+ if(result)
+ return result;
+
+ result = Curl_client_write(data, CLIENTWRITE_BOTH,
+ (char *)"Accept-ranges: bytes\r\n", 0);
+ if(result)
+ return result;
+
+#ifdef HAVE_STRFTIME
+ if(fstated) {
+ struct tm *tm;
+ time_t clock = (time_t)statbuf.st_mtime;
+#ifdef HAVE_GMTIME_R
+ struct tm buffer;
+ tm = (struct tm *)gmtime_r(&clock, &buffer);
+#else
+ tm = gmtime(&clock);
+#endif
+ /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
+ strftime(buf, BUFSIZE-1, "Last-Modified: %a, %d %b %Y %H:%M:%S GMT\r\n",
+ tm);
+ result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
+ }
+#endif
+ return result;
}
/* Added by Dolbneff A.V & Spiridonoff A.V */
@@ -168,20 +343,21 @@ CURLcode Curl_file(struct connectdata *conn)
/* Is this error code suitable in such situation? */
return CURLE_FTP_BAD_DOWNLOAD_RESUME;
- if (expected_size == 0)
+ if (fstated && (expected_size == 0))
return CURLE_OK;
/* The following is a shortcut implementation of file reading
this is both more efficient than the former call to download() and
it avoids problems with select() and recv() on file descriptors
in Winsock */
- if(expected_size != -1)
+ if(fstated)
Curl_pgrsSetDownloadSize(data, expected_size);
if(conn->resume_from)
- /* Added by Dolbneff A.V & Spiridonoff A.V */
lseek(fd, conn->resume_from, SEEK_SET);
+ Curl_pgrsTime(data, TIMER_STARTTRANSFER);
+
while (res == CURLE_OK) {
nread = read(fd, buf, BUFSIZE-1);
@@ -192,20 +368,18 @@ CURLcode Curl_file(struct connectdata *conn)
break;
bytecount += nread;
- /* NOTE: The following call to fwrite does CR/LF translation on
- Windows systems if the target is stdout. Use -O or -o parameters
- to prevent CR/LF translation (this then goes to a binary mode
- file descriptor). */
res = Curl_client_write(data, CLIENTWRITE_BODY, buf, nread);
if(res)
return res;
- now = Curl_tvnow();
+ Curl_pgrsSetDownloadCounter(data, bytecount);
+
if(Curl_pgrsUpdate(conn))
res = CURLE_ABORTED_BY_CALLBACK;
+ else
+ res = Curl_speedcheck(data, now);
}
- now = Curl_tvnow();
if(Curl_pgrsUpdate(conn))
res = CURLE_ABORTED_BY_CALLBACK;
@@ -213,12 +387,4 @@ CURLcode Curl_file(struct connectdata *conn)
return res;
}
-
-/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
- */
#endif
diff --git a/Source/CTest/Curl/file.h b/Source/CTest/Curl/file.h
index b11dcb7..689b8ae 100644
--- a/Source/CTest/Curl/file.h
+++ b/Source/CTest/Curl/file.h
@@ -8,7 +8,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -24,7 +24,8 @@
* $Id$
***************************************************************************/
#ifndef CURL_DISABLE_FILE
-CURLcode Curl_file(struct connectdata *conn);
-CURLcode Curl_file_connect(struct connectdata *conn);
+CURLcode Curl_file(struct connectdata *);
+CURLcode Curl_file_done(struct connectdata *, CURLcode);
+CURLcode Curl_file_connect(struct connectdata *);
#endif
#endif
diff --git a/Source/CTest/Curl/formdata.c b/Source/CTest/Curl/formdata.c
index e99b99f..4fd83c0 100644
--- a/Source/CTest/Curl/formdata.c
+++ b/Source/CTest/Curl/formdata.c
@@ -1,16 +1,16 @@
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -97,17 +97,13 @@ Content-Type: text/plain
Content-Disposition: form-data; name="FILECONTENT"
...
- For the old FormParse used by curl_formparse use:
-
- gcc -DHAVE_CONFIG_H -I../ -g -D_OLD_FORM_DEBUG -o formdata -I../include formdata.c strequal.c
-
- run the 'formdata' executable and make sure the output is ok!
-
- try './formdata "name=Daniel" "poo=noo" "foo=bar"' and similarly
-
*/
#include "setup.h"
+#include <curl/curl.h>
+
+/* Length of the random boundary string. */
+#define BOUNDARY_LENGTH 40
#ifndef CURL_DISABLE_HTTP
@@ -115,282 +111,29 @@ Content-Disposition: form-data; name="FILECONTENT"
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
-
#include <time.h>
-
-#include <curl/curl.h>
+#include <sys/stat.h>
#include "formdata.h"
-
#include "strequal.h"
+#include "memory.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
/* The last #include file should be: */
-#ifdef MALLOCDEBUG
#include "memdebug.h"
-#endif
-
-/* Length of the random boundary string. The risk of this being used
- in binary data is very close to zero, 64^32 makes
- 6277101735386680763835789423207666416102355444464034512896
- combinations... */
-#define BOUNDARY_LENGTH 32
/* What kind of Content-Type to use on un-specified files with unrecognized
extensions. */
-#define HTTPPOST_CONTENTTYPE_DEFAULT "text/plain"
-
-/* This is a silly duplicate of the function in main.c to enable this source
- to compile stand-alone for better debugging */
-static void GetStr(char **string,
- const char *value)
-{
- if(*string)
- free(*string);
- *string = strdup(value);
-}
-
-/***************************************************************************
- *
- * FormParse()
- *
- * Reads a 'name=value' paramter and builds the appropriate linked list.
- *
- * Specify files to upload with 'name=@filename'. Supports specified
- * given Content-Type of the files. Such as ';type=<content-type>'.
- *
- * You may specify more than one file for a single name (field). Specify
- * multiple files by writing it like:
- *
- * 'name=@filename,filename2,filename3'
- *
- * If you want content-types specified for each too, write them like:
- *
- * 'name=@filename;type=image/gif,filename2,filename3'
- *
- ***************************************************************************/
+#define HTTPPOST_CONTENTTYPE_DEFAULT "application/octet-stream"
#define FORM_FILE_SEPARATOR ','
#define FORM_TYPE_SEPARATOR ';'
-static
-int FormParse(char *input,
- struct curl_httppost **httppost,
- struct curl_httppost **last_post)
-{
- /* nextarg MUST be a string in the format 'name=contents' and we'll
- build a linked list with the info */
- char name[256];
- char *contents;
- char major[128];
- char minor[128];
- long flags = 0;
- char *contp;
- const char *type = NULL;
- char *prevtype = NULL;
- char *sep;
- char *sep2;
- struct curl_httppost *post;
- struct curl_httppost *subpost; /* a sub-node */
- unsigned int i;
-
- /* Preallocate contents to the length of input to make sure we don't
- overwrite anything. */
- contents = malloc(strlen(input));
- contents[0] = '\000';
-
- if(1 <= sscanf(input, "%255[^=]=%[^\n]", name, contents)) {
- /* the input was using the correct format */
- contp = contents;
-
- if('@' == contp[0]) {
- /* we use the @-letter to indicate file name(s) */
-
- flags = HTTPPOST_FILENAME;
- contp++;
-
- post=NULL;
-
- do {
- /* since this was a file, it may have a content-type specifier
- at the end too */
-
- sep=strchr(contp, FORM_TYPE_SEPARATOR);
- sep2=strchr(contp, FORM_FILE_SEPARATOR);
-
- /* pick the closest */
- if(sep2 && (sep2 < sep)) {
- sep = sep2;
-
- /* no type was specified! */
- }
- if(sep) {
-
- /* if we got here on a comma, don't do much */
- if(FORM_FILE_SEPARATOR != *sep)
- type = strstr(sep+1, "type=");
- else
- type=NULL;
-
- *sep=0; /* terminate file name at separator */
-
- if(type) {
- type += strlen("type=");
-
- if(2 != sscanf(type, "%127[^/]/%127[^,\n]",
- major, minor)) {
- free(contents);
- return 2; /* illegal content-type syntax! */
- }
- /* now point beyond the content-type specifier */
- sep = (char *)type + strlen(major)+strlen(minor)+1;
-
- /* find the following comma */
- sep=strchr(sep, FORM_FILE_SEPARATOR);
- }
- }
- else {
- type=NULL;
- sep=strchr(contp, FORM_FILE_SEPARATOR);
- }
- if(sep) {
- /* the next file name starts here */
- *sep =0;
- sep++;
- }
- if(!type) {
- /*
- * No 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 struct ContentType ctts[]={
- {".gif", "image/gif"},
- {".jpg", "image/jpeg"},
- {".jpeg", "image/jpeg"},
- {".txt", "text/plain"},
- {".html", "text/plain"}
- };
-
- if(prevtype)
- /* default to the previously set/used! */
- type = prevtype;
- else
- /* It seems RFC1867 defines no Content-Type to default to
- text/plain so we don't actually need to set this: */
- type = HTTPPOST_CONTENTTYPE_DEFAULT;
-
- for(i=0; i<sizeof(ctts)/sizeof(ctts[0]); i++) {
- if(strlen(contp) >= strlen(ctts[i].extension)) {
- if(strequal(contp +
- strlen(contp) - strlen(ctts[i].extension),
- ctts[i].extension)) {
- type = ctts[i].type;
- break;
- }
- }
- }
- /* we have a type by now */
- }
-
- if(NULL == post) {
- /* For the first file name, we allocate and initiate the main list
- node */
-
- post = (struct curl_httppost *)malloc(sizeof(struct curl_httppost));
- if(post) {
- memset(post, 0, sizeof(struct curl_httppost));
- GetStr(&post->name, name); /* get the name */
- GetStr(&post->contents, contp); /* get the contents */
- post->contentslength = 0;
- post->flags = flags;
- if(type) {
- GetStr(&post->contenttype, (char *)type); /* get type */
- prevtype=post->contenttype; /* point to the allocated string! */
- }
- /* make the previous point to this */
- if(*last_post)
- (*last_post)->next = post;
- else
- (*httppost) = post;
-
- (*last_post) = post;
- }
-
- }
- else {
- /* we add a file name to the previously allocated node, known as
- 'post' now */
- subpost =(struct curl_httppost *)
- malloc(sizeof(struct curl_httppost));
- if(subpost) {
- memset(subpost, 0, sizeof(struct curl_httppost));
- GetStr(&subpost->name, name); /* get the name */
- GetStr(&subpost->contents, contp); /* get the contents */
- subpost->contentslength = 0;
- subpost->flags = flags;
- if(type) {
- GetStr(&subpost->contenttype, (char *)type); /* get type */
- prevtype=subpost->contenttype; /* point to allocated string! */
- }
- /* now, point our 'more' to the original 'more' */
- subpost->more = post->more;
-
- /* then move the original 'more' to point to ourselves */
- post->more = subpost;
- }
- }
- contp = sep; /* move the contents pointer to after the separator */
- } while(sep && *sep); /* loop if there's another file name */
- }
- else {
- post = (struct curl_httppost *)malloc(sizeof(struct curl_httppost));
- if(post) {
- memset(post, 0, sizeof(struct curl_httppost));
- GetStr(&post->name, name); /* get the name */
- if( contp[0]=='<' ) {
- GetStr(&post->contents, contp+1); /* get the contents */
- post->contentslength = 0;
- post->flags = HTTPPOST_READFILE;
- }
- else {
- GetStr(&post->contents, contp); /* get the contents */
- post->contentslength = 0;
- post->flags = 0;
- }
-
- /* make the previous point to this */
- if(*last_post)
- (*last_post)->next = post;
- else
- (*httppost) = post;
-
- (*last_post) = post;
- }
-
- }
-
- }
- else {
- free(contents);
- return 1;
- }
- free(contents);
- return 0;
-}
-
-int curl_formparse(char *input,
- struct curl_httppost **httppost,
- struct curl_httppost **last_post)
-{
- return FormParse(input, httppost, last_post);
-}
-
/***************************************************************************
*
* AddHttpPost()
- *
+ *
* Adds a HttpPost structure to the list, if parent_post is given becomes
* a subpost of parent_post instead of a direct list element.
*
@@ -398,12 +141,9 @@ int curl_formparse(char *input,
*
***************************************************************************/
static struct curl_httppost *
-AddHttpPost(char * name, long namelength,
- char * value, long contentslength,
-
- /* CMC: Added support for buffer uploads */
- char * buffer, long bufferlength,
-
+AddHttpPost(char * name, size_t namelength,
+ char * value, size_t contentslength,
+ char * buffer, size_t bufferlength,
char *contenttype,
long flags,
struct curl_slist* contentHeader,
@@ -413,18 +153,14 @@ AddHttpPost(char * name, long namelength,
struct curl_httppost **last_post)
{
struct curl_httppost *post;
- post = (struct curl_httppost *)malloc(sizeof(struct curl_httppost));
+ post = (struct curl_httppost *)calloc(sizeof(struct curl_httppost), 1);
if(post) {
- memset(post, 0, sizeof(struct curl_httppost));
post->name = name;
- post->namelength = name?(namelength?namelength:(long)strlen(name)):0;
+ post->namelength = (long)(name?(namelength?namelength:strlen(name)):0);
post->contents = value;
- post->contentslength = contentslength;
-
- /* CMC: Added support for buffer uploads */
+ post->contentslength = (long)contentslength;
post->buffer = buffer;
- post->bufferlength = bufferlength;
-
+ post->bufferlength = (long)bufferlength;
post->contenttype = contenttype;
post->contentheader = contentHeader;
post->showfilename = showfilename;
@@ -432,13 +168,13 @@ AddHttpPost(char * name, long namelength,
}
else
return NULL;
-
+
if (parent_post) {
/* now, point our 'more' to the original 'more' */
post->more = parent_post->more;
-
+
/* then move the original 'more' to point to ourselves */
- parent_post->more = post;
+ parent_post->more = post;
}
else {
/* make the previous point to this */
@@ -446,8 +182,8 @@ AddHttpPost(char * name, long namelength,
(*last_post)->next = post;
else
(*httppost) = post;
-
- (*last_post) = post;
+
+ (*last_post) = post;
}
return post;
}
@@ -455,7 +191,7 @@ AddHttpPost(char * name, long namelength,
/***************************************************************************
*
* AddFormInfo()
- *
+ *
* Adds a FormInfo structure to the list presented by parent_form_info.
*
* Returns newly allocated FormInfo on success and NULL if malloc failed/
@@ -478,11 +214,11 @@ static FormInfo * AddFormInfo(char *value,
}
else
return NULL;
-
+
if (parent_form_info) {
/* now, point our 'more' to the original 'more' */
form_info->more = parent_form_info->more;
-
+
/* then move the original 'more' to point to ourselves */
parent_form_info->more = form_info;
}
@@ -495,7 +231,7 @@ static FormInfo * AddFormInfo(char *value,
/***************************************************************************
*
* ContentTypeForFilename()
- *
+ *
* Provides content type for filename if one of the known types (else
* (either the prevtype or the default is returned).
*
@@ -520,9 +256,9 @@ static const char * ContentTypeForFilename (const char *filename,
{".jpg", "image/jpeg"},
{".jpeg", "image/jpeg"},
{".txt", "text/plain"},
- {".html", "text/plain"}
+ {".html", "text/html"}
};
-
+
if(prevtype)
/* default to the previously set/used! */
contenttype = prevtype;
@@ -530,7 +266,7 @@ static const char * ContentTypeForFilename (const char *filename,
/* It seems RFC1867 defines no Content-Type to default to
text/plain so we don't actually need to set this: */
contenttype = HTTPPOST_CONTENTTYPE_DEFAULT;
-
+
for(i=0; i<sizeof(ctts)/sizeof(ctts[0]); i++) {
if(strlen(filename) >= strlen(ctts[i].extension)) {
if(strequal(filename +
@@ -538,7 +274,7 @@ static const char * ContentTypeForFilename (const char *filename,
ctts[i].extension)) {
contenttype = ctts[i].type;
break;
- }
+ }
}
}
/* we have a contenttype by now */
@@ -547,41 +283,45 @@ static const char * ContentTypeForFilename (const char *filename,
/***************************************************************************
*
- * AllocAndCopy()
- *
- * Copies the data currently available under *buffer using newly allocated
- * buffer (that becomes *buffer). Uses buffer_length if not null, else
- * uses strlen to determine the length of the buffer to be copied
+ * memdup()
+ *
+ * Copies the 'source' data to a newly allocated buffer buffer (that is
+ * returned). Uses buffer_length if not null, else uses strlen to determine
+ * the length of the buffer to be copied
*
- * Returns 0 on success and 1 if the malloc failed.
+ * Returns the new pointer or NULL on failure.
*
***************************************************************************/
-static int AllocAndCopy (char **buffer, int buffer_length)
+static char *memdup(const char *src, size_t buffer_length)
{
- const char *src = *buffer;
- int length, add = 0;
+ size_t length;
+ bool add = FALSE;
+ char *buffer;
+
if (buffer_length)
length = buffer_length;
else {
- length = (int)strlen(*buffer);
- add = 1;
+ length = strlen(src);
+ add = TRUE;
}
- *buffer = (char*)malloc(length+add);
- if (!*buffer)
- return 1;
- memcpy(*buffer, src, length);
+ buffer = (char*)malloc(length+add);
+ if (!buffer)
+ return NULL; /* fail */
+
+ memcpy(buffer, src, length);
+
/* if length unknown do null termination */
if (add)
- (*buffer)[length] = '\0';
- return 0;
+ buffer[length] = '\0';
+
+ return buffer;
}
/***************************************************************************
*
* FormAdd()
- *
- * Stores a 'name=value' formpost parameter and builds the appropriate
- * linked list.
+ *
+ * Stores a formpost parameter and builds the appropriate linked list.
*
* Has two principal functionalities: using files and byte arrays as
* post parts. Byte arrays are either copied or just the pointer is stored
@@ -631,7 +371,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
struct curl_httppost **last_post,
va_list params)
{
- FormInfo *first_form, *current_form, *form;
+ FormInfo *first_form, *current_form, *form = NULL;
CURLFORMcode return_value = CURL_FORMADD_OK;
const char *prevtype = NULL;
struct curl_httppost *post = NULL;
@@ -647,22 +387,16 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
/*
* We need to allocate the first struct to fill in.
*/
- first_form = (FormInfo *)malloc(sizeof(struct FormInfo));
- if(first_form) {
- memset(first_form, 0, sizeof(FormInfo));
- current_form = first_form;
- }
- else
+ first_form = (FormInfo *)calloc(sizeof(struct FormInfo), 1);
+ if(!first_form)
return CURL_FORMADD_MEMORY;
+ current_form = first_form;
+
/*
- * Loop through all the options set.
+ * Loop through all the options set. Break if we have an error to report.
*/
- while (1) {
-
- /* break if we have an error to report */
- if (return_value != CURL_FORMADD_OK)
- break;
+ while (return_value == CURL_FORMADD_OK) {
/* first see if we have more parts of the array param */
if ( array_state ) {
@@ -757,7 +491,12 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
array_value:va_arg(params, char *);
if (filename) {
current_form->value = strdup(filename);
- current_form->flags |= HTTPPOST_READFILE;
+ if(!current_form->value)
+ return_value = CURL_FORMADD_MEMORY;
+ else {
+ current_form->flags |= HTTPPOST_READFILE;
+ current_form->value_alloc = TRUE;
+ }
}
else
return_value = CURL_FORMADD_NULL;
@@ -784,16 +523,21 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
return_value = CURL_FORMADD_OPTION_TWICE;
}
else {
- if (filename)
+ if (filename) {
current_form->value = strdup(filename);
+ if(!current_form->value)
+ return_value = CURL_FORMADD_MEMORY;
+ else {
+ current_form->flags |= HTTPPOST_FILENAME;
+ current_form->value_alloc = TRUE;
+ }
+ }
else
return_value = CURL_FORMADD_NULL;
- current_form->flags |= HTTPPOST_FILENAME;
}
break;
}
- /* CMC: Added support for buffer uploads */
case CURLFORM_BUFFER:
{
char *filename = array_state?array_value:
@@ -813,16 +557,18 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
return_value = CURL_FORMADD_OPTION_TWICE;
}
else {
- if (filename)
+ if (filename) {
current_form->value = strdup(filename);
+ if(!current_form->value)
+ return_value = CURL_FORMADD_MEMORY;
+ }
else
return_value = CURL_FORMADD_NULL;
current_form->flags |= HTTPPOST_BUFFER;
}
break;
}
-
- /* CMC: Added support for buffer uploads */
+
case CURLFORM_BUFFERPTR:
current_form->flags |= HTTPPOST_PTRBUFFER;
if (current_form->buffer)
@@ -837,7 +583,6 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
}
break;
- /* CMC: Added support for buffer uploads */
case CURLFORM_BUFFERLENGTH:
if (current_form->bufferlength)
return_value = CURL_FORMADD_OPTION_TWICE;
@@ -865,8 +610,13 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
return_value = CURL_FORMADD_OPTION_TWICE;
}
else {
- if (contenttype)
+ if (contenttype) {
current_form->contenttype = strdup(contenttype);
+ if(!current_form->contenttype)
+ return_value = CURL_FORMADD_MEMORY;
+ else
+ current_form->contenttype_alloc = TRUE;
+ }
else
return_value = CURL_FORMADD_NULL;
}
@@ -876,20 +626,15 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
{
/* this "cast increases required alignment of target type" but
we consider it OK anyway */
- struct curl_slist* list=0;
- if ( array_state )
- {
- memcpy(&list, &array_value, sizeof(struct curl_slist*));
- }
- else
- {
- list = va_arg(params, struct curl_slist*);
- }
+ struct curl_slist* list = array_state?
+ (struct curl_slist*)array_value:
+ va_arg(params, struct curl_slist*);
+
if( current_form->contentheader )
return_value = CURL_FORMADD_OPTION_TWICE;
else
current_form->contentheader = list;
-
+
break;
}
case CURLFORM_FILENAME:
@@ -898,8 +643,13 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
va_arg(params, char *);
if( current_form->showfilename )
return_value = CURL_FORMADD_OPTION_TWICE;
- else
+ else {
current_form->showfilename = strdup(filename);
+ if(!current_form->showfilename)
+ return_value = CURL_FORMADD_MEMORY;
+ else
+ current_form->showfilename_alloc = TRUE;
+ }
break;
}
default:
@@ -910,7 +660,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
if(CURL_FORMADD_OK == return_value) {
/* go through the list, check for copleteness and if everything is
* alright add the HttpPost item otherwise set return_value accordingly */
-
+
post = NULL;
for(form = first_form;
form != NULL;
@@ -921,7 +671,6 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
( (form->flags & HTTPPOST_FILENAME) &&
(form->flags & HTTPPOST_PTRCONTENTS) ) ||
- /* CMC: Added support for buffer uploads */
( (!form->buffer) &&
(form->flags & HTTPPOST_BUFFER) &&
(form->flags & HTTPPOST_PTRBUFFER) ) ||
@@ -939,41 +688,46 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
/* our contenttype is missing */
form->contenttype
= strdup(ContentTypeForFilename(form->value, prevtype));
+ if(!form->contenttype) {
+ return_value = CURL_FORMADD_MEMORY;
+ break;
+ }
+ form->contenttype_alloc = TRUE;
}
if ( !(form->flags & HTTPPOST_PTRNAME) &&
(form == first_form) ) {
/* copy name (without strdup; possibly contains null characters) */
- if (AllocAndCopy(&form->name, form->namelength)) {
+ form->name = memdup(form->name, form->namelength);
+ if (!form->name) {
return_value = CURL_FORMADD_MEMORY;
break;
}
+ form->name_alloc = TRUE;
}
if ( !(form->flags & HTTPPOST_FILENAME) &&
- !(form->flags & HTTPPOST_READFILE) &&
+ !(form->flags & HTTPPOST_READFILE) &&
!(form->flags & HTTPPOST_PTRCONTENTS) &&
-
- /* CMC: Added support for buffer uploads */
!(form->flags & HTTPPOST_PTRBUFFER) ) {
-
/* copy value (without strdup; possibly contains null characters) */
- if (AllocAndCopy(&form->value, form->contentslength)) {
+ form->value = memdup(form->value, form->contentslength);
+ if (!form->value) {
return_value = CURL_FORMADD_MEMORY;
break;
}
+ form->value_alloc = TRUE;
}
post = AddHttpPost(form->name, form->namelength,
form->value, form->contentslength,
-
- /* CMC: Added support for buffer uploads */
form->buffer, form->bufferlength,
-
form->contenttype, form->flags,
form->contentheader, form->showfilename,
post, httppost,
last_post);
-
- if(!post)
+
+ if(!post) {
return_value = CURL_FORMADD_MEMORY;
+ break;
+ }
if (form->contenttype)
prevtype = form->contenttype;
@@ -981,11 +735,27 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
}
}
+ if(return_value) {
+ /* we return on error, free possibly allocated fields */
+ if(!form)
+ form = current_form;
+ if(form) {
+ if(form->name_alloc)
+ free(form->name);
+ if(form->value_alloc)
+ free(form->value);
+ if(form->contenttype_alloc)
+ free(form->contenttype);
+ if(form->showfilename_alloc)
+ free(form->showfilename);
+ }
+ }
+
/* always delete the allocated memory before returning */
form = first_form;
while (form != NULL) {
FormInfo *delete_form;
-
+
delete_form = form;
form = form->more;
free (delete_form);
@@ -994,9 +764,13 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
return return_value;
}
+/*
+ * curl_formadd() is a public API to add a section to the multipart formpost.
+ */
+
CURLFORMcode curl_formadd(struct curl_httppost **httppost,
- struct curl_httppost **last_post,
- ...)
+ struct curl_httppost **last_post,
+ ...)
{
va_list arg;
CURLFORMcode result;
@@ -1006,23 +780,37 @@ CURLFORMcode curl_formadd(struct curl_httppost **httppost,
return result;
}
-static int AddFormData(struct FormData **formp,
- const void *line,
- long length)
+/*
+ * 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,
+ size_t length,
+ curl_off_t *size)
{
struct FormData *newform = (struct FormData *)
malloc(sizeof(struct FormData));
+ if (!newform)
+ return CURLE_OUT_OF_MEMORY;
newform->next = NULL;
/* we make it easier for plain strings: */
if(!length)
- length = (long)strlen((char *)line);
+ length = strlen((char *)line);
newform->line = (char *)malloc(length+1);
+ if (!newform->line) {
+ free(newform);
+ return CURLE_OUT_OF_MEMORY;
+ }
memcpy(newform->line, line, length);
newform->length = length;
newform->line[length]=0; /* zero terminate for easier debugging */
-
+ newform->type = type;
+
if(*formp) {
(*formp)->next = newform;
*formp = newform;
@@ -1030,64 +818,63 @@ static int AddFormData(struct FormData **formp,
else
*formp = newform;
- return length;
+ if (size) {
+ if(type == FORM_DATA)
+ *size += length;
+ else {
+ /* Since this is a file to be uploaded here, add the size of the actual
+ file */
+ if(!strequal("-", newform->line)) {
+ struct stat file;
+ if(!stat(newform->line, &file)) {
+ *size += file.st_size;
+ }
+ }
+ }
+ }
+ return CURLE_OK;
}
+/*
+ * AddFormDataf() adds printf()-style formatted data to the formdata chain.
+ */
-static int AddFormDataf(struct FormData **formp,
- const char *fmt, ...)
+static CURLcode AddFormDataf(struct FormData **formp,
+ curl_off_t *size,
+ const char *fmt, ...)
{
char s[4096];
va_list ap;
va_start(ap, fmt);
- vsprintf(s, fmt, ap);
+ vsnprintf(s, sizeof(s), fmt, ap);
va_end(ap);
- return AddFormData(formp, s, 0);
+ return AddFormData(formp, FORM_DATA, s, 0, size);
}
-
-char *Curl_FormBoundary(void)
-{
- char *retstring;
- static int randomizer=0; /* this is just so that two boundaries within
- the same form won't be identical */
- int i;
-
- static char table62[]=
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
-
- retstring = (char *)malloc(BOUNDARY_LENGTH);
-
- if(!retstring)
- return NULL; /* failed */
-
- srand((unsigned int)(time(NULL)+randomizer++)); /* seed */
-
- strcpy(retstring, "curl"); /* bonus commercials 8*) */
-
- for(i=4; i<(BOUNDARY_LENGTH-1); i++) {
- retstring[i] = table62[rand()%62];
- }
- retstring[BOUNDARY_LENGTH-1]=0; /* zero terminate */
-
- return retstring;
-}
-
-/* Used from http.c, this cleans a built FormData linked list */
+/*
+ * Curl_formclean() is used from http.c, this cleans a built FormData linked
+ * list
+ */
void Curl_formclean(struct FormData *form)
{
struct FormData *next;
+ if(!form)
+ return;
+
do {
next=form->next; /* the following form line */
free(form->line); /* free the line */
free(form); /* free the struct */
-
+
} while((form=next)); /* continue */
}
-/* external function to free up a whole form post chain */
+/*
+ * curl_formfree() is an external function to free up a whole form post
+ * chain
+ */
void curl_formfree(struct curl_httppost *form)
{
struct curl_httppost *next;
@@ -1116,16 +903,23 @@ void curl_formfree(struct curl_httppost *form)
} while((form=next)); /* continue */
}
+/*
+ * 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.
+ */
+
CURLcode Curl_getFormData(struct FormData **finalform,
struct curl_httppost *post,
- int *sizep)
+ curl_off_t *sizep)
{
struct FormData *form = NULL;
struct FormData *firstform;
struct curl_httppost *file;
CURLcode result = CURLE_OK;
- int size =0;
+ curl_off_t size=0; /* support potentially ENORMOUS formposts */
char *boundary;
char *fileboundary=NULL;
struct curl_slist* curList;
@@ -1136,30 +930,49 @@ CURLcode Curl_getFormData(struct FormData **finalform,
return result; /* no input => no output! */
boundary = Curl_FormBoundary();
-
+ if(!boundary)
+ return CURLE_OUT_OF_MEMORY;
+
/* Make the first line of the output */
- AddFormDataf(&form,
- "Content-Type: multipart/form-data;"
- " boundary=%s\r\n",
- boundary);
- /* we DO NOT count that line since that'll be part of the header! */
+ result = AddFormDataf(&form, NULL,
+ "Content-Type: multipart/form-data;"
+ " boundary=%s\r\n",
+ boundary);
+ if (result) {
+ free(boundary);
+ 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)
- size += AddFormDataf(&form, "\r\n");
+ if(size) {
+ result = AddFormDataf(&form, &size, "\r\n");
+ if (result)
+ break;
+ }
/* boundary */
- size += AddFormDataf(&form, "--%s\r\n", boundary);
+ result = AddFormDataf(&form, &size, "--%s\r\n", boundary);
+ if (result)
+ break;
- size += AddFormData(&form,
- "Content-Disposition: form-data; name=\"", 0);
+ result = AddFormDataf(&form, &size,
+ "Content-Disposition: form-data; name=\"");
+ if (result)
+ break;
- size += AddFormData(&form, post->name, post->namelength);
+ result = AddFormData(&form, FORM_DATA, post->name, post->namelength,
+ &size);
+ if (result)
+ break;
- size += AddFormData(&form, "\"", 0);
+ result = AddFormDataf(&form, &size, "\"");
+ if (result)
+ break;
if(post->more) {
/* If used, this is a link to more file names, we must then do
@@ -1167,10 +980,12 @@ CURLcode Curl_getFormData(struct FormData **finalform,
fileboundary = Curl_FormBoundary();
- size += AddFormDataf(&form,
- "\r\nContent-Type: multipart/mixed,"
- " boundary=%s\r\n",
- fileboundary);
+ result = AddFormDataf(&form, &size,
+ "\r\nContent-Type: multipart/mixed,"
+ " boundary=%s\r\n",
+ fileboundary);
+ if (result)
+ break;
}
file = post;
@@ -1183,37 +998,48 @@ CURLcode Curl_getFormData(struct FormData **finalform,
if(post->more) {
/* if multiple-file */
- size += AddFormDataf(&form,
- "\r\n--%s\r\nContent-Disposition: "
- "attachment; filename=\"%s\"",
- fileboundary,
- (file->showfilename?file->showfilename:
- file->contents));
+ result = AddFormDataf(&form, &size,
+ "\r\n--%s\r\nContent-Disposition: "
+ "attachment; filename=\"%s\"",
+ fileboundary,
+ (file->showfilename?file->showfilename:
+ file->contents));
+ if (result)
+ break;
}
else if((post->flags & HTTPPOST_FILENAME) ||
-
- /* CMC: Added support for buffer uploads */
(post->flags & HTTPPOST_BUFFER)) {
- size += AddFormDataf(&form,
- "; filename=\"%s\"",
- (post->showfilename?post->showfilename:
- post->contents));
+ result = AddFormDataf(&form, &size,
+ "; filename=\"%s\"",
+ (post->showfilename?post->showfilename:
+ post->contents));
+ if (result)
+ break;
}
-
+
if(file->contenttype) {
/* we have a specified type */
- size += AddFormDataf(&form,
- "\r\nContent-Type: %s",
- file->contenttype);
+ result = AddFormDataf(&form, &size,
+ "\r\nContent-Type: %s",
+ file->contenttype);
+ if (result)
+ break;
}
curList = file->contentheader;
while( curList ) {
/* Process the additional headers specified for this form */
- size += AddFormDataf( &form, "\r\n%s", curList->data );
+ result = AddFormDataf( &form, &size, "\r\n%s", curList->data );
+ if (result)
+ break;
curList = curList->next;
}
+ if (result) {
+ Curl_formclean(firstform);
+ free(boundary);
+ return result;
+ }
#if 0
/* The header Content-Transfer-Encoding: seems to confuse some receivers
@@ -1221,7 +1047,7 @@ CURLcode Curl_getFormData(struct FormData **finalform,
* should, I can just as well skip this to the benefit of the users who
* are using such confused receivers.
*/
-
+
if(file->contenttype &&
!checkprefix("text/", file->contenttype)) {
/* this is not a text content, mention our binary encoding */
@@ -1229,65 +1055,110 @@ CURLcode Curl_getFormData(struct FormData **finalform,
}
#endif
- size += AddFormData(&form, "\r\n\r\n", 0);
+ result = AddFormDataf(&form, &size, "\r\n\r\n");
+ if (result)
+ break;
if((post->flags & HTTPPOST_FILENAME) ||
(post->flags & HTTPPOST_READFILE)) {
/* we should include the contents from the specified file */
FILE *fileread;
- char buffer[1024];
- int nread;
-
- fileread = strequal("-", file->contents)?stdin:
- /* binary read for win32 crap */
- /*VMS??*/ fopen(file->contents, "rb"); /* ONLY ALLOWS FOR STREAM FILES ON VMS */
- /*VMS?? Stream files are OK, as are FIXED & VAR files WITHOUT implied CC */
- /*VMS?? For implied CC, every record needs to have a \n appended & 1 added to SIZE */
- if(fileread) {
- while((nread = (int)fread(buffer, 1, 1024, fileread)))
- size += AddFormData(&form, buffer, nread);
- if(fileread != stdin)
+ fileread = strequal("-", 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 again */
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))) {
+ result = AddFormData(&form, FORM_DATA, buffer, nread, &size);
+ if (result)
+ break;
+ }
+ }
+
+ if (result) {
+ Curl_formclean(firstform);
+ free(boundary);
+ return result;
+ }
+
}
else {
-#if 0
- /* File wasn't found, add a nothing field! */
- size += AddFormData(&form, "", 0);
-#endif
Curl_formclean(firstform);
free(boundary);
*finalform = NULL;
return CURLE_READ_ERROR;
}
- /* CMC: Added support for buffer uploads */
- } else if (post->flags & HTTPPOST_BUFFER) {
- /* include contents of buffer */
- size += AddFormData(&form, post->buffer, post->bufferlength);
+ }
+ else if (post->flags & HTTPPOST_BUFFER) {
+ /* include contents of buffer */
+ result = AddFormData(&form, FORM_DATA, post->buffer,
+ post->bufferlength, &size);
+ if (result)
+ break;
}
else {
/* include the contents we got */
- size += AddFormData(&form, post->contents, post->contentslength);
+ result = AddFormData(&form, FORM_DATA, post->contents,
+ post->contentslength, &size);
+ if (result)
+ break;
}
} while((file = file->more)); /* for each specified file for this field */
+ if (result) {
+ Curl_formclean(firstform);
+ free(boundary);
+ return result;
+ }
if(post->more) {
/* this was a multiple-file inclusion, make a termination file
boundary: */
- size += AddFormDataf(&form,
+ result = AddFormDataf(&form, &size,
"\r\n--%s--",
- fileboundary);
+ fileboundary);
free(fileboundary);
+ if (result)
+ break;
}
} while((post=post->next)); /* for each field */
+ if (result) {
+ Curl_formclean(firstform);
+ free(boundary);
+ return result;
+ }
/* end-boundary for everything */
- size += AddFormDataf(&form,
+ result = AddFormDataf(&form, &size,
"\r\n--%s--\r\n",
boundary);
+ if (result) {
+ Curl_formclean(firstform);
+ free(boundary);
+ return result;
+ }
*sizep = size;
@@ -1298,6 +1169,10 @@ CURLcode Curl_getFormData(struct FormData **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)
@@ -1305,29 +1180,57 @@ int Curl_FormInit(struct Form *form, struct FormData *formdata )
form->data = formdata;
form->sent = 0;
+ form->fp = NULL;
return 0;
}
-/* fread() emulation */
-int Curl_FormReader(char *buffer,
- size_t size,
- size_t nitems,
- FILE *mydata)
+static size_t readfromfile(struct Form *form, char *buffer, size_t size)
+{
+ size_t nread;
+ if(!form->fp) {
+ /* this file hasn't yet been opened */
+ form->fp = fopen(form->data->line, "rb"); /* b is for binary */
+ if(!form->fp)
+ return -1; /* failure */
+ }
+ nread = fread(buffer, 1, size, form->fp);
+
+ if(nread != size) {
+ /* this is the last chunk form the file, move on */
+ 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;
- int wantedsize;
- int gotsize = 0;
+ size_t wantedsize;
+ size_t gotsize = 0;
form=(struct Form *)mydata;
- wantedsize = (int)(size * nitems);
+ wantedsize = size * nitems;
if(!form->data)
return 0; /* nothing, error, empty */
+ if(form->data->type == FORM_FILE)
+ return readfromfile(form, buffer, wantedsize);
+
do {
-
+
if( (form->data->length - form->sent ) > wantedsize - gotsize) {
memcpy(buffer + gotsize , form->data->line + form->sent,
@@ -1342,12 +1245,12 @@ int Curl_FormReader(char *buffer,
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);
+ } while(form->data && (form->data->type == FORM_DATA));
/* 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.
This is the bug reported November 22 1999 on curl 6.3. (Daniel) */
@@ -1355,48 +1258,25 @@ int Curl_FormReader(char *buffer,
return gotsize;
}
-/* possible (old) fread() emulation that copies at most one line */
-int Curl_FormReadOneLine(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)
{
- struct Form *form;
- int wantedsize;
- int gotsize;
-
- form=(struct Form *)mydata;
-
- wantedsize = (int)(size * nitems);
+ char *header;
+ struct Form *form=(struct Form *)formp;
if(!form->data)
- return -1; /* nothing, error, empty */
-
- do {
-
- if( (form->data->length - form->sent ) > wantedsize ) {
+ return 0; /* nothing, ERROR! */
- memcpy(buffer, form->data->line + form->sent, wantedsize);
+ header = form->data->line;
+ *len = form->data->length;
- form->sent += wantedsize;
+ form->data = form->data->next; /* advance */
- return wantedsize;
- }
-
- memcpy(buffer,
- form->data->line + form->sent,
- gotsize = (form->data->length - form->sent) );
-
- form->sent = 0;
-
- form->data = form->data->next; /* advance */
-
- } while(!gotsize && form->data);
- /* 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.
- This is the bug reported November 22 1999 on curl 6.3. (Daniel) */
-
- return gotsize;
+ return header;
}
@@ -1447,7 +1327,7 @@ int main()
int value6length = strlen(value5);
int errors = 0;
int size;
- int nread;
+ size_t nread;
char buffer[4096];
struct curl_httppost *httppost=NULL;
struct curl_httppost *last_post=NULL;
@@ -1546,66 +1426,53 @@ int main()
#endif
-#ifdef _OLD_FORM_DEBUG
-
-int main(int argc, char **argv)
+#else /* CURL_DISABLE_HTTP */
+CURLFORMcode curl_formadd(struct curl_httppost **httppost,
+ struct curl_httppost **last_post,
+ ...)
{
-#if 0
- char *testargs[]={
- "name1 = data in number one",
- "name2 = number two data",
- "test = @upload"
- };
-#endif
- int i;
- char *nextarg;
- struct curl_httppost *httppost=NULL;
- struct curl_httppost *last_post=NULL;
- struct curl_httppost *post;
- int size;
- int nread;
- char buffer[4096];
-
- struct FormData *form;
- struct Form formread;
+ (void)httppost;
+ (void)last_post;
+ return CURL_FORMADD_DISABLED;
+}
- for(i=1; i<argc; i++) {
+void curl_formfree(struct curl_httppost *form)
+{
+ (void)form;
+ /* does nothing HTTP is disabled */
+}
- if( FormParse( argv[i],
- &httppost,
- &last_post)) {
- fprintf(stderr, "Illegally formatted input field: '%s'!\n",
- argv[i]);
- return 1;
- }
- }
+#endif /* CURL_DISABLE_HTTP */
- form=Curl_getFormData(httppost, &size);
+/*
+ * Curl_FormBoundary() creates a suitable boundary string and returns an
+ * allocated one. This is also used by SSL-code so it must be present even
+ * if HTTP is disabled!
+ */
+char *Curl_FormBoundary(void)
+{
+ char *retstring;
+ static int randomizer=0; /* this is just so that two boundaries within
+ the same form won't be identical */
+ size_t i;
- Curl_FormInit(&formread, form);
+ static char table16[]="abcdef0123456789";
- do {
- nread = Curl_FormReader(buffer, 1, sizeof(buffer),
- (FILE *)&formread);
+ retstring = (char *)malloc(BOUNDARY_LENGTH+1);
- if(-1 == nread)
- break;
- fwrite(buffer, nread, 1, stderr);
- } while(1);
+ if(!retstring)
+ return NULL; /* failed */
- fprintf(stderr, "size: %d\n", size);
+ srand(time(NULL)+randomizer++); /* seed */
- return 0;
-}
+ strcpy(retstring, "----------------------------");
-#endif
+ for(i=strlen(retstring); i<BOUNDARY_LENGTH; i++)
+ retstring[i] = table16[rand()%16];
-#endif /* CURL_DISABLE_HTTP */
+ /* 28 dashes and 12 hexadecimal digits makes 12^16 (184884258895036416)
+ combinations */
+ retstring[BOUNDARY_LENGTH]=0; /* zero terminate */
-/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
- */
+ return retstring;
+}
diff --git a/Source/CTest/Curl/formdata.h b/Source/CTest/Curl/formdata.h
index d1cc674..c6a78cd 100644
--- a/Source/CTest/Curl/formdata.h
+++ b/Source/CTest/Curl/formdata.h
@@ -2,18 +2,18 @@
#define __FORMDATA_H
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -23,34 +23,43 @@
*
* $Id$
***************************************************************************/
+
+enum formtype {
+ FORM_DATA, /* regular data */
+ FORM_FILE /* 'line' points to a file name we should read from */
+};
+
/* plain and simple linked list with lines to send */
struct FormData {
struct FormData *next;
+ enum formtype type;
char *line;
- long length;
+ size_t length;
};
struct Form {
struct FormData *data; /* current form line to send */
- int sent; /* number of bytes of the current line that has already
- been sent in a previous invoke */
+ 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 */
};
/* used by FormAdd for temporary storage */
typedef struct FormInfo {
char *name;
- long namelength;
+ bool name_alloc;
+ size_t namelength;
char *value;
- long contentslength;
+ bool value_alloc;
+ size_t contentslength;
char *contenttype;
+ bool contenttype_alloc;
long flags;
-
- /* CMC: Added support for buffer uploads */
char *buffer; /* pointer to existing buffer used for file upload */
- long bufferlength;
-
+ size_t bufferlength;
char *showfilename; /* The file name to show. If not set, the actual
file name will be used */
+ bool showfilename_alloc;
struct curl_slist* contentheader;
struct FormInfo *more;
} FormInfo;
@@ -59,20 +68,21 @@ int Curl_FormInit(struct Form *form, struct FormData *formdata );
CURLcode
Curl_getFormData(struct FormData **,
- struct HttpPost *post,
- int *size);
+ struct curl_httppost *post,
+ curl_off_t *size);
/* fread() emulation */
-int Curl_FormReader(char *buffer,
- size_t size,
- size_t nitems,
- FILE *mydata);
+size_t Curl_FormReader(char *buffer,
+ size_t size,
+ size_t nitems,
+ FILE *mydata);
-/* possible (old) fread() emulation that copies at most one line */
-int Curl_FormReadOneLine(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);
diff --git a/Source/CTest/Curl/ftp.c b/Source/CTest/Curl/ftp.c
index 0163d3a..77de831 100644
--- a/Source/CTest/Curl/ftp.c
+++ b/Source/CTest/Curl/ftp.c
@@ -1,16 +1,16 @@
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -39,7 +39,7 @@
#endif
#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
-#include <winsock.h>
+
#else /* some kind of unix */
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
@@ -65,6 +65,11 @@
#include <errno.h>
#endif
+#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+
#include <curl/curl.h>
#include "urldata.h"
#include "sendf.h"
@@ -77,14 +82,18 @@
#include "http.h" /* for HTTP proxy tunnel stuff */
#include "ftp.h"
-#ifdef KRB4
+#ifdef HAVE_KRB4
#include "security.h"
#include "krb4.h"
#endif
+#include "strtoofft.h"
#include "strequal.h"
#include "ssluse.h"
#include "connect.h"
+#include "strerror.h"
+#include "memory.h"
+#include "inet_ntop.h"
#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
#include "inet_ntoa_r.h"
@@ -94,17 +103,50 @@
#include <curl/mprintf.h>
/* The last #include file should be: */
-#ifdef MALLOCDEBUG
+#ifdef CURLDEBUG
#include "memdebug.h"
#endif
+#ifdef HAVE_NI_WITHSCOPEID
+#define NIFLAGS NI_NUMERICHOST | NI_NUMERICSERV | NI_WITHSCOPEID
+#else
+#define NIFLAGS NI_NUMERICHOST | NI_NUMERICSERV
+#endif
+
/* Local API functions */
-static CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote);
+static CURLcode ftp_sendquote(struct connectdata *conn,
+ struct curl_slist *quote);
static CURLcode ftp_cwd(struct connectdata *conn, char *path);
+static CURLcode ftp_mkd(struct connectdata *conn, char *path);
+static CURLcode ftp_cwd_and_mkd(struct connectdata *conn, char *path);
+static CURLcode ftp_quit(struct connectdata *conn);
+static CURLcode ftp_3rdparty_pretransfer(struct connectdata *conn);
+static CURLcode ftp_3rdparty_transfer(struct connectdata *conn);
+static CURLcode ftp_regular_transfer(struct connectdata *conn);
+static CURLcode ftp_3rdparty(struct connectdata *conn);
/* easy-to-use macro: */
#define FTPSENDF(x,y,z) if((result = Curl_ftpsendf(x,y,z))) return result
+static void freedirs(struct FTP *ftp)
+{
+ int i;
+ if(ftp->dirs) {
+ for (i=0; i < ftp->dirdepth; i++){
+ if(ftp->dirs[i]) {
+ free(ftp->dirs[i]);
+ ftp->dirs[i]=NULL;
+ }
+ }
+ free(ftp->dirs);
+ ftp->dirs = NULL;
+ }
+ if(ftp->file) {
+ free(ftp->file);
+ ftp->file = NULL;
+ }
+}
+
/***********************************************************************
*
* AllowServerConnect()
@@ -114,19 +156,31 @@ static CURLcode ftp_cwd(struct connectdata *conn, char *path);
* connected.
*
*/
-static CURLcode AllowServerConnect(struct SessionHandle *data,
- struct connectdata *conn,
- int sock)
+static CURLcode AllowServerConnect(struct connectdata *conn)
{
fd_set rdset;
struct timeval dt;
-
+ struct SessionHandle *data = conn->data;
+ curl_socket_t sock = conn->sock[SECONDARYSOCKET];
+ struct timeval now = Curl_tvnow();
+ long timespent = Curl_tvdiff(Curl_tvnow(), now)/1000;
+ long timeout = data->set.connecttimeout?data->set.connecttimeout:
+ (data->set.timeout?data->set.timeout: 0);
+
FD_ZERO(&rdset);
FD_SET(sock, &rdset);
- /* we give the server 10 seconds to connect to us */
- dt.tv_sec = 10;
+ if(timeout) {
+ timeout -= timespent;
+ if(timeout<=0) {
+ failf(data, "Timed out before server could connect to us");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+ }
+
+ /* we give the server 60 seconds to connect to us, or a custom timeout */
+ dt.tv_sec = (int)(timeout?timeout:60);
dt.tv_usec = 0;
switch (select(sock+1, &rdset, NULL, NULL, &dt)) {
@@ -141,30 +195,28 @@ static CURLcode AllowServerConnect(struct SessionHandle *data,
default:
/* we have received data here */
{
- int s;
-#ifdef __hpux
- int size = sizeof(struct sockaddr_in);
-#else
- socklen_t size = sizeof(struct sockaddr_in);
-#endif
+ curl_socket_t s;
+ size_t size = sizeof(struct sockaddr_in);
struct sockaddr_in add;
- getsockname(sock, (struct sockaddr *) &add, &size);
- s=(int)accept(sock, (struct sockaddr *) &add, &size);
+ getsockname(sock, (struct sockaddr *) &add, (socklen_t *)&size);
+ s=accept(sock, (struct sockaddr *) &add, (socklen_t *)&size);
sclose(sock); /* close the first socket */
- if (-1 == s) {
+ if (CURL_SOCKET_BAD == s) {
/* DIE! */
failf(data, "Error accept()ing server connect");
return CURLE_FTP_PORT_FAILED;
}
infof(data, "Connection accepted from server\n");
- conn->secondarysocket = s;
+ conn->sock[SECONDARYSOCKET] = s;
+ Curl_nonblock(s, TRUE); /* enable non-blocking */
}
break;
}
+
return CURLE_OK;
}
@@ -177,7 +229,7 @@ static CURLcode AllowServerConnect(struct SessionHandle *data,
* response and extract the relevant return code for the invoking function.
*/
-CURLcode Curl_GetFTPResponse(int *nreadp, /* return number of bytes read */
+CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
struct connectdata *conn,
int *ftpcode) /* return the ftp-code */
{
@@ -188,12 +240,12 @@ CURLcode Curl_GetFTPResponse(int *nreadp, /* return number of bytes read */
* Alas, read as much as possible, split up into lines, use the ending
* line in a response or continue reading. */
- int sockfd = conn->firstsocket;
+ curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
int perline; /* count bytes per line */
bool keepon=TRUE;
ssize_t gotbytes;
char *ptr;
- int timeout; /* timeout in seconds */
+ long timeout; /* timeout in seconds */
struct timeval interval;
fd_set rkeepfd;
fd_set readfd;
@@ -224,7 +276,15 @@ CURLcode Curl_GetFTPResponse(int *nreadp, /* return number of bytes read */
while((*nreadp<BUFSIZE) && (keepon && !result)) {
/* check and reset timeout value every lap */
- if(data->set.timeout)
+ if(data->set.ftp_response_timeout )
+ /* if CURLOPT_FTP_RESPONSE_TIMEOUT is set, use that to determine
+ remaining time. Also, use "now" as opposed to "conn->now"
+ because ftp_response_timeout is only supposed to govern
+ the response for any given ftp response, not for the time
+ from connect to the given ftp response. */
+ timeout = data->set.ftp_response_timeout - /* timeout time */
+ Curl_tvdiff(Curl_tvnow(), now)/1000; /* spent time */
+ else if(data->set.timeout)
/* if timeout is requested, find out how much remaining time we have */
timeout = data->set.timeout - /* timeout time */
Curl_tvdiff(Curl_tvnow(), conn->now)/1000; /* spent time */
@@ -235,24 +295,25 @@ CURLcode Curl_GetFTPResponse(int *nreadp, /* return number of bytes read */
Curl_tvdiff(Curl_tvnow(), now)/1000; /* spent time */
if(timeout <=0 ) {
- failf(data, "Transfer aborted due to timeout");
+ failf(data, "FTP response timeout");
return CURLE_OPERATION_TIMEDOUT; /* already too little time */
}
if(!ftp->cache) {
readfd = rkeepfd; /* set every lap */
- interval.tv_sec = timeout;
+ interval.tv_sec = 1; /* use 1 second timeout intervals */
interval.tv_usec = 0;
switch (select (sockfd+1, &readfd, NULL, NULL, &interval)) {
case -1: /* select() error, stop reading */
result = CURLE_RECV_ERROR;
- failf(data, "Transfer aborted due to select() error: %d", errno);
+ failf(data, "FTP response aborted due to select() error: %d", errno);
break;
case 0: /* timeout */
- result = CURLE_OPERATION_TIMEDOUT;
- failf(data, "Transfer aborted due to timeout");
- break;
+ if(Curl_pgrsUpdate(conn))
+ return CURLE_ABORTED_BY_CALLBACK;
+ continue; /* just continue in our loop for the timeout duration */
+
default:
break;
}
@@ -265,8 +326,15 @@ CURLcode Curl_GetFTPResponse(int *nreadp, /* return number of bytes read */
*/
if(ftp->cache) {
/* we had data in the "cache", copy that instead of doing an actual
- read */
- memcpy(ptr, ftp->cache, ftp->cache_size);
+ * read
+ *
+ * Dave Meyer, December 2003:
+ * ftp->cache_size is cast to int here. This should be safe,
+ * because it would have been populated with something of size
+ * int to begin with, even though its datatype may be larger
+ * than an int.
+ */
+ memcpy(ptr, ftp->cache, (int)ftp->cache_size);
gotbytes = (int)ftp->cache_size;
free(ftp->cache); /* free the cache */
ftp->cache = NULL; /* clear the pointer */
@@ -287,7 +355,7 @@ CURLcode Curl_GetFTPResponse(int *nreadp, /* return number of bytes read */
else if(gotbytes <= 0) {
keepon = FALSE;
result = CURLE_RECV_ERROR;
- failf(data, "Connection aborted");
+ failf(data, "FTP response reading failed");
}
else {
/* we got a whole chunk of data, which can be anything from one
@@ -295,17 +363,18 @@ CURLcode Curl_GetFTPResponse(int *nreadp, /* return number of bytes read */
* line */
int i;
+ conn->headerbytecount += gotbytes;
+
*nreadp += gotbytes;
for(i = 0; i < gotbytes; ptr++, i++) {
perline++;
if(*ptr=='\n') {
/* a newline is CRLF in ftp-talk, so the CR is ignored as
the line isn't really terminated until the LF comes */
- CURLcode result;
/* output debug output if that is requested */
if(data->set.verbose)
- Curl_debug(data, CURLINFO_HEADER_IN, line_start, perline);
+ Curl_debug(data, CURLINFO_HEADER_IN, line_start, perline, conn->host.dispname);
/*
* We pass all response-lines to the callback function registered
@@ -316,7 +385,7 @@ CURLcode Curl_GetFTPResponse(int *nreadp, /* return number of bytes read */
line_start, perline);
if(result)
return result;
-
+
#define lastline(line) (isdigit((int)line[0]) && isdigit((int)line[1]) && \
isdigit((int)line[2]) && (' ' == line[3]))
@@ -346,9 +415,9 @@ CURLcode Curl_GetFTPResponse(int *nreadp, /* return number of bytes read */
already! Cleverly figured out by Eric Lavigne in December
2001. */
ftp->cache_size = gotbytes - i;
- ftp->cache = (char *)malloc(ftp->cache_size);
+ ftp->cache = (char *)malloc((int)ftp->cache_size);
if(ftp->cache)
- memcpy(ftp->cache, line_start, ftp->cache_size);
+ memcpy(ftp->cache, line_start, (int)ftp->cache_size);
else
return CURLE_OUT_OF_MEMORY; /**BANG**/
}
@@ -359,7 +428,7 @@ CURLcode Curl_GetFTPResponse(int *nreadp, /* return number of bytes read */
if(!result)
code = atoi(buf);
-#ifdef KRB4
+#ifdef HAVE_KRB4
/* handle the security-oriented responses 6xx ***/
/* FIXME: some errorchecking perhaps... ***/
switch(code) {
@@ -381,9 +450,16 @@ CURLcode Curl_GetFTPResponse(int *nreadp, /* return number of bytes read */
if(ftpcode)
*ftpcode=code; /* return the initial number like this */
+ /* store the latest code for later retrieval */
+ conn->data->info.httpcode=code;
+
return result;
}
+static const char *ftpauth[]= {
+ "SSL", "TLS", NULL
+};
+
/*
* Curl_ftp_connect() should do everything that is to be considered a part of
* the connection phase.
@@ -391,12 +467,12 @@ CURLcode Curl_GetFTPResponse(int *nreadp, /* return number of bytes read */
CURLcode Curl_ftp_connect(struct connectdata *conn)
{
/* this is FTP and no proxy */
- int nread;
+ ssize_t nread;
struct SessionHandle *data=conn->data;
char *buf = data->state.buffer; /* this is our buffer */
struct FTP *ftp;
CURLcode result;
- int ftpcode;
+ int ftpcode, try;
ftp = (struct FTP *)malloc(sizeof(struct FTP));
if(!ftp)
@@ -411,28 +487,29 @@ CURLcode Curl_ftp_connect(struct connectdata *conn)
/* get some initial data into the ftp struct */
ftp->bytecountp = &conn->bytecount;
- /* no need to duplicate them, the data struct won't change */
- ftp->user = data->state.user;
- ftp->passwd = data->state.passwd;
+ /* no need to duplicate them, this connectdata struct won't change */
+ ftp->user = conn->user;
+ ftp->passwd = conn->passwd;
ftp->response_time = 3600; /* set default response time-out */
- if (data->set.tunnel_thru_httpproxy) {
+#ifndef CURL_DISABLE_HTTP
+ if (conn->bits.tunnel_proxy) {
/* We want "seamless" FTP operations through HTTP proxy tunnel */
- result = Curl_ConnectHTTPProxyTunnel(conn, conn->firstsocket,
- conn->hostname, conn->remote_port);
+ result = Curl_ConnectHTTPProxyTunnel(conn, FIRSTSOCKET,
+ conn->host.name, conn->remote_port);
if(CURLE_OK != result)
return result;
}
+#endif /* CURL_DISABLE_HTTP */
if(conn->protocol & PROT_FTPS) {
/* FTPS is simply ftp with SSL for the control channel */
/* now, perform the SSL initialization for this socket */
- result = Curl_SSLConnect(conn);
+ result = Curl_SSLConnect(conn, FIRSTSOCKET);
if(result)
return result;
}
-
/* The first thing we do is wait for the "220*" line: */
result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
if(result)
@@ -443,7 +520,7 @@ CURLcode Curl_ftp_connect(struct connectdata *conn)
return CURLE_FTP_WEIRD_SERVER_REPLY;
}
-#ifdef KRB4
+#ifdef HAVE_KRB4
/* if not anonymous login, try a secure login */
if(data->set.krb4) {
@@ -460,9 +537,39 @@ CURLcode Curl_ftp_connect(struct connectdata *conn)
infof(data, "Authentication successful\n");
}
#endif
-
+
+ if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) {
+ /* we don't have a SSL/TLS connection, try a FTPS connection now */
+
+ for (try = 0; ftpauth[try]; try++) {
+
+ FTPSENDF(conn, "AUTH %s", ftpauth[try]);
+
+ result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+
+ if(result)
+ return result;
+
+ /* RFC2228 (page 5) says:
+ *
+ * If the server is willing to accept the named security mechanism, and
+ * does not require any security data, it must respond with reply code
+ * 234/334.
+ */
+
+ if((ftpcode == 234) || (ftpcode == 334)) {
+ result = Curl_SSLConnect(conn, FIRSTSOCKET);
+ if(result)
+ return result;
+ conn->protocol |= PROT_FTPS;
+ conn->ssl[SECONDARYSOCKET].use = FALSE; /* clear-text data */
+ break;
+ }
+ }
+ }
+
/* send USER */
- FTPSENDF(conn, "USER %s", ftp->user);
+ FTPSENDF(conn, "USER %s", ftp->user?ftp->user:"");
/* wait for feedback */
result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
@@ -478,7 +585,7 @@ CURLcode Curl_ftp_connect(struct connectdata *conn)
else if(ftpcode == 331) {
/* 331 Password required for ...
(the server requires to send the user's password too) */
- FTPSENDF(conn, "PASS %s", ftp->passwd);
+ FTPSENDF(conn, "PASS %s", ftp->passwd?ftp->passwd:"");
result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
if(result)
return result;
@@ -492,7 +599,7 @@ CURLcode Curl_ftp_connect(struct connectdata *conn)
else if(ftpcode == 230) {
/* 230 User ... logged in.
(user successfully logged in) */
-
+
infof(data, "We have successfully logged in\n");
}
else {
@@ -504,28 +611,71 @@ CURLcode Curl_ftp_connect(struct connectdata *conn)
/* 230 User ... logged in.
(the user logged in without password) */
infof(data, "We have successfully logged in\n");
-#ifdef KRB4
- /* we are logged in (with Kerberos)
- * now set the requested protection level
- */
- if(conn->sec_complete)
- Curl_sec_set_protection_level(conn);
+ if (conn->ssl[FIRSTSOCKET].use) {
+#ifdef HAVE_KRB4
+ /* We are logged in with Kerberos, now set the requested protection
+ * level
+ */
+ if(conn->sec_complete)
+ Curl_sec_set_protection_level(conn);
- /* we may need to issue a KAUTH here to have access to the files
- * do it if user supplied a password
- */
- if(data->state.passwd && *data->state.passwd) {
- result = Curl_krb_kauth(conn);
- if(result)
- return result;
- }
+ /* We may need to issue a KAUTH here to have access to the files
+ * do it if user supplied a password
+ */
+ if(conn->passwd && *conn->passwd) {
+ result = Curl_krb_kauth(conn);
+ if(result)
+ return result;
+ }
#endif
+ }
}
else {
failf(data, "Odd return code after USER");
return CURLE_FTP_WEIRD_USER_REPLY;
}
+ if(conn->ssl[FIRSTSOCKET].use) {
+ /* PBSZ = PROTECTION BUFFER SIZE.
+
+ The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says:
+
+ Specifically, the PROT command MUST be preceded by a PBSZ command
+ and a PBSZ command MUST be preceded by a successful security data
+ exchange (the TLS negotiation in this case)
+
+ ... (and on page 8):
+
+ Thus the PBSZ command must still be issued, but must have a parameter
+ of '0' to indicate that no buffering is taking place and the data
+ connection should not be encapsulated.
+ */
+ FTPSENDF(conn, "PBSZ %d", 0);
+ result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+ if(result)
+ return result;
+
+ /* For TLS, the data connection can have one of two security levels.
+
+ 1)Clear (requested by 'PROT C')
+
+ 2)Private (requested by 'PROT P')
+ */
+ if(!conn->ssl[SECONDARYSOCKET].use) {
+ FTPSENDF(conn, "PROT %c", 'P');
+ result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+ if(result)
+ return result;
+
+ if(ftpcode == 200)
+ /* We have enabled SSL for the data connection! */
+ conn->ssl[SECONDARYSOCKET].use = TRUE;
+
+ /* FTP servers typically responds with 500 if they decide to reject
+ our 'P' request */
+ }
+ }
+
/* send PWD to discover our entry point */
FTPSENDF(conn, "PWD", NULL);
@@ -538,14 +688,17 @@ CURLcode Curl_ftp_connect(struct connectdata *conn)
char *dir = (char *)malloc(nread+1);
char *store=dir;
char *ptr=&buf[4]; /* start on the first letter */
-
+
+ if(!dir)
+ return CURLE_OUT_OF_MEMORY;
+
/* Reply format is like
257<space>"<directory-name>"<space><commentary> and the RFC959 says
The directory name can contain any character; embedded double-quotes
should be escaped by double-quotes (the "quote-doubling" convention).
*/
- if(dir && ('\"' == *ptr)) {
+ if('\"' == *ptr) {
/* it started good */
ptr++;
while(ptr && *ptr) {
@@ -592,27 +745,40 @@ CURLcode Curl_ftp_connect(struct connectdata *conn)
*
* Input argument is already checked for validity.
*/
-CURLcode Curl_ftp_done(struct connectdata *conn)
+CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode status)
{
struct SessionHandle *data = conn->data;
struct FTP *ftp = conn->proto.ftp;
- int nread;
+ ssize_t nread;
int ftpcode;
CURLcode result=CURLE_OK;
+ bool was_ctl_valid = ftp->ctl_valid;
+
+ /* free the dir tree and file parts */
+ freedirs(ftp);
+
+ ftp->ctl_valid = FALSE;
+
if(data->set.upload) {
if((-1 != data->set.infilesize) &&
(data->set.infilesize != *ftp->bytecountp) &&
!data->set.crlf) {
- failf(data, "Uploaded unaligned file size (%d out of %d bytes)",
+ failf(data, "Uploaded unaligned file size (%" FORMAT_OFF_T
+ " out of %" FORMAT_OFF_T " bytes)",
*ftp->bytecountp, data->set.infilesize);
+ conn->bits.close = TRUE; /* close this connection since we don't
+ know what state this error leaves us in */
return CURLE_PARTIAL_FILE;
}
}
else {
if((-1 != conn->size) && (conn->size != *ftp->bytecountp) &&
(conn->maxdownload != *ftp->bytecountp)) {
- failf(data, "Received only partial file: %d bytes", *ftp->bytecountp);
+ failf(data, "Received only partial file: %" FORMAT_OFF_T " bytes",
+ *ftp->bytecountp);
+ conn->bits.close = TRUE; /* close this connection since we don't
+ know what state this error leaves us in */
return CURLE_PARTIAL_FILE;
}
else if(!ftp->dont_check &&
@@ -627,25 +793,43 @@ CURLcode Curl_ftp_done(struct connectdata *conn)
}
}
-#ifdef KRB4
- Curl_sec_fflush_fd(conn, conn->secondarysocket);
+ switch(status) {
+ case CURLE_BAD_DOWNLOAD_RESUME:
+ case CURLE_FTP_WEIRD_PASV_REPLY:
+ case CURLE_FTP_PORT_FAILED:
+ case CURLE_FTP_COULDNT_SET_BINARY:
+ case CURLE_FTP_COULDNT_RETR_FILE:
+ case CURLE_FTP_ACCESS_DENIED:
+ /* the connection stays alive fine even though this happened */
+ /* fall-through */
+ case CURLE_OK: /* doesn't affect the control connection's status */
+ ftp->ctl_valid = was_ctl_valid;
+ break;
+ default: /* by default, an error means the control connection is
+ wedged and should not be used anymore */
+ ftp->ctl_valid = FALSE;
+ break;
+ }
+
+#ifdef HAVE_KRB4
+ Curl_sec_fflush_fd(conn, conn->sock[SECONDARYSOCKET]);
#endif
/* shut down the socket to inform the server we're done */
- sclose(conn->secondarysocket);
- conn->secondarysocket = -1;
+ sclose(conn->sock[SECONDARYSOCKET]);
+ conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
- if(!ftp->no_transfer) {
+ if(!ftp->no_transfer && !status) {
/* Let's see what the server says about the transfer we just performed,
- but lower the timeout as sometimes this connection has died while
- the data has been transfered. This happens when doing through NATs
- etc that abandon old silent connections.
- */
+ * but lower the timeout as sometimes this connection has died while the
+ * data has been transfered. This happens when doing through NATs etc that
+ * abandon old silent connections.
+ */
ftp->response_time = 60; /* give it only a minute for now */
result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
ftp->response_time = 3600; /* set this back to one hour waits */
-
+
if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
failf(data, "control connection looks dead");
return result;
@@ -665,10 +849,15 @@ CURLcode Curl_ftp_done(struct connectdata *conn)
/* clear these for next connection */
ftp->no_transfer = FALSE;
- ftp->dont_check = FALSE;
+ ftp->dont_check = FALSE;
+
+ if (!result && conn->sec_conn) { /* 3rd party transfer */
+ /* "done" with the secondary connection */
+ result = Curl_ftp_done(conn->sec_conn, status);
+ }
/* Send any post-transfer QUOTE strings? */
- if(!result && data->set.postquote)
+ if(!status && !result && data->set.postquote)
result = ftp_sendquote(conn, data->set.postquote);
return result;
@@ -682,11 +871,11 @@ CURLcode Curl_ftp_done(struct connectdata *conn)
* The quote list is passed as an argument.
*/
-static
+static
CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
{
struct curl_slist *item;
- int nread;
+ ssize_t nread;
int ftpcode;
CURLcode result;
@@ -713,33 +902,6 @@ CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
/***********************************************************************
*
- * ftp_cwd()
- *
- * Send 'CWD' to the remote server to Change Working Directory.
- * It is the ftp version of the unix 'cd' command.
- */
-static
-CURLcode ftp_cwd(struct connectdata *conn, char *path)
-{
- int nread;
- int ftpcode;
- CURLcode result;
-
- FTPSENDF(conn, "CWD %s", path);
- result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
- if (result)
- return result;
-
- if (ftpcode != 250) {
- failf(conn->data, "Couldn't cd to %s", path);
- return CURLE_FTP_ACCESS_DENIED;
- }
-
- return CURLE_OK;
-}
-
-/***********************************************************************
- *
* ftp_getfiletime()
*
* Get the timestamp of the given file.
@@ -749,7 +911,7 @@ CURLcode ftp_getfiletime(struct connectdata *conn, char *file)
{
CURLcode result=CURLE_OK;
int ftpcode; /* for ftp status */
- int nread;
+ ssize_t nread;
char *buf = conn->data->state.buffer;
/* we have requested to get the modified-time of the file, this is yet
@@ -770,8 +932,9 @@ CURLcode ftp_getfiletime(struct connectdata *conn, char *file)
&year, &month, &day, &hour, &minute, &second)) {
/* we have a time, reformat it */
time_t secs=time(NULL);
- sprintf(buf, "%04d%02d%02d %02d:%02d:%02d",
- year, month, day, hour, minute, second);
+ snprintf(buf, sizeof(conn->data->state.buffer),
+ "%04d%02d%02d %02d:%02d:%02d GMT",
+ year, month, day, hour, minute, second);
/* now, convert this into a time() value: */
conn->data->info.filetime = curl_getdate(buf, &secs);
}
@@ -800,7 +963,7 @@ static CURLcode ftp_transfertype(struct connectdata *conn,
{
struct SessionHandle *data = conn->data;
int ftpcode;
- int nread;
+ ssize_t nread;
CURLcode result;
FTPSENDF(conn, "TYPE %s", ascii?"A":"I");
@@ -808,7 +971,7 @@ static CURLcode ftp_transfertype(struct connectdata *conn,
result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
if(result)
return result;
-
+
if(ftpcode != 200) {
failf(data, "Couldn't set %s mode",
ascii?"ASCII":"binary");
@@ -827,11 +990,11 @@ static CURLcode ftp_transfertype(struct connectdata *conn,
static
CURLcode ftp_getsize(struct connectdata *conn, char *file,
- ssize_t *size)
+ curl_off_t *size)
{
struct SessionHandle *data = conn->data;
int ftpcode;
- int nread;
+ ssize_t nread;
char *buf=data->state.buffer;
CURLcode result;
@@ -842,7 +1005,7 @@ CURLcode ftp_getsize(struct connectdata *conn, char *file,
if(ftpcode == 213) {
/* get the size from the ascii string: */
- *size = atoi(buf+4);
+ *size = curlx_strtoofft(buf+4, NULL, 0);
}
else
return CURLE_FTP_COULDNT_GET_SIZE;
@@ -861,125 +1024,13 @@ CURLcode ftp_getsize(struct connectdata *conn, char *file,
*/
static void
ftp_pasv_verbose(struct connectdata *conn,
- Curl_ipconnect *addr,
+ Curl_addrinfo *ai,
char *newhost, /* ascii version */
int port)
{
-#ifndef ENABLE_IPV6
- /*****************************************************************
- *
- * IPv4-only code section
- */
-
- struct in_addr in;
- struct hostent * answer;
-
-#ifdef HAVE_INET_NTOA_R
- char ntoa_buf[64];
-#endif
- /* The array size trick below is to make this a large chunk of memory
- suitably 8-byte aligned on 64-bit platforms. This was thoughtfully
- suggested by Philip Gladstone. */
- long bigbuf[9000 / sizeof(long)];
-
-#if defined(HAVE_INET_ADDR)
- in_addr_t address;
-# if defined(HAVE_GETHOSTBYADDR_R)
- int h_errnop;
-# endif
- char *hostent_buf = (char *)bigbuf; /* get a char * to the buffer */
- (void)hostent_buf;
- address = inet_addr(newhost);
-# ifdef HAVE_GETHOSTBYADDR_R
-
-# ifdef HAVE_GETHOSTBYADDR_R_5
- /* AIX, Digital Unix (OSF1, Tru64) style:
- extern int gethostbyaddr_r(char *addr, size_t len, int type,
- struct hostent *htent, struct hostent_data *ht_data); */
-
- /* Fred Noz helped me try this out, now it at least compiles! */
-
- /* Bjorn Reese (November 28 2001):
- The Tru64 man page on gethostbyaddr_r() says that
- the hostent struct must be filled with zeroes before the call to
- gethostbyaddr_r().
-
- ... as must be struct hostent_data Craig Markwardt 19 Sep 2002. */
-
- memset(hostent_buf, 0, sizeof(struct hostent)+sizeof(struct hostent_data));
-
- if(gethostbyaddr_r((char *) &address,
- sizeof(address), AF_INET,
- (struct hostent *)hostent_buf,
- (struct hostent_data *)(hostent_buf + sizeof(*answer))))
- answer=NULL;
- else
- answer=(struct hostent *)hostent_buf;
-
-# endif
-# ifdef HAVE_GETHOSTBYADDR_R_7
- /* Solaris and IRIX */
- answer = gethostbyaddr_r((char *) &address, sizeof(address), AF_INET,
- (struct hostent *)bigbuf,
- hostent_buf + sizeof(*answer),
- sizeof(bigbuf) - sizeof(*answer),
- &h_errnop);
-# endif
-# ifdef HAVE_GETHOSTBYADDR_R_8
- /* Linux style */
- if(gethostbyaddr_r((char *) &address, sizeof(address), AF_INET,
- (struct hostent *)hostent_buf,
- hostent_buf + sizeof(*answer),
- sizeof(bigbuf) - sizeof(*answer),
- &answer,
- &h_errnop))
- answer=NULL; /* error */
-# endif
-
-# else
- answer = gethostbyaddr((char *) &address, sizeof(address), AF_INET);
-# endif
-#else
- answer = NULL;
-#endif
- (void) memcpy(&in.s_addr, addr, sizeof (Curl_ipconnect));
- infof(conn->data, "Connecting to %s (%s) port %u\n",
- answer?answer->h_name:newhost,
-#if defined(HAVE_INET_NTOA_R)
- inet_ntoa_r(in, ntoa_buf, sizeof(ntoa_buf)),
-#else
- inet_ntoa(in),
-#endif
- port);
-
-#else
- /*****************************************************************
- *
- * IPv6-only code section
- */
- char hbuf[NI_MAXHOST]; /* ~1KB */
- char nbuf[NI_MAXHOST]; /* ~1KB */
- char sbuf[NI_MAXSERV]; /* around 32 */
-#ifdef NI_WITHSCOPEID
- const int niflags = NI_NUMERICHOST | NI_NUMERICSERV | NI_WITHSCOPEID;
-#else
- const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
-#endif
- port = 0; /* unused, prevent warning */
- if (getnameinfo(addr->ai_addr, addr->ai_addrlen,
- nbuf, sizeof(nbuf), sbuf, sizeof(sbuf), niflags)) {
- snprintf(nbuf, sizeof(nbuf), "?");
- snprintf(sbuf, sizeof(sbuf), "?");
- }
-
- if (getnameinfo(addr->ai_addr, addr->ai_addrlen,
- hbuf, sizeof(hbuf), NULL, 0, 0)) {
- infof(conn->data, "Connecting to %s (%s) port %s\n", nbuf, newhost, sbuf);
- }
- else {
- infof(conn->data, "Connecting to %s (%s) port %s\n", hbuf, nbuf, sbuf);
- }
-#endif
+ char buf[256];
+ Curl_printable_address(ai, buf, sizeof(buf));
+ infof(conn->data, "Connecting to %s (%s) port %d\n", newhost, buf, port);
}
/***********************************************************************
@@ -995,8 +1046,8 @@ static
CURLcode ftp_use_port(struct connectdata *conn)
{
struct SessionHandle *data=conn->data;
- int portsock=-1;
- int nread;
+ curl_socket_t portsock= CURL_SOCKET_BAD;
+ ssize_t nread;
int ftpcode; /* receive FTP response codes in this */
CURLcode result;
@@ -1013,77 +1064,95 @@ CURLcode ftp_use_port(struct connectdata *conn)
char hbuf[NI_MAXHOST];
struct sockaddr *sa=(struct sockaddr *)&ss;
-#ifdef NI_WITHSCOPEID
- const int niflags = NI_NUMERICHOST | NI_NUMERICSERV | NI_WITHSCOPEID;
-#else
- const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
-#endif
unsigned char *ap;
unsigned char *pp;
- char portmsgbuf[4096], tmp[4096];
+ char portmsgbuf[1024], tmp[1024];
const char *mode[] = { "EPRT", "LPRT", "PORT", NULL };
char **modep;
+ int rc;
+ int error;
/*
* we should use Curl_if2ip? given pickiness of recent ftpd,
* I believe we should use the same address as the control connection.
*/
sslen = sizeof(ss);
- if (getsockname(conn->firstsocket, (struct sockaddr *)&ss, &sslen) < 0)
+ rc = getsockname(conn->sock[FIRSTSOCKET], (struct sockaddr *)&ss, &sslen);
+ if(rc < 0) {
+ failf(data, "getsockname() returned %d\n", rc);
return CURLE_FTP_PORT_FAILED;
-
- if (getnameinfo((struct sockaddr *)&ss, sslen, hbuf, sizeof(hbuf), NULL, 0,
- niflags))
+ }
+
+ rc = getnameinfo((struct sockaddr *)&ss, sslen, hbuf, sizeof(hbuf), NULL, 0,
+ NIFLAGS);
+ if(rc) {
+ failf(data, "getnameinfo() returned %d\n", rc);
return CURLE_FTP_PORT_FAILED;
+ }
memset(&hints, 0, sizeof(hints));
hints.ai_family = sa->sa_family;
/*hints.ai_family = ss.ss_family;
- this way can be used if sockaddr_storage is properly defined, as glibc
+ this way can be used if sockaddr_storage is properly defined, as glibc
2.1.X doesn't do*/
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
- if (getaddrinfo(hbuf, (char *)"0", &hints, &res))
+ rc = getaddrinfo(hbuf, NULL, &hints, &res);
+ if(rc) {
+ failf(data, "getaddrinfo() returned %d\n", rc);
return CURLE_FTP_PORT_FAILED;
-
- portsock = -1;
+ }
+
+ portsock = CURL_SOCKET_BAD;
+ error = 0;
for (ai = res; ai; ai = ai->ai_next) {
+ /*
+ * Workaround for AIX5 getaddrinfo() problem (it doesn't set ai_socktype):
+ */
+ if (ai->ai_socktype == 0)
+ ai->ai_socktype = hints.ai_socktype;
+
portsock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
- if (portsock < 0)
+ if (portsock == CURL_SOCKET_BAD) {
+ error = Curl_ourerrno();
continue;
+ }
if (bind(portsock, ai->ai_addr, ai->ai_addrlen) < 0) {
+ error = Curl_ourerrno();
sclose(portsock);
- portsock = -1;
+ portsock = CURL_SOCKET_BAD;
continue;
}
-
+
if (listen(portsock, 1) < 0) {
+ error = Curl_ourerrno();
sclose(portsock);
- portsock = -1;
+ portsock = CURL_SOCKET_BAD;
continue;
}
-
+
break;
}
freeaddrinfo(res);
- if (portsock < 0) {
- failf(data, "%s", strerror(errno));
+ if (portsock == CURL_SOCKET_BAD) {
+ failf(data, "%s", Curl_strerror(conn,error));
return CURLE_FTP_PORT_FAILED;
}
sslen = sizeof(ss);
if (getsockname(portsock, sa, &sslen) < 0) {
- failf(data, "%s", strerror(errno));
+ failf(data, "%s", Curl_strerror(conn,Curl_ourerrno()));
return CURLE_FTP_PORT_FAILED;
}
- for (modep = (char **)mode; modep && *modep; modep++) {
+ for (modep = (char **)(data->set.ftp_use_eprt?&mode[0]:&mode[2]);
+ modep && *modep; modep++) {
int lprtaf, eprtaf;
int alen=0, plen=0;
-
+
switch (sa->sa_family) {
case AF_INET:
ap = (unsigned char *)&((struct sockaddr_in *)&ss)->sin_addr;
@@ -1111,24 +1180,26 @@ CURLcode ftp_use_port(struct connectdata *conn)
if (eprtaf < 0)
continue;
if (getnameinfo((struct sockaddr *)&ss, sslen,
- portmsgbuf, sizeof(portmsgbuf), tmp, sizeof(tmp), niflags))
+ portmsgbuf, sizeof(portmsgbuf), tmp, sizeof(tmp),
+ NIFLAGS))
continue;
/* do not transmit IPv6 scope identifier to the wire */
if (sa->sa_family == AF_INET6) {
char *q = strchr(portmsgbuf, '%');
- if (q)
- *q = '\0';
+ if (q)
+ *q = '\0';
}
result = Curl_ftpsendf(conn, "%s |%d|%s|%s|", *modep, eprtaf,
portmsgbuf, tmp);
if(result)
return result;
- } else if (strcmp(*modep, "LPRT") == 0 ||
- strcmp(*modep, "PORT") == 0) {
+ }
+ else if (strcmp(*modep, "LPRT") == 0 ||
+ strcmp(*modep, "PORT") == 0) {
int i;
-
+
if (strcmp(*modep, "LPRT") == 0 && lprtaf < 0)
continue;
if (strcmp(*modep, "PORT") == 0 && sa->sa_family != AF_INET)
@@ -1148,55 +1219,55 @@ CURLcode ftp_use_port(struct connectdata *conn)
snprintf(tmp, sizeof(tmp), ",%u", ap[i]);
else
snprintf(tmp, sizeof(tmp), "%u", ap[i]);
-
+
if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >=
sizeof(portmsgbuf)) {
continue;
}
}
-
+
if (strcmp(*modep, "LPRT") == 0) {
snprintf(tmp, sizeof(tmp), ",%d", plen);
-
+
if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf))
continue;
}
for (i = 0; i < plen; i++) {
snprintf(tmp, sizeof(tmp), ",%u", pp[i]);
-
+
if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >=
sizeof(portmsgbuf)) {
continue;
}
}
-
+
result = Curl_ftpsendf(conn, "%s %s", *modep, portmsgbuf);
if(result)
return result;
}
-
+
result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
if(result)
return result;
-
+
if (ftpcode != 200) {
- failf(data, "Server does not grok %s", *modep);
continue;
}
else
break;
}
-
+
if (!*modep) {
sclose(portsock);
+ failf(data, "PORT command attempts failed");
return CURLE_FTP_PORT_FAILED;
}
/* we set the secondary socket variable to this for now, it
is only so that the cleanup function will close it in case
we fail before the true secondary stuff is made */
- conn->secondarysocket = portsock;
-
+ conn->sock[SECONDARYSOCKET] = portsock;
+
#else
/******************************************************************
*
@@ -1204,34 +1275,51 @@ CURLcode ftp_use_port(struct connectdata *conn)
*
*/
struct sockaddr_in sa;
- struct Curl_dns_entry *h=NULL;
unsigned short porttouse;
char myhost[256] = "";
bool sa_filled_in = FALSE;
+ Curl_addrinfo *addr = NULL;
+ unsigned short ip[4];
if(data->set.ftpport) {
- if(Curl_if2ip(data->set.ftpport, myhost, sizeof(myhost))) {
- h = Curl_resolv(data, myhost, 0);
- }
+ in_addr_t in;
+
+ /* First check if the given name is an IP address */
+ in=inet_addr(data->set.ftpport);
+
+ if(in != CURL_INADDR_NONE)
+ /* this is an IPv4 address */
+ addr = Curl_ip2addr(in, data->set.ftpport, 0);
else {
- size_t len = strlen(data->set.ftpport);
- if(len>1)
- h = Curl_resolv(data, data->set.ftpport, 0);
- if(h)
- strcpy(myhost, data->set.ftpport); /* buffer overflow risk */
- }
- }
- if(! *myhost) {
+ if(Curl_if2ip(data->set.ftpport, myhost, sizeof(myhost))) {
+ /* The interface to IP conversion provided a dotted address */
+ in=inet_addr(myhost);
+ addr = Curl_ip2addr(in, myhost, 0);
+ }
+ else if(strlen(data->set.ftpport)> 1) {
+ /* might be a host name! */
+ struct Curl_dns_entry *h=NULL;
+ int rc = Curl_resolv(conn, myhost, 0, &h);
+ if(rc == CURLRESOLV_PENDING)
+ rc = Curl_wait_for_resolv(conn, &h);
+ if(h) {
+ addr = h->addr;
+ /* when we return from this function, we can forget about this entry
+ to we can unlock it now already */
+ Curl_resolv_unlock(data, h);
+ } /* (h) */
+ } /* strlen */
+ } /* CURL_INADDR_NONE */
+ } /* data->set.ftpport */
+
+ if(!addr) {
/* pick a suitable default here */
-#ifdef __hpux
- int sslen;
-#else
socklen_t sslen;
-#endif
-
+
sslen = sizeof(sa);
- if (getsockname(conn->firstsocket, (struct sockaddr *)&sa, &sslen) < 0) {
+ if (getsockname(conn->sock[FIRSTSOCKET],
+ (struct sockaddr *)&sa, &sslen) < 0) {
failf(data, "getsockname() failed");
return CURLE_FTP_PORT_FAILED;
}
@@ -1239,39 +1327,28 @@ CURLcode ftp_use_port(struct connectdata *conn)
sa_filled_in = TRUE; /* the sa struct is filled in */
}
- if(h)
- /* when we return from here, we can forget about this */
- Curl_resolv_unlock(h);
+ if (addr || sa_filled_in) {
+ portsock = socket(AF_INET, SOCK_STREAM, 0);
+ if(CURL_SOCKET_BAD != portsock) {
+ socklen_t size;
- if ( h || sa_filled_in) {
- if( (portsock = (int)socket(AF_INET, SOCK_STREAM, 0)) >= 0 ) {
- int size;
-
/* we set the secondary socket variable to this for now, it
is only so that the cleanup function will close it in case
we fail before the true secondary stuff is made */
- conn->secondarysocket = portsock;
+ conn->sock[SECONDARYSOCKET] = portsock;
if(!sa_filled_in) {
- memset((char *)&sa, 0, sizeof(sa));
- memcpy((char *)&sa.sin_addr,
- h->addr->h_addr,
- h->addr->h_length);
- sa.sin_family = AF_INET;
+ memcpy(&sa, addr->ai_addr, sizeof(sa));
sa.sin_addr.s_addr = INADDR_ANY;
}
sa.sin_port = 0;
size = sizeof(sa);
-
+
if(bind(portsock, (struct sockaddr *)&sa, size) >= 0) {
/* we succeeded to bind */
struct sockaddr_in add;
-#ifdef __hpux
- int socksize = sizeof(add);
-#else
socklen_t socksize = sizeof(add);
-#endif
if(getsockname(portsock, (struct sockaddr *) &add,
&socksize)<0) {
@@ -1279,7 +1356,7 @@ CURLcode ftp_use_port(struct connectdata *conn)
return CURLE_FTP_PORT_FAILED;
}
porttouse = ntohs(add.sin_port);
-
+
if ( listen(portsock, 1) < 0 ) {
failf(data, "listen(2) failed on socket");
return CURLE_FTP_PORT_FAILED;
@@ -1296,39 +1373,34 @@ CURLcode ftp_use_port(struct connectdata *conn)
}
}
else {
- failf(data, "could't find my own IP address (%s)", myhost);
+ failf(data, "could't find IP address to use");
return CURLE_FTP_PORT_FAILED;
}
- {
-#ifdef HAVE_INET_NTOA_R
- char ntoa_buf[64];
-#endif
- struct in_addr in;
- unsigned short ip[5];
- (void) memcpy(&in.s_addr,
- h?*h->addr->h_addr_list:(char *)&sa.sin_addr.s_addr,
- sizeof (in.s_addr));
-
-#ifdef HAVE_INET_NTOA_R
- /* ignore the return code from inet_ntoa_r() as it is int or
- char * depending on system */
- inet_ntoa_r(in, ntoa_buf, sizeof(ntoa_buf));
- sscanf( ntoa_buf, "%hu.%hu.%hu.%hu",
- &ip[0], &ip[1], &ip[2], &ip[3]);
-#else
- sscanf( inet_ntoa(in), "%hu.%hu.%hu.%hu",
- &ip[0], &ip[1], &ip[2], &ip[3]);
-#endif
+
+ if(sa_filled_in)
+ Curl_inet_ntop(AF_INET, &((struct sockaddr_in *)&sa)->sin_addr,
+ myhost, sizeof(myhost));
+ else
+ Curl_printable_address(addr, myhost, sizeof(myhost));
+
+ if(4 == sscanf(myhost, "%hu.%hu.%hu.%hu",
+ &ip[0], &ip[1], &ip[2], &ip[3])) {
+
infof(data, "Telling server to connect to %d.%d.%d.%d:%d\n",
ip[0], ip[1], ip[2], ip[3], porttouse);
-
+
result=Curl_ftpsendf(conn, "PORT %d,%d,%d,%d,%d,%d",
ip[0], ip[1], ip[2], ip[3],
porttouse >> 8,
porttouse & 255);
if(result)
return result;
+
}
+ else
+ return CURLE_FTP_PORT_FAILED;
+
+ Curl_freeaddrinfo(addr);
result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
if(result)
@@ -1357,12 +1429,13 @@ CURLcode ftp_use_pasv(struct connectdata *conn,
bool *connected)
{
struct SessionHandle *data = conn->data;
- int nread;
+ ssize_t nread;
char *buf = data->state.buffer; /* this is our buffer */
int ftpcode; /* receive FTP response codes in this */
CURLcode result;
struct Curl_dns_entry *addr=NULL;
- Curl_ipconnect *conninfo;
+ Curl_addrinfo *conninfo;
+ int rc;
/*
Here's the excecutive summary on what to do:
@@ -1378,27 +1451,17 @@ CURLcode ftp_use_pasv(struct connectdata *conn,
*/
-#if 1
const char *mode[] = { "EPSV", "PASV", NULL };
int results[] = { 229, 227, 0 };
-#else
-#if 0
- char *mode[] = { "EPSV", "LPSV", "PASV", NULL };
- int results[] = { 229, 228, 227, 0 };
-#else
- const char *mode[] = { "PASV", NULL };
- int results[] = { 227, 0 };
-#endif
-#endif
int modeoff;
unsigned short connectport; /* the local port connect() should use! */
unsigned short newport=0; /* remote port, not necessary the local one */
-
+
/* newhost must be able to hold a full IP-style address in ASCII, which
in the IPv6 case means 5*8-1 = 39 letters */
char newhost[48];
char *newhostp=NULL;
-
+
for (modeoff = (data->set.ftp_use_epsv?0:1);
mode[modeoff]; modeoff++) {
result = Curl_ftpsendf(conn, "%s", mode[modeoff]);
@@ -1430,7 +1493,7 @@ CURLcode ftp_use_pasv(struct connectdata *conn,
* "227 Data transfer will passively listen to 127,0,0,1,4,51"
* "227 Entering passive mode. 127,0,0,1,4,51"
*/
-
+
while(*str) {
if (6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
&ip[0], &ip[1], &ip[2], &ip[3],
@@ -1444,11 +1507,11 @@ CURLcode ftp_use_pasv(struct connectdata *conn,
return CURLE_FTP_WEIRD_227_FORMAT;
}
- sprintf(newhost, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
+ snprintf(newhost, sizeof(newhost),
+ "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
newhostp = newhost;
- newport = (unsigned short)((port[0]<<8) + port[1]);
+ newport = (port[0]<<8) + port[1];
}
-#if 1
else if (229 == results[modeoff]) {
char *ptr = strchr(buf, '(');
if(ptr) {
@@ -1461,12 +1524,24 @@ CURLcode ftp_use_pasv(struct connectdata *conn,
&separator[2],
&num,
&separator[3])) {
- /* the four separators should be identical */
- newport = (unsigned short)num;
+ char sep1 = separator[0];
+ int i;
- /* we should use the same host we already are connected to */
- newhostp = conn->name;
- }
+ /* The four separators should be identical, or else this is an oddly
+ formatted reply and we bail out immediately. */
+ for(i=1; i<4; i++) {
+ if(separator[i] != sep1) {
+ ptr=NULL; /* set to NULL to signal error */
+ break;
+ }
+ }
+ if(ptr) {
+ newport = num;
+
+ /* we should use the same host we already are connected to */
+ newhostp = conn->host.name;
+ }
+ }
else
ptr=NULL;
}
@@ -1475,11 +1550,10 @@ CURLcode ftp_use_pasv(struct connectdata *conn,
return CURLE_FTP_WEIRD_PASV_REPLY;
}
}
-#endif
else
return CURLE_FTP_CANT_RECONNECT;
- if(data->change.proxy) {
+ if(data->change.proxy && *data->change.proxy) {
/*
* This is a tunnel through a http proxy and we need to connect to the
* proxy again here.
@@ -1487,51 +1561,57 @@ CURLcode ftp_use_pasv(struct connectdata *conn,
* We don't want to rely on a former host lookup that might've expired
* now, instead we remake the lookup here and now!
*/
- addr = Curl_resolv(data, conn->proxyhost, conn->port);
+ rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &addr);
+ if(rc == CURLRESOLV_PENDING)
+ rc = Curl_wait_for_resolv(conn, &addr);
+
connectport =
- (unsigned short)conn->port; /* we connect to the proxy's port */
+ (unsigned short)conn->port; /* we connect to the proxy's port */
}
else {
/* normal, direct, ftp connection */
- addr = Curl_resolv(data, newhostp, newport);
+ rc = Curl_resolv(conn, newhostp, newport, &addr);
+ if(rc == CURLRESOLV_PENDING)
+ rc = Curl_wait_for_resolv(conn, &addr);
+
if(!addr) {
failf(data, "Can't resolve new host %s:%d", newhostp, newport);
return CURLE_FTP_CANT_GET_HOST;
}
connectport = newport; /* we connect to the remote port */
}
-
+
result = Curl_connecthost(conn,
addr,
- connectport,
- &conn->secondarysocket,
+ &conn->sock[SECONDARYSOCKET],
&conninfo,
connected);
- Curl_resolv_unlock(addr); /* we're done using this address */
+ Curl_resolv_unlock(data, addr); /* we're done using this address */
+
+ if(result)
+ return result;
/*
* When this is used from the multi interface, this might've returned with
* the 'connected' set to FALSE and thus we are now awaiting a non-blocking
* connect to connect and we should not be "hanging" here waiting.
*/
-
- if((CURLE_OK == result) &&
- data->set.verbose)
+
+ if(data->set.verbose)
/* this just dumps information about this second connection */
ftp_pasv_verbose(conn, conninfo, newhostp, connectport);
-
- if(CURLE_OK != result)
- return result;
- if (data->set.tunnel_thru_httpproxy) {
+#ifndef CURL_DISABLE_HTTP
+ if(conn->bits.tunnel_proxy) {
/* We want "seamless" FTP operations through HTTP proxy tunnel */
- result = Curl_ConnectHTTPProxyTunnel(conn, conn->secondarysocket,
+ result = Curl_ConnectHTTPProxyTunnel(conn, SECONDARYSOCKET,
newhostp, newport);
if(CURLE_OK != result)
return result;
}
+#endif /* CURL_DISABLE_HTTP */
return CURLE_OK;
}
@@ -1548,12 +1628,12 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
struct SessionHandle *data=conn->data;
char *buf = data->state.buffer; /* this is our buffer */
CURLcode result;
- int nread;
+ ssize_t nread;
int ftpcode; /* for ftp status */
/* the ftp struct is already inited in Curl_ftp_connect() */
struct FTP *ftp = conn->proto.ftp;
- long *bytecountp = ftp->bytecountp;
+ curl_off_t *bytecountp = ftp->bytecountp;
if(data->set.upload) {
@@ -1585,7 +1665,7 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
if(conn->resume_from < 0 ) {
/* we could've got a specified offset from the command line,
but now we know we didn't */
- ssize_t gottensize;
+ curl_off_t gottensize;
if(CURLE_OK != ftp_getsize(conn, ftp->file, &gottensize)) {
failf(data, "Couldn't get remote file size");
@@ -1596,7 +1676,7 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
if(conn->resume_from) {
/* do we still game? */
- int passed=0;
+ curl_off_t passed=0;
/* enable append instead */
data->set.ftp_append = 1;
@@ -1604,19 +1684,20 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
input. If we knew it was a proper file we could've just
fseek()ed but we only have a stream here */
do {
- size_t readthisamountnow = (conn->resume_from - passed);
- size_t actuallyread;
+ curl_off_t readthisamountnow = (conn->resume_from - passed);
+ curl_off_t actuallyread;
if(readthisamountnow > BUFSIZE)
readthisamountnow = BUFSIZE;
- actuallyread =
- conn->fread(data->state.buffer, 1, readthisamountnow,
+ actuallyread = (curl_off_t)
+ conn->fread(data->state.buffer, 1, (size_t)readthisamountnow,
conn->fread_in);
- passed += (int)actuallyread;
+ passed += actuallyread;
if(actuallyread != readthisamountnow) {
- failf(data, "Could only read %d bytes from the input", passed);
+ failf(data, "Could only read %" FORMAT_OFF_T
+ " bytes from the input", passed);
return CURLE_FTP_COULDNT_USE_REST;
}
}
@@ -1631,10 +1712,10 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
/* no data to transfer */
result=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
-
+
/* Set no_transfer so that we won't get any error in
* Curl_ftp_done() because we didn't transfer anything! */
- ftp->no_transfer = TRUE;
+ ftp->no_transfer = TRUE;
return CURLE_OK;
}
@@ -1664,11 +1745,20 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
if(data->set.ftp_use_port) {
/* PORT means we are now awaiting the server to connect to us. */
- result = AllowServerConnect(data, conn, conn->secondarysocket);
+ result = AllowServerConnect(conn);
if( result )
return result;
}
+ if(conn->ssl[SECONDARYSOCKET].use) {
+ /* since we only have a plaintext TCP connection here, we must now
+ do the TLS stuff */
+ infof(data, "Doing the SSL/TLS handshake on the data stream\n");
+ result = Curl_SSLConnect(conn, SECONDARYSOCKET);
+ if(result)
+ return result;
+ }
+
*bytecountp=0;
/* When we know we're uploading a specified file, we can get the file
@@ -1677,26 +1767,26 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
Curl_pgrsSetUploadSize(data, data->set.infilesize);
result = Curl_Transfer(conn, -1, -1, FALSE, NULL, /* no download */
- conn->secondarysocket, bytecountp);
+ SECONDARYSOCKET, bytecountp);
if(result)
return result;
-
+
}
- else if(!data->set.no_body) {
+ else if(!conn->bits.no_body) {
/* Retrieve file or directory */
bool dirlist=FALSE;
- long downloadsize=-1;
+ curl_off_t downloadsize=-1;
if(conn->bits.use_range && conn->range) {
- long from, to;
- int totalsize=-1;
+ curl_off_t from, to;
+ curl_off_t totalsize=-1;
char *ptr;
char *ptr2;
- from=strtol(conn->range, &ptr, 0);
+ from=curlx_strtoofft(conn->range, &ptr, 0);
while(ptr && *ptr && (isspace((int)*ptr) || (*ptr=='-')))
ptr++;
- to=strtol(ptr, &ptr2, 0);
+ to=curlx_strtoofft(ptr, &ptr2, 0);
if(ptr == ptr2) {
/* we didn't get any digit */
to=-1;
@@ -1704,25 +1794,26 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
if((-1 == to) && (from>=0)) {
/* X - */
conn->resume_from = from;
- infof(data, "FTP RANGE %d to end of file\n", from);
+ infof(data, "FTP RANGE %" FORMAT_OFF_T " to end of file\n", from);
}
else if(from < 0) {
/* -Y */
totalsize = -from;
conn->maxdownload = -from;
conn->resume_from = from;
- infof(data, "FTP RANGE the last %d bytes\n", totalsize);
+ infof(data, "FTP RANGE the last %" FORMAT_OFF_T " bytes\n", totalsize);
}
else {
/* X-Y */
totalsize = to-from;
conn->maxdownload = totalsize+1; /* include the last mentioned byte */
conn->resume_from = from;
- infof(data, "FTP RANGE from %d getting %d bytes\n", from,
- conn->maxdownload);
+ infof(data, "FTP RANGE from %" FORMAT_OFF_T
+ " getting %" FORMAT_OFF_T " bytes\n", from, conn->maxdownload);
}
- infof(data, "range-download from %d to %d, totally %d bytes\n",
- from, to, totalsize);
+ infof(data, "range-download from %" FORMAT_OFF_T
+ " to %" FORMAT_OFF_T ", totally %" FORMAT_OFF_T " bytes\n",
+ from, to, conn->maxdownload);
ftp->dont_check = TRUE; /* dont check for successful transfer */
}
@@ -1746,14 +1837,14 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
(data->set.ftp_list_only?"NLST":"LIST"));
}
else {
- ssize_t foundsize;
+ curl_off_t foundsize;
/* Set type to binary (unless specified ASCII) */
result = ftp_transfertype(conn, data->set.ftp_ascii);
if(result)
return result;
- /* Send any PREQUOTE strings after transfer type is set? (Wesley Laxton)*/
+ /* Send any PREQUOTE strings after transfer type is set? */
if(data->set.prequote) {
if ((result = ftp_sendquote(conn, data->set.prequote)) != CURLE_OK)
return result;
@@ -1763,8 +1854,13 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
downloads and when talking to servers that don't give away the size
in the RETR response line. */
result = ftp_getsize(conn, ftp->file, &foundsize);
- if(CURLE_OK == result)
+ if(CURLE_OK == result) {
+ if (data->set.max_filesize && foundsize > data->set.max_filesize) {
+ failf(data, "Maximum file size exceeded");
+ return CURLE_FILESIZE_EXCEEDED;
+ }
downloadsize = foundsize;
+ }
if(conn->resume_from) {
@@ -1791,7 +1887,8 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
if(conn->resume_from< 0) {
/* We're supposed to download the last abs(from) bytes */
if(foundsize < -conn->resume_from) {
- failf(data, "Offset (%d) was beyond file size (%d)",
+ failf(data, "Offset (%" FORMAT_OFF_T
+ ") was beyond file size (%" FORMAT_OFF_T ")",
conn->resume_from, foundsize);
return CURLE_FTP_BAD_DOWNLOAD_RESUME;
}
@@ -1802,7 +1899,8 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
}
else {
if(foundsize < conn->resume_from) {
- failf(data, "Offset (%d) was beyond file size (%d)",
+ failf(data, "Offset (%" FORMAT_OFF_T
+ ") was beyond file size (%" FORMAT_OFF_T ")",
conn->resume_from, foundsize);
return CURLE_FTP_BAD_DOWNLOAD_RESUME;
}
@@ -1821,12 +1919,13 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
ftp->no_transfer = TRUE;
return CURLE_OK;
}
-
+
/* Set resume file transfer offset */
- infof(data, "Instructs server to resume from offset %d\n",
+ infof(data, "Instructs server to resume from offset %" FORMAT_OFF_T
+ "\n",
conn->resume_from);
- FTPSENDF(conn, "REST %d", conn->resume_from);
+ FTPSENDF(conn, "REST %" FORMAT_OFF_T, conn->resume_from);
result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
if(result)
@@ -1851,24 +1950,34 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
A;
150 Opening BINARY mode data connection for /etc/passwd (2241
bytes). (ok, the file is being transfered)
-
+
B:
- 150 Opening ASCII mode data connection for /bin/ls
+ 150 Opening ASCII mode data connection for /bin/ls
C:
150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes).
D:
150 Opening ASCII mode data connection for /linux/fisk/kpanelrc (0.0.0.0,0) (545 bytes).
-
+
E:
125 Data connection already open; Transfer starting. */
- int size=-1; /* default unknown size */
+ curl_off_t size=-1; /* default unknown size */
+
+
+ /*
+ * It appears that there are FTP-servers that return size 0 for files
+ * when SIZE is used on the file while being in BINARY mode. To work
+ * around that (stupid) behavior, we attempt to parse the RETR response
+ * even if the SIZE returned size zero.
+ *
+ * Debugging help from Salvatore Sorrentino on February 26, 2003.
+ */
if(!dirlist &&
!data->set.ftp_ascii &&
- (-1 == downloadsize)) {
+ (downloadsize < 1)) {
/*
* It seems directory listings either don't show the size or very
* often uses size 0 anyway. ASCII transfers may very well turn out
@@ -1879,9 +1988,9 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
char *bytes;
bytes=strstr(buf, " bytes");
if(bytes--) {
- int index=(int)(bytes-buf);
+ long in=bytes-buf;
/* this is a hint there is size information in there! ;-) */
- while(--index) {
+ while(--in) {
/* scan for the parenthesis and break there */
if('(' == *bytes)
break;
@@ -1896,34 +2005,52 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
/* only if we have nothing but digits: */
if(bytes++) {
/* get the number! */
- size = atoi(bytes);
+ size = curlx_strtoofft(bytes, NULL, 0);
}
-
+
}
}
else if(downloadsize > -1)
size = downloadsize;
if(data->set.ftp_use_port) {
- result = AllowServerConnect(data, conn, conn->secondarysocket);
+ result = AllowServerConnect(conn);
if( result )
return result;
}
- infof(data, "Getting file with size: %d\n", size);
+ if(conn->ssl[SECONDARYSOCKET].use) {
+ /* since we only have a plaintext TCP connection here, we must now
+ do the TLS stuff */
+ infof(data, "Doing the SSL/TLS handshake on the data stream\n");
+ result = Curl_SSLConnect(conn, SECONDARYSOCKET);
+ if(result)
+ return result;
+ }
+
+ if(size > conn->maxdownload && conn->maxdownload > 0)
+ size = conn->size = conn->maxdownload;
+
+ infof(data, "Getting file with size: %" FORMAT_OFF_T "\n", size);
/* FTP download: */
- result=Curl_Transfer(conn, conn->secondarysocket, size, FALSE,
+ result=Curl_Transfer(conn, SECONDARYSOCKET, size, FALSE,
bytecountp,
-1, NULL); /* no upload here */
if(result)
return result;
}
else {
- failf(data, "%s", buf+4);
- return CURLE_FTP_COULDNT_RETR_FILE;
+ if(dirlist && (ftpcode == 450)) {
+ /* simply no matching files */
+ ftp->no_transfer = TRUE; /* don't think we should download anything */
+ }
+ else {
+ failf(data, "%s", buf+4);
+ return CURLE_FTP_COULDNT_RETR_FILE;
+ }
}
-
+
}
/* end of transfer */
@@ -1956,39 +2083,76 @@ CURLcode ftp_perform(struct connectdata *conn,
if ((result = ftp_sendquote(conn, data->set.quote)) != CURLE_OK)
return result;
}
-
+
/* This is a re-used connection. Since we change directory to where the
transfer is taking place, we must now get back to the original dir
where we ended up after login: */
if (conn->bits.reuse && ftp->entrypath) {
- if ((result = ftp_cwd(conn, ftp->entrypath)) != CURLE_OK)
+ if ((result = ftp_cwd_and_mkd(conn, ftp->entrypath)) != CURLE_OK)
return result;
}
- /* change directory first! */
- if(ftp->dir && ftp->dir[0]) {
- if ((result = ftp_cwd(conn, ftp->dir)) != CURLE_OK)
+ {
+ int i; /* counter for loop */
+ for (i=0; i < ftp->dirdepth; i++) {
+ /* RFC 1738 says empty components should be respected too, but
+ that is plain stupid since CWD can't be used with an empty argument */
+ if ((result = ftp_cwd_and_mkd(conn, ftp->dirs[i])) != CURLE_OK)
return result;
+ }
}
- /* Requested time of file? */
- if(data->set.get_filetime && ftp->file) {
+ /* Requested time of file or time-depended transfer? */
+ if((data->set.get_filetime || data->set.timecondition) &&
+ ftp->file) {
result = ftp_getfiletime(conn, ftp->file);
- if(result)
- return result;
+ switch( result )
+ {
+ case CURLE_FTP_COULDNT_RETR_FILE:
+ case CURLE_OK:
+ if(data->set.timecondition) {
+ if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
+ switch(data->set.timecondition) {
+ case CURL_TIMECOND_IFMODSINCE:
+ default:
+ if(data->info.filetime < data->set.timevalue) {
+ infof(data, "The requested document is not new enough\n");
+ ftp->no_transfer = TRUE; /* mark this to not transfer data */
+ return CURLE_OK;
+ }
+ break;
+ case CURL_TIMECOND_IFUNMODSINCE:
+ if(data->info.filetime > data->set.timevalue) {
+ infof(data, "The requested document is not old enough\n");
+ ftp->no_transfer = TRUE; /* mark this to not transfer data */
+ return CURLE_OK;
+ }
+ break;
+ } /* switch */
+ }
+ else {
+ infof(data, "Skipping time comparison\n");
+ }
+ }
+ break;
+ default:
+ return result;
+ } /* switch */
}
/* If we have selected NOBODY and HEADER, it means that we only want file
information. Which in FTP can't be much more than the file size and
date. */
- if(data->set.no_body && data->set.include_header && ftp->file) {
+ if(conn->bits.no_body && data->set.include_header && ftp->file) {
/* The SIZE command is _not_ RFC 959 specified, and therefor many servers
may not support it! It is however the only way we have to get a file's
size! */
- ssize_t filesize;
+ curl_off_t filesize;
+ ssize_t nread;
+ int ftpcode;
ftp->no_transfer = TRUE; /* this means no actual transfer is made */
-
+
/* Some servers return different sizes for different modes, and thus we
must set the proper type before we check the size */
result = ftp_transfertype(conn, data->set.ftp_ascii);
@@ -1999,26 +2163,40 @@ CURLcode ftp_perform(struct connectdata *conn,
result = ftp_getsize(conn, ftp->file, &filesize);
if(CURLE_OK == result) {
- sprintf(buf, "Content-Length: %d\r\n", filesize);
+ snprintf(buf, sizeof(data->state.buffer),
+ "Content-Length: %" FORMAT_OFF_T "\r\n", filesize);
result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
if(result)
return result;
}
+ /* Determine if server can respond to REST command and therefore
+ whether it can do a range */
+ FTPSENDF(conn, "REST 0", NULL);
+ result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+
+ if ((CURLE_OK == result) && (ftpcode == 350)) {
+ result = Curl_client_write(data, CLIENTWRITE_BOTH,
+ (char *)"Accept-ranges: bytes\r\n", 0);
+ if(result)
+ return result;
+ }
+
/* If we asked for a time of the file and we actually got one as
well, we "emulate" a HTTP-style header in our output. */
#ifdef HAVE_STRFTIME
if(data->set.get_filetime && (data->info.filetime>=0) ) {
struct tm *tm;
-#ifdef HAVE_LOCALTIME_R
+ time_t clock = (time_t)data->info.filetime;
+#ifdef HAVE_GMTIME_R
struct tm buffer;
- tm = (struct tm *)localtime_r((time_t*)&data->info.filetime, &buffer);
+ tm = (struct tm *)gmtime_r(&clock, &buffer);
#else
- tm = localtime((time_t *)&data->info.filetime);
+ tm = gmtime(&clock);
#endif
- /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
- strftime(buf, BUFSIZE-1, "Last-Modified: %a, %d %b %Y %H:%M:%S %Z\r\n",
+ /* format: "Tue, 15 Nov 1994 12:45:26" */
+ strftime(buf, BUFSIZE-1, "Last-Modified: %a, %d %b %Y %H:%M:%S GMT\r\n",
tm);
result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
if(result)
@@ -2029,7 +2207,7 @@ CURLcode ftp_perform(struct connectdata *conn,
return CURLE_OK;
}
- if(data->set.no_body)
+ if(conn->bits.no_body)
/* doesn't really transfer any data */
ftp->no_transfer = TRUE;
/* Get us a second connection up and connected */
@@ -2045,10 +2223,10 @@ CURLcode ftp_perform(struct connectdata *conn,
else {
/* We have chosen (this is default) to use the PASV command */
result = ftp_use_pasv(conn, connected);
- if(connected)
+ if(CURLE_OK == result && *connected)
infof(data, "Connected the data stream with PASV!\n");
}
-
+
return result;
}
@@ -2063,64 +2241,12 @@ CURLcode ftp_perform(struct connectdata *conn,
*/
CURLcode Curl_ftp(struct connectdata *conn)
{
- CURLcode retcode;
- bool connected;
+ CURLcode retcode = CURLE_OK;
- struct SessionHandle *data = conn->data;
- struct FTP *ftp;
- int dirlength=0; /* 0 forces strlen() */
-
- /* the ftp struct is already inited in ftp_connect() */
- ftp = conn->proto.ftp;
-
- /* We split the path into dir and file parts *before* we URLdecode
- it */
- ftp->file = strrchr(conn->ppath, '/');
- if(ftp->file) {
- if(ftp->file != conn->ppath)
- /* don't count the traling slash */
- dirlength=(int)(ftp->file-conn->ppath);
-
- ftp->file++; /* point to the first letter in the file name part or
- remain NULL */
- }
- else {
- ftp->file = conn->ppath; /* there's only a file part */
- }
-
- if(*ftp->file) {
- ftp->file = curl_unescape(ftp->file, 0);
- if(NULL == ftp->file) {
- failf(data, "no memory");
- return CURLE_OUT_OF_MEMORY;
- }
- }
+ if (conn->sec_conn) /* 3rd party transfer */
+ retcode = ftp_3rdparty(conn);
else
- ftp->file=NULL; /* instead of point to a zero byte, we make it a NULL
- pointer */
-
- ftp->urlpath = conn->ppath;
- if(dirlength) {
- ftp->dir = curl_unescape(ftp->urlpath, dirlength);
- if(NULL == ftp->dir) {
- if(ftp->file)
- free(ftp->file);
- failf(data, "no memory");
- return CURLE_OUT_OF_MEMORY; /* failure */
- }
- }
- else
- ftp->dir = NULL;
-
- retcode = ftp_perform(conn, &connected);
-
- if(CURLE_OK == retcode) {
- if(connected)
- retcode = Curl_ftp_nextconnect(conn);
- else
- /* since we didn't connect now, we want do_more to get called */
- conn->bits.do_more = TRUE;
- }
+ retcode = ftp_regular_transfer(conn);
return retcode;
}
@@ -2139,7 +2265,7 @@ CURLcode Curl_ftpsendf(struct connectdata *conn,
{
ssize_t bytes_written;
char s[256];
- ssize_t write_len;
+ size_t write_len;
char *sptr=s;
CURLcode res = CURLE_OK;
@@ -2147,35 +2273,60 @@ CURLcode Curl_ftpsendf(struct connectdata *conn,
va_start(ap, fmt);
vsnprintf(s, 250, fmt, ap);
va_end(ap);
-
+
strcat(s, "\r\n"); /* append a trailing CRLF */
bytes_written=0;
- write_len = (int)strlen(s);
+ write_len = strlen(s);
- do {
- res = Curl_write(conn, conn->firstsocket, sptr, write_len,
+ while(1) {
+ res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
&bytes_written);
if(CURLE_OK != res)
break;
if(conn->data->set.verbose)
- Curl_debug(conn->data, CURLINFO_HEADER_OUT, sptr, bytes_written);
+ Curl_debug(conn->data, CURLINFO_HEADER_OUT, sptr, bytes_written, conn->host.dispname);
- if(bytes_written != write_len) {
+ if(bytes_written != (ssize_t)write_len) {
write_len -= bytes_written;
sptr += bytes_written;
}
else
break;
- } while(1);
+ }
return res;
}
/***********************************************************************
*
+ * ftp_quit()
+ *
+ * This should be called before calling sclose() on an ftp control connection
+ * (not data connections). We should then wait for the response from the
+ * server before returning. The calling code should then try to close the
+ * connection.
+ *
+ */
+static CURLcode ftp_quit(struct connectdata *conn)
+{
+ ssize_t nread;
+ int ftpcode;
+ CURLcode ret = CURLE_OK;
+
+ if(conn->proto.ftp->ctl_valid) {
+ ret = Curl_ftpsendf(conn, "%s", "QUIT");
+ if(CURLE_OK == ret)
+ ret = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+ }
+
+ return ret;
+}
+
+/***********************************************************************
+ *
* Curl_ftp_disconnect()
*
* Disconnect from an FTP server. Cleanup protocol-specific per-connection
@@ -2185,28 +2336,424 @@ CURLcode Curl_ftp_disconnect(struct connectdata *conn)
{
struct FTP *ftp= conn->proto.ftp;
+ /* We cannot send quit unconditionally. If this connection is stale or
+ bad in any way, sending quit and waiting around here will make the
+ disconnect wait in vain and cause more problems than we need to.
+
+ ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
+ will try to send the QUIT command, otherwise it will just return.
+ */
+
/* The FTP session may or may not have been allocated/setup at this point! */
if(ftp) {
+ (void)ftp_quit(conn); /* ignore errors on the QUIT */
+
if(ftp->entrypath)
free(ftp->entrypath);
- if(ftp->cache)
+ if(ftp->cache) {
free(ftp->cache);
- if(ftp->file)
- free(ftp->file);
- if(ftp->dir)
- free(ftp->dir);
+ ftp->cache = NULL;
+ }
+ freedirs(ftp);
+ }
+ return CURLE_OK;
+}
+
+/***********************************************************************
+ *
+ * ftp_mkd()
+ *
+ * Makes a directory on the FTP server.
+ *
+ * Calls failf()
+ */
+static CURLcode ftp_mkd(struct connectdata *conn, char *path)
+{
+ CURLcode result=CURLE_OK;
+ int ftpcode; /* for ftp status */
+ ssize_t nread;
+
+ /* Create a directory on the remote server */
+ FTPSENDF(conn, "MKD %s", path);
- ftp->file = ftp->dir = NULL; /* zero */
+ result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+ if(result)
+ return result;
+
+ switch(ftpcode) {
+ case 257:
+ /* success! */
+ infof( conn->data , "Created remote directory %s\n" , path );
+ break;
+ case 550:
+ failf(conn->data, "Permission denied to make directory %s", path);
+ result = CURLE_FTP_ACCESS_DENIED;
+ break;
+ default:
+ failf(conn->data, "unrecognized MKD response: %d", ftpcode );
+ result = CURLE_FTP_ACCESS_DENIED;
+ break;
+ }
+ return result;
+}
+
+/***********************************************************************
+ *
+ * ftp_cwd()
+ *
+ * Send 'CWD' to the remote server to Change Working Directory. It is the ftp
+ * version of the unix 'cd' command. This function is only called from the
+ * ftp_cwd_and_mkd() function these days.
+ *
+ * This function does NOT call failf().
+ */
+static
+CURLcode ftp_cwd(struct connectdata *conn, char *path)
+{
+ ssize_t nread;
+ int ftpcode;
+ CURLcode result;
+
+ FTPSENDF(conn, "CWD %s", path);
+ result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+ if (!result) {
+ /* According to RFC959, CWD is supposed to return 250 on success, but
+ there seem to be non-compliant FTP servers out there that return 200,
+ so we accept any '2xy' code here. */
+ if (ftpcode/100 != 2)
+ result = CURLE_FTP_ACCESS_DENIED;
+ }
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * ftp_cwd_and_mkd()
+ *
+ * Change to the given directory. If the directory is not present, and we
+ * have been told to allow it, then create the directory and cd to it.
+ *
+ */
+static CURLcode ftp_cwd_and_mkd(struct connectdata *conn, char *path)
+{
+ CURLcode result;
+
+ result = ftp_cwd(conn, path);
+ if (result) {
+ if(conn->data->set.ftp_create_missing_dirs) {
+ result = ftp_mkd(conn, path);
+ if (result)
+ /* ftp_mkd() calls failf() itself */
+ return result;
+ result = ftp_cwd(conn, path);
+ }
+ if(result)
+ failf(conn->data, "Couldn't cd to %s", path);
}
+ return result;
+}
+
+
+
+/***********************************************************************
+ *
+ * ftp_3rdparty_pretransfer()
+ *
+ * Preparation for 3rd party transfer.
+ *
+ */
+static CURLcode ftp_3rdparty_pretransfer(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ struct connectdata *sec_conn = conn->sec_conn;
+
+ /* sets transfer type */
+ result = ftp_transfertype(conn, data->set.ftp_ascii);
+ if (result)
+ return result;
+
+ result = ftp_transfertype(sec_conn, data->set.ftp_ascii);
+ if (result)
+ return result;
+
+ /* Send any PREQUOTE strings after transfer type is set? */
+ if (data->set.source_prequote) {
+ /* sends command(s) to source server before file transfer */
+ result = ftp_sendquote(sec_conn, data->set.source_prequote);
+ }
+ if (!result && data->set.prequote)
+ result = ftp_sendquote(conn, data->set.prequote);
+
+ return result;
+}
+
+
+
+/***********************************************************************
+ *
+ * ftp_3rdparty_transfer()
+ *
+ * Performs 3rd party transfer.
+ *
+ */
+static CURLcode ftp_3rdparty_transfer(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ ssize_t nread;
+ int ftpcode, ip[4], port[2];
+ struct SessionHandle *data = conn->data;
+ struct connectdata *sec_conn = conn->sec_conn;
+ char *buf = data->state.buffer; /* this is our buffer */
+ char *str = buf;
+ char pasv_port[50];
+ const char *stor_cmd;
+ struct connectdata *pasv_conn;
+ struct connectdata *port_conn;
+
+ if (data->set.pasvHost == CURL_TARGET_PASV) {
+ pasv_conn = conn;
+ port_conn = sec_conn;
+ }
+ else {
+ pasv_conn = sec_conn;
+ port_conn = conn;
+ }
+
+ /* sets the passive mode */
+ FTPSENDF(pasv_conn, "%s", "PASV");
+ result = Curl_GetFTPResponse(&nread, pasv_conn, &ftpcode);
+ if (result) return result;
+ if (ftpcode != 227) {
+ failf(data, "Odd return code after PASV:%s", buf + 3);
+ return CURLE_FTP_WEIRD_PASV_REPLY;
+ }
+
+ while (*str) {
+ if (6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
+ &ip[0], &ip[1], &ip[2], &ip[3], &port[0], &port[1]))
+ break;
+ str++;
+ }
+
+ if (!*str) {
+ failf(pasv_conn->data, "Couldn't interpret this 227-reply: %s", buf);
+ return CURLE_FTP_WEIRD_227_FORMAT;
+ }
+
+ snprintf(pasv_port, sizeof(pasv_port), "%d,%d,%d,%d,%d,%d", ip[0], ip[1],
+ ip[2], ip[3], port[0], port[1]);
+
+ /* sets data connection between remote hosts */
+ FTPSENDF(port_conn, "PORT %s", pasv_port);
+ result = Curl_GetFTPResponse(&nread, port_conn, &ftpcode);
+ if (result)
+ return result;
+
+ if (ftpcode != 200) {
+ failf(data, "PORT command attempts failed:%s", buf + 3);
+ return CURLE_FTP_PORT_FAILED;
+ }
+
+ /* we might append onto the file instead of overwriting it */
+ stor_cmd = data->set.ftp_append?"APPE":"STOR";
+
+ /* transfers file between remote hosts */
+ FTPSENDF(sec_conn, "RETR %s", data->set.source_path);
+
+ if(data->set.pasvHost == CURL_TARGET_PASV) {
+
+ result = Curl_GetFTPResponse(&nread, sec_conn, &ftpcode);
+ if (result)
+ return result;
+
+ if (ftpcode != 150) {
+ failf(data, "Failed RETR: %s", buf + 4);
+ return CURLE_FTP_COULDNT_RETR_FILE;
+ }
+
+ result = Curl_ftpsendf(conn, "%s %s", stor_cmd, conn->path);
+ if(CURLE_OK == result)
+ result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+ if (result)
+ return result;
+
+ if (ftpcode != 150) {
+ failf(data, "Failed FTP upload: %s", buf + 4);
+ return CURLE_FTP_COULDNT_STOR_FILE;
+ }
+
+ }
+ else {
+
+ result = Curl_ftpsendf(conn, "%s %s", stor_cmd, conn->path);
+ if(CURLE_OK == result)
+ result = Curl_GetFTPResponse(&nread, sec_conn, &ftpcode);
+ if (result)
+ return result;
+
+ if (ftpcode != 150) {
+ failf(data, "Failed FTP upload: %s", buf + 4);
+ return CURLE_FTP_COULDNT_STOR_FILE;
+ }
+
+ result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+ if (result)
+ return result;
+
+ if (ftpcode != 150) {
+ failf(data, "Failed FTP upload: %s", buf + 4);
+ return CURLE_FTP_COULDNT_STOR_FILE;
+ }
+ }
+
return CURLE_OK;
}
-/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
+
+
+/***********************************************************************
+ *
+ * ftp_regular_transfer()
+ *
+ * The input argument is already checked for validity.
+ * Performs a regular transfer between local and remote hosts.
+ *
+ * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
+ * Curl_ftp_done() function without finding any major problem.
*/
+static
+CURLcode ftp_regular_transfer(struct connectdata *conn)
+{
+ CURLcode retcode=CURLE_OK;
+ bool connected=0;
+ struct SessionHandle *data = conn->data;
+ struct FTP *ftp;
+
+ char *slash_pos; /* position of the first '/' char in curpos */
+ char *cur_pos=conn->path; /* current position in ppath. point at the begin
+ of next path component */
+
+ /* the ftp struct is already inited in ftp_connect() */
+ ftp = conn->proto.ftp;
+ ftp->ctl_valid = FALSE;
+ conn->size = -1; /* make sure this is unknown at this point */
+
+ Curl_pgrsSetUploadCounter(data, 0);
+ Curl_pgrsSetDownloadCounter(data, 0);
+ Curl_pgrsSetUploadSize(data, 0);
+ Curl_pgrsSetDownloadSize(data, 0);
+
+ ftp->dirdepth = 0;
+ ftp->diralloc = 5; /* default dir depth to allocate */
+ ftp->dirs = (char **)malloc(ftp->diralloc * sizeof(ftp->dirs[0]));
+ if(!ftp->dirs)
+ return CURLE_OUT_OF_MEMORY;
+ ftp->dirs[0] = NULL; /* to start with */
+
+ /* parse the URL path into separate path components */
+ while((slash_pos=strchr(cur_pos, '/'))) {
+ /* 1 or 0 to indicate absolute directory */
+ bool absolute_dir = (cur_pos - conn->path > 0) && (ftp->dirdepth == 0);
+
+ /* seek out the next path component */
+ if (slash_pos-cur_pos) {
+ /* we skip empty path components, like "x//y" since the FTP command CWD
+ requires a parameter and a non-existant parameter a) doesn't work on
+ many servers and b) has no effect on the others. */
+ int len = (int)(slash_pos - cur_pos + absolute_dir);
+ ftp->dirs[ftp->dirdepth] = curl_unescape(cur_pos - absolute_dir, len);
+
+ if (!ftp->dirs[ftp->dirdepth]) { /* run out of memory ... */
+ failf(data, "no memory");
+ freedirs(ftp);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+ else {
+ cur_pos = slash_pos + 1; /* jump to the rest of the string */
+ continue;
+ }
+
+ if(!retcode) {
+ cur_pos = slash_pos + 1; /* jump to the rest of the string */
+ if(++ftp->dirdepth >= ftp->diralloc) {
+ /* enlarge array */
+ char *bigger;
+ ftp->diralloc *= 2; /* double the size each time */
+ bigger = realloc(ftp->dirs, ftp->diralloc * sizeof(ftp->dirs[0]));
+ if(!bigger) {
+ freedirs(ftp);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ ftp->dirs = (char **)bigger;
+ }
+ }
+ }
+
+ ftp->file = cur_pos; /* the rest is the file name */
+
+ if(*ftp->file) {
+ ftp->file = curl_unescape(ftp->file, 0);
+ if(NULL == ftp->file) {
+ freedirs(ftp);
+ failf(data, "no memory");
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+ else
+ ftp->file=NULL; /* instead of point to a zero byte, we make it a NULL
+ pointer */
+
+ retcode = ftp_perform(conn, &connected);
+
+ if(CURLE_OK == retcode) {
+ if(connected)
+ retcode = Curl_ftp_nextconnect(conn);
+
+ if(retcode && (conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD)) {
+ /* Failure detected, close the second socket if it was created already */
+ sclose(conn->sock[SECONDARYSOCKET]);
+ conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
+ }
+
+ if(ftp->no_transfer)
+ /* no data to transfer */
+ retcode=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+ else if(!connected)
+ /* since we didn't connect now, we want do_more to get called */
+ conn->bits.do_more = TRUE;
+ }
+ else
+ freedirs(ftp);
+
+ ftp->ctl_valid = TRUE; /* seems good */
+
+ return retcode;
+}
+
+
+
+/***********************************************************************
+ *
+ * ftp_3rdparty()
+ *
+ * The input argument is already checked for validity.
+ * Performs a 3rd party transfer between two remote hosts.
+ */
+static CURLcode ftp_3rdparty(struct connectdata *conn)
+{
+ CURLcode retcode = CURLE_OK;
+
+ conn->proto.ftp->ctl_valid = conn->sec_conn->proto.ftp->ctl_valid = TRUE;
+ conn->size = conn->sec_conn->size = -1;
+
+ retcode = ftp_3rdparty_pretransfer(conn);
+ if (!retcode)
+ retcode = ftp_3rdparty_transfer(conn);
+
+ return retcode;
+}
#endif /* CURL_DISABLE_FTP */
diff --git a/Source/CTest/Curl/ftp.h b/Source/CTest/Curl/ftp.h
index 60440db..dc7cf79 100644
--- a/Source/CTest/Curl/ftp.h
+++ b/Source/CTest/Curl/ftp.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -25,11 +25,11 @@
#ifndef CURL_DISABLE_FTP
CURLcode Curl_ftp(struct connectdata *conn);
-CURLcode Curl_ftp_done(struct connectdata *conn);
+CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode);
CURLcode Curl_ftp_connect(struct connectdata *conn);
CURLcode Curl_ftp_disconnect(struct connectdata *conn);
CURLcode Curl_ftpsendf(struct connectdata *, const char *fmt, ...);
-CURLcode Curl_GetFTPResponse(int *nread, struct connectdata *conn,
+CURLcode Curl_GetFTPResponse(ssize_t *nread, struct connectdata *conn,
int *ftpcode);
CURLcode Curl_ftp_nextconnect(struct connectdata *conn);
#endif
diff --git a/Source/CTest/Curl/getdate.c b/Source/CTest/Curl/getdate.c
index 5ab79e3..cd1df6f 100644
--- a/Source/CTest/Curl/getdate.c
+++ b/Source/CTest/Curl/getdate.c
@@ -1,26 +1,97 @@
+/* A Bison parser, made by GNU Bison 1.875a. */
-/* A Bison parser, made from getdate.y
- by GNU Bison version 1.28 */
-
-#define YYBISON 1 /* Identify Bison output. */
-
-#define tAGO 257
-#define tDAY 258
-#define tDAY_UNIT 259
-#define tDAYZONE 260
-#define tDST 261
-#define tHOUR_UNIT 262
-#define tID 263
-#define tMERIDIAN 264
-#define tMINUTE_UNIT 265
-#define tMONTH 266
-#define tMONTH_UNIT 267
-#define tSEC_UNIT 268
-#define tSNUMBER 269
-#define tUNUMBER 270
-#define tYEAR_UNIT 271
-#define tZONE 272
+/* Skeleton parser for Yacc-like parsing with Bison,
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* As a special exception, when this file is copied by Bison into a
+ Bison output file, you may use that output file without restriction.
+ This special exception was added by the Free Software Foundation
+ in version 1.24 of Bison. */
+
+/* Written by Richard Stallman by simplifying the original so called
+ ``semantic'' parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 1
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ tAGO = 258,
+ tDAY = 259,
+ tDAY_UNIT = 260,
+ tDAYZONE = 261,
+ tDST = 262,
+ tHOUR_UNIT = 263,
+ tID = 264,
+ tMERIDIAN = 265,
+ tMINUTE_UNIT = 266,
+ tMONTH = 267,
+ tMONTH_UNIT = 268,
+ tSEC_UNIT = 269,
+ tSNUMBER = 270,
+ tUNUMBER = 271,
+ tYEAR_UNIT = 272,
+ tZONE = 273
+ };
+#endif
+#define tAGO 258
+#define tDAY 259
+#define tDAY_UNIT 260
+#define tDAYZONE 261
+#define tDST 262
+#define tHOUR_UNIT 263
+#define tID 264
+#define tMERIDIAN 265
+#define tMINUTE_UNIT 266
+#define tMONTH 267
+#define tMONTH_UNIT 268
+#define tSEC_UNIT 269
+#define tSNUMBER 270
+#define tUNUMBER 271
+#define tYEAR_UNIT 272
+#define tZONE 273
+
+
+
+
+/* Copy the first part of user declarations. */
#line 1 "getdate.y"
/*
@@ -29,6 +100,9 @@
** a couple of people on Usenet. Completely overhauled by Rich $alz
** <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990.
**
+** This code has been modified since it was included in curl, to make it
+** thread-safe and to make compilers complain less about it.
+**
** This code is in the public domain and has no copyright.
*/
@@ -47,6 +121,11 @@
#define YYDEBUG 0
#endif
+#ifndef YYSTACK_USE_ALLOCA
+ /* to satisfy gcc -Wundef, we set this to 0 */
+#define YYSTACK_USE_ALLOCA 0
+#endif
+
/* Since the code of getdate.y is not included in the Emacs executable
itself, there is no need to #define static in this file. Even if
the code were included in the Emacs executable, it probably
@@ -80,13 +159,13 @@
#if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
# define IN_CTYPE_DOMAIN(c) 1
#else
-# define IN_CTYPE_DOMAIN(c) isascii((int)(c))
+# define IN_CTYPE_DOMAIN(c) isascii(c)
#endif
-#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace ((int)(c)))
-#define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha ((int)(c)))
-#define ISUPPER(c) (IN_CTYPE_DOMAIN (c) && isupper ((int)(c)))
-#define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit ((int)(c)))
+#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c))
+#define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c))
+#define ISUPPER(c) (IN_CTYPE_DOMAIN (c) && isupper (c))
+#define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c))
/* ISDIGIT differs from ISDIGIT_LOCALE, as follows:
- Its arg may be any int or unsigned int; it need not be an unsigned char.
@@ -102,9 +181,12 @@
# include <string.h>
#endif
+#include "memory.h"
/* The last #include file should be: */
-#ifdef MALLOCDEBUG
#include "memdebug.h"
+
+#ifndef YYMAXDEPTH
+#define YYMAXDEPTH 0
#endif
#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
@@ -169,9 +251,6 @@
#define yytable Curl_gd_yytable
#define yycheck Curl_gd_yycheck
-static int yylex ();
-static int yyerror ();
-
#define EPOCH 1970
#define HOUR(x) ((x) * 60)
@@ -195,7 +274,7 @@ typedef enum _MERIDIAN {
} MERIDIAN;
/* parse results and input string */
-typedef struct _CONTEXT {
+typedef struct _CURL_CONTEXT {
const char *yyInput;
int yyDayOrdinal;
int yyDayNumber;
@@ -218,482 +297,783 @@ typedef struct _CONTEXT {
int yyRelMonth;
int yyRelSeconds;
int yyRelYear;
-} CONTEXT;
+} CURL_CONTEXT;
/* enable use of extra argument to yyparse and yylex which can be used to pass
-** in a user defined value (CONTEXT struct in our case)
+** in a user defined value (CURL_CONTEXT struct in our case)
*/
#define YYPARSE_PARAM cookie
#define YYLEX_PARAM cookie
-#define context ((CONTEXT *) cookie)
+#define context ((CURL_CONTEXT *) cookie)
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
-#line 215 "getdate.y"
-typedef union {
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+#line 223 "getdate.y"
+typedef union YYSTYPE {
int Number;
enum _MERIDIAN Meridian;
} YYSTYPE;
-#include <stdio.h>
-
-#ifndef __cplusplus
-#ifndef __STDC__
-#define const
-#endif
+/* Line 191 of yacc.c. */
+#line 331 "y.tab.c"
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
#endif
-#define YYFINAL 61
-#define YYFLAG -32768
-#define YYNTBASE 22
-
-#define YYTRANSLATE(x) ((unsigned)(x) <= 272 ? yytranslate[x] : 32)
-
-static const char yytranslate[] = { 0,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 20, 2, 2, 21, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 19, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 1, 3, 4, 5, 6,
- 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
- 17, 18
-};
+/* Copy the second part of user declarations. */
+#line 228 "getdate.y"
-#if YYDEBUG != 0
-static const short yyprhs[] = { 0,
- 0, 1, 4, 6, 8, 10, 12, 14, 16, 19,
- 24, 29, 36, 43, 45, 47, 50, 52, 55, 58,
- 62, 68, 72, 76, 79, 84, 87, 91, 94, 96,
- 99, 102, 104, 107, 110, 112, 115, 118, 120, 123,
- 126, 128, 131, 134, 136, 139, 142, 144, 146, 147
-};
+static int yylex (YYSTYPE *yylval, void *cookie);
+static int yyerror (const char *s);
-static const short yyrhs[] = { -1,
- 22, 23, 0, 24, 0, 25, 0, 27, 0, 26,
- 0, 28, 0, 30, 0, 16, 10, 0, 16, 19,
- 16, 31, 0, 16, 19, 16, 15, 0, 16, 19,
- 16, 19, 16, 31, 0, 16, 19, 16, 19, 16,
- 15, 0, 18, 0, 6, 0, 18, 7, 0, 4,
- 0, 4, 20, 0, 16, 4, 0, 16, 21, 16,
- 0, 16, 21, 16, 21, 16, 0, 16, 15, 15,
- 0, 16, 12, 15, 0, 12, 16, 0, 12, 16,
- 20, 16, 0, 16, 12, 0, 16, 12, 16, 0,
- 29, 3, 0, 29, 0, 16, 17, 0, 15, 17,
- 0, 17, 0, 16, 13, 0, 15, 13, 0, 13,
- 0, 16, 5, 0, 15, 5, 0, 5, 0, 16,
- 8, 0, 15, 8, 0, 8, 0, 16, 11, 0,
- 15, 11, 0, 11, 0, 16, 14, 0, 15, 14,
- 0, 14, 0, 16, 0, 0, 10, 0
-};
-#endif
+/* Line 214 of yacc.c. */
+#line 347 "y.tab.c"
-#if YYDEBUG != 0
-static const short yyrline[] = { 0,
- 231, 232, 235, 238, 241, 244, 247, 250, 253, 259,
- 265, 274, 280, 292, 295, 298, 304, 308, 312, 318,
- 322, 340, 346, 352, 356, 361, 365, 372, 380, 383,
- 386, 389, 392, 395, 398, 401, 404, 407, 410, 413,
- 416, 419, 422, 425, 428, 431, 434, 439, 473, 477
-};
-#endif
+#if ! defined (yyoverflow) || YYERROR_VERBOSE
+/* The parser invokes alloca or malloc; define the necessary symbols. */
-#if YYDEBUG != 0 || defined (YYERROR_VERBOSE)
+# if YYSTACK_USE_ALLOCA
+# define YYSTACK_ALLOC alloca
+# else
+# ifndef YYSTACK_USE_ALLOCA
+# if defined (alloca) || defined (_ALLOCA_H)
+# define YYSTACK_ALLOC alloca
+# else
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# endif
+# endif
+# endif
+# endif
-static const char * const yytname[] = { "$","error","$undefined.","tAGO","tDAY",
-"tDAY_UNIT","tDAYZONE","tDST","tHOUR_UNIT","tID","tMERIDIAN","tMINUTE_UNIT",
-"tMONTH","tMONTH_UNIT","tSEC_UNIT","tSNUMBER","tUNUMBER","tYEAR_UNIT","tZONE",
-"':'","','","'/'","spec","item","time","zone","day","date","rel","relunit","number",
-"o_merid", NULL
-};
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+# else
+# if defined (__STDC__) || defined (__cplusplus)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# endif
+# define YYSTACK_ALLOC malloc
+# define YYSTACK_FREE free
+# endif
+#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */
+
+
+#if (! defined (yyoverflow) \
+ && (! defined (__cplusplus) \
+ || (YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ short yyss;
+ YYSTYPE yyvs;
+ };
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (short) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ register YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (0)
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (0)
+
+#endif
+
+#if defined (__STDC__) || defined (__cplusplus)
+ typedef signed char yysigned_char;
+#else
+ typedef short yysigned_char;
#endif
-static const short yyr1[] = { 0,
- 22, 22, 23, 23, 23, 23, 23, 23, 24, 24,
- 24, 24, 24, 25, 25, 25, 26, 26, 26, 27,
- 27, 27, 27, 27, 27, 27, 27, 28, 28, 29,
- 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
- 29, 29, 29, 29, 29, 29, 29, 30, 31, 31
-};
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 2
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 50
-static const short yyr2[] = { 0,
- 0, 2, 1, 1, 1, 1, 1, 1, 2, 4,
- 4, 6, 6, 1, 1, 2, 1, 2, 2, 3,
- 5, 3, 3, 2, 4, 2, 3, 2, 1, 2,
- 2, 1, 2, 2, 1, 2, 2, 1, 2, 2,
- 1, 2, 2, 1, 2, 2, 1, 1, 0, 1
-};
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 22
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 11
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 51
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 61
-static const short yydefact[] = { 1,
- 0, 17, 38, 15, 41, 44, 0, 35, 47, 0,
- 48, 32, 14, 2, 3, 4, 6, 5, 7, 29,
- 8, 18, 24, 37, 40, 43, 34, 46, 31, 19,
- 36, 39, 9, 42, 26, 33, 45, 0, 30, 0,
- 0, 16, 28, 0, 23, 27, 22, 49, 20, 25,
- 50, 11, 0, 10, 0, 49, 21, 13, 12, 0,
- 0
-};
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 273
-static const short yydefgoto[] = { 1,
- 14, 15, 16, 17, 18, 19, 20, 21, 54
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const unsigned char yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 20, 2, 2, 21, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 19, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18
};
-static const short yypact[] = {-32768,
- 0, -19,-32768,-32768,-32768,-32768, -13,-32768,-32768, 30,
- 15,-32768, 14,-32768,-32768,-32768,-32768,-32768,-32768, 19,
--32768,-32768, 4,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
--32768,-32768,-32768,-32768, -6,-32768,-32768, 16,-32768, 17,
- 23,-32768,-32768, 24,-32768,-32768,-32768, 27, 28,-32768,
--32768,-32768, 29,-32768, 32, -8,-32768,-32768,-32768, 50,
--32768
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const unsigned char yyprhs[] =
+{
+ 0, 0, 3, 4, 7, 9, 11, 13, 15, 17,
+ 19, 22, 27, 32, 39, 46, 48, 50, 53, 55,
+ 58, 61, 65, 71, 75, 79, 82, 87, 90, 94,
+ 97, 99, 102, 105, 107, 110, 113, 115, 118, 121,
+ 123, 126, 129, 131, 134, 137, 139, 142, 145, 147,
+ 149, 150
};
-static const short yypgoto[] = {-32768,
--32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, -5
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yysigned_char yyrhs[] =
+{
+ 23, 0, -1, -1, 23, 24, -1, 25, -1, 26,
+ -1, 28, -1, 27, -1, 29, -1, 31, -1, 16,
+ 10, -1, 16, 19, 16, 32, -1, 16, 19, 16,
+ 15, -1, 16, 19, 16, 19, 16, 32, -1, 16,
+ 19, 16, 19, 16, 15, -1, 18, -1, 6, -1,
+ 18, 7, -1, 4, -1, 4, 20, -1, 16, 4,
+ -1, 16, 21, 16, -1, 16, 21, 16, 21, 16,
+ -1, 16, 15, 15, -1, 16, 12, 15, -1, 12,
+ 16, -1, 12, 16, 20, 16, -1, 16, 12, -1,
+ 16, 12, 16, -1, 30, 3, -1, 30, -1, 16,
+ 17, -1, 15, 17, -1, 17, -1, 16, 13, -1,
+ 15, 13, -1, 13, -1, 16, 5, -1, 15, 5,
+ -1, 5, -1, 16, 8, -1, 15, 8, -1, 8,
+ -1, 16, 11, -1, 15, 11, -1, 11, -1, 16,
+ 14, -1, 15, 14, -1, 14, -1, 16, -1, -1,
+ 10, -1
};
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const unsigned short yyrline[] =
+{
+ 0, 244, 244, 245, 248, 251, 254, 257, 260, 263,
+ 266, 272, 278, 287, 293, 305, 308, 312, 317, 321,
+ 325, 331, 335, 353, 359, 365, 369, 374, 378, 385,
+ 393, 396, 399, 402, 405, 408, 411, 414, 417, 420,
+ 423, 426, 429, 432, 435, 438, 441, 444, 447, 452,
+ 487, 490
+};
+#endif
-#define YYLAST 51
+#if YYDEBUG || YYERROR_VERBOSE
+/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "tAGO", "tDAY", "tDAY_UNIT", "tDAYZONE",
+ "tDST", "tHOUR_UNIT", "tID", "tMERIDIAN", "tMINUTE_UNIT", "tMONTH",
+ "tMONTH_UNIT", "tSEC_UNIT", "tSNUMBER", "tUNUMBER", "tYEAR_UNIT",
+ "tZONE", "':'", "','", "'/'", "$accept", "spec", "item", "time", "zone",
+ "day", "date", "rel", "relunit", "number", "o_merid", 0
+};
+#endif
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const unsigned short yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 58,
+ 44, 47
+};
+# endif
-static const short yytable[] = { 60,
- 22, 51, 23, 2, 3, 4, 58, 5, 45, 46,
- 6, 7, 8, 9, 10, 11, 12, 13, 30, 31,
- 42, 43, 32, 44, 33, 34, 35, 36, 37, 38,
- 47, 39, 48, 40, 24, 41, 51, 25, 49, 50,
- 26, 52, 27, 28, 56, 53, 29, 57, 55, 61,
- 59
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const unsigned char yyr1[] =
+{
+ 0, 22, 23, 23, 24, 24, 24, 24, 24, 24,
+ 25, 25, 25, 25, 25, 26, 26, 26, 27, 27,
+ 27, 28, 28, 28, 28, 28, 28, 28, 28, 29,
+ 29, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 31,
+ 32, 32
};
-static const short yycheck[] = { 0,
- 20, 10, 16, 4, 5, 6, 15, 8, 15, 16,
- 11, 12, 13, 14, 15, 16, 17, 18, 4, 5,
- 7, 3, 8, 20, 10, 11, 12, 13, 14, 15,
- 15, 17, 16, 19, 5, 21, 10, 8, 16, 16,
- 11, 15, 13, 14, 16, 19, 17, 16, 21, 0,
- 56
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const unsigned char yyr2[] =
+{
+ 0, 2, 0, 2, 1, 1, 1, 1, 1, 1,
+ 2, 4, 4, 6, 6, 1, 1, 2, 1, 2,
+ 2, 3, 5, 3, 3, 2, 4, 2, 3, 2,
+ 1, 2, 2, 1, 2, 2, 1, 2, 2, 1,
+ 2, 2, 1, 2, 2, 1, 2, 2, 1, 1,
+ 0, 1
};
-#define YYPURE 1
-/* -*-C-*- Note some compilers choke on comments on `#line' lines. */
-#line 3 "/usr/local/share/bison.simple"
-/* This file comes from bison-1.28. */
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const unsigned char yydefact[] =
+{
+ 2, 0, 1, 18, 39, 16, 42, 45, 0, 36,
+ 48, 0, 49, 33, 15, 3, 4, 5, 7, 6,
+ 8, 30, 9, 19, 25, 38, 41, 44, 35, 47,
+ 32, 20, 37, 40, 10, 43, 27, 34, 46, 0,
+ 31, 0, 0, 17, 29, 0, 24, 28, 23, 50,
+ 21, 26, 51, 12, 0, 11, 0, 50, 22, 14,
+ 13
+};
-/* Skeleton output parser for bison,
- Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc.
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yysigned_char yydefgoto[] =
+{
+ -1, 1, 15, 16, 17, 18, 19, 20, 21, 22,
+ 55
+};
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -20
+static const yysigned_char yypact[] =
+{
+ -20, 0, -20, -19, -20, -20, -20, -20, -13, -20,
+ -20, 30, 15, -20, 14, -20, -20, -20, -20, -20,
+ -20, 19, -20, -20, 4, -20, -20, -20, -20, -20,
+ -20, -20, -20, -20, -20, -20, -6, -20, -20, 16,
+ -20, 17, 23, -20, -20, 24, -20, -20, -20, 27,
+ 28, -20, -20, -20, 29, -20, 32, -8, -20, -20,
+ -20
+};
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+/* YYPGOTO[NTERM-NUM]. */
+static const yysigned_char yypgoto[] =
+{
+ -20, -20, -20, -20, -20, -20, -20, -20, -20, -20,
+ -7
+};
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -1
+static const unsigned char yytable[] =
+{
+ 2, 23, 52, 24, 3, 4, 5, 59, 6, 46,
+ 47, 7, 8, 9, 10, 11, 12, 13, 14, 31,
+ 32, 43, 44, 33, 45, 34, 35, 36, 37, 38,
+ 39, 48, 40, 49, 41, 25, 42, 52, 26, 50,
+ 51, 27, 53, 28, 29, 57, 54, 30, 58, 56,
+ 60
+};
-/* As a special exception, when this file is copied by Bison into a
- Bison output file, you may use that output file without restriction.
- This special exception was added by the Free Software Foundation
- in version 1.24 of Bison. */
+static const unsigned char yycheck[] =
+{
+ 0, 20, 10, 16, 4, 5, 6, 15, 8, 15,
+ 16, 11, 12, 13, 14, 15, 16, 17, 18, 4,
+ 5, 7, 3, 8, 20, 10, 11, 12, 13, 14,
+ 15, 15, 17, 16, 19, 5, 21, 10, 8, 16,
+ 16, 11, 15, 13, 14, 16, 19, 17, 16, 21,
+ 57
+};
-/* This is the parser code that is written into each bison parser
- when the %semantic_parser declaration is not specified in the grammar.
- It was written by Richard Stallman by simplifying the hairy parser
- used when %semantic_parser is specified. */
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const unsigned char yystos[] =
+{
+ 0, 23, 0, 4, 5, 6, 8, 11, 12, 13,
+ 14, 15, 16, 17, 18, 24, 25, 26, 27, 28,
+ 29, 30, 31, 20, 16, 5, 8, 11, 13, 14,
+ 17, 4, 5, 8, 10, 11, 12, 13, 14, 15,
+ 17, 19, 21, 7, 3, 20, 15, 16, 15, 16,
+ 16, 16, 10, 15, 19, 32, 21, 16, 16, 15,
+ 32
+};
-#ifndef YYSTACK_USE_ALLOCA
-#ifdef alloca
-#define YYSTACK_USE_ALLOCA
-#else /* alloca not defined */
-#ifdef __GNUC__
-#define YYSTACK_USE_ALLOCA
-#define alloca __builtin_alloca
-#else /* not GNU C. */
-#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) || (defined (__sun) && defined (__i386))
-#define YYSTACK_USE_ALLOCA
-#include <alloca.h>
-#else /* not sparc */
-/* We think this test detects Watcom and Microsoft C. */
-/* This used to test MSDOS, but that is a bad idea
- since that symbol is in the user namespace. */
-#if (defined (_MSDOS) || defined (_MSDOS_)) && !defined (__TURBOC__)
-#if 0 /* No need for malloc.h, which pollutes the namespace;
- instead, just don't use alloca. */
-#include <malloc.h>
+#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
+# define YYSIZE_T __SIZE_TYPE__
#endif
-#else /* not MSDOS, or __TURBOC__ */
-#if defined(_AIX)
-/* I don't know what this was needed for, but it pollutes the namespace.
- So I turned it off. rms, 2 May 1997. */
-/* #include <malloc.h> */
- #pragma alloca
-#define YYSTACK_USE_ALLOCA
-#else /* not MSDOS, or __TURBOC__, or _AIX */
-#if 0
-#ifdef __hpux /* haible@ilog.fr says this works for HPUX 9.05 and up,
- and on HPUX 10. Eventually we can turn this on. */
-#define YYSTACK_USE_ALLOCA
-#define alloca __builtin_alloca
-#endif /* __hpux */
+#if ! defined (YYSIZE_T) && defined (size_t)
+# define YYSIZE_T size_t
#endif
-#endif /* not _AIX */
-#endif /* not MSDOS, or __TURBOC__ */
-#endif /* not sparc */
-#endif /* not GNU C */
-#endif /* alloca not defined */
-#endif /* YYSTACK_USE_ALLOCA not defined */
-
-#ifdef YYSTACK_USE_ALLOCA
-#define YYSTACK_ALLOC alloca
-#else
-#define YYSTACK_ALLOC malloc
+#if ! defined (YYSIZE_T)
+# if defined (__STDC__) || defined (__cplusplus)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# endif
+#endif
+#if ! defined (YYSIZE_T)
+# define YYSIZE_T unsigned int
#endif
-
-/* Note: there must be only one dollar sign in this file.
- It is replaced by the list of actions, each action
- as one case of the switch. */
#define yyerrok (yyerrstatus = 0)
#define yyclearin (yychar = YYEMPTY)
-#define YYEMPTY -2
+#define YYEMPTY (-2)
#define YYEOF 0
+
#define YYACCEPT goto yyacceptlab
#define YYABORT goto yyabortlab
#define YYERROR goto yyerrlab1
-/* Like YYERROR except do call yyerror.
- This remains here temporarily to ease the
- transition to the new meaning of YYERROR, for GCC.
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
Once GCC version 2 has supplanted version 1, this can go. */
+
#define YYFAIL goto yyerrlab
+
#define YYRECOVERING() (!!yyerrstatus)
-#define YYBACKUP(token, value) \
+
+#define YYBACKUP(Token, Value) \
do \
if (yychar == YYEMPTY && yylen == 1) \
- { yychar = (token), yylval = (value); \
- yychar1 = YYTRANSLATE (yychar); \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ yytoken = YYTRANSLATE (yychar); \
YYPOPSTACK; \
goto yybackup; \
} \
else \
- { yyerror ("syntax error: cannot back up"); YYERROR; } \
+ { \
+ yyerror ("syntax error: cannot back up");\
+ YYERROR; \
+ } \
while (0)
#define YYTERROR 1
#define YYERRCODE 256
-#ifndef YYPURE
-#define YYLEX yylex()
-#endif
+/* YYLLOC_DEFAULT -- Compute the default location (before the actions
+ are run). */
-#ifdef YYPURE
-#ifdef YYLSP_NEEDED
-#ifdef YYLEX_PARAM
-#define YYLEX yylex(&yylval, &yylloc, YYLEX_PARAM)
-#else
-#define YYLEX yylex(&yylval, &yylloc)
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ Current.first_line = Rhs[1].first_line; \
+ Current.first_column = Rhs[1].first_column; \
+ Current.last_line = Rhs[N].last_line; \
+ Current.last_column = Rhs[N].last_column;
#endif
-#else /* not YYLSP_NEEDED */
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
#ifdef YYLEX_PARAM
-#define YYLEX yylex(&yylval, YYLEX_PARAM)
+# define YYLEX yylex (&yylval, YYLEX_PARAM)
#else
-#define YYLEX yylex(&yylval)
-#endif
-#endif /* not YYLSP_NEEDED */
+# define YYLEX yylex (&yylval)
#endif
-/* If nonreentrant, generate the variables here */
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
-#ifndef YYPURE
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (0)
+
+# define YYDSYMPRINT(Args) \
+do { \
+ if (yydebug) \
+ yysymprint Args; \
+} while (0)
+
+# define YYDSYMPRINTF(Title, Token, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yysymprint (stderr, \
+ Token, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (0)
-int yychar; /* the lookahead symbol */
-YYSTYPE yylval; /* the semantic value of the */
- /* lookahead symbol */
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (cinluded). |
+`------------------------------------------------------------------*/
-#ifdef YYLSP_NEEDED
-YYLTYPE yylloc; /* location data for the lookahead */
- /* symbol */
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_stack_print (short *bottom, short *top)
+#else
+static void
+yy_stack_print (bottom, top)
+ short *bottom;
+ short *top;
#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (/* Nothing. */; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
+ YYFPRINTF (stderr, "\n");
+}
-int yynerrs; /* number of parse errors so far */
-#endif /* not YYPURE */
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (0)
-#if YYDEBUG != 0
-int yydebug; /* nonzero means print parse trace */
-/* Since this is uninitialized, it does not stop multiple parsers
- from coexisting. */
-#endif
-/* YYINITDEPTH indicates the initial size of the parser's stacks */
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_reduce_print (int yyrule)
+#else
+static void
+yy_reduce_print (yyrule)
+ int yyrule;
+#endif
+{
+ int yyi;
+ unsigned int yylineno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ",
+ yyrule - 1, yylineno);
+ /* Print the symbols being reduced, and their result. */
+ for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++)
+ YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]);
+ YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]);
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (Rule); \
+} while (0)
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YYDSYMPRINT(Args)
+# define YYDSYMPRINTF(Title, Token, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
#ifndef YYINITDEPTH
-#define YYINITDEPTH 200
+# define YYINITDEPTH 200
#endif
-/* YYMAXDEPTH is the maximum size the stacks can grow to
- (effective only if the built-in stack extension method is used). */
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
#if YYMAXDEPTH == 0
-#undef YYMAXDEPTH
+# undef YYMAXDEPTH
#endif
#ifndef YYMAXDEPTH
-#define YYMAXDEPTH 10000
+# define YYMAXDEPTH 10000
#endif
+
-/* Define __yy_memcpy. Note that the size argument
- should be passed with type unsigned int, because that is what the non-GCC
- definitions require. With GCC, __builtin_memcpy takes an arg
- of type size_t, but it can handle unsigned int. */
-
-#if __GNUC__ > 1 /* GNU C and GNU C++ define this. */
-#define __yy_memcpy(TO,FROM,COUNT) __builtin_memcpy(TO,FROM,COUNT)
-#else /* not GNU C or C++ */
-#ifndef __cplusplus
-
-/* This is the most reliable way to avoid incompatibilities
- in available built-in functions on various systems. */
-static void
-__yy_memcpy (to, from, count)
- char *to;
- char *from;
- unsigned int count;
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined (__GLIBC__) && defined (_STRING_H)
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+static YYSIZE_T
+# if defined (__STDC__) || defined (__cplusplus)
+yystrlen (const char *yystr)
+# else
+yystrlen (yystr)
+ const char *yystr;
+# endif
+{
+ register const char *yys = yystr;
+
+ while (*yys++ != '\0')
+ continue;
+
+ return yys - yystr - 1;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE)
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+static char *
+# if defined (__STDC__) || defined (__cplusplus)
+yystpcpy (char *yydest, const char *yysrc)
+# else
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+# endif
{
- register char *f = from;
- register char *t = to;
- register int i = count;
+ register char *yyd = yydest;
+ register const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
- while (i-- > 0)
- *t++ = *f++;
+ return yyd - 1;
}
+# endif
+# endif
+
+#endif /* !YYERROR_VERBOSE */
+
+
-#else /* __cplusplus */
+#if YYDEBUG
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
-/* This is the most reliable way to avoid incompatibilities
- in available built-in functions on various systems. */
+#if defined (__STDC__) || defined (__cplusplus)
static void
-__yy_memcpy (char *to, char *from, unsigned int count)
+yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yysymprint (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
{
- register char *t = to;
- register char *f = from;
- register int i = count;
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+
+ if (yytype < YYNTOKENS)
+ {
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+# ifdef YYPRINT
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# endif
+ }
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
- while (i-- > 0)
- *t++ = *f++;
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+ YYFPRINTF (yyoutput, ")");
}
+#endif /* ! YYDEBUG */
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yydestruct (int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yytype, yyvaluep)
+ int yytype;
+ YYSTYPE *yyvaluep;
#endif
-#endif
+{
+ /* Pacify ``unused variable'' warnings. */
+ (void) yyvaluep;
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
-#line 217 "/usr/local/share/bison.simple"
-/* The user can define YYPARSE_PARAM as the name of an argument to be passed
- into yyparse. The argument should have type void *.
- It should actually point to an object.
- Grammar actions can access the variable by casting it
- to the proper pointer type. */
+/* Prevent warnings from -Wmissing-prototypes. */
#ifdef YYPARSE_PARAM
-#ifdef __cplusplus
-#define YYPARSE_PARAM_ARG void *YYPARSE_PARAM
-#define YYPARSE_PARAM_DECL
-#else /* not __cplusplus */
-#define YYPARSE_PARAM_ARG YYPARSE_PARAM
-#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM;
-#endif /* not __cplusplus */
-#else /* not YYPARSE_PARAM */
-#define YYPARSE_PARAM_ARG
-#define YYPARSE_PARAM_DECL
-#endif /* not YYPARSE_PARAM */
-
-/* Prevent warning if -Wstrict-prototypes. */
-#ifdef __GNUC__
-#ifdef YYPARSE_PARAM
-int yyparse (void *);
-#else
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM);
+# else
+int yyparse ();
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
int yyparse (void);
+#else
+int yyparse ();
#endif
-#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM)
+# else
+int yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int
+yyparse (void)
+#else
int
-yyparse(YYPARSE_PARAM_ARG)
- YYPARSE_PARAM_DECL
+yyparse ()
+
+#endif
+#endif
{
+ /* The lookahead symbol. */
+int yychar;
+
+/* The semantic value of the lookahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
register int yystate;
register int yyn;
+ int yyresult;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken = 0;
+
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ short yyssa[YYINITDEPTH];
+ short *yyss = yyssa;
register short *yyssp;
- register YYSTYPE *yyvsp;
- int yyerrstatus; /* number of tokens to shift before error messages enabled */
- int yychar1 = 0; /* lookahead token as an internal (translated) token number */
- short yyssa[YYINITDEPTH]; /* the state stack */
- YYSTYPE yyvsa[YYINITDEPTH]; /* the semantic value stack */
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ register YYSTYPE *yyvsp;
- short *yyss = yyssa; /* refer to the stacks thru separate pointers */
- YYSTYPE *yyvs = yyvsa; /* to allow yyoverflow to reallocate them elsewhere */
-#ifdef YYLSP_NEEDED
- YYLTYPE yylsa[YYINITDEPTH]; /* the location stack */
- YYLTYPE *yyls = yylsa;
- YYLTYPE *yylsp;
-#define YYPOPSTACK (yyvsp--, yyssp--, yylsp--)
-#else
#define YYPOPSTACK (yyvsp--, yyssp--)
-#endif
- int yystacksize = YYINITDEPTH;
- int yyfree_stacks = 0;
+ YYSIZE_T yystacksize = YYINITDEPTH;
-#ifdef YYPURE
- int yychar;
- YYSTYPE yylval;
- int yynerrs;
-#ifdef YYLSP_NEEDED
- YYLTYPE yylloc;
-#endif
-#endif
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
- YYSTYPE yyval; /* the variable used to return */
- /* semantic values from the action */
- /* routines */
+ /* When reducing, the number of symbols on the RHS of the reduced
+ rule. */
int yylen;
-#if YYDEBUG != 0
- if (yydebug)
- fprintf(stderr, "Starting parse\n");
-#endif
+ YYDPRINTF ((stderr, "Starting parse\n"));
- yylval.Number = 0;
- yyval.Number = 0;
-
yystate = 0;
yyerrstatus = 0;
yynerrs = 0;
@@ -704,110 +1084,96 @@ yyparse(YYPARSE_PARAM_ARG)
so that they stay on the same level as the state stack.
The wasted elements are never initialized. */
- yyssp = yyss - 1;
+ yyssp = yyss;
yyvsp = yyvs;
-#ifdef YYLSP_NEEDED
- yylsp = yyls;
-#endif
-/* Push a new state, which is found in yystate . */
-/* In all cases, when you get here, the value and location stacks
- have just been pushed. so pushing a state here evens the stacks. */
-yynewstate:
+ goto yysetstate;
- *++yyssp = (short)yystate;
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. so pushing a state here evens the stacks.
+ */
+ yyssp++;
- if (yyssp >= yyss + yystacksize - 1)
- {
- /* Give user a chance to reallocate the stack */
- /* Use copies of these so that the &'s don't force the real ones into memory. */
- YYSTYPE *yyvs1 = yyvs;
- short *yyss1 = yyss;
-#ifdef YYLSP_NEEDED
- YYLTYPE *yyls1 = yyls;
-#endif
+ yysetstate:
+ *yyssp = yystate;
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
/* Get the current used size of the three stacks, in elements. */
- int size = (int)(yyssp - yyss + 1);
+ YYSIZE_T yysize = yyssp - yyss + 1;
#ifdef yyoverflow
- /* Each stack pointer address is followed by the size of
- the data in use in that stack, in bytes. */
-#ifdef YYLSP_NEEDED
- /* This used to be a conditional around just the two extra args,
- but that might be undefined if yyoverflow is a macro. */
- yyoverflow("parser stack overflow",
- &yyss1, size * sizeof (*yyssp),
- &yyvs1, size * sizeof (*yyvsp),
- &yyls1, size * sizeof (*yylsp),
- &yystacksize);
-#else
- yyoverflow("parser stack overflow",
- &yyss1, size * sizeof (*yyssp),
- &yyvs1, size * sizeof (*yyvsp),
- &yystacksize);
-#endif
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ short *yyss1 = yyss;
- yyss = yyss1; yyvs = yyvs1;
-#ifdef YYLSP_NEEDED
- yyls = yyls1;
-#endif
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow ("parser stack overflow",
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyoverflowlab;
+# else
/* Extend the stack our own way. */
- if (yystacksize >= YYMAXDEPTH)
- {
- yyerror("parser stack overflow");
- if (yyfree_stacks)
- {
- free (yyss);
- free (yyvs);
-#ifdef YYLSP_NEEDED
- free (yyls);
-#endif
- }
- return 2;
- }
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyoverflowlab;
yystacksize *= 2;
- if (yystacksize > YYMAXDEPTH)
+ if (YYMAXDEPTH < yystacksize)
yystacksize = YYMAXDEPTH;
-#ifndef YYSTACK_USE_ALLOCA
- yyfree_stacks = 1;
-#endif
- yyss = (short *) YYSTACK_ALLOC (yystacksize * sizeof (*yyssp));
- __yy_memcpy ((char *)yyss, (char *)yyss1,
- size * (unsigned int) sizeof (*yyssp));
- yyvs = (YYSTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yyvsp));
- __yy_memcpy ((char *)yyvs, (char *)yyvs1,
- size * (unsigned int) sizeof (*yyvsp));
-#ifdef YYLSP_NEEDED
- yyls = (YYLTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yylsp));
- __yy_memcpy ((char *)yyls, (char *)yyls1,
- size * (unsigned int) sizeof (*yylsp));
-#endif
+
+ {
+ short *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyoverflowlab;
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
#endif /* no yyoverflow */
- yyssp = yyss + size - 1;
- yyvsp = yyvs + size - 1;
-#ifdef YYLSP_NEEDED
- yylsp = yyls + size - 1;
-#endif
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
-#if YYDEBUG != 0
- if (yydebug)
- fprintf(stderr, "Stack size increased to %d\n", yystacksize);
-#endif
- if (yyssp >= yyss + yystacksize - 1)
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
YYABORT;
}
-#if YYDEBUG != 0
- if (yydebug)
- fprintf(stderr, "Entering state %d\n", yystate);
-#endif
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
goto yybackup;
- yybackup:
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
/* Do appropriate processing given the current state. */
/* Read a lookahead token if we need one and don't already have one. */
@@ -816,183 +1182,154 @@ yynewstate:
/* First try to decide what to do without reference to lookahead token. */
yyn = yypact[yystate];
- if (yyn == YYFLAG)
+ if (yyn == YYPACT_NINF)
goto yydefault;
/* Not known => get a lookahead token if don't already have one. */
- /* yychar is either YYEMPTY or YYEOF
- or a valid token in external form. */
-
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
if (yychar == YYEMPTY)
{
-#if YYDEBUG != 0
- if (yydebug)
- fprintf(stderr, "Reading a token: ");
-#endif
+ YYDPRINTF ((stderr, "Reading a token: "));
yychar = YYLEX;
}
- /* Convert token to internal form (in yychar1) for indexing tables with */
-
- if (yychar <= 0) /* This means end of input. */
+ if (yychar <= YYEOF)
{
- yychar1 = 0;
- yychar = YYEOF; /* Don't call YYLEX any more */
-
-#if YYDEBUG != 0
- if (yydebug)
- fprintf(stderr, "Now at end of input.\n");
-#endif
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
}
else
{
- yychar1 = YYTRANSLATE(yychar);
-
-#if YYDEBUG != 0
- if (yydebug)
- {
- fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]);
- /* Give the individual parser a way to print the precise meaning
- of a token, for further debugging info. */
-#ifdef YYPRINT
- YYPRINT (stderr, yychar, yylval);
-#endif
- fprintf (stderr, ")\n");
- }
-#endif
+ yytoken = YYTRANSLATE (yychar);
+ YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc);
}
- yyn += yychar1;
- if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1)
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
goto yydefault;
-
yyn = yytable[yyn];
-
- /* yyn is what to do for this token type in this state.
- Negative => reduce, -yyn is rule number.
- Positive => shift, yyn is new state.
- New state is final state => don't bother to shift,
- just return success.
- 0, or most negative number => error. */
-
- if (yyn < 0)
+ if (yyn <= 0)
{
- if (yyn == YYFLAG)
+ if (yyn == 0 || yyn == YYTABLE_NINF)
goto yyerrlab;
yyn = -yyn;
goto yyreduce;
}
- else if (yyn == 0)
- goto yyerrlab;
if (yyn == YYFINAL)
YYACCEPT;
/* Shift the lookahead token. */
-
-#if YYDEBUG != 0
- if (yydebug)
- fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]);
-#endif
+ YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken]));
/* Discard the token being shifted unless it is eof. */
if (yychar != YYEOF)
yychar = YYEMPTY;
*++yyvsp = yylval;
-#ifdef YYLSP_NEEDED
- *++yylsp = yylloc;
-#endif
- /* count tokens shifted since error; after three, turn off error status. */
- if (yyerrstatus) yyerrstatus--;
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
yystate = yyn;
goto yynewstate;
-/* Do the default action for the current state. */
-yydefault:
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
yyn = yydefact[yystate];
if (yyn == 0)
goto yyerrlab;
+ goto yyreduce;
+
-/* Do a reduction. yyn is the number of a rule to reduce with. */
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
yyreduce:
+ /* yyn is the number of a rule to reduce with. */
yylen = yyr2[yyn];
- if (yylen > 0)
- yyval = yyvsp[1-yylen]; /* implement default value of the action */
-#if YYDEBUG != 0
- if (yydebug)
- {
- int i;
-
- fprintf (stderr, "Reducing via rule %d (line %d), ",
- yyn, yyrline[yyn]);
-
- /* Print the symbols being reduced, and their result. */
- for (i = yyprhs[yyn]; yyrhs[i] > 0; i++)
- fprintf (stderr, "%s ", yytname[yyrhs[i]]);
- fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]);
- }
-#endif
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
- switch (yyn) {
-case 3:
-#line 235 "getdate.y"
-{
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 4:
+#line 248 "getdate.y"
+ {
context->yyHaveTime++;
- ;
- break;}
-case 4:
-#line 238 "getdate.y"
-{
+ }
+ break;
+
+ case 5:
+#line 251 "getdate.y"
+ {
context->yyHaveZone++;
- ;
- break;}
-case 5:
-#line 241 "getdate.y"
-{
+ }
+ break;
+
+ case 6:
+#line 254 "getdate.y"
+ {
context->yyHaveDate++;
- ;
- break;}
-case 6:
-#line 244 "getdate.y"
-{
+ }
+ break;
+
+ case 7:
+#line 257 "getdate.y"
+ {
context->yyHaveDay++;
- ;
- break;}
-case 7:
-#line 247 "getdate.y"
-{
+ }
+ break;
+
+ case 8:
+#line 260 "getdate.y"
+ {
context->yyHaveRel++;
- ;
- break;}
-case 9:
-#line 253 "getdate.y"
-{
+ }
+ break;
+
+ case 10:
+#line 266 "getdate.y"
+ {
context->yyHour = yyvsp[-1].Number;
context->yyMinutes = 0;
context->yySeconds = 0;
context->yyMeridian = yyvsp[0].Meridian;
- ;
- break;}
-case 10:
-#line 259 "getdate.y"
-{
+ }
+ break;
+
+ case 11:
+#line 272 "getdate.y"
+ {
context->yyHour = yyvsp[-3].Number;
context->yyMinutes = yyvsp[-1].Number;
context->yySeconds = 0;
context->yyMeridian = yyvsp[0].Meridian;
- ;
- break;}
-case 11:
-#line 265 "getdate.y"
-{
+ }
+ break;
+
+ case 12:
+#line 278 "getdate.y"
+ {
context->yyHour = yyvsp[-3].Number;
context->yyMinutes = yyvsp[-1].Number;
context->yyMeridian = MER24;
@@ -1000,20 +1337,22 @@ case 11:
context->yyTimezone = (yyvsp[0].Number < 0
? -yyvsp[0].Number % 100 + (-yyvsp[0].Number / 100) * 60
: - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60));
- ;
- break;}
-case 12:
-#line 274 "getdate.y"
-{
+ }
+ break;
+
+ case 13:
+#line 287 "getdate.y"
+ {
context->yyHour = yyvsp[-5].Number;
context->yyMinutes = yyvsp[-3].Number;
context->yySeconds = yyvsp[-1].Number;
context->yyMeridian = yyvsp[0].Meridian;
- ;
- break;}
-case 13:
-#line 280 "getdate.y"
-{
+ }
+ break;
+
+ case 14:
+#line 293 "getdate.y"
+ {
context->yyHour = yyvsp[-5].Number;
context->yyMinutes = yyvsp[-3].Number;
context->yySeconds = yyvsp[-1].Number;
@@ -1022,57 +1361,65 @@ case 13:
context->yyTimezone = (yyvsp[0].Number < 0
? -yyvsp[0].Number % 100 + (-yyvsp[0].Number / 100) * 60
: - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60));
- ;
- break;}
-case 14:
-#line 292 "getdate.y"
-{
+ }
+ break;
+
+ case 15:
+#line 305 "getdate.y"
+ {
context->yyTimezone = yyvsp[0].Number;
- ;
- break;}
-case 15:
-#line 295 "getdate.y"
-{
+ }
+ break;
+
+ case 16:
+#line 308 "getdate.y"
+ {
context->yyTimezone = yyvsp[0].Number - 60;
- ;
- break;}
-case 16:
-#line 299 "getdate.y"
-{
+ }
+ break;
+
+ case 17:
+#line 312 "getdate.y"
+ {
context->yyTimezone = yyvsp[-1].Number - 60;
- ;
- break;}
-case 17:
-#line 304 "getdate.y"
-{
+ }
+ break;
+
+ case 18:
+#line 317 "getdate.y"
+ {
context->yyDayOrdinal = 1;
context->yyDayNumber = yyvsp[0].Number;
- ;
- break;}
-case 18:
-#line 308 "getdate.y"
-{
+ }
+ break;
+
+ case 19:
+#line 321 "getdate.y"
+ {
context->yyDayOrdinal = 1;
context->yyDayNumber = yyvsp[-1].Number;
- ;
- break;}
-case 19:
-#line 312 "getdate.y"
-{
+ }
+ break;
+
+ case 20:
+#line 325 "getdate.y"
+ {
context->yyDayOrdinal = yyvsp[-1].Number;
context->yyDayNumber = yyvsp[0].Number;
- ;
- break;}
-case 20:
-#line 318 "getdate.y"
-{
+ }
+ break;
+
+ case 21:
+#line 331 "getdate.y"
+ {
context->yyMonth = yyvsp[-2].Number;
context->yyDay = yyvsp[0].Number;
- ;
- break;}
-case 21:
-#line 322 "getdate.y"
-{
+ }
+ break;
+
+ case 22:
+#line 335 "getdate.y"
+ {
/* Interpret as YYYY/MM/DD if $1 >= 1000, otherwise as MM/DD/YY.
The goal in recognizing YYYY/MM/DD is solely to support legacy
machine-generated dates like those in an RCS log listing. If
@@ -1089,178 +1436,204 @@ case 21:
context->yyDay = yyvsp[-2].Number;
context->yyYear = yyvsp[0].Number;
}
- ;
- break;}
-case 22:
-#line 340 "getdate.y"
-{
+ }
+ break;
+
+ case 23:
+#line 353 "getdate.y"
+ {
/* ISO 8601 format. yyyy-mm-dd. */
context->yyYear = yyvsp[-2].Number;
context->yyMonth = -yyvsp[-1].Number;
context->yyDay = -yyvsp[0].Number;
- ;
- break;}
-case 23:
-#line 346 "getdate.y"
-{
+ }
+ break;
+
+ case 24:
+#line 359 "getdate.y"
+ {
/* e.g. 17-JUN-1992. */
context->yyDay = yyvsp[-2].Number;
context->yyMonth = yyvsp[-1].Number;
context->yyYear = -yyvsp[0].Number;
- ;
- break;}
-case 24:
-#line 352 "getdate.y"
-{
+ }
+ break;
+
+ case 25:
+#line 365 "getdate.y"
+ {
context->yyMonth = yyvsp[-1].Number;
context->yyDay = yyvsp[0].Number;
- ;
- break;}
-case 25:
-#line 356 "getdate.y"
-{
+ }
+ break;
+
+ case 26:
+#line 369 "getdate.y"
+ {
context->yyMonth = yyvsp[-3].Number;
context->yyDay = yyvsp[-2].Number;
context->yyYear = yyvsp[0].Number;
- ;
- break;}
-case 26:
-#line 361 "getdate.y"
-{
+ }
+ break;
+
+ case 27:
+#line 374 "getdate.y"
+ {
context->yyMonth = yyvsp[0].Number;
context->yyDay = yyvsp[-1].Number;
- ;
- break;}
-case 27:
-#line 365 "getdate.y"
-{
+ }
+ break;
+
+ case 28:
+#line 378 "getdate.y"
+ {
context->yyMonth = yyvsp[-1].Number;
context->yyDay = yyvsp[-2].Number;
context->yyYear = yyvsp[0].Number;
- ;
- break;}
-case 28:
-#line 372 "getdate.y"
-{
+ }
+ break;
+
+ case 29:
+#line 385 "getdate.y"
+ {
context->yyRelSeconds = -context->yyRelSeconds;
context->yyRelMinutes = -context->yyRelMinutes;
context->yyRelHour = -context->yyRelHour;
context->yyRelDay = -context->yyRelDay;
context->yyRelMonth = -context->yyRelMonth;
context->yyRelYear = -context->yyRelYear;
- ;
- break;}
-case 30:
-#line 383 "getdate.y"
-{
+ }
+ break;
+
+ case 31:
+#line 396 "getdate.y"
+ {
context->yyRelYear += yyvsp[-1].Number * yyvsp[0].Number;
- ;
- break;}
-case 31:
-#line 386 "getdate.y"
-{
+ }
+ break;
+
+ case 32:
+#line 399 "getdate.y"
+ {
context->yyRelYear += yyvsp[-1].Number * yyvsp[0].Number;
- ;
- break;}
-case 32:
-#line 389 "getdate.y"
-{
+ }
+ break;
+
+ case 33:
+#line 402 "getdate.y"
+ {
context->yyRelYear += yyvsp[0].Number;
- ;
- break;}
-case 33:
-#line 392 "getdate.y"
-{
+ }
+ break;
+
+ case 34:
+#line 405 "getdate.y"
+ {
context->yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number;
- ;
- break;}
-case 34:
-#line 395 "getdate.y"
-{
+ }
+ break;
+
+ case 35:
+#line 408 "getdate.y"
+ {
context->yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number;
- ;
- break;}
-case 35:
-#line 398 "getdate.y"
-{
+ }
+ break;
+
+ case 36:
+#line 411 "getdate.y"
+ {
context->yyRelMonth += yyvsp[0].Number;
- ;
- break;}
-case 36:
-#line 401 "getdate.y"
-{
+ }
+ break;
+
+ case 37:
+#line 414 "getdate.y"
+ {
context->yyRelDay += yyvsp[-1].Number * yyvsp[0].Number;
- ;
- break;}
-case 37:
-#line 404 "getdate.y"
-{
+ }
+ break;
+
+ case 38:
+#line 417 "getdate.y"
+ {
context->yyRelDay += yyvsp[-1].Number * yyvsp[0].Number;
- ;
- break;}
-case 38:
-#line 407 "getdate.y"
-{
+ }
+ break;
+
+ case 39:
+#line 420 "getdate.y"
+ {
context->yyRelDay += yyvsp[0].Number;
- ;
- break;}
-case 39:
-#line 410 "getdate.y"
-{
+ }
+ break;
+
+ case 40:
+#line 423 "getdate.y"
+ {
context->yyRelHour += yyvsp[-1].Number * yyvsp[0].Number;
- ;
- break;}
-case 40:
-#line 413 "getdate.y"
-{
+ }
+ break;
+
+ case 41:
+#line 426 "getdate.y"
+ {
context->yyRelHour += yyvsp[-1].Number * yyvsp[0].Number;
- ;
- break;}
-case 41:
-#line 416 "getdate.y"
-{
+ }
+ break;
+
+ case 42:
+#line 429 "getdate.y"
+ {
context->yyRelHour += yyvsp[0].Number;
- ;
- break;}
-case 42:
-#line 419 "getdate.y"
-{
+ }
+ break;
+
+ case 43:
+#line 432 "getdate.y"
+ {
context->yyRelMinutes += yyvsp[-1].Number * yyvsp[0].Number;
- ;
- break;}
-case 43:
-#line 422 "getdate.y"
-{
+ }
+ break;
+
+ case 44:
+#line 435 "getdate.y"
+ {
context->yyRelMinutes += yyvsp[-1].Number * yyvsp[0].Number;
- ;
- break;}
-case 44:
-#line 425 "getdate.y"
-{
+ }
+ break;
+
+ case 45:
+#line 438 "getdate.y"
+ {
context->yyRelMinutes += yyvsp[0].Number;
- ;
- break;}
-case 45:
-#line 428 "getdate.y"
-{
+ }
+ break;
+
+ case 46:
+#line 441 "getdate.y"
+ {
context->yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number;
- ;
- break;}
-case 46:
-#line 431 "getdate.y"
-{
+ }
+ break;
+
+ case 47:
+#line 444 "getdate.y"
+ {
context->yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number;
- ;
- break;}
-case 47:
-#line 434 "getdate.y"
-{
+ }
+ break;
+
+ case 48:
+#line 447 "getdate.y"
+ {
context->yyRelSeconds += yyvsp[0].Number;
- ;
- break;}
-case 48:
-#line 440 "getdate.y"
-{
+ }
+ break;
+
+ case 49:
+#line 453 "getdate.y"
+ {
if (context->yyHaveTime && context->yyHaveDate &&
!context->yyHaveRel)
context->yyYear = yyvsp[0].Number;
@@ -1290,243 +1663,222 @@ case 48:
context->yyMeridian = MER24;
}
}
- ;
- break;}
-case 49:
-#line 474 "getdate.y"
-{
+ }
+ break;
+
+ case 50:
+#line 487 "getdate.y"
+ {
yyval.Meridian = MER24;
- ;
- break;}
-case 50:
-#line 478 "getdate.y"
-{
+ }
+ break;
+
+ case 51:
+#line 491 "getdate.y"
+ {
yyval.Meridian = yyvsp[0].Meridian;
- ;
- break;}
-}
- /* the action file gets copied in in place of this dollarsign */
-#line 543 "/usr/local/share/bison.simple"
+ }
+ break;
+
+
+ }
+
+/* Line 999 of yacc.c. */
+#line 1688 "y.tab.c"
yyvsp -= yylen;
yyssp -= yylen;
-#ifdef YYLSP_NEEDED
- yylsp -= yylen;
-#endif
-#if YYDEBUG != 0
- if (yydebug)
- {
- short *ssp1 = yyss - 1;
- fprintf (stderr, "state stack now");
- while (ssp1 != yyssp)
- fprintf (stderr, " %d", *++ssp1);
- fprintf (stderr, "\n");
- }
-#endif
+
+ YY_STACK_PRINT (yyss, yyssp);
*++yyvsp = yyval;
-#ifdef YYLSP_NEEDED
- yylsp++;
- if (yylen == 0)
- {
- yylsp->first_line = yylloc.first_line;
- yylsp->first_column = yylloc.first_column;
- yylsp->last_line = (yylsp-1)->last_line;
- yylsp->last_column = (yylsp-1)->last_column;
- yylsp->text = 0;
- }
- else
- {
- yylsp->last_line = (yylsp+yylen-1)->last_line;
- yylsp->last_column = (yylsp+yylen-1)->last_column;
- }
-#endif
- /* Now "shift" the result of the reduction.
- Determine what state that goes to,
- based on the state we popped back to
- and the rule number reduced by. */
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
yyn = yyr1[yyn];
- yystate = yypgoto[yyn - YYNTBASE] + *yyssp;
- if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
yystate = yytable[yystate];
else
- yystate = yydefgoto[yyn - YYNTBASE];
+ yystate = yydefgoto[yyn - YYNTOKENS];
goto yynewstate;
-yyerrlab: /* here on detecting error */
- if (! yyerrstatus)
- /* If not already recovering from an error, report this error. */
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
{
++yynerrs;
-
-#ifdef YYERROR_VERBOSE
+#if YYERROR_VERBOSE
yyn = yypact[yystate];
- if (yyn > YYFLAG && yyn < YYLAST)
+ if (YYPACT_NINF < yyn && yyn < YYLAST)
{
- int size = 0;
- char *msg;
- int x, count;
-
- count = 0;
- /* Start X at -yyn if nec to avoid negative indexes in yycheck. */
- for (x = (yyn < 0 ? -yyn : 0);
- x < (sizeof(yytname) / sizeof(char *)); x++)
- if (yycheck[x + yyn] == x)
- size += strlen(yytname[x]) + 15, count++;
- msg = (char *) malloc(size + 15);
- if (msg != 0)
+ YYSIZE_T yysize = 0;
+ int yytype = YYTRANSLATE (yychar);
+ char *yymsg;
+ int yyx, yycount;
+
+ yycount = 0;
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ for (yyx = yyn < 0 ? -yyn : 0;
+ yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ yysize += yystrlen (yytname[yyx]) + 15, yycount++;
+ yysize += yystrlen ("syntax error, unexpected ") + 1;
+ yysize += yystrlen (yytname[yytype]);
+ yymsg = (char *) YYSTACK_ALLOC (yysize);
+ if (yymsg != 0)
{
- strcpy(msg, "parse error");
+ char *yyp = yystpcpy (yymsg, "syntax error, unexpected ");
+ yyp = yystpcpy (yyp, yytname[yytype]);
- if (count < 5)
+ if (yycount < 5)
{
- count = 0;
- for (x = (yyn < 0 ? -yyn : 0);
- x < (sizeof(yytname) / sizeof(char *)); x++)
- if (yycheck[x + yyn] == x)
+ yycount = 0;
+ for (yyx = yyn < 0 ? -yyn : 0;
+ yyx < (int) (sizeof (yytname) / sizeof (char *));
+ yyx++)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
{
- strcat(msg, count == 0 ? ", expecting `" : " or `");
- strcat(msg, yytname[x]);
- strcat(msg, "'");
- count++;
+ const char *yyq = ! yycount ? ", expecting " : " or ";
+ yyp = yystpcpy (yyp, yyq);
+ yyp = yystpcpy (yyp, yytname[yyx]);
+ yycount++;
}
}
- yyerror(msg);
- free(msg);
+ yyerror (yymsg);
+ YYSTACK_FREE (yymsg);
}
else
- yyerror ("parse error; also virtual memory exceeded");
+ yyerror ("syntax error; also virtual memory exhausted");
}
else
#endif /* YYERROR_VERBOSE */
- yyerror("parse error");
+ yyerror ("syntax error");
}
- goto yyerrlab1;
-yyerrlab1: /* here on error raised explicitly by an action */
+
if (yyerrstatus == 3)
{
- /* if just tried and failed to reuse lookahead token after an error, discard it. */
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
- /* return failure if at end of input */
+ /* Return failure if at end of input. */
if (yychar == YYEOF)
- YYABORT;
-
-#if YYDEBUG != 0
- if (yydebug)
- fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]);
-#endif
+ {
+ /* Pop the error token. */
+ YYPOPSTACK;
+ /* Pop the rest of the stack. */
+ while (yyss < yyssp)
+ {
+ YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
+ yydestruct (yystos[*yyssp], yyvsp);
+ YYPOPSTACK;
+ }
+ YYABORT;
+ }
+ YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc);
+ yydestruct (yytoken, &yylval);
yychar = YYEMPTY;
- }
- /* Else will try to reuse lookahead token
- after shifting the error token. */
-
- yyerrstatus = 3; /* Each real token shifted decrements this */
-
- goto yyerrhandle;
-
-yyerrdefault: /* current state does not do anything special for the error token. */
+ }
-#if 0
- /* This is wrong; only states that explicitly want error tokens
- should shift them. */
- yyn = yydefact[yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/
- if (yyn) goto yydefault;
-#endif
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab1;
-yyerrpop: /* pop the current state because it cannot handle the error token */
- if (yyssp == yyss) YYABORT;
- yyvsp--;
- yystate = *--yyssp;
-#ifdef YYLSP_NEEDED
- yylsp--;
-#endif
+/*----------------------------------------------------.
+| yyerrlab1 -- error raised explicitly by an action. |
+`----------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
-#if YYDEBUG != 0
- if (yydebug)
+ for (;;)
{
- short *ssp1 = yyss - 1;
- fprintf (stderr, "Error: state stack now");
- while (ssp1 != yyssp)
- fprintf (stderr, " %d", *++ssp1);
- fprintf (stderr, "\n");
- }
-#endif
-
-yyerrhandle:
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
- yyn = yypact[yystate];
- if (yyn == YYFLAG)
- goto yyerrdefault;
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
- yyn += YYTERROR;
- if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR)
- goto yyerrdefault;
+ YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
+ yydestruct (yystos[yystate], yyvsp);
+ yyvsp--;
+ yystate = *--yyssp;
- yyn = yytable[yyn];
- if (yyn < 0)
- {
- if (yyn == YYFLAG)
- goto yyerrpop;
- yyn = -yyn;
- goto yyreduce;
+ YY_STACK_PRINT (yyss, yyssp);
}
- else if (yyn == 0)
- goto yyerrpop;
if (yyn == YYFINAL)
YYACCEPT;
-#if YYDEBUG != 0
- if (yydebug)
- fprintf(stderr, "Shifting error token, ");
-#endif
+ YYDPRINTF ((stderr, "Shifting error token, "));
*++yyvsp = yylval;
-#ifdef YYLSP_NEEDED
- *++yylsp = yylloc;
-#endif
+
yystate = yyn;
goto yynewstate;
- yyacceptlab:
- /* YYACCEPT comes here. */
- if (yyfree_stacks)
- {
- free (yyss);
- free (yyvs);
-#ifdef YYLSP_NEEDED
- free (yyls);
-#endif
- }
- return 0;
- yyabortlab:
- /* YYABORT comes here. */
- if (yyfree_stacks)
- {
- free (yyss);
- free (yyvs);
-#ifdef YYLSP_NEEDED
- free (yyls);
-#endif
- }
- return 1;
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#ifndef yyoverflow
+/*----------------------------------------------.
+| yyoverflowlab -- parser overflow comes here. |
+`----------------------------------------------*/
+yyoverflowlab:
+ yyerror ("parser stack overflow");
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+ return yyresult;
}
-#line 483 "getdate.y"
+
+
+#line 496 "getdate.y"
/* Include this file down here because bison inserts code above which
@@ -1535,9 +1887,9 @@ yyerrhandle:
#include "getdate.h"
#ifndef WIN32 /* the windows dudes don't need these, does anyone really? */
-extern struct tm *gmtime (const time_t *timer);
-extern struct tm *localtime (const time_t *timer);
-extern time_t mktime (struct tm *timeptr);
+extern struct tm *gmtime (const time_t *);
+extern struct tm *localtime (const time_t *);
+extern time_t mktime (struct tm *);
#endif
/* Month and day table. */
@@ -1729,17 +2081,13 @@ static TABLE const MilitaryTable[] = {
/* ARGSUSED */
static int
-yyerror (s)
- char *s ATTRIBUTE_UNUSED;
+yyerror (const char *s ATTRIBUTE_UNUSED)
{
- (void)s;
return 0;
}
static int
-ToHour (Hours, Meridian)
- int Hours;
- MERIDIAN Meridian;
+ToHour (int Hours, MERIDIAN Meridian)
{
switch (Meridian)
{
@@ -1760,14 +2108,14 @@ ToHour (Hours, Meridian)
Hours = 0;
return Hours + 12;
default:
- abort ();
+ break; /* used to do abort() here */
}
- /* NOTREACHED */
+ /* NOTREACHED - but make gcc happy! */
+ return -1;
}
static int
-ToYear (Year)
- int Year;
+ToYear (int Year)
{
if (Year < 0)
Year = -Year;
@@ -1783,20 +2131,18 @@ ToYear (Year)
}
static int
-LookupWord (yylval, buff)
- YYSTYPE *yylval;
- char *buff;
+LookupWord (YYSTYPE *yylval, char *buff)
{
- register char *p;
- register char *q;
- register const TABLE *tp;
- int i;
+ char *p;
+ char *q;
+ const TABLE *tp;
+ size_t i;
int abbrev;
/* Make it lowercase. */
for (p = buff; *p; p++)
- if (ISUPPER ((unsigned int)(*p)))
- *p = (char)tolower ((unsigned int)(*p));
+ if (ISUPPER ((unsigned char) *p))
+ *p = tolower ((int)*p);
if (strcmp (buff, "am") == 0 || strcmp (buff, "a.m.") == 0)
{
@@ -1855,7 +2201,7 @@ LookupWord (yylval, buff)
}
/* Strip off any plural and try the units table again. */
- i = (int)strlen (buff) - 1;
+ i = strlen (buff) - 1;
if (buff[i] == 's')
{
buff[i] = '\0';
@@ -1905,9 +2251,7 @@ LookupWord (yylval, buff)
}
static int
-yylex (yylval, cookie)
- YYSTYPE *yylval;
- void *cookie;
+yylex (YYSTYPE *yylval, void *cookie)
{
register unsigned char c;
register char *p;
@@ -1992,7 +2336,7 @@ curl_getdate (const char *p, const time_t *now)
{
struct tm tm, tm0, *tmp;
time_t Start;
- CONTEXT cookie;
+ CURL_CONTEXT cookie;
#ifdef HAVE_LOCALTIME_R
struct tm keeptime;
#endif
@@ -2025,7 +2369,7 @@ curl_getdate (const char *p, const time_t *now)
cookie.yyHaveTime = 0;
cookie.yyHaveZone = 0;
- if (yyparse ((void*)&cookie)
+ if (yyparse (&cookie)
|| cookie.yyHaveTime > 1 || cookie.yyHaveZone > 1 ||
cookie.yyHaveDate > 1 || cookie.yyHaveDay > 1)
return -1;
@@ -2106,8 +2450,8 @@ curl_getdate (const char *p, const time_t *now)
struct tm *gmt;
#ifdef HAVE_GMTIME_R
/* thread-safe version */
- struct tm keeptime;
- gmt = (struct tm *)gmtime_r(&Start, &keeptime);
+ struct tm keeptime2;
+ gmt = (struct tm *)gmtime_r(&Start, &keeptime2);
#else
gmt = gmtime(&Start);
#endif
@@ -2122,32 +2466,4 @@ curl_getdate (const char *p, const time_t *now)
return Start;
}
-#if defined (TEST)
-
-/* ARGSUSED */
-int
-main (ac, av)
- int ac;
- char *av[];
-{
- char buff[MAX_BUFF_LEN + 1];
- time_t d;
-
- (void) printf ("Enter date, or blank line to exit.\n\t> ");
- (void) fflush (stdout);
- buff[MAX_BUFF_LEN] = 0;
- while (fgets (buff, MAX_BUFF_LEN, stdin) && buff[0])
- {
- d = curl_getdate (buff, (time_t *) NULL);
- if (d == -1)
- (void) printf ("Bad format - couldn't convert.\n");
- else
- (void) printf ("%s", ctime (&d));
- (void) printf ("\t> ");
- (void) fflush (stdout);
- }
- exit (0);
- /* NOTREACHED */
-}
-#endif /* defined (TEST) */
diff --git a/Source/CTest/Curl/getenv.c b/Source/CTest/Curl/getenv.c
index efb4be1..a21502c 100644
--- a/Source/CTest/Curl/getenv.c
+++ b/Source/CTest/Curl/getenv.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -35,9 +35,10 @@
#include <unixlib.h>
#endif
-#ifdef MALLOCDEBUG
+#include <curl/curl.h>
+#include "memory.h"
+
#include "memdebug.h"
-#endif
static
char *GetEnv(const char *variable)
@@ -53,8 +54,7 @@ char *GetEnv(const char *variable)
#ifdef VMS
char *env = getenv(variable);
if (env && strcmp("HOME",variable) == 0) {
- /* VMS does not work because of warning on icc */
- /* env = decc$translate_vms(env); */
+ env = decc$translate_vms(env);
}
#else
/* no length control */
@@ -68,11 +68,3 @@ char *curl_getenv(const char *v)
{
return GetEnv(v);
}
-
-/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
- */
diff --git a/Source/CTest/Curl/getinfo.c b/Source/CTest/Curl/getinfo.c
index d044075..bdb909e 100644
--- a/Source/CTest/Curl/getinfo.c
+++ b/Source/CTest/Curl/getinfo.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -26,21 +26,16 @@
#include <curl/curl.h>
#include "urldata.h"
+#include "getinfo.h"
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
-
-#ifdef VMS
-#include <stdlib.h>
-#endif
+#include <stdlib.h>
+#include "memory.h"
/* Make this the last #include */
-#ifdef MALLOCDEBUG
#include "memdebug.h"
-#else
-#include <stdlib.h>
-#endif
/*
* This is supposed to be called in the beginning of a permform() session
@@ -103,9 +98,12 @@ CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...)
case CURLINFO_EFFECTIVE_URL:
*param_charp = data->change.url?data->change.url:(char *)"";
break;
- case CURLINFO_HTTP_CODE:
+ case CURLINFO_RESPONSE_CODE:
*param_longp = data->info.httpcode;
break;
+ case CURLINFO_HTTP_CONNECTCODE:
+ *param_longp = data->info.httpproxycode;
+ break;
case CURLINFO_FILETIME:
*param_longp = data->info.filetime;
break;
@@ -131,25 +129,25 @@ CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...)
*param_doublep = data->progress.t_starttransfer;
break;
case CURLINFO_SIZE_UPLOAD:
- *param_doublep = data->progress.uploaded;
+ *param_doublep = (double)data->progress.uploaded;
break;
case CURLINFO_SIZE_DOWNLOAD:
- *param_doublep = data->progress.downloaded;
+ *param_doublep = (double)data->progress.downloaded;
break;
case CURLINFO_SPEED_DOWNLOAD:
- *param_doublep = data->progress.dlspeed;
+ *param_doublep = (double)data->progress.dlspeed;
break;
case CURLINFO_SPEED_UPLOAD:
- *param_doublep = data->progress.ulspeed;
+ *param_doublep = (double)data->progress.ulspeed;
break;
case CURLINFO_SSL_VERIFYRESULT:
*param_longp = data->set.ssl.certverifyresult;
break;
case CURLINFO_CONTENT_LENGTH_DOWNLOAD:
- *param_doublep = data->progress.size_dl;
+ *param_doublep = (double)data->progress.size_dl;
break;
case CURLINFO_CONTENT_LENGTH_UPLOAD:
- *param_doublep = data->progress.size_ul;
+ *param_doublep = (double)data->progress.size_ul;
break;
case CURLINFO_REDIRECT_TIME:
*param_doublep = data->progress.t_redirect;
@@ -161,18 +159,16 @@ CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...)
*param_charp = data->info.contenttype;
break;
case CURLINFO_PRIVATE:
- *param_charp = data->set.private?data->set.private:(char *)"";
+ *param_charp = data->set.private;
+ break;
+ case CURLINFO_HTTPAUTH_AVAIL:
+ *param_longp = data->info.httpauthavail;
+ break;
+ case CURLINFO_PROXYAUTH_AVAIL:
+ *param_longp = data->info.proxyauthavail;
break;
default:
return CURLE_BAD_FUNCTION_ARGUMENT;
}
return CURLE_OK;
}
-
-/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
- */
diff --git a/Source/CTest/Curl/getinfo.h b/Source/CTest/Curl/getinfo.h
index dd30afb..2fe1b5c 100644
--- a/Source/CTest/Curl/getinfo.h
+++ b/Source/CTest/Curl/getinfo.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
diff --git a/Source/CTest/Curl/getpass.c b/Source/CTest/Curl/getpass.c
deleted file mode 100644
index 22692fd..0000000
--- a/Source/CTest/Curl/getpass.c
+++ /dev/null
@@ -1,236 +0,0 @@
-/* ============================================================================
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * Redistribution and use are freely permitted provided that:
- *
- * 1) This header remain in tact.
- * 2) The prototypes for getpass and getpass_r are not changed from:
- * char *getpass(const char *prompt)
- * char *getpass_r(const char *prompt, char* buffer, int buflen)
- * 3) This source code is not used outside of this(getpass.c) file.
- * 4) Any changes to this(getpass.c) source code are made publicly available.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
- * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * ============================================================================
- *
- * $Id$
- *
- * The spirit of this license is to allow use of this source code in any
- * project be it open or closed but still encourage the use of the open,
- * library based equivilents.
- *
- * Author(s):
- * Angus Mackay <amackay@gus.ml.org>
- *
- * Contributor(s):
- * Daniel Stenberg <daniel@haxx.se>
- */
-
-#include "setup.h" /* setup.h is required for read() prototype */
-
-#ifndef HAVE_GETPASS_R
-
-#ifndef WIN32
-#ifdef VMS
-#include <stdio.h>
-#include <string.h>
-#include descrip
-#include starlet
-#include iodef
-#include iosbdef
-char *getpass_r(const char *prompt, char *buffer, size_t buflen)
-{
- long sts;
- short chan;
- struct _iosb iosb;
- /* VMS does not work because of warnings on icc */
- /* $DESCRIPTOR(ttdesc, "TT");
-
- buffer[0]='\0';
- if ((sts = sys$assign(&ttdesc, &chan,0,0)) & 1) {
- if (((sts = sys$qiow(0, chan, IO$_READPROMPT | IO$M_NOECHO, &iosb, 0, 0, buffer, buflen, 0, 0, prompt, strlen(prompt))) & 1) && (iosb.iosb$w_status&1)) {
- buffer[iosb.iosb$w_bcnt] = '\0';
- }
- sts = sys$dassgn(chan);
- }
- */
- return buffer; /* we always return success */
-}
-#else /* VMS */
-#ifdef HAVE_TERMIOS_H
-# if !defined(HAVE_TCGETATTR) && !defined(HAVE_TCSETATTR)
-# undef HAVE_TERMIOS_H
-# endif
-#endif
-
-#ifndef RETSIGTYPE
-# define RETSIGTYPE void
-#endif
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <stdio.h>
-#include <signal.h>
-#ifdef HAVE_TERMIOS_H
-# include <termios.h>
-#else
-# ifdef HAVE_TERMIO_H
-# include <termio.h>
-# else
-# endif
-#endif
-
-/* The last #include file should be: */
-#ifdef MALLOCDEBUG
-#include "memdebug.h"
-#endif
-
-char *getpass_r(const char *prompt, char *buffer, size_t buflen)
-{
- FILE *infp;
- char infp_fclose = 0;
- FILE *outfp;
- RETSIGTYPE (*sigint)();
-#ifndef __EMX__
- RETSIGTYPE (*sigtstp)();
-#endif
- size_t bytes_read;
- int infd;
- int outfd;
-#ifdef HAVE_TERMIOS_H
- struct termios orig;
- struct termios noecho;
-#else
-# ifdef HAVE_TERMIO_H
- struct termio orig;
- struct termio noecho;
-# else
-# endif
-#endif
-
- sigint = signal(SIGINT, SIG_IGN);
- /* 20000318 mgs
- * this is needed by the emx system, SIGTSTP is not a supported signal */
-#ifndef __EMX__
- sigtstp = signal(SIGTSTP, SIG_IGN);
-#endif
-
- infp=fopen("/dev/tty", "r");
- if( NULL == infp )
- infp = stdin;
- else
- infp_fclose = 1;
-
- outfp = stderr;
-
- infd = fileno(infp);
- outfd = fileno(outfp);
-
- /* dissable echo */
-#ifdef HAVE_TERMIOS_H
- tcgetattr(outfd, &orig);
-
- noecho = orig;
- noecho.c_lflag &= ~ECHO;
- tcsetattr(outfd, TCSANOW, &noecho);
-#else
-# ifdef HAVE_TERMIO_H
- ioctl(outfd, TCGETA, &orig);
- noecho = orig;
- noecho.c_lflag &= ~ECHO;
- ioctl(outfd, TCSETA, &noecho);
-# else
-# endif
-#endif
-
- fputs(prompt, outfp);
- fflush(outfp);
-
- bytes_read=read(infd, buffer, buflen);
- buffer[bytes_read > 0 ? (bytes_read -1) : 0] = '\0';
-
- /* print a new line if needed */
-#ifdef HAVE_TERMIOS_H
- fputs("\n", outfp);
-#else
-# ifdef HAVE_TERMIO_H
- fputs("\n", outfp);
-# else
-# endif
-#endif
-
- /*
- * reset term charectaristics, use TCSAFLUSH incase the
- * user types more than buflen
- */
-#ifdef HAVE_TERMIOS_H
- tcsetattr(outfd, TCSAFLUSH, &orig);
-#else
-# ifdef HAVE_TERMIO_H
- ioctl(outfd, TCSETA, &orig);
-# else
-# endif
-#endif
-
- signal(SIGINT, sigint);
-#ifndef __EMX__
- signal(SIGTSTP, sigtstp);
-#endif
-
- if(infp_fclose)
- fclose(infp);
-
- return buffer; /* we always return success */
-}
-#endif /* VMS */
-#else /* WIN32 */
-#include <stdio.h>
-#include <conio.h>
-char *getpass_r(const char *prompt, char *buffer, int buflen)
-{
- int i;
- printf("%s", prompt);
-
- for(i=0; i<buflen; i++) {
- buffer[i] = (char)getch();
- if ( buffer[i] == '\r' ) {
- buffer[i] = 0;
- break;
- }
- }
- /* if user didn't hit ENTER, terminate buffer */
- if (i==buflen)
- buffer[buflen-1]=0;
-
- return buffer; /* we always return success */
-}
-#endif
-
-#endif /* ifndef HAVE_GETPASS_R */
-
-#if 0
-/* for consistensy, here's the old-style function: */
-char *getpass(const char *prompt)
-{
- static char buf[256];
- return getpass_r(prompt, buf, sizeof(buf));
-}
-#endif
-
-/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
- */
diff --git a/Source/CTest/Curl/hash.c b/Source/CTest/Curl/hash.c
index 6d4ce2e..be841b3 100644
--- a/Source/CTest/Curl/hash.c
+++ b/Source/CTest/Curl/hash.c
@@ -1,16 +1,16 @@
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -28,17 +28,13 @@
#include "hash.h"
#include "llist.h"
+#include "memory.h"
-#ifdef MALLOCDEBUG
/* this must be the last include file */
#include "memdebug.h"
-#endif
-
-/* {{{ static unsigned long _hash_str (const char *, size_t)
- */
static unsigned long
-_hash_str (const char *key, size_t key_length)
+hash_str(const char *key, size_t key_length)
{
char *end = (char *) key + key_length;
unsigned long h = 5381;
@@ -50,12 +46,9 @@ _hash_str (const char *key, size_t key_length)
return h;
}
-/* }}} */
-/* {{{ static void _hash_element_dtor (void *, void *)
- */
-static void
-_hash_element_dtor (void *user, void *element)
+static void
+hash_element_dtor(void *user, void *element)
{
curl_hash *h = (curl_hash *) user;
curl_hash_element *e = (curl_hash_element *) element;
@@ -68,49 +61,55 @@ _hash_element_dtor (void *user, void *element)
free(e);
}
-/* }}} */
-/* {{{ void curl_hash_init (curl_hash *, int, curl_hash_dtor)
- */
-void
-Curl_hash_init (curl_hash *h, int slots, curl_hash_dtor dtor)
+/* return 1 on error, 0 is fine */
+int
+Curl_hash_init(curl_hash *h, int slots, curl_hash_dtor dtor)
{
int i;
h->dtor = dtor;
h->size = 0;
- h->slots = slots;
+ h->slots = slots;
h->table = (curl_llist **) malloc(slots * sizeof(curl_llist *));
- for (i = 0; i < slots; ++i) {
- h->table[i] = Curl_llist_alloc((curl_llist_dtor) _hash_element_dtor);
+ if(h->table) {
+ for (i = 0; i < slots; ++i) {
+ h->table[i] = Curl_llist_alloc((curl_llist_dtor) hash_element_dtor);
+ if(!h->table[i]) {
+ while(i--)
+ Curl_llist_destroy(h->table[i], NULL);
+ free(h->table);
+ return 1; /* failure */
+ }
+ }
+ return 0; /* fine */
}
+ else
+ return 1; /* failure */
}
-/* }}} */
-/* {{{ curl_hash *curl_hash_alloc (int, curl_hash_dtor)
- */
curl_hash *
-Curl_hash_alloc (int slots, curl_hash_dtor dtor)
+Curl_hash_alloc(int slots, curl_hash_dtor dtor)
{
curl_hash *h;
h = (curl_hash *) malloc(sizeof(curl_hash));
- if (NULL == h)
- return NULL;
-
- Curl_hash_init(h, slots, dtor);
+ if (h) {
+ if(Curl_hash_init(h, slots, dtor)) {
+ /* failure */
+ free(h);
+ h = NULL;
+ }
+ }
return h;
}
-/* }}} */
-/* {{{ static int _hash_key_compare (char *, size_t, char *, size_t)
- */
-static int
-_hash_key_compare (char *key1, size_t key1_len, char *key2, size_t key2_len)
+static int
+hash_key_compare(char *key1, size_t key1_len, char *key2, size_t key2_len)
{
- if (key1_len == key2_len &&
+ if (key1_len == key2_len &&
*key1 == *key2 &&
memcmp(key1, key2, key1_len) == 0) {
return 1;
@@ -118,108 +117,90 @@ _hash_key_compare (char *key1, size_t key1_len, char *key2, size_t key2_len)
return 0;
}
-/* }}} */
-/* {{{ static int _mk_hash_element (curl_hash_element **, char *, size_t, const void *)
- */
-static int
-_mk_hash_element (curl_hash_element **e, char *key, size_t key_len, const void *p)
+static curl_hash_element *
+mk_hash_element(char *key, size_t key_len, const void *p)
{
- *e = (curl_hash_element *) malloc(sizeof(curl_hash_element));
- (*e)->key = strdup(key);
- (*e)->key_len = key_len;
- (*e)->ptr = (void *) p;
- return 0;
+ curl_hash_element *he =
+ (curl_hash_element *) malloc(sizeof(curl_hash_element));
+
+ if(he) {
+ char *dup = strdup(key);
+ if(dup) {
+ he->key = dup;
+ he->key_len = key_len;
+ he->ptr = (void *) p;
+ }
+ else {
+ /* failed to duplicate the key, free memory and fail */
+ free(he);
+ he = NULL;
+ }
+ }
+ return he;
}
-/* }}} */
-#define find_slot(__h, __k, __k_len) (_hash_str(__k, __k_len) % (__h)->slots)
+#define find_slot(__h, __k, __k_len) (hash_str(__k, __k_len) % (__h)->slots)
-#define FETCH_LIST \
- curl_llist *l = h->table[find_slot(h, key, key_len)]
+#define FETCH_LIST(x,y,z) x->table[find_slot(x, y, z)]
-
-/* {{{ int curl_hash_add (curl_hash *, char *, size_t, const void *)
- */
-int
-Curl_hash_add (curl_hash *h, char *key, size_t key_len, const void *p)
+/* Return the data in the hash. If there already was a match in the hash,
+ that data is returned. */
+void *
+Curl_hash_add(curl_hash *h, char *key, size_t key_len, void *p)
{
curl_hash_element *he;
curl_llist_element *le;
- FETCH_LIST;
-
- for (le = CURL_LLIST_HEAD(l);
- le != NULL;
- le = CURL_LLIST_NEXT(le)) {
- he = (curl_hash_element *) CURL_LLIST_VALP(le);
- if (_hash_key_compare(he->key, he->key_len, key, key_len)) {
- h->dtor(he->ptr);
- he->ptr = (void *) p;
- return 1;
- }
- }
-
- if (_mk_hash_element(&he, key, key_len, p) != 0)
- return 0;
+ curl_llist *l = FETCH_LIST(h, key, key_len);
- if (Curl_llist_insert_next(l, CURL_LLIST_TAIL(l), he)) {
- ++h->size;
- return 1;
+ for (le = l->head; le; le = le->next) {
+ he = (curl_hash_element *) le->ptr;
+ if (hash_key_compare(he->key, he->key_len, key, key_len)) {
+ h->dtor(p); /* remove the NEW entry */
+ return he->ptr; /* return the EXISTING entry */
+ }
}
- return 0;
-}
-/* }}} */
-
-/* {{{ int curl_hash_delete (curl_hash *, char *, size_t)
- */
-int
-Curl_hash_delete(curl_hash *h, char *key, size_t key_len)
-{
- curl_hash_element *he;
- curl_llist_element *le;
- FETCH_LIST;
-
- for (le = CURL_LLIST_HEAD(l);
- le != NULL;
- le = CURL_LLIST_NEXT(le)) {
- he = CURL_LLIST_VALP(le);
- if (_hash_key_compare(he->key, he->key_len, key, key_len)) {
- Curl_llist_remove(l, le, (void *) h);
- --h->size;
- return 1;
+ he = mk_hash_element(key, key_len, p);
+ if (he) {
+ if(Curl_llist_insert_next(l, l->tail, he)) {
+ ++h->size;
+ return p; /* return the new entry */
}
+ /*
+ * Couldn't insert it, destroy the 'he' element and the key again. We
+ * don't call hash_element_dtor() since that would also call the
+ * "destructor" for the actual data 'p'. When we fail, we shall not touch
+ * that data.
+ */
+ free(he->key);
+ free(he);
}
- return 0;
+ return NULL; /* failure */
}
-/* }}} */
-/* {{{ int curl_hash_pick (curl_hash *, char *, size_t, void **)
- */
void *
Curl_hash_pick(curl_hash *h, char *key, size_t key_len)
{
curl_llist_element *le;
curl_hash_element *he;
- FETCH_LIST;
+ curl_llist *l = FETCH_LIST(h, key, key_len);
- for (le = CURL_LLIST_HEAD(l);
- le != NULL;
- le = CURL_LLIST_NEXT(le)) {
- he = CURL_LLIST_VALP(le);
- if (_hash_key_compare(he->key, he->key_len, key, key_len)) {
+ for (le = l->head;
+ le;
+ le = le->next) {
+ he = le->ptr;
+ if (hash_key_compare(he->key, he->key_len, key, key_len)) {
return he->ptr;
}
}
return NULL;
}
-/* }}} */
-/* {{{ void curl_hash_apply (curl_hash *, void *, void (*)(void *, curl_hash_element *))
- */
-void
+#if defined(CURLDEBUG) && defined(AGGRESIVE_TEST)
+void
Curl_hash_apply(curl_hash *h, void *user,
void (*cb)(void *user, void *ptr))
{
@@ -227,18 +208,16 @@ Curl_hash_apply(curl_hash *h, void *user,
int i;
for (i = 0; i < h->slots; ++i) {
- for (le = CURL_LLIST_HEAD(h->table[i]);
- le != NULL;
- le = CURL_LLIST_NEXT(le)) {
- curl_hash_element *el = CURL_LLIST_VALP(le);
+ for (le = (h->table[i])->head;
+ le;
+ le = le->next) {
+ curl_hash_element *el = le->ptr;
cb(user, el->ptr);
}
}
}
-/* }}} */
+#endif
-/* {{{ void curl_hash_clean (curl_hash *)
- */
void
Curl_hash_clean(curl_hash *h)
{
@@ -250,45 +229,33 @@ Curl_hash_clean(curl_hash *h)
free(h->table);
}
-/* }}} */
-/* {{{ void curl_hash_clean_with_criterium (curl_hash *, void *,
- int (*)(void *, void *))
- */
void
Curl_hash_clean_with_criterium(curl_hash *h, void *user,
int (*comp)(void *, void *))
{
curl_llist_element *le;
curl_llist_element *lnext;
+ curl_llist *list;
int i;
for (i = 0; i < h->slots; ++i) {
- le = CURL_LLIST_HEAD(h->table[i]);
- while(le != NULL)
- if (comp(user, ((curl_hash_element *) CURL_LLIST_VALP(le))->ptr)) {
- lnext = CURL_LLIST_NEXT(le);
- Curl_llist_remove(h->table[i], le, (void *) h);
- --h->size;
- le = lnext;
+ list = h->table[i];
+ le = list->head; /* get first list entry */
+ while(le) {
+ curl_hash_element *he = le->ptr;
+ lnext = le->next;
+ /* ask the callback function if we shall remove this entry or not */
+ if (comp(user, he->ptr)) {
+ Curl_llist_remove(list, le, (void *) h);
+ --h->size; /* one less entry in the hash now */
}
- else
- le = CURL_LLIST_NEXT(le);
+ le = lnext;
+ }
}
}
-/* {{{ int curl_hash_count (curl_hash *)
- */
-int
-Curl_hash_count(curl_hash *h)
-{
- return (int)h->size;
-}
-/* }}} */
-
-/* {{{ void curl_hash_destroy (curl_hash *)
- */
-void
+void
Curl_hash_destroy(curl_hash *h)
{
if (!h)
@@ -297,12 +264,4 @@ Curl_hash_destroy(curl_hash *h)
Curl_hash_clean(h);
free(h);
}
-/* }}} */
-
-/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
- */
+
diff --git a/Source/CTest/Curl/hash.h b/Source/CTest/Curl/hash.h
index c3464c3..7814674 100644
--- a/Source/CTest/Curl/hash.h
+++ b/Source/CTest/Curl/hash.h
@@ -1,18 +1,18 @@
#ifndef __HASH_H
#define __HASH_H
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -45,9 +45,9 @@ typedef struct _curl_hash_element {
} curl_hash_element;
-void Curl_hash_init(curl_hash *, int, curl_hash_dtor);
+int Curl_hash_init(curl_hash *, int, curl_hash_dtor);
curl_hash *Curl_hash_alloc(int, curl_hash_dtor);
-int Curl_hash_add(curl_hash *, char *, size_t, const void *);
+void *Curl_hash_add(curl_hash *, char *, size_t, void *);
int Curl_hash_delete(curl_hash *h, char *key, size_t key_len);
void *Curl_hash_pick(curl_hash *, char *, size_t);
void Curl_hash_apply(curl_hash *h, void *user,
@@ -58,11 +58,3 @@ void Curl_hash_clean_with_criterium(curl_hash *h, void *user, int (*comp)(void *
void Curl_hash_destroy(curl_hash *h);
#endif
-
-/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
- */
diff --git a/Source/CTest/Curl/hostares.c b/Source/CTest/Curl/hostares.c
new file mode 100644
index 0000000..48d6211
--- /dev/null
+++ b/Source/CTest/Curl/hostares.c
@@ -0,0 +1,301 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#include <string.h>
+#include <errno.h>
+
+#define _REENTRANT
+
+#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
+#include <malloc.h>
+#else
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h> /* required for free() prototypes */
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h> /* for the close() proto */
+#endif
+#ifdef VMS
+#include <in.h>
+#include <inet.h>
+#include <stdlib.h>
+#endif
+#endif
+
+#ifdef HAVE_SETJMP_H
+#include <setjmp.h>
+#endif
+
+#ifdef WIN32
+#include <process.h>
+#endif
+
+#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "strerror.h"
+#include "url.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
+#include "inet_ntoa_r.h"
+#endif
+
+#include "memory.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/***********************************************************************
+ * Only for ares-enabled builds
+ **********************************************************************/
+
+#ifdef CURLRES_ARES
+
+/*
+ * Curl_fdset() is called when someone from the outside world (using
+ * curl_multi_fdset()) wants to get our fd_set setup and we're talking with
+ * ares. The caller must make sure that this function is only called when we
+ * have a working ares channel.
+ *
+ * Returns: CURLE_OK always!
+ */
+
+CURLcode Curl_fdset(struct connectdata *conn,
+ fd_set *read_fd_set,
+ fd_set *write_fd_set,
+ int *max_fdp)
+
+{
+ int max = ares_fds(conn->data->state.areschannel,
+ read_fd_set, write_fd_set);
+ *max_fdp = max;
+
+ return CURLE_OK;
+}
+
+/*
+ * Curl_is_resolved() is called repeatedly to check if a previous name resolve
+ * request has completed. It should also make sure to time-out if the
+ * operation seems to take too long.
+ *
+ * Returns normal CURLcode errors.
+ */
+CURLcode Curl_is_resolved(struct connectdata *conn,
+ struct Curl_dns_entry **dns)
+{
+ fd_set read_fds, write_fds;
+ struct timeval tv={0,0};
+ struct SessionHandle *data = conn->data;
+ int nfds;
+
+ FD_ZERO(&read_fds);
+ FD_ZERO(&write_fds);
+
+ nfds = ares_fds(data->state.areschannel, &read_fds, &write_fds);
+
+ (void)select(nfds, &read_fds, &write_fds, NULL,
+ (struct timeval *)&tv);
+
+ /* Call ares_process() unconditonally here, even if we simply timed out
+ above, as otherwise the ares name resolve won't timeout! */
+ ares_process(data->state.areschannel, &read_fds, &write_fds);
+
+ *dns = NULL;
+
+ if(conn->async.done) {
+ /* we're done, kill the ares handle */
+ if(!conn->async.dns) {
+ failf(data, "Could not resolve host: %s (%s)", conn->host.dispname,
+ ares_strerror(conn->async.status));
+ return CURLE_COULDNT_RESOLVE_HOST;
+ }
+ *dns = conn->async.dns;
+ }
+
+ return CURLE_OK;
+}
+
+/*
+ * Curl_wait_for_resolv() waits for a resolve to finish. This function should
+ * be avoided since using this risk getting the multi interface to "hang".
+ *
+ * If 'entry' is non-NULL, make it point to the resolved dns entry
+ *
+ * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, and
+ * CURLE_OPERATION_TIMEDOUT if a time-out occurred.
+ */
+CURLcode Curl_wait_for_resolv(struct connectdata *conn,
+ struct Curl_dns_entry **entry)
+{
+ CURLcode rc=CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ long timeout = CURL_TIMEOUT_RESOLVE; /* default name resolve timeout */
+
+ /* now, see if there's a connect timeout or a regular timeout to
+ use instead of the default one */
+ if(conn->data->set.connecttimeout)
+ timeout = conn->data->set.connecttimeout;
+ else if(conn->data->set.timeout)
+ timeout = conn->data->set.timeout;
+
+ /* We convert the number of seconds into number of milliseconds here: */
+ if(timeout < 2147483)
+ /* maximum amount of seconds that can be multiplied with 1000 and
+ still fit within 31 bits */
+ timeout *= 1000;
+ else
+ timeout = 0x7fffffff; /* ridiculous amount of time anyway */
+
+ /* Wait for the name resolve query to complete. */
+ while (1) {
+ int nfds=0;
+ fd_set read_fds, write_fds;
+ struct timeval *tvp, tv, store;
+ int count;
+ struct timeval now = Curl_tvnow();
+ long timediff;
+
+ store.tv_sec = (int)timeout/1000;
+ store.tv_usec = (timeout%1000)*1000;
+
+ FD_ZERO(&read_fds);
+ FD_ZERO(&write_fds);
+ nfds = ares_fds(data->state.areschannel, &read_fds, &write_fds);
+ if (nfds == 0)
+ /* no file descriptors means we're done waiting */
+ break;
+ tvp = ares_timeout(data->state.areschannel, &store, &tv);
+ count = select(nfds, &read_fds, &write_fds, NULL, tvp);
+ if (count < 0 && errno != EINVAL)
+ break;
+
+ ares_process(data->state.areschannel, &read_fds, &write_fds);
+
+ timediff = Curl_tvdiff(Curl_tvnow(), now); /* spent time */
+ timeout -= timediff?timediff:1; /* always deduct at least 1 */
+ if (timeout < 0) {
+ /* our timeout, so we cancel the ares operation */
+ ares_cancel(data->state.areschannel);
+ break;
+ }
+ }
+
+ /* Operation complete, if the lookup was successful we now have the entry
+ in the cache. */
+
+ if(entry)
+ *entry = conn->async.dns;
+
+ if(!conn->async.dns) {
+ /* a name was not resolved */
+ if((timeout < 0) || (conn->async.status == ARES_ETIMEOUT)) {
+ failf(data, "Resolving host timed out: %s", conn->host.dispname);
+ rc = CURLE_OPERATION_TIMEDOUT;
+ }
+ else if(conn->async.done) {
+ failf(data, "Could not resolve host: %s (%s)", conn->host.dispname,
+ ares_strerror(conn->async.status));
+ rc = CURLE_COULDNT_RESOLVE_HOST;
+ }
+ else
+ rc = CURLE_OPERATION_TIMEDOUT;
+
+ /* close the connection, since we can't return failure here without
+ cleaning up this connection properly */
+ Curl_disconnect(conn);
+ }
+
+ return rc;
+}
+
+/*
+ * Curl_getaddrinfo() - when using ares
+ *
+ * Returns name information about the given hostname and port number. If
+ * successful, the 'hostent' is returned and the forth argument will point to
+ * memory we need to free after use. That memory *MUST* be freed with
+ * Curl_freeaddrinfo(), nothing else.
+ */
+Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
+ char *hostname,
+ int port,
+ int *waitp)
+{
+ char *bufp;
+ struct SessionHandle *data = conn->data;
+ in_addr_t in = inet_addr(hostname);
+
+ *waitp = FALSE;
+
+ if (in != CURL_INADDR_NONE) {
+ /* This is a dotted IP address 123.123.123.123-style */
+ return Curl_ip2addr(in, hostname, port);
+ }
+
+ bufp = strdup(hostname);
+
+ if(bufp) {
+ Curl_safefree(conn->async.hostname);
+ conn->async.hostname = bufp;
+ conn->async.port = port;
+ conn->async.done = FALSE; /* not done */
+ conn->async.status = 0; /* clear */
+ conn->async.dns = NULL; /* clear */
+
+ /* areschannel is already setup in the Curl_open() function */
+ ares_gethostbyname(data->state.areschannel, hostname, PF_INET,
+ Curl_addrinfo4_callback, conn);
+
+ *waitp = TRUE; /* please wait for the response */
+ }
+ return NULL; /* no struct yet */
+}
+
+#endif /* CURLRES_ARES */
diff --git a/Source/CTest/Curl/hostasyn.c b/Source/CTest/Curl/hostasyn.c
new file mode 100644
index 0000000..6256370
--- /dev/null
+++ b/Source/CTest/Curl/hostasyn.c
@@ -0,0 +1,170 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#include <string.h>
+#include <errno.h>
+
+#define _REENTRANT
+
+#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
+#include <malloc.h>
+#else
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h> /* required for free() prototypes */
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h> /* for the close() proto */
+#endif
+#ifdef VMS
+#include <in.h>
+#include <inet.h>
+#include <stdlib.h>
+#endif
+#endif
+
+#ifdef HAVE_SETJMP_H
+#include <setjmp.h>
+#endif
+
+#ifdef WIN32
+#include <process.h>
+#endif
+
+#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "strerror.h"
+#include "url.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
+#include "inet_ntoa_r.h"
+#endif
+
+#include "memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/***********************************************************************
+ * Only for builds using asynchronous name resolves
+ **********************************************************************/
+#ifdef CURLRES_ASYNCH
+/*
+ * addrinfo_callback() gets called by ares, gethostbyname_thread() or
+ * getaddrinfo_thread() when we got the name resolved (or not!).
+ *
+ * If the status argument is CURL_ASYNC_SUCCESS, we might need to copy the
+ * address field since it might be freed when this function returns. This
+ * operation stores the resolved data in the DNS cache.
+ *
+ * NOTE: for IPv6 operations, Curl_addrinfo_copy() returns the same
+ * pointer it is given as argument!
+ *
+ * The storage operation locks and unlocks the DNS cache.
+ */
+static void addrinfo_callback(void *arg, /* "struct connectdata *" */
+ int status,
+ void *addr)
+{
+ struct connectdata *conn = (struct connectdata *)arg;
+ struct Curl_dns_entry *dns = NULL;
+
+ conn->async.done = TRUE;
+ conn->async.status = status;
+
+ if(CURL_ASYNC_SUCCESS == status) {
+
+ /*
+ * IPv4: Curl_addrinfo_copy() copies the address and returns an allocated
+ * version.
+ *
+ * IPv6: Curl_addrinfo_copy() returns the input pointer!
+ */
+ Curl_addrinfo *ai = Curl_addrinfo_copy(addr, conn->async.port);
+ if(ai) {
+ struct SessionHandle *data = conn->data;
+
+ if(data->share)
+ Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+ dns = Curl_cache_addr(data, ai,
+ conn->async.hostname,
+ conn->async.port);
+ if(!dns)
+ /* failed to store, cleanup and return error */
+ Curl_freeaddrinfo(ai);
+
+ if(data->share)
+ Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+ }
+ }
+
+ conn->async.dns = dns;
+
+ /* ipv4: The input hostent struct will be freed by ares when we return from
+ this function */
+}
+
+void Curl_addrinfo4_callback(void *arg, /* "struct connectdata *" */
+ int status,
+ struct hostent *hostent)
+{
+ addrinfo_callback(arg, status, hostent);
+}
+
+#ifdef CURLRES_IPV6
+void Curl_addrinfo6_callback(void *arg, /* "struct connectdata *" */
+ int status,
+ struct addrinfo *ai)
+{
+ addrinfo_callback(arg, status, ai);
+}
+#endif
+
+#endif /* CURLRES_ASYNC */
diff --git a/Source/CTest/Curl/hostip.c b/Source/CTest/Curl/hostip.c
index b525007..715ec0b 100644
--- a/Source/CTest/Curl/hostip.c
+++ b/Source/CTest/Curl/hostip.c
@@ -1,16 +1,16 @@
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -29,7 +29,7 @@
#define _REENTRANT
#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
-#include <winsock.h>
+#include <malloc.h>
#else
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
@@ -49,6 +49,9 @@
#ifdef HAVE_STDLIB_H
#include <stdlib.h> /* required for free() prototypes */
#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h> /* for the close() proto */
+#endif
#ifdef VMS
#include <in.h>
#include <inet.h>
@@ -60,10 +63,23 @@
#include <setjmp.h>
#endif
+#ifdef WIN32
+#include <process.h>
+#endif
+
+#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+
#include "urldata.h"
#include "sendf.h"
#include "hostip.h"
#include "hash.h"
+#include "share.h"
+#include "strerror.h"
+#include "url.h"
+#include "inet_ntop.h"
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
@@ -72,32 +88,78 @@
#include "inet_ntoa_r.h"
#endif
+#include "memory.h"
/* The last #include file should be: */
-#ifdef MALLOCDEBUG
#include "memdebug.h"
-#endif
+/*
+ * hostip.c explained
+ * ==================
+ *
+ * The main COMPILE-TIME DEFINES to keep in mind when reading the host*.c
+ * source file are these:
+ *
+ * CURLRES_IPV6 - this host has getaddrinfo() and family, and thus we use
+ * that. The host may not be able to resolve IPv6, but we don't really have to
+ * take that into account. Hosts that aren't IPv6-enabled have CURLRES_IPV4
+ * defined.
+ *
+ * CURLRES_ARES - is defined if libcurl is built to use c-ares for
+ * asynchronous name resolves. It cannot have ENABLE_IPV6 defined at the same
+ * time, as c-ares has no ipv6 support. This can be Windows or *nix.
+ *
+ * CURLRES_THREADED - is defined if libcurl is built to run under (native)
+ * Windows, and then the name resolve will be done in a new thread, and the
+ * supported API will be the same as for ares-builds.
+ *
+ * If any of the two previous are defined, CURLRES_ASYNCH is defined too. If
+ * libcurl is not built to use an asynchronous resolver, CURLRES_SYNCH is
+ * defined.
+ *
+ * The host*.c sources files are split up like this:
+ *
+ * hostip.c - method-independent resolver functions and utility functions
+ * hostasyn.c - functions for asynchronous name resolves
+ * hostsyn.c - functions for synchronous name resolves
+ * hostares.c - functions for ares-using name resolves
+ * hostthre.c - functions for threaded name resolves
+ * hostip4.c - ipv4-specific functions
+ * hostip6.c - ipv6-specific functions
+ *
+ * The hostip.h is the united header file for all this. It defines the
+ * CURLRES_* defines based on the config*.h and setup.h defines.
+ */
+
+/* These two symbols are for the global DNS cache */
static curl_hash hostname_cache;
static int host_cache_initialized;
-static Curl_addrinfo *my_getaddrinfo(struct SessionHandle *data,
- char *hostname,
- int port,
- char **bufp);
+static void freednsentry(void *freethis);
+/*
+ * Curl_global_host_cache_init() initializes and sets up a global DNS cache.
+ * Global DNS cache is general badness. Do not use. This will be removed in
+ * a future version. Use the share interface instead!
+ */
void Curl_global_host_cache_init(void)
{
if (!host_cache_initialized) {
- Curl_hash_init(&hostname_cache, 7, Curl_freednsinfo);
+ Curl_hash_init(&hostname_cache, 7, freednsentry);
host_cache_initialized = 1;
}
}
+/*
+ * Return a pointer to the global cache
+ */
curl_hash *Curl_global_host_cache_get(void)
{
return &hostname_cache;
}
+/*
+ * Destroy and cleanup the global DNS cache
+ */
void Curl_global_host_cache_dtor(void)
{
if (host_cache_initialized) {
@@ -106,625 +168,358 @@ void Curl_global_host_cache_dtor(void)
}
}
-/* count the number of characters that an integer takes up */
-static int _num_chars(int i)
+/*
+ * Return # of adresses in a Curl_addrinfo struct
+ */
+int Curl_num_addresses(const Curl_addrinfo *addr)
{
- int chars = 0;
-
- /* While the number divided by 10 is greater than one,
- * re-divide the number by 10, and increment the number of
- * characters by 1.
- *
- * this relies on the fact that for every multiple of 10,
- * a new digit is added onto every number
- */
- do {
- chars++;
-
- i = (int) i / 10;
- } while (i >= 1);
-
- return chars;
+ int i;
+ for (i = 0; addr; addr = addr->ai_next, i++);
+ return i;
}
-/* Create a hostcache id */
-static char *
-create_hostcache_id(char *server, int port, ssize_t *entry_len)
+/*
+ * Curl_printable_address() returns a printable version of the 1st address
+ * given in the 'ip' argument. The result will be stored in the buf that is
+ * bufsize bytes big.
+ *
+ * If the conversion fails, it returns NULL.
+ */
+const char *Curl_printable_address(const Curl_addrinfo *ip,
+ char *buf, size_t bufsize)
{
- char *id = NULL;
-
- /* Get the length of the new entry id */
- *entry_len = *entry_len + /* Hostname length */
- 1 + /* The ':' seperator */
- _num_chars(port); /* The number of characters the port will take up */
-
- /* Allocate the new entry id */
- id = malloc(*entry_len + 1);
- if (!id) {
- return NULL;
- }
+ const void *ip4 = &((const struct sockaddr_in*)ip->ai_addr)->sin_addr;
+ int af = ip->ai_family;
+#ifdef CURLRES_IPV6
+ const void *ip6 = &((const struct sockaddr_in6*)ip->ai_addr)->sin6_addr;
+#else
+ const void *ip6 = NULL;
+#endif
- /* Create the new entry */
- /* If sprintf() doesn't return the entry length, that signals failure */
- if (sprintf(id, "%s:%d", server, port) != *entry_len) {
- /* Free the allocated id, set length to zero and return NULL */
- *entry_len = 0;
- free(id);
- return NULL;
- }
+ return Curl_inet_ntop(af, af == AF_INET ? ip4 : ip6, buf, bufsize);
+}
- return id;
+/*
+ * Return a hostcache id string for the providing host + port, to be used by
+ * the DNS caching.
+ */
+static char *
+create_hostcache_id(char *server, int port)
+{
+ /* create and return the new allocated entry */
+ return aprintf("%s:%d", server, port);
}
struct hostcache_prune_data {
int cache_timeout;
- int now;
+ time_t now;
};
+/*
+ * This function is set as a callback to be called for every entry in the DNS
+ * cache when we want to prune old unused entries.
+ *
+ * Returning non-zero means remove the entry, return 0 to keep it in the
+ * cache.
+ */
static int
hostcache_timestamp_remove(void *datap, void *hc)
{
- struct hostcache_prune_data *data =
+ struct hostcache_prune_data *data =
(struct hostcache_prune_data *) datap;
struct Curl_dns_entry *c = (struct Curl_dns_entry *) hc;
-
+
if ((data->now - c->timestamp < data->cache_timeout) ||
c->inuse) {
/* please don't remove */
return 0;
}
-
+
/* fine, remove */
return 1;
}
+/*
+ * Prune the DNS cache. This assumes that a lock has already been taken.
+ */
static void
-hostcache_prune(curl_hash *hostcache, int cache_timeout, int now)
+hostcache_prune(curl_hash *hostcache, int cache_timeout, time_t now)
{
struct hostcache_prune_data user;
user.cache_timeout = cache_timeout;
user.now = now;
-
- Curl_hash_clean_with_criterium(hostcache,
- (void *) &user,
+
+ Curl_hash_clean_with_criterium(hostcache,
+ (void *) &user,
hostcache_timestamp_remove);
}
-#if defined(MALLOCDEBUG) && defined(AGGRESIVE_TEST)
-/* Called from Curl_done() to check that there's no DNS cache entry with
- a non-zero counter left. */
-void Curl_scan_cache_used(void *user, void *ptr)
+/*
+ * Library-wide function for pruning the DNS cache. This function takes and
+ * returns the appropriate locks.
+ */
+void Curl_hostcache_prune(struct SessionHandle *data)
{
- struct Curl_dns_entry *e = ptr;
- (void)user; /* prevent compiler warning */
- if(e->inuse) {
- fprintf(stderr, "*** WARNING: locked DNS cache entry detected: %s\n",
- e->entry_id);
- /* perform a segmentation fault to draw attention */
- *(void **)0 = 0;
- }
-}
-#endif
+ time_t now;
+
+ if(data->set.dns_cache_timeout == -1)
+ /* cache forever means never prune! */
+ return;
+
+ if(data->share)
+ Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+ time(&now);
-/* Macro to save redundant free'ing of entry_id */
-#define HOSTCACHE_RETURN(dns) \
-{ \
- free(entry_id); \
- return dns; \
+ /* Remove outdated and unused entries from the hostcache */
+ hostcache_prune(data->hostcache,
+ data->set.dns_cache_timeout,
+ now);
+
+ if(data->share)
+ Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
}
#ifdef HAVE_SIGSETJMP
-/* Beware this is a global and unique instance */
+/* Beware this is a global and unique instance. This is used to store the
+ return address that we can jump back to from inside a signal handler. This
+ is not thread-safe stuff. */
sigjmp_buf curl_jmpenv;
#endif
-struct Curl_dns_entry *Curl_resolv(struct SessionHandle *data,
- char *hostname,
- int port)
+
+/*
+ * Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache.
+ *
+ * When calling Curl_resolv() has resulted in a response with a returned
+ * address, we call this function to store the information in the dns
+ * cache etc
+ *
+ * Returns the Curl_dns_entry entry pointer or NULL if the storage failed.
+ */
+struct Curl_dns_entry *
+Curl_cache_addr(struct SessionHandle *data,
+ Curl_addrinfo *addr,
+ char *hostname,
+ int port)
{
- char *entry_id = NULL;
- struct Curl_dns_entry *dns = NULL;
- ssize_t entry_len;
+ char *entry_id;
+ size_t entry_len;
+ struct Curl_dns_entry *dns;
+ struct Curl_dns_entry *dns2;
time_t now;
- char *bufp;
-
-#ifdef HAVE_SIGSETJMP
- /* this allows us to time-out from the name resolver, as the timeout
- will generate a signal and we will siglongjmp() from that here */
- if(!data->set.no_signal && sigsetjmp(curl_jmpenv, 1)) {
- /* this is coming from a siglongjmp() */
- failf(data, "name lookup time-outed");
- return NULL;
- }
-#endif
/* Create an entry id, based upon the hostname and port */
- entry_len = (int)strlen(hostname);
- entry_id = create_hostcache_id(hostname, port, &entry_len);
+ entry_id = create_hostcache_id(hostname, port);
/* If we can't create the entry id, fail */
if (!entry_id)
return NULL;
-
- /* See if its already in our dns cache */
- dns = Curl_hash_pick(data->hostcache, entry_id, entry_len+1);
+ entry_len = strlen(entry_id);
+ /* Create a new cache entry */
+ dns = (struct Curl_dns_entry *) malloc(sizeof(struct Curl_dns_entry));
if (!dns) {
- Curl_addrinfo *addr = my_getaddrinfo(data, hostname, port, &bufp);
-
- if (!addr) {
- HOSTCACHE_RETURN(NULL);
- }
-
- /* Create a new cache entry */
- dns = (struct Curl_dns_entry *) malloc(sizeof(struct Curl_dns_entry));
- if (!dns) {
- Curl_freeaddrinfo(addr);
- HOSTCACHE_RETURN(NULL);
- }
+ free(entry_id);
+ return NULL;
+ }
- dns->inuse = 0;
- dns->addr = addr;
- /* Save it in our host cache */
- Curl_hash_add(data->hostcache, entry_id, entry_len+1, (const void *) dns);
+ dns->inuse = 0; /* init to not used */
+ dns->addr = addr; /* this is the address(es) */
+
+ /* Store the resolved data in our DNS cache. This function may return a
+ pointer to an existing struct already present in the hash, and it may
+ return the same argument we pass in. Make no assumptions. */
+ dns2 = Curl_hash_add(data->hostcache, entry_id, entry_len+1, (void *)dns);
+ if(!dns2) {
+ /* Major badness, run away. */
+ free(dns);
+ free(entry_id);
+ return NULL;
}
time(&now);
+ dns = dns2;
- dns->timestamp = now;
+ dns->timestamp = now; /* used now */
dns->inuse++; /* mark entry as in-use */
-#ifdef MALLOCDEBUG
- dns->entry_id = entry_id;
-#endif
- /* Remove outdated and unused entries from the hostcache */
- hostcache_prune(data->hostcache,
- data->set.dns_cache_timeout,
- (int)now);
+ /* free the allocated entry_id again */
+ free(entry_id);
- HOSTCACHE_RETURN(dns);
+ return dns;
}
/*
- * This is a wrapper function for freeing name information in a protocol
- * independent way. This takes care of using the appropriate underlaying
- * function.
+ * Curl_resolv() is the main name resolve function within libcurl. It resolves
+ * a name and returns a pointer to the entry in the 'entry' argument (if one
+ * is provided). This function might return immediately if we're using asynch
+ * resolves. See the return codes.
+ *
+ * The cache entry we return will get its 'inuse' counter increased when this
+ * function is used. You MUST call Curl_resolv_unlock() later (when you're
+ * done using this struct) to decrease the counter again.
+ *
+ * Return codes:
+ *
+ * CURLRESOLV_ERROR (-1) = error, no pointer
+ * CURLRESOLV_RESOLVED (0) = OK, pointer provided
+ * CURLRESOLV_PENDING (1) = waiting for response, no pointer
*/
-void Curl_freeaddrinfo(Curl_addrinfo *p)
-{
-#ifdef ENABLE_IPV6
- freeaddrinfo(p);
-#else
- free(p);
-#endif
-}
-/*
- * Free a cache dns entry.
- */
-void Curl_freednsinfo(void *freethis)
+int Curl_resolv(struct connectdata *conn,
+ char *hostname,
+ int port,
+ struct Curl_dns_entry **entry)
{
- struct Curl_dns_entry *p = (struct Curl_dns_entry *) freethis;
-
- Curl_freeaddrinfo(p->addr);
-
- free(p);
-}
-
-/* --- resolve name or IP-number --- */
+ char *entry_id = NULL;
+ struct Curl_dns_entry *dns = NULL;
+ size_t entry_len;
+ int wait;
+ struct SessionHandle *data = conn->data;
+ CURLcode result;
-#ifdef ENABLE_IPV6
+ /* default to failure */
+ int rc = CURLRESOLV_ERROR;
+ *entry = NULL;
-#ifdef MALLOCDEBUG
-/* These two are strictly for memory tracing and are using the same
- * style as the family otherwise present in memdebug.c. I put these ones
- * here since they require a bunch of struct types I didn't wanna include
- * in memdebug.c
- */
-int curl_getaddrinfo(char *hostname, char *service,
- struct addrinfo *hints,
- struct addrinfo **result,
- int line, const char *source)
-{
- int res=(getaddrinfo)(hostname, service, hints, result);
- if(0 == res) {
- /* success */
- if(logfile)
- fprintf(logfile, "ADDR %s:%d getaddrinfo() = %p\n",
- source, line, (void *)*result);
- }
- else {
- if(logfile)
- fprintf(logfile, "ADDR %s:%d getaddrinfo() failed\n",
- source, line);
+#ifdef HAVE_SIGSETJMP
+ /* this allows us to time-out from the name resolver, as the timeout
+ will generate a signal and we will siglongjmp() from that here */
+ if(!data->set.no_signal && sigsetjmp(curl_jmpenv, 1)) {
+ /* this is coming from a siglongjmp() */
+ failf(data, "name lookup timed out");
+ return CURLRESOLV_ERROR;
}
- return res;
-}
+#endif
-void curl_freeaddrinfo(struct addrinfo *freethis,
- int line, const char *source)
-{
- (freeaddrinfo)(freethis);
- if(logfile)
- fprintf(logfile, "ADDR %s:%d freeaddrinfo(%p)\n",
- source, line, (void *)freethis);
-}
+ /* Create an entry id, based upon the hostname and port */
+ entry_id = create_hostcache_id(hostname, port);
+ /* If we can't create the entry id, fail */
+ if (!entry_id)
+ return CURLRESOLV_ERROR;
-#endif
+ entry_len = strlen(entry_id);
-/*
- * Return name information about the given hostname and port number. If
- * successful, the 'addrinfo' is returned and the forth argument will point to
- * memory we need to free after use. That meory *MUST* be freed with
- * Curl_freeaddrinfo(), nothing else.
- */
-static Curl_addrinfo *my_getaddrinfo(struct SessionHandle *data,
- char *hostname,
- int port,
- char **bufp)
-{
- struct addrinfo hints, *res;
- int error;
- char sbuf[NI_MAXSERV];
- int s, pf = PF_UNSPEC;
-
- /* see if we have an IPv6 stack */
- s = socket(PF_INET6, SOCK_DGRAM, 0);
- if (s < 0)
- /* Some non-IPv6 stacks have been found to make very slow name resolves
- * when PF_UNSPEC is used, so thus we switch to a mere PF_INET lookup if
- * the stack seems to be a non-ipv6 one. */
- pf = PF_INET;
- else
- /* This seems to be an IPv6-capable stack, use PF_UNSPEC for the widest
- * possible checks. And close the socket again.
- */
- sclose(s);
-
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = pf;
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_flags = AI_CANONNAME;
- snprintf(sbuf, sizeof(sbuf), "%d", port);
- error = getaddrinfo(hostname, sbuf, &hints, &res);
- if (error) {
- infof(data, "getaddrinfo(3) failed for %s:%d\n", hostname, port);
- return NULL;
- }
- *bufp=(char *)res; /* make it point to the result struct */
+ if(data->share)
+ Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
- return res;
-}
-#else /* following code is IPv4-only */
+ /* See if its already in our dns cache */
+ dns = Curl_hash_pick(data->hostcache, entry_id, entry_len+1);
-#ifndef HAVE_GETHOSTBYNAME_R
-static void hostcache_fixoffset(struct hostent *h, int offset);
-/**
- * Performs a "deep" copy of a hostent into a buffer (returns a pointer to the
- * copy). Make absolutely sure the destination buffer is big enough!
- *
- * Keith McGuigan
- * 10/3/2001 */
-static struct hostent* pack_hostent(char** buf, struct hostent* orig)
-{
- char *bufptr;
- struct hostent *newbuf;
- struct hostent* copy;
+ if(data->share)
+ Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
- int i;
- char *str;
- size_t len;
+ /* free the allocated entry_id again */
+ free(entry_id);
- bufptr = *buf;
- memcpy(&copy, &bufptr, sizeof(struct hostent*));
+ if (!dns) {
+ /* The entry was not in the cache. Resolve it to IP address */
- bufptr += sizeof(struct hostent);
- copy->h_name = bufptr;
- len = strlen(orig->h_name) + 1;
- strncpy(bufptr, orig->h_name, len);
- bufptr += len;
+ Curl_addrinfo *addr;
- /* we align on even 64bit boundaries for safety */
-#define MEMALIGN(x) ((x)+(8-(((unsigned long)(x))&0x7)))
+ /* Check what IP specifics the app has requested and if we can provide it.
+ * If not, bail out. */
+ if(!Curl_ipvalid(data))
+ return CURLRESOLV_ERROR;
- /* This must be aligned properly to work on many CPU architectures! */
- bufptr = MEMALIGN(bufptr);
-
- memcpy(&copy->h_aliases, &bufptr, sizeof(char**));
+ /* If Curl_getaddrinfo() returns NULL, 'wait' might be set to a non-zero
+ value indicating that we need to wait for the response to the resolve
+ call */
+ addr = Curl_getaddrinfo(conn, hostname, port, &wait);
- /* Figure out how many aliases there are */
- for (i = 0; orig->h_aliases[i] != NULL; ++i);
+ if (!addr) {
+ if(wait) {
+ /* the response to our resolve call will come asynchronously at
+ a later time, good or bad */
+ /* First, check that we haven't received the info by now */
+ result = Curl_is_resolved(conn, &dns);
+ if(result) /* error detected */
+ return CURLRESOLV_ERROR;
+ if(dns)
+ rc = CURLRESOLV_RESOLVED; /* pointer provided */
+ else
+ rc = CURLRESOLV_PENDING; /* no info yet */
+ }
+ }
+ else {
+ if(data->share)
+ Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
- /* Reserve room for the array */
- bufptr += (i + 1) * sizeof(char*);
+ /* we got a response, store it in the cache */
+ dns = Curl_cache_addr(data, addr, hostname, port);
- /* Clone all known aliases */
- for(i = 0; (str = orig->h_aliases[i]); i++) {
- len = strlen(str) + 1;
- strncpy(bufptr, str, len);
- copy->h_aliases[i] = bufptr;
- bufptr += len;
+ if(data->share)
+ Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+
+ if(!dns)
+ /* returned failure, bail out nicely */
+ Curl_freeaddrinfo(addr);
+ else
+ rc = CURLRESOLV_RESOLVED;
+ }
}
- /* Terminate the alias list with a NULL */
- copy->h_aliases[i] = NULL;
-
- copy->h_addrtype = orig->h_addrtype;
- copy->h_length = orig->h_length;
-
- /* align it for (at least) 32bit accesses */
- bufptr = MEMALIGN(bufptr);
-
- memcpy(&copy->h_addr_list, &bufptr, sizeof(char**));
-
- /* Figure out how many addresses there are */
- for (i = 0; orig->h_addr_list[i] != NULL; ++i);
-
- /* Reserve room for the array */
- bufptr += (i + 1) * sizeof(char*);
-
- i = 0;
- len = orig->h_length;
- str = orig->h_addr_list[i];
- while (str != NULL) {
- memcpy(bufptr, str, len);
- copy->h_addr_list[i] = bufptr;
- bufptr += len;
- str = orig->h_addr_list[++i];
+ else {
+ dns->inuse++; /* we use it! */
+ rc = CURLRESOLV_RESOLVED;
}
- copy->h_addr_list[i] = NULL;
- /* now, shrink the allocated buffer to the size we actually need, which
- most often is only a fraction of the original alloc */
- newbuf=(struct hostent *)realloc(*buf, (int)(bufptr-*buf));
+ *entry = dns;
- /* if the alloc moved, we need to adjust things again */
- if((char*)newbuf != *buf)
- hostcache_fixoffset((struct hostent*)newbuf, (int)((char*)newbuf-*buf));
-
- /* setup the return */
- *buf = (char*)newbuf;
- copy = (struct hostent*)newbuf;
-
- return copy;
+ return rc;
}
-#endif
-static char *MakeIP(unsigned long num,char *addr, int addr_len)
+/*
+ * Curl_resolv_unlock() unlocks the given cached DNS entry. When this has been
+ * made, the struct may be destroyed due to pruning. It is important that only
+ * one unlock is made for each Curl_resolv() call.
+ */
+void Curl_resolv_unlock(struct SessionHandle *data, struct Curl_dns_entry *dns)
{
-#if defined(HAVE_INET_NTOA) || defined(HAVE_INET_NTOA_R)
- struct in_addr in;
- in.s_addr = htonl(num);
-
-#if defined(HAVE_INET_NTOA_R)
- inet_ntoa_r(in,addr,addr_len);
-#else
- strncpy(addr,inet_ntoa(in),addr_len);
-#endif
-#else
- unsigned char *paddr;
+ curlassert(dns && (dns->inuse>0));
- num = htonl(num); /* htonl() added to avoid endian probs */
- paddr = (unsigned char *)&num;
- sprintf(addr, "%u.%u.%u.%u", paddr[0], paddr[1], paddr[2], paddr[3]);
-#endif
- return (addr);
-}
+ if(data->share)
+ Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
-#ifndef INADDR_NONE
-#define INADDR_NONE (in_addr_t) ~0
-#endif
+ dns->inuse--;
-static void hostcache_fixoffset(struct hostent *h, int offset)
-{
- int i=0;
- h->h_name=(char *)((long)h->h_name+offset);
- h->h_aliases=(char **)((long)h->h_aliases+offset);
- while(h->h_aliases[i]) {
- h->h_aliases[i]=(char *)((long)h->h_aliases[i]+offset);
- i++;
- }
- h->h_addr_list=(char **)((long)h->h_addr_list+offset);
- i=0;
- while(h->h_addr_list[i]) {
- h->h_addr_list[i]=(char *)((long)h->h_addr_list[i]+offset);
- i++;
- }
+ if(data->share)
+ Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
}
-/* The original code to this function was once stolen from the Dancer source
- code, written by Bjorn Reese, it has since been patched and modified
- considerably. */
-static Curl_addrinfo *my_getaddrinfo(struct SessionHandle *data,
- char *hostname,
- int port,
- char **bufp)
+/*
+ * File-internal: free a cache dns entry.
+ */
+static void freednsentry(void *freethis)
{
- struct hostent *h = NULL;
- in_addr_t in;
- int ret; /* this variable is unused on several platforms but used on some */
-
-#define CURL_NAMELOOKUP_SIZE 9000
- /* Allocate enough memory to hold the full name information structs and
- * everything. OSF1 is known to require at least 8872 bytes. The buffer
- * required for storing all possible aliases and IP numbers is according to
- * Stevens' Unix Network Programming 2nd editor, p. 304: 8192 bytes! */
- port=0; /* unused in IPv4 code */
- ret = 0; /* to prevent the compiler warning */
- (void)ret;
-
- if ( (in=inet_addr(hostname)) != INADDR_NONE ) {
- struct in_addr *addrentry;
- struct namebuf {
- struct hostent hostentry;
- char *h_addr_list[2];
- struct in_addr addrentry;
- char h_name[128];
- } *buf = (struct namebuf *)malloc(sizeof(struct namebuf));
- if(!buf)
- return NULL; /* major failure */
- *bufp = (char *)buf;
-
- h = &buf->hostentry;
- h->h_addr_list = &buf->h_addr_list[0];
- addrentry = &buf->addrentry;
- addrentry->s_addr = in;
- h->h_addr_list[0] = (char*)addrentry;
- h->h_addr_list[1] = NULL;
- h->h_addrtype = AF_INET;
- h->h_length = sizeof(*addrentry);
- h->h_name = &buf->h_name[0];
- MakeIP(ntohl(in), (char*)h->h_name, sizeof(buf->h_name));
- }
-#if defined(HAVE_GETHOSTBYNAME_R)
- else {
- int h_errnop;
- int res=ERANGE;
- int step_size=200;
- int *buf = (int *)malloc(CURL_NAMELOOKUP_SIZE);
- if(!buf)
- return NULL; /* major failure */
- *bufp=(char *)buf;
-
- /* Workaround for gethostbyname_r bug in qnx nto. It is also _required_
- for some of these functions. */
- memset(buf, 0, CURL_NAMELOOKUP_SIZE);
-#ifdef HAVE_GETHOSTBYNAME_R_5
- /* Solaris, IRIX and more */
- (void)res; /* prevent compiler warning */
- while(!h) {
- h = gethostbyname_r(hostname,
- (struct hostent *)buf,
- (char *)buf + sizeof(struct hostent),
- step_size - sizeof(struct hostent),
- &h_errnop);
-
- /* If the buffer is too small, it returns NULL and sets errno to
- ERANGE. The errno is thread safe if this is compiled with
- -D_REENTRANT as then the 'errno' variable is a macro defined to
- get used properly for threads. */
-
- if(h || (errno != ERANGE))
- break;
-
- step_size+=200;
- }
+ struct Curl_dns_entry *p = (struct Curl_dns_entry *) freethis;
-#ifdef MALLOCDEBUG
- infof(data, "gethostbyname_r() uses %d bytes\n", step_size);
-#endif
+ Curl_freeaddrinfo(p->addr);
- if(h) {
- int offset;
- h=(struct hostent *)realloc(buf, step_size);
- offset=(long)h-(long)buf;
- hostcache_fixoffset(h, offset);
- buf=(int *)h;
- *bufp=(char *)buf;
- }
- else
-#endif
-#ifdef HAVE_GETHOSTBYNAME_R_6
- /* Linux */
- do {
- res=gethostbyname_r(hostname,
- (struct hostent *)buf,
- (char *)buf + sizeof(struct hostent),
- step_size - sizeof(struct hostent),
- &h, /* DIFFERENCE */
- &h_errnop);
- /* Redhat 8, using glibc 2.2.93 changed the behavior. Now all of a
- sudden this function returns EAGAIN if the given buffer size is too
- small. Previous versions are known to return ERANGE for the same
- problem.
-
- This wouldn't be such a big problem if older versions wouldn't
- sometimes return EAGAIN on a common failure case. Alas, we can't
- assume that EAGAIN *or* ERANGE means ERANGE for any given version of
- glibc.
-
- For now, we do that and thus we may call the function repeatedly and
- fail for older glibc versions that return EAGAIN, until we run out
- of buffer size (step_size grows beyond CURL_NAMELOOKUP_SIZE).
-
- If anyone has a better fix, please tell us!
- */
-
- if((ERANGE == res) || (EAGAIN == res)) {
- step_size+=200;
- continue;
- }
- break;
- } while(step_size <= CURL_NAMELOOKUP_SIZE);
-
- if(!h) /* failure */
- res=1;
-
-#ifdef MALLOCDEBUG
- infof(data, "gethostbyname_r() uses %d bytes\n", step_size);
-#endif
- if(!res) {
- int offset;
- h=(struct hostent *)realloc(buf, step_size);
- offset=(long)h-(long)buf;
- hostcache_fixoffset(h, offset);
- buf=(int *)h;
- *bufp=(char *)buf;
- }
- else
-#endif
-#ifdef HAVE_GETHOSTBYNAME_R_3
- /* AIX, Digital Unix, HPUX 10, more? */
-
- if(CURL_NAMELOOKUP_SIZE >=
- (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
- * size dilemma. */
-
- ret = gethostbyname_r(hostname,
- (struct hostent *)buf,
- (struct hostent_data *)((char *)buf + sizeof(struct hostent)));
- else
- ret = -1; /* failure, too smallish buffer size */
-
- /* result expected in h */
- h = (struct hostent*)buf;
- h_errnop= errno; /* we don't deal with this, but set it anyway */
- if(ret)
-#endif
- {
- infof(data, "gethostbyname_r(2) failed for %s\n", hostname);
- h = NULL; /* set return code to NULL */
- free(buf);
- *bufp=NULL;
- }
-#else
- else {
- if ((h = gethostbyname(hostname)) == NULL ) {
- infof(data, "gethostbyname(2) failed for %s\n", hostname);
- *bufp=NULL;
- }
- else
- {
- char *buf=(char *)malloc(CURL_NAMELOOKUP_SIZE);
- /* we make a copy of the hostent right now, right here, as the
- static one we got a pointer to might get removed when we don't
- want/expect that */
- h = pack_hostent(&buf, h);
- *bufp=(char *)buf;
- }
-#endif
- }
- return (h);
+ free(p);
+}
+
+/*
+ * Curl_mk_dnscache() creates a new DNS cache and returns the handle for it.
+ */
+curl_hash *Curl_mk_dnscache(void)
+{
+ return Curl_hash_alloc(7, freednsentry);
}
-#endif /* end of IPv4-specific code */
+#ifdef CURLRES_ADDRINFO_COPY
+
+/* align on even 64bit boundaries */
+#define MEMALIGN(x) ((x)+(8-(((unsigned long)(x))&0x7)))
/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
+ * Curl_addrinfo_copy() performs a "deep" copy of a hostent into a buffer and
+ * returns a pointer to the malloc()ed copy. You need to call free() on the
+ * returned buffer when you're done with it.
*/
-
+Curl_addrinfo *Curl_addrinfo_copy(void *org, int port)
+{
+ struct hostent *orig = org;
+
+ return Curl_he2ai(orig, port);
+}
+#endif /* CURLRES_ADDRINFO_COPY */
diff --git a/Source/CTest/Curl/hostip.h b/Source/CTest/Curl/hostip.h
index 136b514..ea9d080 100644
--- a/Source/CTest/Curl/hostip.h
+++ b/Source/CTest/Curl/hostip.h
@@ -1,18 +1,18 @@
#ifndef __HOSTIP_H
#define __HOSTIP_H
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -26,8 +26,89 @@
#include "setup.h"
#include "hash.h"
+/*
+ * Setup comfortable CURLRES_* defines to use in the host*.c sources.
+ */
+
+#ifdef USE_ARES
+#define CURLRES_ASYNCH
+#define CURLRES_ARES
+#endif
+
+#ifdef USE_THREADING_GETHOSTBYNAME
+#define CURLRES_ASYNCH
+#define CURLRES_THREADED
+#endif
+
+#ifdef USE_THREADING_GETADDRINFO
+#define CURLRES_ASYNCH
+#define CURLRES_THREADED
+#endif
+
+#ifdef ENABLE_IPV6
+#define CURLRES_IPV6
+#else
+#define CURLRES_IPV4
+#endif
+
+#ifdef CURLRES_IPV4
+#if !defined(HAVE_GETHOSTBYNAME_R) || defined(CURLRES_ASYNCH)
+/* If built for ipv4 and missing gethostbyname_r(), or if using async name
+ resolve, we need the Curl_addrinfo_copy() function (which itself needs the
+ Curl_hostent_relocate() function)) */
+#define CURLRES_ADDRINFO_COPY
+#endif
+#endif /* IPv4-only */
+
+#ifndef CURLRES_ASYNCH
+#define CURLRES_SYNCH
+#endif
+
+#ifndef USE_LIBIDN
+#define CURLRES_IDN
+#endif
+
+/* Allocate enough memory to hold the full name information structs and
+ * everything. OSF1 is known to require at least 8872 bytes. The buffer
+ * required for storing all possible aliases and IP numbers is according to
+ * Stevens' Unix Network Programming 2nd edition, p. 304: 8192 bytes!
+ */
+#define CURL_HOSTENT_SIZE 9000
+
+#define CURL_TIMEOUT_RESOLVE 300 /* when using asynch methods, we allow this
+ many seconds for a name resolve */
+
+#ifdef CURLRES_ARES
+#define CURL_ASYNC_SUCCESS ARES_SUCCESS
+#else
+#define CURL_ASYNC_SUCCESS CURLE_OK
+#endif
+
+/*
+ * Curl_addrinfo MUST be used for all name resolved info.
+ */
+#ifdef CURLRES_IPV6
+typedef struct addrinfo Curl_addrinfo;
+#else
+/* OK, so some ipv4-only include tree probably have the addrinfo struct, but
+ to work even on those that don't, we provide our own look-alike! */
+struct Curl_addrinfo {
+ int ai_flags;
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+ size_t ai_addrlen;
+ struct sockaddr *ai_addr;
+ char *ai_canonname;
+ struct Curl_addrinfo *ai_next;
+};
+typedef struct Curl_addrinfo Curl_addrinfo;
+#endif
+
struct addrinfo;
+struct hostent;
struct SessionHandle;
+struct connectdata;
void Curl_global_host_cache_init(void);
void Curl_global_host_cache_dtor(void);
@@ -40,9 +121,6 @@ struct Curl_dns_entry {
time_t timestamp;
long inuse; /* use-counter, make very sure you decrease this
when you're done using the address you received */
-#ifdef MALLOCDEBUG
- char *entry_id;
-#endif
};
/*
@@ -52,13 +130,44 @@ struct Curl_dns_entry {
* The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after
* use, or we'll leak memory!
*/
+/* return codes */
+#define CURLRESOLV_ERROR -1
+#define CURLRESOLV_RESOLVED 0
+#define CURLRESOLV_PENDING 1
+int Curl_resolv(struct connectdata *conn, char *hostname,
+ int port, struct Curl_dns_entry **dnsentry);
+
+/*
+ * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've
+ * been set and returns TRUE if they are OK.
+ */
+bool Curl_ipvalid(struct SessionHandle *data);
+
+/*
+ * Curl_getaddrinfo() is the generic low-level name resolve API within this
+ * source file. There are several versions of this function - for different
+ * name resolve layers (selected at build-time). They all take this same set
+ * of arguments
+ */
+Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
+ char *hostname,
+ int port,
+ int *waitp);
-struct Curl_dns_entry *Curl_resolv(struct SessionHandle *data,
- char *hostname,
- int port);
+CURLcode Curl_is_resolved(struct connectdata *conn,
+ struct Curl_dns_entry **dns);
+CURLcode Curl_wait_for_resolv(struct connectdata *conn,
+ struct Curl_dns_entry **dnsentry);
+/* Curl_fdset() is a generic function that exists in multiple versions
+ depending on what name resolve technology we've built to use. The function
+ is called from the curl_multi_fdset() function */
+CURLcode Curl_fdset(struct connectdata *conn,
+ fd_set *read_fd_set,
+ fd_set *write_fd_set,
+ int *max_fdp);
/* unlock a previously resolved dns entry */
-#define Curl_resolv_unlock(dns) dns->inuse--
+void Curl_resolv_unlock(struct SessionHandle *data, struct Curl_dns_entry *dns);
/* for debugging purposes only: */
void Curl_scan_cache_used(void *user, void *ptr);
@@ -66,16 +175,78 @@ void Curl_scan_cache_used(void *user, void *ptr);
/* free name info */
void Curl_freeaddrinfo(Curl_addrinfo *freeaddr);
-/* free cached name info */
-void Curl_freednsinfo(void *freethis);
+/* make a new dns cache and return the handle */
+curl_hash *Curl_mk_dnscache(void);
-#ifdef MALLOCDEBUG
-void curl_freeaddrinfo(struct addrinfo *freethis,
+/* prune old entries from the DNS cache */
+void Curl_hostcache_prune(struct SessionHandle *data);
+
+/* Return # of adresses in a Curl_addrinfo struct */
+int Curl_num_addresses (const Curl_addrinfo *addr);
+
+#ifdef CURLDEBUG
+void curl_dofreeaddrinfo(struct addrinfo *freethis,
+ int line, const char *source);
+int curl_dogetaddrinfo(char *hostname, char *service,
+ struct addrinfo *hints,
+ struct addrinfo **result,
int line, const char *source);
-int curl_getaddrinfo(char *hostname, char *service,
- struct addrinfo *hints,
- struct addrinfo **result,
- int line, const char *source);
+int curl_dogetnameinfo(const struct sockaddr *sa, socklen_t salen,
+ char *host, size_t hostlen,
+ char *serv, size_t servlen, int flags,
+ int line, const char *source);
+#endif
+
+/* This is the callback function that is used when we build with asynch
+ resolve, ipv4 */
+void Curl_addrinfo4_callback(void *arg,
+ int status,
+ struct hostent *hostent);
+/* This is the callback function that is used when we build with asynch
+ resolve, ipv6 */
+void Curl_addrinfo6_callback(void *arg,
+ int status,
+ struct addrinfo *ai);
+
+
+/* [ipv4 only] Creates a Curl_addrinfo struct from a numerical-only IP
+ address */
+Curl_addrinfo *Curl_ip2addr(in_addr_t num, char *hostname, int port);
+
+/* [ipv4 only] Curl_he2ai() converts a struct hostent to a Curl_addrinfo chain
+ and returns it */
+Curl_addrinfo *Curl_he2ai(struct hostent *, int port);
+
+/* relocate a hostent struct */
+void Curl_hostent_relocate(struct hostent *h, long offset);
+
+/* Clone a Curl_addrinfo struct, works protocol independently */
+Curl_addrinfo *Curl_addrinfo_copy(void *orig, int port);
+
+/*
+ * Curl_printable_address() returns a printable version of the 1st address
+ * given in the 'ip' argument. The result will be stored in the buf that is
+ * bufsize bytes big.
+ */
+const char *Curl_printable_address(const Curl_addrinfo *ip,
+ char *buf, size_t bufsize);
+
+/*
+ * Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache.
+ *
+ * Returns the Curl_dns_entry entry pointer or NULL if the storage failed.
+ */
+struct Curl_dns_entry *
+Curl_cache_addr(struct SessionHandle *data, Curl_addrinfo *addr,
+ char *hostname, int port);
+
+#ifndef INADDR_NONE
+#define CURL_INADDR_NONE (in_addr_t) ~0
+#else
+#define CURL_INADDR_NONE INADDR_NONE
#endif
+
+
+
#endif
diff --git a/Source/CTest/Curl/hostip4.c b/Source/CTest/Curl/hostip4.c
new file mode 100644
index 0000000..50d2ada
--- /dev/null
+++ b/Source/CTest/Curl/hostip4.c
@@ -0,0 +1,449 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#include <string.h>
+#include <errno.h>
+
+#define _REENTRANT
+
+#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
+#include <malloc.h>
+#else
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h> /* required for free() prototypes */
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h> /* for the close() proto */
+#endif
+#ifdef VMS
+#include <in.h>
+#include <inet.h>
+#include <stdlib.h>
+#endif
+#endif
+
+#ifdef HAVE_SETJMP_H
+#include <setjmp.h>
+#endif
+
+#ifdef WIN32
+#include <process.h>
+#endif
+
+#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "strerror.h"
+#include "url.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
+#include "inet_ntoa_r.h"
+#endif
+
+#include "memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/***********************************************************************
+ * Only for plain-ipv4 builds
+ **********************************************************************/
+#ifdef CURLRES_IPV4 /* plain ipv4 code coming up */
+
+/*
+ * This is a function for freeing name information in a protocol independent
+ * way.
+ */
+void Curl_freeaddrinfo(Curl_addrinfo *ai)
+{
+ Curl_addrinfo *next;
+
+ /* walk over the list and free all entries */
+ while(ai) {
+ next = ai->ai_next;
+ free(ai);
+ ai = next;
+ }
+}
+
+/*
+ * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've
+ * been set and returns TRUE if they are OK.
+ */
+bool Curl_ipvalid(struct SessionHandle *data)
+{
+ if(data->set.ip_version == CURL_IPRESOLVE_V6)
+ /* an ipv6 address was requested and we can't get/use one */
+ return FALSE;
+
+ return TRUE; /* OK, proceed */
+}
+
+struct namebuf {
+ struct hostent hostentry;
+ char *h_addr_list[2];
+ struct in_addr addrentry;
+ char h_name[16]; /* 123.123.123.123 = 15 letters is maximum */
+};
+
+/*
+ * Curl_ip2addr() takes a 32bit ipv4 internet address as input parameter
+ * together with a pointer to the string version of the address, and it
+ * returns a Curl_addrinfo chain filled in correctly with information for this
+ * address/host.
+ *
+ * The input parameters ARE NOT checked for validity but they are expected
+ * to have been checked already when this is called.
+ */
+Curl_addrinfo *Curl_ip2addr(in_addr_t num, char *hostname, int port)
+{
+ Curl_addrinfo *ai;
+ struct hostent *h;
+ struct in_addr *addrentry;
+ struct namebuf buffer;
+ struct namebuf *buf = &buffer;
+
+ h = &buf->hostentry;
+ h->h_addr_list = &buf->h_addr_list[0];
+ addrentry = &buf->addrentry;
+ addrentry->s_addr = num;
+ h->h_addr_list[0] = (char*)addrentry;
+ h->h_addr_list[1] = NULL;
+ h->h_addrtype = AF_INET;
+ h->h_length = sizeof(*addrentry);
+ h->h_name = &buf->h_name[0];
+ h->h_aliases = NULL;
+
+ /* Now store the dotted version of the address */
+ snprintf(h->h_name, 16, "%s", hostname);
+
+ ai = Curl_he2ai(h, port);
+
+ return ai;
+}
+
+#ifdef CURLRES_SYNCH /* the functions below are for synchronous resolves */
+
+/*
+ * Curl_getaddrinfo() - the ipv4 synchronous version.
+ *
+ * The original code to this function was once stolen from the Dancer source
+ * code, written by Bjorn Reese, it has since been patched and modified
+ * considerably.
+ *
+ * gethostbyname_r() is the thread-safe version of the gethostbyname()
+ * function. When we build for plain IPv4, we attempt to use this
+ * function. There are _three_ different gethostbyname_r() versions, and we
+ * detect which one this platform supports in the configure script and set up
+ * the HAVE_GETHOSTBYNAME_R_3, HAVE_GETHOSTBYNAME_R_5 or
+ * HAVE_GETHOSTBYNAME_R_6 defines accordingly. Note that HAVE_GETADDRBYNAME
+ * has the corresponding rules. This is primarily on *nix. Note that some unix
+ * flavours have thread-safe versions of the plain gethostbyname() etc.
+ *
+ */
+Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
+ char *hostname,
+ int port,
+ int *waitp)
+{
+ Curl_addrinfo *ai = NULL;
+ struct hostent *h = NULL;
+ in_addr_t in;
+ struct SessionHandle *data = conn->data;
+ struct hostent *buf = NULL;
+
+ (void)port; /* unused in IPv4 code */
+
+ *waitp = 0; /* don't wait, we act synchronously */
+
+ in=inet_addr(hostname);
+ if (in != CURL_INADDR_NONE) {
+ /* This is a dotted IP address 123.123.123.123-style */
+ return Curl_ip2addr(in, hostname, port);
+ }
+
+#if defined(HAVE_GETHOSTBYNAME_R)
+ /*
+ * gethostbyname_r() is the preferred resolve function for many platforms.
+ * Since there are three different versions of it, the following code is
+ * somewhat #ifdef-ridden.
+ */
+ else {
+ int h_errnop;
+ int res=ERANGE;
+
+ buf = (struct hostent *)calloc(CURL_HOSTENT_SIZE, 1);
+ if(!buf)
+ return NULL; /* major failure */
+ /*
+ * The clearing of the buffer is a workaround for a gethostbyname_r bug in
+ * qnx nto and it is also _required_ for some of these functions on some
+ * platforms.
+ */
+
+#ifdef HAVE_GETHOSTBYNAME_R_5
+ /* Solaris, IRIX and more */
+ (void)res; /* prevent compiler warning */
+ h = gethostbyname_r(hostname,
+ (struct hostent *)buf,
+ (char *)buf + sizeof(struct hostent),
+ CURL_HOSTENT_SIZE - sizeof(struct hostent),
+ &h_errnop);
+
+ /* If the buffer is too small, it returns NULL and sets errno to
+ * ERANGE. The errno is thread safe if this is compiled with
+ * -D_REENTRANT as then the 'errno' variable is a macro defined to get
+ * used properly for threads.
+ */
+
+ if(h) {
+ ;
+ }
+ else
+#endif /* HAVE_GETHOSTBYNAME_R_5 */
+#ifdef HAVE_GETHOSTBYNAME_R_6
+ /* Linux */
+
+ res=gethostbyname_r(hostname,
+ (struct hostent *)buf,
+ (char *)buf + sizeof(struct hostent),
+ CURL_HOSTENT_SIZE - sizeof(struct hostent),
+ &h, /* DIFFERENCE */
+ &h_errnop);
+ /* Redhat 8, using glibc 2.2.93 changed the behavior. Now all of a
+ * sudden this function returns EAGAIN if the given buffer size is too
+ * small. Previous versions are known to return ERANGE for the same
+ * problem.
+ *
+ * This wouldn't be such a big problem if older versions wouldn't
+ * sometimes return EAGAIN on a common failure case. Alas, we can't
+ * assume that EAGAIN *or* ERANGE means ERANGE for any given version of
+ * glibc.
+ *
+ * For now, we do that and thus we may call the function repeatedly and
+ * fail for older glibc versions that return EAGAIN, until we run out of
+ * buffer size (step_size grows beyond CURL_HOSTENT_SIZE).
+ *
+ * If anyone has a better fix, please tell us!
+ *
+ * -------------------------------------------------------------------
+ *
+ * On October 23rd 2003, Dan C dug up more details on the mysteries of
+ * gethostbyname_r() in glibc:
+ *
+ * In glibc 2.2.5 the interface is different (this has also been
+ * discovered in glibc 2.1.1-6 as shipped by Redhat 6). What I can't
+ * explain, is that tests performed on glibc 2.2.4-34 and 2.2.4-32
+ * (shipped/upgraded by Redhat 7.2) don't show this behavior!
+ *
+ * In this "buggy" version, the return code is -1 on error and 'errno'
+ * is set to the ERANGE or EAGAIN code. Note that 'errno' is not a
+ * thread-safe variable.
+ */
+
+ if(!h) /* failure */
+#endif/* HAVE_GETHOSTBYNAME_R_6 */
+#ifdef HAVE_GETHOSTBYNAME_R_3
+ /* AIX, Digital Unix/Tru64, HPUX 10, more? */
+
+ /* For AIX 4.3 or later, we don't use gethostbyname_r() at all, because of
+ * the plain fact that it does not return unique full buffers on each
+ * call, but instead several of the pointers in the hostent structs will
+ * point to the same actual data! This have the unfortunate down-side that
+ * our caching system breaks down horribly. Luckily for us though, AIX 4.3
+ * and more recent versions have a "completely thread-safe"[*] libc where
+ * all the data is stored in thread-specific memory areas making calls to
+ * the plain old gethostbyname() work fine even for multi-threaded
+ * programs.
+ *
+ * This AIX 4.3 or later detection is all made in the configure script.
+ *
+ * Troels Walsted Hansen helped us work this out on March 3rd, 2003.
+ *
+ * [*] = much later we've found out that it isn't at all "completely
+ * thread-safe", but at least the gethostbyname() function is.
+ */
+
+ if(CURL_HOSTENT_SIZE >=
+ (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
+ * size dilemma.
+ */
+
+ res = gethostbyname_r(hostname,
+ (struct hostent *)buf,
+ (struct hostent_data *)((char *)buf +
+ sizeof(struct hostent)));
+ h_errnop= errno; /* we don't deal with this, but set it anyway */
+ }
+ else
+ res = -1; /* failure, too smallish buffer size */
+
+ if(!res) { /* success */
+
+ h = buf; /* result expected in h */
+
+ /* This is the worst kind of the different gethostbyname_r() interfaces.
+ * Since we don't know how big buffer this particular lookup required,
+ * we can't realloc down the huge alloc without doing closer analysis of
+ * the returned data. Thus, we always use CURL_HOSTENT_SIZE for every
+ * name lookup. Fixing this would require an extra malloc() and then
+ * calling Curl_addrinfo_copy() that subsequent realloc()s down the new
+ * memory area to the actually used amount.
+ */
+ }
+ else
+#endif /* HAVE_GETHOSTBYNAME_R_3 */
+ {
+ infof(data, "gethostbyname_r(2) failed for %s\n", hostname);
+ h = NULL; /* set return code to NULL */
+ free(buf);
+ }
+#else /* HAVE_GETHOSTBYNAME_R */
+ /*
+ * Here is code for platforms that don't have gethostbyname_r() or for
+ * which the gethostbyname() is the preferred() function.
+ */
+ else {
+ h = gethostbyname(hostname);
+ if (!h)
+ infof(data, "gethostbyname(2) failed for %s\n", hostname);
+#endif /*HAVE_GETHOSTBYNAME_R */
+ }
+
+ if(h) {
+ ai = Curl_he2ai(h, port);
+
+ if (buf) /* used a *_r() function */
+ free(buf);
+ }
+
+ return ai;
+}
+
+#endif /* CURLRES_SYNCH */
+
+/*
+ * Curl_he2ai() translates from a hostent struct to a Curl_addrinfo struct.
+ * The Curl_addrinfo is meant to work like the addrinfo struct does for IPv6
+ * stacks, but for all hosts and environments.
+
+struct Curl_addrinfo {
+ int ai_flags;
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+ size_t ai_addrlen;
+ struct sockaddr *ai_addr;
+ char *ai_canonname;
+ struct addrinfo *ai_next;
+};
+
+struct hostent {
+ char *h_name; * official name of host *
+ char **h_aliases; * alias list *
+ int h_addrtype; * host address type *
+ int h_length; * length of address *
+ char **h_addr_list; * list of addresses *
+}
+#define h_addr h_addr_list[0] * for backward compatibility *
+
+*/
+
+Curl_addrinfo *Curl_he2ai(struct hostent *he, int port)
+{
+ Curl_addrinfo *ai;
+ Curl_addrinfo *prevai = NULL;
+ Curl_addrinfo *firstai = NULL;
+ struct sockaddr_in *addr;
+ int i;
+ struct in_addr *curr;
+
+ if(!he)
+ /* no input == no output! */
+ return NULL;
+
+ for(i=0; (curr = (struct in_addr *)he->h_addr_list[i]); i++) {
+
+ ai = calloc(1, sizeof(Curl_addrinfo) + sizeof(struct sockaddr_in));
+
+ if(!ai)
+ break;
+
+ if(!firstai)
+ /* store the pointer we want to return from this function */
+ firstai = ai;
+
+ if(prevai)
+ /* make the previous entry point to this */
+ prevai->ai_next = ai;
+
+ ai->ai_family = AF_INET; /* we only support this */
+ ai->ai_socktype = SOCK_STREAM; /* we only support this */
+ ai->ai_addrlen = sizeof(struct sockaddr_in);
+ /* make the ai_addr point to the address immediately following this struct
+ and use that area to store the address */
+ ai->ai_addr = (struct sockaddr *) ((char*)ai + sizeof(Curl_addrinfo));
+
+ /* leave the rest of the struct filled with zero */
+
+ addr = (struct sockaddr_in *)ai->ai_addr; /* storage area for this info */
+
+ memcpy((char *)&(addr->sin_addr), curr, sizeof(struct in_addr));
+ addr->sin_family = he->h_addrtype;
+ addr->sin_port = htons((unsigned short)port);
+
+ prevai = ai;
+ }
+ return firstai;
+}
+
+#endif /* CURLRES_IPV4 */
diff --git a/Source/CTest/Curl/hostip6.c b/Source/CTest/Curl/hostip6.c
new file mode 100644
index 0000000..4d7c89f
--- /dev/null
+++ b/Source/CTest/Curl/hostip6.c
@@ -0,0 +1,263 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#include <string.h>
+#include <errno.h>
+
+#define _REENTRANT
+
+#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
+#include <malloc.h>
+#else
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h> /* required for free() prototypes */
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h> /* for the close() proto */
+#endif
+#ifdef VMS
+#include <in.h>
+#include <inet.h>
+#include <stdlib.h>
+#endif
+#endif
+
+#ifdef HAVE_SETJMP_H
+#include <setjmp.h>
+#endif
+
+#ifdef WIN32
+#include <process.h>
+#endif
+
+#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "strerror.h"
+#include "url.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
+#include "inet_ntoa_r.h"
+#endif
+
+#include "memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/***********************************************************************
+ * Only for ipv6-enabled builds
+ **********************************************************************/
+#ifdef CURLRES_IPV6
+/*
+ * This is a wrapper function for freeing name information in a protocol
+ * independent way. This takes care of using the appropriate underlaying
+ * function.
+ */
+void Curl_freeaddrinfo(Curl_addrinfo *p)
+{
+ freeaddrinfo(p);
+}
+
+#ifdef CURLRES_ASYNCH
+/*
+ * Curl_addrinfo_copy() is used by the asynch callback to copy a given
+ * address. But this is an ipv6 build and then we don't copy the address, we
+ * just return the same pointer!
+ */
+Curl_addrinfo *Curl_addrinfo_copy(void *source, int port)
+{
+ (void) port;
+ return source;
+}
+#endif
+
+#ifdef CURLDEBUG
+/* These are strictly for memory tracing and are using the same style as the
+ * family otherwise present in memdebug.c. I put these ones here since they
+ * require a bunch of structs I didn't wanna include in memdebug.c
+ */
+int curl_dogetaddrinfo(char *hostname, char *service,
+ struct addrinfo *hints,
+ struct addrinfo **result,
+ int line, const char *source)
+{
+ int res=(getaddrinfo)(hostname, service, hints, result);
+ if(0 == res) {
+ /* success */
+ if(logfile)
+ fprintf(logfile, "ADDR %s:%d getaddrinfo() = %p\n",
+ source, line, (void *)*result);
+ }
+ else {
+ if(logfile)
+ fprintf(logfile, "ADDR %s:%d getaddrinfo() failed\n",
+ source, line);
+ }
+ return res;
+}
+
+int curl_dogetnameinfo(const struct sockaddr *sa, socklen_t salen,
+ char *host, size_t hostlen,
+ char *serv, size_t servlen, int flags,
+ int line, const char *source)
+{
+ int res=(getnameinfo)(sa, salen, host, hostlen, serv, servlen, flags);
+ if(0 == res) {
+ /* success */
+ if(logfile)
+ fprintf(logfile, "GETNAME %s:%d getnameinfo()\n",
+ source, line);
+ }
+ else {
+ if(logfile)
+ fprintf(logfile, "GETNAME %s:%d getnameinfo() failed = %d\n",
+ source, line, res);
+ }
+ return res;
+}
+
+void curl_dofreeaddrinfo(struct addrinfo *freethis,
+ int line, const char *source)
+{
+ (freeaddrinfo)(freethis);
+ if(logfile)
+ fprintf(logfile, "ADDR %s:%d freeaddrinfo(%p)\n",
+ source, line, (void *)freethis);
+}
+
+#endif
+
+/*
+ * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've
+ * been set and returns TRUE if they are OK.
+ */
+bool Curl_ipvalid(struct SessionHandle *data)
+{
+ if(data->set.ip_version == CURL_IPRESOLVE_V6) {
+ /* see if we have an IPv6 stack */
+ curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0);
+ if (s == CURL_SOCKET_BAD)
+ /* an ipv6 address was requested and we can't get/use one */
+ return FALSE;
+ sclose(s);
+ }
+ return TRUE;
+}
+
+#ifndef USE_THREADING_GETADDRINFO
+/*
+ * Curl_getaddrinfo() when built ipv6-enabled (non-threading version).
+ *
+ * Returns name information about the given hostname and port number. If
+ * successful, the 'addrinfo' is returned and the forth argument will point to
+ * memory we need to free after use. That memory *MUST* be freed with
+ * Curl_freeaddrinfo(), nothing else.
+ */
+Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
+ char *hostname,
+ int port,
+ int *waitp)
+{
+ struct addrinfo hints, *res;
+ int error;
+ char sbuf[NI_MAXSERV];
+ curl_socket_t s;
+ int pf;
+ struct SessionHandle *data = conn->data;
+
+ *waitp=0; /* don't wait, we have the response now */
+
+ /* see if we have an IPv6 stack */
+ s = socket(PF_INET6, SOCK_DGRAM, 0);
+ if (s < 0) {
+ /* Some non-IPv6 stacks have been found to make very slow name resolves
+ * when PF_UNSPEC is used, so thus we switch to a mere PF_INET lookup if
+ * the stack seems to be a non-ipv6 one. */
+
+ pf = PF_INET;
+ }
+ else {
+ /* This seems to be an IPv6-capable stack, use PF_UNSPEC for the widest
+ * possible checks. And close the socket again.
+ */
+ sclose(s);
+
+ /*
+ * Check if a more limited name resolve has been requested.
+ */
+ switch(data->set.ip_version) {
+ case CURL_IPRESOLVE_V4:
+ pf = PF_INET;
+ break;
+ case CURL_IPRESOLVE_V6:
+ pf = PF_INET6;
+ break;
+ default:
+ pf = PF_UNSPEC;
+ break;
+ }
+ }
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = pf;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_CANONNAME;
+ snprintf(sbuf, sizeof(sbuf), "%d", port);
+ error = getaddrinfo(hostname, sbuf, &hints, &res);
+ if (error) {
+ infof(data, "getaddrinfo(3) failed for %s:%d\n", hostname, port);
+ return NULL;
+ }
+
+ return res;
+}
+#endif /* USE_THREADING_GETADDRINFO */
+#endif /* ipv6 */
+
diff --git a/Source/CTest/Curl/hostsyn.c b/Source/CTest/Curl/hostsyn.c
new file mode 100644
index 0000000..77ffe71
--- /dev/null
+++ b/Source/CTest/Curl/hostsyn.c
@@ -0,0 +1,149 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#include <string.h>
+#include <errno.h>
+
+#define _REENTRANT
+
+#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
+#include <malloc.h>
+#else
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h> /* required for free() prototypes */
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h> /* for the close() proto */
+#endif
+#ifdef VMS
+#include <in.h>
+#include <inet.h>
+#include <stdlib.h>
+#endif
+#endif
+
+#ifdef HAVE_SETJMP_H
+#include <setjmp.h>
+#endif
+
+#ifdef WIN32
+#include <process.h>
+#endif
+
+#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "strerror.h"
+#include "url.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
+#include "inet_ntoa_r.h"
+#endif
+
+#include "memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/***********************************************************************
+ * Only for builds using synchronous name resolves
+ **********************************************************************/
+#ifdef CURLRES_SYNCH
+
+/*
+ * Curl_wait_for_resolv() for synch-builds. Curl_resolv() can never return
+ * wait==TRUE, so this function will never be called. If it still gets called,
+ * we return failure at once.
+ *
+ * We provide this function only to allow multi.c to remain unaware if we are
+ * doing asynch resolves or not.
+ */
+CURLcode Curl_wait_for_resolv(struct connectdata *conn,
+ struct Curl_dns_entry **entry)
+{
+ (void)conn;
+ *entry=NULL;
+ return CURLE_COULDNT_RESOLVE_HOST;
+}
+
+/*
+ * This function will never be called when synch-built. If it still gets
+ * called, we return failure at once.
+ *
+ * We provide this function only to allow multi.c to remain unaware if we are
+ * doing asynch resolves or not.
+ */
+CURLcode Curl_is_resolved(struct connectdata *conn,
+ struct Curl_dns_entry **dns)
+{
+ (void)conn;
+ *dns = NULL;
+
+ return CURLE_COULDNT_RESOLVE_HOST;
+}
+
+/*
+ * We just return OK, this function is never actually used for synch builds.
+ * It is present here to keep #ifdefs out from multi.c
+ */
+
+CURLcode Curl_fdset(struct connectdata *conn,
+ fd_set *read_fd_set,
+ fd_set *write_fd_set,
+ int *max_fdp)
+{
+ (void)conn;
+ (void)read_fd_set;
+ (void)write_fd_set;
+ (void)max_fdp;
+
+ return CURLE_OK;
+}
+
+#endif /* truly sync */
diff --git a/Source/CTest/Curl/hostthre.c b/Source/CTest/Curl/hostthre.c
new file mode 100644
index 0000000..738efa5
--- /dev/null
+++ b/Source/CTest/Curl/hostthre.c
@@ -0,0 +1,550 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#include <string.h>
+#include <errno.h>
+
+#define _REENTRANT
+
+#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
+#include <malloc.h>
+#else
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h> /* required for free() prototypes */
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h> /* for the close() proto */
+#endif
+#ifdef VMS
+#include <in.h>
+#include <inet.h>
+#include <stdlib.h>
+#endif
+#endif
+
+#ifdef HAVE_SETJMP_H
+#include <setjmp.h>
+#endif
+
+#ifdef WIN32
+#include <process.h>
+#endif
+
+#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "strerror.h"
+#include "url.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include "inet_ntop.h"
+
+#include "memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/***********************************************************************
+ * Only for Windows threaded name resolves builds
+ **********************************************************************/
+#ifdef CURLRES_THREADED
+
+/* This function is used to init a threaded resolve */
+static bool init_resolve_thread(struct connectdata *conn,
+ const char *hostname, int port,
+ const Curl_addrinfo *hints);
+
+#ifdef CURLRES_IPV4
+ #define THREAD_FUNC gethostbyname_thread
+ #define THREAD_NAME "gethostbyname_thread"
+#else
+ #define THREAD_FUNC getaddrinfo_thread
+ #define THREAD_NAME "getaddrinfo_thread"
+#endif
+
+#if defined(DEBUG_THREADING_GETHOSTBYNAME) || \
+ defined(DEBUG_THREADING_GETADDRINFO)
+/* If this is defined, provide tracing */
+#define TRACE(args) \
+ do { trace_it("%u: ", __LINE__); trace_it args; } while (0)
+
+static void trace_it (const char *fmt, ...)
+{
+ static int do_trace = -1;
+ va_list args;
+
+ if (do_trace == -1) {
+ const char *env = getenv("CURL_TRACE");
+ do_trace = (env && atoi(env) > 0);
+ }
+ if (!do_trace)
+ return;
+ va_start (args, fmt);
+ vfprintf (stderr, fmt, args);
+ fflush (stderr);
+ va_end (args);
+}
+#else
+#define TRACE(x)
+#endif
+
+#ifdef DEBUG_THREADING_GETADDRINFO
+static void dump_addrinfo (struct connectdata *conn, const struct addrinfo *ai)
+{
+ TRACE(("dump_addrinfo:\n"));
+ for ( ; ai; ai = ai->ai_next) {
+ char buf [INET6_ADDRSTRLEN];
+
+ trace_it(" fam %2d, CNAME %s, ",
+ ai->ai_family, ai->ai_canonname ? ai->ai_canonname : "<none>");
+ if (Curl_printable_address(ai, buf, sizeof(buf)))
+ trace_it("%s\n", buf);
+ else
+ trace_it("failed; %s\n", Curl_strerror(conn,WSAGetLastError()));
+ }
+}
+#endif
+
+struct thread_data {
+ HANDLE thread_hnd;
+ unsigned thread_id;
+ DWORD thread_status;
+ curl_socket_t dummy_sock; /* dummy for Curl_fdset() */
+ FILE *stderr_file;
+#ifdef CURLRES_IPV6
+ struct addrinfo hints;
+#endif
+};
+
+#if defined(CURLRES_IPV4)
+/*
+ * gethostbyname_thread() resolves a name, calls the Curl_addrinfo4_callback
+ * and then exits.
+ *
+ * For builds without ARES/ENABLE_IPV6, create a resolver thread and wait on
+ * it.
+ */
+static unsigned __stdcall gethostbyname_thread (void *arg)
+{
+ struct connectdata *conn = (struct connectdata*) arg;
+ struct thread_data *td = (struct thread_data*) conn->async.os_specific;
+ struct hostent *he;
+ int rc;
+
+ /* Sharing the same _iob[] element with our parent thread should
+ * hopefully make printouts synchronised. I'm not sure it works
+ * with a static runtime lib (MSVC's libc.lib).
+ */
+ *stderr = *td->stderr_file;
+
+ WSASetLastError (conn->async.status = NO_DATA); /* pending status */
+ he = gethostbyname (conn->async.hostname);
+ if (he) {
+ Curl_addrinfo4_callback(conn, CURL_ASYNC_SUCCESS, he);
+ rc = 1;
+ }
+ else {
+ Curl_addrinfo4_callback(conn, (int)WSAGetLastError(), NULL);
+ rc = 0;
+ }
+ TRACE(("Winsock-error %d, addr %s\n", conn->async.status,
+ he ? inet_ntoa(*(struct in_addr*)he->h_addr) : "unknown"));
+ return (rc);
+ /* An implicit _endthreadex() here */
+}
+
+#elif defined(CURLRES_IPV6)
+
+/*
+ * getaddrinfo_thread() resolves a name, calls Curl_addrinfo6_callback and then
+ * exits.
+ *
+ * For builds without ARES, but with ENABLE_IPV6, create a resolver thread
+ * and wait on it.
+ */
+static unsigned __stdcall getaddrinfo_thread (void *arg)
+{
+ struct connectdata *conn = (struct connectdata*) arg;
+ struct thread_data *td = (struct thread_data*) conn->async.os_specific;
+ struct addrinfo *res;
+ char service [NI_MAXSERV];
+ int rc;
+
+ *stderr = *td->stderr_file;
+
+ itoa(conn->async.port, service, 10);
+
+ WSASetLastError(conn->async.status = NO_DATA); /* pending status */
+
+ rc = getaddrinfo(conn->async.hostname, service, &td->hints, &res);
+
+ if (rc == 0) {
+#ifdef DEBUG_THREADING_GETADDRINFO
+ dump_addrinfo (conn, res);
+#endif
+ Curl_addrinfo6_callback(conn, CURL_ASYNC_SUCCESS, res);
+ }
+ else {
+ Curl_addrinfo6_callback(conn, (int)WSAGetLastError(), NULL);
+ TRACE(("Winsock-error %d, no address\n", conn->async.status));
+ }
+ return (rc);
+ /* An implicit _endthreadex() here */
+}
+#endif
+
+/*
+ * destroy_thread_data() cleans up async resolver data.
+ * Complementary of ares_destroy.
+ */
+static void destroy_thread_data (struct Curl_async *async)
+{
+ if (async->hostname)
+ free(async->hostname);
+
+ if (async->os_specific) {
+ curl_socket_t sock = ((const struct thread_data*)async->os_specific)->dummy_sock;
+
+ if (sock != CURL_SOCKET_BAD)
+ sclose(sock);
+ free(async->os_specific);
+ }
+ async->hostname = NULL;
+ async->os_specific = NULL;
+}
+
+/*
+ * init_resolve_thread() starts a new thread that performs the actual
+ * resolve. This function returns before the resolve is done.
+ *
+ * Returns FALSE in case of failure, otherwise TRUE.
+ */
+static bool init_resolve_thread (struct connectdata *conn,
+ const char *hostname, int port,
+ const Curl_addrinfo *hints)
+{
+ struct thread_data *td = calloc(sizeof(*td), 1);
+
+ if (!td) {
+ SetLastError(ENOMEM);
+ return FALSE;
+ }
+
+ Curl_safefree(conn->async.hostname);
+ conn->async.hostname = strdup(hostname);
+ if (!conn->async.hostname) {
+ free(td);
+ SetLastError(ENOMEM);
+ return FALSE;
+ }
+
+ conn->async.port = port;
+ conn->async.done = FALSE;
+ conn->async.status = 0;
+ conn->async.dns = NULL;
+ conn->async.os_specific = (void*) td;
+
+ td->dummy_sock = CURL_SOCKET_BAD;
+ td->stderr_file = stderr;
+ td->thread_hnd = (HANDLE) _beginthreadex(NULL, 0, THREAD_FUNC,
+ conn, 0, &td->thread_id);
+#ifdef CURLRES_IPV6
+ curlassert(hints);
+ td->hints = *hints;
+#else
+ (void) hints;
+#endif
+
+ if (!td->thread_hnd) {
+ SetLastError(errno);
+ TRACE(("_beginthreadex() failed; %s\n", Curl_strerror(conn,errno)));
+ destroy_thread_data(&conn->async);
+ return FALSE;
+ }
+ /* This socket is only to keep Curl_fdset() and select() happy; should never
+ * become signalled for read/write since it's unbound but Windows needs
+ * atleast 1 socket in select().
+ */
+ td->dummy_sock = socket(AF_INET, SOCK_DGRAM, 0);
+ return TRUE;
+}
+
+
+/*
+ * Curl_wait_for_resolv() waits for a resolve to finish. This function should
+ * be avoided since using this risk getting the multi interface to "hang".
+ *
+ * If 'entry' is non-NULL, make it point to the resolved dns entry
+ *
+ * This is the version for resolves-in-a-thread.
+ */
+CURLcode Curl_wait_for_resolv(struct connectdata *conn,
+ struct Curl_dns_entry **entry)
+{
+ struct thread_data *td = (struct thread_data*) conn->async.os_specific;
+ struct SessionHandle *data = conn->data;
+ long timeout;
+ DWORD status, ticks;
+ CURLcode rc;
+
+ curlassert (conn && td);
+
+ /* now, see if there's a connect timeout or a regular timeout to
+ use instead of the default one */
+ timeout =
+ conn->data->set.connecttimeout ? conn->data->set.connecttimeout :
+ conn->data->set.timeout ? conn->data->set.timeout :
+ CURL_TIMEOUT_RESOLVE; /* default name resolve timeout */
+ ticks = GetTickCount();
+
+ status = WaitForSingleObject(td->thread_hnd, 1000UL*timeout);
+ if (status == WAIT_OBJECT_0 || status == WAIT_ABANDONED) {
+ /* Thread finished before timeout; propagate Winsock error to this thread.
+ * 'conn->async.done = TRUE' is set in Curl_addrinfo4/6_callback().
+ */
+ WSASetLastError(conn->async.status);
+ GetExitCodeThread(td->thread_hnd, &td->thread_status);
+ TRACE(("%s() status %lu, thread retval %lu, ",
+ THREAD_NAME, status, td->thread_status));
+ }
+ else {
+ conn->async.done = TRUE;
+ td->thread_status = (DWORD)-1;
+ TRACE(("%s() timeout, ", THREAD_NAME));
+ }
+
+ TRACE(("elapsed %lu ms\n", GetTickCount()-ticks));
+
+ CloseHandle(td->thread_hnd);
+
+ if(entry)
+ *entry = conn->async.dns;
+
+ rc = CURLE_OK;
+
+ if (!conn->async.dns) {
+ /* a name was not resolved */
+ if (td->thread_status == (DWORD)-1 || conn->async.status == NO_DATA) {
+ failf(data, "Resolving host timed out: %s", conn->host.name);
+ rc = CURLE_OPERATION_TIMEDOUT;
+ }
+ else if(conn->async.done) {
+ failf(data, "Could not resolve host: %s; %s",
+ conn->host.name, Curl_strerror(conn,conn->async.status));
+ rc = CURLE_COULDNT_RESOLVE_HOST;
+ }
+ else
+ rc = CURLE_OPERATION_TIMEDOUT;
+ }
+
+ destroy_thread_data(&conn->async);
+
+ if(CURLE_OK != rc)
+ /* close the connection, since we must not return failure from here
+ without cleaning up this connection properly */
+ Curl_disconnect(conn);
+
+ return (rc);
+}
+
+/*
+ * Curl_is_resolved() is called repeatedly to check if a previous name resolve
+ * request has completed. It should also make sure to time-out if the
+ * operation seems to take too long.
+ */
+CURLcode Curl_is_resolved(struct connectdata *conn,
+ struct Curl_dns_entry **entry)
+{
+ *entry = NULL;
+
+ if (conn->async.done) {
+ /* we're done */
+ destroy_thread_data(&conn->async);
+ if (!conn->async.dns) {
+ TRACE(("Curl_is_resolved(): CURLE_COULDNT_RESOLVE_HOST\n"));
+ return CURLE_COULDNT_RESOLVE_HOST;
+ }
+ *entry = conn->async.dns;
+ TRACE(("resolved okay, dns %p\n", *entry));
+ }
+ else
+ TRACE(("not yet\n"));
+ return CURLE_OK;
+}
+
+CURLcode Curl_fdset(struct connectdata *conn,
+ fd_set *read_fd_set,
+ fd_set *write_fd_set,
+ int *max_fdp)
+{
+ const struct thread_data *td =
+ (const struct thread_data *) conn->async.os_specific;
+
+ if (td && td->dummy_sock != CURL_SOCKET_BAD) {
+ FD_SET(td->dummy_sock,write_fd_set);
+ *max_fdp = td->dummy_sock;
+ }
+ (void) read_fd_set;
+ return CURLE_OK;
+}
+
+#ifdef CURLRES_IPV4
+/*
+ * Curl_getaddrinfo() - for Windows threading without ENABLE_IPV6.
+ */
+Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
+ char *hostname,
+ int port,
+ int *waitp)
+{
+ struct hostent *h = NULL;
+ struct SessionHandle *data = conn->data;
+ in_addr_t in;
+
+ *waitp = 0; /* don't wait, we act synchronously */
+
+ in = inet_addr(hostname);
+ if (in != CURL_INADDR_NONE)
+ /* This is a dotted IP address 123.123.123.123-style */
+ return Curl_ip2addr(in, hostname, port);
+
+ /* fire up a new resolver thread! */
+ if (init_resolve_thread(conn, hostname, port, NULL)) {
+ *waitp = TRUE; /* please wait for the response */
+ return NULL;
+ }
+
+ /* fall-back to blocking version */
+ infof(data, "init_resolve_thread() failed for %s; code %lu\n",
+ hostname, GetLastError());
+
+ h = gethostbyname(hostname);
+ if (!h) {
+ infof(data, "gethostbyname(2) failed for %s:%d; %s\n",
+ hostname, port, Curl_strerror(conn,WSAGetLastError()));
+ return NULL;
+ }
+ return Curl_he2ai(h, port);
+}
+#endif /* CURLRES_IPV4 */
+
+#ifdef CURLRES_IPV6
+/*
+ * Curl_getaddrinfo() - for Windows threading IPv6 enabled
+ */
+Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
+ char *hostname,
+ int port,
+ int *waitp)
+{
+ struct addrinfo hints, *res;
+ int error;
+ char sbuf[NI_MAXSERV];
+ curl_socket_t s;
+ int pf;
+ struct SessionHandle *data = conn->data;
+
+ *waitp = FALSE; /* default to synch response */
+
+ /* see if we have an IPv6 stack */
+ s = socket(PF_INET6, SOCK_DGRAM, 0);
+ if (s == CURL_SOCKET_BAD) {
+ /* Some non-IPv6 stacks have been found to make very slow name resolves
+ * when PF_UNSPEC is used, so thus we switch to a mere PF_INET lookup if
+ * the stack seems to be a non-ipv6 one. */
+
+ pf = PF_INET;
+ }
+ else {
+ /* This seems to be an IPv6-capable stack, use PF_UNSPEC for the widest
+ * possible checks. And close the socket again.
+ */
+ sclose(s);
+
+ /*
+ * Check if a more limited name resolve has been requested.
+ */
+ switch(data->set.ip_version) {
+ case CURL_IPRESOLVE_V4:
+ pf = PF_INET;
+ break;
+ case CURL_IPRESOLVE_V6:
+ pf = PF_INET6;
+ break;
+ default:
+ pf = PF_UNSPEC;
+ break;
+ }
+ }
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = pf;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_CANONNAME;
+ itoa(port, sbuf, 10);
+
+ /* fire up a new resolver thread! */
+ if (init_resolve_thread(conn, hostname, port, &hints)) {
+ *waitp = TRUE; /* please wait for the response */
+ return NULL;
+ }
+
+ /* fall-back to blocking version */
+ infof(data, "init_resolve_thread() failed for %s; code %lu\n",
+ hostname, GetLastError());
+
+ error = getaddrinfo(hostname, sbuf, &hints, &res);
+ if (error) {
+ infof(data, "getaddrinfo() failed for %s:%d; %s\n",
+ hostname, port, Curl_strerror(conn,WSAGetLastError()));
+ return NULL;
+ }
+ return res;
+}
+#endif /* CURLRES_IPV6 */
+#endif /* CURLRES_THREADED */
diff --git a/Source/CTest/Curl/http.c b/Source/CTest/Curl/http.c
index 9b9fa8e..107c846 100644
--- a/Source/CTest/Curl/http.c
+++ b/Source/CTest/Curl/http.c
@@ -1,16 +1,16 @@
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -36,7 +36,6 @@
#include <errno.h>
#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
-#include <winsock.h>
#include <time.h>
#include <io.h>
#else
@@ -54,7 +53,6 @@
#endif
#endif
-#include <sys/resource.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
@@ -76,7 +74,6 @@
#include <sys/select.h>
#endif
-
#endif
#include "urldata.h"
@@ -89,35 +86,548 @@
#include "cookie.h"
#include "strequal.h"
#include "ssluse.h"
+#include "http_digest.h"
+#include "http_ntlm.h"
+#include "http_negotiate.h"
+#include "url.h"
+#include "share.h"
+#include "hostip.h"
+#include "http.h"
+#include "memory.h"
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
/* The last #include file should be: */
-#ifdef MALLOCDEBUG
#include "memdebug.h"
+
+/*
+ * 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.
+ */
+static char *checkheaders(struct SessionHandle *data, const char *thisheader)
+{
+ struct curl_slist *head;
+ size_t thislen = strlen(thisheader);
+
+ for(head = data->set.headers; head; head=head->next) {
+ if(strnequal(head->data, thisheader, thislen))
+ return head->data;
+ }
+ return NULL;
+}
+
+/*
+ * Curl_output_basic() sets up an Authorization: header (or the proxy version)
+ * for HTTP Basic authentication.
+ *
+ * Returns CURLcode.
+ */
+static CURLcode Curl_output_basic(struct connectdata *conn, bool proxy)
+{
+ char *authorization;
+ struct SessionHandle *data=conn->data;
+ char **userp;
+ char *user;
+ char *pwd;
+
+ if(proxy) {
+ userp = &conn->allocptr.proxyuserpwd;
+ user = conn->proxyuser;
+ pwd = conn->proxypasswd;
+ }
+ else {
+ userp = &conn->allocptr.userpwd;
+ user = conn->user;
+ pwd = conn->passwd;
+ }
+
+ snprintf(data->state.buffer, sizeof(data->state.buffer), "%s:%s", user, pwd);
+ if(Curl_base64_encode(data->state.buffer,
+ strlen(data->state.buffer),
+ &authorization) > 0) {
+ if(*userp)
+ free(*userp);
+ *userp = aprintf( "%sAuthorization: Basic %s\015\012",
+ proxy?"Proxy-":"",
+ authorization);
+ free(authorization);
+ }
+ else
+ return CURLE_OUT_OF_MEMORY;
+ return CURLE_OK;
+}
+
+/* pickoneauth() selects the most favourable authentication method from the
+ * ones available and the ones we want.
+ *
+ * return TRUE if one was picked
+ */
+static bool pickoneauth(struct auth *pick)
+{
+ bool picked;
+ /* only deal with authentication we want */
+ long avail = pick->avail & pick->want;
+ picked = TRUE;
+
+ /* The order of these checks is highly relevant, as this will be the order
+ of preference in case of the existance of multiple accepted types. */
+ if(avail & CURLAUTH_GSSNEGOTIATE)
+ pick->picked = CURLAUTH_GSSNEGOTIATE;
+ else if(avail & CURLAUTH_DIGEST)
+ pick->picked = CURLAUTH_DIGEST;
+ else if(avail & CURLAUTH_NTLM)
+ pick->picked = CURLAUTH_NTLM;
+ else if(avail & CURLAUTH_BASIC)
+ pick->picked = CURLAUTH_BASIC;
+ else {
+ pick->picked = CURLAUTH_PICKNONE; /* we select to use nothing */
+ picked = FALSE;
+ }
+ pick->avail = CURLAUTH_NONE; /* clear it here */
+
+ return picked;
+}
+
+/*
+ * Curl_http_auth_act() gets called when a all HTTP headers have been received
+ * and it checks what authentication methods that are available and decides
+ * which one (if any) to use. It will set 'newurl' if an auth metod was
+ * picked.
+ */
+
+CURLcode Curl_http_auth_act(struct connectdata *conn)
+{
+ struct SessionHandle *data = conn->data;
+ bool pickhost = FALSE;
+ bool pickproxy = FALSE;
+ CURLcode code = CURLE_OK;
+
+ if(data->state.authproblem)
+ return data->set.http_fail_on_error?CURLE_HTTP_RETURNED_ERROR:CURLE_OK;
+
+ if(conn->bits.user_passwd &&
+ ((conn->keep.httpcode == 401) ||
+ (conn->bits.authprobe && conn->keep.httpcode < 300))) {
+ pickhost = pickoneauth(&data->state.authhost);
+ if(!pickhost)
+ data->state.authproblem = TRUE;
+ }
+ if(conn->bits.proxy_user_passwd &&
+ ((conn->keep.httpcode == 407) ||
+ (conn->bits.authprobe && conn->keep.httpcode < 300))) {
+ pickproxy = pickoneauth(&data->state.authproxy);
+ if(!pickproxy)
+ data->state.authproblem = TRUE;
+ }
+
+ if(pickhost || pickproxy)
+ conn->newurl = strdup(data->change.url); /* clone URL */
+
+ else if((conn->keep.httpcode < 300) &&
+ (!data->state.authhost.done) &&
+ conn->bits.authprobe) {
+ /* no (known) authentication available,
+ authentication is not "done" yet and
+ no authentication seems to be required and
+ we didn't try HEAD or GET */
+ if((data->set.httpreq != HTTPREQ_GET) &&
+ (data->set.httpreq != HTTPREQ_HEAD)) {
+ conn->newurl = strdup(data->change.url); /* clone URL */
+ data->state.authhost.done = TRUE;
+ }
+ }
+ if (Curl_http_should_fail(conn)) {
+ failf (data, "The requested URL returned error: %d",
+ conn->keep.httpcode);
+ code = CURLE_HTTP_RETURNED_ERROR;
+ }
+
+ return code;
+}
+
+/**
+ * Curl_http_output_auth() setups the authentication headers for the
+ * host/proxy and the correct authentication
+ * method. conn->data->state.authdone is set to TRUE when authentication is
+ * done.
+ *
+ * @param conn all information about the current connection
+ * @param request pointer to the request keyword
+ * @param path pointer to the requested path
+ * @param proxytunnel boolean if this is the request setting up a "proxy
+ * tunnel"
+ *
+ * @returns CURLcode
+ */
+static CURLcode
+Curl_http_output_auth(struct connectdata *conn,
+ char *request,
+ char *path,
+ bool proxytunnel) /* TRUE if this is the request setting
+ up the proxy tunnel */
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ char *auth=NULL;
+
+ curlassert(data);
+
+ if((conn->bits.httpproxy && conn->bits.proxy_user_passwd) ||
+ conn->bits.user_passwd)
+ /* continue please */ ;
+ else {
+ data->state.authhost.done = TRUE;
+ data->state.authproxy.done = TRUE;
+ return CURLE_OK; /* no authentication with no user or password */
+ }
+
+ if(data->state.authhost.want && !data->state.authhost.picked)
+ /* The app has selected one or more methods, but none has been picked
+ so far by a server round-trip. Then we set the picked one to the
+ want one, and if this is one single bit it'll be used instantly. */
+ data->state.authhost.picked = data->state.authhost.want;
+
+ if(data->state.authproxy.want && !data->state.authproxy.picked)
+ /* The app has selected one or more methods, but none has been picked so
+ far by a proxy round-trip. Then we set the picked one to the want one,
+ and if this is one single bit it'll be used instantly. */
+ data->state.authproxy.picked = data->state.authproxy.want;
+
+ /* To prevent the user+password to get sent to other than the original
+ host due to a location-follow, we do some weirdo checks here */
+ if(!data->state.this_is_a_follow ||
+ !data->state.auth_host ||
+ curl_strequal(data->state.auth_host, conn->host.name) ||
+ data->set.http_disable_hostname_check_before_authentication) {
+
+ /* Send proxy authentication header if needed */
+ if (conn->bits.httpproxy &&
+ (conn->bits.tunnel_proxy == proxytunnel)) {
+#ifdef USE_SSLEAY
+ if(data->state.authproxy.want == CURLAUTH_NTLM) {
+ auth=(char *)"NTLM";
+ result = Curl_output_ntlm(conn, TRUE);
+ if(result)
+ return result;
+ }
+ else
+#endif
+ if(data->state.authproxy.want == CURLAUTH_BASIC) {
+ /* Basic */
+ if(conn->bits.proxy_user_passwd &&
+ !checkheaders(data, "Proxy-authorization:")) {
+ auth=(char *)"Basic";
+ result = Curl_output_basic(conn, TRUE);
+ if(result)
+ return result;
+ }
+ data->state.authproxy.done = TRUE;
+ }
+ else if(data->state.authproxy.want == CURLAUTH_DIGEST) {
+ auth=(char *)"Digest";
+ result = Curl_output_digest(conn,
+ TRUE, /* proxy */
+ (unsigned char *)request,
+ (unsigned char *)path);
+ if(result)
+ return result;
+ }
+
+ infof(data, "Proxy auth using %s with user '%s'\n",
+ auth, conn->proxyuser?conn->proxyuser:"");
+ }
+ else
+ /* we have no proxy so let's pretend we're done authenticating
+ with it */
+ data->state.authproxy.done = TRUE;
+
+ /* Send web authentication header if needed */
+ {
+ auth = NULL;
+#ifdef HAVE_GSSAPI
+ if((data->state.authhost.want == CURLAUTH_GSSNEGOTIATE) &&
+ data->state.negotiate.context &&
+ !GSS_ERROR(data->state.negotiate.status)) {
+ auth=(char *)"GSS-Negotiate";
+ result = Curl_output_negotiate(conn);
+ if (result)
+ return result;
+ data->state.authhost.done = TRUE;
+ }
+ else
+#endif
+#ifdef USE_SSLEAY
+ if(data->state.authhost.picked == CURLAUTH_NTLM) {
+ auth=(char *)"NTLM";
+ result = Curl_output_ntlm(conn, FALSE);
+ if(result)
+ return result;
+ }
+ else
+#endif
+ {
+ if(data->state.authhost.picked == CURLAUTH_DIGEST) {
+ auth=(char *)"Digest";
+ result = Curl_output_digest(conn,
+ FALSE, /* not a proxy */
+ (unsigned char *)request,
+ (unsigned char *)path);
+ if(result)
+ return result;
+ }
+ else if(data->state.authhost.picked == CURLAUTH_BASIC) {
+ if(conn->bits.user_passwd &&
+ !checkheaders(data, "Authorization:")) {
+ auth=(char *)"Basic";
+ result = Curl_output_basic(conn, FALSE);
+ if(result)
+ return result;
+ }
+ /* basic is always ready */
+ data->state.authhost.done = TRUE;
+ }
+ }
+ if(auth)
+ infof(data, "Server auth using %s with user '%s'\n",
+ auth, conn->user);
+ }
+ }
+ else
+ data->state.authhost.done = TRUE;
+
+ return result;
+}
+
+
+/*
+ * Curl_http_input_auth() deals with Proxy-Authenticate: and WWW-Authenticate:
+ * headers. They are dealt with both in the transfer.c main loop and in the
+ * proxy CONNECT loop.
+ */
+
+CURLcode Curl_http_input_auth(struct connectdata *conn,
+ int httpcode,
+ char *header) /* the first non-space */
+{
+ /*
+ * This resource requires authentication
+ */
+ struct SessionHandle *data = conn->data;
+
+ long *availp;
+ char *start;
+ struct auth *authp;
+
+ if (httpcode == 407) {
+ start = header+strlen("Proxy-authenticate:");
+ availp = &data->info.proxyauthavail;
+ authp = &data->state.authproxy;
+ }
+ else {
+ start = header+strlen("WWW-Authenticate:");
+ availp = &data->info.httpauthavail;
+ authp = &data->state.authhost;
+ }
+
+ /* pass all white spaces */
+ while(*start && isspace((int)*start))
+ start++;
+
+ /*
+ * Here we check if we want the specific single authentiction (using ==) and
+ * if we do, we initiate usage of it.
+ *
+ * If the provided authentication is wanted as one out of several accepted
+ * types (using &), we OR this authenticaion type to the authavail
+ * variable.
+ */
+
+#ifdef HAVE_GSSAPI
+ if (checkprefix("GSS-Negotiate", start) ||
+ checkprefix("Negotiate", start)) {
+ *availp |= CURLAUTH_GSSNEGOTIATE;
+ authp->avail |= CURLAUTH_GSSNEGOTIATE;
+ if(authp->picked == CURLAUTH_GSSNEGOTIATE) {
+ /* if exactly this is wanted, go */
+ int neg = Curl_input_negotiate(conn, start);
+ if (neg == 0) {
+ conn->newurl = strdup(data->change.url);
+ data->state.authproblem = (conn->newurl == NULL);
+ }
+ else {
+ infof(data, "Authentication problem. Ignoring this.\n");
+ data->state.authproblem = TRUE;
+ }
+ }
+ }
+ else
+#endif
+#ifdef USE_SSLEAY
+ /* NTLM support requires the SSL crypto libs */
+ if(checkprefix("NTLM", start)) {
+ *availp |= CURLAUTH_NTLM;
+ authp->avail |= CURLAUTH_NTLM;
+ if(authp->picked == CURLAUTH_NTLM) {
+ /* NTLM authentication is picked and activated */
+ CURLntlm ntlm =
+ Curl_input_ntlm(conn, (bool)(httpcode == 407), start);
+
+ if(CURLNTLM_BAD != ntlm)
+ data->state.authproblem = FALSE;
+ else {
+ infof(data, "Authentication problem. Ignoring this.\n");
+ data->state.authproblem = TRUE;
+ }
+ }
+ }
+ else
+#endif
+ if(checkprefix("Digest", start)) {
+ CURLdigest dig;
+ *availp |= CURLAUTH_DIGEST;
+ authp->avail |= CURLAUTH_DIGEST;
+
+ /* We call this function on input Digest headers even if Digest
+ * authentication isn't activated yet, as we need to store the
+ * incoming data from this header in case we are gonna use Digest. */
+ dig = Curl_input_digest(conn, (bool)(httpcode == 407), start);
+
+ if(CURLDIGEST_FINE != dig) {
+ infof(data, "Authentication problem. Ignoring this.\n");
+ data->state.authproblem = TRUE;
+ }
+ }
+ else if(checkprefix("Basic", start)) {
+ *availp |= CURLAUTH_BASIC;
+ authp->avail |= CURLAUTH_BASIC;
+ if(authp->picked == CURLAUTH_BASIC) {
+ /* We asked for Basic authentication but got a 40X back
+ anyway, which basicly means our name+password isn't
+ valid. */
+ authp->avail = CURLAUTH_NONE;
+ infof(data, "Authentication problem. Ignoring this.\n");
+ data->state.authproblem = TRUE;
+ }
+ }
+
+ return CURLE_OK;
+}
+
+/**
+ * Curl_http_should_fail() determines whether an HTTP response has gotten us
+ * into an error state or not.
+ *
+ * @param conn all information about the current connection
+ *
+ * @retval 0 communications should continue
+ *
+ * @retval 1 communications should not continue
+ */
+int Curl_http_should_fail(struct connectdata *conn)
+{
+ struct SessionHandle *data;
+ struct Curl_transfer_keeper *k;
+
+ curlassert(conn);
+ data = conn->data;
+ curlassert(data);
+
+ /*
+ ** For readability
+ */
+ k = &conn->keep;
+
+ /*
+ ** If we haven't been asked to fail on error,
+ ** don't fail.
+ */
+ if (!data->set.http_fail_on_error)
+ return 0;
+
+ /*
+ ** Any code < 400 is never terminal.
+ */
+ if (k->httpcode < 400)
+ return 0;
+
+ /*
+ ** Any code >= 400 that's not 401 or 407 is always
+ ** a terminal error
+ */
+ if ((k->httpcode != 401) &&
+ (k->httpcode != 407))
+ return 1;
+
+ /*
+ ** All we have left to deal with is 401 and 407
+ */
+ curlassert((k->httpcode == 401) || (k->httpcode == 407));
+
+ /*
+ ** Examine the current authentication state to see if this
+ ** is an error. The idea is for this function to get
+ ** called after processing all the headers in a response
+ ** message. So, if we've been to asked to authenticate a
+ ** particular stage, and we've done it, we're OK. But, if
+ ** we're already completely authenticated, it's not OK to
+ ** get another 401 or 407.
+ **
+ ** It is possible for authentication to go stale such that
+ ** the client needs to reauthenticate. Once that info is
+ ** available, use it here.
+ */
+#if 0 /* set to 1 when debugging this functionality */
+ infof(data,"%s: authstage = %d\n",__FUNCTION__,data->state.authstage);
+ infof(data,"%s: authwant = 0x%08x\n",__FUNCTION__,data->state.authwant);
+ infof(data,"%s: authavail = 0x%08x\n",__FUNCTION__,data->state.authavail);
+ infof(data,"%s: httpcode = %d\n",__FUNCTION__,k->httpcode);
+ infof(data,"%s: authdone = %d\n",__FUNCTION__,data->state.authdone);
+ infof(data,"%s: newurl = %s\n",__FUNCTION__,conn->newurl ? conn->newurl : "(null)");
+ infof(data,"%s: authproblem = %d\n",__FUNCTION__,data->state.authproblem);
#endif
-/* fread() emulation to provide POST and/or request data */
-static int readmoredata(char *buffer,
- size_t size,
- size_t nitems,
- void *userp)
+ /*
+ ** Either we're not authenticating, or we're supposed to
+ ** be authenticating something else. This is an error.
+ */
+ if((k->httpcode == 401) && !conn->bits.user_passwd)
+ return TRUE;
+ if((k->httpcode == 407) && !conn->bits.proxy_user_passwd)
+ return TRUE;
+
+ return data->state.authproblem;
+}
+
+/*
+ * readmoredata() is a "fread() emulation" to provide POST and/or request
+ * data. It is used when a huge POST is to be made and the entire chunk wasn't
+ * sent in the first send(). This function will then be called from the
+ * transfer.c loop when more data is to be sent to the peer.
+ *
+ * Returns the amount of bytes it filled the buffer with.
+ */
+static size_t readmoredata(char *buffer,
+ size_t size,
+ size_t nitems,
+ void *userp)
{
struct connectdata *conn = (struct connectdata *)userp;
struct HTTP *http = conn->proto.http;
- int fullsize = (int)(size * nitems);
+ size_t fullsize = size * nitems;
if(0 == http->postsize)
/* nothing to return */
return 0;
-
+
/* make sure that a HTTP request is never sent away chunked! */
- conn->bits.forbidchunk=(bool)((http->sending==HTTPSEND_REQUEST)?TRUE:FALSE);
+ conn->bits.forbidchunk= (http->sending == HTTPSEND_REQUEST)?TRUE:FALSE;
- if(http->postsize <= fullsize) {
- memcpy(buffer, http->postdata, http->postsize);
- fullsize = http->postsize;
+ if(http->postsize <= (curl_off_t)fullsize) {
+ memcpy(buffer, http->postdata, (size_t)http->postsize);
+ fullsize = (size_t)http->postsize;
if(http->backup.postsize) {
/* move backup data into focus and continue on that */
@@ -161,7 +671,7 @@ static CURLcode
add_buffer(send_buffer *in, const void *inptr, size_t size);
/*
- * add_buffer_init() returns a fine buffer struct
+ * add_buffer_init() sets up and returns a fine buffer struct
*/
static
send_buffer *add_buffer_init(void)
@@ -177,10 +687,11 @@ send_buffer *add_buffer_init(void)
/*
* add_buffer_send() sends a buffer and frees all associated memory.
+ *
+ * Returns CURLcode
*/
static
CURLcode add_buffer_send(send_buffer *in,
- int sockfd,
struct connectdata *conn,
long *bytes_written) /* add the number of sent
bytes to this counter */
@@ -188,33 +699,58 @@ CURLcode add_buffer_send(send_buffer *in,
ssize_t amount;
CURLcode res;
char *ptr;
- int size;
+ size_t size;
struct HTTP *http = conn->proto.http;
+ size_t sendsize;
+ curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
/* The looping below is required since we use non-blocking sockets, but due
to the circumstances we will just loop and try again and again etc */
ptr = in->buffer;
- size = (int)in->size_used;
+ size = in->size_used;
- res = Curl_write(conn, sockfd, ptr, size, &amount);
+ if(conn->protocol & PROT_HTTPS) {
+ /* We never send more than CURL_MAX_WRITE_SIZE bytes in one single chunk
+ when we speak HTTPS, as if only a fraction of it is sent now, this data
+ needs to fit into the normal read-callback buffer later on and that
+ buffer is using this size.
+ */
+
+ sendsize= (size > CURL_MAX_WRITE_SIZE)?CURL_MAX_WRITE_SIZE:size;
+
+ /* OpenSSL is very picky and we must send the SAME buffer pointer to the
+ library when we attempt to re-send this buffer. Sending the same data
+ is not enough, we must use the exact same address. For this reason, we
+ must copy the data to the uploadbuffer first, since that is the buffer
+ we will be using if this send is retried later.
+ */
+ memcpy(conn->data->state.uploadbuffer, ptr, sendsize);
+ ptr = conn->data->state.uploadbuffer;
+ }
+ else
+ sendsize = size;
+
+ res = Curl_write(conn, sockfd, ptr, sendsize, &amount);
if(CURLE_OK == res) {
if(conn->data->set.verbose)
/* this data _may_ contain binary stuff */
- Curl_debug(conn->data, CURLINFO_HEADER_OUT, ptr, amount);
+ Curl_debug(conn->data, CURLINFO_HEADER_OUT, ptr, amount,
+ conn->host.dispname);
*bytes_written += amount;
-
- if(amount != size) {
+
+ if((size_t)amount != size) {
/* The whole request could not be sent in one system call. We must queue
it up and send it later when we get the chance. We must not loop here
and wait until it might work again. */
size -= amount;
- ptr += amount;
-
+
+ ptr = in->buffer + amount;
+
/* backup the currently set pointers */
http->backup.fread = conn->fread;
http->backup.fread_in = conn->fread_in;
@@ -225,14 +761,14 @@ CURLcode add_buffer_send(send_buffer *in,
conn->fread = (curl_read_callback)readmoredata;
conn->fread_in = (void *)conn;
http->postdata = ptr;
- http->postsize = size;
+ http->postsize = (curl_off_t)size;
http->send_buffer = in;
http->sending = HTTPSEND_REQUEST;
-
+
return CURLE_OK;
}
-
+ http->sending = HTTPSEND_BODY;
/* the full buffer was sent, clean up and return */
}
if(in->buffer)
@@ -243,13 +779,12 @@ CURLcode add_buffer_send(send_buffer *in,
}
-/*
- * add_bufferf() builds a buffer from the formatted input
+/*
+ * add_bufferf() add the formatted input to the buffer.
*/
static
CURLcode add_bufferf(send_buffer *in, const char *fmt, ...)
{
- CURLcode result = CURLE_OUT_OF_MEMORY;
char *s;
va_list ap;
va_start(ap, fmt);
@@ -257,24 +792,30 @@ CURLcode add_bufferf(send_buffer *in, const char *fmt, ...)
va_end(ap);
if(s) {
- result = add_buffer(in, s, strlen(s));
+ CURLcode result = add_buffer(in, s, strlen(s));
free(s);
+ if(CURLE_OK == result)
+ return CURLE_OK;
}
- return result;
+ /* If we failed, we cleanup the whole buffer and return error */
+ if(in->buffer)
+ free(in->buffer);
+ free(in);
+ return CURLE_OUT_OF_MEMORY;
}
/*
- * add_buffer() appends a memory chunk to the existing one
+ * add_buffer() appends a memory chunk to the existing buffer
*/
static
CURLcode add_buffer(send_buffer *in, const void *inptr, size_t size)
{
char *new_rb;
- int new_size;
+ size_t new_size;
if(!in->buffer ||
((in->size_used + size) > (in->size_max - 1))) {
- new_size = (int)((in->size_used+size)*2);
+ new_size = (in->size_used+size)*2;
if(in->buffer)
/* we have a buffer, enlarge the existing one */
new_rb = (char *)realloc(in->buffer, new_size);
@@ -289,7 +830,7 @@ CURLcode add_buffer(send_buffer *in, const void *inptr, size_t size)
in->size_max = new_size;
}
memcpy(&in->buffer[in->size_used], inptr, size);
-
+
in->size_used += size;
return CURLE_OK;
@@ -354,47 +895,34 @@ Curl_compareheader(char *headerline, /* line to check */
}
/*
- * This function checks the linked list of custom HTTP headers for a particular
- * header (prefix).
- */
-static char *checkheaders(struct SessionHandle *data, const char *thisheader)
-{
- struct curl_slist *head;
- size_t thislen = strlen(thisheader);
-
- for(head = data->set.headers; head; head=head->next) {
- if(strnequal(head->data, thisheader, thislen))
- return head->data;
- }
- return NULL;
-}
-
-/*
* ConnectHTTPProxyTunnel() requires that we're connected to a HTTP proxy. This
* function will issue the necessary commands to get a seamless tunnel through
* this proxy. After that, the socket can be used just as a normal socket.
*/
CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn,
- int tunnelsocket,
- char *hostname, int remote_port)
+ int sockindex,
+ char *hostname,
+ int remote_port)
{
- int httperror=0;
int subversion=0;
struct SessionHandle *data=conn->data;
+ struct Curl_transfer_keeper *k = &conn->keep;
CURLcode result;
int res;
- int nread; /* total size read */
+ size_t nread; /* total size read */
int perline; /* count bytes per line */
bool keepon=TRUE;
ssize_t gotbytes;
char *ptr;
- int timeout = 3600; /* default timeout in seconds */
+ long timeout = 3600; /* default timeout in seconds */
struct timeval interval;
fd_set rkeepfd;
fd_set readfd;
char *line_start;
+ char *host_port;
+ curl_socket_t tunnelsocket = conn->sock[sockindex];
#define SELECT_OK 0
#define SELECT_ERROR 1
@@ -403,137 +931,200 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn,
infof(data, "Establish HTTP proxy tunnel to %s:%d\n", hostname, remote_port);
- /* OK, now send the connect request to the proxy */
- result =
- Curl_sendf(tunnelsocket, conn,
- "CONNECT %s:%d HTTP/1.0\015\012"
- "%s"
- "%s"
- "\r\n",
- hostname, remote_port,
- (conn->bits.proxy_user_passwd)?conn->allocptr.proxyuserpwd:"",
- (data->set.useragent?conn->allocptr.uagent:"")
- );
- if(result) {
- failf(data, "Failed sending CONNECT to proxy");
- return result;
- }
-
- /* Now, read the full reply we get from the proxy */
-
-
- if(data->set.timeout) {
- /* if timeout is requested, find out how much remaining time we have */
- timeout = data->set.timeout - /* timeout time */
- Curl_tvdiff(Curl_tvnow(), conn->now)/1000; /* spent time */
- if(timeout <=0 ) {
- failf(data, "Transfer aborted due to timeout");
- return (CURLcode)-SELECT_TIMEOUT; /* already too little time */
+ do {
+ if(conn->newurl) {
+ /* This only happens if we've looped here due to authentication reasons,
+ and we don't really use the newly cloned URL here then. Just free()
+ it. */
+ free(conn->newurl);
+ conn->newurl = NULL;
}
- }
-
- FD_ZERO (&readfd); /* clear it */
- FD_SET (tunnelsocket, &readfd); /* read socket */
- /* get this in a backup variable to be able to restore it on each lap in the
- select() loop */
- rkeepfd = readfd;
-
- ptr=data->state.buffer;
- line_start = ptr;
-
- nread=0;
- perline=0;
- keepon=TRUE;
+ host_port = aprintf("%s:%d", hostname, remote_port);
+ if(!host_port)
+ return CURLE_OUT_OF_MEMORY;
- while((nread<BUFSIZE) && (keepon && !error)) {
- readfd = rkeepfd; /* set every lap */
- interval.tv_sec = timeout;
- interval.tv_usec = 0;
+ /* Setup the proxy-authorization header, if any */
+ result = Curl_http_output_auth(conn, (char *)"CONNECT", host_port, TRUE);
+ if(CURLE_OK == result) {
+
+ /* OK, now send the connect request to the proxy */
+ result =
+ Curl_sendf(tunnelsocket, conn,
+ "CONNECT %s:%d HTTP/1.0\015\012"
+ "%s"
+ "%s"
+ "\r\n",
+ hostname, remote_port,
+ conn->bits.proxy_user_passwd?
+ conn->allocptr.proxyuserpwd:"",
+ data->set.useragent?conn->allocptr.uagent:""
+ );
+ if(result)
+ failf(data, "Failed sending CONNECT to proxy");
+ }
+ free(host_port);
+ if(result)
+ return result;
- switch (select (tunnelsocket+1, &readfd, NULL, NULL, &interval)) {
- case -1: /* select() error, stop reading */
- error = SELECT_ERROR;
- failf(data, "Transfer aborted due to select() error");
- break;
- case 0: /* timeout */
- error = SELECT_TIMEOUT;
- failf(data, "Transfer aborted due to timeout");
- break;
- default:
- /*
- * This code previously didn't use the kerberos sec_read() code
- * to read, but when we use Curl_read() it may do so. Do confirm
- * that this is still ok and then remove this comment!
- */
- res= Curl_read(conn, tunnelsocket, ptr, BUFSIZE-nread,
- &gotbytes);
- if(res< 0)
- /* EWOULDBLOCK */
- continue; /* go loop yourself */
- else if(res)
- keepon = FALSE;
- else if(gotbytes <= 0) {
- keepon = FALSE;
- error = SELECT_ERROR;
- failf(data, "Connection aborted");
+ FD_ZERO (&readfd); /* clear it */
+ FD_SET (tunnelsocket, &readfd); /* read socket */
+
+ /* get this in a backup variable to be able to restore it on each lap in
+ the select() loop */
+ rkeepfd = readfd;
+
+ ptr=data->state.buffer;
+ line_start = ptr;
+
+ nread=0;
+ perline=0;
+ keepon=TRUE;
+
+ while((nread<BUFSIZE) && (keepon && !error)) {
+ readfd = rkeepfd; /* set every lap */
+ interval.tv_sec = 1; /* timeout each second and check the timeout */
+ interval.tv_usec = 0;
+
+ if(data->set.timeout) {
+ /* if timeout is requested, find out how much remaining time we have */
+ timeout = data->set.timeout - /* timeout time */
+ Curl_tvdiff(Curl_tvnow(), conn->now)/1000; /* spent time */
+ if(timeout <=0 ) {
+ failf(data, "Proxy connection aborted due to timeout");
+ error = SELECT_TIMEOUT; /* already too little time */
+ break;
+ }
}
- else {
- /* we got a whole chunk of data, which can be anything from one
- * byte to a set of lines and possibly just a piece of the last
- * line */
- int i;
-
- nread += gotbytes;
- for(i = 0; i < gotbytes; ptr++, i++) {
- perline++; /* amount of bytes in this line so far */
- if(*ptr=='\n') {
- /* a newline is CRLF in ftp-talk, so the CR is ignored as
- the line isn't really terminated until the LF comes */
-
- /* output debug output if that is requested */
- if(data->set.verbose)
- Curl_debug(data, CURLINFO_DATA_IN, line_start, perline);
-
- if('\r' == line_start[0]) {
- /* end of headers */
- keepon=FALSE;
- break; /* breaks out of loop, not switch */
- }
- if(2 == sscanf(line_start, "HTTP/1.%d %d",
- &subversion,
- &httperror)) {
- ;
+ switch (select (tunnelsocket+1, &readfd, NULL, NULL, &interval)) {
+ case -1: /* select() error, stop reading */
+ error = SELECT_ERROR;
+ failf(data, "Proxy CONNECT aborted due to select() error");
+ break;
+ case 0: /* timeout */
+ break;
+ default:
+ /*
+ * This code previously didn't use the kerberos sec_read() code
+ * to read, but when we use Curl_read() it may do so. Do confirm
+ * that this is still ok and then remove this comment!
+ */
+ res= Curl_read(conn, tunnelsocket, ptr, BUFSIZE-nread, &gotbytes);
+ if(res< 0)
+ /* EWOULDBLOCK */
+ continue; /* go loop yourself */
+ else if(res)
+ keepon = FALSE;
+ else if(gotbytes <= 0) {
+ keepon = FALSE;
+ error = SELECT_ERROR;
+ failf(data, "Proxy CONNECT aborted");
+ }
+ else {
+ /*
+ * We got a whole chunk of data, which can be anything from one byte
+ * to a set of lines and possibly just a piece of the last line.
+ *
+ * TODO: To make this code work less error-prone, we need to make
+ * sure that we read and create full lines before we compare them,
+ * as there is really nothing that stops the proxy from delivering
+ * the response lines in multiple parts, each part consisting of
+ * only a little piece of the line(s). */
+ int i;
+
+ nread += gotbytes;
+ for(i = 0; i < gotbytes; ptr++, i++) {
+ perline++; /* amount of bytes in this line so far */
+ if(*ptr=='\n') {
+ char letter;
+ int writetype;
+
+ /* output debug output if that is requested */
+ if(data->set.verbose)
+ Curl_debug(data, CURLINFO_HEADER_IN, line_start, perline,
+ conn->host.dispname);
+
+ /* send the header to the callback */
+ writetype = CLIENTWRITE_HEADER;
+ if(data->set.include_header)
+ writetype |= CLIENTWRITE_BODY;
+
+ result = Curl_client_write(data, writetype, line_start, perline);
+ if(result)
+ return result;
+
+ /* 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])) {
+ /* end of response-headers from the proxy */
+ keepon=FALSE;
+ break; /* breaks out of for-loop, not switch() */
+ }
+
+ /* keep a backup of the position we are about to blank */
+ letter = line_start[perline];
+ line_start[perline]=0; /* zero terminate the buffer */
+ if((checkprefix("WWW-Authenticate:", line_start) &&
+ (401 == k->httpcode)) ||
+ (checkprefix("Proxy-authenticate:", line_start) &&
+ (407 == k->httpcode))) {
+ result = Curl_http_input_auth(conn, k->httpcode, line_start);
+ if(result)
+ return result;
+ }
+ else if(2 == sscanf(line_start, "HTTP/1.%d %d",
+ &subversion,
+ &k->httpcode)) {
+ /* store the HTTP code from the proxy */
+ data->info.httpproxycode = k->httpcode;
+ }
+ /* put back the letter we blanked out before */
+ line_start[perline]= letter;
+
+ perline=0; /* line starts over here */
+ line_start = ptr+1; /* this skips the zero byte we wrote */
}
-
- perline=0; /* line starts over here */
- line_start = ptr+1;
}
}
- }
- break;
- } /* switch */
- } /* while there's buffer left and loop is requested */
+ break;
+ } /* switch */
+ } /* while there's buffer left and loop is requested */
- if(error)
- return CURLE_RECV_ERROR;
+ if(error)
+ return CURLE_RECV_ERROR;
+
+ if(data->info.httpproxycode != 200)
+ /* Deal with the possibly already received authenticate
+ headers. 'newurl' is set to a new URL if we must loop. */
+ Curl_http_auth_act(conn);
- if(200 != httperror) {
- if(407 == httperror)
- /* Added Nov 6 1998 */
- failf(data, "Proxy requires authorization!");
- else
- failf(data, "Received error code %d from proxy", httperror);
+ } while(conn->newurl);
+
+ if(200 != k->httpcode) {
+ failf(data, "Received HTTP code %d from proxy after CONNECT",
+ k->httpcode);
return CURLE_RECV_ERROR;
}
- infof (data, "Proxy replied to CONNECT request\n");
+ /* 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
+ after we've connected. So let's free and clear it here. */
+ Curl_safefree(conn->allocptr.proxyuserpwd);
+ conn->allocptr.proxyuserpwd = NULL;
+
+ data->state.authproxy.done = TRUE;
+
+ infof (data, "Proxy replied OK to CONNECT request\n");
return CURLE_OK;
}
/*
- * HTTP stuff to do at connect-time.
+ * Curl_http_connect() performs HTTP stuff to do at connect-time, called from
+ * the generic Curl_connect().
*/
CURLcode Curl_http_connect(struct connectdata *conn)
{
@@ -542,26 +1133,25 @@ CURLcode Curl_http_connect(struct connectdata *conn)
data=conn->data;
- /* If we are not using a proxy and we want a secure connection,
- * perform SSL initialization & connection now.
- * If using a proxy with https, then we must tell the proxy to CONNECT
- * us to the host we want to talk to. Only after the connect
- * has occured, can we start talking SSL
+ /* If we are not using a proxy and we want a secure connection, perform SSL
+ * initialization & connection now. If using a proxy with https, then we
+ * must tell the proxy to CONNECT to the host we want to talk to. Only
+ * after the connect has occured, can we start talking SSL
*/
- if(conn->bits.httpproxy &&
- ((conn->protocol & PROT_HTTPS) || data->set.tunnel_thru_httpproxy)) {
+ if(conn->bits.tunnel_proxy) {
- /* either HTTPS over proxy, OR explicitly asked for a tunnel */
- result = Curl_ConnectHTTPProxyTunnel(conn, conn->firstsocket,
- conn->hostname, conn->remote_port);
+ /* either SSL over proxy, or explicitly asked for */
+ result = Curl_ConnectHTTPProxyTunnel(conn, FIRSTSOCKET,
+ conn->host.name,
+ conn->remote_port);
if(CURLE_OK != result)
return result;
- }
+ }
if(conn->protocol & PROT_HTTPS) {
/* now, perform the SSL initialization for this socket */
- result = Curl_SSLConnect(conn);
+ result = Curl_SSLConnect(conn, FIRSTSOCKET);
if(result)
return result;
}
@@ -573,16 +1163,23 @@ CURLcode Curl_http_connect(struct connectdata *conn)
/* Free to avoid leaking memory on multiple requests*/
free(data->state.auth_host);
- data->state.auth_host = strdup(conn->hostname);
+ data->state.auth_host = strdup(conn->host.name);
}
return CURLE_OK;
}
-CURLcode Curl_http_done(struct connectdata *conn)
+/*
+ * Curl_http_done() gets called from Curl_done() after a single HTTP request
+ * has been performed.
+ */
+
+CURLcode Curl_http_done(struct connectdata *conn,
+ CURLcode status)
{
struct SessionHandle *data;
struct HTTP *http;
+ (void)status; /* no use for us */
data=conn->data;
http=conn->proto.http;
@@ -591,24 +1188,32 @@ CURLcode Curl_http_done(struct connectdata *conn)
conn->fread = data->set.fread; /* restore */
conn->fread_in = data->set.in; /* restore */
+ if (http == NULL)
+ return CURLE_OK;
+
if(http->send_buffer) {
send_buffer *buff = http->send_buffer;
-
+
free(buff->buffer);
free(buff);
+ http->send_buffer = NULL; /* cleaer the pointer */
}
if(HTTPREQ_POST_FORM == data->set.httpreq) {
conn->bytecount = http->readbytecount + http->writebytecount;
-
+
Curl_formclean(http->sendit); /* Now free that whole lot */
}
else if(HTTPREQ_PUT == data->set.httpreq)
conn->bytecount = http->readbytecount + http->writebytecount;
- if(0 == (http->readbytecount + conn->headerbytecount)) {
- /* nothing was read from the HTTP server, this can't be right
- so we return an error here */
+ if(!conn->bits.retry &&
+ ((http->readbytecount +
+ conn->headerbytecount -
+ conn->deductheadercount)) <= 0) {
+ /* If this connection isn't simply closed to be retried, AND nothing was
+ read from the HTTP server (that counts), this can't be right so we
+ return an error here */
failf(data, "Empty reply from server");
return CURLE_GOT_NOTHING;
}
@@ -616,16 +1221,24 @@ CURLcode Curl_http_done(struct connectdata *conn)
return CURLE_OK;
}
+/*
+ * Curl_http() gets called from the generic Curl_do() function when a HTTP
+ * request is to be performed. This creates and sends a properly constructed
+ * HTTP request.
+ */
CURLcode Curl_http(struct connectdata *conn)
{
struct SessionHandle *data=conn->data;
char *buf = data->state.buffer; /* this is a short cut to the buffer */
CURLcode result=CURLE_OK;
struct HTTP *http;
- struct Cookie *co=NULL; /* no cookies from start */
- char *ppath = conn->ppath; /* three previous function arguments */
- char *host = conn->name;
+ char *ppath = conn->path;
+ char *host = conn->host.name;
const char *te = ""; /* tranfer-encoding */
+ char *ptr;
+ char *request;
+ Curl_HttpReq httpreq = data->set.httpreq;
+ char *addcookies = NULL;
if(!conn->proto.http) {
/* Only allocate this struct if we don't already have it! */
@@ -644,62 +1257,85 @@ CURLcode Curl_http(struct connectdata *conn)
if ( (conn->protocol&(PROT_HTTP|PROT_FTP)) &&
data->set.upload) {
- data->set.httpreq = HTTPREQ_PUT;
+ httpreq = HTTPREQ_PUT;
+ }
+
+ /* Now set the 'request' pointer to the proper request string */
+ if(data->set.customrequest)
+ request = data->set.customrequest;
+ else {
+ if(conn->bits.no_body)
+ request = (char *)"HEAD";
+ else {
+ curlassert((httpreq > HTTPREQ_NONE) && (httpreq < HTTPREQ_LAST));
+ switch(httpreq) {
+ case HTTPREQ_POST:
+ case HTTPREQ_POST_FORM:
+ request = (char *)"POST";
+ break;
+ case HTTPREQ_PUT:
+ request = (char *)"PUT";
+ break;
+ default: /* this should never happen */
+ case HTTPREQ_GET:
+ request = (char *)"GET";
+ break;
+ case HTTPREQ_HEAD:
+ request = (char *)"HEAD";
+ break;
+ }
+ }
}
-
- /* The User-Agent string has been built in url.c already, because it might
- have been used in the proxy connect, but if we have got a header with
- the user-agent string specified, we erase the previously made string
+
+ /* The User-Agent string might have been allocated in url.c already, because
+ it might have been used in the proxy connect, but if we have got a header
+ with the user-agent string specified, we erase the previously made string
here. */
if(checkheaders(data, "User-Agent:") && conn->allocptr.uagent) {
free(conn->allocptr.uagent);
conn->allocptr.uagent=NULL;
}
- if((conn->bits.user_passwd) && !checkheaders(data, "Authorization:")) {
- char *authorization;
-
- /* To prevent the user+password to get sent to other than the original
- host due to a location-follow, we do some weirdo checks here */
- if(!data->state.this_is_a_follow ||
- !data->state.auth_host ||
- curl_strequal(data->state.auth_host, conn->hostname)) {
- sprintf(data->state.buffer, "%s:%s",
- data->state.user, data->state.passwd);
- if(Curl_base64_encode(data->state.buffer,
- (int)strlen(data->state.buffer),
- &authorization) >= 0) {
- if(conn->allocptr.userpwd)
- free(conn->allocptr.userpwd);
- conn->allocptr.userpwd = aprintf( "Authorization: Basic %s\015\012",
- authorization);
- free(authorization);
- }
- }
+ /* setup the authentication headers */
+ result = Curl_http_output_auth(conn, request, ppath, FALSE);
+ if(result)
+ return result;
+
+ if((!data->state.authhost.done || !data->state.authproxy.done ) &&
+ (httpreq != HTTPREQ_GET)) {
+ /* Until we are authenticated, we switch over to HEAD. Unless its a GET
+ we want to do. The explanation for this is rather long and boring, but
+ the point is that it can't be done otherwise without risking having to
+ send the POST or PUT data multiple times. */
+ httpreq = HTTPREQ_HEAD;
+ request = (char *)"HEAD";
+ conn->bits.no_body = TRUE;
+ conn->bits.authprobe = TRUE; /* this is a request done to probe for
+ authentication methods */
}
- if((data->change.referer) && !checkheaders(data, "Referer:")) {
- if(conn->allocptr.ref)
- free(conn->allocptr.ref);
+ else
+ conn->bits.authprobe = FALSE;
+
+ Curl_safefree(conn->allocptr.ref);
+ if(data->change.referer && !checkheaders(data, "Referer:"))
conn->allocptr.ref = aprintf("Referer: %s\015\012", data->change.referer);
- }
- if(data->set.cookie && !checkheaders(data, "Cookie:")) {
- if(conn->allocptr.cookie)
- free(conn->allocptr.cookie);
- conn->allocptr.cookie = aprintf("Cookie: %s\015\012", data->set.cookie);
- }
+ else
+ conn->allocptr.ref = NULL;
- if(!conn->bits.upload_chunky && (data->set.httpreq != HTTPREQ_GET)) {
- /* not a chunky transfer but data is to be sent */
- char *ptr = checkheaders(data, "Transfer-Encoding:");
+ if(data->set.cookie && !checkheaders(data, "Cookie:"))
+ addcookies = data->set.cookie;
+
+ if(!conn->bits.upload_chunky && (httpreq != HTTPREQ_GET)) {
+ /* not a chunky transfer yet, but data is to be sent */
+ ptr = checkheaders(data, "Transfer-Encoding:");
if(ptr) {
/* Some kind of TE is requested, check if 'chunked' is chosen */
- if(Curl_compareheader(ptr, "Transfer-Encoding:", "chunked"))
- /* we have been told explicitly to upload chunky so deal with it! */
- conn->bits.upload_chunky = TRUE;
+ conn->bits.upload_chunky =
+ Curl_compareheader(ptr, "Transfer-Encoding:", "chunked");
+ te = "";
}
}
-
- if(conn->bits.upload_chunky) {
+ else if(conn->bits.upload_chunky) {
/* RFC2616 section 4.4:
Messages MUST NOT include both a Content-Length header field and a
non-identity transfer-coding. If the message does include a non-
@@ -709,46 +1345,44 @@ CURLcode Curl_http(struct connectdata *conn)
te = "Transfer-Encoding: chunked\r\n";
}
else {
- /* The "Transfer-Encoding:" header was already added. */
te = "";
+ conn->bits.upload_chunky = FALSE; /* transfer-encoding was disabled,
+ so don't chunkify this! */
}
}
- if(data->cookies) {
- co = Curl_cookie_getlist(data->cookies,
- host, ppath,
- (bool)(conn->protocol&PROT_HTTPS?TRUE:FALSE));
- }
- if (data->change.proxy && *data->change.proxy &&
- !data->set.tunnel_thru_httpproxy &&
- !(conn->protocol&PROT_HTTPS)) {
- /* The path sent to the proxy is in fact the entire URL */
- ppath = data->change.url;
- }
- if(HTTPREQ_POST_FORM == data->set.httpreq) {
- /* we must build the whole darned post sequence first, so that we have
- a size of the whole shebang before we start to send it */
- result = Curl_getFormData(&http->sendit, data->set.httppost,
- &http->postsize);
- if(CURLE_OK != result) {
- /* Curl_getFormData() doesn't use failf() */
- failf(data, "failed creating formpost data");
- return result;
- }
- }
-
- if(!checkheaders(data, "Host:")) {
- /* if ptr_host is already set, it is almost OK since we only re-use
- connections to the very same host and port, but when we use a HTTP
- proxy we have a persistant connect and yet we must change the Host:
- header! */
-
- if(conn->allocptr.host)
- free(conn->allocptr.host);
+ Curl_safefree(conn->allocptr.host);
+
+ ptr = checkheaders(data, "Host:");
+ if(ptr && !data->state.this_is_a_follow) {
+ /* If we have a given custom Host: header, we extract the host name in
+ order to possibly use it for cookie reasons later on. We only allow the
+ custom Host: header if this is NOT a redirect, as setting Host: in the
+ redirected request is being out on thin ice. */
+ char *start = ptr+strlen("Host:");
+ while(*start && isspace((int)*start ))
+ start++;
+ ptr = start; /* start host-scanning here */
+
+ /* scan through the string to find the end (space or colon) */
+ while(*ptr && !isspace((int)*ptr) && !(':'==*ptr))
+ ptr++;
+
+ if(ptr != start) {
+ size_t len=ptr-start;
+ conn->allocptr.cookiehost = malloc(len+1);
+ if(!conn->allocptr.cookiehost)
+ return CURLE_OUT_OF_MEMORY;
+ memcpy(conn->allocptr.cookiehost, start, len);
+ conn->allocptr.cookiehost[len]=0;
+ }
+ conn->allocptr.host = NULL;
+ }
+ else {
/* When building Host: headers, we must put the host name within
[brackets] if the host name is a plain IPv6-address. RFC2732-style. */
-
+
if(((conn->protocol&PROT_HTTPS) && (conn->remote_port == PORT_HTTPS)) ||
(!(conn->protocol&PROT_HTTPS) && (conn->remote_port == PORT_HTTP)) )
/* If (HTTPS on port 443) OR (non-HTTPS on port 80) then don't include
@@ -763,17 +1397,76 @@ CURLcode Curl_http(struct connectdata *conn)
host,
conn->bits.ipv6_ip?"]":"",
conn->remote_port);
+
+ if(!conn->allocptr.host)
+ /* without Host: we can't make a nice request */
+ return CURLE_OUT_OF_MEMORY;
}
+ 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
+ host is a IDN-name, we must make sure that the request we produce only
+ uses the encoded host name! */
+ if(conn->host.dispname != conn->host.name) {
+ char *url = data->change.url;
+ char *ptr = strstr(url, conn->host.dispname);
+ if(ptr) {
+ /* This is where the display name starts in the URL, now replace this
+ part with the encoded name. TODO: This method of replacing the host
+ name is rather crude as I believe there's a slight risk that the
+ user has entered a user name or password that contain the host name
+ string. */
+ size_t currlen = strlen(conn->host.dispname);
+ size_t newlen = strlen(conn->host.name);
+ size_t urllen = strlen(url);
+
+ char *newurl;
+
+ newurl = malloc(urllen + newlen - currlen + 1);
+ if(newurl) {
+ /* copy the part before the host name */
+ memcpy(newurl, url, ptr - url);
+ /* append the new host name instead of the old */
+ memcpy(newurl + (ptr - url), conn->host.name, newlen);
+ /* append the piece after the host name */
+ memcpy(newurl + newlen + (ptr - url),
+ ptr + currlen, /* copy the trailing zero byte too */
+ urllen - (ptr-url) - currlen + 1);
+ if(data->change.url_alloc)
+ free(data->change.url);
+ data->change.url = newurl;
+ data->change.url_alloc = TRUE;
+ }
+ else
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+ ppath = data->change.url;
+ }
+ if(HTTPREQ_POST_FORM == httpreq) {
+ /* we must build the whole darned post sequence first, so that we have
+ a size of the whole shebang before we start to send it */
+ result = Curl_getFormData(&http->sendit, data->set.httppost,
+ &http->postsize);
+ if(CURLE_OK != result) {
+ /* Curl_getFormData() doesn't use failf() */
+ failf(data, "failed creating formpost data");
+ return result;
+ }
+ }
+
+
if(!checkheaders(data, "Pragma:"))
http->p_pragma = "Pragma: no-cache\r\n";
if(!checkheaders(data, "Accept:"))
- http->p_accept = "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*\r\n";
+ http->p_accept = "Accept: */*\r\n";
- if(( (HTTPREQ_POST == data->set.httpreq) ||
- (HTTPREQ_POST_FORM == data->set.httpreq) ||
- (HTTPREQ_PUT == data->set.httpreq) ) &&
+ if(( (HTTPREQ_POST == httpreq) ||
+ (HTTPREQ_POST_FORM == httpreq) ||
+ (HTTPREQ_PUT == httpreq) ) &&
conn->resume_from) {
/**********************************************************************
* Resuming upload in HTTP means that we PUT or POST and that we have
@@ -782,7 +1475,7 @@ CURLcode Curl_http(struct connectdata *conn)
* 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.
*********************************************************************/
-
+
if(conn->resume_from < 0 ) {
/*
* This is meant to get the size of the present remote-file by itself.
@@ -793,25 +1486,26 @@ CURLcode Curl_http(struct connectdata *conn)
if(conn->resume_from) {
/* do we still game? */
- int passed=0;
+ curl_off_t passed=0;
/* Now, let's read off the proper amount of bytes from the
input. If we knew it was a proper file we could've just
fseek()ed but we only have a stream here */
do {
- int readthisamountnow = (conn->resume_from - passed);
- int actuallyread;
+ size_t readthisamountnow = (size_t)(conn->resume_from - passed);
+ size_t actuallyread;
if(readthisamountnow > BUFSIZE)
readthisamountnow = BUFSIZE;
- actuallyread = (int)
- data->set.fread(data->state.buffer, 1, readthisamountnow,
+ actuallyread =
+ data->set.fread(data->state.buffer, 1, (size_t)readthisamountnow,
data->set.in);
passed += actuallyread;
if(actuallyread != readthisamountnow) {
- failf(data, "Could only read %d bytes from the input",
+ failf(data, "Could only read %" FORMAT_OFF_T
+ " bytes from the input",
passed);
return CURLE_READ_ERROR;
}
@@ -835,103 +1529,137 @@ CURLcode Curl_http(struct connectdata *conn)
* or uploading and we always let customized headers override our internal
* ones if any such are specified.
*/
- if((data->set.httpreq == HTTPREQ_GET) &&
+ if((httpreq == HTTPREQ_GET) &&
!checkheaders(data, "Range:")) {
/* if a line like this was already allocated, free the previous one */
if(conn->allocptr.rangeline)
free(conn->allocptr.rangeline);
conn->allocptr.rangeline = aprintf("Range: bytes=%s\r\n", conn->range);
}
- else if((data->set.httpreq != HTTPREQ_GET) &&
+ else if((httpreq != HTTPREQ_GET) &&
!checkheaders(data, "Content-Range:")) {
if(conn->resume_from) {
/* This is because "resume" was selected */
- long total_expected_size= conn->resume_from + data->set.infilesize;
- conn->allocptr.rangeline = aprintf("Content-Range: bytes %s%ld/%ld\r\n",
- conn->range, total_expected_size-1,
- total_expected_size);
+ curl_off_t total_expected_size=
+ conn->resume_from + data->set.infilesize;
+ conn->allocptr.rangeline =
+ aprintf("Content-Range: bytes %s%" FORMAT_OFF_T
+ "/%" FORMAT_OFF_T "\r\n",
+ conn->range, total_expected_size-1,
+ total_expected_size);
}
else {
- /* Range was selected and then we just pass the incoming range and
+ /* Range was selected and then we just pass the incoming range and
append total size */
- conn->allocptr.rangeline = aprintf("Content-Range: bytes %s/%d\r\n",
- conn->range, data->set.infilesize);
+ conn->allocptr.rangeline =
+ aprintf("Content-Range: bytes %s/%" FORMAT_OFF_T "\r\n",
+ conn->range, data->set.infilesize);
}
}
}
- do {
+ {
/* Use 1.1 unless the use specificly asked for 1.0 */
const char *httpstring=
data->set.httpversion==CURL_HTTP_VERSION_1_0?"1.0":"1.1";
send_buffer *req_buffer;
struct curl_slist *headers=data->set.headers;
+ curl_off_t postsize; /* off_t type to be able to hold a large file size */
/* initialize a dynamic send-buffer */
req_buffer = add_buffer_init();
+ if(!req_buffer)
+ return CURLE_OUT_OF_MEMORY;
+
/* add the main request stuff */
- add_bufferf(req_buffer,
- "%s " /* GET/HEAD/POST/PUT */
- "%s HTTP/%s\r\n" /* path */
- "%s" /* proxyuserpwd */
- "%s" /* userpwd */
- "%s" /* range */
- "%s" /* user agent */
- "%s" /* cookie */
- "%s" /* host */
- "%s" /* pragma */
- "%s" /* accept */
- "%s" /* accept-encoding */
- "%s" /* referer */
- "%s",/* transfer-encoding */
-
- data->set.customrequest?data->set.customrequest:
- (data->set.no_body?"HEAD":
- ((HTTPREQ_POST == data->set.httpreq) ||
- (HTTPREQ_POST_FORM == data->set.httpreq))?"POST":
- (HTTPREQ_PUT == data->set.httpreq)?"PUT":"GET"),
- ppath, httpstring,
- (conn->bits.proxy_user_passwd &&
- conn->allocptr.proxyuserpwd)?conn->allocptr.proxyuserpwd:"",
- (conn->bits.user_passwd && conn->allocptr.userpwd)?
- conn->allocptr.userpwd:"",
+ result =
+ add_bufferf(req_buffer,
+ "%s " /* GET/HEAD/POST/PUT */
+ "%s HTTP/%s\r\n" /* path + HTTP version */
+ "%s" /* proxyuserpwd */
+ "%s" /* userpwd */
+ "%s" /* range */
+ "%s" /* user agent */
+ "%s" /* host */
+ "%s" /* pragma */
+ "%s" /* accept */
+ "%s" /* accept-encoding */
+ "%s" /* referer */
+ "%s",/* transfer-encoding */
+
+ request,
+ ppath,
+ httpstring,
+ conn->allocptr.proxyuserpwd?
+ conn->allocptr.proxyuserpwd:"",
+ conn->allocptr.userpwd?conn->allocptr.userpwd:"",
(conn->bits.use_range && conn->allocptr.rangeline)?
conn->allocptr.rangeline:"",
(data->set.useragent && *data->set.useragent && conn->allocptr.uagent)?
conn->allocptr.uagent:"",
- (conn->allocptr.cookie?conn->allocptr.cookie:""), /* Cookie: <data> */
(conn->allocptr.host?conn->allocptr.host:""), /* Host: host */
http->p_pragma?http->p_pragma:"",
http->p_accept?http->p_accept:"",
(data->set.encoding && *data->set.encoding && conn->allocptr.accept_encoding)?
- conn->allocptr.accept_encoding:"", /* 08/28/02 jhrg */
- (data->change.referer && conn->allocptr.ref)?conn->allocptr.ref:"" /* Referer: <data> <CRLF> */,
+ conn->allocptr.accept_encoding:"",
+ (data->change.referer && conn->allocptr.ref)?conn->allocptr.ref:"" /* Referer: <data> */,
te
);
- if(co) {
+ if(result)
+ return result;
+
+ if(data->cookies || addcookies) {
+ struct Cookie *co=NULL; /* no cookies from start */
int count=0;
- struct Cookie *store=co;
- /* now loop through all cookies that matched */
- while(co) {
- if(co->value && strlen(co->value)) {
- if(0 == count) {
- add_bufferf(req_buffer, "Cookie: ");
+
+ if(data->cookies) {
+ Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
+ co = Curl_cookie_getlist(data->cookies,
+ conn->allocptr.cookiehost?
+ conn->allocptr.cookiehost:host, ppath,
+ (bool)(conn->protocol&PROT_HTTPS?TRUE:FALSE));
+ Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+ }
+ if(co) {
+ struct Cookie *store=co;
+ /* now loop through all cookies that matched */
+ while(co) {
+ if(co->value) {
+ if(0 == count) {
+ result = add_bufferf(req_buffer, "Cookie: ");
+ if(result)
+ break;
+ }
+ result = add_bufferf(req_buffer,
+ "%s%s=%s", count?"; ":"",
+ co->name, co->value);
+ if(result)
+ break;
+ count++;
}
- add_bufferf(req_buffer,
- "%s%s=%s", count?"; ":"", co->name, co->value);
- count++;
+ co = co->next; /* next cookie please */
}
- co = co->next; /* next cookie please */
+ Curl_cookie_freelist(store); /* free the cookie list */
}
- if(count) {
- add_buffer(req_buffer, "\r\n", 2);
+ if(addcookies && (CURLE_OK == result)) {
+ if(!count)
+ result = add_bufferf(req_buffer, "Cookie: ");
+ if(CURLE_OK == result) {
+ result = add_bufferf(req_buffer, "%s%s",
+ count?"; ":"",
+ addcookies);
+ count++;
+ }
}
- Curl_cookie_freelist(store); /* free the cookie list */
- co=NULL;
+ if(count && (CURLE_OK == result))
+ result = add_buffer(req_buffer, "\r\n", 2);
+
+ if(result)
+ return result;
}
if(data->set.timecondition) {
@@ -951,10 +1679,6 @@ CURLcode Curl_http(struct connectdata *conn)
#else
thistime = gmtime(&data->set.timevalue);
#endif
- if(NULL == thistime) {
- failf(data, "localtime() failed!");
- return CURLE_OUT_OF_MEMORY;
- }
#ifdef HAVE_STRFTIME
/* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
@@ -966,22 +1690,24 @@ CURLcode Curl_http(struct connectdata *conn)
switch(data->set.timecondition) {
case CURL_TIMECOND_IFMODSINCE:
default:
- add_bufferf(req_buffer,
- "If-Modified-Since: %s\r\n", buf);
+ result = add_bufferf(req_buffer,
+ "If-Modified-Since: %s\r\n", buf);
break;
case CURL_TIMECOND_IFUNMODSINCE:
- add_bufferf(req_buffer,
- "If-Unmodified-Since: %s\r\n", buf);
+ result = add_bufferf(req_buffer,
+ "If-Unmodified-Since: %s\r\n", buf);
break;
case CURL_TIMECOND_LASTMOD:
- add_bufferf(req_buffer,
- "Last-Modified: %s\r\n", buf);
+ result = add_bufferf(req_buffer,
+ "Last-Modified: %s\r\n", buf);
break;
}
+ if(result)
+ return result;
}
while(headers) {
- char *ptr = strchr(headers->data, ':');
+ ptr = strchr(headers->data, ':');
if(ptr) {
/* we require a colon for this to be a true header */
@@ -992,13 +1718,22 @@ CURLcode Curl_http(struct connectdata *conn)
if(*ptr) {
/* only send this if the contents was non-blank */
- add_bufferf(req_buffer, "%s\r\n", headers->data);
+ result = add_bufferf(req_buffer, "%s\r\n", headers->data);
+ if(result)
+ return result;
}
}
headers = headers->next;
}
- switch(data->set.httpreq) {
+ http->postdata = NULL; /* nothing to post at this point */
+ Curl_pgrsSetUploadSize(data, 0); /* upload size is 0 atm */
+
+ /* If 'authdone' is FALSE, we must not set the write socket index to the
+ Curl_transfer() call below, as we're not ready to actually upload any
+ data yet. */
+
+ switch(httpreq) {
case HTTPREQ_POST_FORM:
if(Curl_FormInit(&http->form, http->sendit)) {
@@ -1012,58 +1747,64 @@ CURLcode Curl_http(struct connectdata *conn)
http->sending = HTTPSEND_BODY;
- if(!conn->bits.upload_chunky)
+ if(!conn->bits.upload_chunky) {
/* only add Content-Length if not uploading chunked */
- add_bufferf(req_buffer,
- "Content-Length: %d\r\n", http->postsize);
+ result = add_bufferf(req_buffer,
+ "Content-Length: %" FORMAT_OFF_T "\r\n",
+ http->postsize);
+ if(result)
+ return result;
+ }
if(!checkheaders(data, "Expect:")) {
/* if not disabled explicitly we add a Expect: 100-continue
to the headers which actually speeds up post operations (as
there is one packet coming back from the web server) */
- add_bufferf(req_buffer,
- "Expect: 100-continue\r\n");
+ result = add_bufferf(req_buffer,
+ "Expect: 100-continue\r\n");
+ if(result)
+ return result;
data->set.expect100header = TRUE;
}
if(!checkheaders(data, "Content-Type:")) {
- /* Get Content-Type: line from Curl_FormReadOneLine, which happens
- to always be the first line. We can know this for sure since
- we always build the formpost linked list the same way!
+ /* Get Content-Type: line from Curl_formpostheader.
The Content-Type header line also contains the MIME boundary
string etc why disabling this header is likely to not make things
- work, but we support it anyway.
+ work, but we support disabling it anyway.
*/
- char contentType[256];
- int linelength=0;
- linelength = Curl_FormReadOneLine (contentType,
- sizeof(contentType),
- 1,
- (FILE *)&http->form);
- if(linelength == -1) {
+ 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;
}
- add_buffer(req_buffer, contentType, linelength);
+ result = add_buffer(req_buffer, contentType, linelength);
+ if(result)
+ return result;
}
/* make the request end in a true CRLF */
- add_buffer(req_buffer, "\r\n", 2);
+ result = add_buffer(req_buffer, "\r\n", 2);
+ if(result)
+ return result;
/* set upload size to the progress meter */
Curl_pgrsSetUploadSize(data, http->postsize);
/* fire away the whole request to the server */
- result = add_buffer_send(req_buffer, conn->firstsocket, conn,
+ result = add_buffer_send(req_buffer, conn,
&data->info.request_size);
if(result)
failf(data, "Failed sending POST request");
else
/* setup variables for the upcoming transfer */
- result = Curl_Transfer(conn, conn->firstsocket, -1, TRUE,
+ result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
&http->readbytecount,
- conn->firstsocket,
+ FIRSTSOCKET,
&http->writebytecount);
if(result) {
Curl_formclean(http->sendit); /* free that whole lot */
@@ -1073,27 +1814,43 @@ CURLcode Curl_http(struct connectdata *conn)
case HTTPREQ_PUT: /* Let's PUT the data to the server! */
- if((data->set.infilesize>0) && !conn->bits.upload_chunky)
+ if((data->set.infilesize>0) && !conn->bits.upload_chunky) {
/* only add Content-Length if not uploading chunked */
- add_bufferf(req_buffer,
- "Content-Length: %d\r\n", /* file size */
- data->set.infilesize );
+ result = add_bufferf(req_buffer,
+ "Content-Length: %" FORMAT_OFF_T "\r\n", /* size */
+ data->set.infilesize );
+ if(result)
+ return result;
+ }
+
+ if(!checkheaders(data, "Expect:")) {
+ /* if not disabled explicitly we add a Expect: 100-continue
+ to the headers which actually speeds up post operations (as
+ there is one packet coming back from the web server) */
+ result = add_bufferf(req_buffer,
+ "Expect: 100-continue\r\n");
+ if(result)
+ return result;
+ data->set.expect100header = TRUE;
+ }
- add_bufferf(req_buffer, "\r\n");
+ result = add_buffer(req_buffer, "\r\n", 2); /* end of headers */
+ if(result)
+ return result;
/* set the upload size to the progress meter */
Curl_pgrsSetUploadSize(data, data->set.infilesize);
/* this sends the buffer and frees all the buffer resources */
- result = add_buffer_send(req_buffer, conn->firstsocket, conn,
+ result = add_buffer_send(req_buffer, conn,
&data->info.request_size);
if(result)
failf(data, "Failed sending POST request");
else
/* prepare for transfer */
- result = Curl_Transfer(conn, conn->firstsocket, -1, TRUE,
+ result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
&http->readbytecount,
- conn->firstsocket,
+ FIRSTSOCKET,
&http->writebytecount);
if(result)
return result;
@@ -1102,91 +1859,139 @@ CURLcode Curl_http(struct connectdata *conn)
case HTTPREQ_POST:
/* this is the simple POST, using x-www-form-urlencoded style */
+ /* store the size of the postfields */
+ postsize = data->set.postfieldsize?
+ data->set.postfieldsize:
+ (data->set.postfields?(curl_off_t)strlen(data->set.postfields):0);
+
if(!conn->bits.upload_chunky) {
/* 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(!checkheaders(data, "Content-Length:"))
+ if(!checkheaders(data, "Content-Length:")) {
/* we allow replacing this header, although it isn't very wise to
actually set your own */
- add_bufferf(req_buffer,
- "Content-Length: %d\r\n",
- data->set.postfieldsize?
- data->set.postfieldsize:
- (data->set.postfields?strlen(data->set.postfields):0) );
+ result = add_bufferf(req_buffer,
+ "Content-Length: %" FORMAT_OFF_T"\r\n",
+ postsize);
+ if(result)
+ return result;
+ }
}
- if(!checkheaders(data, "Content-Type:"))
- add_bufferf(req_buffer,
- "Content-Type: application/x-www-form-urlencoded\r\n");
-
- add_buffer(req_buffer, "\r\n", 2);
+ if(!checkheaders(data, "Content-Type:")) {
+ result = add_bufferf(req_buffer,
+ "Content-Type: application/x-www-form-urlencoded\r\n");
+ if(result)
+ return result;
+ }
- /* and here we setup the pointers to the actual data */
if(data->set.postfields) {
- if(data->set.postfieldsize)
- http->postsize = (int)data->set.postfieldsize;
- else
- http->postsize = (int)strlen(data->set.postfields);
- http->postdata = data->set.postfields;
- http->sending = HTTPSEND_BODY;
-
- conn->fread = (curl_read_callback)readmoredata;
- conn->fread_in = (void *)conn;
+ if((data->state.authhost.done || data->state.authproxy.done )
+ && (postsize < (100*1024))) {
+ /* If we're not done with the authentication phase, we don't expect
+ to actually send off any data yet. Hence, we delay the sending of
+ the body until we receive that friendly 100-continue response */
+
+ /* The post data is less than 100K, then append it to the header.
+ This limit is no magic limit but only set to prevent really huge
+ POSTs to get the data duplicated with malloc() and family. */
+
+ result = add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
+ if(result)
+ return result;
+
+ if(!conn->bits.upload_chunky) {
+ /* We're not sending it 'chunked', append it to the request
+ already now to reduce the number if send() calls */
+ result = add_buffer(req_buffer, data->set.postfields,
+ (size_t)postsize);
+ }
+ else {
+ /* Append the POST data chunky-style */
+ result = add_bufferf(req_buffer, "%x\r\n", (int)postsize);
+ if(CURLE_OK == result)
+ result = add_buffer(req_buffer, data->set.postfields,
+ (size_t)postsize);
+ if(CURLE_OK == result)
+ result = add_buffer(req_buffer,
+ "\r\n0\r\n\r\n", 7); /* end of a chunked
+ transfer stream */
+ }
+ if(result)
+ return result;
+ }
+ else {
+ /* A huge POST coming up, do data separate from the request */
+ http->postsize = postsize;
+ http->postdata = data->set.postfields;
+
+ http->sending = HTTPSEND_BODY;
+
+ conn->fread = (curl_read_callback)readmoredata;
+ conn->fread_in = (void *)conn;
+
+ /* set the upload size to the progress meter */
+ Curl_pgrsSetUploadSize(data, http->postsize);
+
+ if(!checkheaders(data, "Expect:")) {
+ /* if not disabled explicitly we add a Expect: 100-continue to the
+ headers which actually speeds up post operations (as there is
+ one packet coming back from the web server) */
+ add_bufferf(req_buffer,
+ "Expect: 100-continue\r\n");
+ data->set.expect100header = TRUE;
+ }
- /* set the upload size to the progress meter */
- Curl_pgrsSetUploadSize(data, http->postsize);
+ add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
+ }
}
- else
+ else {
+ add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
+
/* set the upload size to the progress meter */
Curl_pgrsSetUploadSize(data, data->set.infilesize);
- /* issue the request, headers-only */
- result = add_buffer_send(req_buffer, conn->firstsocket, conn,
+ /* set the pointer to mark that we will send the post body using
+ the read callback */
+ http->postdata = (char *)&http->postdata;
+ }
+ /* issue the request */
+ result = add_buffer_send(req_buffer, conn,
&data->info.request_size);
if(result)
failf(data, "Failed sending HTTP POST request");
else
result =
- Curl_Transfer(conn, conn->firstsocket, -1, TRUE,
+ Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
&http->readbytecount,
- conn->firstsocket,
- &http->writebytecount);
+ http->postdata?FIRSTSOCKET:-1,
+ http->postdata?&http->writebytecount:NULL);
break;
default:
add_buffer(req_buffer, "\r\n", 2);
-
+
/* issue the request */
- result = add_buffer_send(req_buffer, conn->firstsocket, conn,
+ result = add_buffer_send(req_buffer, conn,
&data->info.request_size);
if(result)
failf(data, "Failed sending HTTP request");
else
/* HTTP GET/HEAD download: */
- result = Curl_Transfer(conn, conn->firstsocket, -1, TRUE,
+ result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
&http->readbytecount,
- http->postdata?conn->firstsocket:-1,
+ http->postdata?FIRSTSOCKET:-1,
http->postdata?&http->writebytecount:NULL);
}
if(result)
return result;
- } while (0); /* this is just a left-over from the multiple document download
- attempts */
+ }
return CURLE_OK;
}
-
-
-/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
- */
#endif
diff --git a/Source/CTest/Curl/http.h b/Source/CTest/Curl/http.h
index 2f40ea1..80c1807 100644
--- a/Source/CTest/Curl/http.h
+++ b/Source/CTest/Curl/http.h
@@ -2,18 +2,18 @@
#define __HTTP_H
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -35,12 +35,27 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn,
/* protocol-specific functions set up to be called by the main engine */
CURLcode Curl_http(struct connectdata *conn);
-CURLcode Curl_http_done(struct connectdata *conn);
+CURLcode Curl_http_done(struct connectdata *, CURLcode);
CURLcode Curl_http_connect(struct connectdata *conn);
/* The following functions are defined in http_chunks.c */
void Curl_httpchunk_init(struct connectdata *conn);
CHUNKcode Curl_httpchunk_read(struct connectdata *conn, char *datap,
ssize_t length, ssize_t *wrote);
+
+/* These functions are in http.c */
+void Curl_http_auth_stage(struct SessionHandle *data, int stage);
+CURLcode Curl_http_input_auth(struct connectdata *conn,
+ int httpcode, char *header);
+CURLcode Curl_http_auth_act(struct connectdata *conn);
+
+int Curl_http_should_fail(struct connectdata *conn);
+
+/* If only the PICKNONE bit is set, there has been a round-trip and we
+ selected to use no auth at all. Ie, we actively select no auth, as opposed
+ to not having one selected. The other CURLAUTH_* defines are present in the
+ public curl/curl.h header. */
+#define CURLAUTH_PICKNONE (1<<30) /* don't use auth */
+
#endif
#endif
diff --git a/Source/CTest/Curl/http_chunks.c b/Source/CTest/Curl/http_chunks.c
index 4ee37b8..baf2d66 100644
--- a/Source/CTest/Curl/http_chunks.c
+++ b/Source/CTest/Curl/http_chunks.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -33,15 +33,15 @@
#include "urldata.h" /* it includes http_chunks.h */
#include "sendf.h" /* for the client write stuff */
-#include "content_encoding.h" /* 08/29/02 jhrg */
+#include "content_encoding.h"
+#include "http.h"
+#include "memory.h"
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
/* The last #include file should be: */
-#ifdef MALLOCDEBUG
#include "memdebug.h"
-#endif
/*
* Chunk format (simplified):
@@ -99,13 +99,17 @@ void Curl_httpchunk_init(struct connectdata *conn)
*/
CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
char *datap,
- size_t length,
- size_t *wrote)
+ ssize_t datalen,
+ ssize_t *wrotep)
{
- CURLcode result;
+ CURLcode result=CURLE_OK;
struct Curl_chunker *ch = &conn->proto.http->chunk;
- int piece;
- *wrote = 0; /* nothing yet */
+ struct Curl_transfer_keeper *k = &conn->keep;
+ size_t piece;
+ size_t length = (size_t)datalen;
+ size_t *wrote = (size_t *)wrotep;
+
+ *wrote = 0; /* nothing's written yet */
while(length) {
switch(ch->state) {
@@ -171,30 +175,38 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
We expect another 'datasize' of data. We have 'length' right now,
it can be more or less than 'datasize'. Get the smallest piece.
*/
- piece = (int)((ch->datasize >= length)?length:ch->datasize);
+ piece = (ch->datasize >= length)?length:ch->datasize;
/* Write the data portion available */
- /* Added content-encoding here; untested but almost identical to the
- tested code in transfer.c. 08/29/02 jhrg */
#ifdef HAVE_LIBZ
switch (conn->keep.content_encoding) {
case IDENTITY:
#endif
- result = Curl_client_write(conn->data, CLIENTWRITE_BODY, datap,
- piece);
+ if(!k->ignorebody)
+ result = Curl_client_write(conn->data, CLIENTWRITE_BODY, datap,
+ piece);
#ifdef HAVE_LIBZ
break;
case DEFLATE:
- result = Curl_unencode_deflate_write(conn->data, &conn->keep, piece);
+ /* update conn->keep.str to point to the chunk data. */
+ conn->keep.str = datap;
+ result = Curl_unencode_deflate_write(conn->data, &conn->keep,
+ (ssize_t)piece);
break;
case GZIP:
+ /* update conn->keep.str to point to the chunk data. */
+ conn->keep.str = datap;
+ result = Curl_unencode_gzip_write(conn->data, &conn->keep,
+ (ssize_t)piece);
+ break;
+
case COMPRESS:
default:
failf (conn->data,
"Unrecognized content encoding type. "
- "libcurl understands `identity' and `deflate' "
+ "libcurl understands `identity', `deflate' and `gzip' "
"content encodings.");
return CHUNKE_BAD_ENCODING;
}
@@ -202,6 +214,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
if(result)
return CHUNKE_WRITE_ERROR;
+
*wrote += piece;
ch->datasize -= piece; /* decrease amount left to expect */
@@ -248,12 +261,4 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
}
return CHUNKE_OK;
}
-
-/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
- */
#endif /* CURL_DISABLE_HTTP */
diff --git a/Source/CTest/Curl/http_chunks.h b/Source/CTest/Curl/http_chunks.h
index 1b15d6c..26b79de 100644
--- a/Source/CTest/Curl/http_chunks.h
+++ b/Source/CTest/Curl/http_chunks.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
diff --git a/Source/CTest/Curl/http_digest.c b/Source/CTest/Curl/http_digest.c
new file mode 100644
index 0000000..20f5dc4
--- /dev/null
+++ b/Source/CTest/Curl/http_digest.c
@@ -0,0 +1,482 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+#include "setup.h"
+
+#ifndef CURL_DISABLE_HTTP
+/* -- WIN32 approved -- */
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "urldata.h"
+#include "sendf.h"
+#include "strequal.h"
+#include "base64.h"
+#include "md5.h"
+#include "http_digest.h"
+#include "strtok.h"
+#include "url.h" /* for Curl_safefree() */
+#include "memory.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/* Test example headers:
+
+WWW-Authenticate: Digest realm="testrealm", nonce="1053604598"
+Proxy-Authenticate: Digest realm="testrealm", nonce="1053604598"
+
+*/
+
+CURLdigest Curl_input_digest(struct connectdata *conn,
+ bool proxy,
+ char *header) /* rest of the *-authenticate:
+ header */
+{
+ bool more = TRUE;
+ char *token = NULL;
+ char *tmp = NULL;
+ bool foundAuth = FALSE;
+ bool foundAuthInt = FALSE;
+ struct SessionHandle *data=conn->data;
+ bool before = FALSE; /* got a nonce before */
+ struct digestdata *d;
+
+ if(proxy) {
+ d = &data->state.proxydigest;
+ }
+ else {
+ d = &data->state.digest;
+ }
+
+ /* skip initial whitespaces */
+ while(*header && isspace((int)*header))
+ header++;
+
+ if(checkprefix("Digest", header)) {
+ header += strlen("Digest");
+
+ /* If we already have received a nonce, keep that in mind */
+ if(d->nonce)
+ before = TRUE;
+
+ /* clear off any former leftovers and init to defaults */
+ Curl_digest_cleanup_one(d);
+
+ while(more) {
+ char value[32];
+ char content[128];
+ size_t totlen=0;
+
+ while(*header && isspace((int)*header))
+ header++;
+
+ /* how big can these strings be? */
+ if((2 == sscanf(header, "%31[^=]=\"%127[^\"]\"",
+ value, content)) ||
+ /* try the same scan but without quotes around the content but don't
+ include the possibly trailing comma */
+ (2 == sscanf(header, "%31[^=]=%127[^,]",
+ value, content)) ) {
+ if(strequal(value, "nonce")) {
+ d->nonce = strdup(content);
+ if(!d->nonce)
+ return CURLDIGEST_NOMEM;
+ }
+ else if(strequal(value, "stale")) {
+ if(strequal(content, "true")) {
+ d->stale = TRUE;
+ d->nc = 1; /* we make a new nonce now */
+ }
+ }
+ else if(strequal(value, "realm")) {
+ d->realm = strdup(content);
+ if(!d->realm)
+ return CURLDIGEST_NOMEM;
+ }
+ else if(strequal(value, "opaque")) {
+ d->opaque = strdup(content);
+ if(!d->opaque)
+ return CURLDIGEST_NOMEM;
+ }
+ else if(strequal(value, "qop")) {
+ char *tok_buf;
+ /* tokenize the list and choose auth if possible, use a temporary
+ clone of the buffer since strtok_r() ruins it */
+ tmp = strdup(content);
+ if(!tmp)
+ return CURLDIGEST_NOMEM;
+ token = strtok_r(tmp, ",", &tok_buf);
+ while (token != NULL) {
+ if (strequal(token, "auth")) {
+ foundAuth = TRUE;
+ }
+ else if (strequal(token, "auth-int")) {
+ foundAuthInt = TRUE;
+ }
+ token = strtok_r(NULL, ",", &tok_buf);
+ }
+ free(tmp);
+ /*select only auth o auth-int. Otherwise, ignore*/
+ if (foundAuth) {
+ d->qop = strdup("auth");
+ if(!d->qop)
+ return CURLDIGEST_NOMEM;
+ }
+ else if (foundAuthInt) {
+ d->qop = strdup("auth-int");
+ if(!d->qop)
+ return CURLDIGEST_NOMEM;
+ }
+ }
+ else if(strequal(value, "algorithm")) {
+ d->algorithm = strdup(content);
+ if(!d->algorithm)
+ return CURLDIGEST_NOMEM;
+ if(strequal(content, "MD5-sess"))
+ d->algo = CURLDIGESTALGO_MD5SESS;
+ else if(strequal(content, "MD5"))
+ d->algo = CURLDIGESTALGO_MD5;
+ else
+ return CURLDIGEST_BADALGO;
+ }
+ else {
+ /* unknown specifier, ignore it! */
+ }
+ totlen = strlen(value)+strlen(content)+1;
+
+ if(header[strlen(value)+1] == '\"')
+ /* the contents were within quotes, then add 2 for them to the
+ length */
+ totlen += 2;
+ }
+ else
+ break; /* we're done here */
+
+ header += totlen;
+ if(',' == *header)
+ /* allow the list to be comma-separated */
+ header++;
+ }
+ /* We had a nonce since before, and we got another one now without
+ 'stale=true'. This means we provided bad credentials in the previous
+ request */
+ if(before && !d->stale)
+ return CURLDIGEST_BAD;
+
+ /* We got this header without a nonce, that's a bad Digest line! */
+ if(!d->nonce)
+ return CURLDIGEST_BAD;
+ }
+ else
+ /* else not a digest, get out */
+ return CURLDIGEST_NONE;
+
+ return CURLDIGEST_FINE;
+}
+
+/* convert md5 chunk to RFC2617 (section 3.1.3) -suitable ascii string*/
+static void md5_to_ascii(unsigned char *source, /* 16 bytes */
+ unsigned char *dest) /* 33 bytes */
+{
+ int i;
+ for(i=0; i<16; i++)
+ snprintf((char *)&dest[i*2], 3, "%02x", source[i]);
+}
+
+CURLcode Curl_output_digest(struct connectdata *conn,
+ bool proxy,
+ unsigned char *request,
+ unsigned char *uripath)
+{
+ /* We have a Digest setup for this, use it! Now, to get all the details for
+ this sorted out, I must urge you dear friend to read up on the RFC2617
+ section 3.2.2, */
+ unsigned char md5buf[16]; /* 16 bytes/128 bits */
+ unsigned char request_digest[33];
+ unsigned char *md5this;
+ unsigned char *ha1;
+ unsigned char ha2[33];/* 32 digits and 1 zero byte */
+ char cnoncebuf[7];
+ char *cnonce;
+ char *tmp = NULL;
+ struct timeval now;
+
+ char **allocuserpwd;
+ char *userp;
+ char *passwdp;
+ struct auth *authp;
+
+ struct SessionHandle *data = conn->data;
+ struct digestdata *d;
+
+ if(proxy) {
+ d = &data->state.proxydigest;
+ allocuserpwd = &conn->allocptr.proxyuserpwd;
+ userp = conn->proxyuser;
+ passwdp = conn->proxypasswd;
+ authp = &data->state.authproxy;
+ }
+ else {
+ d = &data->state.digest;
+ allocuserpwd = &conn->allocptr.userpwd;
+ userp = conn->user;
+ passwdp = conn->passwd;
+ authp = &data->state.authhost;
+ }
+
+ /* not set means empty */
+ if(!userp)
+ userp=(char *)"";
+
+ if(!passwdp)
+ passwdp=(char *)"";
+
+ if(!d->nonce) {
+ authp->done = FALSE;
+ return CURLE_OK;
+ }
+ authp->done = TRUE;
+
+ if(!d->nc)
+ d->nc = 1;
+
+ if(!d->cnonce) {
+ /* Generate a cnonce */
+ now = Curl_tvnow();
+ snprintf(cnoncebuf, sizeof(cnoncebuf), "%06ld", now.tv_sec);
+ if(Curl_base64_encode(cnoncebuf, strlen(cnoncebuf), &cnonce))
+ d->cnonce = cnonce;
+ else
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ /*
+ if the algorithm is "MD5" or unspecified (which then defaults to MD5):
+
+ A1 = unq(username-value) ":" unq(realm-value) ":" passwd
+
+ if the algorithm is "MD5-sess" then:
+
+ A1 = H( unq(username-value) ":" unq(realm-value) ":" passwd )
+ ":" unq(nonce-value) ":" unq(cnonce-value)
+ */
+
+ md5this = (unsigned char *)
+ aprintf("%s:%s:%s", userp, d->realm, passwdp);
+ if(!md5this)
+ return CURLE_OUT_OF_MEMORY;
+ Curl_md5it(md5buf, md5this);
+ free(md5this); /* free this again */
+
+ ha1 = (unsigned char *)malloc(33); /* 32 digits and 1 zero byte */
+ if(!ha1)
+ return CURLE_OUT_OF_MEMORY;
+
+ md5_to_ascii(md5buf, ha1);
+
+ if(d->algo == CURLDIGESTALGO_MD5SESS) {
+ /* nonce and cnonce are OUTSIDE the hash */
+ tmp = aprintf("%s:%s:%s", ha1, d->nonce, d->cnonce);
+ free(ha1);
+ if(!tmp)
+ return CURLE_OUT_OF_MEMORY;
+ ha1 = (unsigned char *)tmp;
+ }
+
+ /*
+ If the "qop" directive's value is "auth" or is unspecified, then A2 is:
+
+ A2 = Method ":" digest-uri-value
+
+ If the "qop" value is "auth-int", then A2 is:
+
+ A2 = Method ":" digest-uri-value ":" H(entity-body)
+
+ (The "Method" value is the HTTP request method as specified in section
+ 5.1.1 of RFC 2616)
+ */
+
+ md5this = (unsigned char *)aprintf("%s:%s", request, uripath);
+ if(!md5this) {
+ free(ha1);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ if (d->qop && strequal(d->qop, "auth-int")) {
+ /* We don't support auth-int at the moment. I can't see a easy way to get
+ entity-body here */
+ /* TODO: Append H(entity-body)*/
+ }
+ Curl_md5it(md5buf, md5this);
+ free(md5this); /* free this again */
+ md5_to_ascii(md5buf, ha2);
+
+ if (d->qop) {
+ md5this = (unsigned char *)aprintf("%s:%s:%08x:%s:%s:%s",
+ ha1,
+ d->nonce,
+ d->nc,
+ d->cnonce,
+ d->qop,
+ ha2);
+ }
+ else {
+ md5this = (unsigned char *)aprintf("%s:%s:%s",
+ ha1,
+ d->nonce,
+ ha2);
+ }
+ free(ha1);
+ if(!md5this)
+ return CURLE_OUT_OF_MEMORY;
+
+ Curl_md5it(md5buf, md5this);
+ free(md5this); /* free this again */
+ md5_to_ascii(md5buf, request_digest);
+
+ /* for test case 64 (snooped from a Mozilla 1.3a request)
+
+ Authorization: Digest username="testuser", realm="testrealm", \
+ nonce="1053604145", uri="/64", response="c55f7f30d83d774a3d2dcacf725abaca"
+ */
+
+ Curl_safefree(*allocuserpwd);
+
+ if (d->qop) {
+ *allocuserpwd =
+ aprintf( "%sAuthorization: Digest "
+ "username=\"%s\", "
+ "realm=\"%s\", "
+ "nonce=\"%s\", "
+ "uri=\"%s\", "
+ "cnonce=\"%s\", "
+ "nc=%08x, "
+ "qop=\"%s\", "
+ "response=\"%s\"",
+ proxy?"Proxy-":"",
+ userp,
+ d->realm,
+ d->nonce,
+ uripath, /* this is the PATH part of the URL */
+ d->cnonce,
+ d->nc,
+ d->qop,
+ request_digest);
+
+ if(strequal(d->qop, "auth"))
+ d->nc++; /* The nc (from RFC) has to be a 8 hex digit number 0 padded
+ which tells to the server how many times you are using the
+ same nonce in the qop=auth mode. */
+ }
+ else {
+ *allocuserpwd =
+ aprintf( "%sAuthorization: Digest "
+ "username=\"%s\", "
+ "realm=\"%s\", "
+ "nonce=\"%s\", "
+ "uri=\"%s\", "
+ "response=\"%s\"",
+ proxy?"Proxy-":"",
+ userp,
+ d->realm,
+ d->nonce,
+ uripath, /* this is the PATH part of the URL */
+ request_digest);
+ }
+ if(!*allocuserpwd)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Add optional fields */
+ if(d->opaque) {
+ /* append opaque */
+ tmp = aprintf("%s, opaque=\"%s\"", *allocuserpwd, d->opaque);
+ if(!tmp)
+ return CURLE_OUT_OF_MEMORY;
+ free(*allocuserpwd);
+ *allocuserpwd = tmp;
+ }
+
+ if(d->algorithm) {
+ /* append algorithm */
+ tmp = aprintf("%s, algorithm=\"%s\"", *allocuserpwd, d->algorithm);
+ if(!tmp)
+ return CURLE_OUT_OF_MEMORY;
+ free(*allocuserpwd);
+ *allocuserpwd = tmp;
+ }
+
+ /* append CRLF to the userpwd header */
+ tmp = (char*) realloc(*allocuserpwd, strlen(*allocuserpwd) + 3 + 1);
+ if(!tmp)
+ return CURLE_OUT_OF_MEMORY;
+ strcat(tmp, "\r\n");
+ *allocuserpwd = tmp;
+
+ return CURLE_OK;
+}
+
+void Curl_digest_cleanup_one(struct digestdata *d)
+{
+ if(d->nonce)
+ free(d->nonce);
+ d->nonce = NULL;
+
+ if(d->cnonce)
+ free(d->cnonce);
+ d->cnonce = NULL;
+
+ if(d->realm)
+ free(d->realm);
+ d->realm = NULL;
+
+ if(d->opaque)
+ free(d->opaque);
+ d->opaque = NULL;
+
+ if(d->qop)
+ free(d->qop);
+ d->qop = NULL;
+
+ if(d->algorithm)
+ free(d->algorithm);
+ d->algorithm = NULL;
+
+ d->nc = 0;
+ d->algo = CURLDIGESTALGO_MD5; /* default algorithm */
+ d->stale = FALSE; /* default means normal, not stale */
+}
+
+
+void Curl_digest_cleanup(struct SessionHandle *data)
+{
+ Curl_digest_cleanup_one(&data->state.digest);
+ Curl_digest_cleanup_one(&data->state.proxydigest);
+}
+
+#endif
diff --git a/Source/CTest/Curl/http_digest.h b/Source/CTest/Curl/http_digest.h
new file mode 100644
index 0000000..b4fca06
--- /dev/null
+++ b/Source/CTest/Curl/http_digest.h
@@ -0,0 +1,53 @@
+#ifndef __HTTP_DIGEST_H
+#define __HTTP_DIGEST_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+typedef enum {
+ CURLDIGEST_NONE, /* not a digest */
+ CURLDIGEST_BAD, /* a digest, but one we don't like */
+ CURLDIGEST_BADALGO, /* unsupported algorithm requested */
+ CURLDIGEST_NOMEM,
+ CURLDIGEST_FINE, /* a digest we act on */
+
+ CURLDIGEST_LAST /* last entry in this enum, don't use */
+} CURLdigest;
+
+enum {
+ CURLDIGESTALGO_MD5,
+ CURLDIGESTALGO_MD5SESS
+};
+
+/* this is for digest header input */
+CURLdigest Curl_input_digest(struct connectdata *conn,
+ bool proxy, char *header);
+
+/* this is for creating digest header output */
+CURLcode Curl_output_digest(struct connectdata *conn,
+ bool proxy,
+ unsigned char *request,
+ unsigned char *uripath);
+void Curl_digest_cleanup(struct SessionHandle *data);
+void Curl_digest_cleanup_one(struct digestdata *dig);
+
+#endif
diff --git a/Source/CTest/Curl/http_negotiate.c b/Source/CTest/Curl/http_negotiate.c
new file mode 100644
index 0000000..43f1da4
--- /dev/null
+++ b/Source/CTest/Curl/http_negotiate.c
@@ -0,0 +1,332 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+#include "setup.h"
+
+#ifdef HAVE_GSSAPI
+#ifdef HAVE_GSSMIT
+#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
+#endif
+
+#ifndef CURL_DISABLE_HTTP
+ /* -- WIN32 approved -- */
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "urldata.h"
+#include "sendf.h"
+#include "strequal.h"
+#include "base64.h"
+#include "http_negotiate.h"
+#include "memory.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+static int
+get_gss_name(struct connectdata *conn, gss_name_t *server)
+{
+ struct negotiatedata *neg_ctx = &conn->data->state.negotiate;
+ OM_uint32 major_status, minor_status;
+ gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
+ char name[2048];
+ const char* service;
+
+ /* GSSAPI implementation by Globus (known as GSI) requires the name to be
+ of form "<service>/<fqdn>" instead of <service>@<fqdn> (ie. slash instead
+ of at-sign). Also GSI servers are often identified as 'host' not 'khttp'.
+ Change following lines if you want to use GSI */
+
+ /* IIS uses the <service>@<fqdn> form but uses 'http' as the service name */
+
+ if (neg_ctx->gss)
+ service = "KHTTP";
+ else
+ service = "HTTP";
+
+ token.length = strlen(service) + 1 + strlen(conn->host.name) + 1;
+ if (token.length + 1 > sizeof(name))
+ return EMSGSIZE;
+
+ snprintf(name, sizeof(name), "%s@%s", service, conn->host.name);
+
+ token.value = (void *) name;
+ major_status = gss_import_name(&minor_status,
+ &token,
+ GSS_C_NT_HOSTBASED_SERVICE,
+ server);
+
+ return GSS_ERROR(major_status) ? -1 : 0;
+}
+
+static void
+log_gss_error(struct connectdata *conn, OM_uint32 error_status, char *prefix)
+{
+ OM_uint32 maj_stat, min_stat;
+ OM_uint32 msg_ctx = 0;
+ gss_buffer_desc status_string;
+ char buf[1024];
+ size_t len;
+
+ snprintf(buf, sizeof(buf), "%s", prefix);
+ len = strlen(buf);
+ do {
+ maj_stat = gss_display_status (&min_stat,
+ error_status,
+ GSS_C_MECH_CODE,
+ GSS_C_NO_OID,
+ &msg_ctx,
+ &status_string);
+ if (sizeof(buf) > len + status_string.length + 1) {
+ snprintf(buf + len, sizeof(buf) - len,
+ ": %s", (char*) status_string.value);
+ len += status_string.length;
+ }
+ gss_release_buffer(&min_stat, &status_string);
+ } while (!GSS_ERROR(maj_stat) && msg_ctx != 0);
+
+ infof(conn->data, buf);
+}
+
+int Curl_input_negotiate(struct connectdata *conn, char *header)
+{
+ struct negotiatedata *neg_ctx = &conn->data->state.negotiate;
+ OM_uint32 major_status, minor_status, minor_status2;
+ gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
+ int ret;
+ size_t len;
+ bool gss;
+ const char* protocol;
+
+ while(*header && isspace((int)*header))
+ header++;
+ if(checkprefix("GSS-Negotiate", header)) {
+ protocol = "GSS-Negotiate";
+ gss = TRUE;
+ }
+ else if (checkprefix("Negotiate", header)) {
+ protocol = "Negotiate";
+ gss = FALSE;
+ }
+ else
+ return -1;
+
+ if (neg_ctx->context) {
+ if (neg_ctx->gss != gss) {
+ return -1;
+ }
+ }
+ else {
+ neg_ctx->protocol = protocol;
+ neg_ctx->gss = gss;
+ }
+
+ if (neg_ctx->context && neg_ctx->status == GSS_S_COMPLETE) {
+ /* We finished succesfully our part of authentication, but server
+ * rejected it (since we're again here). Exit with an error since we
+ * can't invent anything better */
+ Curl_cleanup_negotiate(conn->data);
+ return -1;
+ }
+
+ if (neg_ctx->server_name == NULL &&
+ (ret = get_gss_name(conn, &neg_ctx->server_name)))
+ return ret;
+
+ header += strlen(neg_ctx->protocol);
+ while(*header && isspace((int)*header))
+ header++;
+
+ len = strlen(header);
+ if (len > 0) {
+ int rawlen;
+ input_token.length = (len+3)/4 * 3;
+ input_token.value = malloc(input_token.length);
+ if (input_token.value == NULL)
+ return ENOMEM;
+ rawlen = Curl_base64_decode(header, input_token.value);
+ if (rawlen < 0)
+ return -1;
+ input_token.length = rawlen;
+
+#ifdef HAVE_SPNEGO /* Handle SPNEGO */
+ if (checkprefix("Negotiate", header)) {
+ ASN1_OBJECT * object = NULL;
+ int rc = 1;
+ unsigned char * spnegoToken = NULL;
+ size_t spnegoTokenLength = 0;
+ unsigned char * mechToken = NULL;
+ size_t mechTokenLength = 0;
+
+ spnegoToken = malloc(input_token.length);
+ if (input_token.value == NULL)
+ return ENOMEM;
+ spnegoTokenLength = input_token.length;
+
+ object = OBJ_txt2obj ("1.2.840.113554.1.2.2", 1);
+ if (!parseSpnegoTargetToken(spnegoToken,
+ spnegoTokenLength,
+ NULL,
+ NULL,
+ &mechToken,
+ &mechTokenLength,
+ NULL,
+ NULL)) {
+ free(spnegoToken);
+ spnegoToken = NULL;
+ infof(conn->data, "Parse SPNEGO Target Token failed\n");
+ }
+ else {
+ free(input_token.value);
+ input_token.value = NULL;
+ input_token.value = malloc(mechTokenLength);
+ memcpy(input_token.value, mechToken,mechTokenLength);
+ input_token.length = mechTokenLength;
+ free(mechToken);
+ mechToken = NULL;
+ infof(conn->data, "Parse SPNEGO Target Token succeded\n");
+ }
+ }
+#endif
+ }
+
+ major_status = gss_init_sec_context(&minor_status,
+ GSS_C_NO_CREDENTIAL,
+ &neg_ctx->context,
+ neg_ctx->server_name,
+ GSS_C_NO_OID,
+ GSS_C_DELEG_FLAG,
+ 0,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ &input_token,
+ NULL,
+ &output_token,
+ NULL,
+ NULL);
+ if (input_token.length > 0)
+ gss_release_buffer(&minor_status2, &input_token);
+ neg_ctx->status = major_status;
+ if (GSS_ERROR(major_status)) {
+ /* Curl_cleanup_negotiate(conn->data) ??? */
+ log_gss_error(conn, minor_status,
+ (char *)"gss_init_sec_context() failed: ");
+ return -1;
+ }
+
+ if (output_token.length == 0) {
+ return -1;
+ }
+
+ neg_ctx->output_token = output_token;
+ /* conn->bits.close = FALSE; */
+
+ return 0;
+}
+
+
+CURLcode Curl_output_negotiate(struct connectdata *conn)
+{
+ struct negotiatedata *neg_ctx = &conn->data->state.negotiate;
+ OM_uint32 minor_status;
+ char *encoded = NULL;
+ int len;
+
+#ifdef HAVE_SPNEGO /* Handle SPNEGO */
+ if (checkprefix("Negotiate",neg_ctx->protocol)) {
+ ASN1_OBJECT * object = NULL;
+ int rc = 1;
+ unsigned char * spnegoToken = NULL;
+ size_t spnegoTokenLength = 0;
+ unsigned char * responseToken = NULL;
+ size_t responseTokenLength = 0;
+
+ responseToken = malloc(neg_ctx->output_token.length);
+ if ( responseToken == NULL)
+ return CURLE_OUT_OF_MEMORY;
+ memcpy(responseToken, neg_ctx->output_token.value,
+ neg_ctx->output_token.length);
+ responseTokenLength = neg_ctx->output_token.length;
+
+ object=OBJ_txt2obj ("1.2.840.113554.1.2.2", 1);
+ if (!makeSpnegoInitialToken (object,
+ responseToken,
+ responseTokenLength,
+ &spnegoToken,
+ &spnegoTokenLength)) {
+ free(responseToken);
+ responseToken = NULL;
+ infof(conn->data, "Make SPNEGO Initial Token failed\n");
+ }
+ else {
+ free(neg_ctx->output_token.value);
+ responseToken = NULL;
+ neg_ctx->output_token.value = malloc(spnegoTokenLength);
+ memcpy(neg_ctx->output_token.value, spnegoToken,spnegoTokenLength);
+ neg_ctx->output_token.length = spnegoTokenLength;
+ free(spnegoToken);
+ spnegoToken = NULL;
+ infof(conn->data, "Make SPNEGO Initial Token succeded\n");
+ }
+ }
+#endif
+ len = Curl_base64_encode(neg_ctx->output_token.value,
+ neg_ctx->output_token.length,
+ &encoded);
+
+ if (len < 0)
+ return CURLE_OUT_OF_MEMORY;
+
+ conn->allocptr.userpwd =
+ aprintf("Authorization: %s %s\r\n", neg_ctx->protocol, encoded);
+ free(encoded);
+ gss_release_buffer(&minor_status, &neg_ctx->output_token);
+ return (conn->allocptr.userpwd == NULL) ? CURLE_OUT_OF_MEMORY : CURLE_OK;
+}
+
+void Curl_cleanup_negotiate(struct SessionHandle *data)
+{
+ OM_uint32 minor_status;
+ struct negotiatedata *neg_ctx = &data->state.negotiate;
+
+ if (neg_ctx->context != GSS_C_NO_CONTEXT)
+ gss_delete_sec_context(&minor_status, &neg_ctx->context, GSS_C_NO_BUFFER);
+
+ if (neg_ctx->output_token.length != 0)
+ gss_release_buffer(&minor_status, &neg_ctx->output_token);
+
+ if (neg_ctx->server_name != GSS_C_NO_NAME)
+ gss_release_name(&minor_status, &neg_ctx->server_name);
+
+ memset(neg_ctx, 0, sizeof(*neg_ctx));
+}
+
+
+#endif
+#endif
diff --git a/Source/CTest/Curl/http_negotiate.h b/Source/CTest/Curl/http_negotiate.h
new file mode 100644
index 0000000..ce0d083
--- /dev/null
+++ b/Source/CTest/Curl/http_negotiate.h
@@ -0,0 +1,39 @@
+#ifndef __HTTP_NEGOTIATE_H
+#define __HTTP_NEGOTIATE_H
+
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#ifdef HAVE_GSSAPI
+
+/* this is for Negotiate header input */
+int Curl_input_negotiate(struct connectdata *conn, char *header);
+
+/* this is for creating Negotiate header output */
+CURLcode Curl_output_negotiate(struct connectdata *conn);
+
+void Curl_cleanup_negotiate(struct SessionHandle *data);
+
+#endif
+
+#endif
diff --git a/Source/CTest/Curl/http_ntlm.c b/Source/CTest/Curl/http_ntlm.c
new file mode 100644
index 0000000..dc31e83
--- /dev/null
+++ b/Source/CTest/Curl/http_ntlm.c
@@ -0,0 +1,585 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+#include "setup.h"
+
+/* NTLM details:
+
+ http://davenport.sourceforge.net/ntlm.html
+ http://www.innovation.ch/java/ntlm.html
+
+*/
+
+#ifndef CURL_DISABLE_HTTP
+#ifdef USE_SSLEAY
+/* We need OpenSSL for the crypto lib to provide us with MD4 and DES */
+
+/* -- WIN32 approved -- */
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "urldata.h"
+#include "sendf.h"
+#include "strequal.h"
+#include "base64.h"
+#include "http_ntlm.h"
+#include "url.h"
+#include "memory.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include <openssl/des.h>
+#include <openssl/md4.h>
+#include <openssl/ssl.h>
+
+#if OPENSSL_VERSION_NUMBER < 0x00907001L
+#define DES_key_schedule des_key_schedule
+#define DES_cblock des_cblock
+#define DES_set_odd_parity des_set_odd_parity
+#define DES_set_key des_set_key
+#define DES_ecb_encrypt des_ecb_encrypt
+
+/* This is how things were done in the old days */
+#define DESKEY(x) x
+#define DESKEYARG(x) x
+#else
+/* Modern version */
+#define DESKEYARG(x) *x
+#define DESKEY(x) &x
+#endif
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/* Define this to make the type-3 message include the NT response message */
+#define USE_NTRESPONSES 1
+
+/*
+ (*) = A "security buffer" is a triplet consisting of two shorts and one
+ long:
+
+ 1. a 'short' containing the length of the buffer in bytes
+ 2. a 'short' containing the allocated space for the buffer in bytes
+ 3. a 'long' containing the offset to the start of the buffer from the
+ beginning of the NTLM message, in bytes.
+*/
+
+
+CURLntlm Curl_input_ntlm(struct connectdata *conn,
+ bool proxy, /* if proxy or not */
+ char *header) /* rest of the www-authenticate:
+ header */
+{
+ /* point to the correct struct with this */
+ struct ntlmdata *ntlm;
+
+ ntlm = proxy?&conn->proxyntlm:&conn->ntlm;
+
+ /* skip initial whitespaces */
+ while(*header && isspace((int)*header))
+ header++;
+
+ if(checkprefix("NTLM", header)) {
+ unsigned char buffer[256];
+ header += strlen("NTLM");
+
+ while(*header && isspace((int)*header))
+ header++;
+
+ if(*header) {
+ /* We got a type-2 message here:
+
+ Index Description Content
+ 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
+ (0x4e544c4d53535000)
+ 8 NTLM Message Type long (0x02000000)
+ 12 Target Name security buffer(*)
+ 20 Flags long
+ 24 Challenge 8 bytes
+ (32) Context (optional) 8 bytes (two consecutive longs)
+ (40) Target Information (optional) security buffer(*)
+ 32 (48) start of data block
+ */
+
+ size_t size = Curl_base64_decode(header, (char *)buffer);
+
+ ntlm->state = NTLMSTATE_TYPE2; /* we got a type-2 */
+
+ if(size >= 48)
+ /* the nonce of interest is index [24 .. 31], 8 bytes */
+ memcpy(ntlm->nonce, &buffer[24], 8);
+
+ /* at index decimal 20, there's a 32bit NTLM flag field */
+
+ }
+ else {
+ if(ntlm->state >= NTLMSTATE_TYPE1)
+ return CURLNTLM_BAD;
+
+ ntlm->state = NTLMSTATE_TYPE1; /* we should sent away a type-1 */
+ }
+ }
+ return CURLNTLM_FINE;
+}
+
+/*
+ * Turns a 56 bit key into the 64 bit, odd parity key and sets the key. The
+ * key schedule ks is also set.
+ */
+static void setup_des_key(unsigned char *key_56,
+ DES_key_schedule DESKEYARG(ks))
+{
+ DES_cblock key;
+
+ key[0] = key_56[0];
+ key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
+ key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
+ key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
+ key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
+ key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
+ key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
+ key[7] = (key_56[6] << 1) & 0xFF;
+
+ DES_set_odd_parity(&key);
+ DES_set_key(&key, ks);
+}
+
+ /*
+ * takes a 21 byte array and treats it as 3 56-bit DES keys. The
+ * 8 byte plaintext is encrypted with each key and the resulting 24
+ * bytes are stored in the results array.
+ */
+static void calc_resp(unsigned char *keys,
+ unsigned char *plaintext,
+ unsigned char *results)
+{
+ DES_key_schedule ks;
+
+ setup_des_key(keys, DESKEY(ks));
+ DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) results,
+ DESKEY(ks), DES_ENCRYPT);
+
+ setup_des_key(keys+7, DESKEY(ks));
+ DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+8),
+ DESKEY(ks), DES_ENCRYPT);
+
+ setup_des_key(keys+14, DESKEY(ks));
+ DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+16),
+ DESKEY(ks), DES_ENCRYPT);
+}
+
+/*
+ * Set up lanmanager and nt hashed passwords
+ */
+static void mkhash(char *password,
+ unsigned char *nonce, /* 8 bytes */
+ unsigned char *lmresp /* must fit 0x18 bytes */
+#ifdef USE_NTRESPONSES
+ , unsigned char *ntresp /* must fit 0x18 bytes */
+#endif
+ )
+{
+ unsigned char lmbuffer[21];
+#ifdef USE_NTRESPONSES
+ unsigned char ntbuffer[21];
+#endif
+ unsigned char *pw;
+ static const unsigned char magic[] = {
+ 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25
+ };
+ unsigned int i;
+ size_t len = strlen(password);
+
+ /* make it fit at least 14 bytes */
+ pw = malloc(len<7?14:len*2);
+ if(!pw)
+ return; /* this will lead to a badly generated package */
+
+ if (len > 14)
+ len = 14;
+
+ for (i=0; i<len; i++)
+ pw[i] = toupper(password[i]);
+
+ for (; i<14; i++)
+ pw[i] = 0;
+
+ {
+ /* create LanManager hashed password */
+ DES_key_schedule ks;
+
+ setup_des_key(pw, DESKEY(ks));
+ DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)lmbuffer,
+ DESKEY(ks), DES_ENCRYPT);
+
+ setup_des_key(pw+7, DESKEY(ks));
+ DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer+8),
+ DESKEY(ks), DES_ENCRYPT);
+
+ memset(lmbuffer+16, 0, 5);
+ }
+ /* create LM responses */
+ calc_resp(lmbuffer, nonce, lmresp);
+
+#ifdef USE_NTRESPONSES
+ {
+ /* create NT hashed password */
+ MD4_CTX MD4;
+
+ len = strlen(password);
+
+ for (i=0; i<len; i++) {
+ pw[2*i] = password[i];
+ pw[2*i+1] = 0;
+ }
+
+ MD4_Init(&MD4);
+ MD4_Update(&MD4, pw, 2*len);
+ MD4_Final(ntbuffer, &MD4);
+
+ memset(ntbuffer+16, 0, 8);
+ }
+
+ calc_resp(ntbuffer, nonce, ntresp);
+#endif
+
+ free(pw);
+}
+
+#define SHORTPAIR(x) ((x) & 0xff), ((x) >> 8)
+#define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8)&0xff), \
+ (((x) >>16)&0xff), ((x)>>24)
+
+/* this is for creating ntlm header output */
+CURLcode Curl_output_ntlm(struct connectdata *conn,
+ bool proxy)
+{
+ const char *domain=""; /* empty */
+ const char *host=""; /* empty */
+ int domlen=(int)strlen(domain);
+ int hostlen = (int)strlen(host);
+ int hostoff; /* host name offset */
+ int domoff; /* domain name offset */
+ size_t size;
+ char *base64=NULL;
+ unsigned char ntlmbuf[256]; /* enough, unless the host/domain is very long */
+
+ /* point to the address of the pointer that holds the string to sent to the
+ server, which is for a plain host or for a HTTP proxy */
+ char **allocuserpwd;
+
+ /* point to the name and password for this */
+ char *userp;
+ char *passwdp;
+ /* point to the correct struct with this */
+ struct ntlmdata *ntlm;
+ struct auth *authp;
+
+ curlassert(conn);
+ curlassert(conn->data);
+
+ if(proxy) {
+ allocuserpwd = &conn->allocptr.proxyuserpwd;
+ userp = conn->proxyuser;
+ passwdp = conn->proxypasswd;
+ ntlm = &conn->proxyntlm;
+ authp = &conn->data->state.authproxy;
+ }
+ else {
+ allocuserpwd = &conn->allocptr.userpwd;
+ userp = conn->user;
+ passwdp = conn->passwd;
+ ntlm = &conn->ntlm;
+ authp = &conn->data->state.authhost;
+ }
+ authp->done = FALSE;
+
+ /* not set means empty */
+ if(!userp)
+ userp=(char *)"";
+
+ if(!passwdp)
+ passwdp=(char *)"";
+
+ switch(ntlm->state) {
+ case NTLMSTATE_TYPE1:
+ default: /* for the weird cases we (re)start here */
+ hostoff = 32;
+ domoff = hostoff + hostlen;
+
+ /* Create and send a type-1 message:
+
+ Index Description Content
+ 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
+ (0x4e544c4d53535000)
+ 8 NTLM Message Type long (0x01000000)
+ 12 Flags long
+ 16 Supplied Domain security buffer(*)
+ 24 Supplied Workstation security buffer(*)
+ 32 start of data block
+
+ */
+
+ snprintf((char *)ntlmbuf, sizeof(ntlmbuf), "NTLMSSP%c"
+ "\x01%c%c%c" /* 32-bit type = 1 */
+ "%c%c%c%c" /* 32-bit NTLM flag field */
+ "%c%c" /* domain length */
+ "%c%c" /* domain allocated space */
+ "%c%c" /* domain name offset */
+ "%c%c" /* 2 zeroes */
+ "%c%c" /* host length */
+ "%c%c" /* host allocated space */
+ "%c%c" /* host name offset */
+ "%c%c" /* 2 zeroes */
+ "%s" /* host name */
+ "%s", /* domain string */
+ 0, /* trailing zero */
+ 0,0,0, /* part of type-1 long */
+
+ LONGQUARTET(
+ NTLMFLAG_NEGOTIATE_OEM| /* 2 */
+ NTLMFLAG_NEGOTIATE_NTLM_KEY /* 200 */
+ /* equals 0x0202 */
+ ),
+ SHORTPAIR(domlen),
+ SHORTPAIR(domlen),
+ SHORTPAIR(domoff),
+ 0,0,
+ SHORTPAIR(hostlen),
+ SHORTPAIR(hostlen),
+ SHORTPAIR(hostoff),
+ 0,0,
+ host, domain);
+
+ /* initial packet length */
+ size = 32 + hostlen + domlen;
+
+ /* now keeper of the base64 encoded package size */
+ size = Curl_base64_encode((char *)ntlmbuf, size, &base64);
+
+ if(size >0 ) {
+ Curl_safefree(*allocuserpwd);
+ *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
+ proxy?"Proxy-":"",
+ base64);
+ free(base64);
+ }
+ else
+ return CURLE_OUT_OF_MEMORY; /* FIX TODO */
+
+ break;
+
+ case NTLMSTATE_TYPE2:
+ /* We received the type-2 already, create a type-3 message:
+
+ Index Description Content
+ 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
+ (0x4e544c4d53535000)
+ 8 NTLM Message Type long (0x03000000)
+ 12 LM/LMv2 Response security buffer(*)
+ 20 NTLM/NTLMv2 Response security buffer(*)
+ 28 Domain Name security buffer(*)
+ 36 User Name security buffer(*)
+ 44 Workstation Name security buffer(*)
+ (52) Session Key (optional) security buffer(*)
+ (60) Flags (optional) long
+ 52 (64) start of data block
+
+ */
+
+ {
+ int lmrespoff;
+ int ntrespoff;
+ int useroff;
+ unsigned char lmresp[0x18]; /* fixed-size */
+#ifdef USE_NTRESPONSES
+ unsigned char ntresp[0x18]; /* fixed-size */
+#endif
+ const char *user;
+ int userlen;
+
+ user = strchr(userp, '\\');
+ if(!user)
+ user = strchr(userp, '/');
+
+ if (user) {
+ domain = userp;
+ domlen = (int)(user - domain);
+ user++;
+ }
+ else
+ user = userp;
+ userlen = (int)strlen(user);
+
+ mkhash(passwdp, &ntlm->nonce[0], lmresp
+#ifdef USE_NTRESPONSES
+ , ntresp
+#endif
+ );
+
+ domoff = 64; /* always */
+ useroff = domoff + domlen;
+ hostoff = useroff + userlen;
+ lmrespoff = hostoff + hostlen;
+ ntrespoff = lmrespoff + 0x18;
+
+ /* Create the big type-3 message binary blob */
+ size = snprintf((char *)ntlmbuf, sizeof(ntlmbuf),
+ "NTLMSSP%c"
+ "\x03%c%c%c" /* type-3, 32 bits */
+
+ "%c%c%c%c" /* LanManager length + allocated space */
+ "%c%c" /* LanManager offset */
+ "%c%c" /* 2 zeroes */
+
+ "%c%c" /* NT-response length */
+ "%c%c" /* NT-response allocated space */
+ "%c%c" /* NT-response offset */
+ "%c%c" /* 2 zeroes */
+
+ "%c%c" /* domain length */
+ "%c%c" /* domain allocated space */
+ "%c%c" /* domain name offset */
+ "%c%c" /* 2 zeroes */
+
+ "%c%c" /* user length */
+ "%c%c" /* user allocated space */
+ "%c%c" /* user offset */
+ "%c%c" /* 2 zeroes */
+
+ "%c%c" /* host length */
+ "%c%c" /* host allocated space */
+ "%c%c" /* host offset */
+ "%c%c%c%c%c%c" /* 6 zeroes */
+
+ "\xff\xff" /* message length */
+ "%c%c" /* 2 zeroes */
+
+ "\x01\x82" /* flags */
+ "%c%c" /* 2 zeroes */
+
+ /* domain string */
+ /* user string */
+ /* host string */
+ /* LanManager response */
+ /* NT response */
+ ,
+ 0, /* zero termination */
+ 0,0,0, /* type-3 long, the 24 upper bits */
+
+ SHORTPAIR(0x18), /* LanManager response length, twice */
+ SHORTPAIR(0x18),
+ SHORTPAIR(lmrespoff),
+ 0x0, 0x0,
+
+#ifdef USE_NTRESPONSES
+ SHORTPAIR(0x18), /* NT-response length, twice */
+ SHORTPAIR(0x18),
+#else
+ 0x0, 0x0,
+ 0x0, 0x0,
+#endif
+ SHORTPAIR(ntrespoff),
+ 0x0, 0x0,
+
+ SHORTPAIR(domlen),
+ SHORTPAIR(domlen),
+ SHORTPAIR(domoff),
+ 0x0, 0x0,
+
+ SHORTPAIR(userlen),
+ SHORTPAIR(userlen),
+ SHORTPAIR(useroff),
+ 0x0, 0x0,
+
+ SHORTPAIR(hostlen),
+ SHORTPAIR(hostlen),
+ SHORTPAIR(hostoff),
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+
+ 0x0, 0x0,
+
+ 0x0, 0x0);
+
+ /* size is now 64 */
+ size=64;
+ ntlmbuf[62]=ntlmbuf[63]=0;
+
+ memcpy(&ntlmbuf[size], domain, domlen);
+ size += domlen;
+
+ memcpy(&ntlmbuf[size], user, userlen);
+ size += userlen;
+
+ /* we append the binary hashes to the end of the blob */
+ if(size < ((int)sizeof(ntlmbuf) - 0x18)) {
+ memcpy(&ntlmbuf[size], lmresp, 0x18);
+ size += 0x18;
+ }
+
+#ifdef USE_NTRESPONSES
+ if(size < ((int)sizeof(ntlmbuf) - 0x18)) {
+ memcpy(&ntlmbuf[size], ntresp, 0x18);
+ size += 0x18;
+ }
+#endif
+
+ ntlmbuf[56] = (unsigned char)(size & 0xff);
+ ntlmbuf[57] = (unsigned char)(size >> 8);
+
+ /* convert the binary blob into base64 */
+ size = Curl_base64_encode((char *)ntlmbuf, size, &base64);
+
+ if(size >0 ) {
+ Curl_safefree(*allocuserpwd);
+ *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
+ proxy?"Proxy-":"",
+ base64);
+ free(base64);
+ }
+ else
+ return CURLE_OUT_OF_MEMORY; /* FIX TODO */
+
+ ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */
+ authp->done = TRUE;
+ }
+ break;
+
+ case NTLMSTATE_TYPE3:
+ /* connection is already authenticated,
+ * don't send a header in future requests */
+ if(*allocuserpwd) {
+ free(*allocuserpwd);
+ *allocuserpwd=NULL;
+ }
+ authp->done = TRUE;
+ break;
+ }
+
+ return CURLE_OK;
+}
+#endif /* USE_SSLEAY */
+#endif /* !CURL_DISABLE_HTTP */
diff --git a/Source/CTest/Curl/http_ntlm.h b/Source/CTest/Curl/http_ntlm.h
new file mode 100644
index 0000000..4386a1c
--- /dev/null
+++ b/Source/CTest/Curl/http_ntlm.h
@@ -0,0 +1,143 @@
+#ifndef __HTTP_NTLM_H
+#define __HTTP_NTLM_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+typedef enum {
+ CURLNTLM_NONE, /* not a ntlm */
+ CURLNTLM_BAD, /* an ntlm, but one we don't like */
+ CURLNTLM_FIRST, /* the first 401-reply we got with NTLM */
+ CURLNTLM_FINE, /* an ntlm we act on */
+
+ CURLNTLM_LAST /* last entry in this enum, don't use */
+} CURLntlm;
+
+/* this is for ntlm header input */
+CURLntlm Curl_input_ntlm(struct connectdata *conn, bool proxy, char *header);
+
+/* this is for creating ntlm header output */
+CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy);
+
+void Curl_ntlm_cleanup(struct SessionHandle *data);
+
+
+/* Flag bits definitions based on http://davenport.sourceforge.net/ntlm.html */
+
+#define NTLMFLAG_NEGOTIATE_UNICODE (1<<0)
+/* Indicates that Unicode strings are supported for use in security buffer
+ data. */
+
+#define NTLMFLAG_NEGOTIATE_OEM (1<<1)
+/* Indicates that OEM strings are supported for use in security buffer data. */
+
+#define NTLMFLAG_REQUEST_TARGET (1<<2)
+/* Requests that the server's authentication realm be included in the Type 2
+ message. */
+
+/* unknown (1<<3) */
+#define NTLMFLAG_NEGOTIATE_SIGN (1<<4)
+/* Specifies that authenticated communication between the client and server
+ should carry a digital signature (message integrity). */
+
+#define NTLMFLAG_NEGOTIATE_SEAL (1<<5)
+/* Specifies that authenticated communication between the client and server
+ should be encrypted (message confidentiality). */
+
+#define NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE (1<<6)
+/* unknown purpose */
+
+#define NTLMFLAG_NEGOTIATE_LM_KEY (1<<7)
+/* Indicates that the LAN Manager session key should be used for signing and
+ sealing authenticated communications. */
+
+#define NTLMFLAG_NEGOTIATE_NETWARE (1<<8)
+/* unknown purpose */
+
+#define NTLMFLAG_NEGOTIATE_NTLM_KEY (1<<9)
+/* Indicates that NTLM authentication is being used. */
+
+/* unknown (1<<10) */
+/* unknown (1<<11) */
+
+#define NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED (1<<12)
+/* Sent by the client in the Type 1 message to indicate that a desired
+ authentication realm is included in the message. */
+
+#define NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED (1<<13)
+/* Sent by the client in the Type 1 message to indicate that the client
+ workstation's name is included in the message. */
+
+#define NTLMFLAG_NEGOTIATE_LOCAL_CALL (1<<14)
+/* Sent by the server to indicate that the server and client are on the same
+ machine. Implies that the client may use a pre-established local security
+ context rather than responding to the challenge. */
+
+#define NTLMFLAG_NEGOTIATE_ALWAYS_SIGN (1<<15)
+/* Indicates that authenticated communication between the client and server
+ should be signed with a "dummy" signature. */
+
+#define NTLMFLAG_TARGET_TYPE_DOMAIN (1<<16)
+/* Sent by the server in the Type 2 message to indicate that the target
+ authentication realm is a domain. */
+
+#define NTLMFLAG_TARGET_TYPE_SERVER (1<<17)
+/* Sent by the server in the Type 2 message to indicate that the target
+ authentication realm is a server. */
+
+#define NTLMFLAG_TARGET_TYPE_SHARE (1<<18)
+/* Sent by the server in the Type 2 message to indicate that the target
+ authentication realm is a share. Presumably, this is for share-level
+ authentication. Usage is unclear. */
+
+#define NTLMFLAG_NEGOTIATE_NTLM2_KEY (1<<19)
+/* Indicates that the NTLM2 signing and sealing scheme should be used for
+ protecting authenticated communications. */
+
+#define NTLMFLAG_REQUEST_INIT_RESPONSE (1<<20)
+/* unknown purpose */
+
+#define NTLMFLAG_REQUEST_ACCEPT_RESPONSE (1<<21)
+/* unknown purpose */
+
+#define NTLMFLAG_REQUEST_NONNT_SESSION_KEY (1<<22)
+/* unknown purpose */
+
+#define NTLMFLAG_NEGOTIATE_TARGET_INFO (1<<23)
+/* Sent by the server in the Type 2 message to indicate that it is including a
+ Target Information block in the message. */
+
+/* unknown (1<24) */
+/* unknown (1<25) */
+/* unknown (1<26) */
+/* unknown (1<27) */
+/* unknown (1<28) */
+
+#define NTLMFLAG_NEGOTIATE_128 (1<<29)
+/* Indicates that 128-bit encryption is supported. */
+
+#define NTLMFLAG_NEGOTIATE_KEY_EXCHANGE (1<<30)
+/* unknown purpose */
+
+#define NTLMFLAG_NEGOTIATE_56 (1<<31)
+/* Indicates that 56-bit encryption is supported. */
+#endif
diff --git a/Source/CTest/Curl/if2ip.c b/Source/CTest/Curl/if2ip.c
index 00fb9fb..0587951 100644
--- a/Source/CTest/Curl/if2ip.c
+++ b/Source/CTest/Curl/if2ip.c
@@ -1,16 +1,16 @@
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -27,12 +27,12 @@
#include <stdlib.h>
#include <string.h>
-
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
-#if ! defined(WIN32) && ! defined(__BEOS__) && !defined(__CYGWIN32__)
+#if !defined(WIN32) && !defined(__BEOS__) && !defined(__CYGWIN32__) && \
+ !defined(__riscos__) && !defined(__INTERIX) && !defined(NETWARE)
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
@@ -51,7 +51,9 @@
#ifdef HAVE_NET_IF_H
#include <net/if.h>
#endif
+#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
+#endif
/* -- if2ip() -- */
#ifdef HAVE_NETDB_H
@@ -62,27 +64,27 @@
#include <sys/sockio.h>
#endif
-#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
+#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
#include "inet_ntoa_r.h"
#endif
#ifdef VMS
-#define IOCTL_3_ARGS
#include <inet.h>
#endif
+#include "if2ip.h"
+#include "memory.h"
+
/* The last #include file should be: */
-#ifdef MALLOCDEBUG
#include "memdebug.h"
-#endif
#define SYS_ERROR -1
-char *Curl_if2ip(char *interface, char *buf, int buf_size)
+char *Curl_if2ip(const char *interface, char *buf, int buf_size)
{
int dummy;
char *ip=NULL;
-
+
if(!interface)
return NULL;
@@ -92,8 +94,11 @@ char *Curl_if2ip(char *interface, char *buf, int buf_size)
}
else {
struct ifreq req;
+ size_t len = strlen(interface);
memset(&req, 0, sizeof(req));
- strcpy(req.ifr_name, interface);
+ if(len >= sizeof(req.ifr_name))
+ return NULL; /* this can't be a fine interface name */
+ memcpy(req.ifr_name, interface, len+1);
req.ifr_addr.sa_family = AF_INET;
#ifdef IOCTL_3_ARGS
if (SYS_ERROR == ioctl(dummy, SIOCGIFADDR, &req)) {
@@ -106,9 +111,7 @@ char *Curl_if2ip(char *interface, char *buf, int buf_size)
else {
struct in_addr in;
- struct sockaddr_in *s;
- struct sockaddr *sadd = &req.ifr_dstaddr;
- memcpy(&s, &sadd, sizeof(struct sockaddr_in*));
+ struct sockaddr_in *s = (struct sockaddr_in *)&req.ifr_dstaddr;
memcpy(&in, &(s->sin_addr.s_addr), sizeof(in));
#if defined(HAVE_INET_NTOA_R)
ip = inet_ntoa_r(in,buf,buf_size);
@@ -124,13 +127,11 @@ char *Curl_if2ip(char *interface, char *buf, int buf_size)
/* -- end of if2ip() -- */
#else
-#define if2ip(x) NULL
+char *Curl_if2ip(const char *interface, char *buf, int buf_size)
+{
+ (void) interface;
+ (void) buf;
+ (void) buf_size;
+ return NULL;
+}
#endif
-
-/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
- */
diff --git a/Source/CTest/Curl/if2ip.h b/Source/CTest/Curl/if2ip.h
index 3cb0a46..45a1805 100644
--- a/Source/CTest/Curl/if2ip.h
+++ b/Source/CTest/Curl/if2ip.h
@@ -1,18 +1,18 @@
#ifndef __IF2IP_H
#define __IF2IP_H
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -24,8 +24,9 @@
***************************************************************************/
#include "setup.h"
-#if ! defined(WIN32) && ! defined(__BEOS__) && !defined(__CYGWIN32__)
-extern char *Curl_if2ip(char *interface, char *buf, int buf_size);
+#if !defined(WIN32) && !defined(__BEOS__) && !defined(__CYGWIN32__) && \
+ !defined(__riscos__) && !defined(__INTERIX)
+extern char *Curl_if2ip(const char *interface, char *buf, int buf_size);
#else
#define Curl_if2ip(a,b,c) NULL
#endif
@@ -62,7 +63,7 @@ struct ifreq {
#define ifr_metric ifr_ifru.ifru_metric /* metric */
#define ifr_mtu ifr_ifru.ifru_mtu /* mtu */
-#define SIOCGIFADDR _IOW('s', 102, struct ifreq) /* Get if addr */
+#define SIOCGIFADDR _IOW('s', 102, struct ifreq) /* Get if addr */
#endif /* interix */
#endif
diff --git a/Source/CTest/Curl/inet_ntop.c b/Source/CTest/Curl/inet_ntop.c
new file mode 100644
index 0000000..6b15c02
--- /dev/null
+++ b/Source/CTest/Curl/inet_ntop.c
@@ -0,0 +1,198 @@
+/*
+ * Original code by Paul Vixie. "curlified" by Gisle Vanem.
+ */
+
+#include "setup.h"
+
+#ifndef HAVE_INET_NTOP
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include "inet_ntop.h"
+
+#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
+/* this platform has a inet_ntoa_r() function, but no proto declared anywhere
+ so we include our own proto to make compilers happy */
+#include "inet_ntoa_r.h"
+#endif
+
+#define IN6ADDRSZ 16
+#define INADDRSZ 4
+#define INT16SZ 2
+
+#ifdef WIN32
+#define EAFNOSUPPORT WSAEAFNOSUPPORT
+#define SET_ERRNO(e) WSASetLastError(errno = (e))
+#else
+#define SET_ERRNO(e) errno = e
+#endif
+
+/*
+ * Format an IPv4 address, more or less like inet_ntoa().
+ *
+ * Returns `dst' (as a const)
+ * Note:
+ * - uses no statics
+ * - takes a u_char* not an in_addr as input
+ */
+static const char *inet_ntop4 (const u_char *src, char *dst, size_t size)
+{
+#ifdef HAVE_INET_NTOA_R
+ return inet_ntoa_r(*(struct in_addr*)src, dst, size);
+#else
+ const char *addr = inet_ntoa(*(struct in_addr*)src);
+
+ if (strlen(addr) >= size)
+ {
+ SET_ERRNO(ENOSPC);
+ return (NULL);
+ }
+ return strcpy(dst, addr);
+#endif
+}
+
+#ifdef ENABLE_IPV6
+/*
+ * Convert IPv6 binary address into presentation (printable) format.
+ */
+static const char *inet_ntop6 (const u_char *src, char *dst, size_t size)
+{
+ /*
+ * Note that int32_t and int16_t need only be "at least" large enough
+ * to contain a value of the specified size. On some systems, like
+ * Crays, there is no such thing as an integer variable with 16 bits.
+ * Keep this in mind if you think this function should have been coded
+ * to use pointer overlays. All the world's not a VAX.
+ */
+ char tmp [sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
+ char *tp;
+ struct {
+ long base;
+ long len;
+ } best, cur;
+ u_long words [IN6ADDRSZ / INT16SZ];
+ int i;
+
+ /* Preprocess:
+ * Copy the input (bytewise) array into a wordwise array.
+ * Find the longest run of 0x00's in src[] for :: shorthanding.
+ */
+ memset(words, 0, sizeof(words));
+ for (i = 0; i < IN6ADDRSZ; i++)
+ words[i/2] |= (src[i] << ((1 - (i % 2)) << 3));
+
+ best.base = -1;
+ cur.base = -1;
+ for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++)
+ {
+ if (words[i] == 0)
+ {
+ if (cur.base == -1)
+ cur.base = i, cur.len = 1;
+ else
+ cur.len++;
+ }
+ else if (cur.base != -1)
+ {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ cur.base = -1;
+ }
+ }
+ if ((cur.base != -1) && (best.base == -1 || cur.len > best.len))
+ best = cur;
+ if (best.base != -1 && best.len < 2)
+ best.base = -1;
+
+ /* Format the result.
+ */
+ tp = tmp;
+ for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++)
+ {
+ /* Are we inside the best run of 0x00's?
+ */
+ if (best.base != -1 && i >= best.base && i < (best.base + best.len))
+ {
+ if (i == best.base)
+ *tp++ = ':';
+ continue;
+ }
+
+ /* Are we following an initial run of 0x00s or any real hex?
+ */
+ if (i != 0)
+ *tp++ = ':';
+
+ /* Is this address an encapsulated IPv4?
+ */
+ 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);
+ return (NULL);
+ }
+ tp += strlen(tp);
+ break;
+ }
+ tp += snprintf(tp, 5, "%lx", words[i]);
+ }
+
+ /* Was it a trailing run of 0x00's?
+ */
+ if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ))
+ *tp++ = ':';
+ *tp++ = '\0';
+
+ /* Check for overflow, copy, and we're done.
+ */
+ if ((size_t)(tp - tmp) > size)
+ {
+ SET_ERRNO(ENOSPC);
+ return (NULL);
+ }
+ return strcpy (dst, tmp);
+}
+#endif /* ENABLE_IPV6 */
+
+/*
+ * Convert a network format address to presentation format.
+ *
+ * Returns pointer to presentation format address (`dst'),
+ * Returns NULL on error (see errno).
+ */
+const char *Curl_inet_ntop(int af, const void *src, char *buf, size_t size)
+{
+ switch (af) {
+ case AF_INET:
+ return inet_ntop4((const u_char*)src, buf, size);
+#ifdef ENABLE_IPV6
+ case AF_INET6:
+ return inet_ntop6((const u_char*)src, buf, size);
+#endif
+ default:
+ SET_ERRNO(EAFNOSUPPORT);
+ return NULL;
+ }
+}
+#endif /* HAVE_INET_NTOP */
diff --git a/Source/CTest/Curl/inet_ntop.h b/Source/CTest/Curl/inet_ntop.h
new file mode 100644
index 0000000..5948a12
--- /dev/null
+++ b/Source/CTest/Curl/inet_ntop.h
@@ -0,0 +1,37 @@
+#ifndef __INET_NTOP_H
+#define __INET_NTOP_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#ifdef HAVE_INET_NTOP
+#define Curl_inet_ntop(af,addr,buf,size) inet_ntop(af,addr,buf,size)
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#else
+const char *Curl_inet_ntop(int af, const void *addr, char *buf, size_t size);
+#endif
+
+#endif /* __INET_NTOP_H */
diff --git a/Source/CTest/Curl/inet_pton.c b/Source/CTest/Curl/inet_pton.c
new file mode 100644
index 0000000..5e8e9b3
--- /dev/null
+++ b/Source/CTest/Curl/inet_pton.c
@@ -0,0 +1,240 @@
+/* This is from the BIND 4.9.4 release, modified to compile by itself */
+
+/* Copyright (c) 1996 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#include "setup.h"
+
+#ifndef HAVE_INET_PTON
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+#include "inet_pton.h"
+
+#define IN6ADDRSZ 16
+#define INADDRSZ 4
+#define INT16SZ 2
+
+#ifdef WIN32
+#define EAFNOSUPPORT WSAEAFNOSUPPORT
+#endif
+
+/*
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+static int inet_pton4(const char *src, unsigned char *dst);
+#ifdef ENABLE_IPV6
+static int inet_pton6(const char *src, unsigned char *dst);
+#endif
+
+/* int
+ * inet_pton(af, src, dst)
+ * convert from presentation format (which usually means ASCII printable)
+ * to network format (which is usually some kind of binary format).
+ * return:
+ * 1 if the address was valid for the specified address family
+ * 0 if the address wasn't valid (`dst' is untouched in this case)
+ * -1 if some other error occurred (`dst' is untouched in this case, too)
+ * author:
+ * Paul Vixie, 1996.
+ */
+int
+Curl_inet_pton(int af, const char *src, void *dst)
+{
+ switch (af) {
+ case AF_INET:
+ return (inet_pton4(src, dst));
+#ifdef ENABLE_IPV6
+#ifndef AF_INET6
+#define AF_INET6 AF_MAX+1 /* just to let this compile */
+#endif
+ case AF_INET6:
+ return (inet_pton6(src, dst));
+#endif
+ default:
+ errno = EAFNOSUPPORT;
+ return (-1);
+ }
+ /* NOTREACHED */
+}
+
+/* int
+ * inet_pton4(src, dst)
+ * like inet_aton() but without all the hexadecimal and shorthand.
+ * return:
+ * 1 if `src' is a valid dotted quad, else 0.
+ * notice:
+ * does not touch `dst' unless it's returning 1.
+ * author:
+ * Paul Vixie, 1996.
+ */
+static int
+inet_pton4(const char *src, unsigned char *dst)
+{
+ static const char digits[] = "0123456789";
+ int saw_digit, octets, ch;
+ unsigned char tmp[INADDRSZ], *tp;
+
+ saw_digit = 0;
+ octets = 0;
+ *(tp = tmp) = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr(digits, ch)) != NULL) {
+ u_int new = *tp * 10 + (pch - digits);
+
+ if (new > 255)
+ return (0);
+ *tp = new;
+ if (! saw_digit) {
+ if (++octets > 4)
+ return (0);
+ saw_digit = 1;
+ }
+ } else if (ch == '.' && saw_digit) {
+ if (octets == 4)
+ return (0);
+ *++tp = 0;
+ saw_digit = 0;
+ } else
+ return (0);
+ }
+ if (octets < 4)
+ return (0);
+ /* bcopy(tmp, dst, INADDRSZ); */
+ memcpy(dst, tmp, INADDRSZ);
+ return (1);
+}
+
+#ifdef ENABLE_IPV6
+/* int
+ * inet_pton6(src, dst)
+ * convert presentation level address to network order binary form.
+ * return:
+ * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
+ * notice:
+ * (1) does not touch `dst' unless it's returning 1.
+ * (2) :: in a full address is silently ignored.
+ * credit:
+ * inspired by Mark Andrews.
+ * author:
+ * Paul Vixie, 1996.
+ */
+static int
+inet_pton6(const char *src, unsigned char *dst)
+{
+ static const char xdigits_l[] = "0123456789abcdef",
+ xdigits_u[] = "0123456789ABCDEF";
+ unsigned char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
+ const char *xdigits, *curtok;
+ int ch, saw_xdigit;
+ u_int val;
+
+ memset((tp = tmp), 0, IN6ADDRSZ);
+ endp = tp + IN6ADDRSZ;
+ colonp = NULL;
+ /* Leading :: requires some special handling. */
+ if (*src == ':')
+ if (*++src != ':')
+ return (0);
+ curtok = src;
+ saw_xdigit = 0;
+ val = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+ pch = strchr((xdigits = xdigits_u), ch);
+ if (pch != NULL) {
+ val <<= 4;
+ val |= (pch - xdigits);
+ if (val > 0xffff)
+ return (0);
+ saw_xdigit = 1;
+ continue;
+ }
+ if (ch == ':') {
+ curtok = src;
+ if (!saw_xdigit) {
+ if (colonp)
+ return (0);
+ colonp = tp;
+ continue;
+ }
+ if (tp + INT16SZ > endp)
+ return (0);
+ *tp++ = (unsigned char) (val >> 8) & 0xff;
+ *tp++ = (unsigned char) val & 0xff;
+ saw_xdigit = 0;
+ val = 0;
+ continue;
+ }
+ if (ch == '.' && ((tp + INADDRSZ) <= endp) &&
+ inet_pton4(curtok, tp) > 0) {
+ tp += INADDRSZ;
+ saw_xdigit = 0;
+ break; /* '\0' was seen by inet_pton4(). */
+ }
+ return (0);
+ }
+ if (saw_xdigit) {
+ if (tp + INT16SZ > endp)
+ return (0);
+ *tp++ = (unsigned char) (val >> 8) & 0xff;
+ *tp++ = (unsigned char) val & 0xff;
+ }
+ if (colonp != NULL) {
+ /*
+ * Since some memmove()'s erroneously fail to handle
+ * overlapping regions, we'll do the shift by hand.
+ */
+ const int n = tp - colonp;
+ int i;
+
+ for (i = 1; i <= n; i++) {
+ endp[- i] = colonp[n - i];
+ colonp[n - i] = 0;
+ }
+ tp = endp;
+ }
+ if (tp != endp)
+ return (0);
+ /* bcopy(tmp, dst, IN6ADDRSZ); */
+ memcpy(dst, tmp, IN6ADDRSZ);
+ return (1);
+}
+#endif /* ENABLE_IPV6 */
+
+#endif /* HAVE_INET_PTON */
diff --git a/Source/CTest/Curl/getpass.h b/Source/CTest/Curl/inet_pton.h
index 475d275..b0a70d4 100644
--- a/Source/CTest/Curl/getpass.h
+++ b/Source/CTest/Curl/inet_pton.h
@@ -1,5 +1,5 @@
-#ifndef __GETPASS_H
-#define __GETPASS_H
+#ifndef __INET_PTON_H
+#define __INET_PTON_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -22,14 +22,16 @@
*
* $Id$
***************************************************************************/
-#ifndef HAVE_GETPASS_R
-/* If there's a system-provided function named like this, we trust it is
- also found in one of the standard headers. */
-/*
- * Returning NULL will abort the continued operation!
- */
-char* getpass_r(const char *prompt, char* buffer, size_t buflen );
-#endif
+#include "setup.h"
+#ifdef HAVE_INET_PTON
+#define Curl_inet_pton(x,y,z) inet_pton(x,y,z)
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#else
+int Curl_inet_pton(int, const char *, void *);
#endif
+
+#endif /* __INET_PTON_H */
diff --git a/Source/CTest/Curl/krb4.c b/Source/CTest/Curl/krb4.c
index af8fc87..904ca77 100644
--- a/Source/CTest/Curl/krb4.c
+++ b/Source/CTest/Curl/krb4.c
@@ -10,22 +10,22 @@
* Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
- *
+ *
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -41,15 +41,17 @@
#include "setup.h"
#ifndef CURL_DISABLE_FTP
-#ifdef KRB4
+#ifdef HAVE_KRB4
#include "security.h"
#include "base64.h"
#include <stdlib.h>
+#ifdef HAVE_NETDB_H
#include <netdb.h>
-#include <syslog.h>
+#endif
#include <string.h>
#include <krb.h>
+#include <des.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h> /* for getpid() */
@@ -57,27 +59,27 @@
#include "ftp.h"
#include "sendf.h"
+#include "krb4.h"
+#include "memory.h"
#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
#include "inet_ntoa_r.h"
#endif
/* The last #include file should be: */
-#ifdef MALLOCDEBUG
#include "memdebug.h"
-#endif
#define LOCAL_ADDR (&conn->local_addr)
-#define REMOTE_ADDR (&conn->serv_addr)
+#define REMOTE_ADDR conn->ip_addr->ai_addr
#define myctladdr LOCAL_ADDR
#define hisctladdr REMOTE_ADDR
struct krb4_data {
- des_cblock key;
- des_key_schedule schedule;
- char name[ANAME_SZ];
- char instance[INST_SZ];
- char realm[REALM_SZ];
+ des_cblock key;
+ des_key_schedule schedule;
+ char name[ANAME_SZ];
+ char instance[INST_SZ];
+ char realm[REALM_SZ];
};
#ifndef HAVE_STRLCPY
@@ -85,18 +87,18 @@ struct krb4_data {
static size_t
strlcpy (char *dst, const char *src, size_t dst_sz)
{
- size_t n;
- char *p;
-
- for (p = dst, n = 0;
- n + 1 < dst_sz && *src != '\0';
- ++p, ++src, ++n)
- *p = *src;
- *p = '\0';
- if (*src == '\0')
- return n;
- else
- return n + strlen (src);
+ size_t n;
+ char *p;
+
+ for (p = dst, n = 0;
+ n + 1 < dst_sz && *src != '\0';
+ ++p, ++src, ++n)
+ *p = *src;
+ *p = '\0';
+ if (*src == '\0')
+ return n;
+ else
+ return n + strlen (src);
}
#else
size_t strlcpy (char *dst, const char *src, size_t dst_sz);
@@ -115,24 +117,25 @@ static int
krb4_decode(void *app_data, void *buf, int len, int level,
struct connectdata *conn)
{
- MSG_DAT m;
- int e;
- struct krb4_data *d = app_data;
-
- if(level == prot_safe)
- e = krb_rd_safe(buf, len, &d->key,
- (struct sockaddr_in *)REMOTE_ADDR,
- (struct sockaddr_in *)LOCAL_ADDR, &m);
- else
- e = krb_rd_priv(buf, len, d->schedule, &d->key,
- (struct sockaddr_in *)REMOTE_ADDR,
- (struct sockaddr_in *)LOCAL_ADDR, &m);
- if(e){
- syslog(LOG_ERR, "krb4_decode: %s", krb_get_err_text(e));
- return -1;
- }
- memmove(buf, m.app_data, m.app_length);
- return m.app_length;
+ MSG_DAT m;
+ int e;
+ struct krb4_data *d = app_data;
+
+ if(level == prot_safe)
+ e = krb_rd_safe(buf, len, &d->key,
+ (struct sockaddr_in *)REMOTE_ADDR,
+ (struct sockaddr_in *)LOCAL_ADDR, &m);
+ else
+ e = krb_rd_priv(buf, len, d->schedule, &d->key,
+ (struct sockaddr_in *)REMOTE_ADDR,
+ (struct sockaddr_in *)LOCAL_ADDR, &m);
+ if(e) {
+ struct SessionHandle *data = conn->data;
+ infof(data, "krb4_decode: %s\n", krb_get_err_text(e));
+ return -1;
+ }
+ memmove(buf, m.app_data, m.app_length);
+ return m.app_length;
}
static int
@@ -149,44 +152,48 @@ static int
krb4_encode(void *app_data, void *from, int length, int level, void **to,
struct connectdata *conn)
{
- struct krb4_data *d = app_data;
- *to = malloc(length + 31);
- if(level == prot_safe)
- return krb_mk_safe(from, *to, length, &d->key,
- (struct sockaddr_in *)LOCAL_ADDR,
- (struct sockaddr_in *)REMOTE_ADDR);
- else if(level == prot_private)
- return krb_mk_priv(from, *to, length, d->schedule, &d->key,
- (struct sockaddr_in *)LOCAL_ADDR,
- (struct sockaddr_in *)REMOTE_ADDR);
- else
- return -1;
+ struct krb4_data *d = app_data;
+ *to = malloc(length + 31);
+ if(level == prot_safe)
+ return krb_mk_safe(from, *to, length, &d->key,
+ (struct sockaddr_in *)LOCAL_ADDR,
+ (struct sockaddr_in *)REMOTE_ADDR);
+ else if(level == prot_private)
+ return krb_mk_priv(from, *to, length, d->schedule, &d->key,
+ (struct sockaddr_in *)LOCAL_ADDR,
+ (struct sockaddr_in *)REMOTE_ADDR);
+ else
+ return -1;
}
static int
-mk_auth(struct krb4_data *d, KTEXT adat,
+mk_auth(struct krb4_data *d, KTEXT adat,
const char *service, char *host, int checksum)
{
- int ret;
- CREDENTIALS cred;
- char sname[SNAME_SZ], inst[INST_SZ], realm[REALM_SZ];
-
- strlcpy(sname, service, sizeof(sname));
- strlcpy(inst, krb_get_phost(host), sizeof(inst));
- strlcpy(realm, krb_realmofhost(host), sizeof(realm));
- ret = krb_mk_req(adat, sname, inst, realm, checksum);
- if(ret)
- return ret;
- strlcpy(sname, service, sizeof(sname));
- strlcpy(inst, krb_get_phost(host), sizeof(inst));
- strlcpy(realm, krb_realmofhost(host), sizeof(realm));
- ret = krb_get_cred(sname, inst, realm, &cred);
- memmove(&d->key, &cred.session, sizeof(des_cblock));
- des_key_sched(&d->key, d->schedule);
- memset(&cred, 0, sizeof(cred));
+ int ret;
+ CREDENTIALS cred;
+ char sname[SNAME_SZ], inst[INST_SZ], realm[REALM_SZ];
+
+ strlcpy(sname, service, sizeof(sname));
+ strlcpy(inst, krb_get_phost(host), sizeof(inst));
+ strlcpy(realm, krb_realmofhost(host), sizeof(realm));
+ ret = krb_mk_req(adat, sname, inst, realm, checksum);
+ if(ret)
return ret;
+ strlcpy(sname, service, sizeof(sname));
+ strlcpy(inst, krb_get_phost(host), sizeof(inst));
+ strlcpy(realm, krb_realmofhost(host), sizeof(realm));
+ ret = krb_get_cred(sname, inst, realm, &cred);
+ memmove(&d->key, &cred.session, sizeof(des_cblock));
+ des_key_sched(&d->key, d->schedule);
+ memset(&cred, 0, sizeof(cred));
+ return ret;
}
+#ifdef HAVE_KRB_GET_OUR_IP_FOR_REALM
+int krb_get_our_ip_for_realm(char *, struct in_addr *);
+#endif
+
static int
krb4_auth(void *app_data, struct connectdata *conn)
{
@@ -198,13 +205,13 @@ krb4_auth(void *app_data, struct connectdata *conn)
int checksum;
u_int32_t cs;
struct krb4_data *d = app_data;
- char *host = conn->hostname;
+ char *host = conn->host.name;
ssize_t nread;
int l = sizeof(conn->local_addr);
struct SessionHandle *data = conn->data;
CURLcode result;
- if(getsockname(conn->firstsocket,
+ if(getsockname(conn->sock[FIRSTSOCKET],
(struct sockaddr *)LOCAL_ADDR, &l) < 0)
perror("getsockname()");
@@ -216,7 +223,7 @@ krb4_auth(void *app_data, struct connectdata *conn)
Curl_infof(data, "%s\n", krb_get_err_text(ret));
return AUTH_CONTINUE;
}
-
+
#ifdef HAVE_KRB_GET_OUR_IP_FOR_REALM
if (krb_get_config_bool("nat_in_use")) {
struct sockaddr_in *localaddr = (struct sockaddr_in *)LOCAL_ADDR;
@@ -242,7 +249,7 @@ krb4_auth(void *app_data, struct connectdata *conn)
}
#endif
- if(Curl_base64_encode(adat.dat, adat.length, &p) < 0) {
+ if(Curl_base64_encode((char *)adat.dat, adat.length, &p) < 1) {
Curl_failf(data, "Out of memory base64-encoding");
return AUTH_CONTINUE;
}
@@ -268,17 +275,17 @@ krb4_auth(void *app_data, struct connectdata *conn)
return AUTH_ERROR;
}
p += 5;
- len = Curl_base64_decode(p, adat.dat);
+ len = Curl_base64_decode(p, (char *)adat.dat);
if(len < 0) {
Curl_failf(data, "Failed to decode base64 from server");
return AUTH_ERROR;
}
adat.length = len;
- ret = krb_rd_safe(adat.dat, adat.length, &d->key,
- (struct sockaddr_in *)hisctladdr,
+ ret = krb_rd_safe(adat.dat, adat.length, &d->key,
+ (struct sockaddr_in *)hisctladdr,
(struct sockaddr_in *)myctladdr, &msg_data);
if(ret) {
- Curl_failf(data, "Error reading reply from server: %s",
+ Curl_failf(data, "Error reading reply from server: %s",
krb_get_err_text(ret));
return AUTH_ERROR;
}
@@ -317,7 +324,7 @@ CURLcode Curl_krb_kauth(struct connectdata *conn)
save = Curl_set_command_prot(conn, prot_private);
- result = Curl_ftpsendf(conn, "SITE KAUTH %s", conn->data->state.user);
+ result = Curl_ftpsendf(conn, "SITE KAUTH %s", conn->user);
if(result)
return result;
@@ -328,7 +335,7 @@ CURLcode Curl_krb_kauth(struct connectdata *conn)
if(conn->data->state.buffer[0] != '3'){
Curl_set_command_prot(conn, save);
- return;
+ return CURLE_FTP_WEIRD_SERVER_REPLY;
}
p = strstr(conn->data->state.buffer, "T=");
@@ -339,7 +346,7 @@ CURLcode Curl_krb_kauth(struct connectdata *conn)
}
p += 2;
- tmp = Curl_base64_decode(p, &tkt.dat);
+ tmp = Curl_base64_decode(p, (char *)tkt.dat);
if(tmp < 0) {
Curl_failf(conn->data, "Failed to decode base64 in reply.\n");
Curl_set_command_prot(conn, save);
@@ -347,7 +354,7 @@ CURLcode Curl_krb_kauth(struct connectdata *conn)
}
tkt.length = tmp;
tktcopy.length = tkt.length;
-
+
p = strstr(conn->data->state.buffer, "P=");
if(!p) {
Curl_failf(conn->data, "Bad reply from server");
@@ -358,26 +365,26 @@ CURLcode Curl_krb_kauth(struct connectdata *conn)
for(; *p && *p != ' ' && *p != '\r' && *p != '\n'; p++);
*p = 0;
- des_string_to_key (conn->data->state.passwd, &key);
+ des_string_to_key (conn->passwd, &key);
des_key_sched(&key, schedule);
-
- des_pcbc_encrypt((des_cblock*)tkt.dat, (des_cblock*)tktcopy.dat,
+
+ des_pcbc_encrypt((void *)tkt.dat, (void *)tktcopy.dat,
tkt.length,
schedule, &key, DES_DECRYPT);
if (strcmp ((char*)tktcopy.dat + 8,
KRB_TICKET_GRANTING_TICKET) != 0) {
- afs_string_to_key (passwd,
- krb_realmofhost(conn->hostname),
- &key);
- des_key_sched (&key, schedule);
- des_pcbc_encrypt((des_cblock*)tkt.dat, (des_cblock*)tktcopy.dat,
+ afs_string_to_key(passwd,
+ krb_realmofhost(conn->host.name),
+ &key);
+ des_key_sched(&key, schedule);
+ des_pcbc_encrypt((void *)tkt.dat, (void *)tktcopy.dat,
tkt.length,
schedule, &key, DES_DECRYPT);
}
memset(key, 0, sizeof(key));
memset(schedule, 0, sizeof(schedule));
memset(passwd, 0, sizeof(passwd));
- if(Curl_base64_encode(tktcopy.dat, tktcopy.length, &p) < 0) {
+ if(Curl_base64_encode((char *)tktcopy.dat, tktcopy.length, &p) < 1) {
failf(conn->data, "Out of memory base64-encoding.");
Curl_set_command_prot(conn, save);
return CURLE_OUT_OF_MEMORY;
@@ -397,13 +404,5 @@ CURLcode Curl_krb_kauth(struct connectdata *conn)
return CURLE_OK;
}
-#endif /* KRB4 */
+#endif /* HAVE_KRB4 */
#endif /* CURL_DISABLE_FTP */
-
-/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
- */
diff --git a/Source/CTest/Curl/krb4.h b/Source/CTest/Curl/krb4.h
index ad314b5..cded35b 100644
--- a/Source/CTest/Curl/krb4.h
+++ b/Source/CTest/Curl/krb4.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
diff --git a/Source/CTest/Curl/ldap.c b/Source/CTest/Curl/ldap.c
index 3cb28fb..8a87664 100644
--- a/Source/CTest/Curl/ldap.c
+++ b/Source/CTest/Curl/ldap.c
@@ -1,16 +1,16 @@
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -34,14 +34,18 @@
#include <sys/stat.h>
#include <errno.h>
-#if defined(WIN32) && !defined(__GNUC__)
-#else
-# ifdef HAVE_UNISTD_H
-# include <unistd.h>
-# endif
-# ifdef HAVE_DLFCN_H
-# include <dlfcn.h>
-# endif
+#if defined(WIN32)
+# include <windows.h>
+# include <malloc.h>
+# include <WinLdap.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_DLFCN_H
+# include <dlfcn.h>
#endif
#include "urldata.h"
@@ -49,28 +53,63 @@
#include "sendf.h"
#include "escape.h"
#include "transfer.h"
+#include "strequal.h"
+#include "strtok.h"
+#include "ldap.h"
+#include "memory.h"
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
-#define DYNA_GET_FUNCTION(type, fnc) \
- { \
- union { void* ptr; type; } u; \
- u.ptr = DynaGetFunction(#fnc); \
- (fnc) = u.fptr; \
- if ((fnc) == NULL) { \
- return CURLE_FUNCTION_NOT_FOUND; \
- } \
- }
+#include "memdebug.h"
+
+/* WLdap32.dll functions are *not* stdcall. Must call these via __cdecl
+ * pointers in case libcurl was compiled as fastcall (-Gr).
+ */
+#if !defined(WIN32) && !defined(__cdecl)
+#define __cdecl
+#endif
+
+#ifndef LDAP_SIZELIMIT_EXCEEDED
+#define LDAP_SIZELIMIT_EXCEEDED 4
+#endif
+
+#define DLOPEN_MODE RTLD_LAZY /*! assume all dlopen() implementations have
+ this */
+
+#if defined(RTLD_LAZY_GLOBAL) /* It turns out some systems use this: */
+# undef DLOPEN_MODE
+# define DLOPEN_MODE RTLD_LAZY_GLOBAL
+#elif defined(RTLD_GLOBAL)
+# undef DLOPEN_MODE
+# define DLOPEN_MODE (RTLD_LAZY | RTLD_GLOBAL)
+#endif
+
+#define DYNA_GET_FUNCTION(type, fnc) do { \
+ (fnc) = (type)DynaGetFunction(#fnc); \
+ if ((fnc) == NULL) \
+ return CURLE_FUNCTION_NOT_FOUND; \
+ } while (0)
+
+/*! CygWin etc. configure could set these, but we don't want it.
+ * Must use WLdap32.dll code.
+ */
+#if defined(WIN32)
+#undef HAVE_DLOPEN
+#undef HAVE_LIBDL
+#endif
+
+typedef void * (*dynafunc)(void *input);
/***********************************************************************
*/
static void *libldap = NULL;
+#ifndef WIN32
static void *liblber = NULL;
+#endif
-static void DynaOpen(void)
+static int DynaOpen(const char **mod_name)
{
- (void)liblber;
#if defined(HAVE_DLOPEN) || defined(HAVE_LIBDL)
if (libldap == NULL) {
/*
@@ -78,20 +117,26 @@ static void DynaOpen(void)
* liblber.so automatically, but since it does not we will
* handle it here by opening liblber.so as global.
*/
- dlopen("liblber.so",
-#ifdef RTLD_LAZY_GLOBAL /* It turns out some systems use this: */
- RTLD_LAZY_GLOBAL
-#else
-#ifdef RTLD_GLOBAL
- RTLD_LAZY | RTLD_GLOBAL
-#else
- /* and some systems don't have the RTLD_GLOBAL symbol */
- RTLD_LAZY
-#endif
-#endif
- );
- libldap = dlopen("libldap.so", RTLD_LAZY);
+ *mod_name = "liblber.so";
+ liblber = dlopen(*mod_name, DLOPEN_MODE);
+
+ /* Assume loading libldap.so will fail if loading of liblber.so failed
+ */
+ if (liblber) {
+ *mod_name = "libldap.so";
+ libldap = dlopen(*mod_name, RTLD_LAZY);
+ }
}
+ return (libldap != NULL && liblber != NULL);
+
+#elif defined(WIN32)
+ *mod_name = "wldap32.dll";
+ if (!libldap)
+ libldap = (void*)LoadLibrary(*mod_name);
+ return (libldap != NULL);
+
+#else
+ return (0);
#endif
}
@@ -106,133 +151,475 @@ static void DynaClose(void)
dlclose(liblber);
liblber=NULL;
}
+#elif defined(WIN32)
+ if (libldap) {
+ FreeLibrary ((HMODULE)libldap);
+ libldap = NULL;
+ }
#endif
}
-static void * DynaGetFunction(const char *name)
+static dynafunc DynaGetFunction(const char *name)
{
- void *func = NULL;
- (void)name;
+ dynafunc func = (dynafunc)NULL;
#if defined(HAVE_DLOPEN) || defined(HAVE_LIBDL)
if (libldap) {
- func = dlsym(libldap, name);
+ /* This typecast magic below was brought by Joe Halpin. In ISO C, you
+ * cannot typecast a data pointer to a function pointer, but that's
+ * exactly what we need to do here to avoid compiler warnings on picky
+ * compilers! */
+ *(void**) (&func) = dlsym(libldap, name);
+ }
+#elif defined(WIN32)
+ if (libldap) {
+ func = (dynafunc)GetProcAddress((HINSTANCE)libldap, name);
}
#endif
-
return func;
}
-static int WriteProc(void *param, char *text, int len)
-{
- struct SessionHandle *data = (struct SessionHandle *)param;
- len = 0; /* prevent compiler warning */
- Curl_client_write(data, CLIENTWRITE_BODY, text, 0);
- return 0;
-}
-
/***********************************************************************
*/
+typedef struct ldap_url_desc {
+ struct ldap_url_desc *lud_next;
+ char *lud_scheme;
+ char *lud_host;
+ int lud_port;
+ char *lud_dn;
+ char **lud_attrs;
+ int lud_scope;
+ char *lud_filter;
+ char **lud_exts;
+ int lud_crit_exts;
+} LDAPURLDesc;
+
+#ifdef WIN32
+static int _ldap_url_parse (const struct connectdata *conn,
+ LDAPURLDesc **ludp);
+static void _ldap_free_urldesc (LDAPURLDesc *ludp);
+
+static void (*ldap_free_urldesc)(LDAPURLDesc *) = _ldap_free_urldesc;
+#endif
+
+#ifdef DEBUG_LDAP
+ #define LDAP_TRACE(x) do { \
+ _ldap_trace ("%u: ", __LINE__); \
+ _ldap_trace x; \
+ } while (0)
+
+ static void _ldap_trace (const char *fmt, ...);
+#else
+ #define LDAP_TRACE(x) ((void)0)
+#endif
+
+
CURLcode Curl_ldap(struct connectdata *conn)
{
CURLcode status = CURLE_OK;
- int rc;
- void *(*ldap_open)(char *, int);
- int (*ldap_simple_bind_s)(void *, char *, char *);
- int (*ldap_unbind_s)(void *);
- int (*ldap_url_search_s)(void *, char *, int, void **);
- void *(*ldap_first_entry)(void *, void *);
- void *(*ldap_next_entry)(void *, void *);
- char *(*ldap_err2string)(int);
- int (*ldap_entry2text)(void *, char *, void *, void *, char **, char **, int (*)(void *, char *, int), void *, char *, int, unsigned long);
- int (*ldap_entry2html)(void *, char *, void *, void *, char **, char **, int (*)(void *, char *, int), void *, char *, int, unsigned long, char *, char *);
+ int rc = 0;
+#ifndef WIN32
+ int (*ldap_url_parse)(char *, LDAPURLDesc **);
+ void (*ldap_free_urldesc)(void *);
+#endif
+ void *(__cdecl *ldap_init)(char *, int);
+ int (__cdecl *ldap_simple_bind_s)(void *, char *, char *);
+ int (__cdecl *ldap_unbind_s)(void *);
+ int (__cdecl *ldap_search_s)(void *, char *, int, char *, char **,
+ int, void **);
+ void *(__cdecl *ldap_first_entry)(void *, void *);
+ void *(__cdecl *ldap_next_entry)(void *, void *);
+ char *(__cdecl *ldap_err2string)(int);
+ char *(__cdecl *ldap_get_dn)(void *, void *);
+ char *(__cdecl *ldap_first_attribute)(void *, void *, void **);
+ char *(__cdecl *ldap_next_attribute)(void *, void *, void *);
+ char **(__cdecl *ldap_get_values)(void *, void *, const char *);
+ void (__cdecl *ldap_value_free)(char **);
+ void (__cdecl *ldap_memfree)(void *);
+ void (__cdecl *ber_free)(void *, int);
+
void *server;
+ LDAPURLDesc *ludp = NULL;
+ const char *mod_name;
void *result;
- void *entryIterator;
-
- int ldaptext;
+ void *entryIterator; /*! type should be 'LDAPMessage *' */
+ int num = 0;
struct SessionHandle *data=conn->data;
-
- infof(data, "LDAP: %s\n", data->change.url);
- DynaOpen();
- if (libldap == NULL) {
- failf(data, "The needed LDAP library/libraries couldn't be opened");
+ infof(data, "LDAP local: %s\n", data->change.url);
+
+ if (!DynaOpen(&mod_name)) {
+ failf(data, "The %s LDAP library/libraries couldn't be opened", mod_name);
return CURLE_LIBRARY_NOT_FOUND;
}
- ldaptext = data->set.ftp_ascii; /* This is a dirty hack */
-
/* The types are needed because ANSI C distinguishes between
* pointer-to-object (data) and pointer-to-function.
*/
- DYNA_GET_FUNCTION(void *(*fptr)(char *, int), ldap_open);
- DYNA_GET_FUNCTION(int (*fptr)(void *, char *, char *), ldap_simple_bind_s);
- DYNA_GET_FUNCTION(int (*fptr)(void *), ldap_unbind_s);
- DYNA_GET_FUNCTION(int (*fptr)(void *, char *, int, void **), ldap_url_search_s);
- DYNA_GET_FUNCTION(void *(*fptr)(void *, void *), ldap_first_entry);
- DYNA_GET_FUNCTION(void *(*fptr)(void *, void *), ldap_next_entry);
- DYNA_GET_FUNCTION(char *(*fptr)(int), ldap_err2string);
- DYNA_GET_FUNCTION(int (*fptr)(void *, char *, void *, void *, char **, char **, int (*)(void *, char *, int), void *, char *, int, unsigned long), ldap_entry2text);
- DYNA_GET_FUNCTION(int (*fptr)(void *, char *, void *, void *, char **, char **, int (*)(void *, char *, int), void *, char *, int, unsigned long, char *, char *), ldap_entry2html);
-
- server = ldap_open(conn->hostname, conn->port);
+ DYNA_GET_FUNCTION(void *(*)(char *, int), ldap_init);
+ DYNA_GET_FUNCTION(int (*)(void *, char *, char *), ldap_simple_bind_s);
+ DYNA_GET_FUNCTION(int (*)(void *), ldap_unbind_s);
+#ifndef WIN32
+ DYNA_GET_FUNCTION(int (*)(char *, LDAPURLDesc **), ldap_url_parse);
+ DYNA_GET_FUNCTION(void (*)(void *), ldap_free_urldesc);
+#endif
+ DYNA_GET_FUNCTION(int (*)(void *, char *, int, char *, char **, int,
+ void **), ldap_search_s);
+ DYNA_GET_FUNCTION(void *(*)(void *, void *), ldap_first_entry);
+ DYNA_GET_FUNCTION(void *(*)(void *, void *), ldap_next_entry);
+ DYNA_GET_FUNCTION(char *(*)(int), ldap_err2string);
+ DYNA_GET_FUNCTION(char *(*)(void *, void *), ldap_get_dn);
+ DYNA_GET_FUNCTION(char *(*)(void *, void *, void **), ldap_first_attribute);
+ DYNA_GET_FUNCTION(char *(*)(void *, void *, void *), ldap_next_attribute);
+ DYNA_GET_FUNCTION(char **(*)(void *, void *, const char *), ldap_get_values);
+ DYNA_GET_FUNCTION(void (*)(char **), ldap_value_free);
+ DYNA_GET_FUNCTION(void (*)(void *), ldap_memfree);
+ DYNA_GET_FUNCTION(void (*)(void *, int), ber_free);
+
+ server = (*ldap_init)(conn->host.name, (int)conn->port);
if (server == NULL) {
- failf(data, "LDAP: Cannot connect to %s:%d",
- conn->hostname, conn->port);
+ failf(data, "LDAP local: Cannot connect to %s:%d",
+ conn->host.name, conn->port);
status = CURLE_COULDNT_CONNECT;
- } else {
- rc = ldap_simple_bind_s(server,
- conn->bits.user_passwd?data->state.user:NULL,
- conn->bits.user_passwd?data->state.passwd:NULL);
- if (rc != 0) {
- failf(data, "LDAP: %s", ldap_err2string(rc));
- status = CURLE_LDAP_CANNOT_BIND;
- } else {
- rc = ldap_url_search_s(server, data->change.url, 0, &result);
- if (rc != 0) {
- failf(data, "LDAP: %s", ldap_err2string(rc));
- status = CURLE_LDAP_SEARCH_FAILED;
- } else {
- for (entryIterator = ldap_first_entry(server, result);
- entryIterator;
- entryIterator = ldap_next_entry(server, entryIterator))
- {
- if (ldaptext) {
- rc = ldap_entry2text(server, NULL, entryIterator, NULL,
- NULL, NULL, WriteProc, data,
- (char *)"", 0, 0);
- if (rc != 0) {
- failf(data, "LDAP: %s", ldap_err2string(rc));
- status = CURLE_LDAP_SEARCH_FAILED;
- }
- } else {
- rc = ldap_entry2html(server, NULL, entryIterator, NULL,
- NULL, NULL, WriteProc, data,
- (char *)"", 0, 0, NULL, NULL);
- if (rc != 0) {
- failf(data, "LDAP: %s", ldap_err2string(rc));
- status = CURLE_LDAP_SEARCH_FAILED;
- }
- }
- }
+ goto quit;
+ }
+
+ rc = (*ldap_simple_bind_s)(server,
+ conn->bits.user_passwd ? conn->user : NULL,
+ conn->bits.user_passwd ? conn->passwd : NULL);
+ if (rc != 0) {
+ failf(data, "LDAP local: %s", (*ldap_err2string)(rc));
+ status = CURLE_LDAP_CANNOT_BIND;
+ goto quit;
+ }
+
+#ifdef WIN32
+ rc = _ldap_url_parse(conn, &ludp);
+#else
+ rc = (*ldap_url_parse)(data->change.url, &ludp);
+#endif
+
+ if (rc != 0) {
+ failf(data, "LDAP local: %s", (*ldap_err2string)(rc));
+ status = CURLE_LDAP_INVALID_URL;
+ goto quit;
+ }
+
+ rc = (*ldap_search_s)(server, ludp->lud_dn, ludp->lud_scope,
+ ludp->lud_filter, ludp->lud_attrs, 0, &result);
+
+ if (rc != 0 && rc != LDAP_SIZELIMIT_EXCEEDED) {
+ failf(data, "LDAP remote: %s", (*ldap_err2string)(rc));
+ status = CURLE_LDAP_SEARCH_FAILED;
+ goto quit;
+ }
+
+ for(num = 0, entryIterator = (*ldap_first_entry)(server, result);
+ entryIterator;
+ entryIterator = (*ldap_next_entry)(server, entryIterator), num++)
+ {
+ void *ber = NULL; /*! is really 'BerElement **' */
+ void *attribute; /*! suspicious that this isn't 'const' */
+ char *dn = (*ldap_get_dn)(server, entryIterator);
+ int i;
+
+ Curl_client_write(data, CLIENTWRITE_BODY, (char *)"DN: ", 4);
+ Curl_client_write(data, CLIENTWRITE_BODY, (char *)dn, 0);
+ Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
+
+ for (attribute = (*ldap_first_attribute)(server, entryIterator, &ber);
+ attribute;
+ attribute = (*ldap_next_attribute)(server, entryIterator, ber))
+ {
+ char **vals = (*ldap_get_values)(server, entryIterator, attribute);
+
+ if (vals != NULL)
+ {
+ for (i = 0; (vals[i] != NULL); i++)
+ {
+ Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\t", 1);
+ Curl_client_write(data, CLIENTWRITE_BODY, (char*) attribute, 0);
+ Curl_client_write(data, CLIENTWRITE_BODY, (char *)": ", 2);
+ Curl_client_write(data, CLIENTWRITE_BODY, vals[i], 0);
+ Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 0);
+ }
+
+ /* Free memory used to store values */
+ (*ldap_value_free)(vals);
}
- ldap_unbind_s(server);
+ Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
+
+ (*ldap_memfree)(attribute);
+ (*ldap_memfree)(dn);
}
+ if (ber)
+ (*ber_free)(ber, 0);
}
+
+quit:
+ LDAP_TRACE (("Received %d entries\n", num));
+ if (rc == LDAP_SIZELIMIT_EXCEEDED)
+ infof(data, "There are more than %d entries\n", num);
+ if (ludp)
+ (*ldap_free_urldesc)(ludp);
+ if (server)
+ (*ldap_unbind_s)(server);
+
DynaClose();
/* no data to transfer */
Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
-
+
return status;
}
+#ifdef DEBUG_LDAP
+static void _ldap_trace (const char *fmt, ...)
+{
+ static int do_trace = -1;
+ va_list args;
+
+ if (do_trace == -1) {
+ const char *env = getenv("CURL_TRACE");
+ do_trace = (env && atoi(env) > 0);
+ }
+ if (!do_trace)
+ return;
+
+ va_start (args, fmt);
+ vfprintf (stderr, fmt, args);
+ va_end (args);
+}
+#endif
+
+#ifdef WIN32
/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
+ * Return scope-value for a scope-string.
*/
-#endif
+static int str2scope (const char *p)
+{
+ if (!stricmp(p, "one"))
+ return LDAP_SCOPE_ONELEVEL;
+ if (!stricmp(p, "onetree"))
+ return LDAP_SCOPE_ONELEVEL;
+ if (!stricmp(p, "base"))
+ return LDAP_SCOPE_BASE;
+ if (!stricmp(p, "sub"))
+ return LDAP_SCOPE_SUBTREE;
+ if (!stricmp( p, "subtree"))
+ return LDAP_SCOPE_SUBTREE;
+ return (-1);
+}
+
+/*
+ * Split 'str' into strings separated by commas.
+ * Note: res[] points into 'str'.
+ */
+static char **split_str (char *str)
+{
+ char **res, *lasts, *s;
+ int i;
+
+ for (i = 2, s = strchr(str,','); s; i++)
+ s = strchr(++s,',');
+
+ res = calloc(i, sizeof(char*));
+ if (!res)
+ return NULL;
+
+ for (i = 0, s = strtok_r(str, ",", &lasts); s;
+ s = strtok_r(NULL, ",", &lasts), i++)
+ res[i] = s;
+ return res;
+}
+
+/*
+ * Unescape the LDAP-URL components
+ */
+static bool unescape_elements (LDAPURLDesc *ludp)
+{
+ int i;
+
+ if (ludp->lud_filter) {
+ ludp->lud_filter = curl_unescape(ludp->lud_filter, 0);
+ if (!ludp->lud_filter)
+ return (FALSE);
+ }
+
+ for (i = 0; ludp->lud_attrs && ludp->lud_attrs[i]; i++) {
+ ludp->lud_attrs[i] = curl_unescape(ludp->lud_attrs[i], 0);
+ if (!ludp->lud_attrs[i])
+ return (FALSE);
+ }
+
+ for (i = 0; ludp->lud_exts && ludp->lud_exts[i]; i++) {
+ ludp->lud_exts[i] = curl_unescape(ludp->lud_exts[i], 0);
+ if (!ludp->lud_exts[i])
+ return (FALSE);
+ }
+
+ if (ludp->lud_dn) {
+ char *dn = ludp->lud_dn;
+ char *new_dn = curl_unescape(dn, 0);
+
+ free(dn);
+ if (!new_dn)
+ return (FALSE);
+ ludp->lud_dn = new_dn;
+ }
+ return (TRUE);
+}
+
+/*
+ * Break apart the pieces of an LDAP URL.
+ * Syntax:
+ * ldap://<hostname>:<port>/<base_dn>?<attributes>?<scope>?<filter>?<ext>
+ *
+ * <hostname> already known from 'conn->host.name'.
+ * <port> already known from 'conn->remote_port'.
+ * extract the rest from 'conn->path+1'. All fields are optional. e.g.
+ * ldap://<hostname>:<port>/?<attributes>?<scope>?<filter> yields ludp->lud_dn = "".
+ *
+ * Ref. http://developer.netscape.com/docs/manuals/dirsdk/csdk30/url.htm#2831915
+ */
+static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp)
+{
+ char *p, *q;
+ int i;
+
+ if (!conn->path || conn->path[0] != '/' ||
+ !checkprefix(conn->protostr, conn->data->change.url))
+ return LDAP_INVALID_SYNTAX;
+
+ ludp->lud_scope = LDAP_SCOPE_BASE;
+ ludp->lud_port = conn->remote_port;
+ ludp->lud_host = conn->host.name;
+
+ /* parse DN (Distinguished Name).
+ */
+ ludp->lud_dn = strdup(conn->path+1);
+ if (!ludp->lud_dn)
+ return LDAP_NO_MEMORY;
+
+ p = strchr(ludp->lud_dn, '?');
+ LDAP_TRACE (("DN '%.*s'\n", p ? (size_t)(p-ludp->lud_dn) : strlen(ludp->lud_dn),
+ ludp->lud_dn));
+
+ if (!p)
+ goto success;
+
+ *p++ = '\0';
+
+ /* parse attributes. skip "??".
+ */
+ q = strchr(p, '?');
+ if (q)
+ *q++ = '\0';
+
+ if (*p && *p != '?') {
+ ludp->lud_attrs = split_str(p);
+ if (!ludp->lud_attrs)
+ return LDAP_NO_MEMORY;
+
+ for (i = 0; ludp->lud_attrs[i]; i++)
+ LDAP_TRACE (("attr[%d] '%s'\n", i, ludp->lud_attrs[i]));
+ }
+
+ p = q;
+ if (!p)
+ goto success;
+
+ /* parse scope. skip "??"
+ */
+ q = strchr(p, '?');
+ if (q)
+ *q++ = '\0';
+
+ if (*p && *p != '?') {
+ ludp->lud_scope = str2scope(p);
+ if (ludp->lud_scope == -1)
+ return LDAP_INVALID_SYNTAX;
+ LDAP_TRACE (("scope %d\n", ludp->lud_scope));
+ }
+
+ p = q;
+ if (!p)
+ goto success;
+
+ /* parse filter
+ */
+ q = strchr(p, '?');
+ if (q)
+ *q++ = '\0';
+ if (!*p)
+ return LDAP_INVALID_SYNTAX;
+
+ ludp->lud_filter = p;
+ LDAP_TRACE (("filter '%s'\n", ludp->lud_filter));
+
+ p = q;
+ if (!p)
+ goto success;
+
+ /* parse extensions
+ */
+ ludp->lud_exts = split_str(p);
+ if (!ludp->lud_exts)
+ return LDAP_NO_MEMORY;
+
+ for (i = 0; ludp->lud_exts[i]; i++)
+ LDAP_TRACE (("exts[%d] '%s'\n", i, ludp->lud_exts[i]));
+
+success:
+ if (!unescape_elements(ludp))
+ return LDAP_NO_MEMORY;
+ return LDAP_SUCCESS;
+}
+
+static int _ldap_url_parse (const struct connectdata *conn,
+ LDAPURLDesc **ludpp)
+{
+ LDAPURLDesc *ludp = calloc(sizeof(*ludp), 1);
+ int rc;
+
+ *ludpp = NULL;
+ if (!ludp)
+ return LDAP_NO_MEMORY;
+
+ rc = _ldap_url_parse2 (conn, ludp);
+ if (rc != LDAP_SUCCESS) {
+ _ldap_free_urldesc(ludp);
+ ludp = NULL;
+ }
+ *ludpp = ludp;
+ return (rc);
+}
+
+static void _ldap_free_urldesc (LDAPURLDesc *ludp)
+{
+ int i;
+
+ if (!ludp)
+ return;
+
+ if (ludp->lud_dn)
+ free(ludp->lud_dn);
+
+ if (ludp->lud_filter)
+ free(ludp->lud_filter);
+
+ if (ludp->lud_attrs) {
+ for (i = 0; ludp->lud_attrs[i]; i++)
+ free(ludp->lud_attrs[i]);
+ free(ludp->lud_attrs);
+ }
+
+ if (ludp->lud_exts) {
+ for (i = 0; ludp->lud_exts[i]; i++)
+ free(ludp->lud_exts[i]);
+ free(ludp->lud_exts);
+ }
+ free (ludp);
+}
+#endif /* WIN32 */
+#endif /* CURL_DISABLE_LDAP */
diff --git a/Source/CTest/Curl/ldap.h b/Source/CTest/Curl/ldap.h
index 2be32a8..b95cf74 100644
--- a/Source/CTest/Curl/ldap.h
+++ b/Source/CTest/Curl/ldap.h
@@ -8,7 +8,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -25,6 +25,5 @@
***************************************************************************/
#ifndef CURL_DISABLE_LDAP
CURLcode Curl_ldap(struct connectdata *conn);
-CURLcode Curl_ldap_done(struct connectdata *conn);
#endif
#endif /* __LDAP_H */
diff --git a/Source/CTest/Curl/llist.c b/Source/CTest/Curl/llist.c
index a9e65a8..9618486 100644
--- a/Source/CTest/Curl/llist.c
+++ b/Source/CTest/Curl/llist.c
@@ -1,16 +1,16 @@
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -27,12 +27,12 @@
#include <stdlib.h>
#include "llist.h"
+#include "memory.h"
-#ifdef MALLOCDEBUG
/* this must be the last include file */
#include "memdebug.h"
-#endif
-void
+
+void
Curl_llist_init(curl_llist *l, curl_llist_dtor dtor)
{
l->size = 0;
@@ -55,24 +55,31 @@ Curl_llist_alloc(curl_llist_dtor dtor)
return list;
}
+/*
+ * Curl_llist_insert_next() returns 1 on success and 0 on failure.
+ */
int
Curl_llist_insert_next(curl_llist *list, curl_llist_element *e, const void *p)
{
- curl_llist_element *ne;
+ curl_llist_element *ne =
+ (curl_llist_element *) malloc(sizeof(curl_llist_element));
+ if(!ne)
+ return 0;
- ne = (curl_llist_element *) malloc(sizeof(curl_llist_element));
ne->ptr = (void *) p;
if (list->size == 0) {
list->head = ne;
list->head->prev = NULL;
list->head->next = NULL;
list->tail = ne;
- } else {
+ }
+ else {
ne->next = e->next;
ne->prev = e;
if (e->next) {
e->next->prev = ne;
- } else {
+ }
+ else {
list->tail = ne;
}
e->next = ne;
@@ -83,34 +90,7 @@ Curl_llist_insert_next(curl_llist *list, curl_llist_element *e, const void *p)
return 1;
}
-int
-Curl_llist_insert_prev(curl_llist *list, curl_llist_element *e, const void *p)
-{
- curl_llist_element *ne;
-
- ne = (curl_llist_element *) malloc(sizeof(curl_llist_element));
- ne->ptr = (void *) p;
- if (list->size == 0) {
- list->head = ne;
- list->head->prev = NULL;
- list->head->next = NULL;
- list->tail = ne;
- } else {
- ne->next = e;
- ne->prev = e->prev;
- if (e->prev)
- e->prev->next = ne;
- else
- list->head = ne;
- e->prev = ne;
- }
-
- ++list->size;
-
- return 1;
-}
-
-int
+int
Curl_llist_remove(curl_llist *list, curl_llist_element *e, void *user)
{
if (e == NULL || list->size == 0)
@@ -138,31 +118,13 @@ Curl_llist_remove(curl_llist *list, curl_llist_element *e, void *user)
return 1;
}
-int
-Curl_llist_remove_next(curl_llist *list, curl_llist_element *e, void *user)
-{
- return Curl_llist_remove(list, e->next, user);
-}
-
-int
-Curl_llist_remove_prev(curl_llist *list, curl_llist_element *e, void *user)
-{
- return Curl_llist_remove(list, e->prev, user);
-}
-
-size_t
-Curl_llist_count(curl_llist *list)
-{
- return list->size;
-}
-
-void
+void
Curl_llist_destroy(curl_llist *list, void *user)
{
- while (list->size > 0) {
- Curl_llist_remove(list, CURL_LLIST_TAIL(list), user);
- }
+ if(list) {
+ while (list->size > 0)
+ Curl_llist_remove(list, list->tail, user);
- free(list);
- list = NULL;
+ free(list);
+ }
}
diff --git a/Source/CTest/Curl/llist.h b/Source/CTest/Curl/llist.h
index fa38e74..4f76513 100644
--- a/Source/CTest/Curl/llist.h
+++ b/Source/CTest/Curl/llist.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -53,12 +53,4 @@ int Curl_llist_remove_next(curl_llist *, curl_llist_element *, void *);
size_t Curl_llist_count(curl_llist *);
void Curl_llist_destroy(curl_llist *, void *);
-#define CURL_LLIST_HEAD(__l) ((__l)->head)
-#define CURL_LLIST_TAIL(__l) ((__l)->tail)
-#define CURL_LLIST_NEXT(__e) ((__e)->next)
-#define CURL_LLIST_PREV(__e) ((__e)->prev)
-#define CURL_LLIST_VALP(__e) ((__e)->ptr)
-#define CURL_LLIST_IS_TAIL(__e) ((__e)->next ? 0 : 1)
-#define CURL_LLIST_IS_HEAD(__e) ((__e)->prev ? 0 : 1)
-
#endif
diff --git a/Source/CTest/Curl/md5.c b/Source/CTest/Curl/md5.c
new file mode 100644
index 0000000..269726b
--- /dev/null
+++ b/Source/CTest/Curl/md5.c
@@ -0,0 +1,348 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#ifndef USE_SSLEAY
+/* This code segment is only used if OpenSSL is not provided, as if it is
+ we use the MD5-function provided there instead. No good duplicating
+ code! */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+#include <string.h>
+
+/* UINT4 defines a four byte word */
+typedef unsigned int UINT4;
+
+/* MD5 context. */
+struct md5_ctx {
+ UINT4 state[4]; /* state (ABCD) */
+ UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ unsigned char buffer[64]; /* input buffer */
+};
+
+typedef struct md5_ctx MD5_CTX;
+
+static void MD5_Init(struct md5_ctx *);
+static void MD5_Update(struct md5_ctx *, unsigned char *, unsigned int);
+static void MD5_Final(unsigned char [16], struct md5_ctx *);
+
+/* Constants for MD5Transform routine.
+ */
+
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+static void MD5Transform(UINT4 [4], unsigned char [64]);
+static void Encode(unsigned char *, UINT4 *, unsigned int);
+static void Decode(UINT4 *, unsigned char *, unsigned int);
+
+static unsigned char PADDING[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context.
+ */
+static void MD5_Init(struct md5_ctx *context)
+{
+ context->count[0] = context->count[1] = 0;
+ /* Load magic initialization constants. */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xefcdab89;
+ context->state[2] = 0x98badcfe;
+ context->state[3] = 0x10325476;
+}
+
+/* MD5 block update operation. Continues an MD5 message-digest
+ operation, processing another message block, and updating the
+ context.
+ */
+static void MD5_Update (struct md5_ctx *context, /* context */
+ unsigned char *input, /* input block */
+ unsigned int inputLen)/* length of input block */
+{
+ unsigned int i, bufindex, partLen;
+
+ /* Compute number of bytes mod 64 */
+ bufindex = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+ /* Update number of bits */
+ if ((context->count[0] += ((UINT4)inputLen << 3))
+ < ((UINT4)inputLen << 3))
+ context->count[1]++;
+ context->count[1] += ((UINT4)inputLen >> 29);
+
+ partLen = 64 - bufindex;
+
+ /* Transform as many times as possible. */
+ if (inputLen >= partLen) {
+ memcpy((void *)&context->buffer[bufindex], (void *)input, partLen);
+ MD5Transform(context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ MD5Transform(context->state, &input[i]);
+
+ bufindex = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ memcpy((void *)&context->buffer[bufindex], (void *)&input[i], inputLen-i);
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+ the message digest and zeroizing the context.
+*/
+static void MD5_Final(unsigned char digest[16], /* message digest */
+ struct md5_ctx *context) /* context */
+{
+ unsigned char bits[8];
+ unsigned int count, padLen;
+
+ /* Save number of bits */
+ Encode (bits, context->count, 8);
+
+ /* Pad out to 56 mod 64. */
+ count = (unsigned int)((context->count[0] >> 3) & 0x3f);
+ padLen = (count < 56) ? (56 - count) : (120 - count);
+ MD5_Update (context, PADDING, padLen);
+
+ /* Append length (before padding) */
+ MD5_Update (context, bits, 8);
+
+ /* Store state in digest */
+ Encode (digest, context->state, 16);
+
+ /* Zeroize sensitive information. */
+ memset ((void *)context, 0, sizeof (*context));
+}
+
+/* MD5 basic transformation. Transforms state based on block. */
+static void MD5Transform(UINT4 state[4],
+ unsigned char block[64])
+{
+ UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ Decode (x, block, 64);
+
+ /* Round 1 */
+ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
+ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+
+ /* Zeroize sensitive information. */
+ memset((void *)x, 0, sizeof (x));
+}
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
+ a multiple of 4.
+ */
+static void Encode (unsigned char *output,
+ UINT4 *input,
+ unsigned int len)
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (unsigned char)(input[i] & 0xff);
+ output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+ output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+ output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+ }
+}
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+ a multiple of 4.
+*/
+static void Decode (UINT4 *output,
+ unsigned char *input,
+ unsigned int len)
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
+ (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
+
+#else
+/* If OpenSSL is present */
+#include <openssl/md5.h>
+#include <string.h>
+#endif
+
+#include "md5.h"
+
+void Curl_md5it(unsigned char *outbuffer, /* 16 bytes */
+ unsigned char *input)
+{
+ MD5_CTX ctx;
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, input, strlen((char *)input));
+ MD5_Final(outbuffer, &ctx);
+}
diff --git a/Source/CTest/Curl/md5.h b/Source/CTest/Curl/md5.h
new file mode 100644
index 0000000..12b3a5e
--- /dev/null
+++ b/Source/CTest/Curl/md5.h
@@ -0,0 +1,29 @@
+#ifndef __MD5_H
+#define __MD5_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+void Curl_md5it(unsigned char *output,
+ unsigned char *input);
+
+#endif
diff --git a/Source/CTest/Curl/memdebug.c b/Source/CTest/Curl/memdebug.c
index 996aebb..f5ef34d 100644
--- a/Source/CTest/Curl/memdebug.c
+++ b/Source/CTest/Curl/memdebug.c
@@ -1,17 +1,17 @@
-#ifdef MALLOCDEBUG
+#ifdef CURLDEBUG
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -26,13 +26,9 @@
#include <curl/curl.h>
-#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
-#include <winsock.h>
-#else /* some kind of unix */
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
-#endif
#define _MPRINTF_REPLACE
#include <curl/mprintf.h>
@@ -45,10 +41,12 @@
#include <unistd.h>
#endif
-/* DONT include memdebug.h here! */
+#define MEMDEBUG_NODEFINES /* don't redefine the standard functions */
+#include "memory.h"
+#include "memdebug.h"
struct memdebug {
- int size;
+ size_t size;
double mem[1];
/* I'm hoping this is the thing with the strictest alignment
* requirements. That also means we waste some space :-( */
@@ -62,7 +60,10 @@ struct memdebug {
* Don't use these with multithreaded test programs!
*/
-FILE *logfile;
+#define logfile curl_debuglogfile
+FILE *curl_debuglogfile;
+static bool memlimit; /* enable memory limit */
+static long memsize; /* set number of mallocs allowed */
/* this sets the log file name */
void curl_memdebug(const char *logname)
@@ -73,16 +74,54 @@ void curl_memdebug(const char *logname)
logfile = stderr;
}
+/* This function sets the number of malloc() calls that should return
+ successfully! */
+void curl_memlimit(long limit)
+{
+ memlimit = TRUE;
+ memsize = limit;
+}
+
+/* returns TRUE if this isn't allowed! */
+static bool countcheck(const char *func, int line, const char *source)
+{
+ /* if source is NULL, then the call is made internally and this check
+ should not be made */
+ if(memlimit && source) {
+ if(!memsize) {
+ if(logfile && source)
+ fprintf(logfile, "LIMIT %s:%d %s reached memlimit\n",
+ source, line, func);
+ if(source)
+ fprintf(stderr, "LIMIT %s:%d %s reached memlimit\n",
+ source, line, func);
+ return TRUE; /* RETURN ERROR! */
+ }
+ else
+ memsize--; /* countdown */
+
+ /* log the countdown */
+ if(logfile && source)
+ fprintf(logfile, "LIMIT %s:%d %ld ALLOCS left\n",
+ source, line, memsize);
+
+ }
+
+ return FALSE; /* allow this */
+}
void *curl_domalloc(size_t wantedsize, int line, const char *source)
{
struct memdebug *mem;
size_t size;
+ if(countcheck("malloc", line, source))
+ return NULL;
+
/* alloc at least 64 bytes */
size = sizeof(struct memdebug)+wantedsize;
- mem=(struct memdebug *)(malloc)(size);
+ mem=(struct memdebug *)(Curl_cmalloc)(size);
if(mem) {
/* fill memory with junk */
memset(mem->mem, 0xA5, wantedsize);
@@ -90,46 +129,78 @@ void *curl_domalloc(size_t wantedsize, int line, const char *source)
}
if(logfile && source)
- fprintf(logfile, "MEM %s:%d malloc(%d) = %p\n",
- source, line, wantedsize, mem->mem);
- return mem->mem;
+ fprintf(logfile, "MEM %s:%d malloc(%zd) = %p\n",
+ source, line, wantedsize, mem ? mem->mem : 0);
+ return (mem ? mem->mem : NULL);
+}
+
+void *curl_docalloc(size_t wanted_elements, size_t wanted_size,
+ int line, const char *source)
+{
+ struct memdebug *mem;
+ size_t size, user_size;
+
+ if(countcheck("calloc", line, source))
+ return NULL;
+
+ /* alloc at least 64 bytes */
+ user_size = wanted_size * wanted_elements;
+ size = sizeof(struct memdebug) + user_size;
+
+ mem = (struct memdebug *)(Curl_cmalloc)(size);
+ if(mem) {
+ /* fill memory with zeroes */
+ memset(mem->mem, 0, user_size);
+ mem->size = user_size;
+ }
+
+ if(logfile && source)
+ fprintf(logfile, "MEM %s:%d calloc(%u,%u) = %p\n",
+ source, line, wanted_elements, wanted_size, mem ? mem->mem : 0);
+ return (mem ? mem->mem : NULL);
}
char *curl_dostrdup(const char *str, int line, const char *source)
{
char *mem;
size_t len;
-
- if(NULL ==str) {
- fprintf(stderr, "ILLEGAL strdup() on NULL at %s:%d\n",
- source, line);
- exit(2);
- }
+
+ curlassert(str != NULL);
+
+ if(countcheck("strdup", line, source))
+ return NULL;
len=strlen(str)+1;
mem=curl_domalloc(len, 0, NULL); /* NULL prevents logging */
+ if (mem)
memcpy(mem, str, len);
if(logfile)
- fprintf(logfile, "MEM %s:%d strdup(%p) (%d) = %p\n",
+ fprintf(logfile, "MEM %s:%d strdup(%p) (%zd) = %p\n",
source, line, str, len, mem);
return mem;
}
+/* We provide a realloc() that accepts a NULL as pointer, which then
+ performs a malloc(). In order to work with ares. */
void *curl_dorealloc(void *ptr, size_t wantedsize,
int line, const char *source)
{
- struct memdebug *mem;
+ struct memdebug *mem=NULL;
size_t size = sizeof(struct memdebug)+wantedsize;
- mem = (struct memdebug *)((char *)ptr - offsetof(struct memdebug, mem));
+ if(countcheck("realloc", line, source))
+ return NULL;
+
+ if(ptr)
+ mem = (struct memdebug *)((char *)ptr - offsetof(struct memdebug, mem));
- mem=(struct memdebug *)(realloc)(mem, size);
+ mem=(struct memdebug *)(Curl_crealloc)(mem, size);
if(logfile)
- fprintf(logfile, "MEM %s:%d realloc(%p, %d) = %p\n",
+ fprintf(logfile, "MEM %s:%d realloc(0x%x, %zd) = %p\n",
source, line, ptr, wantedsize, mem?mem->mem:NULL);
if(mem) {
@@ -144,35 +215,35 @@ void curl_dofree(void *ptr, int line, const char *source)
{
struct memdebug *mem;
- if(NULL == ptr) {
- fprintf(stderr, "ILLEGAL free() on NULL at %s:%d\n",
- source, line);
- exit(2);
- }
+ curlassert(ptr != NULL);
+
mem = (struct memdebug *)((char *)ptr - offsetof(struct memdebug, mem));
/* destroy */
memset(mem->mem, 0x13, mem->size);
-
+
/* free for real */
- (free)(mem);
+ (Curl_cfree)(mem);
if(logfile)
fprintf(logfile, "MEM %s:%d free(%p)\n", source, line, ptr);
}
-int curl_socket(int domain, int type, int protocol, int line, char *source)
+int curl_socket(int domain, int type, int protocol, int line,
+ const char *source)
{
int sockfd=(socket)(domain, type, protocol);
- if(logfile)
+ if(logfile && (sockfd!=-1))
fprintf(logfile, "FD %s:%d socket() = %d\n",
source, line, sockfd);
return sockfd;
}
-int curl_accept(int s, struct sockaddr *addr, socklen_t *addrlen,
+int curl_accept(int s, void *saddr, void *saddrlen,
int line, const char *source)
{
+ struct sockaddr *addr = (struct sockaddr *)saddr;
+ socklen_t *addrlen = (socklen_t *)saddrlen;
int sockfd=(accept)(s, addr, addrlen);
if(logfile)
fprintf(logfile, "FD %s:%d accept() = %d\n",
@@ -181,7 +252,7 @@ int curl_accept(int s, struct sockaddr *addr, socklen_t *addrlen,
}
/* this is our own defined way to close sockets on *ALL* platforms */
-int curl_sclose(int sockfd, int line, char *source)
+int curl_sclose(int sockfd, int line, const char *source)
{
int res=sclose(sockfd);
if(logfile)
@@ -195,8 +266,8 @@ FILE *curl_fopen(const char *file, const char *mode,
{
FILE *res=(fopen)(file, mode);
if(logfile)
- fprintf(logfile, "FILE %s:%d fopen(\"%s\") = %p\n",
- source, line, file, res);
+ fprintf(logfile, "FILE %s:%d fopen(\"%s\",\"%s\") = %p\n",
+ source, line, file, mode, res);
return res;
}
@@ -204,11 +275,7 @@ int curl_fclose(FILE *file, int line, const char *source)
{
int res;
- if(NULL == file) {
- fprintf(stderr, "ILLEGAL flose() on NULL at %s:%d\n",
- source, line);
- exit(2);
- }
+ curlassert(file != NULL);
res=(fclose)(file);
if(logfile)
@@ -218,14 +285,9 @@ int curl_fclose(FILE *file, int line, const char *source)
}
#else
#ifdef VMS
-int VOID_VAR_MEMDEBUG;
-#endif
-#endif /* MALLOCDEBUG */
-
-/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
- */
+int VOID_VAR_MEMDEBUG;
+#else
+/* we provide a fake do-nothing function here to avoid compiler warnings */
+void curl_memdebug(void) {}
+#endif /* VMS */
+#endif /* CURLDEBUG */
diff --git a/Source/CTest/Curl/memdebug.h b/Source/CTest/Curl/memdebug.h
index 3fa87ac..42574cf 100644
--- a/Source/CTest/Curl/memdebug.h
+++ b/Source/CTest/Curl/memdebug.h
@@ -1,4 +1,6 @@
-#ifdef MALLOCDEBUG
+#ifdef CURLDEBUG
+#ifndef _CURL_MEDEBUG_H
+#define _CURL_MEDEBUG_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
@@ -6,7 +8,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -22,6 +24,11 @@
* $Id$
***************************************************************************/
+/*
+ * CAUTION: this header is designed to work when included by the app-side
+ * as well as the library. Do not mix with library internals!
+ */
+
#include "setup.h"
#ifdef HAVE_SYS_TYPES_H
@@ -36,19 +43,23 @@
#include <memory.h>
#endif
+#define logfile curl_debuglogfile
+
extern FILE *logfile;
/* memory functions */
void *curl_domalloc(size_t size, int line, const char *source);
+void *curl_docalloc(size_t elements, size_t size, int line, const char *source);
void *curl_dorealloc(void *ptr, size_t size, int line, const char *source);
void curl_dofree(void *ptr, int line, const char *source);
char *curl_dostrdup(const char *str, int line, const char *source);
void curl_memdebug(const char *logname);
+void curl_memlimit(long limit);
/* file descriptor manipulators */
-int curl_socket(int domain, int type, int protocol, int, const char *);
+int curl_socket(int domain, int type, int protocol, int line , const char *);
int curl_sclose(int sockfd, int, const char *source);
-int curl_accept(int s, struct sockaddr *addr, socklen_t *addrlen,
+int curl_accept(int s, void *addr, void *addrlen,
int line, const char *source);
/* FILE functions */
@@ -56,29 +67,42 @@ FILE *curl_fopen(const char *file, const char *mode, int line,
const char *source);
int curl_fclose(FILE *file, int line, const char *source);
+#ifndef MEMDEBUG_NODEFINES
+
/* Set this symbol on the command-line, recompile all lib-sources */
#undef strdup
#define strdup(ptr) curl_dostrdup(ptr, __LINE__, __FILE__)
#define malloc(size) curl_domalloc(size, __LINE__, __FILE__)
+#define calloc(nbelem,size) curl_docalloc(nbelem, size, __LINE__, __FILE__)
#define realloc(ptr,size) curl_dorealloc(ptr, size, __LINE__, __FILE__)
#define free(ptr) curl_dofree(ptr, __LINE__, __FILE__)
#define socket(domain,type,protocol)\
curl_socket(domain,type,protocol,__LINE__,__FILE__)
+#undef accept /* for those with accept as a macro */
#define accept(sock,addr,len)\
curl_accept(sock,addr,len,__LINE__,__FILE__)
#define getaddrinfo(host,serv,hint,res) \
- curl_getaddrinfo(host,serv,hint,res,__LINE__,__FILE__)
+ curl_dogetaddrinfo(host,serv,hint,res,__LINE__,__FILE__)
+#define getnameinfo(sa,salen,host,hostlen,serv,servlen,flags) \
+ curl_dogetnameinfo(sa,salen,host,hostlen,serv,servlen,flags, __LINE__, \
+ __FILE__)
#define freeaddrinfo(data) \
- curl_freeaddrinfo(data,__LINE__,__FILE__)
+ curl_dofreeaddrinfo(data,__LINE__,__FILE__)
/* sclose is probably already defined, redefine it! */
#undef sclose
#define sclose(sockfd) curl_sclose(sockfd,__LINE__,__FILE__)
+/* ares-adjusted define: */
+#undef closesocket
+#define closesocket(sockfd) curl_sclose(sockfd,__LINE__,__FILE__)
#undef fopen
#define fopen(file,mode) curl_fopen(file,mode,__LINE__,__FILE__)
#define fclose(file) curl_fclose(file,__LINE__,__FILE__)
-#endif
+#endif /* MEMDEBUG_NODEFINES */
+
+#endif /* _CURL_MEDEBUG_H */
+#endif /* CURLDEBUG */
diff --git a/Source/CTest/Curl/memory.h b/Source/CTest/Curl/memory.h
new file mode 100644
index 0000000..4e32a67
--- /dev/null
+++ b/Source/CTest/Curl/memory.h
@@ -0,0 +1,50 @@
+#ifndef _CURL_MEMORY_H
+#define _CURL_MEMORY_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include <curl/curl.h> /* for the typedefs */
+
+extern curl_malloc_callback Curl_cmalloc;
+extern curl_free_callback Curl_cfree;
+extern curl_realloc_callback Curl_crealloc;
+extern curl_strdup_callback Curl_cstrdup;
+extern curl_calloc_callback Curl_ccalloc;
+
+#ifndef CURLDEBUG
+/* Only do this define-mania if we're not using the memdebug system, as that
+ has preference on this magic. */
+#undef strdup
+#define strdup(ptr) Curl_cstrdup(ptr)
+#undef malloc
+#define malloc(size) Curl_cmalloc(size)
+#undef calloc
+#define calloc(nbelem,size) Curl_ccalloc(nbelem, size)
+#undef realloc
+#define realloc(ptr,size) Curl_crealloc(ptr, size)
+#undef free
+#define free(ptr) Curl_cfree(ptr)
+
+#endif
+
+#endif /* _CURL_MEMORY_H */
diff --git a/Source/CTest/Curl/mprintf.c b/Source/CTest/Curl/mprintf.c
index 7822876..9135a13 100644
--- a/Source/CTest/Curl/mprintf.c
+++ b/Source/CTest/Curl/mprintf.c
@@ -38,19 +38,26 @@
#include <ctype.h>
#include <string.h>
-#ifndef SIZEOF_LONG_LONG
-/* prevents warnings on picky compilers */
-#define SIZEOF_LONG_LONG 0
-#endif
+#include <curl/mprintf.h>
+
#ifndef SIZEOF_LONG_DOUBLE
#define SIZEOF_LONG_DOUBLE 0
#endif
+#ifndef SIZEOF_SIZE_T
+/* default to 4 bytes for size_t unless defined in the config.h */
+#define SIZEOF_SIZE_T 4
+#endif
+
+#ifdef DPRINTF_DEBUG
+#define HAVE_LONGLONG
+#define LONG_LONG long long
+#define ENABLE_64BIT
+#endif
+#include "memory.h"
/* The last #include file should be: */
-#ifdef MALLOCDEBUG
#include "memdebug.h"
-#endif
#define BUFFSIZE 256 /* buffer for long-to-str and float-to-str calcs */
#define MAX_PARAMETERS 128 /* lame static limit */
@@ -75,7 +82,13 @@ static const char lower_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
/* Upper-case digits. */
static const char upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-#define OUTCHAR(x) done+=(stream(x, (FILE *)data)==-1?0:1)
+#define OUTCHAR(x) \
+ do{ \
+ if(stream((unsigned char)(x), (FILE *)data) != -1) \
+ done++; \
+ else \
+ return done; /* return immediately on failure */ \
+ } while(0)
/* Data type to read from the arglist */
typedef enum {
@@ -119,19 +132,16 @@ enum {
typedef struct {
FormatType type;
int flags;
- int width; /* width OR width parameter number */
- int precision; /* precision OR precision parameter number */
+ long width; /* width OR width parameter number */
+ long precision; /* precision OR precision parameter number */
union {
char *str;
void *ptr;
long num;
-#if SIZEOF_LONG_LONG /* if this is non-zero */
- long long lnum;
+#ifdef ENABLE_64BIT
+ LONG_LONG lnum;
#endif
double dnum;
-#if SIZEOF_LONG_DOUBLE
- long double ldnum;
-#endif
} data;
} va_stack_t;
@@ -145,11 +155,13 @@ struct asprintf {
char *buffer; /* allocated buffer */
size_t len; /* length of string */
size_t alloc; /* length of alloc */
+ bool fail; /* TRUE if an alloc has failed and thus the output is not
+ the complete data */
};
int curl_msprintf(char *buffer, const char *format, ...);
-static int dprintf_DollarString(char *input, char **end)
+static long dprintf_DollarString(char *input, char **end)
{
int number=0;
while(isdigit((int)*input)) {
@@ -170,7 +182,8 @@ static BOOL dprintf_IsQualifierNoDollar(char c)
case '-': case '+': case ' ': case '#': case '.':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
- case 'h': case 'l': case 'L': case 'Z': case 'q':
+ case 'h': case 'l': case 'L': case 'z': case 'q':
+ case '*': case 'O':
return TRUE;
default:
return FALSE;
@@ -211,7 +224,7 @@ int dprintf_Pass1Report(va_stack_t *vto, int max)
break;
case FORMAT_LONGDOUBLE:
type = "long double";
- break;
+ break;
}
@@ -277,16 +290,17 @@ int dprintf_Pass1Report(va_stack_t *vto, int max)
*
******************************************************************/
-static int dprintf_Pass1(char *format, va_stack_t *vto, char **endpos, va_list arglist)
+static long dprintf_Pass1(char *format, va_stack_t *vto, char **endpos,
+ va_list arglist)
{
char *fmt = format;
int param_num = 0;
- int this_param;
- int width;
- int precision;
+ long this_param;
+ long width;
+ long precision;
int flags;
- int max_param=0;
- int i;
+ long max_param=0;
+ long i;
while (*fmt) {
if (*fmt++ == '%') {
@@ -300,7 +314,7 @@ static int dprintf_Pass1(char *format, va_stack_t *vto, char **endpos, va_list a
/* Handle the positional case (N$) */
param_num++;
-
+
this_param = dprintf_DollarString(fmt, &fmt);
if (0 == this_param)
/* we got no positional, get the next counter */
@@ -373,11 +387,21 @@ static int dprintf_Pass1(char *format, va_stack_t *vto, char **endpos, va_list a
case 'q':
flags |= FLAGS_LONGLONG;
break;
- case 'Z':
- if (sizeof(size_t) > sizeof(unsigned long int))
- flags |= FLAGS_LONGLONG;
- if (sizeof(size_t) > sizeof(unsigned int))
- flags |= FLAGS_LONG;
+ case 'z':
+ /* the code below generates a warning if -Wunreachable-code is
+ used */
+#if SIZEOF_SIZE_T>4
+ flags |= FLAGS_LONGLONG;
+#else
+ flags |= FLAGS_LONG;
+#endif
+ break;
+ case 'O':
+#if SIZEOF_CURL_OFF_T > 4
+ flags |= FLAGS_LONGLONG;
+#else
+ flags |= FLAGS_LONG;
+#endif
break;
case '0':
if (!(flags & FLAGS_LEFT))
@@ -391,7 +415,7 @@ static int dprintf_Pass1(char *format, va_stack_t *vto, char **endpos, va_list a
case '*': /* Special case */
flags |= FLAGS_WIDTHPARAM;
param_num++;
-
+
i = dprintf_DollarString(fmt, &fmt);
if(i)
width = i;
@@ -444,18 +468,26 @@ static int dprintf_Pass1(char *format, va_stack_t *vto, char **endpos, va_list a
case 'c':
vto[i].type = FORMAT_INT;
flags |= FLAGS_CHAR;
- break;
+ break;
case 'f':
vto[i].type = FORMAT_DOUBLE;
break;
- case 'e': case 'E':
+ case 'e':
+ vto[i].type = FORMAT_DOUBLE;
+ flags |= FLAGS_FLOATE;
+ break;
+ case 'E':
vto[i].type = FORMAT_DOUBLE;
- flags |= FLAGS_FLOATE| (('E' == *fmt)?FLAGS_UPPER:0);
+ flags |= FLAGS_FLOATE|FLAGS_UPPER;
break;
- case 'g': case 'G':
+ case 'g':
vto[i].type = FORMAT_DOUBLE;
- flags |= FLAGS_FLOATG| (('G' == *fmt)?FLAGS_UPPER:0);
- break;
+ flags |= FLAGS_FLOATG;
+ break;
+ case 'G':
+ vto[i].type = FORMAT_DOUBLE;
+ flags |= FLAGS_FLOATG|FLAGS_UPPER;
+ break;
default:
vto[i].type = FORMAT_UNKNOWN;
break;
@@ -464,7 +496,7 @@ static int dprintf_Pass1(char *format, va_stack_t *vto, char **endpos, va_list a
vto[i].flags = flags;
vto[i].width = width;
vto[i].precision = precision;
-
+
if (flags & FLAGS_WIDTHPARAM) {
/* we have the width specified from a parameter, so we make that
parameter's info setup properly */
@@ -473,7 +505,7 @@ static int dprintf_Pass1(char *format, va_stack_t *vto, char **endpos, va_list a
vto[i].type = FORMAT_WIDTH;
vto[i].flags = FLAGS_NEW;
vto[i].precision = vto[i].width = 0; /* can't use width or precision
- of width! */
+ of width! */
}
if (flags & FLAGS_PRECPARAM) {
/* we have the precision specified from a parameter, so we make that
@@ -508,17 +540,17 @@ static int dprintf_Pass1(char *format, va_stack_t *vto, char **endpos, va_list a
case FORMAT_STRING:
vto[i].data.str = va_arg(arglist, char *);
break;
-
+
case FORMAT_INTPTR:
case FORMAT_UNKNOWN:
case FORMAT_PTR:
vto[i].data.ptr = va_arg(arglist, void *);
break;
-
+
case FORMAT_INT:
-#if SIZEOF_LONG_LONG
+#ifdef ENABLE_64BIT
if(vto[i].flags & FLAGS_LONGLONG)
- vto[i].data.lnum = va_arg(arglist, long long);
+ vto[i].data.lnum = va_arg(arglist, LONG_LONG);
else
#endif
if(vto[i].flags & FLAGS_LONG)
@@ -526,23 +558,18 @@ static int dprintf_Pass1(char *format, va_stack_t *vto, char **endpos, va_list a
else
vto[i].data.num = va_arg(arglist, int);
break;
-
+
case FORMAT_DOUBLE:
-#if SIZEOF_LONG_DOUBLE
- if(vto[i].flags & FLAGS_LONG)
- vto[i].data.ldnum = va_arg(arglist, long double);
- else
-#endif
- vto[i].data.dnum = va_arg(arglist, double);
+ vto[i].data.dnum = va_arg(arglist, double);
break;
-
+
case FORMAT_WIDTH:
/* Argument has been read. Silently convert it into an integer
* for later use
*/
vto[i].type = FORMAT_INT;
break;
-
+
default:
break;
}
@@ -553,12 +580,12 @@ static int dprintf_Pass1(char *format, va_stack_t *vto, char **endpos, va_list a
}
static int dprintf_formatf(
- void *data, /* untouched by format(), just sent to the
- stream() function in the first argument */
- int (*stream)(int, FILE *), /* function pointer called for each
- output character */
- const char *format, /* %-formatted string */
- va_list ap_save) /* list of parameters */
+ void *data, /* untouched by format(), just sent to the stream() function in
+ the second argument */
+ /* function pointer called for each output character */
+ int (*stream)(int, FILE *),
+ const char *format, /* %-formatted string */
+ va_list ap_save) /* list of parameters */
{
/* Base-36 digits for numbers. */
const char *digits = lower_digits;
@@ -567,7 +594,7 @@ static int dprintf_formatf(
char *f;
/* Number of characters written. */
- register size_t done = 0;
+ int done = 0;
long param; /* current parameter to read */
long param_num=0; /* parameter counter */
@@ -585,31 +612,32 @@ static int dprintf_formatf(
end = &endpos[0]; /* the initial end-position from the list dprintf_Pass1()
created for us */
-
+
f = (char *)format;
while (*f != '\0') {
/* Format spec modifiers. */
char alt;
-
+
/* Width of a field. */
- register long width;
+ long width;
+
/* Precision of a field. */
long prec;
-
+
/* Decimal integer is negative. */
char is_neg;
-
+
/* Base of a number to be written. */
long base;
/* Integral values to be written. */
-#if SIZEOF_LONG_LONG
- unsigned long long num;
+#ifdef ENABLE_64BIT
+ unsigned LONG_LONG num;
#else
unsigned long num;
#endif
long signed_num;
-
+
if (*f != '%') {
/* This isn't a format spec, so write everything out until the next one
OR end of string is reached. */
@@ -618,9 +646,9 @@ static int dprintf_formatf(
} while(*++f && ('%' != *f));
continue;
}
-
+
++f;
-
+
/* Check for "%%". Note that although the ANSI standard lists
'%' as a conversion specifier, it says "The complete format
specification shall be `%%'," so we can avoid all the width
@@ -639,7 +667,7 @@ static int dprintf_formatf(
param = param_num;
else
--param;
-
+
param_num++; /* increase this always to allow "%2$s %1$s %s" and then the
third %s will pick the 3rd argument */
@@ -659,8 +687,8 @@ static int dprintf_formatf(
else
prec = -1;
- alt = (char)(p->flags & FLAGS_ALT);
-
+ alt = (p->flags & FLAGS_ALT)?TRUE:FALSE;
+
switch (p->type) {
case FORMAT_INT:
num = p->data.num;
@@ -696,9 +724,9 @@ static int dprintf_formatf(
/* Decimal integer. */
base = 10;
-#if SIZEOF_LONG_LONG
+#ifdef ENABLE_64BIT
if(p->flags & FLAGS_LONGLONG) {
- /* long long */
+ /* long long */
is_neg = p->data.lnum < 0;
num = is_neg ? (- p->data.lnum) : p->data.lnum;
}
@@ -706,63 +734,62 @@ static int dprintf_formatf(
#endif
{
signed_num = (long) num;
-
- is_neg = (char)(signed_num < 0);
+ is_neg = signed_num < 0;
num = is_neg ? (- signed_num) : signed_num;
}
goto number;
-
- unsigned_number:;
+
+ unsigned_number:
/* Unsigned number of base BASE. */
is_neg = 0;
-
- number:;
+
+ number:
/* Number of base BASE. */
{
char *workend = &work[sizeof(work) - 1];
- register char *w;
-
+ char *w;
+
/* Supply a default precision if none was given. */
if (prec == -1)
prec = 1;
-
+
/* Put the number in WORK. */
w = workend;
while (num > 0) {
*w-- = digits[num % base];
num /= base;
}
- width -= (long)(workend - w);
- prec -= (long)(workend - w);
-
+ width -= workend - w;
+ prec -= workend - w;
+
if (alt && base == 8 && prec <= 0) {
*w-- = '0';
--width;
}
-
+
if (prec > 0) {
width -= prec;
while (prec-- > 0)
*w-- = '0';
}
-
+
if (alt && base == 16)
width -= 2;
-
+
if (is_neg || (p->flags & FLAGS_SHOWSIGN) || (p->flags & FLAGS_SPACE))
--width;
-
+
if (!(p->flags & FLAGS_LEFT) && !(p->flags & FLAGS_PAD_NIL))
while (width-- > 0)
OUTCHAR(' ');
-
+
if (is_neg)
OUTCHAR('-');
else if (p->flags & FLAGS_SHOWSIGN)
OUTCHAR('+');
else if (p->flags & FLAGS_SPACE)
OUTCHAR(' ');
-
+
if (alt && base == 16) {
OUTCHAR('0');
if(p->flags & FLAGS_UPPER)
@@ -774,25 +801,25 @@ static int dprintf_formatf(
if (!(p->flags & FLAGS_LEFT) && (p->flags & FLAGS_PAD_NIL))
while (width-- > 0)
OUTCHAR('0');
-
+
/* Write the number. */
while (++w <= workend) {
OUTCHAR(*w);
}
-
+
if (p->flags & FLAGS_LEFT)
while (width-- > 0)
OUTCHAR(' ');
}
break;
-
+
case FORMAT_STRING:
/* String. */
{
static char null[] = "(nil)";
char *str;
size_t len;
-
+
str = (char *) p->data.str;
if ( str == NULL) {
/* Write null[] if there's space. */
@@ -809,10 +836,10 @@ static int dprintf_formatf(
}
else
len = strlen(str);
-
+
if (prec != -1 && (size_t) prec < len)
len = prec;
- width -= (long)len;
+ width -= len;
if (p->flags & FLAGS_ALT)
OUTCHAR('"');
@@ -820,7 +847,7 @@ static int dprintf_formatf(
if (!(p->flags&FLAGS_LEFT))
while (width-- > 0)
OUTCHAR(' ');
-
+
while (len-- > 0)
OUTCHAR(*str++);
if (p->flags&FLAGS_LEFT)
@@ -831,7 +858,7 @@ static int dprintf_formatf(
OUTCHAR('"');
}
break;
-
+
case FORMAT_PTR:
/* Generic pointer. */
{
@@ -849,8 +876,8 @@ static int dprintf_formatf(
else {
/* Write "(nil)" for a nil pointer. */
static char strnil[] = "(nil)";
- register char *point;
-
+ char *point;
+
width -= sizeof(strnil) - 1;
if (p->flags & FLAGS_LEFT)
while (width-- > 0)
@@ -868,7 +895,9 @@ static int dprintf_formatf(
{
char formatbuf[32]="%";
char *fptr;
-
+ size_t left = sizeof(formatbuf)-strlen(formatbuf);
+ int len;
+
width = -1;
if (p->flags & FLAGS_WIDTH)
width = p->width;
@@ -894,31 +923,31 @@ static int dprintf_formatf(
if(width >= 0) {
/* RECURSIVE USAGE */
- fptr += curl_msprintf(fptr, "%d", width);
+ len = curl_msnprintf(fptr, left, "%ld", width);
+ fptr += len;
+ left -= len;
}
if(prec >= 0) {
/* RECURSIVE USAGE */
- fptr += curl_msprintf(fptr, ".%d", prec);
+ len = curl_msnprintf(fptr, left, ".%ld", prec);
+ fptr += len;
+ left -= len;
}
if (p->flags & FLAGS_LONG)
- strcat(fptr, "l");
+ *fptr++ = 'l';
if (p->flags & FLAGS_FLOATE)
- strcat(fptr, p->flags&FLAGS_UPPER?"E":"e");
+ *fptr++ = p->flags&FLAGS_UPPER ? 'E':'e';
else if (p->flags & FLAGS_FLOATG)
- strcat(fptr, (p->flags & FLAGS_UPPER) ? "G" : "g");
+ *fptr++ = p->flags & FLAGS_UPPER ? 'G' : 'g';
else
- strcat(fptr, "f");
+ *fptr++ = 'f';
+
+ *fptr = 0; /* and a final zero termination */
/* NOTE NOTE NOTE!! Not all sprintf() implementations returns number
of output characters */
-#if SIZEOF_LONG_DOUBLE
- if (p->flags & FLAGS_LONG)
- /* This is for support of the 'long double' type */
- (sprintf)(work, formatbuf, p->data.ldnum);
- else
-#endif
- (sprintf)(work, formatbuf, p->data.dnum);
+ (sprintf)(work, formatbuf, p->data.dnum);
for(fptr=work; *fptr; fptr++)
OUTCHAR(*fptr);
@@ -927,17 +956,17 @@ static int dprintf_formatf(
case FORMAT_INTPTR:
/* Answer the count of characters written. */
-#if SIZEOF_LONG_LONG
+#ifdef ENABLE_64BIT
if (p->flags & FLAGS_LONGLONG)
- *(long long int *) p->data.ptr = done;
+ *(LONG_LONG *) p->data.ptr = (LONG_LONG)done;
else
#endif
if (p->flags & FLAGS_LONG)
- *(long int *) p->data.ptr = (long int)done;
+ *(long *) p->data.ptr = (long)done;
else if (!(p->flags & FLAGS_SHORT))
*(int *) p->data.ptr = (int)done;
else
- *(short int *) p->data.ptr = (short int)done;
+ *(short *) p->data.ptr = (short)done;
break;
default:
@@ -946,27 +975,28 @@ static int dprintf_formatf(
f = *end++; /* goto end of %-code */
}
- return (int)done;
+ return done;
}
/* fputc() look-alike */
static int addbyter(int output, FILE *data)
{
struct nsprintf *infop=(struct nsprintf *)data;
-
+ unsigned char outc = (unsigned char)output;
+
if(infop->length < infop->max) {
/* only do this if we haven't reached max length yet */
- infop->buffer[0] = (char)output; /* store */
+ infop->buffer[0] = outc; /* store */
infop->buffer++; /* increase pointer */
infop->length++; /* we are now one byte larger */
- return output; /* fputc() returns like this on success */
+ return outc; /* fputc() returns like this on success */
}
return -1;
}
-int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...)
+int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format,
+ va_list ap_save)
{
- va_list ap_save; /* argument pointer */
int retcode;
struct nsprintf info;
@@ -974,40 +1004,40 @@ int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...)
info.length = 0;
info.max = maxlength;
- va_start(ap_save, format);
retcode = dprintf_formatf(&info, addbyter, format, ap_save);
- va_end(ap_save);
- info.buffer[0] = 0; /* we terminate this with a zero byte */
-
- /* we could even return things like */
-
+ if(info.max) {
+ /* we terminate this with a zero byte */
+ if(info.max == info.length)
+ /* we're at maximum, scrap the last letter */
+ info.buffer[-1] = 0;
+ else
+ info.buffer[0] = 0;
+ }
return retcode;
}
-int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format, va_list ap_save)
+int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...)
{
int retcode;
- struct nsprintf info;
-
- info.buffer = buffer;
- info.length = 0;
- info.max = maxlength;
-
- retcode = dprintf_formatf(&info, addbyter, format, ap_save);
- info.buffer[0] = 0; /* we terminate this with a zero byte */
+ va_list ap_save; /* argument pointer */
+ va_start(ap_save, format);
+ retcode = curl_mvsnprintf(buffer, maxlength, format, ap_save);
+ va_end(ap_save);
return retcode;
}
-
/* fputc() look-alike */
static int alloc_addbyter(int output, FILE *data)
{
struct asprintf *infop=(struct asprintf *)data;
-
+ unsigned char outc = (unsigned char)output;
+
if(!infop->buffer) {
infop->buffer=(char *)malloc(32);
- if(!infop->buffer)
+ if(!infop->buffer) {
+ infop->fail = TRUE;
return -1; /* fail */
+ }
infop->alloc = 32;
infop->len =0;
}
@@ -1017,17 +1047,18 @@ static int alloc_addbyter(int output, FILE *data)
newptr = (char *)realloc(infop->buffer, infop->alloc*2);
if(!newptr) {
+ infop->fail = TRUE;
return -1;
}
infop->buffer = newptr;
infop->alloc *= 2;
}
- infop->buffer[ infop->len ] = (char)output;
+ infop->buffer[ infop->len ] = outc;
infop->len++;
- return output; /* fputc() returns like this on success */
+ return outc; /* fputc() returns like this on success */
}
char *curl_maprintf(const char *format, ...)
@@ -1039,11 +1070,12 @@ char *curl_maprintf(const char *format, ...)
info.buffer = NULL;
info.len = 0;
info.alloc = 0;
+ info.fail = FALSE;
va_start(ap_save, format);
retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save);
va_end(ap_save);
- if(-1 == retcode) {
+ if((-1 == retcode) || info.fail) {
if(info.alloc)
free(info.buffer);
return NULL;
@@ -1064,9 +1096,10 @@ char *curl_mvaprintf(const char *format, va_list ap_save)
info.buffer = NULL;
info.len = 0;
info.alloc = 0;
+ info.fail = FALSE;
retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save);
- if(-1 == retcode) {
+ if((-1 == retcode) || info.fail) {
if(info.alloc)
free(info.buffer);
return NULL;
@@ -1083,9 +1116,10 @@ char *curl_mvaprintf(const char *format, va_list ap_save)
static int storebuffer(int output, FILE *data)
{
char **buffer = (char **)data;
- **buffer = (char)output;
+ unsigned char outc = (unsigned char)output;
+ **buffer = outc;
(*buffer)++;
- return output; /* act like fputc() ! */
+ return outc; /* act like fputc() ! */
}
int curl_msprintf(char *buffer, const char *format, ...)
@@ -1146,14 +1180,16 @@ int main()
{
char buffer[129];
char *ptr;
-#if SIZEOF_LONG_LONG>0
- long long hullo;
- dprintf("%3$12s %1$s %2$qd %4$d\n", "daniel", hullo, "stenberg", 65);
+#ifdef ENABLE_64BIT
+ long long one=99;
+ long long two=100;
+ long long test = 0x1000000000LL;
+ curl_mprintf("%lld %lld %lld\n", one, two, test);
#endif
- mprintf("%3d %5d\n", 10, 1998);
-
- ptr=maprintf("test this then baby %s%s%s%s%s%s %d %d %d loser baby get a hit in yer face now!", "", "pretty long string pretty long string pretty long string pretty long string pretty long string", "/", "/", "/", "pretty long string", 1998, 1999, 2001);
+ curl_mprintf("%3d %5d\n", 10, 1998);
+
+ ptr=curl_maprintf("test this then baby %s%s%s%s%s%s %d %d %d loser baby get a hit in yer face now!", "", "pretty long string pretty long string pretty long string pretty long string pretty long string", "/", "/", "/", "pretty long string", 1998, 1999, 2001);
puts(ptr);
@@ -1162,15 +1198,15 @@ int main()
free(ptr);
#if 1
- mprintf(buffer, "%s %s %d", "daniel", "stenberg", 19988);
+ curl_mprintf(buffer, "%s %s %d", "daniel", "stenberg", 19988);
puts(buffer);
- mfprintf(stderr, "%s %#08x\n", "dummy", 65);
+ curl_mfprintf(stderr, "%s %#08x\n", "dummy", 65);
printf("%s %#08x\n", "dummy", 65);
{
double tryout = 3.14156592;
- mprintf(buffer, "%.2g %G %f %e %E", tryout, tryout, tryout, tryout, tryout);
+ curl_mprintf(buffer, "%.2g %G %f %e %E", tryout, tryout, tryout, tryout, tryout);
puts(buffer);
printf("%.2g %G %f %e %E\n", tryout, tryout, tryout, tryout, tryout);
}
@@ -1180,11 +1216,3 @@ int main()
}
#endif
-
-/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
- */
diff --git a/Source/CTest/Curl/multi.c b/Source/CTest/Curl/multi.c
index 630342b..12b987f 100644
--- a/Source/CTest/Curl/multi.c
+++ b/Source/CTest/Curl/multi.c
@@ -1,16 +1,16 @@
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -24,20 +24,28 @@
#include "setup.h"
#include <stdlib.h>
#include <string.h>
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
#include <curl/curl.h>
#include "urldata.h"
#include "transfer.h"
#include "url.h"
#include "connect.h"
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
+#include "progress.h"
+#include "memory.h"
/* The last #include file should be: */
-#ifdef MALLOCDEBUG
#include "memdebug.h"
-#endif
struct Curl_message {
/* the 'CURLMsg' is the part that is visible to the external user */
@@ -47,7 +55,8 @@ struct Curl_message {
typedef enum {
CURLM_STATE_INIT,
- CURLM_STATE_CONNECT, /* connect has been sent off */
+ CURLM_STATE_CONNECT, /* resolve/connect has been sent off */
+ CURLM_STATE_WAITRESOLVE, /* we're awaiting the resolve to finalize */
CURLM_STATE_WAITCONNECT, /* we're awaiting the connect to finalize */
CURLM_STATE_DO, /* send off the request (part 1) */
CURLM_STATE_DO_MORE, /* send off the request (part 2) */
@@ -62,7 +71,7 @@ struct Curl_one_easy {
/* first, two fields for the linked list of these */
struct Curl_one_easy *next;
struct Curl_one_easy *prev;
-
+
struct SessionHandle *easy_handle; /* the easy handle for this unit */
struct connectdata *easy_conn; /* the "unit's" connection */
@@ -90,7 +99,7 @@ struct Curl_multi {
long type;
/* We have a linked list with easy handles */
- struct Curl_one_easy easy;
+ struct Curl_one_easy easy;
/* This is the amount of entries in the linked list above. */
int num_easy;
@@ -111,7 +120,15 @@ CURLM *curl_multi_init(void)
memset(multi, 0, sizeof(struct Curl_multi));
multi->type = CURL_MULTI_HANDLE;
}
-
+ else
+ return NULL;
+
+ multi->hostcache = Curl_mk_dnscache();
+ if(!multi->hostcache) {
+ /* failure, free mem and bail out */
+ free(multi);
+ multi = NULL;
+ }
return (CURLM *) multi;
}
@@ -124,7 +141,7 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle,
/* First, make some basic checks that the CURLM handle is a good handle */
if(!GOOD_MULTI_HANDLE(multi))
return CURLM_BAD_HANDLE;
-
+
/* Verify that we got a somewhat good easy handle too */
if(!GOOD_EASY_HANDLE(easy_handle))
return CURLM_BAD_EASY_HANDLE;
@@ -133,18 +150,21 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle,
easy = (struct Curl_one_easy *)malloc(sizeof(struct Curl_one_easy));
if(!easy)
return CURLM_OUT_OF_MEMORY;
-
+
/* clean it all first (just to be sure) */
memset(easy, 0, sizeof(struct Curl_one_easy));
/* set the easy handle */
easy->easy_handle = easy_handle;
easy->state = CURLM_STATE_INIT;
-
+
+ /* for multi interface connections, we share DNS cache automaticly */
+ easy->easy_handle->hostcache = multi->hostcache;
+
/* We add this new entry first in the list. We make our 'next' point to the
previous next and our 'prev' point back to the 'first' struct */
easy->next = multi->easy.next;
- easy->prev = &multi->easy;
+ easy->prev = &multi->easy;
/* make 'easy' the first node in the chain */
multi->easy.next = easy;
@@ -169,7 +189,7 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
/* First, make some basic checks that the CURLM handle is a good handle */
if(!GOOD_MULTI_HANDLE(multi))
return CURLM_BAD_HANDLE;
-
+
/* Verify that we got a somewhat good easy handle too */
if(!GOOD_EASY_HANDLE(curl_handle))
return CURLM_BAD_EASY_HANDLE;
@@ -177,7 +197,7 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
/* scan through the list and remove the 'curl_handle' */
easy = multi->easy.next;
while(easy) {
- if((CURL*)(easy->easy_handle) == curl_handle)
+ if(easy->easy_handle == (struct SessionHandle *)curl_handle)
break;
easy=easy->next;
}
@@ -187,14 +207,14 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
/* clear out the usage of the shared DNS cache */
easy->easy_handle->hostcache = NULL;
-
+
/* make the previous node point to our next */
if(easy->prev)
easy->prev->next = easy->next;
/* make our next point to our previous node */
if(easy->next)
easy->next->prev = easy->prev;
-
+
/* NOTE NOTE NOTE
We do not touch the easy handle here! */
if (easy->msg)
@@ -230,30 +250,37 @@ CURLMcode curl_multi_fdset(CURLM *multi_handle,
switch(easy->state) {
default:
break;
+ case CURLM_STATE_WAITRESOLVE:
+ /* waiting for a resolve to complete */
+ Curl_fdset(easy->easy_conn, read_fd_set, write_fd_set, &this_max_fd);
+ if(this_max_fd > *max_fd)
+ *max_fd = this_max_fd;
+ break;
+
case CURLM_STATE_WAITCONNECT:
case CURLM_STATE_DO_MORE:
{
/* when we're waiting for a connect, we wait for the socket to
become writable */
struct connectdata *conn = easy->easy_conn;
- int sockfd;
+ curl_socket_t sockfd;
if(CURLM_STATE_WAITCONNECT == easy->state) {
- sockfd = conn->firstsocket;
+ sockfd = conn->sock[FIRSTSOCKET];
FD_SET(sockfd, write_fd_set);
}
else {
/* When in DO_MORE state, we could be either waiting for us
to connect to a remote site, or we could wait for that site
to connect to us. It makes a difference in the way: if we
- connect to the site we wait for the socket to become writable, if
+ connect to the site we wait for the socket to become writable, if
the site connects to us we wait for it to become readable */
- sockfd = conn->secondarysocket;
+ sockfd = conn->sock[SECONDARYSOCKET];
FD_SET(sockfd, write_fd_set);
}
- if(sockfd > *max_fd)
- *max_fd = sockfd;
+ if((int)sockfd > *max_fd)
+ *max_fd = (int)sockfd;
}
break;
case CURLM_STATE_PERFORM:
@@ -284,6 +311,7 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
CURLMcode result=CURLM_OK;
struct Curl_message *msg = NULL;
bool connected;
+ bool async;
*running_handles = 0; /* bump this once for every living handle */
@@ -292,54 +320,106 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
easy=multi->easy.next;
while(easy) {
-
-#ifdef MALLOCDEBUG
+#if 0
fprintf(stderr, "HANDLE %p: State: %x\n",
(char *)easy, easy->state);
#endif
+ do {
+ if (CURLM_STATE_WAITCONNECT <= easy->state &&
+ easy->state <= CURLM_STATE_DO &&
+ easy->easy_handle->change.url_changed) {
+ char *gotourl;
+ Curl_posttransfer(easy->easy_handle);
- switch(easy->state) {
- case CURLM_STATE_INIT:
- /* init this transfer. */
- easy->result=Curl_pretransfer(easy->easy_handle);
-
- if(CURLE_OK == easy->result) {
- /* after init, go CONNECT */
- easy->state = CURLM_STATE_CONNECT;
- result = CURLM_CALL_MULTI_PERFORM;
-
- easy->easy_handle->state.used_interface = Curl_if_multi;
- }
- break;
- case CURLM_STATE_CONNECT:
- if (Curl_global_host_cache_use(easy->easy_handle)) {
- easy->easy_handle->hostcache = Curl_global_host_cache_get();
+ easy->result = Curl_done(&easy->easy_conn, CURLE_OK);
+ if(CURLE_OK == easy->result) {
+ gotourl = strdup(easy->easy_handle->change.url);
+ if(gotourl) {
+ easy->easy_handle->change.url_changed = FALSE;
+ easy->result = Curl_follow(easy->easy_handle, gotourl);
+ if(CURLE_OK == easy->result)
+ easy->state = CURLM_STATE_CONNECT;
+ else
+ free(gotourl);
+ }
+ else {
+ easy->result = CURLE_OUT_OF_MEMORY;
+ easy->state = CURLM_STATE_COMPLETED;
+ break;
+ }
+ }
}
- else {
- if (multi->hostcache == NULL)
- multi->hostcache = Curl_hash_alloc(7, Curl_freednsinfo);
- easy->easy_handle->hostcache = multi->hostcache;
- }
+ easy->easy_handle->change.url_changed = FALSE;
+
+ switch(easy->state) {
+ case CURLM_STATE_INIT:
+ /* init this transfer. */
+ easy->result=Curl_pretransfer(easy->easy_handle);
+
+ if(CURLE_OK == easy->result) {
+ /* after init, go CONNECT */
+ easy->state = CURLM_STATE_CONNECT;
+ result = CURLM_CALL_MULTI_PERFORM;
+
+ easy->easy_handle->state.used_interface = Curl_if_multi;
+ }
+ break;
+
+ case CURLM_STATE_CONNECT:
+ /* Connect. We get a connection identifier filled in. */
+ Curl_pgrsTime(easy->easy_handle, TIMER_STARTSINGLE);
+ easy->result = Curl_connect(easy->easy_handle, &easy->easy_conn,
+ &async);
- /* Connect. We get a connection identifier filled in. */
- easy->result = Curl_connect(easy->easy_handle, &easy->easy_conn);
+ if(CURLE_OK == easy->result) {
+ if(async)
+ /* We're now waiting for an asynchronous name lookup */
+ easy->state = CURLM_STATE_WAITRESOLVE;
+ else {
+ /* after the connect has been sent off, go WAITCONNECT */
+ easy->state = CURLM_STATE_WAITCONNECT;
+ result = CURLM_CALL_MULTI_PERFORM;
+ }
+ }
+ break;
+
+ case CURLM_STATE_WAITRESOLVE:
+ /* awaiting an asynch name resolve to complete */
+ {
+ struct Curl_dns_entry *dns = NULL;
+
+ /* check if we have the name resolved by now */
+ easy->result = Curl_is_resolved(easy->easy_conn, &dns);
- /* after the connect has been sent off, go WAITCONNECT */
- if(CURLE_OK == easy->result) {
- easy->state = CURLM_STATE_WAITCONNECT;
- result = CURLM_CALL_MULTI_PERFORM;
+ if(dns) {
+ /* Perform the next step in the connection phase, and then move on
+ to the WAITCONNECT state */
+ easy->result = Curl_async_resolved(easy->easy_conn);
+
+ if(CURLE_OK != easy->result)
+ /* if Curl_async_resolved() returns failure, the connection struct
+ is already freed and gone */
+ easy->easy_conn = NULL; /* no more connection */
+
+ easy->state = CURLM_STATE_WAITCONNECT;
+ }
+
+ if(CURLE_OK != easy->result) {
+ /* failure detected */
+ Curl_disconnect(easy->easy_conn); /* disconnect properly */
+ easy->easy_conn = NULL; /* no more connection */
+ break;
+ }
}
break;
- case CURLM_STATE_WAITCONNECT:
- {
- bool connected;
- easy->result = Curl_is_connected(easy->easy_conn,
- easy->easy_conn->firstsocket,
+ case CURLM_STATE_WAITCONNECT:
+ /* awaiting a completion of an asynch connect */
+ easy->result = Curl_is_connected(easy->easy_conn, FIRSTSOCKET,
&connected);
if(connected)
- easy->result = Curl_protocol_connect(easy->easy_conn, NULL);
+ easy->result = Curl_protocol_connect(easy->easy_conn);
if(CURLE_OK != easy->result) {
/* failure detected */
@@ -351,127 +431,131 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
if(connected) {
/* after the connect has completed, go DO */
easy->state = CURLM_STATE_DO;
- result = CURLM_CALL_MULTI_PERFORM;
+ result = CURLM_CALL_MULTI_PERFORM;
}
- }
- break;
+ break;
- case CURLM_STATE_DO:
- /* Do the fetch or put request */
- easy->result = Curl_do(&easy->easy_conn);
- if(CURLE_OK == easy->result) {
-
- /* after do, go PERFORM... or DO_MORE */
- if(easy->easy_conn->bits.do_more) {
- /* we're supposed to do more, but we need to sit down, relax
- and wait a little while first */
- easy->state = CURLM_STATE_DO_MORE;
- result = CURLM_OK;
- }
- else {
- /* we're done with the DO, now PERFORM */
- easy->result = Curl_readwrite_init(easy->easy_conn);
- if(CURLE_OK == easy->result) {
- easy->state = CURLM_STATE_PERFORM;
- result = CURLM_CALL_MULTI_PERFORM;
+ case CURLM_STATE_DO:
+ /* Do the fetch or put request */
+ easy->result = Curl_do(&easy->easy_conn);
+ if(CURLE_OK == easy->result) {
+
+ /* after do, go PERFORM... or DO_MORE */
+ if(easy->easy_conn->bits.do_more) {
+ /* we're supposed to do more, but we need to sit down, relax
+ and wait a little while first */
+ easy->state = CURLM_STATE_DO_MORE;
+ result = CURLM_OK;
+ }
+ else {
+ /* we're done with the DO, now PERFORM */
+ easy->result = Curl_readwrite_init(easy->easy_conn);
+ if(CURLE_OK == easy->result) {
+ easy->state = CURLM_STATE_PERFORM;
+ result = CURLM_CALL_MULTI_PERFORM;
+ }
}
}
- }
- break;
+ break;
- case CURLM_STATE_DO_MORE:
- /*
- * First, check if we really are ready to do more.
- */
- easy->result = Curl_is_connected(easy->easy_conn,
- easy->easy_conn->secondarysocket,
- &connected);
- if(connected) {
+ case CURLM_STATE_DO_MORE:
/*
- * When we are connected, DO MORE and then go PERFORM
+ * First, check if we really are ready to do more.
*/
- easy->result = Curl_do_more(easy->easy_conn);
+ easy->result = Curl_is_connected(easy->easy_conn, SECONDARYSOCKET,
+ &connected);
+ if(connected) {
+ /*
+ * When we are connected, DO MORE and then go PERFORM
+ */
+ easy->result = Curl_do_more(easy->easy_conn);
- if(CURLE_OK == easy->result)
- easy->result = Curl_readwrite_init(easy->easy_conn);
+ if(CURLE_OK == easy->result)
+ easy->result = Curl_readwrite_init(easy->easy_conn);
- if(CURLE_OK == easy->result) {
- easy->state = CURLM_STATE_PERFORM;
- result = CURLM_CALL_MULTI_PERFORM;
+ if(CURLE_OK == easy->result) {
+ easy->state = CURLM_STATE_PERFORM;
+ result = CURLM_CALL_MULTI_PERFORM;
+ }
}
- }
- break;
+ break;
- case CURLM_STATE_PERFORM:
- /* read/write data if it is ready to do so */
- easy->result = Curl_readwrite(easy->easy_conn, &done);
-
- if(easy->result) {
- /* The transfer phase returned error, we mark the connection to get
- * closed to prevent being re-used. This is becasue we can't
- * possibly know if the connection is in a good shape or not now. */
- easy->easy_conn->bits.close = TRUE;
-
- if(-1 !=easy->easy_conn->secondarysocket) {
- /* if we failed anywhere, we must clean up the secondary socket if
- it was used */
- sclose(easy->easy_conn->secondarysocket);
- easy->easy_conn->secondarysocket=-1;
+ case CURLM_STATE_PERFORM:
+ /* read/write data if it is ready to do so */
+ easy->result = Curl_readwrite(easy->easy_conn, &done);
+
+ if(easy->result) {
+ /* The transfer phase returned error, we mark the connection to get
+ * closed to prevent being re-used. This is becasue we can't
+ * possibly know if the connection is in a good shape or not now. */
+ easy->easy_conn->bits.close = TRUE;
+
+ if(CURL_SOCKET_BAD != easy->easy_conn->sock[SECONDARYSOCKET]) {
+ /* if we failed anywhere, we must clean up the secondary socket if
+ it was used */
+ sclose(easy->easy_conn->sock[SECONDARYSOCKET]);
+ easy->easy_conn->sock[SECONDARYSOCKET]=-1;
+ }
+ Curl_posttransfer(easy->easy_handle);
+ Curl_done(&easy->easy_conn, easy->result);
}
- Curl_posttransfer(easy->easy_handle);
- Curl_done(easy->easy_conn);
- }
-
- /* after the transfer is done, go DONE */
- else if(TRUE == done) {
-
- /* call this even if the readwrite function returned error */
- Curl_posttransfer(easy->easy_handle);
- /* When we follow redirects, must to go back to the CONNECT state */
- if(easy->easy_conn->newurl) {
- easy->result = Curl_follow(easy->easy_handle,
- strdup(easy->easy_conn->newurl));
- if(CURLE_OK == easy->result) {
- easy->state = CURLM_STATE_CONNECT;
+ /* after the transfer is done, go DONE */
+ else if(TRUE == done) {
+
+ /* call this even if the readwrite function returned error */
+ Curl_posttransfer(easy->easy_handle);
+
+ /* When we follow redirects, must to go back to the CONNECT state */
+ if(easy->easy_conn->newurl) {
+ char *newurl = easy->easy_conn->newurl;
+ easy->easy_conn->newurl = NULL;
+ easy->result = Curl_done(&easy->easy_conn, CURLE_OK);
+ if(easy->result == CURLE_OK)
+ easy->result = Curl_follow(easy->easy_handle, newurl);
+ if(CURLE_OK == easy->result) {
+ easy->state = CURLM_STATE_CONNECT;
+ result = CURLM_CALL_MULTI_PERFORM;
+ }
+ }
+ else {
+ easy->state = CURLM_STATE_DONE;
result = CURLM_CALL_MULTI_PERFORM;
}
}
- else {
- easy->state = CURLM_STATE_DONE;
- result = CURLM_CALL_MULTI_PERFORM;
- }
- }
- break;
- case CURLM_STATE_DONE:
- /* post-transfer command */
- easy->result = Curl_done(easy->easy_conn);
+ break;
+ case CURLM_STATE_DONE:
+ /* post-transfer command */
+ easy->result = Curl_done(&easy->easy_conn, CURLE_OK);
- /* after we have DONE what we're supposed to do, go COMPLETED, and
- it doesn't matter what the Curl_done() returned! */
- easy->state = CURLM_STATE_COMPLETED;
- break;
+ /* after we have DONE what we're supposed to do, go COMPLETED, and
+ it doesn't matter what the Curl_done() returned! */
+ easy->state = CURLM_STATE_COMPLETED;
+ break;
- case CURLM_STATE_COMPLETED:
- /* this is a completed transfer, it is likely to still be connected */
+ case CURLM_STATE_COMPLETED:
+ /* this is a completed transfer, it is likely to still be connected */
- /* This node should be delinked from the list now and we should post
- an information message that we are complete. */
- break;
- default:
- return CURLM_INTERNAL_ERROR;
- }
+ /* This node should be delinked from the list now and we should post
+ an information message that we are complete. */
+ break;
+ default:
+ return CURLM_INTERNAL_ERROR;
+ }
- if(CURLM_STATE_COMPLETED != easy->state) {
- if(CURLE_OK != easy->result)
- /*
- * If an error was returned, and we aren't in completed state now,
- * then we go to completed and consider this transfer aborted. */
- easy->state = CURLM_STATE_COMPLETED;
- else
- /* this one still lives! */
- (*running_handles)++;
- }
+ if(CURLM_STATE_COMPLETED != easy->state) {
+ if(CURLE_OK != easy->result) {
+ /*
+ * If an error was returned, and we aren't in completed state now,
+ * then we go to completed and consider this transfer aborted. */
+ easy->state = CURLM_STATE_COMPLETED;
+ }
+ else
+ /* this one still lives! */
+ (*running_handles)++;
+ }
+
+ } while (easy->easy_handle->change.url_changed);
if ((CURLM_STATE_COMPLETED == easy->state) && !easy->msg) {
/* clear out the usage of the shared DNS cache */
@@ -535,9 +619,11 @@ CURLMsg *curl_multi_info_read(CURLM *multi_handle, int *msgs_in_queue)
{
struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
+ *msgs_in_queue = 0; /* default to none */
+
if(GOOD_MULTI_HANDLE(multi)) {
struct Curl_one_easy *easy;
-
+
if(!multi->num_msgs)
return NULL; /* no messages left to return */
@@ -560,11 +646,3 @@ CURLMsg *curl_multi_info_read(CURLM *multi_handle, int *msgs_in_queue)
else
return NULL;
}
-
-/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
- */
diff --git a/Source/CTest/Curl/netrc.c b/Source/CTest/Curl/netrc.c
index da10a33..950beb0 100644
--- a/Source/CTest/Curl/netrc.c
+++ b/Source/CTest/Curl/netrc.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -41,14 +41,17 @@
#endif
#include <curl/curl.h>
+#include "netrc.h"
#include "strequal.h"
#include "strtok.h"
+#include "memory.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
/* The last #include file should be: */
-#ifdef MALLOCDEBUG
#include "memdebug.h"
-#endif
/* Debug this single source file with:
'make netrc' then run './netrc'!
@@ -71,56 +74,27 @@ enum {
#define LOGINSIZE 64
#define PASSWORDSIZE 64
+/* returns -1 on failure, 0 if the host is found, 1 is the host isn't found */
int Curl_parsenetrc(char *host,
char *login,
- char *password)
+ char *password,
+ char *netrcfile)
{
FILE *file;
- char netrcbuffer[256];
int retcode=1;
-
int specific_login = (login[0] != 0);
-
char *home = NULL;
+ bool home_alloc = FALSE;
+ bool netrc_alloc = FALSE;
int state=NOTHING;
char state_login=0; /* Found a login keyword */
char state_password=0; /* Found a password keyword */
- char state_our_login=0; /* With specific_login, found *our* login name */
+ int state_our_login=FALSE; /* With specific_login, found *our* login name */
#define NETRC DOT_CHAR "netrc"
-#if defined(HAVE_GETPWUID) && defined(HAVE_GETEUID)
- struct passwd *pw;
- pw= getpwuid(geteuid());
- if (pw) {
-#ifdef VMS
- /* VMS does not work because of warnings on icc */
- /* home = decc$translate_vms(pw->pw_dir); */
-#else
- home = pw->pw_dir;
-#endif
- }
-#else
- void *pw=NULL;
-#endif
-
- if(NULL == pw) {
- home = curl_getenv("HOME"); /* portable environment reader */
- if(!home) {
- return -1;
- }
- }
-
- if(strlen(home)>(sizeof(netrcbuffer)-strlen(NETRC))) {
- if(NULL==pw)
- free(home);
- return -1;
- }
-
- sprintf(netrcbuffer, "%s%s%s", home, DIR_CHAR, NETRC);
-
-#ifdef MALLOCDEBUG
+#ifdef CURLDEBUG
{
/* This is a hack to allow testing.
* If compiled with --enable-debug and CURL_DEBUG_NETRC is defined,
@@ -128,32 +102,59 @@ int Curl_parsenetrc(char *host,
char *override = curl_getenv("CURL_DEBUG_NETRC");
- if (override != NULL) {
- printf("NETRC: overridden .netrc file: %s\n", home);
+ if (override) {
+ printf("NETRC: overridden " NETRC " file: %s\n", home);
+ netrcfile = override;
+ netrc_alloc = TRUE;
+ }
+ }
+#endif /* CURLDEBUG */
+ if(!netrcfile) {
+ home = curl_getenv("HOME"); /* portable environment reader */
+ if(home) {
+ home_alloc = TRUE;
+#if defined(HAVE_GETPWUID) && defined(HAVE_GETEUID)
+ }
+ else {
+ struct passwd *pw;
+ pw= getpwuid(geteuid());
+ if (pw) {
+#ifdef VMS
+ home = decc$translate_vms(pw->pw_dir);
+#else
+ home = pw->pw_dir;
+#endif
+ }
+#endif
+ }
- if (strlen(override)+1 > sizeof(netrcbuffer)) {
- free(override);
- if(NULL==pw)
- free(home);
+ if(!home)
+ return -1;
- return -1;
- }
- strcpy(netrcbuffer, override);
- free(override);
+ netrcfile = curl_maprintf("%s%s%s", home, DIR_CHAR, NETRC);
+ if(!netrcfile) {
+ if(home_alloc)
+ free(home);
+ return -1;
}
+ netrc_alloc = TRUE;
}
-#endif /* MALLOCDEBUG */
- file = fopen(netrcbuffer, "r");
+ file = fopen(netrcfile, "r");
if(file) {
char *tok;
- char *tok_buf;
- while(fgets(netrcbuffer, sizeof(netrcbuffer), file)) {
+ char *tok_buf;
+ bool done=FALSE;
+ char netrcbuffer[256];
+
+ while(!done && fgets(netrcbuffer, sizeof(netrcbuffer), file)) {
tok=strtok_r(netrcbuffer, " \t\n", &tok_buf);
- while(tok) {
+ while(!done && tok) {
- if (login[0] && password[0])
- goto done;
+ if (login[0] && password[0]) {
+ done=TRUE;
+ break;
+ }
switch(state) {
case NOTHING:
@@ -182,8 +183,9 @@ int Curl_parsenetrc(char *host,
/* we are now parsing sub-keywords concerning "our" host */
if(state_login) {
if (specific_login) {
- state_our_login = (char)strequal(login, tok);
- }else{
+ state_our_login = strequal(login, tok);
+ }
+ else {
strncpy(login, tok, LOGINSIZE-1);
#ifdef _NETRC_DEBUG
printf("LOGIN: %s\n", login);
@@ -207,7 +209,7 @@ int Curl_parsenetrc(char *host,
else if(strequal("machine", tok)) {
/* ok, there's machine here go => */
state = HOSTFOUND;
- state_our_login = 0;
+ state_our_login = FALSE;
}
break;
} /* switch (state) */
@@ -216,12 +218,13 @@ int Curl_parsenetrc(char *host,
} /* while (tok) */
} /* while fgets() */
-done:
fclose(file);
}
- if(NULL==pw)
+ if(home_alloc)
free(home);
+ if(netrc_alloc)
+ free(netrcfile);
return retcode;
}
@@ -242,11 +245,3 @@ int main(int argc, char **argv)
}
#endif
-
-/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
- */
diff --git a/Source/CTest/Curl/netrc.h b/Source/CTest/Curl/netrc.h
index bbafb3d..939c552 100644
--- a/Source/CTest/Curl/netrc.h
+++ b/Source/CTest/Curl/netrc.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -24,7 +24,8 @@
***************************************************************************/
int Curl_parsenetrc(char *host,
char *login,
- char *password);
+ char *password,
+ char *filename);
/* Assume: password[0]=0, host[0] != 0.
* If login[0] = 0, search for login and password within a machine section
* in the netrc.
diff --git a/Source/CTest/Curl/nwlib.c b/Source/CTest/Curl/nwlib.c
new file mode 100644
index 0000000..b0eea56
--- /dev/null
+++ b/Source/CTest/Curl/nwlib.c
@@ -0,0 +1,300 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <library.h>
+#include <netware.h>
+#include <screen.h>
+#include <nks/thread.h>
+#include <nks/synch.h>
+
+#include "memory.h"
+#include "memdebug.h"
+
+typedef struct
+{
+ int _errno;
+ void *twentybytes;
+} libthreaddata_t;
+
+typedef struct
+{
+ int x;
+ int y;
+ int z;
+ void *tenbytes;
+ NXKey_t perthreadkey; /* if -1, no key obtained... */
+ NXMutex_t *lock;
+} libdata_t;
+
+int gLibId = -1;
+void *gLibHandle = (void *) NULL;
+rtag_t gAllocTag = (rtag_t) NULL;
+NXMutex_t *gLibLock = (NXMutex_t *) NULL;
+
+/* internal library function prototypes... */
+int DisposeLibraryData ( void * );
+void DisposeThreadData ( void * );
+int GetOrSetUpData ( int id, libdata_t **data, libthreaddata_t **threaddata );
+
+
+int _NonAppStart( void *NLMHandle,
+ void *errorScreen,
+ const char *cmdLine,
+ const char *loadDirPath,
+ size_t uninitializedDataLength,
+ void *NLMFileHandle,
+ int (*readRoutineP)( int conn,
+ void *fileHandle, size_t offset,
+ size_t nbytes,
+ size_t *bytesRead,
+ void *buffer ),
+ size_t customDataOffset,
+ size_t customDataSize,
+ int messageCount,
+ const char **messages )
+{
+ NX_LOCK_INFO_ALLOC(liblock, "Per-Application Data Lock", 0);
+
+#ifndef __GNUC__
+#pragma unused(cmdLine)
+#pragma unused(loadDirPath)
+#pragma unused(uninitializedDataLength)
+#pragma unused(NLMFileHandle)
+#pragma unused(readRoutineP)
+#pragma unused(customDataOffset)
+#pragma unused(customDataSize)
+#pragma unused(messageCount)
+#pragma unused(messages)
+#endif
+
+/*
+** Here we process our command line, post errors (to the error screen),
+** perform initializations and anything else we need to do before being able
+** to accept calls into us. If we succeed, we return non-zero and the NetWare
+** Loader will leave us up, otherwise we fail to load and get dumped.
+*/
+ gAllocTag = AllocateResourceTag(NLMHandle,
+ "<library-name> memory allocations",
+ AllocSignature);
+
+ if (!gAllocTag) {
+ OutputToScreen(errorScreen, "Unable to allocate resource tag for "
+ "library memory allocations.\n");
+ return -1;
+ }
+
+ gLibId = register_library(DisposeLibraryData);
+
+ if (gLibId < -1) {
+ OutputToScreen(errorScreen, "Unable to register library with kernel.\n");
+ return -1;
+ }
+
+ gLibHandle = NLMHandle;
+
+ gLibLock = NXMutexAlloc(0, 0, &liblock);
+
+ if (!gLibLock) {
+ OutputToScreen(errorScreen, "Unable to allocate library data lock.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+** Here we clean up any resources we allocated. Resource tags is a big part
+** of what we created, but NetWare doesn't ask us to free those.
+*/
+void _NonAppStop( void )
+{
+ (void) unregister_library(gLibId);
+ NXMutexFree(gLibLock);
+}
+
+/*
+** This function cannot be the first in the file for if the file is linked
+** first, then the check-unload function's offset will be nlmname.nlm+0
+** which is how to tell that there isn't one. When the check function is
+** first in the linked objects, it is ambiguous. For this reason, we will
+** put it inside this file after the stop function.
+**
+** Here we check to see if it's alright to ourselves to be unloaded. If not,
+** we return a non-zero value. Right now, there isn't any reason not to allow
+** it.
+*/
+int _NonAppCheckUnload( void )
+{
+ return 0;
+}
+
+int GetOrSetUpData(int id, libdata_t **appData,
+ libthreaddata_t **threadData )
+{
+ int err;
+ libdata_t *app_data;
+ libthreaddata_t *thread_data;
+ NXKey_t key;
+ NX_LOCK_INFO_ALLOC(liblock, "Application Data Lock", 0);
+
+ err = 0;
+ thread_data = (libthreaddata_t *) NULL;
+
+/*
+** Attempt to get our data for the application calling us. This is where we
+** store whatever application-specific information we need to carry in support
+** of calling applications.
+*/
+ app_data = (libdata_t *) get_app_data(id);
+
+ if (!app_data) {
+/*
+** This application hasn't called us before; set up application AND per-thread
+** data. Of course, just in case a thread from this same application is calling
+** us simultaneously, we better lock our application data-creation mutex. We
+** also need to recheck for data after we acquire the lock because WE might be
+** that other thread that was too late to create the data and the first thread
+** in will have created it.
+*/
+ NXLock(gLibLock);
+
+ if (!(app_data = (libdata_t *) get_app_data(id))) {
+ app_data = (libdata_t *) malloc(sizeof(libdata_t));
+
+ if (app_data) {
+ memset(app_data, 0, sizeof(libdata_t));
+
+ app_data->tenbytes = malloc(10);
+ app_data->lock = NXMutexAlloc(0, 0, &liblock);
+
+ if (!app_data->tenbytes || !app_data->lock) {
+ if (app_data->lock)
+ NXMutexFree(app_data->lock);
+
+ free(app_data);
+ app_data = (libdata_t *) NULL;
+ err = ENOMEM;
+ }
+
+ if (app_data) {
+/*
+** Here we burn in the application data that we were trying to get by calling
+** get_app_data(). Next time we call the first function, we'll get this data
+** we're just now setting. We also go on here to establish the per-thread data
+** for the calling thread, something we'll have to do on each application
+** thread the first time it calls us.
+*/
+ err = set_app_data(gLibId, app_data);
+
+ if (err) {
+ free(app_data);
+ app_data = (libdata_t *) NULL;
+ err = ENOMEM;
+ }
+ else {
+ /* create key for thread-specific data... */
+ err = NXKeyCreate(DisposeThreadData, (void *) NULL, &key);
+
+ if (err) /* (no more keys left?) */
+ key = -1;
+
+ app_data->perthreadkey = key;
+ }
+ }
+ }
+ }
+
+ NXUnlock(gLibLock);
+ }
+
+ if (app_data) {
+ key = app_data->perthreadkey;
+
+ if (key != -1 /* couldn't create a key? no thread data */
+ && !(err = NXKeyGetValue(key, (void **) &thread_data))
+ && !thread_data) {
+/*
+** Allocate the per-thread data for the calling thread. Regardless of whether
+** there was already application data or not, this may be the first call by a
+** a new thread. The fact that we allocation 20 bytes on a pointer is not very
+** important, this just helps to demonstrate that we can have arbitrarily
+** complex per-thread data.
+*/
+ thread_data = (libthreaddata_t *) malloc(sizeof(libthreaddata_t));
+
+ if (thread_data) {
+ thread_data->_errno = 0;
+ thread_data->twentybytes = malloc(20);
+
+ if (!thread_data->twentybytes) {
+ free(thread_data);
+ thread_data = (libthreaddata_t *) NULL;
+ err = ENOMEM;
+ }
+
+ if ((err = NXKeySetValue(key, thread_data))) {
+ free(thread_data->twentybytes);
+ free(thread_data);
+ thread_data = (libthreaddata_t *) NULL;
+ }
+ }
+ }
+ }
+
+ if (appData)
+ *appData = app_data;
+
+ if (threadData)
+ *threadData = thread_data;
+
+ return err;
+}
+
+int DisposeLibraryData( void *data)
+{
+ if (data) {
+ void *tenbytes = ((libdata_t *) data)->tenbytes;
+
+ if (tenbytes)
+ free(tenbytes);
+
+ free(data);
+ }
+
+ return 0;
+}
+
+void DisposeThreadData(void *data)
+{
+ if (data) {
+ void *twentybytes = ((libthreaddata_t *) data)->twentybytes;
+
+ if (twentybytes)
+ free(twentybytes);
+
+ free(data);
+ }
+}
diff --git a/Source/CTest/Curl/progress.c b/Source/CTest/Curl/progress.c
index 76fa18c..36be56e 100644
--- a/Source/CTest/Curl/progress.c
+++ b/Source/CTest/Curl/progress.c
@@ -1,16 +1,16 @@
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -24,17 +24,8 @@
#include "setup.h"
#include <string.h>
-
-#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
-#if defined(__MINGW32__)
-#include <winsock.h>
-#endif
#include <time.h>
-#endif
-/* 20000318 mgs
- * later we use _scrsize to determine the screen width, this emx library
- * function needs stdlib.h to be included */
#if defined(__EMX__)
#include <stdlib.h>
#endif
@@ -42,46 +33,94 @@
#include <curl/curl.h>
#include "urldata.h"
#include "sendf.h"
-
#include "progress.h"
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
-
-static void time2str(char *r, int t)
+/* Provide a string that is 2 + 1 + 2 + 1 + 2 = 8 letters long (plus the zero
+ byte) */
+static void time2str(char *r, long t)
{
- int h = (t/3600);
- int m = (t-(h*3600))/60;
- int s = (t-(h*3600)-(m*60));
- sprintf(r,"%2d:%02d:%02d",h,m,s);
+ long h;
+ if(!t) {
+ strcpy(r, "--:--:--");
+ return;
+ }
+ h = (t/3600);
+ if(h <= 99) {
+ long m = (t-(h*3600))/60;
+ long s = (t-(h*3600)-(m*60));
+ snprintf(r, 9, "%2ld:%02ld:%02ld",h,m,s);
+ }
+ else {
+ /* this equals to more than 99 hours, switch to a more suitable output
+ format to fit within the limits. */
+ if(h/24 <= 999)
+ snprintf(r, 9, "%3ldd %02ldh", h/24, h-(h/24)*24);
+ else
+ snprintf(r, 9, "%7ldd", h/24);
+ }
}
/* The point of this function would be to return a string of the input data,
- but never longer than 5 columns. Add suffix k, M, G when suitable... */
-static char *max5data(double bytes, char *max5)
+ but never longer than 5 columns (+ one zero byte).
+ Add suffix k, M, G when suitable... */
+static char *max5data(curl_off_t bytes, char *max5)
{
#define ONE_KILOBYTE 1024
-#define ONE_MEGABYTE (1024*1024)
+#define ONE_MEGABYTE (1024* ONE_KILOBYTE)
+#define ONE_GIGABYTE (1024* ONE_MEGABYTE)
+#define ONE_TERRABYTE ((curl_off_t)1024* ONE_GIGABYTE)
+#define ONE_PETABYTE ((curl_off_t)1024* ONE_TERRABYTE)
if(bytes < 100000) {
- sprintf(max5, "%5d", (int)bytes);
- return max5;
+ snprintf(max5, 6, "%5" FORMAT_OFF_T, bytes);
}
- if(bytes < (9999*ONE_KILOBYTE)) {
- sprintf(max5, "%4dk", (int)bytes/ONE_KILOBYTE);
- return max5;
+ else if(bytes < (10000*ONE_KILOBYTE)) {
+ snprintf(max5, 6, "%4" FORMAT_OFF_T "k", (curl_off_t)(bytes/ONE_KILOBYTE));
}
- if(bytes < (100*ONE_MEGABYTE)) {
+ else if(bytes < (100*ONE_MEGABYTE)) {
/* 'XX.XM' is good as long as we're less than 100 megs */
- sprintf(max5, "%4.1fM", bytes/ONE_MEGABYTE);
- return max5;
+ snprintf(max5, 6, "%2d.%0dM",
+ (int)(bytes/ONE_MEGABYTE),
+ (int)(bytes%ONE_MEGABYTE)/(ONE_MEGABYTE/10) );
}
- sprintf(max5, "%4dM", (int)bytes/ONE_MEGABYTE);
+#if SIZEOF_CURL_OFF_T > 4
+ else if(bytes < ( (curl_off_t)10000*ONE_MEGABYTE))
+ /* 'XXXXM' is good until we're at 10000MB or above */
+ snprintf(max5, 6, "%4" FORMAT_OFF_T "M", (curl_off_t)(bytes/ONE_MEGABYTE));
+
+ else if(bytes < (curl_off_t)100*ONE_GIGABYTE)
+ /* 10000 MB - 100 GB, we show it as XX.XG */
+ snprintf(max5, 6, "%2d.%0dG",
+ (int)(bytes/ONE_GIGABYTE),
+ (int)(bytes%ONE_GIGABYTE)/(ONE_GIGABYTE/10) );
+
+ else if(bytes < (curl_off_t)10000 * ONE_GIGABYTE)
+ /* up to 10000GB, display without decimal: XXXXG */
+ snprintf(max5, 6, "%4dG", (int)(bytes/ONE_GIGABYTE));
+
+ else if(bytes < (curl_off_t)10000 * ONE_TERRABYTE)
+ /* up to 10000TB, display without decimal: XXXXT */
+ snprintf(max5, 6, "%4dT", (int)(bytes/ONE_TERRABYTE));
+ else {
+ /* up to 10000PB, display without decimal: XXXXP */
+ snprintf(max5, 6, "%4dP", (int)(bytes/ONE_PETABYTE));
+
+ /* 16384 petabytes (16 exabytes) is maximum a 64 bit number can hold,
+ but this type is signed so 8192PB will be max.*/
+ }
+
+#else
+ else
+ snprintf(max5, 6, "%4" FORMAT_OFF_T "M", (curl_off_t)(bytes/ONE_MEGABYTE));
+#endif
+
return max5;
}
-/*
+/*
New proposed interface, 9th of February 2000:
@@ -98,13 +137,12 @@ static char *max5data(double bytes, char *max5)
void Curl_pgrsDone(struct connectdata *conn)
{
struct SessionHandle *data = conn->data;
- if(!(data->progress.flags & PGRS_HIDE)) {
- data->progress.lastshow=0;
- Curl_pgrsUpdate(conn); /* the final (forced) update */
- if(!data->progress.callback)
- /* only output if we don't use progress callback */
- fprintf(data->set.err, "\n");
- }
+ data->progress.lastshow=0;
+ Curl_pgrsUpdate(conn); /* the final (forced) update */
+ if(!(data->progress.flags & PGRS_HIDE) &&
+ !data->progress.callback)
+ /* only output if we don't use a progress callback and we're not hidden */
+ fprintf(data->set.err, "\n");
}
/* reset all times except redirect */
@@ -130,26 +168,26 @@ void Curl_pgrsTime(struct SessionHandle *data, timerid timer)
case TIMER_NAMELOOKUP:
data->progress.t_nslookup =
- (double)Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle)/1000.0;
+ Curl_tvdiff_secs(Curl_tvnow(), data->progress.t_startsingle);
break;
case TIMER_CONNECT:
data->progress.t_connect =
- (double)Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle)/1000.0;
+ Curl_tvdiff_secs(Curl_tvnow(), data->progress.t_startsingle);
break;
case TIMER_PRETRANSFER:
data->progress.t_pretransfer =
- (double)Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle)/1000.0;
+ Curl_tvdiff_secs(Curl_tvnow(), data->progress.t_startsingle);
break;
case TIMER_STARTTRANSFER:
data->progress.t_starttransfer =
- (double)Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle)/1000.0;
+ Curl_tvdiff_secs(Curl_tvnow(), data->progress.t_startsingle);
break;
case TIMER_POSTRANSFER:
/* this is the normal end-of-transfer thing */
break;
case TIMER_REDIRECT:
data->progress.t_redirect =
- (double)Curl_tvdiff(Curl_tvnow(), data->progress.start)/1000.0;
+ Curl_tvdiff_secs(Curl_tvnow(), data->progress.start);
break;
}
}
@@ -160,70 +198,55 @@ void Curl_pgrsStartNow(struct SessionHandle *data)
data->progress.start = Curl_tvnow();
}
-void Curl_pgrsSetDownloadCounter(struct SessionHandle *data, double size)
+void Curl_pgrsSetDownloadCounter(struct SessionHandle *data, curl_off_t size)
{
data->progress.downloaded = size;
}
-void Curl_pgrsSetUploadCounter(struct SessionHandle *data, double size)
+void Curl_pgrsSetUploadCounter(struct SessionHandle *data, curl_off_t size)
{
data->progress.uploaded = size;
}
-void Curl_pgrsSetDownloadSize(struct SessionHandle *data, double size)
+void Curl_pgrsSetDownloadSize(struct SessionHandle *data, curl_off_t size)
{
- if(size > 0) {
- data->progress.size_dl = size;
+ data->progress.size_dl = size;
+ if(size > 0)
data->progress.flags |= PGRS_DL_SIZE_KNOWN;
- }
+ else
+ data->progress.flags &= ~PGRS_DL_SIZE_KNOWN;
}
-void Curl_pgrsSetUploadSize(struct SessionHandle *data, double size)
+void Curl_pgrsSetUploadSize(struct SessionHandle *data, curl_off_t size)
{
- if(size > 0) {
- data->progress.size_ul = size;
+ data->progress.size_ul = size;
+ if(size > 0)
data->progress.flags |= PGRS_UL_SIZE_KNOWN;
- }
+ else
+ data->progress.flags &= ~PGRS_UL_SIZE_KNOWN;
}
-/* EXAMPLE OUTPUT to follow:
-
- % Total % Received % Xferd Average Speed Time Curr.
- Dload Upload Total Current Left Speed
-100 12345 100 12345 100 12345 12345 12345 12:12:12 12:12:12 12:12:12 12345
-
- */
-
int Curl_pgrsUpdate(struct connectdata *conn)
{
struct timeval now;
int result;
-
char max5[6][10];
- double dlpercen=0;
- double ulpercen=0;
- double total_percen=0;
-
- double total_transfer;
- double total_expected_transfer;
- double timespent;
-
+ int dlpercen=0;
+ int ulpercen=0;
+ int total_percen=0;
+ curl_off_t total_transfer;
+ curl_off_t total_expected_transfer;
+ long timespent;
struct SessionHandle *data = conn->data;
-
int nowindex = data->progress.speeder_c% CURR_TIME;
int checkindex;
-
int countindex; /* amount of seconds stored in the speeder array */
-
char time_left[10];
char time_total[10];
- char time_current[10];
-
- double ulestimate=0;
- double dlestimate=0;
-
- double total_estimate;
-
+ char time_spent[10];
+ long ulestimate=0;
+ long dlestimate=0;
+ long total_estimate;
if(data->progress.flags & PGRS_HIDE)
; /* We do enter this function even if we don't wanna see anything, since
@@ -232,32 +255,35 @@ int Curl_pgrsUpdate(struct connectdata *conn)
else if(!(data->progress.flags & PGRS_HEADERS_OUT)) {
if (!data->progress.callback) {
if(conn->resume_from)
- fprintf(data->set.err, "** Resuming transfer from byte position %d\n",
+ fprintf(data->set.err,
+ "** Resuming transfer from byte position %" FORMAT_OFF_T
+ "\n",
conn->resume_from);
fprintf(data->set.err,
- " %% Total %% Received %% Xferd Average Speed Time Curr.\n"
- " Dload Upload Total Current Left Speed\n");
+ " %% Total %% Received %% Xferd Average Speed Time Time Time Current\n"
+ " Dload Upload Total Spent Left Speed\n");
}
data->progress.flags |= PGRS_HEADERS_OUT; /* headers are shown */
}
now = Curl_tvnow(); /* what time is it */
- /* The exact time spent so far (from the start) */
- timespent = (double)Curl_tvdiff (now, data->progress.start)/1000;
-
- data->progress.timespent = timespent;
+ /* The time spent so far (from the start) */
+ data->progress.timespent = Curl_tvdiff_secs(now, data->progress.start);
+ timespent = (long)data->progress.timespent;
/* The average download speed this far */
- data->progress.dlspeed =
- data->progress.downloaded/(timespent>0.01?timespent:1);
+ data->progress.dlspeed = (curl_off_t)
+ ((double)data->progress.downloaded/
+ (data->progress.timespent>0?data->progress.timespent:1));
/* The average upload speed this far */
- data->progress.ulspeed =
- data->progress.uploaded/(timespent>0.01?timespent:1);
+ data->progress.ulspeed = (curl_off_t)
+ ((double)data->progress.uploaded/
+ (data->progress.timespent>0?data->progress.timespent:1));
if(data->progress.lastshow == Curl_tvlong(now))
- return 0; /* never update this more than once a second if the end isn't
+ return 0; /* never update this more than once a second if the end isn't
reached */
data->progress.lastshow = now.tv_sec;
@@ -297,10 +323,21 @@ int Curl_pgrsUpdate(struct connectdata *conn)
if(0 == span_ms)
span_ms=1; /* at least one millisecond MUST have passed */
- /* Calculate the average speed the last 'countindex' seconds */
- data->progress.current_speed =
- (data->progress.speeder[nowindex]-
- data->progress.speeder[checkindex])/((double)span_ms/1000);
+ /* Calculate the average speed the last 'span_ms' milliseconds */
+ {
+ curl_off_t amount = data->progress.speeder[nowindex]-
+ data->progress.speeder[checkindex];
+
+ if(amount > 0xffffffff/1000)
+ /* the 'amount' value is bigger than would fit in 32 bits if
+ multiplied with 1000, so we use the double math for this */
+ data->progress.current_speed = (curl_off_t)
+ ((double)amount/((double)span_ms/1000.0));
+ else
+ /* the 'amount' value is small enough to fit within 32 bits even
+ when multiplied with 1000 */
+ data->progress.current_speed = amount*1000/span_ms;
+ }
}
else
/* the first second we use the main average */
@@ -315,74 +352,70 @@ int Curl_pgrsUpdate(struct connectdata *conn)
/* There's a callback set, so we call that instead of writing
anything ourselves. This really is the way to go. */
result= data->set.fprogress(data->set.progress_client,
- data->progress.size_dl,
- data->progress.downloaded,
- data->progress.size_ul,
- data->progress.uploaded);
+ (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;
}
/* Figure out the estimated time of arrival for the upload */
- if((data->progress.flags & PGRS_UL_SIZE_KNOWN) && data->progress.ulspeed){
- ulestimate = data->progress.size_ul / data->progress.ulspeed;
- ulpercen = (data->progress.uploaded / data->progress.size_ul)*100;
+ if((data->progress.flags & PGRS_UL_SIZE_KNOWN) &&
+ (data->progress.ulspeed>0) &&
+ (data->progress.size_ul > 100) ) {
+ ulestimate = (long)(data->progress.size_ul / data->progress.ulspeed);
+ ulpercen = (int)(100*(data->progress.uploaded/100) /
+ (data->progress.size_ul/100) );
}
/* ... and the download */
- if((data->progress.flags & PGRS_DL_SIZE_KNOWN) && data->progress.dlspeed) {
- dlestimate = data->progress.size_dl / data->progress.dlspeed;
- dlpercen = (data->progress.downloaded / data->progress.size_dl)*100;
+ if((data->progress.flags & PGRS_DL_SIZE_KNOWN) &&
+ (data->progress.dlspeed>0) &&
+ (data->progress.size_dl>100)) {
+ dlestimate = (long)(data->progress.size_dl / data->progress.dlspeed);
+ dlpercen = (int)(100*(data->progress.downloaded/100) /
+ (data->progress.size_dl/100));
}
-
+
/* Now figure out which of them that is slower and use for the for
total estimate! */
total_estimate = ulestimate>dlestimate?ulestimate:dlestimate;
-
- /* If we have a total estimate, we can display that and the expected
- time left */
- if(total_estimate) {
- time2str(time_left, (int)(total_estimate - data->progress.timespent));
- time2str(time_total, (int)total_estimate);
- }
- else {
- /* otherwise we blank those times */
- strcpy(time_left, "--:--:--");
- strcpy(time_total, "--:--:--");
- }
- /* The time spent so far is always known */
- time2str(time_current, (int)data->progress.timespent);
+ /* create the three time strings */
+ time2str(time_left, total_estimate > 0?(total_estimate - timespent):0);
+ time2str(time_total, total_estimate);
+ time2str(time_spent, timespent);
/* Get the total amount of data expected to get transfered */
- total_expected_transfer =
+ total_expected_transfer =
(data->progress.flags & PGRS_UL_SIZE_KNOWN?
data->progress.size_ul:data->progress.uploaded)+
(data->progress.flags & PGRS_DL_SIZE_KNOWN?
data->progress.size_dl:data->progress.downloaded);
-
+
/* We have transfered this much so far */
total_transfer = data->progress.downloaded + data->progress.uploaded;
/* Get the percentage of data transfered so far */
- if(total_expected_transfer)
- total_percen=(double)(total_transfer/total_expected_transfer)*100;
+ if(total_expected_transfer > 100)
+ total_percen=(int)(100*(total_transfer/100) /
+ (total_expected_transfer/100) );
fprintf(data->set.err,
"\r%3d %s %3d %s %3d %s %s %s %s %s %s %s",
- (int)total_percen, /* total % */
+ total_percen, /* 3 letters */ /* total % */
max5data(total_expected_transfer, max5[2]), /* total size */
- (int)dlpercen, /* rcvd % */
+ dlpercen, /* 3 letters */ /* rcvd % */
max5data(data->progress.downloaded, max5[0]), /* rcvd size */
- (int)ulpercen, /* xfer % */
+ ulpercen, /* 3 letters */ /* xfer % */
max5data(data->progress.uploaded, max5[1]), /* xfer size */
-
- max5data(data->progress.dlspeed, max5[3]), /* avrg dl speed */
- max5data(data->progress.ulspeed, max5[4]), /* avrg ul speed */
- time_total, /* total time */
- time_current, /* current time */
- time_left, /* time left */
+ max5data(data->progress.dlspeed, max5[3]), /* avrg dl speed */
+ max5data(data->progress.ulspeed, max5[4]), /* avrg ul speed */
+ time_total, /* 8 letters */ /* total time */
+ time_spent, /* 8 letters */ /* time spent */
+ time_left, /* 8 letters */ /* time left */
max5data(data->progress.current_speed, max5[5]) /* current speed */
);
@@ -391,11 +424,3 @@ int Curl_pgrsUpdate(struct connectdata *conn)
return 0;
}
-
-/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
- */
diff --git a/Source/CTest/Curl/progress.h b/Source/CTest/Curl/progress.h
index 51994cb..dcfcaf7 100644
--- a/Source/CTest/Curl/progress.h
+++ b/Source/CTest/Curl/progress.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -40,10 +40,10 @@ typedef enum {
void Curl_pgrsDone(struct connectdata *);
void Curl_pgrsStartNow(struct SessionHandle *data);
-void Curl_pgrsSetDownloadSize(struct SessionHandle *data, double size);
-void Curl_pgrsSetUploadSize(struct SessionHandle *data, double size);
-void Curl_pgrsSetDownloadCounter(struct SessionHandle *data, double size);
-void Curl_pgrsSetUploadCounter(struct SessionHandle *data, double size);
+void Curl_pgrsSetDownloadSize(struct SessionHandle *data, curl_off_t size);
+void Curl_pgrsSetUploadSize(struct SessionHandle *data, curl_off_t size);
+void Curl_pgrsSetDownloadCounter(struct SessionHandle *data, curl_off_t size);
+void Curl_pgrsSetUploadCounter(struct SessionHandle *data, curl_off_t size);
int Curl_pgrsUpdate(struct connectdata *);
void Curl_pgrsResetTimes(struct SessionHandle *data);
void Curl_pgrsTime(struct SessionHandle *data, timerid timer);
diff --git a/Source/CTest/Curl/security.c b/Source/CTest/Curl/security.c
index c8f3c22..3b2a392 100644
--- a/Source/CTest/Curl/security.c
+++ b/Source/CTest/Curl/security.c
@@ -10,22 +10,22 @@
* Copyright (c) 1998, 1999 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
- *
+ *
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -41,7 +41,7 @@
#include "setup.h"
#ifndef CURL_DISABLE_FTP
-#ifdef KRB4
+#ifdef HAVE_KRB4
#define _MPRINTF_REPLACE /* we want curl-functions instead of native ones */
#include <curl/mprintf.h>
@@ -58,11 +58,10 @@
#include "base64.h"
#include "sendf.h"
#include "ftp.h"
+#include "memory.h"
/* The last #include file should be: */
-#ifdef MALLOCDEBUG
#include "memdebug.h"
-#endif
#define min(a, b) ((a) < (b) ? (a) : (b))
@@ -76,7 +75,7 @@ static struct {
{ prot_private, "private" }
};
-static enum protection_level
+static enum protection_level
name_to_level(const char *name)
{
int i;
@@ -90,7 +89,7 @@ static struct Curl_sec_client_mech *mechs[] = {
#ifdef KRB5
/* not supported */
#endif
-#ifdef KRB4
+#ifdef HAVE_KRB4
&Curl_krb4_client_mech,
#endif
NULL
@@ -147,7 +146,7 @@ sec_get_data(struct connectdata *conn,
{
int len;
int b;
-
+
b = block_read(fd, &len, sizeof(len));
if (b == 0)
return 0;
@@ -207,12 +206,12 @@ Curl_sec_read(struct connectdata *conn, int fd, void *buffer, int length)
conn->in_buffer.eof_flag = 0;
return 0;
}
-
+
len = buffer_read(&conn->in_buffer, buffer, length);
length -= len;
rx += len;
buffer = (char*)buffer + len;
-
+
while(length) {
if(sec_get_data(conn, fd, &conn->in_buffer) < 0)
return -1;
@@ -262,7 +261,7 @@ Curl_sec_write(struct connectdata *conn, int fd, char *buffer, int length)
{
int len = conn->buffer_size;
int tx = 0;
-
+
if(conn->data_prot == prot_clear)
return write(fd, buffer, length);
@@ -284,7 +283,7 @@ Curl_sec_putc(struct connectdata *conn, int c, FILE *F)
char ch = c;
if(conn->data_prot == prot_clear)
return putc(c, F);
-
+
buffer_write(&conn->out_buffer, &ch, 1);
if(c == '\n' || conn->out_buffer.index >= 1024 /* XXX */) {
Curl_sec_write(conn, fileno(F), conn->out_buffer.data,
@@ -297,36 +296,38 @@ Curl_sec_putc(struct connectdata *conn, int c, FILE *F)
int
Curl_sec_read_msg(struct connectdata *conn, char *s, int level)
{
- int len;
- char *buf;
- int code;
-
- buf = malloc(strlen(s));
- len = Curl_base64_decode(s + 4, buf); /* XXX */
-
- len = (conn->mech->decode)(conn->app_data, buf, len, level, conn);
- if(len < 0)
- return -1;
-
- buf[len] = '\0';
-
- if(buf[3] == '-')
- code = 0;
- else
- sscanf(buf, "%d", &code);
- if(buf[len-1] == '\n')
- buf[len-1] = '\0';
- strcpy(s, buf);
+ int len;
+ char *buf;
+ int code;
+
+ buf = malloc(strlen(s));
+ len = Curl_base64_decode(s + 4, buf); /* XXX */
+
+ len = (conn->mech->decode)(conn->app_data, buf, len, level, conn);
+ if(len < 0) {
free(buf);
- return code;
+ return -1;
+ }
+
+ buf[len] = '\0';
+
+ if(buf[3] == '-')
+ code = 0;
+ else
+ sscanf(buf, "%d", &code);
+ if(buf[len-1] == '\n')
+ buf[len-1] = '\0';
+ strcpy(s, buf);
+ free(buf);
+ return code;
}
enum protection_level
Curl_set_command_prot(struct connectdata *conn, enum protection_level level)
{
- enum protection_level old = conn->command_prot;
- conn->command_prot = level;
- return old;
+ enum protection_level old = conn->command_prot;
+ conn->command_prot = level;
+ return old;
}
static int
@@ -372,7 +373,7 @@ sec_prot_internal(struct connectdata *conn, int level)
failf(conn->data, "Failed to set protection level.");
return -1;
}
-
+
conn->data_prot = (enum protection_level)level;
return 0;
}
@@ -413,7 +414,7 @@ Curl_sec_login(struct connectdata *conn)
return -1;
}
conn->app_data = tmp;
-
+
if((*m)->init && (*(*m)->init)(conn->app_data) != 0) {
infof(data, "Skipping %s...\n", (*m)->name);
continue;
@@ -447,7 +448,7 @@ Curl_sec_login(struct connectdata *conn)
}
ret = (*(*m)->auth)(conn->app_data, conn);
-
+
if(ret == AUTH_CONTINUE)
continue;
else if(ret != AUTH_OK){
@@ -459,7 +460,7 @@ Curl_sec_login(struct connectdata *conn)
conn->command_prot = prot_safe;
break;
}
-
+
return *m == NULL;
}
@@ -478,13 +479,5 @@ Curl_sec_end(struct connectdata *conn)
conn->mech=NULL;
}
-#endif /* KRB4 */
+#endif /* HAVE_KRB4 */
#endif /* CURL_DISABLE_FTP */
-
-/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
- */
diff --git a/Source/CTest/Curl/security.h b/Source/CTest/Curl/security.h
index 3bbb78f..5213ba5 100644
--- a/Source/CTest/Curl/security.h
+++ b/Source/CTest/Curl/security.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
diff --git a/Source/CTest/Curl/sendf.c b/Source/CTest/Curl/sendf.c
index 01cfb23..7d0f71d 100644
--- a/Source/CTest/Curl/sendf.c
+++ b/Source/CTest/Curl/sendf.c
@@ -1,16 +1,16 @@
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -39,25 +39,22 @@
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
-#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
-#include <winsock.h>
-#endif
#include <curl/curl.h>
#include "urldata.h"
#include "sendf.h"
+#include "connect.h" /* for the Curl_ourerrno() proto */
#define _MPRINTF_REPLACE /* use the internal *printf() functions */
#include <curl/mprintf.h>
-#ifdef KRB4
+#ifdef HAVE_KRB4
#include "security.h"
#endif
#include <string.h>
+#include "memory.h"
/* The last #include file should be: */
-#ifdef MALLOCDEBUG
#include "memdebug.h"
-#endif
/* returns last node in linked list */
static struct curl_slist *slist_get_last(struct curl_slist *list)
@@ -76,11 +73,13 @@ static struct curl_slist *slist_get_last(struct curl_slist *list)
return item;
}
-/* append a struct to the linked list. It always retunrs the address of the
- * first record, so that you can sure this function as an initialization
- * function as well as an append function. If you find this bothersome,
- * then simply create a separate _init function and call it appropriately from
- * within the proram. */
+/*
+ * curl_slist_append() appends a string to the linked list. It always retunrs
+ * the address of the first record, so that you can sure this function as an
+ * initialization function as well as an append function. If you find this
+ * bothersome, then simply create a separate _init function and call it
+ * appropriately from within the proram.
+ */
struct curl_slist *curl_slist_append(struct curl_slist *list,
const char *data)
{
@@ -89,13 +88,18 @@ struct curl_slist *curl_slist_append(struct curl_slist *list,
new_item = (struct curl_slist *) malloc(sizeof(struct curl_slist));
if (new_item) {
- new_item->next = NULL;
- new_item->data = strdup(data);
+ char *dup = strdup(data);
+ if(dup) {
+ new_item->next = NULL;
+ new_item->data = dup;
+ }
+ else {
+ free(new_item);
+ return NULL;
+ }
}
- if (new_item == NULL || new_item->data == NULL) {
- fprintf(stderr, "Cannot allocate memory for QUOTE list.\n");
+ else
return NULL;
- }
if (list) {
last = slist_get_last(list);
@@ -119,7 +123,7 @@ void curl_slist_free_all(struct curl_slist *list)
item = list;
do {
next = item->next;
-
+
if (item->data) {
free(item->data);
}
@@ -132,13 +136,13 @@ void curl_slist_free_all(struct curl_slist *list)
void Curl_infof(struct SessionHandle *data, const char *fmt, ...)
{
- va_list ap;
- if(data->set.verbose) {
+ if(data && data->set.verbose) {
+ va_list ap;
char print_buffer[1024 + 1];
va_start(ap, fmt);
vsnprintf(print_buffer, 1024, fmt, ap);
va_end(ap);
- Curl_debug(data, CURLINFO_TEXT, print_buffer, strlen(print_buffer));
+ Curl_debug(data, CURLINFO_TEXT, print_buffer, strlen(print_buffer), NULL);
}
}
@@ -155,14 +159,14 @@ void Curl_failf(struct SessionHandle *data, const char *fmt, ...)
data->state.errorbuf = TRUE; /* wrote error string */
if(data->set.verbose) {
- int len = (int)strlen(data->set.errorbuffer);
+ size_t len = strlen(data->set.errorbuffer);
bool doneit=FALSE;
- if(len < CURL_ERROR_SIZE) {
+ if(len < CURL_ERROR_SIZE - 1) {
doneit = TRUE;
data->set.errorbuffer[len] = '\n';
data->set.errorbuffer[++len] = '\0';
}
- Curl_debug(data, CURLINFO_TEXT, data->set.errorbuffer, len);
+ Curl_debug(data, CURLINFO_TEXT, data->set.errorbuffer, len, NULL);
if(doneit)
/* cut off the newline again */
data->set.errorbuffer[--len]=0;
@@ -172,12 +176,12 @@ void Curl_failf(struct SessionHandle *data, const char *fmt, ...)
}
/* Curl_sendf() sends formated data to the server */
-CURLcode Curl_sendf(int sockfd, struct connectdata *conn,
+CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn,
const char *fmt, ...)
{
struct SessionHandle *data = conn->data;
ssize_t bytes_written;
- ssize_t write_len;
+ size_t write_len;
CURLcode res;
char *s;
char *sptr;
@@ -189,10 +193,10 @@ CURLcode Curl_sendf(int sockfd, struct connectdata *conn,
return CURLE_OUT_OF_MEMORY; /* failure */
bytes_written=0;
- write_len = (int)strlen(s);
+ write_len = strlen(s);
sptr = s;
- do {
+ while (1) {
/* Write the buffer to the socket */
res = Curl_write(conn, sockfd, sptr, write_len, &bytes_written);
@@ -200,9 +204,10 @@ CURLcode Curl_sendf(int sockfd, struct connectdata *conn,
break;
if(data->set.verbose)
- Curl_debug(data, CURLINFO_DATA_OUT, sptr, bytes_written);
+ Curl_debug(data, CURLINFO_DATA_OUT, sptr, bytes_written,
+ conn->host.dispname);
- if(bytes_written != write_len) {
+ if((size_t)bytes_written != write_len) {
/* if not all was written at once, we must advance the pointer, decrease
the size left and try again! */
write_len -= bytes_written;
@@ -210,8 +215,7 @@ CURLcode Curl_sendf(int sockfd, struct connectdata *conn,
}
else
break;
-
- } while(1);
+ }
free(s); /* free the output string */
@@ -221,33 +225,51 @@ CURLcode Curl_sendf(int sockfd, struct connectdata *conn,
/*
* Curl_write() is an internal write function that sends plain (binary) data
* to the server. Works with plain sockets, SSL or kerberos.
- *
*/
-CURLcode Curl_write(struct connectdata *conn, int sockfd,
- void *mem, size_t len,
+CURLcode Curl_write(struct connectdata *conn,
+ curl_socket_t sockfd,
+ void *mem,
+ size_t len,
ssize_t *written)
{
ssize_t bytes_written;
- (void)conn;
+ CURLcode retcode;
#ifdef USE_SSLEAY
+ /* Set 'num' to 0 or 1, depending on which socket that has been sent here.
+ If it is the second socket, we set num to 1. Otherwise to 0. This lets
+ us use the correct ssl handle. */
+ int num = (sockfd == conn->sock[SECONDARYSOCKET]);
/* SSL_write() is said to return 'int' while write() and send() returns
'size_t' */
- if (conn->ssl.use) {
+ if (conn->ssl[num].use) {
int err;
- int rc = SSL_write(conn->ssl.handle, mem, len);
+ char error_buffer[120]; /* OpenSSL documents that this must be at least
+ 120 bytes long. */
+ unsigned long sslerror;
+ int rc = SSL_write(conn->ssl[num].handle, mem, (int)len);
if(rc < 0) {
- err = SSL_get_error(conn->ssl.handle, rc);
-
+ err = SSL_get_error(conn->ssl[num].handle, rc);
+
switch(err) {
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
- /* this is basicly the EWOULDBLOCK equivalent */
+ /* The operation did not complete; the same TLS/SSL I/O function
+ should be called again later. This is basicly an EWOULDBLOCK
+ equivalent. */
*written = 0;
return CURLE_OK;
case SSL_ERROR_SYSCALL:
- failf(conn->data, "SSL_write() returned SYSCALL, errno = %d\n", errno);
+ failf(conn->data, "SSL_write() returned SYSCALL, errno = %d\n",
+ Curl_ourerrno());
+ return CURLE_SEND_ERROR;
+ case SSL_ERROR_SSL:
+ /* A failure in the SSL library occurred, usually a protocol error.
+ The OpenSSL error queue contains more information on the error. */
+ sslerror = ERR_get_error();
+ failf(conn->data, "SSL_write() error: %s\n",
+ ERR_error_string(sslerror, error_buffer));
return CURLE_SEND_ERROR;
}
/* a true error */
@@ -257,34 +279,44 @@ CURLcode Curl_write(struct connectdata *conn, int sockfd,
bytes_written = rc;
}
else {
+#else
+ (void)conn;
#endif
-#ifdef KRB4
+#ifdef HAVE_KRB4
if(conn->sec_complete) {
bytes_written = Curl_sec_write(conn, sockfd, mem, len);
}
else
-#endif /* KRB4 */
+#endif /* HAVE_KRB4 */
{
- bytes_written = (int)swrite(sockfd, mem, (int)len);
+ bytes_written = (ssize_t)swrite(sockfd, mem, len);
}
if(-1 == bytes_written) {
-#ifdef WIN32
- if(WSAEWOULDBLOCK == GetLastError())
+ int err = Curl_ourerrno();
+
+ if(
+#ifdef WSAEWOULDBLOCK
+ /* This is how Windows does it */
+ (WSAEWOULDBLOCK == err)
#else
- if(EWOULDBLOCK == errno)
+ /* As pointed out by Christophe Demory on March 11 2003, errno
+ may be EWOULDBLOCK or on some systems EAGAIN when it returned
+ due to its inability to send off data without blocking. We
+ therefor treat both error codes the same here */
+ (EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err)
#endif
- {
+ )
/* this is just a case of EWOULDBLOCK */
- *written=0;
- return CURLE_OK;
- }
+ bytes_written=0;
}
#ifdef USE_SSLEAY
}
#endif
*written = bytes_written;
- return (-1 != bytes_written)?CURLE_OK:CURLE_SEND_ERROR;
+ retcode = (-1 != bytes_written)?CURLE_OK:CURLE_SEND_ERROR;
+
+ return retcode;
}
/* client_write() sends data to the write callback(s)
@@ -324,7 +356,7 @@ CURLcode Curl_client_write(struct SessionHandle *data,
return CURLE_WRITE_ERROR;
}
}
-
+
return CURLE_OK;
}
@@ -335,23 +367,27 @@ CURLcode Curl_client_write(struct SessionHandle *data,
* If the read would block (EWOULDBLOCK) we return -1. Otherwise we return
* a regular CURLcode value.
*/
-int Curl_read(struct connectdata *conn,
- int sockfd,
- char *buf,
- size_t buffersize,
- ssize_t *n)
+int Curl_read(struct connectdata *conn, /* connection data */
+ curl_socket_t sockfd, /* read from this socket */
+ char *buf, /* store read data here */
+ size_t buffersize, /* max amount to read */
+ ssize_t *n) /* amount bytes read */
{
ssize_t nread;
+#ifdef USE_SSLEAY
+ /* Set 'num' to 0 or 1, depending on which socket that has been sent here.
+ If it is the second socket, we set num to 1. Otherwise to 0. This lets
+ us use the correct ssl handle. */
+ int num = (sockfd == conn->sock[SECONDARYSOCKET]);
+
*n=0; /* reset amount to zero */
- (void)conn;
-#ifdef USE_SSLEAY
- if (conn->ssl.use) {
- nread = SSL_read(conn->ssl.handle, buf, buffersize);
+ if (conn->ssl[num].use) {
+ nread = (ssize_t)SSL_read(conn->ssl[num].handle, buf, (int)buffersize);
if(nread < 0) {
/* failed SSL_read */
- int err = SSL_get_error(conn->ssl.handle, nread);
+ int err = SSL_get_error(conn->ssl[num].handle, (int)nread);
switch(err) {
case SSL_ERROR_NONE: /* this is not an error */
@@ -362,25 +398,37 @@ int Curl_read(struct connectdata *conn,
/* there's data pending, re-invoke SSL_read() */
return -1; /* basicly EWOULDBLOCK */
default:
- failf(conn->data, "SSL read error: %d", err);
+ /* openssl/ssl.h says "look at error stack/return value/errno" */
+ {
+ char error_buffer[120]; /* OpenSSL documents that this must be at
+ least 120 bytes long. */
+ unsigned long sslerror = ERR_get_error();
+ failf(conn->data, "SSL read: %s, errno %d",
+ ERR_error_string(sslerror, error_buffer),
+ Curl_ourerrno() );
+ }
return CURLE_RECV_ERROR;
}
}
}
else {
+#else
+ (void)conn;
#endif
-#ifdef KRB4
+ *n=0; /* reset amount to zero */
+#ifdef HAVE_KRB4
if(conn->sec_complete)
nread = Curl_sec_read(conn, sockfd, buf, buffersize);
else
#endif
- nread = sread (sockfd, buf, (int)buffersize);
+ nread = sread(sockfd, buf, buffersize);
if(-1 == nread) {
+ int err = Curl_ourerrno();
#ifdef WIN32
- if(WSAEWOULDBLOCK == GetLastError())
+ if(WSAEWOULDBLOCK == err)
#else
- if(EWOULDBLOCK == errno)
+ if((EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err))
#endif
return -1;
}
@@ -393,11 +441,11 @@ int Curl_read(struct connectdata *conn,
}
/* return 0 on success */
-int Curl_debug(struct SessionHandle *data, curl_infotype type,
- char *ptr, size_t size)
+static int showit(struct SessionHandle *data, curl_infotype type,
+ char *ptr, size_t size)
{
static const char * const s_infotype[CURLINFO_END] = {
- "* ", "< ", "> ", "{ ", "} " };
+ "* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
if(data->set.fdebug)
return (*data->set.fdebug)(data, type, ptr, size,
@@ -406,6 +454,7 @@ int Curl_debug(struct SessionHandle *data, curl_infotype type,
switch(type) {
case CURLINFO_TEXT:
case CURLINFO_HEADER_OUT:
+ case CURLINFO_HEADER_IN:
fwrite(s_infotype[type], 2, 1, data->set.err);
fwrite(ptr, size, 1, data->set.err);
break;
@@ -415,11 +464,33 @@ int Curl_debug(struct SessionHandle *data, curl_infotype type,
return 0;
}
+int Curl_debug(struct SessionHandle *data, curl_infotype type,
+ char *ptr, size_t size, char *host)
+{
+ int rc;
+ if(data->set.printhost && host) {
+ char buffer[160];
+ const char *t=NULL;
+ switch (type) {
+ case CURLINFO_HEADER_IN:
+ case CURLINFO_DATA_IN:
+ t = "from";
+ break;
+ case CURLINFO_HEADER_OUT:
+ case CURLINFO_DATA_OUT:
+ t = "to";
+ break;
+ default:
+ break;
+ }
-/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
- */
+ if(t) {
+ snprintf(buffer, sizeof(buffer), "[Data %s %s]", t, host);
+ rc = showit(data, CURLINFO_TEXT, buffer, strlen(buffer));
+ if(rc)
+ return rc;
+ }
+ }
+ rc = showit(data, type, ptr, size);
+ return rc;
+}
diff --git a/Source/CTest/Curl/sendf.h b/Source/CTest/Curl/sendf.h
index 97e2fa9..bdd3a79 100644
--- a/Source/CTest/Curl/sendf.h
+++ b/Source/CTest/Curl/sendf.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -23,7 +23,8 @@
* $Id$
***************************************************************************/
-CURLcode Curl_sendf(int fd, struct connectdata *, const char *fmt, ...);
+CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *,
+ const char *fmt, ...);
void Curl_infof(struct SessionHandle *, const char *fmt, ...);
void Curl_failf(struct SessionHandle *, const char *fmt, ...);
@@ -38,17 +39,18 @@ CURLcode Curl_client_write(struct SessionHandle *data, int type, char *ptr,
size_t len);
/* internal read-function, does plain socket, SSL and krb4 */
-int Curl_read(struct connectdata *conn, int sockfd,
+int Curl_read(struct connectdata *conn, curl_socket_t sockfd,
char *buf, size_t buffersize,
ssize_t *n);
/* internal write-function, does plain socket, SSL and krb4 */
-CURLcode Curl_write(struct connectdata *conn, int sockfd,
+CURLcode Curl_write(struct connectdata *conn,
+ curl_socket_t sockfd,
void *mem, size_t len,
ssize_t *written);
/* the function used to output verbose information */
int Curl_debug(struct SessionHandle *handle, curl_infotype type,
- char *data, size_t size);
+ char *data, size_t size, char *host);
#endif
diff --git a/Source/CTest/Curl/setup.h b/Source/CTest/Curl/setup.h
index e10206e..fff6974 100644
--- a/Source/CTest/Curl/setup.h
+++ b/Source/CTest/Curl/setup.h
@@ -1,18 +1,18 @@
#ifndef __SETUP_H
#define __SETUP_H
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -23,9 +23,6 @@
* $Id$
***************************************************************************/
-/* MN 06/07/02 */
-/* #define HTTP_ONLY
-*/
#ifdef HTTP_ONLY
#define CURL_DISABLE_FTP
#define CURL_DISABLE_LDAP
@@ -35,35 +32,64 @@
#define CURL_DISABLE_GOPHER
#endif
-#if !defined(WIN32) && (defined(__WIN32__) || defined(_WIN32))
+#if !defined(WIN32) && defined(__WIN32__)
/* This should be a good Borland fix. Alexander J. Oss told us! */
#define WIN32
#endif
#ifdef HAVE_CONFIG_H
-
-#ifdef VMS
-#include "config-vms.h"
-#else
#include "config.h" /* the configure script results */
-#endif
-
#else
#ifdef WIN32
/* hand-modified win32 config.h! */
#include "config-win32.h"
#endif
+#endif
+
#ifdef macintosh
/* hand-modified MacOS config.h! */
#include "config-mac.h"
#endif
+#ifdef AMIGA
+/* hand-modified AmigaOS config.h! */
+#include "amigaos.h"
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
#endif
-#ifndef __cplusplus /* (rabe) */
+#if !defined(__cplusplus) && !defined(__BEOS__)
typedef unsigned char bool;
#define typedef_bool
-#endif /* (rabe) */
+#endif
+
+#ifdef HAVE_LONGLONG
+#define LONG_LONG long long
+#define ENABLE_64BIT
+#else
+#ifdef _MSC_VER
+#define LONG_LONG __int64
+#define ENABLE_64BIT
+#endif
+#endif /* HAVE_LONGLONG */
+
+#ifndef SIZEOF_CURL_OFF_T
+/* If we don't know the size here, we assume a conservative size: 4. When
+ building libcurl, the actual size of this variable should be define in the
+ config*.h file. */
+#define SIZEOF_CURL_OFF_T 4
+#endif
+
+/* We set up our internal prefered (CURL_)FORMAT_OFF_T here */
+#if SIZEOF_CURL_OFF_T > 4
+#define FORMAT_OFF_T "lld"
+#else
+#define FORMAT_OFF_T "ld"
+#endif
#ifdef NEED_REENTRANT
/* Solaris machines needs _REENTRANT set for a few function prototypes and
@@ -72,14 +98,14 @@ typedef unsigned char bool;
#define _REENTRANT
#endif
-
#include <stdio.h>
-#ifndef OS
-#ifdef WIN32
-#define OS "win32"
-#else
-#define OS "unknown"
+#ifdef HAVE_ASSERT_H
+#include <assert.h>
#endif
+#include <errno.h>
+
+#ifdef __TANDEM /* for nsr-tandem-nsk systems */
+#include <floss.h>
#endif
#if defined(HAVE_X509_H) && defined(HAVE_SSL_H) && defined(HAVE_RSA_H) && \
@@ -100,18 +126,26 @@ defined(HAVE_LIBSSL) && defined(HAVE_LIBCRYPTO)
#endif
#ifndef STDC_HEADERS /* no standard C headers! */
-#ifdef VMS
-#include "../include/curl/stdcheaders.h"
-#else
#include <curl/stdcheaders.h>
#endif
+#if defined(CURLDEBUG) && defined(HAVE_ASSERT_H)
+#define curlassert(x) assert(x)
#else
-#ifdef _AIX
-#include <curl/stdcheaders.h>
+/* does nothing without CURLDEBUG defined */
+#define curlassert(x)
#endif
+
+#ifdef MSG_NOSIGNAL
+/* If we have the MSG_NOSIGNAL define, we make sure to use that in the forth
+ argument to send() and recv() */
+#define SEND_4TH_ARG MSG_NOSIGNAL
+#define HAVE_MSG_NOSIGNAL 1 /* we have MSG_NOSIGNAL */
+#else
+#define SEND_4TH_ARG 0
#endif
+
/* Below we define four functions. They should
1. close a socket
2. read from a socket
@@ -122,71 +156,139 @@ defined(HAVE_LIBSSL) && defined(HAVE_LIBCRYPTO)
*/
#ifdef WIN32
-/* Disable unnecessary warnings on Visual Studio */
-#ifdef _MSC_VER
-#pragma warning ( disable : 4127 )
-#pragma warning ( disable : 4514 )
-#pragma warning ( disable : 4706 )
-#pragma warning ( disable : 4131 ) /* Old style declaration */
-#pragma warning ( disable : 4055 ) /* Cast void*(*)() to void* */
-#pragma warning ( disable : 4311 ) /* Allow cast from void* to long/int */
-#pragma warning ( disable : 4312 ) /* Allow cast from long to char* */
-struct _RPC_ASYNC_STATE;
-#endif
-/* Disable unnecessary warnings on Borland */
-#ifdef __BORLANDC__
-#pragma warn -8004
+
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN /* Prevent including <winsock*.h> in <windows.h> */
+#endif
+
+#if (defined(ENABLE_IPV6) || defined(CURLDEBUG)) && defined(_MSC_VER) && \
+ (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0500)
+/*
+ * Needed to pull in the real getaddrinfo() and not the inline version
+ * in <wspiAPI.H> which doesn't support IPv6 (IPv4 only). <wspiAPI.H> is
+ * included from <ws2tcpip.h> for <= 0x0500 SDKs.
+ */
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x0501
+#endif
+
+#include <winsock2.h> /* required by telnet.c */
+
+#if defined(ENABLE_IPV6) || defined(USE_SSLEAY)
+#include <ws2tcpip.h>
#endif
+
#if !defined(__GNUC__) || defined(__MINGW32__)
#define sclose(x) closesocket(x)
-#define sread(x,y,z) recv(x,y,z,0)
-#define swrite(x,y,z) (size_t)send(x,y,z,0)
+#define sread(x,y,z) recv(x,y,z, SEND_4TH_ARG)
+#define swrite(x,y,z) (size_t)send(x,y,z, SEND_4TH_ARG)
#undef HAVE_ALARM
#else
/* gcc-for-win is still good :) */
#define sclose(x) close(x)
-#define sread(x,y,z) recv(x,y,z,0)
-#define swrite(x,y,z) send(x,y,z,0)
+#define sread(x,y,z) recv(x,y,z, SEND_4TH_ARG)
+#define swrite(x,y,z) send(x,y,z, SEND_4TH_ARG)
#define HAVE_ALARM
#endif
-#define PATH_CHAR ";"
#define DIR_CHAR "\\"
#define DOT_CHAR "_"
#else
+
+#ifdef DJGPP
+#define sclose(x) close_s(x)
+#define sread(x,y,z) read_s(x,y,z)
+#define swrite(x,y,z) write_s(x,y,z)
+#define select(n,r,w,x,t) select_s(n,r,w,x,t)
+#define ioctl(x,y,z) ioctlsocket(x,y,(char *)(z))
+#define IOCTL_3_ARGS
+#include <tcp.h>
+#ifdef word
+#undef word
+#endif
+
+#else
+
+#ifdef __BEOS__
+#define sclose(x) closesocket(x)
+#define sread(x,y,z) (ssize_t)recv(x,y,z, SEND_4TH_ARG)
+#define swrite(x,y,z) (ssize_t)send(x,y,z, SEND_4TH_ARG)
+#else
#define sclose(x) close(x)
-#define sread(x,y,z) recv(x,y,z,0)
-#define swrite(x,y,z) send(x,y,z,0)
+#define sread(x,y,z) recv(x,y,z, SEND_4TH_ARG)
+#define swrite(x,y,z) send(x,y,z, SEND_4TH_ARG)
+#endif
+
#define HAVE_ALARM
-#define PATH_CHAR ":"
+#endif
+
+#ifdef _AMIGASF
+#undef HAVE_ALARM
+#undef sclose
+#define sclose(x) CloseSocket(x)
+#endif
+
#define DIR_CHAR "/"
#define DOT_CHAR "."
-#ifdef HAVE_STRCASECMP
-/* this is for "-ansi -Wall -pedantic" to stop complaining! */
-extern int (strcasecmp)(const char *s1, const char *s2);
-extern int (strncasecmp)(const char *s1, const char *s2, size_t n);
+#ifdef DJGPP
+#undef DOT_CHAR
+#define DOT_CHAR "_"
+#endif
+
#ifndef fileno /* sunos 4 have this as a macro! */
int fileno( FILE *stream);
#endif
+
#endif
+/* now typedef our socket type */
+#ifdef WIN32
+typedef SOCKET curl_socket_t;
+#define CURL_SOCKET_BAD INVALID_SOCKET
+#else
+typedef int curl_socket_t;
+#define CURL_SOCKET_BAD -1
#endif
-/*
- * Curl_addrinfo MUST be used for name resolving information.
- * Information regarding a single IP witin a Curl_addrinfo MUST be stored in
- * a Curl_ipconnect struct.
- */
+#if defined(ENABLE_IPV6) && defined(USE_ARES)
+#error "ares does not yet support IPv6. Disable IPv6 or ares and rebuild"
+#endif
+
+#if defined(WIN32) && !defined(__CYGWIN__) && !defined(USE_ARES) && \
+ !defined(__LCC__) /* lcc-win32 doesn't have _beginthreadex() */
#ifdef ENABLE_IPV6
-typedef struct addrinfo Curl_addrinfo;
-typedef struct addrinfo Curl_ipconnect;
+#define USE_THREADING_GETADDRINFO
+#else
+#define USE_THREADING_GETHOSTBYNAME /* Cygwin uses alarm() function */
+#endif
+#endif
+
+#ifdef mpeix
+#define IOCTL_3_ARGS
+#endif
+
+#ifndef ECONNRESET
+#ifdef WSAECONNRESET
+#define ECONNRESET WSAECONNRESET
#else
-typedef struct hostent Curl_addrinfo;
-typedef struct in_addr Curl_ipconnect;
+/* This will effectively prevent the code from working in this particular
+ aspect, but it still compile fine! */
+#define ECONNRESET 10000
+#endif
#endif
+#ifdef NETWARE
+#undef HAVE_ALARM
+#endif
+
+#ifdef HAVE_LIBIDN
+/* This could benefit from additional checks that some of the used/important
+ header files are present as well before we define the USE_* define. */
+#define USE_LIBIDN
+#define LIBIDN_REQUIRED_VERSION "0.4.1"
+#endif
#endif /* __CONFIG_H */
diff --git a/Source/CTest/Curl/share.c b/Source/CTest/Curl/share.c
new file mode 100644
index 0000000..5c01845
--- /dev/null
+++ b/Source/CTest/Curl/share.c
@@ -0,0 +1,219 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <curl/curl.h>
+#include "urldata.h"
+#include "share.h"
+#include "memory.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+CURLSH *
+curl_share_init(void)
+{
+ struct Curl_share *share =
+ (struct Curl_share *)malloc(sizeof(struct Curl_share));
+ if (share) {
+ memset (share, 0, sizeof(struct Curl_share));
+ share->specifier |= (1<<CURL_LOCK_DATA_SHARE);
+ }
+
+ return share;
+}
+
+CURLSHcode
+curl_share_setopt(CURLSH *sh, CURLSHoption option, ...)
+{
+ struct Curl_share *share = (struct Curl_share *)sh;
+ va_list param;
+ int type;
+ curl_lock_function lockfunc;
+ curl_unlock_function unlockfunc;
+ void *ptr;
+
+ if (share->dirty)
+ /* don't allow setting options while one or more handles are already
+ using this share */
+ return CURLSHE_IN_USE;
+
+ va_start(param, option);
+
+ switch(option) {
+ case CURLSHOPT_SHARE:
+ /* this is a type this share will share */
+ type = va_arg(param, int);
+ share->specifier |= (1<<type);
+ switch( type ) {
+ case CURL_LOCK_DATA_DNS:
+ if (!share->hostcache) {
+ share->hostcache = Curl_mk_dnscache();
+ if(!share->hostcache)
+ return CURLSHE_NOMEM;
+ }
+ break;
+
+#ifndef CURL_DISABLE_HTTP
+ case CURL_LOCK_DATA_COOKIE:
+ if (!share->cookies) {
+ share->cookies = Curl_cookie_init(NULL, NULL, NULL, TRUE );
+ if(!share->cookies)
+ return CURLSHE_NOMEM;
+ }
+ break;
+#endif /* CURL_DISABLE_HTTP */
+
+ case CURL_LOCK_DATA_SSL_SESSION: /* not supported (yet) */
+ case CURL_LOCK_DATA_CONNECT: /* not supported (yet) */
+
+ default:
+ return CURLSHE_BAD_OPTION;
+ }
+ break;
+
+ case CURLSHOPT_UNSHARE:
+ /* this is a type this share will no longer share */
+ type = va_arg(param, int);
+ share->specifier &= ~(1<<type);
+ switch( type )
+ {
+ case CURL_LOCK_DATA_DNS:
+ if (share->hostcache) {
+ Curl_hash_destroy(share->hostcache);
+ share->hostcache = NULL;
+ }
+ break;
+
+#ifndef CURL_DISABLE_HTTP
+ case CURL_LOCK_DATA_COOKIE:
+ if (share->cookies) {
+ Curl_cookie_cleanup(share->cookies);
+ share->cookies = NULL;
+ }
+ break;
+#endif /* CURL_DISABLE_HTTP */
+
+ case CURL_LOCK_DATA_SSL_SESSION:
+ break;
+
+ case CURL_LOCK_DATA_CONNECT:
+ break;
+
+ default:
+ return CURLSHE_BAD_OPTION;
+ }
+ break;
+
+ case CURLSHOPT_LOCKFUNC:
+ lockfunc = va_arg(param, curl_lock_function);
+ share->lockfunc = lockfunc;
+ break;
+
+ case CURLSHOPT_UNLOCKFUNC:
+ unlockfunc = va_arg(param, curl_unlock_function);
+ share->unlockfunc = unlockfunc;
+ break;
+
+ case CURLSHOPT_USERDATA:
+ ptr = va_arg(param, void *);
+ share->clientdata = ptr;
+ break;
+
+ default:
+ return CURLSHE_BAD_OPTION;
+ }
+
+ return CURLSHE_OK;
+}
+
+CURLSHcode
+curl_share_cleanup(CURLSH *sh)
+{
+ struct Curl_share *share = (struct Curl_share *)sh;
+
+ if (share == NULL)
+ return CURLSHE_INVALID;
+
+ if(share->lockfunc)
+ share->lockfunc(NULL, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE,
+ share->clientdata);
+
+ if (share->dirty) {
+ if(share->unlockfunc)
+ share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata);
+ return CURLSHE_IN_USE;
+ }
+
+ if(share->hostcache)
+ Curl_hash_destroy(share->hostcache);
+
+#ifndef CURL_DISABLE_HTTP
+ if(share->cookies)
+ Curl_cookie_cleanup(share->cookies);
+#endif /* CURL_DISABLE_HTTP */
+
+ if(share->unlockfunc)
+ share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata);
+ free(share);
+
+ return CURLSHE_OK;
+}
+
+
+CURLSHcode
+Curl_share_lock(struct SessionHandle *data, curl_lock_data type,
+ curl_lock_access accesstype)
+{
+ struct Curl_share *share = data->share;
+
+ if (share == NULL)
+ return CURLSHE_INVALID;
+
+ if(share->specifier & (1<<type)) {
+ if(share->lockfunc) /* only call this if set! */
+ share->lockfunc(data, type, accesstype, share->clientdata);
+ }
+ /* else if we don't share this, pretend successful lock */
+
+ return CURLSHE_OK;
+}
+
+CURLSHcode
+Curl_share_unlock(struct SessionHandle *data, curl_lock_data type)
+{
+ struct Curl_share *share = data->share;
+
+ if (share == NULL)
+ return CURLSHE_INVALID;
+
+ if(share->specifier & (1<<type)) {
+ if(share->unlockfunc) /* only call this if set! */
+ share->unlockfunc (data, type, share->clientdata);
+ }
+
+ return CURLSHE_OK;
+}
diff --git a/Source/CTest/Curl/share.h b/Source/CTest/Curl/share.h
index fdd6ec5..5c85c80 100644
--- a/Source/CTest/Curl/share.h
+++ b/Source/CTest/Curl/share.h
@@ -8,7 +8,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -26,27 +26,30 @@
#include "setup.h"
#include <curl/curl.h>
+#include "cookie.h"
/* this struct is libcurl-private, don't export details */
struct Curl_share {
unsigned int specifier;
- unsigned int locked;
- unsigned int dirty;
+ volatile unsigned int dirty;
curl_lock_function lockfunc;
curl_unlock_function unlockfunc;
void *clientdata;
+
+ curl_hash *hostcache;
+ struct CookieInfo *cookies;
};
-CURLSHcode Curl_share_aquire_lock (struct SessionHandle *, curl_lock_data);
-CURLSHcode Curl_share_release_lock (struct SessionHandle *, curl_lock_data);
+CURLSHcode Curl_share_lock (
+ struct SessionHandle *,
+ curl_lock_data,
+ curl_lock_access
+ );
-#endif /* __CURL_SHARE_H */
+CURLSHcode Curl_share_unlock (
+ struct SessionHandle *,
+ curl_lock_data
+ );
-/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
- */
+#endif /* __CURL_SHARE_H */
diff --git a/Source/CTest/Curl/speedcheck.c b/Source/CTest/Curl/speedcheck.c
index 5b4d018..33a8e5d 100644
--- a/Source/CTest/Curl/speedcheck.c
+++ b/Source/CTest/Curl/speedcheck.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -25,9 +25,6 @@
#include <stdio.h>
#include <string.h>
-#if defined(__MINGW32__)
-#include <winsock.h>
-#endif
#include <curl/curl.h>
#include "urldata.h"
@@ -68,11 +65,3 @@ CURLcode Curl_speedcheck(struct SessionHandle *data,
}
return CURLE_OK;
}
-
-/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
- */
diff --git a/Source/CTest/Curl/speedcheck.h b/Source/CTest/Curl/speedcheck.h
index e5397d2..62475f6 100644
--- a/Source/CTest/Curl/speedcheck.h
+++ b/Source/CTest/Curl/speedcheck.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
diff --git a/Source/CTest/Curl/ssluse.c b/Source/CTest/Curl/ssluse.c
index 5049746..d5aaee5 100644
--- a/Source/CTest/Curl/ssluse.c
+++ b/Source/CTest/Curl/ssluse.c
@@ -1,16 +1,16 @@
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -30,17 +30,37 @@
#include <string.h>
#include <stdlib.h>
+#include <ctype.h>
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
#include "urldata.h"
#include "sendf.h"
#include "formdata.h" /* for the boundary function */
+#include "url.h" /* for the ssl config check function */
+#include "inet_pton.h"
+#include "ssluse.h"
+#include "connect.h" /* Curl_ourerrno() proto */
+#include "strequal.h"
+
+#define _MPRINTF_REPLACE /* use the internal *printf() functions */
+#include <curl/mprintf.h>
#ifdef USE_SSLEAY
#include <openssl/rand.h>
+#include <openssl/x509v3.h>
+
+#include "memory.h"
/* The last #include file should be: */
-#ifdef MALLOCDEBUG
#include "memdebug.h"
+
+#ifndef min
+#define min(a, b) ((a) < (b) ? (a) : (b))
#endif
#if OPENSSL_VERSION_NUMBER >= 0x0090581fL
@@ -63,6 +83,10 @@
#undef HAVE_ENGINE_LOAD_FOUR_ARGS
#endif
+#if OPENSSL_VERSION_NUMBER >= 0x00906001L
+#define HAVE_ERR_ERROR_STRING_N 1
+#endif
+
#ifndef HAVE_USERDATA_IN_PWD_CALLBACK
static char global_passwd[64];
@@ -82,28 +106,33 @@ static int passwd_callback(char *buf, int num, int verify
else {
if(num > (int)strlen((char *)global_passwd)) {
strcpy(buf, global_passwd);
- return strlen(buf);
+ return (int)strlen(buf);
}
- }
+ }
return 0;
}
-static
-bool seed_enough(int nread)
-{
-#ifdef HAVE_RAND_STATUS
- nread = 0; /* to prevent compiler warnings */
+/*
+ * rand_enough() is a function that returns TRUE if we have seeded the random
+ * engine properly. We use some preprocessor magic to provide a seed_enough()
+ * macro to use, just to prevent a compiler warning on this function if we
+ * pass in an argument that is never used.
+ */
- /* only available in OpenSSL 0.9.5a and later */
- if(RAND_status())
- return TRUE;
+#ifdef HAVE_RAND_STATUS
+#define seed_enough(x) rand_enough()
+static bool rand_enough(void)
+{
+ return RAND_status()?TRUE:FALSE;
+}
#else
- if(nread > 500)
- /* this is a very silly decision to make */
- return TRUE;
-#endif
- return FALSE; /* not enough */
+#define seed_enough(x) rand_enough(x)
+static bool rand_enough(int nread)
+{
+ /* this is a very silly decision to make */
+ return (nread > 500)?TRUE:FALSE;
}
+#endif
static
int random_the_seed(struct SessionHandle *data)
@@ -141,7 +170,8 @@ int random_the_seed(struct SessionHandle *data)
{
/* If there's an option and a define, the option overrides the
define */
- int ret = RAND_egd(data->set.ssl.egdsocket?data->set.ssl.egdsocket:EGD_SOCKET);
+ int ret = RAND_egd(data->set.ssl.egdsocket?
+ data->set.ssl.egdsocket:EGD_SOCKET);
if(-1 != ret) {
nread += ret;
if(seed_enough(nread))
@@ -159,21 +189,31 @@ int random_the_seed(struct SessionHandle *data)
#else
{
int len;
- char *area = Curl_FormBoundary();
- if(!area)
- return 3; /* out of memory */
-
- len = strlen(area);
- RAND_seed(area, len);
+ char *area;
+
+ /* Changed call to RAND_seed to use the underlying RAND_add implementation
+ * directly. Do this in a loop, with the amount of additional entropy
+ * being dependent upon the algorithm used by Curl_FormBoundary(): N bytes
+ * of a 7-bit ascii set. -- Richard Gorton, March 11 2003.
+ */
+
+ do {
+ area = Curl_FormBoundary();
+ if(!area)
+ return 3; /* out of memory */
+
+ len = (int)strlen(area);
+ RAND_add(area, len, (len >> 1));
- free(area); /* now remove the random junk */
+ free(area); /* now remove the random junk */
+ } while (!RAND_status());
}
#endif
/* generates a default path for the random seed file */
buf[0]=0; /* blank it first */
RAND_file_name(buf, BUFSIZE);
- if ( buf[0] ) {
+ if(buf[0]) {
/* we got a file name to try */
nread += RAND_load_file(buf, 16384);
if(seed_enough(nread))
@@ -189,19 +229,20 @@ int random_the_seed(struct SessionHandle *data)
#endif
static int do_file_type(const char *type)
{
- if (!type || !type[0])
+ if(!type || !type[0])
return SSL_FILETYPE_PEM;
- if (curl_strequal(type, "PEM"))
+ if(curl_strequal(type, "PEM"))
return SSL_FILETYPE_PEM;
- if (curl_strequal(type, "DER"))
+ if(curl_strequal(type, "DER"))
return SSL_FILETYPE_ASN1;
- if (curl_strequal(type, "ENG"))
+ if(curl_strequal(type, "ENG"))
return SSL_FILETYPE_ENGINE;
return -1;
}
static
int cert_stuff(struct connectdata *conn,
+ SSL_CTX* ctx,
char *cert_file,
const char *cert_type,
char *key_file,
@@ -210,7 +251,7 @@ int cert_stuff(struct connectdata *conn,
struct SessionHandle *data = conn->data;
int file_type;
- if (cert_file != NULL) {
+ if(cert_file != NULL) {
SSL *ssl;
X509 *x509;
@@ -220,16 +261,18 @@ int cert_stuff(struct connectdata *conn,
* If password has been given, we store that in the global
* area (*shudder*) for a while:
*/
- strcpy(global_passwd, data->set.key_passwd);
+ size_t len = strlen(data->set.key_passwd);
+ if(len < sizeof(global_passwd))
+ memcpy(global_passwd, data->set.key_passwd, len+1);
#else
/*
* We set the password in the callback userdata
*/
- SSL_CTX_set_default_passwd_cb_userdata(conn->ssl.ctx,
+ SSL_CTX_set_default_passwd_cb_userdata(ctx,
data->set.key_passwd);
#endif
/* Set passwd callback: */
- SSL_CTX_set_default_passwd_cb(conn->ssl.ctx, passwd_callback);
+ SSL_CTX_set_default_passwd_cb(ctx, passwd_callback);
}
file_type = do_file_type(cert_type);
@@ -237,8 +280,8 @@ int cert_stuff(struct connectdata *conn,
switch(file_type) {
case SSL_FILETYPE_PEM:
/* SSL_CTX_use_certificate_chain_file() only works on PEM files */
- if (SSL_CTX_use_certificate_chain_file(conn->ssl.ctx,
- cert_file) != 1) {
+ if(SSL_CTX_use_certificate_chain_file(ctx,
+ cert_file) != 1) {
failf(data, "unable to set certificate file (wrong password?)");
return 0;
}
@@ -248,9 +291,9 @@ int cert_stuff(struct connectdata *conn,
/* SSL_CTX_use_certificate_file() works with either PEM or ASN1, but
we use the case above for PEM so this can only be performed with
ASN1 files. */
- if (SSL_CTX_use_certificate_file(conn->ssl.ctx,
- cert_file,
- file_type) != 1) {
+ if(SSL_CTX_use_certificate_file(ctx,
+ cert_file,
+ file_type) != 1) {
failf(data, "unable to set certificate file (wrong password?)");
return 0;
}
@@ -268,13 +311,11 @@ int cert_stuff(struct connectdata *conn,
switch(file_type) {
case SSL_FILETYPE_PEM:
- if (key_file == NULL)
+ if(key_file == NULL)
/* cert & key can only be in PEM case in the same file */
key_file=cert_file;
case SSL_FILETYPE_ASN1:
- if (SSL_CTX_use_PrivateKey_file(conn->ssl.ctx,
- key_file,
- file_type) != 1) {
+ if(SSL_CTX_use_PrivateKey_file(ctx, key_file, file_type) != 1) {
failf(data, "unable to set private key file: '%s' type %s\n",
key_file, key_type?key_type:"PEM");
return 0;
@@ -284,24 +325,26 @@ int cert_stuff(struct connectdata *conn,
#ifdef HAVE_OPENSSL_ENGINE_H
{ /* XXXX still needs some work */
EVP_PKEY *priv_key = NULL;
- if (conn && conn->data && conn->data->engine) {
+ if(conn && conn->data && conn->data->engine) {
#ifdef HAVE_ENGINE_LOAD_FOUR_ARGS
UI_METHOD *ui_method = UI_OpenSSL();
#endif
- if (!key_file || !key_file[0]) {
+ if(!key_file || !key_file[0]) {
failf(data, "no key set to load from crypto engine\n");
return 0;
}
- priv_key = ENGINE_load_private_key(conn->data->engine,key_file,
+ /* the typecast below was added to please mingw32 */
+ priv_key = (EVP_PKEY *)
+ ENGINE_load_private_key(conn->data->engine,key_file,
#ifdef HAVE_ENGINE_LOAD_FOUR_ARGS
- ui_method,
+ ui_method,
#endif
- data->set.key_passwd);
- if (!priv_key) {
+ data->set.key_passwd);
+ if(!priv_key) {
failf(data, "failed to load private key from crypto engine\n");
return 0;
}
- if (SSL_CTX_use_PrivateKey(conn->ssl.ctx, priv_key) != 1) {
+ if(SSL_CTX_use_PrivateKey(ctx, priv_key) != 1) {
failf(data, "unable to set private key\n");
EVP_PKEY_free(priv_key);
return 0;
@@ -313,22 +356,22 @@ int cert_stuff(struct connectdata *conn,
return 0;
}
}
+ break;
#else
failf(data, "file type ENG for private key not supported\n");
return 0;
#endif
- break;
default:
failf(data, "not supported file type for private key\n");
return 0;
}
- ssl=SSL_new(conn->ssl.ctx);
+ ssl=SSL_new(ctx);
x509=SSL_get_certificate(ssl);
/* This version was provided by Evan Jordan and is supposed to not
leak memory as the previous version: */
- if (x509 != NULL) {
+ if(x509 != NULL) {
EVP_PKEY *pktmp = X509_get_pubkey(x509);
EVP_PKEY_copy_parameters(pktmp,SSL_get_privatekey(ssl));
EVP_PKEY_free(pktmp);
@@ -338,15 +381,15 @@ int cert_stuff(struct connectdata *conn,
/* If we are using DSA, we can copy the parameters from
* the private key */
-
-
+
+
/* Now we know that a key and cert have been set against
* the SSL context */
- if (!SSL_CTX_check_private_key(conn->ssl.ctx)) {
+ if(!SSL_CTX_check_private_key(ctx)) {
failf(data, "Private key does not match the certificate public key");
return(0);
}
-#ifndef HAVE_USERDATA_IN_PWD_CALLBACK
+#ifndef HAVE_USERDATA_IN_PWD_CALLBACK
/* erase it now */
memset(global_passwd, 0, sizeof(global_passwd));
#endif
@@ -361,21 +404,17 @@ int cert_verify_callback(int ok, X509_STORE_CTX *ctx)
char buf[256];
err_cert=X509_STORE_CTX_get_current_cert(ctx);
- X509_NAME_oneline(X509_get_subject_name(err_cert),buf,256);
-
+ X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
return ok;
}
-#endif
-
-#ifdef USE_SSLEAY
/* "global" init done? */
static int init_ssl=0;
/* we have the "SSL is seeded" boolean global for the application to
prevent multiple time-consuming seedings in vain */
static bool ssl_seeded = FALSE;
-#endif
+#endif /* USE_SSLEAY */
/* Global init */
void Curl_SSL_init(void)
@@ -410,7 +449,7 @@ void Curl_SSL_cleanup(void)
/* Free the SSL error strings */
ERR_free_strings();
-
+
/* EVP_cleanup() removes all ciphers and digests from the
table. */
EVP_cleanup();
@@ -419,6 +458,12 @@ void Curl_SSL_cleanup(void)
ENGINE_cleanup();
#endif
+#ifdef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA
+ /* this function was not present in 0.9.6b, but was added sometimes
+ later */
+ CRYPTO_cleanup_all_ex_data();
+#endif
+
init_ssl=0; /* not inited any more */
}
#else
@@ -426,6 +471,13 @@ void Curl_SSL_cleanup(void)
#endif
}
+#ifndef USE_SSLEAY
+void Curl_SSL_Close(struct connectdata *conn)
+{
+ (void)conn;
+}
+#endif
+
#ifdef USE_SSLEAY
/*
@@ -433,7 +485,8 @@ void Curl_SSL_cleanup(void)
*/
void Curl_SSL_Close(struct connectdata *conn)
{
- if (conn->ssl.use) {
+ if(conn->ssl[FIRSTSOCKET].use) {
+ int i;
/*
ERR_remove_state() frees the error queue associated with
thread pid. If pid == 0, the current thread will have its
@@ -445,18 +498,22 @@ void Curl_SSL_Close(struct connectdata *conn)
*/
ERR_remove_state(0);
- if(conn->ssl.handle) {
- (void)SSL_shutdown(conn->ssl.handle);
- SSL_set_connect_state(conn->ssl.handle);
+ for(i=0; i<2; i++) {
+ struct ssl_connect_data *connssl = &conn->ssl[i];
- SSL_free (conn->ssl.handle);
- conn->ssl.handle = NULL;
- }
- if(conn->ssl.ctx) {
- SSL_CTX_free (conn->ssl.ctx);
- conn->ssl.ctx = NULL;
+ if(connssl->handle) {
+ (void)SSL_shutdown(connssl->handle);
+ SSL_set_connect_state(connssl->handle);
+
+ SSL_free (connssl->handle);
+ connssl->handle = NULL;
+ }
+ if(connssl->ctx) {
+ SSL_CTX_free (connssl->ctx);
+ connssl->ctx = NULL;
+ }
+ connssl->use = FALSE; /* get back to ordinary socket usage */
}
- conn->ssl.use = FALSE; /* get back to ordinary socket usage */
}
}
@@ -504,8 +561,9 @@ static int Get_SSL_Session(struct connectdata *conn,
if(!check->sessionid)
/* not session ID means blank entry */
continue;
- if(strequal(conn->name, check->name) &&
- (conn->remote_port == check->remote_port) ) {
+ if(curl_strequal(conn->host.name, check->name) &&
+ (conn->remote_port == check->remote_port) &&
+ Curl_ssl_config_matches(&conn->ssl_config, &check->ssl_config)) {
/* yes, we have a session ID! */
data->state.sessionage++; /* increase general age */
check->age = data->state.sessionage; /* set this as used in this age */
@@ -529,7 +587,10 @@ static int Kill_Single_Session(struct curl_ssl_session *session)
SSL_SESSION_free(session->sessionid);
session->sessionid=NULL;
session->age = 0; /* fresh */
- free(session->name);
+
+ Curl_free_ssl_config(&session->ssl_config);
+
+ Curl_safefree(session->name);
session->name = NULL; /* no name */
return 0; /* ok */
@@ -546,16 +607,16 @@ int Curl_SSL_Close_All(struct SessionHandle *data)
{
int i;
- if(data->state.session) {
+ if(data->state.session) {
for(i=0; i< data->set.ssl.numsessions; i++)
/* the single-killer function handles empty table slots */
Kill_Single_Session(&data->state.session[i]);
-
+
/* free the cache data */
free(data->state.session);
}
#ifdef HAVE_OPENSSL_ENGINE_H
- if (data->engine)
+ if(data->engine)
{
ENGINE_free(data->engine);
data->engine = NULL;
@@ -567,33 +628,39 @@ int Curl_SSL_Close_All(struct SessionHandle *data)
/*
* Extract the session id and store it in the session cache.
*/
-static int Store_SSL_Session(struct connectdata *conn)
+static int Store_SSL_Session(struct connectdata *conn,
+ struct ssl_connect_data *ssl)
{
SSL_SESSION *ssl_sessionid;
int i;
struct SessionHandle *data=conn->data; /* the mother of all structs */
struct curl_ssl_session *store = &data->state.session[0];
- int oldest_age=data->state.session[0].age; /* zero if unused */
+ long oldest_age=data->state.session[0].age; /* zero if unused */
+ char *clone_host;
+
+ clone_host = strdup(conn->host.name);
+ if(!clone_host)
+ return -1; /* bail out */
/* ask OpenSSL, say please */
#ifdef HAVE_SSL_GET1_SESSION
- ssl_sessionid = SSL_get1_session(conn->ssl.handle);
+ ssl_sessionid = SSL_get1_session(ssl->handle);
/* SSL_get1_session() will increment the reference
count and the session will stay in memory until explicitly freed with
- SSL_SESSION_free(3), regardless of its state.
+ SSL_SESSION_free(3), regardless of its state.
This function was introduced in openssl 0.9.5a. */
#else
- ssl_sessionid = SSL_get_session(conn->ssl.handle);
+ ssl_sessionid = SSL_get_session(ssl->handle);
/* if SSL_get1_session() is unavailable, use SSL_get_session().
This is an inferior option because the session can be flushed
at any time by openssl. It is included only so curl compiles
under versions of openssl < 0.9.5a.
-
+
WARNING: How curl behaves if it's session is flushed is
- untested.
+ untested.
*/
#endif
@@ -613,13 +680,15 @@ static int Store_SSL_Session(struct connectdata *conn)
Kill_Single_Session(store);
else
store = &data->state.session[i]; /* use this slot */
-
+
/* now init the session struct wisely */
store->sessionid = ssl_sessionid;
- store->age = data->state.sessionage; /* set current age */
- store->name = strdup(conn->name); /* clone host name */
+ store->age = data->state.sessionage; /* set current age */
+ store->name = clone_host; /* clone host name */
store->remote_port = conn->remote_port; /* port number */
+ Curl_clone_ssl_config(&conn->ssl_config, &store->ssl_config);
+
return 0;
}
@@ -639,30 +708,30 @@ static int Curl_ASN1_UTCTIME_output(struct connectdata *conn,
i=tm->length;
asn1_string=(char *)tm->data;
- if (i < 10)
+ if(i < 10)
return 1;
- if (asn1_string[i-1] == 'Z')
+ if(asn1_string[i-1] == 'Z')
gmt=TRUE;
for (i=0; i<10; i++)
- if ((asn1_string[i] > '9') || (asn1_string[i] < '0'))
+ if((asn1_string[i] > '9') || (asn1_string[i] < '0'))
return 2;
year= (asn1_string[0]-'0')*10+(asn1_string[1]-'0');
- if (year < 50)
+ if(year < 50)
year+=100;
month= (asn1_string[2]-'0')*10+(asn1_string[3]-'0');
- if ((month > 12) || (month < 1))
+ if((month > 12) || (month < 1))
return 3;
day= (asn1_string[4]-'0')*10+(asn1_string[5]-'0');
hour= (asn1_string[6]-'0')*10+(asn1_string[7]-'0');
minute= (asn1_string[8]-'0')*10+(asn1_string[9]-'0');
- if ( (asn1_string[10] >= '0') && (asn1_string[10] <= '9') &&
- (asn1_string[11] >= '0') && (asn1_string[11] <= '9'))
+ if((asn1_string[10] >= '0') && (asn1_string[10] <= '9') &&
+ (asn1_string[11] >= '0') && (asn1_string[11] <= '9'))
second= (asn1_string[10]-'0')*10+(asn1_string[11]-'0');
-
+
infof(data,
"%s%04d-%02d-%02d %02d:%02d:%02d %s\n",
prefix, year+1900, month, day, hour, minute, second, (gmt?"GMT":""));
@@ -670,64 +739,374 @@ static int Curl_ASN1_UTCTIME_output(struct connectdata *conn,
return 0;
}
-#endif
+#endif
/* ====================================================== */
#ifdef USE_SSLEAY
+
+/*
+ * Match a hostname against a wildcard pattern.
+ * E.g.
+ * "foo.host.com" matches "*.host.com".
+ *
+ * We are a bit more liberal than RFC2818 describes in that we
+ * accept multiple "*" in pattern (similar to what some other browsers do).
+ * E.g.
+ * "abc.def.domain.com" should strickly not match "*.domain.com", but we
+ * don't consider "." to be important in CERT checking.
+ */
+#define HOST_NOMATCH 0
+#define HOST_MATCH 1
+
+static int hostmatch(const char *hostname, const char *pattern)
+{
+ while (1) {
+ int c = *pattern++;
+
+ if (c == '\0')
+ return (*hostname ? HOST_NOMATCH : HOST_MATCH);
+
+ if (c == '*') {
+ c = *pattern;
+ if (c == '\0') /* "*\0" matches anything remaining */
+ return HOST_MATCH;
+
+ while (*hostname) {
+ /* The only recursive function in libcurl! */
+ if (hostmatch(hostname++,pattern) == HOST_MATCH)
+ return HOST_MATCH;
+ }
+ return HOST_NOMATCH;
+ }
+
+ if (toupper(c) != toupper(*hostname++))
+ return HOST_NOMATCH;
+ }
+}
+
static int
-cert_hostcheck(const char *certname, const char *hostname)
+cert_hostcheck(const char *match_pattern, const char *hostname)
{
- char *tmp;
- const char *certdomain;
-
- if(!certname ||
- strlen(certname)<3 ||
- !hostname ||
- !strlen(hostname)) /* sanity check */
+ if (!match_pattern || !*match_pattern ||
+ !hostname || !*hostname) /* sanity check */
return 0;
- if(strequal(certname, hostname)) /* trivial case */
+ if(curl_strequal(hostname,match_pattern)) /* trivial case */
return 1;
- certdomain = certname + 1;
-
- if((certname[0] != '*') || (certdomain[0] != '.'))
- return 0; /* not a wildcard certificate, check failed */
-
- if(!strchr(certdomain+1, '.'))
- return 0; /* the certificate must have at least another dot in its name */
-
- /* find 'certdomain' within 'hostname' */
- tmp = strstr(hostname, certdomain);
- if(tmp) {
- /* ok the certname's domain matches the hostname, let's check that it's a
- tail-match */
- if(strequal(tmp, certdomain))
- /* looks like a match. Just check we havent swallowed a '.' */
- return tmp == strchr(hostname, '.');
- else
- return 0;
- }
+ if (hostmatch(hostname,match_pattern) == HOST_MATCH)
+ return 1;
return 0;
}
+
+/* Quote from RFC2818 section 3.1 "Server Identity"
+
+ If a subjectAltName extension of type dNSName is present, that MUST
+ be used as the identity. Otherwise, the (most specific) Common Name
+ field in the Subject field of the certificate MUST be used. Although
+ the use of the Common Name is existing practice, it is deprecated and
+ Certification Authorities are encouraged to use the dNSName instead.
+
+ Matching is performed using the matching rules specified by
+ [RFC2459]. If more than one identity of a given type is present in
+ the certificate (e.g., more than one dNSName name, a match in any one
+ of the set is considered acceptable.) Names may contain the wildcard
+ character * which is considered to match any single domain name
+ component or component fragment. E.g., *.a.com matches foo.a.com but
+ not bar.foo.a.com. f*.com matches foo.com but not bar.com.
+
+ In some cases, the URI is specified as an IP address rather than a
+ hostname. In this case, the iPAddress subjectAltName must be present
+ in the certificate and must exactly match the IP in the URI.
+
+*/
+static CURLcode verifyhost(struct connectdata *conn,
+ X509 *server_cert)
+{
+ bool matched = FALSE; /* no alternative match yet */
+ int target = GEN_DNS; /* target type, GEN_DNS or GEN_IPADD */
+ int addrlen = 0;
+ struct SessionHandle *data = conn->data;
+ STACK_OF(GENERAL_NAME) *altnames;
+#ifdef ENABLE_IPV6
+ struct in6_addr addr;
+#else
+ struct in_addr addr;
+#endif
+
+#ifdef ENABLE_IPV6
+ if(conn->bits.ipv6_ip &&
+ Curl_inet_pton(AF_INET6, conn->host.name, &addr)) {
+ target = GEN_IPADD;
+ addrlen = sizeof(struct in6_addr);
+ }
+ else
+#endif
+ if(Curl_inet_pton(AF_INET, conn->host.name, &addr)) {
+ target = GEN_IPADD;
+ addrlen = sizeof(struct in_addr);
+ }
+
+ /* get a "list" of alternative names */
+ altnames = X509_get_ext_d2i(server_cert, NID_subject_alt_name, NULL, NULL);
+
+ if(altnames) {
+ int numalts;
+ int i;
+
+ /* get amount of alternatives, RFC2459 claims there MUST be at least
+ one, but we don't depend on it... */
+ numalts = sk_GENERAL_NAME_num(altnames);
+
+ /* loop through all alternatives while none has matched */
+ for (i=0; (i<numalts) && !matched; i++) {
+ /* get a handle to alternative name number i */
+ const GENERAL_NAME *check = sk_GENERAL_NAME_value(altnames, i);
+
+ /* only check alternatives of the same type the target is */
+ if(check->type == target) {
+ /* get data and length */
+ const char *altptr = (char *)ASN1_STRING_data(check->d.ia5);
+ int altlen;
+
+ switch(target) {
+ case GEN_DNS: /* name/pattern comparison */
+ /* The OpenSSL man page explicitly says: "In general it cannot be
+ assumed that the data returned by ASN1_STRING_data() is null
+ terminated or does not contain embedded nulls." But also that
+ "The actual format of the data will depend on the actual string
+ type itself: for example for and IA5String the data will be ASCII"
+
+ Gisle researched the OpenSSL sources:
+ "I checked the 0.9.6 and 0.9.8 sources before my patch and
+ it always 0-terminates an IA5String."
+ */
+ if (cert_hostcheck(altptr, conn->host.name))
+ matched = TRUE;
+ break;
+
+ case GEN_IPADD: /* IP address comparison */
+ /* compare alternative IP address if the data chunk is the same size
+ our server IP address is */
+ altlen = ASN1_STRING_length(check->d.ia5);
+ if((altlen == addrlen) && !memcmp(altptr, &addr, altlen))
+ matched = TRUE;
+ break;
+ }
+ }
+ }
+ GENERAL_NAMES_free(altnames);
+ }
+
+ if(matched)
+ /* an alternative name matched the server hostname */
+ infof(data, "\t subjectAltName: %s matched\n", conn->host.dispname);
+ else {
+ /* we have to look to the last occurence of a commonName in the
+ distinguished one to get the most significant one. */
+ int j,i=-1 ;
+
+/* The following is done because of a bug in 0.9.6b */
+
+ unsigned char *nulstr = (unsigned char *)"";
+ unsigned char *peer_CN = nulstr;
+
+ X509_NAME *name = X509_get_subject_name(server_cert) ;
+ if (name)
+ while ((j=X509_NAME_get_index_by_NID(name,NID_commonName,i))>=0)
+ i=j;
+
+ /* we have the name entry and we will now convert this to a string
+ that we can use for comparison. Doing this we support BMPstring,
+ UTF8 etc. */
+
+ if (i>=0) {
+ ASN1_STRING *tmp = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name,i));
+
+ /* In OpenSSL 0.9.7d and earlier, ASN1_STRING_to_UTF8 fails if the input
+ is already UTF-8 encoded. We check for this case and copy the raw
+ string manually to avoid the problem. This code can be made
+ conditional in the future when OpenSSL has been fixed. Work-around
+ brought by Alexis S. L. Carvalho. */
+ if (tmp && ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) {
+ j = ASN1_STRING_length(tmp);
+ if (j >= 0) {
+ peer_CN = OPENSSL_malloc(j+1);
+ if (peer_CN) {
+ memcpy(peer_CN, ASN1_STRING_data(tmp), j);
+ peer_CN[j] = '\0';
+ }
+ }
+ }
+ else /* not a UTF8 name */
+ j = ASN1_STRING_to_UTF8(&peer_CN, tmp);
+ }
+
+ if (peer_CN == nulstr)
+ peer_CN = NULL;
+
+ if (!peer_CN) {
+ if(data->set.ssl.verifyhost > 1) {
+ failf(data,
+ "SSL: unable to obtain common name from peer certificate");
+ return CURLE_SSL_PEER_CERTIFICATE;
+ }
+ else {
+ /* Consider verifyhost == 1 as an "OK" for a missing CN field, but we
+ output a note about the situation */
+ infof(data, "\t common name: WARNING couldn't obtain\n");
+ }
+ }
+ else if(!cert_hostcheck((const char *)peer_CN, conn->host.name)) {
+ if(data->set.ssl.verifyhost > 1) {
+ failf(data, "SSL: certificate subject name '%s' does not match "
+ "target host name '%s'", peer_CN, conn->host.dispname);
+ OPENSSL_free(peer_CN);
+ return CURLE_SSL_PEER_CERTIFICATE ;
+ }
+ else
+ infof(data, "\t common name: %s (does not match '%s')\n",
+ peer_CN, conn->host.dispname);
+ }
+ else {
+ infof(data, "\t common name: %s (matched)\n", peer_CN);
+ OPENSSL_free(peer_CN);
+ }
+ }
+ return CURLE_OK;
+}
+#endif
+
+/* The SSL_CTRL_SET_MSG_CALLBACK doesn't exist in ancient OpenSSL versions
+ and thus this cannot be done there. */
+#ifdef SSL_CTRL_SET_MSG_CALLBACK
+
+static const char *ssl_msg_type(int ssl_ver, int msg)
+{
+ if (ssl_ver == SSL2_VERSION_MAJOR) {
+ switch (msg) {
+ case SSL2_MT_ERROR:
+ return "Error";
+ case SSL2_MT_CLIENT_HELLO:
+ return "Client hello";
+ case SSL2_MT_CLIENT_MASTER_KEY:
+ return "Client key";
+ case SSL2_MT_CLIENT_FINISHED:
+ return "Client finished";
+ case SSL2_MT_SERVER_HELLO:
+ return "Server hello";
+ case SSL2_MT_SERVER_VERIFY:
+ return "Server verify";
+ case SSL2_MT_SERVER_FINISHED:
+ return "Server finished";
+ case SSL2_MT_REQUEST_CERTIFICATE:
+ return "Request CERT";
+ case SSL2_MT_CLIENT_CERTIFICATE:
+ return "Client CERT";
+ }
+ }
+ else if (ssl_ver == SSL3_VERSION_MAJOR) {
+ switch (msg) {
+ case SSL3_MT_HELLO_REQUEST:
+ return "Hello request";
+ case SSL3_MT_CLIENT_HELLO:
+ return "Client hello";
+ case SSL3_MT_SERVER_HELLO:
+ return "Server hello";
+ case SSL3_MT_CERTIFICATE:
+ return "CERT";
+ case SSL3_MT_SERVER_KEY_EXCHANGE:
+ return "Server key exchange";
+ case SSL3_MT_CLIENT_KEY_EXCHANGE:
+ return "Client key exchange";
+ case SSL3_MT_CERTIFICATE_REQUEST:
+ return "Request CERT";
+ case SSL3_MT_SERVER_DONE:
+ return "Server finished";
+ case SSL3_MT_CERTIFICATE_VERIFY:
+ return "CERT verify";
+ case SSL3_MT_FINISHED:
+ return "Finished";
+ }
+ }
+ return "Unknown";
+}
+
+static const char *tls_rt_type(int type)
+{
+ return (
+ type == SSL3_RT_CHANGE_CIPHER_SPEC ? "TLS change cipher, " :
+ type == SSL3_RT_ALERT ? "TLS alert, " :
+ type == SSL3_RT_HANDSHAKE ? "TLS handshake, " :
+ type == SSL3_RT_APPLICATION_DATA ? "TLS app data, " :
+ "TLS Unknown, ");
+}
+
+
+/*
+ * Our callback from the SSL/TLS layers.
+ */
+static void ssl_tls_trace(int direction, int ssl_ver, int content_type,
+ const void *buf, size_t len, const SSL *ssl,
+ struct connectdata *conn)
+{
+ struct SessionHandle *data = conn->data;
+ const char *msg_name, *tls_rt_name;
+ char ssl_buf[1024];
+ int ver, msg_type, txt_len;
+
+ if (!conn || !conn->data || !conn->data->set.fdebug ||
+ (direction != 0 && direction != 1))
+ return;
+
+ data = conn->data;
+ ssl_ver >>= 8;
+ ver = (ssl_ver == SSL2_VERSION_MAJOR ? '2' :
+ ssl_ver == SSL3_VERSION_MAJOR ? '3' : '?');
+
+ /* SSLv2 doesn't seem to have TLS record-type headers, so OpenSSL
+ * always pass-up content-type as 0. But the interesting message-type
+ * is at 'buf[0]'.
+ */
+ if (ssl_ver == SSL3_VERSION_MAJOR && content_type != 0)
+ tls_rt_name = tls_rt_type(content_type);
+ else
+ tls_rt_name = "";
+
+ msg_type = *(char*)buf;
+ msg_name = ssl_msg_type(ssl_ver, msg_type);
+
+ txt_len = 1 + snprintf(ssl_buf, sizeof(ssl_buf), "SSLv%c, %s%s (%d):\n",
+ ver, tls_rt_name, msg_name, msg_type);
+ Curl_debug(data, CURLINFO_TEXT, ssl_buf, txt_len, NULL);
+
+ Curl_debug(data, (direction == 1) ? CURLINFO_SSL_DATA_OUT :
+ CURLINFO_SSL_DATA_IN, (char *)buf, len, NULL);
+ (void) ssl;
+}
#endif
/* ====================================================== */
CURLcode
-Curl_SSLConnect(struct connectdata *conn)
+Curl_SSLConnect(struct connectdata *conn,
+ int sockindex)
{
CURLcode retcode = CURLE_OK;
#ifdef USE_SSLEAY
struct SessionHandle *data = conn->data;
int err;
+ long lerr;
+ int what;
char * str;
SSL_METHOD *req_method;
SSL_SESSION *ssl_sessionid=NULL;
ASN1_TIME *certdate;
+ curl_socket_t sockfd = conn->sock[sockindex];
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
/* mark this is being ssl enabled from here on out. */
- conn->ssl.use = TRUE;
+ connssl->use = TRUE;
if(!ssl_seeded || data->set.ssl.random_file || data->set.ssl.egdsocket) {
/* Make funny stuff to get random input */
@@ -753,115 +1132,156 @@ Curl_SSLConnect(struct connectdata *conn)
req_method = SSLv3_client_method();
break;
}
-
- conn->ssl.ctx = SSL_CTX_new(req_method);
- if(!conn->ssl.ctx) {
+ connssl->ctx = SSL_CTX_new(req_method);
+
+ if(!connssl->ctx) {
failf(data, "SSL: couldn't create a context!");
return CURLE_OUT_OF_MEMORY;
}
-
+
+#ifdef SSL_CTRL_SET_MSG_CALLBACK
+ if (data->set.fdebug) {
+ SSL_CTX_callback_ctrl(connssl->ctx, SSL_CTRL_SET_MSG_CALLBACK,
+ ssl_tls_trace);
+ SSL_CTX_ctrl(connssl->ctx, SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, conn);
+ }
+#endif
+
+ /* OpenSSL contains code to work-around lots of bugs and flaws in various
+ SSL-implementations. SSL_CTX_set_options() is used to enabled those
+ work-arounds. The man page for this option states that SSL_OP_ALL enables
+ ll the work-arounds and that "It is usually safe to use SSL_OP_ALL to
+ enable the bug workaround options if compatibility with somewhat broken
+ implementations is desired."
+
+ */
+ SSL_CTX_set_options(connssl->ctx, SSL_OP_ALL);
+
+#if 0
+ /*
+ * Not sure it's needed to tell SSL_connect() that socket is
+ * non-blocking. It doesn't seem to care, but just return with
+ * SSL_ERROR_WANT_x.
+ */
+ if (data->state.used_interface == Curl_if_multi)
+ SSL_CTX_ctrl(connssl->ctx, BIO_C_SET_NBIO, 1, NULL);
+#endif
+
if(data->set.cert) {
- if (!cert_stuff(conn,
- data->set.cert,
- data->set.cert_type,
- data->set.key,
- data->set.key_type)) {
+ if(!cert_stuff(conn,
+ connssl->ctx,
+ data->set.cert,
+ data->set.cert_type,
+ data->set.key,
+ data->set.key_type)) {
/* failf() is already done in cert_stuff() */
return CURLE_SSL_CERTPROBLEM;
}
}
if(data->set.ssl.cipher_list) {
- if (!SSL_CTX_set_cipher_list(conn->ssl.ctx,
- data->set.ssl.cipher_list)) {
+ if(!SSL_CTX_set_cipher_list(connssl->ctx,
+ data->set.ssl.cipher_list)) {
failf(data, "failed setting cipher list");
return CURLE_SSL_CIPHER;
}
}
- if(data->set.ssl.verifypeer){
- SSL_CTX_set_verify(conn->ssl.ctx,
- SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT|
- SSL_VERIFY_CLIENT_ONCE,
- cert_verify_callback);
- if ((data->set.ssl.CAfile || data->set.ssl.CApath) &&
- !SSL_CTX_load_verify_locations(conn->ssl.ctx,
- data->set.ssl.CAfile,
+ if (data->set.ssl.CAfile || data->set.ssl.CApath) {
+ /* tell SSL where to find CA certificates that are used to verify
+ the servers certificate. */
+ if (!SSL_CTX_load_verify_locations(connssl->ctx, data->set.ssl.CAfile,
data->set.ssl.CApath)) {
- failf(data,"error setting cerficate verify locations");
- return CURLE_SSL_CACERT;
+ if (data->set.ssl.verifypeer) {
+ /* Fail if we insist on successfully verifying the server. */
+ failf(data,"error setting certificate verify locations:\n"
+ " CAfile: %s\n CApath: %s\n",
+ data->set.ssl.CAfile ? data->set.ssl.CAfile : "none",
+ data->set.ssl.CApath ? data->set.ssl.CApath : "none");
+ return CURLE_SSL_CACERT;
+ }
+ else {
+ /* Just continue with a warning if no strict certificate verification
+ is required. */
+ infof(data, "error setting certificate verify locations,"
+ " continuing anyway:\n");
+ }
+ }
+ else {
+ /* Everything is fine. */
+ infof(data, "successfully set certificate verify locations:\n");
+ }
+ infof(data,
+ " CAfile: %s\n"
+ " CApath: %s\n",
+ data->set.ssl.CAfile ? data->set.ssl.CAfile : "none",
+ data->set.ssl.CApath ? data->set.ssl.CApath : "none");
+ }
+ /* SSL always tries to verify the peer, this only says whether it should
+ * fail to connect if the verification fails, or if it should continue
+ * anyway. In the latter case the result of the verification is checked with
+ * SSL_get_verify_result() below. */
+ SSL_CTX_set_verify(connssl->ctx,
+ data->set.ssl.verifypeer?SSL_VERIFY_PEER:SSL_VERIFY_NONE,
+ cert_verify_callback);
+
+ /* give application a chance to interfere with SSL set up. */
+ if(data->set.ssl.fsslctx) {
+ retcode = (*data->set.ssl.fsslctx)(data, connssl->ctx,
+ data->set.ssl.fsslctxp);
+ if(retcode) {
+ failf(data,"error signaled by ssl ctx callback");
+ return retcode;
}
}
- else
- SSL_CTX_set_verify(conn->ssl.ctx, SSL_VERIFY_NONE, cert_verify_callback);
-
/* Lets make an SSL structure */
- conn->ssl.handle = SSL_new (conn->ssl.ctx);
- SSL_set_connect_state (conn->ssl.handle);
+ connssl->handle = SSL_new(connssl->ctx);
+ SSL_set_connect_state(connssl->handle);
- conn->ssl.server_cert = 0x0;
+ connssl->server_cert = 0x0;
if(!conn->bits.reuse) {
/* We're not re-using a connection, check if there's a cached ID we
can/should use here! */
if(!Get_SSL_Session(conn, &ssl_sessionid)) {
/* we got a session id, use it! */
- SSL_set_session(conn->ssl.handle, ssl_sessionid);
+ SSL_set_session(connssl->handle, ssl_sessionid);
/* Informational message */
infof (data, "SSL re-using session ID\n");
}
}
/* pass the raw socket into the SSL layers */
- SSL_set_fd(conn->ssl.handle, conn->firstsocket);
+ SSL_set_fd(connssl->handle, sockfd);
- do {
- int what;
+ while(1) {
fd_set writefd;
fd_set readfd;
struct timeval interval;
long timeout_ms;
- err = SSL_connect(conn->ssl.handle);
-
- what = SSL_get_error(conn->ssl.handle, err);
-
- FD_ZERO(&writefd);
- FD_ZERO(&readfd);
-
- if(SSL_ERROR_WANT_READ == what)
- FD_SET(conn->firstsocket, &readfd);
- else if(SSL_ERROR_WANT_WRITE == what)
- FD_SET(conn->firstsocket, &writefd);
- else
- break; /* untreated error */
-
/* Find out if any timeout is set. If not, use 300 seconds.
Otherwise, figure out the most strict timeout of the two possible one
and then how much time that has elapsed to know how much time we
allow for the connect call */
if(data->set.timeout || data->set.connecttimeout) {
- double has_passed;
+ long has_passed;
/* Evaluate in milliseconds how much time that has passed */
has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.start);
-#ifndef min
-#define min(a, b) ((a) < (b) ? (a) : (b))
-#endif
-
/* get the most strict timeout of the ones converted to milliseconds */
if(data->set.timeout &&
(data->set.timeout>data->set.connecttimeout))
timeout_ms = data->set.timeout*1000;
else
timeout_ms = data->set.connecttimeout*1000;
-
+
/* subtract the passed time */
- timeout_ms -= (long)has_passed;
-
+ timeout_ms -= has_passed;
+
if(timeout_ms < 0) {
/* a precaution, no need to continue if time already is up */
failf(data, "SSL connection timeout");
@@ -870,139 +1290,198 @@ Curl_SSLConnect(struct connectdata *conn)
}
else
/* no particular time-out has been set */
- timeout_ms=300000; /* milliseconds, default to five minutes */
+ timeout_ms= DEFAULT_CONNECT_TIMEOUT;
- interval.tv_sec = timeout_ms/1000;
- timeout_ms -= interval.tv_sec*1000;
- interval.tv_usec = timeout_ms*1000;
+ FD_ZERO(&writefd);
+ FD_ZERO(&readfd);
- what = select(conn->firstsocket+1, &readfd, &writefd, NULL, &interval);
- if(what > 0)
- /* reabable or writable, go loop yourself */
- continue;
- else if(0 == what) {
- /* timeout */
- failf(data, "SSL connection timeout");
- return CURLE_OPERATION_TIMEOUTED;
+ err = SSL_connect(connssl->handle);
+
+ /* 1 is fine
+ 0 is "not successful but was shut down controlled"
+ <0 is "handshake was not successful, because a fatal error occurred" */
+ if(1 != err) {
+ int detail = SSL_get_error(connssl->handle, err);
+
+ if(SSL_ERROR_WANT_READ == detail)
+ FD_SET(sockfd, &readfd);
+ else if(SSL_ERROR_WANT_WRITE == detail)
+ FD_SET(sockfd, &writefd);
+ else {
+ /* untreated error */
+ unsigned long errdetail;
+ char error_buffer[120]; /* OpenSSL documents that this must be at least
+ 120 bytes long. */
+ CURLcode rc;
+ const char *cert_problem = NULL;
+
+ errdetail = ERR_get_error(); /* Gets the earliest error code from the
+ thread's error queue and removes the
+ entry. */
+
+ switch(errdetail) {
+ case 0x1407E086:
+ /* 1407E086:
+ SSL routines:
+ SSL2_SET_CERTIFICATE:
+ certificate verify failed */
+ /* fall-through */
+ case 0x14090086:
+ /* 14090086:
+ SSL routines:
+ SSL3_GET_SERVER_CERTIFICATE:
+ certificate verify failed */
+ cert_problem = "SSL certificate problem, verify that the CA cert is"
+ " OK. Details:\n";
+ rc = CURLE_SSL_CACERT;
+ break;
+ default:
+ rc = CURLE_SSL_CONNECT_ERROR;
+ break;
+ }
+
+ /* detail is already set to the SSL error above */
+
+ /* If we e.g. use SSLv2 request-method and the server doesn't like us
+ * (RST connection etc.), OpenSSL gives no explanation whatsoever and
+ * the SO_ERROR is also lost.
+ */
+ if (CURLE_SSL_CONNECT_ERROR == rc && errdetail == 0) {
+ failf(data, "Unknown SSL protocol error in connection to %s:%d ",
+ conn->host.name, conn->port);
+ return rc;
+ }
+ /* Could be a CERT problem */
+
+#ifdef HAVE_ERR_ERROR_STRING_N
+ /* OpenSSL 0.9.6 and later has a function named
+ ERRO_error_string_n() that takes the size of the buffer as a
+ third argument */
+ ERR_error_string_n(errdetail, error_buffer, sizeof(error_buffer));
+#else
+ ERR_error_string(errdetail, error_buffer);
+#endif
+ failf(data, "%s%s", cert_problem ? cert_problem : "", error_buffer);
+ return rc;
+ }
}
else
- break; /* get out of loop */
- } while(1);
-
- /* 1 is fine
- 0 is "not successful but was shut down controlled"
- <0 is "handshake was not successful, because a fatal error occurred" */
- if (err <= 0) {
- err = ERR_get_error();
- failf(data, "SSL: %s", ERR_error_string(err, NULL));
- return CURLE_SSL_CONNECT_ERROR;
- }
+ /* we have been connected fine, get out of the connect loop */
+ break;
+
+ interval.tv_sec = (int)(timeout_ms/1000);
+ timeout_ms -= interval.tv_sec*1000;
+
+ interval.tv_usec = timeout_ms*1000;
+
+ while(1) {
+ what = select(sockfd+1, &readfd, &writefd, NULL, &interval);
+ if(what > 0)
+ /* reabable or writable, go loop in the outer loop */
+ break;
+ else if(0 == what) {
+ /* timeout */
+ failf(data, "SSL connection timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+ else {
+#if !defined(WIN32) && defined(EINTR)
+ /* For platforms without EINTR all errnos are bad */
+ if (errno == EINTR)
+ continue; /* retry the select() */
+#endif
+ /* anything other than the unimportant EINTR is fatally bad */
+ failf(data, "select on SSL socket, errno: %d", Curl_ourerrno());
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ } /* while()-loop for the select() */
+ } /* while()-loop for the SSL_connect() */
/* Informational message */
infof (data, "SSL connection using %s\n",
- SSL_get_cipher(conn->ssl.handle));
+ SSL_get_cipher(connssl->handle));
if(!ssl_sessionid) {
/* Since this is not a cached session ID, then we want to stach this one
in the cache! */
- Store_SSL_Session(conn);
+ Store_SSL_Session(conn, connssl);
}
-
+
/* Get server's certificate (note: beware of dynamic allocation) - opt */
/* major serious hack alert -- we should check certificates
* to authenticate the server; otherwise we risk man-in-the-middle
* attack
*/
- conn->ssl.server_cert = SSL_get_peer_certificate (conn->ssl.handle);
- if(!conn->ssl.server_cert) {
+ connssl->server_cert = SSL_get_peer_certificate(connssl->handle);
+ if(!connssl->server_cert) {
failf(data, "SSL: couldn't get peer certificate!");
return CURLE_SSL_PEER_CERTIFICATE;
}
infof (data, "Server certificate:\n");
-
- str = X509_NAME_oneline (X509_get_subject_name (conn->ssl.server_cert),
- NULL, 0);
+
+ str = X509_NAME_oneline(X509_get_subject_name(connssl->server_cert),
+ NULL, 0);
if(!str) {
failf(data, "SSL: couldn't get X509-subject!");
- X509_free(conn->ssl.server_cert);
+ X509_free(connssl->server_cert);
return CURLE_SSL_CONNECT_ERROR;
}
infof(data, "\t subject: %s\n", str);
CRYPTO_free(str);
- certdate = X509_get_notBefore(conn->ssl.server_cert);
+ certdate = X509_get_notBefore(connssl->server_cert);
Curl_ASN1_UTCTIME_output(conn, "\t start date: ", certdate);
- certdate = X509_get_notAfter(conn->ssl.server_cert);
+ certdate = X509_get_notAfter(connssl->server_cert);
Curl_ASN1_UTCTIME_output(conn, "\t expire date: ", certdate);
- if (data->set.ssl.verifyhost) {
- char peer_CN[257];
- if (X509_NAME_get_text_by_NID(X509_get_subject_name(conn->ssl.server_cert),
- NID_commonName,
- peer_CN,
- sizeof(peer_CN)) < 0) {
- failf(data, "SSL: unable to obtain common name from peer certificate");
- X509_free(conn->ssl.server_cert);
- return CURLE_SSL_PEER_CERTIFICATE;
+ if(data->set.ssl.verifyhost) {
+ retcode = verifyhost(conn, connssl->server_cert);
+ if(retcode) {
+ X509_free(connssl->server_cert);
+ return retcode;
}
-
- if (!cert_hostcheck(peer_CN, conn->hostname)) {
- if (data->set.ssl.verifyhost > 1) {
- failf(data, "SSL: certificate subject name '%s' does not match "
- "target host name '%s'",
- peer_CN, conn->hostname);
- X509_free(conn->ssl.server_cert);
- return CURLE_SSL_PEER_CERTIFICATE;
- }
- else
- infof(data,
- "\t common name: %s (does not match '%s')\n",
- peer_CN, conn->hostname);
- }
- else
- infof(data, "\t common name: %s (matched)\n", peer_CN);
}
- str = X509_NAME_oneline (X509_get_issuer_name (conn->ssl.server_cert),
- NULL, 0);
+ str = X509_NAME_oneline(X509_get_issuer_name(connssl->server_cert),
+ NULL, 0);
if(!str) {
failf(data, "SSL: couldn't get X509-issuer name!");
- X509_free(conn->ssl.server_cert);
- return CURLE_SSL_CONNECT_ERROR;
+ retcode = CURLE_SSL_CONNECT_ERROR;
}
- infof(data, "\t issuer: %s\n", str);
- CRYPTO_free(str);
-
- /* We could do all sorts of certificate verification stuff here before
- deallocating the certificate. */
-
- if(data->set.ssl.verifypeer) {
- data->set.ssl.certverifyresult=SSL_get_verify_result(conn->ssl.handle);
- if (data->set.ssl.certverifyresult != X509_V_OK) {
- failf(data, "SSL certificate verify result: %d",
- data->set.ssl.certverifyresult);
- retcode = CURLE_SSL_PEER_CERTIFICATE;
+ else {
+ infof(data, "\t issuer: %s\n", str);
+ CRYPTO_free(str);
+
+ /* We could do all sorts of certificate verification stuff here before
+ deallocating the certificate. */
+
+ lerr = data->set.ssl.certverifyresult=
+ SSL_get_verify_result(connssl->handle);
+ if(data->set.ssl.certverifyresult != X509_V_OK) {
+ if(data->set.ssl.verifypeer) {
+ /* We probably never reach this, because SSL_connect() will fail
+ and we return earlyer if verifypeer is set? */
+ failf(data, "SSL certificate verify result: %s (%ld)",
+ X509_verify_cert_error_string(lerr), lerr);
+ retcode = CURLE_SSL_PEER_CERTIFICATE;
+ }
+ else
+ infof(data, "SSL certificate verify result: %s (%ld),"
+ " continuing anyway.\n",
+ X509_verify_cert_error_string(err), lerr);
}
+ else
+ infof(data, "SSL certificate verify ok.\n");
}
- else
- data->set.ssl.certverifyresult=0;
- X509_free(conn->ssl.server_cert);
+ X509_free(connssl->server_cert);
#else /* USE_SSLEAY */
- /* this is for "-ansi -Wall -pedantic" to stop complaining! (rabe) */
- (void) conn;
+ (void)conn;
+ (void)sockindex;
#endif
return retcode;
}
-
-/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
- */
diff --git a/Source/CTest/Curl/ssluse.h b/Source/CTest/Curl/ssluse.h
index b8526a3..886d2ca 100644
--- a/Source/CTest/Curl/ssluse.h
+++ b/Source/CTest/Curl/ssluse.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -23,7 +23,7 @@
* $Id$
***************************************************************************/
#include "urldata.h"
-CURLcode Curl_SSLConnect(struct connectdata *conn);
+CURLcode Curl_SSLConnect(struct connectdata *conn, int sockindex);
void Curl_SSL_init(void); /* Global SSL init */
void Curl_SSL_cleanup(void); /* Global SSL cleanup */
diff --git a/Source/CTest/Curl/strequal.c b/Source/CTest/Curl/strequal.c
index 0cc22ea..f993e38 100644
--- a/Source/CTest/Curl/strequal.c
+++ b/Source/CTest/Curl/strequal.c
@@ -1,16 +1,16 @@
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -26,14 +26,22 @@
#include <string.h>
#include <ctype.h>
+#include "strequal.h"
+
+#ifdef HAVE_STRCASECMP
+/* this is for "-ansi -Wall -pedantic" to stop complaining! */
+extern int (strcasecmp)(const char *s1, const char *s2);
+extern int (strncasecmp)(const char *s1, const char *s2, size_t n);
+#endif
+
int curl_strequal(const char *first, const char *second)
{
#if defined(HAVE_STRCASECMP)
return !(strcasecmp)(first, second);
-#elif defined(HAVE_STRICMP)
- return !(stricmp)(first, second);
#elif defined(HAVE_STRCMPI)
return !(strcmpi)(first, second);
+#elif defined(HAVE_STRICMP)
+ return !(stricmp)(first, second);
#else
while (*first && *second) {
if (toupper(*first) != toupper(*second)) {
@@ -50,10 +58,10 @@ int curl_strnequal(const char *first, const char *second, size_t max)
{
#if defined(HAVE_STRCASECMP)
return !strncasecmp(first, second, max);
-#elif defined(HAVE_STRICMP)
- return !strnicmp(first, second, max);
#elif defined(HAVE_STRCMPI)
return !strncmpi(first, second, max);
+#elif defined(HAVE_STRICMP)
+ return !strnicmp(first, second, max);
#else
while (*first && *second && max) {
if (toupper(*first) != toupper(*second)) {
@@ -70,6 +78,25 @@ int curl_strnequal(const char *first, const char *second, size_t max)
#endif
}
+/*
+ * Curl_strcasestr() finds the first occurrence of the substring needle in the
+ * string haystack. The terminating `\0' characters are not compared. The
+ * matching is done CASE INSENSITIVE, which thus is the difference between
+ * this and strstr().
+ */
+char *Curl_strcasestr(const char *haystack, const char *needle)
+{
+ size_t nlen = strlen(needle);
+ size_t hlen = strlen(haystack);
+
+ while(hlen-- >= nlen) {
+ if(curl_strnequal(haystack, needle, nlen))
+ return (char *)haystack;
+ haystack++;
+ }
+ return NULL;
+}
+
#ifndef HAVE_STRLCAT
/*
* The strlcat() function appends the NUL-terminated string src to the end
@@ -82,7 +109,7 @@ int curl_strnequal(const char *first, const char *second, size_t max)
* src. While this may seem somewhat confusing it was done to make trunca-
* tion detection simple.
*
- *
+ *
*/
size_t Curl_strlcat(char *dst, const char *src, size_t siz)
{
@@ -111,11 +138,3 @@ size_t Curl_strlcat(char *dst, const char *src, size_t siz)
return(dlen + (s - src)); /* count does not include NUL */
}
#endif
-
-/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
- */
diff --git a/Source/CTest/Curl/strequal.h b/Source/CTest/Curl/strequal.h
index e63dc21..5865211 100644
--- a/Source/CTest/Curl/strequal.h
+++ b/Source/CTest/Curl/strequal.h
@@ -1,18 +1,18 @@
#ifndef __STREQUAL_H
#define __STREQUAL_H
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -36,6 +36,9 @@ int curl_strnequal(const char *first, const char *second, size_t max);
argument is zero-byte terminated */
#define checkprefix(a,b) strnequal(a,b,strlen(a))
+/* case insensitive strstr() */
+char *Curl_strcasestr(const char *haystack, const char *needle);
+
#ifndef HAVE_STRLCAT
#define strlcat(x,y,z) Curl_strlcat(x,y,z)
size_t Curl_strlcat(char *dst, const char *src, size_t siz);
diff --git a/Source/CTest/Curl/strerror.c b/Source/CTest/Curl/strerror.c
new file mode 100644
index 0000000..3179dd6
--- /dev/null
+++ b/Source/CTest/Curl/strerror.c
@@ -0,0 +1,558 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "setup.h"
+
+#include <curl/curl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "strerror.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#ifdef HAVE_NO_STRERROR_R_DECL
+#ifdef HAVE_POSIX_STRERROR_R
+/* seen on AIX 5100-02 gcc 2.9 */
+extern int strerror_r(int errnum, char *strerrbuf, size_t buflen);
+#else
+extern char *strerror_r(int errnum, char *buf, size_t buflen);
+#endif
+#endif
+
+const char *
+curl_easy_strerror(CURLcode error)
+{
+ switch (error) {
+ case CURLE_OK:
+ return "no error";
+
+ case CURLE_UNSUPPORTED_PROTOCOL:
+ return "unsupported protocol";
+
+ case CURLE_FAILED_INIT:
+ return "failed init";
+
+ case CURLE_URL_MALFORMAT:
+ return "URL using bad/illegal format or missing URL";
+
+ case CURLE_COULDNT_RESOLVE_PROXY:
+ return "couldnt resolve proxy";
+
+ case CURLE_COULDNT_RESOLVE_HOST:
+ return "couldnt resolve host";
+
+ case CURLE_COULDNT_CONNECT:
+ return "couldn't connect";
+
+ case CURLE_FTP_WEIRD_SERVER_REPLY:
+ return "FTP: weird server reply";
+
+ case CURLE_FTP_ACCESS_DENIED:
+ return "FTP: access denied";
+
+ case CURLE_FTP_USER_PASSWORD_INCORRECT:
+ return "FTP: user and/or password incorrect";
+
+ case CURLE_FTP_WEIRD_PASS_REPLY:
+ return "FTP: unknown PASS reply";
+
+ case CURLE_FTP_WEIRD_USER_REPLY:
+ return "FTP: unknown USER reply";
+
+ case CURLE_FTP_WEIRD_PASV_REPLY:
+ return "FTP: unknown PASV reply";
+
+ case CURLE_FTP_WEIRD_227_FORMAT:
+ return "FTP: unknown 227 response format";
+
+ case CURLE_FTP_CANT_GET_HOST:
+ return "FTP: can't figure out the host in the PASV response";
+
+ case CURLE_FTP_CANT_RECONNECT:
+ return "FTP: can't connect to server the response code is unknown";
+
+ case CURLE_FTP_COULDNT_SET_BINARY:
+ return "FTP: couldn't set binary mode";
+
+ case CURLE_PARTIAL_FILE:
+ return "Transferred a partial file";
+
+ case CURLE_FTP_COULDNT_RETR_FILE:
+ return "FTP: couldn't retrieve (RETR failed) the specified file";
+
+ case CURLE_FTP_WRITE_ERROR:
+ return "FTP: the post-transfer acknowledge response was not OK";
+
+ case CURLE_FTP_QUOTE_ERROR:
+ return "FTP: a quote command returned error";
+
+ case CURLE_HTTP_RETURNED_ERROR:
+ return "HTTP response code said error";
+
+ case CURLE_WRITE_ERROR:
+ return "failed writing received data to disk/application";
+
+ case CURLE_FTP_COULDNT_STOR_FILE:
+ return "failed FTP upload (the STOR command)";
+
+ case CURLE_READ_ERROR:
+ return "failed to open/read local data from file/application";
+
+ case CURLE_OUT_OF_MEMORY:
+ return "out of memory";
+
+ case CURLE_OPERATION_TIMEOUTED:
+ return "a timeout was reached";
+
+ case CURLE_FTP_COULDNT_SET_ASCII:
+ return "FTP could not set ASCII mode (TYPE A)";
+
+ case CURLE_FTP_PORT_FAILED:
+ return "FTP command PORT failed";
+
+ case CURLE_FTP_COULDNT_USE_REST:
+ return "FTP command REST failed";
+
+ case CURLE_FTP_COULDNT_GET_SIZE:
+ return "FTP command SIZE failed";
+
+ case CURLE_HTTP_RANGE_ERROR:
+ return "a range was requested but the server did not deliver it";
+
+ case CURLE_HTTP_POST_ERROR:
+ return "internal problem setting up the POST";
+
+ case CURLE_SSL_CONNECT_ERROR:
+ return "SSL connect error";
+
+ case CURLE_FTP_BAD_DOWNLOAD_RESUME:
+ return "couldn't resume FTP download";
+
+ case CURLE_FILE_COULDNT_READ_FILE:
+ return "couldn't read a file:// file";
+
+ case CURLE_LDAP_CANNOT_BIND:
+ return "LDAP: cannot bind";
+
+ case CURLE_LDAP_SEARCH_FAILED:
+ return "LDAP: search failed";
+
+ case CURLE_LIBRARY_NOT_FOUND:
+ return "a required shared library was not found";
+
+ case CURLE_FUNCTION_NOT_FOUND:
+ return "a required function in the shared library was not found";
+
+ case CURLE_ABORTED_BY_CALLBACK:
+ return "the operation was aborted by an application callback";
+
+ case CURLE_BAD_FUNCTION_ARGUMENT:
+ return "a libcurl function was given a bad argument";
+
+ case CURLE_INTERFACE_FAILED:
+ return "failed binding local connection end";
+
+ case CURLE_TOO_MANY_REDIRECTS :
+ return "number of redirects hit maximum amount";
+
+ case CURLE_UNKNOWN_TELNET_OPTION:
+ return "User specified an unknown option";
+
+ case CURLE_TELNET_OPTION_SYNTAX :
+ return "Malformed telnet option";
+
+ case CURLE_SSL_PEER_CERTIFICATE:
+ return "SSL peer certificate was not ok";
+
+ case CURLE_GOT_NOTHING:
+ return "server returned nothing (no headers, no data)";
+
+ case CURLE_SSL_ENGINE_NOTFOUND:
+ return "SSL crypto engine not found";
+
+ case CURLE_SSL_ENGINE_SETFAILED:
+ return "can not set SSL crypto engine as default";
+
+ case CURLE_SEND_ERROR:
+ return "failed sending data to the peer";
+
+ case CURLE_RECV_ERROR:
+ return "failure when receiving data from the peer";
+
+ case CURLE_SHARE_IN_USE:
+ return "share is already in use";
+
+ case CURLE_SSL_CERTPROBLEM:
+ return "problem with the local SSL certificate";
+
+ case CURLE_SSL_CIPHER:
+ return "couldn't use specified SSL cipher";
+
+ case CURLE_SSL_CACERT:
+ return "problem with the SSL CA cert (path? access rights?)";
+
+ case CURLE_BAD_CONTENT_ENCODING:
+ return "Unrecognized HTTP Content-Encoding";
+
+ case CURLE_LDAP_INVALID_URL:
+ return "Invalid LDAP URL";
+
+ case CURLE_FILESIZE_EXCEEDED:
+ return "Maximum file size exceeded";
+
+ case CURLE_FTP_SSL_FAILED:
+ return "Requested FTP SSL level failed";
+
+ case CURLE_URL_MALFORMAT_USER: /* not used by current libcurl */
+ case CURLE_MALFORMAT_USER: /* not used by current libcurl */
+ case CURLE_BAD_CALLING_ORDER: /* not used by current libcurl */
+ case CURLE_BAD_PASSWORD_ENTERED:/* not used by current libcurl */
+ case CURLE_OBSOLETE: /* not used by current libcurl */
+ case CURL_LAST:
+ break;
+ }
+ /*
+ * By using a switch, gcc -Wall will complain about enum values
+ * which do not appear, helping keep this function up-to-date.
+ * By using gcc -Wall -Werror, you can't forget.
+ *
+ * A table would not have the same benefit. Most compilers will
+ * generate code very similar to a table in any case, so there
+ * is little performance gain from a table. And something is broken
+ * for the user's application, anyways, so does it matter how fast
+ * it _doesn't_ work?
+ *
+ * The line number for the error will be near this comment, which
+ * is why it is here, and not at the start of the switch.
+ */
+ return "unknown error";
+}
+
+const char *
+curl_multi_strerror(CURLMcode error)
+{
+ switch (error) {
+ case CURLM_CALL_MULTI_PERFORM:
+ return "please call curl_multi_perform() soon";
+
+ case CURLM_OK:
+ return "no error";
+
+ case CURLM_BAD_HANDLE:
+ return "invalid multi handle";
+
+ case CURLM_BAD_EASY_HANDLE:
+ return "invalid easy handle";
+
+ case CURLM_OUT_OF_MEMORY:
+ return "out of memory";
+
+ case CURLM_INTERNAL_ERROR:
+ return "internal error";
+
+ case CURLM_LAST:
+ break;
+ }
+
+ return "unknown error";
+}
+
+const char *
+curl_share_strerror(CURLSHcode error)
+{
+ switch (error) {
+ case CURLSHE_OK:
+ return "no error";
+
+ case CURLSHE_BAD_OPTION:
+ return "unknown share option";
+
+ case CURLSHE_IN_USE:
+ return "share currently in use";
+
+ case CURLSHE_INVALID:
+ return "invalid share handle";
+
+ case CURLSHE_NOMEM:
+ return "out of memory";
+
+ case CURLSHE_LAST:
+ break;
+ }
+
+ return "CURLSH unknown";
+}
+
+#if defined(WIN32) && !defined(__CYGWIN__)
+
+/* This function handles most / all (?) Winsock errors cURL is able to produce.
+ */
+static const char *
+get_winsock_error (int err, char *buf, size_t len)
+{
+ char *p;
+
+ switch (err) {
+ case WSAEINTR:
+ p = "Call interrupted.";
+ break;
+ case WSAEBADF:
+ p = "Bad file";
+ break;
+ case WSAEACCES:
+ p = "Bad access";
+ break;
+ case WSAEFAULT:
+ p = "Bad argument";
+ break;
+ case WSAEINVAL:
+ p = "Invalid arguments";
+ break;
+ case WSAEMFILE:
+ p = "Out of file descriptors";
+ break;
+ case WSAEWOULDBLOCK:
+ p = "Call would block";
+ break;
+ case WSAEINPROGRESS:
+ case WSAEALREADY:
+ p = "Blocking call in progress";
+ break;
+ case WSAENOTSOCK:
+ p = "Descriptor is not a socket.";
+ break;
+ case WSAEDESTADDRREQ:
+ p = "Need destination address";
+ break;
+ case WSAEMSGSIZE:
+ p = "Bad message size";
+ break;
+ case WSAEPROTOTYPE:
+ p = "Bad protocol";
+ break;
+ case WSAENOPROTOOPT:
+ p = "Protocol option is unsupported";
+ break;
+ case WSAEPROTONOSUPPORT:
+ p = "Protocol is unsupported";
+ break;
+ case WSAESOCKTNOSUPPORT:
+ p = "Socket is unsupported";
+ break;
+ case WSAEOPNOTSUPP:
+ p = "Operation not supported";
+ break;
+ case WSAEAFNOSUPPORT:
+ p = "Address family not supported";
+ break;
+ case WSAEPFNOSUPPORT:
+ p = "Protocol family not supported";
+ break;
+ case WSAEADDRINUSE:
+ p = "Address already in use";
+ break;
+ case WSAEADDRNOTAVAIL:
+ p = "Address not available";
+ break;
+ case WSAENETDOWN:
+ p = "Network down";
+ break;
+ case WSAENETUNREACH:
+ p = "Network unreachable";
+ break;
+ case WSAENETRESET:
+ p = "Network has been reset";
+ break;
+ case WSAECONNABORTED:
+ p = "Connection was aborted";
+ break;
+ case WSAECONNRESET:
+ p = "Connection was reset";
+ break;
+ case WSAENOBUFS:
+ p = "No buffer space";
+ break;
+ case WSAEISCONN:
+ p = "Socket is already connected";
+ break;
+ case WSAENOTCONN:
+ p = "Socket is not connected";
+ break;
+ case WSAESHUTDOWN:
+ p = "Socket has been shut down";
+ break;
+ case WSAETOOMANYREFS:
+ p = "Too many references";
+ break;
+ case WSAETIMEDOUT:
+ p = "Timed out";
+ break;
+ case WSAECONNREFUSED:
+ p = "Connection refused";
+ break;
+ case WSAELOOP:
+ p = "Loop??";
+ break;
+ case WSAENAMETOOLONG:
+ p = "Name too long";
+ break;
+ case WSAEHOSTDOWN:
+ p = "Host down";
+ break;
+ case WSAEHOSTUNREACH:
+ p = "Host unreachable";
+ break;
+ case WSAENOTEMPTY:
+ p = "Not empty";
+ break;
+ case WSAEPROCLIM:
+ p = "Process limit reached";
+ break;
+ case WSAEUSERS:
+ p = "Too many users";
+ break;
+ case WSAEDQUOT:
+ p = "Bad quota";
+ break;
+ case WSAESTALE:
+ p = "Something is stale";
+ break;
+ case WSAEREMOTE:
+ p = "Remote error";
+ break;
+ case WSAEDISCON:
+ p = "Disconnected";
+ break;
+
+ /* Extended Winsock errors */
+ case WSASYSNOTREADY:
+ p = "Winsock library is not ready";
+ break;
+ case WSANOTINITIALISED:
+ p = "Winsock library not initalised";
+ break;
+ case WSAVERNOTSUPPORTED:
+ p = "Winsock version not supported.";
+ break;
+
+ /* getXbyY() errors (already handled in herrmsg):
+ * Authoritative Answer: Host not found */
+ case WSAHOST_NOT_FOUND:
+ p = "Host not found";
+ break;
+
+ /* Non-Authoritative: Host not found, or SERVERFAIL */
+ case WSATRY_AGAIN:
+ p = "Host not found, try again";
+ break;
+
+ /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */
+ case WSANO_RECOVERY:
+ p = "Unrecoverable error in call to nameserver";
+ break;
+
+ /* Valid name, no data record of requested type */
+ case WSANO_DATA:
+ p = "No data record of requested type";
+ break;
+
+ default:
+ return NULL;
+ }
+ strncpy (buf, p, len);
+ buf [len-1] = '\0';
+ return buf;
+}
+#endif /* WIN32 && !__CYGWIN__ */
+
+/*
+ * Our thread-safe and smart strerror() replacement.
+ *
+ * The 'err' argument passed in to this function MUST be a true errno number
+ * as reported on this system. We do no range checking on the number before
+ * we pass it to the "number-to-message" convertion function and there might
+ * be systems that don't do proper range checking in there themselves.
+ *
+ * We don't do range checking (on systems other than Windows) since there is
+ * no good reliable and portable way to do it.
+ */
+const char *Curl_strerror(struct connectdata *conn, int err)
+{
+ char *buf, *p;
+ size_t max;
+
+ curlassert(conn);
+ curlassert(err >= 0);
+
+ buf = conn->syserr_buf;
+ max = sizeof(conn->syserr_buf)-1;
+ *buf = '\0';
+
+#if defined(WIN32) && !defined(__CYGWIN__)
+ /* 'sys_nerr' is the maximum errno number, it is not widely portable */
+ if (err >= 0 && err < sys_nerr)
+ strncpy(buf, strerror(err), max);
+ else {
+ if (!get_winsock_error (err, buf, max) &&
+ !FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
+ LANG_NEUTRAL, buf, max, NULL))
+ snprintf(buf, max, "Unknown error %d (%#x)", err, err);
+ }
+#else /* not native Windows coming up */
+
+ /* These should be atomic and hopefully thread-safe */
+#ifdef HAVE_STRERROR_R
+ /* There are two different APIs for strerror_r(). The POSIX and the GLIBC
+ versions. */
+#ifdef HAVE_POSIX_STRERROR_R
+ strerror_r(err, buf, max);
+ /* this may set errno to ERANGE if insufficient storage was supplied via
+ 'strerrbuf' and 'buflen' to contain the generated message string, or
+ EINVAL if the value of 'errnum' is not a valid error number.*/
+#else
+ {
+ /* HAVE_GLIBC_STRERROR_R */
+ char buffer[256];
+ char *msg = strerror_r(err, buffer, sizeof(buffer));
+ /* this version of strerror_r() only *might* use the buffer we pass to
+ the function, but it always returns the error message as a pointer,
+ so we must copy that string unconditionally */
+ strncpy(buf, msg, max);
+ }
+#endif /* end of HAVE_GLIBC_STRERROR_R */
+#else /* HAVE_STRERROR_R */
+ strncpy(buf, strerror(err), max);
+#endif /* end of HAVE_STRERROR_R */
+#endif /* end of ! Windows */
+
+ buf[max] = '\0'; /* make sure the string is zero terminated */
+
+ /* strip trailing '\r\n' or '\n'. */
+ if ((p = strrchr(buf,'\n')) != NULL && (p - buf) >= 2)
+ *p = '\0';
+ if ((p = strrchr(buf,'\r')) != NULL && (p - buf) >= 1)
+ *p = '\0';
+ return buf;
+}
diff --git a/Source/CTest/Curl/strerror.h b/Source/CTest/Curl/strerror.h
new file mode 100644
index 0000000..7d68723
--- /dev/null
+++ b/Source/CTest/Curl/strerror.h
@@ -0,0 +1,30 @@
+#ifndef __CURL_STRERROR_H
+#define __CURL_STRERROR_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "urldata.h"
+
+const char *Curl_strerror (struct connectdata *conn, int err);
+
+#endif
diff --git a/Source/CTest/Curl/strtok.c b/Source/CTest/Curl/strtok.c
index 42ac1d8..630e4e0 100644
--- a/Source/CTest/Curl/strtok.c
+++ b/Source/CTest/Curl/strtok.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -27,6 +27,8 @@
#include <stddef.h>
#include <string.h>
+#include "strtok.h"
+
char *
Curl_strtok_r(char *ptr, const char *sep, char **end)
{
@@ -64,11 +66,3 @@ Curl_strtok_r(char *ptr, const char *sep, char **end)
}
#endif /* this was only compiled if strtok_r wasn't present */
-
-/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
- */
diff --git a/Source/CTest/Curl/strtok.h b/Source/CTest/Curl/strtok.h
index 242319a..cf9fac8 100644
--- a/Source/CTest/Curl/strtok.h
+++ b/Source/CTest/Curl/strtok.h
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
diff --git a/Source/CTest/Curl/strtoofft.c b/Source/CTest/Curl/strtoofft.c
new file mode 100644
index 0000000..1bcfb1a
--- /dev/null
+++ b/Source/CTest/Curl/strtoofft.c
@@ -0,0 +1,157 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+#include "strtoofft.h"
+
+#ifdef NEED_CURL_STRTOLL
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+
+static int get_char(char c, int base);
+
+/**
+ * Emulated version of the strtoll function. This extracts a long long
+ * value from the given input string and returns it.
+ */
+curl_off_t
+curlx_strtoll(const char *nptr, char **endptr, int base)
+{
+ char *end;
+ int is_negative = 0;
+ int overflow;
+ int i;
+ curl_off_t value = 0;
+ curl_off_t newval;
+
+ /* Skip leading whitespace. */
+ end = (char *)nptr;
+ while (isspace((int)end[0])) {
+ end++;
+ }
+
+ /* Handle the sign, if any. */
+ if (end[0] == '-') {
+ is_negative = 1;
+ end++;
+ }
+ else if (end[0] == '+') {
+ end++;
+ }
+ else if (end[0] == '\0') {
+ /* We had nothing but perhaps some whitespace -- there was no number. */
+ if (endptr) {
+ *endptr = end;
+ }
+ return 0;
+ }
+
+ /* Handle special beginnings, if present and allowed. */
+ if (end[0] == '0' && end[1] == 'x') {
+ if (base == 16 || base == 0) {
+ end += 2;
+ base = 16;
+ }
+ }
+ else if (end[0] == '0') {
+ if (base == 8 || base == 0) {
+ end++;
+ base = 8;
+ }
+ }
+
+ /* Matching strtol, if the base is 0 and it doesn't look like
+ * the number is octal or hex, we assume it's base 10.
+ */
+ if (base == 0) {
+ base = 10;
+ }
+
+ /* Loop handling digits. */
+ value = 0;
+ overflow = 0;
+ for (i = get_char(end[0], base);
+ i != -1;
+ end++, i = get_char(end[0], base)) {
+ newval = base * value + i;
+ if (newval < value) {
+ /* We've overflowed. */
+ overflow = 1;
+ break;
+ }
+ else
+ value = newval;
+ }
+
+ if (!overflow) {
+ if (is_negative) {
+ /* Fix the sign. */
+ value *= -1;
+ }
+ }
+ else {
+ if (is_negative)
+ value = 0x8000000000000000L;
+ else
+ value = 0x7FFFFFFFFFFFFFFFL;
+
+ errno = ERANGE;
+ }
+
+ if (endptr)
+ *endptr = end;
+
+ return value;
+}
+
+/**
+ * Returns the value of c in the given base, or -1 if c cannot
+ * be interpreted properly in that base (i.e., is out of range,
+ * is a null, etc.).
+ *
+ * @param c the character to interpret according to base
+ * @param base the base in which to interpret c
+ *
+ * @return the value of c in base, or -1 if c isn't in range
+ */
+static int get_char(char c, int base)
+{
+ int value = -1;
+ if (c <= '9' && c >= '0') {
+ value = c - '0';
+ }
+ else if (c <= 'Z' && c >= 'A') {
+ value = c - 'A' + 10;
+ }
+ else if (c <= 'z' && c >= 'a') {
+ value = c - 'a' + 10;
+ }
+
+ if (value >= base) {
+ value = -1;
+ }
+
+ return value;
+}
+#endif /* Only present if we need strtoll, but don't have it. */
diff --git a/Source/CTest/Curl/strtoofft.h b/Source/CTest/Curl/strtoofft.h
new file mode 100644
index 0000000..4c5d265
--- /dev/null
+++ b/Source/CTest/Curl/strtoofft.h
@@ -0,0 +1,62 @@
+#ifndef _CURL_STRTOOFFT_H
+#define _CURL_STRTOOFFT_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+/*
+ * CAUTION: this header is designed to work when included by the app-side
+ * as well as the library. Do not mix with library internals!
+ */
+
+#include "setup.h"
+#include <stddef.h>
+#include <curl/curl.h> /* for the curl_off_t type */
+
+/* Determine what type of file offset conversion handling we wish to use. For
+ * systems with a 32-bit curl_off_t type, we should use strtol. For systems
+ * with a 64-bit curl_off_t type, we should use strtoll if it exists, and if
+ * not, should try to emulate its functionality. At any rate, we define
+ * 'strtoofft' such that it can be used to work with curl_off_t's regardless.
+ */
+#if SIZEOF_CURL_OFF_T > 4
+#if HAVE_STRTOLL
+#define curlx_strtoofft strtoll
+#else /* HAVE_STRTOLL */
+
+/* For MSVC7 we can use _strtoi64() which seems to be a strtoll() clone */
+#if defined(_MSC_VER) && (_MSC_VER >= 1300)
+#define curlx_strtoofft _strtoi64
+#else /* MSVC7 or later */
+curl_off_t curlx_strtoll(const char *nptr, char **endptr, int base);
+#define curlx_strtoofft curlx_strtoll
+#define NEED_CURL_STRTOLL
+#endif /* MSVC7 or later */
+
+#endif /* HAVE_STRTOLL */
+#else /* SIZEOF_CURL_OFF_T > 4 */
+/* simply use strtol() to get 32bit numbers */
+#define curlx_strtoofft strtol
+#endif
+
+#endif
+
diff --git a/Source/CTest/Curl/telnet.c b/Source/CTest/Curl/telnet.c
index ef1b828..b0f74bb 100644
--- a/Source/CTest/Curl/telnet.c
+++ b/Source/CTest/Curl/telnet.c
@@ -1,16 +1,16 @@
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -35,23 +35,15 @@
#include <errno.h>
-#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
-#ifdef _MSC_VER
-#pragma warning (push,1)
-#endif
-#include <winsock2.h>
+#if defined(WIN32)
#include <time.h>
#include <io.h>
-#ifdef _MSC_VER
-#pragma warning (pop)
-#endif
#else
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#include <netinet/in.h>
#include <sys/time.h>
-#include <sys/resource.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
@@ -80,6 +72,7 @@
#include <curl/curl.h>
#include "transfer.h"
#include "sendf.h"
+#include "telnet.h"
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
@@ -88,29 +81,34 @@
#define TELCMDS
#include "arpa_telnet.h"
+#include "memory.h"
/* The last #include file should be: */
-#ifdef MALLOCDEBUG
#include "memdebug.h"
-#endif
#define SUBBUFSIZE 512
-#define SB_CLEAR(x) x->subpointer = x->subbuffer;
-#define SB_TERM(x) { x->subend = x->subpointer; SB_CLEAR(x); }
-#define SB_ACCUM(x,c) if (x->subpointer < (x->subbuffer+sizeof x->subbuffer)) { \
- *x->subpointer++ = (char)(c); \
- }
+#define CURL_SB_CLEAR(x) x->subpointer = x->subbuffer;
+#define CURL_SB_TERM(x) { x->subend = x->subpointer; CURL_SB_CLEAR(x); }
+#define CURL_SB_ACCUM(x,c) \
+ if (x->subpointer < (x->subbuffer+sizeof x->subbuffer)) { \
+ *x->subpointer++ = (c); \
+ }
-#define SB_GET(x) ((*x->subpointer++)&0xff)
-#define SB_PEEK(x) ((*x->subpointer)&0xff)
-#define SB_EOF(x) (x->subpointer >= x->subend)
-#define SB_LEN(x) (x->subend - x->subpointer)
+#define CURL_SB_GET(x) ((*x->subpointer++)&0xff)
+#define CURL_SB_PEEK(x) ((*x->subpointer)&0xff)
+#define CURL_SB_EOF(x) (x->subpointer >= x->subend)
+#define CURL_SB_LEN(x) (x->subend - x->subpointer)
+
+#ifdef WIN32
+typedef FARPROC WSOCK2_FUNC;
+static CURLcode check_wsock2 ( struct SessionHandle *data );
+#endif
static
void telrcv(struct connectdata *,
unsigned char *inbuf, /* Data received from socket */
- int count); /* Number of bytes received */
+ ssize_t count); /* Number of bytes received */
static void printoption(struct SessionHandle *data,
const char *direction,
@@ -122,43 +120,44 @@ static void set_local_option(struct connectdata *, int cmd, int option);
static void set_remote_option(struct connectdata *, int cmd, int option);
static void printsub(struct SessionHandle *data,
- int direction, unsigned char *pointer, int length);
+ int direction, unsigned char *pointer,
+ size_t length);
static void suboption(struct connectdata *);
/* For negotiation compliant to RFC 1143 */
-#define NO 0
-#define YES 1
-#define WANTYES 2
-#define WANTNO 3
+#define CURL_NO 0
+#define CURL_YES 1
+#define CURL_WANTYES 2
+#define CURL_WANTNO 3
-#define EMPTY 0
-#define OPPOSITE 1
+#define CURL_EMPTY 0
+#define CURL_OPPOSITE 1
/*
* Telnet receiver states for fsm
*/
typedef enum
{
- TS_DATA = 0,
- TS_IAC,
- TS_WILL,
- TS_WONT,
- TS_DO,
- TS_DONT,
- TS_CR,
- TS_SB, /* sub-option collection */
- TS_SE /* looking for sub-option end */
+ CURL_TS_DATA = 0,
+ CURL_TS_IAC,
+ CURL_TS_WILL,
+ CURL_TS_WONT,
+ CURL_TS_DO,
+ CURL_TS_DONT,
+ CURL_TS_CR,
+ CURL_TS_SB, /* sub-option collection */
+ CURL_TS_SE /* looking for sub-option end */
} TelnetReceive;
struct TELNET {
int please_negotiate;
int already_negotiated;
- int us[256];
- int usq[256];
- int us_preferred[256];
- int him[256];
- int himq[256];
- int him_preferred[256];
+ int us[256];
+ int usq[256];
+ int us_preferred[256];
+ int him[256];
+ int himq[256];
+ int him_preferred[256];
char subopt_ttype[32]; /* Set with suboption TTYPE */
char subopt_xdisploc[128]; /* Set with suboption XDISPLOC */
struct curl_slist *telnet_vars; /* Environment variables */
@@ -166,43 +165,70 @@ struct TELNET {
/* suboptions */
char subbuffer[SUBBUFSIZE];
char *subpointer, *subend; /* buffer for sub-options */
-
+
TelnetReceive telrcv_state;
};
+#ifdef WIN32
+static CURLcode
+check_wsock2 ( struct SessionHandle *data )
+{
+ int err;
+ WORD wVersionRequested;
+ WSADATA wsaData;
+
+ curlassert(data);
+
+ /* telnet requires at least WinSock 2.0 so ask for it. */
+ wVersionRequested = MAKEWORD(2, 0);
+
+ err = WSAStartup(wVersionRequested, &wsaData);
+
+ /* We must've called this once already, so this call */
+ /* should always succeed. But, just in case... */
+ if (err != 0) {
+ failf(data,"WSAStartup failed (%d)",err);
+ return CURLE_FAILED_INIT;
+ }
+
+ /* We have to have a WSACleanup call for every successful */
+ /* WSAStartup call. */
+ WSACleanup();
+
+ /* Check that our version is supported */
+ if (LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) ||
+ HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested)) {
+ /* Our version isn't supported */
+ failf(data,"insufficient winsock version to support "
+ "telnet");
+ return CURLE_FAILED_INIT;
+ }
+
+ /* Our version is supported */
+ return CURLE_OK;
+}
+#endif
static
CURLcode init_telnet(struct connectdata *conn)
{
struct TELNET *tn;
- tn = (struct TELNET *)malloc(sizeof(struct TELNET));
+ tn = (struct TELNET *)calloc(1, sizeof(struct TELNET));
if(!tn)
return CURLE_OUT_OF_MEMORY;
-
- conn->proto.telnet = (void *)tn; /* make us known */
- memset(tn, 0, sizeof(struct TELNET));
+ conn->proto.telnet = (void *)tn; /* make us known */
- tn->telrcv_state = TS_DATA;
+ tn->telrcv_state = CURL_TS_DATA;
/* Init suboptions */
- SB_CLEAR(tn);
-
- /* Set all options to NO */
-#if 0
- /* NO is zero => default fill pattern */
- memset(tn->us, NO, 256);
- memset(tn->usq, NO, 256);
- memset(tn->us_preferred, NO, 256);
- memset(tn->him, NO, 256);
- memset(tn->himq, NO, 256);
- memset(tn->him_preferred, NO, 256);
-#endif
+ CURL_SB_CLEAR(tn);
+
/* Set the options we want by default */
- tn->us_preferred[TELOPT_BINARY] = YES;
- tn->us_preferred[TELOPT_SGA] = YES;
- tn->him_preferred[TELOPT_BINARY] = YES;
- tn->him_preferred[TELOPT_SGA] = YES;
+ tn->us_preferred[CURL_TELOPT_BINARY] = CURL_YES;
+ tn->us_preferred[CURL_TELOPT_SGA] = CURL_YES;
+ tn->him_preferred[CURL_TELOPT_BINARY] = CURL_YES;
+ tn->him_preferred[CURL_TELOPT_SGA] = CURL_YES;
return CURLE_OK;
}
@@ -211,14 +237,14 @@ static void negotiate(struct connectdata *conn)
{
int i;
struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
-
- for(i = 0;i < NTELOPTS;i++)
+
+ for(i = 0;i < CURL_NTELOPTS;i++)
{
- if(tn->us_preferred[i] == YES)
- set_local_option(conn, i, YES);
-
- if(tn->him_preferred[i] == YES)
- set_remote_option(conn, i, YES);
+ if(tn->us_preferred[i] == CURL_YES)
+ set_local_option(conn, i, CURL_YES);
+
+ if(tn->him_preferred[i] == CURL_YES)
+ set_remote_option(conn, i, CURL_YES);
}
}
@@ -227,25 +253,25 @@ static void printoption(struct SessionHandle *data,
{
const char *fmt;
const char *opt;
-
+
if (data->set.verbose)
{
- if (cmd == IAC)
+ if (cmd == CURL_IAC)
{
- if (TELCMD_OK(option))
- Curl_infof(data, "%s IAC %s\n", direction, TELCMD(option));
+ if (CURL_TELCMD_OK(option))
+ Curl_infof(data, "%s IAC %s\n", direction, CURL_TELCMD(option));
else
Curl_infof(data, "%s IAC %d\n", direction, option);
}
else
{
- fmt = (cmd == WILL) ? "WILL" : (cmd == WONT) ? "WONT" :
- (cmd == DO) ? "DO" : (cmd == DONT) ? "DONT" : 0;
+ fmt = (cmd == CURL_WILL) ? "WILL" : (cmd == CURL_WONT) ? "WONT" :
+ (cmd == CURL_DO) ? "DO" : (cmd == CURL_DONT) ? "DONT" : 0;
if (fmt)
{
- if (TELOPT_OK(option))
- opt = TELOPT(option);
- else if (option == TELOPT_EXOPL)
+ if (CURL_TELOPT_OK(option))
+ opt = CURL_TELOPT(option);
+ else if (option == CURL_TELOPT_EXOPL)
opt = "EXOPL";
else
opt = NULL;
@@ -265,12 +291,12 @@ static void send_negotiation(struct connectdata *conn, int cmd, int option)
{
unsigned char buf[3];
- buf[0] = IAC;
- buf[1] = (unsigned char)cmd;
- buf[2] = (unsigned char)option;
-
- swrite(conn->firstsocket, (char*)buf, 3);
-
+ buf[0] = CURL_IAC;
+ buf[1] = cmd;
+ buf[2] = option;
+
+ (void)swrite(conn->sock[FIRSTSOCKET], buf, 3);
+
printoption(conn->data, "SENT", cmd, option);
}
@@ -278,40 +304,40 @@ static
void set_remote_option(struct connectdata *conn, int option, int newstate)
{
struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
- if(newstate == YES)
+ if(newstate == CURL_YES)
{
switch(tn->him[option])
{
- case NO:
- tn->him[option] = WANTYES;
- send_negotiation(conn, DO, option);
+ case CURL_NO:
+ tn->him[option] = CURL_WANTYES;
+ send_negotiation(conn, CURL_DO, option);
break;
-
- case YES:
+
+ case CURL_YES:
/* Already enabled */
break;
-
- case WANTNO:
+
+ case CURL_WANTNO:
switch(tn->himq[option])
{
- case EMPTY:
- /* Already negotiating for YES, queue the request */
- tn->himq[option] = OPPOSITE;
+ case CURL_EMPTY:
+ /* Already negotiating for CURL_YES, queue the request */
+ tn->himq[option] = CURL_OPPOSITE;
break;
- case OPPOSITE:
+ case CURL_OPPOSITE:
/* Error: already queued an enable request */
break;
}
break;
-
- case WANTYES:
+
+ case CURL_WANTYES:
switch(tn->himq[option])
{
- case EMPTY:
+ case CURL_EMPTY:
/* Error: already negotiating for enable */
break;
- case OPPOSITE:
- tn->himq[option] = EMPTY;
+ case CURL_OPPOSITE:
+ tn->himq[option] = CURL_EMPTY;
break;
}
break;
@@ -321,34 +347,34 @@ void set_remote_option(struct connectdata *conn, int option, int newstate)
{
switch(tn->him[option])
{
- case NO:
+ case CURL_NO:
/* Already disabled */
break;
-
- case YES:
- tn->him[option] = WANTNO;
- send_negotiation(conn, DONT, option);
+
+ case CURL_YES:
+ tn->him[option] = CURL_WANTNO;
+ send_negotiation(conn, CURL_DONT, option);
break;
-
- case WANTNO:
+
+ case CURL_WANTNO:
switch(tn->himq[option])
{
- case EMPTY:
+ case CURL_EMPTY:
/* Already negotiating for NO */
break;
- case OPPOSITE:
- tn->himq[option] = EMPTY;
+ case CURL_OPPOSITE:
+ tn->himq[option] = CURL_EMPTY;
break;
}
break;
-
- case WANTYES:
+
+ case CURL_WANTYES:
switch(tn->himq[option])
{
- case EMPTY:
- tn->himq[option] = OPPOSITE;
+ case CURL_EMPTY:
+ tn->himq[option] = CURL_OPPOSITE;
break;
- case OPPOSITE:
+ case CURL_OPPOSITE:
break;
}
break;
@@ -362,135 +388,136 @@ void rec_will(struct connectdata *conn, int option)
struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
switch(tn->him[option])
{
- case NO:
- if(tn->him_preferred[option] == YES)
+ case CURL_NO:
+ if(tn->him_preferred[option] == CURL_YES)
{
- tn->him[option] = YES;
- send_negotiation(conn, DO, option);
+ tn->him[option] = CURL_YES;
+ send_negotiation(conn, CURL_DO, option);
}
else
{
- send_negotiation(conn, DONT, option);
+ send_negotiation(conn, CURL_DONT, option);
}
break;
-
- case YES:
+
+ case CURL_YES:
/* Already enabled */
break;
-
- case WANTNO:
+
+ case CURL_WANTNO:
switch(tn->himq[option])
{
- case EMPTY:
+ case CURL_EMPTY:
/* Error: DONT answered by WILL */
- tn->him[option] = NO;
+ tn->him[option] = CURL_NO;
break;
- case OPPOSITE:
+ case CURL_OPPOSITE:
/* Error: DONT answered by WILL */
- tn->him[option] = YES;
- tn->himq[option] = EMPTY;
+ tn->him[option] = CURL_YES;
+ tn->himq[option] = CURL_EMPTY;
break;
}
break;
-
- case WANTYES:
+
+ case CURL_WANTYES:
switch(tn->himq[option])
{
- case EMPTY:
- tn->him[option] = YES;
+ case CURL_EMPTY:
+ tn->him[option] = CURL_YES;
break;
- case OPPOSITE:
- tn->him[option] = WANTNO;
- tn->himq[option] = EMPTY;
- send_negotiation(conn, DONT, option);
+ case CURL_OPPOSITE:
+ tn->him[option] = CURL_WANTNO;
+ tn->himq[option] = CURL_EMPTY;
+ send_negotiation(conn, CURL_DONT, option);
break;
}
break;
}
}
-
+
static
void rec_wont(struct connectdata *conn, int option)
{
struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
switch(tn->him[option])
{
- case NO:
+ case CURL_NO:
/* Already disabled */
break;
-
- case YES:
- tn->him[option] = NO;
- send_negotiation(conn, DONT, option);
+
+ case CURL_YES:
+ tn->him[option] = CURL_NO;
+ send_negotiation(conn, CURL_DONT, option);
break;
-
- case WANTNO:
+
+ case CURL_WANTNO:
switch(tn->himq[option])
{
- case EMPTY:
- tn->him[option] = NO;
+ case CURL_EMPTY:
+ tn->him[option] = CURL_NO;
break;
-
- case OPPOSITE:
- tn->him[option] = WANTYES;
- tn->himq[option] = EMPTY;
- send_negotiation(conn, DO, option);
+
+ case CURL_OPPOSITE:
+ tn->him[option] = CURL_WANTYES;
+ tn->himq[option] = CURL_EMPTY;
+ send_negotiation(conn, CURL_DO, option);
break;
}
break;
-
- case WANTYES:
+
+ case CURL_WANTYES:
switch(tn->himq[option])
{
- case EMPTY:
- tn->him[option] = NO;
+ case CURL_EMPTY:
+ tn->him[option] = CURL_NO;
break;
- case OPPOSITE:
- tn->him[option] = NO;
- tn->himq[option] = EMPTY;
+ case CURL_OPPOSITE:
+ tn->him[option] = CURL_NO;
+ tn->himq[option] = CURL_EMPTY;
break;
}
break;
}
}
-
-static void set_local_option(struct connectdata *conn, int option, int newstate)
+
+static void
+set_local_option(struct connectdata *conn, int option, int newstate)
{
struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
- if(newstate == YES)
+ if(newstate == CURL_YES)
{
switch(tn->us[option])
{
- case NO:
- tn->us[option] = WANTYES;
- send_negotiation(conn, WILL, option);
+ case CURL_NO:
+ tn->us[option] = CURL_WANTYES;
+ send_negotiation(conn, CURL_WILL, option);
break;
-
- case YES:
+
+ case CURL_YES:
/* Already enabled */
break;
-
- case WANTNO:
+
+ case CURL_WANTNO:
switch(tn->usq[option])
{
- case EMPTY:
- /* Already negotiating for YES, queue the request */
- tn->usq[option] = OPPOSITE;
+ case CURL_EMPTY:
+ /* Already negotiating for CURL_YES, queue the request */
+ tn->usq[option] = CURL_OPPOSITE;
break;
- case OPPOSITE:
+ case CURL_OPPOSITE:
/* Error: already queued an enable request */
break;
}
break;
-
- case WANTYES:
+
+ case CURL_WANTYES:
switch(tn->usq[option])
{
- case EMPTY:
+ case CURL_EMPTY:
/* Error: already negotiating for enable */
break;
- case OPPOSITE:
- tn->usq[option] = EMPTY;
+ case CURL_OPPOSITE:
+ tn->usq[option] = CURL_EMPTY;
break;
}
break;
@@ -500,34 +527,34 @@ static void set_local_option(struct connectdata *conn, int option, int newstate)
{
switch(tn->us[option])
{
- case NO:
+ case CURL_NO:
/* Already disabled */
break;
-
- case YES:
- tn->us[option] = WANTNO;
- send_negotiation(conn, WONT, option);
+
+ case CURL_YES:
+ tn->us[option] = CURL_WANTNO;
+ send_negotiation(conn, CURL_WONT, option);
break;
-
- case WANTNO:
+
+ case CURL_WANTNO:
switch(tn->usq[option])
{
- case EMPTY:
+ case CURL_EMPTY:
/* Already negotiating for NO */
break;
- case OPPOSITE:
- tn->usq[option] = EMPTY;
+ case CURL_OPPOSITE:
+ tn->usq[option] = CURL_EMPTY;
break;
}
break;
-
- case WANTYES:
+
+ case CURL_WANTYES:
switch(tn->usq[option])
{
- case EMPTY:
- tn->usq[option] = OPPOSITE;
+ case CURL_EMPTY:
+ tn->usq[option] = CURL_OPPOSITE;
break;
- case OPPOSITE:
+ case CURL_OPPOSITE:
break;
}
break;
@@ -541,92 +568,92 @@ void rec_do(struct connectdata *conn, int option)
struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
switch(tn->us[option])
{
- case NO:
- if(tn->us_preferred[option] == YES)
+ case CURL_NO:
+ if(tn->us_preferred[option] == CURL_YES)
{
- tn->us[option] = YES;
- send_negotiation(conn, WILL, option);
+ tn->us[option] = CURL_YES;
+ send_negotiation(conn, CURL_WILL, option);
}
else
{
- send_negotiation(conn, WONT, option);
+ send_negotiation(conn, CURL_WONT, option);
}
break;
-
- case YES:
+
+ case CURL_YES:
/* Already enabled */
break;
-
- case WANTNO:
+
+ case CURL_WANTNO:
switch(tn->usq[option])
{
- case EMPTY:
+ case CURL_EMPTY:
/* Error: DONT answered by WILL */
- tn->us[option] = NO;
+ tn->us[option] = CURL_NO;
break;
- case OPPOSITE:
+ case CURL_OPPOSITE:
/* Error: DONT answered by WILL */
- tn->us[option] = YES;
- tn->usq[option] = EMPTY;
+ tn->us[option] = CURL_YES;
+ tn->usq[option] = CURL_EMPTY;
break;
}
break;
-
- case WANTYES:
+
+ case CURL_WANTYES:
switch(tn->usq[option])
{
- case EMPTY:
- tn->us[option] = YES;
+ case CURL_EMPTY:
+ tn->us[option] = CURL_YES;
break;
- case OPPOSITE:
- tn->us[option] = WANTNO;
- tn->himq[option] = EMPTY;
- send_negotiation(conn, WONT, option);
+ case CURL_OPPOSITE:
+ tn->us[option] = CURL_WANTNO;
+ tn->himq[option] = CURL_EMPTY;
+ send_negotiation(conn, CURL_WONT, option);
break;
}
break;
}
}
-static
+static
void rec_dont(struct connectdata *conn, int option)
{
struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
switch(tn->us[option])
{
- case NO:
+ case CURL_NO:
/* Already disabled */
break;
-
- case YES:
- tn->us[option] = NO;
- send_negotiation(conn, WONT, option);
+
+ case CURL_YES:
+ tn->us[option] = CURL_NO;
+ send_negotiation(conn, CURL_WONT, option);
break;
-
- case WANTNO:
+
+ case CURL_WANTNO:
switch(tn->usq[option])
{
- case EMPTY:
- tn->us[option] = NO;
+ case CURL_EMPTY:
+ tn->us[option] = CURL_NO;
break;
-
- case OPPOSITE:
- tn->us[option] = WANTYES;
- tn->usq[option] = EMPTY;
- send_negotiation(conn, WILL, option);
+
+ case CURL_OPPOSITE:
+ tn->us[option] = CURL_WANTYES;
+ tn->usq[option] = CURL_EMPTY;
+ send_negotiation(conn, CURL_WILL, option);
break;
}
break;
-
- case WANTYES:
+
+ case CURL_WANTYES:
switch(tn->usq[option])
{
- case EMPTY:
- tn->us[option] = NO;
+ case CURL_EMPTY:
+ tn->us[option] = CURL_NO;
break;
- case OPPOSITE:
- tn->us[option] = NO;
- tn->usq[option] = EMPTY;
+ case CURL_OPPOSITE:
+ tn->us[option] = CURL_NO;
+ tn->usq[option] = CURL_EMPTY;
break;
}
break;
@@ -637,9 +664,9 @@ void rec_dont(struct connectdata *conn, int option)
static void printsub(struct SessionHandle *data,
int direction, /* '<' or '>' */
unsigned char *pointer, /* where suboption data is */
- int length) /* length of suboption data */
+ size_t length) /* length of suboption data */
{
- int i = 0;
+ unsigned int i = 0;
if (data->set.verbose)
{
@@ -653,19 +680,19 @@ static void printsub(struct SessionHandle *data,
i = pointer[length-2];
j = pointer[length-1];
- if (i != IAC || j != SE)
+ if (i != CURL_IAC || j != CURL_SE)
{
Curl_infof(data, "(terminated by ");
- if (TELOPT_OK(i))
- Curl_infof(data, "%s ", TELOPT(i));
- else if (TELCMD_OK(i))
- Curl_infof(data, "%s ", TELCMD(i));
+ if (CURL_TELOPT_OK(i))
+ Curl_infof(data, "%s ", CURL_TELOPT(i));
+ else if (CURL_TELCMD_OK(i))
+ Curl_infof(data, "%s ", CURL_TELCMD(i));
else
Curl_infof(data, "%d ", i);
- if (TELOPT_OK(j))
- Curl_infof(data, "%s", TELOPT(j));
- else if (TELCMD_OK(j))
- Curl_infof(data, "%s", TELCMD(j));
+ if (CURL_TELOPT_OK(j))
+ Curl_infof(data, "%s", CURL_TELOPT(j));
+ else if (CURL_TELCMD_OK(j))
+ Curl_infof(data, "%s", CURL_TELCMD(j));
else
Curl_infof(data, "%d", j);
Curl_infof(data, ", not IAC SE!) ");
@@ -679,15 +706,15 @@ static void printsub(struct SessionHandle *data,
return;
}
- if (TELOPT_OK(pointer[0])) {
+ if (CURL_TELOPT_OK(pointer[0])) {
switch(pointer[0]) {
- case TELOPT_TTYPE:
- case TELOPT_XDISPLOC:
- case TELOPT_NEW_ENVIRON:
- Curl_infof(data, "%s", TELOPT(pointer[0]));
+ case CURL_TELOPT_TTYPE:
+ case CURL_TELOPT_XDISPLOC:
+ case CURL_TELOPT_NEW_ENVIRON:
+ Curl_infof(data, "%s", CURL_TELOPT(pointer[0]));
break;
default:
- Curl_infof(data, "%s (unsupported)", TELOPT(pointer[0]));
+ Curl_infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0]));
break;
}
}
@@ -695,35 +722,35 @@ static void printsub(struct SessionHandle *data,
Curl_infof(data, "%d (unknown)", pointer[i]);
switch(pointer[1]) {
- case TELQUAL_IS:
+ case CURL_TELQUAL_IS:
Curl_infof(data, " IS");
break;
- case TELQUAL_SEND:
+ case CURL_TELQUAL_SEND:
Curl_infof(data, " SEND");
break;
- case TELQUAL_INFO:
+ case CURL_TELQUAL_INFO:
Curl_infof(data, " INFO/REPLY");
break;
- case TELQUAL_NAME:
+ case CURL_TELQUAL_NAME:
Curl_infof(data, " NAME");
break;
}
-
+
switch(pointer[0]) {
- case TELOPT_TTYPE:
- case TELOPT_XDISPLOC:
+ case CURL_TELOPT_TTYPE:
+ case CURL_TELOPT_XDISPLOC:
pointer[length] = 0;
Curl_infof(data, " \"%s\"", &pointer[2]);
break;
- case TELOPT_NEW_ENVIRON:
- if(pointer[1] == TELQUAL_IS) {
+ case CURL_TELOPT_NEW_ENVIRON:
+ if(pointer[1] == CURL_TELQUAL_IS) {
Curl_infof(data, " ");
for(i = 3;i < length;i++) {
switch(pointer[i]) {
- case NEW_ENV_VAR:
+ case CURL_NEW_ENV_VAR:
Curl_infof(data, ", ");
break;
- case NEW_ENV_VALUE:
+ case CURL_NEW_ENV_VALUE:
Curl_infof(data, " = ");
break;
default:
@@ -738,7 +765,7 @@ static void printsub(struct SessionHandle *data,
Curl_infof(data, " %.2x", pointer[i]);
break;
}
-
+
if (direction)
{
Curl_infof(data, "\n");
@@ -746,7 +773,7 @@ static void printsub(struct SessionHandle *data,
}
}
-static int check_telnet_options(struct connectdata *conn)
+static CURLcode check_telnet_options(struct connectdata *conn)
{
struct curl_slist *head;
char option_keyword[128];
@@ -759,11 +786,10 @@ static int check_telnet_options(struct connectdata *conn)
was given on the command line */
if(conn->bits.user_passwd)
{
- char *buf = malloc(256);
- sprintf(buf, "USER,%s", data->state.user);
- tn->telnet_vars = curl_slist_append(tn->telnet_vars, buf);
+ snprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user);
+ tn->telnet_vars = curl_slist_append(tn->telnet_vars, option_arg);
- tn->us_preferred[TELOPT_NEW_ENVIRON] = YES;
+ tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
}
for(head = data->set.telnet_options; head; head=head->next) {
@@ -771,28 +797,28 @@ static int check_telnet_options(struct connectdata *conn)
option_keyword, option_arg) == 2) {
/* Terminal type */
- if(strequal(option_keyword, "TTYPE")) {
+ if(curl_strequal(option_keyword, "TTYPE")) {
strncpy(tn->subopt_ttype, option_arg, 31);
tn->subopt_ttype[31] = 0; /* String termination */
- tn->us_preferred[TELOPT_TTYPE] = YES;
+ tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
continue;
}
/* Display variable */
- if(strequal(option_keyword, "XDISPLOC")) {
+ if(curl_strequal(option_keyword, "XDISPLOC")) {
strncpy(tn->subopt_xdisploc, option_arg, 127);
tn->subopt_xdisploc[127] = 0; /* String termination */
- tn->us_preferred[TELOPT_XDISPLOC] = YES;
+ tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
continue;
}
/* Environment variable */
- if(strequal(option_keyword, "NEW_ENV")) {
+ if(curl_strequal(option_keyword, "NEW_ENV")) {
buf = strdup(option_arg);
if(!buf)
return CURLE_OUT_OF_MEMORY;
tn->telnet_vars = curl_slist_append(tn->telnet_vars, buf);
- tn->us_preferred[TELOPT_NEW_ENVIRON] = YES;
+ tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
continue;
}
@@ -817,78 +843,77 @@ static int check_telnet_options(struct connectdata *conn)
static void suboption(struct connectdata *conn)
{
struct curl_slist *v;
- unsigned char subchar;
unsigned char temp[2048];
- int len;
- int tmplen;
+ size_t len;
+ size_t tmplen;
char varname[128];
char varval[128];
struct SessionHandle *data = conn->data;
struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
- printsub(data, '<', (unsigned char *)tn->subbuffer, (int)SB_LEN(tn)+2);
- switch (subchar = (unsigned char)SB_GET(tn)) {
- case TELOPT_TTYPE:
- len = (int)strlen(tn->subopt_ttype) + 4 + 2;
+ printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn)+2);
+ switch (CURL_SB_GET(tn)) {
+ case CURL_TELOPT_TTYPE:
+ len = strlen(tn->subopt_ttype) + 4 + 2;
snprintf((char *)temp, sizeof(temp),
- "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
- TELQUAL_IS, tn->subopt_ttype, IAC, SE);
- swrite(conn->firstsocket, (char*)temp, len);
+ "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE,
+ CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE);
+ (void)swrite(conn->sock[FIRSTSOCKET], temp, len);
printsub(data, '>', &temp[2], len-2);
break;
- case TELOPT_XDISPLOC:
- len = (int)strlen(tn->subopt_xdisploc) + 4 + 2;
+ case CURL_TELOPT_XDISPLOC:
+ len = strlen(tn->subopt_xdisploc) + 4 + 2;
snprintf((char *)temp, sizeof(temp),
- "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC,
- TELQUAL_IS, tn->subopt_xdisploc, IAC, SE);
- swrite(conn->firstsocket, (char*)temp, len);
+ "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC,
+ CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE);
+ (void)swrite(conn->sock[FIRSTSOCKET], temp, len);
printsub(data, '>', &temp[2], len-2);
break;
- case TELOPT_NEW_ENVIRON:
+ case CURL_TELOPT_NEW_ENVIRON:
snprintf((char *)temp, sizeof(temp),
- "%c%c%c%c", IAC, SB, TELOPT_NEW_ENVIRON, TELQUAL_IS);
+ "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON,
+ CURL_TELQUAL_IS);
len = 4;
for(v = tn->telnet_vars;v;v = v->next) {
- tmplen = (int)(strlen(v->data) + 1);
+ tmplen = (strlen(v->data) + 1);
/* Add the variable only if it fits */
if(len + tmplen < (int)sizeof(temp)-6) {
- sscanf(v->data, "%127[^,],%s", varname, varval);
+ sscanf(v->data, "%127[^,],%127s", varname, varval);
snprintf((char *)&temp[len], sizeof(temp) - len,
- "%c%s%c%s", NEW_ENV_VAR, varname,
- NEW_ENV_VALUE, varval);
+ "%c%s%c%s", CURL_NEW_ENV_VAR, varname,
+ CURL_NEW_ENV_VALUE, varval);
len += tmplen;
}
}
snprintf((char *)&temp[len], sizeof(temp) - len,
- "%c%c", IAC, SE);
+ "%c%c", CURL_IAC, CURL_SE);
len += 2;
- swrite(conn->firstsocket, (char*)temp, len);
+ (void)swrite(conn->sock[FIRSTSOCKET], temp, len);
printsub(data, '>', &temp[2], len-2);
break;
}
- (void)subchar;
return;
}
static
void telrcv(struct connectdata *conn,
unsigned char *inbuf, /* Data received from socket */
- int count) /* Number of bytes received */
+ ssize_t count) /* Number of bytes received */
{
unsigned char c;
- int index = 0;
+ int in = 0;
struct SessionHandle *data = conn->data;
struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
while(count--)
{
- c = inbuf[index++];
+ c = inbuf[in++];
switch (tn->telrcv_state)
{
- case TS_CR:
- tn->telrcv_state = TS_DATA;
+ case CURL_TS_CR:
+ tn->telrcv_state = CURL_TS_DATA;
if (c == '\0')
{
break; /* Ignore \0 after CR */
@@ -897,96 +922,96 @@ void telrcv(struct connectdata *conn,
Curl_client_write(data, CLIENTWRITE_BODY, (char *)&c, 1);
continue;
- case TS_DATA:
- if (c == IAC)
+ case CURL_TS_DATA:
+ if (c == CURL_IAC)
{
- tn->telrcv_state = TS_IAC;
+ tn->telrcv_state = CURL_TS_IAC;
break;
}
else if(c == '\r')
{
- tn->telrcv_state = TS_CR;
+ tn->telrcv_state = CURL_TS_CR;
}
Curl_client_write(data, CLIENTWRITE_BODY, (char *)&c, 1);
continue;
- case TS_IAC:
+ case CURL_TS_IAC:
process_iac:
switch (c)
{
- case WILL:
- tn->telrcv_state = TS_WILL;
+ case CURL_WILL:
+ tn->telrcv_state = CURL_TS_WILL;
continue;
- case WONT:
- tn->telrcv_state = TS_WONT;
+ case CURL_WONT:
+ tn->telrcv_state = CURL_TS_WONT;
continue;
- case DO:
- tn->telrcv_state = TS_DO;
+ case CURL_DO:
+ tn->telrcv_state = CURL_TS_DO;
continue;
- case DONT:
- tn->telrcv_state = TS_DONT;
+ case CURL_DONT:
+ tn->telrcv_state = CURL_TS_DONT;
continue;
- case SB:
- SB_CLEAR(tn);
- tn->telrcv_state = TS_SB;
+ case CURL_SB:
+ CURL_SB_CLEAR(tn);
+ tn->telrcv_state = CURL_TS_SB;
continue;
- case IAC:
+ case CURL_IAC:
Curl_client_write(data, CLIENTWRITE_BODY, (char *)&c, 1);
break;
- case DM:
- case NOP:
- case GA:
+ case CURL_DM:
+ case CURL_NOP:
+ case CURL_GA:
default:
- printoption(data, "RCVD", IAC, c);
+ printoption(data, "RCVD", CURL_IAC, c);
break;
}
- tn->telrcv_state = TS_DATA;
+ tn->telrcv_state = CURL_TS_DATA;
continue;
- case TS_WILL:
- printoption(data, "RCVD", WILL, c);
+ case CURL_TS_WILL:
+ printoption(data, "RCVD", CURL_WILL, c);
tn->please_negotiate = 1;
rec_will(conn, c);
- tn->telrcv_state = TS_DATA;
+ tn->telrcv_state = CURL_TS_DATA;
continue;
-
- case TS_WONT:
- printoption(data, "RCVD", WONT, c);
+
+ case CURL_TS_WONT:
+ printoption(data, "RCVD", CURL_WONT, c);
tn->please_negotiate = 1;
rec_wont(conn, c);
- tn->telrcv_state = TS_DATA;
+ tn->telrcv_state = CURL_TS_DATA;
continue;
-
- case TS_DO:
- printoption(data, "RCVD", DO, c);
+
+ case CURL_TS_DO:
+ printoption(data, "RCVD", CURL_DO, c);
tn->please_negotiate = 1;
rec_do(conn, c);
- tn->telrcv_state = TS_DATA;
+ tn->telrcv_state = CURL_TS_DATA;
continue;
-
- case TS_DONT:
- printoption(data, "RCVD", DONT, c);
+
+ case CURL_TS_DONT:
+ printoption(data, "RCVD", CURL_DONT, c);
tn->please_negotiate = 1;
rec_dont(conn, c);
- tn->telrcv_state = TS_DATA;
+ tn->telrcv_state = CURL_TS_DATA;
continue;
- case TS_SB:
- if (c == IAC)
+ case CURL_TS_SB:
+ if (c == CURL_IAC)
{
- tn->telrcv_state = TS_SE;
+ tn->telrcv_state = CURL_TS_SE;
}
else
{
- SB_ACCUM(tn,c);
+ CURL_SB_ACCUM(tn,c);
}
continue;
- case TS_SE:
- if (c != SE)
+ case CURL_TS_SE:
+ if (c != CURL_SE)
{
- if (c != IAC)
+ if (c != CURL_IAC)
{
/*
* This is an error. We only expect to get
@@ -1000,36 +1025,38 @@ void telrcv(struct connectdata *conn,
* we terminate the suboption, and process the
* partial suboption if we can.
*/
- SB_ACCUM(tn, (unsigned char)IAC);
- SB_ACCUM(tn, c);
+ CURL_SB_ACCUM(tn, (unsigned char)CURL_IAC);
+ CURL_SB_ACCUM(tn, c);
tn->subpointer -= 2;
- SB_TERM(tn);
-
- printoption(data, "In SUBOPTION processing, RCVD", IAC, c);
+ CURL_SB_TERM(tn);
+
+ printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c);
suboption(conn); /* handle sub-option */
- tn->telrcv_state = TS_IAC;
+ tn->telrcv_state = CURL_TS_IAC;
goto process_iac;
}
- SB_ACCUM(tn,c);
- tn->telrcv_state = TS_SB;
+ CURL_SB_ACCUM(tn,c);
+ tn->telrcv_state = CURL_TS_SB;
}
else
{
- SB_ACCUM(tn, (unsigned char)IAC);
- SB_ACCUM(tn, (unsigned char)SE);
+ CURL_SB_ACCUM(tn, (unsigned char)CURL_IAC);
+ CURL_SB_ACCUM(tn, (unsigned char)CURL_SE);
tn->subpointer -= 2;
- SB_TERM(tn);
+ CURL_SB_TERM(tn);
suboption(conn); /* handle sub-option */
- tn->telrcv_state = TS_DATA;
+ tn->telrcv_state = CURL_TS_DATA;
}
break;
}
}
}
-CURLcode Curl_telnet_done(struct connectdata *conn)
+CURLcode Curl_telnet_done(struct connectdata *conn, CURLcode status)
{
struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
+ (void)status; /* unused */
+
curl_slist_free_all(tn->telnet_vars);
free(conn->proto.telnet);
@@ -1042,25 +1069,29 @@ CURLcode Curl_telnet(struct connectdata *conn)
{
CURLcode code;
struct SessionHandle *data = conn->data;
- int sockfd = conn->firstsocket;
+ curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
#ifdef WIN32
+ HMODULE wsock2;
+ WSOCK2_FUNC close_event_func;
+ WSOCK2_FUNC create_event_func;
+ WSOCK2_FUNC event_select_func;
+ WSOCK2_FUNC enum_netevents_func;
WSAEVENT event_handle;
WSANETWORKEVENTS events;
HANDLE stdin_handle;
HANDLE objs[2];
+ DWORD obj_count;
+ DWORD wait_timeout;
DWORD waitret;
+ DWORD readfile_read;
#else
fd_set readfd;
fd_set keepfd;
#endif
+ ssize_t nread;
bool keepon = TRUE;
char *buf = data->state.buffer;
- ssize_t nread;
struct TELNET *tn;
- struct timeval now; /* current time */
- now.tv_sec = 0;
- now.tv_usec = 0;
- (void) now;
code = init_telnet(conn);
if(code)
@@ -1068,90 +1099,211 @@ CURLcode Curl_telnet(struct connectdata *conn)
tn = (struct TELNET *)conn->proto.telnet;
- code = (CURLcode)check_telnet_options(conn);
+ code = check_telnet_options(conn);
if(code)
return code;
#ifdef WIN32
+ /*
+ ** This functionality only works with WinSock >= 2.0. So,
+ ** make sure have it.
+ */
+ code = check_wsock2(data);
+ if (code)
+ return code;
+
+ /* OK, so we have WinSock 2.0. We need to dynamically */
+ /* load ws2_32.dll and get the function pointers we need. */
+ wsock2 = LoadLibrary("WS2_32.DLL");
+ if (wsock2 == NULL) {
+ failf(data,"failed to load WS2_32.DLL (%d)",GetLastError());
+ return CURLE_FAILED_INIT;
+ }
+
+ /* Grab a pointer to WSACreateEvent */
+ create_event_func = GetProcAddress(wsock2,"WSACreateEvent");
+ if (create_event_func == NULL) {
+ failf(data,"failed to find WSACreateEvent function (%d)",
+ GetLastError());
+ FreeLibrary(wsock2);
+ return CURLE_FAILED_INIT;
+ }
+
+ /* And WSACloseEvent */
+ close_event_func = GetProcAddress(wsock2,"WSACloseEvent");
+ if (create_event_func == NULL) {
+ failf(data,"failed to find WSACloseEvent function (%d)",
+ GetLastError());
+ FreeLibrary(wsock2);
+ return CURLE_FAILED_INIT;
+ }
+
+ /* And WSAEventSelect */
+ event_select_func = GetProcAddress(wsock2,"WSAEventSelect");
+ if (event_select_func == NULL) {
+ failf(data,"failed to find WSAEventSelect function (%d)",
+ GetLastError());
+ FreeLibrary(wsock2);
+ return CURLE_FAILED_INIT;
+ }
+
+ /* And WSAEnumNetworkEvents */
+ enum_netevents_func = GetProcAddress(wsock2,"WSAEnumNetworkEvents");
+ if (enum_netevents_func == NULL) {
+ failf(data,"failed to find WSAEnumNetworkEvents function (%d)",
+ GetLastError());
+ FreeLibrary(wsock2);
+ return CURLE_FAILED_INIT;
+ }
+
/* We want to wait for both stdin and the socket. Since
** the select() function in winsock only works on sockets
** we have to use the WaitForMultipleObjects() call.
*/
/* First, create a sockets event object */
- event_handle = WSACreateEvent();
+ event_handle = (WSAEVENT)create_event_func();
+ if (event_handle == WSA_INVALID_EVENT) {
+ failf(data,"WSACreateEvent failed (%d)",WSAGetLastError());
+ FreeLibrary(wsock2);
+ return CURLE_FAILED_INIT;
+ }
/* The get the Windows file handle for stdin */
stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
/* Create the list of objects to wait for */
- objs[0] = stdin_handle;
- objs[1] = event_handle;
+ objs[0] = event_handle;
+ objs[1] = stdin_handle;
/* Tell winsock what events we want to listen to */
- if(WSAEventSelect(sockfd, event_handle, FD_READ|FD_CLOSE) == SOCKET_ERROR) {
+ if(event_select_func(sockfd, event_handle, FD_READ|FD_CLOSE) == SOCKET_ERROR) {
+ close_event_func(event_handle);
+ FreeLibrary(wsock2);
return 0;
}
+ /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it,
+ else use the old WaitForMultipleObjects() way */
+ if(GetFileType(stdin_handle) == FILE_TYPE_PIPE) {
+ /* Don't wait for stdin_handle, just wait for event_handle */
+ obj_count = 1;
+ /* Check stdin_handle per 100 milliseconds */
+ wait_timeout = 100;
+ } else {
+ obj_count = 2;
+ wait_timeout = INFINITE;
+ }
+
/* Keep on listening and act on events */
while(keepon) {
- waitret = WaitForMultipleObjects(2, objs, FALSE, INFINITE);
- switch(waitret - WAIT_OBJECT_0)
+ waitret = WaitForMultipleObjects(obj_count, objs, FALSE, wait_timeout);
+ switch(waitret) {
+ case WAIT_TIMEOUT:
{
- case 0:
- {
- unsigned char outbuf[2];
- int out_count = 0;
- ssize_t bytes_written;
- char *buffer = buf;
-
- if(!ReadFile(stdin_handle, buf, 255, ((DWORD*)&nread), NULL)) {
+ unsigned char outbuf[2];
+ int out_count = 0;
+ ssize_t bytes_written;
+ char *buffer = buf;
+
+ for(;;) {
+ if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL, &readfile_read, NULL)) {
keepon = FALSE;
break;
}
-
+ nread = readfile_read;
+
+ if(!nread)
+ break;
+
+ if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
+ &readfile_read, NULL)) {
+ keepon = FALSE;
+ break;
+ }
+ nread = readfile_read;
+
while(nread--) {
outbuf[0] = *buffer++;
out_count = 1;
- if(outbuf[0] == IAC)
- outbuf[out_count++] = IAC;
-
- Curl_write(conn, conn->firstsocket, outbuf,
+ if(outbuf[0] == CURL_IAC)
+ outbuf[out_count++] = CURL_IAC;
+
+ Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf,
out_count, &bytes_written);
}
}
- break;
-
- case 1:
- if(WSAEnumNetworkEvents(sockfd, event_handle, &events)
- != SOCKET_ERROR)
- {
- if(events.lNetworkEvents & FD_READ)
- {
- /* This reallu OUGHT to check its return code. */
- Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
-
- telrcv(conn, (unsigned char *)buf, nread);
-
- fflush(stdout);
-
- /* Negotiate if the peer has started negotiating,
- otherwise don't. We don't want to speak telnet with
- non-telnet servers, like POP or SMTP. */
- if(tn->please_negotiate && !tn->already_negotiated) {
- negotiate(conn);
- tn->already_negotiated = 1;
- }
- }
-
- if(events.lNetworkEvents & FD_CLOSE)
- {
- keepon = FALSE;
+ }
+ break;
+
+ case WAIT_OBJECT_0 + 1:
+ {
+ unsigned char outbuf[2];
+ int out_count = 0;
+ ssize_t bytes_written;
+ char *buffer = buf;
+
+ if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
+ &readfile_read, NULL)) {
+ keepon = FALSE;
+ break;
+ }
+ nread = readfile_read;
+
+ while(nread--) {
+ outbuf[0] = *buffer++;
+ out_count = 1;
+ if(outbuf[0] == CURL_IAC)
+ outbuf[out_count++] = CURL_IAC;
+
+ Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf,
+ out_count, &bytes_written);
+ }
+ }
+ break;
+
+ case WAIT_OBJECT_0:
+ if(enum_netevents_func(sockfd, event_handle, &events)
+ != SOCKET_ERROR) {
+ if(events.lNetworkEvents & FD_READ) {
+ /* This reallu OUGHT to check its return code. */
+ (void)Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
+
+ telrcv(conn, (unsigned char *)buf, nread);
+
+ fflush(stdout);
+
+ /* Negotiate if the peer has started negotiating,
+ otherwise don't. We don't want to speak telnet with
+ non-telnet servers, like POP or SMTP. */
+ if(tn->please_negotiate && !tn->already_negotiated) {
+ negotiate(conn);
+ tn->already_negotiated = 1;
}
}
- break;
+
+ if(events.lNetworkEvents & FD_CLOSE) {
+ keepon = FALSE;
+ }
+ }
+ break;
}
}
+
+ /* We called WSACreateEvent, so call WSACloseEvent */
+ if (close_event_func(event_handle) == FALSE) {
+ infof(data,"WSACloseEvent failed (%d)",WSAGetLastError());
+ }
+
+ /* "Forget" pointers into the library we're about to free */
+ create_event_func = NULL;
+ close_event_func = NULL;
+ event_select_func = NULL;
+ enum_netevents_func = NULL;
+
+ /* We called LoadLibrary, so call FreeLibrary */
+ if (!FreeLibrary(wsock2))
+ infof(data,"FreeLibrary(wsock2) failed (%d)",GetLastError());
#else
FD_ZERO (&readfd); /* clear it */
FD_SET (sockfd, &readfd);
@@ -1178,23 +1330,23 @@ CURLcode Curl_telnet(struct connectdata *conn)
int out_count = 0;
ssize_t bytes_written;
char *buffer = buf;
-
+
nread = read(0, buf, 255);
while(nread--) {
outbuf[0] = *buffer++;
out_count = 1;
- if(outbuf[0] == IAC)
- outbuf[out_count++] = IAC;
-
- Curl_write(conn, conn->firstsocket, outbuf,
+ if(outbuf[0] == CURL_IAC)
+ outbuf[out_count++] = CURL_IAC;
+
+ Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf,
out_count, &bytes_written);
}
}
if(FD_ISSET(sockfd, &readfd)) {
/* This OUGHT to check the return code... */
- Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
+ (void)Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
/* if we receive 0 or less here, the server closed the connection and
we bail out from this! */
@@ -1215,6 +1367,7 @@ CURLcode Curl_telnet(struct connectdata *conn)
}
}
if(data->set.timeout) {
+ struct timeval now; /* current time */
now = Curl_tvnow();
if(Curl_tvdiff(now, conn->created)/1000 >= data->set.timeout) {
failf(data, "Time-out");
@@ -1229,12 +1382,4 @@ CURLcode Curl_telnet(struct connectdata *conn)
return code;
}
-
-/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
- */
#endif
diff --git a/Source/CTest/Curl/telnet.h b/Source/CTest/Curl/telnet.h
index a985517..86dd99b 100644
--- a/Source/CTest/Curl/telnet.h
+++ b/Source/CTest/Curl/telnet.h
@@ -8,7 +8,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -25,6 +25,6 @@
***************************************************************************/
#ifndef CURL_DISABLE_TELNET
CURLcode Curl_telnet(struct connectdata *conn);
-CURLcode Curl_telnet_done(struct connectdata *conn);
+CURLcode Curl_telnet_done(struct connectdata *conn, CURLcode);
#endif
#endif
diff --git a/Source/CTest/Curl/timeval.c b/Source/CTest/Curl/timeval.c
index 3f55deb..11f3d7a 100644
--- a/Source/CTest/Curl/timeval.c
+++ b/Source/CTest/Curl/timeval.c
@@ -1,16 +1,16 @@
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -21,17 +21,14 @@
* $Id$
***************************************************************************/
-#include "setup.h"
-#ifdef WIN32
-#include <windows.h>
-#endif
#include "timeval.h"
#ifndef HAVE_GETTIMEOFDAY
#ifdef WIN32
-int
-gettimeofday (struct timeval *tp, void *nothing)
+#include <mmsystem.h>
+
+static int gettimeofday(struct timeval *tp, void *nothing)
{
#ifdef WITHOUT_MM_LIB
SYSTEMTIME st;
@@ -65,45 +62,55 @@ gettimeofday (struct timeval *tp, void *nothing)
Usec = (Ticks - (Sec*1000))*1000;
tp->tv_sec = Sec;
tp->tv_usec = Usec;
-#endif
+#endif /* WITHOUT_MM_LIB */
(void)nothing;
- return 1;
+ return 0;
}
-#define HAVE_GETTIMEOFDAY
-#endif
-#endif
+#else /* WIN32 */
+/* non-win32 version of Curl_gettimeofday() */
+static int gettimeofday(struct timeval *tp, void *nothing)
+{
+ (void)nothing; /* we don't support specific time-zones */
+ tp->tv_sec = (long)time(NULL);
+ tp->tv_usec = 0;
+ return 0;
+}
+#endif /* WIN32 */
+#endif /* HAVE_GETTIMEOFDAY */
-struct timeval Curl_tvnow (void)
+/* Return the current time in a timeval struct */
+struct timeval curlx_tvnow(void)
{
- struct timeval now;
-#ifdef HAVE_GETTIMEOFDAY
- gettimeofday (&now, NULL);
-#else
- now.tv_sec = (long) time(NULL);
- now.tv_usec = 0;
-#endif
- return now;
+ struct timeval now;
+ (void)gettimeofday(&now, NULL);
+ return now;
}
/*
* Make sure that the first argument is the more recent time, as otherwise
* we'll get a weird negative time-diff back...
+ *
+ * Returns: the time difference in number of milliseconds.
*/
-long Curl_tvdiff (struct timeval newer, struct timeval older)
+long curlx_tvdiff(struct timeval newer, struct timeval older)
{
return (newer.tv_sec-older.tv_sec)*1000+
- (499+newer.tv_usec-older.tv_usec)/1000;
+ (newer.tv_usec-older.tv_usec)/1000;
}
-long Curl_tvlong (struct timeval t1)
+/*
+ * Same as curlx_tvdiff but with full usec resolution.
+ *
+ * Returns: the time difference in seconds with subsecond resolution.
+ */
+double curlx_tvdiff_secs(struct timeval newer, struct timeval older)
{
- return t1.tv_sec;
+ return (double)(newer.tv_sec-older.tv_sec)+
+ (double)(newer.tv_usec-older.tv_usec)/1000000.0;
}
-/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
- */
+/* return the number of seconds in the given input timeval struct */
+long Curl_tvlong(struct timeval t1)
+{
+ return t1.tv_sec;
+}
diff --git a/Source/CTest/Curl/timeval.h b/Source/CTest/Curl/timeval.h
index b5ef901..67b885a 100644
--- a/Source/CTest/Curl/timeval.h
+++ b/Source/CTest/Curl/timeval.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -23,18 +23,22 @@
* $Id$
***************************************************************************/
+/*
+ * CAUTION: this header is designed to work when included by the app-side
+ * as well as the library. Do not mix with library internals!
+ */
+
#include "setup.h"
#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
#include <time.h>
-#include <winsock.h>
#else
#include <sys/time.h>
#endif
-
#ifndef HAVE_GETTIMEOFDAY
-#if !defined(_WINSOCKAPI_) && !defined(__MINGW32__)
+#if !defined(_WINSOCKAPI_) && !defined(__MINGW32__) && !defined(_AMIGASF) && \
+ !defined(__LCC__)
struct timeval {
long tv_sec;
long tv_usec;
@@ -42,11 +46,29 @@ struct timeval {
#endif
#endif
-struct timeval Curl_tvnow (void);
+struct timeval curlx_tvnow(void);
+
+/*
+ * Make sure that the first argument (t1) is the more recent time and t2 is
+ * the older time, as otherwise you get a weird negative time-diff back...
+ *
+ * Returns: the time difference in number of milliseconds.
+ */
+long curlx_tvdiff(struct timeval t1, struct timeval t2);
+
+/*
+ * Same as curlx_tvdiff but with full usec resolution.
+ *
+ * Returns: the time difference in seconds with subsecond resolution.
+ */
+double curlx_tvdiff_secs(struct timeval t1, struct timeval t2);
-/* the diff is from now on returned in number of milliseconds! */
-long Curl_tvdiff (struct timeval t1, struct timeval t2);
+long Curl_tvlong(struct timeval t1);
-long Curl_tvlong (struct timeval t1);
+/* These two defines below exist to provide the older API for library
+ internals only. */
+#define Curl_tvnow() curlx_tvnow()
+#define Curl_tvdiff(x,y) curlx_tvdiff(x,y)
+#define Curl_tvdiff_secs(x,y) curlx_tvdiff_secs(x,y)
#endif
diff --git a/Source/CTest/Curl/transfer.c b/Source/CTest/Curl/transfer.c
index ca7731b..93df4c5 100644
--- a/Source/CTest/Curl/transfer.c
+++ b/Source/CTest/Curl/transfer.c
@@ -1,16 +1,16 @@
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -29,24 +29,27 @@
#include <stdarg.h>
#include <stdlib.h>
#include <ctype.h>
+#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
+#endif
#include <sys/stat.h>
#include <errno.h>
+#include "strtoofft.h"
#include "strequal.h"
#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
-#include <winsock.h>
#include <time.h>
#include <io.h>
#else
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
+#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
+#endif
#include <sys/time.h>
-#include <sys/resource.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
@@ -57,7 +60,9 @@
#ifdef HAVE_NET_IF_H
#include <net/if.h>
#endif
+#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
+#endif
#include <signal.h>
#ifdef HAVE_SYS_PARAM_H
@@ -79,34 +84,32 @@
#include "urldata.h"
#include <curl/curl.h>
-#include <curl/types.h>
#include "netrc.h"
-#include "content_encoding.h" /* content encoding support. 08/27/02 jhrg */
-
+#include "content_encoding.h"
#include "hostip.h"
#include "transfer.h"
#include "sendf.h"
#include "speedcheck.h"
-#include "getpass.h"
#include "progress.h"
#include "getdate.h"
#include "http.h"
#include "url.h"
#include "getinfo.h"
#include "ssluse.h"
+#include "http_digest.h"
+#include "http_ntlm.h"
+#include "http_negotiate.h"
+#include "share.h"
+#include "memory.h"
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
/* The last #include file should be: */
-#ifdef MALLOCDEBUG
#include "memdebug.h"
-#endif
-#ifndef min
-#define min(a, b) ((a) < (b) ? (a) : (b))
-#endif
+#define CURL_TIMEOUT_EXPECT_100 1000 /* counting ms here */
enum {
KEEP_NONE,
@@ -122,10 +125,10 @@ static struct timeval notimeout={0,0};
* This function will call the read callback to fill our buffer with data
* to upload.
*/
-static int fillbuffer(struct connectdata *conn,
- int bytes)
+CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp)
{
- int buffersize = bytes;
+ struct SessionHandle *data = conn->data;
+ size_t buffersize = (size_t)bytes;
int nread;
if(conn->bits.upload_chunky) {
@@ -133,10 +136,17 @@ static int fillbuffer(struct connectdata *conn,
buffersize -= (8 + 2 + 2); /* 32bit hex + CRLF + CRLF */
conn->upload_fromhere += 10; /* 32bit hex + CRLF */
}
-
+
+ /* this function returns a size_t, so we typecast to int to prevent warnings
+ with picky compilers */
nread = (int)conn->fread(conn->upload_fromhere, 1,
buffersize, conn->fread_in);
-
+
+ if(nread == CURL_READFUNC_ABORT) {
+ failf(data, "operation aborted by callback\n");
+ return CURLE_ABORTED_BY_CALLBACK;
+ }
+
if(!conn->bits.forbidchunk && conn->bits.upload_chunky) {
/* if chunked Transfer-Encoding */
char hexbuffer[11];
@@ -148,18 +158,21 @@ static int fillbuffer(struct connectdata *conn,
/* copy the prefix to the buffer */
memcpy(conn->upload_fromhere, hexbuffer, hexlen);
- if(nread>hexlen) {
- /* append CRLF to the data */
- memcpy(conn->upload_fromhere +
- nread, "\r\n", 2);
- nread+=2;
- }
- else {
+
+ /* always append CRLF to the data */
+ memcpy(conn->upload_fromhere + nread, "\r\n", 2);
+
+ if((nread - hexlen) == 0) {
/* mark this as done once this chunk is transfered */
conn->keep.upload_done = TRUE;
}
+
+ nread+=2; /* for the added CRLF */
}
- return nread;
+
+ *nreadp = nread;
+
+ return CURLE_OK;
}
/*
@@ -185,15 +198,20 @@ checkhttpprefix(struct SessionHandle *data,
return FALSE;
}
+
+/*
+ * Curl_readwrite() is the low-level function to be called when data is to
+ * be read and written to/from the connection.
+ */
CURLcode Curl_readwrite(struct connectdata *conn,
bool *done)
{
struct Curl_transfer_keeper *k = &conn->keep;
struct SessionHandle *data = conn->data;
- int result;
+ CURLcode result;
ssize_t nread; /* number of bytes read */
int didwhat=0;
-
+
/* These two are used only if no other select() or _fdset() have been
invoked before this. This typicly happens if you use the multi interface
and call curl_multi_perform() without calling curl_multi_fdset()
@@ -203,7 +221,8 @@ CURLcode Curl_readwrite(struct connectdata *conn,
fd_set *readfdp = k->readfdp;
fd_set *writefdp = k->writefdp;
-
+ curl_off_t contentlength;
+
if((k->keepon & KEEP_READ) && !readfdp) {
/* reading is requested, but no socket descriptor pointer was set */
FD_ZERO(&extrareadfd);
@@ -225,31 +244,39 @@ CURLcode Curl_readwrite(struct connectdata *conn,
do {
/* If we still have reading to do, we check if we have a readable
- socket. Sometimes the reafdp is NULL, it no fd_set was done using
+ socket. Sometimes the reafdp is NULL, if no fd_set was done using
the multi interface and then we can do nothing but to attempt a
read to be sure. */
if((k->keepon & KEEP_READ) &&
- (FD_ISSET(conn->sockfd, readfdp))) {
+ (!readfdp || FD_ISSET(conn->sockfd, readfdp))) {
- bool readdone = FALSE;
+ bool readdone = TRUE;
/* This is where we loop until we have read everything there is to
read or we get a EWOULDBLOCK */
do {
+ size_t buffersize = data->set.buffer_size?
+ data->set.buffer_size:BUFSIZE -1;
- /* read! */
- result = Curl_read(conn, conn->sockfd, k->buf,
- data->set.buffer_size?
- data->set.buffer_size:BUFSIZE -1,
- &nread);
+ /* receive data from the network! */
+ int readrc = Curl_read(conn, conn->sockfd, k->buf, buffersize, &nread);
- if(0>result)
+ /* subzero, this would've blocked */
+ if(0>readrc)
break; /* get out of loop */
+
+ /* get the CURLcode from the int */
+ result = (CURLcode)readrc;
+
if(result>0)
- return (CURLcode)result;
+ return result;
- if ((k->bytecount == 0) && (k->writebytecount == 0))
+ if ((k->bytecount == 0) && (k->writebytecount == 0)) {
Curl_pgrsTime(data, TIMER_STARTTRANSFER);
+ if(k->wait100_after_headers)
+ /* set time stamp to compare with when waiting for the 100 */
+ k->start100 = Curl_tvnow();
+ }
didwhat |= KEEP_READ;
@@ -271,20 +298,23 @@ CURLcode Curl_readwrite(struct connectdata *conn,
k->str = k->buf;
/* Since this is a two-state thing, we check if we are parsing
- headers at the moment or not. */
+ headers at the moment or not. */
if (k->header) {
/* we are in parse-the-header-mode */
bool stop_reading = FALSE;
/* header line within buffer loop */
do {
- int hbufp_index;
-
+ size_t hbufp_index;
+ size_t rest_length;
+ size_t full_length;
+ int writetype;
+
/* str_start is start of line within buf */
k->str_start = k->str;
-
+
k->end_ptr = strchr (k->str_start, '\n');
-
+
if (!k->end_ptr) {
/* Not a complete header line within buffer, append the data to
the end of the headerbuff. */
@@ -292,9 +322,9 @@ CURLcode Curl_readwrite(struct connectdata *conn,
if (k->hbuflen + nread >= data->state.headersize) {
/* We enlarge the header buffer as it is too small */
char *newbuff;
- long newsize=MAX((k->hbuflen+nread)*3/2,
- data->state.headersize*2);
- hbufp_index = (int)(k->hbufp - data->state.headerbuff);
+ size_t newsize=CURLMAX((k->hbuflen+nread)*3/2,
+ data->state.headersize*2);
+ hbufp_index = k->hbufp - data->state.headerbuff;
newbuff = (char *)realloc(data->state.headerbuff, newsize);
if(!newbuff) {
failf (data, "Failed to alloc memory for big header!");
@@ -317,27 +347,29 @@ CURLcode Curl_readwrite(struct connectdata *conn,
}
}
- break; /* read more and try again */
+ break; /* read more and try again */
}
- /* decrease the size of the remaining buffer */
- nread -= (int)((k->end_ptr - k->str)+1);
+ /* decrease the size of the remaining (supposed) header line */
+ rest_length = (k->end_ptr - k->str)+1;
+ nread -= rest_length;
k->str = k->end_ptr + 1; /* move past new line */
+ full_length = k->str - k->str_start;
+
/*
* We're about to copy a chunk of data to the end of the
* already received header. We make sure that the full string
- * fit in the allocated header buffer, or else we enlarge
+ * fit in the allocated header buffer, or else we enlarge
* it.
*/
- if (k->hbuflen + (k->str - k->str_start) >=
+ if (k->hbuflen + full_length >=
data->state.headersize) {
char *newbuff;
- long newsize=(long)MAX((k->hbuflen+
- (k->str-k->str_start))*3/2,
- data->state.headersize*2);
- hbufp_index = (int)(k->hbufp - data->state.headerbuff);
+ size_t newsize=CURLMAX((k->hbuflen+full_length)*3/2,
+ data->state.headersize*2);
+ hbufp_index = k->hbufp - data->state.headerbuff;
newbuff = (char *)realloc(data->state.headerbuff, newsize);
if(!newbuff) {
failf (data, "Failed to alloc memory for big header!");
@@ -349,13 +381,14 @@ CURLcode Curl_readwrite(struct connectdata *conn,
}
/* copy to end of line */
- strncpy (k->hbufp, k->str_start, k->str - k->str_start);
- k->hbufp += k->str - k->str_start;
- k->hbuflen += (int)(k->str - k->str_start);
+ strncpy (k->hbufp, k->str_start, full_length);
+ k->hbufp += full_length;
+ k->hbuflen += full_length;
*k->hbufp = 0;
-
+ k->end_ptr = k->hbufp;
+
k->p = data->state.headerbuff;
-
+
/****
* We now have a FULL header line that p points to
*****/
@@ -366,13 +399,20 @@ CURLcode Curl_readwrite(struct connectdata *conn,
!checkhttpprefix(data, data->state.headerbuff)) {
/* this is not the beginning of a HTTP first header line */
k->header = FALSE;
- k->badheader = HEADER_PARTHEADER;
+ if(nread)
+ /* since there's more, this is a partial bad header */
+ k->badheader = HEADER_PARTHEADER;
+ else {
+ /* this was all we read so its all a bad header */
+ k->badheader = HEADER_ALLBAD;
+ nread = (ssize_t)rest_length;
+ }
break;
}
}
if (('\n' == *k->p) || ('\r' == *k->p)) {
- int headerlen;
+ size_t headerlen;
/* Zero-length header line means end of headers! */
if ('\r' == *k->p)
@@ -382,9 +422,9 @@ CURLcode Curl_readwrite(struct connectdata *conn,
if(100 == k->httpcode) {
/*
- * we have made a HTTP PUT or POST and this is 1.1-lingo
+ * We have made a HTTP PUT or POST and this is 1.1-lingo
* that tells us that the server is OK with this and ready
- * to receive our stuff.
+ * to receive the data.
* However, we'll get more headers now so we must get
* back into the header-parsing state!
*/
@@ -414,23 +454,66 @@ CURLcode Curl_readwrite(struct connectdata *conn,
FD_ZERO(&k->wkeepfd);
}
+#ifndef CURL_DISABLE_HTTP
+ /*
+ * When all the headers have been parsed, see if we should give
+ * up and return an error.
+ */
+ if (Curl_http_should_fail(conn)) {
+ failf (data, "The requested URL returned error: %d",
+ k->httpcode);
+ return CURLE_HTTP_RETURNED_ERROR;
+ }
+#endif /* CURL_DISABLE_HTTP */
+
/* now, only output this if the header AND body are requested:
*/
- k->writetype = CLIENTWRITE_HEADER;
- if (data->set.http_include_header)
- k->writetype |= CLIENTWRITE_BODY;
+ writetype = CLIENTWRITE_HEADER;
+ if (data->set.include_header)
+ writetype |= CLIENTWRITE_BODY;
- headerlen = (int)(k->p - data->state.headerbuff);
+ headerlen = k->p - data->state.headerbuff;
- result = Curl_client_write(data, k->writetype,
+ result = Curl_client_write(data, writetype,
data->state.headerbuff,
headerlen);
if(result)
- return (CURLcode)result;
+ return result;
data->info.header_size += headerlen;
conn->headerbytecount += headerlen;
+ conn->deductheadercount =
+ (100 == k->httpcode)?conn->headerbytecount:0;
+
+ if (conn->resume_from &&
+ !k->content_range &&
+ (data->set.httpreq==HTTPREQ_GET)) {
+ if(k->httpcode == 416) {
+ /* "Requested Range Not Satisfiable" */
+ stop_reading = TRUE;
+ }
+ else {
+ /* we wanted to resume a download, although the server
+ * doesn't seem to support this and we did this with a GET
+ * (if it wasn't a GET we did a POST or PUT resume) */
+ failf (data, "HTTP server doesn't seem to support "
+ "byte ranges. Cannot resume.");
+ return CURLE_HTTP_RANGE_ERROR;
+ }
+ }
+#ifndef CURL_DISABLE_HTTP
+ if(!stop_reading) {
+ /* Curl_http_auth_act() checks what authentication methods
+ * that are available and decides which one (if any) to
+ * use. It will set 'newurl' if an auth metod was picked. */
+ result = Curl_http_auth_act(conn);
+
+ if(result)
+ return result;
+ }
+#endif /* CURL_DISABLE_HTTP */
+
if(!k->header) {
/*
* really end-of-headers.
@@ -438,21 +521,39 @@ CURLcode Curl_readwrite(struct connectdata *conn,
* If we requested a "no body", this is a good time to get
* out and return home.
*/
- if(data->set.no_body)
+ if(conn->bits.no_body)
stop_reading = TRUE;
- else if(!conn->bits.close) {
- /* If this is not the last request before a close, we must
- set the maximum download size to the size of the
- expected document or else, we won't know when to stop
- reading! */
- if(-1 != conn->size)
- conn->maxdownload = conn->size;
+ else {
+ /* If we know the expected size of this document, we set the
+ maximum download size to the size of the expected
+ document or else, we won't know when to stop reading!
+
+ Note that we set the download maximum even if we read a
+ "Connection: close" header, to make sure that
+ "Content-Length: 0" still prevents us from attempting to
+ read the (missing) response-body.
+ */
+ /* According to RFC2616 section 4.4, we MUST ignore
+ Content-Length: headers if we are now receiving data
+ using chunked Transfer-Encoding.
+ */
+ if(conn->bits.chunk)
+ conn->size=-1;
+
+ }
+ if(-1 != conn->size) {
+ /* We do this operation even if no_body is true, since this
+ data might be retrieved later with curl_easy_getinfo()
+ and its CURLINFO_CONTENT_LENGTH_DOWNLOAD option. */
+
+ Curl_pgrsSetDownloadSize(data, conn->size);
+ conn->maxdownload = conn->size;
}
/* If max download size is *zero* (nothing) we already
have nothing and can safely return ok now! */
if(0 == conn->maxdownload)
stop_reading = TRUE;
-
+
if(stop_reading) {
/* we make sure that this socket isn't read more now */
k->keepon &= ~KEEP_READ;
@@ -472,15 +573,15 @@ CURLcode Curl_readwrite(struct connectdata *conn,
/*
* Checks for special headers coming up.
*/
-
+
if (!k->headerline++) {
/* This is the first header, it MUST be the error code line
or else we consiser this to be the body right away! */
int httpversion_major;
- int nc=sscanf (k->p, " HTTP/%d.%d %3d",
- &httpversion_major,
- &k->httpversion,
- &k->httpcode);
+ int nc=sscanf(k->p, " HTTP/%d.%d %3d",
+ &httpversion_major,
+ &k->httpversion,
+ &k->httpcode);
if (nc==3) {
k->httpversion += 10 * httpversion_major;
}
@@ -488,9 +589,9 @@ CURLcode Curl_readwrite(struct connectdata *conn,
/* this is the real world, not a Nirvana
NCSA 1.5.x returns this crap when asked for HTTP/1.1
*/
- nc=sscanf (k->p, " HTTP %3d", &k->httpcode);
+ nc=sscanf(k->p, " HTTP %3d", &k->httpcode);
k->httpversion = 10;
-
+
/* If user has set option HTTP200ALIASES,
compare header line against list of aliases
*/
@@ -508,13 +609,21 @@ CURLcode Curl_readwrite(struct connectdata *conn,
data->info.httpcode = k->httpcode;
data->info.httpversion = k->httpversion;
- /* 404 -> URL not found! */
+ /*
+ * This code executes as part of processing the header. As a
+ * result, it's not totally clear how to interpret the
+ * response code yet as that depends on what other headers may
+ * be present. 401 and 407 may be errors, but may be OK
+ * depending on how authentication is working. Other codes
+ * are definitely errors, so give up here.
+ */
if (data->set.http_fail_on_error &&
- (k->httpcode >= 400)) {
- /* If we have been told to fail hard on HTTP-errors,
- here is the check for that: */
+ (k->httpcode >= 400) &&
+ (k->httpcode != 401) &&
+ (k->httpcode != 407)) {
/* serious error, go home! */
- failf (data, "The requested file was not found");
+ failf (data, "The requested URL returned error: %d",
+ k->httpcode);
return CURLE_HTTP_RETURNED_ERROR;
}
@@ -532,10 +641,14 @@ CURLcode Curl_readwrite(struct connectdata *conn,
* message-body, and thus is always terminated by the first
* empty line after the header fields. */
/* FALLTHROUGH */
+ case 416: /* Requested Range Not Satisfiable, it has the
+ Content-Length: set as the "real" document but no
+ actual response is sent. */
case 304:
- /* (quote from RFC2616, section 10.3.5): The 304 response MUST
- * NOT contain a message-body, and thus is always terminated
- * by the first empty line after the header fields. */
+ /* (quote from RFC2616, section 10.3.5): The 304 response
+ * MUST NOT contain a message-body, and thus is always
+ * terminated by the first empty line after the header
+ * fields. */
conn->size=0;
conn->maxdownload=0;
break;
@@ -550,37 +663,64 @@ CURLcode Curl_readwrite(struct connectdata *conn,
}
}
- /* check for Content-Length: header lines to get size */
- if (checkprefix("Content-Length:", k->p) &&
- sscanf (k->p+15, " %ld", &k->contentlength)) {
- conn->size = k->contentlength;
- Curl_pgrsSetDownloadSize(data, k->contentlength);
+ /* Check for Content-Length: header lines to get size. Ignore
+ the header completely if we get a 416 response as then we're
+ resuming a document that we don't get, and this header contains
+ info about the true size of the document we didn't get now. */
+ if ((k->httpcode != 416) &&
+ checkprefix("Content-Length:", k->p)) {
+ 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)
+ conn->size = contentlength;
+ else {
+ /* Negative Content-Length is really odd, and we know it
+ happens for example when older Apache servers send large
+ files */
+ conn->bits.close = TRUE;
+ infof(data, "Negative content-length: %" FORMAT_OFF_T
+ ", closing after transfer\n", contentlength);
+ }
}
/* check for Content-Type: header lines to get the mime-type */
else if (checkprefix("Content-Type:", k->p)) {
char *start;
char *end;
- int len;
-
+ size_t len;
+
/* Find the first non-space letter */
- for(start=k->p+14;
+ for(start=k->p+13;
*start && isspace((int)*start);
start++);
- /* count all non-space letters following */
- for(end=start, len=0;
- *end && !isspace((int)*end);
- end++, len++);
+ end = strchr(start, '\r');
+ if(!end)
+ end = strchr(start, '\n');
- /* allocate memory of a cloned copy */
- data->info.contenttype = malloc(len + 1);
- if (NULL == data->info.contenttype)
- return CURLE_OUT_OF_MEMORY;
+ if(end) {
+ /* skip all trailing space letters */
+ for(; isspace((int)*end) && (end > start); end--);
- /* copy the content-type string */
- memcpy(data->info.contenttype, start, len);
- data->info.contenttype[len] = 0; /* zero terminate */
+ /* get length of the type */
+ len = end-start+1;
+
+ /* allocate memory of a cloned copy */
+ Curl_safefree(data->info.contenttype);
+
+ data->info.contenttype = malloc(len + 1);
+ if (NULL == data->info.contenttype)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* copy the content-type string */
+ memcpy(data->info.contenttype, start, len);
+ data->info.contenttype[len] = 0; /* zero terminate */
+ }
}
+#ifndef CURL_DISABLE_HTTP
else if((k->httpversion == 10) &&
conn->bits.httpproxy &&
Curl_compareheader(k->p,
@@ -632,12 +772,12 @@ CURLcode Curl_readwrite(struct connectdata *conn,
else if (checkprefix("Content-Encoding:", k->p) &&
data->set.encoding) {
/*
- * Process Content-Encoding. Look for the values: identity, gzip,
- * defalte, compress, x-gzip and x-compress. x-gzip and
+ * Process Content-Encoding. Look for the values: identity,
+ * gzip, deflate, compress, x-gzip and x-compress. x-gzip and
* x-compress are the same as gzip and compress. (Sec 3.5 RFC
- * 2616). zlib cannot handle compress, and gzip is not currently
- * implemented. However, errors are handled further down when the
- * response body is processed 08/27/02 jhrg */
+ * 2616). zlib cannot handle compress. However, errors are
+ * handled further down when the response body is processed
+ */
char *start;
/* Find the first non-space letter */
@@ -645,33 +785,51 @@ CURLcode Curl_readwrite(struct connectdata *conn,
*start && isspace((int)*start);
start++);
- /* Record the content-encoding for later use. 08/27/02 jhrg */
+ /* Record the content-encoding for later use */
if (checkprefix("identity", start))
k->content_encoding = IDENTITY;
else if (checkprefix("deflate", start))
k->content_encoding = DEFLATE;
- else if (checkprefix("gzip", start)
+ else if (checkprefix("gzip", start)
|| checkprefix("x-gzip", start))
k->content_encoding = GZIP;
- else if (checkprefix("compress", start)
+ else if (checkprefix("compress", start)
|| checkprefix("x-compress", start))
k->content_encoding = COMPRESS;
}
- else if (checkprefix("Content-Range:", k->p)) {
- if (sscanf (k->p+14, " bytes %d-", &k->offset) ||
- sscanf (k->p+14, " bytes: %d-", &k->offset)) {
- /* This second format was added August 1st 2000 by Igor
- Khristophorov since Sun's webserver JavaWebServer/1.1.1
- obviously sends the header this way! :-( */
- if (conn->resume_from == k->offset) {
- /* we asked for a resume and we got it */
- k->content_range = TRUE;
- }
- }
+ else if (Curl_compareheader(k->p, "Content-Range:", "bytes")) {
+ /* Content-Range: bytes [num]-
+ Content-Range: bytes: [num]-
+
+ The second format was added August 1st 2000 by Igor
+ Khristophorov since Sun's webserver JavaWebServer/1.1.1
+ obviously sends the header this way! :-( */
+
+ char *ptr = strstr(k->p, "bytes");
+ ptr+=5;
+
+ if(*ptr == ':')
+ /* stupid colon skip */
+ ptr++;
+
+ k->offset = curlx_strtoofft(ptr, NULL, 10);
+
+ if (conn->resume_from == k->offset)
+ /* we asked for a resume and we got it */
+ k->content_range = TRUE;
}
else if(data->cookies &&
checkprefix("Set-Cookie:", k->p)) {
- Curl_cookie_add(data->cookies, TRUE, k->p+11, conn->name);
+ Curl_share_lock(data, CURL_LOCK_DATA_COOKIE,
+ CURL_LOCK_ACCESS_SINGLE);
+ Curl_cookie_add(data,
+ 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?
+ conn->allocptr.cookiehost:conn->host.name,
+ conn->path);
+ Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
}
else if(checkprefix("Last-Modified:", k->p) &&
(data->set.timecondition || data->set.get_filetime) ) {
@@ -681,53 +839,70 @@ CURLcode Curl_readwrite(struct connectdata *conn,
if(data->set.get_filetime)
data->info.filetime = k->timeofdoc;
}
+ else if((checkprefix("WWW-Authenticate:", k->p) &&
+ (401 == k->httpcode)) ||
+ (checkprefix("Proxy-authenticate:", k->p) &&
+ (407 == k->httpcode))) {
+ result = Curl_http_input_auth(conn, k->httpcode, k->p);
+ if(result)
+ return result;
+ }
else if ((k->httpcode >= 300 && k->httpcode < 400) &&
- (data->set.http_follow_location) &&
checkprefix("Location:", k->p)) {
- /* this is the URL that the server advices us to get instead */
- char *ptr;
- char *start=k->p;
- char backup;
-
- start += 9; /* pass "Location:" */
-
- /* Skip spaces and tabs. We do this to support multiple
- white spaces after the "Location:" keyword. */
- while(*start && isspace((int)*start ))
- start++;
- ptr = start; /* start scanning here */
-
- /* scan through the string to find the end */
- while(*ptr && !isspace((int)*ptr))
+ if(data->set.http_follow_location) {
+ /* this is the URL that the server advices us to get instead */
+ char *ptr;
+ char *start=k->p;
+ char backup;
+
+ start += 9; /* pass "Location:" */
+
+ /* Skip spaces and tabs. We do this to support multiple
+ white spaces after the "Location:" keyword. */
+ while(*start && isspace((int)*start ))
+ start++;
+
+ /* Scan through the string from the end to find the last
+ non-space. k->end_ptr points to the actual terminating zero
+ letter, move pointer one letter back and start from
+ there. This logic strips off trailing whitespace, but keeps
+ any embedded whitespace. */
+ ptr = k->end_ptr-1;
+ while((ptr>=start) && isspace((int)*ptr))
+ ptr--;
ptr++;
- backup = *ptr; /* store the ending letter */
- if(ptr != start) {
- *ptr = '\0'; /* zero terminate */
- conn->newurl = strdup(start); /* clone string */
- *ptr = backup; /* restore ending letter */
+
+ backup = *ptr; /* store the ending letter */
+ if(ptr != start) {
+ *ptr = '\0'; /* zero terminate */
+ conn->newurl = strdup(start); /* clone string */
+ *ptr = backup; /* restore ending letter */
+ if(!conn->newurl)
+ return CURLE_OUT_OF_MEMORY;
+ }
}
}
+#endif /* CURL_DISABLE_HTTP */
/*
* End of header-checks. Write them to the client.
*/
- k->writetype = CLIENTWRITE_HEADER;
- if (data->set.http_include_header)
- k->writetype |= CLIENTWRITE_BODY;
+ writetype = CLIENTWRITE_HEADER;
+ if (data->set.include_header)
+ writetype |= CLIENTWRITE_BODY;
if(data->set.verbose)
Curl_debug(data, CURLINFO_HEADER_IN,
- k->p, k->hbuflen);
+ k->p, k->hbuflen, conn->host.dispname);
- result = Curl_client_write(data, k->writetype, k->p,
- k->hbuflen);
+ result = Curl_client_write(data, writetype, k->p, k->hbuflen);
if(result)
- return (CURLcode)result;
+ return result;
data->info.header_size += k->hbuflen;
conn->headerbytecount += k->hbuflen;
-
+
/* reset hbufp pointer && hbuflen */
k->hbufp = data->state.headerbuff;
k->hbuflen = 0;
@@ -748,38 +923,36 @@ CURLcode Curl_readwrite(struct connectdata *conn,
parsing, where the beginning of the buffer is headers and the end
is non-headers. */
if (k->str && !k->header && (nread > 0)) {
-
+
if(0 == k->bodywrites) {
/* These checks are only made the first time we are about to
write a piece of the body */
if(conn->protocol&PROT_HTTP) {
/* HTTP-only checks */
+
if (conn->newurl) {
- /* abort after the headers if "follow Location" is set */
- infof (data, "Follow to new URL: %s\n", conn->newurl);
- k->keepon &= ~KEEP_READ;
- FD_ZERO(&k->rkeepfd);
- *done = TRUE;
- return CURLE_OK;
- }
- else if (conn->resume_from &&
- !k->content_range &&
- (data->set.httpreq==HTTPREQ_GET)) {
- /* we wanted to resume a download, although the server
- doesn't seem to support this and we did this with a GET
- (if it wasn't a GET we did a POST or PUT resume) */
- failf (data, "HTTP server doesn't seem to support "
- "byte ranges. Cannot resume.");
- return CURLE_HTTP_RANGE_ERROR;
+ if(conn->bits.close) {
+ /* Abort after the headers if "follow Location" is set
+ and we're set to close anyway. */
+ k->keepon &= ~KEEP_READ;
+ FD_ZERO(&k->rkeepfd);
+ *done = TRUE;
+ return CURLE_OK;
+ }
+ /* We have a new url to load, but since we want to be able
+ to re-use this connection properly, we read the full
+ response in "ignore more" */
+ k->ignorebody = TRUE;
+ infof(data, "Ignoring the response-body\n");
}
- else if(data->set.timecondition && !conn->range) {
+ if(data->set.timecondition && !conn->range) {
/* A time condition has been set AND no ranges have been
requested. This seems to be what chapter 13.3.4 of
RFC 2616 defines to be the correct action for a
HTTP/1.1 client */
if((k->timeofdoc > 0) && (data->set.timevalue > 0)) {
switch(data->set.timecondition) {
- case TIMECOND_IFMODSINCE:
+ case CURL_TIMECOND_IFMODSINCE:
default:
if(k->timeofdoc < data->set.timevalue) {
infof(data,
@@ -788,7 +961,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
return CURLE_OK;
}
break;
- case TIMECOND_IFUNMODSINCE:
+ case CURL_TIMECOND_IFUNMODSINCE:
if(k->timeofdoc > data->set.timevalue) {
infof(data,
"The requested document is not old enough\n");
@@ -808,14 +981,17 @@ CURLcode Curl_readwrite(struct connectdata *conn,
if(data->set.verbose) {
if(k->badheader) {
Curl_debug(data, CURLINFO_DATA_IN, data->state.headerbuff,
- k->hbuflen);
+ k->hbuflen, conn->host.dispname);
if(k->badheader == HEADER_PARTHEADER)
- Curl_debug(data, CURLINFO_DATA_IN, k->str, nread);
+ Curl_debug(data, CURLINFO_DATA_IN, k->str, nread,
+ conn->host.dispname);
}
else
- Curl_debug(data, CURLINFO_DATA_IN, k->str, nread);
+ Curl_debug(data, CURLINFO_DATA_IN, k->str, nread,
+ conn->host.dispname);
}
+#ifndef CURL_DISABLE_HTTP
if(conn->bits.chunk) {
/*
* Bless me father for I have sinned. Here comes a chunked
@@ -831,7 +1007,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
failf(data, "Failed writing data");
return CURLE_WRITE_ERROR;
}
- failf(data, "Received problem in the chunky parser");
+ failf(data, "Received problem %d in the chunky parser", res);
return CURLE_RECV_ERROR;
}
else if(CHUNKE_STOP == res) {
@@ -845,10 +1021,11 @@ CURLcode Curl_readwrite(struct connectdata *conn,
}
/* If it returned OK, we just keep going */
}
+#endif /* CURL_DISABLE_HTTP */
if((-1 != conn->maxdownload) &&
(k->bytecount + nread >= conn->maxdownload)) {
- nread = conn->maxdownload - k->bytecount;
+ nread = (ssize_t) (conn->maxdownload - k->bytecount);
if(nread < 0 ) /* this should be unusual */
nread = 0;
@@ -858,12 +1035,12 @@ CURLcode Curl_readwrite(struct connectdata *conn,
k->bytecount += nread;
- Curl_pgrsSetDownloadCounter(data, (double)k->bytecount);
-
+ Curl_pgrsSetDownloadCounter(data, k->bytecount);
+
if(!conn->bits.chunk && (nread || k->badheader)) {
/* If this is chunky transfer, it was already written */
- if(k->badheader) {
+ if(k->badheader && !k->ignorebody) {
/* we parsed a piece of data wrongly assuming it was a header
and now we output it as body instead */
result = Curl_client_write(data, CLIENTWRITE_BODY,
@@ -873,30 +1050,36 @@ CURLcode Curl_readwrite(struct connectdata *conn,
if(k->badheader < HEADER_ALLBAD) {
/* This switch handles various content encodings. If there's an
error here, be sure to check over the almost identical code
- in http_chunk.c. 08/29/02 jhrg */
+ in http_chunks.c.
+ Make sure that ALL_CONTENT_ENCODINGS contains all the
+ encodings handled here. */
#ifdef HAVE_LIBZ
switch (k->content_encoding) {
case IDENTITY:
#endif
/* This is the default when the server sends no
Content-Encoding header. See Curl_readwrite_init; the
- memset() call initializes k->content_encoding to zero.
- 08/28/02 jhrg */
- result = Curl_client_write(data, CLIENTWRITE_BODY, k->str,
- nread);
+ memset() call initializes k->content_encoding to zero. */
+ if(!k->ignorebody)
+ result = Curl_client_write(data, CLIENTWRITE_BODY, k->str,
+ nread);
#ifdef HAVE_LIBZ
break;
- case DEFLATE:
+ case DEFLATE:
/* Assume CLIENTWRITE_BODY; headers are not encoded. */
result = Curl_unencode_deflate_write(data, k, nread);
break;
- case GZIP: /* FIXME 08/27/02 jhrg */
+ case GZIP:
+ /* Assume CLIENTWRITE_BODY; headers are not encoded. */
+ result = Curl_unencode_gzip_write(data, k, nread);
+ break;
+
case COMPRESS:
default:
failf (data, "Unrecognized content encoding type. "
- "libcurl understands `identity' and `deflate' "
+ "libcurl understands `identity', `deflate' and `gzip' "
"content encodings.");
result = CURLE_BAD_CONTENT_ENCODING;
break;
@@ -906,7 +1089,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
k->badheader = HEADER_NORMAL; /* taken care of now */
if(result)
- return (CURLcode)result;
+ return result;
}
} /* if (! header and data to read ) */
@@ -916,16 +1099,16 @@ CURLcode Curl_readwrite(struct connectdata *conn,
} /* if( read from socket ) */
/* If we still have writing to do, we check if we have a writable
- socket. Sometimes the writefdp is NULL, it no fd_set was done using
+ socket. Sometimes the writefdp is NULL, if no fd_set was done using
the multi interface and then we can do nothing but to attempt a
write to be sure. */
if((k->keepon & KEEP_WRITE) &&
- (FD_ISSET(conn->writesockfd, writefdp)) ) {
+ (!writefdp || FD_ISSET(conn->writesockfd, writefdp)) ) {
/* write */
int i, si;
ssize_t bytes_written;
- bool writedone=FALSE;
+ bool writedone=TRUE;
if ((k->bytecount == 0) && (k->writebytecount == 0))
Curl_pgrsTime(data, TIMER_STARTTRANSFER);
@@ -937,15 +1120,39 @@ CURLcode Curl_readwrite(struct connectdata *conn,
* data to send or until we get EWOULDBLOCK back
*/
do {
-
+
/* only read more data if there's no upload data already
present in the upload buffer */
if(0 == conn->upload_present) {
/* init the "upload from here" pointer */
conn->upload_fromhere = k->uploadbuf;
- if(!k->upload_done)
- nread = fillbuffer(conn, BUFSIZE);
+ if(!k->upload_done) {
+ /* HTTP pollution, this should be written nicer to become more
+ protocol agnostic. */
+ int fillcount;
+
+ if(k->wait100_after_headers &&
+ (conn->proto.http->sending == HTTPSEND_BODY)) {
+ /* If this call is to send body data, we must take some action:
+ We have sent off the full HTTP 1.1 request, and we shall now
+ go into the Expect: 100 state and await such a header */
+ k->wait100_after_headers = FALSE; /* headers sent */
+ k->write_after_100_header = TRUE; /* wait for the header */
+ FD_ZERO (&k->writefd); /* clear it */
+ k->wkeepfd = k->writefd; /* set the keeper variable */
+ k->keepon &= ~KEEP_WRITE; /* disable writing */
+ k->start100 = Curl_tvnow(); /* timeout count starts now */
+ didwhat &= ~KEEP_WRITE; /* we didn't write anything actually */
+ break;
+ }
+
+ result = Curl_fillreadbuffer(conn, BUFSIZE, &fillcount);
+ if(result)
+ return result;
+
+ nread = (ssize_t)fillcount;
+ }
else
nread = 0; /* we're done uploading/reading */
@@ -964,6 +1171,12 @@ CURLcode Curl_readwrite(struct connectdata *conn,
/* convert LF to CRLF if so asked */
if (data->set.crlf) {
+ if(data->state.scratch == NULL)
+ data->state.scratch = malloc(2*BUFSIZE);
+ if(data->state.scratch == NULL) {
+ failf (data, "Failed to alloc scratch buffer!");
+ return CURLE_OUT_OF_MEMORY;
+ }
for(i = 0, si = 0; i < nread; i++, si++) {
if (conn->upload_fromhere[i] == 0x0a) {
data->state.scratch[si++] = 0x0d;
@@ -997,8 +1210,14 @@ CURLcode Curl_readwrite(struct connectdata *conn,
conn->upload_present, /* buffer size */
&bytes_written); /* actually send away */
if(result)
- return (CURLcode)result;
- else if(conn->upload_present != bytes_written) {
+ return result;
+
+ if(data->set.verbose)
+ /* show the data before we change the pointer upload_fromhere */
+ Curl_debug(data, CURLINFO_DATA_OUT, conn->upload_fromhere,
+ bytes_written, conn->host.dispname);
+
+ if(conn->upload_present != bytes_written) {
/* we only wrote a part of the buffer (if anything), deal with it! */
/* store the amount of bytes left in the buffer to write */
@@ -1023,20 +1242,16 @@ CURLcode Curl_readwrite(struct connectdata *conn,
}
}
- if(data->set.verbose)
- Curl_debug(data, CURLINFO_DATA_OUT, conn->upload_fromhere,
- bytes_written);
-
-
k->writebytecount += bytes_written;
- Curl_pgrsSetUploadCounter(data, (double)k->writebytecount);
+ Curl_pgrsSetUploadCounter(data, k->writebytecount);
} while(!writedone); /* loop until we're done writing! */
-
+
}
} while(0); /* just to break out from! */
+ k->now = Curl_tvnow();
if(didwhat) {
/* Update read/write counters */
if(conn->bytecountp)
@@ -1050,25 +1265,39 @@ CURLcode Curl_readwrite(struct connectdata *conn,
/* This should allow some time for the header to arrive, but only a
very short time as otherwise it'll be too much wasted times too
often. */
- k->write_after_100_header = FALSE;
- FD_SET (conn->writesockfd, &k->writefd); /* write socket */
- k->keepon |= KEEP_WRITE;
- k->wkeepfd = k->writefd;
- }
+
+ /* Quoting RFC2616, section "8.2.3 Use of the 100 (Continue) Status":
+
+ Therefore, when a client sends this header field to an origin server
+ (possibly via a proxy) from which it has never seen a 100 (Continue)
+ status, the client SHOULD NOT wait for an indefinite period before
+ sending the request body.
+
+ */
+
+ long ms = Curl_tvdiff(k->now, k->start100);
+ if(ms > CURL_TIMEOUT_EXPECT_100) {
+ /* we've waited long enough, continue anyway */
+ k->write_after_100_header = FALSE;
+ FD_SET (conn->writesockfd, &k->writefd); /* write socket */
+ k->keepon |= KEEP_WRITE;
+ k->wkeepfd = k->writefd;
+ }
+ }
}
- k->now = Curl_tvnow();
if(Curl_pgrsUpdate(conn))
result = CURLE_ABORTED_BY_CALLBACK;
else
- result = Curl_speedcheck (data, k->now);
+ result = Curl_speedcheck(data, k->now);
if (result)
- return (CURLcode)result;
-
+ return result;
+
if (data->set.timeout &&
((Curl_tvdiff(k->now, k->start)/1000) >= data->set.timeout)) {
- failf (data, "Operation timed out with %d out of %d bytes received",
- k->bytecount, conn->size);
+ failf(data, "Operation timed out with %" FORMAT_OFF_T
+ " out of %" FORMAT_OFF_T " bytes received",
+ k->bytecount, conn->size);
return CURLE_OPERATION_TIMEOUTED;
}
@@ -1078,11 +1307,12 @@ CURLcode Curl_readwrite(struct connectdata *conn,
* returning.
*/
- if(!(data->set.no_body) && k->contentlength &&
- (k->bytecount != k->contentlength) &&
+ if(!(conn->bits.no_body) && (conn->size != -1) &&
+ (k->bytecount != conn->size) &&
!conn->newurl) {
- failf(data, "transfer closed with %d bytes remaining to read",
- k->contentlength-k->bytecount);
+ failf(data, "transfer closed with %" FORMAT_OFF_T
+ " bytes remaining to read",
+ conn->size - k->bytecount);
return CURLE_PARTIAL_FILE;
}
else if(conn->bits.chunk && conn->proto.http->chunk.datasize) {
@@ -1095,18 +1325,23 @@ CURLcode Curl_readwrite(struct connectdata *conn,
}
/* Now update the "done" boolean we return */
- *done = (bool)!k->keepon;
+ *done = !k->keepon;
return CURLE_OK;
}
+
+/*
+ * Curl_readwrite_init() inits the readwrite session.
+ */
+
CURLcode Curl_readwrite_init(struct connectdata *conn)
{
struct SessionHandle *data = conn->data;
struct Curl_transfer_keeper *k = &conn->keep;
/* NB: the content encoding software depends on this initialization of
- Curl_transfer_keeper. 08/28/02 jhrg */
+ Curl_transfer_keeper. */
memset(k, 0, sizeof(struct Curl_transfer_keeper));
k->start = Curl_tvnow(); /* start time */
@@ -1120,6 +1355,7 @@ CURLcode Curl_readwrite_init(struct connectdata *conn)
k->maxfd = (conn->sockfd>conn->writesockfd?
conn->sockfd:conn->writesockfd)+1;
k->hbufp = data->state.headerbuff;
+ k->ignorebody=FALSE;
Curl_pgrsTime(data, TIMER_PRETRANSFER);
Curl_speedinit(data);
@@ -1133,20 +1369,36 @@ CURLcode Curl_readwrite_init(struct connectdata *conn)
Curl_pgrsSetDownloadSize(data, conn->size);
}
/* we want header and/or body, if neither then don't do this! */
- if(conn->bits.getheader || !data->set.no_body) {
+ if(conn->bits.getheader || !conn->bits.no_body) {
FD_ZERO (&k->readfd); /* clear it */
- if(conn->sockfd != -1) {
+ if(conn->sockfd != CURL_SOCKET_BAD) {
FD_SET (conn->sockfd, &k->readfd); /* read socket */
k->keepon |= KEEP_READ;
}
FD_ZERO (&k->writefd); /* clear it */
- if(conn->writesockfd != -1) {
- if (data->set.expect100header)
+ if(conn->writesockfd != CURL_SOCKET_BAD) {
+ /* HTTP 1.1 magic:
+
+ Even if we require a 100-return code before uploading data, we might
+ need to write data before that since the REQUEST may not have been
+ finished sent off just yet.
+
+ Thus, we must check if the request has been sent before we set the
+ state info where we wait for the 100-return code
+ */
+ if (data->set.expect100header &&
+ (conn->proto.http->sending == HTTPSEND_BODY)) {
/* wait with write until we either got 100-continue or a timeout */
k->write_after_100_header = TRUE;
+ k->start100 = k->start;
+ }
else {
+ if(data->set.expect100header)
+ /* when we've sent off the rest of the headers, we must await a
+ 100-continue */
+ k->wait100_after_headers = TRUE;
FD_SET (conn->writesockfd, &k->writefd); /* write socket */
k->keepon |= KEEP_WRITE;
}
@@ -1162,6 +1414,13 @@ CURLcode Curl_readwrite_init(struct connectdata *conn)
return CURLE_OK;
}
+/*
+ * Curl_single_fdset() gets called by the multi interface code when the app
+ * has requested to get the fd_sets for the current connection. This function
+ * will then be called once for every connection that the multi interface
+ * keeps track of. This function will only be called for connections that are
+ * in the proper state to have this information available.
+ */
void Curl_single_fdset(struct connectdata *conn,
fd_set *read_fd_set,
fd_set *write_fd_set,
@@ -1176,7 +1435,10 @@ void Curl_single_fdset(struct connectdata *conn,
}
if(conn->keep.keepon & KEEP_WRITE) {
FD_SET(conn->writesockfd, write_fd_set);
- if(conn->writesockfd > *max_fd)
+
+ /* since sockets are curl_socket_t nowadays, we typecast it to int here
+ to compare it nicely */
+ if((int)conn->writesockfd > *max_fd)
*max_fd = conn->writesockfd;
conn->keep.writefdp = write_fd_set; /* store the address of the set */
}
@@ -1194,7 +1456,7 @@ void Curl_single_fdset(struct connectdata *conn,
* The transfer must already have been setup by a call to Curl_Transfer().
*
* Note that headers are created in a preallocated buffer of a default size.
- * That buffer can be enlarged on demand, but it is never shrinken again.
+ * That buffer can be enlarged on demand, but it is never shrunken again.
*
* Parts of this function was once written by the friendly Mark Butler
* <butlerm@xmission.com>.
@@ -1203,19 +1465,22 @@ void Curl_single_fdset(struct connectdata *conn,
static CURLcode
Transfer(struct connectdata *conn)
{
- struct SessionHandle *data = conn->data;
CURLcode result;
struct Curl_transfer_keeper *k = &conn->keep;
bool done=FALSE;
- Curl_readwrite_init(conn);
+ if(!(conn->protocol & PROT_FILE))
+ /* Only do this if we are not transferring FILE:, since the file: treatment
+ is different*/
+ Curl_readwrite_init(conn);
- if((conn->sockfd == -1) && (conn->writesockfd == -1))
+ if((conn->sockfd == CURL_SOCKET_BAD) &&
+ (conn->writesockfd == CURL_SOCKET_BAD))
/* nothing to read, nothing to write, we're already OK! */
return CURLE_OK;
/* we want header and/or body, if neither then don't do this! */
- if(!conn->bits.getheader && data->set.no_body)
+ if(!conn->bits.getheader && conn->bits.no_body)
return CURLE_OK;
k->writefdp = &k->writefd; /* store the address of the set */
@@ -1240,22 +1505,22 @@ Transfer(struct connectdata *conn)
done = TRUE; /* no more read or write */
continue;
case 0: /* timeout */
- result = Curl_readwrite(conn, &done);
- break;
-
default: /* readable descriptors */
result = Curl_readwrite(conn, &done);
break;
}
if(result)
return result;
-
+
/* "done" signals to us if the transfer(s) are ready */
}
return CURLE_OK;
}
+/*
+ * Curl_pretransfer() is called immediately before a transfer starts.
+ */
CURLcode Curl_pretransfer(struct SessionHandle *data)
{
if(!data->change.url)
@@ -1263,30 +1528,42 @@ CURLcode Curl_pretransfer(struct SessionHandle *data)
return CURLE_URL_MALFORMAT;
#ifdef USE_SSLEAY
- /* Init the SSL session ID cache here. We do it here since we want to
- do it after the *_setopt() calls (that could change the size) but
- before any transfer. */
- Curl_SSL_InitSessions(data, data->set.ssl.numsessions);
+ {
+ /* Init the SSL session ID cache here. We do it here since we want to do
+ it after the *_setopt() calls (that could change the size of the cache)
+ but before any transfer takes place. */
+ CURLcode res = Curl_SSL_InitSessions(data, data->set.ssl.numsessions);
+ if(res)
+ return res;
+ }
#endif
data->set.followlocation=0; /* reset the location-follow counter */
data->state.this_is_a_follow = FALSE; /* reset this */
data->state.errorbuf = FALSE; /* no error has occurred */
+ data->state.authproblem = FALSE;
+ data->state.authhost.want = data->set.httpauth;
+ data->state.authproxy.want = data->set.proxyauth;
+
+#ifndef CURL_DISABLE_HTTP
/* If there was a list of cookie files to read and we haven't done it before,
do it now! */
if(data->change.cookielist) {
struct curl_slist *list = data->change.cookielist;
+ Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
while(list) {
- data->cookies = Curl_cookie_init(list->data,
+ data->cookies = Curl_cookie_init(data,
+ list->data,
data->cookies,
data->set.cookiesession);
list = list->next;
}
+ Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
curl_slist_free_all(data->change.cookielist); /* clean up list */
data->change.cookielist = NULL; /* don't do this again! */
}
-
+#endif /* CURL_DISABLE_HTTP */
/* Allow data->set.use_port to set which port to use. This needs to be
@@ -1294,13 +1571,13 @@ CURLcode Curl_pretransfer(struct SessionHandle *data)
* different ports! */
data->state.allow_port = TRUE;
-#if defined(HAVE_SIGNAL) && defined(SIGPIPE)
+#if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(HAVE_MSG_NOSIGNAL)
/*************************************************************
* Tell signal handler to ignore SIGPIPE
*************************************************************/
if(!data->set.no_signal)
data->state.prev_signal = signal(SIGPIPE, SIG_IGN);
-#endif
+#endif
Curl_initinfo(data); /* reset session-specific information "variables" */
Curl_pgrsStartNow(data);
@@ -1308,18 +1585,87 @@ CURLcode Curl_pretransfer(struct SessionHandle *data)
return CURLE_OK;
}
+/*
+ * Curl_posttransfer() is called immediately after a transfer ends
+ */
CURLcode Curl_posttransfer(struct SessionHandle *data)
{
- (void)data;
-#if defined(HAVE_SIGNAL) && defined(SIGPIPE)
+#if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(HAVE_MSG_NOSIGNAL)
/* restore the signal handler for SIGPIPE before we get back */
if(!data->set.no_signal)
signal(SIGPIPE, data->state.prev_signal);
-#endif
+#else
+ (void)data; /* unused parameter */
+#endif
return CURLE_OK;
}
+/*
+ * strlen_url() returns the length of the given URL if the spaces within the
+ * URL were properly URL encoded.
+ */
+static int strlen_url(char *url)
+{
+ char *ptr;
+ int newlen=0;
+ bool left=TRUE; /* left side of the ? */
+
+ for(ptr=url; *ptr; ptr++) {
+ switch(*ptr) {
+ case '?':
+ left=FALSE;
+ default:
+ newlen++;
+ break;
+ case ' ':
+ if(left)
+ newlen+=3;
+ else
+ newlen++;
+ break;
+ }
+ }
+ return newlen;
+}
+
+/* strcpy_url() copies a url to a output buffer and URL-encodes the spaces in
+ * the source URL accordingly.
+ */
+static void strcpy_url(char *output, char *url)
+{
+ /* we must add this with whitespace-replacing */
+ bool left=TRUE;
+ char *iptr;
+ char *optr = output;
+ for(iptr = url; /* read from here */
+ *iptr; /* until zero byte */
+ iptr++) {
+ switch(*iptr) {
+ case '?':
+ left=FALSE;
+ default:
+ *optr++=*iptr;
+ break;
+ case ' ':
+ if(left) {
+ *optr++='%'; /* add a '%' */
+ *optr++='2'; /* add a '2' */
+ *optr++='0'; /* add a '0' */
+ }
+ else
+ *optr++='+'; /* add a '+' here */
+ break;
+ }
+ }
+ *optr=0; /* zero terminate output buffer */
+
+}
+
+/*
+ * Curl_follow() handles the URL redirect magic. Pass in the 'newurl' string
+ * as given by the remote server and set up the new URL to request.
+ */
CURLcode Curl_follow(struct SessionHandle *data,
char *newurl) /* this 'newurl' is the Location: string,
and it must be malloc()ed before passed
@@ -1328,7 +1674,9 @@ CURLcode Curl_follow(struct SessionHandle *data,
/* Location: redirect */
char prot[16]; /* URL protocol string storage */
char letter; /* used for a silly sscanf */
-
+ size_t newlen;
+ char *newest;
+
if (data->set.maxredirs &&
(data->set.followlocation >= data->set.maxredirs)) {
failf(data,"Maximum (%d) redirects followed", data->set.maxredirs);
@@ -1364,9 +1712,9 @@ CURLcode Curl_follow(struct SessionHandle *data,
*/
char *protsep;
char *pathsep;
- char *newest;
char *useurl = newurl;
+ size_t urllen;
/* we must make our own copy of the URL to play with, as it may
point to read-only data */
@@ -1390,7 +1738,7 @@ CURLcode Curl_follow(struct SessionHandle *data,
pathsep = strrchr(protsep, '?');
if(pathsep)
*pathsep=0;
-
+
/* we have a relative path to append to the last slash if
there's one available */
pathsep = strrchr(protsep, '/');
@@ -1410,11 +1758,11 @@ CURLcode Curl_follow(struct SessionHandle *data,
if((useurl[0] == '.') && (useurl[1] == '/'))
useurl+=2; /* just skip the "./" */
-
+
while((useurl[0] == '.') &&
(useurl[1] == '.') &&
(useurl[2] == '/')) {
- level++;
+ level++;
useurl+=3; /* pass the "../" */
}
@@ -1437,65 +1785,114 @@ CURLcode Curl_follow(struct SessionHandle *data,
pathsep = strchr(protsep, '/');
if(pathsep)
*pathsep=0;
+ else {
+ /* There was no slash. Now, since we might be operating on a badly
+ formatted URL, such as "http://www.url.com?id=2380" which doesn't
+ use a slash separator as it is supposed to, we need to check for a
+ ?-letter as well! */
+ pathsep = strchr(protsep, '?');
+ if(pathsep)
+ *pathsep=0;
+ }
}
- newest=(char *)malloc( strlen(url_clone) +
- 1 + /* possible slash */
- strlen(useurl) + 1/* zero byte */);
-
- if(!newest)
+ /* If the new part contains a space, this is a mighty stupid redirect
+ but we still make an effort to do "right". To the left of a '?'
+ letter we replace each space with %20 while it is replaced with '+'
+ on the right side of the '?' letter.
+ */
+ newlen = strlen_url(useurl);
+
+ urllen = strlen(url_clone);
+
+ newest=(char *)malloc( urllen + 1 + /* possible slash */
+ newlen + 1 /* zero byte */);
+
+ if(!newest) {
+ free(url_clone); /* don't leak this */
return CURLE_OUT_OF_MEMORY; /* go out from this */
+ }
+
+ /* copy over the root url part */
+ memcpy(newest, url_clone, urllen);
+
+ /* check if we need to append a slash */
+ if(('/' == useurl[0]) || (protsep && !*protsep))
+ ;
+ else
+ newest[urllen++]='/';
+
+ /* then append the new piece on the right side */
+ strcpy_url(&newest[urllen], useurl);
- sprintf(newest, "%s%s%s", url_clone,
- (('/' == useurl[0]) || (protsep && !*protsep))?"":"/",
- useurl);
free(newurl); /* newurl is the allocated pointer */
free(url_clone);
newurl = newest;
}
- else
+ else {
/* This is an absolute URL, don't allow the custom port number */
data->state.allow_port = FALSE;
+ if(strchr(newurl, ' ')) {
+ /* This new URL contains at least one space, this is a mighty stupid
+ redirect but we still make an effort to do "right". */
+ newlen = strlen_url(newurl);
+
+ newest = malloc(newlen+1); /* get memory for this */
+ if(newest) {
+ strcpy_url(newest, newurl); /* create a space-free URL */
+
+ free(newurl); /* that was no good */
+ newurl = newest; /* use this instead now */
+ }
+ }
+
+ }
+
if(data->change.url_alloc)
free(data->change.url);
else
data->change.url_alloc = TRUE; /* the URL is allocated */
-
- /* TBD: set the URL with curl_setopt() */
+
data->change.url = newurl;
newurl = NULL; /* don't free! */
- infof(data, "Follows Location: to new URL: '%s'\n", data->change.url);
+ infof(data, "Issue another request to this URL: '%s'\n", data->change.url);
/*
- * We get here when the HTTP code is 300-399. We need to perform
+ * We get here when the HTTP code is 300-399 (and 401). We need to perform
* differently based on exactly what return code there was.
- * Discussed on the curl mailing list and posted about on the 26th
- * of January 2001.
+ *
+ * News from 7.10.6: we can also get here on a 401 or 407, in case we act on
+ * a HTTP (proxy-) authentication scheme other than Basic.
*/
switch(data->info.httpcode) {
- case 300: /* Multiple Choices */
- case 306: /* Not used */
- case 307: /* Temporary Redirect */
- default: /* for all unknown ones */
- /* These are explicitly mention since I've checked RFC2616 and they
+ /* 401 - Act on a www-authentication, we keep on moving and do the
+ Authorization: XXXX header in the HTTP request code snippet */
+ /* 407 - Act on a proxy-authentication, we keep on moving and do the
+ Proxy-Authorization: XXXX header in the HTTP request code snippet */
+ /* 300 - Multiple Choices */
+ /* 306 - Not used */
+ /* 307 - Temporary Redirect */
+ default: /* for all above (and the unknown ones) */
+ /* Some codes are explicitly mentioned since I've checked RFC2616 and they
* seem to be OK to POST to.
*/
break;
case 301: /* Moved Permanently */
/* (quote from RFC2616, section 10.3.2):
- *
- * Note: When automatically redirecting a POST request after
- * receiving a 301 status code, some existing HTTP/1.0 user agents
- * will erroneously change it into a GET request.
+ *
+ * Note: When automatically redirecting a POST request after receiving a
+ * 301 status code, some existing HTTP/1.0 user agents will erroneously
+ * change it into a GET request.
*
* ----
- * Warning: Because most of importants user agents do this clear
- * RFC2616 violation, many webservers expect this misbehavior. So
- * these servers often answers to a POST request with an error page.
- * To be sure that libcurl gets the page that most user agents
- * would get, libcurl has to force GET:
+ *
+ * Warning: Because most of importants user agents do this obvious RFC2616
+ * violation, many webservers expect this misbehavior. So these servers
+ * often answers to a POST request with an error page. To be sure that
+ * libcurl gets the page that most user agents would get, libcurl has to
+ * force GET:
*/
if( data->set.httpreq == HTTPREQ_POST
|| data->set.httpreq == HTTPREQ_POST_FORM) {
@@ -1506,7 +1903,7 @@ CURLcode Curl_follow(struct SessionHandle *data,
break;
case 302: /* Found */
/* (From 10.3.3)
-
+
Note: RFC 1945 and RFC 2068 specify that the client is not allowed
to change the method on the redirected request. However, most
existing user agent implementations treat 302 as if it were a 303
@@ -1514,13 +1911,13 @@ CURLcode Curl_follow(struct SessionHandle *data,
of the original request method. The status codes 303 and 307 have
been added for servers that wish to make unambiguously clear which
kind of reaction is expected of the client.
-
+
(From 10.3.4)
-
+
Note: Many pre-HTTP/1.1 user agents do not understand the 303
status. When interoperability with such clients is a concern, the
302 status code may be used instead, since most user agents react
- to a 302 response as described here for 303.
+ to a 302 response as described here for 303.
*/
case 303: /* See Other */
/* Disable both types of POSTs, since doing a second POST when
@@ -1528,7 +1925,7 @@ CURLcode Curl_follow(struct SessionHandle *data,
if(data->set.httpreq != HTTPREQ_GET) {
data->set.httpreq = HTTPREQ_GET; /* enforce GET request */
infof(data, "Disables POST, goes with %s\n",
- data->set.no_body?"HEAD":"GET");
+ data->set.opt_no_body?"HEAD":"GET");
}
break;
case 304: /* Not Modified */
@@ -1552,6 +1949,55 @@ CURLcode Curl_follow(struct SessionHandle *data,
return CURLE_OK;
}
+static CURLcode
+Curl_connect_host(struct SessionHandle *data,
+ struct connectdata **conn)
+{
+ CURLcode res = CURLE_OK;
+ int urlchanged = FALSE;
+
+ do {
+ bool async;
+ Curl_pgrsTime(data, TIMER_STARTSINGLE);
+ data->change.url_changed = FALSE;
+ res = Curl_connect(data, conn, &async);
+
+ if((CURLE_OK == res) && async) {
+ /* Now, if async is TRUE here, we need to wait for the name
+ to resolve */
+ res = Curl_wait_for_resolv(*conn, NULL);
+ if(CURLE_OK == res)
+ /* Resolved, continue with the connection */
+ res = Curl_async_resolved(*conn);
+ }
+ if(res)
+ break;
+
+ /* If a callback (or something) has altered the URL we should use within
+ the Curl_connect(), we detect it here and act as if we are redirected
+ to the new URL */
+ urlchanged = data->change.url_changed;
+ if ((CURLE_OK == res) && urlchanged) {
+ res = Curl_done(conn, res);
+ if(CURLE_OK == res) {
+ char *gotourl = strdup(data->change.url);
+ res = Curl_follow(data, gotourl);
+ if(res)
+ free(gotourl);
+ }
+ }
+ } while (urlchanged && res == CURLE_OK);
+
+ return res;
+}
+
+
+
+/*
+ * Curl_perform() is the internal high-level function that gets called by the
+ * external curl_easy_perform() function. It inits, performs and cleans up a
+ * single file transfer.
+ */
CURLcode Curl_perform(struct SessionHandle *data)
{
CURLcode res;
@@ -1573,49 +2019,72 @@ CURLcode Curl_perform(struct SessionHandle *data)
*/
do {
- Curl_pgrsTime(data, TIMER_STARTSINGLE);
- res = Curl_connect(data, &conn);
+ res = Curl_connect_host(data, &conn); /* primary connection */
+
+ if(res == CURLE_OK) {
+ if (data->set.source_host) /* 3rd party transfer */
+ res = Curl_pretransfersec(conn);
+ else
+ conn->sec_conn = NULL;
+ }
+
if(res == CURLE_OK) {
- res = Curl_do(&conn);
- if(res == CURLE_OK) {
- CURLcode res2; /* just a local extra result container */
+ res = Curl_do(&conn);
- if(conn->protocol&PROT_FTPS)
- /* FTPS, disable ssl while transfering data */
- conn->ssl.use = FALSE;
+ /* for non 3rd party transfer only */
+ if(res == CURLE_OK && !data->set.source_host) {
res = Transfer(conn); /* now fetch that URL please */
- if(conn->protocol&PROT_FTPS)
- /* FTPS, enable ssl again after havving transferred data */
- conn->ssl.use = TRUE;
-
- if(res == CURLE_OK)
- /*
- * We must duplicate the new URL here as the connection data
- * may be free()ed in the Curl_done() function.
- */
- newurl = conn->newurl?strdup(conn->newurl):NULL;
+ if(res == CURLE_OK) {
+
+ if((conn->keep.bytecount+conn->headerbytecount == 0) &&
+ conn->bits.reuse) {
+ /* We got no data and we attempted to re-use a connection. This
+ might happen if the connection was left alive when we were done
+ using it before, but that was closed when we wanted to read
+ from it again. Bad luck. Retry the same request on a fresh
+ connect! */
+ infof(data, "Connection died, retrying a fresh connect\n");
+ newurl = strdup(conn->data->change.url);
+
+ conn->bits.close = TRUE; /* close this connection */
+ conn->bits.retry = TRUE; /* mark this as a connection we're about
+ to retry. Marking it this way should
+ prevent i.e HTTP transfers to return
+ error just because nothing has been
+ transfered! */
+ }
+ else
+ /*
+ * We must duplicate the new URL here as the connection data
+ * may be free()ed in the Curl_done() function.
+ */
+ newurl = conn->newurl?strdup(conn->newurl):NULL;
+ }
else {
/* The transfer phase returned error, we mark the connection to get
* closed to prevent being re-used. This is becasue we can't
* possibly know if the connection is in a good shape or not now. */
conn->bits.close = TRUE;
- if(-1 !=conn->secondarysocket) {
+ if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
/* if we failed anywhere, we must clean up the secondary socket if
it was used */
- sclose(conn->secondarysocket);
- conn->secondarysocket=-1;
+ sclose(conn->sock[SECONDARYSOCKET]);
+ conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
}
}
/* Always run Curl_done(), even if some of the previous calls
failed, but return the previous (original) error code */
- res2 = Curl_done(conn);
+ res2 = Curl_done(&conn, res);
if(CURLE_OK == res)
res = res2;
}
+ else
+ /* Curl_do() failed, clean up left-overs in the done-call */
+ res2 = Curl_done(&conn, res);
/*
* Important: 'conn' cannot be used here, since it may have been closed
@@ -1646,15 +2115,20 @@ CURLcode Curl_perform(struct SessionHandle *data)
return res;
}
-CURLcode
+/*
+ * Curl_Transfer() is called to setup some basic properties for the upcoming
+ * transfer.
+ */
+CURLcode
Curl_Transfer(struct connectdata *c_conn, /* connection data */
- int sockfd, /* socket to read from or -1 */
- int size, /* -1 if unknown at this point */
- bool getheader, /* TRUE if header parsing is wanted */
- long *bytecountp, /* return number of bytes read or NULL */
- int writesockfd, /* socket to write to, it may very well be
- the same we read from. -1 disables */
- long *writebytecountp /* return number of bytes written or
+ int sockindex, /* socket index to read from or -1 */
+ curl_off_t size, /* -1 if unknown at this point */
+ bool getheader, /* TRUE if header parsing is wanted */
+ curl_off_t *bytecountp, /* return number of bytes read or NULL */
+ int writesockindex, /* socket index to write to, it may very
+ well be the same we read from. -1
+ disables */
+ curl_off_t *writecountp /* return number of bytes written or
NULL */
)
{
@@ -1662,22 +2136,52 @@ Curl_Transfer(struct connectdata *c_conn, /* connection data */
if(!conn)
return CURLE_BAD_FUNCTION_ARGUMENT;
+ curlassert((sockindex <= 1) && (sockindex >= -1));
+
/* now copy all input parameters */
- conn->sockfd = sockfd;
+ conn->sockfd = sockindex==-1?
+ CURL_SOCKET_BAD:conn->sock[sockindex];
conn->size = size;
conn->bits.getheader = getheader;
conn->bytecountp = bytecountp;
- conn->writesockfd = writesockfd;
- conn->writebytecountp = writebytecountp;
+ conn->writesockfd = writesockindex==-1?
+ CURL_SOCKET_BAD:conn->sock[writesockindex];
+ conn->writebytecountp = writecountp;
return CURLE_OK;
}
-
+
/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
+ * Curl_pretransfersec() prepares the secondary connection (used for 3rd party
+ * FTP transfers).
*/
+CURLcode Curl_pretransfersec(struct connectdata *conn)
+{
+ CURLcode status = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ struct connectdata *sec_conn = NULL; /* secondary connection */
+
+ /* update data with source host options */
+ char *url = aprintf( "%s://%s/", conn->protostr, data->set.source_host);
+
+ if(!url)
+ return CURLE_OUT_OF_MEMORY;
+
+ if(data->change.url_alloc)
+ free(data->change.url);
+
+ data->change.url_alloc = TRUE;
+ data->change.url = url;
+ data->set.ftpport = data->set.source_port;
+ data->set.userpwd = data->set.source_userpwd;
+
+ /* secondary connection */
+ status = Curl_connect_host(data, &sec_conn);
+ if(CURLE_OK == status) {
+ sec_conn->data = data;
+ conn->sec_conn = sec_conn;
+ }
+
+ return status;
+}
diff --git a/Source/CTest/Curl/transfer.h b/Source/CTest/Curl/transfer.h
index cc15343..1b7eb82 100644
--- a/Source/CTest/Curl/transfer.h
+++ b/Source/CTest/Curl/transfer.h
@@ -1,18 +1,18 @@
#ifndef __TRANSFER_H
#define __TRANSFER_H
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -24,25 +24,29 @@
***************************************************************************/
CURLcode Curl_perform(struct SessionHandle *data);
CURLcode Curl_pretransfer(struct SessionHandle *data);
+CURLcode Curl_pretransfersec(struct connectdata *conn);
CURLcode Curl_posttransfer(struct SessionHandle *data);
CURLcode Curl_follow(struct SessionHandle *data, char *newurl);
CURLcode Curl_readwrite(struct connectdata *conn, bool *done);
-void Curl_single_fdset(struct connectdata *conn,
+void Curl_single_fdset(struct connectdata *conn,
fd_set *read_fd_set,
fd_set *write_fd_set,
fd_set *exc_fd_set,
int *max_fd);
CURLcode Curl_readwrite_init(struct connectdata *conn);
+CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp);
+
/* This sets up a forthcoming transfer */
-CURLcode
+CURLcode
Curl_Transfer (struct connectdata *data,
- int sockfd, /* socket to read from or -1 */
- int size, /* -1 if unknown at this point */
+ int sockindex, /* socket index to read from or -1 */
+ curl_off_t size, /* -1 if unknown at this point */
bool getheader, /* TRUE if header parsing is wanted */
- long *bytecountp, /* return number of bytes read */
- int writesockfd, /* socket to write to, it may very well be
- the same we read from. -1 disables */
- long *writebytecountp /* return number of bytes written */
+ curl_off_t *bytecountp, /* return number of bytes read */
+ int writesockindex, /* socket index to write to, it may
+ very well be the same we read from.
+ -1 disables */
+ curl_off_t *writecountp /* return number of bytes written */
);
#endif
diff --git a/Source/CTest/Curl/url.c b/Source/CTest/Curl/url.c
index 883e838..6fff8bf 100644
--- a/Source/CTest/Curl/url.c
+++ b/Source/CTest/Curl/url.c
@@ -1,16 +1,16 @@
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -36,7 +36,6 @@
#include <errno.h>
#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
-#include <winsock.h>
#include <time.h>
#include <io.h>
#else
@@ -45,7 +44,6 @@
#endif
#include <netinet/in.h>
#include <sys/time.h>
-#include <sys/resource.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
@@ -67,7 +65,7 @@
#include <sys/select.h>
#endif
-#ifdef VMS
+#ifdef VMS
#include <in.h>
#include <inet.h>
#endif
@@ -83,8 +81,28 @@
#error "We can't compile without socket() support!"
#endif
+
+#endif
+
+#ifdef USE_LIBIDN
+#include <idna.h>
+#include <stringprep.h>
+#ifdef HAVE_IDN_FREE_H
+#include <idn-free.h>
+#else
+void idn_free (void *ptr); /* prototype from idn-free.h, not provided by
+ libidn 0.4.5's make install! */
+#endif
+#ifndef HAVE_IDN_FREE
+/* if idn_free() was not found in this version of libidn, use plain free()
+ instead */
+#define idn_free(x) (free)(x)
+#endif
#endif
+#ifdef HAVE_OPENSSL_ENGINE_H
+#include <openssl/engine.h>
+#endif
#include "urldata.h"
#include "netrc.h"
@@ -95,13 +113,15 @@
#include "if2ip.h"
#include "transfer.h"
#include "sendf.h"
-#include "getpass.h"
#include "progress.h"
#include "cookie.h"
#include "strequal.h"
#include "escape.h"
#include "strtok.h"
#include "share.h"
+#include "content_encoding.h"
+#include "http_digest.h"
+#include "http_negotiate.h"
/* And now for the protocols */
#include "ftp.h"
@@ -112,9 +132,8 @@
#include "ldap.h"
#include "url.h"
#include "connect.h"
-#include "ca-bundle.h"
-
-#include <curl/types.h>
+#include "inet_ntop.h"
+#include <ca-bundle.h>
#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
#include "inet_ntoa_r.h"
@@ -123,25 +142,28 @@
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
-#ifdef KRB4
+#ifdef HAVE_KRB4
#include "security.h"
#endif
+#include "memory.h"
/* The last #include file should be: */
-#ifdef MALLOCDEBUG
#include "memdebug.h"
-#endif
/* Local static prototypes */
-static int ConnectionKillOne(struct SessionHandle *data);
+static long ConnectionKillOne(struct SessionHandle *data);
static bool ConnectionExists(struct SessionHandle *data,
struct connectdata *needle,
struct connectdata **usethis);
-static unsigned int ConnectionStore(struct SessionHandle *data,
- struct connectdata *conn);
+static long ConnectionStore(struct SessionHandle *data,
+ struct connectdata *conn);
+static bool safe_strequal(char* str1, char* str2);
+#ifndef USE_ARES
+/* not for Win32, unless it is cygwin
+ not for ares builds */
+#if !defined(WIN32) || defined(__CYGWIN32__)
-#if !defined(WIN32)||defined(__CYGWIN32__)
#ifndef RETSIGTYPE
#define RETSIGTYPE void
#endif
@@ -149,17 +171,23 @@ static unsigned int ConnectionStore(struct SessionHandle *data,
extern sigjmp_buf curl_jmpenv;
#endif
static
-RETSIGTYPE alarmfunc(int signal)
+RETSIGTYPE alarmfunc(int sig)
{
/* this is for "-ansi -Wall -pedantic" to stop complaining! (rabe) */
- (void)signal;
+ (void)sig;
#ifdef HAVE_SIGSETJMP
siglongjmp(curl_jmpenv, 1);
#endif
return;
}
#endif
+#endif /* USE_ARES */
+void Curl_safefree(void *ptr)
+{
+ if(ptr)
+ free(ptr);
+}
/*
* This is the internal function curl_easy_cleanup() calls. This should
@@ -180,15 +208,11 @@ CURLcode Curl_close(struct SessionHandle *data)
Curl_SSL_Close_All(data);
#endif
- /* No longer a dirty share, if it exists */
- if (data->share)
- data->share->dirty--;
-
if(data->change.cookielist) /* clean up list if any */
curl_slist_free_all(data->change.cookielist);
- if(data->state.auth_host)
- free(data->state.auth_host);
+ Curl_safefree(data->state.auth_host);
+ Curl_safefree(data->state.scratch);
if(data->change.proxy_alloc)
free(data->change.proxy);
@@ -199,120 +223,142 @@ CURLcode Curl_close(struct SessionHandle *data)
if(data->change.url_alloc)
free(data->change.url);
- if(data->state.headerbuff)
- free(data->state.headerbuff);
+ Curl_safefree(data->state.headerbuff);
#ifndef CURL_DISABLE_HTTP
- if(data->set.cookiejar)
+ Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
+ if(data->set.cookiejar) {
/* we have a "destination" for all the cookies to get dumped to */
- Curl_cookie_output(data->cookies, data->set.cookiejar);
-
- Curl_cookie_cleanup(data->cookies);
+ if(Curl_cookie_output(data->cookies, data->set.cookiejar))
+ infof(data, "WARNING: failed to save cookies in %s\n",
+ data->set.cookiejar);
+ }
+
+ if( !data->share || (data->cookies != data->share->cookies) ) {
+ Curl_cookie_cleanup(data->cookies);
+ }
+ Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+
+ Curl_digest_cleanup(data);
#endif
/* free the connection cache */
free(data->state.connects);
- if(data->info.contenttype)
- free(data->info.contenttype);
+ Curl_safefree(data->info.contenttype);
- free(data);
- return CURLE_OK;
-}
+#ifdef USE_ARES
+ /* this destroys the channel and we cannot use it anymore after this */
+ ares_destroy(data->state.areschannel);
+#endif
-static
-int my_getpass(void *clientp, const char *prompt, char* buffer, int buflen )
-{
- char *retbuf;
- clientp=NULL; /* prevent compiler warning */
+ /* No longer a dirty share, if it exists */
+ if (data->share)
+ data->share->dirty--;
- retbuf = getpass_r(prompt, buffer, buflen);
- if(NULL == retbuf)
- return 1;
- else
- return 0; /* success */
+ free(data);
+ return CURLE_OK;
}
+/**
+ * Curl_open()
+ *
+ * @param curl is a pointer to a sessionhandle pointer that gets set by this
+ * function.
+ * @return CURLcode
+ */
CURLcode Curl_open(struct SessionHandle **curl)
{
- /* We don't yet support specifying the URL at this point */
+ CURLcode res = CURLE_OK;
struct SessionHandle *data;
/* Very simple start-up: alloc the struct, init it with zeroes and return */
- data = (struct SessionHandle *)malloc(sizeof(struct SessionHandle));
+ data = (struct SessionHandle *)calloc(1, sizeof(struct SessionHandle));
if(!data)
/* this is a very serious error */
return CURLE_OUT_OF_MEMORY;
-
- memset(data, 0, sizeof(struct SessionHandle));
+
+#ifdef USE_ARES
+ if(ARES_SUCCESS != ares_init(&data->state.areschannel)) {
+ free(data);
+ return CURLE_FAILED_INIT;
+ }
+ /* make sure that all other returns from this function should destroy the
+ ares channel before returning error! */
+#endif
/* We do some initial setup here, all those fields that can't be just 0 */
data->state.headerbuff=(char*)malloc(HEADERSIZE);
- if(!data->state.headerbuff) {
- free(data); /* free the memory again */
- return CURLE_OUT_OF_MEMORY;
- }
+ if(!data->state.headerbuff)
+ res = CURLE_OUT_OF_MEMORY;
+ else {
+ data->state.headersize=HEADERSIZE;
- data->state.headersize=HEADERSIZE;
+ data->set.out = stdout; /* default output to stdout */
+ data->set.in = stdin; /* default input from stdin */
+ data->set.err = stderr; /* default stderr to stderr */
- data->set.out = stdout; /* default output to stdout */
- data->set.in = stdin; /* default input from stdin */
- data->set.err = stderr; /* default stderr to stderr */
-
- /* use fwrite as default function to store output */
- data->set.fwrite = (curl_write_callback)fwrite;
+ /* use fwrite as default function to store output */
+ data->set.fwrite = (curl_write_callback)fwrite;
- /* use fread as default function to read input */
- data->set.fread = (curl_read_callback)fread;
-
- /* set the default passwd function */
- data->set.fpasswd = my_getpass;
+ /* use fread as default function to read input */
+ data->set.fread = (curl_read_callback)fread;
- data->set.infilesize = -1; /* we don't know any size */
+ data->set.infilesize = -1; /* we don't know any size */
- data->state.current_speed = -1; /* init to negative == impossible */
+ data->state.current_speed = -1; /* init to negative == impossible */
- data->set.httpreq = HTTPREQ_GET; /* Default HTTP request */
- data->set.ftp_use_epsv = TRUE; /* FTP defaults to EPSV operations */
+ data->set.httpreq = HTTPREQ_GET; /* Default HTTP request */
+ data->set.ftp_use_epsv = TRUE; /* FTP defaults to EPSV operations */
+ data->set.ftp_use_eprt = TRUE; /* FTP defaults to EPRT operations */
- data->set.dns_cache_timeout = 60; /* Timeout every 60 seconds by default */
-
- /* make libcurl quiet by default: */
- data->set.hide_progress = TRUE; /* CURLOPT_NOPROGRESS changes these */
- data->progress.flags |= PGRS_HIDE;
+ data->set.dns_cache_timeout = 60; /* Timeout every 60 seconds by default */
- /* Set the default size of the SSL session ID cache */
- data->set.ssl.numsessions = 5;
+ /* make libcurl quiet by default: */
+ data->set.hide_progress = TRUE; /* CURLOPT_NOPROGRESS changes these */
+ data->progress.flags |= PGRS_HIDE;
- data->set.proxyport = 1080;
-
- data->set.proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */
+ /* Set the default size of the SSL session ID cache */
+ data->set.ssl.numsessions = 5;
- /* create an array with connection data struct pointers */
- data->state.numconnects = 5; /* hard-coded right now */
- data->state.connects = (struct connectdata **)
- malloc(sizeof(struct connectdata *) * data->state.numconnects);
-
- if(!data->state.connects) {
- free(data);
- return CURLE_OUT_OF_MEMORY;
- }
+ data->set.proxyport = 1080;
+ data->set.proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */
+ data->set.httpauth = CURLAUTH_BASIC; /* defaults to basic */
+ data->set.proxyauth = CURLAUTH_BASIC; /* defaults to basic */
- /*
- * libcurl 7.10 introduces SSL verification *by default*! This needs to be
- * switched off unless wanted.
- */
- data->set.ssl.verifypeer = TRUE;
- data->set.ssl.verifyhost = 2;
+ /* create an array with connection data struct pointers */
+ data->state.numconnects = 5; /* hard-coded right now */
+ data->state.connects = (struct connectdata **)
+ malloc(sizeof(struct connectdata *) * data->state.numconnects);
+
+ if(!data->state.connects)
+ res = CURLE_OUT_OF_MEMORY;
+ else
+ memset(data->state.connects, 0,
+ sizeof(struct connectdata *)*data->state.numconnects);
+
+ /*
+ * libcurl 7.10 introduced SSL verification *by default*! This needs to be
+ * switched off unless wanted.
+ */
+ data->set.ssl.verifypeer = TRUE;
+ data->set.ssl.verifyhost = 2;
#ifdef CURL_CA_BUNDLE
- /* This is our prefered CA cert bundle since install time */
- data->set.ssl.CAfile = (char *)CURL_CA_BUNDLE;
+ /* This is our prefered CA cert bundle since install time */
+ data->set.ssl.CAfile = (char *)CURL_CA_BUNDLE;
#endif
+ }
-
- memset(data->state.connects, 0,
- sizeof(struct connectdata *)*data->state.numconnects);
+ if(res) {
+#ifdef USE_ARES
+ ares_destroy(data->state.areschannel);
+#endif
+ if(data->state.headerbuff)
+ free(data->state.headerbuff);
+ free(data);
+ data = NULL;
+ }
*curl = data;
return CURLE_OK;
@@ -329,14 +375,14 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
case CURLOPT_DNS_CACHE_TIMEOUT:
data->set.dns_cache_timeout = va_arg(param, int);
break;
- case CURLOPT_DNS_USE_GLOBAL_CACHE:
+ case CURLOPT_DNS_USE_GLOBAL_CACHE:
{
int use_cache = va_arg(param, int);
if (use_cache) {
Curl_global_host_cache_init();
}
- data->set.global_dns_cache = (bool)use_cache;
+ data->set.global_dns_cache = use_cache;
}
break;
case CURLOPT_SSL_CIPHER_LIST:
@@ -365,12 +411,12 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
{
long newconnects= va_arg(param, long);
struct connectdata **newptr;
+ long i;
if(newconnects < data->state.numconnects) {
/* Since this number is *decreased* from the existing number, we must
close the possibly open connections that live on the indexes that
are being removed! */
- int i;
for(i=newconnects; i< data->state.numconnects; i++)
Curl_disconnect(data->state.connects[i]);
}
@@ -381,6 +427,12 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
if(!newptr)
/* we closed a few connections in vain, but so what? */
return CURLE_OUT_OF_MEMORY;
+
+ /* nullify the newly added pointers */
+ for(i=data->state.numconnects; i<newconnects; i++) {
+ newptr[i] = NULL;
+ }
+
data->state.connects = newptr;
data->state.numconnects = newconnects;
}
@@ -398,33 +450,33 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
* When this transfer is done, it must not be left to be reused by a
* subsequent transfer but shall be closed immediately.
*/
- data->set.reuse_forbid = (bool)(va_arg(param, long)?TRUE:FALSE);
+ data->set.reuse_forbid = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_FRESH_CONNECT:
/*
* This transfer shall not use a previously cached connection but
* should be made with a fresh new connect!
*/
- data->set.reuse_fresh = (bool)(va_arg(param, long)?TRUE:FALSE);
+ data->set.reuse_fresh = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_VERBOSE:
/*
* Verbose means infof() calls that give a lot of information about
* the connection and transfer procedures as well as internal choices.
*/
- data->set.verbose = (bool)(va_arg(param, long)?TRUE:FALSE);
+ data->set.verbose = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_HEADER:
/*
* Set to include the header in the general data output stream.
*/
- data->set.http_include_header = (bool)(va_arg(param, long)?TRUE:FALSE);
+ data->set.include_header = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_NOPROGRESS:
/*
* Shut off the internal supported progress meter
*/
- data->set.hide_progress = (bool)(va_arg(param, long)?TRUE:FALSE);
+ data->set.hide_progress = va_arg(param, long)?TRUE:FALSE;
if(data->set.hide_progress)
data->progress.flags |= PGRS_HIDE;
else
@@ -434,20 +486,25 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
/*
* Do not include the body part in the output data stream.
*/
- data->set.no_body = (bool)(va_arg(param, long)?TRUE:FALSE);
+ data->set.opt_no_body = va_arg(param, long)?TRUE:FALSE;
+ if(data->set.opt_no_body)
+ /* in HTTP lingo, this means using the HEAD request */
+ data->set.httpreq = HTTPREQ_HEAD;
break;
case CURLOPT_FAILONERROR:
/*
* Don't output the >=300 error code HTML-page, but instead only
* return error.
*/
- data->set.http_fail_on_error = (bool)(va_arg(param, long)?TRUE:FALSE);
+ data->set.http_fail_on_error = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_UPLOAD:
+ case CURLOPT_PUT:
/*
- * We want to sent data to the remote host
+ * We want to sent data to the remote host. If this is HTTP, that equals
+ * using the PUT request.
*/
- data->set.upload = (bool)(va_arg(param, long)?TRUE:FALSE);
+ data->set.upload = va_arg(param, long)?TRUE:FALSE;
if(data->set.upload)
/* If this is HTTP, PUT is what's needed to "upload" */
data->set.httpreq = HTTPREQ_PUT;
@@ -457,20 +514,34 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
* Try to get the file time of the remote document. The time will
* later (possibly) become available using curl_easy_getinfo().
*/
- data->set.get_filetime = (bool)(va_arg(param, long)?TRUE:FALSE);
+ data->set.get_filetime = va_arg(param, long)?TRUE:FALSE;
+ break;
+ case CURLOPT_FTP_CREATE_MISSING_DIRS:
+ /*
+ * An FTP option that modifies an upload to create missing directories on
+ * the server.
+ */
+ data->set.ftp_create_missing_dirs = va_arg( param , long )?TRUE:FALSE;
+ break;
+ case CURLOPT_FTP_RESPONSE_TIMEOUT:
+ /*
+ * An FTP option that specifies how quickly an FTP response must be
+ * obtained before it is considered failure.
+ */
+ data->set.ftp_response_timeout = va_arg( param , long );
break;
case CURLOPT_FTPLISTONLY:
/*
* An FTP option that changes the command to one that asks for a list
* only, no file info details.
*/
- data->set.ftp_list_only = (bool)(va_arg(param, long)?TRUE:FALSE);
+ data->set.ftp_list_only = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_FTPAPPEND:
/*
* We want to upload and append to an existing (FTP) file.
*/
- data->set.ftp_append = (bool)(va_arg(param, long)?TRUE:FALSE);
+ data->set.ftp_append = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_NETRC:
/*
@@ -478,18 +549,11 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
*/
data->set.use_netrc = (enum CURL_NETRC_OPTION)va_arg(param, long);
break;
- case CURLOPT_FOLLOWLOCATION:
- /*
- * Follow Location: header hints on a HTTP-server.
- */
- data->set.http_follow_location = (bool)(va_arg(param, long)?TRUE:FALSE);
- break;
- case CURLOPT_HTTP_VERSION:
+ case CURLOPT_NETRC_FILE:
/*
- * This sets a requested HTTP version to be used. The value is one of
- * the listed enums in curl/curl.h.
+ * Use this file instead of the $HOME/.netrc file
*/
- data->set.httpversion = va_arg(param, long);
+ data->set.netrc_file = va_arg(param, char *);
break;
case CURLOPT_TRANSFERTEXT:
/*
@@ -498,15 +562,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
*
* Transfer using ASCII (instead of BINARY).
*/
- data->set.ftp_ascii = (bool)(va_arg(param, long)?TRUE:FALSE);
- break;
- case CURLOPT_PUT:
- /*
- * Use the HTTP PUT request to transfer data if this is TRUE. If this is
- * FALSE, don't set the httpreq. We can't know what to revert it to!
- */
- if(va_arg(param, long))
- data->set.httpreq = HTTPREQ_PUT;
+ data->set.ftp_ascii = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_TIMECONDITION:
/*
@@ -520,7 +576,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
* This is the value to compare with the remote document with the
* method set with CURLOPT_TIMECONDITION
*/
- data->set.timevalue = va_arg(param, long);
+ data->set.timevalue = (time_t)va_arg(param, long);
break;
case CURLOPT_SSLVERSION:
/*
@@ -530,6 +586,167 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
data->set.ssl.version = va_arg(param, long);
break;
+#ifndef CURL_DISABLE_HTTP
+ case CURLOPT_AUTOREFERER:
+ /*
+ * Switch on automatic referer that gets set if curl follows locations.
+ */
+ data->set.http_auto_referer = va_arg(param, long)?1:0;
+ break;
+
+ case CURLOPT_ENCODING:
+ /*
+ * String to use at the value of Accept-Encoding header.
+ *
+ * If the encoding is set to "" we use an Accept-Encoding header that
+ * encompasses all the encodings we support.
+ * If the encoding is set to NULL we don't send an Accept-Encoding header
+ * and ignore an received Content-Encoding header.
+ *
+ */
+ data->set.encoding = va_arg(param, char *);
+ if(data->set.encoding && !*data->set.encoding)
+ data->set.encoding = (char*)ALL_CONTENT_ENCODINGS;
+ break;
+
+ case CURLOPT_FOLLOWLOCATION:
+ /*
+ * Follow Location: header hints on a HTTP-server.
+ */
+ data->set.http_follow_location = va_arg(param, long)?TRUE:FALSE;
+ break;
+
+ case CURLOPT_UNRESTRICTED_AUTH:
+ /*
+ * Send authentication (user+password) when following locations, even when
+ * hostname changed.
+ */
+ data->set.http_disable_hostname_check_before_authentication =
+ va_arg(param, long)?TRUE:FALSE;
+ break;
+
+ case CURLOPT_MAXREDIRS:
+ /*
+ * The maximum amount of hops you allow curl to follow Location:
+ * headers. This should mostly be used to detect never-ending loops.
+ */
+ data->set.maxredirs = va_arg(param, long);
+ break;
+
+ case CURLOPT_POST:
+ /* Does this option serve a purpose anymore? Yes it does, when
+ CURLOPT_POSTFIELDS isn't used and the POST data is read off the
+ callback! */
+ if(va_arg(param, long))
+ data->set.httpreq = HTTPREQ_POST;
+ break;
+
+ case CURLOPT_POSTFIELDS:
+ /*
+ * A string with POST data. Makes curl HTTP POST.
+ */
+ data->set.postfields = va_arg(param, char *);
+ if(data->set.postfields)
+ data->set.httpreq = HTTPREQ_POST;
+ break;
+
+ case CURLOPT_POSTFIELDSIZE:
+ /*
+ * The size of the POSTFIELD data to prevent libcurl to do strlen() to
+ * figure it out. Enables binary posts.
+ */
+ data->set.postfieldsize = va_arg(param, long);
+ break;
+
+ case CURLOPT_POSTFIELDSIZE_LARGE:
+ /*
+ * The size of the POSTFIELD data to prevent libcurl to do strlen() to
+ * figure it out. Enables binary posts.
+ */
+ data->set.postfieldsize = va_arg(param, curl_off_t);
+ break;
+
+ case CURLOPT_HTTPPOST:
+ /*
+ * Set to make us do HTTP POST
+ */
+ data->set.httppost = va_arg(param, struct curl_httppost *);
+ if(data->set.httppost)
+ data->set.httpreq = HTTPREQ_POST_FORM;
+ break;
+
+ case CURLOPT_REFERER:
+ /*
+ * String to set in the HTTP Referer: field.
+ */
+ if(data->change.referer_alloc) {
+ free(data->change.referer);
+ data->change.referer_alloc = FALSE;
+ }
+ data->set.set_referer = va_arg(param, char *);
+ data->change.referer = data->set.set_referer;
+ break;
+
+ case CURLOPT_USERAGENT:
+ /*
+ * String to use in the HTTP User-Agent field
+ */
+ data->set.useragent = va_arg(param, char *);
+ break;
+
+ case CURLOPT_HTTPHEADER:
+ /*
+ * Set a list with HTTP headers to use (or replace internals with)
+ */
+ data->set.headers = va_arg(param, struct curl_slist *);
+ break;
+
+ case CURLOPT_HTTP200ALIASES:
+ /*
+ * Set a list of aliases for HTTP 200 in response header
+ */
+ data->set.http200aliases = va_arg(param, struct curl_slist *);
+ break;
+
+ case CURLOPT_COOKIE:
+ /*
+ * Cookie string to send to the remote server in the request.
+ */
+ data->set.cookie = va_arg(param, char *);
+ break;
+
+ case CURLOPT_COOKIEFILE:
+ /*
+ * Set cookie file to read and parse. Can be used multiple times.
+ */
+ cookiefile = (char *)va_arg(param, void *);
+ if(cookiefile) {
+ struct curl_slist *cl;
+ /* append the cookie file name to the list of file names, and deal with
+ them later */
+ cl = curl_slist_append(data->change.cookielist, cookiefile);
+
+ if(!cl)
+ return CURLE_OUT_OF_MEMORY;
+
+ data->change.cookielist = cl;
+ }
+ break;
+
+ case CURLOPT_COOKIEJAR:
+ /*
+ * Set cookie file name to dump all cookies to when we're done.
+ */
+ data->set.cookiejar = (char *)va_arg(param, void *);
+
+ /*
+ * Activate the cookie parser. This may or may not already
+ * have been made.
+ */
+ data->cookies = Curl_cookie_init(data, NULL, data->cookies,
+ data->set.cookiesession);
+ break;
+
case CURLOPT_COOKIESESSION:
/*
* Set this option to TRUE to start a new "cookie session". It will
@@ -549,33 +766,111 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
data->set.cookiesession = (bool)va_arg(param, long);
break;
-#ifndef CURL_DISABLE_HTTP
- case CURLOPT_COOKIEFILE:
+ case CURLOPT_HTTPGET:
/*
- * Set cookie file to read and parse. Can be used multiple times.
+ * Set to force us do HTTP GET
*/
- cookiefile = (char *)va_arg(param, void *);
- if(cookiefile)
- /* append the cookie file name to the list of file names, and deal with
- them later */
- data->change.cookielist =
- curl_slist_append(data->change.cookielist, cookiefile);
+ if(va_arg(param, long)) {
+ data->set.httpreq = HTTPREQ_GET;
+ data->set.upload = FALSE; /* switch off upload */
+ }
break;
- case CURLOPT_COOKIEJAR:
+ case CURLOPT_HTTP_VERSION:
/*
- * Set cookie file name to dump all cookies to when we're done.
+ * This sets a requested HTTP version to be used. The value is one of
+ * the listed enums in curl/curl.h.
*/
- data->set.cookiejar = (char *)va_arg(param, void *);
+ data->set.httpversion = va_arg(param, long);
+ break;
+ case CURLOPT_HTTPPROXYTUNNEL:
/*
- * Activate the cookie parser. This may or may not already
- * have been made.
+ * Tunnel operations through the proxy instead of normal proxy use
*/
- data->cookies = Curl_cookie_init(NULL, data->cookies,
- data->set.cookiesession);
+ data->set.tunnel_thru_httpproxy = va_arg(param, long)?TRUE:FALSE;
break;
+
+ case CURLOPT_CUSTOMREQUEST:
+ /*
+ * Set a custom string to use as request
+ */
+ data->set.customrequest = va_arg(param, char *);
+
+ /* we don't set
+ data->set.httpreq = HTTPREQ_CUSTOM;
+ here, we continue as if we were using the already set type
+ and this just changes the actual request keyword */
+ break;
+
+ case CURLOPT_PROXY:
+ /*
+ * Set proxy server:port to use as HTTP proxy.
+ *
+ * If the proxy is set to "" we explicitly say that we don't want to use a
+ * proxy (even though there might be environment variables saying so).
+ *
+ * Setting it to NULL, means no proxy but allows the environment variables
+ * to decide for us.
+ */
+ if(data->change.proxy_alloc) {
+ /*
+ * The already set string is allocated, free that first
+ */
+ data->change.proxy_alloc=FALSE;;
+ free(data->change.proxy);
+ }
+ data->set.set_proxy = va_arg(param, char *);
+ data->change.proxy = data->set.set_proxy;
+ break;
+
+ case CURLOPT_PROXYPORT:
+ /*
+ * Explicitly set HTTP proxy port number.
+ */
+ data->set.proxyport = va_arg(param, long);
+ break;
+
+ case CURLOPT_HTTPAUTH:
+ /*
+ * Set HTTP Authentication type BITMASK.
+ */
+ {
+ long auth = va_arg(param, long);
+ /* switch off bits we can't support */
+#ifndef USE_SSLEAY
+ auth &= ~CURLAUTH_NTLM; /* no NTLM without SSL */
+#endif
+#ifndef HAVE_GSSAPI
+ auth &= ~CURLAUTH_GSSNEGOTIATE; /* no GSS-Negotiate without GSSAPI */
#endif
+ if(!auth)
+ return CURLE_FAILED_INIT; /* no supported types left! */
+
+ data->set.httpauth = auth;
+ }
+ break;
+
+ case CURLOPT_PROXYAUTH:
+ /*
+ * Set HTTP Authentication type BITMASK.
+ */
+ {
+ long auth = va_arg(param, long);
+ /* switch off bits we can't support */
+#ifndef USE_SSLEAY
+ auth &= ~CURLAUTH_NTLM; /* no NTLM without SSL */
+#endif
+#ifndef HAVE_GSSAPI
+ auth &= ~CURLAUTH_GSSNEGOTIATE; /* no GSS-Negotiate without GSSAPI */
+#endif
+ if(!auth)
+ return CURLE_FAILED_INIT; /* no supported types left! */
+
+ data->set.proxyauth = auth;
+ }
+ break;
+#endif /* CURL_DISABLE_HTTP */
case CURLOPT_WRITEHEADER:
/*
@@ -583,12 +878,6 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
*/
data->set.writeheader = (void *)va_arg(param, void *);
break;
- case CURLOPT_COOKIE:
- /*
- * Cookie string to send to the remote server in the request.
- */
- data->set.cookie = va_arg(param, char *);
- break;
case CURLOPT_ERRORBUFFER:
/*
* Error buffer provided by the caller to get the human readable
@@ -607,47 +896,15 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
* Use FTP PORT, this also specifies which IP address to use
*/
data->set.ftpport = va_arg(param, char *);
- data->set.ftp_use_port = (bool)(data->set.ftpport?TRUE:FALSE);
- break;
-
- case CURLOPT_FTP_USE_EPSV:
- data->set.ftp_use_epsv = (bool)(va_arg(param, long)?TRUE:FALSE);
+ data->set.ftp_use_port = data->set.ftpport?1:0;
break;
- case CURLOPT_HTTPHEADER:
- /*
- * Set a list with HTTP headers to use (or replace internals with)
- */
- data->set.headers = va_arg(param, struct curl_slist *);
- break;
- case CURLOPT_CUSTOMREQUEST:
- /*
- * Set a custom string to use as request
- */
- data->set.customrequest = va_arg(param, char *);
-
- /* we don't set
- data->set.httpreq = HTTPREQ_CUSTOM;
- here, we continue as if we were using the already set type
- and this just changes the actual request keyword */
- break;
- case CURLOPT_HTTPPOST:
- /*
- * Set to make us do HTTP POST
- */
- data->set.httppost = va_arg(param, struct HttpPost *);
- if(data->set.httppost)
- data->set.httpreq = HTTPREQ_POST_FORM;
+ case CURLOPT_FTP_USE_EPRT:
+ data->set.ftp_use_eprt = va_arg(param, long)?TRUE:FALSE;
break;
- case CURLOPT_HTTPGET:
- /*
- * Set to force us do HTTP GET
- */
- if(va_arg(param, long)) {
- data->set.httpreq = HTTPREQ_GET;
- data->set.upload = FALSE; /* switch off upload */
- }
+ case CURLOPT_FTP_USE_EPSV:
+ data->set.ftp_use_epsv = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_INFILE:
@@ -664,6 +921,13 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
*/
data->set.infilesize = va_arg(param, long);
break;
+ case CURLOPT_INFILESIZE_LARGE:
+ /*
+ * If known, this should inform curl about the file size of the
+ * to-be-uploaded file.
+ */
+ data->set.infilesize = va_arg(param, curl_off_t);
+ break;
case CURLOPT_LOW_SPEED_LIMIT:
/*
* The low speed limit that if transfers are below this for
@@ -689,6 +953,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
}
data->set.set_url = va_arg(param, char *);
data->change.url = data->set.set_url;
+ data->change.url_changed = TRUE;
break;
case CURLOPT_PORT:
/*
@@ -696,77 +961,6 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
*/
data->set.use_port = va_arg(param, long);
break;
- case CURLOPT_POST:
- /* Does this option serve a purpose anymore? Yes it does, when
- CURLOPT_POSTFIELDS isn't used and the POST data is read off the
- callback! */
- if(va_arg(param, long))
- data->set.httpreq = HTTPREQ_POST;
- break;
- case CURLOPT_POSTFIELDS:
- /*
- * A string with POST data. Makes curl HTTP POST.
- */
- data->set.postfields = va_arg(param, char *);
- if(data->set.postfields)
- data->set.httpreq = HTTPREQ_POST;
- break;
- case CURLOPT_POSTFIELDSIZE:
- /*
- * The size of the POSTFIELD data, if curl should now do a strlen
- * to find out. Enables binary posts.
- */
- data->set.postfieldsize = va_arg(param, long);
- break;
- case CURLOPT_REFERER:
- /*
- * String to set in the HTTP Referer: field.
- */
- if(data->change.referer_alloc) {
- free(data->change.referer);
- data->change.referer_alloc = FALSE;
- }
- data->set.set_referer = va_arg(param, char *);
- data->change.referer = data->set.set_referer;
- break;
- case CURLOPT_AUTOREFERER:
- /*
- * Switch on automatic referer that gets set if curl follows locations.
- */
- data->set.http_auto_referer = (bool)(va_arg(param, long)?TRUE:FALSE);
- break;
- case CURLOPT_PROXY:
- /*
- * Set proxy server:port to use as HTTP proxy.
- *
- * If the proxy is set to "" we explicitly say that we don't want to use a
- * proxy (even though there might be environment variables saying so).
- *
- * Setting it to NULL, means no proxy but allows the environment variables
- * to decide for us.
- */
- if(data->change.proxy_alloc) {
- /*
- * The already set string is allocated, free that first
- */
- data->change.proxy_alloc=FALSE;;
- free(data->change.proxy);
- }
- data->set.set_proxy = va_arg(param, char *);
- data->change.proxy = data->set.set_proxy;
- break;
- case CURLOPT_HTTPPROXYTUNNEL:
- /*
- * Tunnel operations through the proxy instead of normal proxy use
- */
- data->set.tunnel_thru_httpproxy = (bool)(va_arg(param, long)?TRUE:FALSE);
- break;
- case CURLOPT_PROXYPORT:
- /*
- * Explicitly set HTTP proxy port number.
- */
- data->set.proxyport = va_arg(param, long);
- break;
case CURLOPT_TIMEOUT:
/*
* The maximum time you allow curl to use for a single transfer
@@ -780,25 +974,6 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
*/
data->set.connecttimeout = va_arg(param, long);
break;
- case CURLOPT_MAXREDIRS:
- /*
- * The maximum amount of hops you allow curl to follow Location:
- * headers. This should mostly be used to detect never-ending loops.
- */
- data->set.maxredirs = va_arg(param, long);
- break;
- case CURLOPT_USERAGENT:
- /*
- * String to use in the HTTP User-Agent field
- */
- data->set.useragent = va_arg(param, char *);
- break;
- case CURLOPT_ENCODING:
- /*
- * String to use at the value of Accept-Encoding header. 08/28/02 jhrg
- */
- data->set.encoding = va_arg(param, char *);
- break;
case CURLOPT_USERPWD:
/*
@@ -808,7 +983,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
break;
case CURLOPT_POSTQUOTE:
/*
- * List of RAW FTP commands to use after a transfer
+ * List of RAW FTP commands to use after a transfer
*/
data->set.postquote = va_arg(param, struct curl_slist *);
break;
@@ -820,7 +995,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
break;
case CURLOPT_QUOTE:
/*
- * List of RAW FTP commands to use before a transfer
+ * List of RAW FTP commands to use before a transfer
*/
data->set.quote = va_arg(param, struct curl_slist *);
break;
@@ -841,25 +1016,6 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
*/
data->set.progress_client = va_arg(param, void *);
break;
- case CURLOPT_PASSWDFUNCTION:
- /*
- * Password prompt callback
- */
- data->set.fpasswd = va_arg(param, curl_passwd_callback);
- /*
- * if the callback provided is null, reset the default callback
- */
- if(!data->set.fpasswd)
- {
- data->set.fpasswd = my_getpass;
- }
- break;
- case CURLOPT_PASSWDDATA:
- /*
- * Custom client data to pass to the password callback
- */
- data->set.passwd_client = va_arg(param, void *);
- break;
case CURLOPT_PROXYUSERPWD:
/*
* user:password needed to use the proxy
@@ -878,6 +1034,12 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
*/
data->set.set_resume_from = va_arg(param, long);
break;
+ case CURLOPT_RESUME_FROM_LARGE:
+ /*
+ * Resume transfer at the give file position
+ */
+ data->set.set_resume_from = va_arg(param, curl_off_t);
+ break;
case CURLOPT_DEBUGFUNCTION:
/*
* stderr write callback.
@@ -914,12 +1076,18 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
* Set data write callback
*/
data->set.fwrite = va_arg(param, curl_write_callback);
+ if(!data->set.fwrite)
+ /* When set to NULL, reset to our internal default function */
+ data->set.fwrite = (curl_write_callback)fwrite;
break;
case CURLOPT_READFUNCTION:
/*
* Read data callback
*/
data->set.fread = va_arg(param, curl_read_callback);
+ if(!data->set.fread)
+ /* When set to NULL, reset to our internal default function */
+ data->set.fread = (curl_read_callback)fread;
break;
case CURLOPT_SSLCERT:
/*
@@ -1001,7 +1169,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
/*
* Kludgy option to enable CRLF convertions. Subject for removal.
*/
- data->set.crlf = (bool)(va_arg(param, long)?TRUE:FALSE);
+ data->set.crlf = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_INTERFACE:
/*
@@ -1015,7 +1183,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
* A string that defines the krb4 security level.
*/
data->set.krb4_level = va_arg(param, char *);
- data->set.krb4=(bool)(data->set.krb4_level?TRUE:FALSE);
+ data->set.krb4=data->set.krb4_level?TRUE:FALSE;
break;
case CURLOPT_SSL_VERIFYPEER:
/*
@@ -1029,6 +1197,18 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
*/
data->set.ssl.verifyhost = va_arg(param, long);
break;
+ case CURLOPT_SSL_CTX_FUNCTION:
+ /*
+ * Set a SSL_CTX callback
+ */
+ data->set.ssl.fsslctx = va_arg(param, curl_ssl_ctx_callback);
+ break;
+ case CURLOPT_SSL_CTX_DATA:
+ /*
+ * Set a SSL_CTX callback parameter pointer
+ */
+ data->set.ssl.fsslctxp = va_arg(param, void *);
+ break;
case CURLOPT_CAINFO:
/*
* Set CA info for SSL connection. Specify file name of the CA certificate
@@ -1057,7 +1237,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
*/
data->set.buffer_size = va_arg(param, long);
- if(data->set.buffer_size> (BUFSIZE -1 ))
+ if((data->set.buffer_size> (BUFSIZE -1 )) ||
+ (data->set.buffer_size < 1))
data->set.buffer_size = 0; /* huge internal default */
break;
@@ -1067,18 +1248,63 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
* The application asks not to set any signal() or alarm() handlers,
* even when using a timeout.
*/
- data->set.no_signal = (bool)(va_arg(param, long) ? TRUE : FALSE);
+ data->set.no_signal = va_arg(param, long) ? TRUE : FALSE;
break;
case CURLOPT_SHARE:
{
struct Curl_share *set;
set = va_arg(param, struct Curl_share *);
- if(data->share)
+
+ /* disconnect from old share, if any */
+ if(data->share) {
+ Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
+
+ if(data->share->hostcache == data->hostcache)
+ data->hostcache = NULL;
+
+ if(data->share->cookies == data->cookies)
+ data->cookies = NULL;
+
data->share->dirty--;
+ Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
+ data->share = NULL;
+ }
+
+ /* use new share if it set */
data->share = set;
- data->share->dirty++;
+ if(data->share) {
+
+ Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
+
+ data->share->dirty++;
+
+ if(data->share->hostcache) {
+ /* use shared host cache, first free own one if any */
+ if(data->hostcache)
+ Curl_hash_destroy(data->hostcache);
+
+ data->hostcache = data->share->hostcache;
+ }
+#ifndef CURL_DISABLE_HTTP
+ if(data->share->cookies) {
+ /* use shared cookie list, first free own one if any */
+ if (data->cookies)
+ Curl_cookie_cleanup(data->cookies);
+ data->cookies = data->share->cookies;
+ }
+#endif /* CURL_DISABLE_HTTP */
+ Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
+
+ }
+#ifndef CURL_DISABLE_HTTP
+ /* check cookie list is set */
+ if(!data->cookies)
+ data->cookies = Curl_cookie_init(data, NULL, NULL, TRUE );
+#endif /* CURL_DISABLE_HTTP */
+ /* check for host cache not needed,
+ * it will be done by curl_easy_perform */
}
break;
@@ -1096,13 +1322,90 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
data->set.private = va_arg(param, char *);
break;
- case CURLOPT_HTTP200ALIASES:
+ case CURLOPT_MAXFILESIZE:
/*
- * Set a list of aliases for HTTP 200 in response header
+ * Set the maximum size of a file to download.
*/
- data->set.http200aliases = va_arg(param, struct curl_slist *);
+ data->set.max_filesize = va_arg(param, long);
+ break;
+
+ case CURLOPT_FTP_SSL:
+ /*
+ * Make FTP transfers attempt to use SSL/TLS.
+ */
+ data->set.ftp_ssl = (curl_ftpssl)va_arg(param, long);
+ break;
+
+ case CURLOPT_IPRESOLVE:
+ data->set.ip_version = va_arg(param, long);
break;
-
+
+ case CURLOPT_MAXFILESIZE_LARGE:
+ /*
+ * Set the maximum size of a file to download.
+ */
+ data->set.max_filesize = va_arg(param, curl_off_t);
+ break;
+
+ case CURLOPT_TCP_NODELAY:
+ /*
+ * Enable or disable TCP_NODELAY, which will disable/enable the Nagle
+ * algorithm
+ */
+ data->set.tcp_nodelay = (bool)va_arg(param, long);
+ break;
+
+ /*********** 3rd party transfer options ***********/
+ case CURLOPT_SOURCE_HOST:
+ /*
+ * Use SOURCE HOST
+ */
+ data->set.source_host = va_arg(param, char *);
+ data->set.printhost = (data->set.source_host != NULL);
+ break;
+
+ case CURLOPT_SOURCE_PORT:
+ /*
+ * Use SOURCE PORT
+ */
+ data->set.source_port = va_arg(param, char *);
+ break;
+
+ case CURLOPT_SOURCE_USERPWD:
+ /*
+ * Use SOURCE USER[:PASSWORD]
+ */
+ data->set.source_userpwd = va_arg(param, char *);
+ break;
+
+ case CURLOPT_SOURCE_PATH:
+ /*
+ * Use SOURCE PATH
+ */
+ data->set.source_path = va_arg(param, char *);
+ break;
+
+ case CURLOPT_PASV_HOST:
+ /*
+ * Indicates whether source or target host is passive
+ */
+ data->set.pasvHost = va_arg(param, long)?CURL_SOURCE_PASV:CURL_TARGET_PASV;
+ break;
+
+ case CURLOPT_SOURCE_PREQUOTE:
+ /*
+ * List of RAW FTP commands to use before a transfer on the source host
+ */
+ data->set.source_prequote = va_arg(param, struct curl_slist *);
+ break;
+
+ case CURLOPT_SOURCE_POSTQUOTE:
+ /*
+ * List of RAW FTP commands to use after a transfer on the source host
+ */
+ data->set.source_postquote = va_arg(param, struct curl_slist *);
+ break;
+
default:
/* unknown tag and its companion, just ignore: */
return CURLE_FAILED_INIT; /* correct this */
@@ -1112,9 +1415,12 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
CURLcode Curl_disconnect(struct connectdata *conn)
{
+ struct SessionHandle *data;
if(!conn)
return CURLE_OK; /* this is closed and fine already */
+ data = conn->data;
+
/*
* The range string is usually freed in curl_done(), but we might
* get here *instead* if we fail prematurely. Thus we need to be able
@@ -1125,54 +1431,77 @@ CURLcode Curl_disconnect(struct connectdata *conn)
conn->bits.rangestringalloc = FALSE;
}
- if(-1 != conn->connectindex) {
- /* unlink ourselves! */
- infof(conn->data, "Closing connection #%d\n", conn->connectindex);
- conn->data->state.connects[conn->connectindex] = NULL;
+ if((conn->ntlm.state != NTLMSTATE_NONE) ||
+ (conn->proxyntlm.state != NTLMSTATE_NONE)) {
+ /* Authentication data is a mix of connection-related and sessionhandle-
+ related stuff. NTLM is connection-related so when we close the shop
+ we shall forget. */
+ data->state.authhost.done = FALSE;
+ data->state.authhost.picked =
+ data->state.authhost.want;
+
+ data->state.authproxy.done = FALSE;
+ data->state.authproxy.picked =
+ data->state.authhost.want;
+
+ data->state.authproblem = FALSE;
}
if(conn->curl_disconnect)
/* This is set if protocol-specific cleanups should be made */
conn->curl_disconnect(conn);
- if(conn->proto.generic)
- free(conn->proto.generic);
-
- if(conn->newurl)
- free(conn->newurl);
-
- if(conn->path) /* the URL path part */
- free(conn->path);
-
-#ifdef USE_SSLEAY
+ if(-1 != conn->connectindex) {
+ /* unlink ourselves! */
+ infof(data, "Closing connection #%ld\n", conn->connectindex);
+ data->state.connects[conn->connectindex] = NULL;
+ }
+
+ Curl_safefree(conn->proto.generic);
+ Curl_safefree(conn->newurl);
+ Curl_safefree(conn->pathbuffer); /* the URL path buffer */
+
+ Curl_safefree(conn->host.rawalloc); /* host name buffer */
+ Curl_safefree(conn->proxy.rawalloc); /* proxy name buffer */
+#ifdef USE_LIBIDN
+ if(conn->host.encalloc)
+ idn_free(conn->host.encalloc); /* encoded host name buffer, must be freed
+ with idn_free() since this was allocated
+ by libidn */
+ if(conn->proxy.encalloc)
+ idn_free(conn->proxy.encalloc); /* encoded proxy name buffer, must be
+ freed with idn_free() since this was
+ allocated by libidn */
+#endif
Curl_SSL_Close(conn);
-#endif /* USE_SSLEAY */
/* close possibly still open sockets */
- if(-1 != conn->secondarysocket)
- sclose(conn->secondarysocket);
- if(-1 != conn->firstsocket)
- sclose(conn->firstsocket);
-
- if(conn->allocptr.proxyuserpwd)
- free(conn->allocptr.proxyuserpwd);
- if(conn->allocptr.uagent)
- free(conn->allocptr.uagent);
- if(conn->allocptr.userpwd)
- free(conn->allocptr.userpwd);
- if(conn->allocptr.accept_encoding)
- free(conn->allocptr.accept_encoding);
- if(conn->allocptr.rangeline)
- free(conn->allocptr.rangeline);
- if(conn->allocptr.ref)
- free(conn->allocptr.ref);
- if(conn->allocptr.cookie)
- free(conn->allocptr.cookie);
- if(conn->allocptr.host)
- free(conn->allocptr.host);
-
- if(conn->proxyhost)
- free(conn->proxyhost);
+ if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET])
+ sclose(conn->sock[SECONDARYSOCKET]);
+ if(CURL_SOCKET_BAD != conn->sock[FIRSTSOCKET])
+ sclose(conn->sock[FIRSTSOCKET]);
+
+ Curl_safefree(conn->user);
+ Curl_safefree(conn->passwd);
+ Curl_safefree(conn->proxyuser);
+ Curl_safefree(conn->proxypasswd);
+ Curl_safefree(conn->allocptr.proxyuserpwd);
+ Curl_safefree(conn->allocptr.uagent);
+ Curl_safefree(conn->allocptr.userpwd);
+ Curl_safefree(conn->allocptr.accept_encoding);
+ Curl_safefree(conn->allocptr.rangeline);
+ Curl_safefree(conn->allocptr.ref);
+ Curl_safefree(conn->allocptr.host);
+ Curl_safefree(conn->allocptr.cookiehost);
+
+#if defined(USE_ARES) || defined(USE_THREADING_GETHOSTBYNAME) || \
+ defined(USE_THREADING_GETADDRINFO)
+ /* possible left-overs from the async name resolve */
+ Curl_safefree(conn->async.hostname);
+ Curl_safefree(conn->async.os_specific);
+#endif
+
+ Curl_free_ssl_config(&conn->ssl_config);
free(conn); /* free all the connection oriented data */
@@ -1184,24 +1513,24 @@ CURLcode Curl_disconnect(struct connectdata *conn)
* be dead. Most commonly this happens when the server has closed the
* connection due to inactivity.
*/
-static bool SocketIsDead(int sock)
-{
- int sval;
- bool ret_val = TRUE;
- fd_set check_set;
- struct timeval to;
+static bool SocketIsDead(curl_socket_t sock)
+{
+ int sval;
+ bool ret_val = TRUE;
+ fd_set check_set;
+ struct timeval to;
- FD_ZERO(&check_set);
- FD_SET(sock,&check_set);
+ FD_ZERO(&check_set);
+ FD_SET(sock, &check_set);
- to.tv_sec = 0;
- to.tv_usec = 0;
+ to.tv_sec = 0;
+ to.tv_usec = 0;
sval = select(sock + 1, &check_set, 0, 0, &to);
if(sval == 0)
/* timeout */
ret_val = FALSE;
-
+
return ret_val;
}
@@ -1228,6 +1557,11 @@ ConnectionExists(struct SessionHandle *data,
if(!check)
/* NULL pointer means not filled-in entry */
continue;
+
+ if((needle->protocol&PROT_SSL) != (check->protocol&PROT_SSL))
+ /* don't do mixed SSL and non-SSL connections */
+ continue;
+
if(!needle->bits.httpproxy || needle->protocol&PROT_SSL) {
/* The requested connection does not use a HTTP proxy or it
uses SSL. */
@@ -1238,13 +1572,23 @@ ConnectionExists(struct SessionHandle *data,
continue;
if(strequal(needle->protostr, check->protostr) &&
- strequal(needle->name, check->name) &&
+ strequal(needle->host.name, check->host.name) &&
(needle->remote_port == check->remote_port) ) {
- if(strequal(needle->protostr, "FTP")) {
- /* This is FTP, verify that we're using the same name and
- password as well */
- if(!strequal(needle->data->state.user, check->proto.ftp->user) ||
- !strequal(needle->data->state.passwd, check->proto.ftp->passwd)) {
+ if(needle->protocol & PROT_SSL) {
+ /* This is SSL, verify that we're using the same
+ ssl options as well */
+ if(!Curl_ssl_config_matches(&needle->ssl_config,
+ &check->ssl_config)) {
+ continue;
+ }
+ }
+ if((needle->protocol & PROT_FTP) ||
+ ((needle->protocol & PROT_HTTP) &&
+ (needle->data->state.authhost.want==CURLAUTH_NTLM))) {
+ /* This is FTP or HTTP+NTLM, verify that we're using the same name
+ and password as well */
+ if(!strequal(needle->user, check->user) ||
+ !strequal(needle->passwd, check->passwd)) {
/* one of them was different */
continue;
}
@@ -1255,7 +1599,7 @@ ConnectionExists(struct SessionHandle *data,
else { /* The requested needle connection is using a proxy,
is the checked one using the same? */
if(check->bits.httpproxy &&
- strequal(needle->proxyhost, check->proxyhost) &&
+ strequal(needle->proxy.name, check->proxy.name) &&
needle->port == check->port) {
/* This is the same proxy connection, use it! */
match = TRUE;
@@ -1263,7 +1607,7 @@ ConnectionExists(struct SessionHandle *data,
}
if(match) {
- bool dead = SocketIsDead(check->firstsocket);
+ bool dead = SocketIsDead(check->sock[FIRSTSOCKET]);
if(dead) {
/*
*/
@@ -1288,22 +1632,21 @@ ConnectionExists(struct SessionHandle *data,
* should take the previously set policy into account when deciding which
* of the connections to kill.
*/
-static int
+static long
ConnectionKillOne(struct SessionHandle *data)
{
long i;
struct connectdata *conn;
- int highscore=-1;
- int connindex=-1;
- int score;
- CURLcode result;
+ long highscore=-1;
+ long connindex=-1;
+ long score;
struct timeval now;
now = Curl_tvnow();
for(i=0; i< data->state.numconnects; i++) {
conn = data->state.connects[i];
-
+
if(!conn)
continue;
@@ -1336,8 +1679,7 @@ ConnectionKillOne(struct SessionHandle *data)
if(connindex >= 0) {
/* the winner gets the honour of being disconnected */
- result = Curl_disconnect(data->state.connects[connindex]);
- (void)result;
+ (void) Curl_disconnect(data->state.connects[connindex]);
/* clean the array entry */
data->state.connects[connindex] = NULL;
@@ -1354,7 +1696,7 @@ ConnectionKillOne(struct SessionHandle *data)
* The given connection should be unique. That must've been checked prior to
* this call.
*/
-static unsigned int
+static long
ConnectionStore(struct SessionHandle *data,
struct connectdata *conn)
{
@@ -1384,32 +1726,49 @@ ConnectionStore(struct SessionHandle *data,
* This function logs in to a SOCKS5 proxy and sends the specifies the final
* desitination server.
*/
-static int handleSock5Proxy(
- const char *proxy_name,
- const char *proxy_password,
- struct connectdata *conn,
- int sock)
+static int handleSock5Proxy(const char *proxy_name,
+ const char *proxy_password,
+ struct connectdata *conn)
{
+ /*
+ According to the RFC1928, section "6. Replies". This is what a SOCK5
+ replies:
+
+ +----+-----+-------+------+----------+----------+
+ |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
+ +----+-----+-------+------+----------+----------+
+ | 1 | 1 | X'00' | 1 | Variable | 2 |
+ +----+-----+-------+------+----------+----------+
+
+ Where:
+
+ o VER protocol version: X'05'
+ o REP Reply field:
+ o X'00' succeeded
+ */
+
unsigned char socksreq[600]; /* room for large user/pw (255 max each) */
ssize_t actualread;
ssize_t written;
- CURLcode result;
+ int result;
+ CURLcode code;
+ int sock = conn->sock[FIRSTSOCKET];
Curl_nonblock(sock, FALSE);
socksreq[0] = 5; /* version */
- socksreq[1] = (char)(proxy_name[0] ? 2 : 1); /* number of methods (below) */
+ socksreq[1] = (char)(proxy_name ? 2 : 1); /* number of methods (below) */
socksreq[2] = 0; /* no authentication */
socksreq[3] = 2; /* username/password */
- result = Curl_write(conn, sock, (char *)socksreq, (2 + (int)socksreq[1]),
+ code = Curl_write(conn, sock, (char *)socksreq, (2 + (int)socksreq[1]),
&written);
- if ((result != CURLE_OK) || (written != (2 + (int)socksreq[1]))) {
+ if ((code != CURLE_OK) || (written != (2 + (int)socksreq[1]))) {
failf(conn->data, "Unable to send initial SOCKS5 request.");
return 1;
}
- result=(CURLcode)Curl_read(conn, sock, (char *)socksreq, 2, &actualread);
+ result=Curl_read(conn, sock, (char *)socksreq, 2, &actualread);
if ((result != CURLE_OK) || (actualread != 2)) {
failf(conn->data, "Unable to receive initial SOCKS5 response.");
return 1;
@@ -1428,7 +1787,7 @@ static int handleSock5Proxy(
int userlen, pwlen, len;
userlen = (int)strlen(proxy_name);
- pwlen = (int)strlen(proxy_password);
+ pwlen = proxy_password?(int)strlen(proxy_password):0;
/* username/password request looks like
* +----+------+----------+------+----------+
@@ -1446,13 +1805,13 @@ static int handleSock5Proxy(
memcpy(socksreq + len, proxy_password, (int) pwlen);
len += pwlen;
- result = Curl_write(conn, sock, (char *)socksreq, len, &written);
- if ((result != CURLE_OK) || (len != written)) {
+ code = Curl_write(conn, sock, (char *)socksreq, len, &written);
+ if ((code != CURLE_OK) || (len != written)) {
failf(conn->data, "Failed to send SOCKS5 sub-negotiation request.");
return 1;
}
- result=(CURLcode)Curl_read(conn, sock, (char *)socksreq, 2, &actualread);
+ result=Curl_read(conn, sock, (char *)socksreq, 2, &actualread);
if ((result != CURLE_OK) || (actualread != 2)) {
failf(conn->data, "Unable to receive SOCKS5 sub-negotiation response.");
return 1;
@@ -1481,7 +1840,7 @@ static int handleSock5Proxy(
" that the SOCKS5 server wanted a username/password, since none"
" was supplied to the server on this connection.)");
}
- else {
+ else {
failf(conn->data, "No authentication method was acceptable.");
}
return 1;
@@ -1498,54 +1857,61 @@ static int handleSock5Proxy(
socksreq[1] = 1; /* connect */
socksreq[2] = 0; /* must be zero */
socksreq[3] = 1; /* IPv4 = 1 */
-
+
{
-#ifndef ENABLE_IPV6
struct Curl_dns_entry *dns;
Curl_addrinfo *hp=NULL;
- dns = Curl_resolv(conn->data, conn->hostname, conn->remote_port);
+ int rc = Curl_resolv(conn, conn->host.name, (int)conn->remote_port, &dns);
+
+ if(rc == CURLRESOLV_ERROR)
+ return 1;
+
+ if(rc == CURLRESOLV_PENDING)
+ /* this requires that we're in "wait for resolve" state */
+ rc = Curl_wait_for_resolv(conn, &dns);
+
/*
* We cannot use 'hostent' as a struct that Curl_resolv() returns. It
* returns a Curl_addrinfo pointer that may not always look the same.
*/
if(dns)
hp=dns->addr;
- if (hp && hp->h_addr_list[0]) {
- socksreq[4] = ((char*)hp->h_addr_list[0])[0];
- socksreq[5] = ((char*)hp->h_addr_list[0])[1];
- socksreq[6] = ((char*)hp->h_addr_list[0])[2];
- socksreq[7] = ((char*)hp->h_addr_list[0])[3];
+ if (hp) {
+ char buf[64];
+ unsigned short ip[4];
+ Curl_printable_address(hp, buf, sizeof(buf));
+
+ if(4 == sscanf( buf, "%hu.%hu.%hu.%hu",
+ &ip[0], &ip[1], &ip[2], &ip[3])) {
+ socksreq[4] = (unsigned char)ip[0];
+ socksreq[5] = (unsigned char)ip[1];
+ socksreq[6] = (unsigned char)ip[2];
+ socksreq[7] = (unsigned char)ip[3];
+ }
+ else
+ hp = NULL; /* fail! */
- Curl_resolv_unlock(dns); /* not used anymore from now on */
+ Curl_resolv_unlock(conn->data, dns); /* not used anymore from now on */
}
- else {
+ if(!hp) {
failf(conn->data, "Failed to resolve \"%s\" for SOCKS5 connect.",
- conn->hostname);
+ conn->host.name);
return 1;
}
-#else
- failf(conn->data,
- "%s:%d has an internal error an needs to be fixed to work",
- __FILE__, __LINE__);
- return 1;
-#endif
}
- {
- unsigned short htons_res = htons(conn->remote_port);
- memcpy(&socksreq[8], &htons_res, sizeof(unsigned short*));
- }
+ *((unsigned short*)&socksreq[8]) = htons(conn->remote_port);
{
const int packetsize = 10;
- result = Curl_write(conn, sock, (char *)socksreq, packetsize, &written);
- if ((result != CURLE_OK) || (written != packetsize)) {
+ code = Curl_write(conn, sock, (char *)socksreq, packetsize, &written);
+ if ((code != CURLE_OK) || (written != packetsize)) {
failf(conn->data, "Failed to send SOCKS5 connect request.");
return 1;
}
- result = (CURLcode)Curl_read(conn, sock, (char *)socksreq, packetsize, &actualread);
+ result = Curl_read(conn, sock, (char *)socksreq, packetsize, &actualread);
if ((result != CURLE_OK) || (actualread != packetsize)) {
failf(conn->data, "Failed to receive SOCKS5 connect request ack.");
return 1;
@@ -1557,13 +1923,11 @@ static int handleSock5Proxy(
return 1;
}
if (socksreq[1] != 0) { /* Anything besides 0 is an error */
- unsigned short ntohs_arg;
- memcpy(&ntohs_arg, &socksreq[8], sizeof(unsigned short*));
failf(conn->data,
"Can't complete SOCKS5 connection to %d.%d.%d.%d:%d. (%d)",
(unsigned char)socksreq[4], (unsigned char)socksreq[5],
(unsigned char)socksreq[6], (unsigned char)socksreq[7],
- (unsigned int)ntohs(ntohs_arg),
+ (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])),
socksreq[1]);
return 1;
}
@@ -1578,38 +1942,30 @@ static CURLcode ConnectPlease(struct connectdata *conn,
bool *connected)
{
CURLcode result;
- Curl_ipconnect *addr;
+ Curl_addrinfo *addr;
+ struct SessionHandle *data = conn->data;
+ char *hostname = data->change.proxy?conn->proxy.name:conn->host.name;
+
+ infof(data, "About to connect() to %s port %d\n",
+ hostname, conn->port);
/*************************************************************
* Connect to server/proxy
*************************************************************/
result= Curl_connecthost(conn,
hostaddr,
- conn->port,
- &conn->firstsocket,
+ &conn->sock[FIRSTSOCKET],
&addr,
connected);
if(CURLE_OK == result) {
- /* All is cool, then we store the current information from the hostaddr
- struct to the serv_addr, as it might be needed later. The address
- returned from the function above is crucial here. */
- conn->connect_addr = hostaddr;
-
-#ifdef ENABLE_IPV6
- conn->serv_addr = addr;
-#else
- memset((char *) &conn->serv_addr, '\0', sizeof(conn->serv_addr));
- memcpy((char *)&(conn->serv_addr.sin_addr),
- (struct in_addr *)addr, sizeof(struct in_addr));
- conn->serv_addr.sin_family = hostaddr->addr->h_addrtype;
- conn->serv_addr.sin_port = htons((unsigned short)conn->port);
-#endif
+ /* All is cool, then we store the current information */
+ conn->dns_entry = hostaddr;
+ conn->ip_addr = addr;
if (conn->data->set.proxytype == CURLPROXY_SOCKS5) {
- return handleSock5Proxy(conn->data->state.proxyuser,
- conn->data->state.proxypasswd,
- conn,
- conn->firstsocket) ?
+ return handleSock5Proxy(conn->proxyuser,
+ conn->proxypasswd,
+ conn) ?
CURLE_COULDNT_CONNECT : CURLE_OK;
}
else if (conn->data->set.proxytype == CURLPROXY_HTTP) {
@@ -1617,7 +1973,7 @@ static CURLcode ConnectPlease(struct connectdata *conn,
}
else {
failf(conn->data, "unknown proxytype option given");
- return CURLE_COULDNT_CONNECT;
+ return CURLE_COULDNT_CONNECT;
}
}
@@ -1625,54 +1981,18 @@ static CURLcode ConnectPlease(struct connectdata *conn,
}
/*
- * ALERT! The 'dns' pointer being passed in here might be NULL at times.
+ * verboseconnect() displays verbose information after a connect
*/
-static void verboseconnect(struct connectdata *conn,
- struct Curl_dns_entry *dns)
+static void verboseconnect(struct connectdata *conn)
{
-#ifdef HAVE_INET_NTOA_R
- char ntoa_buf[64];
-#endif
struct SessionHandle *data = conn->data;
+ char addrbuf[256];
- /* Figure out the ip-number and display the first host name it shows: */
-#ifdef ENABLE_IPV6
- (void)dns; /* not used in the IPv6 enabled version */
- {
- char hbuf[NI_MAXHOST];
-#ifdef NI_WITHSCOPEID
- const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID;
-#else
- const int niflags = NI_NUMERICHOST;
-#endif
- struct addrinfo *ai = conn->serv_addr;
-
- if (getnameinfo(ai->ai_addr, ai->ai_addrlen, hbuf, sizeof(hbuf), NULL, 0,
- niflags)) {
- snprintf(hbuf, sizeof(hbuf), "?");
- }
- if (ai->ai_canonname) {
- infof(data, "Connected to %s (%s) port %d\n", ai->ai_canonname, hbuf,
- conn->port);
- } else {
- infof(data, "Connected to %s port %d\n", hbuf, conn->port);
- }
- }
-#else
- {
- Curl_addrinfo *hostaddr=dns?dns->addr:NULL;
- struct in_addr in;
- (void) memcpy(&in.s_addr, &conn->serv_addr.sin_addr, sizeof (in.s_addr));
- infof(data, "Connected to %s (%s) port %d\n",
- hostaddr?hostaddr->h_name:"",
-#if defined(HAVE_INET_NTOA_R)
- inet_ntoa_r(in, ntoa_buf, sizeof(ntoa_buf)),
-#else
- inet_ntoa(in),
-#endif
- conn->port);
- }
-#endif
+ /* Get a printable version of the network address. */
+ Curl_printable_address(conn->ip_addr, addrbuf, sizeof(addrbuf));
+ infof(data, "Connected to %s (%s) port %d\n",
+ conn->bits.httpproxy ? conn->proxy.dispname : conn->host.dispname,
+ addrbuf[0] ? addrbuf : "??", conn->port);
}
/*
@@ -1682,15 +2002,13 @@ static void verboseconnect(struct connectdata *conn,
* If we're using the multi interface, this host address pointer is most
* likely NULL at this point as we can't keep the resolved info around. This
* may call for some reworking, like a reference counter in the struct or
- * something. The hostaddr is not used for very much though, we have the
- * 'serv_addr' field in the connectdata struct for most of it.
+ * something.
*/
-CURLcode Curl_protocol_connect(struct connectdata *conn,
- struct Curl_dns_entry *hostaddr)
+CURLcode Curl_protocol_connect(struct connectdata *conn)
{
struct SessionHandle *data = conn->data;
CURLcode result=CURLE_OK;
-
+
if(conn->bits.tcpconnect)
/* We already are connected, get back. This may happen when the connect
worked fine in the first call, like when we connect to a local server
@@ -1700,7 +2018,7 @@ CURLcode Curl_protocol_connect(struct connectdata *conn,
Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
if(data->set.verbose)
- verboseconnect(conn, hostaddr);
+ verboseconnect(conn);
if(conn->curl_connect) {
/* is there a protocol-specific connect() procedure? */
@@ -1717,30 +2035,104 @@ CURLcode Curl_protocol_connect(struct connectdata *conn,
return result; /* pass back status */
}
+/*
+ * Helpers for IDNA convertions.
+ */
+#ifdef USE_LIBIDN
+static bool is_ASCII_name (const char *hostname)
+{
+ const unsigned char *ch = (const unsigned char*)hostname;
+
+ while (*ch) {
+ if (*ch++ & 0x80)
+ return FALSE;
+ }
+ return TRUE;
+}
+#endif
+
+static void fix_hostname(struct connectdata *conn, struct hostname *host)
+{
+ /* set the name we use to display the host name */
+ host->dispname = host->name;
+
+#ifdef USE_LIBIDN
+ /*************************************************************
+ * Check name for non-ASCII and convert hostname to ACE form.
+ *************************************************************/
+ if (!is_ASCII_name(host->name) &&
+ stringprep_check_version(LIBIDN_REQUIRED_VERSION)) {
+ char *ace_hostname = NULL;
+ struct SessionHandle *data = conn->data;
+ int rc = idna_to_ascii_lz(host->name, &ace_hostname, 0);
+ infof (data, "Input domain encoded as `%s'\n",
+ stringprep_locale_charset ());
+ if (rc != IDNA_SUCCESS)
+ infof(data, "Failed to convert %s to ACE; IDNA error %d\n",
+ host->name, rc);
+ else {
+ host->encalloc = ace_hostname;
+ /* change the name pointer to point to the encoded hostname */
+ host->name = host->encalloc;
+ }
+ }
+#else
+ (void)conn; /* never used */
+#endif
+}
+
+
+/**
+ * CreateConnection() sets up a new connectdata struct, or re-uses an already
+ * existing one, and resolves host name.
+ *
+ * if this function returns CURLE_OK and *async is set to TRUE, the resolve
+ * response will be coming asynchronously. If *async is FALSE, the name is
+ * already resolved.
+ *
+ * @param data The sessionhandle pointer
+ * @param in_connect is set to the next connection data pointer
+ * @param addr is set to the new dns entry for this connection
+ * @param async is set TRUE/FALSE depending on the nature of this lookup
+ * @return CURLcode
+ * @see SetupConnection()
+ */
+
static CURLcode CreateConnection(struct SessionHandle *data,
- struct connectdata **in_connect)
+ struct connectdata **in_connect,
+ struct Curl_dns_entry **addr,
+ bool *async)
{
char *tmp;
- char *buf;
CURLcode result=CURLE_OK;
- char resumerange[40]="";
struct connectdata *conn;
struct connectdata *conn_temp;
- int urllen;
+ size_t urllen;
struct Curl_dns_entry *hostaddr;
-#ifdef HAVE_ALARM
+#if defined(HAVE_ALARM) && !defined(USE_ARES)
unsigned int prev_alarm=0;
#endif
char endbracket;
+ char user[MAX_CURL_USER_LENGTH];
+ char passwd[MAX_CURL_PASSWORD_LENGTH];
+ int rc;
+ bool reuse;
+#ifndef USE_ARES
+#ifdef SIGALRM
#ifdef HAVE_SIGACTION
struct sigaction keep_sigact; /* store the old struct here */
bool keep_copysig=FALSE; /* did copy it? */
#else
#ifdef HAVE_SIGNAL
void *keep_sigact; /* store the old handler here */
-#endif
-#endif
+#endif /* HAVE_SIGNAL */
+#endif /* HAVE_SIGACTION */
+#endif /* SIGALRM */
+#endif /* USE_ARES */
+
+ *addr = NULL; /* nothing yet */
+ *async = FALSE;
/*************************************************************
* Check input data
@@ -1769,25 +2161,17 @@ static CURLcode CreateConnection(struct SessionHandle *data,
/* and we setup a few fields in case we end up actually using this struct */
conn->data = data; /* remember our daddy */
- conn->firstsocket = -1; /* no file descriptor */
- conn->secondarysocket = -1; /* no file descriptor */
+ conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
+ conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
conn->connectindex = -1; /* no index */
- conn->bits.httpproxy = (bool)((data->change.proxy && *data->change.proxy &&
+ conn->bits.httpproxy = (data->change.proxy && *data->change.proxy &&
(data->set.proxytype == CURLPROXY_HTTP))?
- TRUE:FALSE); /* http proxy or not */
- conn->bits.use_range = (bool)(data->set.set_range?TRUE:FALSE);
- /* range status */
- conn->range = data->set.set_range; /* clone the range setting */
- conn->resume_from = data->set.set_resume_from; /* inherite resume_from */
+ TRUE:FALSE; /* http proxy or not */
/* Default protocol-independent behavior doesn't support persistant
connections, so we set this to force-close. Protocols that support
this need to set this to FALSE in their "curl_do" functions. */
- conn->bits.close = (bool)TRUE;
-
- /* inherite initial knowledge from the data struct */
- conn->bits.user_passwd = (bool)(data->set.userpwd?TRUE:FALSE);
- conn->bits.proxy_user_passwd = (bool)(data->set.proxyuserpwd?TRUE:FALSE);
+ conn->bits.close = TRUE;
/* maxdownload must be -1 on init, as 0 is a valid value! */
conn->maxdownload = -1; /* might have been used previously! */
@@ -1795,23 +2179,22 @@ static CURLcode CreateConnection(struct SessionHandle *data,
/* Store creation time to help future close decision making */
conn->created = Curl_tvnow();
+ conn->bits.use_range = data->set.set_range?TRUE:FALSE; /* range status */
+ conn->range = data->set.set_range; /* clone the range setting */
+ conn->resume_from = data->set.set_resume_from; /* inherite resume_from */
+
/* Set the start time temporary to this creation time to allow easier
timeout checks before the transfer has started for real. The start time
is later set "for real" using Curl_pgrsStartNow(). */
- conn->data->progress.start = conn->created;
+ conn->data->progress.start = conn->created;
- conn->bits.upload_chunky = (bool)(
- ((conn->protocol&PROT_HTTP) &&
- data->set.upload &&
- (data->set.infilesize == -1) &&
- (data->set.httpversion != CURL_HTTP_VERSION_1_0))?
- /* HTTP, upload, unknown file size and not HTTP 1.0 */
- TRUE:
- /* else, no chunky upload */
- FALSE);
+ conn->bits.user_passwd = data->set.userpwd?1:0;
+ conn->bits.proxy_user_passwd = data->set.proxyuserpwd?1:0;
+ conn->bits.no_body = data->set.opt_no_body;
+ conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy;
- conn->fread = data->set.fread;
- conn->fread_in = data->set.in;
+ /* This initing continues below, see the comment "Continue connectdata
+ * initialization here" */
/***********************************************************
* We need to allocate memory to store the path in. We get the size of the
@@ -1819,13 +2202,19 @@ static CURLcode CreateConnection(struct SessionHandle *data,
* other parts of the code will rely on this fact
***********************************************************/
#define LEAST_PATH_ALLOC 256
- urllen=(int)strlen(data->change.url);
+ urllen=strlen(data->change.url);
if(urllen < LEAST_PATH_ALLOC)
urllen=LEAST_PATH_ALLOC;
-
- conn->path=(char *)malloc(urllen);
- if(NULL == conn->path)
+
+ conn->pathbuffer=(char *)malloc(urllen);
+ if(NULL == conn->pathbuffer)
return CURLE_OUT_OF_MEMORY; /* really bad error */
+ conn->path = conn->pathbuffer;
+
+ conn->host.rawalloc=(char *)malloc(urllen);
+ if(NULL == conn->host.rawalloc)
+ return CURLE_OUT_OF_MEMORY;
+ conn->host.name = conn->host.rawalloc;
/*************************************************************
* Parse the URL.
@@ -1835,9 +2224,19 @@ static CURLcode CreateConnection(struct SessionHandle *data,
* proxy -- and we don't know if we will need to use SSL until we parse the
* url ...
************************************************************/
- if((2 == sscanf(data->change.url, "%64[^:]://%[^\n]",
+ if((2 == sscanf(data->change.url, "%15[^:]:%[^\n]",
conn->protostr,
conn->path)) && strequal(conn->protostr, "file")) {
+ if(conn->path[0] == '/' && conn->path[1] == '/') {
+ /* Allow omitted hostname (e.g. file:/<path>). This is not strictly
+ * speaking a valid file: URL by RFC 1738, but treating file:/<path> as
+ * file://localhost/<path> is similar to how other schemes treat missing
+ * hostnames. See RFC 1808. */
+
+ /* This cannot be done with strcpy() in a portable manner, since the
+ memory areas overlap! */
+ memmove(conn->path, conn->path + 2, strlen(conn->path + 2)+1);
+ }
/*
* we deal with file://<host>/<path> differently since it supports no
* hostname other than "localhost" and "127.0.0.1", which is unique among
@@ -1849,14 +2248,14 @@ static CURLcode CreateConnection(struct SessionHandle *data,
char *ptr=strchr(conn->path, '/');
if(ptr) {
/* there was a slash present
-
+
RFC1738 (section 3.1, page 5) says:
-
+
The rest of the locator consists of data specific to the scheme,
and is known as the "url-path". It supplies the details of how the
specified resource can be accessed. Note that the "/" between the
host (or port) and the url-path is NOT part of the url-path.
-
+
As most agents use file://localhost/foo to get '/foo' although the
slash preceeding foo is a separator and not a slash for the path,
a URL as file://localhost//foo must be valid as well, to refer to
@@ -1866,29 +2265,35 @@ static CURLcode CreateConnection(struct SessionHandle *data,
if(ptr[1] && ('/' == ptr[1]))
/* if there was two slashes, we skip the first one as that is then
used truly as a separator */
- ptr++;
-
- strcpy(conn->path, ptr);
+ ptr++;
+
+ /* This cannot be made with strcpy, as the memory chunks overlap! */
+ memmove(conn->path, ptr, strlen(ptr)+1);
}
}
strcpy(conn->protostr, "file"); /* store protocol string lowercase */
}
else {
- /* Set default host and default path */
- strcpy(conn->gname, "curl.haxx.se");
+ /* Set default path */
strcpy(conn->path, "/");
+ /* We need to search for '/' OR '?' - whichever comes first after host
+ * name but before the path. We need to change that to handle things like
+ * http://example.com?param= (notice the missing '/'). Later we'll insert
+ * that missing slash at the beginning of the path.
+ */
if (2 > sscanf(data->change.url,
- "%64[^\n:]://%512[^\n/]%[^\n]",
- conn->protostr, conn->gname, conn->path)) {
-
+ "%15[^\n:]://%[^\n/?]%[^\n]",
+ conn->protostr,
+ conn->host.name, conn->path)) {
+
/*
* The URL was badly formatted, let's try the browser-style _without_
* protocol specified like 'http://'.
*/
- if((1 > sscanf(data->change.url, "%512[^\n/]%[^\n]",
- conn->gname, conn->path)) ) {
+ if((1 > sscanf(data->change.url, "%[^\n/?]%[^\n]",
+ conn->host.name, conn->path)) ) {
/*
* We couldn't even get this format.
*/
@@ -1904,22 +2309,21 @@ static CURLcode CreateConnection(struct SessionHandle *data,
/* Note: if you add a new protocol, please update the list in
* lib/version.c too! */
- if(checkprefix("FTP", conn->gname)) {
- strcpy(conn->protostr, "ftp");
- }
- else if(checkprefix("GOPHER", conn->gname))
+ if(checkprefix("GOPHER", conn->host.name))
strcpy(conn->protostr, "gopher");
#ifdef USE_SSLEAY
- else if(checkprefix("HTTPS", conn->gname))
+ else if(checkprefix("HTTPS", conn->host.name))
strcpy(conn->protostr, "https");
- else if(checkprefix("FTPS", conn->gname))
+ else if(checkprefix("FTPS", conn->host.name))
strcpy(conn->protostr, "ftps");
#endif /* USE_SSLEAY */
- else if(checkprefix("TELNET", conn->gname))
+ else if(checkprefix("FTP", conn->host.name))
+ strcpy(conn->protostr, "ftp");
+ else if(checkprefix("TELNET", conn->host.name))
strcpy(conn->protostr, "telnet");
- else if (checkprefix("DICT", conn->gname))
+ else if (checkprefix("DICT", conn->host.name))
strcpy(conn->protostr, "DICT");
- else if (checkprefix("LDAP", conn->gname))
+ else if (checkprefix("LDAP", conn->host.name))
strcpy(conn->protostr, "LDAP");
else {
strcpy(conn->protostr, "http");
@@ -1929,13 +2333,22 @@ static CURLcode CreateConnection(struct SessionHandle *data,
}
}
- buf = data->state.buffer; /* this is our buffer */
- (void)buf;
+ /* If the URL is malformatted (missing a '/' after hostname before path) we
+ * insert a slash here. The only letter except '/' we accept to start a path
+ * is '?'.
+ */
+ if(conn->path[0] == '?') {
+ /* We need this function to deal with overlapping memory areas. We know
+ that the memory area 'path' points to is 'urllen' bytes big and that
+ is bigger than the path. Use +1 to move the zero byte too. */
+ memmove(&conn->path[1], conn->path, strlen(conn->path)+1);
+ conn->path[0] = '/';
+ }
/*
* So if the URL was A://B/C,
* conn->protostr is A
- * conn->gname is B
+ * conn->host.name is B
* conn->path is /C
*/
@@ -1943,38 +2356,22 @@ static CURLcode CreateConnection(struct SessionHandle *data,
* Take care of proxy authentication stuff
*************************************************************/
if(conn->bits.proxy_user_passwd) {
- data->state.proxyuser[0] =0;
- data->state.proxypasswd[0]=0;
-
- if(*data->set.proxyuserpwd != ':') {
- /* the name is given, get user+password */
- sscanf(data->set.proxyuserpwd, "%127[^:]:%127[^\n]",
- data->state.proxyuser, data->state.proxypasswd);
- }
- else
- /* no name given, get the password only */
- sscanf(data->set.proxyuserpwd+1, "%127[^\n]", data->state.proxypasswd);
-
- /* check for password, if no ask for one */
- if( !data->state.proxypasswd[0] ) {
- if(data->set.fpasswd( data->set.passwd_client,
- "proxy password:",
- data->state.proxypasswd,
- sizeof(data->state.proxypasswd))) {
- failf(data, "Bad password from password callback");
- return CURLE_BAD_PASSWORD_ENTERED;
- }
- }
+ char proxyuser[MAX_CURL_USER_LENGTH]="";
+ char proxypasswd[MAX_CURL_PASSWORD_LENGTH]="";
- }
+ sscanf(data->set.proxyuserpwd,
+ "%" MAX_CURL_USER_LENGTH_TXT "[^:]:"
+ "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^\n]",
+ proxyuser, proxypasswd);
- /*************************************************************
- * Set a few convenience pointers
- *************************************************************/
- conn->name = conn->gname;
- conn->ppath = conn->path;
- conn->hostname = conn->name;
+ conn->proxyuser = strdup(proxyuser);
+ if(!conn->proxyuser)
+ return CURLE_OUT_OF_MEMORY;
+ conn->proxypasswd = strdup(proxypasswd);
+ if(!conn->proxypasswd)
+ return CURLE_OUT_OF_MEMORY;
+ }
/*************************************************************
* Detect what (if any) proxy to use
@@ -2013,16 +2410,16 @@ static CURLcode CreateConnection(struct SessionHandle *data,
nope=no_proxy?strtok_r(no_proxy, ", ", &no_proxy_tok_buf):NULL;
while(nope) {
- unsigned int namelen;
- char *endptr = strchr(conn->name, ':');
+ size_t namelen;
+ char *endptr = strchr(conn->host.name, ':');
if(endptr)
- namelen=(unsigned int)(endptr-conn->name);
+ namelen=endptr-conn->host.name;
else
- namelen=(unsigned int)strlen(conn->name);
+ namelen=strlen(conn->host.name);
if(strlen(nope) <= namelen) {
char *checkn=
- conn->name + namelen - strlen(nope);
+ conn->host.name + namelen - strlen(nope);
if(checkprefix(nope, checkn)) {
/* no proxy for this host! */
break;
@@ -2038,7 +2435,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
/* Now, build <protocol>_proxy and check for such a one to use */
while(*protop)
- *envp++ = (char)tolower((int)*protop++);
+ *envp++ = tolower((int)*protop++);
/* append _proxy */
strcpy(envp, "_proxy");
@@ -2054,14 +2451,14 @@ static CURLcode CreateConnection(struct SessionHandle *data,
* environment (cgi or php), this environment variable can
* be controlled by the web server user by setting the
* http header 'Proxy:' to some value.
- *
+ *
* This can cause 'internal' http/ftp requests to be
* arbitrarily redirected by any external attacker.
*/
if(!prox && !strequal("http_proxy", proxy_env)) {
/* There was no lowercase variable, try the uppercase version: */
for(envp = proxy_env; *envp; envp++)
- *envp = (char)toupper((int)*envp);
+ *envp = toupper((int)*envp);
prox=curl_getenv(proxy_env);
}
@@ -2076,6 +2473,61 @@ static CURLcode CreateConnection(struct SessionHandle *data,
if(proxy && *proxy) {
/* we have a proxy here to set */
+ char *ptr;
+ char proxyuser[MAX_CURL_USER_LENGTH];
+ char proxypasswd[MAX_CURL_PASSWORD_LENGTH];
+
+ char *fineptr;
+
+ /* skip the possible protocol piece */
+ ptr=strstr(proxy, "://");
+ if(ptr)
+ ptr += 3;
+ else
+ ptr = proxy;
+
+ fineptr = ptr;
+
+ /* check for an @-letter */
+ ptr = strchr(ptr, '@');
+ if(ptr && (2 == sscanf(fineptr,
+ "%" MAX_CURL_USER_LENGTH_TXT"[^:]:"
+ "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]",
+ proxyuser, proxypasswd))) {
+ CURLcode res = CURLE_OK;
+
+ /* found user and password, rip them out */
+ Curl_safefree(conn->proxyuser);
+ conn->proxyuser = strdup(proxyuser);
+
+ if(!conn->proxyuser)
+ res = CURLE_OUT_OF_MEMORY;
+ else {
+ Curl_safefree(conn->proxypasswd);
+ conn->proxypasswd = strdup(proxypasswd);
+
+ if(!conn->proxypasswd)
+ res = CURLE_OUT_OF_MEMORY;
+ }
+
+ if(CURLE_OK == res) {
+ conn->bits.proxy_user_passwd = TRUE; /* enable it */
+ ptr = strdup(ptr+1); /* the right side of the @-letter */
+
+ if(ptr) {
+ free(proxy); /* free the former proxy string */
+ proxy = ptr; /* now use this instead */
+ }
+ else
+ res = CURLE_OUT_OF_MEMORY;
+ }
+
+ if(res) {
+ free(proxy); /* free the allocated proxy string */
+ return res;
+ }
+ }
+
data->change.proxy = proxy;
data->change.proxy_alloc=TRUE; /* this needs to be freed later */
conn->bits.httpproxy = TRUE;
@@ -2118,8 +2570,9 @@ static CURLcode CreateConnection(struct SessionHandle *data,
if(conn->resume_from) {
if(!conn->bits.use_range) {
/* if it already was in use, we just skip this */
- snprintf(resumerange, sizeof(resumerange), "%d-", conn->resume_from);
- conn->range=strdup(resumerange); /* tell ourselves to fetch this range */
+ conn->range = aprintf("%" FORMAT_OFF_T "-", conn->resume_from);
+ if(!conn->range)
+ return CURLE_OUT_OF_MEMORY;
conn->bits.rangestringalloc = TRUE; /* mark as allocated */
conn->bits.use_range = 1; /* switch on range usage */
}
@@ -2171,10 +2624,10 @@ static CURLcode CreateConnection(struct SessionHandle *data,
conn->remote_port = PORT_GOPHER;
/* Skip /<item-type>/ in path if present */
if (isdigit((int)conn->path[1])) {
- conn->ppath = strchr(&conn->path[1], '/');
- if (conn->ppath == NULL)
- conn->ppath = conn->path;
- }
+ conn->path = strchr(&conn->path[1], '/');
+ if (conn->path == NULL)
+ conn->path = conn->pathbuffer;
+ }
conn->protocol |= PROT_GOPHER;
conn->curl_do = Curl_http;
conn->curl_do_more = NULL;
@@ -2187,13 +2640,15 @@ static CURLcode CreateConnection(struct SessionHandle *data,
else if(strequal(conn->protostr, "FTP") ||
strequal(conn->protostr, "FTPS")) {
-/* MN 06/07/02 */
#ifndef CURL_DISABLE_FTP
char *type;
+ int port = PORT_FTP;
if(strequal(conn->protostr, "FTPS")) {
#ifdef USE_SSLEAY
conn->protocol |= PROT_FTPS|PROT_SSL;
+ conn->ssl[SECONDARYSOCKET].use = TRUE; /* send data securely */
+ port = PORT_FTPS;
#else
failf(data, LIBCURL_NAME
" was built with SSL disabled, ftps: not supported!");
@@ -2202,8 +2657,8 @@ static CURLcode CreateConnection(struct SessionHandle *data,
}
conn->port = (data->set.use_port && data->state.allow_port)?
- data->set.use_port:PORT_FTP;
- conn->remote_port = PORT_FTP;
+ data->set.use_port:port;
+ conn->remote_port = port;
conn->protocol |= PROT_FTP;
if(data->change.proxy &&
@@ -2233,18 +2688,18 @@ static CURLcode CreateConnection(struct SessionHandle *data,
conn->curl_disconnect = Curl_ftp_disconnect;
}
- conn->ppath++; /* don't include the initial slash */
+ conn->path++; /* don't include the initial slash */
/* FTP URLs support an extension like ";type=<typecode>" that
* we'll try to get now! */
- type=strstr(conn->ppath, ";type=");
+ type=strstr(conn->path, ";type=");
if(!type) {
- type=strstr(conn->gname, ";type=");
+ type=strstr(conn->host.rawalloc, ";type=");
}
if(type) {
char command;
*type=0; /* it was in the middle of the hostname */
- command = (char)toupper((int)type[6]);
+ command = toupper((int)type[6]);
switch(command) {
case 'A': /* ASCII mode */
data->set.ftp_ascii = 1;
@@ -2259,8 +2714,6 @@ static CURLcode CreateConnection(struct SessionHandle *data,
break;
}
}
-
-/* MN 06/07/02 */
#else /* CURL_DISABLE_FTP */
failf(data, LIBCURL_NAME
" was built with FTP disabled, ftp/ftps: not supported!");
@@ -2313,7 +2766,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
conn->protocol |= PROT_FILE;
conn->curl_do = Curl_file;
- /* no done() function */
+ conn->curl_done = Curl_file_done;
/* anyway, this is supposed to be the connect function so we better
at least check that the file is present here! */
@@ -2348,24 +2801,23 @@ static CURLcode CreateConnection(struct SessionHandle *data,
* To be able to detect port number flawlessly, we must not confuse them
* IPv6-specified addresses in the [0::1] style. (RFC2732)
*
- * The conn->name is currently [user:passwd@]host[:port] where host could
- * be a hostname, IPv4 address or IPv6 address.
+ * The conn->host.name is currently [user:passwd@]host[:port] where host
+ * could be a hostname, IPv4 address or IPv6 address.
*************************************************************/
- if((1 == sscanf(conn->name, "[%*39[0-9a-fA-F:.]%c", &endbracket)) &&
+ if((1 == sscanf(conn->host.name, "[%*39[0-9a-fA-F:.]%c", &endbracket)) &&
(']' == endbracket)) {
/* this is a RFC2732-style specified IP-address */
conn->bits.ipv6_ip = TRUE;
- conn->name++; /* pass the starting bracket */
- conn->hostname++;
- tmp = strchr(conn->name, ']');
+ conn->host.name++; /* pass the starting bracket */
+ tmp = strchr(conn->host.name, ']');
*tmp = 0; /* zero terminate */
tmp++; /* pass the ending bracket */
if(':' != *tmp)
tmp = NULL; /* no port number available */
}
else
- tmp = strrchr(conn->name, ':');
+ tmp = strrchr(conn->host.name, ':');
if (tmp) {
char *rest;
@@ -2434,12 +2886,22 @@ static CURLcode CreateConnection(struct SessionHandle *data,
}
/* now, clone the cleaned proxy host name */
- conn->proxyhost = strdup(proxyptr);
+ conn->proxy.rawalloc = strdup(proxyptr);
+ conn->proxy.name = conn->proxy.rawalloc;
free(proxydup); /* free the duplicate pointer and not the modified */
+ if(!conn->proxy.rawalloc)
+ return CURLE_OUT_OF_MEMORY;
}
/*************************************************************
+ * If the protcol is using SSL and HTTP proxy is used, we set
+ * the tunnel_proxy bit.
+ *************************************************************/
+ if((conn->protocol&PROT_SSL) && conn->bits.httpproxy)
+ conn->bits.tunnel_proxy = TRUE;
+
+ /*************************************************************
* Take care of user and password authentication stuff
*************************************************************/
@@ -2447,37 +2909,37 @@ static CURLcode CreateConnection(struct SessionHandle *data,
* Inputs: data->set.userpwd (CURLOPT_USERPWD)
* data->set.fpasswd (CURLOPT_PASSWDFUNCTION)
* data->set.use_netrc (CURLOPT_NETRC)
- * conn->hostname
+ * conn->host.name
* netrc file
* hard-coded defaults
*
* Outputs: (almost :- all currently undefined)
* conn->bits.user_passwd - non-zero if non-default passwords exist
- * conn->state.user - non-zero length if defined
- * conn->state.passwd - ditto
- * conn->hostname - remove user name and password
+ * conn->user - non-zero length if defined
+ * conn->passwd - ditto
+ * conn->host.name - remove user name and password
*/
/* At this point, we're hoping all the other special cases have
- * been taken care of, so conn->hostname is at most
+ * been taken care of, so conn->host.name is at most
* [user[:password]]@]hostname
*
* We need somewhere to put the embedded details, so do that first.
*/
- data->state.user[0] =0; /* to make everything well-defined */
- data->state.passwd[0]=0;
-
+ user[0] =0; /* to make everything well-defined */
+ passwd[0]=0;
+
if (conn->protocol & (PROT_FTP|PROT_HTTP)) {
/* This is a FTP or HTTP URL, we will now try to extract the possible
* user+password pair in a string like:
* ftp://user:password@ftp.my.site:8021/README */
- char *ptr=strchr(conn->name, '@');
- char *userpass = conn->name;
+ char *ptr=strchr(conn->host.name, '@');
+ char *userpass = conn->host.name;
if(ptr != NULL) {
/* there's a user+password given here, to the left of the @ */
- conn->name = conn->hostname = ++ptr;
+ conn->host.name = ++ptr;
/* So the hostname is sane. Only bother interpreting the
* results if we could care. It could still be wasted
@@ -2493,30 +2955,31 @@ static CURLcode CreateConnection(struct SessionHandle *data,
if(*userpass != ':') {
/* the name is given, get user+password */
sscanf(userpass, "%127[^:@]:%127[^@]",
- data->state.user, data->state.passwd);
+ user, passwd);
}
else
/* no name given, get the password only */
- sscanf(userpass, ":%127[^@]", data->state.passwd);
+ sscanf(userpass, ":%127[^@]", passwd);
- /* we have set the password */
- data->state.passwdgiven = TRUE;
+ if(user[0]) {
+ char *newname=curl_unescape(user, 0);
+ if(!newname)
+ return CURLE_OUT_OF_MEMORY;
+ if(strlen(newname) < sizeof(user))
+ strcpy(user, newname);
- if(data->state.user[0]) {
- char *newname=curl_unescape(data->state.user, 0);
- if(strlen(newname) < sizeof(data->state.user)) {
- strcpy(data->state.user, newname);
- }
/* if the new name is longer than accepted, then just use
the unconverted name, it'll be wrong but what the heck */
free(newname);
}
- if (data->state.passwd[0]) {
+ if (passwd[0]) {
/* we have a password found in the URL, decode it! */
- char *newpasswd=curl_unescape(data->state.passwd, 0);
- if(strlen(newpasswd) < sizeof(data->state.passwd)) {
- strcpy(data->state.passwd, newpasswd);
- }
+ char *newpasswd=curl_unescape(passwd, 0);
+ if(!newpasswd)
+ return CURLE_OUT_OF_MEMORY;
+ if(strlen(newpasswd) < sizeof(passwd))
+ strcpy(passwd, newpasswd);
+
free(newpasswd);
}
}
@@ -2533,50 +2996,39 @@ static CURLcode CreateConnection(struct SessionHandle *data,
* so it doesn't have to be set in this block
*/
if (data->set.userpwd != NULL) {
- if(*data->set.userpwd != ':') {
- /* the name is given, get user+password */
- sscanf(data->set.userpwd, "%127[^:]:%127[^\n]",
- data->state.user, data->state.passwd);
- if(strchr(data->set.userpwd, ':'))
- /* a colon means the password was given, even if blank */
- data->state.passwdgiven = TRUE;
+ /* the name is given, get user+password */
+ sscanf(data->set.userpwd,
+ "%" MAX_CURL_USER_LENGTH_TXT "[^:]:"
+ "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^\n]",
+ user, passwd);
+ }
+
+ if (data->set.use_netrc != CURL_NETRC_IGNORED) {
+ if(Curl_parsenetrc(conn->host.name,
+ user, passwd,
+ data->set.netrc_file)) {
+ infof(data, "Couldn't find host %s in the .netrc file, using defaults\n",
+ conn->host.name);
}
else
- /* no name given, starts with a colon, get the password only */
- sscanf(data->set.userpwd+1, "%127[^\n]", data->state.passwd);
- }
-
- if (data->set.use_netrc != CURL_NETRC_IGNORED &&
- !data->state.passwdgiven) { /* need passwd */
- if(Curl_parsenetrc(conn->hostname,
- data->state.user,
- data->state.passwd)) {
- infof(data, "Couldn't find host %s in the .netrc file, using defaults",
- conn->hostname);
- } else
conn->bits.user_passwd = 1; /* enable user+password */
}
- /* if we have a user but no password, ask for one */
- if(conn->bits.user_passwd && !data->state.passwdgiven ) {
- if(data->set.fpasswd(data->set.passwd_client,
- "password:", data->state.passwd,
- sizeof(data->state.passwd)))
- return CURLE_BAD_PASSWORD_ENTERED;
- }
-
- /* So we could have a password but no user; that's just too bad. */
-
/* If our protocol needs a password and we have none, use the defaults */
- if ( (conn->protocol & (PROT_FTP|PROT_HTTP)) &&
- !conn->bits.user_passwd &&
- !data->state.passwdgiven) {
-
- strcpy(data->state.user, CURL_DEFAULT_USER);
- strcpy(data->state.passwd, CURL_DEFAULT_PASSWORD);
+ if ( (conn->protocol & PROT_FTP) &&
+ !conn->bits.user_passwd) {
+ conn->user = strdup(CURL_DEFAULT_USER);
+ conn->passwd = strdup(CURL_DEFAULT_PASSWORD);
/* This is the default password, so DON'T set conn->bits.user_passwd */
}
+ else {
+ /* store user + password, zero-length if not set */
+ conn->user = strdup(user);
+ conn->passwd = strdup(passwd);
+ }
+ if(!conn->user || !conn->passwd)
+ return CURLE_OUT_OF_MEMORY;
/*************************************************************
* Check the current list of connections to see if we can
@@ -2584,10 +3036,21 @@ static CURLcode CreateConnection(struct SessionHandle *data,
* new one.
*************************************************************/
- /* reuse_fresh is set TRUE if we are told to use a fresh connection
- by force */
- if(!data->set.reuse_fresh &&
- ConnectionExists(data, conn, &conn_temp)) {
+ /* get a cloned copy of the SSL config situation stored in the
+ connection struct */
+ if(!Curl_clone_ssl_config(&data->set.ssl, &conn->ssl_config))
+ return CURLE_OUT_OF_MEMORY;
+
+ /* reuse_fresh is TRUE if we are told to use a new connection by force, but
+ we only acknowledge this option if this is not a re-used connection
+ already (which happens due to follow-location or during a HTTP
+ authentication phase). */
+ if(data->set.reuse_fresh && !data->state.this_is_a_follow)
+ reuse = FALSE;
+ else
+ reuse = ConnectionExists(data, conn, &conn_temp);
+
+ if(reuse) {
/*
* We already have a connection for this, we got the former connection
* in the conn_temp variable and thus we need to cleanup the one we
@@ -2595,26 +3058,36 @@ static CURLcode CreateConnection(struct SessionHandle *data,
* existing one.
*/
struct connectdata *old_conn = conn;
- char *path = old_conn->path; /* setup the current path pointer properly */
- char *ppath = old_conn->ppath; /* this is the modified path pointer */
- if(old_conn->proxyhost)
- free(old_conn->proxyhost);
+
+ if(old_conn->proxy.rawalloc)
+ free(old_conn->proxy.rawalloc);
+
+ /* free the SSL config struct from this connection struct as this was
+ allocated in vain and is targeted for destruction */
+ Curl_free_ssl_config(&conn->ssl_config);
+
conn = conn_temp; /* use this connection from now on */
- /* If we speak over a proxy, we need to copy the host name too, as it
- might be another remote host even when re-using a connection */
- strcpy(conn->gname, old_conn->gname); /* safe strcpy() */
+ /* get the user+password information from the old_conn struct since it may
+ * be new for this request even when we re-use an existing connection */
+ conn->bits.user_passwd = old_conn->bits.user_passwd;
+ conn->bits.proxy_user_passwd = old_conn->bits.proxy_user_passwd;
- /* we need these pointers if we speak over a proxy */
- conn->hostname = conn->gname;
- conn->name = &conn->gname[old_conn->name - old_conn->gname];
+ /* host can change, when doing keepalive with a proxy ! */
+ if (conn->bits.httpproxy) {
+ free(conn->host.rawalloc);
+ conn->host=old_conn->host;
+ }
+
+ /* get the newly set value, not the old one */
+ conn->bits.no_body = old_conn->bits.no_body;
- free(conn->path); /* free the previously allocated path pointer */
+ if (!conn->bits.httpproxy)
+ free(old_conn->host.rawalloc); /* free the newly allocated name buffer */
- /* 'path' points to the allocated data, 'ppath' may have been advanced
- to point somewhere within the 'path' area. */
- conn->path = path;
- conn->ppath = ppath;
+ free(conn->pathbuffer); /* free the newly allocated path pointer */
+ conn->pathbuffer = old_conn->pathbuffer; /* use the old one */
+ conn->path = old_conn->path;
/* re-use init */
conn->bits.reuse = TRUE; /* yes, we're re-using here */
@@ -2622,6 +3095,14 @@ static CURLcode CreateConnection(struct SessionHandle *data,
otherwise */
conn->maxdownload = -1; /* might have been used previously! */
+ Curl_safefree(old_conn->user);
+ Curl_safefree(old_conn->passwd);
+ Curl_safefree(old_conn->proxyuser);
+ Curl_safefree(old_conn->proxypasswd);
+
+ if(old_conn->bits.rangestringalloc)
+ free(old_conn->range);
+
free(old_conn); /* we don't need this anymore */
/*
@@ -2630,25 +3111,32 @@ static CURLcode CreateConnection(struct SessionHandle *data,
*/
conn->resume_from = data->set.set_resume_from;
if (conn->resume_from) {
- snprintf(resumerange, sizeof(resumerange), "%d-", conn->resume_from);
- if (conn->bits.rangestringalloc == TRUE)
- free(conn->range);
-
- /* tell ourselves to fetch this range */
- conn->range = strdup(resumerange);
- conn->bits.use_range = TRUE; /* enable range download */
- conn->bits.rangestringalloc = TRUE; /* mark range string allocated */
+ if (conn->bits.rangestringalloc == TRUE)
+ free(conn->range);
+ conn->range = aprintf("%" FORMAT_OFF_T "-", conn->resume_from);
+ if(!conn->range)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* tell ourselves to fetch this range */
+ conn->bits.use_range = TRUE; /* enable range download */
+ conn->bits.rangestringalloc = TRUE; /* mark range string allocated */
}
else if (data->set.set_range) {
/* There is a range, but is not a resume, useful for random ftp access */
conn->range = strdup(data->set.set_range);
+ if(!conn->range)
+ return CURLE_OUT_OF_MEMORY;
conn->bits.rangestringalloc = TRUE; /* mark range string allocated */
conn->bits.use_range = TRUE; /* enable range download */
}
-
+ else
+ conn->bits.use_range = FALSE; /* disable range download */
+
*in_connect = conn; /* return this instead! */
- infof(data, "Re-using existing connection! (#%d)\n", conn->connectindex);
+ infof(data, "Re-using existing connection! (#%ld) with host %s\n",
+ conn->connectindex,
+ conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname);
}
else {
/*
@@ -2658,8 +3146,27 @@ static CURLcode CreateConnection(struct SessionHandle *data,
ConnectionStore(data, conn);
}
+ /* Continue connectdata initialization here.
+ *
+ * Inherit the proper values from the urldata struct AFTER we have arranged
+ * the persistant conncetion stuff */
+ conn->fread = data->set.fread;
+ conn->fread_in = data->set.in;
+
+ conn->bits.upload_chunky =
+ ((conn->protocol&PROT_HTTP) &&
+ data->set.upload &&
+ (data->set.infilesize == -1) &&
+ (data->set.httpversion != CURL_HTTP_VERSION_1_0))?
+ /* HTTP, upload, unknown file size and not HTTP 1.0 */
+ TRUE:
+ /* else, no chunky upload */
+ FALSE;
+
+#ifndef USE_ARES
/*************************************************************
- * Set timeout if that is being used
+ * Set timeout if that is being used, and we're not using an asynchronous
+ * name resolve.
*************************************************************/
if((data->set.timeout || data->set.connecttimeout) && !data->set.no_signal) {
/*************************************************************
@@ -2667,6 +3174,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
* Store the old value to be able to set it back later!
*************************************************************/
+#ifdef SIGALRM
#ifdef HAVE_SIGACTION
struct sigaction sigact;
sigaction(SIGALRM, NULL, &sigact);
@@ -2679,12 +3187,12 @@ static CURLcode CreateConnection(struct SessionHandle *data,
#endif
/* now set the new struct */
sigaction(SIGALRM, &sigact, NULL);
-#else
+#else /* HAVE_SIGACTION */
/* no sigaction(), revert to the much lamer signal() */
#ifdef HAVE_SIGNAL
keep_sigact = signal(SIGALRM, alarmfunc);
#endif
-#endif
+#endif /* HAVE_SIGACTION */
/* We set the timeout on the name resolving phase first, separately from
* the download/upload part to allow a maximum time on everything. This is
@@ -2701,7 +3209,9 @@ static CURLcode CreateConnection(struct SessionHandle *data,
recently set in the beginning of this function and nothing slow
has been done since then until now. */
#endif
+#endif /* SIGALRM */
}
+#endif /* USE_ARES */
/*************************************************************
* Resolve the name of the server or proxy
@@ -2709,35 +3219,56 @@ static CURLcode CreateConnection(struct SessionHandle *data,
if(conn->bits.reuse) {
/* re-used connection, no resolving is necessary */
hostaddr = NULL;
+ conn->dns_entry = NULL; /* we don't connect now so we don't have any fresh
+ dns entry struct to point to */
+
+ if (conn->bits.httpproxy)
+ fix_hostname(conn, &conn->host);
}
- else if(!data->change.proxy || !*data->change.proxy) {
- /* If not connecting via a proxy, extract the port from the URL, if it is
- * there, thus overriding any defaults that might have been set above. */
- conn->port = conn->remote_port; /* it is the same port */
+ else {
+ /* this is a fresh connect */
- /* Resolve target host right on */
- hostaddr = Curl_resolv(data, conn->name, conn->port);
+ /* set a pointer to the hostname we display */
+ fix_hostname(conn, &conn->host);
- if(!hostaddr) {
- failf(data, "Couldn't resolve host '%s'", conn->name);
- result = CURLE_COULDNT_RESOLVE_HOST;
- /* don't return yet, we need to clean up the timeout first */
+ if(!data->change.proxy || !*data->change.proxy) {
+ /* If not connecting via a proxy, extract the port from the URL, if it is
+ * there, thus overriding any defaults that might have been set above. */
+ conn->port = conn->remote_port; /* it is the same port */
+
+ /* Resolve target host right on */
+ rc = Curl_resolv(conn, conn->host.name, (int)conn->port, &hostaddr);
+ if(rc == CURLRESOLV_PENDING)
+ *async = TRUE;
+
+ else if(!hostaddr) {
+ failf(data, "Couldn't resolve host '%s'", conn->host.dispname);
+ result = CURLE_COULDNT_RESOLVE_HOST;
+ /* don't return yet, we need to clean up the timeout first */
+ }
}
- }
- else {
- /* This is a proxy that hasn't been resolved yet. */
+ else {
+ /* This is a proxy that hasn't been resolved yet. */
- /* resolve proxy */
- hostaddr = Curl_resolv(data, conn->proxyhost, conn->port);
+ /* IDN-fix the proxy name */
+ fix_hostname(conn, &conn->proxy);
- if(!hostaddr) {
- failf(data, "Couldn't resolve proxy '%s'", conn->proxyhost);
- result = CURLE_COULDNT_RESOLVE_PROXY;
- /* don't return yet, we need to clean up the timeout first */
+ /* resolve proxy */
+ rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &hostaddr);
+
+ if(rc == CURLRESOLV_PENDING)
+ *async = TRUE;
+
+ else if(!hostaddr) {
+ failf(data, "Couldn't resolve proxy '%s'", conn->proxy.dispname);
+ result = CURLE_COULDNT_RESOLVE_PROXY;
+ /* don't return yet, we need to clean up the timeout first */
+ }
}
}
- Curl_pgrsTime(data, TIMER_NAMELOOKUP);
-#ifdef HAVE_ALARM
+ *addr = hostaddr;
+
+#if defined(HAVE_ALARM) && defined(SIGALRM) && !defined(USE_ARES)
if((data->set.timeout || data->set.connecttimeout) && !data->set.no_signal) {
#ifdef HAVE_SIGACTION
if(keep_copysig) {
@@ -2750,19 +3281,22 @@ static CURLcode CreateConnection(struct SessionHandle *data,
/* restore the previous SIGALRM handler */
signal(SIGALRM, keep_sigact);
#endif
-#endif
+#endif /* HAVE_SIGACTION */
+
/* switch back the alarm() to either zero or to what it was before minus
the time we spent until now! */
if(prev_alarm) {
/* there was an alarm() set before us, now put it back */
- long elapsed_ms = Curl_tvdiff(Curl_tvnow(), conn->created);
- long alarm_set;
+ unsigned long elapsed_ms = Curl_tvdiff(Curl_tvnow(), conn->created);
+ unsigned long alarm_set;
/* the alarm period is counted in even number of seconds */
alarm_set = prev_alarm - elapsed_ms/1000;
- if(alarm_set<=0) {
- /* if it turned negative, we should fire off a SIGALRM here, but we
+ if(!alarm_set ||
+ ((alarm_set >= 0x80000000) && (prev_alarm < 0x80000000)) ) {
+ /* if the alarm time-left reached zero or turned "negative" (counted
+ with unsigned values), we should fire off a SIGALRM here, but we
won't, and zero would be to switch it off so we never set it to
less than 1! */
alarm(1);
@@ -2770,31 +3304,32 @@ static CURLcode CreateConnection(struct SessionHandle *data,
failf(data, "Previous alarm fired off!");
}
else
- alarm(alarm_set);
+ alarm((unsigned int)alarm_set);
}
else
alarm(0); /* just shut it off */
}
#endif
- if(result)
- return result;
- /*************************************************************
- * Proxy authentication
- *************************************************************/
- if(conn->bits.proxy_user_passwd) {
- char *authorization;
- snprintf(data->state.buffer, BUFSIZE, "%s:%s",
- data->state.proxyuser, data->state.proxypasswd);
- if(Curl_base64_encode(data->state.buffer, (int)strlen(data->state.buffer),
- &authorization) >= 0) {
- if(conn->allocptr.proxyuserpwd)
- free(conn->allocptr.proxyuserpwd);
- conn->allocptr.proxyuserpwd =
- aprintf("Proxy-authorization: Basic %s\015\012", authorization);
- free(authorization);
- }
- }
+ return result;
+}
+
+/* SetupConnection() should be called after the name resolve initiated in
+ * CreateConnection() is all done.
+ */
+
+static CURLcode SetupConnection(struct connectdata *conn,
+ struct Curl_dns_entry *hostaddr)
+{
+ struct SessionHandle *data = conn->data;
+ CURLcode result=CURLE_OK;
+
+ Curl_pgrsTime(data, TIMER_NAMELOOKUP);
+
+ if(conn->protocol & PROT_FILE)
+ /* There's nothing in this function to setup if we're only doing
+ a file:// transfer */
+ return result;
/*************************************************************
* Send user-agent to HTTP proxies even if the target protocol
@@ -2803,31 +3338,33 @@ static CURLcode CreateConnection(struct SessionHandle *data,
if((conn->protocol&PROT_HTTP) ||
(data->change.proxy && *data->change.proxy)) {
if(data->set.useragent) {
- if(conn->allocptr.uagent)
- free(conn->allocptr.uagent);
+ Curl_safefree(conn->allocptr.uagent);
conn->allocptr.uagent =
aprintf("User-Agent: %s\015\012", data->set.useragent);
+ if(!conn->allocptr.uagent)
+ return CURLE_OUT_OF_MEMORY;
}
}
if(data->set.encoding) {
- if(conn->allocptr.accept_encoding)
- free(conn->allocptr.accept_encoding);
+ Curl_safefree(conn->allocptr.accept_encoding);
conn->allocptr.accept_encoding =
aprintf("Accept-Encoding: %s\015\012", data->set.encoding);
+ if(!conn->allocptr.accept_encoding)
+ return CURLE_OUT_OF_MEMORY;
}
conn->bytecount = 0;
conn->headerbytecount = 0;
-
- if(-1 == conn->firstsocket) {
+
+ if(CURL_SOCKET_BAD == conn->sock[FIRSTSOCKET]) {
bool connected;
/* Connect only if not already connected! */
result = ConnectPlease(conn, hostaddr, &connected);
if(connected) {
- result = Curl_protocol_connect(conn, hostaddr);
+ result = Curl_protocol_connect(conn);
if(CURLE_OK == result)
conn->bits.tcpconnect = TRUE;
}
@@ -2842,7 +3379,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */
conn->bits.tcpconnect = TRUE;
if(data->set.verbose)
- verboseconnect(conn, hostaddr);
+ verboseconnect(conn);
}
conn->now = Curl_tvnow(); /* time this *after* the connect is done, we
@@ -2864,30 +3401,68 @@ static CURLcode CreateConnection(struct SessionHandle *data,
}
CURLcode Curl_connect(struct SessionHandle *data,
- struct connectdata **in_connect)
+ struct connectdata **in_connect,
+ bool *asyncp)
{
CURLcode code;
- struct connectdata *conn;
+ struct Curl_dns_entry *dns;
+
+ *asyncp = FALSE; /* assume synchronous resolves by default */
/* call the stuff that needs to be called */
- code = CreateConnection(data, in_connect);
+ code = CreateConnection(data, in_connect, &dns, asyncp);
+
+ if(CURLE_OK == code) {
+ /* no error */
+ if(dns || !*asyncp)
+ /* If an address is available it means that we already have the name
+ resolved, OR it isn't async.
+ If so => continue connecting from here */
+ code = SetupConnection(*in_connect, dns);
+ /* else
+ response will be received and treated async wise */
+ }
if(CURLE_OK != code) {
/* We're not allowed to return failure with memory left allocated
in the connectdata struct, free those here */
- conn = (struct connectdata *)*in_connect;
- if(conn) {
- Curl_disconnect(conn); /* close the connection */
- *in_connect = NULL; /* return a NULL */
+ if(*in_connect) {
+ Curl_disconnect(*in_connect); /* close the connection */
+ *in_connect = NULL; /* return a NULL */
}
}
+
return code;
}
-CURLcode Curl_done(struct connectdata *conn)
+/* Call this function after Curl_connect() has returned async=TRUE and
+ then a successful name resolve has been received */
+CURLcode Curl_async_resolved(struct connectdata *conn)
+{
+#if defined(USE_ARES) || defined(USE_THREADING_GETHOSTBYNAME) || \
+ defined(USE_THREADING_GETADDRINFO)
+ CURLcode code = SetupConnection(conn, conn->async.dns);
+
+ if(code)
+ /* We're not allowed to return failure with memory left allocated
+ in the connectdata struct, free those here */
+ Curl_disconnect(conn); /* close the connection */
+
+ return code;
+#else
+ (void)conn;
+ return CURLE_OK;
+#endif
+}
+
+
+CURLcode Curl_done(struct connectdata **connp,
+ CURLcode status) /* an error if this is called after an
+ error was detected */
{
- struct SessionHandle *data=conn->data;
CURLcode result;
+ struct connectdata *conn = *connp;
+ struct SessionHandle *data=conn->data;
/* cleanups done even if the connection is re-used */
@@ -2902,18 +3477,20 @@ CURLcode Curl_done(struct connectdata *conn)
conn->newurl = NULL;
}
- if(conn->connect_addr)
- Curl_resolv_unlock(conn->connect_addr); /* done with this */
+ if(conn->dns_entry)
+ Curl_resolv_unlock(conn->data, conn->dns_entry); /* done with this */
-#if defined(MALLOCDEBUG) && defined(AGGRESIVE_TEST)
+#if defined(CURLDEBUG) && defined(AGGRESIVE_TEST)
/* scan for DNS cache entries still marked as in use */
Curl_hash_apply(data->hostcache,
NULL, Curl_scan_cache_used);
#endif
+ Curl_hostcache_prune(data); /* kill old DNS cache entries */
+
/* this calls the protocol-specific function pointer previously set */
if(conn->curl_done)
- result = conn->curl_done(conn);
+ result = conn->curl_done(conn, status);
else
result = CURLE_OK;
@@ -2921,15 +3498,26 @@ CURLcode Curl_done(struct connectdata *conn)
/* if data->set.reuse_forbid is TRUE, it means the libcurl client has
forced us to close this no matter what we think.
-
+
if conn->bits.close is TRUE, it means that the connection should be
closed in spite of all our efforts to be nice, due to protocol
restrictions in our or the server's end */
- if(data->set.reuse_forbid ||
- ((CURLE_OK == result) && conn->bits.close))
- result = Curl_disconnect(conn); /* close the connection */
+ if(data->set.reuse_forbid || conn->bits.close) {
+ CURLcode res2;
+ res2 = Curl_disconnect(conn); /* close the connection */
+
+ *connp = NULL; /* to make the caller of this function better detect that
+ this was actually killed here */
+
+ /* If we had an error already, make sure we return that one. But
+ if we got a new error, return that. */
+ if(!result && res2)
+ result = res2;
+ }
else
- infof(data, "Connection #%d left intact\n", conn->connectindex);
+ infof(data, "Connection #%ld to host %s left intact\n",
+ conn->connectindex,
+ conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname);
return result;
}
@@ -2947,7 +3535,7 @@ CURLcode Curl_do(struct connectdata **connp)
result = conn->curl_do(conn);
/* This was formerly done in transfer.c, but we better do it here */
-
+
if((CURLE_SEND_ERROR == result) && conn->bits.reuse) {
/* This was a re-use of a connection and we got a write error in the
* DO-phase. Then we DISCONNECT this connection and have another attempt
@@ -2957,14 +3545,35 @@ CURLcode Curl_do(struct connectdata **connp)
infof(data, "Re-used connection seems dead, get a new one\n");
- conn->bits.close = TRUE; /* enforce close of this connetion */
- result = Curl_done(conn); /* we are so done with this */
+ conn->bits.close = TRUE; /* enforce close of this connection */
+ result = Curl_done(&conn, result); /* we are so done with this */
+
+ /* conn may no longer be a good pointer */
+
if(CURLE_OK == result) {
+ bool async;
/* Now, redo the connect and get a new connection */
- result = Curl_connect(data, connp);
- if(CURLE_OK == result)
+ result = Curl_connect(data, connp, &async);
+ if(CURLE_OK == result) {
+ /* We have connected or sent away a name resolve query fine */
+
+ conn = *connp; /* setup conn to again point to something nice */
+ if(async) {
+ /* Now, if async is TRUE here, we need to wait for the name
+ to resolve */
+ result = Curl_wait_for_resolv(conn, NULL);
+ if(result)
+ return result;
+
+ /* Resolved, continue with the connection */
+ result = Curl_async_resolved(conn);
+ if(result)
+ return result;
+ }
+
/* ... finally back to actually retry the DO phase */
- result = conn->curl_do(*connp);
+ result = conn->curl_do(conn);
+ }
}
}
}
@@ -2981,10 +3590,89 @@ CURLcode Curl_do_more(struct connectdata *conn)
return result;
}
-/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
- */
+static bool safe_strequal(char* str1, char* str2)
+{
+ if(str1 && str2)
+ /* both pointers point to something then compare them */
+ return strequal(str1, str2);
+ else
+ /* if both pointers are NULL then treat them as equal */
+ return (!str1 && !str2);
+}
+
+bool
+Curl_ssl_config_matches(struct ssl_config_data* data,
+ struct ssl_config_data* needle)
+{
+ if((data->version == needle->version) &&
+ (data->verifypeer == needle->verifypeer) &&
+ (data->verifyhost == needle->verifyhost) &&
+ safe_strequal(data->CApath, needle->CApath) &&
+ safe_strequal(data->CAfile, needle->CAfile) &&
+ safe_strequal(data->random_file, needle->random_file) &&
+ safe_strequal(data->egdsocket, needle->egdsocket) &&
+ safe_strequal(data->cipher_list, needle->cipher_list))
+ return TRUE;
+
+ return FALSE;
+}
+
+bool
+Curl_clone_ssl_config(struct ssl_config_data *source,
+ struct ssl_config_data *dest)
+{
+ dest->verifyhost = source->verifyhost;
+ dest->verifypeer = source->verifypeer;
+ dest->version = source->version;
+
+ if(source->CAfile) {
+ dest->CAfile = strdup(source->CAfile);
+ if(!dest->CAfile)
+ return FALSE;
+ }
+
+ if(source->CApath) {
+ dest->CApath = strdup(source->CApath);
+ if(!dest->CApath)
+ return FALSE;
+ }
+
+ if(source->cipher_list) {
+ dest->cipher_list = strdup(source->cipher_list);
+ if(!dest->cipher_list)
+ return FALSE;
+ }
+
+ if(source->egdsocket) {
+ dest->egdsocket = strdup(source->egdsocket);
+ if(!dest->egdsocket)
+ return FALSE;
+ }
+
+ if(source->random_file) {
+ dest->random_file = strdup(source->random_file);
+ if(!dest->random_file)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void Curl_free_ssl_config(struct ssl_config_data* sslc)
+{
+ if(sslc->CAfile)
+ free(sslc->CAfile);
+
+ if(sslc->CApath)
+ free(sslc->CApath);
+
+ if(sslc->cipher_list)
+ free(sslc->cipher_list);
+
+ if(sslc->egdsocket)
+ free(sslc->egdsocket);
+
+ if(sslc->random_file)
+ free(sslc->random_file);
+}
+
diff --git a/Source/CTest/Curl/url.h b/Source/CTest/Curl/url.h
index 2da8ade..8fd4795 100644
--- a/Source/CTest/Curl/url.h
+++ b/Source/CTest/Curl/url.h
@@ -1,18 +1,18 @@
#ifndef __URL_H
#define __URL_H
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -30,11 +30,18 @@
CURLcode Curl_open(struct SessionHandle **curl);
CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...);
CURLcode Curl_close(struct SessionHandle *data); /* opposite of curl_open() */
-CURLcode Curl_connect(struct SessionHandle *, struct connectdata **);
+CURLcode Curl_connect(struct SessionHandle *, struct connectdata **,
+ bool *async);
+CURLcode Curl_async_resolved(struct connectdata *conn);
CURLcode Curl_do(struct connectdata **);
CURLcode Curl_do_more(struct connectdata *);
-CURLcode Curl_done(struct connectdata *);
+CURLcode Curl_done(struct connectdata **, CURLcode);
CURLcode Curl_disconnect(struct connectdata *);
-CURLcode Curl_protocol_connect(struct connectdata *conn,
- struct Curl_dns_entry *dns);
+CURLcode Curl_protocol_connect(struct connectdata *conn);
+bool Curl_ssl_config_matches(struct ssl_config_data* data,
+ struct ssl_config_data* needle);
+bool Curl_clone_ssl_config(struct ssl_config_data* source,
+ struct ssl_config_data* dest);
+void Curl_free_ssl_config(struct ssl_config_data* sslc);
+void Curl_safefree(void *ptr);
#endif
diff --git a/Source/CTest/Curl/urldata.h b/Source/CTest/Curl/urldata.h
index 923da5c..d951c93 100644
--- a/Source/CTest/Curl/urldata.h
+++ b/Source/CTest/Curl/urldata.h
@@ -1,18 +1,18 @@
#ifndef __URLDATA_H
#define __URLDATA_H
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -28,6 +28,7 @@
#include "setup.h"
#define PORT_FTP 21
+#define PORT_FTPS 990
#define PORT_TELNET 23
#define PORT_GOPHER 70
#define PORT_HTTP 80
@@ -47,7 +48,7 @@
#include "cookie.h"
#include "formdata.h"
-
+
#ifdef USE_SSLEAY
/* SSLeay stuff usually in /usr/local/ssl/include */
#ifdef USE_OPENSSL
@@ -76,14 +77,27 @@
#include "timeval.h"
+#ifdef HAVE_ZLIB_H
+#include <zlib.h> /* for content-encoding */
+#endif
+
+#ifdef USE_ARES
+#include <ares.h>
+#endif
+
#include <curl/curl.h>
#include "http_chunks.h" /* for the structs and enum stuff */
#include "hostip.h"
#include "hash.h"
-#ifdef HAVE_ZLIB_H
-#include <zlib.h> /* for content-encoding 08/28/02 jhrg */
+#ifdef HAVE_GSSAPI
+#ifdef HAVE_GSSMIT
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_generic.h>
+#else
+#include <gssapi.h>
+#endif
#endif
/* Download buffer size, keep it fairly big for speed reasons */
@@ -93,12 +107,11 @@
of need. */
#define HEADERSIZE 256
-/* Just a convenience macro to get the larger value out of two given */
-#ifndef MAX
-#define MAX(x,y) ((x)>(y)?(x):(y))
-#endif
+/* Just a convenience macro to get the larger value out of two given.
+ We prefix with CURL to prevent name collisions. */
+#define CURLMAX(x,y) ((x)>(y)?(x):(y))
-#ifdef KRB4
+#ifdef HAVE_KRB4
/* Types needed for krb4-ftp connections */
struct krb4buffer {
void *data;
@@ -106,20 +119,17 @@ struct krb4buffer {
size_t index;
int eof_flag;
};
-enum protection_level {
- prot_clear,
- prot_safe,
- prot_confidential,
- prot_private
+enum protection_level {
+ prot_clear,
+ prot_safe,
+ prot_confidential,
+ prot_private
};
#endif
-#ifndef HAVE_OPENSSL_ENGINE_H
-typedef void ENGINE;
-#endif
-/* struct for data related to SSL and SSL connections */
+/* struct for data related to each SSL connection */
struct ssl_connect_data {
- bool use; /* use ssl encrypted communications TRUE/FALSE */
+ bool use; /* use ssl encrypted communications TRUE/FALSE */
#ifdef USE_SSLEAY
/* these ones requires specific SSL-types */
SSL_CTX* ctx;
@@ -128,14 +138,6 @@ struct ssl_connect_data {
#endif /* USE_SSLEAY */
};
-/* information about one single SSL session */
-struct curl_ssl_session {
- char *name; /* host name for which this ID was used */
- void *sessionid; /* as returned from the SSL layer */
- long age; /* just a number, the higher the more recent */
- unsigned short remote_port; /* remote port to connect to */
-};
-
struct ssl_config_data {
long version; /* what version the client wants to use */
long certverifyresult; /* result from the certificate verification */
@@ -149,20 +151,75 @@ struct ssl_config_data {
char *egdsocket; /* path to file containing the EGD daemon socket */
char *cipher_list; /* list of ciphers to use */
long numsessions; /* SSL session id cache size */
+ curl_ssl_ctx_callback fsslctx; /* function to initialize ssl ctx */
+ void *fsslctxp; /*parameter for call back */
};
+/* information stored about one single SSL session */
+struct curl_ssl_session {
+ char *name; /* host name for which this ID was used */
+ void *sessionid; /* as returned from the SSL layer */
+ long age; /* just a number, the higher the more recent */
+ unsigned short remote_port; /* remote port to connect to */
+ struct ssl_config_data ssl_config; /* setup for this session */
+};
+
+/* Struct used for Digest challenge-response authentication */
+struct digestdata {
+ char *nonce;
+ char *cnonce;
+ char *realm;
+ int algo;
+ bool stale; /* set true for re-negotiation */
+ char *opaque;
+ char *qop;
+ char *algorithm;
+ int nc; /* nounce count */
+};
+
+typedef enum {
+ NTLMSTATE_NONE,
+ NTLMSTATE_TYPE1,
+ NTLMSTATE_TYPE2,
+ NTLMSTATE_TYPE3,
+ NTLMSTATE_LAST
+} curlntlm;
+
+/* for 3rd party transfers to decide which side that issues PASV */
+typedef enum {
+ CURL_TARGET_PASV,
+ CURL_SOURCE_PASV
+} curl_pasv_side;
+
+/* Struct used for NTLM challenge-response authentication */
+struct ntlmdata {
+ curlntlm state;
+ unsigned char nonce[8];
+};
+
+#ifdef HAVE_GSSAPI
+struct negotiatedata {
+ bool gss; /* Whether we're processing GSS-Negotiate or Negotiate */
+ const char* protocol; /* "GSS-Negotiate" or "Negotiate" */
+ OM_uint32 status;
+ gss_ctx_id_t context;
+ gss_name_t server_name;
+ gss_buffer_desc output_token;
+};
+#endif
+
/****************************************************************************
* HTTP unique setup
***************************************************************************/
struct HTTP {
struct FormData *sendit;
- int postsize;
+ curl_off_t postsize; /* off_t to handle large file sizes */
char *postdata;
const char *p_pragma; /* Pragma: string */
const char *p_accept; /* Accept: string */
- long readbytecount;
- long writebytecount;
+ curl_off_t readbytecount;
+ curl_off_t writebytecount;
/* For FORM posting */
struct Form form;
@@ -172,7 +229,7 @@ struct HTTP {
curl_read_callback fread; /* backup storage for fread pointer */
void *fread_in; /* backup storage for fread_in pointer */
char *postdata;
- int postsize;
+ curl_off_t postsize;
} backup;
enum {
@@ -190,17 +247,19 @@ struct HTTP {
* FTP unique setup
***************************************************************************/
struct FTP {
- long *bytecountp;
+ curl_off_t *bytecountp;
char *user; /* user name string */
char *passwd; /* password string */
char *urlpath; /* the originally given path part of the URL */
- char *dir; /* decoded directory */
+ char **dirs; /* realloc()ed array for path components */
+ int dirdepth; /* number of entries used in the 'dirs' array */
+ int diralloc; /* number of entries allocated for the 'dirs' array */
char *file; /* decoded file */
char *entrypath; /* the PWD reply when we logged on */
char *cache; /* data cache between getresponse()-calls */
- size_t cache_size; /* size of cache in bytes */
+ curl_off_t cache_size; /* size of cache in bytes */
bool dont_check; /* Set to TRUE to prevent the final (post-transfer)
file size and 226/250 status check. It should still
read the line, just ignore the result. */
@@ -209,13 +268,20 @@ struct FTP {
long response_time; /* When no timeout is given, this is the amount of
seconds we await for an FTP response. Initialized
in Curl_ftp_connect() */
+ bool ctl_valid; /* Tells Curl_ftp_quit() whether or not to do
+ anything. If the connection has timed out or
+ been closed, this should be FALSE when it gets
+ to Curl_ftp_quit() */
};
/****************************************************************************
* FILE unique setup
***************************************************************************/
-struct FILE {
- int fd; /* open file descriptor to read from! */
+struct FILEPROTO {
+ char *path; /* the path we operate on */
+ char *freepath; /* pointer to the allocated block we must free, this might
+ differ from the 'path' pointer */
+ int fd; /* open file descriptor to read from! */
};
/*
@@ -246,6 +312,23 @@ struct ConnectBits {
bool tcpconnect; /* the tcp stream (or simimlar) is connected, this
is set the first time on the first connect function
call */
+ bool retry; /* this connection is about to get closed and then
+ re-attempted at another connection. */
+ bool no_body; /* CURLOPT_NO_BODY (or similar) was set */
+ bool tunnel_proxy; /* if CONNECT is used to "tunnel" through the proxy.
+ This is implicit when SSL-protocols are used through
+ proxies, but can also be enabled explicitly by
+ apps */
+ bool authprobe; /* set TRUE when this transfer is done to probe for auth
+ types, as when asking for "any" type when speaking
+ HTTP */
+};
+
+struct hostname {
+ char *rawalloc; /* allocated "raw" version of the name */
+ char *encalloc; /* allocated IDN-encoded version of the name */
+ char *name; /* name to use internally, might be encoded, might be raw */
+ char *dispname; /* name to display, as 'name' might be encoded */
};
/*
@@ -255,35 +338,38 @@ struct ConnectBits {
*/
struct Curl_transfer_keeper {
- int bytecount; /* total number of bytes read */
- int writebytecount; /* number of bytes written */
- long contentlength; /* size of incoming data */
+ curl_off_t bytecount; /* total number of bytes read */
+ curl_off_t writebytecount; /* number of bytes written */
struct timeval start; /* transfer started at this time */
struct timeval now; /* current time */
bool header; /* incoming data has HTTP header */
enum {
- HEADER_NORMAL, /* no bad header at all */
- HEADER_PARTHEADER, /* part of the chunk is a bad header, the rest is
- normal data */
- HEADER_ALLBAD /* all was believed to be header */
+ HEADER_NORMAL, /* no bad header at all */
+ HEADER_PARTHEADER, /* part of the chunk is a bad header, the rest
+ is normal data */
+ HEADER_ALLBAD /* all was believed to be header */
} badheader; /* the header was deemed bad and will be
written as body */
int headerline; /* counts header lines to better track the
first one */
char *hbufp; /* points at *end* of header line */
- int hbuflen;
+ size_t hbuflen;
char *str; /* within buf */
char *str_start; /* within buf */
char *end_ptr; /* within buf */
char *p; /* within headerbuff */
bool content_range; /* set TRUE if Content-Range: was found */
- int offset; /* possible resume offset read from the
+ curl_off_t offset; /* possible resume offset read from the
Content-Range: header */
int httpcode; /* error code from the 'HTTP/1.? XXX' line */
int httpversion; /* the HTTP version*10 */
- bool write_after_100_header; /* should we enable the write after
- we received a 100-continue/timeout
- or directly */
+ struct timeval start100; /* time stamp to wait for the 100 code from */
+ bool write_after_100_header; /* TRUE = we enable the write after we
+ received a 100-continue/timeout or
+ FALSE = directly */
+ bool wait100_after_headers; /* TRUE = after the request-headers have been
+ sent off properly, we go into the wait100
+ state, FALSE = don't */
int content_encoding; /* What content encoding. sec 3.5, RFC2616. */
#define IDENTITY 0 /* No encoding */
@@ -293,18 +379,16 @@ struct Curl_transfer_keeper {
#ifdef HAVE_LIBZ
bool zlib_init; /* True if zlib already initialized;
- undefined if Content-Encdoing header. */
+ undefined if Content-Encoding header. */
z_stream z; /* State structure for zlib. */
#endif
- /* for the low speed checks: */
time_t timeofdoc;
long bodywrites;
- int writetype;
char *buf;
char *uploadbuf;
- int maxfd;
+ curl_socket_t maxfd;
/* pointers to the actual descriptors we check */
fd_set *readfdp;
@@ -319,8 +403,24 @@ struct Curl_transfer_keeper {
bool upload_done; /* set to TRUE when doing chunked transfer-encoding upload
and we're uploading the last chunk */
+
+ bool ignorebody; /* we read a response-body but we ignore it! */
};
+#if defined(USE_ARES) || defined(USE_THREADING_GETHOSTBYNAME) || \
+ defined(USE_THREADING_GETADDRINFO)
+struct Curl_async {
+ char *hostname;
+ int port;
+ struct Curl_dns_entry *dns;
+ bool done; /* set TRUE when the lookup is complete */
+ int status; /* if done is TRUE, this is the status from the callback */
+ void *os_specific; /* 'struct thread_data' for Windows */
+};
+#endif
+
+#define FIRSTSOCKET 0
+#define SECONDARYSOCKET 1
/*
* The connectdata struct contains all fields and variables that should be
@@ -329,7 +429,7 @@ struct Curl_transfer_keeper {
struct connectdata {
/**** Fields set when inited and not modified again */
struct SessionHandle *data; /* link to the root CURL struct */
- int connectindex; /* what index in the connects index this particular
+ long connectindex; /* what index in the connects index this particular
struct has */
long protocol; /* PROT_* flags concerning the protocol set */
@@ -346,97 +446,106 @@ struct connectdata {
#define PROT_SSL (1<<10) /* protocol requires SSL */
/* the particular host we use, in two different ways */
- struct Curl_dns_entry *connect_addr;
+ struct Curl_dns_entry *dns_entry;
+ Curl_addrinfo *ip_addr; /* the particular IP we connected to */
-#ifdef ENABLE_IPV6
- struct addrinfo *serv_addr;
-#else
- struct sockaddr_in serv_addr;
-#endif
- char protostr[64]; /* store the protocol string in this buffer */
- char gname[513]; /* store the hostname in this buffer */
- char *name; /* host name pointer to fool around with */
- char *path; /* allocated buffer to store the URL's path part in */
- char *hostname; /* hostname to connect, as parsed from url */
+ char protostr[16]; /* store the protocol string in this buffer */
+
+ struct hostname host;
+ struct hostname proxy;
+
+ char *pathbuffer;/* allocated buffer to store the URL's path part in */
+ char *path; /* path to use, points to somewhere within the pathbuffer
+ area */
long port; /* which port to use locally */
unsigned short remote_port; /* what remote port to connect to,
not the proxy port! */
- char *ppath;
- long bytecount;
+ curl_off_t bytecount;
long headerbytecount; /* only count received headers */
+ long deductheadercount; /* this amount of bytes doesn't count when we check
+ if anything has been transfered at the end of
+ a connection. We use this counter to make only
+ a 100 reply (without a following second response
+ code) result in a CURLE_GOT_NOTHING error code */
char *range; /* range, if used. See README for detailed specification on
this syntax. */
- ssize_t resume_from; /* continue [ftp] transfer from here */
+ curl_off_t resume_from; /* continue [ftp] transfer from here */
+
+ char *user; /* user name string, allocated */
+ char *passwd; /* password string, allocated */
- char *proxyhost; /* name of the http proxy host */
+ char *proxyuser; /* proxy user name string, allocated */
+ char *proxypasswd; /* proxy password string, allocated */
struct timeval now; /* "current" time */
struct timeval created; /* creation time */
- int firstsocket; /* the main socket to use */
- int secondarysocket; /* for i.e ftp transfers */
- long maxdownload; /* in bytes, the maximum amount of data to fetch, 0
- means unlimited */
-
- struct ssl_connect_data ssl; /* this is for ssl-stuff */
+ curl_socket_t sock[2]; /* two sockets, the second is used for the data
+ transfer when doing FTP */
+ curl_off_t maxdownload; /* in bytes, the maximum amount of data to fetch, 0
+ means unlimited */
+
+ struct ssl_connect_data ssl[2]; /* this is for ssl-stuff */
+ struct ssl_config_data ssl_config;
struct ConnectBits bits; /* various state-flags for this connection */
/* These two functions MUST be set by the curl_connect() function to be
be protocol dependent */
- CURLcode (*curl_do)(struct connectdata *connect);
- CURLcode (*curl_done)(struct connectdata *connect);
+ CURLcode (*curl_do)(struct connectdata *);
+ CURLcode (*curl_done)(struct connectdata *, CURLcode);
/* If the curl_do() function is better made in two halves, this
* curl_do_more() function will be called afterwards, if set. For example
* for doing the FTP stuff after the PASV/PORT command.
*/
- CURLcode (*curl_do_more)(struct connectdata *connect);
+ CURLcode (*curl_do_more)(struct connectdata *);
/* This function *MAY* be set to a protocol-dependent function that is run
* after the connect() and everything is done, as a step in the connection.
- */
- CURLcode (*curl_connect)(struct connectdata *connect);
+ */
+ CURLcode (*curl_connect)(struct connectdata *);
/* This function *MAY* be set to a protocol-dependent function that is run
* by the curl_disconnect(), as a step in the disconnection.
- */
- CURLcode (*curl_disconnect)(struct connectdata *connect);
+ */
+ CURLcode (*curl_disconnect)(struct connectdata *);
/* This function *MAY* be set to a protocol-dependent function that is run
* in the curl_close() function if protocol-specific cleanups are required.
- */
- CURLcode (*curl_close)(struct connectdata *connect);
+ */
+ CURLcode (*curl_close)(struct connectdata *);
/**** curl_get() phase fields */
/* READ stuff */
- int sockfd; /* socket to read from or -1 */
- int size; /* -1 if unknown at this point */
- long *bytecountp; /* return number of bytes read or NULL */
-
+ curl_socket_t sockfd; /* socket to read from or CURL_SOCKET_BAD */
+ curl_off_t size; /* -1 if unknown at this point */
+ curl_off_t *bytecountp; /* return number of bytes read or NULL */
+
/* WRITE stuff */
- int writesockfd; /* socket to write to, it may very well be
- the same we read from. -1 disables */
- long *writebytecountp; /* return number of bytes written or NULL */
+ curl_socket_t writesockfd; /* socket to write to, it may very
+ well be the same we read from.
+ CURL_SOCKET_BAD disables */
+ curl_off_t *writebytecountp; /* return number of bytes written or NULL */
/** Dynamicly allocated strings, may need to be freed before this **/
/** struct is killed. **/
struct dynamically_allocated_data {
char *proxyuserpwd; /* free later if not NULL! */
char *uagent; /* free later if not NULL! */
- char *accept_encoding; /* free later if not NULL! 08/28/02 jhrg */
+ char *accept_encoding; /* free later if not NULL! */
char *userpwd; /* free later if not NULL! */
char *rangeline; /* free later if not NULL! */
char *ref; /* free later if not NULL! */
- char *cookie; /* free later if not NULL! */
char *host; /* free later if not NULL */
+ char *cookiehost; /* free later if not NULL */
} allocptr;
char *newurl; /* This can only be set if a Location: was in the
document headers */
-#ifdef KRB4
+#ifdef HAVE_KRB4
enum protection_level command_prot;
enum protection_level data_prot;
enum protection_level request_data_prot;
@@ -459,12 +568,8 @@ struct connectdata {
struct HTTP *gopher; /* alias, just for the sake of being more readable */
struct HTTP *https; /* alias, just for the sake of being more readable */
struct FTP *ftp;
- struct FILE *file;
+ struct FILEPROTO *file;
void *telnet; /* private for telnet.c-eyes only */
-#if 0 /* no need for special ones for these: */
- struct LDAP *ldap;
- struct DICT *dict;
-#endif
void *generic;
} proto;
@@ -473,7 +578,7 @@ struct connectdata {
/* 'upload_present' is used to keep a byte counter of how much data there is
still left in the buffer, aimed for upload. */
- int upload_present;
+ ssize_t upload_present;
/* 'upload_fromhere' is used as a read-pointer when we uploaded parts of a
buffer, so the next read should read from where this pointer points to,
@@ -483,21 +588,42 @@ struct connectdata {
curl_read_callback fread; /* function that reads the input */
void *fread_in; /* pointer to pass to the fread() above */
+
+ struct ntlmdata ntlm; /* NTLM differs from other authentication schemes
+ because it authenticates connections, not
+ single requests! */
+ struct ntlmdata proxyntlm; /* NTLM data for proxy */
+
+ char syserr_buf [256]; /* buffer for Curl_strerror() */
+
+#if defined(USE_ARES) || defined(USE_THREADING_GETHOSTBYNAME) || \
+ defined(USE_THREADING_GETADDRINFO)
+ /* data used for the asynch name resolve callback */
+ struct Curl_async async;
+#endif
+ struct connectdata *sec_conn; /* secondary connection for 3rd party
+ transfer */
};
-/* The end of connectdata. 08/27/02 jhrg */
+/* The end of connectdata. */
/*
* Struct to keep statistical and informational data.
*/
struct PureInfo {
- int httpcode;
+ int httpcode; /* Recent HTTP or FTP response code */
+ int httpproxycode;
int httpversion;
- long filetime; /* If requested, this is might get set. Set to -1 if
- the time was unretrievable */
+ long filetime; /* If requested, this is might get set. Set to -1 if the time
+ was unretrievable. We cannot have this of type time_t,
+ since time_t is unsigned on several platforms such as
+ OpenVMS. */
long header_size; /* size of read header(s) in bytes */
long request_size; /* the amount of bytes sent in the request(s) */
+ long proxyauthavail;
+ long httpauthavail;
+
char *contenttype; /* the content type of the object */
};
@@ -505,12 +631,12 @@ struct PureInfo {
struct Progress {
long lastshow; /* time() of the last displayed progress meter or NULL to
force redraw at next call */
- double size_dl;
- double size_ul;
- double downloaded;
- double uploaded;
+ curl_off_t size_dl; /* total expected size */
+ curl_off_t size_ul; /* total expected size */
+ curl_off_t downloaded; /* transfered so far */
+ curl_off_t uploaded; /* transfered so far */
- double current_speed; /* uses the currently fastest transfer */
+ curl_off_t current_speed; /* uses the currently fastest transfer */
bool callback; /* set when progress callback is used */
int width; /* screen width at download start */
@@ -518,8 +644,8 @@ struct Progress {
double timespent;
- double dlspeed;
- double ulspeed;
+ curl_off_t dlspeed;
+ curl_off_t ulspeed;
double t_nslookup;
double t_connect;
@@ -531,7 +657,7 @@ struct Progress {
struct timeval t_startsingle;
#define CURR_TIME (5+1) /* 6 entries for 5 seconds */
- double speeder[ CURR_TIME ];
+ curl_off_t speeder[ CURR_TIME ];
struct timeval speeder_time[ CURR_TIME ];
int speeder_c;
};
@@ -542,6 +668,7 @@ typedef enum {
HTTPREQ_POST,
HTTPREQ_POST_FORM, /* we make a difference internally */
HTTPREQ_PUT,
+ HTTPREQ_HEAD,
HTTPREQ_CUSTOM,
HTTPREQ_LAST /* last in list */
} Curl_HttpReq;
@@ -556,6 +683,18 @@ typedef enum {
* Session-data MUST be put in the connectdata struct and here. */
#define MAX_CURL_USER_LENGTH 256
#define MAX_CURL_PASSWORD_LENGTH 256
+#define MAX_CURL_USER_LENGTH_TXT "255"
+#define MAX_CURL_PASSWORD_LENGTH_TXT "255"
+
+struct auth {
+ long want; /* Bitmask set to the authentication methods wanted by the app
+ (with CURLOPT_HTTPAUTH or CURLOPT_PROXYAUTH). */
+ long picked;
+ long avail; /* bitmask for what the server reports to support for this
+ resource */
+ bool done; /* TRUE when the auth phase is done and ready to do the *actual*
+ request */
+};
struct UrlState {
enum {
@@ -565,14 +704,6 @@ struct UrlState {
} used_interface;
/* buffers to store authentication data in, as parsed from input options */
- char user[MAX_CURL_USER_LENGTH];
- char passwd[MAX_CURL_PASSWORD_LENGTH];
- char proxyuser[MAX_CURL_USER_LENGTH];
- char proxypasswd[MAX_CURL_PASSWORD_LENGTH];
-
- bool passwdgiven; /* set TRUE if an application-provided password has been
- set */
-
struct timeval keeps_speed; /* for the progress meter really */
/* 'connects' will be an allocated array with pointers. If the pointer is
@@ -581,12 +712,12 @@ struct UrlState {
long numconnects; /* size of the 'connects' array */
char *headerbuff; /* allocated buffer to store headers in */
- int headersize; /* size of the allocation */
+ size_t headersize; /* size of the allocation */
char buffer[BUFSIZE+1]; /* download buffer */
char uploadbuffer[BUFSIZE+1]; /* upload buffer */
- double current_speed; /* the ProgressShow() funcion sets this */
-
+ curl_off_t current_speed; /* the ProgressShow() funcion sets this,
+ bytes / second */
bool this_is_a_follow; /* this is a followed Location: request */
char *auth_host; /* if set, this should be the host name that we will
@@ -598,7 +729,7 @@ struct UrlState {
struct curl_ssl_session *session; /* array of 'numsessions' size */
long sessionage; /* number of the most recent session */
- char scratch[BUFSIZE*2]; /* huge buffer when doing upload CRLF replacing */
+ char *scratch; /* huge buffer[BUFSIZE*2] when doing upload CRLF replacing */
bool errorbuf; /* Set to TRUE if the error buffer is already filled in.
This must be set to FALSE every time _easy_perform() is
called. */
@@ -609,6 +740,21 @@ struct UrlState {
#endif
bool allow_port; /* Is set.use_port allowed to take effect or not. This
is always set TRUE when curl_easy_perform() is called. */
+
+ struct digestdata digest;
+ struct digestdata proxydigest;
+
+#ifdef HAVE_GSSAPI
+ struct negotiatedata negotiate;
+#endif
+
+ struct auth authhost;
+ struct auth authproxy;
+
+ bool authproblem; /* TRUE if there's some problem authenticating */
+#ifdef USE_ARES
+ ares_channel areschannel; /* for name resolves */
+#endif
};
@@ -622,6 +768,10 @@ struct UrlState {
struct DynamicStatic {
char *url; /* work URL, copied from UserDefined */
bool url_alloc; /* URL string is malloc()'ed */
+ bool url_changed; /* set on CURL_OPT_URL, used to detect if the URL was
+ changed after the connect phase, as we allow callback
+ to change it and if so, we reconnect to use the new
+ URL instead */
char *proxy; /* work proxy, copied from UserDefined */
bool proxy_alloc; /* http proxy string is malloc()'ed */
char *referer; /* referer string */
@@ -645,7 +795,7 @@ struct UserDefined {
char *proxyuserpwd; /* Proxy <user:password>, if used */
long proxyport; /* If non-zero, use this port number by default. If the
proxy string features a ":[port]" that one will override
- this. */
+ this. */
void *out; /* the fetched file goes here */
void *in; /* the uploaded file is read from here */
void *writeheader; /* write the header to this is non-NULL */
@@ -653,6 +803,8 @@ struct UserDefined {
char *set_proxy; /* proxy to use */
long use_port; /* which port to use (when not using default) */
char *userpwd; /* <user:password>, if used */
+ long httpauth; /* what kind of HTTP authentication to use (bitmask) */
+ long proxyauth; /* what kind of proxy authentication to use (bitmask) */
char *set_range; /* range, if used. See README for detailed specification
on this syntax. */
long followlocation; /* as in HTTP Location: */
@@ -663,9 +815,9 @@ struct UserDefined {
char *useragent; /* User-Agent string */
char *encoding; /* Accept-Encoding string */
char *postfields; /* if POST, set the fields' values here */
- size_t postfieldsize; /* if POST, this might have a size to use instead of
- strlen(), and then the data *may* be binary (contain
- zero bytes) */
+ curl_off_t postfieldsize; /* if POST, this might have a size to use instead
+ of strlen(), and then the data *may* be binary
+ (contain zero bytes) */
char *ftpport; /* port to send with the FTP PORT command */
char *device; /* network interface to use */
curl_write_callback fwrite; /* function that stores the output */
@@ -674,17 +826,16 @@ struct UserDefined {
curl_progress_callback fprogress; /* function for progress information */
curl_debug_callback fdebug; /* function that write informational data */
void *progress_client; /* pointer to pass to the progress callback */
- curl_passwd_callback fpasswd; /* call for password */
- void *passwd_client; /* pass to the passwd callback */
long timeout; /* in seconds, 0 means no timeout */
long connecttimeout; /* in seconds, 0 means no timeout */
- long infilesize; /* size of file to upload, -1 means unknown */
+ long ftp_response_timeout; /* in seconds, 0 means no timeout */
+ curl_off_t infilesize; /* size of file to upload, -1 means unknown */
long low_speed_limit; /* bytes/second */
long low_speed_time; /* number of seconds */
- int set_resume_from; /* continue [ftp] transfer from here */
+ curl_off_t set_resume_from; /* continue [ftp] transfer from here */
char *cookie; /* HTTP cookie string to send */
struct curl_slist *headers; /* linked list of extra headers */
- struct HttpPost *httppost; /* linked list of POST data */
+ struct curl_httppost *httppost; /* linked list of POST data */
char *cert; /* certificate */
char *cert_type; /* format for certificate (default: PEM) */
char *key; /* private key */
@@ -696,7 +847,11 @@ struct UserDefined {
bool crlf; /* convert crlf on ftp upload(?) */
struct curl_slist *quote; /* after connection is established */
struct curl_slist *postquote; /* after the transfer */
- struct curl_slist *prequote; /* before the transfer, after type (Wesley Laxton)*/
+ struct curl_slist *prequote; /* before the transfer, after type */
+ struct curl_slist *source_prequote; /* in 3rd party transfer mode - before
+ the transfer on source host */
+ struct curl_slist *source_postquote; /* in 3rd party transfer mode - after
+ the transfer on source host */
struct curl_slist *telnet_options; /* linked list of telnet options */
curl_TimeCond timecondition; /* kind of time/date comparison */
time_t timevalue; /* what time to compare with */
@@ -720,39 +875,55 @@ struct UserDefined {
char *private; /* Private data */
struct curl_slist *http200aliases; /* linked list of aliases for http200 */
-
+
+ long ip_version;
+
+ curl_off_t max_filesize; /* Maximum file size to download */
+
+ char *source_host; /* for 3rd party transfer */
+ char *source_port; /* for 3rd party transfer */
+ char *source_userpwd; /* for 3rd party transfer */
+ char *source_path; /* for 3rd party transfer */
+ curl_pasv_side pasvHost; /* for 3rd party transfer indicates passive host */
+
/* Here follows boolean settings that define how to behave during
this session. They are STATIC, set by libcurl users or at least initially
and they don't change during operations. */
+ bool printhost; /* printing host name in debug info */
bool get_filetime;
bool tunnel_thru_httpproxy;
bool ftp_append;
bool ftp_ascii;
bool ftp_list_only;
+ bool ftp_create_missing_dirs;
bool ftp_use_port;
bool hide_progress;
bool http_fail_on_error;
bool http_follow_location;
- bool include_header;
-#define http_include_header include_header /* former name */
-
+ bool http_disable_hostname_check_before_authentication;
+ bool include_header; /* include received protocol headers in data output */
bool http_set_referer;
bool http_auto_referer; /* set "correct" referer when following location: */
- bool no_body;
+ bool opt_no_body; /* as set with CURLOPT_NO_BODY */
bool set_port;
bool upload;
enum CURL_NETRC_OPTION
use_netrc; /* defined in include/curl.h */
+ char *netrc_file; /* if not NULL, use this instead of trying to find
+ $HOME/.netrc */
bool verbose;
bool krb4; /* kerberos4 connection requested */
bool reuse_forbid; /* forbidden to be reused, close after use */
bool reuse_fresh; /* do not re-use an existing connection */
bool expect100header; /* TRUE if we added Expect: 100-continue */
bool ftp_use_epsv; /* if EPSV is to be attempted or not */
+ bool ftp_use_eprt; /* if EPRT is to be attempted or not */
+ curl_ftpssl ftp_ssl; /* if AUTH TLS is to be attempted etc */
bool no_signal; /* do not use any signal/alarm handler */
+ bool global_dns_cache; /* subject for future removal */
+ bool tcp_nodelay; /* whether to enable TCP_NODELAY or not */
- bool global_dns_cache;
};
/*
@@ -777,7 +948,7 @@ struct SessionHandle {
struct UrlState state; /* struct for fields used for state info and
other dynamic purposes */
struct PureInfo info; /* stats, reports and info data */
-#ifdef USE_SSLEAY
+#if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H)
ENGINE* engine;
#endif /* USE_SSLEAY */
};
diff --git a/Source/CTest/Curl/version.c b/Source/CTest/Curl/version.c
index f442b16..510c20a 100644
--- a/Source/CTest/Curl/version.c
+++ b/Source/CTest/Curl/version.c
@@ -1,16 +1,16 @@
/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
- *
+ *
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
@@ -29,8 +29,19 @@
#include <curl/curl.h>
#include "urldata.h"
+#define _MPRINTF_REPLACE /* use the internal *printf() functions */
+#include <curl/mprintf.h>
+
+#ifdef USE_ARES
+#include <ares_version.h>
+#endif
+
+#ifdef USE_LIBIDN
+#include <stringprep.h>
+#endif
+
#ifdef USE_SSLEAY
-static void getssl_version(char *ptr, long *num)
+static int getssl_version(char *ptr, size_t left, long *num)
{
#if (SSLEAY_VERSION_NUMBER >= 0x905000)
@@ -39,33 +50,33 @@ static void getssl_version(char *ptr, long *num)
unsigned long ssleay_value;
sub[1]='\0';
ssleay_value=SSLeay();
- *num = ssleay_value;
+ *num = (long)ssleay_value;
if(ssleay_value < 0x906000) {
ssleay_value=SSLEAY_VERSION_NUMBER;
sub[0]='\0';
}
else {
if(ssleay_value&0xff0) {
- sub[0]=((ssleay_value>>4)&0xff) + 'a' -1;
+ sub[0]=(char)((ssleay_value>>4)&0xff) + 'a' -1;
}
else
sub[0]='\0';
}
- sprintf(ptr, " OpenSSL/%lx.%lx.%lx%s",
- (ssleay_value>>28)&0xf,
- (ssleay_value>>20)&0xff,
- (ssleay_value>>12)&0xff,
- sub);
+ return snprintf(ptr, left, " OpenSSL/%lx.%lx.%lx%s",
+ (ssleay_value>>28)&0xf,
+ (ssleay_value>>20)&0xff,
+ (ssleay_value>>12)&0xff,
+ sub);
}
#else
*num = SSLEAY_VERSION_NUMBER;
#if (SSLEAY_VERSION_NUMBER >= 0x900000)
- sprintf(ptr, " OpenSSL/%lx.%lx.%lx",
- (SSLEAY_VERSION_NUMBER>>28)&0xff,
- (SSLEAY_VERSION_NUMBER>>20)&0xff,
- (SSLEAY_VERSION_NUMBER>>12)&0xf);
+ return snprintf(ptr, left, " OpenSSL/%lx.%lx.%lx",
+ (SSLEAY_VERSION_NUMBER>>28)&0xff,
+ (SSLEAY_VERSION_NUMBER>>20)&0xff,
+ (SSLEAY_VERSION_NUMBER>>12)&0xf);
#else
{
char sub[2];
@@ -76,10 +87,10 @@ static void getssl_version(char *ptr, long *num)
else
sub[0]='\0';
- sprintf(ptr, " SSL/%x.%x.%x%s",
- (SSLEAY_VERSION_NUMBER>>12)&0xff,
- (SSLEAY_VERSION_NUMBER>>8)&0xf,
- (SSLEAY_VERSION_NUMBER>>4)&0xf, sub);
+ return snprintf(ptr, left, " SSL/%x.%x.%x%s",
+ (SSLEAY_VERSION_NUMBER>>12)&0xff,
+ (SSLEAY_VERSION_NUMBER>>8)&0xf,
+ (SSLEAY_VERSION_NUMBER>>4)&0xf, sub);
}
#endif
#endif
@@ -90,31 +101,46 @@ static void getssl_version(char *ptr, long *num)
char *curl_version(void)
{
static char version[200];
- char *ptr;
- long num=0;
- strcpy(version, LIBCURL_NAME "/" LIBCURL_VERSION );
- ptr=strchr(version, '\0');
+ char *ptr=version;
+ /* to prevent compier warnings, we only declare len if we have code
+ that uses it */
+#if defined(USE_SSLEAY) || defined(HAVE_LIBZ) || defined(USE_ARES) || \
+ defined(USE_LIBIDN)
+ int len;
+#endif
+ size_t left = sizeof(version);
+ strcpy(ptr, LIBCURL_NAME "/" LIBCURL_VERSION );
+ ptr=strchr(ptr, '\0');
+ left -= strlen(ptr);
#ifdef USE_SSLEAY
- getssl_version(ptr, &num);
- ptr=strchr(version, '\0');
-#else
- (void)num; /* no compiler warning please */
+ {
+ long num;
+ len = getssl_version(ptr, left, &num);
+ left -= len;
+ ptr += len;
+ }
#endif
-#ifdef KRB4
- sprintf(ptr, " krb4");
- ptr += strlen(ptr);
+#ifdef HAVE_LIBZ
+ len = snprintf(ptr, left, " zlib/%s", zlibVersion());
+ left -= len;
+ ptr += len;
#endif
-#ifdef ENABLE_IPV6
- sprintf(ptr, " ipv6");
- ptr += strlen(ptr);
+#ifdef USE_ARES
+ /* this function is only present in c-ares, not in the original ares */
+ len = snprintf(ptr, left, " c-ares/%s", ares_version(NULL));
+ left -= len;
+ ptr += len;
#endif
-#ifdef HAVE_LIBZ
- sprintf(ptr, " zlib/%s", zlibVersion());
- ptr += strlen(ptr);
+#ifdef USE_LIBIDN
+ if(stringprep_check_version(LIBIDN_REQUIRED_VERSION)) {
+ len = snprintf(ptr, left, " libidn/%s", stringprep_check_version(NULL));
+ left -= len;
+ ptr += len;
+ }
#endif
- (void)ptr;
+
return version;
}
@@ -155,7 +181,7 @@ static const char *protocols[] = {
};
static curl_version_info_data version_info = {
- CURLVERSION_FIRST,
+ CURLVERSION_NOW,
LIBCURL_VERSION,
LIBCURL_VERSION_NUM,
OS, /* as found by configure or set by hand at build-time */
@@ -163,20 +189,39 @@ static curl_version_info_data version_info = {
#ifdef ENABLE_IPV6
| CURL_VERSION_IPV6
#endif
-#ifdef KRB4
+#ifdef HAVE_KRB4
| CURL_VERSION_KERBEROS4
#endif
#ifdef USE_SSLEAY
| CURL_VERSION_SSL
+ | CURL_VERSION_NTLM /* since this requires OpenSSL */
#endif
#ifdef HAVE_LIBZ
| CURL_VERSION_LIBZ
#endif
+#ifdef HAVE_GSSAPI
+ | CURL_VERSION_GSSNEGOTIATE
+#endif
+#ifdef CURLDEBUG
+ | CURL_VERSION_DEBUG
+#endif
+#ifdef USE_ARES
+ | CURL_VERSION_ASYNCHDNS
+#endif
+#ifdef HAVE_SPNEGO
+ | CURL_VERSION_SPNEGO
+#endif
+#if defined(ENABLE_64BIT) && (SIZEOF_CURL_OFF_T > 4)
+ | CURL_VERSION_LARGEFILE
+#endif
,
NULL, /* ssl_version */
0, /* ssl_version_num */
NULL, /* zlib_version */
- protocols
+ protocols,
+ NULL, /* c-ares version */
+ 0, /* c-ares version numerical */
+ NULL, /* libidn version */
};
curl_version_info_data *curl_version_info(CURLversion stamp)
@@ -184,7 +229,7 @@ curl_version_info_data *curl_version_info(CURLversion stamp)
#ifdef USE_SSLEAY
static char ssl_buffer[80];
long num;
- getssl_version(ssl_buffer, &num);
+ getssl_version(ssl_buffer, sizeof(ssl_buffer), &num);
version_info.ssl_version = ssl_buffer;
version_info.ssl_version_num = num;
@@ -195,15 +240,21 @@ curl_version_info_data *curl_version_info(CURLversion stamp)
version_info.libz_version = zlibVersion();
/* libz left NULL if non-existing */
#endif
+#ifdef USE_ARES
+ {
+ int aresnum;
+ version_info.ares = ares_version(&aresnum);
+ version_info.ares_num = aresnum;
+ }
+#endif
+#ifdef USE_LIBIDN
+ /* This returns a version string if we use the given version or later,
+ otherwise it returns NULL */
+ version_info.libidn = stringprep_check_version(LIBIDN_REQUIRED_VERSION);
+ if(version_info.libidn)
+ version_info.features |= CURL_VERSION_IDN;
+#endif
(void)stamp; /* avoid compiler warnings, we don't use this */
return &version_info;
}
-
-/*
- * local variables:
- * eval: (load-file "../curl-mode.el")
- * end:
- * vim600: fdm=marker
- * vim: et sw=2 ts=2 sts=2 tw=78
- */