aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorAlex Deymo <deymo@google.com>2017-12-19 19:04:07 +0100
committerElliott Hughes <enh@google.com>2017-12-20 14:03:33 -0800
commit486467e11b5904b3e04adc2f5fdb96fcfe65da84 (patch)
tree492c1de56730f0b42bba1f651aa78c8cac13cfa7 /lib
parent7d91b4f63bd1fd29c11c9ff1ba6e7c42622e0687 (diff)
downloadexternal_curl-486467e11b5904b3e04adc2f5fdb96fcfe65da84.tar.gz
external_curl-486467e11b5904b3e04adc2f5fdb96fcfe65da84.tar.bz2
external_curl-486467e11b5904b3e04adc2f5fdb96fcfe65da84.zip
Update from 7.55.1 to 7.57.0
Update the local patch to match the new config. Removed the packages/Android/Android.mk file added by upstream (outdated Android.mk version which will confuse people). Updated Android.bp with the new files. Bug: http://b/70741465 Test: builds, boots, `vendor/google/tools/fake-ota on streaming` works Change-Id: Ib2411f5e64db4e11ffd916dc81cd23b46888b900
Diffstat (limited to 'lib')
-rw-r--r--lib/CMakeLists.txt19
-rw-r--r--lib/Makefile.am16
-rw-r--r--lib/Makefile.inc7
-rw-r--r--lib/Makefile.m3278
-rw-r--r--lib/asyn-ares.c28
-rw-r--r--lib/asyn-thread.c24
-rwxr-xr-xlib/checksrc.pl55
-rw-r--r--lib/config-dos.h6
-rw-r--r--lib/config-os400.h10
-rw-r--r--lib/config-tpf.h3
-rw-r--r--lib/config-win32.h8
-rw-r--r--lib/config-win32ce.h3
-rw-r--r--lib/conncache.c141
-rw-r--r--lib/conncache.h10
-rw-r--r--lib/connect.c156
-rw-r--r--lib/connect.h7
-rw-r--r--lib/content_encoding.c739
-rw-r--r--lib/content_encoding.h45
-rw-r--r--lib/cookie.c144
-rw-r--r--lib/cookie.h11
-rw-r--r--lib/curl_addrinfo.c6
-rw-r--r--lib/curl_config.h30
-rw-r--r--lib/curl_config.h.cmake12
-rw-r--r--lib/curl_config.h.in33
-rw-r--r--lib/curl_fnmatch.c32
-rw-r--r--lib/curl_ntlm_core.c117
-rw-r--r--lib/curl_ntlm_core.h14
-rw-r--r--lib/curl_ntlm_wb.c7
-rw-r--r--lib/curl_sasl.c6
-rw-r--r--lib/curl_setup.h20
-rw-r--r--lib/curl_sha256.h32
-rw-r--r--lib/curlx.h12
-rw-r--r--lib/dict.c14
-rw-r--r--lib/dotdot.c30
-rw-r--r--lib/easy.c103
-rw-r--r--lib/escape.c26
-rw-r--r--lib/file.c43
-rw-r--r--lib/formdata.c887
-rw-r--r--lib/formdata.h54
-rw-r--r--lib/ftp.c218
-rw-r--r--lib/ftp.h1
-rw-r--r--lib/ftplistparser.c213
-rw-r--r--lib/getinfo.c32
-rw-r--r--lib/gopher.c10
-rw-r--r--lib/hash.c4
-rw-r--r--lib/hostasyn.c10
-rw-r--r--lib/hostcheck.c14
-rw-r--r--lib/hostip.c29
-rw-r--r--lib/hostip4.c13
-rw-r--r--lib/hostip6.c14
-rw-r--r--lib/hostsyn.c10
-rw-r--r--lib/http.c494
-rw-r--r--lib/http.h6
-rw-r--r--lib/http2.c20
-rw-r--r--lib/http_chunks.c68
-rw-r--r--lib/http_ntlm.c13
-rw-r--r--lib/http_proxy.c32
-rw-r--r--lib/if2ip.c6
-rw-r--r--lib/imap.c145
-rw-r--r--lib/imap.h3
-rw-r--r--lib/inet_ntop.c2
-rw-r--r--lib/ldap.c8
-rw-r--r--lib/libcurl.plist6
-rw-r--r--lib/llist.c6
-rw-r--r--lib/memdebug.c54
-rw-r--r--lib/memdebug.h15
-rw-r--r--lib/mime.c1908
-rw-r--r--lib/mime.h137
-rwxr-xr-xlib/mk-ca-bundle.pl4
-rw-r--r--lib/mprintf.c38
-rw-r--r--lib/multi.c206
-rw-r--r--lib/multihandle.h4
-rw-r--r--lib/netrc.c39
-rw-r--r--lib/non-ascii.c83
-rw-r--r--lib/non-ascii.h4
-rw-r--r--lib/openldap.c16
-rw-r--r--lib/parsedate.c64
-rw-r--r--lib/pingpong.c51
-rw-r--r--lib/pingpong.h4
-rw-r--r--lib/progress.c84
-rw-r--r--lib/progress.h2
-rw-r--r--lib/rand.c2
-rw-r--r--lib/rtsp.c20
-rw-r--r--lib/security.c4
-rw-r--r--lib/select.c12
-rw-r--r--lib/sendf.c60
-rw-r--r--lib/setopt.c2554
-rw-r--r--lib/setopt.h27
-rw-r--r--lib/sha256.c262
-rw-r--r--lib/share.c6
-rw-r--r--lib/share.h5
-rw-r--r--lib/smb.c2
-rw-r--r--lib/smtp.c48
-rw-r--r--lib/socks.c26
-rw-r--r--lib/socks_gssapi.c59
-rw-r--r--lib/socks_sspi.c24
-rw-r--r--lib/speedcheck.c2
-rw-r--r--lib/splay.c2
-rw-r--r--lib/splay.h4
-rw-r--r--lib/ssh.c62
-rw-r--r--lib/strcase.c11
-rw-r--r--lib/strdup.c6
-rw-r--r--lib/strtoofft.c66
-rw-r--r--lib/strtoofft.h37
-rw-r--r--lib/telnet.c38
-rw-r--r--lib/tftp.c63
-rw-r--r--lib/timeval.c98
-rw-r--r--lib/timeval.h27
-rw-r--r--lib/transfer.c204
-rw-r--r--lib/transfer.h5
-rw-r--r--lib/url.c2802
-rw-r--r--lib/url.h12
-rw-r--r--lib/urldata.h225
-rw-r--r--lib/vauth/digest.c194
-rw-r--r--lib/vauth/digest.h6
-rw-r--r--lib/vauth/digest_sspi.c4
-rw-r--r--lib/vauth/ntlm.c19
-rw-r--r--lib/vauth/ntlm_sspi.c9
-rw-r--r--lib/vauth/vauth.h5
-rw-r--r--lib/version.c56
-rw-r--r--lib/vtls/axtls.c190
-rw-r--r--lib/vtls/axtls.h39
-rw-r--r--lib/vtls/cyassl.c223
-rw-r--r--lib/vtls/cyassl.h63
-rw-r--r--lib/vtls/darwinssl.c542
-rw-r--r--lib/vtls/darwinssl.h71
-rw-r--r--lib/vtls/gskit.c191
-rw-r--r--lib/vtls/gskit.h38
-rw-r--r--lib/vtls/gtls.c210
-rw-r--r--lib/vtls/gtls.h64
-rw-r--r--lib/vtls/mbedtls.c237
-rw-r--r--lib/vtls/mbedtls.h52
-rw-r--r--lib/vtls/nss.c217
-rw-r--r--lib/vtls/nssg.h71
-rw-r--r--lib/vtls/openssl.c597
-rw-r--r--lib/vtls/openssl.h91
-rw-r--r--lib/vtls/polarssl.c198
-rw-r--r--lib/vtls/polarssl.h52
-rw-r--r--lib/vtls/polarssl_threadlock.c4
-rw-r--r--lib/vtls/schannel.c532
-rw-r--r--lib/vtls/schannel.h89
-rw-r--r--lib/vtls/vtls.c513
-rw-r--r--lib/vtls/vtls.h82
-rw-r--r--lib/warnless.c32
144 files changed, 11185 insertions, 7359 deletions
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index d6c99618..1fabdba9 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -108,7 +108,24 @@ if(WIN32)
endif()
endif()
+target_include_directories(${LIB_NAME} INTERFACE
+ $<INSTALL_INTERFACE:include>)
+
install(TARGETS ${LIB_NAME}
+ EXPORT libcurl-target
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
- RUNTIME DESTINATION bin)
+ RUNTIME DESTINATION bin
+)
+
+export(TARGETS ${LIB_NAME}
+ APPEND FILE ${PROJECT_BINARY_DIR}/libcurl-target.cmake
+ NAMESPACE CURL::
+)
+
+install(EXPORT libcurl-target
+ FILE libcurl-target.cmake
+ NAMESPACE CURL::
+ DESTINATION ${CURL_INSTALL_CMAKE_DIR}
+)
+
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 176bf334..151c2615 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -66,21 +66,7 @@ endif
# Prevent LIBS from being used for all link targets
LIBS = $(BLANK_AT_MAKETIME)
-if SONAME_BUMP
-#
-# Bumping of SONAME conditionally may seem like a weird thing to do, and yeah
-# it is. The problem is that we try to avoid the bump as hard as possible, but
-# yet it is still necessary for a few rare situations. The configure script will
-# attempt to figure out these situations, and it can be forced to consider this
-# to be such a case! See README.curl_off_t for further details.
-#
-# This conditional soname bump SHOULD be removed at next "proper" bump.
-#
-VERSIONINFO=-version-info 9:0:4
-else
-VERSIONINFO=-version-info 8:0:4
-endif
-
+VERSIONINFO=-version-info 9:0:5
# This flag accepts an argument of the form current[:revision[:age]]. So,
# passing -version-info 3:12:1 sets current to 3, revision to 12, and age to
# 1.
diff --git a/lib/Makefile.inc b/lib/Makefile.inc
index 19f58000..0a88b8eb 100644
--- a/lib/Makefile.inc
+++ b/lib/Makefile.inc
@@ -5,7 +5,7 @@
# | (__| |_| | _ <| |___
# \___|\___/|_| \_\_____|
#
-# Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+# Copyright (C) 1998 - 2017, 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,7 +53,8 @@ LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \
http_proxy.c non-ascii.c asyn-ares.c asyn-thread.c curl_gssapi.c \
http_ntlm.c curl_ntlm_wb.c curl_ntlm_core.c curl_sasl.c rand.c \
curl_multibyte.c hostcheck.c conncache.c pipeline.c dotdot.c \
- x509asn1.c http2.c smb.c curl_endian.c curl_des.c system_win32.c
+ x509asn1.c http2.c smb.c curl_endian.c curl_des.c system_win32.c \
+ mime.c sha256.c setopt.c
LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \
formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h if2ip.h \
@@ -72,7 +73,7 @@ LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \
curl_sasl.h curl_multibyte.h hostcheck.h conncache.h \
curl_setup_once.h multihandle.h setup-vms.h pipeline.h dotdot.h \
x509asn1.h http2.h sigpipe.h smb.h curl_endian.h curl_des.h \
- curl_printf.h system_win32.h rand.h
+ curl_printf.h system_win32.h rand.h mime.h curl_sha256.h setopt.h
LIB_RCFILES = libcurl.rc
diff --git a/lib/Makefile.m32 b/lib/Makefile.m32
index 8e4c7033..773187ad 100644
--- a/lib/Makefile.m32
+++ b/lib/Makefile.m32
@@ -22,8 +22,9 @@
###########################################################################
#
-## Makefile for building libcurl.a with MingW (GCC-3.2 or later)
-## and optionally OpenSSL (1.0.2a), libssh2 (1.5), zlib (1.2.8), librtmp (2.4)
+## Makefile for building libcurl.a with MingW (GCC-3.2 or later or LLVM/Clang)
+## and optionally OpenSSL (1.0.2a), libssh2 (1.5), zlib (1.2.8), librtmp (2.4),
+## brotli (1.0.1)
##
## Usage: mingw32-make -f Makefile.m32 CFG=-feature1[-feature2][-feature3][...]
## Example: mingw32-make -f Makefile.m32 CFG=-zlib-ssl-sspi-winidn
@@ -38,6 +39,10 @@
ifndef ZLIB_PATH
ZLIB_PATH = ../../zlib-1.2.8
endif
+# Edit the path below to point to the base of your Brotli sources.
+ifndef BROTLI_PATH
+BROTLI_PATH = ../../brotli-1.0.1
+endif
# Edit the path below to point to the base of your OpenSSL package.
ifndef OPENSSL_PATH
OPENSSL_PATH = ../../openssl-1.0.2a
@@ -50,9 +55,9 @@ endif
ifndef LIBRTMP_PATH
LIBRTMP_PATH = ../../librtmp-2.4
endif
-# Edit the path below to point to the base of your libidn package.
-ifndef LIBIDN_PATH
-LIBIDN_PATH = ../../libidn-1.32
+# Edit the path below to point to the base of your libidn2 package.
+ifndef LIBIDN2_PATH
+LIBIDN2_PATH = ../../libidn2-2.0.3
endif
# Edit the path below to point to the base of your MS IDN package.
# Microsoft Internationalized Domain Names (IDN) Mitigation APIs 1.1
@@ -76,13 +81,23 @@ ifndef LIBCARES_PATH
LIBCARES_PATH = $(PROOT)/ares
endif
-CC = $(CROSSPREFIX)gcc
+ifeq ($(CURL_CC),)
+CURL_CC := $(CROSSPREFIX)gcc
+endif
+ifeq ($(CURL_AR),)
+CURL_AR := $(CROSSPREFIX)ar
+endif
+ifeq ($(CURL_RANLIB),)
+CURL_RANLIB := $(CROSSPREFIX)ranlib
+endif
+
+CC = $(CURL_CC)
CFLAGS = $(CURL_CFLAG_EXTRAS) -g -O2 -Wall -W
CFLAGS += -fno-strict-aliasing
# comment LDFLAGS below to keep debug info
LDFLAGS = $(CURL_LDFLAG_EXTRAS) $(CURL_LDFLAG_EXTRAS_DLL) -s
-AR = $(CROSSPREFIX)ar
-RANLIB = $(CROSSPREFIX)ranlib
+AR = $(CURL_AR)
+RANLIB = $(CURL_RANLIB)
RC = $(CROSSPREFIX)windres
RCFLAGS = --include-dir=$(PROOT)/include -DDEBUGBUILD=0 -O COFF
STRIP = $(CROSSPREFIX)strip -g
@@ -153,9 +168,7 @@ ZLIB = 1
endif
ifeq ($(findstring -ssh2,$(CFG)),-ssh2)
SSH2 = 1
-ifneq ($(findstring -winssl,$(CFG)),-winssl)
SSL = 1
-endif
ZLIB = 1
endif
ifeq ($(findstring -ssl,$(CFG)),-ssl)
@@ -167,8 +180,11 @@ endif
ifeq ($(findstring -zlib,$(CFG)),-zlib)
ZLIB = 1
endif
-ifeq ($(findstring -idn,$(CFG)),-idn)
-IDN = 1
+ifeq ($(findstring -brotli,$(CFG)),-brotli)
+BROTLI = 1
+endif
+ifeq ($(findstring -idn2,$(CFG)),-idn2)
+IDN2 = 1
endif
ifeq ($(findstring -winidn,$(CFG)),-winidn)
WINIDN = 1
@@ -192,6 +208,11 @@ endif
INCLUDES = -I. -I../include
CFLAGS += -DBUILDING_LIBCURL
+ifdef SSL
+ ifdef WINSSL
+ CFLAGS += -DCURL_WITH_MULTI_SSL
+ endif
+endif
ifdef SYNC
CFLAGS += -DUSE_SYNC_DNS
@@ -257,20 +278,30 @@ ifdef SSL
CFLAGS += -DHAVE_OPENSSL_SRP -DUSE_TLS_SRP
endif
endif
-else
+endif
ifdef WINSSL
+ CFLAGS += -DUSE_SCHANNEL
DLL_LIBS += -lcrypt32
endif
-endif
ifdef ZLIB
INCLUDES += -I"$(ZLIB_PATH)"
CFLAGS += -DHAVE_LIBZ -DHAVE_ZLIB_H
DLL_LIBS += -L"$(ZLIB_PATH)" -lz
endif
-ifdef IDN
- INCLUDES += -I"$(LIBIDN_PATH)/include"
- CFLAGS += -DUSE_LIBIDN
- DLL_LIBS += -L"$(LIBIDN_PATH)/lib" -lidn
+ifdef BROTLI
+ INCLUDES += -I"$(BROTLI_PATH)/include"
+ CFLAGS += -DHAVE_BROTLI
+ DLL_LIBS += -L"$(BROTLI_PATH)/lib"
+ ifdef BROTLI_LIBS
+ DLL_LIBS += $(BROTLI_LIBS)
+ else
+ DLL_LIBS += -lbrotlidec
+ endif
+endif
+ifdef IDN2
+ INCLUDES += -I"$(LIBIDN2_PATH)/include"
+ CFLAGS += -DUSE_LIBIDN2
+ DLL_LIBS += -L"$(LIBIDN2_PATH)/lib" -lidn2
else
ifdef WINIDN
CFLAGS += -DUSE_WIN32_IDN
@@ -280,9 +311,6 @@ endif
endif
ifdef SSPI
CFLAGS += -DUSE_WINDOWS_SSPI
- ifdef WINSSL
- CFLAGS += -DUSE_SCHANNEL
- endif
endif
ifdef SPNEGO
CFLAGS += -DHAVE_SPNEGO
@@ -313,8 +341,12 @@ DLL_LIBS += -lws2_32
# Makefile.inc provides the CSOURCES and HHEADERS defines
include Makefile.inc
-libcurl_dll_LIBRARY = libcurl.dll
-libcurl_dll_a_LIBRARY = libcurldll.a
+ifeq ($(CURL_DLL_A_SUFFIX),)
+CURL_DLL_A_SUFFIX := dll
+endif
+
+libcurl_dll_LIBRARY = libcurl$(CURL_DLL_SUFFIX).dll
+libcurl_dll_a_LIBRARY = libcurl$(CURL_DLL_A_SUFFIX).a
libcurl_a_LIBRARY = libcurl.a
libcurl_a_OBJECTS := $(patsubst %.c,%.o,$(strip $(CSOURCES)))
diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c
index 9b6515cd..38ede999 100644
--- a/lib/asyn-ares.c
+++ b/lib/asyn-ares.c
@@ -22,6 +22,14 @@
#include "curl_setup.h"
+/***********************************************************************
+ * Only for ares-enabled builds
+ * And only for functions that fulfill the asynch resolver backend API
+ * as defined in asyn.h, nothing else belongs in this file!
+ **********************************************************************/
+
+#ifdef CURLRES_ARES
+
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
@@ -48,14 +56,6 @@
#define in_addr_t unsigned long
#endif
-/***********************************************************************
- * Only for ares-enabled builds
- * And only for functions that fulfill the asynch resolver backend API
- * as defined in asyn.h, nothing else belongs in this file!
- **********************************************************************/
-
-#ifdef CURLRES_ARES
-
#include "urldata.h"
#include "sendf.h"
#include "hostip.h"
@@ -260,7 +260,7 @@ static int waitperform(struct connectdata *conn, int timeout_ms)
bitmask = ares_getsock((ares_channel)data->state.resolver, socks,
ARES_GETSOCK_MAXNUM);
- for(i=0; i < ARES_GETSOCK_MAXNUM; i++) {
+ for(i = 0; i < ARES_GETSOCK_MAXNUM; i++) {
pfd[i].events = 0;
pfd[i].revents = 0;
if(ARES_GETSOCK_READABLE(bitmask, i)) {
@@ -289,7 +289,7 @@ static int waitperform(struct connectdata *conn, int timeout_ms)
ARES_SOCKET_BAD);
else {
/* move through the descriptors and ask for processing on them */
- for(i=0; i < num; i++)
+ for(i = 0; i < num; i++)
ares_process_fd((ares_channel)data->state.resolver,
pfd[i].revents & (POLLRDNORM|POLLIN)?
pfd[i].fd:ARES_SOCKET_BAD,
@@ -354,8 +354,8 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
{
CURLcode result = CURLE_OK;
struct Curl_easy *data = conn->data;
- long timeout;
- struct curltime now = Curl_tvnow();
+ timediff_t timeout;
+ struct curltime now = Curl_now();
struct Curl_dns_entry *temp_entry;
if(entry)
@@ -400,8 +400,8 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
if(Curl_pgrsUpdate(conn))
result = CURLE_ABORTED_BY_CALLBACK;
else {
- struct curltime now2 = Curl_tvnow();
- time_t timediff = Curl_tvdiff(now2, now); /* spent time */
+ struct curltime now2 = Curl_now();
+ timediff_t timediff = Curl_timediff(now2, now); /* spent time */
if(timediff <= 0)
timeout -= 1; /* always deduct at least 1 */
else if(timediff > timeout)
diff --git a/lib/asyn-thread.c b/lib/asyn-thread.c
index 8936b603..1ac3fc80 100644
--- a/lib/asyn-thread.c
+++ b/lib/asyn-thread.c
@@ -210,6 +210,10 @@ int init_thread_sync_data(struct thread_data * td,
tsd->td = td;
tsd->port = port;
+ /* Treat the request as done until the thread actually starts so any early
+ * cleanup gets done properly.
+ */
+ tsd->done = 1;
#ifdef HAVE_GETADDRINFO
DEBUGASSERT(hints);
tsd->hints = *hints;
@@ -380,11 +384,11 @@ static bool init_resolve_thread(struct connectdata *conn,
const struct addrinfo *hints)
{
struct thread_data *td = calloc(1, sizeof(struct thread_data));
- int err = RESOLVER_ENOMEM;
+ int err = ENOMEM;
conn->async.os_specific = (void *)td;
if(!td)
- goto err_exit;
+ goto errno_exit;
conn->async.port = port;
conn->async.done = FALSE;
@@ -392,14 +396,20 @@ static bool init_resolve_thread(struct connectdata *conn,
conn->async.dns = NULL;
td->thread_hnd = curl_thread_t_null;
- if(!init_thread_sync_data(td, hostname, port, hints))
- goto err_exit;
+ if(!init_thread_sync_data(td, hostname, port, hints)) {
+ conn->async.os_specific = NULL;
+ free(td);
+ goto errno_exit;
+ }
free(conn->async.hostname);
conn->async.hostname = strdup(hostname);
if(!conn->async.hostname)
goto err_exit;
+ /* The thread will set this to 1 when complete. */
+ td->tsd.done = 0;
+
#ifdef HAVE_GETADDRINFO
td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd);
#else
@@ -407,6 +417,8 @@ static bool init_resolve_thread(struct connectdata *conn,
#endif
if(!td->thread_hnd) {
+ /* The thread never started, so mark it as done here for proper cleanup. */
+ td->tsd.done = 1;
err = errno;
goto err_exit;
}
@@ -416,6 +428,7 @@ static bool init_resolve_thread(struct connectdata *conn,
err_exit:
destroy_async_data(&conn->async);
+ errno_exit:
errno = err;
return FALSE;
}
@@ -522,7 +535,8 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
}
else {
/* poll for name lookup done with exponential backoff up to 250ms */
- time_t elapsed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle);
+ timediff_t elapsed = Curl_timediff(Curl_now(),
+ data->progress.t_startsingle);
if(elapsed < 0)
elapsed = 0;
diff --git a/lib/checksrc.pl b/lib/checksrc.pl
index 2eff3e0c..c1f74beb 100755
--- a/lib/checksrc.pl
+++ b/lib/checksrc.pl
@@ -58,7 +58,11 @@ my %warnings = (
'OPENCOMMENT' => 'file ended with a /* comment still "open"',
'ASTERISKSPACE' => 'pointer declared with space after asterisk',
'ASTERISKNOSPACE' => 'pointer declared without space before asterisk',
- 'ASSIGNWITHINCONDITION' => 'assignment within conditional expression'
+ 'ASSIGNWITHINCONDITION' => 'assignment within conditional expression',
+ 'EQUALSNOSPACE' => 'equals sign without following space',
+ 'NOSPACEEQUALS' => 'equals sign without preceeding space',
+ 'SEMINOSPACE' => 'semicolon without following space',
+ 'MULTISPACE' => 'multiple spaces used when not suitable',
);
sub readwhitelist {
@@ -345,6 +349,9 @@ sub scanfile {
elsif($3 eq "return") {
# return must have a space
}
+ elsif($3 eq "case") {
+ # case must have a space
+ }
elsif($4 eq "*") {
# (* beginning makes the space OK!
}
@@ -523,6 +530,52 @@ sub scanfile {
"wrongly placed open brace");
}
}
+
+ # check for equals sign without spaces next to it
+ if($nostr =~ /(.*)\=[a-z0-9]/i) {
+ checkwarn("EQUALSNOSPACE",
+ $line, length($1)+1, $file, $ol,
+ "no space after equals sign");
+ }
+ # check for equals sign without spaces before it
+ elsif($nostr =~ /(.*)[a-z0-9]\=/i) {
+ checkwarn("NOSPACEEQUALS",
+ $line, length($1)+1, $file, $ol,
+ "no space before equals sign");
+ }
+
+ # check for plus signs without spaces next to it
+ if($nostr =~ /(.*)[^+]\+[a-z0-9]/i) {
+ checkwarn("PLUSNOSPACE",
+ $line, length($1)+1, $file, $ol,
+ "no space after plus sign");
+ }
+ # check for plus sign without spaces before it
+ elsif($nostr =~ /(.*)[a-z0-9]\+[^+]/i) {
+ checkwarn("NOSPACEPLUS",
+ $line, length($1)+1, $file, $ol,
+ "no space before plus sign");
+ }
+
+ # check for semicolons without space next to it
+ if($nostr =~ /(.*)\;[a-z0-9]/i) {
+ checkwarn("SEMINOSPACE",
+ $line, length($1)+1, $file, $ol,
+ "no space after semilcolon");
+ }
+
+ # check for more than one consecutive space before open brace or
+ # question mark. Skip lines containing strings since they make it hard
+ # due to artificially getting multiple spaces
+ if(($l eq $nostr) &&
+ $nostr =~ /^(.*(\S)) + [{?]/i) {
+ checkwarn("MULTISPACE",
+ $line, length($1)+1, $file, $ol,
+ "multiple space");
+ print STDERR "L: $l\n";
+ print STDERR "nostr: $nostr\n";
+ }
+
$line++;
$prevl = $ol;
}
diff --git a/lib/config-dos.h b/lib/config-dos.h
index f2c9ff40..eec7af98 100644
--- a/lib/config-dos.h
+++ b/lib/config-dos.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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,8 +40,10 @@
#define PACKAGE "curl"
#define HAVE_ARPA_INET_H 1
+#define HAVE_ASSERT_H 1
#define HAVE_ERRNO_H 1
#define HAVE_FCNTL_H 1
+#define HAVE_FREEADDRINFO 1
#define HAVE_GETADDRINFO 1
#define HAVE_GETNAMEINFO 1
#define HAVE_GETPROTOBYNAME 1
@@ -85,9 +87,11 @@
#define RETSIGTYPE void
#define SIZEOF_INT 4
+#define SIZEOF_LONG 4
#define SIZEOF_LONG_DOUBLE 16
#define SIZEOF_SHORT 2
#define SIZEOF_SIZE_T 4
+#define SIZEOF_CURL_OFF_T 4
#define STDC_HEADERS 1
#define TIME_WITH_SYS_TIME 1
diff --git a/lib/config-os400.h b/lib/config-os400.h
index fe5b864d..7844444f 100644
--- a/lib/config-os400.h
+++ b/lib/config-os400.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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
@@ -403,8 +403,14 @@
/* The size of `short', as computed by sizeof. */
#define SIZEOF_SHORT 2
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 4
+
/* The size of `size_t', as computed by sizeof. */
-#define SIZEOF_SIZE_T 8
+#define SIZEOF_SIZE_T 4
+
+/* The size of `curl_off_t', as computed by sizeof. */
+#define SIZEOF_CURL_OFF_T 8
/* Whether long long constants must be suffixed by LL. */
diff --git a/lib/config-tpf.h b/lib/config-tpf.h
index d1714fdf..d1eb3d90 100644
--- a/lib/config-tpf.h
+++ b/lib/config-tpf.h
@@ -618,6 +618,9 @@
/* The size of `short', as computed by sizeof. */
#define SIZEOF_SHORT 2
+/* Define to the size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 8
+
/* The size of `size_t', as computed by sizeof. */
#define SIZEOF_SIZE_T 8
diff --git a/lib/config-win32.h b/lib/config-win32.h
index 4cac859c..309f701a 100644
--- a/lib/config-win32.h
+++ b/lib/config-win32.h
@@ -399,6 +399,9 @@
/* Define to the size of `short', as computed by sizeof. */
#define SIZEOF_SHORT 2
+/* Define to the size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 4
+
/* Define to the size of `size_t', as computed by sizeof. */
#if defined(_WIN64)
# define SIZEOF_SIZE_T 8
@@ -406,6 +409,9 @@
# define SIZEOF_SIZE_T 4
#endif
+/* Define to the size of `curl_off_t', as computed by sizeof. */
+#define SIZEOF_CURL_OFF_T 8
+
/* ---------------------------------------------------------------- */
/* BSD-style lwIP TCP/IP stack SPECIFIC */
/* ---------------------------------------------------------------- */
@@ -703,9 +709,7 @@ Vista
#endif
/* Define to use the Windows crypto library. */
-#if !defined(USE_OPENSSL) && !defined(USE_NSS)
#define USE_WIN32_CRYPTO
-#endif
/* ---------------------------------------------------------------- */
/* ADDITIONAL DEFINITIONS */
diff --git a/lib/config-win32ce.h b/lib/config-win32ce.h
index eb444c58..28a15f2a 100644
--- a/lib/config-win32ce.h
+++ b/lib/config-win32ce.h
@@ -346,6 +346,9 @@
/* The size of `short', as computed by sizeof. */
#define SIZEOF_SHORT 2
+/* Define to the size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 4
+
/* The size of `size_t', as computed by sizeof. */
#if defined(_WIN64)
# define SIZEOF_SIZE_T 8
diff --git a/lib/conncache.c b/lib/conncache.c
index c79d2276..f8ef2e88 100644
--- a/lib/conncache.c
+++ b/lib/conncache.c
@@ -31,11 +31,21 @@
#include "multiif.h"
#include "sendf.h"
#include "conncache.h"
+#include "share.h"
+#include "sigpipe.h"
+#include "connect.h"
+
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"
+#define CONN_LOCK(x) if((x)->share) \
+ Curl_share_lock((x), CURL_LOCK_DATA_CONNECT, CURL_LOCK_ACCESS_SINGLE)
+#define CONN_UNLOCK(x) if((x)->share) \
+ Curl_share_unlock((x), CURL_LOCK_DATA_CONNECT)
+
+
static void conn_llist_dtor(void *user, void *element)
{
struct connectdata *data = element;
@@ -109,8 +119,23 @@ static void free_bundle_hash_entry(void *freethis)
int Curl_conncache_init(struct conncache *connc, int size)
{
- return Curl_hash_init(&connc->hash, size, Curl_hash_str,
- Curl_str_key_compare, free_bundle_hash_entry);
+ int rc;
+
+ /* allocate a new easy handle to use when closing cached connections */
+ connc->closure_handle = curl_easy_init();
+ if(!connc->closure_handle)
+ return 1; /* bad */
+
+ rc = Curl_hash_init(&connc->hash, size, Curl_hash_str,
+ Curl_str_key_compare, free_bundle_hash_entry);
+ if(rc) {
+ Curl_close(connc->closure_handle);
+ connc->closure_handle = NULL;
+ }
+ else
+ connc->closure_handle->state.conn_cache = connc;
+
+ return rc;
}
void Curl_conncache_destroy(struct conncache *connc)
@@ -149,7 +174,9 @@ struct connectbundle *Curl_conncache_find_bundle(struct connectdata *conn,
if(connc) {
char key[128];
hashkey(conn, key, sizeof(key));
+ CONN_LOCK(conn->data);
bundle = Curl_hash_pick(&connc->hash, key, strlen(key));
+ CONN_UNLOCK(conn->data);
}
return bundle;
@@ -206,7 +233,9 @@ CURLcode Curl_conncache_add_conn(struct conncache *connc,
return result;
hashkey(conn, key, sizeof(key));
+ CONN_LOCK(data);
rc = conncache_add_bundle(data->state.conn_cache, key, new_bundle);
+ CONN_UNLOCK(data);
if(!rc) {
bundle_destroy(new_bundle);
@@ -215,12 +244,15 @@ CURLcode Curl_conncache_add_conn(struct conncache *connc,
bundle = new_bundle;
}
+ CONN_LOCK(data);
result = bundle_add_conn(bundle, conn);
if(result) {
if(new_bundle)
conncache_remove_bundle(data->state.conn_cache, new_bundle);
+ CONN_UNLOCK(data);
return result;
}
+ CONN_UNLOCK(data);
conn->connection_id = connc->next_connection_id++;
connc->num_connections++;
@@ -240,11 +272,11 @@ void Curl_conncache_remove_conn(struct conncache *connc,
/* The bundle pointer can be NULL, since this function can be called
due to a failed connection attempt, before being added to a bundle */
if(bundle) {
+ CONN_LOCK(conn->data);
bundle_remove_conn(bundle, conn);
- if(bundle->num_connections == 0) {
+ if(bundle->num_connections == 0)
conncache_remove_bundle(connc, bundle);
- }
-
+ CONN_UNLOCK(conn->data);
if(connc) {
connc->num_connections--;
@@ -261,7 +293,8 @@ void Curl_conncache_remove_conn(struct conncache *connc,
Return 0 from func() to continue the loop, return 1 to abort it.
*/
-void Curl_conncache_foreach(struct conncache *connc,
+void Curl_conncache_foreach(struct Curl_easy *data,
+ struct conncache *connc,
void *param,
int (*func)(struct connectdata *conn, void *param))
{
@@ -272,6 +305,7 @@ void Curl_conncache_foreach(struct conncache *connc,
if(!connc)
return;
+ CONN_LOCK(data);
Curl_hash_start_iterate(&connc->hash, &iter);
he = Curl_hash_next_element(&iter);
@@ -288,14 +322,21 @@ void Curl_conncache_foreach(struct conncache *connc,
struct connectdata *conn = curr->ptr;
curr = curr->next;
- if(1 == func(conn, param))
+ if(1 == func(conn, param)) {
+ CONN_UNLOCK(data);
return;
+ }
}
}
+ CONN_UNLOCK(data);
}
/* Return the first connection found in the cache. Used when closing all
- connections */
+ connections.
+
+ NOTE: no locking is done here as this is presumably only done when cleaning
+ up a cache!
+*/
struct connectdata *
Curl_conncache_find_first_connection(struct conncache *connc)
{
@@ -321,6 +362,90 @@ Curl_conncache_find_first_connection(struct conncache *connc)
return NULL;
}
+/*
+ * This function finds the connection in the connection
+ * cache that has been unused for the longest time.
+ *
+ * Returns the pointer to the oldest idle connection, or NULL if none was
+ * found.
+ */
+struct connectdata *
+Curl_conncache_oldest_idle(struct Curl_easy *data)
+{
+ struct conncache *bc = data->state.conn_cache;
+ struct curl_hash_iterator iter;
+ struct curl_llist_element *curr;
+ struct curl_hash_element *he;
+ timediff_t highscore =- 1;
+ timediff_t score;
+ struct curltime now;
+ struct connectdata *conn_candidate = NULL;
+ struct connectbundle *bundle;
+
+ now = Curl_now();
+
+ CONN_LOCK(data);
+ Curl_hash_start_iterate(&bc->hash, &iter);
+
+ he = Curl_hash_next_element(&iter);
+ while(he) {
+ struct connectdata *conn;
+
+ bundle = he->ptr;
+
+ curr = bundle->conn_list.head;
+ while(curr) {
+ conn = curr->ptr;
+
+ if(!conn->inuse) {
+ /* Set higher score for the age passed since the connection was used */
+ score = Curl_timediff(now, conn->now);
+
+ if(score > highscore) {
+ highscore = score;
+ conn_candidate = conn;
+ }
+ }
+ curr = curr->next;
+ }
+
+ he = Curl_hash_next_element(&iter);
+ }
+ CONN_UNLOCK(data);
+
+ return conn_candidate;
+}
+
+void Curl_conncache_close_all_connections(struct conncache *connc)
+{
+ struct connectdata *conn;
+
+ conn = Curl_conncache_find_first_connection(connc);
+ while(conn) {
+ SIGPIPE_VARIABLE(pipe_st);
+ conn->data = connc->closure_handle;
+
+ sigpipe_ignore(conn->data, &pipe_st);
+ conn->data->easy_conn = NULL; /* clear the easy handle's connection
+ pointer */
+ /* This will remove the connection from the cache */
+ connclose(conn, "kill all");
+ (void)Curl_disconnect(conn, FALSE);
+ sigpipe_restore(&pipe_st);
+
+ conn = Curl_conncache_find_first_connection(connc);
+ }
+
+ if(connc->closure_handle) {
+ SIGPIPE_VARIABLE(pipe_st);
+ sigpipe_ignore(connc->closure_handle, &pipe_st);
+
+ Curl_hostcache_clean(connc->closure_handle,
+ connc->closure_handle->dns.hostcache);
+ Curl_close(connc->closure_handle);
+ sigpipe_restore(&pipe_st);
+ }
+}
#if 0
/* Useful for debugging the connection cache */
diff --git a/lib/conncache.h b/lib/conncache.h
index 14be4e8e..0d97a6ce 100644
--- a/lib/conncache.h
+++ b/lib/conncache.h
@@ -28,6 +28,8 @@ struct conncache {
size_t num_connections;
long next_connection_id;
struct curltime last_cleanup;
+ /* handle used for closing cached connections */
+ struct Curl_easy *closure_handle;
};
#define BUNDLE_NO_MULTIUSE -1
@@ -41,8 +43,8 @@ struct connectbundle {
struct curl_llist conn_list; /* The connectdata members of the bundle */
};
+/* returns 1 on error, 0 is fine */
int Curl_conncache_init(struct conncache *, int size);
-
void Curl_conncache_destroy(struct conncache *connc);
/* return the correct bundle, to a host or a proxy */
@@ -55,7 +57,8 @@ CURLcode Curl_conncache_add_conn(struct conncache *connc,
void Curl_conncache_remove_conn(struct conncache *connc,
struct connectdata *conn);
-void Curl_conncache_foreach(struct conncache *connc,
+void Curl_conncache_foreach(struct Curl_easy *data,
+ struct conncache *connc,
void *param,
int (*func)(struct connectdata *conn,
void *param));
@@ -63,6 +66,9 @@ void Curl_conncache_foreach(struct conncache *connc,
struct connectdata *
Curl_conncache_find_first_connection(struct conncache *connc);
+struct connectdata *
+Curl_conncache_oldest_idle(struct Curl_easy *data);
+void Curl_conncache_close_all_connections(struct conncache *connc);
void Curl_conncache_print(struct conncache *connc);
#endif /* HEADER_CURL_CONNCACHE_H */
diff --git a/lib/connect.c b/lib/connect.c
index 8d5d32ba..3edb71eb 100644
--- a/lib/connect.c
+++ b/lib/connect.c
@@ -28,8 +28,10 @@
#ifdef HAVE_SYS_UN_H
#include <sys/un.h> /* for sockaddr_un */
#endif
-#ifdef HAVE_NETINET_TCP_H
-#include <netinet/tcp.h> /* for TCP_NODELAY */
+#ifdef HAVE_LINUX_TCP_H
+#include <linux/tcp.h>
+#elif defined(HAVE_NETINET_TCP_H)
+#include <netinet/tcp.h>
#endif
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
@@ -179,12 +181,12 @@ singleipconnect(struct connectdata *conn,
*
* @unittest: 1303
*/
-time_t Curl_timeleft(struct Curl_easy *data,
- struct curltime *nowp,
- bool duringconnect)
+timediff_t Curl_timeleft(struct Curl_easy *data,
+ struct curltime *nowp,
+ bool duringconnect)
{
int timeout_set = 0;
- time_t timeout_ms = duringconnect?DEFAULT_CONNECT_TIMEOUT:0;
+ timediff_t timeout_ms = duringconnect?DEFAULT_CONNECT_TIMEOUT:0;
struct curltime now;
/* if a timeout is set, use the most restrictive one */
@@ -218,17 +220,17 @@ time_t Curl_timeleft(struct Curl_easy *data,
}
if(!nowp) {
- now = Curl_tvnow();
+ now = Curl_now();
nowp = &now;
}
/* subtract elapsed time */
if(duringconnect)
/* since this most recent connect started */
- timeout_ms -= Curl_tvdiff(*nowp, data->progress.t_startsingle);
+ timeout_ms -= Curl_timediff(*nowp, data->progress.t_startsingle);
else
/* since the entire operation started */
- timeout_ms -= Curl_tvdiff(*nowp, data->progress.t_startop);
+ timeout_ms -= Curl_timediff(*nowp, data->progress.t_startop);
if(!timeout_ms)
/* avoid returning 0 as that means no timeout! */
return -1;
@@ -249,7 +251,7 @@ static CURLcode bindlocal(struct connectdata *conn,
struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
#endif
- struct Curl_dns_entry *h=NULL;
+ struct Curl_dns_entry *h = NULL;
unsigned short port = data->set.localport; /* use this port number, 0 for
"random" */
/* how many port numbers to try to bind to, increasing one at a time */
@@ -285,6 +287,34 @@ static CURLcode bindlocal(struct connectdata *conn,
/* interface */
if(!is_host) {
+#ifdef SO_BINDTODEVICE
+ /* I am not sure any other OSs than Linux that provide this feature,
+ * and at the least I cannot test. --Ben
+ *
+ * This feature allows one to tightly bind the local socket to a
+ * particular interface. This will force even requests to other
+ * local interfaces to go out the external interface.
+ *
+ *
+ * Only bind to the interface when specified as interface, not just
+ * as a hostname or ip address.
+ *
+ * interface might be a VRF, eg: vrf-blue, which means it cannot be
+ * converted to an IP address and would fail Curl_if2ip. Simply try
+ * to use it straight away.
+ */
+ if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
+ dev, (curl_socklen_t)strlen(dev) + 1) == 0) {
+ /* This is typically "errno 1, error: Operation not permitted" if
+ * you're not running as root or another suitable privileged
+ * user.
+ * If it succeeds it means the parameter was a valid interface and
+ * not an IP address. Return immediately.
+ */
+ return CURLE_OK;
+ }
+#endif
+
switch(Curl_if2ip(af, scope, conn->scope_id, dev,
myhost, sizeof(myhost))) {
case IF2IP_NOT_FOUND:
@@ -305,30 +335,6 @@ static CURLcode bindlocal(struct connectdata *conn,
infof(data, "Local Interface %s is ip %s using address family %i\n",
dev, myhost, af);
done = 1;
-
-#ifdef SO_BINDTODEVICE
- /* I am not sure any other OSs than Linux that provide this feature,
- * and at the least I cannot test. --Ben
- *
- * This feature allows one to tightly bind the local socket to a
- * particular interface. This will force even requests to other
- * local interfaces to go out the external interface.
- *
- *
- * Only bind to the interface when specified as interface, not just
- * as a hostname or ip address.
- */
- if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
- dev, (curl_socklen_t)strlen(dev)+1) != 0) {
- error = SOCKERRNO;
- infof(data, "SO_BINDTODEVICE %s failed with errno %d: %s;"
- " will do regular bind\n",
- dev, error, Curl_strerror(conn, error));
- /* This is typically "errno 1, error: Operation not permitted" if
- you're not running as root or another suitable privileged
- user */
- }
-#endif
break;
}
}
@@ -408,6 +414,10 @@ static CURLcode bindlocal(struct connectdata *conn,
}
if(done < 1) {
+ /* errorbuf is set false so failf will overwrite any message already in
+ the error buffer, so the user receives this error message instead of a
+ generic resolve error. */
+ data->state.errorbuf = FALSE;
failf(data, "Couldn't bind to '%s'", dev);
return CURLE_INTERFACE_FAILED;
}
@@ -721,7 +731,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
{
struct Curl_easy *data = conn->data;
CURLcode result = CURLE_OK;
- time_t allow;
+ timediff_t allow;
int error = 0;
struct curltime now;
int rc;
@@ -737,7 +747,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
return CURLE_OK;
}
- now = Curl_tvnow();
+ now = Curl_now();
/* figure out how long time we have left to connect */
allow = Curl_timeleft(data, &now, TRUE);
@@ -748,7 +758,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
return CURLE_OPERATION_TIMEDOUT;
}
- for(i=0; i<2; i++) {
+ for(i = 0; i<2; i++) {
const int other = i ^ 1;
if(conn->tempsock[i] == CURL_SOCKET_BAD)
continue;
@@ -765,7 +775,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
if(rc == 0) { /* no connection yet */
error = 0;
- if(curlx_tvdiff(now, conn->connecttime) >= conn->timeoutms_per_addr) {
+ if(Curl_timediff(now, conn->connecttime) >= conn->timeoutms_per_addr) {
infof(data, "After %ldms connect time, move on!\n",
conn->timeoutms_per_addr);
error = ETIMEDOUT;
@@ -773,7 +783,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
/* should we try another protocol family? */
if(i == 0 && conn->tempaddr[1] == NULL &&
- curlx_tvdiff(now, conn->connecttime) >= HAPPY_EYEBALLS_TIMEOUT) {
+ Curl_timediff(now, conn->connecttime) >= HAPPY_EYEBALLS_TIMEOUT) {
trynextip(conn, sockindex, 1);
}
}
@@ -785,6 +795,9 @@ CURLcode Curl_is_connected(struct connectdata *conn,
conn->sock[sockindex] = conn->tempsock[i];
conn->ip_addr = conn->tempaddr[i];
conn->tempsock[i] = CURL_SOCKET_BAD;
+#ifdef ENABLE_IPV6
+ conn->bits.ipv6 = (conn->ip_addr->ai_family == AF_INET6)?TRUE:FALSE;
+#endif
/* close the other socket, if open */
if(conn->tempsock[other] != CURL_SOCKET_BAD) {
@@ -900,7 +913,7 @@ void Curl_tcpnodelay(struct connectdata *conn, curl_socket_t sockfd)
static void nosigpipe(struct connectdata *conn,
curl_socket_t sockfd)
{
- struct Curl_easy *data= conn->data;
+ struct Curl_easy *data = conn->data;
int onoff = 1;
if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
sizeof(onoff)) < 0)
@@ -978,6 +991,9 @@ static CURLcode singleipconnect(struct connectdata *conn,
char ipaddress[MAX_IPADR_LEN];
long port;
bool is_tcp;
+#ifdef TCP_FASTOPEN_CONNECT
+ int optval = 1;
+#endif
*sockp = CURL_SOCKET_BAD;
@@ -1051,25 +1067,45 @@ static CURLcode singleipconnect(struct connectdata *conn,
/* set socket non-blocking */
(void)curlx_nonblock(sockfd, TRUE);
- conn->connecttime = Curl_tvnow();
+ conn->connecttime = Curl_now();
if(conn->num_addr > 1)
Curl_expire(data, conn->timeoutms_per_addr, EXPIRE_DNS_PER_NAME);
/* Connect TCP sockets, bind UDP */
if(!isconnected && (conn->socktype == SOCK_STREAM)) {
if(conn->bits.tcp_fastopen) {
-#if defined(CONNECT_DATA_IDEMPOTENT) /* OS X */
- sa_endpoints_t endpoints;
- endpoints.sae_srcif = 0;
- endpoints.sae_srcaddr = NULL;
- endpoints.sae_srcaddrlen = 0;
- endpoints.sae_dstaddr = &addr.sa_addr;
- endpoints.sae_dstaddrlen = addr.addrlen;
-
- rc = connectx(sockfd, &endpoints, SAE_ASSOCID_ANY,
- CONNECT_RESUME_ON_READ_WRITE | CONNECT_DATA_IDEMPOTENT,
- NULL, 0, NULL, NULL);
-#elif defined(MSG_FASTOPEN) /* Linux */
+#if defined(CONNECT_DATA_IDEMPOTENT) /* Darwin */
+# if defined(HAVE_BUILTIN_AVAILABLE)
+ /* while connectx function is available since macOS 10.11 / iOS 9,
+ it did not have the interface declared correctly until
+ Xcode 9 / macOS SDK 10.13 */
+ if(__builtin_available(macOS 10.11, iOS 9.0, tvOS 9.0, watchOS 2.0, *)) {
+ sa_endpoints_t endpoints;
+ endpoints.sae_srcif = 0;
+ endpoints.sae_srcaddr = NULL;
+ endpoints.sae_srcaddrlen = 0;
+ endpoints.sae_dstaddr = &addr.sa_addr;
+ endpoints.sae_dstaddrlen = addr.addrlen;
+
+ rc = connectx(sockfd, &endpoints, SAE_ASSOCID_ANY,
+ CONNECT_RESUME_ON_READ_WRITE | CONNECT_DATA_IDEMPOTENT,
+ NULL, 0, NULL, NULL);
+ }
+ else {
+ rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
+ }
+# else
+ rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
+# endif /* HAVE_BUILTIN_AVAILABLE */
+#elif defined(TCP_FASTOPEN_CONNECT) /* Linux >= 4.11 */
+ if(setsockopt(sockfd, IPPROTO_TCP, TCP_FASTOPEN_CONNECT,
+ (void *)&optval, sizeof(optval)) < 0)
+ infof(data, "Failed to enable TCP Fast Open on fd %d\n", sockfd);
+ else
+ infof(data, "TCP_FASTOPEN_CONNECT set\n");
+
+ rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
+#elif defined(MSG_FASTOPEN) /* old Linux */
if(conn->given->flags & PROTOPT_SSL)
rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
else
@@ -1088,10 +1124,6 @@ static CURLcode singleipconnect(struct connectdata *conn,
return CURLE_OK;
}
-#ifdef ENABLE_IPV6
- conn->bits.ipv6 = (addr.family == AF_INET6)?TRUE:FALSE;
-#endif
-
if(-1 == rc) {
switch(error) {
case EINPROGRESS:
@@ -1136,10 +1168,10 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
const struct Curl_dns_entry *remotehost)
{
struct Curl_easy *data = conn->data;
- struct curltime before = Curl_tvnow();
+ struct curltime before = Curl_now();
CURLcode result = CURLE_COULDNT_CONNECT;
- time_t timeout_ms = Curl_timeleft(data, &before, TRUE);
+ timediff_t timeout_ms = Curl_timeleft(data, &before, TRUE);
if(timeout_ms < 0) {
/* a precaution, no need to continue if time already is up */
@@ -1152,7 +1184,6 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
conn->tempaddr[1] = NULL;
conn->tempsock[0] = CURL_SOCKET_BAD;
conn->tempsock[1] = CURL_SOCKET_BAD;
- Curl_expire(conn->data, HAPPY_EYEBALLS_TIMEOUT, EXPIRE_HAPPY_EYEBALLS);
/* Max time for the next connection attempt */
conn->timeoutms_per_addr =
@@ -1173,6 +1204,7 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
}
data->info.numconnects++; /* to track the number of connections made */
+ Curl_expire(conn->data, HAPPY_EYEBALLS_TIMEOUT, EXPIRE_HAPPY_EYEBALLS);
return CURLE_OK;
}
@@ -1216,7 +1248,7 @@ curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
find.tofind = data->state.lastconnect;
find.found = FALSE;
- Curl_conncache_foreach(data->multi_easy?
+ Curl_conncache_foreach(data, data->multi_easy?
&data->multi_easy->conn_cache:
&data->multi->conn_cache, &find, conn_is_conn);
@@ -1324,7 +1356,7 @@ CURLcode Curl_socket(struct connectdata *conn,
addr->family = ai->ai_family;
addr->socktype = conn->socktype;
- addr->protocol = conn->socktype==SOCK_DGRAM?IPPROTO_UDP:ai->ai_protocol;
+ addr->protocol = conn->socktype == SOCK_DGRAM?IPPROTO_UDP:ai->ai_protocol;
addr->addrlen = ai->ai_addrlen;
if(addr->addrlen > sizeof(struct Curl_sockaddr_storage))
diff --git a/lib/connect.h b/lib/connect.h
index 3f05c397..39744863 100644
--- a/lib/connect.h
+++ b/lib/connect.h
@@ -25,6 +25,7 @@
#include "nonblock.h" /* for curlx_nonblock(), formerly Curl_nonblock() */
#include "sockaddr.h"
+#include "timeval.h"
CURLcode Curl_is_connected(struct connectdata *conn,
int sockindex,
@@ -35,9 +36,9 @@ CURLcode Curl_connecthost(struct connectdata *conn,
/* generic function that returns how much time there's left to run, according
to the timeouts set */
-time_t Curl_timeleft(struct Curl_easy *data,
- struct curltime *nowp,
- bool duringconnect);
+timediff_t Curl_timeleft(struct Curl_easy *data,
+ struct curltime *nowp,
+ bool duringconnect);
#define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */
#define HAPPY_EYEBALLS_TIMEOUT 200 /* milliseconds to wait between
diff --git a/lib/content_encoding.c b/lib/content_encoding.c
index 652ed976..3d061375 100644
--- a/lib/content_encoding.c
+++ b/lib/content_encoding.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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,22 +22,43 @@
#include "curl_setup.h"
-#ifdef HAVE_LIBZ
-
#include "urldata.h"
#include <curl/curl.h>
+#include <stddef.h>
+
+#ifdef HAVE_ZLIB_H
+#include <zlib.h>
+#ifdef __SYMBIAN32__
+/* zlib pollutes the namespace with this definition */
+#undef WIN32
+#endif
+#endif
+
+#ifdef HAVE_BROTLI
+#include <brotli/decode.h>
+#endif
+
#include "sendf.h"
+#include "http.h"
#include "content_encoding.h"
#include "strdup.h"
+#include "strcase.h"
#include "curl_memory.h"
#include "memdebug.h"
+#define CONTENT_ENCODING_DEFAULT "identity"
+
+#ifndef CURL_DISABLE_HTTP
+
+#define DSIZ CURL_MAX_WRITE_SIZE /* buffer size for decompressed data */
+
+
+#ifdef HAVE_LIBZ
+
/* Comment this out if zlib is always going to be at least ver. 1.2.0.4
(doing so will reduce code size slightly). */
#define OLD_ZLIB_SUPPORT 1
-#define DSIZ CURL_MAX_WRITE_SIZE /* buffer size for decompressed data */
-
#define GZIP_MAGIC_0 0x1f
#define GZIP_MAGIC_1 0x8b
@@ -49,6 +70,21 @@
#define COMMENT 0x10 /* bit 4 set: file comment present */
#define RESERVED 0xE0 /* bits 5..7: reserved */
+typedef enum {
+ ZLIB_UNINIT, /* uninitialized */
+ ZLIB_INIT, /* initialized */
+ ZLIB_GZIP_HEADER, /* reading gzip header */
+ ZLIB_GZIP_INFLATING, /* inflating gzip stream */
+ ZLIB_INIT_GZIP /* initialized in transparent gzip mode */
+} zlibInitState;
+
+/* Writer parameters. */
+typedef struct {
+ zlibInitState zlib_init; /* zlib init state */
+ z_stream z; /* State structure for zlib. */
+} zlib_params;
+
+
static voidpf
zalloc_cb(voidpf opaque, unsigned int items, unsigned int size)
{
@@ -79,19 +115,27 @@ process_zlib_error(struct connectdata *conn, z_stream *z)
}
static CURLcode
-exit_zlib(z_stream *z, zlibInitState *zlib_init, CURLcode result)
+exit_zlib(struct connectdata *conn,
+ z_stream *z, zlibInitState *zlib_init, CURLcode result)
{
- inflateEnd(z);
- *zlib_init = ZLIB_UNINIT;
+ if(*zlib_init == ZLIB_GZIP_HEADER)
+ Curl_safefree(z->next_in);
+
+ if(*zlib_init != ZLIB_UNINIT) {
+ if(inflateEnd(z) != Z_OK && result == CURLE_OK)
+ result = process_zlib_error(conn, z);
+ *zlib_init = ZLIB_UNINIT;
+ }
+
return result;
}
static CURLcode
-inflate_stream(struct connectdata *conn,
- struct SingleRequest *k)
+inflate_stream(struct connectdata *conn, contenc_writer *writer)
{
+ zlib_params *zp = (zlib_params *) &writer->params;
int allow_restart = 1;
- z_stream *z = &k->z; /* zlib state structure */
+ z_stream *z = &zp->z; /* zlib state structure */
uInt nread = z->avail_in;
Bytef *orig_in = z->next_in;
int status; /* zlib status */
@@ -102,44 +146,42 @@ inflate_stream(struct connectdata *conn,
large to hold on the stack */
decomp = malloc(DSIZ);
if(decomp == NULL) {
- return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY);
+ return exit_zlib(conn, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
}
/* because the buffer size is fixed, iteratively decompress and transfer to
the client via client_write. */
for(;;) {
+ if(z->avail_in == 0) {
+ free(decomp);
+ return result;
+ }
+
/* (re)set buffer for decompressed output for every iteration */
- z->next_out = (Bytef *)decomp;
+ z->next_out = (Bytef *) decomp;
z->avail_out = DSIZ;
status = inflate(z, Z_SYNC_FLUSH);
if(status == Z_OK || status == Z_STREAM_END) {
allow_restart = 0;
- if((DSIZ - z->avail_out) && (!k->ignorebody)) {
- result = Curl_client_write(conn, CLIENTWRITE_BODY, decomp,
+ result = Curl_unencode_write(conn, writer->downstream, decomp,
DSIZ - z->avail_out);
- /* if !CURLE_OK, clean up, return */
- if(result) {
- free(decomp);
- return exit_zlib(z, &k->zlib_init, result);
- }
+ /* if !CURLE_OK, clean up, return */
+ if(result) {
+ free(decomp);
+ return exit_zlib(conn, z, &zp->zlib_init, result);
}
/* Done? clean up, return */
if(status == Z_STREAM_END) {
free(decomp);
- if(inflateEnd(z) == Z_OK)
- return exit_zlib(z, &k->zlib_init, result);
- return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
+ return exit_zlib(conn, z, &zp->zlib_init, result);
}
/* Done with these bytes, exit */
/* status is always Z_OK at this point! */
- if(z->avail_in == 0) {
- free(decomp);
- return result;
- }
+ continue;
}
else if(allow_restart && status == Z_DATA_ERROR) {
/* some servers seem to not generate zlib headers, so this is an attempt
@@ -148,7 +190,8 @@ inflate_stream(struct connectdata *conn,
(void) inflateEnd(z); /* don't care about the return code */
if(inflateInit2(z, -MAX_WBITS) != Z_OK) {
free(decomp);
- return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
+ zp->zlib_init = ZLIB_UNINIT; /* inflateEnd() already called. */
+ return exit_zlib(conn, z, &zp->zlib_init, process_zlib_error(conn, z));
}
z->next_in = orig_in;
z->avail_in = nread;
@@ -157,36 +200,97 @@ inflate_stream(struct connectdata *conn,
}
else { /* Error; exit loop, handle below */
free(decomp);
- return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
+ return exit_zlib(conn, z, &zp->zlib_init, process_zlib_error(conn, z));
}
}
- /* Will never get here */
+ /* UNREACHED */
}
-CURLcode
-Curl_unencode_deflate_write(struct connectdata *conn,
- struct SingleRequest *k,
- ssize_t nread)
+
+/* Deflate handler. */
+static CURLcode deflate_init_writer(struct connectdata *conn,
+ contenc_writer *writer)
{
- z_stream *z = &k->z; /* zlib state structure */
+ zlib_params *zp = (zlib_params *) &writer->params;
+ z_stream *z = &zp->z; /* zlib state structure */
- /* Initialize zlib? */
- if(k->zlib_init == ZLIB_UNINIT) {
- memset(z, 0, sizeof(z_stream));
- z->zalloc = (alloc_func)zalloc_cb;
- z->zfree = (free_func)zfree_cb;
+ if(!writer->downstream)
+ return CURLE_WRITE_ERROR;
- if(inflateInit(z) != Z_OK)
- return process_zlib_error(conn, z);
- k->zlib_init = ZLIB_INIT;
- }
+ /* Initialize zlib */
+ z->zalloc = (alloc_func) zalloc_cb;
+ z->zfree = (free_func) zfree_cb;
+
+ if(inflateInit(z) != Z_OK)
+ return process_zlib_error(conn, z);
+ zp->zlib_init = ZLIB_INIT;
+ return CURLE_OK;
+}
+
+static CURLcode deflate_unencode_write(struct connectdata *conn,
+ contenc_writer *writer,
+ const char *buf, size_t nbytes)
+{
+ zlib_params *zp = (zlib_params *) &writer->params;
+ z_stream *z = &zp->z; /* zlib state structure */
/* Set the compressed input when this function is called */
- z->next_in = (Bytef *)k->str;
- z->avail_in = (uInt)nread;
+ z->next_in = (Bytef *) buf;
+ z->avail_in = (uInt) nbytes;
/* Now uncompress the data */
- return inflate_stream(conn, k);
+ return inflate_stream(conn, writer);
+}
+
+static void deflate_close_writer(struct connectdata *conn,
+ contenc_writer *writer)
+{
+ zlib_params *zp = (zlib_params *) &writer->params;
+ z_stream *z = &zp->z; /* zlib state structure */
+
+ exit_zlib(conn, z, &zp->zlib_init, CURLE_OK);
+}
+
+static const content_encoding deflate_encoding = {
+ "deflate",
+ NULL,
+ deflate_init_writer,
+ deflate_unencode_write,
+ deflate_close_writer,
+ sizeof(zlib_params)
+};
+
+
+/* Gzip handler. */
+static CURLcode gzip_init_writer(struct connectdata *conn,
+ contenc_writer *writer)
+{
+ zlib_params *zp = (zlib_params *) &writer->params;
+ z_stream *z = &zp->z; /* zlib state structure */
+
+ if(!writer->downstream)
+ return CURLE_WRITE_ERROR;
+
+ /* Initialize zlib */
+ z->zalloc = (alloc_func) zalloc_cb;
+ z->zfree = (free_func) zfree_cb;
+
+ if(strcmp(zlibVersion(), "1.2.0.4") >= 0) {
+ /* zlib ver. >= 1.2.0.4 supports transparent gzip decompressing */
+ if(inflateInit2(z, MAX_WBITS + 32) != Z_OK) {
+ return process_zlib_error(conn, z);
+ }
+ zp->zlib_init = ZLIB_INIT_GZIP; /* Transparent gzip decompress state */
+ }
+ else {
+ /* we must parse the gzip header ourselves */
+ if(inflateInit2(z, -MAX_WBITS) != Z_OK) {
+ return process_zlib_error(conn, z);
+ }
+ zp->zlib_init = ZLIB_INIT; /* Initial call state */
+ }
+
+ return CURLE_OK;
}
#ifdef OLD_ZLIB_SUPPORT
@@ -227,7 +331,7 @@ static enum {
extra_len = (data[1] << 8) | data[0];
- if(len < (extra_len+2))
+ if(len < (extra_len + 2))
return GZIP_UNDERFLOW;
len -= (extra_len + 2);
@@ -273,47 +377,25 @@ static enum {
}
#endif
-CURLcode
-Curl_unencode_gzip_write(struct connectdata *conn,
- struct SingleRequest *k,
- ssize_t nread)
+static CURLcode gzip_unencode_write(struct connectdata *conn,
+ contenc_writer *writer,
+ const char *buf, size_t nbytes)
{
- z_stream *z = &k->z; /* zlib state structure */
-
- /* Initialize zlib? */
- if(k->zlib_init == ZLIB_UNINIT) {
- memset(z, 0, sizeof(z_stream));
- z->zalloc = (alloc_func)zalloc_cb;
- z->zfree = (free_func)zfree_cb;
-
- if(strcmp(zlibVersion(), "1.2.0.4") >= 0) {
- /* zlib ver. >= 1.2.0.4 supports transparent gzip decompressing */
- if(inflateInit2(z, MAX_WBITS+32) != Z_OK) {
- return process_zlib_error(conn, z);
- }
- k->zlib_init = ZLIB_INIT_GZIP; /* Transparent gzip decompress state */
- }
- else {
- /* we must parse the gzip header ourselves */
- if(inflateInit2(z, -MAX_WBITS) != Z_OK) {
- return process_zlib_error(conn, z);
- }
- k->zlib_init = ZLIB_INIT; /* Initial call state */
- }
- }
+ zlib_params *zp = (zlib_params *) &writer->params;
+ z_stream *z = &zp->z; /* zlib state structure */
- if(k->zlib_init == ZLIB_INIT_GZIP) {
+ if(zp->zlib_init == ZLIB_INIT_GZIP) {
/* Let zlib handle the gzip decompression entirely */
- z->next_in = (Bytef *)k->str;
- z->avail_in = (uInt)nread;
+ z->next_in = (Bytef *) buf;
+ z->avail_in = (uInt) nbytes;
/* Now uncompress the data */
- return inflate_stream(conn, k);
+ return inflate_stream(conn, writer);
}
#ifndef OLD_ZLIB_SUPPORT
/* Support for old zlib versions is compiled away and we are running with
an old version, so return an error. */
- return exit_zlib(z, &k->zlib_init, CURLE_WRITE_ERROR);
+ return exit_zlib(conn, z, &zp->zlib_init, CURLE_WRITE_ERROR);
#else
/* This next mess is to get around the potential case where there isn't
@@ -326,18 +408,18 @@ Curl_unencode_gzip_write(struct connectdata *conn,
* can handle the gzip header themselves.
*/
- switch(k->zlib_init) {
+ switch(zp->zlib_init) {
/* Skip over gzip header? */
case ZLIB_INIT:
{
/* Initial call state */
ssize_t hlen;
- switch(check_gzip_header((unsigned char *)k->str, nread, &hlen)) {
+ switch(check_gzip_header((unsigned char *) buf, nbytes, &hlen)) {
case GZIP_OK:
- z->next_in = (Bytef *)k->str + hlen;
- z->avail_in = (uInt)(nread - hlen);
- k->zlib_init = ZLIB_GZIP_INFLATING; /* Inflating stream state */
+ z->next_in = (Bytef *) buf + hlen;
+ z->avail_in = (uInt) (nbytes - hlen);
+ zp->zlib_init = ZLIB_GZIP_INFLATING; /* Inflating stream state */
break;
case GZIP_UNDERFLOW:
@@ -348,19 +430,19 @@ Curl_unencode_gzip_write(struct connectdata *conn,
* the first place, and it's even more unlikely for a transfer to fail
* immediately afterwards, it should seldom be a problem.
*/
- z->avail_in = (uInt)nread;
+ z->avail_in = (uInt) nbytes;
z->next_in = malloc(z->avail_in);
if(z->next_in == NULL) {
- return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY);
+ return exit_zlib(conn, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
}
- memcpy(z->next_in, k->str, z->avail_in);
- k->zlib_init = ZLIB_GZIP_HEADER; /* Need more gzip header data state */
+ memcpy(z->next_in, buf, z->avail_in);
+ zp->zlib_init = ZLIB_GZIP_HEADER; /* Need more gzip header data state */
/* We don't have any data to inflate yet */
return CURLE_OK;
case GZIP_BAD:
default:
- return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
+ return exit_zlib(conn, z, &zp->zlib_init, process_zlib_error(conn, z));
}
}
@@ -370,22 +452,22 @@ Curl_unencode_gzip_write(struct connectdata *conn,
{
/* Need more gzip header data state */
ssize_t hlen;
- z->avail_in += (uInt)nread;
+ z->avail_in += (uInt) nbytes;
z->next_in = Curl_saferealloc(z->next_in, z->avail_in);
if(z->next_in == NULL) {
- return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY);
+ return exit_zlib(conn, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
}
/* Append the new block of data to the previous one */
- memcpy(z->next_in + z->avail_in - nread, k->str, nread);
+ memcpy(z->next_in + z->avail_in - nbytes, buf, nbytes);
switch(check_gzip_header(z->next_in, z->avail_in, &hlen)) {
case GZIP_OK:
/* This is the zlib stream data */
free(z->next_in);
/* Don't point into the malloced block since we just freed it */
- z->next_in = (Bytef *)k->str + hlen + nread - z->avail_in;
- z->avail_in = (uInt)(z->avail_in - hlen);
- k->zlib_init = ZLIB_GZIP_INFLATING; /* Inflating stream state */
+ z->next_in = (Bytef *) buf + hlen + nbytes - z->avail_in;
+ z->avail_in = (uInt) (z->avail_in - hlen);
+ zp->zlib_init = ZLIB_GZIP_INFLATING; /* Inflating stream state */
break;
case GZIP_UNDERFLOW:
@@ -394,8 +476,7 @@ Curl_unencode_gzip_write(struct connectdata *conn,
case GZIP_BAD:
default:
- free(z->next_in);
- return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
+ return exit_zlib(conn, z, &zp->zlib_init, process_zlib_error(conn, z));
}
}
@@ -404,8 +485,8 @@ Curl_unencode_gzip_write(struct connectdata *conn,
case ZLIB_GZIP_INFLATING:
default:
/* Inflating stream state */
- z->next_in = (Bytef *)k->str;
- z->avail_in = (uInt)nread;
+ z->next_in = (Bytef *) buf;
+ z->avail_in = (uInt) nbytes;
break;
}
@@ -415,17 +496,465 @@ Curl_unencode_gzip_write(struct connectdata *conn,
}
/* We've parsed the header, now uncompress the data */
- return inflate_stream(conn, k);
+ return inflate_stream(conn, writer);
#endif
}
+static void gzip_close_writer(struct connectdata *conn,
+ contenc_writer *writer)
+{
+ zlib_params *zp = (zlib_params *) &writer->params;
+ z_stream *z = &zp->z; /* zlib state structure */
+
+ exit_zlib(conn, z, &zp->zlib_init, CURLE_OK);
+}
+
+static const content_encoding gzip_encoding = {
+ "gzip",
+ "x-gzip",
+ gzip_init_writer,
+ gzip_unencode_write,
+ gzip_close_writer,
+ sizeof(zlib_params)
+};
+
+#endif /* HAVE_LIBZ */
+
+
+#ifdef HAVE_BROTLI
+
+/* Writer parameters. */
+typedef struct {
+ BrotliDecoderState *br; /* State structure for brotli. */
+} brotli_params;
+
+
+static CURLcode brotli_map_error(BrotliDecoderErrorCode be)
+{
+ switch(be) {
+ case BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE:
+ case BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE:
+ case BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET:
+ case BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME:
+ case BROTLI_DECODER_ERROR_FORMAT_CL_SPACE:
+ case BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE:
+ case BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT:
+ case BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1:
+ case BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2:
+ case BROTLI_DECODER_ERROR_FORMAT_TRANSFORM:
+ case BROTLI_DECODER_ERROR_FORMAT_DICTIONARY:
+ case BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS:
+ case BROTLI_DECODER_ERROR_FORMAT_PADDING_1:
+ case BROTLI_DECODER_ERROR_FORMAT_PADDING_2:
+ case BROTLI_DECODER_ERROR_COMPOUND_DICTIONARY:
+ case BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET:
+ case BROTLI_DECODER_ERROR_INVALID_ARGUMENTS:
+ return CURLE_BAD_CONTENT_ENCODING;
+ case BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES:
+ case BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS:
+ case BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP:
+ case BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1:
+ case BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2:
+ case BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES:
+ return CURLE_OUT_OF_MEMORY;
+ default:
+ break;
+ }
+ return CURLE_WRITE_ERROR;
+}
+
+static CURLcode brotli_init_writer(struct connectdata *conn,
+ contenc_writer *writer)
+{
+ brotli_params *bp = (brotli_params *) &writer->params;
+
+ (void) conn;
+
+ if(!writer->downstream)
+ return CURLE_WRITE_ERROR;
+
+ bp->br = BrotliDecoderCreateInstance(NULL, NULL, NULL);
+ return bp->br? CURLE_OK: CURLE_OUT_OF_MEMORY;
+}
+
+static CURLcode brotli_unencode_write(struct connectdata *conn,
+ contenc_writer *writer,
+ const char *buf, size_t nbytes)
+{
+ brotli_params *bp = (brotli_params *) &writer->params;
+ const uint8_t *src = (const uint8_t *) buf;
+ char *decomp;
+ uint8_t *dst;
+ size_t dstleft;
+ CURLcode result = CURLE_OK;
+
+ if(!bp->br)
+ return CURLE_WRITE_ERROR; /* Stream already ended. */
+
+ decomp = malloc(DSIZ);
+ if(!decomp)
+ return CURLE_OUT_OF_MEMORY;
+
+ while(nbytes && result == CURLE_OK) {
+ BrotliDecoderResult r;
+
+ dst = (uint8_t *) decomp;
+ dstleft = DSIZ;
+ r = BrotliDecoderDecompressStream(bp->br,
+ &nbytes, &src, &dstleft, &dst, NULL);
+ result = Curl_unencode_write(conn, writer->downstream,
+ decomp, DSIZ - dstleft);
+ if(result)
+ break;
+ switch(r) {
+ case BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT:
+ case BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT:
+ break;
+ case BROTLI_DECODER_RESULT_SUCCESS:
+ BrotliDecoderDestroyInstance(bp->br);
+ bp->br = NULL;
+ if(nbytes)
+ result = CURLE_WRITE_ERROR;
+ break;
+ default:
+ result = brotli_map_error(BrotliDecoderGetErrorCode(bp->br));
+ break;
+ }
+ }
+ free(decomp);
+ return result;
+}
+
+static void brotli_close_writer(struct connectdata *conn,
+ contenc_writer *writer)
+{
+ brotli_params *bp = (brotli_params *) &writer->params;
+
+ (void) conn;
+
+ if(bp->br) {
+ BrotliDecoderDestroyInstance(bp->br);
+ bp->br = NULL;
+ }
+}
+
+static const content_encoding brotli_encoding = {
+ "br",
+ NULL,
+ brotli_init_writer,
+ brotli_unencode_write,
+ brotli_close_writer,
+ sizeof(brotli_params)
+};
+#endif
+
+
+/* Identity handler. */
+static CURLcode identity_init_writer(struct connectdata *conn,
+ contenc_writer *writer)
+{
+ (void) conn;
+ return writer->downstream? CURLE_OK: CURLE_WRITE_ERROR;
+}
+
+static CURLcode identity_unencode_write(struct connectdata *conn,
+ contenc_writer *writer,
+ const char *buf, size_t nbytes)
+{
+ return Curl_unencode_write(conn, writer->downstream, buf, nbytes);
+}
+
+static void identity_close_writer(struct connectdata *conn,
+ contenc_writer *writer)
+{
+ (void) conn;
+ (void) writer;
+}
+
+static const content_encoding identity_encoding = {
+ "identity",
+ NULL,
+ identity_init_writer,
+ identity_unencode_write,
+ identity_close_writer,
+ 0
+};
+
+
+/* supported content encodings table. */
+static const content_encoding * const encodings[] = {
+ &identity_encoding,
+#ifdef HAVE_LIBZ
+ &deflate_encoding,
+ &gzip_encoding,
+#endif
+#ifdef HAVE_BROTLI
+ &brotli_encoding,
+#endif
+ NULL
+};
+
+
+/* Return a list of comma-separated names of supported encodings. */
+char *Curl_all_content_encodings(void)
+{
+ size_t len = 0;
+ const content_encoding * const *cep;
+ const content_encoding *ce;
+ char *ace;
+ char *p;
+
+ for(cep = encodings; *cep; cep++) {
+ ce = *cep;
+ if(!strcasecompare(ce->name, CONTENT_ENCODING_DEFAULT))
+ len += strlen(ce->name) + 2;
+ }
+
+ if(!len)
+ return strdup(CONTENT_ENCODING_DEFAULT);
+
+ ace = malloc(len);
+ if(ace) {
+ p = ace;
+ for(cep = encodings; *cep; cep++) {
+ ce = *cep;
+ if(!strcasecompare(ce->name, CONTENT_ENCODING_DEFAULT)) {
+ strcpy(p, ce->name);
+ p += strlen(p);
+ *p++ = ',';
+ *p++ = ' ';
+ }
+ }
+ p[-2] = '\0';
+ }
+
+ return ace;
+}
+
+
+/* Real client writer: no downstream. */
+static CURLcode client_init_writer(struct connectdata *conn,
+ contenc_writer *writer)
+{
+ (void) conn;
+ return writer->downstream? CURLE_WRITE_ERROR: CURLE_OK;
+}
+
+static CURLcode client_unencode_write(struct connectdata *conn,
+ contenc_writer *writer,
+ const char *buf, size_t nbytes)
+{
+ struct Curl_easy *data = conn->data;
+ struct SingleRequest *k = &data->req;
+
+ (void) writer;
+
+ if(!nbytes || k->ignorebody)
+ return CURLE_OK;
+
+ return Curl_client_write(conn, CLIENTWRITE_BODY, (char *) buf, nbytes);
+}
+
+static void client_close_writer(struct connectdata *conn,
+ contenc_writer *writer)
+{
+ (void) conn;
+ (void) writer;
+}
+
+static const content_encoding client_encoding = {
+ NULL,
+ NULL,
+ client_init_writer,
+ client_unencode_write,
+ client_close_writer,
+ 0
+};
+
+
+/* Deferred error dummy writer. */
+static CURLcode error_init_writer(struct connectdata *conn,
+ contenc_writer *writer)
+{
+ (void) conn;
+ return writer->downstream? CURLE_OK: CURLE_WRITE_ERROR;
+}
+
+static CURLcode error_unencode_write(struct connectdata *conn,
+ contenc_writer *writer,
+ const char *buf, size_t nbytes)
+{
+ char *all = Curl_all_content_encodings();
+
+ (void) writer;
+ (void) buf;
+ (void) nbytes;
+
+ if(!all)
+ return CURLE_OUT_OF_MEMORY;
+ failf(conn->data, "Unrecognized content encoding type. "
+ "libcurl understands %s content encodings.", all);
+ free(all);
+ return CURLE_BAD_CONTENT_ENCODING;
+}
+
+static void error_close_writer(struct connectdata *conn,
+ contenc_writer *writer)
+{
+ (void) conn;
+ (void) writer;
+}
+
+static const content_encoding error_encoding = {
+ NULL,
+ NULL,
+ error_init_writer,
+ error_unencode_write,
+ error_close_writer,
+ 0
+};
+
+/* Create an unencoding writer stage using the given handler. */
+static contenc_writer *new_unencoding_writer(struct connectdata *conn,
+ const content_encoding *handler,
+ contenc_writer *downstream)
+{
+ size_t sz = offsetof(contenc_writer, params) + handler->paramsize;
+ contenc_writer *writer = (contenc_writer *) malloc(sz);
+
+ if(writer) {
+ memset(writer, 0, sz);
+ writer->handler = handler;
+ writer->downstream = downstream;
+ if(handler->init_writer(conn, writer)) {
+ free(writer);
+ writer = NULL;
+ }
+ }
+
+ return writer;
+}
+
+/* Write data using an unencoding writer stack. */
+CURLcode Curl_unencode_write(struct connectdata *conn, contenc_writer *writer,
+ const char *buf, size_t nbytes)
+{
+ if(!nbytes)
+ return CURLE_OK;
+ return writer->handler->unencode_write(conn, writer, buf, nbytes);
+}
+
+/* Close and clean-up the connection's writer stack. */
void Curl_unencode_cleanup(struct connectdata *conn)
{
struct Curl_easy *data = conn->data;
struct SingleRequest *k = &data->req;
- z_stream *z = &k->z;
- if(k->zlib_init != ZLIB_UNINIT)
- (void) exit_zlib(z, &k->zlib_init, CURLE_OK);
+ contenc_writer *writer = k->writer_stack;
+
+ while(writer) {
+ k->writer_stack = writer->downstream;
+ writer->handler->close_writer(conn, writer);
+ free(writer);
+ writer = k->writer_stack;
+ }
}
-#endif /* HAVE_LIBZ */
+/* Find the content encoding by name. */
+static const content_encoding *find_encoding(const char *name, size_t len)
+{
+ const content_encoding * const *cep;
+ const content_encoding *ce;
+
+ for(cep = encodings; *cep; cep++) {
+ ce = *cep;
+ if((strncasecompare(name, ce->name, len) && !ce->name[len]) ||
+ (ce->alias && strncasecompare(name, ce->alias, len) && !ce->alias[len]))
+ return ce;
+ }
+ return NULL;
+}
+
+/* Set-up the unencoding stack from the Content-Encoding header value.
+ * See RFC 7231 section 3.1.2.2. */
+CURLcode Curl_build_unencoding_stack(struct connectdata *conn,
+ const char *enclist, int maybechunked)
+{
+ struct Curl_easy *data = conn->data;
+ struct SingleRequest *k = &data->req;
+
+ do {
+ const char *name;
+ size_t namelen;
+
+ /* Parse a single encoding name. */
+ while(ISSPACE(*enclist) || *enclist == ',')
+ enclist++;
+
+ name = enclist;
+
+ for(namelen = 0; *enclist && *enclist != ','; enclist++)
+ if(!ISSPACE(*enclist))
+ namelen = enclist - name + 1;
+
+ /* Special case: chunked encoding is handled at the reader level. */
+ if(maybechunked && namelen == 7 && strncasecompare(name, "chunked", 7)) {
+ k->chunk = TRUE; /* chunks coming our way. */
+ Curl_httpchunk_init(conn); /* init our chunky engine. */
+ }
+ else if(namelen) {
+ const content_encoding *encoding = find_encoding(name, namelen);
+ contenc_writer *writer;
+
+ if(!k->writer_stack) {
+ k->writer_stack = new_unencoding_writer(conn, &client_encoding, NULL);
+
+ if(!k->writer_stack)
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ if(!encoding)
+ encoding = &error_encoding; /* Defer error at stack use. */
+
+ /* Stack the unencoding stage. */
+ writer = new_unencoding_writer(conn, encoding, k->writer_stack);
+ if(!writer)
+ return CURLE_OUT_OF_MEMORY;
+ k->writer_stack = writer;
+ }
+ } while(*enclist);
+
+ return CURLE_OK;
+}
+
+#else
+/* Stubs for builds without HTTP. */
+CURLcode Curl_build_unencoding_stack(struct connectdata *conn,
+ const char *enclist, int maybechunked)
+{
+ (void) conn;
+ (void) enclist;
+ (void) maybechunked;
+ return CURLE_NOT_BUILT_IN;
+}
+
+CURLcode Curl_unencode_write(struct connectdata *conn, contenc_writer *writer,
+ const char *buf, size_t nbytes)
+{
+ (void) conn;
+ (void) writer;
+ (void) buf;
+ (void) nbytes;
+ return CURLE_NOT_BUILT_IN;
+}
+
+void Curl_unencode_cleanup(struct connectdata *conn)
+{
+ (void) conn;
+}
+
+char *Curl_all_content_encodings(void)
+{
+ return strdup(CONTENT_ENCODING_DEFAULT); /* Satisfy caller. */
+}
+
+#endif /* CURL_DISABLE_HTTP */
diff --git a/lib/content_encoding.h b/lib/content_encoding.h
index 3fadd289..4cd52be6 100644
--- a/lib/content_encoding.h
+++ b/lib/content_encoding.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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,26 +23,33 @@
***************************************************************************/
#include "curl_setup.h"
-/*
- * Comma-separated list all supported Content-Encodings ('identity' is implied)
- */
-#ifdef HAVE_LIBZ
-#define ALL_CONTENT_ENCODINGS "deflate, gzip"
-/* force a cleanup */
-void Curl_unencode_cleanup(struct connectdata *conn);
-#else
-#define ALL_CONTENT_ENCODINGS "identity"
-#define Curl_unencode_cleanup(x) Curl_nop_stmt
-#endif
+/* Decoding writer. */
+typedef struct contenc_writer_s contenc_writer;
+typedef struct content_encoding_s content_encoding;
+
+struct contenc_writer_s {
+ const content_encoding *handler; /* Encoding handler. */
+ contenc_writer *downstream; /* Downstream writer. */
+ void *params; /* Encoding-specific storage (variable length). */
+};
-CURLcode Curl_unencode_deflate_write(struct connectdata *conn,
- struct SingleRequest *req,
- ssize_t nread);
+/* Content encoding writer. */
+struct content_encoding_s {
+ const char *name; /* Encoding name. */
+ const char *alias; /* Encoding name alias. */
+ CURLcode (*init_writer)(struct connectdata *conn, contenc_writer *writer);
+ CURLcode (*unencode_write)(struct connectdata *conn, contenc_writer *writer,
+ const char *buf, size_t nbytes);
+ void (*close_writer)(struct connectdata *conn, contenc_writer *writer);
+ size_t paramsize;
+};
-CURLcode
-Curl_unencode_gzip_write(struct connectdata *conn,
- struct SingleRequest *k,
- ssize_t nread);
+CURLcode Curl_build_unencoding_stack(struct connectdata *conn,
+ const char *enclist, int maybechunked);
+CURLcode Curl_unencode_write(struct connectdata *conn, contenc_writer *writer,
+ const char *buf, size_t nbytes);
+void Curl_unencode_cleanup(struct connectdata *conn);
+char *Curl_all_content_encodings(void);
#endif /* HEADER_CURL_CONTENT_ENCODING_H */
diff --git a/lib/cookie.c b/lib/cookie.c
index 6b678aeb..c7afc7ae 100644
--- a/lib/cookie.c
+++ b/lib/cookie.c
@@ -125,7 +125,7 @@ static bool tailmatch(const char *cooke_domain, const char *hostname)
if(hostname_len < cookie_domain_len)
return FALSE;
- if(!strcasecompare(cooke_domain, hostname+hostname_len-cookie_domain_len))
+ if(!strcasecompare(cooke_domain, hostname + hostname_len-cookie_domain_len))
return FALSE;
/* A lead char of cookie_domain is not '.'.
@@ -309,7 +309,7 @@ static void remove_expired(struct CookieInfo *cookies)
while(co) {
nx = co->next;
if(co->expires && co->expires < now) {
- if(co == cookies->cookies) {
+ if(!pv) {
cookies->cookies = co->next;
}
else {
@@ -375,9 +375,8 @@ Curl_cookie_add(struct Curl_easy *data,
unless set */
{
struct Cookie *clist;
- char name[MAX_NAME];
struct Cookie *co;
- struct Cookie *lastc=NULL;
+ struct Cookie *lastc = NULL;
time_t now = time(NULL);
bool replace_old = FALSE;
bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */
@@ -397,17 +396,19 @@ Curl_cookie_add(struct Curl_easy *data,
if(httpheader) {
/* This line was read off a HTTP-header */
+ char name[MAX_NAME];
+ char what[MAX_NAME];
const char *ptr;
const char *semiptr;
- char *what;
- what = malloc(MAX_COOKIE_LINE);
- if(!what) {
+ size_t linelength = strlen(lineptr);
+ if(linelength > MAX_COOKIE_LINE) {
+ /* discard overly long lines at once */
free(co);
return NULL;
}
- semiptr=strchr(lineptr, ';'); /* first, find a semicolon */
+ semiptr = strchr(lineptr, ';'); /* first, find a semicolon */
while(*lineptr && ISBLANK(*lineptr))
lineptr++;
@@ -415,9 +416,9 @@ Curl_cookie_add(struct Curl_easy *data,
ptr = lineptr;
do {
/* we have a <what>=<this> pair or a stand-alone word here */
- name[0]=what[0]=0; /* init the buffers */
+ name[0] = what[0] = 0; /* init the buffers */
if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;\r\n=] =%"
- MAX_COOKIE_LINE_TXT "[^;\r\n]",
+ MAX_NAME_TXT "[^;\r\n]",
name, what)) {
/* Use strstore() below to properly deal with received cookie
headers that have the same string property set more than once,
@@ -425,10 +426,24 @@ Curl_cookie_add(struct Curl_easy *data,
const char *whatptr;
bool done = FALSE;
bool sep;
- size_t len=strlen(what);
+ size_t len = strlen(what);
size_t nlen = strlen(name);
const char *endofn = &ptr[ nlen ];
+ infof(data, "cookie size: name/val %d + %d bytes\n",
+ nlen, len);
+
+ if(nlen >= (MAX_NAME-1) || len >= (MAX_NAME-1) ||
+ ((nlen + len) > MAX_NAME)) {
+ /* too long individual name or contents, or too long combination of
+ name + contents. Chrome and Firefox support 4095 or 4096 bytes
+ combo. */
+ freecookie(co);
+ infof(data, "oversized cookie dropped, name/val %d + %d bytes\n",
+ nlen, len);
+ return NULL;
+ }
+
/* name ends with a '=' ? */
sep = (*endofn == '=')?TRUE:FALSE;
@@ -440,18 +455,18 @@ Curl_cookie_add(struct Curl_easy *data,
endofn--;
nlen--;
}
- name[nlen]=0; /* new end of name */
+ name[nlen] = 0; /* new end of name */
}
}
/* Strip off trailing whitespace from the 'what' */
while(len && ISBLANK(what[len-1])) {
- what[len-1]=0;
+ what[len-1] = 0;
len--;
}
/* Skip leading whitespace from the 'what' */
- whatptr=what;
+ whatptr = what;
while(*whatptr && ISBLANK(*whatptr))
whatptr++;
@@ -484,6 +499,7 @@ Curl_cookie_add(struct Curl_easy *data,
badcookie = TRUE; /* out of memory bad */
break;
}
+ free(co->spath); /* if this is set again */
co->spath = sanitize_cookie_path(co->path);
if(!co->spath) {
badcookie = TRUE; /* out of memory bad */
@@ -510,7 +526,7 @@ Curl_cookie_add(struct Curl_easy *data,
/* check for more dots */
dotp = strchr(whatptr, '.');
if(!dotp && !strcasecompare("localhost", whatptr))
- domain=":";
+ domain = ":";
}
#endif
@@ -525,14 +541,14 @@ Curl_cookie_add(struct Curl_easy *data,
break;
}
if(!is_ip)
- co->tailmatch=TRUE; /* we always do that if the domain name was
- given */
+ co->tailmatch = TRUE; /* we always do that if the domain name was
+ given */
}
else {
/* we did not get a tailmatch and then the attempted set domain
is not a domain to which the current host belongs. Mark as
bad. */
- badcookie=TRUE;
+ badcookie = TRUE;
infof(data, "skipped cookie with bad tailmatch domain: %s\n",
whatptr);
}
@@ -581,26 +597,32 @@ Curl_cookie_add(struct Curl_easy *data,
continue;
}
- ptr=semiptr+1;
+ ptr = semiptr + 1;
while(*ptr && ISBLANK(*ptr))
ptr++;
- semiptr=strchr(ptr, ';'); /* now, find the next semicolon */
+ semiptr = strchr(ptr, ';'); /* now, find the next semicolon */
if(!semiptr && *ptr)
/* There are no more semicolons, but there's a final name=value pair
coming up */
- semiptr=strchr(ptr, '\0');
+ semiptr = strchr(ptr, '\0');
} while(semiptr);
if(co->maxage) {
- co->expires =
- curlx_strtoofft((*co->maxage=='\"')?
- &co->maxage[1]:&co->maxage[0], NULL, 10);
- if(CURL_OFF_T_MAX - now < co->expires)
- /* avoid overflow */
+ CURLofft offt;
+ offt = curlx_strtoofft((*co->maxage == '\"')?
+ &co->maxage[1]:&co->maxage[0], NULL, 10,
+ &co->expires);
+ if(offt == CURL_OFFT_FLOW)
+ /* overflow, used max value */
co->expires = CURL_OFF_T_MAX;
- else
- co->expires += now;
+ else if(!offt) {
+ if(CURL_OFF_T_MAX - now < co->expires)
+ /* would overflow */
+ co->expires = CURL_OFF_T_MAX;
+ else
+ co->expires += now;
+ }
}
else if(co->expirestr) {
/* Note that if the date couldn't get parsed for whatever reason,
@@ -619,7 +641,7 @@ Curl_cookie_add(struct Curl_easy *data,
if(!badcookie && !co->domain) {
if(domain) {
/* no domain was given in the header line, set the default */
- co->domain=strdup(domain);
+ co->domain = strdup(domain);
if(!co->domain)
badcookie = TRUE;
}
@@ -639,11 +661,11 @@ Curl_cookie_add(struct Curl_easy *data,
else
endslash = memrchr(path, '/', (size_t)(queryp - path));
if(endslash) {
- size_t pathlen = (size_t)(endslash-path+1); /* include ending slash */
- co->path=malloc(pathlen+1); /* one extra for the zero byte */
+ size_t pathlen = (size_t)(endslash-path + 1); /* include end slash */
+ co->path = malloc(pathlen + 1); /* one extra for the zero byte */
if(co->path) {
memcpy(co->path, path, pathlen);
- co->path[pathlen]=0; /* zero terminate */
+ co->path[pathlen] = 0; /* zero terminate */
co->spath = sanitize_cookie_path(co->path);
if(!co->spath)
badcookie = TRUE; /* out of memory bad */
@@ -653,8 +675,6 @@ Curl_cookie_add(struct Curl_easy *data,
}
}
- free(what);
-
if(badcookie || !co->name) {
/* we didn't get a cookie name or a bad one,
this is an illegal line, bail out */
@@ -668,7 +688,7 @@ Curl_cookie_add(struct Curl_easy *data,
reading the odd netscape cookies-file format here */
char *ptr;
char *firstptr;
- char *tok_buf=NULL;
+ char *tok_buf = NULL;
int fields;
/* IE introduced HTTP-only cookies to prevent XSS attacks. Cookies
@@ -689,19 +709,19 @@ Curl_cookie_add(struct Curl_easy *data,
return NULL;
}
/* strip off the possible end-of-line characters */
- ptr=strchr(lineptr, '\r');
+ ptr = strchr(lineptr, '\r');
if(ptr)
- *ptr=0; /* clear it */
- ptr=strchr(lineptr, '\n');
+ *ptr = 0; /* clear it */
+ ptr = strchr(lineptr, '\n');
if(ptr)
- *ptr=0; /* clear it */
+ *ptr = 0; /* clear it */
- firstptr=strtok_r(lineptr, "\t", &tok_buf); /* tokenize it on the TAB */
+ firstptr = strtok_r(lineptr, "\t", &tok_buf); /* tokenize it on the TAB */
/* Now loop through the fields and init the struct we already have
allocated */
- for(ptr=firstptr, fields=0; ptr && !badcookie;
- ptr=strtok_r(NULL, "\t", &tok_buf), fields++) {
+ for(ptr = firstptr, fields = 0; ptr && !badcookie;
+ ptr = strtok_r(NULL, "\t", &tok_buf), fields++) {
switch(fields) {
case 0:
if(ptr[0]=='.') /* skip preceding dots */
@@ -753,7 +773,8 @@ Curl_cookie_add(struct Curl_easy *data,
co->secure = strcasecompare(ptr, "TRUE")?TRUE:FALSE;
break;
case 4:
- co->expires = curlx_strtoofft(ptr, NULL, 10);
+ if(curlx_strtoofft(ptr, NULL, 10, &co->expires))
+ badcookie = TRUE;
break;
case 5:
co->name = strdup(ptr);
@@ -828,7 +849,7 @@ Curl_cookie_add(struct Curl_easy *data,
if(strcasecompare(clist->domain, co->domain) &&
(clist->tailmatch == co->tailmatch))
/* The domains are identical */
- replace_old=TRUE;
+ replace_old = TRUE;
}
else if(!clist->domain && !co->domain)
replace_old = TRUE;
@@ -957,7 +978,7 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
{
struct CookieInfo *c;
FILE *fp = NULL;
- bool fromfile=TRUE;
+ bool fromfile = TRUE;
char *line = NULL;
if(NULL == inc) {
@@ -977,7 +998,7 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
if(file && !strcmp(file, "-")) {
fp = stdin;
- fromfile=FALSE;
+ fromfile = FALSE;
}
else if(file && !*file) {
/* points to a "" string */
@@ -998,12 +1019,12 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
while(get_line(line, MAX_COOKIE_LINE, fp)) {
if(checkprefix("Set-Cookie:", line)) {
/* This is a cookie line, get it! */
- lineptr=&line[11];
- headerline=TRUE;
+ lineptr = &line[11];
+ headerline = TRUE;
}
else {
- lineptr=line;
- headerline=FALSE;
+ lineptr = line;
+ headerline = FALSE;
}
while(*lineptr && ISBLANK(*lineptr))
lineptr++;
@@ -1113,7 +1134,7 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
struct Cookie *newco;
struct Cookie *co;
time_t now = time(NULL);
- struct Cookie *mainco=NULL;
+ struct Cookie *mainco = NULL;
size_t matches = 0;
bool is_ip;
@@ -1185,7 +1206,7 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
co = mainco;
- for(i=0; co; co = co->next)
+ for(i = 0; co; co = co->next)
array[i++] = co;
/* now sort the cookie pointers in path length order */
@@ -1194,8 +1215,8 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
/* remake the linked list order according to the new order */
mainco = array[0]; /* start here */
- for(i=0; i<matches-1; i++)
- array[i]->next = array[i+1];
+ for(i = 0; i<matches-1; i++)
+ array[i]->next = array[i + 1];
array[matches-1]->next = NULL; /* terminate the list */
free(array); /* remove the temporary data again */
@@ -1335,7 +1356,7 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere)
{
struct Cookie *co;
FILE *out;
- bool use_stdout=FALSE;
+ bool use_stdout = FALSE;
char *format_ptr;
if((NULL == c) || (0 == c->numcookies))
@@ -1349,7 +1370,7 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere)
if(!strcmp("-", dumphere)) {
/* use stdout */
out = stdout;
- use_stdout=TRUE;
+ use_stdout = TRUE;
}
else {
out = fopen(dumphere, FOPEN_WRITETEXT);
@@ -1382,7 +1403,7 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere)
return 0;
}
-struct curl_slist *Curl_cookie_list(struct Curl_easy *data)
+static struct curl_slist *cookie_list(struct Curl_easy *data)
{
struct curl_slist *list = NULL;
struct curl_slist *beg;
@@ -1413,6 +1434,15 @@ struct curl_slist *Curl_cookie_list(struct Curl_easy *data)
return list;
}
+struct curl_slist *Curl_cookie_list(struct Curl_easy *data)
+{
+ struct curl_slist *list;
+ Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
+ list = cookie_list(data);
+ Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+ return list;
+}
+
void Curl_flush_cookies(struct Curl_easy *data, int cleanup)
{
if(data->set.str[STRING_COOKIEJAR]) {
diff --git a/lib/cookie.h b/lib/cookie.h
index a9a45785..cb50b71c 100644
--- a/lib/cookie.h
+++ b/lib/cookie.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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
@@ -62,13 +62,16 @@ struct CookieInfo {
that comprise the cookie non-terminal in the syntax description of the
Set-Cookie header)"
+ We allow max 5000 bytes cookie header. Max 4095 bytes length per cookie
+ name and value. Name + value may not exceed 4096 bytes.
+
*/
#define MAX_COOKIE_LINE 5000
#define MAX_COOKIE_LINE_TXT "4999"
-/* This is the maximum length of a cookie name we deal with: */
-#define MAX_NAME 1024
-#define MAX_NAME_TXT "1023"
+/* This is the maximum length of a cookie name or content we deal with: */
+#define MAX_NAME 4096
+#define MAX_NAME_TXT "4095"
struct Curl_easy;
/*
diff --git a/lib/curl_addrinfo.c b/lib/curl_addrinfo.c
index 1adf3198..6eb28bbc 100644
--- a/lib/curl_addrinfo.c
+++ b/lib/curl_addrinfo.c
@@ -286,7 +286,7 @@ Curl_he2ai(const struct hostent *he, int port)
DEBUGASSERT((he->h_name != NULL) && (he->h_addr_list != NULL));
- for(i=0; (curr = he->h_addr_list[i]) != NULL; i++) {
+ for(i = 0; (curr = he->h_addr_list[i]) != NULL; i++) {
size_t ss_size;
#ifdef ENABLE_IPV6
@@ -570,9 +570,9 @@ curl_dogetaddrinfo(const char *hostname,
int line, const char *source)
{
#ifdef USE_LWIPSOCK
- int res=lwip_getaddrinfo(hostname, service, hints, result);
+ int res = lwip_getaddrinfo(hostname, service, hints, result);
#else
- int res=(getaddrinfo)(hostname, service, hints, result);
+ int res = (getaddrinfo)(hostname, service, hints, result);
#endif
if(0 == res)
/* success */
diff --git a/lib/curl_config.h b/lib/curl_config.h
index 6ba8faca..7da71f1c 100644
--- a/lib/curl_config.h
+++ b/lib/curl_config.h
@@ -10,6 +10,9 @@
/* Location of default ca path */
#define CURL_CA_PATH "/system/etc/security/cacerts"
+/* Default SSL backend */
+/* #undef CURL_DEFAULT_SSL_BACKEND */
+
/* to disable cookies support */
/* #undef CURL_DISABLE_COOKIES */
@@ -73,6 +76,9 @@
/* Definition to make a library symbol externally visible. */
#define CURL_EXTERN_SYMBOL __attribute__ ((__visibility__ ("default")))
+/* built with multiple SSL backends */
+/* #undef CURL_WITH_MULTI_SSL */
+
/* your Entropy Gathering Daemon socket pathname */
/* #undef EGD_SOCKET */
@@ -127,6 +133,15 @@
/* Define to 1 if using BoringSSL. */
#define HAVE_BORINGSSL 1
+/* if BROTLI is in use */
+/* #undef HAVE_BROTLI */
+
+/* Define to 1 if you have the <brotli/decode.h> header file. */
+/* #undef HAVE_BROTLI_DECODE_H */
+
+/* Define to 1 if you have the __builtin_available function. */
+/* #undef HAVE_BUILTIN_AVAILABLE */
+
/* Define to 1 if you have the clock_gettime function and monotonic timer. */
#if !defined(__APPLE__)
/* CLOCK_MONOTONIC is not defined in mac when building for the host. */
@@ -387,6 +402,9 @@
/* Define to 1 if you have the `ldap_url_parse' function. */
/* #undef HAVE_LDAP_URL_PARSE */
+/* Define to 1 if you have the `brotlidec' library (-lbrotlidec). */
+/* #undef HAVE_LIBBROTLIDEC */
+
/* Define to 1 if you have the <libgen.h> header file. */
#define HAVE_LIBGEN_H 1
@@ -414,6 +432,9 @@
/* Define to 1 if you have the <limits.h> header file. */
#define HAVE_LIMITS_H 1
+/* Define to 1 if you have the <linux/tcp.h> header file. */
+#define HAVE_LINUX_TCP_H 1
+
/* if your compiler supports LL */
#define HAVE_LL 1
@@ -426,6 +447,9 @@
/* Define to 1 if the compiler supports the 'long long' data type. */
#define HAVE_LONGLONG 1
+/* Define to 1 if you have the `mach_absolute_time' function. */
+/* #undef HAVE_MACH_ABSOLUTE_TIME */
+
/* Define to 1 if you have the malloc.h header file. */
#define HAVE_MALLOC_H 1
@@ -476,9 +500,6 @@
/* Define to 1 if you have the <openssl/pem.h> header file. */
#define HAVE_OPENSSL_PEM_H 1
-/* Define to 1 if you have the <openssl/pkcs12.h> header file. */
-#define HAVE_OPENSSL_PKCS12_H 1
-
/* Define to 1 if you have the <openssl/rsa.h> header file. */
#define HAVE_OPENSSL_RSA_H 1
@@ -869,6 +890,9 @@
/* Define to the function return type for send. */
#define SEND_TYPE_RETV ssize_t
+/* The size of `curl_off_t', as computed by sizeof. */
+#define SIZEOF_CURL_OFF_T 8
+
/* The size of `int', as computed by sizeof. */
#define SIZEOF_INT 4
diff --git a/lib/curl_config.h.cmake b/lib/curl_config.h.cmake
index c1452b3e..e4d14c78 100644
--- a/lib/curl_config.h.cmake
+++ b/lib/curl_config.h.cmake
@@ -51,9 +51,6 @@
/* to disable RTSP */
#cmakedefine CURL_DISABLE_RTSP 1
-/* to disable RTMP */
-#cmakedefine CURL_DISABLE_RTMP 1
-
/* to disable SMB */
#cmakedefine CURL_DISABLE_SMB 1
@@ -82,9 +79,6 @@
/* when not building a shared library */
#cmakedefine CURL_STATICLIB 1
-/* Set to explicitly specify we don't want to use thread-safe functions */
-#cmakedefine DISABLED_THREADSAFE 1
-
/* your Entropy Gathering Daemon socket pathname */
#cmakedefine EGD_SOCKET ${EGD_SOCKET}
@@ -894,6 +888,9 @@
/* The size of `off_t', as computed by sizeof. */
#cmakedefine SIZEOF_OFF_T ${SIZEOF_OFF_T}
+/* The size of `curl_off_t', as computed by sizeof. */
+#cmakedefine SIZEOF_CURL_OFF_T ${SIZEOF_CURL_OFF_T}
+
/* The size of `size_t', as computed by sizeof. */
#cmakedefine SIZEOF_SIZE_T ${SIZEOF_SIZE_T}
@@ -1003,3 +1000,6 @@
/* the signed version of size_t */
#cmakedefine ssize_t ${ssize_t}
+
+/* Define to 1 if you have the mach_absolute_time function. */
+#cmakedefine HAVE_MACH_ABSOLUTE_TIME 1
diff --git a/lib/curl_config.h.in b/lib/curl_config.h.in
index a8edda5f..3a3368b9 100644
--- a/lib/curl_config.h.in
+++ b/lib/curl_config.h.in
@@ -9,6 +9,9 @@
/* Location of default ca path */
#undef CURL_CA_PATH
+/* Default SSL backend */
+#undef CURL_DEFAULT_SSL_BACKEND
+
/* to disable cookies support */
#undef CURL_DISABLE_COOKIES
@@ -72,6 +75,9 @@
/* Definition to make a library symbol externally visible. */
#undef CURL_EXTERN_SYMBOL
+/* built with multiple SSL backends */
+#undef CURL_WITH_MULTI_SSL
+
/* your Entropy Gathering Daemon socket pathname */
#undef EGD_SOCKET
@@ -126,6 +132,15 @@
/* Define to 1 if using BoringSSL. */
#undef HAVE_BORINGSSL
+/* if BROTLI is in use */
+#undef HAVE_BROTLI
+
+/* Define to 1 if you have the <brotli/decode.h> header file. */
+#undef HAVE_BROTLI_DECODE_H
+
+/* Define to 1 if you have the __builtin_available function. */
+#undef HAVE_BUILTIN_AVAILABLE
+
/* Define to 1 if you have the clock_gettime function and monotonic timer. */
#undef HAVE_CLOCK_GETTIME_MONOTONIC
@@ -383,6 +398,9 @@
/* Define to 1 if you have the `ldap_url_parse' function. */
#undef HAVE_LDAP_URL_PARSE
+/* Define to 1 if you have the `brotlidec' library (-lbrotlidec). */
+#undef HAVE_LIBBROTLIDEC
+
/* Define to 1 if you have the <libgen.h> header file. */
#undef HAVE_LIBGEN_H
@@ -410,6 +428,9 @@
/* Define to 1 if you have the <limits.h> header file. */
#undef HAVE_LIMITS_H
+/* Define to 1 if you have the <linux/tcp.h> header file. */
+#undef HAVE_LINUX_TCP_H
+
/* if your compiler supports LL */
#undef HAVE_LL
@@ -422,6 +443,9 @@
/* Define to 1 if the compiler supports the 'long long' data type. */
#undef HAVE_LONGLONG
+/* Define to 1 if you have the `mach_absolute_time' function. */
+#undef HAVE_MACH_ABSOLUTE_TIME
+
/* Define to 1 if you have the malloc.h header file. */
#undef HAVE_MALLOC_H
@@ -468,9 +492,6 @@
/* Define to 1 if you have the <openssl/pem.h> header file. */
#undef HAVE_OPENSSL_PEM_H
-/* Define to 1 if you have the <openssl/pkcs12.h> header file. */
-#undef HAVE_OPENSSL_PKCS12_H
-
/* Define to 1 if you have the <openssl/rsa.h> header file. */
#undef HAVE_OPENSSL_RSA_H
@@ -864,6 +885,9 @@
/* Define to the function return type for send. */
#undef SEND_TYPE_RETV
+/* The size of `curl_off_t', as computed by sizeof. */
+#undef SIZEOF_CURL_OFF_T
+
/* The size of `int', as computed by sizeof. */
#undef SIZEOF_INT
@@ -885,9 +909,6 @@
/* The size of `time_t', as computed by sizeof. */
#undef SIZEOF_TIME_T
-/* The size of `void*', as computed by sizeof. */
-#undef SIZEOF_VOIDP
-
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
diff --git a/lib/curl_fnmatch.c b/lib/curl_fnmatch.c
index 46d3ada1..8a1e106c 100644
--- a/lib/curl_fnmatch.c
+++ b/lib/curl_fnmatch.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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
@@ -133,6 +133,9 @@ static int setcharset(unsigned char **p, unsigned char *charset)
unsigned char c;
for(;;) {
c = **p;
+ if(!c)
+ return SETCHARSET_FAIL;
+
switch(state) {
case CURLFNM_SCHS_DEFAULT:
if(ISALNUM(c)) { /* ASCII value */
@@ -151,7 +154,7 @@ static int setcharset(unsigned char **p, unsigned char *charset)
(*p)++;
}
else if(c == '[') {
- char c2 = *((*p)+1);
+ char c2 = *((*p) + 1);
if(c2 == ':') { /* there has to be a keyword */
(*p) += 2;
if(parsekeyword(p, charset)) {
@@ -196,9 +199,6 @@ static int setcharset(unsigned char **p, unsigned char *charset)
else
return SETCHARSET_FAIL;
}
- else if(c == '\0') {
- return SETCHARSET_FAIL;
- }
else {
charset[c] = 1;
(*p)++;
@@ -235,15 +235,10 @@ static int setcharset(unsigned char **p, unsigned char *charset)
return SETCHARSET_FAIL;
break;
case CURLFNM_SCHS_MAYRANGE2:
- if(c == '\\') {
- c = *(++(*p));
- if(!ISPRINT(c))
- return SETCHARSET_FAIL;
- }
if(c == ']') {
return SETCHARSET_OK;
}
- if(c == '\\') {
+ else if(c == '\\') {
c = *(++(*p));
if(ISPRINT(c)) {
charset[c] = 1;
@@ -253,7 +248,7 @@ static int setcharset(unsigned char **p, unsigned char *charset)
else
return SETCHARSET_FAIL;
}
- if(c >= rangestart) {
+ else if(c >= rangestart) {
if((ISLOWER(c) && ISLOWER(rangestart)) ||
(ISDIGIT(c) && ISDIGIT(rangestart)) ||
(ISUPPER(c) && ISUPPER(rangestart))) {
@@ -267,6 +262,8 @@ static int setcharset(unsigned char **p, unsigned char *charset)
else
return SETCHARSET_FAIL;
}
+ else
+ return SETCHARSET_FAIL;
break;
case CURLFNM_SCHS_RIGHTBR:
if(c == '[') {
@@ -277,9 +274,6 @@ static int setcharset(unsigned char **p, unsigned char *charset)
else if(c == ']') {
return SETCHARSET_OK;
}
- else if(c == '\0') {
- return SETCHARSET_FAIL;
- }
else if(ISPRINT(c)) {
charset[c] = 1;
(*p)++;
@@ -319,9 +313,9 @@ static int loop(const unsigned char *pattern, const unsigned char *string)
switch(state) {
case CURLFNM_LOOP_DEFAULT:
if(*p == '*') {
- while(*(p+1) == '*') /* eliminate multiple stars */
+ while(*(p + 1) == '*') /* eliminate multiple stars */
p++;
- if(*s == '\0' && *(p+1) == '\0')
+ if(*s == '\0' && *(p + 1) == '\0')
return CURL_FNMATCH_MATCH;
rc = loop(p + 1, s); /* *.txt matches .txt <=> .txt matches .txt */
if(rc == CURL_FNMATCH_MATCH)
@@ -351,7 +345,7 @@ static int loop(const unsigned char *pattern, const unsigned char *string)
p++;
}
else if(*p == '[') {
- unsigned char *pp = p+1; /* cannot handle with pointer to register */
+ unsigned char *pp = p + 1; /* cannot handle with pointer to register */
if(setcharset(&pp, charset)) {
int found = FALSE;
if(charset[(unsigned int)*s])
@@ -381,7 +375,7 @@ static int loop(const unsigned char *pattern, const unsigned char *string)
found = !found;
if(found) {
- p = pp+1;
+ p = pp + 1;
s++;
memset(charset, 0, CURLFNM_CHSET_SIZE);
}
diff --git a/lib/curl_ntlm_core.c b/lib/curl_ntlm_core.c
index aea54529..e8962769 100644
--- a/lib/curl_ntlm_core.c
+++ b/lib/curl_ntlm_core.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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
@@ -31,6 +31,25 @@
* https://www.innovation.ch/java/ntlm.html
*/
+/* Please keep the SSL backend-specific #if branches in this order:
+
+ 1. USE_OPENSSL
+ 2. USE_GNUTLS_NETTLE
+ 3. USE_GNUTLS
+ 4. USE_NSS
+ 5. USE_MBEDTLS
+ 6. USE_DARWINSSL
+ 7. USE_OS400CRYPTO
+ 8. USE_WIN32_CRYPTO
+
+ This ensures that:
+ - the same SSL branch gets activated throughout this source
+ file even if multiple backends are enabled at the same time.
+ - OpenSSL and NSS have higher priority than Windows Crypt, due
+ to issues with the latter supporting NTLM2Session responses
+ in NTLM type-3 messages.
+ */
+
#if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO)
#ifdef USE_OPENSSL
@@ -76,14 +95,6 @@
# define MD5_DIGEST_LENGTH 16
# define MD4_DIGEST_LENGTH 16
-#elif defined(USE_MBEDTLS)
-
-# include <mbedtls/des.h>
-# include <mbedtls/md4.h>
-# if !defined(MBEDTLS_MD4_C)
-# include "curl_md4.h"
-# endif
-
#elif defined(USE_NSS)
# include <nss.h>
@@ -92,6 +103,14 @@
# include "curl_md4.h"
# define MD5_DIGEST_LENGTH MD5_LENGTH
+#elif defined(USE_MBEDTLS)
+
+# include <mbedtls/des.h>
+# include <mbedtls/md4.h>
+# if !defined(MBEDTLS_MD4_C)
+# include "curl_md4.h"
+# endif
+
#elif defined(USE_DARWINSSL)
# include <CommonCrypto/CommonCryptor.h>
@@ -196,26 +215,6 @@ static void setup_des_key(const unsigned char *key_56,
gcry_cipher_setkey(*des, key, sizeof(key));
}
-#elif defined(USE_MBEDTLS)
-
-static bool encrypt_des(const unsigned char *in, unsigned char *out,
- const unsigned char *key_56)
-{
- mbedtls_des_context ctx;
- char key[8];
-
- /* Expand the 56-bit key to 64-bits */
- extend_key_56_to_64(key_56, key);
-
- /* Set the key parity to odd */
- mbedtls_des_key_set_parity((unsigned char *) key);
-
- /* Perform the encryption */
- mbedtls_des_init(&ctx);
- mbedtls_des_setkey_enc(&ctx, (unsigned char *) key);
- return mbedtls_des_crypt_ecb(&ctx, in, out) == 0;
-}
-
#elif defined(USE_NSS)
/*
@@ -281,6 +280,26 @@ fail:
return rv;
}
+#elif defined(USE_MBEDTLS)
+
+static bool encrypt_des(const unsigned char *in, unsigned char *out,
+ const unsigned char *key_56)
+{
+ mbedtls_des_context ctx;
+ char key[8];
+
+ /* Expand the 56-bit key to 64-bits */
+ extend_key_56_to_64(key_56, key);
+
+ /* Set the key parity to odd */
+ mbedtls_des_key_set_parity((unsigned char *) key);
+
+ /* Perform the encryption */
+ mbedtls_des_init(&ctx);
+ mbedtls_des_setkey_enc(&ctx, (unsigned char *) key);
+ return mbedtls_des_crypt_ecb(&ctx, in, out) == 0;
+}
+
#elif defined(USE_DARWINSSL)
static bool encrypt_des(const unsigned char *in, unsigned char *out,
@@ -428,7 +447,7 @@ void Curl_ntlm_core_lm_resp(const unsigned char *keys,
setup_des_key(keys + 14, &des);
gcry_cipher_encrypt(des, results + 16, 8, plaintext, 8);
gcry_cipher_close(des);
-#elif defined(USE_MBEDTLS) || defined(USE_NSS) || defined(USE_DARWINSSL) \
+#elif defined(USE_NSS) || defined(USE_MBEDTLS) || defined(USE_DARWINSSL) \
|| defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO)
encrypt_des(plaintext, results, keys);
encrypt_des(plaintext, results + 8, keys + 7);
@@ -492,7 +511,7 @@ CURLcode Curl_ntlm_core_mk_lm_hash(struct Curl_easy *data,
setup_des_key(pw + 7, &des);
gcry_cipher_encrypt(des, lmbuffer + 8, 8, magic, 8);
gcry_cipher_close(des);
-#elif defined(USE_MBEDTLS) || defined(USE_NSS) || defined(USE_DARWINSSL) \
+#elif defined(USE_NSS) || defined(USE_MBEDTLS) || defined(USE_DARWINSSL) \
|| defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO)
encrypt_des(magic, lmbuffer, pw);
encrypt_des(magic, lmbuffer + 8, pw + 7);
@@ -538,7 +557,7 @@ CURLcode Curl_ntlm_core_mk_nt_hash(struct Curl_easy *data,
unsigned char *ntbuffer /* 21 bytes */)
{
size_t len = strlen(password);
- unsigned char *pw = malloc(len * 2);
+ unsigned char *pw = len ? malloc(len * 2) : strdup("");
CURLcode result;
if(!pw)
return CURLE_OUT_OF_MEMORY;
@@ -571,13 +590,18 @@ CURLcode Curl_ntlm_core_mk_nt_hash(struct Curl_easy *data,
gcry_md_write(MD4pw, pw, 2 * len);
memcpy(ntbuffer, gcry_md_read(MD4pw, 0), MD4_DIGEST_LENGTH);
gcry_md_close(MD4pw);
-#elif defined(USE_NSS) || defined(USE_OS400CRYPTO) || \
- (defined(USE_MBEDTLS) && !defined(MBEDTLS_MD4_C))
+#elif defined(USE_NSS)
Curl_md4it(ntbuffer, pw, 2 * len);
#elif defined(USE_MBEDTLS)
+#if defined(MBEDTLS_MD4_C)
mbedtls_md4(pw, 2 * len, ntbuffer);
+#else
+ Curl_md4it(ntbuffer, pw, 2 * len);
+#endif
#elif defined(USE_DARWINSSL)
(void)CC_MD4(pw, (CC_LONG)(2 * len), ntbuffer);
+#elif defined(USE_OS400CRYPTO)
+ Curl_md4it(ntbuffer, pw, 2 * len);
#elif defined(USE_WIN32_CRYPTO)
HCRYPTPROV hprov;
if(CryptAcquireContext(&hprov, NULL, NULL, PROV_RSA_FULL,
@@ -622,6 +646,15 @@ CURLcode Curl_hmac_md5(const unsigned char *key, unsigned int keylen,
return CURLE_OK;
}
+#ifndef SIZE_T_MAX
+/* some limits.h headers have this defined, some don't */
+#if defined(SIZEOF_SIZE_T) && (SIZEOF_SIZE_T > 4)
+#define SIZE_T_MAX 18446744073709551615U
+#else
+#define SIZE_T_MAX 4294967295U
+#endif
+#endif
+
/* This creates the NTLMv2 hash by using NTLM hash as the key and Unicode
* (uppercase UserName + Domain) as the data
*/
@@ -631,10 +664,20 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_hash(const char *user, size_t userlen,
unsigned char *ntlmv2hash)
{
/* Unicode representation */
- size_t identity_len = (userlen + domlen) * 2;
- unsigned char *identity = malloc(identity_len);
+ size_t identity_len;
+ unsigned char *identity;
CURLcode result = CURLE_OK;
+ /* we do the length checks below separately to avoid integer overflow risk
+ on extreme data lengths */
+ if((userlen > SIZE_T_MAX/2) ||
+ (domlen > SIZE_T_MAX/2) ||
+ ((userlen + domlen) > SIZE_T_MAX/2))
+ return CURLE_OUT_OF_MEMORY;
+
+ identity_len = (userlen + domlen) * 2;
+ identity = malloc(identity_len);
+
if(!identity)
return CURLE_OUT_OF_MEMORY;
@@ -780,7 +823,7 @@ CURLcode Curl_ntlm_core_mk_lmv2_resp(unsigned char *ntlmv2hash,
/* Concatenate the HMAC MD5 output with the client nonce */
memcpy(lmresp, hmac_output, 16);
- memcpy(lmresp+16, challenge_client, 8);
+ memcpy(lmresp + 16, challenge_client, 8);
return result;
}
diff --git a/lib/curl_ntlm_core.h b/lib/curl_ntlm_core.h
index 4a83d40b..07ef5dea 100644
--- a/lib/curl_ntlm_core.h
+++ b/lib/curl_ntlm_core.h
@@ -26,13 +26,19 @@
#if defined(USE_NTLM)
+/* If NSS is the first available SSL backend (see order in curl_ntlm_core.c)
+ then it must be initialized to be used by NTLM. */
+#if !defined(USE_OPENSSL) && \
+ !defined(USE_GNUTLS_NETTLE) && \
+ !defined(USE_GNUTLS) && \
+ defined(USE_NSS)
+#define NTLM_NEEDS_NSS_INIT
+#endif
+
#if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO)
#ifdef USE_OPENSSL
-# if !defined(OPENSSL_VERSION_NUMBER) && \
- !defined(HEADER_SSL_H) && !defined(HEADER_MD5_H)
-# error "curl_ntlm_core.h shall not be included before OpenSSL headers."
-# endif
+# include <openssl/ssl.h>
#endif
/* Define USE_NTRESPONSES in order to make the type-3 message include
diff --git a/lib/curl_ntlm_wb.c b/lib/curl_ntlm_wb.c
index 9e9586cc..03f47a3a 100644
--- a/lib/curl_ntlm_wb.c
+++ b/lib/curl_ntlm_wb.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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
@@ -48,6 +48,7 @@
#include "sendf.h"
#include "select.h"
#include "vauth/ntlm.h"
+#include "curl_ntlm_core.h"
#include "curl_ntlm_wb.h"
#include "url.h"
#include "strerror.h"
@@ -357,7 +358,7 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn,
/* not set means empty */
if(!userp)
- userp="";
+ userp = "";
switch(ntlm->state) {
case NTLMSTATE_TYPE1:
@@ -413,7 +414,7 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn,
/* connection is already authenticated,
* don't send a header in future requests */
free(*allocuserpwd);
- *allocuserpwd=NULL;
+ *allocuserpwd = NULL;
authp->done = TRUE;
break;
}
diff --git a/lib/curl_sasl.c b/lib/curl_sasl.c
index bd574b5e..550433d6 100644
--- a/lib/curl_sasl.c
+++ b/lib/curl_sasl.c
@@ -331,7 +331,8 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
sasl->authused = SASL_MECH_NTLM;
if(force_ir || data->set.sasl_ir)
- result = Curl_auth_create_ntlm_type1_message(conn->user, conn->passwd,
+ result = Curl_auth_create_ntlm_type1_message(data,
+ conn->user, conn->passwd,
&conn->ntlm, &resp, &len);
}
else
@@ -493,7 +494,8 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
#ifdef USE_NTLM
case SASL_NTLM:
/* Create the type-1 message */
- result = Curl_auth_create_ntlm_type1_message(conn->user, conn->passwd,
+ result = Curl_auth_create_ntlm_type1_message(data,
+ conn->user, conn->passwd,
&conn->ntlm, &resp, &len);
newstate = SASL_NTLM_TYPE2MSG;
break;
diff --git a/lib/curl_setup.h b/lib/curl_setup.h
index 4a3b85c4..25a7b4c5 100644
--- a/lib/curl_setup.h
+++ b/lib/curl_setup.h
@@ -141,14 +141,7 @@
#include <curl/curl.h>
-/*
- * Ensure that no one is using the old SIZEOF_CURL_OFF_T macro
- */
-
-#ifdef SIZEOF_CURL_OFF_T
-# error "SIZEOF_CURL_OFF_T shall not be defined!"
- Error Compilation_aborted_SIZEOF_CURL_OFF_T_shall_not_be_defined
-#endif
+#define CURL_SIZEOF_CURL_OFF_T SIZEOF_CURL_OFF_T
/*
* Disable other protocols when http is the only one desired.
@@ -185,9 +178,6 @@
# ifndef CURL_DISABLE_SMTP
# define CURL_DISABLE_SMTP
# endif
-# ifndef CURL_DISABLE_RTMP
-# define CURL_DISABLE_RTMP
-# endif
# ifndef CURL_DISABLE_GOPHER
# define CURL_DISABLE_GOPHER
# endif
@@ -727,6 +717,7 @@ Therefore we specify it explicitly. https://github.com/curl/curl/pull/258
#if defined(WIN32) || defined(MSDOS)
#define FOPEN_READTEXT "rt"
#define FOPEN_WRITETEXT "wt"
+#define FOPEN_APPENDTEXT "at"
#elif defined(__CYGWIN__)
/* Cygwin has specific behavior we need to address when WIN32 is not defined.
https://cygwin.com/cygwin-ug-net/using-textbinary.html
@@ -736,9 +727,11 @@ endings either CRLF or LF so 't' is appropriate.
*/
#define FOPEN_READTEXT "rt"
#define FOPEN_WRITETEXT "w"
+#define FOPEN_APPENDTEXT "a"
#else
#define FOPEN_READTEXT "r"
#define FOPEN_WRITETEXT "w"
+#define FOPEN_APPENDTEXT "a"
#endif
/* WinSock destroys recv() buffer when send() failed.
@@ -758,9 +751,10 @@ endings either CRLF or LF so 't' is appropriate.
/* Detect Windows App environment which has a restricted access
* to the Win32 APIs. */
-# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0602)
+# if (defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0602)) || \
+ defined(WINAPI_FAMILY)
# include <winapifamily.h>
-# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \
+# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \
!WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
# define CURL_WINDOWS_APP
# endif
diff --git a/lib/curl_sha256.h b/lib/curl_sha256.h
new file mode 100644
index 00000000..6db4b04d
--- /dev/null
+++ b/lib/curl_sha256.h
@@ -0,0 +1,32 @@
+#ifndef HEADER_CURL_SHA256_H
+#define HEADER_CURL_SHA256_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, Florin Petriuc, <petriuc.florin@gmail.com>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+
+void Curl_sha256it(unsigned char *outbuffer,
+ const unsigned char *input);
+
+#endif
+
+#endif /* HEADER_CURL_SHA256_H */
diff --git a/lib/curlx.h b/lib/curlx.h
index 6168dc11..6e418266 100644
--- a/lib/curlx.h
+++ b/lib/curlx.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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
@@ -42,16 +42,6 @@
curl_off_t number from a given string.
*/
-#include "timeval.h"
-/*
- "timeval.h" sets up a 'struct timeval' even for platforms that otherwise
- don't have one and has protos for these functions:
-
- curlx_tvnow()
- curlx_tvdiff()
- curlx_tvdiff_secs()
-*/
-
#include "nonblock.h"
/* "nonblock.h" provides curlx_nonblock() */
diff --git a/lib/dict.c b/lib/dict.c
index 81d89fc4..4fc85521 100644
--- a/lib/dict.c
+++ b/lib/dict.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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
@@ -98,7 +98,7 @@ static char *unescape_word(struct Curl_easy *data, const char *inputbuff)
char *ptr;
size_t len;
char ch;
- int olen=0;
+ int olen = 0;
CURLcode result = Curl_urldecode(data, inputbuff, 0, &newp, &len, FALSE);
if(!newp || result)
@@ -117,7 +117,7 @@ static char *unescape_word(struct Curl_easy *data, const char *inputbuff)
}
dictp[olen++] = ch;
}
- dictp[olen]=0;
+ dictp[olen] = 0;
}
free(newp);
return dictp;
@@ -132,8 +132,8 @@ static CURLcode dict_do(struct connectdata *conn, bool *done)
char *strategy = NULL;
char *nthdef = NULL; /* This is not part of the protocol, but required
by RFC 2229 */
- CURLcode result=CURLE_OK;
- struct Curl_easy *data=conn->data;
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
char *path = data->state.path;
@@ -168,7 +168,7 @@ static CURLcode dict_do(struct connectdata *conn, bool *done)
if((word == NULL) || (*word == (char)0)) {
infof(data, "lookup word is missing\n");
- word=(char *)"default";
+ word = (char *)"default";
}
if((database == NULL) || (*database == (char)0)) {
database = (char *)"!";
@@ -222,7 +222,7 @@ static CURLcode dict_do(struct connectdata *conn, bool *done)
if((word == NULL) || (*word == (char)0)) {
infof(data, "lookup word is missing\n");
- word=(char *)"default";
+ word = (char *)"default";
}
if((database == NULL) || (*database == (char)0)) {
database = (char *)"!";
diff --git a/lib/dotdot.c b/lib/dotdot.c
index 20603bca..cbb308d7 100644
--- a/lib/dotdot.c
+++ b/lib/dotdot.c
@@ -55,7 +55,7 @@ char *Curl_dedotdotify(const char *input)
size_t inlen = strlen(input);
char *clone;
size_t clen = inlen; /* the length of the cloned input */
- char *out = malloc(inlen+1);
+ char *out = malloc(inlen + 1);
char *outptr;
char *orgclone;
char *queryp;
@@ -92,25 +92,25 @@ char *Curl_dedotdotify(const char *input)
remove that prefix from the input buffer; otherwise, */
if(!strncmp("./", clone, 2)) {
- clone+=2;
- clen-=2;
+ clone += 2;
+ clen -= 2;
}
else if(!strncmp("../", clone, 3)) {
- clone+=3;
- clen-=3;
+ clone += 3;
+ clen -= 3;
}
/* B. if the input buffer begins with a prefix of "/./" or "/.", where
"." is a complete path segment, then replace that prefix with "/" in
the input buffer; otherwise, */
else if(!strncmp("/./", clone, 3)) {
- clone+=2;
- clen-=2;
+ clone += 2;
+ clen -= 2;
}
else if(!strcmp("/.", clone)) {
clone[1]='/';
clone++;
- clen-=1;
+ clen -= 1;
}
/* C. if the input buffer begins with a prefix of "/../" or "/..", where
@@ -119,8 +119,8 @@ char *Curl_dedotdotify(const char *input)
any) from the output buffer; otherwise, */
else if(!strncmp("/../", clone, 4)) {
- clone+=3;
- clen-=3;
+ clone += 3;
+ clen -= 3;
/* remove the last segment from the output buffer */
while(outptr > out) {
outptr--;
@@ -131,8 +131,8 @@ char *Curl_dedotdotify(const char *input)
}
else if(!strcmp("/..", clone)) {
clone[2]='/';
- clone+=2;
- clen-=2;
+ clone += 2;
+ clen -= 2;
/* remove the last segment from the output buffer */
while(outptr > out) {
outptr--;
@@ -146,8 +146,8 @@ char *Curl_dedotdotify(const char *input)
that from the input buffer; otherwise, */
else if(!strcmp(".", clone) || !strcmp("..", clone)) {
- *clone=0;
- *out=0;
+ *clone = 0;
+ *out = 0;
}
else {
@@ -172,7 +172,7 @@ char *Curl_dedotdotify(const char *input)
from the correct index. */
size_t oindex = queryp - orgclone;
qlen = strlen(&input[oindex]);
- memcpy(outptr, &input[oindex], qlen+1); /* include the ending zero byte */
+ memcpy(outptr, &input[oindex], qlen + 1); /* include the end zero byte */
}
free(orgclone);
diff --git a/lib/easy.c b/lib/easy.c
index 66ec38a5..5917db36 100644
--- a/lib/easy.c
+++ b/lib/easy.c
@@ -68,10 +68,11 @@
#include "amigaos.h"
#include "non-ascii.h"
#include "warnless.h"
-#include "conncache.h"
#include "multiif.h"
#include "sigpipe.h"
#include "ssh.h"
+#include "setopt.h"
+
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
@@ -214,11 +215,10 @@ static CURLcode global_init(long flags, bool memoryfuncs)
#endif
}
- if(flags & CURL_GLOBAL_SSL)
- if(!Curl_ssl_init()) {
- DEBUGF(fprintf(stderr, "Error: Curl_ssl_init failed\n"));
- return CURLE_FAILED_INIT;
- }
+ if(!Curl_ssl_init()) {
+ DEBUGF(fprintf(stderr, "Error: Curl_ssl_init failed\n"));
+ return CURLE_FAILED_INIT;
+ }
if(flags & CURL_GLOBAL_WIN32)
if(win32_init()) {
@@ -318,10 +318,7 @@ void curl_global_cleanup(void)
return;
Curl_global_host_cache_dtor();
-
- if(init_flags & CURL_GLOBAL_SSL)
- Curl_ssl_cleanup();
-
+ Curl_ssl_cleanup();
Curl_resolver_global_cleanup();
if(init_flags & CURL_GLOBAL_WIN32)
@@ -365,28 +362,6 @@ struct Curl_easy *curl_easy_init(void)
return data;
}
-/*
- * curl_easy_setopt() is the external interface for setting options on an
- * easy handle.
- */
-
-#undef curl_easy_setopt
-CURLcode curl_easy_setopt(struct Curl_easy *data, CURLoption tag, ...)
-{
- va_list arg;
- CURLcode result;
-
- if(!data)
- return CURLE_BAD_FUNCTION_ARGUMENT;
-
- va_start(arg, tag);
-
- result = Curl_setopt(data, tag, arg);
-
- va_end(arg);
- return result;
-}
-
#ifdef CURLDEBUG
struct socketmonitor {
@@ -433,7 +408,7 @@ static int events_timer(struct Curl_multi *multi, /* multi handle */
*/
static int poll2cselect(int pollmask)
{
- int omask=0;
+ int omask = 0;
if(pollmask & POLLIN)
omask |= CURL_CSELECT_IN;
if(pollmask & POLLOUT)
@@ -450,7 +425,7 @@ static int poll2cselect(int pollmask)
*/
static short socketcb2poll(int pollmask)
{
- short omask=0;
+ short omask = 0;
if(pollmask & CURL_POLL_IN)
omask |= POLLIN;
if(pollmask & CURL_POLL_OUT)
@@ -473,7 +448,7 @@ static int events_socket(struct Curl_easy *easy, /* easy handle */
{
struct events *ev = userp;
struct socketmonitor *m;
- struct socketmonitor *prev=NULL;
+ struct socketmonitor *prev = NULL;
#if defined(CURL_DISABLE_VERBOSE_STRINGS)
(void) easy;
@@ -569,14 +544,14 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
struct socketmonitor *m;
struct pollfd *f;
struct pollfd fds[4];
- int numfds=0;
+ int numfds = 0;
int pollrc;
int i;
struct curltime before;
struct curltime after;
/* populate the fds[] array */
- for(m = ev->list, f=&fds[0]; m; m = m->next) {
+ for(m = ev->list, f = &fds[0]; m; m = m->next) {
f->fd = m->socket.fd;
f->events = m->socket.events;
f->revents = 0;
@@ -586,12 +561,12 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
}
/* get the time stamp to use to figure out how long poll takes */
- before = curlx_tvnow();
+ before = Curl_now();
/* wait for activity or timeout */
pollrc = Curl_poll(fds, numfds, (int)ev->ms);
- after = curlx_tvnow();
+ after = Curl_now();
ev->msbump = FALSE; /* reset here */
@@ -619,7 +594,7 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
/* If nothing updated the timeout, we decrease it by the spent time.
* If it was updated, it has the new timeout time stored already.
*/
- time_t timediff = curlx_tvdiff(after, before);
+ timediff_t timediff = Curl_timediff(after, before);
if(timediff > 0) {
if(timediff > ev->ms)
ev->ms = 0;
@@ -655,7 +630,7 @@ static CURLcode easy_events(struct Curl_multi *multi)
{
/* this struct is made static to allow it to be used after this function
returns and curl_multi_remove_handle() is called */
- static struct events evs= {2, FALSE, 0, NULL, 0};
+ static struct events evs = {2, FALSE, 0, NULL, 0};
/* if running event-based, do some further multi inits */
events_setup(multi, &evs);
@@ -680,17 +655,17 @@ static CURLcode easy_transfer(struct Curl_multi *multi)
int still_running = 0;
int rc;
- before = curlx_tvnow();
+ before = Curl_now();
mcode = curl_multi_wait(multi, NULL, 0, 1000, &rc);
if(!mcode) {
if(!rc) {
- struct curltime after = curlx_tvnow();
+ struct curltime after = Curl_now();
/* If it returns without any filedescriptor instantly, we need to
avoid busy-looping during periods where it has nothing particular
to wait for */
- if(curlx_tvdiff(after, before) <= 10) {
+ if(Curl_timediff(after, before) <= 10) {
without_fds++;
if(without_fds > 2) {
int sleep_ms = without_fds < 10 ? (1 << (without_fds - 1)) : 1000;
@@ -861,6 +836,40 @@ CURLcode curl_easy_getinfo(struct Curl_easy *data, CURLINFO info, ...)
return result;
}
+static CURLcode dupset(struct Curl_easy *dst, struct Curl_easy *src)
+{
+ CURLcode result = CURLE_OK;
+ enum dupstring i;
+
+ /* Copy src->set into dst->set first, then deal with the strings
+ afterwards */
+ dst->set = src->set;
+
+ /* clear all string pointers first */
+ memset(dst->set.str, 0, STRING_LAST * sizeof(char *));
+
+ /* duplicate all strings */
+ for(i = (enum dupstring)0; i< STRING_LASTZEROTERMINATED; i++) {
+ result = Curl_setstropt(&dst->set.str[i], src->set.str[i]);
+ if(result)
+ return result;
+ }
+
+ /* duplicate memory areas pointed to */
+ i = STRING_COPYPOSTFIELDS;
+ if(src->set.postfieldsize && src->set.str[i]) {
+ /* postfieldsize is curl_off_t, Curl_memdup() takes a size_t ... */
+ dst->set.str[i] = Curl_memdup(src->set.str[i],
+ curlx_sotouz(src->set.postfieldsize));
+ if(!dst->set.str[i])
+ return CURLE_OUT_OF_MEMORY;
+ /* point to the new copy */
+ dst->set.postfields = dst->set.str[i];
+ }
+
+ return CURLE_OK;
+}
+
/*
* curl_easy_duphandle() is an external interface to allow duplication of a
* given input easy handle. The returned handle will be a new working handle
@@ -888,7 +897,7 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
outcurl->state.headersize = HEADERSIZE;
/* copy all userdefined values */
- if(Curl_dupset(outcurl, data))
+ if(dupset(outcurl, data))
goto fail;
/* the connection cache is setup on demand */
@@ -1027,13 +1036,13 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action)
struct tempbuf writebuf[3]; /* there can only be three */
/* copy the structs to allow for immediate re-pausing */
- for(i=0; i < data->state.tempcount; i++) {
+ for(i = 0; i < data->state.tempcount; i++) {
writebuf[i] = data->state.tempwrite[i];
data->state.tempwrite[i].buf = NULL;
}
data->state.tempcount = 0;
- for(i=0; i < count; i++) {
+ for(i = 0; i < count; i++) {
/* even if one function returns error, this loops through and frees all
buffers */
if(!result)
diff --git a/lib/escape.c b/lib/escape.c
index 973aeb6e..b7e2d32a 100644
--- a/lib/escape.c
+++ b/lib/escape.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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
@@ -84,14 +84,14 @@ char *curl_easy_escape(struct Curl_easy *data, const char *string,
char *testing_ptr = NULL;
unsigned char in; /* we need to treat the characters unsigned */
size_t newlen;
- size_t strindex=0;
+ size_t strindex = 0;
size_t length;
CURLcode result;
if(inlength < 0)
return NULL;
- alloc = (inlength?(size_t)inlength:strlen(string))+1;
+ alloc = (inlength?(size_t)inlength:strlen(string)) + 1;
newlen = alloc;
ns = malloc(alloc);
@@ -104,7 +104,7 @@ char *curl_easy_escape(struct Curl_easy *data, const char *string,
if(Curl_isunreserved(in))
/* just copy this */
- ns[strindex++]=in;
+ ns[strindex++] = in;
else {
/* encode it */
newlen += 2; /* the size grows with two, since this'll become a %XX */
@@ -116,7 +116,7 @@ char *curl_easy_escape(struct Curl_easy *data, const char *string,
ns = testing_ptr;
}
- result = Curl_convert_to_network(data, &in, 1);
+ result = Curl_convert_to_network(data, (char *)&in, 1);
if(result) {
/* Curl_convert_to_network calls failf if unsuccessful */
free(ns);
@@ -125,11 +125,11 @@ char *curl_easy_escape(struct Curl_easy *data, const char *string,
snprintf(&ns[strindex], 4, "%%%02X", in);
- strindex+=3;
+ strindex += 3;
}
string++;
}
- ns[strindex]=0; /* terminate it */
+ ns[strindex] = 0; /* terminate it */
return ns;
}
@@ -148,10 +148,10 @@ CURLcode Curl_urldecode(struct Curl_easy *data,
char **ostring, size_t *olen,
bool reject_ctrl)
{
- size_t alloc = (length?length:strlen(string))+1;
+ size_t alloc = (length?length:strlen(string)) + 1;
char *ns = malloc(alloc);
unsigned char in;
- size_t strindex=0;
+ size_t strindex = 0;
unsigned long hex;
CURLcode result;
@@ -173,15 +173,15 @@ CURLcode Curl_urldecode(struct Curl_easy *data,
in = curlx_ultouc(hex); /* this long is never bigger than 255 anyway */
- result = Curl_convert_from_network(data, &in, 1);
+ result = Curl_convert_from_network(data, (char *)&in, 1);
if(result) {
/* Curl_convert_from_network calls failf if unsuccessful */
free(ns);
return result;
}
- string+=2;
- alloc-=2;
+ string += 2;
+ alloc -= 2;
}
if(reject_ctrl && (in < 0x20)) {
@@ -192,7 +192,7 @@ CURLcode Curl_urldecode(struct Curl_easy *data,
ns[strindex++] = in;
string++;
}
- ns[strindex]=0; /* terminate it */
+ ns[strindex] = 0; /* terminate it */
if(olen)
/* store output size */
diff --git a/lib/file.c b/lib/file.c
index 666cbe75..0bbc0e18 100644
--- a/lib/file.c
+++ b/lib/file.c
@@ -133,37 +133,42 @@ static CURLcode file_setup_connection(struct connectdata *conn)
static CURLcode file_range(struct connectdata *conn)
{
curl_off_t from, to;
- curl_off_t totalsize=-1;
+ curl_off_t totalsize = -1;
char *ptr;
char *ptr2;
struct Curl_easy *data = conn->data;
if(data->state.use_range && data->state.range) {
- from=curlx_strtoofft(data->state.range, &ptr, 0);
- while(*ptr && (ISSPACE(*ptr) || (*ptr=='-')))
+ CURLofft from_t;
+ CURLofft to_t;
+ from_t = curlx_strtoofft(data->state.range, &ptr, 0, &from);
+ if(from_t == CURL_OFFT_FLOW)
+ return CURLE_RANGE_ERROR;
+ while(*ptr && (ISSPACE(*ptr) || (*ptr == '-')))
ptr++;
- to=curlx_strtoofft(ptr, &ptr2, 0);
- if(ptr == ptr2) {
- /* we didn't get any digit */
- to=-1;
- }
- if((-1 == to) && (from>=0)) {
+ to_t = curlx_strtoofft(ptr, &ptr2, 0, &to);
+ if(to_t == CURL_OFFT_FLOW)
+ return CURLE_RANGE_ERROR;
+ if((to_t == CURL_OFFT_INVAL) && !from_t) {
/* X - */
data->state.resume_from = from;
DEBUGF(infof(data, "RANGE %" CURL_FORMAT_CURL_OFF_T " to end of file\n",
from));
}
- else if(from < 0) {
+ else if((from_t == CURL_OFFT_INVAL) && !to_t) {
/* -Y */
- data->req.maxdownload = -from;
- data->state.resume_from = from;
+ data->req.maxdownload = to;
+ data->state.resume_from = -to;
DEBUGF(infof(data, "RANGE the last %" CURL_FORMAT_CURL_OFF_T " bytes\n",
- -from));
+ to));
}
else {
/* X-Y */
totalsize = to-from;
- data->req.maxdownload = totalsize+1; /* include last byte */
+ if(totalsize == CURL_OFF_T_MAX)
+ /* this is too big to increase, so bail out */
+ return CURLE_RANGE_ERROR;
+ data->req.maxdownload = totalsize + 1; /* include last byte */
data->state.resume_from = from;
DEBUGF(infof(data, "RANGE from %" CURL_FORMAT_CURL_OFF_T
" getting %" CURL_FORMAT_CURL_OFF_T " bytes\n",
@@ -226,7 +231,7 @@ static CURLcode file_connect(struct connectdata *conn, bool *done)
}
/* change path separators from '/' to '\\' for DOS, Windows and OS/2 */
- for(i=0; i < real_path_len; ++i)
+ for(i = 0; i < real_path_len; ++i)
if(actual_path[i] == '/')
actual_path[i] = '\\';
else if(!actual_path[i]) { /* binary zero */
@@ -399,7 +404,7 @@ static CURLcode file_upload(struct connectdata *conn)
if(Curl_pgrsUpdate(conn))
result = CURLE_ABORTED_BY_CALLBACK;
else
- result = Curl_speedcheck(data, Curl_tvnow());
+ result = Curl_speedcheck(data, Curl_now());
}
if(!result && Curl_pgrsUpdate(conn))
result = CURLE_ABORTED_BY_CALLBACK;
@@ -428,9 +433,9 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
struct_stat statbuf; /* struct_stat instead of struct stat just to allow the
Windows version to have a different struct without
having to redefine the simple word 'stat' */
- curl_off_t expected_size=0;
+ curl_off_t expected_size = 0;
bool size_known;
- bool fstated=FALSE;
+ bool fstated = FALSE;
ssize_t nread;
struct Curl_easy *data = conn->data;
char *buf = data->state.buffer;
@@ -584,7 +589,7 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
if(Curl_pgrsUpdate(conn))
result = CURLE_ABORTED_BY_CALLBACK;
else
- result = Curl_speedcheck(data, Curl_tvnow());
+ result = Curl_speedcheck(data, Curl_now());
}
if(Curl_pgrsUpdate(conn))
result = CURLE_ABORTED_BY_CALLBACK;
diff --git a/lib/formdata.c b/lib/formdata.c
index e48a6276..d0579c52 100644
--- a/lib/formdata.c
+++ b/lib/formdata.c
@@ -32,6 +32,8 @@
#include "urldata.h" /* for struct Curl_easy */
#include "formdata.h"
+#include "mime.h"
+#include "non-ascii.h"
#include "vtls/vtls.h"
#include "strcase.h"
#include "sendf.h"
@@ -42,13 +44,6 @@
#include "curl_memory.h"
#include "memdebug.h"
-#ifndef HAVE_BASENAME
-static char *Curl_basename(char *path);
-#define basename(x) Curl_basename((x))
-#endif
-
-static size_t readfromfile(struct Form *form, char *buffer, size_t size);
-static CURLcode formboundary(struct Curl_easy *data, char *buffer, size_t len);
/* What kind of Content-Type to use on un-specified files with unrecognized
extensions. */
@@ -197,7 +192,7 @@ static const char *ContentTypeForFilename(const char *filename,
contenttype = HTTPPOST_CONTENTTYPE_DEFAULT;
if(filename) { /* in case a NULL was passed in */
- for(i=0; i<sizeof(ctts)/sizeof(ctts[0]); i++) {
+ for(i = 0; i<sizeof(ctts)/sizeof(ctts[0]); i++) {
if(strlen(filename) >= strlen(ctts[i].extension)) {
if(strcasecompare(filename +
strlen(filename) - strlen(ctts[i].extension),
@@ -272,7 +267,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
struct curl_httppost *post = NULL;
CURLformoption option;
struct curl_forms *forms = NULL;
- char *array_value=NULL; /* value read from an array */
+ char *array_value = NULL; /* value read from an array */
/* This is a state variable, that if TRUE means that we're parsing an
array that we got passed to us. If FALSE we're parsing the input
@@ -641,15 +636,26 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
}
form->contenttype_alloc = TRUE;
}
+ if(form->name && form->namelength) {
+ /* Name should not contain nul bytes. */
+ size_t i;
+ for(i = 0; i < form->namelength; i++)
+ if(!form->name[i]) {
+ return_value = CURL_FORMADD_NULL;
+ break;
+ }
+ if(return_value != CURL_FORMADD_OK)
+ break;
+ }
if(!(form->flags & HTTPPOST_PTRNAME) &&
(form == first_form) ) {
/* Note that there's small risk that form->name is NULL here if the
app passed in a bad combo, so we better check for that first. */
if(form->name) {
- /* copy name (without strdup; possibly contains null characters) */
+ /* copy name (without strdup; possibly not nul-terminated) */
form->name = Curl_memdup(form->name, form->namelength?
form->namelength:
- strlen(form->name)+1);
+ strlen(form->name) + 1);
}
if(!form->name) {
return_value = CURL_FORMADD_MEMORY;
@@ -663,7 +669,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
/* copy value (without strdup; possibly contains null characters) */
size_t clen = (size_t) form->contentslength;
if(!clen)
- clen = strlen(form->value)+1;
+ clen = strlen(form->value) + 1;
form->value = Curl_memdup(form->value, clen);
@@ -746,211 +752,6 @@ CURLFORMcode curl_formadd(struct curl_httppost **httppost,
return result;
}
-#ifdef __VMS
-#include <fabdef.h>
-/*
- * get_vms_file_size does what it takes to get the real size of the file
- *
- * For fixed files, find out the size of the EOF block and adjust.
- *
- * For all others, have to read the entire file in, discarding the contents.
- * Most posted text files will be small, and binary files like zlib archives
- * and CD/DVD images should be either a STREAM_LF format or a fixed format.
- *
- */
-curl_off_t VmsRealFileSize(const char *name,
- const struct_stat *stat_buf)
-{
- char buffer[8192];
- curl_off_t count;
- int ret_stat;
- FILE * file;
-
- file = fopen(name, FOPEN_READTEXT); /* VMS */
- if(file == NULL)
- return 0;
-
- count = 0;
- ret_stat = 1;
- while(ret_stat > 0) {
- ret_stat = fread(buffer, 1, sizeof(buffer), file);
- if(ret_stat != 0)
- count += ret_stat;
- }
- fclose(file);
-
- return count;
-}
-
-/*
- *
- * VmsSpecialSize checks to see if the stat st_size can be trusted and
- * if not to call a routine to get the correct size.
- *
- */
-static curl_off_t VmsSpecialSize(const char *name,
- const struct_stat *stat_buf)
-{
- switch(stat_buf->st_fab_rfm) {
- case FAB$C_VAR:
- case FAB$C_VFC:
- return VmsRealFileSize(name, stat_buf);
- break;
- default:
- return stat_buf->st_size;
- }
-}
-
-#endif
-
-#ifndef __VMS
-#define filesize(name, stat_data) (stat_data.st_size)
-#else
- /* Getting the expected file size needs help on VMS */
-#define filesize(name, stat_data) VmsSpecialSize(name, &stat_data)
-#endif
-
-/*
- * AddFormData() adds a chunk of data to the FormData linked list.
- *
- * size is incremented by the chunk length, unless it is NULL
- */
-static CURLcode AddFormData(struct FormData **formp,
- enum formtype type,
- const void *line,
- curl_off_t length,
- curl_off_t *size)
-{
- struct FormData *newform;
- char *alloc2 = NULL;
- CURLcode result = CURLE_OK;
- if(length < 0 || (size && *size < 0))
- return CURLE_BAD_FUNCTION_ARGUMENT;
-
- newform = malloc(sizeof(struct FormData));
- if(!newform)
- return CURLE_OUT_OF_MEMORY;
- newform->next = NULL;
-
- if(type <= FORM_CONTENT) {
- /* we make it easier for plain strings: */
- if(!length)
- length = strlen((char *)line);
-#if (SIZEOF_SIZE_T < CURL_SIZEOF_CURL_OFF_T)
- else if(length >= (curl_off_t)(size_t)-1) {
- result = CURLE_BAD_FUNCTION_ARGUMENT;
- goto error;
- }
-#endif
- if(type != FORM_DATAMEM) {
- newform->line = malloc((size_t)length+1);
- if(!newform->line) {
- result = CURLE_OUT_OF_MEMORY;
- goto error;
- }
- alloc2 = newform->line;
- memcpy(newform->line, line, (size_t)length);
-
- /* zero terminate for easier debugging */
- newform->line[(size_t)length]=0;
- }
- else {
- newform->line = (char *)line;
- type = FORM_DATA; /* in all other aspects this is just FORM_DATA */
- }
- newform->length = (size_t)length;
- }
- else
- /* For callbacks and files we don't have any actual data so we just keep a
- pointer to whatever this points to */
- newform->line = (char *)line;
-
- newform->type = type;
-
- if(size) {
- if(type != FORM_FILE)
- /* for static content as well as callback data we add the size given
- as input argument */
- *size += length;
- else {
- /* Since this is a file to be uploaded here, add the size of the actual
- file */
- if(strcmp("-", newform->line)) {
- struct_stat file;
- if(!stat(newform->line, &file) && !S_ISDIR(file.st_mode))
- *size += filesize(newform->line, file);
- else {
- result = CURLE_BAD_FUNCTION_ARGUMENT;
- goto error;
- }
- }
- }
- }
-
- if(*formp) {
- (*formp)->next = newform;
- *formp = newform;
- }
- else
- *formp = newform;
-
- return CURLE_OK;
- error:
- if(newform)
- free(newform);
- if(alloc2)
- free(alloc2);
- return result;
-}
-
-/*
- * AddFormDataf() adds printf()-style formatted data to the formdata chain.
- */
-
-static CURLcode AddFormDataf(struct FormData **formp,
- curl_off_t *size,
- const char *fmt, ...)
-{
- char *s;
- CURLcode result;
- va_list ap;
- va_start(ap, fmt);
- s = curl_mvaprintf(fmt, ap);
- va_end(ap);
-
- if(!s)
- return CURLE_OUT_OF_MEMORY;
-
- result = AddFormData(formp, FORM_DATAMEM, s, 0, size);
- if(result)
- free(s);
-
- return result;
-}
-
-/*
- * Curl_formclean() is used from http.c, this cleans a built FormData linked
- * list
- */
-void Curl_formclean(struct FormData **form_ptr)
-{
- struct FormData *next, *form;
-
- form = *form_ptr;
- if(!form)
- return;
-
- do {
- next=form->next; /* the following form line */
- if(form->type <= FORM_CONTENT)
- free(form->line); /* free the line */
- free(form); /* free the struct */
- form = next;
- } while(form); /* continue */
-
- *form_ptr = NULL;
-}
-
/*
* curl_formget()
* Serialize a curl_httppost struct.
@@ -962,42 +763,34 @@ int curl_formget(struct curl_httppost *form, void *arg,
curl_formget_callback append)
{
CURLcode result;
- curl_off_t size;
- struct FormData *data, *ptr;
+ curl_mimepart toppart;
- result = Curl_getformdata(NULL, &data, form, NULL, &size);
- if(result)
- return (int)result;
-
- for(ptr = data; ptr; ptr = ptr->next) {
- if((ptr->type == FORM_FILE) || (ptr->type == FORM_CALLBACK)) {
- char buffer[8192];
- size_t nread;
- struct Form temp;
-
- Curl_FormInit(&temp, ptr);
-
- do {
- nread = readfromfile(&temp, buffer, sizeof(buffer));
- if((nread == (size_t) -1) ||
- (nread > sizeof(buffer)) ||
- (nread != append(arg, buffer, nread))) {
- if(temp.fp)
- fclose(temp.fp);
- Curl_formclean(&data);
- return -1;
- }
- } while(nread);
- }
- else {
- if(ptr->length != append(arg, ptr->line, ptr->length)) {
- Curl_formclean(&data);
- return -1;
- }
+ Curl_mime_initpart(&toppart, NULL); /* default form is empty */
+ result = Curl_getformdata(NULL, &toppart, form, NULL);
+ if(!result)
+ result = Curl_mime_prepare_headers(&toppart, "multipart/form-data",
+ NULL, MIMESTRATEGY_FORM);
+
+ while(!result) {
+ char buffer[8192];
+ size_t nread = Curl_mime_read(buffer, 1, sizeof buffer, &toppart);
+
+ if(!nread)
+ break;
+
+ switch(nread) {
+ default:
+ if(append(arg, buffer, nread) != nread)
+ result = CURLE_READ_ERROR;
+ break;
+ case CURL_READFUNC_ABORT:
+ case CURL_READFUNC_PAUSE:
+ break;
}
}
- Curl_formclean(&data);
- return 0;
+
+ Curl_mime_cleanpart(&toppart);
+ return (int) result;
}
/*
@@ -1013,7 +806,7 @@ void curl_formfree(struct curl_httppost *form)
return;
do {
- next=form->next; /* the following form line */
+ next = form->next; /* the following form line */
/* recurse to sub-contents */
curl_formfree(form->more);
@@ -1031,118 +824,29 @@ void curl_formfree(struct curl_httppost *form)
} while(form); /* continue */
}
-#ifndef HAVE_BASENAME
-/*
- (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004
- Edition)
-
- The basename() function shall take the pathname pointed to by path and
- return a pointer to the final component of the pathname, deleting any
- trailing '/' characters.
-
- If the string pointed to by path consists entirely of the '/' character,
- basename() shall return a pointer to the string "/". If the string pointed
- to by path is exactly "//", it is implementation-defined whether '/' or "//"
- is returned.
- If path is a null pointer or points to an empty string, basename() shall
- return a pointer to the string ".".
-
- The basename() function may modify the string pointed to by path, and may
- return a pointer to static storage that may then be overwritten by a
- subsequent call to basename().
-
- The basename() function need not be reentrant. A function that is not
- required to be reentrant is not required to be thread-safe.
-
-*/
-static char *Curl_basename(char *path)
+/* Set mime part name, taking care of non nul-terminated name string. */
+static CURLcode setname(curl_mimepart *part, const char *name, size_t len)
{
- /* Ignore all the details above for now and make a quick and simple
- implementaion here */
- char *s1;
- char *s2;
-
- s1=strrchr(path, '/');
- s2=strrchr(path, '\\');
+ char *zname;
+ CURLcode res;
- if(s1 && s2) {
- path = (s1 > s2? s1 : s2)+1;
- }
- else if(s1)
- path = s1 + 1;
- else if(s2)
- path = s2 + 1;
-
- return path;
-}
-#endif
-
-static char *strippath(const char *fullfile)
-{
- char *filename;
- char *base;
- filename = strdup(fullfile); /* duplicate since basename() may ruin the
- buffer it works on */
- if(!filename)
- return NULL;
- base = strdup(basename(filename));
-
- free(filename); /* free temporary buffer */
-
- return base; /* returns an allocated string or NULL ! */
-}
-
-static CURLcode formdata_add_filename(const struct curl_httppost *file,
- struct FormData **form,
- curl_off_t *size)
-{
- CURLcode result = CURLE_OK;
- char *filename = file->showfilename;
- char *filebasename = NULL;
- char *filename_escaped = NULL;
-
- if(!filename) {
- filebasename = strippath(file->contents);
- if(!filebasename)
- return CURLE_OUT_OF_MEMORY;
- filename = filebasename;
- }
-
- if(strchr(filename, '\\') || strchr(filename, '"')) {
- char *p0, *p1;
-
- /* filename need be escaped */
- filename_escaped = malloc(strlen(filename)*2+1);
- if(!filename_escaped) {
- free(filebasename);
- return CURLE_OUT_OF_MEMORY;
- }
- p0 = filename_escaped;
- p1 = filename;
- while(*p1) {
- if(*p1 == '\\' || *p1 == '"')
- *p0++ = '\\';
- *p0++ = *p1++;
- }
- *p0 = '\0';
- filename = filename_escaped;
- }
- result = AddFormDataf(form, size,
- "; filename=\"%s\"",
- filename);
- free(filename_escaped);
- free(filebasename);
- return result;
+ if(!name || !len)
+ return curl_mime_name(part, name);
+ zname = malloc(len + 1);
+ if(!zname)
+ return CURLE_OUT_OF_MEMORY;
+ memcpy(zname, name, len);
+ zname[len] = '\0';
+ res = curl_mime_name(part, zname);
+ free(zname);
+ return res;
}
/*
- * Curl_getformdata() converts a linked list of "meta data" into a complete
- * (possibly huge) multipart formdata. The input list is in 'post', while the
- * output resulting linked lists gets stored in '*finalform'. *sizep will get
- * the total size of the whole POST.
- * A multipart/form_data content-type is built, unless a custom content-type
- * is passed in 'custom_content_type'.
+ * Curl_getformdata() converts a linked list of "meta data" into a mime
+ * structure. The input list is in 'post', while the output is stored in
+ * mime part at '*finalform'.
*
* This function will not do a failf() for the potential memory failures but
* should for all other errors it spots. Just note that this function MAY get
@@ -1150,422 +854,123 @@ static CURLcode formdata_add_filename(const struct curl_httppost *file,
*/
CURLcode Curl_getformdata(struct Curl_easy *data,
- struct FormData **finalform,
+ curl_mimepart *finalform,
struct curl_httppost *post,
- const char *custom_content_type,
- curl_off_t *sizep)
+ curl_read_callback fread_func)
{
- struct FormData *form = NULL;
- struct FormData *firstform;
- struct curl_httppost *file;
CURLcode result = CURLE_OK;
- curl_off_t size = 0; /* support potentially ENORMOUS formposts */
- char fileboundary[42];
- struct curl_slist *curList;
- char boundary[42];
+ curl_mime *form = NULL;
+ curl_mime *multipart;
+ curl_mimepart *part;
+ struct curl_httppost *file;
- *finalform = NULL; /* default form is empty */
+ Curl_mime_cleanpart(finalform); /* default form is empty */
if(!post)
return result; /* no input => no output! */
- result = formboundary(data, boundary, sizeof(boundary));
- if(result)
- return result;
-
- /* Make the first line of the output */
- result = AddFormDataf(&form, NULL,
- "%s; boundary=%s\r\n",
- custom_content_type?custom_content_type:
- "Content-Type: multipart/form-data",
- boundary);
-
- if(result) {
- return result;
- }
- /* we DO NOT include that line in the total size of the POST, since it'll be
- part of the header! */
-
- firstform = form;
-
- do {
-
- if(size) {
- result = AddFormDataf(&form, &size, "\r\n");
- if(result)
- break;
- }
-
- /* boundary */
- result = AddFormDataf(&form, &size, "--%s\r\n", boundary);
- if(result)
- break;
-
- /* Maybe later this should be disabled when a custom_content_type is
- passed, since Content-Disposition is not meaningful for all multipart
- types.
- */
- result = AddFormDataf(&form, &size,
- "Content-Disposition: form-data; name=\"");
- if(result)
- break;
-
- result = AddFormData(&form, FORM_DATA, post->name, post->namelength,
- &size);
- if(result)
- break;
+ form = curl_mime_init(data);
+ if(!form)
+ result = CURLE_OUT_OF_MEMORY;
- result = AddFormDataf(&form, &size, "\"");
- if(result)
- break;
+ if(!result)
+ result = curl_mime_subparts(finalform, form);
+ /* Process each top part. */
+ for(; !result && post; post = post->next) {
+ /* If we have more than a file here, create a mime subpart and fill it. */
+ multipart = form;
if(post->more) {
- /* If used, this is a link to more file names, we must then do
- the magic to include several files with the same field name */
-
- result = formboundary(data, fileboundary, sizeof(fileboundary));
- if(result) {
- break;
+ part = curl_mime_addpart(form);
+ if(!part)
+ result = CURLE_OUT_OF_MEMORY;
+ if(!result)
+ result = setname(part, post->name, post->namelength);
+ if(!result) {
+ multipart = curl_mime_init(data);
+ if(!multipart)
+ result = CURLE_OUT_OF_MEMORY;
}
-
- result = AddFormDataf(&form, &size,
- "\r\nContent-Type: multipart/mixed;"
- " boundary=%s\r\n",
- fileboundary);
- if(result)
- break;
+ if(!result)
+ result = curl_mime_subparts(part, multipart);
}
- file = post;
-
- do {
-
- /* If 'showfilename' is set, that is a faked name passed on to us
- to use to in the formpost. If that is not set, the actually used
- local file name should be added. */
-
- if(post->more) {
- /* if multiple-file */
- result = AddFormDataf(&form, &size,
- "\r\n--%s\r\nContent-Disposition: "
- "attachment",
- fileboundary);
- if(result)
- break;
- result = formdata_add_filename(file, &form, &size);
- if(result)
- break;
- }
- else if(post->flags & (HTTPPOST_FILENAME|HTTPPOST_BUFFER|
- HTTPPOST_CALLBACK)) {
- /* it should be noted that for the HTTPPOST_FILENAME and
- HTTPPOST_CALLBACK cases the ->showfilename struct member is always
- assigned at this point */
- if(post->showfilename || (post->flags & HTTPPOST_FILENAME)) {
- result = formdata_add_filename(post, &form, &size);
- }
+ /* Generate all the part contents. */
+ for(file = post; !result && file; file = file->more) {
+ /* Create the part. */
+ part = curl_mime_addpart(multipart);
+ if(!part)
+ result = CURLE_OUT_OF_MEMORY;
- if(result)
- break;
- }
+ /* Set the headers. */
+ if(!result)
+ result = curl_mime_headers(part, file->contentheader, 0);
- if(file->contenttype) {
- /* we have a specified type */
- result = AddFormDataf(&form, &size,
- "\r\nContent-Type: %s",
- file->contenttype);
- if(result)
- break;
- }
+ /* Set the content type. */
+ if(!result && file->contenttype)
+ result = curl_mime_type(part, file->contenttype);
- curList = file->contentheader;
- while(curList) {
- /* Process the additional headers specified for this form */
- result = AddFormDataf(&form, &size, "\r\n%s", curList->data);
- if(result)
- break;
- curList = curList->next;
- }
- if(result)
- break;
+ /* Set field name. */
+ if(!result && !post->more)
+ result = setname(part, post->name, post->namelength);
- result = AddFormDataf(&form, &size, "\r\n\r\n");
- if(result)
- break;
+ /* Process contents. */
+ if(!result) {
+ curl_off_t clen = post->contentslength;
- if((post->flags & HTTPPOST_FILENAME) ||
- (post->flags & HTTPPOST_READFILE)) {
- /* we should include the contents from the specified file */
- FILE *fileread;
-
- fileread = !strcmp("-", file->contents)?
- stdin:fopen(file->contents, "rb"); /* binary read for win32 */
-
- /*
- * VMS: This only allows for stream files on VMS. Stream files are
- * OK, as are FIXED & VAR files WITHOUT implied CC For implied CC,
- * every record needs to have a \n appended & 1 added to SIZE
- */
-
- if(fileread) {
- if(fileread != stdin) {
- /* close the file */
- fclose(fileread);
- /* add the file name only - for later reading from this */
- result = AddFormData(&form, FORM_FILE, file->contents, 0, &size);
- }
- else {
- /* When uploading from stdin, we can't know the size of the file,
- * thus must read the full file as before. We *could* use chunked
- * transfer-encoding, but that only works for HTTP 1.1 and we
- * can't be sure we work with such a server.
- */
- size_t nread;
- char buffer[512];
- while((nread = fread(buffer, 1, sizeof(buffer), fileread)) != 0) {
- result = AddFormData(&form, FORM_CONTENT, buffer, nread, &size);
- if(result || feof(fileread) || ferror(fileread))
- break;
- }
+ if(post->flags & CURL_HTTPPOST_LARGE)
+ clen = post->contentlen;
+ if(!clen)
+ clen = -1;
+
+ if(post->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE)) {
+ if(!strcmp(file->contents, "-")) {
+ /* There are a few cases where the code below won't work; in
+ particular, freopen(stdin) by the caller is not guaranteed
+ to result as expected. This feature has been kept for backward
+ compatibility: use of "-" pseudo file name should be avoided. */
+ result = curl_mime_data_cb(part, (curl_off_t) -1,
+ (curl_read_callback) fread,
+ (curl_seek_callback) fseek,
+ NULL, (void *) stdin);
}
+ else
+ result = curl_mime_filedata(part, file->contents);
+ if(!result && (post->flags & HTTPPOST_READFILE))
+ result = curl_mime_filename(part, NULL);
}
+ else if(post->flags & HTTPPOST_BUFFER)
+ result = curl_mime_data(part, post->buffer,
+ post->bufferlength? post->bufferlength: -1);
+ else if(post->flags & HTTPPOST_CALLBACK)
+ /* the contents should be read with the callback and the size is set
+ with the contentslength */
+ result = curl_mime_data_cb(part, clen,
+ fread_func, NULL, NULL, post->userp);
else {
- if(data)
- failf(data, "couldn't open file \"%s\"", file->contents);
- *finalform = NULL;
- result = CURLE_READ_ERROR;
+ result = curl_mime_data(part, post->contents, (ssize_t) clen);
+#ifdef CURL_DOES_CONVERSIONS
+ /* Convert textual contents now. */
+ if(!result && data && part->datasize)
+ result = Curl_convert_to_network(data, part->data, part->datasize);
+#endif
}
}
- else if(post->flags & HTTPPOST_BUFFER)
- /* include contents of buffer */
- result = AddFormData(&form, FORM_CONTENT, post->buffer,
- post->bufferlength, &size);
- else if(post->flags & HTTPPOST_CALLBACK)
- /* the contents should be read with the callback and the size is set
- with the contentslength */
- result = AddFormData(&form, FORM_CALLBACK, post->userp,
- post->flags&CURL_HTTPPOST_LARGE?
- post->contentlen:post->contentslength, &size);
- else
- /* include the contents we got */
- result = AddFormData(&form, FORM_CONTENT, post->contents,
- post->flags&CURL_HTTPPOST_LARGE?
- post->contentlen:post->contentslength, &size);
- file = file->more;
- } while(file && !result); /* for each specified file for this field */
-
- if(result)
- break;
- if(post->more) {
- /* this was a multiple-file inclusion, make a termination file
- boundary: */
- result = AddFormDataf(&form, &size,
- "\r\n--%s--",
- fileboundary);
- if(result)
- break;
+ /* Set fake file name. */
+ if(!result && post->showfilename)
+ if(post->more || (post->flags & (HTTPPOST_FILENAME | HTTPPOST_BUFFER |
+ HTTPPOST_CALLBACK)))
+ result = curl_mime_filename(part, post->showfilename);
}
- post = post->next;
- } while(post); /* for each field */
-
- /* end-boundary for everything */
- if(!result)
- result = AddFormDataf(&form, &size, "\r\n--%s--\r\n", boundary);
-
- if(result) {
- Curl_formclean(&firstform);
- return result;
}
- *sizep = size;
- *finalform = firstform;
+ if(result)
+ Curl_mime_cleanpart(finalform);
return result;
}
-/*
- * Curl_FormInit() inits the struct 'form' points to with the 'formdata'
- * and resets the 'sent' counter.
- */
-int Curl_FormInit(struct Form *form, struct FormData *formdata)
-{
- if(!formdata)
- return 1; /* error */
-
- form->data = formdata;
- form->sent = 0;
- form->fp = NULL;
- form->fread_func = ZERO_NULL;
-
- return 0;
-}
-
-#ifndef __VMS
-# define fopen_read fopen
-#else
- /*
- * vmsfopenread
- *
- * For upload to work as expected on VMS, different optional
- * parameters must be added to the fopen command based on
- * record format of the file.
- *
- */
-# define fopen_read vmsfopenread
-static FILE * vmsfopenread(const char *file, const char *mode)
-{
- struct_stat statbuf;
- int result;
-
- result = stat(file, &statbuf);
-
- switch(statbuf.st_fab_rfm) {
- case FAB$C_VAR:
- case FAB$C_VFC:
- case FAB$C_STMCR:
- return fopen(file, FOPEN_READTEXT); /* VMS */
- break;
- default:
- return fopen(file, FOPEN_READTEXT, "rfm=stmlf", "ctx=stm");
- }
-}
-#endif
-
-/*
- * readfromfile()
- *
- * The read callback that this function may use can return a value larger than
- * 'size' (which then this function returns) that indicates a problem and it
- * must be properly dealt with
- */
-static size_t readfromfile(struct Form *form, char *buffer,
- size_t size)
-{
- size_t nread;
- bool callback = (form->data->type == FORM_CALLBACK)?TRUE:FALSE;
-
- if(callback) {
- if(form->fread_func == ZERO_NULL)
- return 0;
- nread = form->fread_func(buffer, 1, size, form->data->line);
- }
- else {
- if(!form->fp) {
- /* this file hasn't yet been opened */
- form->fp = fopen_read(form->data->line, "rb"); /* b is for binary */
- if(!form->fp)
- return (size_t)-1; /* failure */
- }
- nread = fread(buffer, 1, size, form->fp);
- }
- if(!nread) {
- /* this is the last chunk from the file, move on */
- if(form->fp) {
- fclose(form->fp);
- form->fp = NULL;
- }
- form->data = form->data->next;
- }
-
- return nread;
-}
-
-/*
- * Curl_FormReader() is the fread() emulation function that will be used to
- * deliver the formdata to the transfer loop and then sent away to the peer.
- */
-size_t Curl_FormReader(char *buffer,
- size_t size,
- size_t nitems,
- FILE *mydata)
-{
- struct Form *form;
- size_t wantedsize;
- size_t gotsize = 0;
-
- form=(struct Form *)mydata;
-
- wantedsize = size * nitems;
-
- if(!form->data)
- return 0; /* nothing, error, empty */
-
- if((form->data->type == FORM_FILE) ||
- (form->data->type == FORM_CALLBACK)) {
- gotsize = readfromfile(form, buffer, wantedsize);
-
- if(gotsize)
- /* If positive or -1, return. If zero, continue! */
- return gotsize;
- }
- do {
-
- if((form->data->length - form->sent) > wantedsize - gotsize) {
-
- memcpy(buffer + gotsize, form->data->line + form->sent,
- wantedsize - gotsize);
-
- form->sent += wantedsize-gotsize;
-
- return wantedsize;
- }
-
- memcpy(buffer+gotsize,
- form->data->line + form->sent,
- (form->data->length - form->sent) );
- gotsize += form->data->length - form->sent;
-
- form->sent = 0;
-
- form->data = form->data->next; /* advance */
-
- } while(form->data && (form->data->type < FORM_CALLBACK));
- /* If we got an empty line and we have more data, we proceed to the next
- line immediately to avoid returning zero before we've reached the end. */
-
- return gotsize;
-}
-
-/*
- * Curl_formpostheader() returns the first line of the formpost, the
- * request-header part (which is not part of the request-body like the rest of
- * the post).
- */
-char *Curl_formpostheader(void *formp, size_t *len)
-{
- char *header;
- struct Form *form=(struct Form *)formp;
-
- if(!form->data)
- return NULL; /* nothing, ERROR! */
-
- header = form->data->line;
- *len = form->data->length;
-
- form->data = form->data->next; /* advance */
-
- return header;
-}
-
-/*
- * formboundary() creates a suitable boundary string and returns an allocated
- * one.
- */
-static CURLcode formboundary(struct Curl_easy *data,
- char *buffer, size_t buflen)
-{
- /* 24 dashes and 16 hexadecimal digits makes 64 bit (18446744073709551615)
- combinations */
- if(buflen < 41)
- return CURLE_BAD_FUNCTION_ARGUMENT;
-
- memset(buffer, '-', 24);
- Curl_rand_hex(data, (unsigned char *)&buffer[24], 17);
-
- return CURLE_OK;
-}
-
#else /* CURL_DISABLE_HTTP */
CURLFORMcode curl_formadd(struct curl_httppost **httppost,
struct curl_httppost **last_post,
diff --git a/lib/formdata.h b/lib/formdata.h
index 69629f62..1246c2bc 100644
--- a/lib/formdata.h
+++ b/lib/formdata.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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,32 +22,6 @@
*
***************************************************************************/
-enum formtype {
- FORM_DATAMEM, /* already allocated FORM_DATA memory */
- FORM_DATA, /* form metadata (convert to network encoding if necessary) */
- FORM_CONTENT, /* form content (never convert) */
- FORM_CALLBACK, /* 'line' points to the custom pointer we pass to the callback
- */
- FORM_FILE /* 'line' points to a file name we should read from
- to create the form data (never convert) */
-};
-
-/* plain and simple linked list with lines to send */
-struct FormData {
- struct FormData *next;
- enum formtype type;
- char *line;
- size_t length;
-};
-
-struct Form {
- struct FormData *data; /* current form line to send */
- size_t sent; /* number of bytes of the current line that has
- already been sent in a previous invoke */
- FILE *fp; /* file to read from */
- curl_read_callback fread_func; /* fread callback pointer */
-};
-
/* used by FormAdd for temporary storage */
typedef struct FormInfo {
char *name;
@@ -69,31 +43,9 @@ typedef struct FormInfo {
struct FormInfo *more;
} FormInfo;
-int Curl_FormInit(struct Form *form, struct FormData *formdata);
-
CURLcode Curl_getformdata(struct Curl_easy *data,
- struct FormData **,
+ curl_mimepart *,
struct curl_httppost *post,
- const char *custom_contenttype,
- curl_off_t *size);
-
-/* fread() emulation */
-size_t Curl_FormReader(char *buffer,
- size_t size,
- size_t nitems,
- FILE *mydata);
-
-/*
- * Curl_formpostheader() returns the first line of the formpost, the
- * request-header part (which is not part of the request-body like the rest of
- * the post).
- */
-char *Curl_formpostheader(void *formp, size_t *len);
-
-char *Curl_FormBoundary(void);
-
-void Curl_formclean(struct FormData **);
-
-CURLcode Curl_formconvert(struct Curl_easy *, struct FormData *);
+ curl_read_callback fread_func);
#endif /* HEADER_CURL_FORMDATA_H */
diff --git a/lib/ftp.c b/lib/ftp.c
index 6e86e538..8042edf4 100644
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -182,7 +182,8 @@ const struct Curl_handler Curl_handler_ftp = {
PORT_FTP, /* defport */
CURLPROTO_FTP, /* protocol */
PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD |
- PROTOPT_NOURLQUERY | PROTOPT_PROXY_AS_HTTP /* flags */
+ PROTOPT_NOURLQUERY | PROTOPT_PROXY_AS_HTTP |
+ PROTOPT_WILDCARD /* flags */
};
@@ -210,7 +211,7 @@ const struct Curl_handler Curl_handler_ftps = {
PORT_FTPS, /* defport */
CURLPROTO_FTPS, /* protocol */
PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION |
- PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY /* flags */
+ PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY | PROTOPT_WILDCARD /* flags */
};
#endif
@@ -239,9 +240,9 @@ static void freedirs(struct ftp_conn *ftpc)
{
int i;
if(ftpc->dirs) {
- for(i=0; i < ftpc->dirdepth; i++) {
+ for(i = 0; i < ftpc->dirdepth; i++) {
free(ftpc->dirs[i]);
- ftpc->dirs[i]=NULL;
+ ftpc->dirs[i] = NULL;
}
free(ftpc->dirs);
ftpc->dirs = NULL;
@@ -288,7 +289,7 @@ static CURLcode AcceptServerConnect(struct connectdata *conn)
if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) {
size = sizeof(add);
- s=accept(sock, (struct sockaddr *) &add, &size);
+ s = accept(sock, (struct sockaddr *) &add, &size);
}
Curl_closesocket(conn, sock); /* close the first socket */
@@ -332,16 +333,16 @@ static CURLcode AcceptServerConnect(struct connectdata *conn)
* Curl_pgrsTime(..., TIMER_STARTACCEPT);
*
*/
-static time_t ftp_timeleft_accept(struct Curl_easy *data)
+static timediff_t ftp_timeleft_accept(struct Curl_easy *data)
{
- time_t timeout_ms = DEFAULT_ACCEPT_TIMEOUT;
- time_t other;
+ timediff_t timeout_ms = DEFAULT_ACCEPT_TIMEOUT;
+ timediff_t other;
struct curltime now;
if(data->set.accepttimeout > 0)
timeout_ms = data->set.accepttimeout;
- now = Curl_tvnow();
+ now = Curl_now();
/* check if the generic timeout possibly is set shorter */
other = Curl_timeleft(data, &now, FALSE);
@@ -351,7 +352,7 @@ static time_t ftp_timeleft_accept(struct Curl_easy *data)
timeout_ms = other;
else {
/* subtract elapsed time */
- timeout_ms -= Curl_tvdiff(now, data->progress.t_acceptdata);
+ timeout_ms -= Curl_timediff(now, data->progress.t_acceptdata);
if(!timeout_ms)
/* avoid returning 0 as that means no timeout! */
return -1;
@@ -457,7 +458,7 @@ static CURLcode InitiateTransfer(struct connectdata *conn)
}
if(conn->proto.ftpc.state_saved == FTP_STOR) {
- *(ftp->bytecountp)=0;
+ *(ftp->bytecountp) = 0;
/* When we know we're uploading a specified file, we can get the file
size prior to the actual upload. */
@@ -592,7 +593,7 @@ static CURLcode ftp_readresp(curl_socket_t sockfd,
#endif
/* store the latest code for later retrieval */
- data->info.httpcode=code;
+ data->info.httpcode = code;
if(ftpcode)
*ftpcode = code;
@@ -640,8 +641,8 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
struct ftp_conn *ftpc = &conn->proto.ftpc;
struct pingpong *pp = &ftpc->pp;
size_t nread;
- int cache_skip=0;
- int value_to_be_ignored=0;
+ int cache_skip = 0;
+ int value_to_be_ignored = 0;
if(ftpcode)
*ftpcode = 0; /* 0 for errors */
@@ -649,13 +650,13 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
/* make the pointer point to something for the rest of this function */
ftpcode = &value_to_be_ignored;
- *nreadp=0;
+ *nreadp = 0;
while(!*ftpcode && !result) {
/* check and reset timeout value every lap */
timeout = Curl_pp_state_timeout(pp);
- if(timeout <=0) {
+ if(timeout <= 0) {
failf(data, "FTP response timeout");
return CURLE_OPERATION_TIMEDOUT; /* already too little time */
}
@@ -713,7 +714,7 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
else
/* when we got data or there is no cache left, we reset the cache skip
counter */
- cache_skip=0;
+ cache_skip = 0;
*nreadp += nread;
@@ -848,7 +849,7 @@ static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
int i;
/* PORT is used to tell the server to connect to us, and during that we
don't do happy eyeballs, but we do if we connect to the server */
- for(s=1, i=0; i<2; i++) {
+ for(s = 1, i = 0; i<2; i++) {
if(conn->tempsock[i] != CURL_SOCKET_BAD) {
socks[s] = conn->tempsock[i];
bits |= GETSOCK_WRITESOCK(s++);
@@ -885,7 +886,7 @@ static CURLcode ftp_state_cwd(struct connectdata *conn)
/* count3 is set to allow a MKD to fail once. In the case when first CWD
fails and then MKD fails (due to another session raced it to create the
dir) this then allows for a second try to CWD to it */
- ftpc->count3 = (conn->data->set.ftp_create_missing_dirs==2)?1:0;
+ ftpc->count3 = (conn->data->set.ftp_create_missing_dirs == 2)?1:0;
if((conn->data->set.ftp_filemethod == FTPFILE_NOCWD) && !ftpc->cwdcount)
/* No CWD necessary */
@@ -928,15 +929,15 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
{
CURLcode result = CURLE_OK;
struct ftp_conn *ftpc = &conn->proto.ftpc;
- struct Curl_easy *data=conn->data;
- curl_socket_t portsock= CURL_SOCKET_BAD;
+ struct Curl_easy *data = conn->data;
+ curl_socket_t portsock = CURL_SOCKET_BAD;
char myhost[256] = "";
struct Curl_sockaddr_storage ss;
Curl_addrinfo *res, *ai;
curl_socklen_t sslen;
char hbuf[NI_MAXHOST];
- struct sockaddr *sa=(struct sockaddr *)&ss;
+ struct sockaddr *sa = (struct sockaddr *)&ss;
struct sockaddr_in * const sa4 = (void *)sa;
#ifdef ENABLE_IPV6
struct sockaddr_in6 * const sa6 = (void *)sa;
@@ -947,7 +948,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
int error;
char *host = NULL;
char *string_ftpport = data->set.str[STRING_FTPPORT];
- struct Curl_dns_entry *h=NULL;
+ struct Curl_dns_entry *h = NULL;
unsigned short port_min = 0;
unsigned short port_max = 0;
unsigned short port;
@@ -975,7 +976,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
char *port_start = NULL;
char *port_sep = NULL;
- addr = calloc(addrlen+1, 1);
+ addr = calloc(addrlen + 1, 1);
if(!addr)
return CURLE_OUT_OF_MEMORY;
@@ -1018,7 +1019,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
if(ip_end != NULL) {
port_start = strchr(ip_end, ':');
if(port_start) {
- port_min = curlx_ultous(strtoul(port_start+1, NULL, 10));
+ port_min = curlx_ultous(strtoul(port_start + 1, NULL, 10));
port_sep = strchr(port_start, '-');
if(port_sep) {
port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10));
@@ -1262,7 +1263,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
/* translate x.x.x.x to x,x,x,x */
while(source && *source) {
if(*source == '.')
- *dest=',';
+ *dest = ',';
else
*dest = *source;
dest++;
@@ -1457,25 +1458,22 @@ static CURLcode ftp_state_list(struct connectdata *conn)
then just do LIST (in that case: nothing to do here)
*/
char *cmd, *lstArg, *slashPos;
+ const char *inpath = data->state.path;
lstArg = NULL;
if((data->set.ftp_filemethod == FTPFILE_NOCWD) &&
- data->state.path &&
- data->state.path[0] &&
- strchr(data->state.path, '/')) {
-
- lstArg = strdup(data->state.path);
- if(!lstArg)
- return CURLE_OUT_OF_MEMORY;
+ inpath && inpath[0] && strchr(inpath, '/')) {
+ size_t n = strlen(inpath);
/* Check if path does not end with /, as then we cut off the file part */
- if(lstArg[strlen(lstArg) - 1] != '/') {
-
+ if(inpath[n - 1] != '/') {
/* chop off the file part if format is dir/dir/file */
- slashPos = strrchr(lstArg, '/');
- if(slashPos)
- *(slashPos+1) = '\0';
+ slashPos = strrchr(inpath, '/');
+ n = slashPos - inpath;
}
+ result = Curl_urldecode(data, inpath, n, &lstArg, NULL, FALSE);
+ if(result)
+ return result;
}
cmd = aprintf("%s%s%s",
@@ -1622,7 +1620,7 @@ static CURLcode ftp_state_ul_setup(struct connectdata *conn,
}
if(seekerr != CURL_SEEKFUNC_OK) {
- curl_off_t passed=0;
+ curl_off_t passed = 0;
if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
failf(data, "Could not seek stream");
return CURLE_FTP_COULDNT_USE_REST;
@@ -1684,7 +1682,7 @@ static CURLcode ftp_state_quote(struct connectdata *conn,
struct Curl_easy *data = conn->data;
struct FTP *ftp = data->req.protop;
struct ftp_conn *ftpc = &conn->proto.ftpc;
- bool quote=FALSE;
+ bool quote = FALSE;
struct curl_slist *item;
switch(instate) {
@@ -1821,11 +1819,11 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
{
struct ftp_conn *ftpc = &conn->proto.ftpc;
CURLcode result;
- struct Curl_easy *data=conn->data;
- struct Curl_dns_entry *addr=NULL;
+ struct Curl_easy *data = conn->data;
+ struct Curl_dns_entry *addr = NULL;
int rc;
unsigned short connectport; /* the local port connect() should use! */
- char *str=&data->state.buffer[4]; /* start on the first letter */
+ char *str = &data->state.buffer[4]; /* start on the first letter */
/* if we come here again, make sure the former name is cleared */
Curl_safefree(ftpc->newhost);
@@ -1849,9 +1847,9 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
/* The four separators should be identical, or else this is an oddly
formatted reply and we bail out immediately. */
- for(i=1; i<4; i++) {
+ for(i = 1; i<4; i++) {
if(separator[i] != sep1) {
- ptr=NULL; /* set to NULL to signal error */
+ ptr = NULL; /* set to NULL to signal error */
break;
}
}
@@ -1867,7 +1865,7 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
}
}
else
- ptr=NULL;
+ ptr = NULL;
}
if(!ptr) {
failf(data, "Weirdly formatted EPSV reply");
@@ -1877,8 +1875,8 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
else if((ftpc->count1 == 1) &&
(ftpcode == 227)) {
/* positive PASV response */
- int ip[4];
- int port[2];
+ unsigned int ip[4];
+ unsigned int port[2];
/*
* Scan for a sequence of six comma-separated numbers and use them as
@@ -1890,14 +1888,15 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
* "227 Entering passive mode. 127,0,0,1,4,51"
*/
while(*str) {
- if(6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
+ if(6 == sscanf(str, "%u,%u,%u,%u,%u,%u",
&ip[0], &ip[1], &ip[2], &ip[3],
&port[0], &port[1]))
break;
str++;
}
- if(!*str) {
+ if(!*str || (ip[0] > 255) || (ip[1] > 255) || (ip[2] > 255) ||
+ (ip[3] > 255) || (port[0] > 255) || (port[1] > 255) ) {
failf(data, "Couldn't interpret the 227-response");
return CURLE_FTP_WEIRD_227_FORMAT;
}
@@ -2041,7 +2040,7 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
int ftpcode)
{
CURLcode result = CURLE_OK;
- struct Curl_easy *data=conn->data;
+ struct Curl_easy *data = conn->data;
struct FTP *ftp = data->req.protop;
struct ftp_conn *ftpc = &conn->proto.ftpc;
@@ -2055,7 +2054,7 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
&year, &month, &day, &hour, &minute, &second)) {
/* we have a time, reformat it */
char timebuf[24];
- time_t secs=time(NULL);
+ time_t secs = time(NULL);
snprintf(timebuf, sizeof(timebuf),
"%04d%02d%02d %02d:%02d:%02d GMT",
@@ -2071,7 +2070,7 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
if(data->set.opt_no_body &&
ftpc->file &&
data->set.get_filetime &&
- (data->info.filetime>=0) ) {
+ (data->info.filetime >= 0) ) {
char headerbuf[128];
time_t filetime = (time_t)data->info.filetime;
struct tm buffer;
@@ -2147,7 +2146,7 @@ static CURLcode ftp_state_type_resp(struct connectdata *conn,
ftpstate instate)
{
CURLcode result = CURLE_OK;
- struct Curl_easy *data=conn->data;
+ struct Curl_easy *data = conn->data;
if(ftpcode/100 != 2) {
/* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a
@@ -2176,7 +2175,7 @@ static CURLcode ftp_state_retr(struct connectdata *conn,
curl_off_t filesize)
{
CURLcode result = CURLE_OK;
- struct Curl_easy *data=conn->data;
+ struct Curl_easy *data = conn->data;
struct FTP *ftp = data->req.protop;
struct ftp_conn *ftpc = &conn->proto.ftpc;
@@ -2259,12 +2258,14 @@ static CURLcode ftp_state_size_resp(struct connectdata *conn,
ftpstate instate)
{
CURLcode result = CURLE_OK;
- struct Curl_easy *data=conn->data;
- curl_off_t filesize;
+ struct Curl_easy *data = conn->data;
+ curl_off_t filesize = -1;
char *buf = data->state.buffer;
/* get the size from the ascii string: */
- filesize = (ftpcode == 213)?curlx_strtoofft(buf+4, NULL, 0):-1;
+ if(ftpcode == 213)
+ /* ignores parsing errors, which will make the size remain unknown */
+ (void)curlx_strtoofft(buf + 4, NULL, 0, &filesize);
if(instate == FTP_SIZE) {
#ifdef CURL_FTP_HTTPSTYLE_HEAD
@@ -2334,7 +2335,7 @@ static CURLcode ftp_state_stor_resp(struct connectdata *conn,
CURLcode result = CURLE_OK;
struct Curl_easy *data = conn->data;
- if(ftpcode>=400) {
+ if(ftpcode >= 400) {
failf(data, "Failed FTP upload: %0d", ftpcode);
state(conn, FTP_STOP);
/* oops, we never close the sockets! */
@@ -2392,7 +2393,7 @@ static CURLcode ftp_state_get_resp(struct connectdata *conn,
E:
125 Data connection already open; Transfer starting. */
- curl_off_t size=-1; /* default unknown size */
+ curl_off_t size = -1; /* default unknown size */
/*
@@ -2416,9 +2417,9 @@ static CURLcode ftp_state_get_resp(struct connectdata *conn,
* Example D above makes this parsing a little tricky */
char *bytes;
char *buf = data->state.buffer;
- bytes=strstr(buf, " bytes");
- if(bytes--) {
- long in=(long)(bytes-buf);
+ bytes = strstr(buf, " bytes");
+ if(bytes) {
+ long in = (long)(--bytes-buf);
/* this is a hint there is size information in there! ;-) */
while(--in) {
/* scan for the left parenthesis and break there */
@@ -2426,7 +2427,7 @@ static CURLcode ftp_state_get_resp(struct connectdata *conn,
break;
/* skip only digits */
if(!ISDIGIT(*bytes)) {
- bytes=NULL;
+ bytes = NULL;
break;
}
/* one more estep backwards */
@@ -2435,7 +2436,7 @@ static CURLcode ftp_state_get_resp(struct connectdata *conn,
/* if we have nothing but digits: */
if(bytes++) {
/* get the number! */
- size = curlx_strtoofft(bytes, NULL, 0);
+ (void)curlx_strtoofft(bytes, NULL, 0, &size);
}
}
}
@@ -2598,7 +2599,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
{
CURLcode result;
curl_socket_t sock = conn->sock[FIRSTSOCKET];
- struct Curl_easy *data=conn->data;
+ struct Curl_easy *data = conn->data;
int ftpcode;
struct ftp_conn *ftpc = &conn->proto.ftpc;
struct pingpong *pp = &ftpc->pp;
@@ -2650,7 +2651,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
/* We don't have a SSL/TLS connection yet, but FTPS is
requested. Try a FTPS connection now */
- ftpc->count3=0;
+ ftpc->count3 = 0;
switch(data->set.ftpsslauth) {
case CURLFTPAUTH_DEFAULT:
case CURLFTPAUTH_SSL:
@@ -2773,10 +2774,11 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
case FTP_PWD:
if(ftpcode == 257) {
- char *ptr=&data->state.buffer[4]; /* start on the first letter */
+ char *ptr = &data->state.buffer[4]; /* start on the first letter */
const size_t buf_size = data->set.buffer_size;
char *dir;
char *store;
+ bool entry_extracted = FALSE;
dir = malloc(nread + 1);
if(!dir)
@@ -2808,7 +2810,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
}
else {
/* end of path */
- *store = '\0'; /* zero terminate */
+ entry_extracted = TRUE;
break; /* get out of this loop */
}
}
@@ -2817,7 +2819,9 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
store++;
ptr++;
}
-
+ *store = '\0'; /* zero terminate */
+ }
+ if(entry_extracted) {
/* If the path name does not look like an absolute path (i.e.: it
does not start with a '/'), we probably need some server-dependent
adjustments. For example, this is the case when connecting to
@@ -2864,7 +2868,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
case FTP_SYST:
if(ftpcode == 215) {
- char *ptr=&data->state.buffer[4]; /* start on the first letter */
+ char *ptr = &data->state.buffer[4]; /* start on the first letter */
char *os;
char *store;
@@ -2955,7 +2959,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
}
else {
/* success */
- ftpc->count2=0;
+ ftpc->count2 = 0;
if(++ftpc->cwdcount <= ftpc->dirdepth) {
/* send next CWD */
PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->cwdcount - 1]);
@@ -3174,7 +3178,7 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
/* now store a copy of the directory we are in */
free(ftpc->prevpath);
- if(data->set.wildcardmatch) {
+ if(data->state.wildcardmatch) {
if(data->set.chunk_end && ftpc->file) {
data->set.chunk_end(data->wildcard.customptr);
}
@@ -3195,15 +3199,16 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
size_t flen = ftpc->file?strlen(ftpc->file):0; /* file is "raw" already */
size_t dlen = strlen(path)-flen;
if(!ftpc->cwdfail) {
+ ftpc->prevmethod = data->set.ftp_filemethod;
if(dlen && (data->set.ftp_filemethod != FTPFILE_NOCWD)) {
ftpc->prevpath = path;
if(flen)
/* if 'path' is not the whole string */
- ftpc->prevpath[dlen]=0; /* terminate */
+ ftpc->prevpath[dlen] = 0; /* terminate */
}
else {
/* we never changed dir */
- ftpc->prevpath=strdup("");
+ ftpc->prevpath = strdup("");
free(path);
}
if(ftpc->prevpath)
@@ -3257,7 +3262,7 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
long old_time = pp->response_time;
pp->response_time = 60*1000; /* give it only a minute for now */
- pp->response = Curl_tvnow(); /* timeout relative now */
+ pp->response = Curl_now(); /* timeout relative now */
result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
@@ -3377,7 +3382,7 @@ CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
PPSENDF(&conn->proto.ftpc.pp, "%s", cmd);
- pp->response = Curl_tvnow(); /* timeout relative now */
+ pp->response = Curl_now(); /* timeout relative now */
result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
if(result)
@@ -3466,35 +3471,36 @@ static CURLcode ftp_range(struct connectdata *conn)
{
curl_off_t from, to;
char *ptr;
- char *ptr2;
struct Curl_easy *data = conn->data;
struct ftp_conn *ftpc = &conn->proto.ftpc;
if(data->state.use_range && data->state.range) {
- from=curlx_strtoofft(data->state.range, &ptr, 0);
- while(*ptr && (ISSPACE(*ptr) || (*ptr=='-')))
+ CURLofft from_t;
+ CURLofft to_t;
+ from_t = curlx_strtoofft(data->state.range, &ptr, 0, &from);
+ if(from_t == CURL_OFFT_FLOW)
+ return CURLE_RANGE_ERROR;
+ while(*ptr && (ISSPACE(*ptr) || (*ptr == '-')))
ptr++;
- to=curlx_strtoofft(ptr, &ptr2, 0);
- if(ptr == ptr2) {
- /* we didn't get any digit */
- to=-1;
- }
- if((-1 == to) && (from>=0)) {
+ to_t = curlx_strtoofft(ptr, NULL, 0, &to);
+ if(to_t == CURL_OFFT_FLOW)
+ return CURLE_RANGE_ERROR;
+ if((to_t == CURL_OFFT_INVAL) && !from_t) {
/* X - */
data->state.resume_from = from;
DEBUGF(infof(conn->data, "FTP RANGE %" CURL_FORMAT_CURL_OFF_T
" to end of file\n", from));
}
- else if(from < 0) {
+ else if(!to_t && (from_t == CURL_OFFT_INVAL)) {
/* -Y */
- data->req.maxdownload = -from;
- data->state.resume_from = from;
+ data->req.maxdownload = to;
+ data->state.resume_from = -to;
DEBUGF(infof(conn->data, "FTP RANGE the last %" CURL_FORMAT_CURL_OFF_T
- " bytes\n", -from));
+ " bytes\n", to));
}
else {
/* X-Y */
- data->req.maxdownload = (to-from)+1; /* include last byte */
+ data->req.maxdownload = (to - from) + 1; /* include last byte */
data->state.resume_from = from;
DEBUGF(infof(conn->data, "FTP RANGE from %" CURL_FORMAT_CURL_OFF_T
" getting %" CURL_FORMAT_CURL_OFF_T " bytes\n",
@@ -3525,7 +3531,7 @@ static CURLcode ftp_range(struct connectdata *conn)
static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
{
- struct Curl_easy *data=conn->data;
+ struct Curl_easy *data = conn->data;
struct ftp_conn *ftpc = &conn->proto.ftpc;
CURLcode result = CURLE_OK;
bool connected = FALSE;
@@ -3692,7 +3698,7 @@ CURLcode ftp_perform(struct connectdata *conn,
bool *dophase_done)
{
/* this is FTP and no proxy */
- CURLcode result=CURLE_OK;
+ CURLcode result = CURLE_OK;
DEBUGF(infof(conn->data, "DO phase starts\n"));
@@ -3957,7 +3963,7 @@ static CURLcode ftp_do(struct connectdata *conn, bool *done)
*done = FALSE; /* default to false */
ftpc->wait_data_conn = FALSE; /* default to no such wait */
- if(conn->data->set.wildcardmatch) {
+ if(conn->data->state.wildcardmatch) {
result = wc_statemach(conn);
if(conn->data->wildcard.state == CURLWC_SKIP ||
conn->data->wildcard.state == CURLWC_DONE) {
@@ -3985,7 +3991,7 @@ CURLcode Curl_ftpsend(struct connectdata *conn, const char *cmd)
#define SBUF_SIZE 1024
char s[SBUF_SIZE];
size_t write_len;
- char *sptr=s;
+ char *sptr = s;
CURLcode result = CURLE_OK;
#ifdef HAVE_GSSAPI
enum protection_level data_sec = conn->data_prot;
@@ -3996,9 +4002,8 @@ CURLcode Curl_ftpsend(struct connectdata *conn, const char *cmd)
return CURLE_BAD_FUNCTION_ARGUMENT;
strcpy(&s[write_len], "\r\n"); /* append a trailing CRLF */
- write_len +=2;
-
- bytes_written=0;
+ write_len += 2;
+ bytes_written = 0;
result = Curl_convert_to_network(conn->data, s, write_len);
/* Curl_convert_to_network calls failf if unsuccessful */
@@ -4076,7 +4081,7 @@ static CURLcode ftp_quit(struct connectdata *conn)
*/
static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection)
{
- struct ftp_conn *ftpc= &conn->proto.ftpc;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
struct pingpong *pp = &ftpc->pp;
/* We cannot send quit unconditionally. If this connection is stale or
@@ -4172,7 +4177,7 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
ftpc->dirdepth = 0;
break;
}
- slash_pos=strrchr(cur_pos, '/');
+ slash_pos = strrchr(cur_pos, '/');
if(slash_pos || !*cur_pos) {
size_t dirlen = slash_pos-cur_pos;
CURLcode result;
@@ -4193,7 +4198,7 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
return result;
}
ftpc->dirdepth = 1; /* we consider it to be a single dir */
- filename = slash_pos ? slash_pos+1 : cur_pos; /* rest is file name */
+ filename = slash_pos ? slash_pos + 1 : cur_pos; /* rest is file name */
}
else
filename = cur_pos; /* this is a file name only */
@@ -4277,8 +4282,8 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
}
}
else
- ftpc->file=NULL; /* instead of point to a zero byte, we make it a NULL
- pointer */
+ ftpc->file = NULL; /* instead of point to a zero byte, we make it a NULL
+ pointer */
if(data->set.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) {
/* We need a file name when uploading. Return error! */
@@ -4302,7 +4307,8 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
dlen -= ftpc->file?strlen(ftpc->file):0;
if((dlen == strlen(ftpc->prevpath)) &&
- !strncmp(path, ftpc->prevpath, dlen)) {
+ !strncmp(path, ftpc->prevpath, dlen) &&
+ (ftpc->prevmethod == data->set.ftp_filemethod)) {
infof(data, "Request has same path as previous transfer\n");
ftpc->cwddone = TRUE;
}
@@ -4373,8 +4379,8 @@ static
CURLcode ftp_regular_transfer(struct connectdata *conn,
bool *dophase_done)
{
- CURLcode result=CURLE_OK;
- bool connected=FALSE;
+ CURLcode result = CURLE_OK;
+ bool connected = FALSE;
struct Curl_easy *data = conn->data;
struct ftp_conn *ftpc = &conn->proto.ftpc;
data->req.size = -1; /* make sure this is unknown at this point */
diff --git a/lib/ftp.h b/lib/ftp.h
index 9c6c2c8d..e4aa63f1 100644
--- a/lib/ftp.h
+++ b/lib/ftp.h
@@ -135,6 +135,7 @@ struct ftp_conn {
caching the current directory */
bool wait_data_conn; /* this is set TRUE if data connection is waited */
char *prevpath; /* conn->path from the previous transfer */
+ curl_ftpfile prevmethod; /* ftp method in previous transfer */
char transfertype; /* set by ftp_transfertype for use by Curl_client_write()a
and others (A/I or zero) */
int count1; /* general purpose counter for the state machine */
diff --git a/lib/ftplistparser.c b/lib/ftplistparser.c
index 2acce31d..262ac030 100644
--- a/lib/ftplistparser.c
+++ b/lib/ftplistparser.c
@@ -264,16 +264,6 @@ static int ftp_pl_get_permission(const char *str)
return permissions;
}
-static void PL_ERROR(struct connectdata *conn, CURLcode err)
-{
- struct ftp_wc_tmpdata *tmpdata = conn->data->wildcard.tmp;
- struct ftp_parselist_data *parser = tmpdata->parser;
- if(parser->file_data)
- Curl_fileinfo_dtor(NULL, parser->file_data);
- parser->file_data = NULL;
- parser->error = err;
-}
-
static CURLcode ftp_pl_insert_finfo(struct connectdata *conn,
struct fileinfo *infop)
{
@@ -338,6 +328,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
struct curl_fileinfo *finfo;
unsigned long i = 0;
CURLcode result;
+ size_t retsize = bufflen;
if(parser->error) { /* error in previous call */
/* scenario:
@@ -346,7 +337,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
* 3. (last) call => is skipped RIGHT HERE and the error is hadled later
* in wc_statemach()
*/
- return bufflen;
+ goto fail;
}
if(parser->os_type == OS_TYPE_UNKNOWN && bufflen > 0) {
@@ -362,12 +353,12 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
parser->file_data = Curl_fileinfo_alloc();
if(!parser->file_data) {
parser->error = CURLE_OUT_OF_MEMORY;
- return bufflen;
+ goto fail;
}
parser->file_data->info.b_data = malloc(FTP_BUFFER_ALLOCSIZE);
if(!parser->file_data->info.b_data) {
- PL_ERROR(conn, CURLE_OUT_OF_MEMORY);
- return bufflen;
+ parser->error = CURLE_OUT_OF_MEMORY;
+ goto fail;
}
parser->file_data->info.b_size = FTP_BUFFER_ALLOCSIZE;
parser->item_offset = 0;
@@ -390,8 +381,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
Curl_fileinfo_dtor(NULL, parser->file_data);
parser->file_data = NULL;
parser->error = CURLE_OUT_OF_MEMORY;
- PL_ERROR(conn, CURLE_OUT_OF_MEMORY);
- return bufflen;
+ goto fail;
}
}
@@ -421,7 +411,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
else if(c == '\n') {
finfo->b_data[parser->item_length - 1] = 0;
if(strncmp("total ", finfo->b_data, 6) == 0) {
- char *endptr = finfo->b_data+6;
+ char *endptr = finfo->b_data + 6;
/* here we can deal with directory size, pass the leading white
spaces and then the digits */
while(ISSPACE(*endptr))
@@ -429,15 +419,15 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
while(ISDIGIT(*endptr))
endptr++;
if(*endptr != 0) {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
+ parser->error = CURLE_FTP_BAD_FILE_LIST;
+ goto fail;
}
parser->state.UNIX.main = PL_UNIX_FILETYPE;
finfo->b_used = 0;
}
else {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
+ parser->error = CURLE_FTP_BAD_FILE_LIST;
+ goto fail;
}
}
break;
@@ -470,8 +460,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
finfo->filetype = CURLFILETYPE_DOOR;
break;
default:
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
+ parser->error = CURLE_FTP_BAD_FILE_LIST;
+ goto fail;
}
parser->state.UNIX.main = PL_UNIX_PERMISSION;
parser->item_length = 0;
@@ -481,21 +471,21 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
parser->item_length++;
if(parser->item_length <= 9) {
if(!strchr("rwx-tTsS", c)) {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
+ parser->error = CURLE_FTP_BAD_FILE_LIST;
+ goto fail;
}
}
else if(parser->item_length == 10) {
unsigned int perm;
if(c != ' ') {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
+ parser->error = CURLE_FTP_BAD_FILE_LIST;
+ goto fail;
}
finfo->b_data[10] = 0; /* terminate permissions */
perm = ftp_pl_get_permission(finfo->b_data + parser->item_offset);
if(perm & FTP_LP_MALFORMATED_PERM) {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
+ parser->error = CURLE_FTP_BAD_FILE_LIST;
+ goto fail;
}
parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_PERM;
parser->file_data->info.perm = perm;
@@ -516,8 +506,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_NUMBER;
}
else {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
+ parser->error = CURLE_FTP_BAD_FILE_LIST;
+ goto fail;
}
}
break;
@@ -538,8 +528,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
parser->state.UNIX.sub.user = PL_UNIX_USER_PRESPACE;
}
else if(c < '0' || c > '9') {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
+ parser->error = CURLE_FTP_BAD_FILE_LIST;
+ goto fail;
}
break;
}
@@ -598,8 +588,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
parser->state.UNIX.sub.size = PL_UNIX_SIZE_NUMBER;
}
else {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
+ parser->error = CURLE_FTP_BAD_FILE_LIST;
+ goto fail;
}
}
break;
@@ -609,20 +599,22 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
char *p;
curl_off_t fsize;
finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
- fsize = curlx_strtoofft(finfo->b_data+parser->item_offset, &p, 10);
- if(p[0] == '\0' && fsize != CURL_OFF_T_MAX &&
- fsize != CURL_OFF_T_MIN) {
- parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE;
- parser->file_data->info.size = fsize;
+ if(!curlx_strtoofft(finfo->b_data + parser->item_offset,
+ &p, 10, &fsize)) {
+ if(p[0] == '\0' && fsize != CURL_OFF_T_MAX &&
+ fsize != CURL_OFF_T_MIN) {
+ parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE;
+ parser->file_data->info.size = fsize;
+ }
+ parser->item_length = 0;
+ parser->item_offset = 0;
+ parser->state.UNIX.main = PL_UNIX_TIME;
+ parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART1;
}
- parser->item_length = 0;
- parser->item_offset = 0;
- parser->state.UNIX.main = PL_UNIX_TIME;
- parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART1;
}
else if(!ISDIGIT(c)) {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
+ parser->error = CURLE_FTP_BAD_FILE_LIST;
+ goto fail;
}
break;
}
@@ -637,8 +629,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
parser->state.UNIX.sub.time = PL_UNIX_TIME_PART1;
}
else {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
+ parser->error = CURLE_FTP_BAD_FILE_LIST;
+ goto fail;
}
}
break;
@@ -648,8 +640,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART2;
}
else if(!ISALNUM(c) && c != '.') {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
+ parser->error = CURLE_FTP_BAD_FILE_LIST;
+ goto fail;
}
break;
case PL_UNIX_TIME_PREPART2:
@@ -659,8 +651,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
parser->state.UNIX.sub.time = PL_UNIX_TIME_PART2;
}
else {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
+ parser->error = CURLE_FTP_BAD_FILE_LIST;
+ goto fail;
}
}
break;
@@ -670,8 +662,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART3;
}
else if(!ISALNUM(c) && c != '.') {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
+ parser->error = CURLE_FTP_BAD_FILE_LIST;
+ goto fail;
}
break;
case PL_UNIX_TIME_PREPART3:
@@ -681,8 +673,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
parser->state.UNIX.sub.time = PL_UNIX_TIME_PART3;
}
else {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
+ parser->error = CURLE_FTP_BAD_FILE_LIST;
+ goto fail;
}
}
break;
@@ -706,8 +698,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
}
}
else if(!ISALNUM(c) && c != '.' && c != ':') {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
+ parser->error = CURLE_FTP_BAD_FILE_LIST;
+ goto fail;
}
break;
}
@@ -732,8 +724,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
parser->state.UNIX.main = PL_UNIX_FILETYPE;
result = ftp_pl_insert_finfo(conn, infop);
if(result) {
- PL_ERROR(conn, result);
- return bufflen;
+ parser->error = result;
+ goto fail;
}
}
break;
@@ -744,13 +736,13 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
parser->state.UNIX.main = PL_UNIX_FILETYPE;
result = ftp_pl_insert_finfo(conn, infop);
if(result) {
- PL_ERROR(conn, result);
- return bufflen;
+ parser->error = result;
+ goto fail;
}
}
else {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
+ parser->error = CURLE_FTP_BAD_FILE_LIST;
+ goto fail;
}
break;
}
@@ -770,8 +762,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET1;
}
else if(c == '\r' || c == '\n') {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
+ parser->error = CURLE_FTP_BAD_FILE_LIST;
+ goto fail;
}
break;
case PL_UNIX_SYMLINK_PRETARGET1:
@@ -780,8 +772,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET2;
}
else if(c == '\r' || c == '\n') {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
+ parser->error = CURLE_FTP_BAD_FILE_LIST;
+ goto fail;
}
else {
parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
@@ -793,8 +785,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET3;
}
else if(c == '\r' || c == '\n') {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
+ parser->error = CURLE_FTP_BAD_FILE_LIST;
+ goto fail;
}
else {
parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
@@ -811,8 +803,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
parser->item_offset = 0;
}
else if(c == '\r' || c == '\n') {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
+ parser->error = CURLE_FTP_BAD_FILE_LIST;
+ goto fail;
}
else {
parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
@@ -825,8 +817,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
parser->item_length = 1;
}
else {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
+ parser->error = CURLE_FTP_BAD_FILE_LIST;
+ goto fail;
}
break;
case PL_UNIX_SYMLINK_TARGET:
@@ -839,8 +831,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
parser->offsets.symlink_target = parser->item_offset;
result = ftp_pl_insert_finfo(conn, infop);
if(result) {
- PL_ERROR(conn, result);
- return bufflen;
+ parser->error = result;
+ goto fail;
}
parser->state.UNIX.main = PL_UNIX_FILETYPE;
}
@@ -851,14 +843,14 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
parser->offsets.symlink_target = parser->item_offset;
result = ftp_pl_insert_finfo(conn, infop);
if(result) {
- PL_ERROR(conn, result);
- return bufflen;
+ parser->error = result;
+ goto fail;
}
parser->state.UNIX.main = PL_UNIX_FILETYPE;
}
else {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
+ parser->error = CURLE_FTP_BAD_FILE_LIST;
+ goto fail;
}
break;
}
@@ -871,8 +863,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
parser->item_length++;
if(parser->item_length < 9) {
if(!strchr("0123456789-", c)) { /* only simple control */
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
+ parser->error = CURLE_FTP_BAD_FILE_LIST;
+ goto fail;
}
}
else if(parser->item_length == 9) {
@@ -881,13 +873,13 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
parser->state.NT.sub.time = PL_WINNT_TIME_PRESPACE;
}
else {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
+ parser->error = CURLE_FTP_BAD_FILE_LIST;
+ goto fail;
}
}
else {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
+ parser->error = CURLE_FTP_BAD_FILE_LIST;
+ goto fail;
}
break;
case PL_WINNT_TIME:
@@ -907,8 +899,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
parser->item_length = 0;
}
else if(!strchr("APM0123456789:", c)) {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
+ parser->error = CURLE_FTP_BAD_FILE_LIST;
+ goto fail;
}
break;
}
@@ -935,21 +927,11 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
}
else {
char *endptr;
- finfo->size = curlx_strtoofft(finfo->b_data +
- parser->item_offset,
- &endptr, 10);
- if(!*endptr) {
- if(finfo->size == CURL_OFF_T_MAX ||
- finfo->size == CURL_OFF_T_MIN) {
- if(errno == ERANGE) {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
- }
- }
- }
- else {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
+ if(curlx_strtoofft(finfo->b_data +
+ parser->item_offset,
+ &endptr, 10, &finfo->size)) {
+ parser->error = CURLE_FTP_BAD_FILE_LIST;
+ goto fail;
}
/* correct file type */
parser->file_data->info.filetype = CURLFILETYPE_FILE;
@@ -984,8 +966,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
parser->offsets.filename = parser->item_offset;
result = ftp_pl_insert_finfo(conn, infop);
if(result) {
- PL_ERROR(conn, result);
- return bufflen;
+ parser->error = result;
+ goto fail;
}
parser->state.NT.main = PL_WINNT_DATE;
parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
@@ -996,15 +978,15 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
parser->offsets.filename = parser->item_offset;
result = ftp_pl_insert_finfo(conn, infop);
if(result) {
- PL_ERROR(conn, result);
- return bufflen;
+ parser->error = result;
+ goto fail;
}
parser->state.NT.main = PL_WINNT_DATE;
parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
}
else {
- PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
- return bufflen;
+ parser->error = CURLE_FTP_BAD_FILE_LIST;
+ goto fail;
}
break;
}
@@ -1012,13 +994,22 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
}
break;
default:
- return bufflen + 1;
+ retsize = bufflen + 1;
+ goto fail;
}
i++;
}
- return bufflen;
+fail:
+
+ /* Clean up any allocated memory. */
+ if(parser->file_data) {
+ Curl_fileinfo_dtor(NULL, parser->file_data);
+ parser->file_data = NULL;
+ }
+
+ return retsize;
}
#endif /* CURL_DISABLE_FTP */
diff --git a/lib/getinfo.c b/lib/getinfo.c
index dc3a107e..862ced01 100644
--- a/lib/getinfo.c
+++ b/lib/getinfo.c
@@ -54,6 +54,7 @@ CURLcode Curl_initinfo(struct Curl_easy *data)
pro->t_starttransfer = 0;
pro->timespent = 0;
pro->t_redirect = 0;
+ pro->is_t_startransfer_set = false;
info->httpcode = 0;
info->httpproxycode = 0;
@@ -359,46 +360,25 @@ static CURLcode getinfo_slist(struct Curl_easy *data, CURLINFO info,
struct curl_tlssessioninfo **tsip = (struct curl_tlssessioninfo **)
param_slistp;
struct curl_tlssessioninfo *tsi = &data->tsi;
+#ifdef USE_SSL
struct connectdata *conn = data->easy_conn;
+#endif
*tsip = tsi;
tsi->backend = Curl_ssl_backend();
tsi->internals = NULL;
+#ifdef USE_SSL
if(conn && tsi->backend != CURLSSLBACKEND_NONE) {
unsigned int i;
for(i = 0; i < (sizeof(conn->ssl) / sizeof(conn->ssl[0])); ++i) {
if(conn->ssl[i].use) {
-#if defined(USE_AXTLS)
- tsi->internals = (void *)conn->ssl[i].ssl;
-#elif defined(USE_CYASSL)
- tsi->internals = (void *)conn->ssl[i].handle;
-#elif defined(USE_DARWINSSL)
- tsi->internals = (void *)conn->ssl[i].ssl_ctx;
-#elif defined(USE_GNUTLS)
- tsi->internals = (void *)conn->ssl[i].session;
-#elif defined(USE_GSKIT)
- tsi->internals = (void *)conn->ssl[i].handle;
-#elif defined(USE_MBEDTLS)
- tsi->internals = (void *)&conn->ssl[i].ssl;
-#elif defined(USE_NSS)
- tsi->internals = (void *)conn->ssl[i].handle;
-#elif defined(USE_OPENSSL)
- /* Legacy: CURLINFO_TLS_SESSION must return an SSL_CTX pointer. */
- tsi->internals = ((info == CURLINFO_TLS_SESSION) ?
- (void *)conn->ssl[i].ctx :
- (void *)conn->ssl[i].handle);
-#elif defined(USE_POLARSSL)
- tsi->internals = (void *)&conn->ssl[i].ssl;
-#elif defined(USE_SCHANNEL)
- tsi->internals = (void *)&conn->ssl[i].ctxt->ctxt_handle;
-#elif defined(USE_SSL)
-#error "SSL backend specific information missing for CURLINFO_TLS_SSL_PTR"
-#endif
+ tsi->internals = Curl_ssl->get_internals(&conn->ssl[i], info);
break;
}
}
}
+#endif
}
break;
default:
diff --git a/lib/gopher.c b/lib/gopher.c
index 836f7255..b7c31b69 100644
--- a/lib/gopher.c
+++ b/lib/gopher.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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
@@ -73,8 +73,8 @@ const struct Curl_handler Curl_handler_gopher = {
static CURLcode gopher_do(struct connectdata *conn, bool *done)
{
- CURLcode result=CURLE_OK;
- struct Curl_easy *data=conn->data;
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
curl_off_t *bytecount = &data->req.bytecount;
@@ -97,11 +97,11 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done)
/* Otherwise, drop / and the first character (i.e., item type) ... */
newp = path;
- newp+=2;
+ newp += 2;
/* ... then turn ? into TAB for search servers, Veronica, etc. ... */
j = strlen(newp);
- for(i=0; i<j; i++)
+ for(i = 0; i<j; i++)
if(newp[i] == '?')
newp[i] = '\x09';
diff --git a/lib/hash.c b/lib/hash.c
index 6afeaa12..c99b1b69 100644
--- a/lib/hash.c
+++ b/lib/hash.c
@@ -300,10 +300,10 @@ Curl_hash_next_element(struct curl_hash_iterator *iter)
/* If we have reached the end of the list, find the next one */
if(!iter->current_element) {
- for(i = iter->slot_index;i < h->slots;i++) {
+ for(i = iter->slot_index; i < h->slots; i++) {
if(h->table[i].head) {
iter->current_element = h->table[i].head;
- iter->slot_index = i+1;
+ iter->slot_index = i + 1;
break;
}
}
diff --git a/lib/hostasyn.c b/lib/hostasyn.c
index 28bdf7a4..7b6e8568 100644
--- a/lib/hostasyn.c
+++ b/lib/hostasyn.c
@@ -22,6 +22,11 @@
#include "curl_setup.h"
+/***********************************************************************
+ * Only for builds using asynchronous name resolves
+ **********************************************************************/
+#ifdef CURLRES_ASYNCH
+
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
@@ -51,11 +56,6 @@
/* The last #include file should be: */
#include "memdebug.h"
-/***********************************************************************
- * Only for builds using asynchronous name resolves
- **********************************************************************/
-#ifdef CURLRES_ASYNCH
-
/*
* Curl_addrinfo_callback() gets called by ares, gethostbyname_thread()
* or getaddrinfo_thread() when we got the name resolved (or not!).
diff --git a/lib/hostcheck.c b/lib/hostcheck.c
index 156091ca..23dc3d2a 100644
--- a/lib/hostcheck.c
+++ b/lib/hostcheck.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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
@@ -73,10 +73,10 @@ static int hostmatch(char *hostname, char *pattern)
/* normalize pattern and hostname by stripping off trailing dots */
size_t len = strlen(hostname);
if(hostname[len-1]=='.')
- hostname[len-1]=0;
+ hostname[len-1] = 0;
len = strlen(pattern);
if(pattern[len-1]=='.')
- pattern[len-1]=0;
+ pattern[len-1] = 0;
pattern_wildcard = strchr(pattern, '*');
if(pattern_wildcard == NULL)
@@ -95,7 +95,7 @@ static int hostmatch(char *hostname, char *pattern)
match. */
wildcard_enabled = 1;
pattern_label_end = strchr(pattern, '.');
- if(pattern_label_end == NULL || strchr(pattern_label_end+1, '.') == NULL ||
+ if(pattern_label_end == NULL || strchr(pattern_label_end + 1, '.') == NULL ||
pattern_wildcard > pattern_label_end ||
strncasecompare(pattern, "xn--", 4)) {
wildcard_enabled = 0;
@@ -116,9 +116,9 @@ static int hostmatch(char *hostname, char *pattern)
return CURL_HOST_NOMATCH;
prefixlen = pattern_wildcard - pattern;
- suffixlen = pattern_label_end - (pattern_wildcard+1);
+ suffixlen = pattern_label_end - (pattern_wildcard + 1);
return strncasecompare(pattern, hostname, prefixlen) &&
- strncasecompare(pattern_wildcard+1, hostname_label_end - suffixlen,
+ strncasecompare(pattern_wildcard + 1, hostname_label_end - suffixlen,
suffixlen) ?
CURL_HOST_MATCH : CURL_HOST_NOMATCH;
}
@@ -137,7 +137,7 @@ int Curl_cert_hostcheck(const char *match_pattern, const char *hostname)
hostp = strdup(hostname);
if(hostp) {
if(hostmatch(hostp, matchp) == CURL_HOST_MATCH)
- res= 1;
+ res = 1;
free(hostp);
}
free(matchp);
diff --git a/lib/hostip.c b/lib/hostip.c
index 619ec84b..7f010a03 100644
--- a/lib/hostip.c
+++ b/lib/hostip.c
@@ -304,9 +304,9 @@ fetch_addr(struct connectdata *conn,
entry_len = strlen(entry_id);
/* See if its already in our dns cache */
- dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1);
+ dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
- if(dns && (data->set.dns_cache_timeout != -1)) {
+ if(dns && (data->set.dns_cache_timeout != -1)) {
/* See whether the returned entry is stale. Done before we release lock */
struct hostcache_prune_data user;
@@ -316,7 +316,7 @@ fetch_addr(struct connectdata *conn,
if(hostcache_timestamp_remove(&user, dns)) {
infof(data, "Hostname in DNS cache was stale, zapped\n");
dns = NULL; /* the memory deallocation is being handled by the hash */
- Curl_hash_delete(data->dns.hostcache, entry_id, entry_len+1);
+ Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1);
}
}
@@ -403,7 +403,7 @@ Curl_cache_addr(struct Curl_easy *data,
dns->timestamp = 1; /* zero indicates CURLOPT_RESOLVE entry */
/* Store the resolved data in our DNS cache. */
- dns2 = Curl_hash_add(data->dns.hostcache, entry_id, entry_len+1,
+ dns2 = Curl_hash_add(data->dns.hostcache, entry_id, entry_len + 1,
(void *)dns);
if(!dns2) {
free(dns);
@@ -688,8 +688,8 @@ clean_up:
the time we spent until now! */
if(prev_alarm) {
/* there was an alarm() set before us, now put it back */
- unsigned long elapsed_secs = (unsigned long) (Curl_tvdiff(Curl_tvnow(),
- conn->created) / 1000);
+ timediff_t elapsed_secs = Curl_timediff(Curl_now(),
+ conn->created) / 1000;
/* the alarm period is counted in even number of seconds */
unsigned long alarm_set = prev_alarm - elapsed_secs;
@@ -778,7 +778,6 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
{
struct curl_slist *hostp;
char hostname[256];
- char address[256];
int port;
for(hostp = data->change.resolve; hostp; hostp = hostp->next) {
@@ -807,7 +806,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
/* delete entry, ignore if it didn't exist */
- Curl_hash_delete(data->dns.hostcache, entry_id, entry_len+1);
+ Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1);
if(data->share)
Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
@@ -820,6 +819,8 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
Curl_addrinfo *addr;
char *entry_id;
size_t entry_len;
+ char buffer[256];
+ char *address = &buffer[0];
if(3 != sscanf(hostp->data, "%255[^:]:%d:%255s", hostname, &port,
address)) {
@@ -828,6 +829,16 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
continue;
}
+ /* allow IP(v6) address within [brackets] */
+ if(address[0] == '[') {
+ size_t alen = strlen(address);
+ if(address[alen-1] != ']')
+ /* it needs to also end with ] to be valid */
+ continue;
+ address[alen-1] = 0; /* zero terminate there */
+ address++; /* pass the open bracket */
+ }
+
addr = Curl_str2addr(address, port);
if(!addr) {
infof(data, "Address in '%s' found illegal!\n", hostp->data);
@@ -848,7 +859,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
/* See if its already in our dns cache */
- dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1);
+ dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
/* free the allocated entry_id again */
free(entry_id);
diff --git a/lib/hostip4.c b/lib/hostip4.c
index e459328a..9d6f115a 100644
--- a/lib/hostip4.c
+++ b/lib/hostip4.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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,11 @@
#include "curl_setup.h"
+/***********************************************************************
+ * Only for plain IPv4 builds
+ **********************************************************************/
+#ifdef CURLRES_IPV4 /* plain IPv4 code coming up */
+
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
@@ -53,10 +58,6 @@
#include "curl_memory.h"
#include "memdebug.h"
-/***********************************************************************
- * Only for plain IPv4 builds
- **********************************************************************/
-#ifdef CURLRES_IPV4 /* plain IPv4 code coming up */
/*
* Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've
* been set and returns TRUE if they are OK.
@@ -249,7 +250,7 @@ Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
*/
if(CURL_HOSTENT_SIZE >=
- (sizeof(struct hostent)+sizeof(struct hostent_data))) {
+ (sizeof(struct hostent) + sizeof(struct hostent_data))) {
/* August 22nd, 2000: Albert Chin-A-Young brought an updated version
* that should work! September 20: Richard Prescott worked on the buffer
diff --git a/lib/hostip6.c b/lib/hostip6.c
index 4ebfc2dc..7c9988f4 100644
--- a/lib/hostip6.c
+++ b/lib/hostip6.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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,11 @@
#include "curl_setup.h"
+/***********************************************************************
+ * Only for IPv6-enabled builds
+ **********************************************************************/
+#ifdef CURLRES_IPV6
+
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
@@ -54,11 +59,6 @@
#include "curl_memory.h"
#include "memdebug.h"
-/***********************************************************************
- * Only for IPv6-enabled builds
- **********************************************************************/
-#ifdef CURLRES_IPV6
-
#if defined(CURLDEBUG) && defined(HAVE_GETNAMEINFO)
/* These are strictly for memory tracing and are using the same style as the
* family otherwise present in memdebug.c. I put these ones here since they
@@ -212,7 +212,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
if(port) {
snprintf(sbuf, sizeof(sbuf), "%d", port);
- sbufptr=sbuf;
+ sbufptr = sbuf;
}
error = Curl_getaddrinfo_ex(hostname, sbufptr, &hints, &res);
diff --git a/lib/hostsyn.c b/lib/hostsyn.c
index 1a95263c..3de6746f 100644
--- a/lib/hostsyn.c
+++ b/lib/hostsyn.c
@@ -22,6 +22,11 @@
#include "curl_setup.h"
+/***********************************************************************
+ * Only for builds using synchronous name resolves
+ **********************************************************************/
+#ifdef CURLRES_SYNCH
+
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
@@ -51,11 +56,6 @@
/* The last #include file should be: */
#include "memdebug.h"
-/***********************************************************************
- * Only for builds using synchronous name resolves
- **********************************************************************/
-#ifdef CURLRES_SYNCH
-
/*
* Function provided by the resolver backend to set DNS servers to use.
*/
diff --git a/lib/http.c b/lib/http.c
index d66b8482..def51abc 100644
--- a/lib/http.c
+++ b/lib/http.c
@@ -50,6 +50,7 @@
#include "transfer.h"
#include "sendf.h"
#include "formdata.h"
+#include "mime.h"
#include "progress.h"
#include "curl_base64.h"
#include "cookie.h"
@@ -72,7 +73,6 @@
#include "http_proxy.h"
#include "warnless.h"
#include "non-ascii.h"
-#include "conncache.h"
#include "pipeline.h"
#include "http2.h"
#include "connect.h"
@@ -162,6 +162,7 @@ CURLcode Curl_http_setup_conn(struct connectdata *conn)
if(!http)
return CURLE_OUT_OF_MEMORY;
+ Curl_mime_initpart(&http->form, conn->data);
conn->data->req.protop = http;
Curl_http2_setup_conn(conn);
@@ -170,26 +171,6 @@ CURLcode Curl_http_setup_conn(struct connectdata *conn)
return CURLE_OK;
}
-/*
- * checkheaders() checks the linked list of custom HTTP headers for a
- * particular header (prefix).
- *
- * Returns a pointer to the first matching header or NULL if none matched.
- */
-char *Curl_checkheaders(const struct connectdata *conn,
- const char *thisheader)
-{
- struct curl_slist *head;
- size_t thislen = strlen(thisheader);
- struct Curl_easy *data = conn->data;
-
- for(head = data->set.headers;head; head=head->next) {
- if(strncasecompare(head->data, thisheader, thislen))
- return head->data;
- }
-
- return NULL;
-}
/*
* checkProxyHeaders() checks the linked list of custom proxy headers
@@ -209,7 +190,7 @@ char *Curl_checkProxyheaders(const struct connectdata *conn,
for(head = (conn->bits.proxy && data->set.sep_headers) ?
data->set.proxyheaders : data->set.headers;
- head; head=head->next) {
+ head; head = head->next) {
if(strncasecompare(head->data, thisheader, thislen))
return head->data;
}
@@ -427,6 +408,7 @@ static CURLcode http_perhapsrewind(struct connectdata *conn)
expectsend = data->state.infilesize;
break;
case HTTPREQ_POST_FORM:
+ case HTTPREQ_POST_MIME:
expectsend = http->postsize;
break;
default:
@@ -610,7 +592,7 @@ output_auth_headers(struct connectdata *conn,
#endif
#if defined(USE_NTLM) && defined(NTLM_WB_ENABLED)
if(authstatus->picked == CURLAUTH_NTLM_WB) {
- auth="NTLM_WB";
+ auth = "NTLM_WB";
result = Curl_output_ntlm_wb(conn, proxy);
if(result)
return result;
@@ -1022,7 +1004,7 @@ static size_t readmoredata(char *buffer,
http->sending++; /* move one step up */
- http->backup.postsize=0;
+ http->backup.postsize = 0;
}
else
http->postsize = 0;
@@ -1150,7 +1132,7 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
/* there was body data sent beyond the initial header part, pass that
on to the debug callback too */
Curl_debug(conn->data, CURLINFO_DATA_OUT,
- ptr+headlen, bodylen, conn);
+ ptr + headlen, bodylen, conn);
}
}
@@ -1262,7 +1244,7 @@ CURLcode Curl_add_buffer(Curl_send_buffer *in, const void *inptr, size_t size)
(~(size * 2) < (in->size_used * 2)))
new_size = (size_t)-1;
else
- new_size = (in->size_used+size) * 2;
+ new_size = (in->size_used + size) * 2;
if(in->buffer)
/* we have a buffer, enlarge the existing one */
@@ -1339,7 +1321,7 @@ Curl_compareheader(const char *headerline, /* line to check */
clen = strlen(content); /* length of the word to find */
/* find the content string in the rest of the line */
- for(;len>=clen;len--, start++) {
+ for(; len >= clen; len--, start++) {
if(strncasecompare(start, content, clen))
return TRUE; /* match! */
}
@@ -1371,7 +1353,7 @@ CURLcode Curl_http_connect(struct connectdata *conn, bool *done)
if(CONNECT_FIRSTSOCKET_PROXY_SSL())
return CURLE_OK; /* wait for HTTPS proxy SSL initialization to complete */
- if(!Curl_connect_complete(conn))
+ if(Curl_connect_ongoing(conn))
/* nothing else to do except wait right now - we're not done here. */
return CURLE_OK;
@@ -1470,18 +1452,17 @@ CURLcode Curl_http_done(struct connectdata *conn,
Curl_http2_done(conn, premature);
- if(HTTPREQ_POST_FORM == data->set.httpreq) {
- data->req.bytecount = http->readbytecount + http->writebytecount;
+ Curl_mime_cleanpart(&http->form);
- Curl_formclean(&http->sendit); /* Now free that whole lot */
- if(http->form.fp) {
- /* a file being uploaded was left opened, close it! */
- fclose(http->form.fp);
- http->form.fp = NULL;
- }
- }
- else if(HTTPREQ_PUT == data->set.httpreq)
+ switch(data->set.httpreq) {
+ case HTTPREQ_PUT:
+ case HTTPREQ_POST_FORM:
+ case HTTPREQ_POST_MIME:
data->req.bytecount = http->readbytecount + http->writebytecount;
+ break;
+ default:
+ break;
+ }
if(status)
return status;
@@ -1581,7 +1562,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
char *ptr;
struct curl_slist *h[2];
struct curl_slist *headers;
- int numlists=1; /* by default */
+ int numlists = 1; /* by default */
struct Curl_easy *data = conn->data;
int i;
@@ -1613,7 +1594,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
}
/* loop through one or two lists */
- for(i=0; i < numlists; i++) {
+ for(i = 0; i < numlists; i++) {
headers = h[i];
while(headers) {
@@ -1637,15 +1618,19 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
/* this header (extended by formdata.c) is sent later */
checkprefix("Content-Type:", headers->data))
;
+ else if(data->set.httpreq == HTTPREQ_POST_MIME &&
+ /* this header is sent later */
+ checkprefix("Content-Type:", headers->data))
+ ;
else if(conn->bits.authneg &&
/* while doing auth neg, don't allow the custom length since
we will force length zero then */
- checkprefix("Content-Length", headers->data))
+ checkprefix("Content-Length:", headers->data))
;
else if(conn->allocptr.te &&
/* when asking for Transfer-Encoding, don't pass on a custom
Connection: */
- checkprefix("Connection", headers->data))
+ checkprefix("Connection:", headers->data))
;
else if((conn->httpversion == 20) &&
checkprefix("Transfer-Encoding:", headers->data))
@@ -1678,6 +1663,10 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
*ptr = ':';
result = Curl_add_bufferf(req_buffer, "%s\r\n",
headers->data);
+
+ /* restore the previous value */
+ *ptr = ';';
+
if(result)
return result;
}
@@ -1775,7 +1764,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
const char *httpstring;
Curl_send_buffer *req_buffer;
curl_off_t postsize = 0; /* curl_off_t to handle large file sizes */
- int seekerr = CURL_SEEKFUNC_OK;
+ int seekerr = CURL_SEEKFUNC_CANTSEEK;
/* Always consider the DO phase done after this function call, even if there
may be parts of the request that is not yet sent, since we can deal with
@@ -1848,6 +1837,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
switch(httpreq) {
case HTTPREQ_POST:
case HTTPREQ_POST_FORM:
+ case HTTPREQ_POST_MIME:
request = "POST";
break;
case HTTPREQ_PUT:
@@ -1873,7 +1863,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
here. */
if(Curl_checkheaders(conn, "User-Agent:")) {
free(conn->allocptr.uagent);
- conn->allocptr.uagent=NULL;
+ conn->allocptr.uagent = NULL;
}
/* setup the authentication headers */
@@ -1942,6 +1932,48 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
}
#endif
+ switch(httpreq) {
+ case HTTPREQ_POST_MIME:
+ http->sendit = &data->set.mimepost;
+ break;
+ case HTTPREQ_POST_FORM:
+ /* Convert the form structure into a mime structure. */
+ Curl_mime_cleanpart(&http->form);
+ result = Curl_getformdata(data, &http->form, data->set.httppost,
+ data->state.fread_func);
+ if(result)
+ return result;
+ http->sendit = &http->form;
+ break;
+ default:
+ http->sendit = NULL;
+ }
+
+ if(http->sendit) {
+ const char *cthdr = Curl_checkheaders(conn, "Content-Type:");
+
+ /* Read and seek body only. */
+ http->sendit->flags |= MIME_BODY_ONLY;
+
+ /* Prepare the mime structure headers & set content type. */
+
+ if(cthdr)
+ for(cthdr += 13; *cthdr == ' '; cthdr++)
+ ;
+ else if(http->sendit->kind == MIMEKIND_MULTIPART)
+ cthdr = "multipart/form-data";
+
+ curl_mime_headers(http->sendit, data->set.headers, 0);
+ result = Curl_mime_prepare_headers(http->sendit, cthdr,
+ NULL, MIMESTRATEGY_FORM);
+ curl_mime_headers(http->sendit, NULL, 0);
+ if(!result)
+ result = Curl_mime_rewind(http->sendit);
+ if(result)
+ return result;
+ http->postsize = Curl_mime_size(http->sendit);
+ }
+
ptr = Curl_checkheaders(conn, "Transfer-Encoding:");
if(ptr) {
/* Some kind of TE is requested, check if 'chunked' is chosen */
@@ -1949,9 +1981,10 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
Curl_compareheader(ptr, "Transfer-Encoding:", "chunked");
}
else {
- if((conn->handler->protocol&PROTO_FAMILY_HTTP) &&
- data->set.upload &&
- (data->state.infilesize == -1)) {
+ if((conn->handler->protocol & PROTO_FAMILY_HTTP) &&
+ (((httpreq == HTTPREQ_POST_MIME || httpreq == HTTPREQ_POST_FORM) &&
+ http->postsize < 0) ||
+ (data->set.upload && data->state.infilesize == -1))) {
if(conn->bits.authneg)
/* don't enable chunked during auth neg */
;
@@ -2049,7 +2082,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
}
#ifndef CURL_DISABLE_PROXY
- if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
+ if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
/* Using a proxy but does not tunnel through it */
/* The path sent to the proxy is in fact the entire URL. But if the remote
@@ -2123,21 +2156,9 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
}
#endif /* CURL_DISABLE_PROXY */
- if(HTTPREQ_POST_FORM == httpreq) {
- /* we must build the whole post sequence first, so that we have a size of
- the whole transfer before we start to send it */
- result = Curl_getformdata(data, &http->sendit, data->set.httppost,
- Curl_checkheaders(conn, "Content-Type:"),
- &http->postsize);
- if(result)
- return result;
- }
-
http->p_accept = Curl_checkheaders(conn, "Accept:")?NULL:"Accept: */*\r\n";
- if(( (HTTPREQ_POST == httpreq) ||
- (HTTPREQ_POST_FORM == httpreq) ||
- (HTTPREQ_PUT == httpreq) ) &&
+ if((HTTPREQ_POST == httpreq || HTTPREQ_PUT == httpreq) &&
data->state.resume_from) {
/**********************************************************************
* Resuming upload in HTTP means that we PUT or POST and that we have
@@ -2145,6 +2166,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
* a Range: header that will be passed along. We need to "fast forward"
* the file the given number of bytes and decrease the assume upload
* file size before we continue this venture in the dark lands of HTTP.
+ * Resuming mime/form posting at an offset > 0 has no sense and is ignored.
*********************************************************************/
if(data->state.resume_from < 0) {
@@ -2166,7 +2188,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
}
if(seekerr != CURL_SEEKFUNC_OK) {
- curl_off_t passed=0;
+ curl_off_t passed = 0;
if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
failf(data, "Could not seek stream");
@@ -2219,7 +2241,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
conn->allocptr.rangeline = aprintf("Range: bytes=%s\r\n",
data->state.range);
}
- else if((httpreq != HTTPREQ_GET) &&
+ else if((httpreq == HTTPREQ_POST || httpreq == HTTPREQ_PUT) &&
!Curl_checkheaders(conn, "Content-Range:")) {
/* if a line like this was already allocated, free the previous one */
@@ -2237,7 +2259,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
}
else if(data->state.resume_from) {
/* This is because "resume" was selected */
- curl_off_t total_expected_size=
+ curl_off_t total_expected_size =
data->state.resume_from + data->state.infilesize;
conn->allocptr.rangeline =
aprintf("Content-Range: bytes %s%" CURL_FORMAT_CURL_OFF_T
@@ -2347,8 +2369,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
#if !defined(CURL_DISABLE_COOKIES)
if(data->cookies || addcookies) {
- struct Cookie *co=NULL; /* no cookies from start */
- int count=0;
+ struct Cookie *co = NULL; /* no cookies from start */
+ int count = 0;
if(data->cookies) {
Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
@@ -2361,7 +2383,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
}
if(co) {
- struct Cookie *store=co;
+ struct Cookie *store = co;
/* now loop through all cookies that matched */
while(co) {
if(co->value) {
@@ -2415,117 +2437,79 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
switch(httpreq) {
- case HTTPREQ_POST_FORM:
- if(!http->sendit || conn->bits.authneg) {
- /* nothing to post! */
- result = Curl_add_bufferf(req_buffer, "Content-Length: 0\r\n\r\n");
- if(result)
- return result;
-
- result = Curl_add_buffer_send(req_buffer, conn,
- &data->info.request_size, 0, FIRSTSOCKET);
- if(result)
- failf(data, "Failed sending POST request");
- else
- /* setup variables for the upcoming transfer */
- Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, &http->readbytecount,
- -1, NULL);
- break;
- }
-
- if(Curl_FormInit(&http->form, http->sendit)) {
- failf(data, "Internal HTTP POST error!");
- return CURLE_HTTP_POST_ERROR;
- }
-
- /* Get the currently set callback function pointer and store that in the
- form struct since we might want the actual user-provided callback later
- on. The data->set.fread_func pointer itself will be changed for the
- multipart case to the function that returns a multipart formatted
- stream. */
- http->form.fread_func = data->state.fread_func;
-
- /* Set the read function to read from the generated form data */
- data->state.fread_func = (curl_read_callback)Curl_FormReader;
- data->state.in = &http->form;
+ case HTTPREQ_PUT: /* Let's PUT the data to the server! */
- http->sending = HTTPSEND_BODY;
+ if(conn->bits.authneg)
+ postsize = 0;
+ else
+ postsize = data->state.infilesize;
- if(!data->req.upload_chunky &&
- !Curl_checkheaders(conn, "Content-Length:")) {
+ if((postsize != -1) && !data->req.upload_chunky &&
+ (conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length:"))) {
/* only add Content-Length if not uploading chunked */
result = Curl_add_bufferf(req_buffer,
"Content-Length: %" CURL_FORMAT_CURL_OFF_T
- "\r\n", http->postsize);
+ "\r\n", postsize);
if(result)
return result;
}
- result = expect100(data, conn, req_buffer);
- if(result)
- return result;
-
- {
-
- /* Get Content-Type: line from Curl_formpostheader.
- */
- char *contentType;
- size_t linelength=0;
- contentType = Curl_formpostheader((void *)&http->form,
- &linelength);
- if(!contentType) {
- failf(data, "Could not get Content-Type header line!");
- return CURLE_HTTP_POST_ERROR;
- }
-
- result = Curl_add_buffer(req_buffer, contentType, linelength);
+ if(postsize != 0) {
+ result = expect100(data, conn, req_buffer);
if(result)
return result;
}
- /* make the request end in a true CRLF */
- result = Curl_add_buffer(req_buffer, "\r\n", 2);
+ result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers */
if(result)
return result;
- /* set upload size to the progress meter */
- Curl_pgrsSetUploadSize(data, http->postsize);
+ /* set the upload size to the progress meter */
+ Curl_pgrsSetUploadSize(data, postsize);
- /* fire away the whole request to the server */
+ /* this sends the buffer and frees all the buffer resources */
result = Curl_add_buffer_send(req_buffer, conn,
&data->info.request_size, 0, FIRSTSOCKET);
if(result)
- failf(data, "Failed sending POST request");
+ failf(data, "Failed sending PUT request");
else
- /* setup variables for the upcoming transfer */
+ /* prepare for transfer */
Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
- &http->readbytecount, FIRSTSOCKET,
- &http->writebytecount);
-
- if(result) {
- Curl_formclean(&http->sendit); /* free that whole lot */
- return result;
- }
-
- /* convert the form data */
- result = Curl_convert_form(data, http->sendit);
- if(result) {
- Curl_formclean(&http->sendit); /* free that whole lot */
+ &http->readbytecount, postsize?FIRSTSOCKET:-1,
+ postsize?&http->writebytecount:NULL);
+ if(result)
return result;
- }
-
break;
- case HTTPREQ_PUT: /* Let's PUT the data to the server! */
+ case HTTPREQ_POST_FORM:
+ case HTTPREQ_POST_MIME:
+ /* This is form posting using mime data. */
+ if(conn->bits.authneg) {
+ /* nothing to post! */
+ result = Curl_add_bufferf(req_buffer, "Content-Length: 0\r\n\r\n");
+ if(result)
+ return result;
- if(conn->bits.authneg)
- postsize = 0;
- else
- postsize = data->state.infilesize;
+ result = Curl_add_buffer_send(req_buffer, conn,
+ &data->info.request_size, 0, FIRSTSOCKET);
+ if(result)
+ failf(data, "Failed sending POST request");
+ else
+ /* setup variables for the upcoming transfer */
+ Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, &http->readbytecount,
+ -1, NULL);
+ break;
+ }
- if((postsize != -1) && !data->req.upload_chunky &&
+ postsize = http->postsize;
+
+ /* We only set Content-Length and allow a custom Content-Length if
+ we don't upload data chunked, as RFC2616 forbids us to set both
+ kinds of headers (Transfer-Encoding: chunked and Content-Length) */
+ if(postsize != -1 && !data->req.upload_chunky &&
(conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length:"))) {
- /* only add Content-Length if not uploading chunked */
+ /* we allow replacing this header if not during auth negotiation,
+ although it isn't very wise to actually set your own */
result = Curl_add_bufferf(req_buffer,
"Content-Length: %" CURL_FORMAT_CURL_OFF_T
"\r\n", postsize);
@@ -2533,24 +2517,52 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
return result;
}
- if(postsize != 0) {
+ /* Output mime-generated headers. */
+ {
+ struct curl_slist *hdr;
+
+ for(hdr = http->sendit->curlheaders; hdr; hdr = hdr->next) {
+ result = Curl_add_bufferf(req_buffer, "%s\r\n", hdr->data);
+ if(result)
+ return result;
+ }
+ }
+
+ /* For really small posts we don't use Expect: headers at all, and for
+ the somewhat bigger ones we allow the app to disable it. Just make
+ sure that the expect100header is always set to the preferred value
+ here. */
+ ptr = Curl_checkheaders(conn, "Expect:");
+ if(ptr) {
+ data->state.expect100header =
+ Curl_compareheader(ptr, "Expect:", "100-continue");
+ }
+ else if(postsize > EXPECT_100_THRESHOLD || postsize < 0) {
result = expect100(data, conn, req_buffer);
if(result)
return result;
}
+ else
+ data->state.expect100header = FALSE;
- result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers */
+ /* make the request end in a true CRLF */
+ result = Curl_add_buffer(req_buffer, "\r\n", 2);
if(result)
return result;
/* set the upload size to the progress meter */
Curl_pgrsSetUploadSize(data, postsize);
+ /* Read from mime structure. */
+ data->state.fread_func = (curl_read_callback) Curl_mime_read;
+ data->state.in = (void *) http->sendit;
+ http->sending = HTTPSEND_BODY;
+
/* this sends the buffer and frees all the buffer resources */
result = Curl_add_buffer_send(req_buffer, conn,
&data->info.request_size, 0, FIRSTSOCKET);
if(result)
- failf(data, "Failed sending PUT request");
+ failf(data, "Failed sending POST request");
else
/* prepare for transfer */
Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
@@ -2558,6 +2570,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
postsize?&http->writebytecount:NULL);
if(result)
return result;
+
break;
case HTTPREQ_POST:
@@ -2614,7 +2627,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
its size. */
if(conn->httpversion != 20 &&
!data->state.expect100header &&
- (postsize < MAX_INITIAL_POST_SIZE)) {
+ (postsize < MAX_INITIAL_POST_SIZE)) {
/* if we don't use expect: 100 AND
postsize is less than MAX_INITIAL_POST_SIZE
@@ -2779,7 +2792,7 @@ checkhttpprefix(struct Curl_easy *data,
failf(data, "Failed to allocate memory for conversion!");
return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */
}
- if(CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s)+1)) {
+ if(CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s) + 1)) {
/* Curl_convert_from_network calls failf if unsuccessful */
free(scratch);
return FALSE; /* can't return CURLE_foobar so return FALSE */
@@ -2809,6 +2822,7 @@ static bool
checkrtspprefix(struct Curl_easy *data,
const char *s)
{
+ bool result = FALSE;
#ifdef CURL_DOES_CONVERSIONS
/* convert from the network encoding using a scratch area */
@@ -2817,18 +2831,19 @@ checkrtspprefix(struct Curl_easy *data,
failf(data, "Failed to allocate memory for conversion!");
return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */
}
- if(CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s)+1)) {
+ if(CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s) + 1)) {
/* Curl_convert_from_network calls failf if unsuccessful */
- free(scratch);
- return FALSE; /* can't return CURLE_foobar so return FALSE */
+ result = FALSE; /* can't return CURLE_foobar so return FALSE */
}
- s = scratch;
+ else
+ result = checkprefix("RTSP/", scratch)? TRUE: FALSE;
+ free(scratch);
#else
(void)data; /* unused */
+ result = checkprefix("RTSP/", s)? TRUE: FALSE;
#endif /* CURL_DOES_CONVERSIONS */
- if(checkprefix("RTSP/", s))
- return TRUE;
- return FALSE;
+
+ return result;
}
#endif /* CURL_DISABLE_RTSP */
@@ -2870,14 +2885,14 @@ static CURLcode header_append(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
}
- newsize=CURLMAX((k->hbuflen+ length)*3/2, data->state.headersize*2);
+ newsize = CURLMAX((k->hbuflen + length) * 3 / 2, data->state.headersize*2);
hbufp_index = k->hbufp - data->state.headerbuff;
newbuff = realloc(data->state.headerbuff, newsize);
if(!newbuff) {
failf(data, "Failed to alloc memory for big header!");
return CURLE_OUT_OF_MEMORY;
}
- data->state.headersize=newsize;
+ data->state.headersize = newsize;
data->state.headerbuff = newbuff;
k->hbufp = data->state.headerbuff + hbufp_index;
}
@@ -2970,7 +2985,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
}
/* decrease the size of the remaining (supposed) header line */
- rest_length = (k->end_ptr - k->str)+1;
+ rest_length = (k->end_ptr - k->str) + 1;
*nread -= (ssize_t)rest_length;
k->str = k->end_ptr + 1; /* move past new line */
@@ -3088,7 +3103,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
!(conn->handler->protocol & CURLPROTO_RTSP) &&
data->set.httpreq != HTTPREQ_HEAD) {
/* On HTTP 1.1, when connection is not to get closed, but no
- Content-Length nor Content-Encoding chunked have been
+ Content-Length nor Transfer-Encoding chunked have been
received, according to RFC2616 section 4.4 point 5, we
assume that the server will close the connection to
signal the end of the document. */
@@ -3169,6 +3184,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
case HTTPREQ_PUT:
case HTTPREQ_POST:
case HTTPREQ_POST_FORM:
+ case HTTPREQ_POST_MIME:
/* We got an error response. If this happened before the whole
* request body has been sent we stop sending and mark the
* connection for closure after we've read the entire response.
@@ -3296,7 +3312,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
#define HEADER1 scratch
#define SCRATCHSIZE 21
CURLcode res;
- char scratch[SCRATCHSIZE+1]; /* "HTTP/major.minor 123" */
+ char scratch[SCRATCHSIZE + 1]; /* "HTTP/major.minor 123" */
/* We can't really convert this yet because we
don't know if it's the 1st header line or the body.
So we do a partial conversion into a scratch area,
@@ -3337,7 +3353,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
separator = ' ';
}
- if((nc==4) && (' ' == separator)) {
+ if((nc == 4) && (' ' == separator)) {
conn->httpversion += 10 * httpversion_major;
if(k->upgr101 == UPGR101_RECEIVED) {
@@ -3350,7 +3366,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
/* this is the real world, not a Nirvana
NCSA 1.5.x returns this crap when asked for HTTP/1.1
*/
- nc=sscanf(HEADER1, " HTTP %3d", &k->httpcode);
+ nc = sscanf(HEADER1, " HTTP %3d", &k->httpcode);
conn->httpversion = 10;
/* If user has set option HTTP200ALIASES,
@@ -3370,12 +3386,14 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
}
}
else if(conn->handler->protocol & CURLPROTO_RTSP) {
+ char separator;
nc = sscanf(HEADER1,
- " RTSP/%d.%d %3d",
+ " RTSP/%1d.%1d%c%3d",
&rtspversion_major,
&conn->rtspversion,
+ &separator,
&k->httpcode);
- if(nc==3) {
+ if((nc == 4) && (' ' == separator)) {
conn->rtspversion += 10 * rtspversion_major;
conn->httpversion = 11; /* For us, RTSP acts like HTTP 1.1 */
}
@@ -3407,7 +3425,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
((k->httpcode != 407) || !conn->bits.proxy_user_passwd) ) {
if(data->state.resume_from &&
- (data->set.httpreq==HTTPREQ_GET) &&
+ (data->set.httpreq == HTTPREQ_GET) &&
(k->httpcode == 416)) {
/* "Requested Range Not Satisfiable", just proceed and
pretend this is no error */
@@ -3463,8 +3481,8 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
* fields. */
if(data->set.timecondition)
data->info.timecond = TRUE;
- k->size=0;
- k->maxdownload=0;
+ k->size = 0;
+ k->maxdownload = 0;
k->ignorecl = TRUE; /* ignore Content-Length headers */
break;
default:
@@ -3486,28 +3504,32 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
/* Check for Content-Length: header lines to get size */
if(!k->ignorecl && !data->set.ignorecl &&
checkprefix("Content-Length:", k->p)) {
- curl_off_t contentlength = curlx_strtoofft(k->p+15, NULL, 10);
- if(data->set.max_filesize &&
- contentlength > data->set.max_filesize) {
- failf(data, "Maximum file size exceeded");
- return CURLE_FILESIZE_EXCEEDED;
- }
- if(contentlength >= 0) {
- k->size = contentlength;
- k->maxdownload = k->size;
- /* we set the progress download size already at this point
- just to make it easier for apps/callbacks to extract this
- info as soon as possible */
- Curl_pgrsSetDownloadSize(data, k->size);
- }
- else {
- /* Negative Content-Length is really odd, and we know it
- happens for example when older Apache servers send large
- files */
- streamclose(conn, "negative content-length");
- infof(data, "Negative content-length: %" CURL_FORMAT_CURL_OFF_T
- ", closing after transfer\n", contentlength);
+ curl_off_t contentlength;
+ if(!curlx_strtoofft(k->p + 15, NULL, 10, &contentlength)) {
+ if(data->set.max_filesize &&
+ contentlength > data->set.max_filesize) {
+ failf(data, "Maximum file size exceeded");
+ return CURLE_FILESIZE_EXCEEDED;
+ }
+ if(contentlength >= 0) {
+ k->size = contentlength;
+ k->maxdownload = k->size;
+ /* we set the progress download size already at this point
+ just to make it easier for apps/callbacks to extract this
+ info as soon as possible */
+ Curl_pgrsSetDownloadSize(data, k->size);
+ }
+ else {
+ /* Negative Content-Length is really odd, and we know it
+ happens for example when older Apache servers send large
+ files */
+ streamclose(conn, "negative content-length");
+ infof(data, "Negative content-length: %" CURL_FORMAT_CURL_OFF_T
+ ", closing after transfer\n", contentlength);
+ }
}
+ else
+ infof(data, "Illegal Content-Length: header\n");
}
/* check for Content-Type: header lines to get the MIME-type */
else if(checkprefix("Content-Type:", k->p)) {
@@ -3591,51 +3613,9 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
* of chunks, and a chunk-data set to zero signals the
* end-of-chunks. */
- char *start;
-
- /* Find the first non-space letter */
- start = k->p + 18;
-
- for(;;) {
- /* skip whitespaces and commas */
- while(*start && (ISSPACE(*start) || (*start == ',')))
- start++;
-
- if(checkprefix("chunked", start)) {
- k->chunk = TRUE; /* chunks coming our way */
-
- /* init our chunky engine */
- Curl_httpchunk_init(conn);
-
- start += 7;
- }
-
- if(k->auto_decoding)
- /* TODO: we only support the first mentioned compression for now */
- break;
-
- if(checkprefix("identity", start)) {
- k->auto_decoding = IDENTITY;
- start += 8;
- }
- else if(checkprefix("deflate", start)) {
- k->auto_decoding = DEFLATE;
- start += 7;
- }
- else if(checkprefix("gzip", start)) {
- k->auto_decoding = GZIP;
- start += 4;
- }
- else if(checkprefix("x-gzip", start)) {
- k->auto_decoding = GZIP;
- start += 6;
- }
- else
- /* unknown! */
- break;
-
- }
-
+ result = Curl_build_unencoding_stack(conn, k->p + 18, TRUE);
+ if(result)
+ return result;
}
else if(checkprefix("Content-Encoding:", k->p) &&
data->set.str[STRING_ENCODING]) {
@@ -3646,21 +3626,9 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
* 2616). zlib cannot handle compress. However, errors are
* handled further down when the response body is processed
*/
- char *start;
-
- /* Find the first non-space letter */
- start = k->p + 17;
- while(*start && ISSPACE(*start))
- start++;
-
- /* Record the content-encoding for later use */
- if(checkprefix("identity", start))
- k->auto_decoding = IDENTITY;
- else if(checkprefix("deflate", start))
- k->auto_decoding = DEFLATE;
- else if(checkprefix("gzip", start)
- || checkprefix("x-gzip", start))
- k->auto_decoding = GZIP;
+ result = Curl_build_unencoding_stack(conn, k->p + 17, FALSE);
+ if(result)
+ return result;
}
else if(checkprefix("Content-Range:", k->p)) {
/* Content-Range: bytes [num]-
@@ -3682,11 +3650,11 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
/* if it truly stopped on a digit */
if(ISDIGIT(*ptr)) {
- k->offset = curlx_strtoofft(ptr, NULL, 10);
-
- if(data->state.resume_from == k->offset)
- /* we asked for a resume and we got it */
- k->content_range = TRUE;
+ if(!curlx_strtoofft(ptr, NULL, 10, &k->offset)) {
+ if(data->state.resume_from == k->offset)
+ /* we asked for a resume and we got it */
+ k->content_range = TRUE;
+ }
}
else
data->state.resume_from = 0; /* get everything */
@@ -3697,7 +3665,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
Curl_share_lock(data, CURL_LOCK_DATA_COOKIE,
CURL_LOCK_ACCESS_SINGLE);
Curl_cookie_add(data,
- data->cookies, TRUE, k->p+11,
+ data->cookies, TRUE, k->p + 11,
/* If there is a custom-set Host: name, use it
here, or else use real peer host name. */
conn->allocptr.cookiehost?
@@ -3708,8 +3676,8 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
#endif
else if(checkprefix("Last-Modified:", k->p) &&
(data->set.timecondition || data->set.get_filetime) ) {
- time_t secs=time(NULL);
- k->timeofdoc = curl_getdate(k->p+strlen("Last-Modified:"),
+ time_t secs = time(NULL);
+ k->timeofdoc = curl_getdate(k->p + strlen("Last-Modified:"),
&secs);
if(data->set.get_filetime)
data->info.filetime = (long)k->timeofdoc;
diff --git a/lib/http.h b/lib/http.h
index a845f564..d2781bc0 100644
--- a/lib/http.h
+++ b/lib/http.h
@@ -40,8 +40,6 @@ bool Curl_compareheader(const char *headerline, /* line to check */
const char *header, /* header keyword _with_ colon */
const char *content); /* content string to find */
-char *Curl_checkheaders(const struct connectdata *conn,
- const char *thisheader);
char *Curl_copy_header_value(const char *header);
char *Curl_checkProxyheaders(const struct connectdata *conn,
@@ -130,7 +128,7 @@ CURLcode Curl_http_perhapsrewind(struct connectdata *conn);
* HTTP unique setup
***************************************************************************/
struct HTTP {
- struct FormData *sendit;
+ curl_mimepart *sendit;
curl_off_t postsize; /* off_t to handle large file sizes */
const char *postdata;
@@ -140,7 +138,7 @@ struct HTTP {
curl_off_t writebytecount;
/* For FORM posting */
- struct Form form;
+ curl_mimepart form;
struct back {
curl_read_callback fread_func; /* backup storage for fread pointer */
diff --git a/lib/http2.c b/lib/http2.c
index 0e558013..8e2fc719 100644
--- a/lib/http2.c
+++ b/lib/http2.c
@@ -32,7 +32,6 @@
#include "curl_base64.h"
#include "strcase.h"
#include "multiif.h"
-#include "conncache.h"
#include "url.h"
#include "connect.h"
#include "strtoofft.h"
@@ -384,12 +383,12 @@ char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header)
struct HTTP *stream = h->data->req.protop;
size_t len = strlen(header);
size_t i;
- for(i=0; i<stream->push_headers_used; i++) {
+ for(i = 0; i<stream->push_headers_used; i++) {
if(!strncmp(header, stream->push_headers[i], len)) {
/* sub-match, make sure that it is followed by a colon */
if(stream->push_headers[i][len] != ':')
continue;
- return &stream->push_headers[i][len+1];
+ return &stream->push_headers[i][len + 1];
}
}
}
@@ -464,7 +463,7 @@ static int push_promise(struct Curl_easy *data,
data->multi->push_userp);
/* free the headers again */
- for(i=0; i<stream->push_headers_used; i++)
+ for(i = 0; i<stream->push_headers_used; i++)
free(stream->push_headers[i]);
free(stream->push_headers);
stream->push_headers = NULL;
@@ -1184,14 +1183,17 @@ CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req,
httpc->local_settings_num);
if(!binlen) {
failf(conn->data, "nghttp2 unexpectedly failed on pack_settings_payload");
+ Curl_add_buffer_free(req);
return CURLE_FAILED_INIT;
}
conn->proto.httpc.binlen = binlen;
result = Curl_base64url_encode(conn->data, (const char *)binsettings, binlen,
&base64, &blen);
- if(result)
+ if(result) {
+ Curl_add_buffer_free(req);
return result;
+ }
result = Curl_add_bufferf(req,
"Connection: Upgrade, HTTP2-Settings\r\n"
@@ -1582,7 +1584,7 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
failf(data, "nghttp2_session_mem_recv() returned %d:%s\n",
rv, nghttp2_strerror((int)rv));
*err = CURLE_RECV_ERROR;
- return 0;
+ return -1;
}
DEBUGF(infof(data, "nghttp2_session_mem_recv() returns %zd\n", rv));
if(nread == rv) {
@@ -1600,7 +1602,7 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
rv = h2_session_send(data, httpc->h2);
if(rv != 0) {
*err = CURLE_SEND_ERROR;
- return 0;
+ return -1;
}
if(should_close_session(httpc)) {
@@ -1846,9 +1848,6 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
goto fail;
}
- hdbuf = end + 1;
-
- end = line_end;
nva[2].name = (unsigned char *)":scheme";
nva[2].namelen = strlen((char *)nva[2].name);
if(conn->handler->flags & PROTOPT_SSL)
@@ -1955,6 +1954,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
switch(conn->data->set.httpreq) {
case HTTPREQ_POST:
case HTTPREQ_POST_FORM:
+ case HTTPREQ_POST_MIME:
case HTTPREQ_PUT:
if(conn->data->state.infilesize != -1)
stream->upload_left = conn->data->state.infilesize;
diff --git a/lib/http_chunks.c b/lib/http_chunks.c
index 1bdf6974..16164296 100644
--- a/lib/http_chunks.c
+++ b/lib/http_chunks.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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
@@ -86,8 +86,8 @@ static bool Curl_isxdigit(char digit)
void Curl_httpchunk_init(struct connectdata *conn)
{
struct Curl_chunker *chunk = &conn->chunk;
- chunk->hexindex=0; /* start at 0 */
- chunk->dataleft=0; /* no data left yet! */
+ chunk->hexindex = 0; /* start at 0 */
+ chunk->dataleft = 0; /* no data left yet! */
chunk->state = CHUNK_HEX; /* we get hex first! */
}
@@ -107,7 +107,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
ssize_t datalen,
ssize_t *wrotep)
{
- CURLcode result=CURLE_OK;
+ CURLcode result = CURLE_OK;
struct Curl_easy *data = conn->data;
struct Curl_chunker *ch = &conn->chunk;
struct SingleRequest *k = &data->req;
@@ -147,7 +147,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
return CHUNKE_ILLEGAL_HEX;
/* length and datap are unmodified */
- ch->hexbuffer[ch->hexindex]=0;
+ ch->hexbuffer[ch->hexindex] = 0;
/* convert to host encoding before calling strtoul */
result = Curl_convert_from_network(conn->data, ch->hexbuffer,
@@ -158,9 +158,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
return CHUNKE_ILLEGAL_HEX;
}
- ch->datasize=curlx_strtoofft(ch->hexbuffer, &endptr, 16);
- if((ch->datasize == CURL_OFF_T_MAX) && (errno == ERANGE))
- /* overflow is an error */
+ if(curlx_strtoofft(ch->hexbuffer, &endptr, 16, &ch->datasize))
return CHUNKE_ILLEGAL_HEX;
ch->state = CHUNK_LF; /* now wait for the CRLF */
}
@@ -172,7 +170,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
/* we're now expecting data to come, unless size was zero! */
if(0 == ch->datasize) {
ch->state = CHUNK_TRAILER; /* now check for trailers */
- conn->trlPos=0;
+ conn->trlPos = 0;
}
else
ch->state = CHUNK_DATA;
@@ -189,49 +187,17 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
piece = curlx_sotouz((ch->datasize >= length)?length:ch->datasize);
/* Write the data portion available */
-#ifdef HAVE_LIBZ
- switch(conn->data->set.http_ce_skip?
- IDENTITY : data->req.auto_decoding) {
- case IDENTITY:
-#endif
- if(!k->ignorebody) {
- if(!data->set.http_te_skip)
- result = Curl_client_write(conn, CLIENTWRITE_BODY, datap,
- piece);
- else
- result = CURLE_OK;
- }
-#ifdef HAVE_LIBZ
- break;
-
- case DEFLATE:
- /* update data->req.keep.str to point to the chunk data. */
- data->req.str = datap;
- result = Curl_unencode_deflate_write(conn, &data->req,
- (ssize_t)piece);
- break;
-
- case GZIP:
- /* update data->req.keep.str to point to the chunk data. */
- data->req.str = datap;
- result = Curl_unencode_gzip_write(conn, &data->req,
- (ssize_t)piece);
- break;
-
- default:
- failf(conn->data,
- "Unrecognized content encoding type. "
- "libcurl understands `identity', `deflate' and `gzip' "
- "content encodings.");
- return CHUNKE_BAD_ENCODING;
+ if(conn->data->set.http_ce_skip || !k->writer_stack) {
+ if(!k->ignorebody)
+ result = Curl_client_write(conn, CLIENTWRITE_BODY, datap, piece);
}
-#endif
+ else
+ result = Curl_unencode_write(conn, k->writer_stack, datap, piece);
if(result)
return CHUNKE_WRITE_ERROR;
*wrote += piece;
-
ch->datasize -= piece; /* decrease amount left to expect */
datap += piece; /* move read pointer forward */
length -= piece; /* decrease space left in this round */
@@ -259,9 +225,9 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
if(conn->trlPos) {
/* we allocate trailer with 3 bytes extra room to fit this */
- conn->trailer[conn->trlPos++]=0x0d;
- conn->trailer[conn->trlPos++]=0x0a;
- conn->trailer[conn->trlPos]=0;
+ conn->trailer[conn->trlPos++] = 0x0d;
+ conn->trailer[conn->trlPos++] = 0x0a;
+ conn->trailer[conn->trlPos] = 0;
/* Convert to host encoding before calling Curl_client_write */
result = Curl_convert_from_network(conn->data, conn->trailer,
@@ -277,7 +243,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
if(result)
return CHUNKE_WRITE_ERROR;
}
- conn->trlPos=0;
+ conn->trlPos = 0;
ch->state = CHUNK_TRAILER_CR;
if(*datap == 0x0a)
/* already on the LF */
@@ -301,7 +267,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
ptr = realloc(conn->trailer, conn->trlMax + 3);
}
else {
- conn->trlMax=128;
+ conn->trlMax = 128;
ptr = malloc(conn->trlMax + 3);
}
if(!ptr)
diff --git a/lib/http_ntlm.c b/lib/http_ntlm.c
index 8a78bd29..0f1edcf6 100644
--- a/lib/http_ntlm.c
+++ b/lib/http_ntlm.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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
@@ -37,11 +37,14 @@
#include "sendf.h"
#include "strcase.h"
#include "http_ntlm.h"
+#include "curl_ntlm_core.h"
#include "curl_ntlm_wb.h"
#include "vauth/vauth.h"
#include "url.h"
-#if defined(USE_NSS)
+/* SSL backend-specific #if branches in this file must be kept in the order
+ documented in curl_ntlm_core. */
+#if defined(NTLM_NEEDS_NSS_INIT)
#include "vtls/nssg.h"
#elif defined(USE_WINDOWS_SSPI)
#include "curl_sspi.h"
@@ -129,7 +132,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
DEBUGASSERT(conn);
DEBUGASSERT(conn->data);
-#ifdef USE_NSS
+#if defined(NTLM_NEEDS_NSS_INIT)
if(CURLE_OK != Curl_nss_force_init(conn->data))
return CURLE_OUT_OF_MEMORY;
#endif
@@ -170,8 +173,8 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
case NTLMSTATE_TYPE1:
default: /* for the weird cases we (re)start here */
/* Create a type-1 message */
- result = Curl_auth_create_ntlm_type1_message(userp, passwdp, ntlm, &base64,
- &len);
+ result = Curl_auth_create_ntlm_type1_message(conn->data, userp, passwdp,
+ ntlm, &base64, &len);
if(result)
return result;
diff --git a/lib/http_proxy.c b/lib/http_proxy.c
index 36567d36..0283c1f3 100644
--- a/lib/http_proxy.c
+++ b/lib/http_proxy.c
@@ -137,7 +137,7 @@ CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex)
bool Curl_connect_complete(struct connectdata *conn)
{
- return conn->connect_state &&
+ return !conn->connect_state ||
(conn->connect_state->tunnel_state == TUNNEL_COMPLETE);
}
@@ -163,10 +163,10 @@ static CURLcode connect_init(struct connectdata *conn, bool reinit)
s = conn->connect_state;
}
s->tunnel_state = TUNNEL_INIT;
- s->keepon=TRUE;
+ s->keepon = TRUE;
s->line_start = s->connect_buffer;
s->ptr = s->line_start;
- s->cl=0;
+ s->cl = 0;
return CURLE_OK;
}
@@ -182,13 +182,13 @@ static CURLcode CONNECT(struct connectdata *conn,
const char *hostname,
int remote_port)
{
- int subversion=0;
- struct Curl_easy *data=conn->data;
+ int subversion = 0;
+ struct Curl_easy *data = conn->data;
struct SingleRequest *k = &data->req;
CURLcode result;
curl_socket_t tunnelsocket = conn->sock[sockindex];
bool closeConnection = FALSE;
- time_t check;
+ timediff_t check;
struct http_connect_state *s = conn->connect_state;
#define SELECT_OK 0
@@ -234,8 +234,8 @@ static CURLcode CONNECT(struct connectdata *conn,
if(!result) {
char *host = NULL;
- const char *proxyconn="";
- const char *useragent="";
+ const char *proxyconn = "";
+ const char *useragent = "";
const char *http = (conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) ?
"1.0" : "1.1";
bool ipv6_ip = conn->bits.ipv6_ip;
@@ -244,7 +244,7 @@ static CURLcode CONNECT(struct connectdata *conn,
/* the hostname may be different */
if(hostname != conn->host.name)
ipv6_ip = (strchr(hostname, ':') != NULL);
- hostheader= /* host:port with IPv6 support */
+ hostheader = /* host:port with IPv6 support */
aprintf("%s%s%s:%hu", ipv6_ip?"[":"", hostname, ipv6_ip?"]":"",
remote_port);
if(!hostheader) {
@@ -410,7 +410,8 @@ static CURLcode CONNECT(struct connectdata *conn,
}
/* convert from the network encoding */
- result = Curl_convert_from_network(data, line_start, perline);
+ result = Curl_convert_from_network(data, s->line_start,
+ (size_t)s->perline);
/* Curl_convert_from_network calls failf if unsuccessful */
if(result)
return result;
@@ -523,8 +524,8 @@ static CURLcode CONNECT(struct connectdata *conn,
k->httpcode);
}
else {
- s->cl = curlx_strtoofft(s->line_start +
- strlen("Content-Length:"), NULL, 10);
+ (void)curlx_strtoofft(s->line_start +
+ strlen("Content-Length:"), NULL, 10, &s->cl);
}
}
else if(Curl_compareheader(s->line_start, "Connection:", "close"))
@@ -566,7 +567,7 @@ static CURLcode CONNECT(struct connectdata *conn,
if(error)
return CURLE_RECV_ERROR;
- if(data->info.httpproxycode != 200) {
+ if(data->info.httpproxycode/100 != 2) {
/* Deal with the possibly already received authenticate
headers. 'newurl' is set to a new URL if we must loop. */
result = Curl_http_auth_act(conn);
@@ -597,7 +598,7 @@ static CURLcode CONNECT(struct connectdata *conn,
} while(data->req.newurl);
- if(200 != data->req.httpcode) {
+ if(data->info.httpproxycode/100 != 2) {
if(closeConnection && data->req.newurl) {
conn->bits.proxy_connect_closed = TRUE;
infof(data, "Connect me again please\n");
@@ -633,7 +634,8 @@ static CURLcode CONNECT(struct connectdata *conn,
data->state.authproxy.done = TRUE;
- infof(data, "Proxy replied OK to CONNECT request\n");
+ infof(data, "Proxy replied %d to CONNECT request\n",
+ data->info.httpproxycode);
data->req.ignorebody = FALSE; /* put it (back) to non-ignore state */
conn->bits.rewindaftersend = FALSE; /* make sure this isn't set for the
document request */
diff --git a/lib/if2ip.c b/lib/if2ip.c
index a91b6d2a..ce38ea11 100644
--- a/lib/if2ip.c
+++ b/lib/if2ip.c
@@ -103,7 +103,7 @@ bool Curl_if_is_interface_name(const char *interf)
struct ifaddrs *iface, *head;
if(getifaddrs(&head) >= 0) {
- for(iface=head; iface != NULL; iface=iface->ifa_next) {
+ for(iface = head; iface != NULL; iface = iface->ifa_next) {
if(strcasecompare(iface->ifa_name, interf)) {
result = TRUE;
break;
@@ -131,7 +131,7 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
#endif
if(getifaddrs(&head) >= 0) {
- for(iface = head; iface != NULL; iface=iface->ifa_next) {
+ for(iface = head; iface != NULL; iface = iface->ifa_next) {
if(iface->ifa_addr != NULL) {
if(iface->ifa_addr->sa_family == af) {
if(strcasecompare(iface->ifa_name, interf)) {
@@ -230,7 +230,7 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
return IF2IP_NOT_FOUND;
memset(&req, 0, sizeof(req));
- memcpy(req.ifr_name, interf, len+1);
+ memcpy(req.ifr_name, interf, len + 1);
req.ifr_addr.sa_family = AF_INET;
if(ioctl(dummy, SIOCGIFADDR, &req) < 0) {
diff --git a/lib/imap.c b/lib/imap.c
index 48af2902..1b52f73a 100644
--- a/lib/imap.c
+++ b/lib/imap.c
@@ -68,6 +68,7 @@
#include "http.h" /* for HTTP proxy tunnel stuff */
#include "socks.h"
#include "imap.h"
+#include "mime.h"
#include "strtoofft.h"
#include "strcase.h"
#include "vtls/vtls.h"
@@ -162,11 +163,15 @@ const struct Curl_handler Curl_handler_imaps = {
};
#endif
+#define IMAP_RESP_OK 1
+#define IMAP_RESP_NOT_OK 2
+#define IMAP_RESP_PREAUTH 3
+
/* SASL parameters for the imap protocol */
static const struct SASLproto saslimap = {
"imap", /* The service name */
'+', /* Code received when continuation is expected */
- 'O', /* Code to receive upon authentication success */
+ IMAP_RESP_OK, /* Code to receive upon authentication success */
0, /* Maximum initial response length (no max) */
imap_perform_authenticate, /* Send authentication command */
imap_continue_authenticate, /* Send authentication continuation */
@@ -249,15 +254,11 @@ static bool imap_endofresp(struct connectdata *conn, char *line, size_t len,
len -= id_len + 1;
if(len >= 2 && !memcmp(line, "OK", 2))
- *resp = 'O';
- else if(len >= 2 && !memcmp(line, "NO", 2))
- *resp = 'N';
- else if(len >= 3 && !memcmp(line, "BAD", 3))
- *resp = 'B';
- else {
- failf(conn->data, "Bad tagged response");
- *resp = -1;
- }
+ *resp = IMAP_RESP_OK;
+ else if(len >= 7 && !memcmp(line, "PREAUTH", 7))
+ *resp = IMAP_RESP_PREAUTH;
+ else
+ *resp = IMAP_RESP_NOT_OK;
return TRUE;
}
@@ -274,15 +275,15 @@ static bool imap_endofresp(struct connectdata *conn, char *line, size_t len,
case IMAP_LIST:
if((!imap->custom && !imap_matchresp(line, len, "LIST")) ||
(imap->custom && !imap_matchresp(line, len, imap->custom) &&
- (strcmp(imap->custom, "STORE") ||
+ (!strcasecompare(imap->custom, "STORE") ||
!imap_matchresp(line, len, "FETCH")) &&
- strcmp(imap->custom, "SELECT") &&
- strcmp(imap->custom, "EXAMINE") &&
- strcmp(imap->custom, "SEARCH") &&
- strcmp(imap->custom, "EXPUNGE") &&
- strcmp(imap->custom, "LSUB") &&
- strcmp(imap->custom, "UID") &&
- strcmp(imap->custom, "NOOP")))
+ !strcasecompare(imap->custom, "SELECT") &&
+ !strcasecompare(imap->custom, "EXAMINE") &&
+ !strcasecompare(imap->custom, "SEARCH") &&
+ !strcasecompare(imap->custom, "EXPUNGE") &&
+ !strcasecompare(imap->custom, "LSUB") &&
+ !strcasecompare(imap->custom, "UID") &&
+ !strcasecompare(imap->custom, "NOOP")))
return FALSE;
break;
@@ -563,9 +564,10 @@ static CURLcode imap_perform_authentication(struct connectdata *conn)
struct imap_conn *imapc = &conn->proto.imapc;
saslprogress progress;
- /* Check we have enough data to authenticate with and end the
- connect phase if we don't */
- if(!Curl_sasl_can_authenticate(&imapc->sasl, conn)) {
+ /* Check if already authenticated OR if there is enough data to authenticate
+ with and end the connect phase if we don't */
+ if(imapc->preauth ||
+ !Curl_sasl_can_authenticate(&imapc->sasl, conn)) {
state(conn, IMAP_STOP);
return result;
}
@@ -707,18 +709,48 @@ static CURLcode imap_perform_fetch(struct connectdata *conn)
static CURLcode imap_perform_append(struct connectdata *conn)
{
CURLcode result = CURLE_OK;
- struct IMAP *imap = conn->data->req.protop;
+ struct Curl_easy *data = conn->data;
+ struct IMAP *imap = data->req.protop;
char *mailbox;
/* Check we have a mailbox */
if(!imap->mailbox) {
- failf(conn->data, "Cannot APPEND without a mailbox.");
+ failf(data, "Cannot APPEND without a mailbox.");
return CURLE_URL_MALFORMAT;
}
+ /* Prepare the mime data if some. */
+ if(data->set.mimepost.kind != MIMEKIND_NONE) {
+ /* Use the whole structure as data. */
+ data->set.mimepost.flags &= ~MIME_BODY_ONLY;
+
+ /* Add external headers and mime version. */
+ curl_mime_headers(&data->set.mimepost, data->set.headers, 0);
+ result = Curl_mime_prepare_headers(&data->set.mimepost, NULL,
+ NULL, MIMESTRATEGY_MAIL);
+
+ if(!result)
+ if(!Curl_checkheaders(conn, "Mime-Version"))
+ result = Curl_mime_add_header(&data->set.mimepost.curlheaders,
+ "Mime-Version: 1.0");
+
+ /* Make sure we will read the entire mime structure. */
+ if(!result)
+ result = Curl_mime_rewind(&data->set.mimepost);
+
+ if(result)
+ return result;
+
+ data->state.infilesize = Curl_mime_size(&data->set.mimepost);
+
+ /* Read from mime structure. */
+ data->state.fread_func = (curl_read_callback) Curl_mime_read;
+ data->state.in = (void *) &data->set.mimepost;
+ }
+
/* Check we know the size of the upload */
- if(conn->data->state.infilesize < 0) {
- failf(conn->data, "Cannot APPEND with unknown input file size\n");
+ if(data->state.infilesize < 0) {
+ failf(data, "Cannot APPEND with unknown input file size\n");
return CURLE_UPLOAD_FAILED;
}
@@ -729,7 +761,7 @@ static CURLcode imap_perform_append(struct connectdata *conn)
/* Send the APPEND command */
result = imap_sendf(conn, "APPEND %s (\\Seen) {%" CURL_FORMAT_CURL_OFF_T "}",
- mailbox, conn->data->state.infilesize);
+ mailbox, data->state.infilesize);
free(mailbox);
@@ -789,19 +821,21 @@ static CURLcode imap_state_servergreet_resp(struct connectdata *conn,
int imapcode,
imapstate instate)
{
- CURLcode result = CURLE_OK;
struct Curl_easy *data = conn->data;
-
(void)instate; /* no use for this yet */
- if(imapcode != 'O') {
+ if(imapcode == IMAP_RESP_PREAUTH) {
+ /* PREAUTH */
+ struct imap_conn *imapc = &conn->proto.imapc;
+ imapc->preauth = TRUE;
+ infof(data, "PREAUTH connection, already authenticated!\n");
+ }
+ else if(imapcode != IMAP_RESP_OK) {
failf(data, "Got unexpected imap-server response");
- result = CURLE_WEIRD_SERVER_REPLY;
+ return CURLE_WEIRD_SERVER_REPLY;
}
- else
- result = imap_perform_capability(conn);
- return result;
+ return imap_perform_capability(conn);
}
/* For CAPABILITY responses */
@@ -868,7 +902,7 @@ static CURLcode imap_state_capability_resp(struct connectdata *conn,
line += wordlen;
}
}
- else if(imapcode == 'O') {
+ else if(imapcode == IMAP_RESP_OK) {
if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
/* We don't have a SSL/TLS connection yet, but SSL is requested */
if(imapc->tls_supported)
@@ -901,7 +935,7 @@ static CURLcode imap_state_starttls_resp(struct connectdata *conn,
(void)instate; /* no use for this yet */
- if(imapcode != 'O') {
+ if(imapcode != IMAP_RESP_OK) {
if(data->set.use_ssl != CURLUSESSL_TRY) {
failf(data, "STARTTLS denied");
result = CURLE_USE_SSL_FAILED;
@@ -959,7 +993,7 @@ static CURLcode imap_state_login_resp(struct connectdata *conn,
(void)instate; /* no use for this yet */
- if(imapcode != 'O') {
+ if(imapcode != IMAP_RESP_OK) {
failf(data, "Access denied. %c", imapcode);
result = CURLE_LOGIN_DENIED;
}
@@ -987,7 +1021,7 @@ static CURLcode imap_state_listsearch_resp(struct connectdata *conn,
result = Curl_client_write(conn, CLIENTWRITE_BODY, line, len + 1);
line[len] = '\0';
}
- else if(imapcode != 'O')
+ else if(imapcode != IMAP_RESP_OK)
result = CURLE_QUOTE_ERROR; /* TODO: Fix error code */
else
/* End of DO phase */
@@ -1016,10 +1050,10 @@ static CURLcode imap_state_select_resp(struct connectdata *conn, int imapcode,
imapc->mailbox_uidvalidity = strdup(tmp);
}
}
- else if(imapcode == 'O') {
+ else if(imapcode == IMAP_RESP_OK) {
/* Check if the UIDVALIDITY has been specified and matches */
if(imap->uidvalidity && imapc->mailbox_uidvalidity &&
- strcmp(imap->uidvalidity, imapc->mailbox_uidvalidity)) {
+ !strcasecompare(imap->uidvalidity, imapc->mailbox_uidvalidity)) {
failf(conn->data, "Mailbox UIDVALIDITY has changed");
result = CURLE_REMOTE_FILE_NOT_FOUND;
}
@@ -1070,10 +1104,11 @@ static CURLcode imap_state_fetch_resp(struct connectdata *conn, int imapcode,
if(*ptr == '{') {
char *endptr;
- size = curlx_strtoofft(ptr + 1, &endptr, 10);
- if(endptr - ptr > 1 && endptr[0] == '}' &&
- endptr[1] == '\r' && endptr[2] == '\0')
- parsed = TRUE;
+ if(!curlx_strtoofft(ptr + 1, &endptr, 10, &size)) {
+ if(endptr - ptr > 1 && endptr[0] == '}' &&
+ endptr[1] == '\r' && endptr[2] == '\0')
+ parsed = TRUE;
+ }
}
if(parsed) {
@@ -1091,6 +1126,11 @@ static CURLcode imap_state_fetch_resp(struct connectdata *conn, int imapcode,
/* The conversion from curl_off_t to size_t is always fine here */
chunk = (size_t)size;
+ if(!chunk) {
+ /* no size, we're done with the data */
+ state(conn, IMAP_STOP);
+ return CURLE_OK;
+ }
result = Curl_client_write(conn, CLIENTWRITE_BODY, pp->cache, chunk);
if(result)
return result;
@@ -1147,7 +1187,7 @@ static CURLcode imap_state_fetch_final_resp(struct connectdata *conn,
(void)instate; /* No use for this yet */
- if(imapcode != 'O')
+ if(imapcode != IMAP_RESP_OK)
result = CURLE_WEIRD_SERVER_REPLY;
else
/* End of DONE phase */
@@ -1191,7 +1231,7 @@ static CURLcode imap_state_append_final_resp(struct connectdata *conn,
(void)instate; /* No use for this yet */
- if(imapcode != 'O')
+ if(imapcode != IMAP_RESP_OK)
result = CURLE_UPLOAD_FAILED;
else
/* End of DONE phase */
@@ -1419,9 +1459,10 @@ static CURLcode imap_done(struct connectdata *conn, CURLcode status,
result = status; /* use the already set error code */
}
else if(!data->set.connect_only && !imap->custom &&
- (imap->uid || data->set.upload)) {
+ (imap->uid || data->set.upload ||
+ data->set.mimepost.kind != MIMEKIND_NONE)) {
/* Handle responses after FETCH or APPEND transfer has finished */
- if(!data->set.upload)
+ if(!data->set.upload && data->set.mimepost.kind == MIMEKIND_NONE)
state(conn, IMAP_FETCH_FINAL);
else {
/* End the APPEND command first by sending an empty line */
@@ -1485,13 +1526,13 @@ static CURLcode imap_perform(struct connectdata *conn, bool *connected,
/* Determine if the requested mailbox (with the same UIDVALIDITY if set)
has already been selected on this connection */
if(imap->mailbox && imapc->mailbox &&
- !strcmp(imap->mailbox, imapc->mailbox) &&
+ strcasecompare(imap->mailbox, imapc->mailbox) &&
(!imap->uidvalidity || !imapc->mailbox_uidvalidity ||
- !strcmp(imap->uidvalidity, imapc->mailbox_uidvalidity)))
+ strcasecompare(imap->uidvalidity, imapc->mailbox_uidvalidity)))
selected = TRUE;
/* Start the first command in the DO phase */
- if(conn->data->set.upload)
+ if(conn->data->set.upload || data->set.mimepost.kind != MIMEKIND_NONE)
/* APPEND can be executed directly */
result = imap_perform_append(conn);
else if(imap->custom && (selected || !imap->mailbox))
@@ -1761,7 +1802,7 @@ static char *imap_atom(const char *str, bool escape_only)
return strdup(str);
/* Calculate the new string length */
- newlen = strlen(str) + backsp_count + quote_count + (others_exists ? 2 : 0);
+ newlen = strlen(str) + backsp_count + quote_count + (escape_only ? 0 : 2);
/* Allocate the new string */
newstr = (char *) malloc((newlen + 1) * sizeof(char));
@@ -1770,7 +1811,7 @@ static char *imap_atom(const char *str, bool escape_only)
/* Surround the string in quotes if necessary */
p2 = newstr;
- if(others_exists) {
+ if(!escape_only) {
newstr[0] = '"';
newstr[newlen - 1] = '"';
p2++;
diff --git a/lib/imap.h b/lib/imap.h
index 5e0e228f..9fc4ff5a 100644
--- a/lib/imap.h
+++ b/lib/imap.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2009 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2009 - 2017, 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
@@ -71,6 +71,7 @@ struct imap_conn {
struct pingpong pp;
imapstate state; /* Always use imap.c:state() to change state! */
bool ssldone; /* Is connect() over SSL done? */
+ bool preauth; /* Is this connection PREAUTH? */
struct SASL sasl; /* SASL-related parameters */
unsigned int preftype; /* Preferred authentication type */
int cmdid; /* Last used command ID */
diff --git a/lib/inet_ntop.c b/lib/inet_ntop.c
index 22f08e84..fb91a505 100644
--- a/lib/inet_ntop.c
+++ b/lib/inet_ntop.c
@@ -141,7 +141,7 @@ static char *inet_ntop6 (const unsigned char *src, char *dst, size_t size)
*/
if(i == 6 && best.base == 0 &&
(best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
- if(!inet_ntop4(src+12, tp, sizeof(tmp) - (tp - tmp))) {
+ if(!inet_ntop4(src + 12, tp, sizeof(tmp) - (tp - tmp))) {
errno = ENOSPC;
return (NULL);
}
diff --git a/lib/ldap.c b/lib/ldap.c
index 435b990a..89047bcb 100644
--- a/lib/ldap.c
+++ b/lib/ldap.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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
@@ -190,9 +190,11 @@ static int ldap_win_bind_auth(LDAP *server, const char *user,
const char *passwd, unsigned long authflags)
{
ULONG method = 0;
- SEC_WINNT_AUTH_IDENTITY cred = { 0, };
+ SEC_WINNT_AUTH_IDENTITY cred;
int rc = LDAP_AUTH_METHOD_NOT_SUPPORTED;
+ memset(&cred, 0, sizeof(cred));
+
#if defined(USE_SPNEGO)
if(authflags & CURLAUTH_NEGOTIATE) {
method = LDAP_AUTH_NEGOTIATE;
@@ -267,7 +269,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
LDAPMessage *ldapmsg = NULL;
LDAPMessage *entryIterator;
int num = 0;
- struct Curl_easy *data=conn->data;
+ struct Curl_easy *data = conn->data;
int ldap_proto = LDAP_VERSION3;
int ldap_ssl = 0;
char *val_b64 = NULL;
diff --git a/lib/libcurl.plist b/lib/libcurl.plist
index f53c58e7..2e377865 100644
--- a/lib/libcurl.plist
+++ b/lib/libcurl.plist
@@ -15,7 +15,7 @@
<string>se.haxx.curl.libcurl</string>
<key>CFBundleVersion</key>
- <string>7.55.1</string>
+ <string>7.57.0</string>
<key>CFBundleName</key>
<string>libcurl</string>
@@ -27,9 +27,9 @@
<string>????</string>
<key>CFBundleShortVersionString</key>
- <string>libcurl 7.55.1</string>
+ <string>libcurl 7.57.0</string>
<key>CFBundleGetInfoString</key>
- <string>libcurl.plist 7.55.1</string>
+ <string>libcurl.plist 7.57.0</string>
</dict>
</plist>
diff --git a/lib/llist.c b/lib/llist.c
index 4bb0a51b..f8769c2a 100644
--- a/lib/llist.c
+++ b/lib/llist.c
@@ -106,7 +106,11 @@ Curl_llist_remove(struct curl_llist *list, struct curl_llist_element *e,
e->next->prev = NULL;
}
else {
- e->prev->next = e->next;
+ if(!e->prev)
+ list->head = e->next;
+ else
+ e->prev->next = e->next;
+
if(!e->next)
list->tail = e->prev;
else
diff --git a/lib/memdebug.c b/lib/memdebug.c
index 8c9fe950..2b81c26a 100644
--- a/lib/memdebug.c
+++ b/lib/memdebug.c
@@ -170,7 +170,7 @@ void *curl_domalloc(size_t wantedsize, int line, const char *source)
return NULL;
/* alloc at least 64 bytes */
- size = sizeof(struct memdebug)+wantedsize;
+ size = sizeof(struct memdebug) + wantedsize;
mem = (Curl_cmalloc)(size);
if(mem) {
@@ -225,9 +225,9 @@ char *curl_dostrdup(const char *str, int line, const char *source)
if(countcheck("strdup", line, source))
return NULL;
- len=strlen(str)+1;
+ len = strlen(str) + 1;
- mem=curl_domalloc(len, 0, NULL); /* NULL prevents logging */
+ mem = curl_domalloc(len, 0, NULL); /* NULL prevents logging */
if(mem)
memcpy(mem, str, len);
@@ -269,9 +269,9 @@ wchar_t *curl_dowcsdup(const wchar_t *str, int line, const char *source)
void *curl_dorealloc(void *ptr, size_t wantedsize,
int line, const char *source)
{
- struct memdebug *mem=NULL;
+ struct memdebug *mem = NULL;
- size_t size = sizeof(struct memdebug)+wantedsize;
+ size_t size = sizeof(struct memdebug) + wantedsize;
DEBUGASSERT(wantedsize != 0);
@@ -343,7 +343,12 @@ curl_socket_t curl_socket(int domain, int type, int protocol,
"FD %s:%d socket() = %ld\n" :
"FD %s:%d socket() = %zd\n";
- curl_socket_t sockfd = socket(domain, type, protocol);
+ curl_socket_t sockfd;
+
+ if(countcheck("socket", line, source))
+ return CURL_SOCKET_BAD;
+
+ sockfd = socket(domain, type, protocol);
if(source && (sockfd != CURL_SOCKET_BAD))
curl_memlog(fmt, source, line, sockfd);
@@ -351,6 +356,35 @@ curl_socket_t curl_socket(int domain, int type, int protocol,
return sockfd;
}
+SEND_TYPE_RETV curl_dosend(SEND_TYPE_ARG1 sockfd,
+ SEND_QUAL_ARG2 SEND_TYPE_ARG2 buf,
+ SEND_TYPE_ARG3 len, SEND_TYPE_ARG4 flags, int line,
+ const char *source)
+{
+ SEND_TYPE_RETV rc;
+ if(countcheck("send", line, source))
+ return -1;
+ rc = send(sockfd, buf, len, flags);
+ if(source)
+ curl_memlog("SEND %s:%d send(%lu) = %ld\n",
+ source, line, (unsigned long)len, (long)rc);
+ return rc;
+}
+
+RECV_TYPE_RETV curl_dorecv(RECV_TYPE_ARG1 sockfd, RECV_TYPE_ARG2 buf,
+ RECV_TYPE_ARG3 len, RECV_TYPE_ARG4 flags, int line,
+ const char *source)
+{
+ RECV_TYPE_RETV rc;
+ if(countcheck("recv", line, source))
+ return -1;
+ rc = recv(sockfd, buf, len, flags);
+ if(source)
+ curl_memlog("RECV %s:%d recv(%lu) = %ld\n",
+ source, line, (unsigned long)len, (long)rc);
+ return rc;
+}
+
#ifdef HAVE_SOCKETPAIR
int curl_socketpair(int domain, int type, int protocol,
curl_socket_t socket_vector[2],
@@ -407,7 +441,7 @@ void curl_mark_sclose(curl_socket_t sockfd, int line, const char *source)
/* this is our own defined way to close sockets on *ALL* platforms */
int curl_sclose(curl_socket_t sockfd, int line, const char *source)
{
- int res=sclose(sockfd);
+ int res = sclose(sockfd);
curl_mark_sclose(sockfd, line, source);
return res;
}
@@ -415,7 +449,7 @@ int curl_sclose(curl_socket_t sockfd, int line, const char *source)
FILE *curl_fopen(const char *file, const char *mode,
int line, const char *source)
{
- FILE *res=fopen(file, mode);
+ FILE *res = fopen(file, mode);
if(source)
curl_memlog("FILE %s:%d fopen(\"%s\",\"%s\") = %p\n",
@@ -428,7 +462,7 @@ FILE *curl_fopen(const char *file, const char *mode,
FILE *curl_fdopen(int filedes, const char *mode,
int line, const char *source)
{
- FILE *res=fdopen(filedes, mode);
+ FILE *res = fdopen(filedes, mode);
if(source)
curl_memlog("FILE %s:%d fdopen(\"%d\",\"%s\") = %p\n",
@@ -444,7 +478,7 @@ int curl_fclose(FILE *file, int line, const char *source)
DEBUGASSERT(file != NULL);
- res=fclose(file);
+ res = fclose(file);
if(source)
curl_memlog("FILE %s:%d fclose(%p)\n",
diff --git a/lib/memdebug.h b/lib/memdebug.h
index 835dab38..6fb8b685 100644
--- a/lib/memdebug.h
+++ b/lib/memdebug.h
@@ -8,7 +8,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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
@@ -66,6 +66,17 @@ CURL_EXTERN int curl_socketpair(int domain, int type, int protocol,
int line, const char *source);
#endif
+/* send/receive sockets */
+CURL_EXTERN SEND_TYPE_RETV curl_dosend(SEND_TYPE_ARG1 sockfd,
+ SEND_QUAL_ARG2 SEND_TYPE_ARG2 buf,
+ SEND_TYPE_ARG3 len,
+ SEND_TYPE_ARG4 flags, int line,
+ const char *source);
+CURL_EXTERN RECV_TYPE_RETV curl_dorecv(RECV_TYPE_ARG1 sockfd,
+ RECV_TYPE_ARG2 buf, RECV_TYPE_ARG3 len,
+ RECV_TYPE_ARG4 flags, int line,
+ const char *source);
+
/* FILE functions */
CURL_EXTERN FILE *curl_fopen(const char *file, const char *mode, int line,
const char *source);
@@ -84,6 +95,8 @@ CURL_EXTERN int curl_fclose(FILE *file, int line, const char *source);
#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 send(a,b,c,d) curl_dosend(a,b,c,d, __LINE__, __FILE__)
+#define recv(a,b,c,d) curl_dorecv(a,b,c,d, __LINE__, __FILE__)
#ifdef WIN32
# ifdef UNICODE
diff --git a/lib/mime.c b/lib/mime.c
new file mode 100644
index 00000000..457000a0
--- /dev/null
+++ b/lib/mime.c
@@ -0,0 +1,1908 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, 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 https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#include "mime.h"
+#include "non-ascii.h"
+#include "urldata.h"
+#include "sendf.h"
+
+#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_SMTP) || \
+ !defined(CURL_DISABLE_IMAP)
+
+#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
+#include <libgen.h>
+#endif
+
+#include "rand.h"
+#include "slist.h"
+#include "strcase.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#ifdef WIN32
+# ifndef R_OK
+# define R_OK 4
+# endif
+#endif
+
+
+#define FILE_CONTENTTYPE_DEFAULT "application/octet-stream"
+#define MULTIPART_CONTENTTYPE_DEFAULT "multipart/mixed"
+#define DISPOSITION_DEFAULT "attachment"
+
+#define READ_ERROR ((size_t) -1)
+
+/* Encoders. */
+static size_t encoder_nop_read(char *buffer, size_t size, bool ateof,
+ curl_mimepart *part);
+static curl_off_t encoder_nop_size(curl_mimepart *part);
+static size_t encoder_7bit_read(char *buffer, size_t size, bool ateof,
+ curl_mimepart *part);
+static size_t encoder_base64_read(char *buffer, size_t size, bool ateof,
+ curl_mimepart *part);
+static curl_off_t encoder_base64_size(curl_mimepart *part);
+static size_t encoder_qp_read(char *buffer, size_t size, bool ateof,
+ curl_mimepart *part);
+static curl_off_t encoder_qp_size(curl_mimepart *part);
+
+static const mime_encoder encoders[] = {
+ {"binary", encoder_nop_read, encoder_nop_size},
+ {"8bit", encoder_nop_read, encoder_nop_size},
+ {"7bit", encoder_7bit_read, encoder_nop_size},
+ {"base64", encoder_base64_read, encoder_base64_size},
+ {"quoted-printable", encoder_qp_read, encoder_qp_size},
+ {ZERO_NULL, ZERO_NULL, ZERO_NULL}
+};
+
+/* Base64 encoding table */
+static const char base64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+/* Quoted-printable character class table.
+ *
+ * We cannot rely on ctype functions since quoted-printable input data
+ * is assumed to be ascii-compatible, even on non-ascii platforms. */
+#define QP_OK 1 /* Can be represented by itself. */
+#define QP_SP 2 /* Space or tab. */
+#define QP_CR 3 /* Carriage return. */
+#define QP_LF 4 /* Line-feed. */
+static const unsigned char qp_class[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 07 */
+ 0, QP_SP, QP_LF, 0, 0, QP_CR, 0, 0, /* 08 - 0F */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 17 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 18 - 1F */
+ QP_SP, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 20 - 27 */
+ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 28 - 2F */
+ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 30 - 37 */
+ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, 0 , QP_OK, QP_OK, /* 38 - 3F */
+ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 40 - 47 */
+ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 48 - 4F */
+ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 50 - 57 */
+ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 58 - 5F */
+ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 60 - 67 */
+ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 68 - 6F */
+ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 70 - 77 */
+ QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, 0, /* 78 - 7F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* F0 - FF */
+};
+
+
+/* Binary --> hexadecimal ASCII table. */
+static const char aschex[] =
+ "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x41\x42\x43\x44\x45\x46";
+
+
+
+#ifndef __VMS
+#define filesize(name, stat_data) (stat_data.st_size)
+#define fopen_read fopen
+
+#else
+
+#include <fabdef.h>
+/*
+ * get_vms_file_size does what it takes to get the real size of the file
+ *
+ * For fixed files, find out the size of the EOF block and adjust.
+ *
+ * For all others, have to read the entire file in, discarding the contents.
+ * Most posted text files will be small, and binary files like zlib archives
+ * and CD/DVD images should be either a STREAM_LF format or a fixed format.
+ *
+ */
+curl_off_t VmsRealFileSize(const char *name,
+ const struct_stat *stat_buf)
+{
+ char buffer[8192];
+ curl_off_t count;
+ int ret_stat;
+ FILE * file;
+
+ file = fopen(name, FOPEN_READTEXT); /* VMS */
+ if(file == NULL)
+ return 0;
+
+ count = 0;
+ ret_stat = 1;
+ while(ret_stat > 0) {
+ ret_stat = fread(buffer, 1, sizeof(buffer), file);
+ if(ret_stat != 0)
+ count += ret_stat;
+ }
+ fclose(file);
+
+ return count;
+}
+
+/*
+ *
+ * VmsSpecialSize checks to see if the stat st_size can be trusted and
+ * if not to call a routine to get the correct size.
+ *
+ */
+static curl_off_t VmsSpecialSize(const char *name,
+ const struct_stat *stat_buf)
+{
+ switch(stat_buf->st_fab_rfm) {
+ case FAB$C_VAR:
+ case FAB$C_VFC:
+ return VmsRealFileSize(name, stat_buf);
+ break;
+ default:
+ return stat_buf->st_size;
+ }
+}
+
+#define filesize(name, stat_data) VmsSpecialSize(name, &stat_data)
+
+/*
+ * vmsfopenread
+ *
+ * For upload to work as expected on VMS, different optional
+ * parameters must be added to the fopen command based on
+ * record format of the file.
+ *
+ */
+static FILE * vmsfopenread(const char *file, const char *mode)
+{
+ struct_stat statbuf;
+ int result;
+
+ result = stat(file, &statbuf);
+
+ switch(statbuf.st_fab_rfm) {
+ case FAB$C_VAR:
+ case FAB$C_VFC:
+ case FAB$C_STMCR:
+ return fopen(file, FOPEN_READTEXT); /* VMS */
+ break;
+ default:
+ return fopen(file, FOPEN_READTEXT, "rfm=stmlf", "ctx=stm");
+ }
+}
+
+#define fopen_read vmsfopenread
+#endif
+
+
+#ifndef HAVE_BASENAME
+/*
+ (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004
+ Edition)
+
+ The basename() function shall take the pathname pointed to by path and
+ return a pointer to the final component of the pathname, deleting any
+ trailing '/' characters.
+
+ If the string pointed to by path consists entirely of the '/' character,
+ basename() shall return a pointer to the string "/". If the string pointed
+ to by path is exactly "//", it is implementation-defined whether '/' or "//"
+ is returned.
+
+ If path is a null pointer or points to an empty string, basename() shall
+ return a pointer to the string ".".
+
+ The basename() function may modify the string pointed to by path, and may
+ return a pointer to static storage that may then be overwritten by a
+ subsequent call to basename().
+
+ The basename() function need not be reentrant. A function that is not
+ required to be reentrant is not required to be thread-safe.
+
+*/
+static char *Curl_basename(char *path)
+{
+ /* Ignore all the details above for now and make a quick and simple
+ implementaion here */
+ char *s1;
+ char *s2;
+
+ s1 = strrchr(path, '/');
+ s2 = strrchr(path, '\\');
+
+ if(s1 && s2) {
+ path = (s1 > s2? s1 : s2) + 1;
+ }
+ else if(s1)
+ path = s1 + 1;
+ else if(s2)
+ path = s2 + 1;
+
+ return path;
+}
+
+#define basename(x) Curl_basename((x))
+#endif
+
+
+/* Set readback state. */
+static void mimesetstate(mime_state *state, enum mimestate tok, void *ptr)
+{
+ state->state = tok;
+ state->ptr = ptr;
+ state->offset = 0;
+}
+
+
+/* Escape header string into allocated memory. */
+static char *escape_string(const char *src)
+{
+ size_t bytecount = 0;
+ size_t i;
+ char *dst;
+
+ for(i = 0; src[i]; i++)
+ if(src[i] == '"' || src[i] == '\\')
+ bytecount++;
+
+ bytecount += i;
+ dst = malloc(bytecount + 1);
+ if(!dst)
+ return NULL;
+
+ for(i = 0; *src; src++) {
+ if(*src == '"' || *src == '\\')
+ dst[i++] = '\\';
+ dst[i++] = *src;
+ }
+
+ dst[i] = '\0';
+ return dst;
+}
+
+/* Check if header matches. */
+static char *match_header(struct curl_slist *hdr, const char *lbl, size_t len)
+{
+ char *value = NULL;
+
+ if(strncasecompare(hdr->data, lbl, len) && hdr->data[len] == ':')
+ for(value = hdr->data + len + 1; *value == ' '; value++)
+ ;
+ return value;
+}
+
+/* Get a header from an slist. */
+static char *search_header(struct curl_slist *hdrlist, const char *hdr)
+{
+ size_t len = strlen(hdr);
+ char *value = NULL;
+
+ for(; !value && hdrlist; hdrlist = hdrlist->next)
+ value = match_header(hdrlist, hdr, len);
+
+ return value;
+}
+
+static char *strippath(const char *fullfile)
+{
+ char *filename;
+ char *base;
+ filename = strdup(fullfile); /* duplicate since basename() may ruin the
+ buffer it works on */
+ if(!filename)
+ return NULL;
+ base = strdup(basename(filename));
+
+ free(filename); /* free temporary buffer */
+
+ return base; /* returns an allocated string or NULL ! */
+}
+
+/* Initialize data encoder state. */
+static void cleanup_encoder_state(mime_encoder_state *p)
+{
+ p->pos = 0;
+ p->bufbeg = 0;
+ p->bufend = 0;
+}
+
+
+/* Dummy encoder. This is used for 8bit and binary content encodings. */
+static size_t encoder_nop_read(char *buffer, size_t size, bool ateof,
+ curl_mimepart *part)
+{
+ mime_encoder_state *st = &part->encstate;
+ size_t insize = st->bufend - st->bufbeg;
+
+ (void) ateof;
+
+ if(size > insize)
+ size = insize;
+ if(size)
+ memcpy(buffer, st->buf, size);
+ st->bufbeg += size;
+ return size;
+}
+
+static curl_off_t encoder_nop_size(curl_mimepart *part)
+{
+ return part->datasize;
+}
+
+
+/* 7bit encoder: the encoder is just a data validity check. */
+static size_t encoder_7bit_read(char *buffer, size_t size, bool ateof,
+ curl_mimepart *part)
+{
+ mime_encoder_state *st = &part->encstate;
+ size_t cursize = st->bufend - st->bufbeg;
+
+ (void) ateof;
+
+ if(size > cursize)
+ size = cursize;
+
+ for(cursize = 0; cursize < size; cursize++) {
+ *buffer = st->buf[st->bufbeg];
+ if(*buffer++ & 0x80)
+ return cursize? cursize: READ_ERROR;
+ st->bufbeg++;
+ }
+
+ return cursize;
+}
+
+
+/* Base64 content encoder. */
+static size_t encoder_base64_read(char *buffer, size_t size, bool ateof,
+ curl_mimepart *part)
+{
+ mime_encoder_state *st = &part->encstate;
+ size_t cursize = 0;
+ int i;
+ char *ptr = buffer;
+
+ while(st->bufbeg < st->bufend) {
+ /* Line full ? */
+ if(st->pos > MAX_ENCODED_LINE_LENGTH - 4) {
+ /* Yes, we need 2 characters for CRLF. */
+ if(size < 2)
+ break;
+ *ptr++ = '\r';
+ *ptr++ = '\n';
+ st->pos = 0;
+ cursize += 2;
+ size -= 2;
+ }
+
+ /* Be sure there is enough space and input data for a base64 group. */
+ if(size < 4 || st->bufend - st->bufbeg < 3)
+ break;
+
+ /* Encode three bytes as four characters. */
+ i = st->buf[st->bufbeg++] & 0xFF;
+ i = (i << 8) | (st->buf[st->bufbeg++] & 0xFF);
+ i = (i << 8) | (st->buf[st->bufbeg++] & 0xFF);
+ *ptr++ = base64[(i >> 18) & 0x3F];
+ *ptr++ = base64[(i >> 12) & 0x3F];
+ *ptr++ = base64[(i >> 6) & 0x3F];
+ *ptr++ = base64[i & 0x3F];
+ cursize += 4;
+ st->pos += 4;
+ size -= 4;
+ }
+
+ /* If at eof, we have to flush the buffered data. */
+ if(ateof && size >= 4) {
+ /* Buffered data size can only be 0, 1 or 2. */
+ ptr[2] = ptr[3] = '=';
+ i = 0;
+ switch(st->bufend - st->bufbeg) {
+ case 2:
+ i = (st->buf[st->bufbeg + 1] & 0xFF) << 8;
+ /* FALLTHROUGH */
+ case 1:
+ i |= (st->buf[st->bufbeg] & 0xFF) << 16;
+ ptr[0] = base64[(i >> 18) & 0x3F];
+ ptr[1] = base64[(i >> 12) & 0x3F];
+ if(++st->bufbeg != st->bufend) {
+ ptr[2] = base64[(i >> 6) & 0x3F];
+ st->bufbeg++;
+ }
+ cursize += 4;
+ st->pos += 4;
+ break;
+ }
+ }
+
+#ifdef CURL_DOES_CONVERSIONS
+ /* This is now textual data, Convert character codes. */
+ if(part->easy && cursize) {
+ CURLcode result = Curl_convert_to_network(part->easy, buffer, cursize);
+ if(result)
+ return READ_ERROR;
+ }
+#endif
+
+ return cursize;
+}
+
+static curl_off_t encoder_base64_size(curl_mimepart *part)
+{
+ curl_off_t size = part->datasize;
+
+ if(size <= 0)
+ return size; /* Unknown size or no data. */
+
+ /* Compute base64 character count. */
+ size = 4 * (1 + (size - 1) / 3);
+
+ /* Effective character count must include CRLFs. */
+ return size + 2 * ((size - 1) / MAX_ENCODED_LINE_LENGTH);
+}
+
+
+/* Quoted-printable lookahead.
+ *
+ * Check if a CRLF or end of data is in input buffer at current position + n.
+ * Return -1 if more data needed, 1 if CRLF or end of data, else 0.
+ */
+static int qp_lookahead_eol(mime_encoder_state *st, int ateof, size_t n)
+{
+ n += st->bufbeg;
+ if(n >= st->bufend && ateof)
+ return 1;
+ if(n + 2 > st->bufend)
+ return ateof? 0: -1;
+ if(qp_class[st->buf[n] & 0xFF] == QP_CR &&
+ qp_class[st->buf[n + 1] & 0xFF] == QP_LF)
+ return 1;
+ return 0;
+}
+
+/* Quoted-printable encoder. */
+static size_t encoder_qp_read(char *buffer, size_t size, bool ateof,
+ curl_mimepart *part)
+{
+ mime_encoder_state *st = &part->encstate;
+ char *ptr = buffer;
+ size_t cursize = 0;
+ int i;
+ size_t len;
+ size_t consumed;
+ int softlinebreak;
+ char buf[4];
+
+ /* On all platforms, input is supposed to be ASCII compatible: for this
+ reason, we use hexadecimal ASCII codes in this function rather than
+ character constants that can be interpreted as non-ascii on some
+ platforms. Preserve ASCII encoding on output too. */
+ while(st->bufbeg < st->bufend) {
+ len = 1;
+ consumed = 1;
+ i = st->buf[st->bufbeg];
+ buf[0] = (char) i;
+ buf[1] = aschex[(i >> 4) & 0xF];
+ buf[2] = aschex[i & 0xF];
+
+ switch(qp_class[st->buf[st->bufbeg] & 0xFF]) {
+ case QP_OK: /* Not a special character. */
+ break;
+ case QP_SP: /* Space or tab. */
+ /* Spacing must be escaped if followed by CRLF. */
+ switch(qp_lookahead_eol(st, ateof, 1)) {
+ case -1: /* More input data needed. */
+ return cursize;
+ case 0: /* No encoding needed. */
+ break;
+ default: /* CRLF after space or tab. */
+ buf[0] = '\x3D'; /* '=' */
+ len = 3;
+ break;
+ }
+ break;
+ case QP_CR: /* Carriage return. */
+ /* If followed by a line-feed, output the CRLF pair.
+ Else escape it. */
+ switch(qp_lookahead_eol(st, ateof, 0)) {
+ case -1: /* Need more data. */
+ return cursize;
+ case 1: /* CRLF found. */
+ buf[len++] = '\x0A'; /* Append '\n'. */
+ consumed = 2;
+ break;
+ default: /* Not followed by LF: escape. */
+ buf[0] = '\x3D'; /* '=' */
+ len = 3;
+ break;
+ }
+ break;
+ default: /* Character must be escaped. */
+ buf[0] = '\x3D'; /* '=' */
+ len = 3;
+ break;
+ }
+
+ /* Be sure the encoded character fits within maximum line length. */
+ if(buf[len - 1] != '\x0A') { /* '\n' */
+ softlinebreak = st->pos + len > MAX_ENCODED_LINE_LENGTH;
+ if(!softlinebreak && st->pos + len == MAX_ENCODED_LINE_LENGTH) {
+ /* We may use the current line only if end of data or followed by
+ a CRLF. */
+ switch(qp_lookahead_eol(st, ateof, consumed)) {
+ case -1: /* Need more data. */
+ return cursize;
+ break;
+ case 0: /* Not followed by a CRLF. */
+ softlinebreak = 1;
+ break;
+ }
+ }
+ if(softlinebreak) {
+ strcpy(buf, "\x3D\x0D\x0A"); /* "=\r\n" */
+ len = 3;
+ consumed = 0;
+ }
+ }
+
+ /* If the output buffer would overflow, do not store. */
+ if(len > size)
+ break;
+
+ /* Append to output buffer. */
+ memcpy(ptr, buf, len);
+ cursize += len;
+ ptr += len;
+ size -= len;
+ st->pos += len;
+ if(buf[len - 1] == '\x0A') /* '\n' */
+ st->pos = 0;
+ st->bufbeg += consumed;
+ }
+
+ return cursize;
+}
+
+static curl_off_t encoder_qp_size(curl_mimepart *part)
+{
+ /* Determining the size can only be done by reading the data: unless the
+ data size is 0, we return it as unknown (-1). */
+ return part->datasize? -1: 0;
+}
+
+
+/* In-memory data callbacks. */
+/* Argument is a pointer to the mime part. */
+static size_t mime_mem_read(char *buffer, size_t size, size_t nitems,
+ void *instream)
+{
+ curl_mimepart *part = (curl_mimepart *) instream;
+ size_t sz = (size_t) part->datasize - part->state.offset;
+ (void) size; /* Always 1.*/
+
+ if(sz > nitems)
+ sz = nitems;
+
+ if(sz)
+ memcpy(buffer, (char *) &part->data[part->state.offset], sz);
+
+ part->state.offset += sz;
+ return sz;
+}
+
+static int mime_mem_seek(void *instream, curl_off_t offset, int whence)
+{
+ curl_mimepart *part = (curl_mimepart *) instream;
+
+ switch(whence) {
+ case SEEK_CUR:
+ offset += part->state.offset;
+ break;
+ case SEEK_END:
+ offset += part->datasize;
+ break;
+ }
+
+ if(offset < 0 || offset > part->datasize)
+ return CURL_SEEKFUNC_FAIL;
+
+ part->state.offset = (size_t) offset;
+ return CURL_SEEKFUNC_OK;
+}
+
+static void mime_mem_free(void *ptr)
+{
+ Curl_safefree(((curl_mimepart *) ptr)->data);
+}
+
+
+/* Named file callbacks. */
+/* Argument is a pointer to the mime part. */
+static int mime_open_file(curl_mimepart * part)
+{
+ /* Open a MIMEKIND_FILE part. */
+
+ if(part->fp)
+ return 0;
+ part->fp = fopen_read(part->data, "rb");
+ return part->fp? 0: -1;
+}
+
+static size_t mime_file_read(char *buffer, size_t size, size_t nitems,
+ void *instream)
+{
+ curl_mimepart *part = (curl_mimepart *) instream;
+
+ if(mime_open_file(part))
+ return READ_ERROR;
+
+ return fread(buffer, size, nitems, part->fp);
+}
+
+static int mime_file_seek(void *instream, curl_off_t offset, int whence)
+{
+ curl_mimepart *part = (curl_mimepart *) instream;
+
+ if(whence == SEEK_SET && !offset && !part->fp)
+ return CURL_SEEKFUNC_OK; /* Not open: implicitly already at BOF. */
+
+ if(mime_open_file(part))
+ return CURL_SEEKFUNC_FAIL;
+
+ return fseek(part->fp, (long) offset, whence)?
+ CURL_SEEKFUNC_CANTSEEK: CURL_SEEKFUNC_OK;
+}
+
+static void mime_file_free(void *ptr)
+{
+ curl_mimepart *part = (curl_mimepart *) ptr;
+
+ if(part->fp) {
+ fclose(part->fp);
+ part->fp = NULL;
+ }
+ Curl_safefree(part->data);
+ part->data = NULL;
+}
+
+
+/* Subparts callbacks. */
+/* Argument is a pointer to the mime structure. */
+
+/* Readback a byte string segment. */
+static size_t readback_bytes(mime_state *state,
+ char *buffer, size_t bufsize,
+ const char *bytes, size_t numbytes,
+ const char *trail)
+{
+ size_t sz;
+
+ if(numbytes > state->offset) {
+ sz = numbytes - state->offset;
+ bytes += state->offset;
+ }
+ else {
+ size_t tsz = strlen(trail);
+
+ sz = state->offset - numbytes;
+ if(sz >= tsz)
+ return 0;
+ bytes = trail + sz;
+ sz = tsz - sz;
+ }
+
+ if(sz > bufsize)
+ sz = bufsize;
+
+ memcpy(buffer, bytes, sz);
+ state->offset += sz;
+ return sz;
+}
+
+/* Read a non-encoded part content. */
+static size_t read_part_content(curl_mimepart *part,
+ char *buffer, size_t bufsize)
+{
+ size_t sz = 0;
+
+ if(part->readfunc)
+ sz = part->readfunc(buffer, 1, bufsize, part->arg);
+ return sz;
+}
+
+/* Read and encode part content. */
+static size_t read_encoded_part_content(curl_mimepart *part,
+ char *buffer, size_t bufsize)
+{
+ mime_encoder_state *st = &part->encstate;
+ size_t cursize = 0;
+ size_t sz;
+ bool ateof = FALSE;
+
+ while(bufsize) {
+ if(st->bufbeg < st->bufend || ateof) {
+ /* Encode buffered data. */
+ sz = part->encoder->encodefunc(buffer, bufsize, ateof, part);
+ switch(sz) {
+ case 0:
+ if(ateof)
+ return cursize;
+ break;
+ case CURL_READFUNC_ABORT:
+ case CURL_READFUNC_PAUSE:
+ case READ_ERROR:
+ return cursize? cursize: sz;
+ default:
+ cursize += sz;
+ buffer += sz;
+ bufsize -= sz;
+ continue;
+ }
+ }
+
+ /* We need more data in input buffer. */
+ if(st->bufbeg) {
+ size_t len = st->bufend - st->bufbeg;
+
+ if(len)
+ memmove(st->buf, st->buf + st->bufbeg, len);
+ st->bufbeg = 0;
+ st->bufend = len;
+ }
+ if(st->bufend >= sizeof st->buf)
+ return cursize? cursize: READ_ERROR; /* Buffer full. */
+ sz = read_part_content(part, st->buf + st->bufend,
+ sizeof st->buf - st->bufend);
+ switch(sz) {
+ case 0:
+ ateof = TRUE;
+ break;
+ case CURL_READFUNC_ABORT:
+ case CURL_READFUNC_PAUSE:
+ case READ_ERROR:
+ return cursize? cursize: sz;
+ default:
+ st->bufend += sz;
+ break;
+ }
+ }
+
+ return cursize;
+}
+
+/* Readback a mime part. */
+static size_t readback_part(curl_mimepart *part,
+ char *buffer, size_t bufsize)
+{
+ size_t cursize = 0;
+ size_t sz;
+ struct curl_slist *hdr;
+#ifdef CURL_DOES_CONVERSIONS
+ char *convbuf = buffer;
+#endif
+
+ /* Readback from part. */
+
+ while(bufsize) {
+ sz = 0;
+ hdr = (struct curl_slist *) part->state.ptr;
+ switch(part->state.state) {
+ case MIMESTATE_BEGIN:
+ mimesetstate(&part->state, part->flags & MIME_BODY_ONLY? MIMESTATE_BODY:
+ MIMESTATE_CURLHEADERS, part->curlheaders);
+ break;
+ case MIMESTATE_USERHEADERS:
+ if(!hdr) {
+ mimesetstate(&part->state, MIMESTATE_EOH, NULL);
+ break;
+ }
+ if(match_header(hdr, "Content-Type", 12)) {
+ mimesetstate(&part->state, MIMESTATE_USERHEADERS, hdr->next);
+ break;
+ }
+ /* FALLTHROUGH */
+ case MIMESTATE_CURLHEADERS:
+ if(!hdr)
+ mimesetstate(&part->state, MIMESTATE_USERHEADERS, part->userheaders);
+ else {
+ sz = readback_bytes(&part->state, buffer, bufsize,
+ hdr->data, strlen(hdr->data), "\r\n");
+ if(!sz)
+ mimesetstate(&part->state, part->state.state, hdr->next);
+ }
+ break;
+ case MIMESTATE_EOH:
+ sz = readback_bytes(&part->state, buffer, bufsize, "\r\n", 2, "");
+ if(!sz)
+ mimesetstate(&part->state, MIMESTATE_BODY, NULL);
+ break;
+ case MIMESTATE_BODY:
+#ifdef CURL_DOES_CONVERSIONS
+ if(part->easy && convbuf < buffer) {
+ CURLcode result = Curl_convert_to_network(part->easy, convbuf,
+ buffer - convbuf);
+ if(result)
+ return READ_ERROR;
+ convbuf = buffer;
+ }
+#endif
+ cleanup_encoder_state(&part->encstate);
+ mimesetstate(&part->state, MIMESTATE_CONTENT, NULL);
+ break;
+ case MIMESTATE_CONTENT:
+ if(part->encoder)
+ sz = read_encoded_part_content(part, buffer, bufsize);
+ else
+ sz = read_part_content(part, buffer, bufsize);
+ switch(sz) {
+ case 0:
+ mimesetstate(&part->state, MIMESTATE_END, NULL);
+ /* Try sparing open file descriptors. */
+ if(part->kind == MIMEKIND_FILE && part->fp) {
+ fclose(part->fp);
+ part->fp = NULL;
+ }
+ /* FALLTHROUGH */
+ case CURL_READFUNC_ABORT:
+ case CURL_READFUNC_PAUSE:
+ case READ_ERROR:
+ return cursize? cursize: sz;
+ }
+ break;
+ case MIMESTATE_END:
+ return cursize;
+ default:
+ break; /* Other values not in part state. */
+ }
+
+ /* Bump buffer and counters according to read size. */
+ cursize += sz;
+ buffer += sz;
+ bufsize -= sz;
+ }
+
+#ifdef CURL_DOES_CONVERSIONS
+ if(part->easy && convbuf < buffer &&
+ part->state.state < MIMESTATE_BODY) {
+ CURLcode result = Curl_convert_to_network(part->easy, convbuf,
+ buffer - convbuf);
+ if(result)
+ return READ_ERROR;
+ }
+#endif
+
+ return cursize;
+}
+
+/* Readback from mime. */
+static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems,
+ void *instream)
+{
+ curl_mime *mime = (curl_mime *) instream;
+ size_t cursize = 0;
+ size_t sz;
+ curl_mimepart *part;
+#ifdef CURL_DOES_CONVERSIONS
+ char *convbuf = buffer;
+#endif
+
+ (void) size; /* Always 1. */
+
+ while(nitems) {
+ sz = 0;
+ part = mime->state.ptr;
+ switch(mime->state.state) {
+ case MIMESTATE_BEGIN:
+ case MIMESTATE_BODY:
+#ifdef CURL_DOES_CONVERSIONS
+ convbuf = buffer;
+#endif
+ mimesetstate(&mime->state, MIMESTATE_BOUNDARY1, mime->firstpart);
+ /* The first boundary always follows the header termination empty line,
+ so is always preceded by a CRLK. We can then spare 2 characters
+ by skipping the leading CRLF in boundary. */
+ mime->state.offset += 2;
+ break;
+ case MIMESTATE_BOUNDARY1:
+ sz = readback_bytes(&mime->state, buffer, nitems, "\r\n--", 4, "");
+ if(!sz)
+ mimesetstate(&mime->state, MIMESTATE_BOUNDARY2, part);
+ break;
+ case MIMESTATE_BOUNDARY2:
+ sz = readback_bytes(&mime->state, buffer, nitems, mime->boundary,
+ strlen(mime->boundary), part? "\r\n": "--\r\n");
+ if(!sz) {
+#ifdef CURL_DOES_CONVERSIONS
+ if(mime->easy && convbuf < buffer) {
+ CURLcode result = Curl_convert_to_network(mime->easy, convbuf,
+ buffer - convbuf);
+ if(result)
+ return READ_ERROR;
+ convbuf = buffer;
+ }
+#endif
+ mimesetstate(&mime->state, MIMESTATE_CONTENT, part);
+ }
+ break;
+ case MIMESTATE_CONTENT:
+ if(!part) {
+ mimesetstate(&mime->state, MIMESTATE_END, NULL);
+ break;
+ }
+ sz = readback_part(part, buffer, nitems);
+ switch(sz) {
+ case CURL_READFUNC_ABORT:
+ case CURL_READFUNC_PAUSE:
+ case READ_ERROR:
+ return cursize? cursize: sz;
+ case 0:
+#ifdef CURL_DOES_CONVERSIONS
+ convbuf = buffer;
+#endif
+ mimesetstate(&mime->state, MIMESTATE_BOUNDARY1, part->nextpart);
+ break;
+ }
+ break;
+ case MIMESTATE_END:
+ return cursize;
+ default:
+ break; /* other values not used in mime state. */
+ }
+
+ /* Bump buffer and counters according to read size. */
+ cursize += sz;
+ buffer += sz;
+ nitems -= sz;
+ }
+
+#ifdef CURL_DOES_CONVERSIONS
+ if(mime->easy && convbuf < buffer &&
+ mime->state.state <= MIMESTATE_CONTENT) {
+ CURLcode result = Curl_convert_to_network(mime->easy, convbuf,
+ buffer - convbuf);
+ if(result)
+ return READ_ERROR;
+ }
+#endif
+
+ return cursize;
+}
+
+static int mime_part_rewind(curl_mimepart *part)
+{
+ int res = CURL_SEEKFUNC_OK;
+ enum mimestate targetstate = MIMESTATE_BEGIN;
+
+ if(part->flags & MIME_BODY_ONLY)
+ targetstate = MIMESTATE_BODY;
+ cleanup_encoder_state(&part->encstate);
+ if(part->state.state > targetstate) {
+ res = CURL_SEEKFUNC_CANTSEEK;
+ if(part->seekfunc) {
+ res = part->seekfunc(part->arg, (curl_off_t) 0, SEEK_SET);
+ switch(res) {
+ case CURL_SEEKFUNC_OK:
+ case CURL_SEEKFUNC_FAIL:
+ case CURL_SEEKFUNC_CANTSEEK:
+ break;
+ case -1: /* For fseek() error. */
+ res = CURL_SEEKFUNC_CANTSEEK;
+ break;
+ default:
+ res = CURL_SEEKFUNC_FAIL;
+ break;
+ }
+ }
+ }
+
+ if(res == CURL_SEEKFUNC_OK)
+ mimesetstate(&part->state, targetstate, NULL);
+
+ return res;
+}
+
+static int mime_subparts_seek(void *instream, curl_off_t offset, int whence)
+{
+ curl_mime *mime = (curl_mime *) instream;
+ curl_mimepart *part;
+ int result = CURL_SEEKFUNC_OK;
+ int res;
+
+ if(whence != SEEK_SET || offset)
+ return CURL_SEEKFUNC_CANTSEEK; /* Only support full rewind. */
+
+ if(mime->state.state == MIMESTATE_BEGIN)
+ return CURL_SEEKFUNC_OK; /* Already rewound. */
+
+ for(part = mime->firstpart; part; part = part->nextpart) {
+ res = mime_part_rewind(part);
+ if(res != CURL_SEEKFUNC_OK)
+ result = res;
+ }
+
+ if(result == CURL_SEEKFUNC_OK)
+ mimesetstate(&mime->state, MIMESTATE_BEGIN, NULL);
+
+ return result;
+}
+
+/* Release part content. */
+static void cleanup_part_content(curl_mimepart *part)
+{
+ if(part->freefunc)
+ part->freefunc(part->arg);
+
+ part->readfunc = NULL;
+ part->seekfunc = NULL;
+ part->freefunc = NULL;
+ part->arg = (void *) part; /* Defaults to part itself. */
+ part->data = NULL;
+ part->fp = NULL;
+ part->datasize = (curl_off_t) 0; /* No size yet. */
+ cleanup_encoder_state(&part->encstate);
+ part->kind = MIMEKIND_NONE;
+}
+
+static void mime_subparts_free(void *ptr)
+{
+ curl_mime *mime = (curl_mime *) ptr;
+
+ if(mime && mime->parent) {
+ mime->parent->freefunc = NULL; /* Be sure we won't be called again. */
+ cleanup_part_content(mime->parent); /* Avoid dangling pointer in part. */
+ }
+ curl_mime_free(mime);
+}
+
+/* Do not free subparts: unbind them. This is used for the top level only. */
+static void mime_subparts_unbind(void *ptr)
+{
+ curl_mime *mime = (curl_mime *) ptr;
+
+ if(mime && mime->parent) {
+ mime->parent->freefunc = NULL; /* Be sure we won't be called again. */
+ cleanup_part_content(mime->parent); /* Avoid dangling pointer in part. */
+ mime->parent = NULL;
+ }
+}
+
+
+void Curl_mime_cleanpart(curl_mimepart *part)
+{
+ cleanup_part_content(part);
+ curl_slist_free_all(part->curlheaders);
+ if(part->flags & MIME_USERHEADERS_OWNER)
+ curl_slist_free_all(part->userheaders);
+ Curl_safefree(part->mimetype);
+ Curl_safefree(part->name);
+ Curl_safefree(part->filename);
+ Curl_mime_initpart(part, part->easy);
+}
+
+/* Recursively delete a mime handle and its parts. */
+void curl_mime_free(curl_mime *mime)
+{
+ curl_mimepart *part;
+
+ if(mime) {
+ mime_subparts_unbind(mime); /* Be sure it's not referenced anymore. */
+ while(mime->firstpart) {
+ part = mime->firstpart;
+ mime->firstpart = part->nextpart;
+ Curl_mime_cleanpart(part);
+ free(part);
+ }
+
+ free(mime->boundary);
+ free(mime);
+ }
+}
+
+/*
+ * Mime build functions.
+ */
+
+/* Create a mime handle. */
+curl_mime *curl_mime_init(struct Curl_easy *easy)
+{
+ curl_mime *mime;
+
+ mime = (curl_mime *) malloc(sizeof *mime);
+
+ if(mime) {
+ mime->easy = easy;
+ mime->parent = NULL;
+ mime->firstpart = NULL;
+ mime->lastpart = NULL;
+
+ /* Get a part boundary. */
+ mime->boundary = malloc(24 + MIME_RAND_BOUNDARY_CHARS + 1);
+ if(!mime->boundary) {
+ free(mime);
+ return NULL;
+ }
+
+ memset(mime->boundary, '-', 24);
+ Curl_rand_hex(easy, (unsigned char *) mime->boundary + 24,
+ MIME_RAND_BOUNDARY_CHARS + 1);
+ mimesetstate(&mime->state, MIMESTATE_BEGIN, NULL);
+ }
+
+ return mime;
+}
+
+/* Initialize a mime part. */
+void Curl_mime_initpart(curl_mimepart *part, struct Curl_easy *easy)
+{
+ memset((char *) part, 0, sizeof *part);
+ part->easy = easy;
+ mimesetstate(&part->state, MIMESTATE_BEGIN, NULL);
+}
+
+/* Create a mime part and append it to a mime handle's part list. */
+curl_mimepart *curl_mime_addpart(curl_mime *mime)
+{
+ curl_mimepart *part;
+
+ if(!mime)
+ return NULL;
+
+ part = (curl_mimepart *) malloc(sizeof *part);
+
+ if(part) {
+ Curl_mime_initpart(part, mime->easy);
+ part->parent = mime;
+
+ if(mime->lastpart)
+ mime->lastpart->nextpart = part;
+ else
+ mime->firstpart = part;
+
+ mime->lastpart = part;
+ }
+
+ return part;
+}
+
+/* Set mime part name. */
+CURLcode curl_mime_name(curl_mimepart *part, const char *name)
+{
+ if(!part)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
+ Curl_safefree(part->name);
+ part->name = NULL;
+
+ if(name) {
+ part->name = strdup(name);
+ if(!part->name)
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ return CURLE_OK;
+}
+
+/* Set mime part remote file name. */
+CURLcode curl_mime_filename(curl_mimepart *part, const char *filename)
+{
+ if(!part)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
+ Curl_safefree(part->filename);
+ part->filename = NULL;
+
+ if(filename) {
+ part->filename = strdup(filename);
+ if(!part->filename)
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ return CURLE_OK;
+}
+
+/* Set mime part content from memory data. */
+CURLcode curl_mime_data(curl_mimepart *part,
+ const char *data, size_t datasize)
+{
+ if(!part)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
+ cleanup_part_content(part);
+
+ if(data) {
+ if(datasize == CURL_ZERO_TERMINATED)
+ datasize = strlen(data);
+
+ part->data = malloc(datasize + 1);
+ if(!part->data)
+ return CURLE_OUT_OF_MEMORY;
+
+ part->datasize = datasize;
+
+ if(datasize)
+ memcpy(part->data, data, datasize);
+ part->data[datasize] = '\0'; /* Set a nul terminator as sentinel. */
+
+ part->readfunc = mime_mem_read;
+ part->seekfunc = mime_mem_seek;
+ part->freefunc = mime_mem_free;
+ part->kind = MIMEKIND_DATA;
+ }
+
+ return CURLE_OK;
+}
+
+/* Set mime part content from named local file. */
+CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename)
+{
+ CURLcode result = CURLE_OK;
+ char *base;
+
+ if(!part)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
+ cleanup_part_content(part);
+
+ if(filename) {
+ struct_stat sbuf;
+
+ if(stat(filename, &sbuf) || access(filename, R_OK))
+ result = CURLE_READ_ERROR;
+
+ part->data = strdup(filename);
+ if(!part->data)
+ result = CURLE_OUT_OF_MEMORY;
+
+ part->datasize = -1;
+ if(!result && S_ISREG(sbuf.st_mode)) {
+ part->datasize = filesize(filename, sbuf);
+ part->seekfunc = mime_file_seek;
+ }
+
+ part->readfunc = mime_file_read;
+ part->freefunc = mime_file_free;
+ part->kind = MIMEKIND_FILE;
+
+ /* As a side effect, set the filename to the current file's base name.
+ It is possible to withdraw this by explicitly calling
+ curl_mime_filename() with a NULL filename argument after the current
+ call. */
+ base = strippath(filename);
+ if(!base)
+ result = CURLE_OUT_OF_MEMORY;
+ else {
+ CURLcode res = curl_mime_filename(part, base);
+
+ if(res)
+ result = res;
+ free(base);
+ }
+ }
+ return result;
+}
+
+/* Set mime part type. */
+CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype)
+{
+ if(!part)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
+ Curl_safefree(part->mimetype);
+ part->mimetype = NULL;
+
+ if(mimetype) {
+ part->mimetype = strdup(mimetype);
+ if(!part->mimetype)
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ return CURLE_OK;
+}
+
+/* Set mime data transfer encoder. */
+CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding)
+{
+ CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
+ const mime_encoder *mep;
+
+ if(!part)
+ return result;
+
+ part->encoder = NULL;
+
+ if(!encoding)
+ return CURLE_OK; /* Removing current encoder. */
+
+ for(mep = encoders; mep->name; mep++)
+ if(strcasecompare(encoding, mep->name)) {
+ part->encoder = mep;
+ result = CURLE_OK;
+ }
+
+ return result;
+}
+
+/* Set mime part headers. */
+CURLcode curl_mime_headers(curl_mimepart *part,
+ struct curl_slist *headers, int take_ownership)
+{
+ if(!part)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
+ if(part->flags & MIME_USERHEADERS_OWNER) {
+ if(part->userheaders != headers) /* Allow setting twice the same list. */
+ curl_slist_free_all(part->userheaders);
+ part->flags &= ~MIME_USERHEADERS_OWNER;
+ }
+ part->userheaders = headers;
+ if(headers && take_ownership)
+ part->flags |= MIME_USERHEADERS_OWNER;
+ return CURLE_OK;
+}
+
+/* Set mime part content from callback. */
+CURLcode curl_mime_data_cb(curl_mimepart *part, curl_off_t datasize,
+ curl_read_callback readfunc,
+ curl_seek_callback seekfunc,
+ curl_free_callback freefunc, void *arg)
+{
+ if(!part)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
+ cleanup_part_content(part);
+
+ if(readfunc) {
+ part->readfunc = readfunc;
+ part->seekfunc = seekfunc;
+ part->freefunc = freefunc;
+ part->arg = arg;
+ part->datasize = datasize;
+ part->kind = MIMEKIND_CALLBACK;
+ }
+
+ return CURLE_OK;
+}
+
+/* Set mime part content from subparts. */
+CURLcode Curl_mime_set_subparts(curl_mimepart *part,
+ curl_mime *subparts, int take_ownership)
+{
+ curl_mime *root;
+
+ if(!part)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
+ /* Accept setting twice the same subparts. */
+ if(part->kind == MIMEKIND_MULTIPART && part->arg == subparts)
+ return CURLE_OK;
+
+ cleanup_part_content(part);
+
+ if(subparts) {
+ /* Must belong to the same data handle. */
+ if(part->easy && subparts->easy && part->easy != subparts->easy)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
+ /* Should not have been attached already. */
+ if(subparts->parent)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
+ /* Should not be the part's root. */
+ root = part->parent;
+ if(root) {
+ while(root->parent && root->parent->parent)
+ root = root->parent->parent;
+ if(subparts == root) {
+ if(part->easy)
+ failf(part->easy, "Can't add itself as a subpart!");
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ }
+ }
+
+ subparts->parent = part;
+ part->readfunc = mime_subparts_read;
+ part->seekfunc = mime_subparts_seek;
+ part->freefunc = take_ownership? mime_subparts_free: mime_subparts_unbind;
+ part->arg = subparts;
+ part->datasize = -1;
+ part->kind = MIMEKIND_MULTIPART;
+ }
+
+ return CURLE_OK;
+}
+
+CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts)
+{
+ return Curl_mime_set_subparts(part, subparts, TRUE);
+}
+
+
+/* Readback from top mime. */
+/* Argument is the dummy top part. */
+size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, void *instream)
+{
+ curl_mimepart *part = (curl_mimepart *) instream;
+
+ (void) size; /* Always 1. */
+ return readback_part(part, buffer, nitems);
+}
+
+/* Rewind mime stream. */
+CURLcode Curl_mime_rewind(curl_mimepart *part)
+{
+ return mime_part_rewind(part) == CURL_SEEKFUNC_OK?
+ CURLE_OK: CURLE_SEND_FAIL_REWIND;
+}
+
+/* Compute header list size. */
+static size_t slist_size(struct curl_slist *s,
+ size_t overhead, const char *skip)
+{
+ size_t size = 0;
+ size_t skiplen = skip? strlen(skip): 0;
+
+ for(; s; s = s->next)
+ if(!skip || !match_header(s, skip, skiplen))
+ size += strlen(s->data) + overhead;
+ return size;
+}
+
+/* Get/compute multipart size. */
+static curl_off_t multipart_size(curl_mime *mime)
+{
+ curl_off_t size;
+ curl_off_t sz;
+ size_t boundarysize;
+ curl_mimepart *part;
+
+ if(!mime)
+ return 0; /* Not present -> empty. */
+
+ boundarysize = 4 + strlen(mime->boundary) + 2;
+ size = boundarysize; /* Final boundary - CRLF after headers. */
+
+ for(part = mime->firstpart; part; part = part->nextpart) {
+ sz = Curl_mime_size(part);
+
+ if(sz < 0)
+ size = sz;
+
+ if(size >= 0)
+ size += boundarysize + sz;
+ }
+
+ return size;
+}
+
+/* Get/compute mime size. */
+curl_off_t Curl_mime_size(curl_mimepart *part)
+{
+ curl_off_t size;
+
+ if(part->kind == MIMEKIND_MULTIPART)
+ part->datasize = multipart_size(part->arg);
+
+ size = part->datasize;
+
+ if(part->encoder)
+ size = part->encoder->sizefunc(part);
+
+ if(size >= 0 && !(part->flags & MIME_BODY_ONLY)) {
+ /* Compute total part size. */
+ size += slist_size(part->curlheaders, 2, NULL);
+ size += slist_size(part->userheaders, 2, "Content-Type");
+ size += 2; /* CRLF after headers. */
+ }
+ return size;
+}
+
+/* Add a header. */
+/* VARARGS2 */
+CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...)
+{
+ struct curl_slist *hdr = NULL;
+ char *s = NULL;
+ va_list ap;
+
+ va_start(ap, fmt);
+ s = curl_mvaprintf(fmt, ap);
+ va_end(ap);
+
+ if(s) {
+ hdr = Curl_slist_append_nodup(*slp, s);
+ if(hdr)
+ *slp = hdr;
+ else
+ free(s);
+ }
+
+ return hdr? CURLE_OK: CURLE_OUT_OF_MEMORY;
+}
+
+/* Add a content type header. */
+static CURLcode add_content_type(struct curl_slist **slp,
+ const char *type, const char *boundary)
+{
+ return Curl_mime_add_header(slp, "Content-Type: %s%s%s", type,
+ boundary? "; boundary=": "",
+ boundary? boundary: "");
+}
+
+
+static const char *ContentTypeForFilename(const char *filename)
+{
+ unsigned int i;
+
+ /*
+ * If no content type was specified, we scan through a few well-known
+ * extensions and pick the first we match!
+ */
+ struct ContentType {
+ const char *extension;
+ const char *type;
+ };
+ static const struct ContentType ctts[] = {
+ {".gif", "image/gif"},
+ {".jpg", "image/jpeg"},
+ {".jpeg", "image/jpeg"},
+ {".png", "image/png"},
+ {".svg", "image/svg+xml"},
+ {".txt", "text/plain"},
+ {".htm", "text/html"},
+ {".html", "text/html"},
+ {".pdf", "application/pdf"},
+ {".xml", "application/xml"}
+ };
+
+ if(filename) {
+ size_t len1 = strlen(filename);
+ const char *nameend = filename + len1;
+
+ for(i = 0; i < sizeof ctts / sizeof ctts[0]; i++) {
+ size_t len2 = strlen(ctts[i].extension);
+
+ if(len1 >= len2 && strcasecompare(nameend - len2, ctts[i].extension))
+ return ctts[i].type;
+ }
+ }
+ return NULL;
+}
+
+CURLcode Curl_mime_prepare_headers(curl_mimepart *part,
+ const char *contenttype,
+ const char *disposition,
+ enum mimestrategy strategy)
+{
+ curl_mime *mime = NULL;
+ const char *boundary = NULL;
+ char *customct;
+ const char *cte = NULL;
+ CURLcode ret = CURLE_OK;
+
+ /* Get rid of previously prepared headers. */
+ curl_slist_free_all(part->curlheaders);
+ part->curlheaders = NULL;
+
+ /* Be sure we won't access old headers later. */
+ if(part->state.state == MIMESTATE_CURLHEADERS)
+ mimesetstate(&part->state, MIMESTATE_CURLHEADERS, NULL);
+
+ /* Check if content type is specified. */
+ customct = part->mimetype;
+ if(!customct)
+ customct = search_header(part->userheaders, "Content-Type");
+ if(customct)
+ contenttype = customct;
+
+ /* If content type is not specified, try to determine it. */
+ if(!contenttype) {
+ switch(part->kind) {
+ case MIMEKIND_MULTIPART:
+ contenttype = MULTIPART_CONTENTTYPE_DEFAULT;
+ break;
+ case MIMEKIND_FILE:
+ contenttype = ContentTypeForFilename(part->filename);
+ if(!contenttype)
+ contenttype = ContentTypeForFilename(part->data);
+ if(!contenttype && part->filename)
+ contenttype = FILE_CONTENTTYPE_DEFAULT;
+ break;
+ default:
+ contenttype = ContentTypeForFilename(part->filename);
+ break;
+ }
+ }
+
+ if(part->kind == MIMEKIND_MULTIPART) {
+ mime = (curl_mime *) part->arg;
+ if(mime)
+ boundary = mime->boundary;
+ }
+ else if(contenttype && !customct &&
+ strcasecompare(contenttype, "text/plain"))
+ if(strategy == MIMESTRATEGY_MAIL || !part->filename)
+ contenttype = NULL;
+
+ /* Issue content-disposition header only if not already set by caller. */
+ if(!search_header(part->userheaders, "Content-Disposition")) {
+ if(!disposition)
+ if(part->filename || part->name ||
+ (contenttype && !strncasecompare(contenttype, "multipart/", 10)))
+ disposition = DISPOSITION_DEFAULT;
+ if(disposition && curl_strequal(disposition, "attachment") &&
+ !part->name && !part->filename)
+ disposition = NULL;
+ if(disposition) {
+ char *name = NULL;
+ char *filename = NULL;
+
+ if(part->name) {
+ name = escape_string(part->name);
+ if(!name)
+ ret = CURLE_OUT_OF_MEMORY;
+ }
+ if(!ret && part->filename) {
+ filename = escape_string(part->filename);
+ if(!filename)
+ ret = CURLE_OUT_OF_MEMORY;
+ }
+ if(!ret)
+ ret = Curl_mime_add_header(&part->curlheaders,
+ "Content-Disposition: %s%s%s%s%s%s%s",
+ disposition,
+ name? "; name=\"": "",
+ name? name: "",
+ name? "\"": "",
+ filename? "; filename=\"": "",
+ filename? filename: "",
+ filename? "\"": "");
+ Curl_safefree(name);
+ Curl_safefree(filename);
+ if(ret)
+ return ret;
+ }
+ }
+
+ /* Issue Content-Type header. */
+ if(contenttype) {
+ ret = add_content_type(&part->curlheaders, contenttype, boundary);
+ if(ret)
+ return ret;
+ }
+
+ /* Content-Transfer-Encoding header. */
+ if(!search_header(part->userheaders, "Content-Transfer-Encoding")) {
+ if(part->encoder)
+ cte = part->encoder->name;
+ else if(contenttype && strategy == MIMESTRATEGY_MAIL &&
+ part->kind != MIMEKIND_MULTIPART)
+ cte = "8bit";
+ if(cte) {
+ ret = Curl_mime_add_header(&part->curlheaders,
+ "Content-Transfer-Encoding: %s", cte);
+ if(ret)
+ return ret;
+ }
+ }
+
+ /* If we were reading curl-generated headers, restart with new ones (this
+ should not occur). */
+ if(part->state.state == MIMESTATE_CURLHEADERS)
+ mimesetstate(&part->state, MIMESTATE_CURLHEADERS, part->curlheaders);
+
+ /* Process subparts. */
+ if(part->kind == MIMEKIND_MULTIPART && mime) {
+ curl_mimepart *subpart;
+
+ disposition = NULL;
+ if(strcasecompare(contenttype, "multipart/form-data"))
+ disposition = "form-data";
+ for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart) {
+ ret = Curl_mime_prepare_headers(subpart, NULL, disposition, strategy);
+ if(ret)
+ return ret;
+ }
+ }
+ return ret;
+}
+
+#else /* !CURL_DISABLE_HTTP || !CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP */
+
+/* Mime not compiled in: define stubs for externally-referenced functions. */
+curl_mime *curl_mime_init(CURL *easy)
+{
+ (void) easy;
+ return NULL;
+}
+
+void curl_mime_free(curl_mime *mime)
+{
+ (void) mime;
+}
+
+curl_mimepart *curl_mime_addpart(curl_mime *mime)
+{
+ (void) mime;
+ return NULL;
+}
+
+CURLcode curl_mime_name(curl_mimepart *part, const char *name)
+{
+ (void) part;
+ (void) name;
+ return CURLE_NOT_BUILT_IN;
+}
+
+CURLcode curl_mime_filename(curl_mimepart *part, const char *filename)
+{
+ (void) part;
+ (void) filename;
+ return CURLE_NOT_BUILT_IN;
+}
+
+CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype)
+{
+ (void) part;
+ (void) mimetype;
+ return CURLE_NOT_BUILT_IN;
+}
+
+CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding)
+{
+ (void) part;
+ (void) encoding;
+ return CURLE_NOT_BUILT_IN;
+}
+
+CURLcode curl_mime_data(curl_mimepart *part,
+ const char *data, size_t datasize)
+{
+ (void) part;
+ (void) data;
+ (void) datasize;
+ return CURLE_NOT_BUILT_IN;
+}
+
+CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename)
+{
+ (void) part;
+ (void) filename;
+ return CURLE_NOT_BUILT_IN;
+}
+
+CURLcode curl_mime_data_cb(curl_mimepart *part,
+ curl_off_t datasize,
+ curl_read_callback readfunc,
+ curl_seek_callback seekfunc,
+ curl_free_callback freefunc,
+ void *arg)
+{
+ (void) part;
+ (void) datasize;
+ (void) readfunc;
+ (void) seekfunc;
+ (void) freefunc;
+ (void) arg;
+ return CURLE_NOT_BUILT_IN;
+}
+
+CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts)
+{
+ (void) part;
+ (void) subparts;
+ return CURLE_NOT_BUILT_IN;
+}
+
+CURLcode curl_mime_headers(curl_mimepart *part,
+ struct curl_slist *headers, int take_ownership)
+{
+ (void) part;
+ (void) headers;
+ (void) take_ownership;
+ return CURLE_NOT_BUILT_IN;
+}
+
+void Curl_mime_initpart(curl_mimepart *part, struct Curl_easy *easy)
+{
+ (void) part;
+ (void) easy;
+}
+
+void Curl_mime_cleanpart(curl_mimepart *part)
+{
+ (void) part;
+}
+
+CURLcode Curl_mime_set_subparts(curl_mimepart *part,
+ curl_mime *subparts, int take_ownership)
+{
+ (void) part;
+ (void) subparts;
+ (void) take_ownership;
+ return CURLE_NOT_BUILT_IN;
+}
+
+CURLcode Curl_mime_prepare_headers(curl_mimepart *part,
+ const char *contenttype,
+ const char *disposition,
+ enum mimestrategy strategy)
+{
+ (void) part;
+ (void) contenttype;
+ (void) disposition;
+ (void) strategy;
+ return CURLE_NOT_BUILT_IN;
+}
+
+curl_off_t Curl_mime_size(curl_mimepart *part)
+{
+ (void) part;
+ return (curl_off_t) -1;
+}
+
+size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, void *instream)
+{
+ (void) buffer;
+ (void) size;
+ (void) nitems;
+ (void) instream;
+ return 0;
+}
+
+CURLcode Curl_mime_rewind(curl_mimepart *part)
+{
+ (void) part;
+ return CURLE_NOT_BUILT_IN;
+}
+
+/* VARARGS2 */
+CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...)
+{
+ (void) slp;
+ (void) fmt;
+ return CURLE_NOT_BUILT_IN;
+}
+
+#endif /* !CURL_DISABLE_HTTP || !CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP */
diff --git a/lib/mime.h b/lib/mime.h
new file mode 100644
index 00000000..7827f741
--- /dev/null
+++ b/lib/mime.h
@@ -0,0 +1,137 @@
+#ifndef HEADER_CURL_MIME_H
+#define HEADER_CURL_MIME_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, 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 https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#define MIME_RAND_BOUNDARY_CHARS 16 /* Nb. of random boundary chars. */
+#define MAX_ENCODED_LINE_LENGTH 76 /* Maximum encoded line length. */
+#define ENCODING_BUFFER_SIZE 256 /* Encoding temp buffers size. */
+
+/* Part flags. */
+#define MIME_USERHEADERS_OWNER (1 << 0)
+#define MIME_BODY_ONLY (1 << 1)
+
+/* Part source kinds. */
+enum mimekind {
+ MIMEKIND_NONE = 0, /* Part not set. */
+ MIMEKIND_DATA, /* Allocated mime data. */
+ MIMEKIND_FILE, /* Data from file. */
+ MIMEKIND_CALLBACK, /* Data from `read' callback. */
+ MIMEKIND_MULTIPART, /* Data is a mime subpart. */
+ MIMEKIND_LAST
+};
+
+/* Readback state tokens. */
+enum mimestate {
+ MIMESTATE_BEGIN, /* Readback has not yet started. */
+ MIMESTATE_CURLHEADERS, /* In curl-generated headers. */
+ MIMESTATE_USERHEADERS, /* In caller's supplied headers. */
+ MIMESTATE_EOH, /* End of headers. */
+ MIMESTATE_BODY, /* Placeholder. */
+ MIMESTATE_BOUNDARY1, /* In boundary prefix. */
+ MIMESTATE_BOUNDARY2, /* In boundary. */
+ MIMESTATE_CONTENT, /* In content. */
+ MIMESTATE_END, /* End of part reached. */
+ MIMESTATE_LAST
+};
+
+/* Mime headers strategies. */
+enum mimestrategy {
+ MIMESTRATEGY_MAIL, /* Mime mail. */
+ MIMESTRATEGY_FORM, /* HTTP post form. */
+ MIMESTRATEGY_LAST
+};
+
+/* Content transfer encoder. */
+typedef struct {
+ const char * name; /* Encoding name. */
+ size_t (*encodefunc)(char *buffer, size_t size, bool ateof,
+ curl_mimepart *part); /* Encoded read. */
+ curl_off_t (*sizefunc)(curl_mimepart *part); /* Encoded size. */
+} mime_encoder;
+
+/* Content transfer encoder state. */
+typedef struct {
+ size_t pos; /* Position on output line. */
+ size_t bufbeg; /* Next data index in input buffer. */
+ size_t bufend; /* First unused byte index in input buffer. */
+ char buf[ENCODING_BUFFER_SIZE]; /* Input buffer. */
+} mime_encoder_state;
+
+/* Mime readback state. */
+typedef struct {
+ enum mimestate state; /* Current state token. */
+ void *ptr; /* State-dependent pointer. */
+ size_t offset; /* State-dependent offset. */
+} mime_state;
+
+/* A mime multipart. */
+struct curl_mime_s {
+ struct Curl_easy *easy; /* The associated easy handle. */
+ curl_mimepart *parent; /* Parent part. */
+ curl_mimepart *firstpart; /* First part. */
+ curl_mimepart *lastpart; /* Last part. */
+ char *boundary; /* The part boundary. */
+ mime_state state; /* Current readback state. */
+};
+
+/* A mime part. */
+struct curl_mimepart_s {
+ struct Curl_easy *easy; /* The associated easy handle. */
+ curl_mime *parent; /* Parent mime structure. */
+ curl_mimepart *nextpart; /* Forward linked list. */
+ enum mimekind kind; /* The part kind. */
+ char *data; /* Memory data or file name. */
+ curl_read_callback readfunc; /* Read function. */
+ curl_seek_callback seekfunc; /* Seek function. */
+ curl_free_callback freefunc; /* Argument free function. */
+ void *arg; /* Argument to callback functions. */
+ FILE *fp; /* File pointer. */
+ struct curl_slist *curlheaders; /* Part headers. */
+ struct curl_slist *userheaders; /* Part headers. */
+ char *mimetype; /* Part mime type. */
+ char *filename; /* Remote file name. */
+ char *name; /* Data name. */
+ curl_off_t datasize; /* Expected data size. */
+ unsigned int flags; /* Flags. */
+ mime_state state; /* Current readback state. */
+ const mime_encoder *encoder; /* Content data encoder. */
+ mime_encoder_state encstate; /* Data encoder state. */
+};
+
+
+/* Prototypes. */
+void Curl_mime_initpart(curl_mimepart *part, struct Curl_easy *easy);
+void Curl_mime_cleanpart(curl_mimepart *part);
+CURLcode Curl_mime_set_subparts(curl_mimepart *part,
+ curl_mime *subparts, int take_ownership);
+CURLcode Curl_mime_prepare_headers(curl_mimepart *part,
+ const char *contenttype,
+ const char *disposition,
+ enum mimestrategy strategy);
+curl_off_t Curl_mime_size(curl_mimepart *part);
+size_t Curl_mime_read(char *buffer, size_t size, size_t nitems,
+ void *instream);
+CURLcode Curl_mime_rewind(curl_mimepart *part);
+CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...);
+
+#endif /* HEADER_CURL_MIME_H */
diff --git a/lib/mk-ca-bundle.pl b/lib/mk-ca-bundle.pl
index cc36c768..dcfec0bb 100755
--- a/lib/mk-ca-bundle.pl
+++ b/lib/mk-ca-bundle.pl
@@ -47,11 +47,9 @@ eval "require LWP::UserAgent";
my %urls = (
'nss' =>
- 'https://hg.mozilla.org/projects/nss/raw-file/tip/lib/ckfw/builtins/certdata.txt',
+ 'https://hg.mozilla.org/projects/nss/raw-file/default/lib/ckfw/builtins/certdata.txt',
'central' =>
'https://hg.mozilla.org/mozilla-central/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt',
- 'aurora' =>
- 'https://hg.mozilla.org/releases/mozilla-aurora/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt',
'beta' =>
'https://hg.mozilla.org/releases/mozilla-beta/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt',
'release' =>
diff --git a/lib/mprintf.c b/lib/mprintf.c
index eb7ee0c6..d2d91d74 100644
--- a/lib/mprintf.c
+++ b/lib/mprintf.c
@@ -46,10 +46,6 @@
* If SIZEOF_SIZE_T has not been defined, default to the size of long.
*/
-#ifndef SIZEOF_SIZE_T
-# define SIZEOF_SIZE_T CURL_SIZEOF_LONG
-#endif
-
#ifdef HAVE_LONGLONG
# define LONG_LONG_TYPE long long
# define HAVE_LONG_LONG_TYPE
@@ -111,7 +107,7 @@ static const char upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
} WHILE_FALSE
/* Data type to read from the arglist */
-typedef enum {
+typedef enum {
FORMAT_UNKNOWN = 0,
FORMAT_STRING,
FORMAT_PTR,
@@ -181,7 +177,7 @@ struct asprintf {
static long dprintf_DollarString(char *input, char **end)
{
- int number=0;
+ int number = 0;
while(ISDIGIT(*input)) {
number *= 10;
number += *input-'0';
@@ -237,7 +233,7 @@ static int dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos,
long width;
long precision;
int flags;
- long max_param=0;
+ long max_param = 0;
long i;
while(*fmt) {
@@ -326,7 +322,7 @@ static int dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos,
break;
#if defined(MP_HAVE_INT_EXTENSIONS)
case 'I':
-#if (CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG)
+#if (SIZEOF_CURL_OFF_T > SIZEOF_LONG)
flags |= FLAGS_LONGLONG;
#else
flags |= FLAGS_LONG;
@@ -348,14 +344,14 @@ static int dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos,
case 'z':
/* the code below generates a warning if -Wunreachable-code is
used */
-#if (SIZEOF_SIZE_T > CURL_SIZEOF_LONG)
+#if (SIZEOF_SIZE_T > SIZEOF_LONG)
flags |= FLAGS_LONGLONG;
#else
flags |= FLAGS_LONG;
#endif
break;
case 'O':
-#if (CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG)
+#if (SIZEOF_CURL_OFF_T > SIZEOF_LONG)
flags |= FLAGS_LONGLONG;
#else
flags |= FLAGS_LONG;
@@ -380,7 +376,7 @@ static int dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos,
else
width = param_num;
if(width > max_param)
- max_param=width;
+ max_param = width;
break;
default:
break;
@@ -486,7 +482,7 @@ static int dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos,
}
/* Read the arg list parameters into our data list */
- for(i=0; i<max_param; i++) {
+ for(i = 0; i<max_param; i++) {
/* Width/precision arguments must be read before the main argument
they are attached to */
if(vto[i].flags & FLAGS_WIDTHPARAM) {
@@ -573,7 +569,7 @@ static int dprintf_formatf(
int done = 0;
long param; /* current parameter to read */
- long param_num=0; /* parameter counter */
+ long param_num = 0; /* parameter counter */
va_stack_t vto[MAX_PARAMETERS];
char *endpos[MAX_PARAMETERS];
@@ -643,7 +639,7 @@ static int dprintf_formatf(
/* If this is a positional parameter, the position must follow immediately
after the %, thus create a %<num>$ sequence */
- param=dprintf_DollarString(f, &f);
+ param = dprintf_DollarString(f, &f);
if(!param)
param = param_num;
@@ -952,7 +948,7 @@ static int dprintf_formatf(
output characters */
(sprintf)(work, formatbuf, p->data.dnum);
DEBUGASSERT(strlen(work) <= sizeof(work));
- for(fptr=work; *fptr; fptr++)
+ for(fptr = work; *fptr; fptr++)
OUTCHAR(*fptr);
}
break;
@@ -984,7 +980,7 @@ static int dprintf_formatf(
/* fputc() look-alike */
static int addbyter(int output, FILE *data)
{
- struct nsprintf *infop=(struct nsprintf *)data;
+ struct nsprintf *infop = (struct nsprintf *)data;
unsigned char outc = (unsigned char)output;
if(infop->length < infop->max) {
@@ -1032,7 +1028,7 @@ int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...)
/* fputc() look-alike */
static int alloc_addbyter(int output, FILE *data)
{
- struct asprintf *infop=(struct asprintf *)data;
+ struct asprintf *infop = (struct asprintf *)data;
unsigned char outc = (unsigned char)output;
if(!infop->buffer) {
@@ -1042,9 +1038,9 @@ static int alloc_addbyter(int output, FILE *data)
return -1; /* fail */
}
infop->alloc = 32;
- infop->len =0;
+ infop->len = 0;
}
- else if(infop->len+1 >= infop->alloc) {
+ else if(infop->len + 1 >= infop->alloc) {
char *newptr = NULL;
size_t newsize = infop->alloc*2;
@@ -1133,7 +1129,7 @@ int curl_msprintf(char *buffer, const char *format, ...)
va_start(ap_save, format);
retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save);
va_end(ap_save);
- *buffer=0; /* we terminate this with a zero byte */
+ *buffer = 0; /* we terminate this with a zero byte */
return retcode;
}
@@ -1162,7 +1158,7 @@ int curl_mvsprintf(char *buffer, const char *format, va_list ap_save)
{
int retcode;
retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save);
- *buffer=0; /* we terminate this with a zero byte */
+ *buffer = 0; /* we terminate this with a zero byte */
return retcode;
}
diff --git a/lib/multi.c b/lib/multi.c
index d5bc532e..9728e5a2 100644
--- a/lib/multi.c
+++ b/lib/multi.c
@@ -59,7 +59,9 @@
#define CURL_SOCKET_HASH_TABLE_SIZE 911
#endif
+#ifndef CURL_CONNECTION_HASH_SIZE
#define CURL_CONNECTION_HASH_SIZE 97
+#endif
#define CURL_MULTI_HANDLE 0x000bab1e
@@ -324,14 +326,6 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
Curl_llist_init(&multi->msglist, multi_freeamsg);
Curl_llist_init(&multi->pending, multi_freeamsg);
- /* allocate a new easy handle to use when closing cached connections */
- multi->closure_handle = curl_easy_init();
- if(!multi->closure_handle)
- goto error;
-
- multi->closure_handle->multi = multi;
- multi->closure_handle->state.conn_cache = &multi->conn_cache;
-
multi->max_pipeline_length = 5;
/* -1 means it not set by user, use the default value */
@@ -343,8 +337,6 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
Curl_hash_destroy(&multi->sockhash);
Curl_hash_destroy(&multi->hostcache);
Curl_conncache_destroy(&multi->conn_cache);
- Curl_close(multi->closure_handle);
- multi->closure_handle = NULL;
Curl_llist_destroy(&multi->msglist, NULL);
Curl_llist_destroy(&multi->pending, NULL);
@@ -405,8 +397,11 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
data->dns.hostcachetype = HCACHE_MULTI;
}
- /* Point to the multi's connection cache */
- data->state.conn_cache = &multi->conn_cache;
+ /* Point to the shared or multi handle connection cache */
+ if(data->share && (data->share->specifier & (1<< CURL_LOCK_DATA_CONNECT)))
+ data->state.conn_cache = &data->share->conn_cache;
+ else
+ data->state.conn_cache = &multi->conn_cache;
/* This adds the new entry at the 'end' of the doubly-linked circular
list of Curl_easy structs to try and maintain a FIFO queue so
@@ -460,8 +455,8 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
state somewhat we clone the timeouts from each added handle so that the
closure handle always has the same timeouts as the most recently added
easy handle. */
- multi->closure_handle->set.timeout = data->set.timeout;
- multi->closure_handle->set.server_response_timeout =
+ data->state.conn_cache->closure_handle->set.timeout = data->set.timeout;
+ data->state.conn_cache->closure_handle->set.server_response_timeout =
data->set.server_response_timeout;
update_timer(multi);
@@ -502,7 +497,7 @@ ConnectionDone(struct Curl_easy *data, struct connectdata *conn)
data->state.conn_cache->num_connections > maxconnects) {
infof(data, "Connection cache is full, closing the oldest one.\n");
- conn_candidate = Curl_oldest_idle_connection(data);
+ conn_candidate = Curl_conncache_oldest_idle(data);
if(conn_candidate) {
/* Set the connection's owner correctly */
@@ -592,7 +587,7 @@ static CURLcode multi_done(struct connectdata **connp,
/* if the transfer was completed in a paused state there can be buffered
data left to free */
- for(i=0; i < data->state.tempcount; i++) {
+ for(i = 0; i < data->state.tempcount; i++) {
free(data->state.tempwrite[i].buf);
}
data->state.tempcount = 0;
@@ -705,12 +700,6 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
curl_easy_cleanup is called. */
Curl_expire_clear(data);
- if(data->dns.hostcachetype == HCACHE_MULTI) {
- /* stop using the multi handle's DNS cache */
- data->dns.hostcache = NULL;
- data->dns.hostcachetype = HCACHE_NONE;
- }
-
if(data->easy_conn) {
/* we must call multi_done() here (if we still own the connection) so that
@@ -729,6 +718,13 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
Curl_getoff_all_pipelines(data, data->easy_conn);
}
+ if(data->dns.hostcachetype == HCACHE_MULTI) {
+ /* stop using the multi handle's DNS cache, *after* the possible
+ multi_done() call above */
+ data->dns.hostcache = NULL;
+ data->dns.hostcachetype = HCACHE_NONE;
+ }
+
Curl_wildcard_dtor(&data->wildcard);
/* destroy the timeout list that is held in the easy handle, do this *after*
@@ -802,8 +798,8 @@ static int waitconnect_getsock(struct connectdata *conn,
int numsocks)
{
int i;
- int s=0;
- int rc=0;
+ int s = 0;
+ int rc = 0;
if(!numsocks)
return GETSOCK_BLANK;
@@ -813,7 +809,7 @@ static int waitconnect_getsock(struct connectdata *conn,
return Curl_ssl_getsock(conn, sock, numsocks);
#endif
- for(i=0; i<2; i++) {
+ for(i = 0; i<2; i++) {
if(conn->tempsock[i] != CURL_SOCKET_BAD) {
sock[s] = conn->tempsock[i];
rc |= GETSOCK_WRITESOCK(s++);
@@ -924,7 +920,7 @@ CURLMcode curl_multi_fdset(struct Curl_multi *multi,
Some easy handles may not have connected to the remote host yet,
and then we must make sure that is done. */
struct Curl_easy *data;
- int this_max_fd=-1;
+ int this_max_fd = -1;
curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE];
int bitmap;
int i;
@@ -933,11 +929,11 @@ CURLMcode curl_multi_fdset(struct Curl_multi *multi,
if(!GOOD_MULTI_HANDLE(multi))
return CURLM_BAD_HANDLE;
- data=multi->easyp;
+ data = multi->easyp;
while(data) {
bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE);
- for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) {
+ for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) {
curl_socket_t s = CURL_SOCKET_BAD;
if((bitmap & GETSOCK_READSOCK(i)) && VALID_SOCK((sockbunch[i]))) {
@@ -994,11 +990,11 @@ CURLMcode curl_multi_wait(struct Curl_multi *multi,
timeout_ms = (int)timeout_internal;
/* Count up how many fds we have from the multi handle */
- data=multi->easyp;
+ data = multi->easyp;
while(data) {
bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE);
- for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) {
+ for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) {
curl_socket_t s = CURL_SOCKET_BAD;
if(bitmap & GETSOCK_READSOCK(i)) {
@@ -1041,11 +1037,11 @@ CURLMcode curl_multi_wait(struct Curl_multi *multi,
if(curlfds) {
/* Add the curl handles to our pollfds first */
- data=multi->easyp;
+ data = multi->easyp;
while(data) {
bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE);
- for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) {
+ for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) {
curl_socket_t s = CURL_SOCKET_BAD;
if(bitmap & GETSOCK_READSOCK(i)) {
@@ -1229,15 +1225,15 @@ static CURLcode multi_reconnect_request(struct connectdata **connp)
*/
static void do_complete(struct connectdata *conn)
{
- conn->data->req.chunk=FALSE;
+ conn->data->req.chunk = FALSE;
conn->data->req.maxfd = (conn->sockfd>conn->writesockfd?
- conn->sockfd:conn->writesockfd)+1;
+ conn->sockfd:conn->writesockfd) + 1;
Curl_pgrsTime(conn->data, TIMER_PRETRANSFER);
}
static CURLcode multi_do(struct connectdata **connp, bool *done)
{
- CURLcode result=CURLE_OK;
+ CURLcode result = CURLE_OK;
struct connectdata *conn = *connp;
struct Curl_easy *data = conn->data;
@@ -1286,7 +1282,7 @@ static CURLcode multi_do(struct connectdata **connp, bool *done)
static CURLcode multi_do_more(struct connectdata *conn, int *complete)
{
- CURLcode result=CURLE_OK;
+ CURLcode result = CURLE_OK;
*complete = 0;
@@ -1315,7 +1311,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
struct SingleRequest *k;
time_t timeout_ms;
time_t recv_timeout_ms;
- time_t send_timeout_ms;
+ timediff_t send_timeout_ms;
int control;
if(!GOOD_EASY_HANDLE(data))
@@ -1379,23 +1375,23 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* Handle timed out */
if(data->mstate == CURLM_STATE_WAITRESOLVE)
failf(data, "Resolving timed out after %ld milliseconds",
- Curl_tvdiff(now, data->progress.t_startsingle));
+ Curl_timediff(now, data->progress.t_startsingle));
else if(data->mstate == CURLM_STATE_WAITCONNECT)
failf(data, "Connection timed out after %ld milliseconds",
- Curl_tvdiff(now, data->progress.t_startsingle));
+ Curl_timediff(now, data->progress.t_startsingle));
else {
k = &data->req;
if(k->size != -1) {
failf(data, "Operation timed out after %ld milliseconds with %"
CURL_FORMAT_CURL_OFF_T " out of %"
CURL_FORMAT_CURL_OFF_T " bytes received",
- Curl_tvdiff(now, data->progress.t_startsingle),
+ Curl_timediff(now, data->progress.t_startsingle),
k->bytecount, k->size);
}
else {
failf(data, "Operation timed out after %ld milliseconds with %"
CURL_FORMAT_CURL_OFF_T " bytes received",
- Curl_tvdiff(now, data->progress.t_startsingle),
+ Curl_timediff(now, data->progress.t_startsingle),
k->bytecount);
}
}
@@ -1415,7 +1411,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
switch(data->mstate) {
case CURLM_STATE_INIT:
/* init this transfer. */
- result=Curl_pretransfer(data);
+ result = Curl_pretransfer(data);
if(!result) {
/* after init, go CONNECT */
@@ -1660,7 +1656,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(!result) {
if(!dophase_done) {
/* some steps needed for wildcard matching */
- if(data->set.wildcardmatch) {
+ if(data->state.wildcardmatch) {
struct WildcardData *wc = &data->wildcard;
if(wc->state == CURLWC_DONE || wc->state == CURLWC_SKIP) {
/* skip some states if it is important */
@@ -1697,7 +1693,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
* back to the CONNECT phase so we can try again.
*/
char *newurl = NULL;
- followtype follow=FOLLOW_NONE;
+ followtype follow = FOLLOW_NONE;
CURLcode drc;
bool retry = FALSE;
@@ -1783,7 +1779,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(control) {
/* if positive, advance to DO_DONE
if negative, go back to DOING */
- multistate(data, control==1?
+ multistate(data, control == 1?
CURLM_STATE_DO_DONE:
CURLM_STATE_DOING);
rc = CURLM_CALL_MULTI_PERFORM;
@@ -1812,7 +1808,13 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
(data->easy_conn->writesockfd != CURL_SOCKET_BAD))
multistate(data, CURLM_STATE_WAITPERFORM);
else
+ {
+ if(data->state.wildcardmatch &&
+ ((data->easy_conn->handler->flags & PROTOPT_WILDCARD) == 0)) {
+ data->wildcard.state = CURLWC_DONE;
+ }
multistate(data, CURLM_STATE_DONE);
+ }
rc = CURLM_CALL_MULTI_PERFORM;
break;
@@ -1938,7 +1940,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
multi_done(&data->easy_conn, result, TRUE);
}
else if(done) {
- followtype follow=FOLLOW_NONE;
+ followtype follow = FOLLOW_NONE;
/* call this even if the readwrite function returned error */
Curl_posttransfer(data);
@@ -2029,7 +2031,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
data->easy_conn = NULL;
}
- if(data->set.wildcardmatch) {
+ if(data->state.wildcardmatch) {
if(data->wildcard.state != CURLWC_DONE) {
/* if a wildcard is set and we are not ending -> lets start again
with CURLM_STATE_INIT */
@@ -2144,14 +2146,14 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles)
{
struct Curl_easy *data;
- CURLMcode returncode=CURLM_OK;
+ CURLMcode returncode = CURLM_OK;
struct Curl_tree *t;
- struct curltime now = Curl_tvnow();
+ struct curltime now = Curl_now();
if(!GOOD_MULTI_HANDLE(multi))
return CURLM_BAD_HANDLE;
- data=multi->easyp;
+ data = multi->easyp;
while(data) {
CURLMcode result;
SIGPIPE_VARIABLE(pipe_st);
@@ -2192,61 +2194,21 @@ CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles)
return returncode;
}
-static void close_all_connections(struct Curl_multi *multi)
-{
- struct connectdata *conn;
-
- conn = Curl_conncache_find_first_connection(&multi->conn_cache);
- while(conn) {
- SIGPIPE_VARIABLE(pipe_st);
- conn->data = multi->closure_handle;
-
- sigpipe_ignore(conn->data, &pipe_st);
- conn->data->easy_conn = NULL; /* clear the easy handle's connection
- pointer */
- /* This will remove the connection from the cache */
- connclose(conn, "kill all");
- (void)Curl_disconnect(conn, FALSE);
- sigpipe_restore(&pipe_st);
-
- conn = Curl_conncache_find_first_connection(&multi->conn_cache);
- }
-}
-
CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
{
struct Curl_easy *data;
struct Curl_easy *nextdata;
if(GOOD_MULTI_HANDLE(multi)) {
- bool restore_pipe = FALSE;
- SIGPIPE_VARIABLE(pipe_st);
-
multi->type = 0; /* not good anymore */
- /* Close all the connections in the connection cache */
- close_all_connections(multi);
-
- if(multi->closure_handle) {
- sigpipe_ignore(multi->closure_handle, &pipe_st);
- restore_pipe = TRUE;
-
- multi->closure_handle->dns.hostcache = &multi->hostcache;
- Curl_hostcache_clean(multi->closure_handle,
- multi->closure_handle->dns.hostcache);
-
- Curl_close(multi->closure_handle);
- }
-
- Curl_hash_destroy(&multi->sockhash);
- Curl_conncache_destroy(&multi->conn_cache);
- Curl_llist_destroy(&multi->msglist, NULL);
- Curl_llist_destroy(&multi->pending, NULL);
-
- /* remove all easy handles */
+ /* Firsrt remove all remaining easy handles */
data = multi->easyp;
while(data) {
- nextdata=data->next;
+ nextdata = data->next;
+ if(!data->state.done && data->easy_conn)
+ /* if DONE was never called for this handle */
+ (void)multi_done(&data->easy_conn, CURLE_OK, TRUE);
if(data->dns.hostcachetype == HCACHE_MULTI) {
/* clear out the usage of the shared DNS cache */
Curl_hostcache_clean(data, data->dns.hostcache);
@@ -2261,6 +2223,14 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
data = nextdata;
}
+ /* Close all the connections in the connection cache */
+ Curl_conncache_close_all_connections(&multi->conn_cache);
+
+ Curl_hash_destroy(&multi->sockhash);
+ Curl_conncache_destroy(&multi->conn_cache);
+ Curl_llist_destroy(&multi->msglist, NULL);
+ Curl_llist_destroy(&multi->pending, NULL);
+
Curl_hash_destroy(&multi->hostcache);
/* Free the blacklists by setting them to NULL */
@@ -2268,8 +2238,6 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
Curl_pipeline_set_server_blacklist(NULL, &multi->pipelining_server_bl);
free(multi);
- if(restore_pipe)
- sigpipe_restore(&pipe_st);
return CURLM_OK;
}
@@ -2326,7 +2294,7 @@ static void singlesocket(struct Curl_multi *multi,
int num;
unsigned int curraction;
- for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++)
+ for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++)
socks[i] = CURL_SOCKET_BAD;
/* Fill in the 'current' struct with the state as it is now: what sockets to
@@ -2338,7 +2306,7 @@ static void singlesocket(struct Curl_multi *multi,
longer supervised ones and add new ones */
/* walk over the sockets we got right now */
- for(i=0; (i< MAX_SOCKSPEREASYHANDLE) &&
+ for(i = 0; (i< MAX_SOCKSPEREASYHANDLE) &&
(curraction & (GETSOCK_READSOCK(i) | GETSOCK_WRITESOCK(i)));
i++) {
int action = CURL_POLL_NONE;
@@ -2382,10 +2350,10 @@ static void singlesocket(struct Curl_multi *multi,
/* when we've walked over all the sockets we should have right now, we must
make sure to detect sockets that are removed */
- for(i=0; i< data->numsocks; i++) {
+ for(i = 0; i< data->numsocks; i++) {
int j;
s = data->sockets[i];
- for(j=0; j<num; j++) {
+ for(j = 0; j<num; j++) {
if(s == socks[j]) {
/* this is still supervised */
s = CURL_SOCKET_BAD;
@@ -2510,9 +2478,9 @@ static CURLMcode add_next_timeout(struct curltime now,
timeout in *tv */
for(e = list->head; e;) {
struct curl_llist_element *n = e->next;
- time_t diff;
+ timediff_t diff;
node = (struct time_node *)e->ptr;
- diff = curlx_tvdiff(node->time, now);
+ diff = Curl_timediff(node->time, now);
if(diff <= 0)
/* remove outdated entry */
Curl_llist_remove(list, e, NULL);
@@ -2549,7 +2517,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
CURLMcode result = CURLM_OK;
struct Curl_easy *data = NULL;
struct Curl_tree *t;
- struct curltime now = Curl_tvnow();
+ struct curltime now = Curl_now();
if(checkall) {
/* *perform() deals with running_handles on its own */
@@ -2558,7 +2526,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
/* walk through each easy handle and do the socket state change magic
and callbacks */
if(result != CURLM_BAD_HANDLE) {
- data=multi->easyp;
+ data = multi->easyp;
while(data) {
singlesocket(multi, data);
data = data->next;
@@ -2625,8 +2593,8 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
data = NULL; /* set data to NULL again to avoid calling
multi_runsingle() in case there's no need to */
- now = Curl_tvnow(); /* get a newer time since the multi_runsingle() loop
- may have taken some time */
+ now = Curl_now(); /* get a newer time since the multi_runsingle() loop
+ may have taken some time */
}
}
else {
@@ -2779,15 +2747,15 @@ static CURLMcode multi_timeout(struct Curl_multi *multi,
if(multi->timetree) {
/* we have a tree of expire times */
- struct curltime now = Curl_tvnow();
+ struct curltime now = Curl_now();
/* splay the lowest to the bottom */
multi->timetree = Curl_splay(tv_zero, multi->timetree);
if(Curl_splaycomparekeys(multi->timetree->key, now) > 0) {
/* some time left before expiration */
- *timeout_ms = (long)curlx_tvdiff(multi->timetree->key, now);
- if(!*timeout_ms)
+ timediff_t diff = Curl_timediff(multi->timetree->key, now);
+ if(diff <= 0)
/*
* Since we only provide millisecond resolution on the returned value
* and the diff might be less than one millisecond here, we don't
@@ -2795,7 +2763,11 @@ static CURLMcode multi_timeout(struct Curl_multi *multi,
* processors while the diff is still present but less than one
* millisecond! instead we return 1 until the time is ripe.
*/
- *timeout_ms=1;
+ *timeout_ms = 1;
+ else
+ /* this should be safe even on 64 bit archs, as we don't use that
+ overly long timeouts */
+ *timeout_ms = (long)diff;
}
else
/* 0 means immediately */
@@ -2831,7 +2803,7 @@ static int update_timer(struct Curl_multi *multi)
return -1;
}
if(timeout_ms < 0) {
- static const struct curltime none={0, 0};
+ static const struct curltime none = {0, 0};
if(Curl_splaycomparekeys(none, multi->timer_lastcall)) {
multi->timer_lastcall = none;
/* there's no timeout now but there was one previously, tell the app to
@@ -2902,7 +2874,7 @@ multi_addtimeout(struct Curl_easy *data,
/* find the correct spot in the list */
for(e = timeoutlist->head; e; e = e->next) {
struct time_node *check = (struct time_node *)e->ptr;
- time_t diff = curlx_tvdiff(check->time, node->time);
+ timediff_t diff = Curl_timediff(check->time, node->time);
if(diff > 0)
break;
prev = e;
@@ -2941,7 +2913,7 @@ void Curl_expire(struct Curl_easy *data, time_t milli, expire_id id)
DEBUGASSERT(id < EXPIRE_LAST);
- set = Curl_tvnow();
+ set = Curl_now();
set.tv_sec += milli/1000;
set.tv_usec += (unsigned int)(milli%1000)*1000;
@@ -2961,7 +2933,7 @@ void Curl_expire(struct Curl_easy *data, time_t milli, expire_id id)
/* This means that the struct is added as a node in the splay tree.
Compare if the new time is earlier, and only remove-old/add-new if it
is. */
- time_t diff = curlx_tvdiff(set, *nowp);
+ timediff_t diff = Curl_timediff(set, *nowp);
if(diff > 0) {
/* The current splay tree entry is sooner than this new expiry time.
@@ -3115,13 +3087,13 @@ void Curl_multi_dump(struct Curl_multi *multi)
int i;
fprintf(stderr, "* Multi status: %d handles, %d alive\n",
multi->num_easy, multi->num_alive);
- for(data=multi->easyp; data; data = data->next) {
+ for(data = multi->easyp; data; data = data->next) {
if(data->mstate < CURLM_STATE_COMPLETED) {
/* only display handles that are not completed */
fprintf(stderr, "handle %p, state %s, %d sockets\n",
(void *)data,
statename[data->mstate], data->numsocks);
- for(i=0; i < data->numsocks; i++) {
+ for(i = 0; i < data->numsocks; i++) {
curl_socket_t s = data->sockets[i];
struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);
diff --git a/lib/multihandle.h b/lib/multihandle.h
index 40575394..de9a7cf5 100644
--- a/lib/multihandle.h
+++ b/lib/multihandle.h
@@ -114,10 +114,6 @@ struct Curl_multi {
/* Shared connection cache (bundles)*/
struct conncache conn_cache;
- /* This handle will be used for closing the cached connections in
- curl_multi_cleanup() */
- struct Curl_easy *closure_handle;
-
long maxconnects; /* if >0, a fixed limit of the maximum number of entries
we're allowed to grow the connection cache to */
diff --git a/lib/netrc.c b/lib/netrc.c
index 6e4858b3..dbcc59ac 100644
--- a/lib/netrc.c
+++ b/lib/netrc.c
@@ -56,14 +56,15 @@ int Curl_parsenetrc(const char *host,
char *netrcfile)
{
FILE *file;
- int retcode=1;
+ int retcode = 1;
int specific_login = (*loginp && **loginp != 0);
bool netrc_alloc = FALSE;
- enum host_lookup_state state=NOTHING;
+ enum host_lookup_state state = NOTHING;
- char state_login=0; /* Found a login keyword */
- char state_password=0; /* Found a password keyword */
- int state_our_login=FALSE; /* With specific_login, found *our* login name */
+ char state_login = 0; /* Found a login keyword */
+ char state_password = 0; /* Found a password keyword */
+ int state_our_login = FALSE; /* With specific_login, found *our* login
+ name */
#define NETRC DOT_CHAR "netrc"
@@ -88,7 +89,7 @@ int Curl_parsenetrc(const char *host,
}
else {
struct passwd *pw;
- pw= getpwuid(geteuid());
+ pw = getpwuid(geteuid());
if(pw) {
home = pw->pw_dir;
}
@@ -113,19 +114,19 @@ int Curl_parsenetrc(const char *host,
if(file) {
char *tok;
char *tok_buf;
- bool done=FALSE;
+ bool done = FALSE;
char netrcbuffer[256];
int netrcbuffsize = (int)sizeof(netrcbuffer);
while(!done && fgets(netrcbuffer, netrcbuffsize, file)) {
- tok=strtok_r(netrcbuffer, " \t\n", &tok_buf);
+ tok = strtok_r(netrcbuffer, " \t\n", &tok_buf);
if(tok && *tok == '#')
/* treat an initial hash as a comment line */
continue;
while(!done && tok) {
if((*loginp && **loginp) && (*passwordp && **passwordp)) {
- done=TRUE;
+ done = TRUE;
break;
}
@@ -136,22 +137,22 @@ int Curl_parsenetrc(const char *host,
delimiter that starts the stuff entered for this machine,
after this we need to search for 'login' and
'password'. */
- state=HOSTFOUND;
+ state = HOSTFOUND;
}
else if(strcasecompare("default", tok)) {
- state=HOSTVALID;
- retcode=0; /* we did find our host */
+ state = HOSTVALID;
+ retcode = 0; /* we did find our host */
}
break;
case HOSTFOUND:
if(strcasecompare(host, tok)) {
/* and yes, this is our host! */
- state=HOSTVALID;
- retcode=0; /* we did find our host */
+ state = HOSTVALID;
+ retcode = 0; /* we did find our host */
}
else
/* not our host */
- state=NOTHING;
+ state = NOTHING;
break;
case HOSTVALID:
/* we are now parsing sub-keywords concerning "our" host */
@@ -167,7 +168,7 @@ int Curl_parsenetrc(const char *host,
goto out;
}
}
- state_login=0;
+ state_login = 0;
}
else if(state_password) {
if(state_our_login || !specific_login) {
@@ -178,12 +179,12 @@ int Curl_parsenetrc(const char *host,
goto out;
}
}
- state_password=0;
+ state_password = 0;
}
else if(strcasecompare("login", tok))
- state_login=1;
+ state_login = 1;
else if(strcasecompare("password", tok))
- state_password=1;
+ state_password = 1;
else if(strcasecompare("machine", tok)) {
/* ok, there's machine here go => */
state = HOSTFOUND;
diff --git a/lib/non-ascii.c b/lib/non-ascii.c
index ae009703..92b2f8d7 100644
--- a/lib/non-ascii.c
+++ b/lib/non-ascii.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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
@@ -82,7 +82,7 @@ CURLcode Curl_convert_clone(struct Curl_easy *data,
CURLcode Curl_convert_to_network(struct Curl_easy *data,
char *buffer, size_t length)
{
- if(data->set.convtonetwork) {
+ if(data && data->set.convtonetwork) {
/* use translation callback */
CURLcode result = data->set.convtonetwork(buffer, length);
if(result) {
@@ -96,14 +96,18 @@ CURLcode Curl_convert_to_network(struct Curl_easy *data,
else {
#ifdef HAVE_ICONV
/* do the translation ourselves */
+ iconv_t tmpcd = (iconv_t) -1;
+ iconv_t *cd = &tmpcd;
char *input_ptr, *output_ptr;
size_t in_bytes, out_bytes, rc;
/* open an iconv conversion descriptor if necessary */
- if(data->outbound_cd == (iconv_t)-1) {
- data->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
- CURL_ICONV_CODESET_OF_HOST);
- if(data->outbound_cd == (iconv_t)-1) {
+ if(data)
+ cd = &data->outbound_cd;
+ if(*cd == (iconv_t)-1) {
+ *cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
+ CURL_ICONV_CODESET_OF_HOST);
+ if(*cd == (iconv_t)-1) {
failf(data,
"The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
CURL_ICONV_CODESET_OF_NETWORK,
@@ -115,8 +119,10 @@ CURLcode Curl_convert_to_network(struct Curl_easy *data,
/* call iconv */
input_ptr = output_ptr = buffer;
in_bytes = out_bytes = length;
- rc = iconv(data->outbound_cd, (const char **)&input_ptr, &in_bytes,
+ rc = iconv(*cd, &input_ptr, &in_bytes,
&output_ptr, &out_bytes);
+ if(!data)
+ iconv_close(tmpcd);
if((rc == ICONV_ERROR) || (in_bytes != 0)) {
failf(data,
"The Curl_convert_to_network iconv call failed with errno %i: %s",
@@ -139,7 +145,7 @@ CURLcode Curl_convert_to_network(struct Curl_easy *data,
CURLcode Curl_convert_from_network(struct Curl_easy *data,
char *buffer, size_t length)
{
- if(data->set.convfromnetwork) {
+ if(data && data->set.convfromnetwork) {
/* use translation callback */
CURLcode result = data->set.convfromnetwork(buffer, length);
if(result) {
@@ -153,14 +159,18 @@ CURLcode Curl_convert_from_network(struct Curl_easy *data,
else {
#ifdef HAVE_ICONV
/* do the translation ourselves */
+ iconv_t tmpcd = (iconv_t) -1;
+ iconv_t *cd = &tmpcd;
char *input_ptr, *output_ptr;
size_t in_bytes, out_bytes, rc;
/* open an iconv conversion descriptor if necessary */
- if(data->inbound_cd == (iconv_t)-1) {
- data->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
- CURL_ICONV_CODESET_OF_NETWORK);
- if(data->inbound_cd == (iconv_t)-1) {
+ if(data)
+ cd = &data->inbound_cd;
+ if(*cd == (iconv_t)-1) {
+ *cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
+ CURL_ICONV_CODESET_OF_NETWORK);
+ if(*cd == (iconv_t)-1) {
failf(data,
"The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
CURL_ICONV_CODESET_OF_HOST,
@@ -172,8 +182,10 @@ CURLcode Curl_convert_from_network(struct Curl_easy *data,
/* call iconv */
input_ptr = output_ptr = buffer;
in_bytes = out_bytes = length;
- rc = iconv(data->inbound_cd, (const char **)&input_ptr, &in_bytes,
+ rc = iconv(*cd, &input_ptr, &in_bytes,
&output_ptr, &out_bytes);
+ if(!data)
+ iconv_close(tmpcd);
if((rc == ICONV_ERROR) || (in_bytes != 0)) {
failf(data,
"Curl_convert_from_network iconv call failed with errno %i: %s",
@@ -196,7 +208,7 @@ CURLcode Curl_convert_from_network(struct Curl_easy *data,
CURLcode Curl_convert_from_utf8(struct Curl_easy *data,
char *buffer, size_t length)
{
- if(data->set.convfromutf8) {
+ if(data && data->set.convfromutf8) {
/* use translation callback */
CURLcode result = data->set.convfromutf8(buffer, length);
if(result) {
@@ -210,15 +222,19 @@ CURLcode Curl_convert_from_utf8(struct Curl_easy *data,
else {
#ifdef HAVE_ICONV
/* do the translation ourselves */
- const char *input_ptr;
+ iconv_t tmpcd = (iconv_t) -1;
+ iconv_t *cd = &tmpcd;
+ char *input_ptr;
char *output_ptr;
size_t in_bytes, out_bytes, rc;
/* open an iconv conversion descriptor if necessary */
- if(data->utf8_cd == (iconv_t)-1) {
- data->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
- CURL_ICONV_CODESET_FOR_UTF8);
- if(data->utf8_cd == (iconv_t)-1) {
+ if(data)
+ cd = &data->utf8_cd;
+ if(*cd == (iconv_t)-1) {
+ *cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
+ CURL_ICONV_CODESET_FOR_UTF8);
+ if(*cd == (iconv_t)-1) {
failf(data,
"The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
CURL_ICONV_CODESET_OF_HOST,
@@ -230,8 +246,10 @@ CURLcode Curl_convert_from_utf8(struct Curl_easy *data,
/* call iconv */
input_ptr = output_ptr = buffer;
in_bytes = out_bytes = length;
- rc = iconv(data->utf8_cd, &input_ptr, &in_bytes,
+ rc = iconv(*cd, &input_ptr, &in_bytes,
&output_ptr, &out_bytes);
+ if(!data)
+ iconv_close(tmpcd);
if((rc == ICONV_ERROR) || (in_bytes != 0)) {
failf(data,
"The Curl_convert_from_utf8 iconv call failed with errno %i: %s",
@@ -301,29 +319,4 @@ void Curl_convert_close(struct Curl_easy *data)
#endif /* HAVE_ICONV */
}
-/*
- * Curl_convert_form() is used from http.c, this converts any form items that
- need to be sent in the network encoding. Returns CURLE_OK on success.
- */
-CURLcode Curl_convert_form(struct Curl_easy *data, struct FormData *form)
-{
- CURLcode result;
-
- if(!data)
- return CURLE_BAD_FUNCTION_ARGUMENT;
-
- while(form) {
- if(form->type == FORM_DATA) {
- result = Curl_convert_to_network(data, form->line, form->length);
- /* Curl_convert_to_network calls failf if unsuccessful */
- if(result)
- return result;
- }
-
- form = form->next;
- }
-
- return CURLE_OK;
-}
-
#endif /* CURL_DOES_CONVERSIONS */
diff --git a/lib/non-ascii.h b/lib/non-ascii.h
index e27f1f41..5fb5771e 100644
--- a/lib/non-ascii.h
+++ b/lib/non-ascii.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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
@@ -48,7 +48,6 @@ CURLcode Curl_convert_from_network(struct Curl_easy *data,
char *buffer, size_t length);
CURLcode Curl_convert_from_utf8(struct Curl_easy *data,
char *buffer, size_t length);
-CURLcode Curl_convert_form(struct Curl_easy *data, struct FormData *form);
#else
#define Curl_convert_clone(a,b,c,d) ((void)a, CURLE_OK)
#define Curl_convert_init(x) Curl_nop_stmt
@@ -57,7 +56,6 @@ CURLcode Curl_convert_form(struct Curl_easy *data, struct FormData *form);
#define Curl_convert_to_network(a,b,c) ((void)a, CURLE_OK)
#define Curl_convert_from_network(a,b,c) ((void)a, CURLE_OK)
#define Curl_convert_from_utf8(a,b,c) ((void)a, CURLE_OK)
-#define Curl_convert_form(a,b) CURLE_OK
#endif
#endif /* HEADER_CURL_NON_ASCII_H */
diff --git a/lib/openldap.c b/lib/openldap.c
index 369309cf..ac356d09 100644
--- a/lib/openldap.c
+++ b/lib/openldap.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2010, Howard Chu, <hyc@openldap.org>
+ * Copyright (C) 2010, 2017, Howard Chu, <hyc@openldap.org>
* Copyright (C) 2011 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
@@ -152,7 +152,7 @@ static CURLcode ldap_setup_connection(struct connectdata *conn)
{
ldapconninfo *li;
LDAPURLDesc *lud;
- struct Curl_easy *data=conn->data;
+ struct Curl_easy *data = conn->data;
int rc, proto;
CURLcode status;
@@ -198,7 +198,7 @@ static CURLcode ldap_connect(struct connectdata *conn, bool *done)
(void)done;
strcpy(hosturl, "ldap");
- ptr = hosturl+4;
+ ptr = hosturl + 4;
if(conn->handler->flags & PROTOPT_SSL)
*ptr++ = 's';
snprintf(ptr, sizeof(hosturl)-(ptr-hosturl), "://%s:%d",
@@ -354,7 +354,7 @@ static CURLcode ldap_do(struct connectdata *conn, bool *done)
int rc = 0;
LDAPURLDesc *ludp = NULL;
int msgid;
- struct Curl_easy *data=conn->data;
+ struct Curl_easy *data = conn->data;
connkeep(conn, "OpenLDAP do");
@@ -519,7 +519,7 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
else
binary = 0;
- for(i=0; bvals[i].bv_val != NULL; i++) {
+ for(i = 0; bvals[i].bv_val != NULL; i++) {
int binval = 0;
writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1);
if(writeerr) {
@@ -549,7 +549,7 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
else {
/* check for unprintable characters */
unsigned int j;
- for(j=0; j<bvals[i].bv_len; j++)
+ for(j = 0; j<bvals[i].bv_len; j++)
if(!ISPRINT(bvals[i].bv_val[j])) {
binval = 1;
break;
@@ -677,7 +677,7 @@ ldapsb_tls_read(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
ber_slen_t ret;
CURLcode err = CURLE_RECV_ERROR;
- ret = li->recv(conn, FIRSTSOCKET, buf, len, &err);
+ ret = (li->recv)(conn, FIRSTSOCKET, buf, len, &err);
if(ret < 0 && err == CURLE_AGAIN) {
SET_SOCKERRNO(EWOULDBLOCK);
}
@@ -692,7 +692,7 @@ ldapsb_tls_write(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
ber_slen_t ret;
CURLcode err = CURLE_SEND_ERROR;
- ret = li->send(conn, FIRSTSOCKET, buf, len, &err);
+ ret = (li->send)(conn, FIRSTSOCKET, buf, len, &err);
if(ret < 0 && err == CURLE_AGAIN) {
SET_SOCKERRNO(EWOULDBLOCK);
}
diff --git a/lib/parsedate.c b/lib/parsedate.c
index 609fd536..b82605bb 100644
--- a/lib/parsedate.c
+++ b/lib/parsedate.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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
@@ -167,20 +167,20 @@ static const struct tzinfo tz[]= {
RFC 1123) had their signs wrong. Here we use the correct signs to match
actual military usage.
*/
- {"A", +1 * 60}, /* Alpha */
- {"B", +2 * 60}, /* Bravo */
- {"C", +3 * 60}, /* Charlie */
- {"D", +4 * 60}, /* Delta */
- {"E", +5 * 60}, /* Echo */
- {"F", +6 * 60}, /* Foxtrot */
- {"G", +7 * 60}, /* Golf */
- {"H", +8 * 60}, /* Hotel */
- {"I", +9 * 60}, /* India */
+ {"A", 1 * 60}, /* Alpha */
+ {"B", 2 * 60}, /* Bravo */
+ {"C", 3 * 60}, /* Charlie */
+ {"D", 4 * 60}, /* Delta */
+ {"E", 5 * 60}, /* Echo */
+ {"F", 6 * 60}, /* Foxtrot */
+ {"G", 7 * 60}, /* Golf */
+ {"H", 8 * 60}, /* Hotel */
+ {"I", 9 * 60}, /* India */
/* "J", Juliet is not used as a timezone, to indicate the observer's local
time */
- {"K", +10 * 60}, /* Kilo */
- {"L", +11 * 60}, /* Lima */
- {"M", +12 * 60}, /* Mike */
+ {"K", 10 * 60}, /* Kilo */
+ {"L", 11 * 60}, /* Lima */
+ {"M", 12 * 60}, /* Mike */
{"N", -1 * 60}, /* November */
{"O", -2 * 60}, /* Oscar */
{"P", -3 * 60}, /* Papa */
@@ -205,14 +205,14 @@ static int checkday(const char *check, size_t len)
{
int i;
const char * const *what;
- bool found= FALSE;
+ bool found = FALSE;
if(len > 3)
what = &weekday[0];
else
what = &Curl_wkday[0];
- for(i=0; i<7; i++) {
+ for(i = 0; i<7; i++) {
if(strcasecompare(check, what[0])) {
- found=TRUE;
+ found = TRUE;
break;
}
what++;
@@ -224,12 +224,12 @@ static int checkmonth(const char *check)
{
int i;
const char * const *what;
- bool found= FALSE;
+ bool found = FALSE;
what = &Curl_month[0];
- for(i=0; i<12; i++) {
+ for(i = 0; i<12; i++) {
if(strcasecompare(check, what[0])) {
- found=TRUE;
+ found = TRUE;
break;
}
what++;
@@ -244,12 +244,12 @@ static int checktz(const char *check)
{
unsigned int i;
const struct tzinfo *what;
- bool found= FALSE;
+ bool found = FALSE;
what = tz;
- for(i=0; i< sizeof(tz)/sizeof(tz[0]); i++) {
+ for(i = 0; i< sizeof(tz)/sizeof(tz[0]); i++) {
if(strcasecompare(check, what->name)) {
- found=TRUE;
+ found = TRUE;
break;
}
what++;
@@ -331,21 +331,21 @@ static time_t my_timegm(struct my_tm *tm)
static int parsedate(const char *date, time_t *output)
{
time_t t = 0;
- int wdaynum=-1; /* day of the week number, 0-6 (mon-sun) */
- int monnum=-1; /* month of the year number, 0-11 */
- int mdaynum=-1; /* day of month, 1 - 31 */
- int hournum=-1;
- int minnum=-1;
- int secnum=-1;
- int yearnum=-1;
- int tzoff=-1;
+ int wdaynum = -1; /* day of the week number, 0-6 (mon-sun) */
+ int monnum = -1; /* month of the year number, 0-11 */
+ int mdaynum = -1; /* day of month, 1 - 31 */
+ int hournum = -1;
+ int minnum = -1;
+ int secnum = -1;
+ int yearnum = -1;
+ int tzoff = -1;
struct my_tm tm;
enum assume dignext = DATE_MDAY;
const char *indate = date; /* save the original pointer */
int part = 0; /* max 6 parts */
while(*date && (part < 6)) {
- bool found=FALSE;
+ bool found = FALSE;
skip(&date);
@@ -386,7 +386,7 @@ static int parsedate(const char *date, time_t *output)
/* a digit */
int val;
char *end;
- int len=0;
+ int len = 0;
if((secnum == -1) &&
(3 == sscanf(date, "%02d:%02d:%02d%n",
&hournum, &minnum, &secnum, &len))) {
diff --git a/lib/pingpong.c b/lib/pingpong.c
index 5ed79b71..438856a9 100644
--- a/lib/pingpong.c
+++ b/lib/pingpong.c
@@ -47,10 +47,10 @@
time_t Curl_pp_state_timeout(struct pingpong *pp)
{
struct connectdata *conn = pp->conn;
- struct Curl_easy *data=conn->data;
+ struct Curl_easy *data = conn->data;
time_t timeout_ms; /* in milliseconds */
time_t timeout2_ms; /* in milliseconds */
- long response_time= (data->set.server_response_timeout)?
+ long response_time = (data->set.server_response_timeout)?
data->set.server_response_timeout: pp->response_time;
/* if CURLOPT_SERVER_RESPONSE_TIMEOUT is set, use that to determine
@@ -61,12 +61,12 @@ time_t Curl_pp_state_timeout(struct pingpong *pp)
/* Without a requested timeout, we only wait 'response_time' seconds for the
full response to arrive before we bail out */
timeout_ms = response_time -
- Curl_tvdiff(Curl_tvnow(), pp->response); /* spent time */
+ Curl_timediff(Curl_now(), pp->response); /* spent time */
if(data->set.timeout) {
/* if timeout is requested, find out how much remaining time we have */
timeout2_ms = data->set.timeout - /* timeout time */
- Curl_tvdiff(Curl_tvnow(), conn->now); /* spent time */
+ Curl_timediff(Curl_now(), conn->now); /* spent time */
/* pick the lowest number */
timeout_ms = CURLMIN(timeout_ms, timeout2_ms);
@@ -85,10 +85,10 @@ CURLcode Curl_pp_statemach(struct pingpong *pp, bool block)
int rc;
time_t interval_ms;
time_t timeout_ms = Curl_pp_state_timeout(pp);
- struct Curl_easy *data=conn->data;
+ struct Curl_easy *data = conn->data;
CURLcode result = CURLE_OK;
- if(timeout_ms <=0) {
+ if(timeout_ms <= 0) {
failf(data, "server response timeout");
return CURLE_OPERATION_TIMEDOUT; /* already too little time */
}
@@ -120,7 +120,7 @@ CURLcode Curl_pp_statemach(struct pingpong *pp, bool block)
if(Curl_pgrsUpdate(conn))
result = CURLE_ABORTED_BY_CALLBACK;
else
- result = Curl_speedcheck(data, Curl_tvnow());
+ result = Curl_speedcheck(data, Curl_now());
if(result)
return result;
@@ -143,7 +143,7 @@ void Curl_pp_init(struct pingpong *pp)
pp->nread_resp = 0;
pp->linestart_resp = conn->data->state.buffer;
pp->pending_resp = TRUE;
- pp->response = Curl_tvnow(); /* start response time-out now! */
+ pp->response = Curl_now(); /* start response time-out now! */
}
@@ -168,16 +168,22 @@ CURLcode Curl_pp_vsendf(struct pingpong *pp,
char *s;
CURLcode result;
struct connectdata *conn = pp->conn;
- struct Curl_easy *data = conn->data;
+ struct Curl_easy *data;
#ifdef HAVE_GSSAPI
- enum protection_level data_sec = conn->data_prot;
+ enum protection_level data_sec;
#endif
DEBUGASSERT(pp->sendleft == 0);
DEBUGASSERT(pp->sendsize == 0);
DEBUGASSERT(pp->sendthis == NULL);
+ if(!conn)
+ /* can't send without a connection! */
+ return CURLE_SEND_ERROR;
+
+ data = conn->data;
+
fmt_crlf = aprintf("%s\r\n", fmt); /* append a trailing CRLF */
if(!fmt_crlf)
return CURLE_OUT_OF_MEMORY;
@@ -205,6 +211,7 @@ CURLcode Curl_pp_vsendf(struct pingpong *pp,
result = Curl_write(conn, conn->sock[FIRSTSOCKET], s, write_len,
&bytes_written);
#ifdef HAVE_GSSAPI
+ data_sec = conn->data_prot;
DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
conn->data_prot = data_sec;
#endif
@@ -228,7 +235,7 @@ CURLcode Curl_pp_vsendf(struct pingpong *pp,
free(s);
pp->sendthis = NULL;
pp->sendleft = pp->sendsize = 0;
- pp->response = Curl_tvnow();
+ pp->response = Curl_now();
}
return CURLE_OK;
@@ -270,7 +277,7 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd,
size_t *size) /* size of the response */
{
ssize_t perline; /* count bytes per line */
- bool keepon=TRUE;
+ bool keepon = TRUE;
ssize_t gotbytes;
char *ptr;
struct connectdata *conn = pp->conn;
@@ -281,7 +288,7 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd,
*code = 0; /* 0 for errors or not done */
*size = 0;
- ptr=buf + pp->nread_resp;
+ ptr = buf + pp->nread_resp;
/* number of bytes in the current line, so far */
perline = (ssize_t)(ptr-pp->linestart_resp);
@@ -297,7 +304,7 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd,
* it would have been populated with something of size int to begin
* with, even though its datatype may be larger than an int.
*/
- DEBUGASSERT((ptr+pp->cache_size) <= (buf+data->set.buffer_size+1));
+ DEBUGASSERT((ptr + pp->cache_size) <= (buf + data->set.buffer_size + 1));
memcpy(ptr, pp->cache, pp->cache_size);
gotbytes = (ssize_t)pp->cache_size;
free(pp->cache); /* free the cache */
@@ -351,7 +358,7 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd,
pp->nread_resp += gotbytes;
for(i = 0; i < gotbytes; ptr++, i++) {
perline++;
- if(*ptr=='\n') {
+ if(*ptr == '\n') {
/* a newline is CRLF in pp-talk, so the CR is ignored as
the line isn't really terminated until the LF comes */
@@ -378,17 +385,17 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd,
start of the buffer and zero terminate, for old times sake */
size_t n = ptr - pp->linestart_resp;
memmove(buf, pp->linestart_resp, n);
- buf[n]=0; /* zero terminate */
- keepon=FALSE;
- pp->linestart_resp = ptr+1; /* advance pointer */
+ buf[n] = 0; /* zero terminate */
+ keepon = FALSE;
+ pp->linestart_resp = ptr + 1; /* advance pointer */
i++; /* skip this before getting out */
*size = pp->nread_resp; /* size of the response */
pp->nread_resp = 0; /* restart */
break;
}
- perline=0; /* line starts over here */
- pp->linestart_resp = ptr+1;
+ perline = 0; /* line starts over here */
+ pp->linestart_resp = ptr + 1;
}
}
@@ -490,9 +497,9 @@ CURLcode Curl_pp_flushsend(struct pingpong *pp)
}
else {
free(pp->sendthis);
- pp->sendthis=NULL;
+ pp->sendthis = NULL;
pp->sendleft = pp->sendsize = 0;
- pp->response = Curl_tvnow();
+ pp->response = Curl_now();
}
return CURLE_OK;
}
diff --git a/lib/pingpong.h b/lib/pingpong.h
index a2c8ff59..5ac8df87 100644
--- a/lib/pingpong.h
+++ b/lib/pingpong.h
@@ -58,8 +58,8 @@ struct pingpong {
server */
size_t sendleft; /* number of bytes left to send from the sendthis buffer */
size_t sendsize; /* total size of the sendthis buffer */
- struct curltime response; /* set to Curl_tvnow() when a command has been sent
- off, used to time-out response reading */
+ struct curltime response; /* set to Curl_now() when a command has been sent
+ off, used to time-out response reading */
long response_time; /* When no timeout is given, this is the amount of
milliseconds we await for a server response. */
diff --git a/lib/progress.c b/lib/progress.c
index 740ff288..72c518a1 100644
--- a/lib/progress.c
+++ b/lib/progress.c
@@ -134,7 +134,7 @@ int Curl_pgrsDone(struct connectdata *conn)
{
int rc;
struct Curl_easy *data = conn->data;
- data->progress.lastshow=0;
+ data->progress.lastshow = 0;
rc = Curl_pgrsUpdate(conn); /* the final (forced) update */
if(rc)
return rc;
@@ -149,14 +149,9 @@ int Curl_pgrsDone(struct connectdata *conn)
return 0;
}
-/* reset all times except redirect, and reset the known transfer sizes */
-void Curl_pgrsResetTimesSizes(struct Curl_easy *data)
+/* reset the known transfer sizes */
+void Curl_pgrsResetTransferSizes(struct Curl_easy *data)
{
- data->progress.t_nslookup = 0;
- data->progress.t_connect = 0;
- data->progress.t_pretransfer = 0;
- data->progress.t_starttransfer = 0;
-
Curl_pgrsSetDownloadSize(data, -1);
Curl_pgrsSetUploadSize(data, -1);
}
@@ -166,7 +161,7 @@ void Curl_pgrsResetTimesSizes(struct Curl_easy *data)
*/
void Curl_pgrsTime(struct Curl_easy *data, timerid timer)
{
- struct curltime now = Curl_tvnow();
+ struct curltime now = Curl_now();
time_t *delta = NULL;
switch(timer) {
@@ -181,6 +176,7 @@ void Curl_pgrsTime(struct Curl_easy *data, timerid timer)
case TIMER_STARTSINGLE:
/* This is set at the start of each single fetch */
data->progress.t_startsingle = now;
+ data->progress.is_t_startransfer_set = false;
break;
case TIMER_STARTACCEPT:
data->progress.t_acceptdata = now;
@@ -205,31 +201,33 @@ void Curl_pgrsTime(struct Curl_easy *data, timerid timer)
* This prevents repeated invocations of the function from incorrectly
* changing the t_starttransfer time.
*/
- if (*delta > data->progress.t_redirect) {
+ if(data->progress.is_t_startransfer_set) {
return;
}
else {
+ data->progress.is_t_startransfer_set = true;
break;
}
case TIMER_POSTRANSFER:
/* this is the normal end-of-transfer thing */
break;
case TIMER_REDIRECT:
- data->progress.t_redirect = Curl_tvdiff_us(now, data->progress.start);
+ data->progress.t_redirect = Curl_timediff_us(now, data->progress.start);
break;
}
if(delta) {
- time_t us = Curl_tvdiff_us(now, data->progress.t_startsingle);
- if(!us)
- us++; /* make sure at least one microsecond passed */
- *delta = us;
+ timediff_t us = Curl_timediff_us(now, data->progress.t_startsingle);
+ if(us < 1)
+ us = 1; /* make sure at least one microsecond passed */
+ *delta += us;
}
}
void Curl_pgrsStartNow(struct Curl_easy *data)
{
data->progress.speeder_c = 0; /* reset the progress meter display */
- data->progress.start = Curl_tvnow();
+ data->progress.start = Curl_now();
+ data->progress.is_t_startransfer_set = false;
data->progress.ul_limit_start.tv_sec = 0;
data->progress.ul_limit_start.tv_usec = 0;
data->progress.dl_limit_start.tv_sec = 0;
@@ -276,7 +274,7 @@ long Curl_pgrsLimitWaitTime(curl_off_t cursize,
return -1;
minimum = (time_t) (CURL_OFF_T_C(1000) * size / limit);
- actual = Curl_tvdiff(now, start);
+ actual = Curl_timediff(now, start);
if(actual < minimum)
/* this is a conversion on some systems (64bit time_t => 32bit long) */
@@ -287,7 +285,7 @@ long Curl_pgrsLimitWaitTime(curl_off_t cursize,
void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size)
{
- struct curltime now = Curl_tvnow();
+ struct curltime now = Curl_now();
data->progress.downloaded = size;
@@ -305,7 +303,7 @@ void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size)
void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size)
{
- struct curltime now = Curl_tvnow();
+ struct curltime now = Curl_now();
data->progress.uploaded = size;
@@ -354,9 +352,9 @@ int Curl_pgrsUpdate(struct connectdata *conn)
struct curltime now;
int result;
char max5[6][10];
- curl_off_t dlpercen=0;
- curl_off_t ulpercen=0;
- curl_off_t total_percen=0;
+ curl_off_t dlpercen = 0;
+ curl_off_t ulpercen = 0;
+ curl_off_t total_percen = 0;
curl_off_t total_transfer;
curl_off_t total_expected_transfer;
curl_off_t timespent;
@@ -367,15 +365,15 @@ int Curl_pgrsUpdate(struct connectdata *conn)
char time_left[10];
char time_total[10];
char time_spent[10];
- curl_off_t ulestimate=0;
- curl_off_t dlestimate=0;
+ curl_off_t ulestimate = 0;
+ curl_off_t dlestimate = 0;
curl_off_t total_estimate;
- bool shownow=FALSE;
+ bool shownow = FALSE;
- now = Curl_tvnow(); /* what time is it */
+ now = Curl_now(); /* what time is it */
/* The time spent so far (from the start) */
- data->progress.timespent = Curl_tvdiff_us(now, data->progress.start);
+ data->progress.timespent = Curl_timediff_us(now, data->progress.start);
timespent = (curl_off_t)data->progress.timespent/1000000; /* seconds */
/* The average download speed this far */
@@ -410,24 +408,24 @@ int Curl_pgrsUpdate(struct connectdata *conn)
array. With N_ENTRIES filled in, we have about N_ENTRIES-1 seconds of
transfer. Imagine, after one second we have filled in two entries,
after two seconds we've filled in three entries etc. */
- countindex = ((data->progress.speeder_c>=CURR_TIME)?
+ countindex = ((data->progress.speeder_c >= CURR_TIME)?
CURR_TIME:data->progress.speeder_c) - 1;
/* first of all, we don't do this if there's no counted seconds yet */
if(countindex) {
- time_t span_ms;
+ timediff_t span_ms;
/* Get the index position to compare with the 'nowindex' position.
Get the oldest entry possible. While we have less than CURR_TIME
entries, the first entry will remain the oldest. */
- checkindex = (data->progress.speeder_c>=CURR_TIME)?
+ checkindex = (data->progress.speeder_c >= CURR_TIME)?
data->progress.speeder_c%CURR_TIME:0;
/* Figure out the exact time for the time span */
- span_ms = Curl_tvdiff(now,
- data->progress.speeder_time[checkindex]);
+ span_ms = Curl_timediff(now,
+ data->progress.speeder_time[checkindex]);
if(0 == span_ms)
- span_ms=1; /* at least one millisecond MUST have passed */
+ span_ms = 1; /* at least one millisecond MUST have passed */
/* Calculate the average speed the last 'span_ms' milliseconds */
{
@@ -457,22 +455,22 @@ int Curl_pgrsUpdate(struct connectdata *conn)
if(data->set.fxferinfo) {
/* There's a callback set, call that */
- result= data->set.fxferinfo(data->set.progress_client,
- data->progress.size_dl,
- data->progress.downloaded,
- data->progress.size_ul,
- data->progress.uploaded);
+ result = data->set.fxferinfo(data->set.progress_client,
+ data->progress.size_dl,
+ data->progress.downloaded,
+ data->progress.size_ul,
+ data->progress.uploaded);
if(result)
failf(data, "Callback aborted");
return result;
}
if(data->set.fprogress) {
/* The older deprecated callback is set, call that */
- result= data->set.fprogress(data->set.progress_client,
- (double)data->progress.size_dl,
- (double)data->progress.downloaded,
- (double)data->progress.size_ul,
- (double)data->progress.uploaded);
+ result = data->set.fprogress(data->set.progress_client,
+ (double)data->progress.size_dl,
+ (double)data->progress.downloaded,
+ (double)data->progress.size_ul,
+ (double)data->progress.uploaded);
if(result)
failf(data, "Callback aborted");
return result;
diff --git a/lib/progress.h b/lib/progress.h
index ed57e336..9333ab25 100644
--- a/lib/progress.h
+++ b/lib/progress.h
@@ -47,7 +47,7 @@ void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size);
void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size);
void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size);
int Curl_pgrsUpdate(struct connectdata *);
-void Curl_pgrsResetTimesSizes(struct Curl_easy *data);
+void Curl_pgrsResetTransferSizes(struct Curl_easy *data);
void Curl_pgrsTime(struct Curl_easy *data, timerid timer);
long Curl_pgrsLimitWaitTime(curl_off_t cursize,
curl_off_t startsize,
diff --git a/lib/rand.c b/lib/rand.c
index 2713a0aa..2670af9d 100644
--- a/lib/rand.c
+++ b/lib/rand.c
@@ -86,7 +86,7 @@ static CURLcode randit(struct Curl_easy *data, unsigned int *rnd)
#endif
if(!seeded) {
- struct curltime now = curlx_tvnow();
+ struct curltime now = Curl_now();
infof(data, "WARNING: Using weak random seed\n");
randseed += (unsigned int)now.tv_usec + (unsigned int)now.tv_sec;
randseed = randseed * 1103515245 + 12345;
diff --git a/lib/rtsp.c b/lib/rtsp.c
index 9bd935fd..925da2c1 100644
--- a/lib/rtsp.c
+++ b/lib/rtsp.c
@@ -250,7 +250,7 @@ static CURLcode rtsp_done(struct connectdata *conn,
static CURLcode rtsp_do(struct connectdata *conn, bool *done)
{
struct Curl_easy *data = conn->data;
- CURLcode result=CURLE_OK;
+ CURLcode result = CURLE_OK;
Curl_RtspReq rtspreq = data->set.rtspreq;
struct RTSP *rtsp = data->req.protop;
struct HTTP *http;
@@ -749,14 +749,28 @@ CURLcode rtp_client_write(struct connectdata *conn, char *ptr, size_t len)
struct Curl_easy *data = conn->data;
size_t wrote;
curl_write_callback writeit;
+ void *user_ptr;
if(len == 0) {
failf(data, "Cannot write a 0 size RTP packet.");
return CURLE_WRITE_ERROR;
}
- writeit = data->set.fwrite_rtp?data->set.fwrite_rtp:data->set.fwrite_func;
- wrote = writeit(ptr, 1, len, data->set.rtp_out);
+ /* If the user has configured CURLOPT_INTERLEAVEFUNCTION then use that
+ function and any configured CURLOPT_INTERLEAVEDATA to write out the RTP
+ data. Otherwise, use the CURLOPT_WRITEFUNCTION with the CURLOPT_WRITEDATA
+ pointer to write out the RTP data. */
+ if(data->set.fwrite_rtp) {
+ writeit = data->set.fwrite_rtp;
+ user_ptr = data->set.rtp_out;
+ }
+ else
+ {
+ writeit = data->set.fwrite_func;
+ user_ptr = data->set.out;
+ }
+
+ wrote = writeit(ptr, 1, len, user_ptr);
if(CURL_WRITEFUNC_PAUSE == wrote) {
failf(data, "Cannot pause RTP");
diff --git a/lib/security.c b/lib/security.c
index f4a87634..9b989681 100644
--- a/lib/security.c
+++ b/lib/security.c
@@ -7,7 +7,7 @@
* rewrite to work around the paragraph 2 in the BSD licenses as explained
* below.
*
- * Copyright (c) 1998, 1999 Kungliga Tekniska Högskolan
+ * Copyright (c) 1998, 1999, 2017 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
*
* Copyright (C) 2001 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
@@ -115,7 +115,7 @@ static char level_to_char(int level)
static int ftp_send_command(struct connectdata *conn, const char *message, ...)
{
int ftp_code;
- ssize_t nread=0;
+ ssize_t nread = 0;
va_list args;
char print_buffer[50];
diff --git a/lib/select.c b/lib/select.c
index f6fecaf5..28390a4a 100644
--- a/lib/select.c
+++ b/lib/select.c
@@ -51,7 +51,7 @@
#include "warnless.h"
/* Convenience local macros */
-#define ELAPSED_MS() (int)curlx_tvdiff(curlx_tvnow(), initial_tv)
+#define ELAPSED_MS() (int)Curl_timediff(Curl_now(), initial_tv)
int Curl_ack_eintr = 0;
#define ERROR_NOT_EINTR(error) (Curl_ack_eintr || error != EINTR)
@@ -96,7 +96,7 @@ int Curl_wait_ms(int timeout_ms)
Sleep(timeout_ms);
#else
pending_ms = timeout_ms;
- initial_tv = curlx_tvnow();
+ initial_tv = Curl_now();
do {
#if defined(HAVE_POLL_FINE)
r = poll(NULL, 0, pending_ms);
@@ -177,14 +177,14 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */
return r;
}
- /* Avoid initial timestamp, avoid curlx_tvnow() call, when elapsed
+ /* Avoid initial timestamp, avoid Curl_now() call, when elapsed
time in this function does not need to be measured. This happens
when function is called with a zero timeout or a negative timeout
value indicating a blocking call should be performed. */
if(timeout_ms > 0) {
pending_ms = (int)timeout_ms;
- initial_tv = curlx_tvnow();
+ initial_tv = Curl_now();
}
#ifdef HAVE_POLL_FINE
@@ -418,14 +418,14 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms)
return r;
}
- /* Avoid initial timestamp, avoid curlx_tvnow() call, when elapsed
+ /* Avoid initial timestamp, avoid Curl_now() call, when elapsed
time in this function does not need to be measured. This happens
when function is called with a zero timeout or a negative timeout
value indicating a blocking call should be performed. */
if(timeout_ms > 0) {
pending_ms = timeout_ms;
- initial_tv = curlx_tvnow();
+ initial_tv = Curl_now();
}
#ifdef HAVE_POLL_FINE
diff --git a/lib/sendf.c b/lib/sendf.c
index 595c3617..a1cb8e47 100644
--- a/lib/sendf.c
+++ b/lib/sendf.c
@@ -22,6 +22,10 @@
#include "curl_setup.h"
+#ifdef HAVE_LINUX_TCP_H
+#include <linux/tcp.h>
+#endif
+
#include <curl/curl.h>
#include "urldata.h"
@@ -63,7 +67,7 @@ static size_t convert_lineends(struct Curl_easy *data,
if(*startPtr == '\n') {
/* This block of incoming data starts with the
previous block's LF so get rid of it */
- memmove(startPtr, startPtr+1, size-1);
+ memmove(startPtr, startPtr + 1, size-1);
size--;
/* and it wasn't a bare CR but a CRLF conversion instead */
data->state.crlf_conversions++;
@@ -75,7 +79,7 @@ static size_t convert_lineends(struct Curl_easy *data,
inPtr = outPtr = memchr(startPtr, '\r', size);
if(inPtr) {
/* at least one CR, now look for CRLF */
- while(inPtr < (startPtr+size-1)) {
+ while(inPtr < (startPtr + size-1)) {
/* note that it's size-1, so we'll never look past the last byte */
if(memcmp(inPtr, "\r\n", 2) == 0) {
/* CRLF found, bump past the CR and copy the NL */
@@ -98,7 +102,7 @@ static size_t convert_lineends(struct Curl_easy *data,
inPtr++;
} /* end of while loop */
- if(inPtr < startPtr+size) {
+ if(inPtr < startPtr + size) {
/* handle last byte */
if(*inPtr == '\r') {
/* deal with a CR at the end of the buffer */
@@ -112,7 +116,7 @@ static size_t convert_lineends(struct Curl_easy *data,
}
outPtr++;
}
- if(outPtr < startPtr+size)
+ if(outPtr < startPtr + size)
/* tidy up by null terminating the now shorter data */
*outPtr = '\0';
@@ -241,25 +245,25 @@ void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
void Curl_failf(struct Curl_easy *data, const char *fmt, ...)
{
- va_list ap;
- size_t len;
- char error[CURL_ERROR_SIZE + 2];
- va_start(ap, fmt);
-
- vsnprintf(error, CURL_ERROR_SIZE, fmt, ap);
- len = strlen(error);
+ if(data->set.verbose || data->set.errorbuffer) {
+ va_list ap;
+ size_t len;
+ char error[CURL_ERROR_SIZE + 2];
+ va_start(ap, fmt);
+ vsnprintf(error, CURL_ERROR_SIZE, fmt, ap);
+ len = strlen(error);
- if(data->set.errorbuffer && !data->state.errorbuf) {
- strcpy(data->set.errorbuffer, error);
- data->state.errorbuf = TRUE; /* wrote error string */
- }
- if(data->set.verbose) {
- error[len] = '\n';
- error[++len] = '\0';
- Curl_debug(data, CURLINFO_TEXT, error, len, NULL);
+ if(data->set.errorbuffer && !data->state.errorbuf) {
+ strcpy(data->set.errorbuffer, error);
+ data->state.errorbuf = TRUE; /* wrote error string */
+ }
+ if(data->set.verbose) {
+ error[len] = '\n';
+ error[++len] = '\0';
+ Curl_debug(data, CURLINFO_TEXT, error, len, NULL);
+ }
+ va_end(ap);
}
-
- va_end(ap);
}
/* Curl_sendf() sends formatted data to the server */
@@ -279,7 +283,7 @@ CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn,
if(!s)
return CURLE_OUT_OF_MEMORY; /* failure */
- bytes_written=0;
+ bytes_written = 0;
write_len = strlen(s);
sptr = s;
@@ -360,7 +364,7 @@ ssize_t Curl_send_plain(struct connectdata *conn, int num,
available. */
pre_receive_plain(conn, num);
-#ifdef MSG_FASTOPEN /* Linux */
+#if defined(MSG_FASTOPEN) && !defined(TCP_FASTOPEN_CONNECT) /* Linux */
if(conn->bits.tcp_fastopen) {
bytes_written = sendto(sockfd, mem, len, MSG_FASTOPEN,
conn->ip_addr->ai_addr, conn->ip_addr->ai_addrlen);
@@ -387,7 +391,7 @@ ssize_t Curl_send_plain(struct connectdata *conn, int num,
#endif
) {
/* this is just a case of EWOULDBLOCK */
- bytes_written=0;
+ bytes_written = 0;
*code = CURLE_AGAIN;
}
else {
@@ -480,7 +484,7 @@ static CURLcode pausewrite(struct Curl_easy *data,
bool newtype = TRUE;
if(s->tempcount) {
- for(i=0; i< s->tempcount; i++) {
+ for(i = 0; i< s->tempcount; i++) {
if(s->tempwrite[i].type == type) {
/* data for this type exists */
newtype = FALSE;
@@ -704,7 +708,7 @@ CURLcode Curl_read(struct connectdata *conn, /* connection data */
us use the correct ssl handle. */
int num = (sockfd == conn->sock[SECONDARYSOCKET]);
- *n=0; /* reset amount to zero */
+ *n = 0; /* reset amount to zero */
/* If session can pipeline, check connection buffer */
if(pipelining) {
@@ -823,8 +827,8 @@ int Curl_debug(struct Curl_easy *data, curl_infotype type,
int rc;
if(data->set.printhost && conn && conn->host.dispname) {
char buffer[160];
- const char *t=NULL;
- const char *w="Data";
+ const char *t = NULL;
+ const char *w = "Data";
switch(type) {
case CURLINFO_HEADER_IN:
w = "Header";
diff --git a/lib/setopt.c b/lib/setopt.c
new file mode 100644
index 00000000..70466bff
--- /dev/null
+++ b/lib/setopt.c
@@ -0,0 +1,2554 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, 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 https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#ifdef HAVE_LINUX_TCP_H
+#include <linux/tcp.h>
+#endif
+
+#include "urldata.h"
+#include "url.h"
+#include "progress.h"
+#include "content_encoding.h"
+#include "strcase.h"
+#include "share.h"
+#include "vtls/vtls.h"
+#include "warnless.h"
+#include "sendf.h"
+#include "http2.h"
+#include "setopt.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+CURLcode Curl_setstropt(char **charp, const char *s)
+{
+ /* Release the previous storage at `charp' and replace by a dynamic storage
+ copy of `s'. Return CURLE_OK or CURLE_OUT_OF_MEMORY. */
+
+ Curl_safefree(*charp);
+
+ if(s) {
+ char *str = strdup(s);
+
+ if(!str)
+ return CURLE_OUT_OF_MEMORY;
+
+ *charp = str;
+ }
+
+ return CURLE_OK;
+}
+
+static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp)
+{
+ CURLcode result = CURLE_OK;
+ char *user = NULL;
+ char *passwd = NULL;
+
+ /* Parse the login details if specified. It not then we treat NULL as a hint
+ to clear the existing data */
+ if(option) {
+ result = Curl_parse_login_details(option, strlen(option),
+ (userp ? &user : NULL),
+ (passwdp ? &passwd : NULL),
+ NULL);
+ }
+
+ if(!result) {
+ /* Store the username part of option if required */
+ if(userp) {
+ if(!user && option && option[0] == ':') {
+ /* Allocate an empty string instead of returning NULL as user name */
+ user = strdup("");
+ if(!user)
+ result = CURLE_OUT_OF_MEMORY;
+ }
+
+ Curl_safefree(*userp);
+ *userp = user;
+ }
+
+ /* Store the password part of option if required */
+ if(passwdp) {
+ Curl_safefree(*passwdp);
+ *passwdp = passwd;
+ }
+ }
+
+ return result;
+}
+
+#define C_SSLVERSION_VALUE(x) (x & 0xffff)
+#define C_SSLVERSION_MAX_VALUE(x) (x & 0xffff0000)
+
+static CURLcode setopt(struct Curl_easy *data, CURLoption option,
+ va_list param)
+{
+ char *argptr;
+ CURLcode result = CURLE_OK;
+ long arg;
+ curl_off_t bigsize;
+
+ switch(option) {
+ case CURLOPT_DNS_CACHE_TIMEOUT:
+ arg = va_arg(param, long);
+ if(arg < -1)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.dns_cache_timeout = arg;
+ break;
+ case CURLOPT_DNS_USE_GLOBAL_CACHE:
+ /* remember we want this enabled */
+ arg = va_arg(param, long);
+ data->set.global_dns_cache = (0 != arg) ? TRUE : FALSE;
+ break;
+ case CURLOPT_SSL_CIPHER_LIST:
+ /* set a list of cipher we want to use in the SSL connection */
+ result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER_LIST_ORIG],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_PROXY_SSL_CIPHER_LIST:
+ /* set a list of cipher we want to use in the SSL connection for proxy */
+ result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER_LIST_PROXY],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_RANDOM_FILE:
+ /*
+ * This is the path name to a file that contains random data to seed
+ * the random SSL stuff with. The file is only used for reading.
+ */
+ result = Curl_setstropt(&data->set.str[STRING_SSL_RANDOM_FILE],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_EGDSOCKET:
+ /*
+ * The Entropy Gathering Daemon socket pathname
+ */
+ result = Curl_setstropt(&data->set.str[STRING_SSL_EGDSOCKET],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_MAXCONNECTS:
+ /*
+ * Set the absolute number of maximum simultaneous alive connection that
+ * libcurl is allowed to have.
+ */
+ arg = va_arg(param, long);
+ if(arg < 0)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.maxconnects = arg;
+ break;
+ case CURLOPT_FORBID_REUSE:
+ /*
+ * When this transfer is done, it must not be left to be reused by a
+ * subsequent transfer but shall be closed immediately.
+ */
+ data->set.reuse_forbid = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+ case CURLOPT_FRESH_CONNECT:
+ /*
+ * This transfer shall not use a previously cached connection but
+ * should be made with a fresh new connect!
+ */
+ data->set.reuse_fresh = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+ case CURLOPT_VERBOSE:
+ /*
+ * Verbose means infof() calls that give a lot of information about
+ * the connection and transfer procedures as well as internal choices.
+ */
+ data->set.verbose = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+ case CURLOPT_HEADER:
+ /*
+ * Set to include the header in the general data output stream.
+ */
+ data->set.include_header = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+ case CURLOPT_NOPROGRESS:
+ /*
+ * Shut off the internal supported progress meter
+ */
+ data->set.hide_progress = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ if(data->set.hide_progress)
+ data->progress.flags |= PGRS_HIDE;
+ else
+ data->progress.flags &= ~PGRS_HIDE;
+ break;
+ case CURLOPT_NOBODY:
+ /*
+ * Do not include the body part in the output data stream.
+ */
+ data->set.opt_no_body = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+ case CURLOPT_FAILONERROR:
+ /*
+ * Don't output the >=400 error code HTML-page, but instead only
+ * return error.
+ */
+ data->set.http_fail_on_error = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+ case CURLOPT_KEEP_SENDING_ON_ERROR:
+ data->set.http_keep_sending_on_error = (0 != va_arg(param, long)) ?
+ TRUE : FALSE;
+ break;
+ case CURLOPT_UPLOAD:
+ case CURLOPT_PUT:
+ /*
+ * We want to sent data to the remote host. If this is HTTP, that equals
+ * using the PUT request.
+ */
+ data->set.upload = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ if(data->set.upload) {
+ /* If this is HTTP, PUT is what's needed to "upload" */
+ data->set.httpreq = HTTPREQ_PUT;
+ data->set.opt_no_body = FALSE; /* this is implied */
+ }
+ else
+ /* In HTTP, the opposite of upload is GET (unless NOBODY is true as
+ then this can be changed to HEAD later on) */
+ data->set.httpreq = HTTPREQ_GET;
+ break;
+ case CURLOPT_REQUEST_TARGET:
+ result = Curl_setstropt(&data->set.str[STRING_TARGET],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_FILETIME:
+ /*
+ * Try to get the file time of the remote document. The time will
+ * later (possibly) become available using curl_easy_getinfo().
+ */
+ data->set.get_filetime = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+ case CURLOPT_FTP_CREATE_MISSING_DIRS:
+ /*
+ * An FTP option that modifies an upload to create missing directories on
+ * the server.
+ */
+ switch(va_arg(param, long)) {
+ case 0:
+ data->set.ftp_create_missing_dirs = 0;
+ break;
+ case 1:
+ data->set.ftp_create_missing_dirs = 1;
+ break;
+ case 2:
+ data->set.ftp_create_missing_dirs = 2;
+ break;
+ default:
+ /* reserve other values for future use */
+ result = CURLE_UNKNOWN_OPTION;
+ break;
+ }
+ break;
+ case CURLOPT_SERVER_RESPONSE_TIMEOUT:
+ /*
+ * Option that specifies how quickly an server response must be obtained
+ * before it is considered failure. For pingpong protocols.
+ */
+ arg = va_arg(param, long);
+ if((arg >= 0) && (arg < (INT_MAX/1000)))
+ data->set.server_response_timeout = arg * 1000;
+ else
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ break;
+ case CURLOPT_TFTP_NO_OPTIONS:
+ /*
+ * Option that prevents libcurl from sending TFTP option requests to the
+ * server.
+ */
+ data->set.tftp_no_options = va_arg(param, long) != 0;
+ break;
+ case CURLOPT_TFTP_BLKSIZE:
+ /*
+ * TFTP option that specifies the block size to use for data transmission.
+ */
+ arg = va_arg(param, long);
+ if(arg < 0)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.tftp_blksize = arg;
+ break;
+ case CURLOPT_DIRLISTONLY:
+ /*
+ * An option that changes the command to one that asks for a list
+ * only, no file info details.
+ */
+ data->set.ftp_list_only = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+ case CURLOPT_APPEND:
+ /*
+ * We want to upload and append to an existing file.
+ */
+ data->set.ftp_append = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+ case CURLOPT_FTP_FILEMETHOD:
+ /*
+ * How do access files over FTP.
+ */
+ arg = va_arg(param, long);
+ if((arg < CURLFTPMETHOD_DEFAULT) || (arg > CURLFTPMETHOD_SINGLECWD))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.ftp_filemethod = (curl_ftpfile)arg;
+ break;
+ case CURLOPT_NETRC:
+ /*
+ * Parse the $HOME/.netrc file
+ */
+ arg = va_arg(param, long);
+ if((arg < CURL_NETRC_IGNORED) || (arg > CURL_NETRC_REQUIRED))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.use_netrc = (enum CURL_NETRC_OPTION)arg;
+ break;
+ case CURLOPT_NETRC_FILE:
+ /*
+ * Use this file instead of the $HOME/.netrc file
+ */
+ result = Curl_setstropt(&data->set.str[STRING_NETRC_FILE],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_TRANSFERTEXT:
+ /*
+ * This option was previously named 'FTPASCII'. Renamed to work with
+ * more protocols than merely FTP.
+ *
+ * Transfer using ASCII (instead of BINARY).
+ */
+ data->set.prefer_ascii = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+ case CURLOPT_TIMECONDITION:
+ /*
+ * Set HTTP time condition. This must be one of the defines in the
+ * curl/curl.h header file.
+ */
+ arg = va_arg(param, long);
+ if((arg < CURL_TIMECOND_NONE) || (arg > CURL_TIMECOND_LASTMOD))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.timecondition = (curl_TimeCond)arg;
+ break;
+ case CURLOPT_TIMEVALUE:
+ /*
+ * This is the value to compare with the remote document with the
+ * method set with CURLOPT_TIMECONDITION
+ */
+ data->set.timevalue = (time_t)va_arg(param, long);
+ break;
+ case CURLOPT_SSLVERSION:
+ /*
+ * Set explicit SSL version to try to connect with, as some SSL
+ * implementations are lame.
+ */
+#ifdef USE_SSL
+ arg = va_arg(param, long);
+ if((arg < CURL_SSLVERSION_DEFAULT) || (arg > CURL_SSLVERSION_TLSv1_3))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.ssl.primary.version = C_SSLVERSION_VALUE(arg);
+ data->set.ssl.primary.version_max = C_SSLVERSION_MAX_VALUE(arg);
+#else
+ result = CURLE_UNKNOWN_OPTION;
+#endif
+ break;
+ case CURLOPT_PROXY_SSLVERSION:
+ /*
+ * Set explicit SSL version to try to connect with for proxy, as some SSL
+ * implementations are lame.
+ */
+#ifdef USE_SSL
+ arg = va_arg(param, long);
+ if((arg < CURL_SSLVERSION_DEFAULT) || (arg > CURL_SSLVERSION_TLSv1_3))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.proxy_ssl.primary.version = C_SSLVERSION_VALUE(arg);
+ data->set.proxy_ssl.primary.version_max = C_SSLVERSION_MAX_VALUE(arg);
+#else
+ result = CURLE_UNKNOWN_OPTION;
+#endif
+ break;
+
+#ifndef CURL_DISABLE_HTTP
+ case CURLOPT_AUTOREFERER:
+ /*
+ * Switch on automatic referer that gets set if curl follows locations.
+ */
+ data->set.http_auto_referer = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_ACCEPT_ENCODING:
+ /*
+ * String to use at the value of Accept-Encoding header.
+ *
+ * If the encoding is set to "" we use an Accept-Encoding header that
+ * encompasses all the encodings we support.
+ * If the encoding is set to NULL we don't send an Accept-Encoding header
+ * and ignore an received Content-Encoding header.
+ *
+ */
+ argptr = va_arg(param, char *);
+ if(argptr && !*argptr) {
+ argptr = Curl_all_content_encodings();
+ if(!argptr)
+ result = CURLE_OUT_OF_MEMORY;
+ else {
+ result = Curl_setstropt(&data->set.str[STRING_ENCODING], argptr);
+ free(argptr);
+ }
+ }
+ else
+ result = Curl_setstropt(&data->set.str[STRING_ENCODING], argptr);
+ break;
+
+ case CURLOPT_TRANSFER_ENCODING:
+ data->set.http_transfer_encoding = (0 != va_arg(param, long)) ?
+ TRUE : FALSE;
+ break;
+
+ case CURLOPT_FOLLOWLOCATION:
+ /*
+ * Follow Location: header hints on a HTTP-server.
+ */
+ data->set.http_follow_location = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_UNRESTRICTED_AUTH:
+ /*
+ * Send authentication (user+password) when following locations, even when
+ * hostname changed.
+ */
+ data->set.http_disable_hostname_check_before_authentication =
+ (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_MAXREDIRS:
+ /*
+ * The maximum amount of hops you allow curl to follow Location:
+ * headers. This should mostly be used to detect never-ending loops.
+ */
+ arg = va_arg(param, long);
+ if(arg < -1)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.maxredirs = arg;
+ break;
+
+ case CURLOPT_POSTREDIR:
+ /*
+ * Set the behaviour of POST when redirecting
+ * CURL_REDIR_GET_ALL - POST is changed to GET after 301 and 302
+ * CURL_REDIR_POST_301 - POST is kept as POST after 301
+ * CURL_REDIR_POST_302 - POST is kept as POST after 302
+ * CURL_REDIR_POST_303 - POST is kept as POST after 303
+ * CURL_REDIR_POST_ALL - POST is kept as POST after 301, 302 and 303
+ * other - POST is kept as POST after 301 and 302
+ */
+ arg = va_arg(param, long);
+ if(arg < CURL_REDIR_GET_ALL)
+ /* no return error on too high numbers since the bitmask could be
+ extended in a future */
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.keep_post = arg & CURL_REDIR_POST_ALL;
+ break;
+
+ case CURLOPT_POST:
+ /* Does this option serve a purpose anymore? Yes it does, when
+ CURLOPT_POSTFIELDS isn't used and the POST data is read off the
+ callback! */
+ if(va_arg(param, long)) {
+ data->set.httpreq = HTTPREQ_POST;
+ data->set.opt_no_body = FALSE; /* this is implied */
+ }
+ else
+ data->set.httpreq = HTTPREQ_GET;
+ break;
+
+ case CURLOPT_COPYPOSTFIELDS:
+ /*
+ * A string with POST data. Makes curl HTTP POST. Even if it is NULL.
+ * If needed, CURLOPT_POSTFIELDSIZE must have been set prior to
+ * CURLOPT_COPYPOSTFIELDS and not altered later.
+ */
+ argptr = va_arg(param, char *);
+
+ if(!argptr || data->set.postfieldsize == -1)
+ result = Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], argptr);
+ else {
+ /*
+ * Check that requested length does not overflow the size_t type.
+ */
+
+ if((data->set.postfieldsize < 0) ||
+ ((sizeof(curl_off_t) != sizeof(size_t)) &&
+ (data->set.postfieldsize > (curl_off_t)((size_t)-1))))
+ result = CURLE_OUT_OF_MEMORY;
+ else {
+ char *p;
+
+ (void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
+
+ /* Allocate even when size == 0. This satisfies the need of possible
+ later address compare to detect the COPYPOSTFIELDS mode, and
+ to mark that postfields is used rather than read function or
+ form data.
+ */
+ p = malloc((size_t)(data->set.postfieldsize?
+ data->set.postfieldsize:1));
+
+ if(!p)
+ result = CURLE_OUT_OF_MEMORY;
+ else {
+ if(data->set.postfieldsize)
+ memcpy(p, argptr, (size_t)data->set.postfieldsize);
+
+ data->set.str[STRING_COPYPOSTFIELDS] = p;
+ }
+ }
+ }
+
+ data->set.postfields = data->set.str[STRING_COPYPOSTFIELDS];
+ data->set.httpreq = HTTPREQ_POST;
+ break;
+
+ case CURLOPT_POSTFIELDS:
+ /*
+ * Like above, but use static data instead of copying it.
+ */
+ data->set.postfields = va_arg(param, void *);
+ /* Release old copied data. */
+ (void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
+ data->set.httpreq = HTTPREQ_POST;
+ break;
+
+ case CURLOPT_POSTFIELDSIZE:
+ /*
+ * The size of the POSTFIELD data to prevent libcurl to do strlen() to
+ * figure it out. Enables binary posts.
+ */
+ bigsize = va_arg(param, long);
+ if(bigsize < -1)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
+ if(data->set.postfieldsize < bigsize &&
+ data->set.postfields == data->set.str[STRING_COPYPOSTFIELDS]) {
+ /* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */
+ (void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
+ data->set.postfields = NULL;
+ }
+
+ data->set.postfieldsize = bigsize;
+ break;
+
+ case CURLOPT_POSTFIELDSIZE_LARGE:
+ /*
+ * The size of the POSTFIELD data to prevent libcurl to do strlen() to
+ * figure it out. Enables binary posts.
+ */
+ bigsize = va_arg(param, curl_off_t);
+ if(bigsize < -1)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
+ if(data->set.postfieldsize < bigsize &&
+ data->set.postfields == data->set.str[STRING_COPYPOSTFIELDS]) {
+ /* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */
+ (void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
+ data->set.postfields = NULL;
+ }
+
+ data->set.postfieldsize = bigsize;
+ break;
+
+ case CURLOPT_HTTPPOST:
+ /*
+ * Set to make us do HTTP POST
+ */
+ data->set.httppost = va_arg(param, struct curl_httppost *);
+ data->set.httpreq = HTTPREQ_POST_FORM;
+ data->set.opt_no_body = FALSE; /* this is implied */
+ break;
+#endif /* CURL_DISABLE_HTTP */
+
+ case CURLOPT_MIMEPOST:
+ /*
+ * Set to make us do MIME/form POST
+ */
+ result = Curl_mime_set_subparts(&data->set.mimepost,
+ va_arg(param, curl_mime *), FALSE);
+ if(!result) {
+ data->set.httpreq = HTTPREQ_POST_MIME;
+ data->set.opt_no_body = FALSE; /* this is implied */
+ }
+ break;
+
+ case CURLOPT_REFERER:
+ /*
+ * String to set in the HTTP Referer: field.
+ */
+ if(data->change.referer_alloc) {
+ Curl_safefree(data->change.referer);
+ data->change.referer_alloc = FALSE;
+ }
+ result = Curl_setstropt(&data->set.str[STRING_SET_REFERER],
+ va_arg(param, char *));
+ data->change.referer = data->set.str[STRING_SET_REFERER];
+ break;
+
+ case CURLOPT_USERAGENT:
+ /*
+ * String to use in the HTTP User-Agent field
+ */
+ result = Curl_setstropt(&data->set.str[STRING_USERAGENT],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_HTTPHEADER:
+ /*
+ * Set a list with HTTP headers to use (or replace internals with)
+ */
+ data->set.headers = va_arg(param, struct curl_slist *);
+ break;
+
+#ifndef CURL_DISABLE_HTTP
+ case CURLOPT_PROXYHEADER:
+ /*
+ * Set a list with proxy headers to use (or replace internals with)
+ *
+ * Since CURLOPT_HTTPHEADER was the only way to set HTTP headers for a
+ * long time we remain doing it this way until CURLOPT_PROXYHEADER is
+ * used. As soon as this option has been used, if set to anything but
+ * NULL, custom headers for proxies are only picked from this list.
+ *
+ * Set this option to NULL to restore the previous behavior.
+ */
+ data->set.proxyheaders = va_arg(param, struct curl_slist *);
+ break;
+
+ case CURLOPT_HEADEROPT:
+ /*
+ * Set header option.
+ */
+ arg = va_arg(param, long);
+ data->set.sep_headers = (arg & CURLHEADER_SEPARATE)? TRUE: FALSE;
+ break;
+
+ case CURLOPT_HTTP200ALIASES:
+ /*
+ * Set a list of aliases for HTTP 200 in response header
+ */
+ data->set.http200aliases = va_arg(param, struct curl_slist *);
+ break;
+
+#if !defined(CURL_DISABLE_COOKIES)
+ case CURLOPT_COOKIE:
+ /*
+ * Cookie string to send to the remote server in the request.
+ */
+ result = Curl_setstropt(&data->set.str[STRING_COOKIE],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_COOKIEFILE:
+ /*
+ * Set cookie file to read and parse. Can be used multiple times.
+ */
+ argptr = (char *)va_arg(param, void *);
+ if(argptr) {
+ struct curl_slist *cl;
+ /* append the cookie file name to the list of file names, and deal with
+ them later */
+ cl = curl_slist_append(data->change.cookielist, argptr);
+ if(!cl) {
+ curl_slist_free_all(data->change.cookielist);
+ data->change.cookielist = NULL;
+ return CURLE_OUT_OF_MEMORY;
+ }
+ data->change.cookielist = cl; /* store the list for later use */
+ }
+ break;
+
+ case CURLOPT_COOKIEJAR:
+ /*
+ * Set cookie file name to dump all cookies to when we're done.
+ */
+ {
+ struct CookieInfo *newcookies;
+ result = Curl_setstropt(&data->set.str[STRING_COOKIEJAR],
+ va_arg(param, char *));
+
+ /*
+ * Activate the cookie parser. This may or may not already
+ * have been made.
+ */
+ newcookies = Curl_cookie_init(data, NULL, data->cookies,
+ data->set.cookiesession);
+ if(!newcookies)
+ result = CURLE_OUT_OF_MEMORY;
+ data->cookies = newcookies;
+ }
+ break;
+
+ case CURLOPT_COOKIESESSION:
+ /*
+ * Set this option to TRUE to start a new "cookie session". It will
+ * prevent the forthcoming read-cookies-from-file actions to accept
+ * cookies that are marked as being session cookies, as they belong to a
+ * previous session.
+ *
+ * In the original Netscape cookie spec, "session cookies" are cookies
+ * with no expire date set. RFC2109 describes the same action if no
+ * 'Max-Age' is set and RFC2965 includes the RFC2109 description and adds
+ * a 'Discard' action that can enforce the discard even for cookies that
+ * have a Max-Age.
+ *
+ * We run mostly with the original cookie spec, as hardly anyone implements
+ * anything else.
+ */
+ data->set.cookiesession = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_COOKIELIST:
+ argptr = va_arg(param, char *);
+
+ if(argptr == NULL)
+ break;
+
+ if(strcasecompare(argptr, "ALL")) {
+ /* clear all cookies */
+ Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
+ Curl_cookie_clearall(data->cookies);
+ Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+ }
+ else if(strcasecompare(argptr, "SESS")) {
+ /* clear session cookies */
+ Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
+ Curl_cookie_clearsess(data->cookies);
+ Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+ }
+ else if(strcasecompare(argptr, "FLUSH")) {
+ /* flush cookies to file, takes care of the locking */
+ Curl_flush_cookies(data, 0);
+ }
+ else if(strcasecompare(argptr, "RELOAD")) {
+ /* reload cookies from file */
+ Curl_cookie_loadfiles(data);
+ break;
+ }
+ else {
+ if(!data->cookies)
+ /* if cookie engine was not running, activate it */
+ data->cookies = Curl_cookie_init(data, NULL, NULL, TRUE);
+
+ argptr = strdup(argptr);
+ if(!argptr || !data->cookies) {
+ result = CURLE_OUT_OF_MEMORY;
+ free(argptr);
+ }
+ else {
+ Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
+
+ if(checkprefix("Set-Cookie:", argptr))
+ /* HTTP Header format line */
+ Curl_cookie_add(data, data->cookies, TRUE, argptr + 11, NULL, NULL);
+
+ else
+ /* Netscape format line */
+ Curl_cookie_add(data, data->cookies, FALSE, argptr, NULL, NULL);
+
+ Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+ free(argptr);
+ }
+ }
+
+ break;
+#endif /* !CURL_DISABLE_COOKIES */
+
+ case CURLOPT_HTTPGET:
+ /*
+ * Set to force us do HTTP GET
+ */
+ if(va_arg(param, long)) {
+ data->set.httpreq = HTTPREQ_GET;
+ data->set.upload = FALSE; /* switch off upload */
+ data->set.opt_no_body = FALSE; /* this is implied */
+ }
+ break;
+
+ case CURLOPT_HTTP_VERSION:
+ /*
+ * This sets a requested HTTP version to be used. The value is one of
+ * the listed enums in curl/curl.h.
+ */
+ arg = va_arg(param, long);
+ if(arg < CURL_HTTP_VERSION_NONE)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+#ifndef USE_NGHTTP2
+ if(arg >= CURL_HTTP_VERSION_2)
+ return CURLE_UNSUPPORTED_PROTOCOL;
+#else
+ if(arg > CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE)
+ return CURLE_UNSUPPORTED_PROTOCOL;
+#endif
+ data->set.httpversion = arg;
+ break;
+
+ case CURLOPT_EXPECT_100_TIMEOUT_MS:
+ /*
+ * Time to wait for a response to a HTTP request containing an
+ * Expect: 100-continue header before sending the data anyway.
+ */
+ arg = va_arg(param, long);
+ if(arg < 0)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.expect_100_timeout = arg;
+ break;
+
+#endif /* CURL_DISABLE_HTTP */
+
+ case CURLOPT_HTTPAUTH:
+ /*
+ * Set HTTP Authentication type BITMASK.
+ */
+ {
+ int bitcheck;
+ bool authbits;
+ unsigned long auth = va_arg(param, unsigned long);
+
+ if(auth == CURLAUTH_NONE) {
+ data->set.httpauth = auth;
+ break;
+ }
+
+ /* the DIGEST_IE bit is only used to set a special marker, for all the
+ rest we need to handle it as normal DIGEST */
+ data->state.authhost.iestyle = (auth & CURLAUTH_DIGEST_IE) ? TRUE : FALSE;
+
+ if(auth & CURLAUTH_DIGEST_IE) {
+ auth |= CURLAUTH_DIGEST; /* set standard digest bit */
+ auth &= ~CURLAUTH_DIGEST_IE; /* unset ie digest bit */
+ }
+
+ /* switch off bits we can't support */
+#ifndef USE_NTLM
+ auth &= ~CURLAUTH_NTLM; /* no NTLM support */
+ auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */
+#elif !defined(NTLM_WB_ENABLED)
+ auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */
+#endif
+#ifndef USE_SPNEGO
+ auth &= ~CURLAUTH_NEGOTIATE; /* no Negotiate (SPNEGO) auth without
+ GSS-API or SSPI */
+#endif
+
+ /* check if any auth bit lower than CURLAUTH_ONLY is still set */
+ bitcheck = 0;
+ authbits = FALSE;
+ while(bitcheck < 31) {
+ if(auth & (1UL << bitcheck++)) {
+ authbits = TRUE;
+ break;
+ }
+ }
+ if(!authbits)
+ return CURLE_NOT_BUILT_IN; /* no supported types left! */
+
+ data->set.httpauth = auth;
+ }
+ break;
+
+ case CURLOPT_CUSTOMREQUEST:
+ /*
+ * Set a custom string to use as request
+ */
+ result = Curl_setstropt(&data->set.str[STRING_CUSTOMREQUEST],
+ va_arg(param, char *));
+
+ /* we don't set
+ data->set.httpreq = HTTPREQ_CUSTOM;
+ here, we continue as if we were using the already set type
+ and this just changes the actual request keyword */
+ break;
+
+#ifndef CURL_DISABLE_PROXY
+ case CURLOPT_HTTPPROXYTUNNEL:
+ /*
+ * Tunnel operations through the proxy instead of normal proxy use
+ */
+ data->set.tunnel_thru_httpproxy = (0 != va_arg(param, long)) ?
+ TRUE : FALSE;
+ break;
+
+ case CURLOPT_PROXYPORT:
+ /*
+ * Explicitly set HTTP proxy port number.
+ */
+ arg = va_arg(param, long);
+ if((arg < 0) || (arg > 65535))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.proxyport = arg;
+ break;
+
+ case CURLOPT_PROXYAUTH:
+ /*
+ * Set HTTP Authentication type BITMASK.
+ */
+ {
+ int bitcheck;
+ bool authbits;
+ unsigned long auth = va_arg(param, unsigned long);
+
+ if(auth == CURLAUTH_NONE) {
+ data->set.proxyauth = auth;
+ break;
+ }
+
+ /* the DIGEST_IE bit is only used to set a special marker, for all the
+ rest we need to handle it as normal DIGEST */
+ data->state.authproxy.iestyle = (auth & CURLAUTH_DIGEST_IE) ? TRUE : FALSE;
+
+ if(auth & CURLAUTH_DIGEST_IE) {
+ auth |= CURLAUTH_DIGEST; /* set standard digest bit */
+ auth &= ~CURLAUTH_DIGEST_IE; /* unset ie digest bit */
+ }
+ /* switch off bits we can't support */
+#ifndef USE_NTLM
+ auth &= ~CURLAUTH_NTLM; /* no NTLM support */
+ auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */
+#elif !defined(NTLM_WB_ENABLED)
+ auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */
+#endif
+#ifndef USE_SPNEGO
+ auth &= ~CURLAUTH_NEGOTIATE; /* no Negotiate (SPNEGO) auth without
+ GSS-API or SSPI */
+#endif
+
+ /* check if any auth bit lower than CURLAUTH_ONLY is still set */
+ bitcheck = 0;
+ authbits = FALSE;
+ while(bitcheck < 31) {
+ if(auth & (1UL << bitcheck++)) {
+ authbits = TRUE;
+ break;
+ }
+ }
+ if(!authbits)
+ return CURLE_NOT_BUILT_IN; /* no supported types left! */
+
+ data->set.proxyauth = auth;
+ }
+ break;
+
+ case CURLOPT_PROXY:
+ /*
+ * Set proxy server:port to use as proxy.
+ *
+ * If the proxy is set to "" (and CURLOPT_SOCKS_PROXY is set to "" or NULL)
+ * we explicitly say that we don't want to use a proxy
+ * (even though there might be environment variables saying so).
+ *
+ * Setting it to NULL, means no proxy but allows the environment variables
+ * to decide for us (if CURLOPT_SOCKS_PROXY setting it to NULL).
+ */
+ result = Curl_setstropt(&data->set.str[STRING_PROXY],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_PRE_PROXY:
+ /*
+ * Set proxy server:port to use as SOCKS proxy.
+ *
+ * If the proxy is set to "" or NULL we explicitly say that we don't want
+ * to use the socks proxy.
+ */
+ result = Curl_setstropt(&data->set.str[STRING_PRE_PROXY],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_PROXYTYPE:
+ /*
+ * Set proxy type. HTTP/HTTP_1_0/SOCKS4/SOCKS4a/SOCKS5/SOCKS5_HOSTNAME
+ */
+ arg = va_arg(param, long);
+ if((arg < CURLPROXY_HTTP) || (arg > CURLPROXY_SOCKS5_HOSTNAME))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.proxytype = (curl_proxytype)arg;
+ break;
+
+ case CURLOPT_PROXY_TRANSFER_MODE:
+ /*
+ * set transfer mode (;type=<a|i>) when doing FTP via an HTTP proxy
+ */
+ switch(va_arg(param, long)) {
+ case 0:
+ data->set.proxy_transfer_mode = FALSE;
+ break;
+ case 1:
+ data->set.proxy_transfer_mode = TRUE;
+ break;
+ default:
+ /* reserve other values for future use */
+ result = CURLE_UNKNOWN_OPTION;
+ break;
+ }
+ break;
+#endif /* CURL_DISABLE_PROXY */
+
+ case CURLOPT_SOCKS5_AUTH:
+ data->set.socks5auth = va_arg(param, unsigned long);
+ if(data->set.socks5auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI))
+ result = CURLE_NOT_BUILT_IN;
+ break;
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+ case CURLOPT_SOCKS5_GSSAPI_NEC:
+ /*
+ * Set flag for NEC SOCK5 support
+ */
+ data->set.socks5_gssapi_nec = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_SOCKS5_GSSAPI_SERVICE:
+ case CURLOPT_PROXY_SERVICE_NAME:
+ /*
+ * Set proxy authentication service name for Kerberos 5 and SPNEGO
+ */
+ result = Curl_setstropt(&data->set.str[STRING_PROXY_SERVICE_NAME],
+ va_arg(param, char *));
+ break;
+#endif
+
+#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) || \
+ defined(USE_SPNEGO)
+ case CURLOPT_SERVICE_NAME:
+ /*
+ * Set authentication service name for DIGEST-MD5, Kerberos 5 and SPNEGO
+ */
+ result = Curl_setstropt(&data->set.str[STRING_SERVICE_NAME],
+ va_arg(param, char *));
+ break;
+
+#endif
+
+ case CURLOPT_HEADERDATA:
+ /*
+ * Custom pointer to pass the header write callback function
+ */
+ data->set.writeheader = (void *)va_arg(param, void *);
+ break;
+ case CURLOPT_ERRORBUFFER:
+ /*
+ * Error buffer provided by the caller to get the human readable
+ * error string in.
+ */
+ data->set.errorbuffer = va_arg(param, char *);
+ break;
+ case CURLOPT_WRITEDATA:
+ /*
+ * FILE pointer to write to. Or possibly
+ * used as argument to the write callback.
+ */
+ data->set.out = va_arg(param, void *);
+ break;
+ case CURLOPT_FTPPORT:
+ /*
+ * Use FTP PORT, this also specifies which IP address to use
+ */
+ result = Curl_setstropt(&data->set.str[STRING_FTPPORT],
+ va_arg(param, char *));
+ data->set.ftp_use_port = (data->set.str[STRING_FTPPORT]) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_FTP_USE_EPRT:
+ data->set.ftp_use_eprt = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_FTP_USE_EPSV:
+ data->set.ftp_use_epsv = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_FTP_USE_PRET:
+ data->set.ftp_use_pret = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_FTP_SSL_CCC:
+ arg = va_arg(param, long);
+ if((arg < CURLFTPSSL_CCC_NONE) || (arg > CURLFTPSSL_CCC_ACTIVE))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.ftp_ccc = (curl_ftpccc)arg;
+ break;
+
+ case CURLOPT_FTP_SKIP_PASV_IP:
+ /*
+ * Enable or disable FTP_SKIP_PASV_IP, which will disable/enable the
+ * bypass of the IP address in PASV responses.
+ */
+ data->set.ftp_skip_ip = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_READDATA:
+ /*
+ * FILE pointer to read the file to be uploaded from. Or possibly
+ * used as argument to the read callback.
+ */
+ data->set.in_set = va_arg(param, void *);
+ break;
+ case CURLOPT_INFILESIZE:
+ /*
+ * If known, this should inform curl about the file size of the
+ * to-be-uploaded file.
+ */
+ arg = va_arg(param, long);
+ if(arg < -1)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.filesize = arg;
+ break;
+ case CURLOPT_INFILESIZE_LARGE:
+ /*
+ * If known, this should inform curl about the file size of the
+ * to-be-uploaded file.
+ */
+ bigsize = va_arg(param, curl_off_t);
+ if(bigsize < -1)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.filesize = bigsize;
+ break;
+ case CURLOPT_LOW_SPEED_LIMIT:
+ /*
+ * The low speed limit that if transfers are below this for
+ * CURLOPT_LOW_SPEED_TIME, the transfer is aborted.
+ */
+ arg = va_arg(param, long);
+ if(arg < 0)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.low_speed_limit = arg;
+ break;
+ case CURLOPT_MAX_SEND_SPEED_LARGE:
+ /*
+ * When transfer uploads are faster then CURLOPT_MAX_SEND_SPEED_LARGE
+ * bytes per second the transfer is throttled..
+ */
+ bigsize = va_arg(param, curl_off_t);
+ if(bigsize < 0)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.max_send_speed = bigsize;
+ break;
+ case CURLOPT_MAX_RECV_SPEED_LARGE:
+ /*
+ * When receiving data faster than CURLOPT_MAX_RECV_SPEED_LARGE bytes per
+ * second the transfer is throttled..
+ */
+ bigsize = va_arg(param, curl_off_t);
+ if(bigsize < 0)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.max_recv_speed = bigsize;
+ break;
+ case CURLOPT_LOW_SPEED_TIME:
+ /*
+ * The low speed time that if transfers are below the set
+ * CURLOPT_LOW_SPEED_LIMIT during this time, the transfer is aborted.
+ */
+ arg = va_arg(param, long);
+ if(arg < 0)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.low_speed_time = arg;
+ break;
+ case CURLOPT_URL:
+ /*
+ * The URL to fetch.
+ */
+ if(data->change.url_alloc) {
+ /* the already set URL is allocated, free it first! */
+ Curl_safefree(data->change.url);
+ data->change.url_alloc = FALSE;
+ }
+ result = Curl_setstropt(&data->set.str[STRING_SET_URL],
+ va_arg(param, char *));
+ data->change.url = data->set.str[STRING_SET_URL];
+ break;
+ case CURLOPT_PORT:
+ /*
+ * The port number to use when getting the URL
+ */
+ arg = va_arg(param, long);
+ if((arg < 0) || (arg > 65535))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.use_port = arg;
+ break;
+ case CURLOPT_TIMEOUT:
+ /*
+ * The maximum time you allow curl to use for a single transfer
+ * operation.
+ */
+ arg = va_arg(param, long);
+ if((arg >= 0) && (arg < (INT_MAX/1000)))
+ data->set.timeout = arg * 1000;
+ else
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ break;
+
+ case CURLOPT_TIMEOUT_MS:
+ arg = va_arg(param, long);
+ if(arg < 0)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.timeout = arg;
+ break;
+
+ case CURLOPT_CONNECTTIMEOUT:
+ /*
+ * The maximum time you allow curl to use to connect.
+ */
+ arg = va_arg(param, long);
+ if((arg >= 0) && (arg < (INT_MAX/1000)))
+ data->set.connecttimeout = arg * 1000;
+ else
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ break;
+
+ case CURLOPT_CONNECTTIMEOUT_MS:
+ arg = va_arg(param, long);
+ if(arg < 0)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.connecttimeout = arg;
+ break;
+
+ case CURLOPT_ACCEPTTIMEOUT_MS:
+ /*
+ * The maximum time you allow curl to wait for server connect
+ */
+ arg = va_arg(param, long);
+ if(arg < 0)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.accepttimeout = arg;
+ break;
+
+ case CURLOPT_USERPWD:
+ /*
+ * user:password to use in the operation
+ */
+ result = setstropt_userpwd(va_arg(param, char *),
+ &data->set.str[STRING_USERNAME],
+ &data->set.str[STRING_PASSWORD]);
+ break;
+
+ case CURLOPT_USERNAME:
+ /*
+ * authentication user name to use in the operation
+ */
+ result = Curl_setstropt(&data->set.str[STRING_USERNAME],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_PASSWORD:
+ /*
+ * authentication password to use in the operation
+ */
+ result = Curl_setstropt(&data->set.str[STRING_PASSWORD],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_LOGIN_OPTIONS:
+ /*
+ * authentication options to use in the operation
+ */
+ result = Curl_setstropt(&data->set.str[STRING_OPTIONS],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_XOAUTH2_BEARER:
+ /*
+ * OAuth 2.0 bearer token to use in the operation
+ */
+ result = Curl_setstropt(&data->set.str[STRING_BEARER],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_POSTQUOTE:
+ /*
+ * List of RAW FTP commands to use after a transfer
+ */
+ data->set.postquote = va_arg(param, struct curl_slist *);
+ break;
+ case CURLOPT_PREQUOTE:
+ /*
+ * List of RAW FTP commands to use prior to RETR (Wesley Laxton)
+ */
+ data->set.prequote = va_arg(param, struct curl_slist *);
+ break;
+ case CURLOPT_QUOTE:
+ /*
+ * List of RAW FTP commands to use before a transfer
+ */
+ data->set.quote = va_arg(param, struct curl_slist *);
+ break;
+ case CURLOPT_RESOLVE:
+ /*
+ * List of NAME:[address] names to populate the DNS cache with
+ * Prefix the NAME with dash (-) to _remove_ the name from the cache.
+ *
+ * Names added with this API will remain in the cache until explicitly
+ * removed or the handle is cleaned up.
+ *
+ * This API can remove any name from the DNS cache, but only entries
+ * that aren't actually in use right now will be pruned immediately.
+ */
+ data->set.resolve = va_arg(param, struct curl_slist *);
+ data->change.resolve = data->set.resolve;
+ break;
+ case CURLOPT_PROGRESSFUNCTION:
+ /*
+ * Progress callback function
+ */
+ data->set.fprogress = va_arg(param, curl_progress_callback);
+ if(data->set.fprogress)
+ data->progress.callback = TRUE; /* no longer internal */
+ else
+ data->progress.callback = FALSE; /* NULL enforces internal */
+ break;
+
+ case CURLOPT_XFERINFOFUNCTION:
+ /*
+ * Transfer info callback function
+ */
+ data->set.fxferinfo = va_arg(param, curl_xferinfo_callback);
+ if(data->set.fxferinfo)
+ data->progress.callback = TRUE; /* no longer internal */
+ else
+ data->progress.callback = FALSE; /* NULL enforces internal */
+
+ break;
+
+ case CURLOPT_PROGRESSDATA:
+ /*
+ * Custom client data to pass to the progress callback
+ */
+ data->set.progress_client = va_arg(param, void *);
+ break;
+
+#ifndef CURL_DISABLE_PROXY
+ case CURLOPT_PROXYUSERPWD:
+ /*
+ * user:password needed to use the proxy
+ */
+ result = setstropt_userpwd(va_arg(param, char *),
+ &data->set.str[STRING_PROXYUSERNAME],
+ &data->set.str[STRING_PROXYPASSWORD]);
+ break;
+ case CURLOPT_PROXYUSERNAME:
+ /*
+ * authentication user name to use in the operation
+ */
+ result = Curl_setstropt(&data->set.str[STRING_PROXYUSERNAME],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_PROXYPASSWORD:
+ /*
+ * authentication password to use in the operation
+ */
+ result = Curl_setstropt(&data->set.str[STRING_PROXYPASSWORD],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_NOPROXY:
+ /*
+ * proxy exception list
+ */
+ result = Curl_setstropt(&data->set.str[STRING_NOPROXY],
+ va_arg(param, char *));
+ break;
+#endif
+
+ case CURLOPT_RANGE:
+ /*
+ * What range of the file you want to transfer
+ */
+ result = Curl_setstropt(&data->set.str[STRING_SET_RANGE],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_RESUME_FROM:
+ /*
+ * Resume transfer at the given file position
+ */
+ arg = va_arg(param, long);
+ if(arg < -1)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.set_resume_from = arg;
+ break;
+ case CURLOPT_RESUME_FROM_LARGE:
+ /*
+ * Resume transfer at the given file position
+ */
+ bigsize = va_arg(param, curl_off_t);
+ if(bigsize < -1)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.set_resume_from = bigsize;
+ break;
+ case CURLOPT_DEBUGFUNCTION:
+ /*
+ * stderr write callback.
+ */
+ data->set.fdebug = va_arg(param, curl_debug_callback);
+ /*
+ * if the callback provided is NULL, it'll use the default callback
+ */
+ break;
+ case CURLOPT_DEBUGDATA:
+ /*
+ * Set to a void * that should receive all error writes. This
+ * defaults to CURLOPT_STDERR for normal operations.
+ */
+ data->set.debugdata = va_arg(param, void *);
+ break;
+ case CURLOPT_STDERR:
+ /*
+ * Set to a FILE * that should receive all error writes. This
+ * defaults to stderr for normal operations.
+ */
+ data->set.err = va_arg(param, FILE *);
+ if(!data->set.err)
+ data->set.err = stderr;
+ break;
+ case CURLOPT_HEADERFUNCTION:
+ /*
+ * Set header write callback
+ */
+ data->set.fwrite_header = va_arg(param, curl_write_callback);
+ break;
+ case CURLOPT_WRITEFUNCTION:
+ /*
+ * Set data write callback
+ */
+ data->set.fwrite_func = va_arg(param, curl_write_callback);
+ if(!data->set.fwrite_func) {
+ data->set.is_fwrite_set = 0;
+ /* When set to NULL, reset to our internal default function */
+ data->set.fwrite_func = (curl_write_callback)fwrite;
+ }
+ else
+ data->set.is_fwrite_set = 1;
+ break;
+ case CURLOPT_READFUNCTION:
+ /*
+ * Read data callback
+ */
+ data->set.fread_func_set = va_arg(param, curl_read_callback);
+ if(!data->set.fread_func_set) {
+ data->set.is_fread_set = 0;
+ /* When set to NULL, reset to our internal default function */
+ data->set.fread_func_set = (curl_read_callback)fread;
+ }
+ else
+ data->set.is_fread_set = 1;
+ break;
+ case CURLOPT_SEEKFUNCTION:
+ /*
+ * Seek callback. Might be NULL.
+ */
+ data->set.seek_func = va_arg(param, curl_seek_callback);
+ break;
+ case CURLOPT_SEEKDATA:
+ /*
+ * Seek control callback. Might be NULL.
+ */
+ data->set.seek_client = va_arg(param, void *);
+ break;
+ case CURLOPT_CONV_FROM_NETWORK_FUNCTION:
+ /*
+ * "Convert from network encoding" callback
+ */
+ data->set.convfromnetwork = va_arg(param, curl_conv_callback);
+ break;
+ case CURLOPT_CONV_TO_NETWORK_FUNCTION:
+ /*
+ * "Convert to network encoding" callback
+ */
+ data->set.convtonetwork = va_arg(param, curl_conv_callback);
+ break;
+ case CURLOPT_CONV_FROM_UTF8_FUNCTION:
+ /*
+ * "Convert from UTF-8 encoding" callback
+ */
+ data->set.convfromutf8 = va_arg(param, curl_conv_callback);
+ break;
+ case CURLOPT_IOCTLFUNCTION:
+ /*
+ * I/O control callback. Might be NULL.
+ */
+ data->set.ioctl_func = va_arg(param, curl_ioctl_callback);
+ break;
+ case CURLOPT_IOCTLDATA:
+ /*
+ * I/O control data pointer. Might be NULL.
+ */
+ data->set.ioctl_client = va_arg(param, void *);
+ break;
+ case CURLOPT_SSLCERT:
+ /*
+ * String that holds file name of the SSL certificate to use
+ */
+ result = Curl_setstropt(&data->set.str[STRING_CERT_ORIG],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_PROXY_SSLCERT:
+ /*
+ * String that holds file name of the SSL certificate to use for proxy
+ */
+ result = Curl_setstropt(&data->set.str[STRING_CERT_PROXY],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_SSLCERTTYPE:
+ /*
+ * String that holds file type of the SSL certificate to use
+ */
+ result = Curl_setstropt(&data->set.str[STRING_CERT_TYPE_ORIG],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_PROXY_SSLCERTTYPE:
+ /*
+ * String that holds file type of the SSL certificate to use for proxy
+ */
+ result = Curl_setstropt(&data->set.str[STRING_CERT_TYPE_PROXY],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_SSLKEY:
+ /*
+ * String that holds file name of the SSL key to use
+ */
+ result = Curl_setstropt(&data->set.str[STRING_KEY_ORIG],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_PROXY_SSLKEY:
+ /*
+ * String that holds file name of the SSL key to use for proxy
+ */
+ result = Curl_setstropt(&data->set.str[STRING_KEY_PROXY],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_SSLKEYTYPE:
+ /*
+ * String that holds file type of the SSL key to use
+ */
+ result = Curl_setstropt(&data->set.str[STRING_KEY_TYPE_ORIG],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_PROXY_SSLKEYTYPE:
+ /*
+ * String that holds file type of the SSL key to use for proxy
+ */
+ result = Curl_setstropt(&data->set.str[STRING_KEY_TYPE_PROXY],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_KEYPASSWD:
+ /*
+ * String that holds the SSL or SSH private key password.
+ */
+ result = Curl_setstropt(&data->set.str[STRING_KEY_PASSWD_ORIG],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_PROXY_KEYPASSWD:
+ /*
+ * String that holds the SSL private key password for proxy.
+ */
+ result = Curl_setstropt(&data->set.str[STRING_KEY_PASSWD_PROXY],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_SSLENGINE:
+ /*
+ * String that holds the SSL crypto engine.
+ */
+ argptr = va_arg(param, char *);
+ if(argptr && argptr[0])
+ result = Curl_ssl_set_engine(data, argptr);
+ break;
+
+ case CURLOPT_SSLENGINE_DEFAULT:
+ /*
+ * flag to set engine as default.
+ */
+ result = Curl_ssl_set_engine_default(data);
+ break;
+ case CURLOPT_CRLF:
+ /*
+ * Kludgy option to enable CRLF conversions. Subject for removal.
+ */
+ data->set.crlf = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_INTERFACE:
+ /*
+ * Set what interface or address/hostname to bind the socket to when
+ * performing an operation and thus what from-IP your connection will use.
+ */
+ result = Curl_setstropt(&data->set.str[STRING_DEVICE],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_LOCALPORT:
+ /*
+ * Set what local port to bind the socket to when performing an operation.
+ */
+ arg = va_arg(param, long);
+ if((arg < 0) || (arg > 65535))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.localport = curlx_sltous(arg);
+ break;
+ case CURLOPT_LOCALPORTRANGE:
+ /*
+ * Set number of local ports to try, starting with CURLOPT_LOCALPORT.
+ */
+ arg = va_arg(param, long);
+ if((arg < 0) || (arg > 65535))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.localportrange = curlx_sltosi(arg);
+ break;
+ case CURLOPT_KRBLEVEL:
+ /*
+ * A string that defines the kerberos security level.
+ */
+ result = Curl_setstropt(&data->set.str[STRING_KRB_LEVEL],
+ va_arg(param, char *));
+ data->set.krb = (data->set.str[STRING_KRB_LEVEL]) ? TRUE : FALSE;
+ break;
+ case CURLOPT_GSSAPI_DELEGATION:
+ /*
+ * GSS-API credential delegation bitmask
+ */
+ arg = va_arg(param, long);
+ if(arg < CURLGSSAPI_DELEGATION_NONE)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.gssapi_delegation = arg;
+ break;
+ case CURLOPT_SSL_VERIFYPEER:
+ /*
+ * Enable peer SSL verifying.
+ */
+ data->set.ssl.primary.verifypeer = (0 != va_arg(param, long)) ?
+ TRUE : FALSE;
+
+ /* Update the current connection ssl_config. */
+ if(data->easy_conn) {
+ data->easy_conn->ssl_config.verifypeer =
+ data->set.ssl.primary.verifypeer;
+ }
+ break;
+ case CURLOPT_PROXY_SSL_VERIFYPEER:
+ /*
+ * Enable peer SSL verifying for proxy.
+ */
+ data->set.proxy_ssl.primary.verifypeer =
+ (0 != va_arg(param, long))?TRUE:FALSE;
+
+ /* Update the current connection proxy_ssl_config. */
+ if(data->easy_conn) {
+ data->easy_conn->proxy_ssl_config.verifypeer =
+ data->set.proxy_ssl.primary.verifypeer;
+ }
+ break;
+ case CURLOPT_SSL_VERIFYHOST:
+ /*
+ * Enable verification of the host name in the peer certificate
+ */
+ arg = va_arg(param, long);
+
+ /* Obviously people are not reading documentation and too many thought
+ this argument took a boolean when it wasn't and misused it. We thus ban
+ 1 as a sensible input and we warn about its use. Then we only have the
+ 2 action internally stored as TRUE. */
+
+ if(1 == arg) {
+ failf(data, "CURLOPT_SSL_VERIFYHOST no longer supports 1 as value!");
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ }
+
+ data->set.ssl.primary.verifyhost = (0 != arg) ? TRUE : FALSE;
+
+ /* Update the current connection ssl_config. */
+ if(data->easy_conn) {
+ data->easy_conn->ssl_config.verifyhost =
+ data->set.ssl.primary.verifyhost;
+ }
+ break;
+ case CURLOPT_PROXY_SSL_VERIFYHOST:
+ /*
+ * Enable verification of the host name in the peer certificate for proxy
+ */
+ arg = va_arg(param, long);
+
+ /* Obviously people are not reading documentation and too many thought
+ this argument took a boolean when it wasn't and misused it. We thus ban
+ 1 as a sensible input and we warn about its use. Then we only have the
+ 2 action internally stored as TRUE. */
+
+ if(1 == arg) {
+ failf(data, "CURLOPT_SSL_VERIFYHOST no longer supports 1 as value!");
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ }
+
+ data->set.proxy_ssl.primary.verifyhost = (0 != arg)?TRUE:FALSE;
+
+ /* Update the current connection proxy_ssl_config. */
+ if(data->easy_conn) {
+ data->easy_conn->proxy_ssl_config.verifyhost =
+ data->set.proxy_ssl.primary.verifyhost;
+ }
+ break;
+ case CURLOPT_SSL_VERIFYSTATUS:
+ /*
+ * Enable certificate status verifying.
+ */
+ if(!Curl_ssl_cert_status_request()) {
+ result = CURLE_NOT_BUILT_IN;
+ break;
+ }
+
+ data->set.ssl.primary.verifystatus = (0 != va_arg(param, long)) ?
+ TRUE : FALSE;
+
+ /* Update the current connection ssl_config. */
+ if(data->easy_conn) {
+ data->easy_conn->ssl_config.verifystatus =
+ data->set.ssl.primary.verifystatus;
+ }
+ break;
+ case CURLOPT_SSL_CTX_FUNCTION:
+ /*
+ * Set a SSL_CTX callback
+ */
+#ifdef USE_SSL
+ if(Curl_ssl->have_ssl_ctx)
+ data->set.ssl.fsslctx = va_arg(param, curl_ssl_ctx_callback);
+ else
+#endif
+ result = CURLE_NOT_BUILT_IN;
+ break;
+ case CURLOPT_SSL_CTX_DATA:
+ /*
+ * Set a SSL_CTX callback parameter pointer
+ */
+#ifdef USE_SSL
+ if(Curl_ssl->have_ssl_ctx)
+ data->set.ssl.fsslctxp = va_arg(param, void *);
+ else
+#endif
+ result = CURLE_NOT_BUILT_IN;
+ break;
+ case CURLOPT_SSL_FALSESTART:
+ /*
+ * Enable TLS false start.
+ */
+ if(!Curl_ssl_false_start()) {
+ result = CURLE_NOT_BUILT_IN;
+ break;
+ }
+
+ data->set.ssl.falsestart = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+ case CURLOPT_CERTINFO:
+#ifdef USE_SSL
+ if(Curl_ssl->have_certinfo)
+ data->set.ssl.certinfo = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ else
+#endif
+ result = CURLE_NOT_BUILT_IN;
+ break;
+ case CURLOPT_PINNEDPUBLICKEY:
+ /*
+ * Set pinned public key for SSL connection.
+ * Specify file name of the public key in DER format.
+ */
+#ifdef USE_SSL
+ if(Curl_ssl->have_pinnedpubkey)
+ result = Curl_setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG],
+ va_arg(param, char *));
+ else
+#endif
+ result = CURLE_NOT_BUILT_IN;
+ break;
+ case CURLOPT_PROXY_PINNEDPUBLICKEY:
+ /*
+ * Set pinned public key for SSL connection.
+ * Specify file name of the public key in DER format.
+ */
+#ifdef USE_SSL
+ if(Curl_ssl->have_pinnedpubkey)
+ result = Curl_setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY],
+ va_arg(param, char *));
+ else
+#endif
+ result = CURLE_NOT_BUILT_IN;
+ break;
+ case CURLOPT_CAINFO:
+ /*
+ * Set CA info for SSL connection. Specify file name of the CA certificate
+ */
+ result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE_ORIG],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_PROXY_CAINFO:
+ /*
+ * Set CA info SSL connection for proxy. Specify file name of the
+ * CA certificate
+ */
+ result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE_PROXY],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_CAPATH:
+ /*
+ * Set CA path info for SSL connection. Specify directory name of the CA
+ * certificates which have been prepared using openssl c_rehash utility.
+ */
+#ifdef USE_SSL
+ if(Curl_ssl->have_ca_path)
+ /* This does not work on windows. */
+ result = Curl_setstropt(&data->set.str[STRING_SSL_CAPATH_ORIG],
+ va_arg(param, char *));
+ else
+#endif
+ result = CURLE_NOT_BUILT_IN;
+ break;
+ case CURLOPT_PROXY_CAPATH:
+ /*
+ * Set CA path info for SSL connection proxy. Specify directory name of the
+ * CA certificates which have been prepared using openssl c_rehash utility.
+ */
+#ifdef USE_SSL
+ if(Curl_ssl->have_ca_path)
+ /* This does not work on windows. */
+ result = Curl_setstropt(&data->set.str[STRING_SSL_CAPATH_PROXY],
+ va_arg(param, char *));
+ else
+#endif
+ result = CURLE_NOT_BUILT_IN;
+ break;
+ case CURLOPT_CRLFILE:
+ /*
+ * Set CRL file info for SSL connection. Specify file name of the CRL
+ * to check certificates revocation
+ */
+ result = Curl_setstropt(&data->set.str[STRING_SSL_CRLFILE_ORIG],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_PROXY_CRLFILE:
+ /*
+ * Set CRL file info for SSL connection for proxy. Specify file name of the
+ * CRL to check certificates revocation
+ */
+ result = Curl_setstropt(&data->set.str[STRING_SSL_CRLFILE_PROXY],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_ISSUERCERT:
+ /*
+ * Set Issuer certificate file
+ * to check certificates issuer
+ */
+ result = Curl_setstropt(&data->set.str[STRING_SSL_ISSUERCERT_ORIG],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_TELNETOPTIONS:
+ /*
+ * Set a linked list of telnet options
+ */
+ data->set.telnet_options = va_arg(param, struct curl_slist *);
+ break;
+
+ case CURLOPT_BUFFERSIZE:
+ /*
+ * The application kindly asks for a differently sized receive buffer.
+ * If it seems reasonable, we'll use it.
+ */
+ arg = va_arg(param, long);
+
+ if(arg > READBUFFER_MAX)
+ arg = READBUFFER_MAX;
+ else if(arg < 1)
+ arg = READBUFFER_SIZE;
+ else if(arg < READBUFFER_MIN)
+ arg = READBUFFER_MIN;
+
+ /* Resize if new size */
+ if(arg != data->set.buffer_size) {
+ char *newbuff = realloc(data->state.buffer, arg + 1);
+ if(!newbuff) {
+ DEBUGF(fprintf(stderr, "Error: realloc of buffer failed\n"));
+ result = CURLE_OUT_OF_MEMORY;
+ }
+ else
+ data->state.buffer = newbuff;
+ }
+ data->set.buffer_size = arg;
+
+ break;
+
+ case CURLOPT_NOSIGNAL:
+ /*
+ * The application asks not to set any signal() or alarm() handlers,
+ * even when using a timeout.
+ */
+ data->set.no_signal = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_SHARE:
+ {
+ struct Curl_share *set;
+ set = va_arg(param, struct Curl_share *);
+
+ /* disconnect from old share, if any */
+ if(data->share) {
+ Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
+
+ if(data->dns.hostcachetype == HCACHE_SHARED) {
+ data->dns.hostcache = NULL;
+ data->dns.hostcachetype = HCACHE_NONE;
+ }
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
+ if(data->share->cookies == data->cookies)
+ data->cookies = NULL;
+#endif
+
+ if(data->share->sslsession == data->state.session)
+ data->state.session = NULL;
+
+ data->share->dirty--;
+
+ Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
+ data->share = NULL;
+ }
+
+ /* use new share if it set */
+ data->share = set;
+ if(data->share) {
+
+ Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
+
+ data->share->dirty++;
+
+ if(data->share->specifier & (1<< CURL_LOCK_DATA_DNS)) {
+ /* use shared host cache */
+ data->dns.hostcache = &data->share->hostcache;
+ data->dns.hostcachetype = HCACHE_SHARED;
+ }
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
+ if(data->share->cookies) {
+ /* use shared cookie list, first free own one if any */
+ Curl_cookie_cleanup(data->cookies);
+ /* enable cookies since we now use a share that uses cookies! */
+ data->cookies = data->share->cookies;
+ }
+#endif /* CURL_DISABLE_HTTP */
+ if(data->share->sslsession) {
+ data->set.general_ssl.max_ssl_sessions = data->share->max_ssl_sessions;
+ data->state.session = data->share->sslsession;
+ }
+ Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
+
+ }
+ /* check for host cache not needed,
+ * it will be done by curl_easy_perform */
+ }
+ break;
+
+ case CURLOPT_PRIVATE:
+ /*
+ * Set private data pointer.
+ */
+ data->set.private_data = va_arg(param, void *);
+ break;
+
+ case CURLOPT_MAXFILESIZE:
+ /*
+ * Set the maximum size of a file to download.
+ */
+ arg = va_arg(param, long);
+ if(arg < 0)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.max_filesize = arg;
+ break;
+
+#ifdef USE_SSL
+ case CURLOPT_USE_SSL:
+ /*
+ * Make transfers attempt to use SSL/TLS.
+ */
+ arg = va_arg(param, long);
+ if((arg < CURLUSESSL_NONE) || (arg > CURLUSESSL_ALL))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.use_ssl = (curl_usessl)arg;
+ break;
+
+ case CURLOPT_SSL_OPTIONS:
+ arg = va_arg(param, long);
+ data->set.ssl.enable_beast = arg&CURLSSLOPT_ALLOW_BEAST?TRUE:FALSE;
+ data->set.ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE);
+ break;
+
+ case CURLOPT_PROXY_SSL_OPTIONS:
+ arg = va_arg(param, long);
+ data->set.proxy_ssl.enable_beast = arg&CURLSSLOPT_ALLOW_BEAST?TRUE:FALSE;
+ data->set.proxy_ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE);
+ break;
+
+#endif
+ case CURLOPT_FTPSSLAUTH:
+ /*
+ * Set a specific auth for FTP-SSL transfers.
+ */
+ arg = va_arg(param, long);
+ if((arg < CURLFTPAUTH_DEFAULT) || (arg > CURLFTPAUTH_TLS))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.ftpsslauth = (curl_ftpauth)arg;
+ break;
+
+ case CURLOPT_IPRESOLVE:
+ arg = va_arg(param, long);
+ if((arg < CURL_IPRESOLVE_WHATEVER) || (arg > CURL_IPRESOLVE_V6))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.ipver = arg;
+ break;
+
+ case CURLOPT_MAXFILESIZE_LARGE:
+ /*
+ * Set the maximum size of a file to download.
+ */
+ bigsize = va_arg(param, curl_off_t);
+ if(bigsize < 0)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.max_filesize = bigsize;
+ break;
+
+ case CURLOPT_TCP_NODELAY:
+ /*
+ * Enable or disable TCP_NODELAY, which will disable/enable the Nagle
+ * algorithm
+ */
+ data->set.tcp_nodelay = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_FTP_ACCOUNT:
+ result = Curl_setstropt(&data->set.str[STRING_FTP_ACCOUNT],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_IGNORE_CONTENT_LENGTH:
+ data->set.ignorecl = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_CONNECT_ONLY:
+ /*
+ * No data transfer, set up connection and let application use the socket
+ */
+ data->set.connect_only = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_FTP_ALTERNATIVE_TO_USER:
+ result = Curl_setstropt(&data->set.str[STRING_FTP_ALTERNATIVE_TO_USER],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_SOCKOPTFUNCTION:
+ /*
+ * socket callback function: called after socket() but before connect()
+ */
+ data->set.fsockopt = va_arg(param, curl_sockopt_callback);
+ break;
+
+ case CURLOPT_SOCKOPTDATA:
+ /*
+ * socket callback data pointer. Might be NULL.
+ */
+ data->set.sockopt_client = va_arg(param, void *);
+ break;
+
+ case CURLOPT_OPENSOCKETFUNCTION:
+ /*
+ * open/create socket callback function: called instead of socket(),
+ * before connect()
+ */
+ data->set.fopensocket = va_arg(param, curl_opensocket_callback);
+ break;
+
+ case CURLOPT_OPENSOCKETDATA:
+ /*
+ * socket callback data pointer. Might be NULL.
+ */
+ data->set.opensocket_client = va_arg(param, void *);
+ break;
+
+ case CURLOPT_CLOSESOCKETFUNCTION:
+ /*
+ * close socket callback function: called instead of close()
+ * when shutting down a connection
+ */
+ data->set.fclosesocket = va_arg(param, curl_closesocket_callback);
+ break;
+
+ case CURLOPT_CLOSESOCKETDATA:
+ /*
+ * socket callback data pointer. Might be NULL.
+ */
+ data->set.closesocket_client = va_arg(param, void *);
+ break;
+
+ case CURLOPT_SSL_SESSIONID_CACHE:
+ data->set.ssl.primary.sessionid = (0 != va_arg(param, long)) ?
+ TRUE : FALSE;
+ data->set.proxy_ssl.primary.sessionid = data->set.ssl.primary.sessionid;
+ break;
+
+#ifdef USE_LIBSSH2
+ /* we only include SSH options if explicitly built to support SSH */
+ case CURLOPT_SSH_AUTH_TYPES:
+ data->set.ssh_auth_types = va_arg(param, long);
+ break;
+
+ case CURLOPT_SSH_PUBLIC_KEYFILE:
+ /*
+ * Use this file instead of the $HOME/.ssh/id_dsa.pub file
+ */
+ result = Curl_setstropt(&data->set.str[STRING_SSH_PUBLIC_KEY],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_SSH_PRIVATE_KEYFILE:
+ /*
+ * Use this file instead of the $HOME/.ssh/id_dsa file
+ */
+ result = Curl_setstropt(&data->set.str[STRING_SSH_PRIVATE_KEY],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_SSH_HOST_PUBLIC_KEY_MD5:
+ /*
+ * Option to allow for the MD5 of the host public key to be checked
+ * for validation purposes.
+ */
+ result = Curl_setstropt(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5],
+ va_arg(param, char *));
+ break;
+#ifdef HAVE_LIBSSH2_KNOWNHOST_API
+ case CURLOPT_SSH_KNOWNHOSTS:
+ /*
+ * Store the file name to read known hosts from.
+ */
+ result = Curl_setstropt(&data->set.str[STRING_SSH_KNOWNHOSTS],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_SSH_KEYFUNCTION:
+ /* setting to NULL is fine since the ssh.c functions themselves will
+ then rever to use the internal default */
+ data->set.ssh_keyfunc = va_arg(param, curl_sshkeycallback);
+ break;
+
+ case CURLOPT_SSH_KEYDATA:
+ /*
+ * Custom client data to pass to the SSH keyfunc callback
+ */
+ data->set.ssh_keyfunc_userp = va_arg(param, void *);
+ break;
+#endif /* HAVE_LIBSSH2_KNOWNHOST_API */
+
+#endif /* USE_LIBSSH2 */
+
+ case CURLOPT_HTTP_TRANSFER_DECODING:
+ /*
+ * disable libcurl transfer encoding is used
+ */
+ data->set.http_te_skip = (0 == va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_HTTP_CONTENT_DECODING:
+ /*
+ * raw data passed to the application when content encoding is used
+ */
+ data->set.http_ce_skip = (0 == va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_NEW_FILE_PERMS:
+ /*
+ * Uses these permissions instead of 0644
+ */
+ arg = va_arg(param, long);
+ if((arg < 0) || (arg > 0777))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.new_file_perms = arg;
+ break;
+
+ case CURLOPT_NEW_DIRECTORY_PERMS:
+ /*
+ * Uses these permissions instead of 0755
+ */
+ arg = va_arg(param, long);
+ if((arg < 0) || (arg > 0777))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.new_directory_perms = arg;
+ break;
+
+ case CURLOPT_ADDRESS_SCOPE:
+ /*
+ * We always get longs when passed plain numericals, but for this value we
+ * know that an unsigned int will always hold the value so we blindly
+ * typecast to this type
+ */
+ arg = va_arg(param, long);
+ if((arg < 0) || (arg > 0xf))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.scope_id = curlx_sltoui(arg);
+ break;
+
+ case CURLOPT_PROTOCOLS:
+ /* set the bitmask for the protocols that are allowed to be used for the
+ transfer, which thus helps the app which takes URLs from users or other
+ external inputs and want to restrict what protocol(s) to deal
+ with. Defaults to CURLPROTO_ALL. */
+ data->set.allowed_protocols = va_arg(param, long);
+ break;
+
+ case CURLOPT_REDIR_PROTOCOLS:
+ /* set the bitmask for the protocols that libcurl is allowed to follow to,
+ as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs
+ to be set in both bitmasks to be allowed to get redirected to. Defaults
+ to all protocols except FILE and SCP. */
+ data->set.redir_protocols = va_arg(param, long);
+ break;
+
+ case CURLOPT_DEFAULT_PROTOCOL:
+ /* Set the protocol to use when the URL doesn't include any protocol */
+ result = Curl_setstropt(&data->set.str[STRING_DEFAULT_PROTOCOL],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_MAIL_FROM:
+ /* Set the SMTP mail originator */
+ result = Curl_setstropt(&data->set.str[STRING_MAIL_FROM],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_MAIL_AUTH:
+ /* Set the SMTP auth originator */
+ result = Curl_setstropt(&data->set.str[STRING_MAIL_AUTH],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_MAIL_RCPT:
+ /* Set the list of mail recipients */
+ data->set.mail_rcpt = va_arg(param, struct curl_slist *);
+ break;
+
+ case CURLOPT_SASL_IR:
+ /* Enable/disable SASL initial response */
+ data->set.sasl_ir = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_RTSP_REQUEST:
+ {
+ /*
+ * Set the RTSP request method (OPTIONS, SETUP, PLAY, etc...)
+ * Would this be better if the RTSPREQ_* were just moved into here?
+ */
+ long curl_rtspreq = va_arg(param, long);
+ Curl_RtspReq rtspreq = RTSPREQ_NONE;
+ switch(curl_rtspreq) {
+ case CURL_RTSPREQ_OPTIONS:
+ rtspreq = RTSPREQ_OPTIONS;
+ break;
+
+ case CURL_RTSPREQ_DESCRIBE:
+ rtspreq = RTSPREQ_DESCRIBE;
+ break;
+
+ case CURL_RTSPREQ_ANNOUNCE:
+ rtspreq = RTSPREQ_ANNOUNCE;
+ break;
+
+ case CURL_RTSPREQ_SETUP:
+ rtspreq = RTSPREQ_SETUP;
+ break;
+
+ case CURL_RTSPREQ_PLAY:
+ rtspreq = RTSPREQ_PLAY;
+ break;
+
+ case CURL_RTSPREQ_PAUSE:
+ rtspreq = RTSPREQ_PAUSE;
+ break;
+
+ case CURL_RTSPREQ_TEARDOWN:
+ rtspreq = RTSPREQ_TEARDOWN;
+ break;
+
+ case CURL_RTSPREQ_GET_PARAMETER:
+ rtspreq = RTSPREQ_GET_PARAMETER;
+ break;
+
+ case CURL_RTSPREQ_SET_PARAMETER:
+ rtspreq = RTSPREQ_SET_PARAMETER;
+ break;
+
+ case CURL_RTSPREQ_RECORD:
+ rtspreq = RTSPREQ_RECORD;
+ break;
+
+ case CURL_RTSPREQ_RECEIVE:
+ rtspreq = RTSPREQ_RECEIVE;
+ break;
+ default:
+ rtspreq = RTSPREQ_NONE;
+ }
+
+ data->set.rtspreq = rtspreq;
+ break;
+ }
+
+
+ case CURLOPT_RTSP_SESSION_ID:
+ /*
+ * Set the RTSP Session ID manually. Useful if the application is
+ * resuming a previously established RTSP session
+ */
+ result = Curl_setstropt(&data->set.str[STRING_RTSP_SESSION_ID],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_RTSP_STREAM_URI:
+ /*
+ * Set the Stream URI for the RTSP request. Unless the request is
+ * for generic server options, the application will need to set this.
+ */
+ result = Curl_setstropt(&data->set.str[STRING_RTSP_STREAM_URI],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_RTSP_TRANSPORT:
+ /*
+ * The content of the Transport: header for the RTSP request
+ */
+ result = Curl_setstropt(&data->set.str[STRING_RTSP_TRANSPORT],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_RTSP_CLIENT_CSEQ:
+ /*
+ * Set the CSEQ number to issue for the next RTSP request. Useful if the
+ * application is resuming a previously broken connection. The CSEQ
+ * will increment from this new number henceforth.
+ */
+ data->state.rtsp_next_client_CSeq = va_arg(param, long);
+ break;
+
+ case CURLOPT_RTSP_SERVER_CSEQ:
+ /* Same as the above, but for server-initiated requests */
+ data->state.rtsp_next_client_CSeq = va_arg(param, long);
+ break;
+
+ case CURLOPT_INTERLEAVEDATA:
+ data->set.rtp_out = va_arg(param, void *);
+ break;
+ case CURLOPT_INTERLEAVEFUNCTION:
+ /* Set the user defined RTP write function */
+ data->set.fwrite_rtp = va_arg(param, curl_write_callback);
+ break;
+
+ case CURLOPT_WILDCARDMATCH:
+ data->set.wildcard_enabled = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+ case CURLOPT_CHUNK_BGN_FUNCTION:
+ data->set.chunk_bgn = va_arg(param, curl_chunk_bgn_callback);
+ break;
+ case CURLOPT_CHUNK_END_FUNCTION:
+ data->set.chunk_end = va_arg(param, curl_chunk_end_callback);
+ break;
+ case CURLOPT_FNMATCH_FUNCTION:
+ data->set.fnmatch = va_arg(param, curl_fnmatch_callback);
+ break;
+ case CURLOPT_CHUNK_DATA:
+ data->wildcard.customptr = va_arg(param, void *);
+ break;
+ case CURLOPT_FNMATCH_DATA:
+ data->set.fnmatch_data = va_arg(param, void *);
+ break;
+#ifdef USE_TLS_SRP
+ case CURLOPT_TLSAUTH_USERNAME:
+ result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_USERNAME_ORIG],
+ va_arg(param, char *));
+ if(data->set.str[STRING_TLSAUTH_USERNAME_ORIG] && !data->set.ssl.authtype)
+ data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */
+ break;
+ case CURLOPT_PROXY_TLSAUTH_USERNAME:
+ result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_USERNAME_PROXY],
+ va_arg(param, char *));
+ if(data->set.str[STRING_TLSAUTH_USERNAME_PROXY] &&
+ !data->set.proxy_ssl.authtype)
+ data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */
+ break;
+ case CURLOPT_TLSAUTH_PASSWORD:
+ result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_ORIG],
+ va_arg(param, char *));
+ if(data->set.str[STRING_TLSAUTH_USERNAME_ORIG] && !data->set.ssl.authtype)
+ data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */
+ break;
+ case CURLOPT_PROXY_TLSAUTH_PASSWORD:
+ result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_PROXY],
+ va_arg(param, char *));
+ if(data->set.str[STRING_TLSAUTH_USERNAME_PROXY] &&
+ !data->set.proxy_ssl.authtype)
+ data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */
+ break;
+ case CURLOPT_TLSAUTH_TYPE:
+ argptr = va_arg(param, char *);
+ if(!argptr ||
+ strncasecompare(argptr, "SRP", strlen("SRP")))
+ data->set.ssl.authtype = CURL_TLSAUTH_SRP;
+ else
+ data->set.ssl.authtype = CURL_TLSAUTH_NONE;
+ break;
+ case CURLOPT_PROXY_TLSAUTH_TYPE:
+ argptr = va_arg(param, char *);
+ if(!argptr ||
+ strncasecompare(argptr, "SRP", strlen("SRP")))
+ data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP;
+ else
+ data->set.proxy_ssl.authtype = CURL_TLSAUTH_NONE;
+ break;
+#endif
+ case CURLOPT_DNS_SERVERS:
+ result = Curl_set_dns_servers(data, va_arg(param, char *));
+ break;
+ case CURLOPT_DNS_INTERFACE:
+ result = Curl_set_dns_interface(data, va_arg(param, char *));
+ break;
+ case CURLOPT_DNS_LOCAL_IP4:
+ result = Curl_set_dns_local_ip4(data, va_arg(param, char *));
+ break;
+ case CURLOPT_DNS_LOCAL_IP6:
+ result = Curl_set_dns_local_ip6(data, va_arg(param, char *));
+ break;
+
+ case CURLOPT_TCP_KEEPALIVE:
+ data->set.tcp_keepalive = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+ case CURLOPT_TCP_KEEPIDLE:
+ arg = va_arg(param, long);
+ if(arg < 0)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.tcp_keepidle = arg;
+ break;
+ case CURLOPT_TCP_KEEPINTVL:
+ arg = va_arg(param, long);
+ if(arg < 0)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.tcp_keepintvl = arg;
+ break;
+ case CURLOPT_TCP_FASTOPEN:
+#if defined(CONNECT_DATA_IDEMPOTENT) || defined(MSG_FASTOPEN) || \
+ defined(TCP_FASTOPEN_CONNECT)
+ data->set.tcp_fastopen = (0 != va_arg(param, long))?TRUE:FALSE;
+#else
+ result = CURLE_NOT_BUILT_IN;
+#endif
+ break;
+ case CURLOPT_SSL_ENABLE_NPN:
+ data->set.ssl_enable_npn = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+ case CURLOPT_SSL_ENABLE_ALPN:
+ data->set.ssl_enable_alpn = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+#ifdef USE_UNIX_SOCKETS
+ case CURLOPT_UNIX_SOCKET_PATH:
+ data->set.abstract_unix_socket = FALSE;
+ result = Curl_setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_ABSTRACT_UNIX_SOCKET:
+ data->set.abstract_unix_socket = TRUE;
+ result = Curl_setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH],
+ va_arg(param, char *));
+ break;
+#endif
+
+ case CURLOPT_PATH_AS_IS:
+ data->set.path_as_is = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+ case CURLOPT_PIPEWAIT:
+ data->set.pipewait = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+ case CURLOPT_STREAM_WEIGHT:
+#ifndef USE_NGHTTP2
+ return CURLE_NOT_BUILT_IN;
+#else
+ arg = va_arg(param, long);
+ if((arg >= 1) && (arg <= 256))
+ data->set.stream_weight = (int)arg;
+ break;
+#endif
+ case CURLOPT_STREAM_DEPENDS:
+ case CURLOPT_STREAM_DEPENDS_E:
+ {
+#ifndef USE_NGHTTP2
+ return CURLE_NOT_BUILT_IN;
+#else
+ struct Curl_easy *dep = va_arg(param, struct Curl_easy *);
+ if(!dep || GOOD_EASY_HANDLE(dep)) {
+ if(data->set.stream_depends_on) {
+ Curl_http2_remove_child(data->set.stream_depends_on, data);
+ }
+ Curl_http2_add_child(dep, data, (option == CURLOPT_STREAM_DEPENDS_E));
+ }
+ break;
+#endif
+ }
+ case CURLOPT_CONNECT_TO:
+ data->set.connect_to = va_arg(param, struct curl_slist *);
+ break;
+ case CURLOPT_SUPPRESS_CONNECT_HEADERS:
+ data->set.suppress_connect_headers = (0 != va_arg(param, long))?TRUE:FALSE;
+ break;
+ case CURLOPT_SSH_COMPRESSION:
+ data->set.ssh_compression = (0 != va_arg(param, long))?TRUE:FALSE;
+ break;
+ default:
+ /* unknown tag and its companion, just ignore: */
+ result = CURLE_UNKNOWN_OPTION;
+ break;
+ }
+
+ return result;
+}
+
+/*
+ * curl_easy_setopt() is the external interface for setting options on an
+ * easy handle.
+ */
+
+#undef curl_easy_setopt
+CURLcode curl_easy_setopt(struct Curl_easy *data, CURLoption tag, ...)
+{
+ va_list arg;
+ CURLcode result;
+
+ if(!data)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
+ va_start(arg, tag);
+
+ result = setopt(data, tag, arg);
+
+ va_end(arg);
+ return result;
+}
+
diff --git a/lib/setopt.h b/lib/setopt.h
new file mode 100644
index 00000000..35769440
--- /dev/null
+++ b/lib/setopt.h
@@ -0,0 +1,27 @@
+#ifndef HEADER_CURL_SETOPT_H
+#define HEADER_CURL_SETOPT_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, 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 https://curl.haxx.se/docs/copyright.html.
+ *
+ * You 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.
+ *
+ ***************************************************************************/
+
+CURLcode Curl_setstropt(char **charp, const char *s);
+
+#endif /* HEADER_CURL_SETOPT_H */
diff --git a/lib/sha256.c b/lib/sha256.c
new file mode 100644
index 00000000..cd81c025
--- /dev/null
+++ b/lib/sha256.c
@@ -0,0 +1,262 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Florin Petriuc, <petriuc.florin@gmail.com>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+
+#include "warnless.h"
+#include "curl_sha256.h"
+
+#if defined(USE_OPENSSL)
+
+/* When OpenSSL is available we use the SHA256-function from OpenSSL */
+#include <openssl/sha.h>
+
+#else
+
+/* When no other crypto library is available we use this code segment */
+
+/* ===== start - public domain SHA256 implementation ===== */
+/* This is based on SHA256 implementation in LibTomCrypt that was released into
+ * public domain by Tom St Denis. */
+
+#define WPA_GET_BE32(a) ((((unsigned long)(a)[0]) << 24) | \
+ (((unsigned long)(a)[1]) << 16) | \
+ (((unsigned long)(a)[2]) << 8) | \
+ ((unsigned long)(a)[3]))
+#define WPA_PUT_BE32(a, val) \
+do { \
+ (a)[0] = (unsigned char)((((unsigned long) (val)) >> 24) & 0xff); \
+ (a)[1] = (unsigned char)((((unsigned long) (val)) >> 16) & 0xff); \
+ (a)[2] = (unsigned char)((((unsigned long) (val)) >> 8) & 0xff); \
+ (a)[3] = (unsigned char)(((unsigned long) (val)) & 0xff); \
+} while(0)
+
+#ifdef HAVE_LONGLONG
+#define WPA_PUT_BE64(a, val) \
+do { \
+ (a)[0] = (unsigned char)(((unsigned long long)(val)) >> 56); \
+ (a)[1] = (unsigned char)(((unsigned long long)(val)) >> 48); \
+ (a)[2] = (unsigned char)(((unsigned long long)(val)) >> 40); \
+ (a)[3] = (unsigned char)(((unsigned long long)(val)) >> 32); \
+ (a)[4] = (unsigned char)(((unsigned long long)(val)) >> 24); \
+ (a)[5] = (unsigned char)(((unsigned long long)(val)) >> 16); \
+ (a)[6] = (unsigned char)(((unsigned long long)(val)) >> 8); \
+ (a)[7] = (unsigned char)(((unsigned long long)(val)) & 0xff); \
+} while(0)
+#else
+#define WPA_PUT_BE64(a, val) \
+do { \
+ (a)[0] = (unsigned char)(((unsigned __int64)(val)) >> 56); \
+ (a)[1] = (unsigned char)(((unsigned __int64)(val)) >> 48); \
+ (a)[2] = (unsigned char)(((unsigned __int64)(val)) >> 40); \
+ (a)[3] = (unsigned char)(((unsigned __int64)(val)) >> 32); \
+ (a)[4] = (unsigned char)(((unsigned __int64)(val)) >> 24); \
+ (a)[5] = (unsigned char)(((unsigned __int64)(val)) >> 16); \
+ (a)[6] = (unsigned char)(((unsigned __int64)(val)) >> 8); \
+ (a)[7] = (unsigned char)(((unsigned __int64)(val)) & 0xff); \
+} while(0)
+#endif
+
+typedef struct sha256_state {
+#ifdef HAVE_LONGLONG
+ unsigned long long length;
+#else
+ unsigned __int64 length;
+#endif
+ unsigned long state[8], curlen;
+ unsigned char buf[64];
+} SHA256_CTX;
+/* the K array */
+static const unsigned long K[64] = {
+ 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL,
+ 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL,
+ 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL,
+ 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
+ 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL,
+ 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL,
+ 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL,
+ 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
+ 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL,
+ 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL,
+ 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL,
+ 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
+ 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
+};
+/* Various logical functions */
+#define RORc(x, y) \
+(((((unsigned long)(x) & 0xFFFFFFFFUL) >> (unsigned long)((y) & 31)) | \
+ ((unsigned long)(x) << (unsigned long)(32 - ((y) & 31)))) & 0xFFFFFFFFUL)
+#define Ch(x,y,z) (z ^ (x & (y ^ z)))
+#define Maj(x,y,z) (((x | y) & z) | (x & y))
+#define S(x, n) RORc((x), (n))
+#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n))
+#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22))
+#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25))
+#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3))
+#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10))
+#ifndef MIN
+#define MIN(x, y) (((x) < (y)) ? (x) : (y))
+#endif
+/* compress 512-bits */
+static int sha256_compress(struct sha256_state *md,
+ unsigned char *buf)
+{
+ unsigned long S[8], W[64], t0, t1;
+ unsigned long t;
+ int i;
+ /* copy state into S */
+ for(i = 0; i < 8; i++) {
+ S[i] = md->state[i];
+ }
+ /* copy the state into 512-bits into W[0..15] */
+ for(i = 0; i < 16; i++)
+ W[i] = WPA_GET_BE32(buf + (4 * i));
+ /* fill W[16..63] */
+ for(i = 16; i < 64; i++) {
+ W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) +
+ W[i - 16];
+ }
+ /* Compress */
+#define RND(a,b,c,d,e,f,g,h,i) \
+ t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
+ t1 = Sigma0(a) + Maj(a, b, c); \
+ d += t0; \
+ h = t0 + t1;
+ for(i = 0; i < 64; ++i) {
+ RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i);
+ t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4];
+ S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t;
+ }
+ /* feedback */
+ for(i = 0; i < 8; i++) {
+ md->state[i] = md->state[i] + S[i];
+ }
+ return 0;
+}
+/* Initialize the hash state */
+static void SHA256_Init(struct sha256_state *md)
+{
+ md->curlen = 0;
+ md->length = 0;
+ md->state[0] = 0x6A09E667UL;
+ md->state[1] = 0xBB67AE85UL;
+ md->state[2] = 0x3C6EF372UL;
+ md->state[3] = 0xA54FF53AUL;
+ md->state[4] = 0x510E527FUL;
+ md->state[5] = 0x9B05688CUL;
+ md->state[6] = 0x1F83D9ABUL;
+ md->state[7] = 0x5BE0CD19UL;
+}
+/**
+ Process a block of memory though the hash
+ @param md The hash state
+ @param in The data to hash
+ @param inlen The length of the data (octets)
+ @return CRYPT_OK if successful
+*/
+static int SHA256_Update(struct sha256_state *md,
+ const unsigned char *in,
+ unsigned long inlen)
+{
+ unsigned long n;
+#define block_size 64
+ if(md->curlen > sizeof(md->buf))
+ return -1;
+ while(inlen > 0) {
+ if(md->curlen == 0 && inlen >= block_size) {
+ if(sha256_compress(md, (unsigned char *)in) < 0)
+ return -1;
+ md->length += block_size * 8;
+ in += block_size;
+ inlen -= block_size;
+ }
+ else {
+ n = MIN(inlen, (block_size - md->curlen));
+ memcpy(md->buf + md->curlen, in, n);
+ md->curlen += n;
+ in += n;
+ inlen -= n;
+ if(md->curlen == block_size) {
+ if(sha256_compress(md, md->buf) < 0)
+ return -1;
+ md->length += 8 * block_size;
+ md->curlen = 0;
+ }
+ }
+ }
+ return 0;
+}
+/**
+ Terminate the hash to get the digest
+ @param md The hash state
+ @param out [out] The destination of the hash (32 bytes)
+ @return CRYPT_OK if successful
+*/
+static int SHA256_Final(unsigned char *out,
+ struct sha256_state *md)
+{
+ int i;
+ if(md->curlen >= sizeof(md->buf))
+ return -1;
+ /* increase the length of the message */
+ md->length += md->curlen * 8;
+ /* append the '1' bit */
+ md->buf[md->curlen++] = (unsigned char)0x80;
+ /* if the length is currently above 56 bytes we append zeros
+ * then compress. Then we can fall back to padding zeros and length
+ * encoding like normal.
+ */
+ if(md->curlen > 56) {
+ while(md->curlen < 64) {
+ md->buf[md->curlen++] = (unsigned char)0;
+ }
+ sha256_compress(md, md->buf);
+ md->curlen = 0;
+ }
+ /* pad upto 56 bytes of zeroes */
+ while(md->curlen < 56) {
+ md->buf[md->curlen++] = (unsigned char)0;
+ }
+ /* store length */
+ WPA_PUT_BE64(md->buf + 56, md->length);
+ sha256_compress(md, md->buf);
+ /* copy output */
+ for(i = 0; i < 8; i++)
+ WPA_PUT_BE32(out + (4 * i), md->state[i]);
+ return 0;
+}
+/* ===== end - public domain SHA256 implementation ===== */
+
+#endif
+
+void Curl_sha256it(unsigned char *outbuffer, /* 32 unsigned chars */
+ const unsigned char *input)
+{
+ SHA256_CTX ctx;
+ SHA256_Init(&ctx);
+ SHA256_Update(&ctx, input, curlx_uztoui(strlen((char *)input)));
+ SHA256_Final(outbuffer, &ctx);
+}
+
+#endif /* CURL_DISABLE_CRYPTO_AUTH */
diff --git a/lib/share.c b/lib/share.c
index 5b3957fc..870b191f 100644
--- a/lib/share.c
+++ b/lib/share.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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
@@ -102,6 +102,8 @@ curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...)
break;
case CURL_LOCK_DATA_CONNECT: /* not supported (yet) */
+ if(Curl_conncache_init(&share->conn_cache, 103))
+ res = CURLSHE_NOMEM;
break;
default:
@@ -186,6 +188,8 @@ curl_share_cleanup(struct Curl_share *share)
return CURLSHE_IN_USE;
}
+ Curl_conncache_close_all_connections(&share->conn_cache);
+ Curl_conncache_destroy(&share->conn_cache);
Curl_hash_destroy(&share->hostcache);
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
diff --git a/lib/share.h b/lib/share.h
index c039a16c..4b13406d 100644
--- a/lib/share.h
+++ b/lib/share.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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,6 +26,7 @@
#include <curl/curl.h>
#include "cookie.h"
#include "urldata.h"
+#include "conncache.h"
/* SalfordC says "A structure member may not be volatile". Hence:
*/
@@ -43,7 +44,7 @@ struct Curl_share {
curl_lock_function lockfunc;
curl_unlock_function unlockfunc;
void *clientdata;
-
+ struct conncache conn_cache;
struct curl_hash hostcache;
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
struct CookieInfo *cookies;
diff --git a/lib/smb.c b/lib/smb.c
index 13dfd514..efcfd2da 100644
--- a/lib/smb.c
+++ b/lib/smb.c
@@ -648,7 +648,7 @@ static CURLcode smb_connection_state(struct connectdata *conn, bool *done)
if(smbc->state == SMB_CONNECTING) {
#ifdef USE_SSL
if((conn->handler->flags & PROTOPT_SSL)) {
- bool ssl_done;
+ bool ssl_done = FALSE;
result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &ssl_done);
if(result && result != CURLE_AGAIN)
return result;
diff --git a/lib/smtp.c b/lib/smtp.c
index 4e2c3361..44ee2e9f 100644
--- a/lib/smtp.c
+++ b/lib/smtp.c
@@ -67,6 +67,7 @@
#include "transfer.h"
#include "escape.h"
#include "http.h" /* for HTTP proxy tunnel stuff */
+#include "mime.h"
#include "socks.h"
#include "smtp.h"
#include "strtoofft.h"
@@ -530,8 +531,40 @@ static CURLcode smtp_perform_mail(struct connectdata *conn)
}
}
+ /* Prepare the mime data if some. */
+ if(data->set.mimepost.kind != MIMEKIND_NONE) {
+ /* Use the whole structure as data. */
+ data->set.mimepost.flags &= ~MIME_BODY_ONLY;
+
+ /* Add external headers and mime version. */
+ curl_mime_headers(&data->set.mimepost, data->set.headers, 0);
+ result = Curl_mime_prepare_headers(&data->set.mimepost, NULL,
+ NULL, MIMESTRATEGY_MAIL);
+
+ if(!result)
+ if(!Curl_checkheaders(conn, "Mime-Version"))
+ result = Curl_mime_add_header(&data->set.mimepost.curlheaders,
+ "Mime-Version: 1.0");
+
+ /* Make sure we will read the entire mime structure. */
+ if(!result)
+ result = Curl_mime_rewind(&data->set.mimepost);
+
+ if(result) {
+ free(from);
+ free(auth);
+ return result;
+ }
+
+ data->state.infilesize = Curl_mime_size(&data->set.mimepost);
+
+ /* Read from mime structure. */
+ data->state.fread_func = (curl_read_callback) Curl_mime_read;
+ data->state.in = (void *) &data->set.mimepost;
+ }
+
/* Calculate the optional SIZE parameter */
- if(conn->proto.smtpc.size_supported && conn->data->state.infilesize > 0) {
+ if(conn->proto.smtpc.size_supported && data->state.infilesize > 0) {
size = aprintf("%" CURL_FORMAT_CURL_OFF_T, data->state.infilesize);
if(!size) {
@@ -1155,11 +1188,15 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
if(!smtp || !pp->conn)
return CURLE_OK;
+ /* Cleanup our per-request based variables */
+ Curl_safefree(smtp->custom);
+
if(status) {
connclose(conn, "SMTP done with bad status"); /* marked for closure */
result = status; /* use the already set error code */
}
- else if(!data->set.connect_only && data->set.upload && data->set.mail_rcpt) {
+ else if(!data->set.connect_only && data->set.mail_rcpt &&
+ (data->set.upload || data->set.mimepost.kind)) {
/* Calculate the EOB taking into account any terminating CRLF from the
previous line of the email or the CRLF of the DATA command when there
is "no mail data". RFC-5321, sect. 4.1.1.4.
@@ -1196,7 +1233,7 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
}
else {
/* Successfully sent so adjust the response timeout relative to now */
- pp->response = Curl_tvnow();
+ pp->response = Curl_now();
free(eob);
}
@@ -1212,9 +1249,6 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
result = smtp_block_statemach(conn);
}
- /* Cleanup our per-request based variables */
- Curl_safefree(smtp->custom);
-
/* Clear the transfer mode for the next request */
smtp->transfer = FTPTRANSFER_BODY;
@@ -1249,7 +1283,7 @@ static CURLcode smtp_perform(struct connectdata *conn, bool *connected,
smtp->rcpt = data->set.mail_rcpt;
/* Start the first command in the DO phase */
- if(data->set.upload && data->set.mail_rcpt)
+ if((data->set.upload || data->set.mimepost.kind) && data->set.mail_rcpt)
/* MAIL transfer */
result = smtp_perform_mail(conn);
else
diff --git a/lib/socks.c b/lib/socks.c
index 000cd9c2..ac4270ea 100644
--- a/lib/socks.c
+++ b/lib/socks.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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
@@ -57,7 +57,7 @@ int Curl_blockread_all(struct connectdata *conn, /* connection data */
ssize_t nread;
ssize_t allread = 0;
int result;
- time_t timeleft;
+ timediff_t timeleft;
*n = 0;
for(;;) {
timeleft = Curl_timeleft(conn->data, NULL, TRUE);
@@ -154,7 +154,7 @@ CURLcode Curl_SOCKS4(const char *proxy_user,
/* DNS resolve only for SOCKS4, not SOCKS4a */
if(!protocol4a) {
struct Curl_dns_entry *dns;
- Curl_addrinfo *hp=NULL;
+ Curl_addrinfo *hp = NULL;
int rc;
rc = Curl_resolv(conn, hostname, remote_port, &dns);
@@ -171,7 +171,7 @@ CURLcode Curl_SOCKS4(const char *proxy_user,
* returns a Curl_addrinfo pointer that may not always look the same.
*/
if(dns)
- hp=dns->addr;
+ hp = dns->addr;
if(hp) {
char buf[64];
Curl_printable_address(hp, buf, sizeof(buf));
@@ -213,7 +213,7 @@ CURLcode Curl_SOCKS4(const char *proxy_user,
return CURLE_COULDNT_CONNECT;
}
/* copy the proxy name WITH trailing zero */
- memcpy(socksreq + 8, proxy_user, plen+1);
+ memcpy(socksreq + 8, proxy_user, plen + 1);
}
/*
@@ -306,7 +306,7 @@ CURLcode Curl_SOCKS4(const char *proxy_user,
", request rejected or failed.",
(unsigned char)socksreq[4], (unsigned char)socksreq[5],
(unsigned char)socksreq[6], (unsigned char)socksreq[7],
- (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]),
+ (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
(unsigned char)socksreq[1]);
return CURLE_COULDNT_CONNECT;
case 92:
@@ -316,7 +316,7 @@ CURLcode Curl_SOCKS4(const char *proxy_user,
"identd on the client.",
(unsigned char)socksreq[4], (unsigned char)socksreq[5],
(unsigned char)socksreq[6], (unsigned char)socksreq[7],
- (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]),
+ (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
(unsigned char)socksreq[1]);
return CURLE_COULDNT_CONNECT;
case 93:
@@ -326,7 +326,7 @@ CURLcode Curl_SOCKS4(const char *proxy_user,
"report different user-ids.",
(unsigned char)socksreq[4], (unsigned char)socksreq[5],
(unsigned char)socksreq[6], (unsigned char)socksreq[7],
- (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]),
+ (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
(unsigned char)socksreq[1]);
return CURLE_COULDNT_CONNECT;
default:
@@ -335,7 +335,7 @@ CURLcode Curl_SOCKS4(const char *proxy_user,
", Unknown.",
(unsigned char)socksreq[4], (unsigned char)socksreq[5],
(unsigned char)socksreq[6], (unsigned char)socksreq[7],
- (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]),
+ (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
(unsigned char)socksreq[1]);
return CURLE_COULDNT_CONNECT;
}
@@ -382,7 +382,7 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
CURLcode code;
curl_socket_t sock = conn->sock[sockindex];
struct Curl_easy *data = conn->data;
- time_t timeout;
+ timediff_t timeout;
bool socks5_resolve_local =
(conn->socks_proxy.proxytype == CURLPROXY_SOCKS5) ? TRUE : FALSE;
const size_t hostname_len = strlen(hostname);
@@ -483,7 +483,7 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
(void)curlx_nonblock(sock, FALSE);
- result=Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread);
+ result = Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread);
if(result || (actualread != 2)) {
failf(data, "Unable to receive initial SOCKS5 response.");
return CURLE_COULDNT_CONNECT;
@@ -542,7 +542,7 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
return CURLE_COULDNT_CONNECT;
}
- result=Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread);
+ result = Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread);
if(result || (actualread != 2)) {
failf(data, "Unable to receive SOCKS5 sub-negotiation response.");
return CURLE_COULDNT_CONNECT;
@@ -615,7 +615,7 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
* returns a Curl_addrinfo pointer that may not always look the same.
*/
if(dns)
- hp=dns->addr;
+ hp = dns->addr;
if(hp) {
int i;
char buf[64];
diff --git a/lib/socks_gssapi.c b/lib/socks_gssapi.c
index 54d06350..96948ac4 100644
--- a/lib/socks_gssapi.c
+++ b/lib/socks_gssapi.c
@@ -5,8 +5,8 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2009, 2011, Markus Moeller, <markus_moeller@compuserve.com>
- * Copyright (C) 2012 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2009, Markus Moeller, <markus_moeller@compuserve.com>
+ * Copyright (C) 2012 - 2017, 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
@@ -65,7 +65,7 @@ static int check_gss_err(struct Curl_easy *data,
&msg_ctx, &status_string);
if(maj_stat == GSS_S_COMPLETE) {
if(sizeof(buf) > len + status_string.length + 1) {
- strcpy(buf+len, (char *) status_string.value);
+ strcpy(buf + len, (char *) status_string.value);
len += status_string.length;
}
gss_release_buffer(&min_stat, &status_string);
@@ -74,7 +74,7 @@ static int check_gss_err(struct Curl_easy *data,
gss_release_buffer(&min_stat, &status_string);
}
if(sizeof(buf) > len + 3) {
- strcpy(buf+len, ".\n");
+ strcpy(buf + len, ".\n");
len += 2;
}
msg_ctx = 0;
@@ -86,7 +86,7 @@ static int check_gss_err(struct Curl_easy *data,
&msg_ctx, &status_string);
if(maj_stat == GSS_S_COMPLETE) {
if(sizeof(buf) > len + status_string.length)
- strcpy(buf+len, (char *) status_string.value);
+ strcpy(buf + len, (char *) status_string.value);
gss_release_buffer(&min_stat, &status_string);
break;
}
@@ -119,7 +119,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
gss_name_t server = GSS_C_NO_NAME;
gss_name_t gss_client_name = GSS_C_NO_NAME;
unsigned short us_length;
- char *user=NULL;
+ char *user = NULL;
unsigned char socksreq[4]; /* room for GSS-API exchange header only */
const char *serviceptr = data->set.str[STRING_PROXY_SERVICE_NAME] ?
data->set.str[STRING_PROXY_SERVICE_NAME] : "rcmd";
@@ -146,11 +146,12 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
}
else {
service.value = malloc(serviceptr_length +
- strlen(conn->socks_proxy.host.name)+2);
+ strlen(conn->socks_proxy.host.name) + 2);
if(!service.value)
return CURLE_OUT_OF_MEMORY;
- service.length = serviceptr_length + strlen(conn->socks_proxy.host.name)+1;
- snprintf(service.value, service.length+1, "%s@%s",
+ service.length = serviceptr_length +
+ strlen(conn->socks_proxy.host.name) + 1;
+ snprintf(service.value, service.length + 1, "%s@%s",
serviceptr, conn->socks_proxy.host.name);
gss_major_status = gss_import_name(&gss_minor_status, &service,
@@ -196,7 +197,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
socksreq[0] = 1; /* GSS-API subnegotiation version */
socksreq[1] = 1; /* authentication message type */
us_length = htons((short)gss_send_token.length);
- memcpy(socksreq+2, &us_length, sizeof(short));
+ memcpy(socksreq + 2, &us_length, sizeof(short));
code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
if(code || (4 != written)) {
@@ -236,7 +237,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
* +----+------+-----+----------------+
*/
- result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread);
+ result = Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread);
if(result || (actualread != 4)) {
failf(data, "Failed to receive GSS-API authentication response.");
gss_release_name(&gss_status, &server);
@@ -261,11 +262,11 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
return CURLE_COULDNT_CONNECT;
}
- memcpy(&us_length, socksreq+2, sizeof(short));
+ memcpy(&us_length, socksreq + 2, sizeof(short));
us_length = ntohs(us_length);
- gss_recv_token.length=us_length;
- gss_recv_token.value=malloc(us_length);
+ gss_recv_token.length = us_length;
+ gss_recv_token.value = malloc(us_length);
if(!gss_recv_token.value) {
failf(data,
"Could not allocate memory for GSS-API authentication "
@@ -275,8 +276,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
return CURLE_OUT_OF_MEMORY;
}
- result=Curl_blockread_all(conn, sock, (char *)gss_recv_token.value,
- gss_recv_token.length, &actualread);
+ result = Curl_blockread_all(conn, sock, (char *)gss_recv_token.value,
+ gss_recv_token.length, &actualread);
if(result || (actualread != us_length)) {
failf(data, "Failed to receive GSS-API authentication token.");
@@ -312,7 +313,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
failf(data, "Failed to determine user name.");
return CURLE_COULDNT_CONNECT;
}
- user=malloc(gss_send_token.length+1);
+ user = malloc(gss_send_token.length + 1);
if(!user) {
gss_delete_sec_context(&gss_status, &gss_context, NULL);
gss_release_name(&gss_status, &gss_client_name);
@@ -326,7 +327,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
gss_release_buffer(&gss_status, &gss_send_token);
infof(data, "SOCKS5 server authencticated user %s with GSS-API.\n",user);
free(user);
- user=NULL;
+ user = NULL;
/* Do encryption */
socksreq[0] = 1; /* GSS-API subnegotiation version */
@@ -341,7 +342,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
gss_enc = 1;
infof(data, "SOCKS5 server supports GSS-API %s data protection.\n",
- (gss_enc==0)?"no":((gss_enc==1)?"integrity":"confidentiality"));
+ (gss_enc == 0)?"no":((gss_enc==1)?"integrity":"confidentiality"));
/* force for the moment to no data protection */
gss_enc = 0;
/*
@@ -376,7 +377,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
*/
if(data->set.socks5_gssapi_nec) {
us_length = htons((short)1);
- memcpy(socksreq+2, &us_length, sizeof(short));
+ memcpy(socksreq + 2, &us_length, sizeof(short));
}
else {
gss_send_token.length = 1;
@@ -401,7 +402,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
gss_release_buffer(&gss_status, &gss_send_token);
us_length = htons((short)gss_w_token.length);
- memcpy(socksreq+2, &us_length, sizeof(short));
+ memcpy(socksreq + 2, &us_length, sizeof(short));
}
code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
@@ -433,7 +434,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
gss_release_buffer(&gss_status, &gss_w_token);
}
- result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread);
+ result = Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread);
if(result || (actualread != 4)) {
failf(data, "Failed to receive GSS-API encryption response.");
gss_delete_sec_context(&gss_status, &gss_context, NULL);
@@ -455,17 +456,17 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
return CURLE_COULDNT_CONNECT;
}
- memcpy(&us_length, socksreq+2, sizeof(short));
+ memcpy(&us_length, socksreq + 2, sizeof(short));
us_length = ntohs(us_length);
- gss_recv_token.length= us_length;
- gss_recv_token.value=malloc(gss_recv_token.length);
+ gss_recv_token.length = us_length;
+ gss_recv_token.value = malloc(gss_recv_token.length);
if(!gss_recv_token.value) {
gss_delete_sec_context(&gss_status, &gss_context, NULL);
return CURLE_OUT_OF_MEMORY;
}
- result=Curl_blockread_all(conn, sock, (char *)gss_recv_token.value,
- gss_recv_token.length, &actualread);
+ result = Curl_blockread_all(conn, sock, (char *)gss_recv_token.value,
+ gss_recv_token.length, &actualread);
if(result || (actualread != us_length)) {
failf(data, "Failed to receive GSS-API encryptrion type.");
@@ -513,8 +514,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
}
infof(data, "SOCKS5 access with%s protection granted.\n",
- (socksreq[0]==0)?"out GSS-API data":
- ((socksreq[0]==1)?" GSS-API integrity":" GSS-API confidentiality"));
+ (socksreq[0] == 0)?"out GSS-API data":
+ ((socksreq[0] == 1)?" GSS-API integrity":" GSS-API confidentiality"));
conn->socks5_gssapi_enctype = socksreq[0];
if(socksreq[0] == 0)
diff --git a/lib/socks_sspi.c b/lib/socks_sspi.c
index edc73ad2..34699d37 100644
--- a/lib/socks_sspi.c
+++ b/lib/socks_sspi.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2012 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 2009, 2011, Markus Moeller, <markus_moeller@compuserve.com>
*
* This software is licensed as described in the file COPYING, which
@@ -108,7 +108,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
if(!service_name)
return CURLE_OUT_OF_MEMORY;
snprintf(service_name, service_length +
- strlen(conn->socks_proxy.host.name)+2, "%s/%s",
+ strlen(conn->socks_proxy.host.name) + 2, "%s/%s",
service, conn->socks_proxy.host.name);
}
@@ -199,7 +199,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
socksreq[0] = 1; /* GSS-API subnegotiation version */
socksreq[1] = 1; /* authentication message type */
us_length = htons((short)sspi_send_token.cbBuffer);
- memcpy(socksreq+2, &us_length, sizeof(short));
+ memcpy(socksreq + 2, &us_length, sizeof(short));
code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
if(code || (4 != written)) {
@@ -283,7 +283,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
return CURLE_COULDNT_CONNECT;
}
- memcpy(&us_length, socksreq+2, sizeof(short));
+ memcpy(&us_length, socksreq + 2, sizeof(short));
us_length = ntohs(us_length);
sspi_recv_token.cbBuffer = us_length;
@@ -341,7 +341,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
gss_enc = 1;
infof(data, "SOCKS5 server supports GSS-API %s data protection.\n",
- (gss_enc==0)?"no":((gss_enc==1)?"integrity":"confidentiality") );
+ (gss_enc == 0)?"no":((gss_enc == 1)?"integrity":"confidentiality") );
/* force to no data protection, avoid encryption/decryption for now */
gss_enc = 0;
/*
@@ -377,7 +377,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
if(data->set.socks5_gssapi_nec) {
us_length = htons((short)1);
- memcpy(socksreq+2, &us_length, sizeof(short));
+ memcpy(socksreq + 2, &us_length, sizeof(short));
}
else {
status = s_pSecFn->QueryContextAttributes(&sspi_context,
@@ -445,8 +445,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
memcpy((PUCHAR) sspi_send_token.pvBuffer +(int)sspi_w_token[0].cbBuffer,
sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer);
memcpy((PUCHAR) sspi_send_token.pvBuffer
- +sspi_w_token[0].cbBuffer
- +sspi_w_token[1].cbBuffer,
+ + sspi_w_token[0].cbBuffer
+ + sspi_w_token[1].cbBuffer,
sspi_w_token[2].pvBuffer, sspi_w_token[2].cbBuffer);
s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
@@ -460,7 +460,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
sspi_w_token[2].cbBuffer = 0;
us_length = htons((short)sspi_send_token.cbBuffer);
- memcpy(socksreq+2, &us_length, sizeof(short));
+ memcpy(socksreq + 2, &us_length, sizeof(short));
}
code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
@@ -517,7 +517,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
return CURLE_COULDNT_CONNECT;
}
- memcpy(&us_length, socksreq+2, sizeof(short));
+ memcpy(&us_length, socksreq + 2, sizeof(short));
us_length = ntohs(us_length);
sspi_w_token[0].cbBuffer = us_length;
@@ -588,8 +588,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
}
infof(data, "SOCKS5 access with%s protection granted.\n",
- (socksreq[0]==0)?"out GSS-API data":
- ((socksreq[0]==1)?" GSS-API integrity":" GSS-API confidentiality"));
+ (socksreq[0] == 0)?"out GSS-API data":
+ ((socksreq[0] == 1)?" GSS-API integrity":" GSS-API confidentiality"));
/* For later use if encryption is required
conn->socks5_gssapi_enctype = socksreq[0];
diff --git a/lib/speedcheck.c b/lib/speedcheck.c
index fe669f11..3aeea911 100644
--- a/lib/speedcheck.c
+++ b/lib/speedcheck.c
@@ -46,7 +46,7 @@ CURLcode Curl_speedcheck(struct Curl_easy *data,
data->state.keeps_speed = now;
else {
/* how long has it been under the limit */
- time_t howlong = Curl_tvdiff(now, data->state.keeps_speed);
+ timediff_t howlong = Curl_timediff(now, data->state.keeps_speed);
if(howlong >= data->set.low_speed_time * 1000) {
/* too long */
diff --git a/lib/splay.c b/lib/splay.c
index 68ff9c5d..69af446e 100644
--- a/lib/splay.c
+++ b/lib/splay.c
@@ -110,7 +110,7 @@ struct Curl_tree *Curl_splayinsert(struct curltime i,
if(t != NULL) {
t = Curl_splay(i, t);
- if(compare(i, t->key)==0) {
+ if(compare(i, t->key) == 0) {
/* There already exists a node in the tree with the very same key. Build
a doubly-linked circular list of nodes. We add the new 'node' struct
to the end of this list. */
diff --git a/lib/splay.h b/lib/splay.h
index 0273bad3..4612ec27 100644
--- a/lib/splay.h
+++ b/lib/splay.h
@@ -54,8 +54,8 @@ int Curl_splayremovebyaddr(struct Curl_tree *t,
struct Curl_tree *removenode,
struct Curl_tree **newroot);
-#define Curl_splaycomparekeys(i,j) ( ((i.tv_sec) < (j.tv_sec)) ? -1 : \
- ( ((i.tv_sec) > (j.tv_sec)) ? 1 : \
+#define Curl_splaycomparekeys(i,j) ( ((i.tv_sec) < (j.tv_sec)) ? -1 : \
+ ( ((i.tv_sec) > (j.tv_sec)) ? 1 : \
( ((i.tv_usec) < (j.tv_usec)) ? -1 : \
( ((i.tv_usec) > (j.tv_usec)) ? 1 : 0))))
diff --git a/lib/ssh.c b/lib/ssh.c
index 9443e24b..2496e7cf 100644
--- a/lib/ssh.c
+++ b/lib/ssh.c
@@ -428,14 +428,14 @@ static CURLcode ssh_getworkingpath(struct connectdata *conn,
/* Check for /~/, indicating relative to the user's home directory */
if(conn->handler->protocol & CURLPROTO_SCP) {
- real_path = malloc(working_path_len+1);
+ real_path = malloc(working_path_len + 1);
if(real_path == NULL) {
free(working_path);
return CURLE_OUT_OF_MEMORY;
}
if((working_path_len > 3) && (!memcmp(working_path, "/~/", 3)))
/* It is referenced to the home directory, so strip the leading '/~/' */
- memcpy(real_path, working_path+3, 4 + working_path_len-3);
+ memcpy(real_path, working_path + 3, 4 + working_path_len-3);
else
memcpy(real_path, working_path, 1 + working_path_len);
}
@@ -451,19 +451,19 @@ static CURLcode ssh_getworkingpath(struct connectdata *conn,
leading '/' */
memcpy(real_path, homedir, homelen);
real_path[homelen] = '/';
- real_path[homelen+1] = '\0';
+ real_path[homelen + 1] = '\0';
if(working_path_len > 3) {
- memcpy(real_path+homelen+1, working_path + 3,
+ memcpy(real_path + homelen + 1, working_path + 3,
1 + working_path_len -3);
}
}
else {
- real_path = malloc(working_path_len+1);
+ real_path = malloc(working_path_len + 1);
if(real_path == NULL) {
free(working_path);
return CURLE_OUT_OF_MEMORY;
}
- memcpy(real_path, working_path, 1+working_path_len);
+ memcpy(real_path, working_path, 1 + working_path_len);
}
}
@@ -1813,7 +1813,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
zero even though libssh2_sftp_open() failed previously! We need
to work around that! */
sshc->actualcode = CURLE_SSH;
- err=-1;
+ err = -1;
}
failf(data, "Upload failed: %s (%d/%d)",
err>= LIBSSH2_FX_OK?sftp_libssh2_strerror(err):"ssh error",
@@ -1831,7 +1831,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
}
if(seekerr != CURL_SEEKFUNC_OK) {
- curl_off_t passed=0;
+ curl_off_t passed = 0;
if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
failf(data, "Could not seek stream");
@@ -1983,13 +1983,13 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
sshc->actualcode = result?result:CURLE_SSH;
break;
}
- sshc->readdir_filename = malloc(PATH_MAX+1);
+ sshc->readdir_filename = malloc(PATH_MAX + 1);
if(!sshc->readdir_filename) {
state(conn, SSH_SFTP_CLOSE);
sshc->actualcode = CURLE_OUT_OF_MEMORY;
break;
}
- sshc->readdir_longentry = malloc(PATH_MAX+1);
+ sshc->readdir_longentry = malloc(PATH_MAX + 1);
if(!sshc->readdir_longentry) {
Curl_safefree(sshc->readdir_filename);
state(conn, SSH_SFTP_CLOSE);
@@ -2023,7 +2023,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
break;
}
result = Curl_client_write(conn, CLIENTWRITE_BODY,
- tmpLine, sshc->readdir_len+1);
+ tmpLine, sshc->readdir_len + 1);
free(tmpLine);
if(result) {
@@ -2032,7 +2032,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
}
/* since this counts what we send to the client, we include the
newline in this counter */
- data->req.bytecount += sshc->readdir_len+1;
+ data->req.bytecount += sshc->readdir_len + 1;
/* output debug output if that is requested */
if(data->set.verbose) {
@@ -2233,18 +2233,25 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
curl_off_t from, to;
char *ptr;
char *ptr2;
+ CURLofft to_t;
+ CURLofft from_t;
- from=curlx_strtoofft(conn->data->state.range, &ptr, 0);
- while(*ptr && (ISSPACE(*ptr) || (*ptr=='-')))
+ from_t = curlx_strtoofft(conn->data->state.range, &ptr, 0, &from);
+ if(from_t == CURL_OFFT_FLOW)
+ return CURLE_RANGE_ERROR;
+ while(*ptr && (ISSPACE(*ptr) || (*ptr == '-')))
ptr++;
- to=curlx_strtoofft(ptr, &ptr2, 0);
- if((ptr == ptr2) /* no "to" value given */
+ to_t = curlx_strtoofft(ptr, &ptr2, 0, &to);
+ if(to_t == CURL_OFFT_FLOW)
+ return CURLE_RANGE_ERROR;
+ if((to_t == CURL_OFFT_INVAL) /* no "to" value given */
|| (to >= size)) {
to = size - 1;
}
- if(from < 0) {
+ if(from_t) {
/* from is relative to end of file */
- from += size;
+ from = size - to;
+ to = size - 1;
}
if(from > size) {
failf(data, "Offset (%"
@@ -2340,8 +2347,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
}
sshc->sftp_handle = NULL;
}
- if(sftp_scp)
- Curl_safefree(sftp_scp->path);
+
+ Curl_safefree(sftp_scp->path);
DEBUGF(infof(data, "SFTP DONE done\n"));
@@ -2826,8 +2833,8 @@ static CURLcode ssh_block_statemach(struct connectdata *conn,
while((sshc->state != SSH_STOP) && !result) {
bool block;
- time_t left = 1000;
- struct curltime now = Curl_tvnow();
+ timediff_t left = 1000;
+ struct curltime now = Curl_now();
result = ssh_statemach_act(conn, &block);
if(result)
@@ -2935,6 +2942,13 @@ static CURLcode ssh_connect(struct connectdata *conn, bool *done)
return CURLE_FAILED_INIT;
}
+ if(data->set.ssh_compression) {
+#if LIBSSH2_VERSION_NUM >= 0x010208
+ if(libssh2_session_flag(ssh->ssh_session, LIBSSH2_FLAG_COMPRESS, 1) < 0)
+#endif
+ infof(data, "Failed to enable compression for ssh session\n");
+ }
+
#ifdef HAVE_LIBSSH2_KNOWNHOST_API
if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
int rc;
@@ -3031,8 +3045,8 @@ static CURLcode ssh_do(struct connectdata *conn, bool *done)
data->req.size = -1; /* make sure this is unknown at this point */
sshc->actualcode = CURLE_OK; /* reset error code */
- sshc->secondCreateDirs =0; /* reset the create dir attempt state
- variable */
+ sshc->secondCreateDirs = 0; /* reset the create dir attempt state
+ variable */
Curl_pgrsSetUploadCounter(data, 0);
Curl_pgrsSetDownloadCounter(data, 0);
diff --git a/lib/strcase.c b/lib/strcase.c
index a74a4be5..24bcca93 100644
--- a/lib/strcase.c
+++ b/lib/strcase.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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
@@ -94,10 +94,11 @@ char Curl_raw_toupper(char in)
}
/*
- * Curl_raw_equal() is for doing "raw" case insensitive strings. This is meant
- * to be locale independent and only compare strings we know are safe for
- * this. See https://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for
- * some further explanation to why this function is necessary.
+ * Curl_strcasecompare() is for doing "raw" case insensitive strings. This is
+ * meant to be locale independent and only compare strings we know are safe
+ * for this. See
+ * https://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for some
+ * further explanation to why this function is necessary.
*
* The function is capable of comparing a-z case insensitively even for
* non-ascii.
diff --git a/lib/strdup.c b/lib/strdup.c
index 136b6937..19cb0441 100644
--- a/lib/strdup.c
+++ b/lib/strdup.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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,11 +44,11 @@ char *curlx_strdup(const char *str)
if(len >= ((size_t)-1) / sizeof(char))
return (char *)NULL;
- newstr = malloc((len+1)*sizeof(char));
+ newstr = malloc((len + 1)*sizeof(char));
if(!newstr)
return (char *)NULL;
- memcpy(newstr, str, (len+1)*sizeof(char));
+ memcpy(newstr, str, (len + 1)*sizeof(char));
return newstr;
diff --git a/lib/strtoofft.c b/lib/strtoofft.c
index c2adc728..36364773 100644
--- a/lib/strtoofft.c
+++ b/lib/strtoofft.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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,6 +20,7 @@
*
***************************************************************************/
+#include <errno.h>
#include "curl_setup.h"
#include "strtoofft.h"
@@ -32,7 +33,29 @@
* https://www.opengroup.org/onlinepubs/009695399/functions/strtoimax.html
*/
-#ifdef NEED_CURL_STRTOLL
+#if (SIZEOF_CURL_OFF_T > SIZEOF_LONG)
+# ifdef HAVE_STRTOLL
+# define strtooff strtoll
+# else
+# if defined(_MSC_VER) && (_MSC_VER >= 1300) && (_INTEGRAL_MAX_BITS >= 64)
+# if defined(_SAL_VERSION)
+ _Check_return_ _CRTIMP __int64 __cdecl _strtoi64(
+ _In_z_ const char *_String,
+ _Out_opt_ _Deref_post_z_ char **_EndPtr, _In_ int _Radix);
+# else
+ _CRTIMP __int64 __cdecl _strtoi64(const char *_String,
+ char **_EndPtr, int _Radix);
+# endif
+# define strtooff _strtoi64
+# else
+# define PRIVATE_STRTOOFF 1
+# endif
+# endif
+#else
+# define strtooff strtol
+#endif
+
+#ifdef PRIVATE_STRTOOFF
/* Range tests can be used for alphanum decoding if characters are consecutive,
like in ASCII. Else an array is scanned. Determine this condition now. */
@@ -48,11 +71,10 @@ static const char valchars[] =
static int get_char(char c, int base);
/**
- * Emulated version of the strtoll function. This extracts a long long
+ * Custom version of the strtooff function. This extracts a curl_off_t
* value from the given input string and returns it.
*/
-curl_off_t
-curlx_strtoll(const char *nptr, char **endptr, int base)
+static curl_off_t strtooff(const char *nptr, char **endptr, int base)
{
char *end;
int is_negative = 0;
@@ -186,3 +208,37 @@ static int get_char(char c, int base)
return value;
}
#endif /* Only present if we need strtoll, but don't have it. */
+
+/*
+ * Parse a *positive* up to 64 bit number written in ascii.
+ */
+CURLofft curlx_strtoofft(const char *str, char **endp, int base,
+ curl_off_t *num)
+{
+ char *end;
+ curl_off_t number;
+ errno = 0;
+ *num = 0; /* clear by default */
+
+ DEBUGASSERT(str);
+
+ while(*str && ISSPACE(*str))
+ str++;
+ if('-' == *str) {
+ if(endp)
+ *endp = (char *)str; /* didn't actually move */
+ return CURL_OFFT_INVAL; /* nothing parsed */
+ }
+ number = strtooff(str, &end, base);
+ if(endp)
+ *endp = end;
+ if(errno == ERANGE)
+ /* overflow/underflow */
+ return CURL_OFFT_FLOW;
+ else if(str == end)
+ /* nothing parsed */
+ return CURL_OFFT_INVAL;
+
+ *num = number;
+ return CURL_OFFT_OK;
+}
diff --git a/lib/strtoofft.h b/lib/strtoofft.h
index f4039f3a..244411a8 100644
--- a/lib/strtoofft.h
+++ b/lib/strtoofft.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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,31 +40,7 @@
* of 'long' the conversion function to use is strtol().
*/
-#if (CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG)
-# ifdef HAVE_STRTOLL
-# define curlx_strtoofft strtoll
-# else
-# if defined(_MSC_VER) && (_MSC_VER >= 1300) && (_INTEGRAL_MAX_BITS >= 64)
-# if defined(_SAL_VERSION)
- _Check_return_ _CRTIMP __int64 __cdecl _strtoi64(
- _In_z_ const char *_String,
- _Out_opt_ _Deref_post_z_ char **_EndPtr, _In_ int _Radix);
-# else
- _CRTIMP __int64 __cdecl _strtoi64(const char *_String,
- char **_EndPtr, int _Radix);
-# endif
-# define curlx_strtoofft _strtoi64
-# else
- curl_off_t curlx_strtoll(const char *nptr, char **endptr, int base);
-# define curlx_strtoofft curlx_strtoll
-# define NEED_CURL_STRTOLL 1
-# endif
-# endif
-#else
-# define curlx_strtoofft strtol
-#endif
-
-#if (CURL_SIZEOF_CURL_OFF_T == 4)
+#if (SIZEOF_CURL_OFF_T == 4)
# define CURL_OFF_T_MAX CURL_OFF_T_C(0x7FFFFFFF)
#else
/* assume CURL_SIZEOF_CURL_OFF_T == 8 */
@@ -72,4 +48,13 @@
#endif
#define CURL_OFF_T_MIN (-CURL_OFF_T_MAX - CURL_OFF_T_C(1))
+typedef enum {
+ CURL_OFFT_OK, /* parsed fine */
+ CURL_OFFT_FLOW, /* over or underflow */
+ CURL_OFFT_INVAL /* nothing was parsed */
+} CURLofft;
+
+CURLofft curlx_strtoofft(const char *str, char **endp, int base,
+ curl_off_t *num);
+
#endif /* HEADER_CURL_STRTOOFFT_H */
diff --git a/lib/telnet.c b/lib/telnet.c
index 3dec9590..48b134ee 100644
--- a/lib/telnet.c
+++ b/lib/telnet.c
@@ -76,7 +76,7 @@
} WHILE_FALSE
#define CURL_SB_ACCUM(x,c) \
do { \
- if(x->subpointer < (x->subbuffer+sizeof x->subbuffer)) \
+ if(x->subpointer < (x->subbuffer + sizeof x->subbuffer)) \
*x->subpointer++ = (c); \
} WHILE_FALSE
@@ -295,8 +295,8 @@ static void negotiate(struct connectdata *conn)
int i;
struct TELNET *tn = (struct TELNET *) conn->data->req.protop;
- for(i = 0;i < CURL_NTELOPTS;i++) {
- if(i==CURL_TELOPT_ECHO)
+ for(i = 0; i < CURL_NTELOPTS; i++) {
+ if(i == CURL_TELOPT_ECHO)
continue;
if(tn->us_preferred[i] == CURL_YES)
@@ -792,7 +792,7 @@ static void printsub(struct Curl_easy *data,
case CURL_TELOPT_NEW_ENVIRON:
if(pointer[1] == CURL_TELQUAL_IS) {
infof(data, " ");
- for(i = 3;i < length;i++) {
+ for(i = 3; i < length; i++) {
switch(pointer[i]) {
case CURL_NEW_ENV_VAR:
infof(data, ", ");
@@ -843,7 +843,7 @@ static CURLcode check_telnet_options(struct connectdata *conn)
tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
}
- for(head = data->set.telnet_options; head; head=head->next) {
+ for(head = data->set.telnet_options; head; head = head->next) {
if(sscanf(head->data, "%127[^= ]%*[ =]%255s",
option_keyword, option_arg) == 2) {
@@ -890,8 +890,8 @@ static CURLcode check_telnet_options(struct connectdata *conn)
/* To take care or not of the 8th bit in data exchange */
if(strcasecompare(option_keyword, "BINARY")) {
- binary_option=atoi(option_arg);
- if(binary_option!=1) {
+ binary_option = atoi(option_arg);
+ if(binary_option != 1) {
tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO;
tn->him_preferred[CURL_TELOPT_BINARY] = CURL_NO;
}
@@ -935,7 +935,7 @@ static void suboption(struct connectdata *conn)
struct Curl_easy *data = conn->data;
struct TELNET *tn = (struct TELNET *)data->req.protop;
- printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn)+2);
+ 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;
@@ -967,7 +967,7 @@ static void suboption(struct connectdata *conn)
CURL_TELQUAL_IS);
len = 4;
- for(v = tn->telnet_vars;v;v = v->next) {
+ for(v = tn->telnet_vars; v; v = v->next) {
tmplen = (strlen(v->data) + 1);
/* Add the variable only if it fits */
if(len + tmplen < (int)sizeof(temp)-6) {
@@ -1019,8 +1019,8 @@ static void sendsuboption(struct connectdata *conn, int option)
CURL_SB_ACCUM(tn, CURL_TELOPT_NAWS);
/* We must deal either with litte or big endian processors */
/* Window size must be sent according to the 'network order' */
- x=htons(tn->subopt_wsx);
- y=htons(tn->subopt_wsy);
+ x = htons(tn->subopt_wsx);
+ y = htons(tn->subopt_wsy);
uc1 = (unsigned char *)&x;
uc2 = (unsigned char *)&y;
CURL_SB_ACCUM(tn, uc1[0]);
@@ -1033,7 +1033,7 @@ static void sendsuboption(struct connectdata *conn, int option)
CURL_SB_TERM(tn);
/* data suboption is now ready */
- printsub(data, '>', (unsigned char *)tn->subbuffer+2,
+ printsub(data, '>', (unsigned char *)tn->subbuffer + 2,
CURL_SB_LEN(tn)-2);
/* we send the header of the suboption... */
@@ -1044,9 +1044,9 @@ static void sendsuboption(struct connectdata *conn, int option)
}
/* ... then the window size with the send_telnet_data() function
to deal with 0xFF cases ... */
- send_telnet_data(conn, (char *)tn->subbuffer+3, 4);
+ send_telnet_data(conn, (char *)tn->subbuffer + 3, 4);
/* ... and the footer */
- bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer+7, 2);
+ bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer + 7, 2);
if(bytes_written < 0) {
err = SOCKERRNO;
failf(data, "Sending data failed (%d)", err);
@@ -1064,7 +1064,7 @@ CURLcode telrcv(struct connectdata *conn,
unsigned char c;
CURLcode result;
int in = 0;
- int startwrite=-1;
+ int startwrite = -1;
struct Curl_easy *data = conn->data;
struct TELNET *tn = (struct TELNET *)data->req.protop;
@@ -1560,8 +1560,8 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done)
}
if(data->set.timeout) {
- now = Curl_tvnow();
- if(Curl_tvdiff(now, conn->created) >= data->set.timeout) {
+ now = Curl_now();
+ if(Curl_timediff(now, conn->created) >= data->set.timeout) {
failf(data, "Time-out");
result = CURLE_OPERATION_TIMEDOUT;
keepon = FALSE;
@@ -1678,8 +1678,8 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done)
} /* poll switch statement */
if(data->set.timeout) {
- now = Curl_tvnow();
- if(Curl_tvdiff(now, conn->created) >= data->set.timeout) {
+ now = Curl_now();
+ if(Curl_timediff(now, conn->created) >= data->set.timeout) {
failf(data, "Time-out");
result = CURLE_OPERATION_TIMEDOUT;
keepon = FALSE;
diff --git a/lib/tftp.c b/lib/tftp.c
index f6f4bce5..20dc6004 100644
--- a/lib/tftp.c
+++ b/lib/tftp.c
@@ -76,12 +76,12 @@
#define TFTP_OPTION_INTERVAL "timeout"
typedef enum {
- TFTP_MODE_NETASCII=0,
+ TFTP_MODE_NETASCII = 0,
TFTP_MODE_OCTET
} tftp_mode_t;
typedef enum {
- TFTP_STATE_START=0,
+ TFTP_STATE_START = 0,
TFTP_STATE_RX,
TFTP_STATE_TX,
TFTP_STATE_FIN
@@ -100,7 +100,7 @@ typedef enum {
} tftp_event_t;
typedef enum {
- TFTP_ERR_UNDEF=0,
+ TFTP_ERR_UNDEF = 0,
TFTP_ERR_NOTFOUND,
TFTP_ERR_PERM,
TFTP_ERR_DISKFULL,
@@ -200,7 +200,7 @@ const struct Curl_handler Curl_handler_tftp = {
static CURLcode tftp_set_timeouts(tftp_state_data_t *state)
{
time_t maxtime, timeout;
- time_t timeout_ms;
+ timediff_t timeout_ms;
bool start = (state->state == TFTP_STATE_START) ? TRUE : FALSE;
time(&state->start_time);
@@ -217,7 +217,7 @@ static CURLcode tftp_set_timeouts(tftp_state_data_t *state)
if(start) {
maxtime = (time_t)(timeout_ms + 500) / 1000;
- state->max_time = state->start_time+maxtime;
+ state->max_time = state->start_time + maxtime;
/* Set per-block timeout to total */
timeout = maxtime;
@@ -232,7 +232,7 @@ static CURLcode tftp_set_timeouts(tftp_state_data_t *state)
/* Compute the re-start interval to suit the timeout */
state->retry_time = (int)timeout/state->retry_max;
if(state->retry_time<1)
- state->retry_time=1;
+ state->retry_time = 1;
}
else {
@@ -241,7 +241,7 @@ static CURLcode tftp_set_timeouts(tftp_state_data_t *state)
else
maxtime = 3600;
- state->max_time = state->start_time+maxtime;
+ state->max_time = state->start_time + maxtime;
/* Set per-block timeout to total */
timeout = maxtime;
@@ -251,15 +251,15 @@ static CURLcode tftp_set_timeouts(tftp_state_data_t *state)
}
/* But bound the total number */
if(state->retry_max<3)
- state->retry_max=3;
+ state->retry_max = 3;
if(state->retry_max>50)
- state->retry_max=50;
+ state->retry_max = 50;
/* Compute the re-ACK interval to suit the timeout */
state->retry_time = (int)(timeout/state->retry_max);
if(state->retry_time<1)
- state->retry_time=1;
+ state->retry_time = 1;
infof(state->conn->data,
"set timeouts for state %d; Total %ld, retry %d maxtry %d\n",
@@ -321,7 +321,7 @@ static const char *tftp_option_get(const char *buf, size_t len,
return NULL;
*option = buf;
- loc += Curl_strnlen(buf+loc, len-loc);
+ loc += Curl_strnlen(buf + loc, len-loc);
loc++; /* NULL term */
if(loc > len)
@@ -475,7 +475,7 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
/* If we are uploading, send an WRQ */
setpacketevent(&state->spacket, TFTP_EVENT_WRQ);
state->conn->data->req.upload_fromhere =
- (char *)state->spacket.data+4;
+ (char *)state->spacket.data + 4;
if(data->state.infilesize != -1)
Curl_pgrsSetUploadSize(data, data->state.infilesize);
}
@@ -493,10 +493,11 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
if(strlen(filename) > (state->blksize - strlen(mode) - 4)) {
failf(data, "TFTP file name too long\n");
+ free(filename);
return CURLE_TFTP_ILLEGAL; /* too long file name field */
}
- snprintf((char *)state->spacket.data+2,
+ snprintf((char *)state->spacket.data + 2,
state->blksize,
"%s%c%s%c", filename, '\0', mode, '\0');
sbytes = 4 + strlen(filename) + strlen(mode);
@@ -511,25 +512,25 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
strcpy(buf, "0"); /* the destination is large enough */
sbytes += tftp_option_add(state, sbytes,
- (char *)state->spacket.data+sbytes,
+ (char *)state->spacket.data + sbytes,
TFTP_OPTION_TSIZE);
sbytes += tftp_option_add(state, sbytes,
- (char *)state->spacket.data+sbytes, buf);
+ (char *)state->spacket.data + sbytes, buf);
/* add blksize option */
snprintf(buf, sizeof(buf), "%d", state->requested_blksize);
sbytes += tftp_option_add(state, sbytes,
- (char *)state->spacket.data+sbytes,
+ (char *)state->spacket.data + sbytes,
TFTP_OPTION_BLKSIZE);
sbytes += tftp_option_add(state, sbytes,
- (char *)state->spacket.data+sbytes, buf);
+ (char *)state->spacket.data + sbytes, buf);
/* add timeout option */
snprintf(buf, sizeof(buf), "%d", state->retry_time);
sbytes += tftp_option_add(state, sbytes,
- (char *)state->spacket.data+sbytes,
+ (char *)state->spacket.data + sbytes,
TFTP_OPTION_INTERVAL);
sbytes += tftp_option_add(state, sbytes,
- (char *)state->spacket.data+sbytes, buf);
+ (char *)state->spacket.data + sbytes, buf);
}
/* the typecase for the 3rd argument is mostly for systems that do
@@ -575,7 +576,7 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
/* the next blocknum is x + 1 but it needs to wrap at an unsigned 16bit
boundary */
-#define NEXT_BLOCKNUM(x) (((x)+1)&0xffff)
+#define NEXT_BLOCKNUM(x) (((x) + 1)&0xffff)
/**********************************************************
*
@@ -626,7 +627,7 @@ static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event)
}
/* Check if completed (That is, a less than full packet is received) */
- if(state->rbytes < (ssize_t)state->blksize+4) {
+ if(state->rbytes < (ssize_t)state->blksize + 4) {
state->state = TFTP_STATE_FIN;
}
else {
@@ -742,7 +743,7 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event)
else {
/* Re-send the data packet */
sbytes = sendto(state->sockfd, (void *)state->spacket.data,
- 4+state->sbytes, SEND_4TH_ARG,
+ 4 + state->sbytes, SEND_4TH_ARG,
(struct sockaddr *)&state->remote_addr,
state->remote_addrlen);
/* Check all sbytes were sent */
@@ -775,7 +776,7 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event)
* data block.
* */
state->sbytes = 0;
- state->conn->data->req.upload_fromhere = (char *)state->spacket.data+4;
+ state->conn->data->req.upload_fromhere = (char *)state->spacket.data + 4;
do {
result = Curl_fillreadbuffer(state->conn, state->blksize - state->sbytes,
&cb);
@@ -812,7 +813,7 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event)
else {
/* Re-send the data packet */
sbytes = sendto(state->sockfd, (void *)state->spacket.data,
- 4+state->sbytes, SEND_4TH_ARG,
+ 4 + state->sbytes, SEND_4TH_ARG,
(struct sockaddr *)&state->remote_addr,
state->remote_addrlen);
/* Check all sbytes were sent */
@@ -1108,11 +1109,11 @@ static CURLcode tftp_receive_packet(struct connectdata *conn)
fromlen = sizeof(fromaddr);
state->rbytes = (int)recvfrom(state->sockfd,
(void *)state->rpacket.data,
- state->blksize+4,
+ state->blksize + 4,
0,
(struct sockaddr *)&fromaddr,
&fromlen);
- if(state->remote_addrlen==0) {
+ if(state->remote_addrlen == 0) {
memcpy(&state->remote_addr, &fromaddr, fromlen);
state->remote_addrlen = fromlen;
}
@@ -1134,7 +1135,7 @@ static CURLcode tftp_receive_packet(struct connectdata *conn)
if(state->rbytes > 4 &&
(NEXT_BLOCKNUM(state->block) == getrpacketblock(&state->rpacket))) {
result = Curl_client_write(conn, CLIENTWRITE_BODY,
- (char *)state->rpacket.data+4,
+ (char *)state->rpacket.data + 4,
state->rbytes-4);
if(result) {
tftp_state_machine(state, TFTP_EVENT_ERROR);
@@ -1148,14 +1149,14 @@ static CURLcode tftp_receive_packet(struct connectdata *conn)
{
unsigned short error = getrpacketblock(&state->rpacket);
state->error = (tftp_error_t)error;
- infof(data, "%s\n", (const char *)state->rpacket.data+4);
+ infof(data, "%s\n", (const char *)state->rpacket.data + 4);
break;
}
case TFTP_EVENT_ACK:
break;
case TFTP_EVENT_OACK:
result = tftp_parse_option_ack(state,
- (const char *)state->rpacket.data+2,
+ (const char *)state->rpacket.data + 2,
state->rbytes-2);
if(result)
return result;
@@ -1199,7 +1200,7 @@ static long tftp_state_timeout(struct connectdata *conn, tftp_event_t *event)
state->state = TFTP_STATE_FIN;
return 0;
}
- if(current > state->rx_time+state->retry_time) {
+ if(current > state->rx_time + state->retry_time) {
if(event)
*event = TFTP_EVENT_TIMEOUT;
time(&state->rx_time); /* update even though we received nothing */
@@ -1292,7 +1293,7 @@ static CURLcode tftp_doing(struct connectdata *conn, bool *dophase_done)
if(Curl_pgrsUpdate(conn))
result = CURLE_ABORTED_BY_CALLBACK;
else
- result = Curl_speedcheck(conn->data, Curl_tvnow());
+ result = Curl_speedcheck(conn->data, Curl_now());
}
return result;
}
diff --git a/lib/timeval.c b/lib/timeval.c
index d7207b3a..66f923a8 100644
--- a/lib/timeval.c
+++ b/lib/timeval.c
@@ -24,7 +24,7 @@
#if defined(WIN32) && !defined(MSDOS)
-struct curltime curlx_tvnow(void)
+struct curltime Curl_now(void)
{
/*
** GetTickCount() is available on _all_ Windows versions from W95 up
@@ -48,7 +48,7 @@ struct curltime curlx_tvnow(void)
#elif defined(HAVE_CLOCK_GETTIME_MONOTONIC)
-struct curltime curlx_tvnow(void)
+struct curltime Curl_now(void)
{
/*
** clock_gettime() is granted to be increased monotonically when the
@@ -84,9 +84,40 @@ struct curltime curlx_tvnow(void)
return cnow;
}
+#elif defined(HAVE_MACH_ABSOLUTE_TIME)
+
+#include <stdint.h>
+#include <mach/mach_time.h>
+
+struct curltime Curl_now(void)
+{
+ /*
+ ** Monotonic timer on Mac OS is provided by mach_absolute_time(), which
+ ** returns time in Mach "absolute time units," which are platform-dependent.
+ ** To convert to nanoseconds, one must use conversion factors specified by
+ ** mach_timebase_info().
+ */
+ static mach_timebase_info_data_t timebase;
+ struct curltime cnow;
+ uint64_t usecs;
+
+ if(0 == timebase.denom)
+ (void) mach_timebase_info(&timebase);
+
+ usecs = mach_absolute_time();
+ usecs *= timebase.numer;
+ usecs /= timebase.denom;
+ usecs /= 1000;
+
+ cnow.tv_sec = usecs / 1000000;
+ cnow.tv_usec = usecs % 1000000;
+
+ return cnow;
+}
+
#elif defined(HAVE_GETTIMEOFDAY)
-struct curltime curlx_tvnow(void)
+struct curltime Curl_now(void)
{
/*
** gettimeofday() is not granted to be increased monotonically, due to
@@ -103,7 +134,7 @@ struct curltime curlx_tvnow(void)
#else
-struct curltime curlx_tvnow(void)
+struct curltime Curl_now(void)
{
/*
** time() returns the value of time in seconds since the Epoch.
@@ -116,47 +147,40 @@ struct curltime curlx_tvnow(void)
#endif
+#if SIZEOF_TIME_T < 8
+#define TIME_MAX INT_MAX
+#define TIME_MIN INT_MIN
+#else
+#define TIME_MAX 9223372036854775807LL
+#define TIME_MIN -9223372036854775807LL
+#endif
+
/*
- * Make sure that the first argument is the more recent time, as otherwise
- * we'll get a weird negative time-diff back...
- *
- * Returns: the time difference in number of milliseconds. For large diffs it
- * returns 0x7fffffff on 32bit time_t systems.
+ * Returns: time difference in number of milliseconds. For too large diffs it
+ * returns max value.
*
* @unittest: 1323
*/
-time_t curlx_tvdiff(struct curltime newer, struct curltime older)
+timediff_t Curl_timediff(struct curltime newer, struct curltime older)
{
-#if SIZEOF_TIME_T < 8
- /* for 32bit time_t systems, add a precaution to avoid overflow for really
- big time differences */
- time_t diff = newer.tv_sec-older.tv_sec;
- if(diff >= (0x7fffffff/1000))
- return 0x7fffffff;
-#endif
- return (newer.tv_sec-older.tv_sec)*1000+
- (int)(newer.tv_usec-older.tv_usec)/1000;
+ timediff_t diff = newer.tv_sec-older.tv_sec;
+ if(diff >= (TIME_MAX/1000))
+ return TIME_MAX;
+ else if(diff <= (TIME_MIN/1000))
+ return TIME_MIN;
+ return diff * 1000 + (newer.tv_usec-older.tv_usec)/1000;
}
/*
- * Make sure that the first argument is the more recent time, as otherwise
- * we'll get a weird negative time-diff back...
- *
- * Returns: the time difference in number of microseconds. For too large diffs
- * it returns max value.
+ * Returns: time difference in number of microseconds. For too large diffs it
+ * returns max value.
*/
-time_t Curl_tvdiff_us(struct curltime newer, struct curltime older)
+timediff_t Curl_timediff_us(struct curltime newer, struct curltime older)
{
- time_t diff = newer.tv_sec-older.tv_sec;
-#if SIZEOF_TIME_T < 8
- /* for 32bit time_t systems */
- if(diff >= (0x7fffffff/1000000))
- return 0x7fffffff;
-#else
- /* for 64bit time_t systems */
- if(diff >= (0x7fffffffffffffffLL/1000000))
- return 0x7fffffffffffffffLL;
-#endif
- return (newer.tv_sec-older.tv_sec)*1000000+
- (int)(newer.tv_usec-older.tv_usec);
+ timediff_t diff = newer.tv_sec-older.tv_sec;
+ if(diff >= (TIME_MAX/1000000))
+ return TIME_MAX;
+ else if(diff <= (TIME_MIN/1000000))
+ return TIME_MIN;
+ return diff * 1000000 + newer.tv_usec-older.tv_usec;
}
diff --git a/lib/timeval.h b/lib/timeval.h
index 1ee4b304..fb3f680c 100644
--- a/lib/timeval.h
+++ b/lib/timeval.h
@@ -22,19 +22,20 @@
*
***************************************************************************/
-/*
- * CAUTION: this header is designed to work when included by the app-side
- * as well as the library. Do not mix with library internals!
- */
-
#include "curl_setup.h"
+#if SIZEOF_TIME_T < 8
+typedef int timediff_t;
+#else
+typedef curl_off_t timediff_t;
+#endif
+
struct curltime {
- time_t tv_sec; /* seconds */
- unsigned int tv_usec; /* microseconds */
+ time_t tv_sec; /* seconds */
+ int tv_usec; /* microseconds */
};
-struct curltime curlx_tvnow(void);
+struct curltime Curl_now(void);
/*
* Make sure that the first argument (t1) is the more recent time and t2 is
@@ -42,7 +43,7 @@ struct curltime curlx_tvnow(void);
*
* Returns: the time difference in number of milliseconds.
*/
-time_t curlx_tvdiff(struct curltime t1, struct curltime t2);
+timediff_t Curl_timediff(struct curltime t1, struct curltime t2);
/*
* Make sure that the first argument (t1) is the more recent time and t2 is
@@ -50,12 +51,6 @@ time_t curlx_tvdiff(struct curltime t1, struct curltime t2);
*
* Returns: the time difference in number of microseconds.
*/
-time_t Curl_tvdiff_us(struct curltime newer, struct curltime older);
-
-/* These two defines below exist to provide the older API for library
- internals only. */
-#define Curl_tvnow() curlx_tvnow()
-#define Curl_tvdiff(x,y) curlx_tvdiff(x,y)
+timediff_t Curl_timediff_us(struct curltime newer, struct curltime older);
#endif /* HEADER_CURL_TIMEVAL_H */
-
diff --git a/lib/transfer.c b/lib/transfer.c
index 3537b58c..8f15b1a1 100644
--- a/lib/transfer.c
+++ b/lib/transfer.c
@@ -73,12 +73,38 @@
#include "connect.h"
#include "non-ascii.h"
#include "http2.h"
+#include "mime.h"
+#include "strcase.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"
+#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_SMTP) || \
+ !defined(CURL_DISABLE_IMAP)
+/*
+ * checkheaders() checks the linked list of custom headers for a
+ * particular header (prefix).
+ *
+ * Returns a pointer to the first matching header or NULL if none matched.
+ */
+char *Curl_checkheaders(const struct connectdata *conn,
+ const char *thisheader)
+{
+ struct curl_slist *head;
+ size_t thislen = strlen(thisheader);
+ struct Curl_easy *data = conn->data;
+
+ for(head = data->set.headers; head; head = head->next) {
+ if(strncasecompare(head->data, thisheader, thislen))
+ return head->data;
+ }
+
+ return NULL;
+}
+#endif
+
/*
* This function will call the read callback to fill our buffer with data
* to upload.
@@ -195,27 +221,30 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp)
strlen(endofline_network));
#ifdef CURL_DOES_CONVERSIONS
- CURLcode result;
- int length;
- if(data->set.prefer_ascii) {
- /* translate the protocol and data */
- length = nread;
- }
- else {
- /* just translate the protocol portion */
- length = strlen(hexbuffer);
+ {
+ CURLcode result;
+ int length;
+ if(data->set.prefer_ascii)
+ /* translate the protocol and data */
+ length = nread;
+ else
+ /* just translate the protocol portion */
+ length = (int)strlen(hexbuffer);
+ result = Curl_convert_to_network(data, data->req.upload_fromhere,
+ length);
+ /* Curl_convert_to_network calls failf if unsuccessful */
+ if(result)
+ return result;
}
- result = Curl_convert_to_network(data, data->req.upload_fromhere, length);
- /* Curl_convert_to_network calls failf if unsuccessful */
- if(result)
- return result;
#endif /* CURL_DOES_CONVERSIONS */
- if((nread - hexlen) == 0)
+ if((nread - hexlen) == 0) {
/* mark this as done once this chunk is transferred */
data->req.upload_done = TRUE;
+ infof(data, "Signaling end of chunked upload via terminating chunk.\n");
+ }
- nread+=(int)strlen(endofline_native); /* for the added end of line */
+ nread += (int)strlen(endofline_native); /* for the added end of line */
}
#ifdef CURL_DOES_CONVERSIONS
else if((data->set.prefer_ascii) && (!sending_http_headers)) {
@@ -241,6 +270,7 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp)
CURLcode Curl_readrewind(struct connectdata *conn)
{
struct Curl_easy *data = conn->data;
+ curl_mimepart *mimepart = &data->set.mimepost;
conn->bits.rewindaftersend = FALSE; /* we rewind now */
@@ -253,9 +283,21 @@ CURLcode Curl_readrewind(struct connectdata *conn)
/* We have sent away data. If not using CURLOPT_POSTFIELDS or
CURLOPT_HTTPPOST, call app to rewind
*/
- if(data->set.postfields ||
- (data->set.httpreq == HTTPREQ_POST_FORM))
+ if(conn->handler->protocol & PROTO_FAMILY_HTTP) {
+ struct HTTP *http = data->req.protop;
+
+ if(http->sendit)
+ mimepart = http->sendit;
+ }
+ if(data->set.postfields)
; /* do nothing */
+ else if(data->set.httpreq == HTTPREQ_POST_MIME ||
+ data->set.httpreq == HTTPREQ_POST_FORM) {
+ if(Curl_mime_rewind(mimepart)) {
+ failf(data, "Cannot rewind mime/post data");
+ return CURLE_SEND_FAIL_REWIND;
+ }
+ }
else {
if(data->set.seek_func) {
int err;
@@ -450,7 +492,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
Curl_pgrsTime(data, TIMER_STARTTRANSFER);
if(k->exp100 > EXP100_SEND_DATA)
/* set time stamp to compare with when waiting for the 100 */
- k->start100 = Curl_tvnow();
+ k->start100 = Curl_now();
}
*didwhat |= KEEP_RECV;
@@ -560,7 +602,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
infof(data, "Ignoring the response-body\n");
}
if(data->state.resume_from && !k->content_range &&
- (data->set.httpreq==HTTPREQ_GET) &&
+ (data->set.httpreq == HTTPREQ_GET) &&
!k->ignorebody) {
if(k->size == data->state.resume_from) {
@@ -737,48 +779,19 @@ static CURLcode readwrite_data(struct Curl_easy *data,
in http_chunks.c.
Make sure that ALL_CONTENT_ENCODINGS contains all the
encodings handled here. */
-#ifdef HAVE_LIBZ
- switch(conn->data->set.http_ce_skip ?
- IDENTITY : k->auto_decoding) {
- case IDENTITY:
-#endif
- /* This is the default when the server sends no
- Content-Encoding header. See Curl_readwrite_init; the
- memset() call initializes k->auto_decoding to zero. */
+ if(conn->data->set.http_ce_skip || !k->writer_stack) {
if(!k->ignorebody) {
-
#ifndef CURL_DISABLE_POP3
- if(conn->handler->protocol&PROTO_FAMILY_POP3)
+ if(conn->handler->protocol & PROTO_FAMILY_POP3)
result = Curl_pop3_write(conn, k->str, nread);
else
#endif /* CURL_DISABLE_POP3 */
-
result = Curl_client_write(conn, CLIENTWRITE_BODY, k->str,
nread);
}
-#ifdef HAVE_LIBZ
- break;
-
- case DEFLATE:
- /* Assume CLIENTWRITE_BODY; headers are not encoded. */
- if(!k->ignorebody)
- result = Curl_unencode_deflate_write(conn, k, nread);
- break;
-
- case GZIP:
- /* Assume CLIENTWRITE_BODY; headers are not encoded. */
- if(!k->ignorebody)
- result = Curl_unencode_gzip_write(conn, k, nread);
- break;
-
- default:
- failf(data, "Unrecognized content encoding type. "
- "libcurl understands `identity', `deflate' and `gzip' "
- "content encodings.");
- result = CURLE_BAD_CONTENT_ENCODING;
- break;
}
-#endif
+ else
+ result = Curl_unencode_write(conn, k->writer_stack, k->str, nread);
}
k->badheader = HEADER_NORMAL; /* taken care of now */
@@ -885,7 +898,7 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
go into the Expect: 100 state and await such a header */
k->exp100 = EXP100_AWAITING_CONTINUE; /* wait for the header */
k->keepon &= ~KEEP_SEND; /* disable writing */
- k->start100 = Curl_tvnow(); /* timeout count starts now */
+ k->start100 = Curl_now(); /* timeout count starts now */
*didwhat &= ~KEEP_SEND; /* we didn't write anything actually */
/* set a timeout for the multi interface */
@@ -915,7 +928,7 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
/* this is a paused transfer */
break;
}
- if(nread<=0) {
+ if(nread <= 0) {
result = done_sending(conn, k);
if(result)
return result;
@@ -1006,7 +1019,8 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
k->writebytecount += bytes_written;
- if(k->writebytecount == data->state.infilesize) {
+ if((!k->upload_chunky || k->forbidchunk) &&
+ (k->writebytecount == data->state.infilesize)) {
/* we have sent all data we were supposed to */
k->upload_done = TRUE;
infof(data, "We are completely uploaded and fine\n");
@@ -1055,7 +1069,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
{
struct SingleRequest *k = &data->req;
CURLcode result;
- int didwhat=0;
+ int didwhat = 0;
curl_socket_t fd_read;
curl_socket_t fd_write;
@@ -1110,7 +1124,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
return result;
}
- k->now = Curl_tvnow();
+ k->now = Curl_now();
if(didwhat) {
/* Update read/write counters */
if(k->bytecountp)
@@ -1134,7 +1148,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
*/
- time_t ms = Curl_tvdiff(k->now, k->start100);
+ timediff_t ms = Curl_timediff(k->now, k->start100);
if(ms >= data->set.expect_100_timeout) {
/* we've waited long enough, continue anyway */
k->exp100 = EXP100_SEND_DATA;
@@ -1158,13 +1172,14 @@ CURLcode Curl_readwrite(struct connectdata *conn,
failf(data, "Operation timed out after %ld milliseconds with %"
CURL_FORMAT_CURL_OFF_T " out of %"
CURL_FORMAT_CURL_OFF_T " bytes received",
- Curl_tvdiff(k->now, data->progress.t_startsingle), k->bytecount,
- k->size);
+ Curl_timediff(k->now, data->progress.t_startsingle),
+ k->bytecount, k->size);
}
else {
failf(data, "Operation timed out after %ld milliseconds with %"
CURL_FORMAT_CURL_OFF_T " bytes received",
- Curl_tvdiff(k->now, data->progress.t_startsingle), k->bytecount);
+ Curl_timediff(k->now, data->progress.t_startsingle),
+ k->bytecount);
}
return CURLE_OPERATION_TIMEDOUT;
}
@@ -1303,7 +1318,8 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
if(result)
return result;
- data->set.followlocation=0; /* reset the location-follow counter */
+ data->state.wildcardmatch = data->set.wildcard_enabled;
+ data->set.followlocation = 0; /* reset the location-follow counter */
data->state.this_is_a_follow = FALSE; /* reset this */
data->state.errorbuf = FALSE; /* no error has occurred */
data->state.httpversion = 0; /* don't assume any particular server version */
@@ -1345,7 +1361,7 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
#endif
Curl_initinfo(data); /* reset session-specific information "variables" */
- Curl_pgrsResetTimesSizes(data);
+ Curl_pgrsResetTransferSizes(data);
Curl_pgrsStartNow(data);
if(data->set.timeout)
@@ -1360,7 +1376,7 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
data->state.authhost.picked &= data->state.authhost.want;
data->state.authproxy.picked &= data->state.authproxy.want;
- if(data->set.wildcardmatch) {
+ if(data->state.wildcardmatch) {
struct WildcardData *wc = &data->wildcard;
if(wc->state < CURLWC_INIT) {
result = Curl_wildcard_init(wc); /* init wildcard structures */
@@ -1427,14 +1443,14 @@ static const char *find_host_sep(const char *url)
static size_t strlen_url(const char *url, bool relative)
{
const unsigned char *ptr;
- size_t newlen=0;
- bool left=TRUE; /* left side of the ? */
+ size_t newlen = 0;
+ bool left = TRUE; /* left side of the ? */
const unsigned char *host_sep = (const unsigned char *) url;
if(!relative)
host_sep = (const unsigned char *) find_host_sep(url);
- for(ptr=(unsigned char *)url; *ptr; ptr++) {
+ for(ptr = (unsigned char *)url; *ptr; ptr++) {
if(ptr < host_sep) {
++newlen;
@@ -1443,7 +1459,7 @@ static size_t strlen_url(const char *url, bool relative)
switch(*ptr) {
case '?':
- left=FALSE;
+ left = FALSE;
/* fall through */
default:
if(*ptr >= 0x80)
@@ -1452,7 +1468,7 @@ static size_t strlen_url(const char *url, bool relative)
break;
case ' ':
if(left)
- newlen+=3;
+ newlen += 3;
else
newlen++;
break;
@@ -1469,7 +1485,7 @@ static size_t strlen_url(const char *url, bool relative)
static void strcpy_url(char *output, const char *url, bool relative)
{
/* we must add this with whitespace-replacing */
- bool left=TRUE;
+ bool left = TRUE;
const unsigned char *iptr;
char *optr = output;
const unsigned char *host_sep = (const unsigned char *) url;
@@ -1488,7 +1504,7 @@ static void strcpy_url(char *output, const char *url, bool relative)
switch(*iptr) {
case '?':
- left=FALSE;
+ left = FALSE;
/* fall through */
default:
if(*iptr >= 0x80) {
@@ -1509,7 +1525,7 @@ static void strcpy_url(char *output, const char *url, bool relative)
break;
}
}
- *optr=0; /* zero terminate output buffer */
+ *optr = 0; /* zero terminate output buffer */
}
@@ -1548,26 +1564,26 @@ static char *concat_url(const char *base, const char *relurl)
/* we must make our own copy of the URL to play with, as it may
point to read-only data */
- char *url_clone=strdup(base);
+ char *url_clone = strdup(base);
if(!url_clone)
return NULL; /* skip out of this NOW */
/* protsep points to the start of the host name */
- protsep=strstr(url_clone, "//");
+ protsep = strstr(url_clone, "//");
if(!protsep)
- protsep=url_clone;
+ protsep = url_clone;
else
- protsep+=2; /* pass the slashes */
+ protsep += 2; /* pass the slashes */
if('/' != relurl[0]) {
- int level=0;
+ int level = 0;
/* First we need to find out if there's a ?-letter in the URL,
and cut it and the right-side of that off */
pathsep = strchr(protsep, '?');
if(pathsep)
- *pathsep=0;
+ *pathsep = 0;
/* we have a relative path to append to the last slash if there's one
available, or if the new URL is just a query string (starts with a
@@ -1576,14 +1592,14 @@ static char *concat_url(const char *base, const char *relurl)
if(useurl[0] != '?') {
pathsep = strrchr(protsep, '/');
if(pathsep)
- *pathsep=0;
+ *pathsep = 0;
}
/* Check if there's any slash after the host name, and if so, remember
that position instead */
pathsep = strchr(protsep, '/');
if(pathsep)
- protsep = pathsep+1;
+ protsep = pathsep + 1;
else
protsep = NULL;
@@ -1591,13 +1607,13 @@ static char *concat_url(const char *base, const char *relurl)
and act accordingly */
if((useurl[0] == '.') && (useurl[1] == '/'))
- useurl+=2; /* just skip the "./" */
+ useurl += 2; /* just skip the "./" */
while((useurl[0] == '.') &&
(useurl[1] == '.') &&
(useurl[2] == '/')) {
level++;
- useurl+=3; /* pass the "../" */
+ useurl += 3; /* pass the "../" */
}
if(protsep) {
@@ -1605,9 +1621,9 @@ static char *concat_url(const char *base, const char *relurl)
/* cut off one more level from the right of the original URL */
pathsep = strrchr(protsep, '/');
if(pathsep)
- *pathsep=0;
+ *pathsep = 0;
else {
- *protsep=0;
+ *protsep = 0;
break;
}
}
@@ -1619,7 +1635,7 @@ static char *concat_url(const char *base, const char *relurl)
if((relurl[0] == '/') && (relurl[1] == '/')) {
/* the new URL starts with //, just keep the protocol part from the
original one */
- *protsep=0;
+ *protsep = 0;
useurl = &relurl[2]; /* we keep the slashes from the original, so we
skip the new ones */
host_changed = TRUE;
@@ -1635,7 +1651,7 @@ static char *concat_url(const char *base, const char *relurl)
char *sep = strchr(protsep, '?');
if(sep && (sep < pathsep))
pathsep = sep;
- *pathsep=0;
+ *pathsep = 0;
}
else {
/* There was no slash. Now, since we might be operating on a badly
@@ -1644,7 +1660,7 @@ static char *concat_url(const char *base, const char *relurl)
?-letter as well! */
pathsep = strchr(protsep, '?');
if(pathsep)
- *pathsep=0;
+ *pathsep = 0;
}
}
}
@@ -1735,7 +1751,7 @@ CURLcode Curl_follow(struct Curl_easy *data,
}
}
- if(!is_absolute_url(newurl)) {
+ if(!is_absolute_url(newurl)) {
/***
*DANG* this is an RFC 2068 violation. The URL is supposed
to be absolute and this doesn't seem to be that!
@@ -1754,7 +1770,7 @@ CURLcode Curl_follow(struct Curl_easy *data,
/* This is an absolute URL, don't allow the custom port number */
disallowport = TRUE;
- newest = malloc(newlen+1); /* get memory for this */
+ newest = malloc(newlen + 1); /* get memory for this */
if(!newest)
return CURLE_OUT_OF_MEMORY;
@@ -1826,7 +1842,8 @@ CURLcode Curl_follow(struct Curl_easy *data,
* can be overridden with CURLOPT_POSTREDIR.
*/
if((data->set.httpreq == HTTPREQ_POST
- || data->set.httpreq == HTTPREQ_POST_FORM)
+ || data->set.httpreq == HTTPREQ_POST_FORM
+ || data->set.httpreq == HTTPREQ_POST_MIME)
&& !(data->set.keep_post & CURL_REDIR_POST_301)) {
infof(data, "Switch from POST to GET\n");
data->set.httpreq = HTTPREQ_GET;
@@ -1850,7 +1867,8 @@ CURLcode Curl_follow(struct Curl_easy *data,
* can be overridden with CURLOPT_POSTREDIR.
*/
if((data->set.httpreq == HTTPREQ_POST
- || data->set.httpreq == HTTPREQ_POST_FORM)
+ || data->set.httpreq == HTTPREQ_POST_FORM
+ || data->set.httpreq == HTTPREQ_POST_MIME)
&& !(data->set.keep_post & CURL_REDIR_POST_302)) {
infof(data, "Switch from POST to GET\n");
data->set.httpreq = HTTPREQ_GET;
@@ -1883,7 +1901,7 @@ CURLcode Curl_follow(struct Curl_easy *data,
break;
}
Curl_pgrsTime(data, TIMER_REDIRECT);
- Curl_pgrsResetTimesSizes(data);
+ Curl_pgrsResetTransferSizes(data);
return CURLE_OK;
#endif /* CURL_DISABLE_HTTP */
@@ -2007,7 +2025,7 @@ Curl_setup_transfer(
(http->sending == HTTPSEND_BODY)) {
/* wait with write until we either got 100-continue or a timeout */
k->exp100 = EXP100_AWAITING_CONTINUE;
- k->start100 = Curl_tvnow();
+ k->start100 = Curl_now();
/* Set a timeout for the multi interface. Add the inaccuracy margin so
that we don't fire slightly too early and get denied to run. */
diff --git a/lib/transfer.h b/lib/transfer.h
index 51896726..72526a83 100644
--- a/lib/transfer.h
+++ b/lib/transfer.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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,9 @@
*
***************************************************************************/
+char *Curl_checkheaders(const struct connectdata *conn,
+ const char *thisheader);
+
void Curl_init_CONNECT(struct Curl_easy *data);
CURLcode Curl_pretransfer(struct Curl_easy *data);
diff --git a/lib/url.c b/lib/url.c
index 71d4d8bb..47f69c9f 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -71,6 +71,7 @@ bool curl_win32_idn_to_ascii(const char *in, char **out);
#include "netrc.h"
#include "formdata.h"
+#include "mime.h"
#include "vtls/vtls.h"
#include "hostip.h"
#include "transfer.h"
@@ -119,6 +120,8 @@ bool curl_win32_idn_to_ascii(const char *in, char **out);
#include "pipeline.h"
#include "dotdot.h"
#include "strdup.h"
+#include "setopt.h"
+
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
@@ -135,15 +138,8 @@ static CURLcode parse_url_login(struct Curl_easy *data,
struct connectdata *conn,
char **userptr, char **passwdptr,
char **optionsptr);
-static CURLcode parse_login_details(const char *login, const size_t len,
- char **userptr, char **passwdptr,
- char **optionsptr);
static unsigned int get_protocol_family(unsigned int protocol);
-#define READBUFFER_SIZE CURL_MAX_WRITE_SIZE
-#define READBUFFER_MAX CURL_MAX_READ_SIZE
-#define READBUFFER_MIN 1024
-
/* Some parts of the code (e.g. chunked encoding) assume this buffer has at
* more than just a few bytes to play with. Don't let it become too small or
* bad things will happen.
@@ -284,7 +280,7 @@ void Curl_freeset(struct Curl_easy *data)
{
/* Free all dynamic strings stored in the data->set substructure. */
enum dupstring i;
- for(i=(enum dupstring)0; i < STRING_LAST; i++) {
+ for(i = (enum dupstring)0; i < STRING_LAST; i++) {
Curl_safefree(data->set.str[i]);
}
@@ -300,98 +296,6 @@ void Curl_freeset(struct Curl_easy *data)
data->change.url = NULL;
}
-static CURLcode setstropt(char **charp, const char *s)
-{
- /* Release the previous storage at `charp' and replace by a dynamic storage
- copy of `s'. Return CURLE_OK or CURLE_OUT_OF_MEMORY. */
-
- Curl_safefree(*charp);
-
- if(s) {
- char *str = strdup(s);
-
- if(!str)
- return CURLE_OUT_OF_MEMORY;
-
- *charp = str;
- }
-
- return CURLE_OK;
-}
-
-static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp)
-{
- CURLcode result = CURLE_OK;
- char *user = NULL;
- char *passwd = NULL;
-
- /* Parse the login details if specified. It not then we treat NULL as a hint
- to clear the existing data */
- if(option) {
- result = parse_login_details(option, strlen(option),
- (userp ? &user : NULL),
- (passwdp ? &passwd : NULL),
- NULL);
- }
-
- if(!result) {
- /* Store the username part of option if required */
- if(userp) {
- if(!user && option && option[0] == ':') {
- /* Allocate an empty string instead of returning NULL as user name */
- user = strdup("");
- if(!user)
- result = CURLE_OUT_OF_MEMORY;
- }
-
- Curl_safefree(*userp);
- *userp = user;
- }
-
- /* Store the password part of option if required */
- if(passwdp) {
- Curl_safefree(*passwdp);
- *passwdp = passwd;
- }
- }
-
- return result;
-}
-
-CURLcode Curl_dupset(struct Curl_easy *dst, struct Curl_easy *src)
-{
- CURLcode result = CURLE_OK;
- enum dupstring i;
-
- /* Copy src->set into dst->set first, then deal with the strings
- afterwards */
- dst->set = src->set;
-
- /* clear all string pointers first */
- memset(dst->set.str, 0, STRING_LAST * sizeof(char *));
-
- /* duplicate all strings */
- for(i=(enum dupstring)0; i< STRING_LASTZEROTERMINATED; i++) {
- result = setstropt(&dst->set.str[i], src->set.str[i]);
- if(result)
- return result;
- }
-
- /* duplicate memory areas pointed to */
- i = STRING_COPYPOSTFIELDS;
- if(src->set.postfieldsize && src->set.str[i]) {
- /* postfieldsize is curl_off_t, Curl_memdup() takes a size_t ... */
- dst->set.str[i] = Curl_memdup(src->set.str[i],
- curlx_sotouz(src->set.postfieldsize));
- if(!dst->set.str[i])
- return CURLE_OUT_OF_MEMORY;
- /* point to the new copy */
- dst->set.postfields = dst->set.str[i];
- }
-
- return CURLE_OK;
-}
-
/*
* This is the internal function curl_easy_cleanup() calls. This should
* cleanup and free all resources associated with this sessionhandle.
@@ -479,6 +383,8 @@ CURLcode Curl_close(struct Curl_easy *data)
Curl_http2_cleanup_dependencies(data);
Curl_convert_close(data);
+ Curl_mime_cleanpart(&data->set.mimepost);
+
/* No longer a dirty share, if it exists */
if(data->share) {
Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
@@ -486,12 +392,8 @@ CURLcode Curl_close(struct Curl_easy *data)
Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
}
- if(data->set.wildcardmatch) {
- /* destruct wildcard structures if it is needed */
- struct WildcardData *wc = &data->wildcard;
- Curl_wildcard_dtor(wc);
- }
-
+ /* destruct wildcard structures if it is needed */
+ Curl_wildcard_dtor(&data->wildcard);
Curl_freeset(data);
free(data);
return CURLE_OK;
@@ -588,25 +490,25 @@ CURLcode Curl_init_userdefined(struct UserDefined *set)
/* This is our preferred CA cert bundle/path since install time */
#if defined(CURL_CA_BUNDLE)
- result = setstropt(&set->str[STRING_SSL_CAFILE_ORIG], CURL_CA_BUNDLE);
+ result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_ORIG], CURL_CA_BUNDLE);
if(result)
return result;
- result = setstropt(&set->str[STRING_SSL_CAFILE_PROXY], CURL_CA_BUNDLE);
+ result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_PROXY], CURL_CA_BUNDLE);
if(result)
return result;
#endif
#if defined(CURL_CA_PATH)
- result = setstropt(&set->str[STRING_SSL_CAPATH_ORIG], CURL_CA_PATH);
+ result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_ORIG], CURL_CA_PATH);
if(result)
return result;
- result = setstropt(&set->str[STRING_SSL_CAPATH_PROXY], CURL_CA_PATH);
+ result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_PROXY], CURL_CA_PATH);
if(result)
return result;
#endif
- set->wildcardmatch = FALSE;
+ set->wildcard_enabled = FALSE;
set->chunk_bgn = ZERO_NULL;
set->chunk_end = ZERO_NULL;
@@ -667,30 +569,31 @@ CURLcode Curl_open(struct Curl_easy **curl)
DEBUGF(fprintf(stderr, "Error: malloc of buffer failed\n"));
result = CURLE_OUT_OF_MEMORY;
}
-
- data->state.headerbuff = malloc(HEADERSIZE);
- if(!data->state.headerbuff) {
- DEBUGF(fprintf(stderr, "Error: malloc of headerbuff failed\n"));
- result = CURLE_OUT_OF_MEMORY;
- }
else {
- result = Curl_init_userdefined(&data->set);
-
- data->state.headersize=HEADERSIZE;
+ Curl_mime_initpart(&data->set.mimepost, data);
- Curl_convert_init(data);
+ data->state.headerbuff = malloc(HEADERSIZE);
+ if(!data->state.headerbuff) {
+ DEBUGF(fprintf(stderr, "Error: malloc of headerbuff failed\n"));
+ result = CURLE_OUT_OF_MEMORY;
+ }
+ else {
+ result = Curl_init_userdefined(&data->set);
- Curl_initinfo(data);
+ data->state.headersize = HEADERSIZE;
+ Curl_convert_init(data);
+ Curl_initinfo(data);
- /* most recent connection is not yet defined */
- data->state.lastconnect = NULL;
+ /* most recent connection is not yet defined */
+ data->state.lastconnect = NULL;
- data->progress.flags |= PGRS_HIDE;
- data->state.current_speed = -1; /* init to negative == impossible */
- data->set.fnmatch = ZERO_NULL;
- data->set.maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */
+ data->progress.flags |= PGRS_HIDE;
+ data->state.current_speed = -1; /* init to negative == impossible */
+ data->set.fnmatch = ZERO_NULL;
+ data->set.maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */
- Curl_http2_init_state(&data->state);
+ Curl_http2_init_state(&data->state);
+ }
}
if(result) {
@@ -707,2244 +610,6 @@ CURLcode Curl_open(struct Curl_easy **curl)
return result;
}
-#define C_SSLVERSION_VALUE(x) (x & 0xffff)
-#define C_SSLVERSION_MAX_VALUE(x) (x & 0xffff0000)
-
-CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option,
- va_list param)
-{
- char *argptr;
- CURLcode result = CURLE_OK;
- long arg;
-#ifndef CURL_DISABLE_HTTP
- curl_off_t bigsize;
-#endif
-
- switch(option) {
- case CURLOPT_DNS_CACHE_TIMEOUT:
- data->set.dns_cache_timeout = va_arg(param, long);
- break;
- case CURLOPT_DNS_USE_GLOBAL_CACHE:
- /* remember we want this enabled */
- arg = va_arg(param, long);
- data->set.global_dns_cache = (0 != arg) ? TRUE : FALSE;
- break;
- case CURLOPT_SSL_CIPHER_LIST:
- /* set a list of cipher we want to use in the SSL connection */
- result = setstropt(&data->set.str[STRING_SSL_CIPHER_LIST_ORIG],
- va_arg(param, char *));
- break;
- case CURLOPT_PROXY_SSL_CIPHER_LIST:
- /* set a list of cipher we want to use in the SSL connection for proxy */
- result = setstropt(&data->set.str[STRING_SSL_CIPHER_LIST_PROXY],
- va_arg(param, char *));
- break;
-
- case CURLOPT_RANDOM_FILE:
- /*
- * This is the path name to a file that contains random data to seed
- * the random SSL stuff with. The file is only used for reading.
- */
- result = setstropt(&data->set.str[STRING_SSL_RANDOM_FILE],
- va_arg(param, char *));
- break;
- case CURLOPT_EGDSOCKET:
- /*
- * The Entropy Gathering Daemon socket pathname
- */
- result = setstropt(&data->set.str[STRING_SSL_EGDSOCKET],
- va_arg(param, char *));
- break;
- case CURLOPT_MAXCONNECTS:
- /*
- * Set the absolute number of maximum simultaneous alive connection that
- * libcurl is allowed to have.
- */
- data->set.maxconnects = va_arg(param, long);
- break;
- case CURLOPT_FORBID_REUSE:
- /*
- * When this transfer is done, it must not be left to be reused by a
- * subsequent transfer but shall be closed immediately.
- */
- data->set.reuse_forbid = (0 != va_arg(param, long)) ? TRUE : FALSE;
- break;
- case CURLOPT_FRESH_CONNECT:
- /*
- * This transfer shall not use a previously cached connection but
- * should be made with a fresh new connect!
- */
- data->set.reuse_fresh = (0 != va_arg(param, long)) ? TRUE : FALSE;
- break;
- case CURLOPT_VERBOSE:
- /*
- * Verbose means infof() calls that give a lot of information about
- * the connection and transfer procedures as well as internal choices.
- */
- data->set.verbose = (0 != va_arg(param, long)) ? TRUE : FALSE;
- break;
- case CURLOPT_HEADER:
- /*
- * Set to include the header in the general data output stream.
- */
- data->set.include_header = (0 != va_arg(param, long)) ? TRUE : FALSE;
- break;
- case CURLOPT_NOPROGRESS:
- /*
- * Shut off the internal supported progress meter
- */
- data->set.hide_progress = (0 != va_arg(param, long)) ? TRUE : FALSE;
- if(data->set.hide_progress)
- data->progress.flags |= PGRS_HIDE;
- else
- data->progress.flags &= ~PGRS_HIDE;
- break;
- case CURLOPT_NOBODY:
- /*
- * Do not include the body part in the output data stream.
- */
- data->set.opt_no_body = (0 != va_arg(param, long)) ? TRUE : FALSE;
- break;
- case CURLOPT_FAILONERROR:
- /*
- * Don't output the >=400 error code HTML-page, but instead only
- * return error.
- */
- data->set.http_fail_on_error = (0 != va_arg(param, long)) ? TRUE : FALSE;
- break;
- case CURLOPT_KEEP_SENDING_ON_ERROR:
- data->set.http_keep_sending_on_error = (0 != va_arg(param, long)) ?
- TRUE : FALSE;
- break;
- case CURLOPT_UPLOAD:
- case CURLOPT_PUT:
- /*
- * We want to sent data to the remote host. If this is HTTP, that equals
- * using the PUT request.
- */
- data->set.upload = (0 != va_arg(param, long)) ? TRUE : FALSE;
- if(data->set.upload) {
- /* If this is HTTP, PUT is what's needed to "upload" */
- data->set.httpreq = HTTPREQ_PUT;
- data->set.opt_no_body = FALSE; /* this is implied */
- }
- else
- /* In HTTP, the opposite of upload is GET (unless NOBODY is true as
- then this can be changed to HEAD later on) */
- data->set.httpreq = HTTPREQ_GET;
- break;
- case CURLOPT_REQUEST_TARGET:
- result = setstropt(&data->set.str[STRING_TARGET],
- va_arg(param, char *));
- break;
- case CURLOPT_FILETIME:
- /*
- * Try to get the file time of the remote document. The time will
- * later (possibly) become available using curl_easy_getinfo().
- */
- data->set.get_filetime = (0 != va_arg(param, long)) ? TRUE : FALSE;
- break;
- case CURLOPT_FTP_CREATE_MISSING_DIRS:
- /*
- * An FTP option that modifies an upload to create missing directories on
- * the server.
- */
- switch(va_arg(param, long)) {
- case 0:
- data->set.ftp_create_missing_dirs = 0;
- break;
- case 1:
- data->set.ftp_create_missing_dirs = 1;
- break;
- case 2:
- data->set.ftp_create_missing_dirs = 2;
- break;
- default:
- /* reserve other values for future use */
- result = CURLE_UNKNOWN_OPTION;
- break;
- }
- break;
- case CURLOPT_SERVER_RESPONSE_TIMEOUT:
- /*
- * Option that specifies how quickly an server response must be obtained
- * before it is considered failure. For pingpong protocols.
- */
- data->set.server_response_timeout = va_arg(param, long) * 1000;
- break;
- case CURLOPT_TFTP_NO_OPTIONS:
- /*
- * Option that prevents libcurl from sending TFTP option requests to the
- * server.
- */
- data->set.tftp_no_options = va_arg(param, long) != 0;
- break;
- case CURLOPT_TFTP_BLKSIZE:
- /*
- * TFTP option that specifies the block size to use for data transmission.
- */
- data->set.tftp_blksize = va_arg(param, long);
- break;
- case CURLOPT_DIRLISTONLY:
- /*
- * An option that changes the command to one that asks for a list
- * only, no file info details.
- */
- data->set.ftp_list_only = (0 != va_arg(param, long)) ? TRUE : FALSE;
- break;
- case CURLOPT_APPEND:
- /*
- * We want to upload and append to an existing file.
- */
- data->set.ftp_append = (0 != va_arg(param, long)) ? TRUE : FALSE;
- break;
- case CURLOPT_FTP_FILEMETHOD:
- /*
- * How do access files over FTP.
- */
- data->set.ftp_filemethod = (curl_ftpfile)va_arg(param, long);
- break;
- case CURLOPT_NETRC:
- /*
- * Parse the $HOME/.netrc file
- */
- data->set.use_netrc = (enum CURL_NETRC_OPTION)va_arg(param, long);
- break;
- case CURLOPT_NETRC_FILE:
- /*
- * Use this file instead of the $HOME/.netrc file
- */
- result = setstropt(&data->set.str[STRING_NETRC_FILE],
- va_arg(param, char *));
- break;
- case CURLOPT_TRANSFERTEXT:
- /*
- * This option was previously named 'FTPASCII'. Renamed to work with
- * more protocols than merely FTP.
- *
- * Transfer using ASCII (instead of BINARY).
- */
- data->set.prefer_ascii = (0 != va_arg(param, long)) ? TRUE : FALSE;
- break;
- case CURLOPT_TIMECONDITION:
- /*
- * Set HTTP time condition. This must be one of the defines in the
- * curl/curl.h header file.
- */
- data->set.timecondition = (curl_TimeCond)va_arg(param, long);
- break;
- case CURLOPT_TIMEVALUE:
- /*
- * This is the value to compare with the remote document with the
- * method set with CURLOPT_TIMECONDITION
- */
- data->set.timevalue = (time_t)va_arg(param, long);
- break;
- case CURLOPT_SSLVERSION:
- /*
- * Set explicit SSL version to try to connect with, as some SSL
- * implementations are lame.
- */
-#ifdef USE_SSL
- arg = va_arg(param, long);
- data->set.ssl.primary.version = C_SSLVERSION_VALUE(arg);
- data->set.ssl.primary.version_max = C_SSLVERSION_MAX_VALUE(arg);
-#else
- result = CURLE_UNKNOWN_OPTION;
-#endif
- break;
- case CURLOPT_PROXY_SSLVERSION:
- /*
- * Set explicit SSL version to try to connect with for proxy, as some SSL
- * implementations are lame.
- */
-#ifdef USE_SSL
- arg = va_arg(param, long);
- data->set.proxy_ssl.primary.version = C_SSLVERSION_VALUE(arg);
- data->set.proxy_ssl.primary.version_max = C_SSLVERSION_MAX_VALUE(arg);
-#else
- result = CURLE_UNKNOWN_OPTION;
-#endif
- break;
-
-#ifndef CURL_DISABLE_HTTP
- case CURLOPT_AUTOREFERER:
- /*
- * Switch on automatic referer that gets set if curl follows locations.
- */
- data->set.http_auto_referer = (0 != va_arg(param, long)) ? TRUE : FALSE;
- break;
-
- case CURLOPT_ACCEPT_ENCODING:
- /*
- * String to use at the value of Accept-Encoding header.
- *
- * If the encoding is set to "" we use an Accept-Encoding header that
- * encompasses all the encodings we support.
- * If the encoding is set to NULL we don't send an Accept-Encoding header
- * and ignore an received Content-Encoding header.
- *
- */
- argptr = va_arg(param, char *);
- result = setstropt(&data->set.str[STRING_ENCODING],
- (argptr && !*argptr)?
- ALL_CONTENT_ENCODINGS: argptr);
- break;
-
- case CURLOPT_TRANSFER_ENCODING:
- data->set.http_transfer_encoding = (0 != va_arg(param, long)) ?
- TRUE : FALSE;
- break;
-
- case CURLOPT_FOLLOWLOCATION:
- /*
- * Follow Location: header hints on a HTTP-server.
- */
- data->set.http_follow_location = (0 != va_arg(param, long)) ? TRUE : FALSE;
- break;
-
- case CURLOPT_UNRESTRICTED_AUTH:
- /*
- * Send authentication (user+password) when following locations, even when
- * hostname changed.
- */
- data->set.http_disable_hostname_check_before_authentication =
- (0 != va_arg(param, long)) ? TRUE : FALSE;
- break;
-
- case CURLOPT_MAXREDIRS:
- /*
- * The maximum amount of hops you allow curl to follow Location:
- * headers. This should mostly be used to detect never-ending loops.
- */
- data->set.maxredirs = va_arg(param, long);
- break;
-
- case CURLOPT_POSTREDIR:
- {
- /*
- * Set the behaviour of POST when redirecting
- * CURL_REDIR_GET_ALL - POST is changed to GET after 301 and 302
- * CURL_REDIR_POST_301 - POST is kept as POST after 301
- * CURL_REDIR_POST_302 - POST is kept as POST after 302
- * CURL_REDIR_POST_303 - POST is kept as POST after 303
- * CURL_REDIR_POST_ALL - POST is kept as POST after 301, 302 and 303
- * other - POST is kept as POST after 301 and 302
- */
- arg = va_arg(param, long);
- data->set.keep_post = arg & CURL_REDIR_POST_ALL;
- }
- break;
-
- case CURLOPT_POST:
- /* Does this option serve a purpose anymore? Yes it does, when
- CURLOPT_POSTFIELDS isn't used and the POST data is read off the
- callback! */
- if(va_arg(param, long)) {
- data->set.httpreq = HTTPREQ_POST;
- data->set.opt_no_body = FALSE; /* this is implied */
- }
- else
- data->set.httpreq = HTTPREQ_GET;
- break;
-
- case CURLOPT_COPYPOSTFIELDS:
- /*
- * A string with POST data. Makes curl HTTP POST. Even if it is NULL.
- * If needed, CURLOPT_POSTFIELDSIZE must have been set prior to
- * CURLOPT_COPYPOSTFIELDS and not altered later.
- */
- argptr = va_arg(param, char *);
-
- if(!argptr || data->set.postfieldsize == -1)
- result = setstropt(&data->set.str[STRING_COPYPOSTFIELDS], argptr);
- else {
- /*
- * Check that requested length does not overflow the size_t type.
- */
-
- if((data->set.postfieldsize < 0) ||
- ((sizeof(curl_off_t) != sizeof(size_t)) &&
- (data->set.postfieldsize > (curl_off_t)((size_t)-1))))
- result = CURLE_OUT_OF_MEMORY;
- else {
- char *p;
-
- (void) setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
-
- /* Allocate even when size == 0. This satisfies the need of possible
- later address compare to detect the COPYPOSTFIELDS mode, and
- to mark that postfields is used rather than read function or
- form data.
- */
- p = malloc((size_t)(data->set.postfieldsize?
- data->set.postfieldsize:1));
-
- if(!p)
- result = CURLE_OUT_OF_MEMORY;
- else {
- if(data->set.postfieldsize)
- memcpy(p, argptr, (size_t)data->set.postfieldsize);
-
- data->set.str[STRING_COPYPOSTFIELDS] = p;
- }
- }
- }
-
- data->set.postfields = data->set.str[STRING_COPYPOSTFIELDS];
- data->set.httpreq = HTTPREQ_POST;
- break;
-
- case CURLOPT_POSTFIELDS:
- /*
- * Like above, but use static data instead of copying it.
- */
- data->set.postfields = va_arg(param, void *);
- /* Release old copied data. */
- (void) setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
- data->set.httpreq = HTTPREQ_POST;
- break;
-
- case CURLOPT_POSTFIELDSIZE:
- /*
- * The size of the POSTFIELD data to prevent libcurl to do strlen() to
- * figure it out. Enables binary posts.
- */
- bigsize = va_arg(param, long);
-
- if(data->set.postfieldsize < bigsize &&
- data->set.postfields == data->set.str[STRING_COPYPOSTFIELDS]) {
- /* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */
- (void) setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
- data->set.postfields = NULL;
- }
-
- data->set.postfieldsize = bigsize;
- break;
-
- case CURLOPT_POSTFIELDSIZE_LARGE:
- /*
- * The size of the POSTFIELD data to prevent libcurl to do strlen() to
- * figure it out. Enables binary posts.
- */
- bigsize = va_arg(param, curl_off_t);
-
- if(data->set.postfieldsize < bigsize &&
- data->set.postfields == data->set.str[STRING_COPYPOSTFIELDS]) {
- /* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */
- (void) setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
- data->set.postfields = NULL;
- }
-
- data->set.postfieldsize = bigsize;
- break;
-
- case CURLOPT_HTTPPOST:
- /*
- * Set to make us do HTTP POST
- */
- data->set.httppost = va_arg(param, struct curl_httppost *);
- data->set.httpreq = HTTPREQ_POST_FORM;
- data->set.opt_no_body = FALSE; /* this is implied */
- break;
-
- case CURLOPT_REFERER:
- /*
- * String to set in the HTTP Referer: field.
- */
- if(data->change.referer_alloc) {
- Curl_safefree(data->change.referer);
- data->change.referer_alloc = FALSE;
- }
- result = setstropt(&data->set.str[STRING_SET_REFERER],
- va_arg(param, char *));
- data->change.referer = data->set.str[STRING_SET_REFERER];
- break;
-
- case CURLOPT_USERAGENT:
- /*
- * String to use in the HTTP User-Agent field
- */
- result = setstropt(&data->set.str[STRING_USERAGENT],
- va_arg(param, char *));
- break;
-
- case CURLOPT_HTTPHEADER:
- /*
- * Set a list with HTTP headers to use (or replace internals with)
- */
- data->set.headers = va_arg(param, struct curl_slist *);
- break;
-
- case CURLOPT_PROXYHEADER:
- /*
- * Set a list with proxy headers to use (or replace internals with)
- *
- * Since CURLOPT_HTTPHEADER was the only way to set HTTP headers for a
- * long time we remain doing it this way until CURLOPT_PROXYHEADER is
- * used. As soon as this option has been used, if set to anything but
- * NULL, custom headers for proxies are only picked from this list.
- *
- * Set this option to NULL to restore the previous behavior.
- */
- data->set.proxyheaders = va_arg(param, struct curl_slist *);
- break;
-
- case CURLOPT_HEADEROPT:
- /*
- * Set header option.
- */
- arg = va_arg(param, long);
- data->set.sep_headers = (arg & CURLHEADER_SEPARATE)? TRUE: FALSE;
- break;
-
- case CURLOPT_HTTP200ALIASES:
- /*
- * Set a list of aliases for HTTP 200 in response header
- */
- data->set.http200aliases = va_arg(param, struct curl_slist *);
- break;
-
-#if !defined(CURL_DISABLE_COOKIES)
- case CURLOPT_COOKIE:
- /*
- * Cookie string to send to the remote server in the request.
- */
- result = setstropt(&data->set.str[STRING_COOKIE],
- va_arg(param, char *));
- break;
-
- case CURLOPT_COOKIEFILE:
- /*
- * Set cookie file to read and parse. Can be used multiple times.
- */
- argptr = (char *)va_arg(param, void *);
- if(argptr) {
- struct curl_slist *cl;
- /* append the cookie file name to the list of file names, and deal with
- them later */
- cl = curl_slist_append(data->change.cookielist, argptr);
- if(!cl) {
- curl_slist_free_all(data->change.cookielist);
- data->change.cookielist = NULL;
- return CURLE_OUT_OF_MEMORY;
- }
- data->change.cookielist = cl; /* store the list for later use */
- }
- break;
-
- case CURLOPT_COOKIEJAR:
- /*
- * Set cookie file name to dump all cookies to when we're done.
- */
- {
- struct CookieInfo *newcookies;
- result = setstropt(&data->set.str[STRING_COOKIEJAR],
- va_arg(param, char *));
-
- /*
- * Activate the cookie parser. This may or may not already
- * have been made.
- */
- newcookies = Curl_cookie_init(data, NULL, data->cookies,
- data->set.cookiesession);
- if(!newcookies)
- result = CURLE_OUT_OF_MEMORY;
- data->cookies = newcookies;
- }
- break;
-
- case CURLOPT_COOKIESESSION:
- /*
- * Set this option to TRUE to start a new "cookie session". It will
- * prevent the forthcoming read-cookies-from-file actions to accept
- * cookies that are marked as being session cookies, as they belong to a
- * previous session.
- *
- * In the original Netscape cookie spec, "session cookies" are cookies
- * with no expire date set. RFC2109 describes the same action if no
- * 'Max-Age' is set and RFC2965 includes the RFC2109 description and adds
- * a 'Discard' action that can enforce the discard even for cookies that
- * have a Max-Age.
- *
- * We run mostly with the original cookie spec, as hardly anyone implements
- * anything else.
- */
- data->set.cookiesession = (0 != va_arg(param, long)) ? TRUE : FALSE;
- break;
-
- case CURLOPT_COOKIELIST:
- argptr = va_arg(param, char *);
-
- if(argptr == NULL)
- break;
-
- if(strcasecompare(argptr, "ALL")) {
- /* clear all cookies */
- Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
- Curl_cookie_clearall(data->cookies);
- Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
- }
- else if(strcasecompare(argptr, "SESS")) {
- /* clear session cookies */
- Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
- Curl_cookie_clearsess(data->cookies);
- Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
- }
- else if(strcasecompare(argptr, "FLUSH")) {
- /* flush cookies to file, takes care of the locking */
- Curl_flush_cookies(data, 0);
- }
- else if(strcasecompare(argptr, "RELOAD")) {
- /* reload cookies from file */
- Curl_cookie_loadfiles(data);
- break;
- }
- else {
- if(!data->cookies)
- /* if cookie engine was not running, activate it */
- data->cookies = Curl_cookie_init(data, NULL, NULL, TRUE);
-
- argptr = strdup(argptr);
- if(!argptr || !data->cookies) {
- result = CURLE_OUT_OF_MEMORY;
- free(argptr);
- }
- else {
- Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
-
- if(checkprefix("Set-Cookie:", argptr))
- /* HTTP Header format line */
- Curl_cookie_add(data, data->cookies, TRUE, argptr + 11, NULL, NULL);
-
- else
- /* Netscape format line */
- Curl_cookie_add(data, data->cookies, FALSE, argptr, NULL, NULL);
-
- Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
- free(argptr);
- }
- }
-
- break;
-#endif /* CURL_DISABLE_COOKIES */
-
- case CURLOPT_HTTPGET:
- /*
- * Set to force us do HTTP GET
- */
- if(va_arg(param, long)) {
- data->set.httpreq = HTTPREQ_GET;
- data->set.upload = FALSE; /* switch off upload */
- data->set.opt_no_body = FALSE; /* this is implied */
- }
- break;
-
- case CURLOPT_HTTP_VERSION:
- /*
- * This sets a requested HTTP version to be used. The value is one of
- * the listed enums in curl/curl.h.
- */
- arg = va_arg(param, long);
-#ifndef USE_NGHTTP2
- if(arg >= CURL_HTTP_VERSION_2)
- return CURLE_UNSUPPORTED_PROTOCOL;
-#endif
- data->set.httpversion = arg;
- break;
-
- case CURLOPT_HTTPAUTH:
- /*
- * Set HTTP Authentication type BITMASK.
- */
- {
- int bitcheck;
- bool authbits;
- unsigned long auth = va_arg(param, unsigned long);
-
- if(auth == CURLAUTH_NONE) {
- data->set.httpauth = auth;
- break;
- }
-
- /* the DIGEST_IE bit is only used to set a special marker, for all the
- rest we need to handle it as normal DIGEST */
- data->state.authhost.iestyle = (auth & CURLAUTH_DIGEST_IE) ? TRUE : FALSE;
-
- if(auth & CURLAUTH_DIGEST_IE) {
- auth |= CURLAUTH_DIGEST; /* set standard digest bit */
- auth &= ~CURLAUTH_DIGEST_IE; /* unset ie digest bit */
- }
-
- /* switch off bits we can't support */
-#ifndef USE_NTLM
- auth &= ~CURLAUTH_NTLM; /* no NTLM support */
- auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */
-#elif !defined(NTLM_WB_ENABLED)
- auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */
-#endif
-#ifndef USE_SPNEGO
- auth &= ~CURLAUTH_NEGOTIATE; /* no Negotiate (SPNEGO) auth without
- GSS-API or SSPI */
-#endif
-
- /* check if any auth bit lower than CURLAUTH_ONLY is still set */
- bitcheck = 0;
- authbits = FALSE;
- while(bitcheck < 31) {
- if(auth & (1UL << bitcheck++)) {
- authbits = TRUE;
- break;
- }
- }
- if(!authbits)
- return CURLE_NOT_BUILT_IN; /* no supported types left! */
-
- data->set.httpauth = auth;
- }
- break;
-
- case CURLOPT_EXPECT_100_TIMEOUT_MS:
- /*
- * Time to wait for a response to a HTTP request containing an
- * Expect: 100-continue header before sending the data anyway.
- */
- data->set.expect_100_timeout = va_arg(param, long);
- break;
-
-#endif /* CURL_DISABLE_HTTP */
-
- case CURLOPT_CUSTOMREQUEST:
- /*
- * Set a custom string to use as request
- */
- result = setstropt(&data->set.str[STRING_CUSTOMREQUEST],
- va_arg(param, char *));
-
- /* we don't set
- data->set.httpreq = HTTPREQ_CUSTOM;
- here, we continue as if we were using the already set type
- and this just changes the actual request keyword */
- break;
-
-#ifndef CURL_DISABLE_PROXY
- case CURLOPT_HTTPPROXYTUNNEL:
- /*
- * Tunnel operations through the proxy instead of normal proxy use
- */
- data->set.tunnel_thru_httpproxy = (0 != va_arg(param, long)) ?
- TRUE : FALSE;
- break;
-
- case CURLOPT_PROXYPORT:
- /*
- * Explicitly set HTTP proxy port number.
- */
- data->set.proxyport = va_arg(param, long);
- break;
-
- case CURLOPT_PROXYAUTH:
- /*
- * Set HTTP Authentication type BITMASK.
- */
- {
- int bitcheck;
- bool authbits;
- unsigned long auth = va_arg(param, unsigned long);
-
- if(auth == CURLAUTH_NONE) {
- data->set.proxyauth = auth;
- break;
- }
-
- /* the DIGEST_IE bit is only used to set a special marker, for all the
- rest we need to handle it as normal DIGEST */
- data->state.authproxy.iestyle = (auth & CURLAUTH_DIGEST_IE) ? TRUE : FALSE;
-
- if(auth & CURLAUTH_DIGEST_IE) {
- auth |= CURLAUTH_DIGEST; /* set standard digest bit */
- auth &= ~CURLAUTH_DIGEST_IE; /* unset ie digest bit */
- }
- /* switch off bits we can't support */
-#ifndef USE_NTLM
- auth &= ~CURLAUTH_NTLM; /* no NTLM support */
- auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */
-#elif !defined(NTLM_WB_ENABLED)
- auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */
-#endif
-#ifndef USE_SPNEGO
- auth &= ~CURLAUTH_NEGOTIATE; /* no Negotiate (SPNEGO) auth without
- GSS-API or SSPI */
-#endif
-
- /* check if any auth bit lower than CURLAUTH_ONLY is still set */
- bitcheck = 0;
- authbits = FALSE;
- while(bitcheck < 31) {
- if(auth & (1UL << bitcheck++)) {
- authbits = TRUE;
- break;
- }
- }
- if(!authbits)
- return CURLE_NOT_BUILT_IN; /* no supported types left! */
-
- data->set.proxyauth = auth;
- }
- break;
-
- case CURLOPT_PROXY:
- /*
- * Set proxy server:port to use as proxy.
- *
- * If the proxy is set to "" (and CURLOPT_SOCKS_PROXY is set to "" or NULL)
- * we explicitly say that we don't want to use a proxy
- * (even though there might be environment variables saying so).
- *
- * Setting it to NULL, means no proxy but allows the environment variables
- * to decide for us (if CURLOPT_SOCKS_PROXY setting it to NULL).
- */
- result = setstropt(&data->set.str[STRING_PROXY],
- va_arg(param, char *));
- break;
-
- case CURLOPT_PRE_PROXY:
- /*
- * Set proxy server:port to use as SOCKS proxy.
- *
- * If the proxy is set to "" or NULL we explicitly say that we don't want
- * to use the socks proxy.
- */
- result = setstropt(&data->set.str[STRING_PRE_PROXY],
- va_arg(param, char *));
- break;
-
- case CURLOPT_PROXYTYPE:
- /*
- * Set proxy type. HTTP/HTTP_1_0/SOCKS4/SOCKS4a/SOCKS5/SOCKS5_HOSTNAME
- */
- data->set.proxytype = (curl_proxytype)va_arg(param, long);
- break;
-
- case CURLOPT_PROXY_TRANSFER_MODE:
- /*
- * set transfer mode (;type=<a|i>) when doing FTP via an HTTP proxy
- */
- switch(va_arg(param, long)) {
- case 0:
- data->set.proxy_transfer_mode = FALSE;
- break;
- case 1:
- data->set.proxy_transfer_mode = TRUE;
- break;
- default:
- /* reserve other values for future use */
- result = CURLE_UNKNOWN_OPTION;
- break;
- }
- break;
-#endif /* CURL_DISABLE_PROXY */
-
- case CURLOPT_SOCKS5_AUTH:
- data->set.socks5auth = va_arg(param, unsigned long);
- if(data->set.socks5auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI))
- result = CURLE_NOT_BUILT_IN;
- break;
-#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
- case CURLOPT_SOCKS5_GSSAPI_NEC:
- /*
- * Set flag for NEC SOCK5 support
- */
- data->set.socks5_gssapi_nec = (0 != va_arg(param, long)) ? TRUE : FALSE;
- break;
-
- case CURLOPT_SOCKS5_GSSAPI_SERVICE:
- case CURLOPT_PROXY_SERVICE_NAME:
- /*
- * Set proxy authentication service name for Kerberos 5 and SPNEGO
- */
- result = setstropt(&data->set.str[STRING_PROXY_SERVICE_NAME],
- va_arg(param, char *));
- break;
-#endif
-
-#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) || \
- defined(USE_SPNEGO)
- case CURLOPT_SERVICE_NAME:
- /*
- * Set authentication service name for DIGEST-MD5, Kerberos 5 and SPNEGO
- */
- result = setstropt(&data->set.str[STRING_SERVICE_NAME],
- va_arg(param, char *));
- break;
-
-#endif
-
- case CURLOPT_HEADERDATA:
- /*
- * Custom pointer to pass the header write callback function
- */
- data->set.writeheader = (void *)va_arg(param, void *);
- break;
- case CURLOPT_ERRORBUFFER:
- /*
- * Error buffer provided by the caller to get the human readable
- * error string in.
- */
- data->set.errorbuffer = va_arg(param, char *);
- break;
- case CURLOPT_WRITEDATA:
- /*
- * FILE pointer to write to. Or possibly
- * used as argument to the write callback.
- */
- data->set.out = va_arg(param, void *);
- break;
- case CURLOPT_FTPPORT:
- /*
- * Use FTP PORT, this also specifies which IP address to use
- */
- result = setstropt(&data->set.str[STRING_FTPPORT],
- va_arg(param, char *));
- data->set.ftp_use_port = (data->set.str[STRING_FTPPORT]) ? TRUE : FALSE;
- break;
-
- case CURLOPT_FTP_USE_EPRT:
- data->set.ftp_use_eprt = (0 != va_arg(param, long)) ? TRUE : FALSE;
- break;
-
- case CURLOPT_FTP_USE_EPSV:
- data->set.ftp_use_epsv = (0 != va_arg(param, long)) ? TRUE : FALSE;
- break;
-
- case CURLOPT_FTP_USE_PRET:
- data->set.ftp_use_pret = (0 != va_arg(param, long)) ? TRUE : FALSE;
- break;
-
- case CURLOPT_FTP_SSL_CCC:
- data->set.ftp_ccc = (curl_ftpccc)va_arg(param, long);
- break;
-
- case CURLOPT_FTP_SKIP_PASV_IP:
- /*
- * Enable or disable FTP_SKIP_PASV_IP, which will disable/enable the
- * bypass of the IP address in PASV responses.
- */
- data->set.ftp_skip_ip = (0 != va_arg(param, long)) ? TRUE : FALSE;
- break;
-
- case CURLOPT_READDATA:
- /*
- * FILE pointer to read the file to be uploaded from. Or possibly
- * used as argument to the read callback.
- */
- data->set.in_set = va_arg(param, void *);
- break;
- case CURLOPT_INFILESIZE:
- /*
- * If known, this should inform curl about the file size of the
- * to-be-uploaded file.
- */
- data->set.filesize = 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.filesize = va_arg(param, curl_off_t);
- break;
- case CURLOPT_LOW_SPEED_LIMIT:
- /*
- * The low speed limit that if transfers are below this for
- * CURLOPT_LOW_SPEED_TIME, the transfer is aborted.
- */
- data->set.low_speed_limit=va_arg(param, long);
- break;
- case CURLOPT_MAX_SEND_SPEED_LARGE:
- /*
- * When transfer uploads are faster then CURLOPT_MAX_SEND_SPEED_LARGE
- * bytes per second the transfer is throttled..
- */
- data->set.max_send_speed=va_arg(param, curl_off_t);
- break;
- case CURLOPT_MAX_RECV_SPEED_LARGE:
- /*
- * When receiving data faster than CURLOPT_MAX_RECV_SPEED_LARGE bytes per
- * second the transfer is throttled..
- */
- data->set.max_recv_speed=va_arg(param, curl_off_t);
- break;
- case CURLOPT_LOW_SPEED_TIME:
- /*
- * The low speed time that if transfers are below the set
- * CURLOPT_LOW_SPEED_LIMIT during this time, the transfer is aborted.
- */
- data->set.low_speed_time=va_arg(param, long);
- break;
- case CURLOPT_URL:
- /*
- * The URL to fetch.
- */
- if(data->change.url_alloc) {
- /* the already set URL is allocated, free it first! */
- Curl_safefree(data->change.url);
- data->change.url_alloc = FALSE;
- }
- result = setstropt(&data->set.str[STRING_SET_URL],
- va_arg(param, char *));
- data->change.url = data->set.str[STRING_SET_URL];
- break;
- case CURLOPT_PORT:
- /*
- * The port number to use when getting the URL
- */
- data->set.use_port = va_arg(param, long);
- break;
- case CURLOPT_TIMEOUT:
- /*
- * The maximum time you allow curl to use for a single transfer
- * operation.
- */
- data->set.timeout = va_arg(param, long) * 1000L;
- break;
-
- case CURLOPT_TIMEOUT_MS:
- data->set.timeout = va_arg(param, long);
- break;
-
- case CURLOPT_CONNECTTIMEOUT:
- /*
- * The maximum time you allow curl to use to connect.
- */
- data->set.connecttimeout = va_arg(param, long) * 1000L;
- break;
-
- case CURLOPT_CONNECTTIMEOUT_MS:
- data->set.connecttimeout = va_arg(param, long);
- break;
-
- case CURLOPT_ACCEPTTIMEOUT_MS:
- /*
- * The maximum time you allow curl to wait for server connect
- */
- data->set.accepttimeout = va_arg(param, long);
- break;
-
- case CURLOPT_USERPWD:
- /*
- * user:password to use in the operation
- */
- result = setstropt_userpwd(va_arg(param, char *),
- &data->set.str[STRING_USERNAME],
- &data->set.str[STRING_PASSWORD]);
- break;
-
- case CURLOPT_USERNAME:
- /*
- * authentication user name to use in the operation
- */
- result = setstropt(&data->set.str[STRING_USERNAME],
- va_arg(param, char *));
- break;
-
- case CURLOPT_PASSWORD:
- /*
- * authentication password to use in the operation
- */
- result = setstropt(&data->set.str[STRING_PASSWORD],
- va_arg(param, char *));
- break;
-
- case CURLOPT_LOGIN_OPTIONS:
- /*
- * authentication options to use in the operation
- */
- result = setstropt(&data->set.str[STRING_OPTIONS],
- va_arg(param, char *));
- break;
-
- case CURLOPT_XOAUTH2_BEARER:
- /*
- * OAuth 2.0 bearer token to use in the operation
- */
- result = setstropt(&data->set.str[STRING_BEARER],
- va_arg(param, char *));
- break;
-
- case CURLOPT_POSTQUOTE:
- /*
- * List of RAW FTP commands to use after a transfer
- */
- data->set.postquote = va_arg(param, struct curl_slist *);
- break;
- case CURLOPT_PREQUOTE:
- /*
- * List of RAW FTP commands to use prior to RETR (Wesley Laxton)
- */
- data->set.prequote = va_arg(param, struct curl_slist *);
- break;
- case CURLOPT_QUOTE:
- /*
- * List of RAW FTP commands to use before a transfer
- */
- data->set.quote = va_arg(param, struct curl_slist *);
- break;
- case CURLOPT_RESOLVE:
- /*
- * List of NAME:[address] names to populate the DNS cache with
- * Prefix the NAME with dash (-) to _remove_ the name from the cache.
- *
- * Names added with this API will remain in the cache until explicitly
- * removed or the handle is cleaned up.
- *
- * This API can remove any name from the DNS cache, but only entries
- * that aren't actually in use right now will be pruned immediately.
- */
- data->set.resolve = va_arg(param, struct curl_slist *);
- data->change.resolve = data->set.resolve;
- break;
- case CURLOPT_PROGRESSFUNCTION:
- /*
- * Progress callback function
- */
- data->set.fprogress = va_arg(param, curl_progress_callback);
- if(data->set.fprogress)
- data->progress.callback = TRUE; /* no longer internal */
- else
- data->progress.callback = FALSE; /* NULL enforces internal */
- break;
-
- case CURLOPT_XFERINFOFUNCTION:
- /*
- * Transfer info callback function
- */
- data->set.fxferinfo = va_arg(param, curl_xferinfo_callback);
- if(data->set.fxferinfo)
- data->progress.callback = TRUE; /* no longer internal */
- else
- data->progress.callback = FALSE; /* NULL enforces internal */
-
- break;
-
- case CURLOPT_PROGRESSDATA:
- /*
- * Custom client data to pass to the progress callback
- */
- data->set.progress_client = va_arg(param, void *);
- break;
-
-#ifndef CURL_DISABLE_PROXY
- case CURLOPT_PROXYUSERPWD:
- /*
- * user:password needed to use the proxy
- */
- result = setstropt_userpwd(va_arg(param, char *),
- &data->set.str[STRING_PROXYUSERNAME],
- &data->set.str[STRING_PROXYPASSWORD]);
- break;
- case CURLOPT_PROXYUSERNAME:
- /*
- * authentication user name to use in the operation
- */
- result = setstropt(&data->set.str[STRING_PROXYUSERNAME],
- va_arg(param, char *));
- break;
- case CURLOPT_PROXYPASSWORD:
- /*
- * authentication password to use in the operation
- */
- result = setstropt(&data->set.str[STRING_PROXYPASSWORD],
- va_arg(param, char *));
- break;
- case CURLOPT_NOPROXY:
- /*
- * proxy exception list
- */
- result = setstropt(&data->set.str[STRING_NOPROXY],
- va_arg(param, char *));
- break;
-#endif
-
- case CURLOPT_RANGE:
- /*
- * What range of the file you want to transfer
- */
- result = setstropt(&data->set.str[STRING_SET_RANGE],
- va_arg(param, char *));
- break;
- case CURLOPT_RESUME_FROM:
- /*
- * Resume transfer at the give file position
- */
- 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.
- */
- data->set.fdebug = va_arg(param, curl_debug_callback);
- /*
- * if the callback provided is NULL, it'll use the default callback
- */
- break;
- case CURLOPT_DEBUGDATA:
- /*
- * Set to a void * that should receive all error writes. This
- * defaults to CURLOPT_STDERR for normal operations.
- */
- data->set.debugdata = va_arg(param, void *);
- break;
- case CURLOPT_STDERR:
- /*
- * Set to a FILE * that should receive all error writes. This
- * defaults to stderr for normal operations.
- */
- data->set.err = va_arg(param, FILE *);
- if(!data->set.err)
- data->set.err = stderr;
- break;
- case CURLOPT_HEADERFUNCTION:
- /*
- * Set header write callback
- */
- data->set.fwrite_header = va_arg(param, curl_write_callback);
- break;
- case CURLOPT_WRITEFUNCTION:
- /*
- * Set data write callback
- */
- data->set.fwrite_func = va_arg(param, curl_write_callback);
- if(!data->set.fwrite_func) {
- data->set.is_fwrite_set = 0;
- /* When set to NULL, reset to our internal default function */
- data->set.fwrite_func = (curl_write_callback)fwrite;
- }
- else
- data->set.is_fwrite_set = 1;
- break;
- case CURLOPT_READFUNCTION:
- /*
- * Read data callback
- */
- data->set.fread_func_set = va_arg(param, curl_read_callback);
- if(!data->set.fread_func_set) {
- data->set.is_fread_set = 0;
- /* When set to NULL, reset to our internal default function */
- data->set.fread_func_set = (curl_read_callback)fread;
- }
- else
- data->set.is_fread_set = 1;
- break;
- case CURLOPT_SEEKFUNCTION:
- /*
- * Seek callback. Might be NULL.
- */
- data->set.seek_func = va_arg(param, curl_seek_callback);
- break;
- case CURLOPT_SEEKDATA:
- /*
- * Seek control callback. Might be NULL.
- */
- data->set.seek_client = va_arg(param, void *);
- break;
- case CURLOPT_CONV_FROM_NETWORK_FUNCTION:
- /*
- * "Convert from network encoding" callback
- */
- data->set.convfromnetwork = va_arg(param, curl_conv_callback);
- break;
- case CURLOPT_CONV_TO_NETWORK_FUNCTION:
- /*
- * "Convert to network encoding" callback
- */
- data->set.convtonetwork = va_arg(param, curl_conv_callback);
- break;
- case CURLOPT_CONV_FROM_UTF8_FUNCTION:
- /*
- * "Convert from UTF-8 encoding" callback
- */
- data->set.convfromutf8 = va_arg(param, curl_conv_callback);
- break;
- case CURLOPT_IOCTLFUNCTION:
- /*
- * I/O control callback. Might be NULL.
- */
- data->set.ioctl_func = va_arg(param, curl_ioctl_callback);
- break;
- case CURLOPT_IOCTLDATA:
- /*
- * I/O control data pointer. Might be NULL.
- */
- data->set.ioctl_client = va_arg(param, void *);
- break;
- case CURLOPT_SSLCERT:
- /*
- * String that holds file name of the SSL certificate to use
- */
- result = setstropt(&data->set.str[STRING_CERT_ORIG],
- va_arg(param, char *));
- break;
- case CURLOPT_PROXY_SSLCERT:
- /*
- * String that holds file name of the SSL certificate to use for proxy
- */
- result = setstropt(&data->set.str[STRING_CERT_PROXY],
- va_arg(param, char *));
- break;
- case CURLOPT_SSLCERTTYPE:
- /*
- * String that holds file type of the SSL certificate to use
- */
- result = setstropt(&data->set.str[STRING_CERT_TYPE_ORIG],
- va_arg(param, char *));
- break;
- case CURLOPT_PROXY_SSLCERTTYPE:
- /*
- * String that holds file type of the SSL certificate to use for proxy
- */
- result = setstropt(&data->set.str[STRING_CERT_TYPE_PROXY],
- va_arg(param, char *));
- break;
- case CURLOPT_SSLKEY:
- /*
- * String that holds file name of the SSL key to use
- */
- result = setstropt(&data->set.str[STRING_KEY_ORIG],
- va_arg(param, char *));
- break;
- case CURLOPT_PROXY_SSLKEY:
- /*
- * String that holds file name of the SSL key to use for proxy
- */
- result = setstropt(&data->set.str[STRING_KEY_PROXY],
- va_arg(param, char *));
- break;
- case CURLOPT_SSLKEYTYPE:
- /*
- * String that holds file type of the SSL key to use
- */
- result = setstropt(&data->set.str[STRING_KEY_TYPE_ORIG],
- va_arg(param, char *));
- break;
- case CURLOPT_PROXY_SSLKEYTYPE:
- /*
- * String that holds file type of the SSL key to use for proxy
- */
- result = setstropt(&data->set.str[STRING_KEY_TYPE_PROXY],
- va_arg(param, char *));
- break;
- case CURLOPT_KEYPASSWD:
- /*
- * String that holds the SSL or SSH private key password.
- */
- result = setstropt(&data->set.str[STRING_KEY_PASSWD_ORIG],
- va_arg(param, char *));
- break;
- case CURLOPT_PROXY_KEYPASSWD:
- /*
- * String that holds the SSL private key password for proxy.
- */
- result = setstropt(&data->set.str[STRING_KEY_PASSWD_PROXY],
- va_arg(param, char *));
- break;
- case CURLOPT_SSLENGINE:
- /*
- * String that holds the SSL crypto engine.
- */
- argptr = va_arg(param, char *);
- if(argptr && argptr[0])
- result = Curl_ssl_set_engine(data, argptr);
- break;
-
- case CURLOPT_SSLENGINE_DEFAULT:
- /*
- * flag to set engine as default.
- */
- result = Curl_ssl_set_engine_default(data);
- break;
- case CURLOPT_CRLF:
- /*
- * Kludgy option to enable CRLF conversions. Subject for removal.
- */
- data->set.crlf = (0 != va_arg(param, long)) ? TRUE : FALSE;
- break;
-
- case CURLOPT_INTERFACE:
- /*
- * Set what interface or address/hostname to bind the socket to when
- * performing an operation and thus what from-IP your connection will use.
- */
- result = setstropt(&data->set.str[STRING_DEVICE],
- va_arg(param, char *));
- break;
- case CURLOPT_LOCALPORT:
- /*
- * Set what local port to bind the socket to when performing an operation.
- */
- arg = va_arg(param, long);
- if((arg < 0) || (arg > 65535))
- return CURLE_BAD_FUNCTION_ARGUMENT;
- data->set.localport = curlx_sltous(arg);
- break;
- case CURLOPT_LOCALPORTRANGE:
- /*
- * Set number of local ports to try, starting with CURLOPT_LOCALPORT.
- */
- arg = va_arg(param, long);
- if((arg < 0) || (arg > 65535))
- return CURLE_BAD_FUNCTION_ARGUMENT;
- data->set.localportrange = curlx_sltosi(arg);
- break;
- case CURLOPT_KRBLEVEL:
- /*
- * A string that defines the kerberos security level.
- */
- result = setstropt(&data->set.str[STRING_KRB_LEVEL],
- va_arg(param, char *));
- data->set.krb = (data->set.str[STRING_KRB_LEVEL]) ? TRUE : FALSE;
- break;
- case CURLOPT_GSSAPI_DELEGATION:
- /*
- * GSS-API credential delegation
- */
- data->set.gssapi_delegation = va_arg(param, long);
- break;
- case CURLOPT_SSL_VERIFYPEER:
- /*
- * Enable peer SSL verifying.
- */
- data->set.ssl.primary.verifypeer = (0 != va_arg(param, long)) ?
- TRUE : FALSE;
- break;
- case CURLOPT_PROXY_SSL_VERIFYPEER:
- /*
- * Enable peer SSL verifying for proxy.
- */
- data->set.proxy_ssl.primary.verifypeer =
- (0 != va_arg(param, long))?TRUE:FALSE;
- break;
- case CURLOPT_SSL_VERIFYHOST:
- /*
- * Enable verification of the host name in the peer certificate
- */
- arg = va_arg(param, long);
-
- /* Obviously people are not reading documentation and too many thought
- this argument took a boolean when it wasn't and misused it. We thus ban
- 1 as a sensible input and we warn about its use. Then we only have the
- 2 action internally stored as TRUE. */
-
- if(1 == arg) {
- failf(data, "CURLOPT_SSL_VERIFYHOST no longer supports 1 as value!");
- return CURLE_BAD_FUNCTION_ARGUMENT;
- }
-
- data->set.ssl.primary.verifyhost = (0 != arg) ? TRUE : FALSE;
- break;
- case CURLOPT_PROXY_SSL_VERIFYHOST:
- /*
- * Enable verification of the host name in the peer certificate for proxy
- */
- arg = va_arg(param, long);
-
- /* Obviously people are not reading documentation and too many thought
- this argument took a boolean when it wasn't and misused it. We thus ban
- 1 as a sensible input and we warn about its use. Then we only have the
- 2 action internally stored as TRUE. */
-
- if(1 == arg) {
- failf(data, "CURLOPT_SSL_VERIFYHOST no longer supports 1 as value!");
- return CURLE_BAD_FUNCTION_ARGUMENT;
- }
-
- data->set.proxy_ssl.primary.verifyhost = (0 != arg)?TRUE:FALSE;
- break;
- case CURLOPT_SSL_VERIFYSTATUS:
- /*
- * Enable certificate status verifying.
- */
- if(!Curl_ssl_cert_status_request()) {
- result = CURLE_NOT_BUILT_IN;
- break;
- }
-
- data->set.ssl.primary.verifystatus = (0 != va_arg(param, long)) ?
- TRUE : FALSE;
- break;
- case CURLOPT_SSL_CTX_FUNCTION:
-#ifdef have_curlssl_ssl_ctx
- /*
- * Set a SSL_CTX callback
- */
- data->set.ssl.fsslctx = va_arg(param, curl_ssl_ctx_callback);
-#else
- result = CURLE_NOT_BUILT_IN;
-#endif
- break;
- case CURLOPT_SSL_CTX_DATA:
-#ifdef have_curlssl_ssl_ctx
- /*
- * Set a SSL_CTX callback parameter pointer
- */
- data->set.ssl.fsslctxp = va_arg(param, void *);
-#else
- result = CURLE_NOT_BUILT_IN;
-#endif
- break;
- case CURLOPT_SSL_FALSESTART:
- /*
- * Enable TLS false start.
- */
- if(!Curl_ssl_false_start()) {
- result = CURLE_NOT_BUILT_IN;
- break;
- }
-
- data->set.ssl.falsestart = (0 != va_arg(param, long)) ? TRUE : FALSE;
- break;
- case CURLOPT_CERTINFO:
-#ifdef have_curlssl_certinfo
- data->set.ssl.certinfo = (0 != va_arg(param, long)) ? TRUE : FALSE;
-#else
- result = CURLE_NOT_BUILT_IN;
-#endif
- break;
- case CURLOPT_PINNEDPUBLICKEY:
-#ifdef have_curlssl_pinnedpubkey /* only by supported backends */
- /*
- * Set pinned public key for SSL connection.
- * Specify file name of the public key in DER format.
- */
- result = setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG],
- va_arg(param, char *));
-#else
- result = CURLE_NOT_BUILT_IN;
-#endif
- break;
- case CURLOPT_PROXY_PINNEDPUBLICKEY:
-#ifdef have_curlssl_pinnedpubkey /* only by supported backends */
- /*
- * Set pinned public key for SSL connection.
- * Specify file name of the public key in DER format.
- */
- result = setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY],
- va_arg(param, char *));
-#else
- result = CURLE_NOT_BUILT_IN;
-#endif
- break;
- case CURLOPT_CAINFO:
- /*
- * Set CA info for SSL connection. Specify file name of the CA certificate
- */
- result = setstropt(&data->set.str[STRING_SSL_CAFILE_ORIG],
- va_arg(param, char *));
- break;
- case CURLOPT_PROXY_CAINFO:
- /*
- * Set CA info SSL connection for proxy. Specify file name of the
- * CA certificate
- */
- result = setstropt(&data->set.str[STRING_SSL_CAFILE_PROXY],
- va_arg(param, char *));
- break;
- case CURLOPT_CAPATH:
-#ifdef have_curlssl_ca_path /* not supported by all backends */
- /*
- * Set CA path info for SSL connection. Specify directory name of the CA
- * certificates which have been prepared using openssl c_rehash utility.
- */
- /* This does not work on windows. */
- result = setstropt(&data->set.str[STRING_SSL_CAPATH_ORIG],
- va_arg(param, char *));
-#else
- result = CURLE_NOT_BUILT_IN;
-#endif
- break;
- case CURLOPT_PROXY_CAPATH:
-#ifdef have_curlssl_ca_path /* not supported by all backends */
- /*
- * Set CA path info for SSL connection proxy. Specify directory name of the
- * CA certificates which have been prepared using openssl c_rehash utility.
- */
- /* This does not work on windows. */
- result = setstropt(&data->set.str[STRING_SSL_CAPATH_PROXY],
- va_arg(param, char *));
-#else
- result = CURLE_NOT_BUILT_IN;
-#endif
- break;
- case CURLOPT_CRLFILE:
- /*
- * Set CRL file info for SSL connection. Specify file name of the CRL
- * to check certificates revocation
- */
- result = setstropt(&data->set.str[STRING_SSL_CRLFILE_ORIG],
- va_arg(param, char *));
- break;
- case CURLOPT_PROXY_CRLFILE:
- /*
- * Set CRL file info for SSL connection for proxy. Specify file name of the
- * CRL to check certificates revocation
- */
- result = setstropt(&data->set.str[STRING_SSL_CRLFILE_PROXY],
- va_arg(param, char *));
- break;
- case CURLOPT_ISSUERCERT:
- /*
- * Set Issuer certificate file
- * to check certificates issuer
- */
- result = setstropt(&data->set.str[STRING_SSL_ISSUERCERT_ORIG],
- va_arg(param, char *));
- break;
- case CURLOPT_TELNETOPTIONS:
- /*
- * Set a linked list of telnet options
- */
- data->set.telnet_options = va_arg(param, struct curl_slist *);
- break;
-
- case CURLOPT_BUFFERSIZE:
- /*
- * The application kindly asks for a differently sized receive buffer.
- * If it seems reasonable, we'll use it.
- */
- arg = va_arg(param, long);
-
- if(arg > READBUFFER_MAX)
- arg = READBUFFER_MAX;
- else if(arg < 1)
- arg = READBUFFER_SIZE;
- else if(arg < READBUFFER_MIN)
- arg = READBUFFER_MIN;
-
- /* Resize if new size */
- if(arg != data->set.buffer_size) {
- char *newbuff = realloc(data->state.buffer, arg + 1);
- if(!newbuff) {
- DEBUGF(fprintf(stderr, "Error: realloc of buffer failed\n"));
- result = CURLE_OUT_OF_MEMORY;
- }
- else
- data->state.buffer = newbuff;
- }
- data->set.buffer_size = arg;
-
- break;
-
- case CURLOPT_NOSIGNAL:
- /*
- * The application asks not to set any signal() or alarm() handlers,
- * even when using a timeout.
- */
- data->set.no_signal = (0 != va_arg(param, long)) ? TRUE : FALSE;
- break;
-
- case CURLOPT_SHARE:
- {
- struct Curl_share *set;
- set = va_arg(param, struct Curl_share *);
-
- /* disconnect from old share, if any */
- if(data->share) {
- Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
-
- if(data->dns.hostcachetype == HCACHE_SHARED) {
- data->dns.hostcache = NULL;
- data->dns.hostcachetype = HCACHE_NONE;
- }
-
-#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
- if(data->share->cookies == data->cookies)
- data->cookies = NULL;
-#endif
-
- if(data->share->sslsession == data->state.session)
- data->state.session = NULL;
-
- data->share->dirty--;
-
- Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
- data->share = NULL;
- }
-
- /* use new share if it set */
- data->share = set;
- if(data->share) {
-
- Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
-
- data->share->dirty++;
-
- if(data->share->specifier & (1<< CURL_LOCK_DATA_DNS)) {
- /* use shared host cache */
- data->dns.hostcache = &data->share->hostcache;
- data->dns.hostcachetype = HCACHE_SHARED;
- }
-#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
- if(data->share->cookies) {
- /* use shared cookie list, first free own one if any */
- Curl_cookie_cleanup(data->cookies);
- /* enable cookies since we now use a share that uses cookies! */
- data->cookies = data->share->cookies;
- }
-#endif /* CURL_DISABLE_HTTP */
- if(data->share->sslsession) {
- data->set.general_ssl.max_ssl_sessions = data->share->max_ssl_sessions;
- data->state.session = data->share->sslsession;
- }
- Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
-
- }
- /* check for host cache not needed,
- * it will be done by curl_easy_perform */
- }
- break;
-
- case CURLOPT_PRIVATE:
- /*
- * Set private data pointer.
- */
- data->set.private_data = va_arg(param, void *);
- break;
-
- case CURLOPT_MAXFILESIZE:
- /*
- * Set the maximum size of a file to download.
- */
- data->set.max_filesize = va_arg(param, long);
- break;
-
-#ifdef USE_SSL
- case CURLOPT_USE_SSL:
- /*
- * Make transfers attempt to use SSL/TLS.
- */
- data->set.use_ssl = (curl_usessl)va_arg(param, long);
- break;
-
- case CURLOPT_SSL_OPTIONS:
- arg = va_arg(param, long);
- data->set.ssl.enable_beast = arg&CURLSSLOPT_ALLOW_BEAST?TRUE:FALSE;
- data->set.ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE);
- break;
-
- case CURLOPT_PROXY_SSL_OPTIONS:
- arg = va_arg(param, long);
- data->set.proxy_ssl.enable_beast = arg&CURLSSLOPT_ALLOW_BEAST?TRUE:FALSE;
- data->set.proxy_ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE);
- break;
-
-#endif
- case CURLOPT_FTPSSLAUTH:
- /*
- * Set a specific auth for FTP-SSL transfers.
- */
- data->set.ftpsslauth = (curl_ftpauth)va_arg(param, long);
- break;
-
- case CURLOPT_IPRESOLVE:
- data->set.ipver = 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 = (0 != va_arg(param, long)) ? TRUE : FALSE;
- break;
-
- case CURLOPT_FTP_ACCOUNT:
- result = setstropt(&data->set.str[STRING_FTP_ACCOUNT],
- va_arg(param, char *));
- break;
-
- case CURLOPT_IGNORE_CONTENT_LENGTH:
- data->set.ignorecl = (0 != va_arg(param, long)) ? TRUE : FALSE;
- break;
-
- case CURLOPT_CONNECT_ONLY:
- /*
- * No data transfer, set up connection and let application use the socket
- */
- data->set.connect_only = (0 != va_arg(param, long)) ? TRUE : FALSE;
- break;
-
- case CURLOPT_FTP_ALTERNATIVE_TO_USER:
- result = setstropt(&data->set.str[STRING_FTP_ALTERNATIVE_TO_USER],
- va_arg(param, char *));
- break;
-
- case CURLOPT_SOCKOPTFUNCTION:
- /*
- * socket callback function: called after socket() but before connect()
- */
- data->set.fsockopt = va_arg(param, curl_sockopt_callback);
- break;
-
- case CURLOPT_SOCKOPTDATA:
- /*
- * socket callback data pointer. Might be NULL.
- */
- data->set.sockopt_client = va_arg(param, void *);
- break;
-
- case CURLOPT_OPENSOCKETFUNCTION:
- /*
- * open/create socket callback function: called instead of socket(),
- * before connect()
- */
- data->set.fopensocket = va_arg(param, curl_opensocket_callback);
- break;
-
- case CURLOPT_OPENSOCKETDATA:
- /*
- * socket callback data pointer. Might be NULL.
- */
- data->set.opensocket_client = va_arg(param, void *);
- break;
-
- case CURLOPT_CLOSESOCKETFUNCTION:
- /*
- * close socket callback function: called instead of close()
- * when shutting down a connection
- */
- data->set.fclosesocket = va_arg(param, curl_closesocket_callback);
- break;
-
- case CURLOPT_CLOSESOCKETDATA:
- /*
- * socket callback data pointer. Might be NULL.
- */
- data->set.closesocket_client = va_arg(param, void *);
- break;
-
- case CURLOPT_SSL_SESSIONID_CACHE:
- data->set.ssl.primary.sessionid = (0 != va_arg(param, long)) ?
- TRUE : FALSE;
- data->set.proxy_ssl.primary.sessionid = data->set.ssl.primary.sessionid;
- break;
-
-#ifdef USE_LIBSSH2
- /* we only include SSH options if explicitly built to support SSH */
- case CURLOPT_SSH_AUTH_TYPES:
- data->set.ssh_auth_types = va_arg(param, long);
- break;
-
- case CURLOPT_SSH_PUBLIC_KEYFILE:
- /*
- * Use this file instead of the $HOME/.ssh/id_dsa.pub file
- */
- result = setstropt(&data->set.str[STRING_SSH_PUBLIC_KEY],
- va_arg(param, char *));
- break;
-
- case CURLOPT_SSH_PRIVATE_KEYFILE:
- /*
- * Use this file instead of the $HOME/.ssh/id_dsa file
- */
- result = setstropt(&data->set.str[STRING_SSH_PRIVATE_KEY],
- va_arg(param, char *));
- break;
- case CURLOPT_SSH_HOST_PUBLIC_KEY_MD5:
- /*
- * Option to allow for the MD5 of the host public key to be checked
- * for validation purposes.
- */
- result = setstropt(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5],
- va_arg(param, char *));
- break;
-#ifdef HAVE_LIBSSH2_KNOWNHOST_API
- case CURLOPT_SSH_KNOWNHOSTS:
- /*
- * Store the file name to read known hosts from.
- */
- result = setstropt(&data->set.str[STRING_SSH_KNOWNHOSTS],
- va_arg(param, char *));
- break;
-
- case CURLOPT_SSH_KEYFUNCTION:
- /* setting to NULL is fine since the ssh.c functions themselves will
- then rever to use the internal default */
- data->set.ssh_keyfunc = va_arg(param, curl_sshkeycallback);
- break;
-
- case CURLOPT_SSH_KEYDATA:
- /*
- * Custom client data to pass to the SSH keyfunc callback
- */
- data->set.ssh_keyfunc_userp = va_arg(param, void *);
- break;
-#endif /* HAVE_LIBSSH2_KNOWNHOST_API */
-
-#endif /* USE_LIBSSH2 */
-
- case CURLOPT_HTTP_TRANSFER_DECODING:
- /*
- * disable libcurl transfer encoding is used
- */
- data->set.http_te_skip = (0 == va_arg(param, long)) ? TRUE : FALSE;
- break;
-
- case CURLOPT_HTTP_CONTENT_DECODING:
- /*
- * raw data passed to the application when content encoding is used
- */
- data->set.http_ce_skip = (0 == va_arg(param, long)) ? TRUE : FALSE;
- break;
-
- case CURLOPT_NEW_FILE_PERMS:
- /*
- * Uses these permissions instead of 0644
- */
- data->set.new_file_perms = va_arg(param, long);
- break;
-
- case CURLOPT_NEW_DIRECTORY_PERMS:
- /*
- * Uses these permissions instead of 0755
- */
- data->set.new_directory_perms = va_arg(param, long);
- break;
-
- case CURLOPT_ADDRESS_SCOPE:
- /*
- * We always get longs when passed plain numericals, but for this value we
- * know that an unsigned int will always hold the value so we blindly
- * typecast to this type
- */
- arg = va_arg(param, long);
- if((arg < 0) || (arg > 0xf))
- return CURLE_BAD_FUNCTION_ARGUMENT;
- data->set.scope_id = curlx_sltoui(arg);
- break;
-
- case CURLOPT_PROTOCOLS:
- /* set the bitmask for the protocols that are allowed to be used for the
- transfer, which thus helps the app which takes URLs from users or other
- external inputs and want to restrict what protocol(s) to deal
- with. Defaults to CURLPROTO_ALL. */
- data->set.allowed_protocols = va_arg(param, long);
- break;
-
- case CURLOPT_REDIR_PROTOCOLS:
- /* set the bitmask for the protocols that libcurl is allowed to follow to,
- as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs
- to be set in both bitmasks to be allowed to get redirected to. Defaults
- to all protocols except FILE and SCP. */
- data->set.redir_protocols = va_arg(param, long);
- break;
-
- case CURLOPT_DEFAULT_PROTOCOL:
- /* Set the protocol to use when the URL doesn't include any protocol */
- result = setstropt(&data->set.str[STRING_DEFAULT_PROTOCOL],
- va_arg(param, char *));
- break;
-
- case CURLOPT_MAIL_FROM:
- /* Set the SMTP mail originator */
- result = setstropt(&data->set.str[STRING_MAIL_FROM],
- va_arg(param, char *));
- break;
-
- case CURLOPT_MAIL_AUTH:
- /* Set the SMTP auth originator */
- result = setstropt(&data->set.str[STRING_MAIL_AUTH],
- va_arg(param, char *));
- break;
-
- case CURLOPT_MAIL_RCPT:
- /* Set the list of mail recipients */
- data->set.mail_rcpt = va_arg(param, struct curl_slist *);
- break;
-
- case CURLOPT_SASL_IR:
- /* Enable/disable SASL initial response */
- data->set.sasl_ir = (0 != va_arg(param, long)) ? TRUE : FALSE;
- break;
-
- case CURLOPT_RTSP_REQUEST:
- {
- /*
- * Set the RTSP request method (OPTIONS, SETUP, PLAY, etc...)
- * Would this be better if the RTSPREQ_* were just moved into here?
- */
- long curl_rtspreq = va_arg(param, long);
- Curl_RtspReq rtspreq = RTSPREQ_NONE;
- switch(curl_rtspreq) {
- case CURL_RTSPREQ_OPTIONS:
- rtspreq = RTSPREQ_OPTIONS;
- break;
-
- case CURL_RTSPREQ_DESCRIBE:
- rtspreq = RTSPREQ_DESCRIBE;
- break;
-
- case CURL_RTSPREQ_ANNOUNCE:
- rtspreq = RTSPREQ_ANNOUNCE;
- break;
-
- case CURL_RTSPREQ_SETUP:
- rtspreq = RTSPREQ_SETUP;
- break;
-
- case CURL_RTSPREQ_PLAY:
- rtspreq = RTSPREQ_PLAY;
- break;
-
- case CURL_RTSPREQ_PAUSE:
- rtspreq = RTSPREQ_PAUSE;
- break;
-
- case CURL_RTSPREQ_TEARDOWN:
- rtspreq = RTSPREQ_TEARDOWN;
- break;
-
- case CURL_RTSPREQ_GET_PARAMETER:
- rtspreq = RTSPREQ_GET_PARAMETER;
- break;
-
- case CURL_RTSPREQ_SET_PARAMETER:
- rtspreq = RTSPREQ_SET_PARAMETER;
- break;
-
- case CURL_RTSPREQ_RECORD:
- rtspreq = RTSPREQ_RECORD;
- break;
-
- case CURL_RTSPREQ_RECEIVE:
- rtspreq = RTSPREQ_RECEIVE;
- break;
- default:
- rtspreq = RTSPREQ_NONE;
- }
-
- data->set.rtspreq = rtspreq;
- break;
- }
-
-
- case CURLOPT_RTSP_SESSION_ID:
- /*
- * Set the RTSP Session ID manually. Useful if the application is
- * resuming a previously established RTSP session
- */
- result = setstropt(&data->set.str[STRING_RTSP_SESSION_ID],
- va_arg(param, char *));
- break;
-
- case CURLOPT_RTSP_STREAM_URI:
- /*
- * Set the Stream URI for the RTSP request. Unless the request is
- * for generic server options, the application will need to set this.
- */
- result = setstropt(&data->set.str[STRING_RTSP_STREAM_URI],
- va_arg(param, char *));
- break;
-
- case CURLOPT_RTSP_TRANSPORT:
- /*
- * The content of the Transport: header for the RTSP request
- */
- result = setstropt(&data->set.str[STRING_RTSP_TRANSPORT],
- va_arg(param, char *));
- break;
-
- case CURLOPT_RTSP_CLIENT_CSEQ:
- /*
- * Set the CSEQ number to issue for the next RTSP request. Useful if the
- * application is resuming a previously broken connection. The CSEQ
- * will increment from this new number henceforth.
- */
- data->state.rtsp_next_client_CSeq = va_arg(param, long);
- break;
-
- case CURLOPT_RTSP_SERVER_CSEQ:
- /* Same as the above, but for server-initiated requests */
- data->state.rtsp_next_client_CSeq = va_arg(param, long);
- break;
-
- case CURLOPT_INTERLEAVEDATA:
- data->set.rtp_out = va_arg(param, void *);
- break;
- case CURLOPT_INTERLEAVEFUNCTION:
- /* Set the user defined RTP write function */
- data->set.fwrite_rtp = va_arg(param, curl_write_callback);
- break;
-
- case CURLOPT_WILDCARDMATCH:
- data->set.wildcardmatch = (0 != va_arg(param, long)) ? TRUE : FALSE;
- break;
- case CURLOPT_CHUNK_BGN_FUNCTION:
- data->set.chunk_bgn = va_arg(param, curl_chunk_bgn_callback);
- break;
- case CURLOPT_CHUNK_END_FUNCTION:
- data->set.chunk_end = va_arg(param, curl_chunk_end_callback);
- break;
- case CURLOPT_FNMATCH_FUNCTION:
- data->set.fnmatch = va_arg(param, curl_fnmatch_callback);
- break;
- case CURLOPT_CHUNK_DATA:
- data->wildcard.customptr = va_arg(param, void *);
- break;
- case CURLOPT_FNMATCH_DATA:
- data->set.fnmatch_data = va_arg(param, void *);
- break;
-#ifdef USE_TLS_SRP
- case CURLOPT_TLSAUTH_USERNAME:
- result = setstropt(&data->set.str[STRING_TLSAUTH_USERNAME_ORIG],
- va_arg(param, char *));
- if(data->set.str[STRING_TLSAUTH_USERNAME_ORIG] && !data->set.ssl.authtype)
- data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */
- break;
- case CURLOPT_PROXY_TLSAUTH_USERNAME:
- result = setstropt(&data->set.str[STRING_TLSAUTH_USERNAME_PROXY],
- va_arg(param, char *));
- if(data->set.str[STRING_TLSAUTH_USERNAME_PROXY] &&
- !data->set.proxy_ssl.authtype)
- data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */
- break;
- case CURLOPT_TLSAUTH_PASSWORD:
- result = setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_ORIG],
- va_arg(param, char *));
- if(data->set.str[STRING_TLSAUTH_USERNAME_ORIG] && !data->set.ssl.authtype)
- data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */
- break;
- case CURLOPT_PROXY_TLSAUTH_PASSWORD:
- result = setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_PROXY],
- va_arg(param, char *));
- if(data->set.str[STRING_TLSAUTH_USERNAME_PROXY] &&
- !data->set.proxy_ssl.authtype)
- data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */
- break;
- case CURLOPT_TLSAUTH_TYPE:
- argptr = va_arg(param, char *);
- if(!argptr ||
- strncasecompare(argptr, "SRP", strlen("SRP")))
- data->set.ssl.authtype = CURL_TLSAUTH_SRP;
- else
- data->set.ssl.authtype = CURL_TLSAUTH_NONE;
- break;
- case CURLOPT_PROXY_TLSAUTH_TYPE:
- argptr = va_arg(param, char *);
- if(!argptr ||
- strncasecompare(argptr, "SRP", strlen("SRP")))
- data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP;
- else
- data->set.proxy_ssl.authtype = CURL_TLSAUTH_NONE;
- break;
-#endif
- case CURLOPT_DNS_SERVERS:
- result = Curl_set_dns_servers(data, va_arg(param, char *));
- break;
- case CURLOPT_DNS_INTERFACE:
- result = Curl_set_dns_interface(data, va_arg(param, char *));
- break;
- case CURLOPT_DNS_LOCAL_IP4:
- result = Curl_set_dns_local_ip4(data, va_arg(param, char *));
- break;
- case CURLOPT_DNS_LOCAL_IP6:
- result = Curl_set_dns_local_ip6(data, va_arg(param, char *));
- break;
-
- case CURLOPT_TCP_KEEPALIVE:
- data->set.tcp_keepalive = (0 != va_arg(param, long)) ? TRUE : FALSE;
- break;
- case CURLOPT_TCP_KEEPIDLE:
- data->set.tcp_keepidle = va_arg(param, long);
- break;
- case CURLOPT_TCP_KEEPINTVL:
- data->set.tcp_keepintvl = va_arg(param, long);
- break;
- case CURLOPT_TCP_FASTOPEN:
-#if defined(CONNECT_DATA_IDEMPOTENT) || defined(MSG_FASTOPEN)
- data->set.tcp_fastopen = (0 != va_arg(param, long))?TRUE:FALSE;
-#else
- result = CURLE_NOT_BUILT_IN;
-#endif
- break;
- case CURLOPT_SSL_ENABLE_NPN:
- data->set.ssl_enable_npn = (0 != va_arg(param, long)) ? TRUE : FALSE;
- break;
- case CURLOPT_SSL_ENABLE_ALPN:
- data->set.ssl_enable_alpn = (0 != va_arg(param, long)) ? TRUE : FALSE;
- break;
-
-#ifdef USE_UNIX_SOCKETS
- case CURLOPT_UNIX_SOCKET_PATH:
- data->set.abstract_unix_socket = FALSE;
- result = setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH],
- va_arg(param, char *));
- break;
- case CURLOPT_ABSTRACT_UNIX_SOCKET:
- data->set.abstract_unix_socket = TRUE;
- result = setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH],
- va_arg(param, char *));
- break;
-#endif
-
- case CURLOPT_PATH_AS_IS:
- data->set.path_as_is = (0 != va_arg(param, long)) ? TRUE : FALSE;
- break;
- case CURLOPT_PIPEWAIT:
- data->set.pipewait = (0 != va_arg(param, long)) ? TRUE : FALSE;
- break;
- case CURLOPT_STREAM_WEIGHT:
-#ifndef USE_NGHTTP2
- return CURLE_NOT_BUILT_IN;
-#else
- arg = va_arg(param, long);
- if((arg>=1) && (arg <= 256))
- data->set.stream_weight = (int)arg;
- break;
-#endif
- case CURLOPT_STREAM_DEPENDS:
- case CURLOPT_STREAM_DEPENDS_E:
- {
-#ifndef USE_NGHTTP2
- return CURLE_NOT_BUILT_IN;
-#else
- struct Curl_easy *dep = va_arg(param, struct Curl_easy *);
- if(!dep || GOOD_EASY_HANDLE(dep)) {
- if(data->set.stream_depends_on) {
- Curl_http2_remove_child(data->set.stream_depends_on, data);
- }
- Curl_http2_add_child(dep, data, (option == CURLOPT_STREAM_DEPENDS_E));
- }
- break;
-#endif
- }
- case CURLOPT_CONNECT_TO:
- data->set.connect_to = va_arg(param, struct curl_slist *);
- break;
- case CURLOPT_SUPPRESS_CONNECT_HEADERS:
- data->set.suppress_connect_headers = (0 != va_arg(param, long))?TRUE:FALSE;
- break;
- default:
- /* unknown tag and its companion, just ignore: */
- result = CURLE_UNKNOWN_OPTION;
- break;
- }
-
- return result;
-}
-
#ifdef USE_RECV_BEFORE_SEND_WORKAROUND
static void conn_reset_postponed_data(struct connectdata *conn, int num)
{
@@ -3259,58 +924,6 @@ static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke)
}
}
-/*
- * This function finds the connection in the connection
- * cache that has been unused for the longest time.
- *
- * Returns the pointer to the oldest idle connection, or NULL if none was
- * found.
- */
-struct connectdata *
-Curl_oldest_idle_connection(struct Curl_easy *data)
-{
- struct conncache *bc = data->state.conn_cache;
- struct curl_hash_iterator iter;
- struct curl_llist_element *curr;
- struct curl_hash_element *he;
- time_t highscore=-1;
- time_t score;
- struct curltime now;
- struct connectdata *conn_candidate = NULL;
- struct connectbundle *bundle;
-
- now = Curl_tvnow();
-
- Curl_hash_start_iterate(&bc->hash, &iter);
-
- he = Curl_hash_next_element(&iter);
- while(he) {
- struct connectdata *conn;
-
- bundle = he->ptr;
-
- curr = bundle->conn_list.head;
- while(curr) {
- conn = curr->ptr;
-
- if(!conn->inuse) {
- /* Set higher score for the age passed since the connection was used */
- score = Curl_tvdiff(now, conn->now);
-
- if(score > highscore) {
- highscore = score;
- conn_candidate = conn;
- }
- }
- curr = curr->next;
- }
-
- he = Curl_hash_next_element(&iter);
- }
-
- return conn_candidate;
-}
-
static bool
proxy_info_matches(const struct proxy_info* data,
const struct proxy_info* needle)
@@ -3336,15 +949,15 @@ find_oldest_idle_connection_in_bundle(struct Curl_easy *data,
struct connectbundle *bundle)
{
struct curl_llist_element *curr;
- time_t highscore=-1;
- time_t score;
+ timediff_t highscore = -1;
+ timediff_t score;
struct curltime now;
struct connectdata *conn_candidate = NULL;
struct connectdata *conn;
(void)data;
- now = Curl_tvnow();
+ now = Curl_now();
curr = bundle->conn_list.head;
while(curr) {
@@ -3352,7 +965,7 @@ find_oldest_idle_connection_in_bundle(struct Curl_easy *data,
if(!conn->inuse) {
/* Set higher score for the age passed since the connection was used */
- score = Curl_tvdiff(now, conn->now);
+ score = Curl_timediff(now, conn->now);
if(score > highscore) {
highscore = score;
@@ -3426,11 +1039,11 @@ static int call_disconnect_if_dead(struct connectdata *conn,
*/
static void prune_dead_connections(struct Curl_easy *data)
{
- struct curltime now = Curl_tvnow();
- time_t elapsed = Curl_tvdiff(now, data->state.conn_cache->last_cleanup);
+ struct curltime now = Curl_now();
+ time_t elapsed = Curl_timediff(now, data->state.conn_cache->last_cleanup);
if(elapsed >= 1000L) {
- Curl_conncache_foreach(data->state.conn_cache, data,
+ Curl_conncache_foreach(data, data->state.conn_cache, data,
call_disconnect_if_dead);
data->state.conn_cache->last_cleanup = now;
}
@@ -3967,7 +1580,7 @@ int Curl_doing_getsock(struct connectdata *conn,
CURLcode Curl_protocol_connecting(struct connectdata *conn,
bool *done)
{
- CURLcode result=CURLE_OK;
+ CURLcode result = CURLE_OK;
if(conn && conn->handler->connecting) {
*done = FALSE;
@@ -3986,7 +1599,7 @@ CURLcode Curl_protocol_connecting(struct connectdata *conn,
CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done)
{
- CURLcode result=CURLE_OK;
+ CURLcode result = CURLE_OK;
if(conn && conn->handler->doing) {
*done = FALSE;
@@ -4006,7 +1619,7 @@ CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done)
CURLcode Curl_protocol_connect(struct connectdata *conn,
bool *protocol_done)
{
- CURLcode result=CURLE_OK;
+ CURLcode result = CURLE_OK;
*protocol_done = FALSE;
@@ -4074,7 +1687,7 @@ static bool is_ASCII_name(const char *hostname)
/*
* Perform any necessary IDN conversion of hostname
*/
-static void fix_hostname(struct connectdata *conn, struct hostname *host)
+static CURLcode fix_hostname(struct connectdata *conn, struct hostname *host)
{
size_t len;
struct Curl_easy *data = conn->data;
@@ -4093,7 +1706,7 @@ static void fix_hostname(struct connectdata *conn, struct hostname *host)
if(len && (host->name[len-1] == '.'))
/* strip off a single trailing dot if present, primarily for SNI but
there's no use for it */
- host->name[len-1]=0;
+ host->name[len-1] = 0;
/* Check name for non-ASCII and convert hostname to ACE form if we can */
if(!is_ASCII_name(host->name)) {
@@ -4114,9 +1727,11 @@ static void fix_hostname(struct connectdata *conn, struct hostname *host)
/* change the name pointer to point to the encoded hostname */
host->name = host->encalloc;
}
- else
- infof(data, "Failed to convert %s to ACE; %s\n", host->name,
+ else {
+ failf(data, "Failed to convert %s to ACE; %s\n", host->name,
idn2_strerror(rc));
+ return CURLE_URL_MALFORMAT;
+ }
}
#elif defined(USE_WIN32_IDN)
char *ace_hostname = NULL;
@@ -4126,12 +1741,24 @@ static void fix_hostname(struct connectdata *conn, struct hostname *host)
/* change the name pointer to point to the encoded hostname */
host->name = host->encalloc;
}
- else
- infof(data, "Failed to convert %s to ACE;\n", host->name);
+ else {
+ failf(data, "Failed to convert %s to ACE;\n", host->name);
+ return CURLE_URL_MALFORMAT;
+ }
#else
infof(data, "IDN support not present, can't parse Unicode domains\n");
#endif
}
+ {
+ char *hostp;
+ for(hostp = host->name; *hostp; hostp++) {
+ if(*hostp <= 32) {
+ failf(data, "Host name '%s' contains bad letter", host->name);
+ return CURLE_URL_MALFORMAT;
+ }
+ }
+ }
+ return CURLE_OK;
}
/*
@@ -4146,7 +1773,7 @@ static void free_fixed_hostname(struct hostname *host)
host->encalloc = NULL;
}
#elif defined(USE_WIN32_IDN)
- free(host->encalloc); /* must be freed withidn_free() since this was
+ free(host->encalloc); /* must be freed with free() since this was
allocated by curl_win32_idn_to_ascii */
host->encalloc = NULL;
#else
@@ -4166,10 +1793,41 @@ static void llist_dtor(void *user, void *element)
*/
static struct connectdata *allocate_conn(struct Curl_easy *data)
{
- struct connectdata *conn = calloc(1, sizeof(struct connectdata));
+ struct connectdata *conn;
+ size_t connsize = sizeof(struct connectdata);
+
+#ifdef USE_SSL
+/* SSLBK_MAX_ALIGN: The max byte alignment a CPU would use */
+#define SSLBK_MAX_ALIGN 32
+ /* The SSL backend-specific data (ssl_backend_data) objects are allocated as
+ part of connectdata at the end. To ensure suitable alignment we will
+ assume a maximum of SSLBK_MAX_ALIGN for alignment. Since calloc returns a
+ pointer suitably aligned for any variable this will ensure the
+ ssl_backend_data array has proper alignment, even if that alignment turns
+ out to be less than SSLBK_MAX_ALIGN. */
+ size_t paddingsize = sizeof(struct connectdata) % SSLBK_MAX_ALIGN;
+ size_t alignsize = paddingsize ? (SSLBK_MAX_ALIGN - paddingsize) : 0;
+ size_t sslbksize = Curl_ssl->sizeof_ssl_backend_data;
+ connsize += alignsize + (4 * sslbksize);
+#endif
+
+ conn = calloc(1, connsize);
if(!conn)
return NULL;
+#ifdef USE_SSL
+ /* Point to the ssl_backend_data objects at the end of connectdata.
+ Note that these backend pointers can be swapped by vtls (eg ssl backend
+ data becomes proxy backend data). */
+ {
+ char *end = (char *)conn + connsize;
+ conn->ssl[0].backend = ((void *)(end - (4 * sslbksize)));
+ conn->ssl[1].backend = ((void *)(end - (3 * sslbksize)));
+ conn->proxy_ssl[0].backend = ((void *)(end - (2 * sslbksize)));
+ conn->proxy_ssl[1].backend = ((void *)(end - (1 * sslbksize)));
+ }
+#endif
+
conn->handler = &Curl_handler_dummy; /* Be sure we have a handler defined
already from start to avoid NULL
situations and checks */
@@ -4194,7 +1852,7 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
connclose(conn, "Default to force-close");
/* Store creation time to help future close decision making */
- conn->created = Curl_tvnow();
+ conn->created = Curl_now();
conn->data = data; /* Setup the association between this connection
and the Curl_easy */
@@ -4390,6 +2048,14 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
('A' <= str[0] && str[0] <= 'Z')) && \
(str[1] == ':'))
+ /* MSDOS/Windows style drive prefix, optionally with
+ * a '|' instead of ':', followed by a slash or NUL */
+#define STARTS_WITH_URL_DRIVE_PREFIX(str) \
+ ((('a' <= (str)[0] && (str)[0] <= 'z') || \
+ ('A' <= (str)[0] && (str)[0] <= 'Z')) && \
+ ((str)[1] == ':' || (str)[1] == '|') && \
+ ((str)[2] == '/' || (str)[2] == 0))
+
/* Don't mistake a drive letter for a scheme if the default protocol is file.
curld --proto-default file c:/foo/bar.txt */
if(STARTS_WITH_DRIVE_PREFIX(data->change.url) &&
@@ -4422,63 +2088,90 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
return CURLE_URL_MALFORMAT;
}
- if(url_has_scheme && path[0] == '/' && path[1] == '/') {
- /* Allow omitted hostname (e.g. file:/<path>). This is not strictly
- * speaking a valid file: URL by RFC 1738, but treating file:/<path> as
- * file://localhost/<path> is similar to how other schemes treat missing
- * hostnames. See RFC 1808. */
-
- /* This cannot be done with strcpy() in a portable manner, since the
- memory areas overlap! */
- memmove(path, path + 2, strlen(path + 2)+1);
+ if(url_has_scheme && path[0] == '/' && path[1] == '/' &&
+ path[2] == '/' && path[3] == '/') {
+ /* This appears to be a UNC string (usually indicating a SMB share).
+ * We don't do SMB in file: URLs. (TODO?)
+ */
+ failf(data, "SMB shares are not supported in file: URLs.");
+ return CURLE_URL_MALFORMAT;
}
- /*
- * we deal with file://<host>/<path> differently since it supports no
- * hostname other than "localhost" and "127.0.0.1", which is unique among
- * the URL protocols specified in RFC 1738
+ /* Extra handling URLs with an authority component (i.e. that start with
+ * "file://")
+ *
+ * We allow omitted hostname (e.g. file:/<path>) -- valid according to
+ * RFC 8089, but not the (current) WHAT-WG URL spec.
*/
- if(path[0] != '/' && !STARTS_WITH_DRIVE_PREFIX(path)) {
- /* the URL includes a host name, it must match "localhost" or
- "127.0.0.1" to be valid */
- char *ptr;
- if(!checkprefix("localhost/", path) &&
- !checkprefix("127.0.0.1/", path)) {
- failf(data, "Invalid file://hostname/, "
- "expected localhost or 127.0.0.1 or none");
- return CURLE_URL_MALFORMAT;
- }
- ptr = &path[9]; /* now points to the slash after the host */
-
- /* there was a host name and slash present
-
- RFC1738 (section 3.1, page 5) says:
-
- The rest of the locator consists of data specific to the scheme,
- and is known as the "url-path". It supplies the details of how the
- specified resource can be accessed. Note that the "/" between the
- host (or port) and the url-path is NOT part of the url-path.
+ if(url_has_scheme && path[0] == '/' && path[1] == '/') {
+ /* swallow the two slashes */
+ char *ptr = &path[2];
- As most agents use file://localhost/foo to get '/foo' although the
- slash preceding foo is a separator and not a slash for the path,
- a URL as file://localhost//foo must be valid as well, to refer to
- the same file with an absolute path.
- */
+ /*
+ * According to RFC 8089, a file: URL can be reliably dereferenced if:
+ *
+ * o it has no/blank hostname, or
+ *
+ * o the hostname matches "localhost" (case-insensitively), or
+ *
+ * o the hostname is a FQDN that resolves to this machine.
+ *
+ * For brevity, we only consider URLs with empty, "localhost", or
+ * "127.0.0.1" hostnames as local.
+ *
+ * Additionally, there is an exception for URLs with a Windows drive
+ * letter in the authority (which was accidentally omitted from RFC 8089
+ * Appendix E, but believe me, it was meant to be there. --MK)
+ */
+ if(ptr[0] != '/' && !STARTS_WITH_URL_DRIVE_PREFIX(ptr)) {
+ /* the URL includes a host name, it must match "localhost" or
+ "127.0.0.1" to be valid */
+ if(!checkprefix("localhost/", ptr) &&
+ !checkprefix("127.0.0.1/", ptr)) {
+ failf(data, "Invalid file://hostname/, "
+ "expected localhost or 127.0.0.1 or none");
+ return CURLE_URL_MALFORMAT;
+ }
+ ptr += 9; /* now points to the slash after the host */
+ }
- if('/' == ptr[1])
- /* if there was two slashes, we skip the first one as that is then
- used truly as a separator */
+ /*
+ * RFC 8089, Appendix D, Section D.1, says:
+ *
+ * > In a POSIX file system, the root of the file system is represented
+ * > as a directory with a zero-length name, usually written as "/"; the
+ * > presence of this root in a file URI can be taken as given by the
+ * > initial slash in the "path-absolute" rule.
+ *
+ * i.e. the first slash is part of the path.
+ *
+ * However in RFC 1738 the "/" between the host (or port) and the
+ * URL-path was NOT part of the URL-path. Any agent that followed the
+ * older spec strictly, and wanted to refer to a file with an absolute
+ * path, would have included a second slash. So if there are two
+ * slashes, swallow one.
+ */
+ if('/' == ptr[1]) /* note: the only way ptr[0]!='/' is if ptr[1]==':' */
ptr++;
- /* This cannot be made with strcpy, as the memory chunks overlap! */
- memmove(path, ptr, strlen(ptr)+1);
+ /* This cannot be done with strcpy, as the memory chunks overlap! */
+ memmove(path, ptr, strlen(ptr) + 1);
}
#if !defined(MSDOS) && !defined(WIN32) && !defined(__CYGWIN__)
- if(STARTS_WITH_DRIVE_PREFIX(path)) {
+ /* Don't allow Windows drive letters when not in Windows.
+ * This catches both "file:/c:" and "file:c:" */
+ if(('/' == path[0] && STARTS_WITH_URL_DRIVE_PREFIX(&path[1])) ||
+ STARTS_WITH_URL_DRIVE_PREFIX(path)) {
failf(data, "File drive letters are only accepted in MSDOS/Windows.");
return CURLE_URL_MALFORMAT;
}
+#else
+ /* If the path starts with a slash and a drive letter, ditch the slash */
+ if('/' == path[0] && STARTS_WITH_URL_DRIVE_PREFIX(&path[1])) {
+ /* This cannot be done with strcpy, as the memory chunks overlap! */
+ memmove(path, &path[1], strlen(&path[1]) + 1);
+ }
#endif
protop = "file"; /* protocol string */
@@ -4487,7 +2180,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
else {
/* clear path */
char slashbuf[4];
- path[0]=0;
+ path[0] = 0;
rc = sscanf(data->change.url,
"%15[^\n/:]:%3[/]%[^\n/?#]%[^\n]",
@@ -4572,7 +2265,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
*/
at = strchr(conn->host.name, '@');
if(at)
- query = strchr(at+1, '?');
+ query = strchr(at + 1, '?');
else
query = strchr(conn->host.name, '?');
@@ -4590,15 +2283,15 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
/* move the existing path plus the zero byte forward, to make room for
the host-name part */
- memmove(path+hostlen+1, path, pathlen+1);
+ memmove(path + hostlen + 1, path, pathlen + 1);
/* now copy the trailing host part in front of the existing path */
- memcpy(path+1, query, hostlen);
+ memcpy(path + 1, query, hostlen);
path[0]='/'; /* prepend the missing slash */
rebuild_url = TRUE;
- *query=0; /* now cut off the hostname at the ? */
+ *query = 0; /* now cut off the hostname at the ? */
}
else if(!path[0]) {
/* if there's no path set, use a single slash */
@@ -4614,7 +2307,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
/* 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(&path[1], path, strlen(path)+1);
+ memmove(&path[1], path, strlen(path) + 1);
path[0] = '/';
rebuild_url = TRUE;
}
@@ -4720,7 +2413,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
if(*endp == ']') {
/* The address scope was well formed. Knock it out of the
hostname. */
- memmove(percent, endp, strlen(endp)+1);
+ memmove(percent, endp, strlen(endp) + 1);
conn->scope_id = (unsigned int)scope;
}
else {
@@ -4990,7 +2683,7 @@ static char *detect_proxy(struct connectdata *conn)
strcpy(envp, "_proxy");
/* read the protocol proxy: */
- prox=curl_getenv(proxy_env);
+ prox = curl_getenv(proxy_env);
/*
* We don't try the uppercase version of HTTP_PROXY because of
@@ -5007,7 +2700,7 @@ static char *detect_proxy(struct connectdata *conn)
if(!prox && !strcasecompare("http_proxy", proxy_env)) {
/* There was no lowercase variable, try the uppercase version: */
Curl_strntoupper(proxy_env, proxy_env, sizeof(proxy_env));
- prox=curl_getenv(proxy_env);
+ prox = curl_getenv(proxy_env);
}
if(prox)
@@ -5015,7 +2708,7 @@ static char *detect_proxy(struct connectdata *conn)
else {
proxy = curl_getenv("all_proxy"); /* default proxy to use */
if(!proxy)
- proxy=curl_getenv("ALL_PROXY");
+ proxy = curl_getenv("ALL_PROXY");
}
return proxy;
@@ -5050,7 +2743,7 @@ static CURLcode parse_proxy(struct Curl_easy *data,
/* Parse the protocol part if present */
endofprot = strstr(proxy, "://");
if(endofprot) {
- proxyptr = endofprot+3;
+ proxyptr = endofprot + 3;
if(checkprefix("https", proxy))
proxytype = CURLPROXY_HTTPS;
else if(checkprefix("socks5h", proxy))
@@ -5072,13 +2765,14 @@ static CURLcode parse_proxy(struct Curl_easy *data,
else
proxyptr = proxy; /* No xxx:// head: It's a HTTP proxy */
-#ifndef HTTPS_PROXY_SUPPORT
- if(proxytype == CURLPROXY_HTTPS) {
- failf(data, "Unsupported proxy \'%s\'"
- ", libcurl is built without the HTTPS-proxy support.", proxy);
- return CURLE_NOT_BUILT_IN;
- }
+#ifdef USE_SSL
+ if(!Curl_ssl->support_https_proxy)
#endif
+ if(proxytype == CURLPROXY_HTTPS) {
+ failf(data, "Unsupported proxy \'%s\', libcurl is built without the "
+ "HTTPS-proxy support.", proxy);
+ return CURLE_NOT_BUILT_IN;
+ }
sockstype = proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
proxytype == CURLPROXY_SOCKS5 ||
@@ -5089,8 +2783,8 @@ static CURLcode parse_proxy(struct Curl_easy *data,
atsign = strchr(proxyptr, '@');
if(atsign) {
CURLcode result =
- parse_login_details(proxyptr, atsign - proxyptr,
- &proxyuser, &proxypasswd, NULL);
+ Curl_parse_login_details(proxyptr, atsign - proxyptr,
+ &proxyuser, &proxypasswd, NULL);
if(result)
return result;
proxyptr = atsign + 1;
@@ -5299,22 +2993,21 @@ static CURLcode create_conn_helper_init_proxy(struct connectdata *conn)
}
}
- no_proxy = curl_getenv("no_proxy");
- if(!no_proxy)
- no_proxy = curl_getenv("NO_PROXY");
+ if(!data->set.str[STRING_NOPROXY]) {
+ no_proxy = curl_getenv("no_proxy");
+ if(!no_proxy)
+ no_proxy = curl_getenv("NO_PROXY");
+ }
- if(check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY]) ||
- (!data->set.str[STRING_NOPROXY] &&
- check_noproxy(conn->host.name, no_proxy))) {
+ if(check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY] ?
+ data->set.str[STRING_NOPROXY] : no_proxy)) {
Curl_safefree(proxy);
Curl_safefree(socksproxy);
}
- else if(!proxy && !socksproxy)
#ifndef CURL_DISABLE_HTTP
+ else if(!proxy && !socksproxy)
/* if the host is not in the noproxy list, detect proxy. */
proxy = detect_proxy(conn);
-#else /* !CURL_DISABLE_HTTP */
- proxy = NULL;
#endif /* CURL_DISABLE_HTTP */
Curl_safefree(no_proxy);
@@ -5482,10 +3175,11 @@ static CURLcode parse_url_login(struct Curl_easy *data,
/* We could use the login information in the URL so extract it. Only parse
options if the handler says we should. */
- result = parse_login_details(login, ptr - login - 1,
- &userp, &passwdp,
- (conn->handler->flags & PROTOPT_URLOPTIONS)?
- &optionsp:NULL);
+ result =
+ Curl_parse_login_details(login, ptr - login - 1,
+ &userp, &passwdp,
+ (conn->handler->flags & PROTOPT_URLOPTIONS)?
+ &optionsp:NULL);
if(result)
goto out;
@@ -5541,7 +3235,7 @@ static CURLcode parse_url_login(struct Curl_easy *data,
}
/*
- * parse_login_details()
+ * Curl_parse_login_details()
*
* This is used to parse a login string for user name, password and options in
* the following formats:
@@ -5569,9 +3263,9 @@ static CURLcode parse_url_login(struct Curl_easy *data,
*
* Returns CURLE_OK on success.
*/
-static CURLcode parse_login_details(const char *login, const size_t len,
- char **userp, char **passwdp,
- char **optionsp)
+CURLcode Curl_parse_login_details(const char *login, const size_t len,
+ char **userp, char **passwdp,
+ char **optionsp)
{
CURLcode result = CURLE_OK;
char *ubuf = NULL;
@@ -5700,7 +3394,13 @@ static CURLcode parse_remote_port(struct Curl_easy *data,
portptr = strchr(conn->host.name, ']');
if(portptr) {
*portptr++ = '\0'; /* zero terminate, killing the bracket */
- if(':' != *portptr)
+ if(*portptr) {
+ if (*portptr != ':') {
+ failf(data, "IPv6 closing bracket followed by '%c'", *portptr);
+ return CURLE_URL_MALFORMAT;
+ }
+ }
+ else
portptr = NULL; /* no port number available */
}
}
@@ -5762,7 +3462,7 @@ static CURLcode parse_remote_port(struct Curl_easy *data,
char *rest;
long port;
- port=strtol(portptr+1, &rest, 10); /* Port number must be decimal */
+ port = strtol(portptr + 1, &rest, 10); /* Port number must be decimal */
if((port < 0) || (port > 0xffff)) {
/* Single unix standard says port numbers are 16 bits long */
@@ -6118,8 +3818,8 @@ static CURLcode resolve_server(struct Curl_easy *data,
struct connectdata *conn,
bool *async)
{
- CURLcode result=CURLE_OK;
- time_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
+ CURLcode result = CURLE_OK;
+ timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
/*************************************************************
* Resolve the name of the server or proxy
@@ -6281,11 +3981,10 @@ static void reuse_conn(struct connectdata *old_conn,
free_fixed_hostname(&conn->conn_to_host);
Curl_safefree(conn->host.rawalloc);
Curl_safefree(conn->conn_to_host.rawalloc);
- conn->host=old_conn->host;
- conn->bits.conn_to_host = old_conn->bits.conn_to_host;
+ conn->host = old_conn->host;
conn->conn_to_host = old_conn->conn_to_host;
- conn->bits.conn_to_port = old_conn->bits.conn_to_port;
conn->conn_to_port = old_conn->conn_to_port;
+ conn->remote_port = old_conn->remote_port;
/* persist connection info in session handle */
Curl_persistconninfo(conn);
@@ -6384,9 +4083,9 @@ static CURLcode create_conn(struct Curl_easy *data,
* other parts of the code will rely on this fact
***********************************************************/
#define LEAST_PATH_ALLOC 256
- urllen=strlen(data->change.url);
+ urllen = strlen(data->change.url);
if(urllen < LEAST_PATH_ALLOC)
- urllen=LEAST_PATH_ALLOC;
+ urllen = LEAST_PATH_ALLOC;
/*
* We malloc() the buffers below urllen+2 to make room for 2 possibilities:
@@ -6397,14 +4096,14 @@ static CURLcode create_conn(struct Curl_easy *data,
Curl_safefree(data->state.pathbuffer);
data->state.path = NULL;
- data->state.pathbuffer = malloc(urllen+2);
+ data->state.pathbuffer = malloc(urllen + 2);
if(NULL == data->state.pathbuffer) {
result = CURLE_OUT_OF_MEMORY; /* really bad error */
goto out;
}
data->state.path = data->state.pathbuffer;
- conn->host.rawalloc = malloc(urllen+2);
+ conn->host.rawalloc = malloc(urllen + 2);
if(NULL == conn->host.rawalloc) {
Curl_safefree(data->state.pathbuffer);
data->state.path = NULL;
@@ -6537,13 +4236,24 @@ static CURLcode create_conn(struct Curl_easy *data,
/*************************************************************
* IDN-fix the hostnames
*************************************************************/
- fix_hostname(conn, &conn->host);
- if(conn->bits.conn_to_host)
- fix_hostname(conn, &conn->conn_to_host);
- if(conn->bits.httpproxy)
- fix_hostname(conn, &conn->http_proxy.host);
- if(conn->bits.socksproxy)
- fix_hostname(conn, &conn->socks_proxy.host);
+ result = fix_hostname(conn, &conn->host);
+ if(result)
+ goto out;
+ if(conn->bits.conn_to_host) {
+ result = fix_hostname(conn, &conn->conn_to_host);
+ if(result)
+ goto out;
+ }
+ if(conn->bits.httpproxy) {
+ result = fix_hostname(conn, &conn->http_proxy.host);
+ if(result)
+ goto out;
+ }
+ if(conn->bits.socksproxy) {
+ result = fix_hostname(conn, &conn->socks_proxy.host);
+ if(result)
+ goto out;
+ }
/*************************************************************
* Check whether the host and the "connect to host" are equal.
@@ -6786,7 +4496,7 @@ static CURLcode create_conn(struct Curl_easy *data,
struct connectdata *conn_candidate;
/* The cache is full. Let's see if we can kill a connection. */
- conn_candidate = Curl_oldest_idle_connection(data);
+ conn_candidate = Curl_conncache_oldest_idle(data);
if(conn_candidate) {
/* Set the connection's owner correctly, then kill it */
@@ -6921,7 +4631,7 @@ CURLcode Curl_setup_conn(struct connectdata *conn,
/* set start time here for timeout purposes in the connect procedure, it
is later set again for the progress meter purpose */
- conn->now = Curl_tvnow();
+ conn->now = Curl_now();
if(CURL_SOCKET_BAD == conn->sock[FIRSTSOCKET]) {
conn->bits.tcpconnect[FIRSTSOCKET] = FALSE;
@@ -6938,7 +4648,7 @@ CURLcode Curl_setup_conn(struct connectdata *conn,
Curl_verboseconnect(conn);
}
- conn->now = Curl_tvnow(); /* time this *after* the connect is done, we
+ conn->now = Curl_now(); /* time this *after* the connect is done, we
set this here perhaps a second time */
#ifdef __EMX__
@@ -7011,13 +4721,17 @@ CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
{
struct SingleRequest *k = &data->req;
- if(conn)
- conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to
- * use */
+ conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to
+ use */
data->state.done = FALSE; /* *_done() is not called yet */
data->state.expect100header = FALSE;
+ /* if the protocol used doesn't support wildcards, switch it off */
+ if(data->state.wildcardmatch &&
+ !(conn->handler->flags & PROTOPT_WILDCARD))
+ data->state.wildcardmatch = FALSE;
+
if(data->set.opt_no_body)
/* in HTTP lingo, no body means using the HEAD request... */
data->set.httpreq = HTTPREQ_HEAD;
@@ -7029,7 +4743,7 @@ CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
HTTP. */
data->set.httpreq = HTTPREQ_GET;
- k->start = Curl_tvnow(); /* start time */
+ k->start = Curl_now(); /* start time */
k->now = k->start; /* current time is now */
k->header = TRUE; /* assume header */
@@ -7037,7 +4751,7 @@ CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
k->buf = data->state.buffer;
k->hbufp = data->state.headerbuff;
- k->ignorebody=FALSE;
+ k->ignorebody = FALSE;
Curl_speedinit(data);
diff --git a/lib/url.h b/lib/url.h
index f13c8e66..5dd04fdf 100644
--- a/lib/url.h
+++ b/lib/url.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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,6 +23,10 @@
***************************************************************************/
#include "curl_setup.h"
+#define READBUFFER_SIZE CURL_MAX_WRITE_SIZE
+#define READBUFFER_MAX CURL_MAX_READ_SIZE
+#define READBUFFER_MIN 1024
+
/*
* Prototypes for library-wide functions provided by url.c
*/
@@ -51,14 +55,14 @@ int Curl_protocol_getsock(struct connectdata *conn,
int Curl_doing_getsock(struct connectdata *conn,
curl_socket_t *socks,
int numsocks);
-
+CURLcode Curl_parse_login_details(const char *login, const size_t len,
+ char **userptr, char **passwdptr,
+ char **optionsptr);
bool Curl_isPipeliningEnabled(const struct Curl_easy *handle);
CURLcode Curl_addHandleToPipeline(struct Curl_easy *handle,
struct curl_llist *pipeline);
int Curl_removeHandleFromPipeline(struct Curl_easy *handle,
struct curl_llist *pipeline);
-struct connectdata *
-Curl_oldest_idle_connection(struct Curl_easy *data);
/* remove the specified connection from all (possible) pipelines and related
queues */
void Curl_getoff_all_pipelines(struct Curl_easy *data,
diff --git a/lib/urldata.h b/lib/urldata.h
index b4f18e7d..edd1fd9a 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -82,89 +82,12 @@
#include "cookie.h"
#include "formdata.h"
-#ifdef USE_OPENSSL
-#include <openssl/ssl.h>
-#ifdef HAVE_OPENSSL_ENGINE_H
-#include <openssl/engine.h>
-#endif
-#endif /* USE_OPENSSL */
-
-#ifdef USE_GNUTLS
-#include <gnutls/gnutls.h>
-#endif
-
-#ifdef USE_MBEDTLS
-
-#include <mbedtls/ssl.h>
-#include <mbedtls/version.h>
-#include <mbedtls/entropy.h>
-#include <mbedtls/ctr_drbg.h>
-
-#elif defined USE_POLARSSL
-
-#include <polarssl/ssl.h>
-#include <polarssl/version.h>
-#if POLARSSL_VERSION_NUMBER<0x01010000
-#include <polarssl/havege.h>
-#else
-#include <polarssl/entropy.h>
-#include <polarssl/ctr_drbg.h>
-#endif /* POLARSSL_VERSION_NUMBER<0x01010000 */
-
-#endif /* USE_POLARSSL */
-
-#ifdef USE_CYASSL
-#undef OCSP_REQUEST /* avoid cyassl/openssl/ssl.h clash with wincrypt.h */
-#undef OCSP_RESPONSE /* avoid cyassl/openssl/ssl.h clash with wincrypt.h */
-#include <cyassl/openssl/ssl.h>
-#endif
-
-#ifdef USE_NSS
-#include <nspr.h>
-#include <pk11pub.h>
-#endif
-
-#ifdef USE_GSKIT
-#include <gskssl.h>
-#endif
-
-#ifdef USE_AXTLS
-#include <axTLS/config.h>
-#include <axTLS/ssl.h>
-#undef malloc
-#undef calloc
-#undef realloc
-#endif /* USE_AXTLS */
-
-#if defined(USE_SCHANNEL) || defined(USE_WINDOWS_SSPI)
-#include "curl_sspi.h"
-#endif
-#ifdef USE_SCHANNEL
-#include <schnlsp.h>
-#include <schannel.h>
-#endif
-
-#ifdef USE_DARWINSSL
-#include <Security/Security.h>
-/* For some reason, when building for iOS, the omnibus header above does
- * not include SecureTransport.h as of iOS SDK 5.1. */
-#include <Security/SecureTransport.h>
-#endif
-
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#include "timeval.h"
-#ifdef HAVE_ZLIB_H
-#include <zlib.h> /* for content-encoding */
-#ifdef __SYMBIAN32__
-/* zlib pollutes the namespace with this definition */
-#undef WIN32
-#endif
-#endif
-
#include <curl/curl.h>
#include "http_chunks.h" /* for the structs and enum stuff */
@@ -172,6 +95,7 @@
#include "hash.h"
#include "splay.h"
+#include "mime.h"
#include "imap.h"
#include "pop3.h"
#include "smtp.h"
@@ -240,20 +164,6 @@ enum protection_level {
};
#endif
-#ifdef USE_SCHANNEL
-/* Structs to store Schannel handles */
-struct curl_schannel_cred {
- CredHandle cred_handle;
- TimeStamp time_stamp;
- int refcount;
-};
-
-struct curl_schannel_ctxt {
- CtxtHandle ctxt_handle;
- TimeStamp time_stamp;
-};
-#endif
-
/* enum for the nonblocking SSL connection state machine */
typedef enum {
ssl_connect_1,
@@ -270,6 +180,9 @@ typedef enum {
ssl_connection_complete
} ssl_connection_state;
+/* SSL backend-specific data; declared differently by each SSL backend */
+struct ssl_backend_data;
+
/* struct for data related to each SSL connection */
struct ssl_connect_data {
/* Use ssl encrypted communications TRUE/FALSE, not necessarily using it atm
@@ -278,78 +191,8 @@ struct ssl_connect_data {
bool use;
ssl_connection_state state;
ssl_connect_state connecting_state;
-#if defined(USE_OPENSSL)
- /* these ones requires specific SSL-types */
- SSL_CTX* ctx;
- SSL* handle;
- X509* server_cert;
-#elif defined(USE_GNUTLS)
- gnutls_session_t session;
- gnutls_certificate_credentials_t cred;
-#ifdef USE_TLS_SRP
- gnutls_srp_client_credentials_t srp_client_cred;
-#endif
-#elif defined(USE_MBEDTLS)
- mbedtls_ctr_drbg_context ctr_drbg;
- mbedtls_entropy_context entropy;
- mbedtls_ssl_context ssl;
- int server_fd;
- mbedtls_x509_crt cacert;
- mbedtls_x509_crt clicert;
- mbedtls_x509_crl crl;
- mbedtls_pk_context pk;
- mbedtls_ssl_config config;
- const char *protocols[3];
-#elif defined(USE_POLARSSL)
- ctr_drbg_context ctr_drbg;
- entropy_context entropy;
- ssl_context ssl;
- int server_fd;
- x509_crt cacert;
- x509_crt clicert;
- x509_crl crl;
- rsa_context rsa;
-#elif defined(USE_CYASSL)
- SSL_CTX* ctx;
- SSL* handle;
-#elif defined(USE_NSS)
- PRFileDesc *handle;
- char *client_nickname;
- struct Curl_easy *data;
- struct curl_llist obj_list;
- PK11GenericObject *obj_clicert;
-#elif defined(USE_GSKIT)
- gsk_handle handle;
- int iocport;
- int localfd;
- int remotefd;
-#elif defined(USE_AXTLS)
- SSL_CTX* ssl_ctx;
- SSL* ssl;
-#elif defined(USE_SCHANNEL)
- struct curl_schannel_cred *cred;
- struct curl_schannel_ctxt *ctxt;
- SecPkgContext_StreamSizes stream_sizes;
- size_t encdata_length, decdata_length;
- size_t encdata_offset, decdata_offset;
- unsigned char *encdata_buffer, *decdata_buffer;
- /* encdata_is_incomplete: if encdata contains only a partial record that
- can't be decrypted without another Curl_read_plain (that is, status is
- SEC_E_INCOMPLETE_MESSAGE) then set this true. after Curl_read_plain writes
- more bytes into encdata then set this back to false. */
- bool encdata_is_incomplete;
- unsigned long req_flags, ret_flags;
- CURLcode recv_unrecoverable_err; /* schannel_recv had an unrecoverable err */
- bool recv_sspi_close_notify; /* true if connection closed by close_notify */
- bool recv_connection_closed; /* true if connection closed, regardless how */
- bool use_alpn; /* true if ALPN is used for this connection */
-#elif defined(USE_DARWINSSL)
- SSLContextRef ssl_ctx;
- curl_socket_t ssl_sockfd;
- bool ssl_direction; /* true if writing, false if reading */
- size_t ssl_write_buffered_length;
-#elif defined(USE_SSL)
-#error "SSL backend specific information missing from ssl_connect_data"
+#if defined(USE_SSL)
+ struct ssl_backend_data *backend;
#endif
};
@@ -359,13 +202,13 @@ struct ssl_primary_config {
bool verifypeer; /* set TRUE if this is desired */
bool verifyhost; /* set TRUE if CN/SAN must match hostname */
bool verifystatus; /* set TRUE if certificate status must be checked */
+ bool sessionid; /* cache session IDs or not */
char *CApath; /* certificate dir (doesn't work on windows) */
char *CAfile; /* certificate to verify peer against */
char *clientcert;
char *random_file; /* path to file containing "random" data */
char *egdsocket; /* path to file containing the EGD daemon socket */
char *cipher_list; /* list of ciphers to use */
- bool sessionid; /* cache session IDs or not */
};
struct ssl_config_data {
@@ -411,6 +254,10 @@ struct curl_ssl_session {
struct ssl_primary_config ssl_config; /* setup for this session */
};
+#ifdef USE_WINDOWS_SSPI
+#include "curl_sspi.h"
+#endif
+
/* Struct used for Digest challenge-response authentication */
struct digestdata {
#if defined(USE_WINDOWS_SSPI)
@@ -431,6 +278,7 @@ struct digestdata {
char *qop;
char *algorithm;
int nc; /* nounce count */
+ bool userhash;
#endif
};
@@ -442,10 +290,6 @@ typedef enum {
NTLMSTATE_LAST
} curlntlm;
-#ifdef USE_WINDOWS_SSPI
-#include "curl_sspi.h"
-#endif
-
#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
#include <iconv.h>
#endif
@@ -612,16 +456,6 @@ struct hostname {
#define KEEP_SENDBITS (KEEP_SEND | KEEP_SEND_HOLD | KEEP_SEND_PAUSE)
-#ifdef HAVE_LIBZ
-typedef enum {
- ZLIB_UNINIT, /* uninitialized */
- ZLIB_INIT, /* initialized */
- ZLIB_GZIP_HEADER, /* reading gzip header */
- ZLIB_GZIP_INFLATING, /* inflating gzip stream */
- ZLIB_INIT_GZIP /* initialized in transparent gzip mode */
-} zlibInitState;
-#endif
-
#ifdef CURLRES_ASYNCH
struct Curl_async {
char *hostname;
@@ -709,18 +543,8 @@ struct SingleRequest {
enum expect100 exp100; /* expect 100 continue state */
enum upgrade101 upgr101; /* 101 upgrade state */
- int auto_decoding; /* What content encoding. sec 3.5, RFC2616. */
-
-#define IDENTITY 0 /* No encoding */
-#define DEFLATE 1 /* zlib deflate [RFC 1950 & 1951] */
-#define GZIP 2 /* gzip algorithm [RFC 1952] */
-
-#ifdef HAVE_LIBZ
- zlibInitState zlib_init; /* possible zlib init state;
- undefined if Content-Encoding header. */
- z_stream z; /* State structure for zlib. */
-#endif
-
+ struct contenc_writer_s *writer_stack; /* Content unencoding stack. */
+ /* See sec 3.5, RFC2616. */
time_t timeofdoc;
long bodywrites;
@@ -868,6 +692,7 @@ struct Curl_handler {
#define PROTOPT_PROXY_AS_HTTP (1<<11) /* allow this non-HTTP scheme over a
HTTP proxy as HTTP proxies may know
this protocol and act as a gateway */
+#define PROTOPT_WILDCARD (1<<12) /* protocol supports wildcard matching */
#define CONNCHECK_NONE 0 /* No checks */
#define CONNCHECK_ISDEAD (1<<0) /* Check if the connection is dead. */
@@ -1259,6 +1084,8 @@ struct Progress {
struct curltime t_startop;
struct curltime t_acceptdata;
+ bool is_t_startransfer_set;
+
/* upload speed limit */
struct curltime ul_limit_start;
curl_off_t ul_limit_size;
@@ -1266,7 +1093,7 @@ struct Progress {
struct curltime dl_limit_start;
curl_off_t dl_limit_size;
-#define CURR_TIME (5+1) /* 6 entries for 5 seconds */
+#define CURR_TIME (5 + 1) /* 6 entries for 5 seconds */
curl_off_t speeder[ CURR_TIME ];
struct curltime speeder_time[ CURR_TIME ];
@@ -1278,6 +1105,7 @@ typedef enum {
HTTPREQ_GET,
HTTPREQ_POST,
HTTPREQ_POST_FORM, /* we make a difference internally */
+ HTTPREQ_POST_MIME, /* we make a difference internally */
HTTPREQ_PUT,
HTTPREQ_HEAD,
HTTPREQ_OPTIONS,
@@ -1387,7 +1215,7 @@ struct UrlState {
size_t headersize; /* size of the allocation */
char *buffer; /* download buffer */
- char uploadbuffer[UPLOAD_BUFSIZE+1]; /* upload buffer */
+ char uploadbuffer[UPLOAD_BUFSIZE + 1]; /* upload buffer */
curl_off_t current_speed; /* the ProgressShow() function sets this,
bytes / second */
bool this_is_a_follow; /* this is a followed Location: request */
@@ -1431,7 +1259,8 @@ struct UrlState {
ares_channel f.e. */
#if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H)
- ENGINE *engine;
+ /* void instead of ENGINE to avoid bleeding OpenSSL into this header */
+ void *engine;
#endif /* USE_OPENSSL */
struct curltime expiretime; /* set this with Curl_expire() only */
struct Curl_tree timenode; /* for the splay stuff */
@@ -1443,7 +1272,7 @@ struct UrlState {
/* set after initial USER failure, to prevent an authentication loop */
bool ftp_trying_alternative;
-
+ bool wildcardmatch; /* enable wildcard matching */
int httpversion; /* the lowest HTTP version*10 reported by any server
involved in this request */
bool expect100header; /* TRUE if we added Expect: 100-continue */
@@ -1588,7 +1417,7 @@ enum dupstring {
STRING_PROXY_SERVICE_NAME, /* Proxy service name */
#endif
#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) || \
- defined(USE_SPNEGO)
+ defined(USE_SPNEGO) || defined(HAVE_GSSAPI)
STRING_SERVICE_NAME, /* Service name */
#endif
STRING_MAIL_FROM,
@@ -1694,7 +1523,8 @@ struct UserDefined {
curl_off_t set_resume_from; /* continue [ftp] transfer from here */
struct curl_slist *headers; /* linked list of extra headers */
struct curl_slist *proxyheaders; /* linked list of extra CONNECT headers */
- struct curl_httppost *httppost; /* linked list of POST data */
+ struct curl_httppost *httppost; /* linked list of old POST data */
+ curl_mimepart mimepost; /* MIME/POST data. */
bool sep_headers; /* handle host and proxy headers separately */
bool cookiesession; /* new cookie session? */
bool crlf; /* convert crlf on ftp upload(?) */
@@ -1740,6 +1570,7 @@ struct UserDefined {
curl_sshkeycallback ssh_keyfunc; /* key matching callback */
void *ssh_keyfunc_userp; /* custom pointer to callback */
+ bool ssh_compression; /* enable SSH compression */
/* Here follows boolean settings that define how to behave during
this session. They are STATIC, set by libcurl users or at least initially
@@ -1805,7 +1636,7 @@ struct UserDefined {
/* Common RTSP header options */
Curl_RtspReq rtspreq; /* RTSP request type */
long rtspversion; /* like httpversion, for RTSP */
- bool wildcardmatch; /* enable wildcard matching */
+ bool wildcard_enabled; /* enable wildcard matching */
curl_chunk_bgn_callback chunk_bgn; /* called before part of transfer
starts */
curl_chunk_end_callback chunk_end; /* called after part transferring
diff --git a/lib/vauth/digest.c b/lib/vauth/digest.c
index 185098ed..131d9da8 100644
--- a/lib/vauth/digest.c
+++ b/lib/vauth/digest.c
@@ -19,6 +19,7 @@
* KIND, either express or implied.
*
* RFC2831 DIGEST-MD5 authentication
+ * RFC7616 DIGEST-SHA256, DIGEST-SHA512-256 authentication
*
***************************************************************************/
@@ -34,6 +35,7 @@
#include "curl_base64.h"
#include "curl_hmac.h"
#include "curl_md5.h"
+#include "curl_sha256.h"
#include "vtls/vtls.h"
#include "warnless.h"
#include "strtok.h"
@@ -144,6 +146,15 @@ static void auth_digest_md5_to_ascii(unsigned char *source, /* 16 bytes */
snprintf((char *) &dest[i * 2], 3, "%02x", source[i]);
}
+/* Convert sha256 chunk to RFC7616 -suitable ascii string*/
+static void auth_digest_sha256_to_ascii(unsigned char *source, /* 32 bytes */
+ unsigned char *dest) /* 65 bytes */
+{
+ int i;
+ for(i = 0; i < 32; i++)
+ snprintf((char *) &dest[i * 2], 3, "%02x", source[i]);
+}
+
/* Perform quoted-string escaping as described in RFC2616 and its errata */
static char *auth_digest_string_quoted(const char *source)
{
@@ -602,9 +613,22 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
digest->algo = CURLDIGESTALGO_MD5SESS;
else if(strcasecompare(content, "MD5"))
digest->algo = CURLDIGESTALGO_MD5;
+ else if(strcasecompare(content, "SHA-256"))
+ digest->algo = CURLDIGESTALGO_SHA256;
+ else if(strcasecompare(content, "SHA-256-SESS"))
+ digest->algo = CURLDIGESTALGO_SHA256SESS;
+ else if(strcasecompare(content, "SHA-512-256"))
+ digest->algo = CURLDIGESTALGO_SHA512_256;
+ else if(strcasecompare(content, "SHA-512-256-SESS"))
+ digest->algo = CURLDIGESTALGO_SHA512_256SESS;
else
return CURLE_BAD_CONTENT_ENCODING;
}
+ else if(strcasecompare(value, "userhash")) {
+ if(strcasecompare(content, "true")) {
+ digest->userhash = TRUE;
+ }
+ }
else {
/* Unknown specifier, ignore it! */
}
@@ -635,7 +659,7 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
}
/*
- * Curl_auth_create_digest_http_message()
+ * _Curl_auth_create_digest_http_message()
*
* This is used to generate a HTTP DIGEST response message ready for sending
* to the recipient.
@@ -654,20 +678,24 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
*
* Returns CURLE_OK on success.
*/
-CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
- const char *userp,
- const char *passwdp,
- const unsigned char *request,
- const unsigned char *uripath,
- struct digestdata *digest,
- char **outptr, size_t *outlen)
+static CURLcode _Curl_auth_create_digest_http_message(
+ struct Curl_easy *data,
+ const char *userp,
+ const char *passwdp,
+ const unsigned char *request,
+ const unsigned char *uripath,
+ struct digestdata *digest,
+ char **outptr, size_t *outlen,
+ void (*convert_to_ascii)(unsigned char *, unsigned char *),
+ void (*hash)(unsigned char *, const unsigned char *))
{
CURLcode result;
- unsigned char md5buf[16]; /* 16 bytes/128 bits */
- unsigned char request_digest[33];
- unsigned char *md5this;
- unsigned char ha1[33]; /* 32 digits and 1 zero byte */
- unsigned char ha2[33]; /* 32 digits and 1 zero byte */
+ unsigned char hashbuf[32]; /* 32 bytes/256 bits */
+ unsigned char request_digest[65];
+ unsigned char *hashthis;
+ unsigned char ha1[65]; /* 64 digits and 1 zero byte */
+ unsigned char ha2[65]; /* 64 digits and 1 zero byte */
+ char userh[65];
char cnoncebuf[33];
char *cnonce = NULL;
size_t cnonce_sz = 0;
@@ -692,6 +720,17 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
digest->cnonce = cnonce;
}
+ if(digest->userhash) {
+ hashthis = (unsigned char *) aprintf("%s:%s", userp, digest->realm);
+ if(!hashthis)
+ return CURLE_OUT_OF_MEMORY;
+
+ CURL_OUTPUT_DIGEST_CONV(data, hashthis);
+ hash(hashbuf, hashthis);
+ free(hashthis);
+ convert_to_ascii(hashbuf, (unsigned char *)userh);
+ }
+
/*
If the algorithm is "MD5" or unspecified (which then defaults to MD5):
@@ -703,26 +742,29 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
unq(nonce-value) ":" unq(cnonce-value)
*/
- md5this = (unsigned char *)
- aprintf("%s:%s:%s", userp, digest->realm, passwdp);
- if(!md5this)
+ hashthis = (unsigned char *)
+ aprintf("%s:%s:%s", digest->userhash ? userh : userp,
+ digest->realm, passwdp);
+ if(!hashthis)
return CURLE_OUT_OF_MEMORY;
- CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */
- Curl_md5it(md5buf, md5this);
- free(md5this);
- auth_digest_md5_to_ascii(md5buf, ha1);
+ CURL_OUTPUT_DIGEST_CONV(data, hashthis); /* convert on non-ASCII machines */
+ hash(hashbuf, hashthis);
+ free(hashthis);
+ convert_to_ascii(hashbuf, ha1);
- if(digest->algo == CURLDIGESTALGO_MD5SESS) {
+ if(digest->algo == CURLDIGESTALGO_MD5SESS ||
+ digest->algo == CURLDIGESTALGO_SHA256SESS ||
+ digest->algo == CURLDIGESTALGO_SHA512_256SESS) {
/* nonce and cnonce are OUTSIDE the hash */
tmp = aprintf("%s:%s:%s", ha1, digest->nonce, digest->cnonce);
if(!tmp)
return CURLE_OUT_OF_MEMORY;
CURL_OUTPUT_DIGEST_CONV(data, tmp); /* Convert on non-ASCII machines */
- Curl_md5it(md5buf, (unsigned char *) tmp);
+ hash(hashbuf, (unsigned char *) tmp);
free(tmp);
- auth_digest_md5_to_ascii(md5buf, ha1);
+ convert_to_ascii(hashbuf, ha1);
}
/*
@@ -738,27 +780,32 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
5.1.1 of RFC 2616)
*/
- md5this = (unsigned char *) aprintf("%s:%s", request, uripath);
+ hashthis = (unsigned char *) aprintf("%s:%s", request, uripath);
if(digest->qop && strcasecompare(digest->qop, "auth-int")) {
/* We don't support auth-int for PUT or POST at the moment.
- TODO: replace md5 of empty string with entity-body for PUT/POST */
- unsigned char *md5this2 = (unsigned char *)
- aprintf("%s:%s", md5this, "d41d8cd98f00b204e9800998ecf8427e");
- free(md5this);
- md5this = md5this2;
+ TODO: replace hash of empty string with entity-body for PUT/POST */
+ char hashed[65];
+ unsigned char *hashthis2;
+
+ hash(hashbuf, (const unsigned char *)"");
+ convert_to_ascii(hashbuf, (unsigned char *)hashed);
+
+ hashthis2 = (unsigned char *)aprintf("%s:%s", hashthis, hashed);
+ free(hashthis);
+ hashthis = hashthis2;
}
- if(!md5this)
+ if(!hashthis)
return CURLE_OUT_OF_MEMORY;
- CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */
- Curl_md5it(md5buf, md5this);
- free(md5this);
- auth_digest_md5_to_ascii(md5buf, ha2);
+ CURL_OUTPUT_DIGEST_CONV(data, hashthis); /* convert on non-ASCII machines */
+ hash(hashbuf, hashthis);
+ free(hashthis);
+ convert_to_ascii(hashbuf, ha2);
if(digest->qop) {
- md5this = (unsigned char *) aprintf("%s:%s:%08x:%s:%s:%s",
+ hashthis = (unsigned char *) aprintf("%s:%s:%08x:%s:%s:%s",
ha1,
digest->nonce,
digest->nc,
@@ -767,19 +814,19 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
ha2);
}
else {
- md5this = (unsigned char *) aprintf("%s:%s:%s",
+ hashthis = (unsigned char *) aprintf("%s:%s:%s",
ha1,
digest->nonce,
ha2);
}
- if(!md5this)
+ if(!hashthis)
return CURLE_OUT_OF_MEMORY;
- CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */
- Curl_md5it(md5buf, md5this);
- free(md5this);
- auth_digest_md5_to_ascii(md5buf, request_digest);
+ CURL_OUTPUT_DIGEST_CONV(data, hashthis); /* convert on non-ASCII machines */
+ hash(hashbuf, hashthis);
+ free(hashthis);
+ convert_to_ascii(hashbuf, request_digest);
/* For test case 64 (snooped from a Mozilla 1.3a request)
@@ -794,7 +841,7 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
characters. algorithm and qop with standard values only contain web-safe
characters.
*/
- userp_quoted = auth_digest_string_quoted(userp);
+ userp_quoted = auth_digest_string_quoted(digest->userhash ? userh : userp);
if(!userp_quoted)
return CURLE_OUT_OF_MEMORY;
@@ -858,6 +905,16 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
response = tmp;
}
+ if(digest->userhash) {
+ /* Append the userhash */
+ tmp = aprintf("%s, userhash=true", response);
+ free(response);
+ if(!tmp)
+ return CURLE_OUT_OF_MEMORY;
+
+ response = tmp;
+ }
+
/* Return the output */
*outptr = response;
*outlen = strlen(response);
@@ -866,6 +923,58 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
}
/*
+ * Curl_auth_create_digest_http_message()
+ *
+ * This is used to generate a HTTP DIGEST response message ready for sending
+ * to the recipient.
+ *
+ * Parameters:
+ *
+ * data [in] - The session handle.
+ * userp [in] - The user name.
+ * passdwp [in] - The user's password.
+ * request [in] - The HTTP request.
+ * uripath [in] - The path of the HTTP uri.
+ * digest [in/out] - The digest data struct being used and modified.
+ * outptr [in/out] - The address where a pointer to newly allocated memory
+ * holding the result will be stored upon completion.
+ * outlen [out] - The length of the output message.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
+ const char *userp,
+ const char *passwdp,
+ const unsigned char *request,
+ const unsigned char *uripath,
+ struct digestdata *digest,
+ char **outptr, size_t *outlen)
+{
+ switch(digest->algo) {
+ case CURLDIGESTALGO_MD5:
+ case CURLDIGESTALGO_MD5SESS:
+ return _Curl_auth_create_digest_http_message(data, userp, passwdp,
+ request, uripath, digest,
+ outptr, outlen,
+ auth_digest_md5_to_ascii,
+ Curl_md5it);
+
+ case CURLDIGESTALGO_SHA256:
+ case CURLDIGESTALGO_SHA256SESS:
+ case CURLDIGESTALGO_SHA512_256:
+ case CURLDIGESTALGO_SHA512_256SESS:
+ return _Curl_auth_create_digest_http_message(data, userp, passwdp,
+ request, uripath, digest,
+ outptr, outlen,
+ auth_digest_sha256_to_ascii,
+ Curl_sha256it);
+
+ default:
+ return CURLE_UNSUPPORTED_PROTOCOL;
+ }
+}
+
+/*
* Curl_auth_digest_cleanup()
*
* This is used to clean up the digest specific data.
@@ -887,6 +996,7 @@ void Curl_auth_digest_cleanup(struct digestdata *digest)
digest->nc = 0;
digest->algo = CURLDIGESTALGO_MD5; /* default algorithm */
digest->stale = FALSE; /* default means normal, not stale */
+ digest->userhash = FALSE;
}
#endif /* !USE_WINDOWS_SSPI */
diff --git a/lib/vauth/digest.h b/lib/vauth/digest.h
index 5722dcec..8686c44a 100644
--- a/lib/vauth/digest.h
+++ b/lib/vauth/digest.h
@@ -31,7 +31,11 @@
enum {
CURLDIGESTALGO_MD5,
- CURLDIGESTALGO_MD5SESS
+ CURLDIGESTALGO_MD5SESS,
+ CURLDIGESTALGO_SHA256,
+ CURLDIGESTALGO_SHA256SESS,
+ CURLDIGESTALGO_SHA512_256,
+ CURLDIGESTALGO_SHA512_256SESS
};
/* This is used to extract the realm from a challenge message */
diff --git a/lib/vauth/digest_sspi.c b/lib/vauth/digest_sspi.c
index f5d619c9..a3f96ed2 100644
--- a/lib/vauth/digest_sspi.c
+++ b/lib/vauth/digest_sspi.c
@@ -352,8 +352,8 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
if(!Curl_auth_digest_get_pair(p, value, content, &p))
break;
- if(Curl_strcasecompare(value, "stale")
- && Curl_strcasecompare(content, "true")) {
+ if(strcasecompare(value, "stale") &&
+ strcasecompare(content, "true")) {
stale = true;
break;
}
diff --git a/lib/vauth/ntlm.c b/lib/vauth/ntlm.c
index 42196455..1e0d4792 100644
--- a/lib/vauth/ntlm.c
+++ b/lib/vauth/ntlm.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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,7 +44,9 @@
#include "rand.h"
#include "vtls/vtls.h"
-#ifdef USE_NSS
+/* SSL backend-specific #if branches in this file must be kept in the order
+ documented in curl_ntlm_core. */
+#if defined(NTLM_NEEDS_NSS_INIT)
#include "vtls/nssg.h" /* for Curl_nss_force_init() */
#endif
@@ -272,7 +274,7 @@ CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data,
unsigned char *type2 = NULL;
size_t type2_len = 0;
-#if defined(USE_NSS)
+#if defined(NTLM_NEEDS_NSS_INIT)
/* Make sure the crypto backend is initialized */
result = Curl_nss_force_init(data);
if(result)
@@ -350,6 +352,7 @@ static void unicodecpy(unsigned char *dest, const char *src, size_t length)
*
* Parameters:
*
+ * data [in] - The session handle.
* userp [in] - The user name in the format User or Domain\User.
* passdwp [in] - The user's password.
* ntlm [in/out] - The NTLM data struct being used and modified.
@@ -359,7 +362,8 @@ static void unicodecpy(unsigned char *dest, const char *src, size_t length)
*
* Returns CURLE_OK on success.
*/
-CURLcode Curl_auth_create_ntlm_type1_message(const char *userp,
+CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
+ const char *userp,
const char *passwdp,
struct ntlmdata *ntlm,
char **outptr, size_t *outlen)
@@ -458,7 +462,7 @@ CURLcode Curl_auth_create_ntlm_type1_message(const char *userp,
});
/* Return with binary blob encoded into base64 */
- return Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, outlen);
+ return Curl_base64_encode(data, (char *)ntlmbuf, size, outptr, outlen);
}
/*
@@ -539,8 +543,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
else
user = userp;
- if(user)
- userlen = strlen(user);
+ userlen = strlen(user);
/* Get the machine's un-qualified host name as NTLM doesn't like the fully
qualified domain name */
@@ -827,7 +830,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
return CURLE_CONV_FAILED;
/* Return with binary blob encoded into base64 */
- result = Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, outlen);
+ result = Curl_base64_encode(data, (char *)ntlmbuf, size, outptr, outlen);
Curl_auth_ntlm_cleanup(ntlm);
diff --git a/lib/vauth/ntlm_sspi.c b/lib/vauth/ntlm_sspi.c
index c3305176..e748ce3b 100644
--- a/lib/vauth/ntlm_sspi.c
+++ b/lib/vauth/ntlm_sspi.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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
@@ -29,6 +29,7 @@
#include "vauth/vauth.h"
#include "urldata.h"
#include "curl_base64.h"
+#include "curl_ntlm_core.h"
#include "warnless.h"
#include "curl_multibyte.h"
#include "sendf.h"
@@ -66,6 +67,7 @@ bool Curl_auth_is_ntlm_supported(void)
*
* Parameters:
*
+ * data [in] - The session handle.
* userp [in] - The user name in the format User or Domain\User.
* passdwp [in] - The user's password.
* ntlm [in/out] - The NTLM data struct being used and modified.
@@ -75,7 +77,8 @@ bool Curl_auth_is_ntlm_supported(void)
*
* Returns CURLE_OK on success.
*/
-CURLcode Curl_auth_create_ntlm_type1_message(const char *userp,
+CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
+ const char *userp,
const char *passwdp,
struct ntlmdata *ntlm,
char **outptr, size_t *outlen)
@@ -166,7 +169,7 @@ CURLcode Curl_auth_create_ntlm_type1_message(const char *userp,
return CURLE_RECV_ERROR;
/* Base64 encode the response */
- return Curl_base64_encode(NULL, (char *) ntlm->output_token,
+ return Curl_base64_encode(data, (char *) ntlm->output_token,
type_1_buf.cbBuffer, outptr, outlen);
}
diff --git a/lib/vauth/vauth.h b/lib/vauth/vauth.h
index 9d61228c..dfaf985c 100644
--- a/lib/vauth/vauth.h
+++ b/lib/vauth/vauth.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2014 - 2016, Steve Holme, <steve_holme@hotmail.com>.
+ * Copyright (C) 2014 - 2017, Steve Holme, <steve_holme@hotmail.com>.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -119,7 +119,8 @@ void Curl_auth_digest_cleanup(struct digestdata *digest);
bool Curl_auth_is_ntlm_supported(void);
/* This is used to generate a base64 encoded NTLM type-1 message */
-CURLcode Curl_auth_create_ntlm_type1_message(const char *userp,
+CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
+ const char *userp,
const char *passwdp,
struct ntlmdata *ntlm,
char **outptr,
diff --git a/lib/version.c b/lib/version.c
index 3d177681..79cc0bba 100644
--- a/lib/version.c
+++ b/lib/version.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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
@@ -64,6 +64,18 @@
#define CURL_LIBSSH2_VERSION LIBSSH2_VERSION
#endif
+#ifdef HAVE_ZLIB_H
+#include <zlib.h>
+#ifdef __SYMBIAN32__
+/* zlib pollutes the namespace with this definition */
+#undef WIN32
+#endif
+#endif
+
+#ifdef HAVE_BROTLI
+#include <brotli/decode.h>
+#endif
+
void Curl_version_init(void);
/* For thread safety purposes this function is called by global_init so that
@@ -74,6 +86,18 @@ void Curl_version_init(void)
curl_version_info(CURLVERSION_NOW);
}
+#ifdef HAVE_BROTLI
+static size_t brotli_version(char *buf, size_t bufsz)
+{
+ uint32_t brotli_version = BrotliDecoderVersion();
+ unsigned int major = brotli_version >> 24;
+ unsigned int minor = (brotli_version & 0x00FFFFFF) >> 12;
+ unsigned int patch = brotli_version & 0x00000FFF;
+
+ return snprintf(buf, bufsz, "%u.%u.%u", major, minor, patch);
+}
+#endif
+
char *curl_version(void)
{
static bool initialized;
@@ -105,6 +129,14 @@ char *curl_version(void)
left -= len;
ptr += len;
#endif
+#ifdef HAVE_BROTLI
+ len = snprintf(ptr, left, "%s", " brotli/");
+ left -= len;
+ ptr += len;
+ len = brotli_version(ptr, left);
+ left -= len;
+ ptr += len;
+#endif
#ifdef USE_ARES
/* this function is only present in c-ares, not in the original ares */
len = snprintf(ptr, left, " c-ares/%s", ares_version(NULL));
@@ -324,8 +356,11 @@ static curl_version_info_data version_info = {
#if defined(USE_LIBPSL)
| CURL_VERSION_PSL
#endif
-#if defined(HTTPS_PROXY_SUPPORT)
- | CURL_VERSION_HTTPS_PROXY
+#if defined(CURL_WITH_MULTI_SSL)
+ | CURL_VERSION_MULTI_SSL
+#endif
+#if defined(HAVE_BROTLI)
+ | CURL_VERSION_BROTLI
#endif
,
NULL, /* ssl_version */
@@ -337,6 +372,8 @@ static curl_version_info_data version_info = {
NULL, /* libidn version */
0, /* iconv version */
NULL, /* ssh lib version */
+ 0, /* brotli_ver_num */
+ NULL, /* brotli version */
};
curl_version_info_data *curl_version_info(CURLversion stamp)
@@ -348,6 +385,9 @@ curl_version_info_data *curl_version_info(CURLversion stamp)
#ifdef USE_SSL
static char ssl_buffer[80];
#endif
+#ifdef HAVE_BROTLI
+ static char brotli_buffer[80];
+#endif
if(initialized)
return &version_info;
@@ -355,6 +395,10 @@ curl_version_info_data *curl_version_info(CURLversion stamp)
#ifdef USE_SSL
Curl_ssl_version(ssl_buffer, sizeof(ssl_buffer));
version_info.ssl_version = ssl_buffer;
+ if(Curl_ssl->support_https_proxy)
+ version_info.features |= CURL_VERSION_HTTPS_PROXY;
+ else
+ version_info.features &= ~CURL_VERSION_HTTPS_PROXY;
#endif
#ifdef HAVE_LIBZ
@@ -392,6 +436,12 @@ curl_version_info_data *curl_version_info(CURLversion stamp)
version_info.libssh_version = ssh_buffer;
#endif
+#ifdef HAVE_BROTLI
+ version_info.brotli_ver_num = BrotliDecoderVersion();
+ brotli_version(brotli_buffer, sizeof brotli_buffer);
+ version_info.brotli_version = brotli_buffer;
+#endif
+
(void)stamp; /* avoid compiler warnings, we don't use this */
initialized = true;
diff --git a/lib/vtls/axtls.c b/lib/vtls/axtls.c
index f0e37664..9294f49e 100644
--- a/lib/vtls/axtls.c
+++ b/lib/vtls/axtls.c
@@ -47,21 +47,12 @@
#include "curl_memory.h"
#include "memdebug.h"
+struct ssl_backend_data {
+ SSL_CTX* ssl_ctx;
+ SSL* ssl;
+};
-/* Global axTLS init, called from Curl_ssl_init() */
-int Curl_axtls_init(void)
-{
-/* axTLS has no global init. Everything is done through SSL and SSL_CTX
- * structs stored in connectdata structure. Perhaps can move to axtls.h.
- */
- return 1;
-}
-
-int Curl_axtls_cleanup(void)
-{
- /* axTLS has no global cleanup. Perhaps can move this to axtls.h. */
- return 1;
-}
+#define BACKEND connssl->backend
static CURLcode map_error_to_curl(int axtls_err)
{
@@ -120,13 +111,13 @@ static Curl_send axtls_send;
static void free_ssl_structs(struct ssl_connect_data *connssl)
{
- if(connssl->ssl) {
- ssl_free(connssl->ssl);
- connssl->ssl = NULL;
+ if(BACKEND->ssl) {
+ ssl_free(BACKEND->ssl);
+ BACKEND->ssl = NULL;
}
- if(connssl->ssl_ctx) {
- ssl_ctx_free(connssl->ssl_ctx);
- connssl->ssl_ctx = NULL;
+ if(BACKEND->ssl_ctx) {
+ ssl_ctx_free(BACKEND->ssl_ctx);
+ BACKEND->ssl_ctx = NULL;
}
}
@@ -137,6 +128,7 @@ static void free_ssl_structs(struct ssl_connect_data *connssl)
*/
static CURLcode connect_prep(struct connectdata *conn, int sockindex)
{
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct Curl_easy *data = conn->data;
SSL_CTX *ssl_ctx;
SSL *ssl = NULL;
@@ -151,7 +143,7 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex)
SSL_SERVER_VERIFY_LATER |
SSL_CONNECT_IN_PARTS;
- if(conn->ssl[sockindex].state == ssl_connection_complete)
+ if(connssl->state == ssl_connection_complete)
/* to make us tolerant against being called more than once for the
same connection */
return CURLE_OK;
@@ -185,8 +177,8 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex)
return CURLE_SSL_CONNECT_ERROR;
}
- conn->ssl[sockindex].ssl_ctx = ssl_ctx;
- conn->ssl[sockindex].ssl = NULL;
+ BACKEND->ssl_ctx = ssl_ctx;
+ BACKEND->ssl = NULL;
/* Load the trusted CA cert bundle file */
if(SSL_CONN_CONFIG(CAfile)) {
@@ -212,7 +204,7 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex)
/* Load client certificate */
if(SSL_SET_OPTION(cert)) {
- i=0;
+ i = 0;
/* Instead of trying to analyze cert type here, let axTLS try them all. */
while(cert_types[i] != 0) {
ssl_fcn_return = ssl_obj_load(ssl_ctx, cert_types[i],
@@ -236,7 +228,7 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex)
If a pkcs12 file successfully loaded a cert, then there's nothing to do
because the key has already been loaded. */
if(SSL_SET_OPTION(key) && cert_types[i] != SSL_OBJ_PKCS12) {
- i=0;
+ i = 0;
/* Instead of trying to analyze key type here, let axTLS try them all. */
while(key_types[i] != 0) {
ssl_fcn_return = ssl_obj_load(ssl_ctx, key_types[i],
@@ -281,10 +273,26 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex)
if(!ssl)
ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex], NULL, 0, NULL);
- conn->ssl[sockindex].ssl = ssl;
+ BACKEND->ssl = ssl;
return CURLE_OK;
}
+static void Curl_axtls_close(struct connectdata *conn, int sockindex)
+{
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+
+ infof(conn->data, " Curl_axtls_close\n");
+
+ /* line from openssl.c: (void)SSL_shutdown(BACKEND->ssl);
+ axTLS compat layer does nothing for SSL_shutdown */
+
+ /* The following line is from openssl.c. There seems to be no axTLS
+ equivalent. ssl_free and ssl_ctx_free close things.
+ SSL_set_connect_state(connssl->handle); */
+
+ free_ssl_structs(connssl);
+}
+
/*
* For both blocking and non-blocking connects, this function finalizes the
* SSL connection.
@@ -292,7 +300,8 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex)
static CURLcode connect_finish(struct connectdata *conn, int sockindex)
{
struct Curl_easy *data = conn->data;
- SSL *ssl = conn->ssl[sockindex].ssl;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ SSL *ssl = BACKEND->ssl;
const char *peer_CN;
uint32_t dns_altname_index;
const char *dns_altname;
@@ -387,7 +396,7 @@ static CURLcode connect_finish(struct connectdata *conn, int sockindex)
}
/* General housekeeping */
- conn->ssl[sockindex].state = ssl_connection_complete;
+ connssl->state = ssl_connection_complete;
conn->recv[sockindex] = axtls_recv;
conn->send[sockindex] = axtls_send;
@@ -409,11 +418,10 @@ static CURLcode connect_finish(struct connectdata *conn, int sockindex)
* Use axTLS's non-blocking connection feature to open an SSL connection.
* This is called after a TCP connection is already established.
*/
-CURLcode Curl_axtls_connect_nonblocking(
- struct connectdata *conn,
- int sockindex,
- bool *done)
+static CURLcode Curl_axtls_connect_nonblocking(struct connectdata *conn,
+ int sockindex, bool *done)
{
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
CURLcode conn_step;
int ssl_fcn_return;
int i;
@@ -421,23 +429,23 @@ CURLcode Curl_axtls_connect_nonblocking(
*done = FALSE;
/* connectdata is calloc'd and connecting_state is only changed in this
function, so this is safe, as the state is effectively initialized. */
- if(conn->ssl[sockindex].connecting_state == ssl_connect_1) {
+ if(connssl->connecting_state == ssl_connect_1) {
conn_step = connect_prep(conn, sockindex);
if(conn_step != CURLE_OK) {
Curl_axtls_close(conn, sockindex);
return conn_step;
}
- conn->ssl[sockindex].connecting_state = ssl_connect_2;
+ connssl->connecting_state = ssl_connect_2;
}
- if(conn->ssl[sockindex].connecting_state == ssl_connect_2) {
+ if(connssl->connecting_state == ssl_connect_2) {
/* Check to make sure handshake was ok. */
- if(ssl_handshake_status(conn->ssl[sockindex].ssl) != SSL_OK) {
+ if(ssl_handshake_status(BACKEND->ssl) != SSL_OK) {
/* Loop to perform more work in between sleeps. This is work around the
fact that axtls does not expose any knowledge about when work needs
to be performed. This can save ~25% of time on SSL handshakes. */
- for(i=0; i<5; i++) {
- ssl_fcn_return = ssl_read(conn->ssl[sockindex].ssl, NULL);
+ for(i = 0; i<5; i++) {
+ ssl_fcn_return = ssl_read(BACKEND->ssl, NULL);
if(ssl_fcn_return < 0) {
Curl_axtls_close(conn, sockindex);
ssl_display_error(ssl_fcn_return); /* goes to stdout. */
@@ -447,10 +455,10 @@ CURLcode Curl_axtls_connect_nonblocking(
}
}
infof(conn->data, "handshake completed successfully\n");
- conn->ssl[sockindex].connecting_state = ssl_connect_3;
+ connssl->connecting_state = ssl_connect_3;
}
- if(conn->ssl[sockindex].connecting_state == ssl_connect_3) {
+ if(connssl->connecting_state == ssl_connect_3) {
conn_step = connect_finish(conn, sockindex);
if(conn_step != CURLE_OK) {
Curl_axtls_close(conn, sockindex);
@@ -458,15 +466,15 @@ CURLcode Curl_axtls_connect_nonblocking(
}
/* Reset connect state */
- conn->ssl[sockindex].connecting_state = ssl_connect_1;
+ connssl->connecting_state = ssl_connect_1;
*done = TRUE;
return CURLE_OK;
}
/* Unrecognized state. Things are very bad. */
- conn->ssl[sockindex].state = ssl_connection_none;
- conn->ssl[sockindex].connecting_state = ssl_connect_1;
+ connssl->state = ssl_connection_none;
+ connssl->connecting_state = ssl_connect_1;
/* Return value perhaps not strictly correct, but distinguishes the issue.*/
return CURLE_BAD_FUNCTION_ARGUMENT;
}
@@ -476,15 +484,13 @@ CURLcode Curl_axtls_connect_nonblocking(
* This function is called after the TCP connect has completed. Setup the TLS
* layer and do all necessary magic for a blocking connect.
*/
-CURLcode
-Curl_axtls_connect(struct connectdata *conn,
- int sockindex)
-
+static CURLcode Curl_axtls_connect(struct connectdata *conn, int sockindex)
{
struct Curl_easy *data = conn->data;
CURLcode conn_step = connect_prep(conn, sockindex);
int ssl_fcn_return;
- SSL *ssl = conn->ssl[sockindex].ssl;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ SSL *ssl = BACKEND->ssl;
long timeout_ms;
if(conn_step != CURLE_OK) {
@@ -530,8 +536,9 @@ static ssize_t axtls_send(struct connectdata *conn,
size_t len,
CURLcode *err)
{
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
/* ssl_write() returns 'int' while write() and send() returns 'size_t' */
- int rc = ssl_write(conn->ssl[sockindex].ssl, mem, (int)len);
+ int rc = ssl_write(BACKEND->ssl, mem, (int)len);
infof(conn->data, " axtls_send\n");
@@ -544,27 +551,11 @@ static ssize_t axtls_send(struct connectdata *conn,
return rc;
}
-void Curl_axtls_close(struct connectdata *conn, int sockindex)
-{
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-
- infof(conn->data, " Curl_axtls_close\n");
-
- /* line from openssl.c: (void)SSL_shutdown(connssl->ssl);
- axTLS compat layer does nothing for SSL_shutdown */
-
- /* The following line is from openssl.c. There seems to be no axTLS
- equivalent. ssl_free and ssl_ctx_free close things.
- SSL_set_connect_state(connssl->handle); */
-
- free_ssl_structs(connssl);
-}
-
/*
* This function is called to shut down the SSL layer but keep the
* socket open (CCC - Clear Command Channel)
*/
-int Curl_axtls_shutdown(struct connectdata *conn, int sockindex)
+static int Curl_axtls_shutdown(struct connectdata *conn, int sockindex)
{
/* Outline taken from openssl.c since functions are in axTLS compat layer.
axTLS's error set is much smaller, so a lot of error-handling was removed.
@@ -584,17 +575,17 @@ int Curl_axtls_shutdown(struct connectdata *conn, int sockindex)
/* axTLS compat layer does nothing for SSL_shutdown, so we do nothing too
if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
- (void)SSL_shutdown(connssl->ssl);
+ (void)SSL_shutdown(BACKEND->ssl);
*/
- if(connssl->ssl) {
+ if(BACKEND->ssl) {
int what = SOCKET_READABLE(conn->sock[sockindex], SSL_SHUTDOWN_TIMEOUT);
if(what > 0) {
/* Something to read, let's do it and hope that it is the close
notify alert from the server. buf is managed internally by
axTLS and will be released upon calling ssl_free via
free_ssl_structs. */
- nread = (ssize_t)ssl_read(connssl->ssl, &buf);
+ nread = (ssize_t)ssl_read(BACKEND->ssl, &buf);
if(nread < SSL_OK) {
failf(data, "close notify alert not received during shutdown");
@@ -630,7 +621,7 @@ static ssize_t axtls_recv(struct connectdata *conn, /* connection data */
*err = CURLE_OK;
if(connssl) {
- ret = ssl_read(connssl->ssl, &read_buf);
+ ret = ssl_read(BACKEND->ssl, &read_buf);
if(ret > SSL_OK) {
/* ssl_read returns SSL_OK if there is more data to read, so if it is
larger, then all data has been read already. */
@@ -663,9 +654,10 @@ static ssize_t axtls_recv(struct connectdata *conn, /* connection data */
* 0 means the connection has been closed
* -1 means the connection status is unknown
*/
-int Curl_axtls_check_cxn(struct connectdata *conn)
+static int Curl_axtls_check_cxn(struct connectdata *conn)
{
- /* openssl.c line: rc = SSL_peek(conn->ssl[FIRSTSOCKET].ssl, (void*)&buf, 1);
+ /* openssl.c line:
+ rc = SSL_peek(conn->ssl[FIRSTSOCKET].backend->ssl, (void*)&buf, 1);
axTLS compat layer always returns the last argument, so connection is
always alive? */
@@ -673,7 +665,7 @@ int Curl_axtls_check_cxn(struct connectdata *conn)
return 1; /* connection still in place */
}
-void Curl_axtls_session_free(void *ptr)
+static void Curl_axtls_session_free(void *ptr)
{
(void)ptr;
/* free the ID */
@@ -681,14 +673,13 @@ void Curl_axtls_session_free(void *ptr)
compatibility layer does nothing, so we do nothing too. */
}
-size_t Curl_axtls_version(char *buffer, size_t size)
+static size_t Curl_axtls_version(char *buffer, size_t size)
{
return snprintf(buffer, size, "axTLS/%s", ssl_version());
}
-CURLcode Curl_axtls_random(struct Curl_easy *data,
- unsigned char *entropy,
- size_t length)
+static CURLcode Curl_axtls_random(struct Curl_easy *data,
+ unsigned char *entropy, size_t length)
{
static bool ssl_seeded = FALSE;
(void)data;
@@ -703,4 +694,49 @@ CURLcode Curl_axtls_random(struct Curl_easy *data,
return CURLE_OK;
}
+static void *Curl_axtls_get_internals(struct ssl_connect_data *connssl,
+ CURLINFO info UNUSED_PARAM)
+{
+ (void)info;
+ return BACKEND->ssl;
+}
+
+const struct Curl_ssl Curl_ssl_axtls = {
+ { CURLSSLBACKEND_AXTLS, "axtls" }, /* info */
+
+ 0, /* have_ca_path */
+ 0, /* have_certinfo */
+ 0, /* have_pinnedpubkey */
+ 0, /* have_ssl_ctx */
+ 0, /* support_https_proxy */
+
+ sizeof(struct ssl_backend_data),
+
+ /*
+ * axTLS has no global init. Everything is done through SSL and SSL_CTX
+ * structs stored in connectdata structure.
+ */
+ Curl_none_init, /* init */
+ /* axTLS has no global cleanup. */
+ Curl_none_cleanup, /* cleanup */
+ Curl_axtls_version, /* version */
+ Curl_axtls_check_cxn, /* check_cxn */
+ Curl_axtls_shutdown, /* shutdown */
+ Curl_none_data_pending, /* data_pending */
+ Curl_axtls_random, /* random */
+ Curl_none_cert_status_request, /* cert_status_request */
+ Curl_axtls_connect, /* connect */
+ Curl_axtls_connect_nonblocking, /* connect_nonblocking */
+ Curl_axtls_get_internals, /* get_internals */
+ Curl_axtls_close, /* close_one */
+ Curl_none_close_all, /* close_all */
+ Curl_axtls_session_free, /* session_free */
+ Curl_none_set_engine, /* set_engine */
+ Curl_none_set_engine_default, /* set_engine_default */
+ Curl_none_engines_list, /* engines_list */
+ Curl_none_false_start, /* false_start */
+ Curl_none_md5sum, /* md5sum */
+ NULL /* sha256sum */
+};
+
#endif /* USE_AXTLS */
diff --git a/lib/vtls/axtls.h b/lib/vtls/axtls.h
index 53797ead..3f1e129c 100644
--- a/lib/vtls/axtls.h
+++ b/lib/vtls/axtls.h
@@ -27,44 +27,7 @@
#include "curl/curl.h"
#include "urldata.h"
-int Curl_axtls_init(void);
-int Curl_axtls_cleanup(void);
-CURLcode Curl_axtls_connect(struct connectdata *conn, int sockindex);
-CURLcode Curl_axtls_connect_nonblocking(
- struct connectdata *conn,
- int sockindex,
- bool *done);
-
- /* close a SSL connection */
-void Curl_axtls_close(struct connectdata *conn, int sockindex);
-
-void Curl_axtls_session_free(void *ptr);
-size_t Curl_axtls_version(char *buffer, size_t size);
-int Curl_axtls_shutdown(struct connectdata *conn, int sockindex);
-int Curl_axtls_check_cxn(struct connectdata *conn);
-CURLcode Curl_axtls_random(struct Curl_easy *data,
- unsigned char *entropy,
- size_t length);
-
-/* Set the API backend definition to axTLS */
-#define CURL_SSL_BACKEND CURLSSLBACKEND_AXTLS
-
-/* API setup for axTLS */
-#define curlssl_init Curl_axtls_init
-#define curlssl_cleanup Curl_axtls_cleanup
-#define curlssl_connect Curl_axtls_connect
-#define curlssl_connect_nonblocking Curl_axtls_connect_nonblocking
-#define curlssl_session_free(x) Curl_axtls_session_free(x)
-#define curlssl_close_all(x) ((void)x)
-#define curlssl_close Curl_axtls_close
-#define curlssl_shutdown(x,y) Curl_axtls_shutdown(x,y)
-#define curlssl_set_engine(x,y) ((void)x, (void)y, CURLE_NOT_BUILT_IN)
-#define curlssl_set_engine_default(x) ((void)x, CURLE_NOT_BUILT_IN)
-#define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL)
-#define curlssl_version Curl_axtls_version
-#define curlssl_check_cxn(x) Curl_axtls_check_cxn(x)
-#define curlssl_data_pending(x,y) ((void)x, (void)y, 0)
-#define curlssl_random(x,y,z) Curl_axtls_random(x,y,z)
+extern const struct Curl_ssl Curl_ssl_axtls;
#endif /* USE_AXTLS */
#endif /* HEADER_CURL_AXTLS_H */
diff --git a/lib/vtls/cyassl.c b/lib/vtls/cyassl.c
index 01bfdabd..e0652230 100644
--- a/lib/vtls/cyassl.c
+++ b/lib/vtls/cyassl.c
@@ -91,6 +91,7 @@ and that's a problem since options.h hasn't been included yet. */
#include "x509asn1.h"
#include "curl_printf.h"
+#include <cyassl/openssl/ssl.h>
#include <cyassl/ssl.h>
#ifdef HAVE_CYASSL_ERROR_SSL_H
#include <cyassl/error-ssl.h>
@@ -110,6 +111,25 @@ and that's a problem since options.h hasn't been included yet. */
#define CYASSL_MAX_ERROR_SZ 80
#endif
+/* KEEP_PEER_CERT is a product of the presence of build time symbol
+ OPENSSL_EXTRA without NO_CERTS, depending on the version. KEEP_PEER_CERT is
+ in wolfSSL's settings.h, and the latter two are build time symbols in
+ options.h. */
+#ifndef KEEP_PEER_CERT
+#if defined(HAVE_CYASSL_GET_PEER_CERTIFICATE) || \
+ defined(HAVE_WOLFSSL_GET_PEER_CERTIFICATE) || \
+ (defined(OPENSSL_EXTRA) && !defined(NO_CERTS))
+#define KEEP_PEER_CERT
+#endif
+#endif
+
+struct ssl_backend_data {
+ SSL_CTX* ctx;
+ SSL* handle;
+};
+
+#define BACKEND connssl->backend
+
static Curl_recv cyassl_recv;
static Curl_send cyassl_send;
@@ -136,7 +156,7 @@ cyassl_connect_step1(struct connectdata *conn,
char error_buffer[CYASSL_MAX_ERROR_SZ];
char *ciphers;
struct Curl_easy *data = conn->data;
- struct ssl_connect_data* conssl = &conn->ssl[sockindex];
+ struct ssl_connect_data* connssl = &conn->ssl[sockindex];
SSL_METHOD* req_method = NULL;
curl_socket_t sockfd = conn->sock[sockindex];
#ifdef HAVE_SNI
@@ -146,7 +166,7 @@ cyassl_connect_step1(struct connectdata *conn,
#define use_sni(x) Curl_nop_stmt
#endif
- if(conssl->state == ssl_connection_complete)
+ if(connssl->state == ssl_connection_complete)
return CURLE_OK;
if(SSL_CONN_CONFIG(version_max) != CURL_SSLVERSION_MAX_NONE) {
@@ -205,11 +225,11 @@ cyassl_connect_step1(struct connectdata *conn,
return CURLE_OUT_OF_MEMORY;
}
- if(conssl->ctx)
- SSL_CTX_free(conssl->ctx);
- conssl->ctx = SSL_CTX_new(req_method);
+ if(BACKEND->ctx)
+ SSL_CTX_free(BACKEND->ctx);
+ BACKEND->ctx = SSL_CTX_new(req_method);
- if(!conssl->ctx) {
+ if(!BACKEND->ctx) {
failf(data, "SSL: couldn't create a context!");
return CURLE_OUT_OF_MEMORY;
}
@@ -225,9 +245,9 @@ cyassl_connect_step1(struct connectdata *conn,
version. We use wolfSSL_CTX_SetMinVersion and not CyaSSL_SetMinVersion
because only the former will work before the user's CTX callback is called.
*/
- if((wolfSSL_CTX_SetMinVersion(conssl->ctx, WOLFSSL_TLSV1) != 1) &&
- (wolfSSL_CTX_SetMinVersion(conssl->ctx, WOLFSSL_TLSV1_1) != 1) &&
- (wolfSSL_CTX_SetMinVersion(conssl->ctx, WOLFSSL_TLSV1_2) != 1)) {
+ if((wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1) != 1) &&
+ (wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1_1) != 1) &&
+ (wolfSSL_CTX_SetMinVersion(BACKEND->ctx, WOLFSSL_TLSV1_2) != 1)) {
failf(data, "SSL: couldn't set the minimum protocol version");
return CURLE_SSL_CONNECT_ERROR;
}
@@ -237,7 +257,7 @@ cyassl_connect_step1(struct connectdata *conn,
ciphers = SSL_CONN_CONFIG(cipher_list);
if(ciphers) {
- if(!SSL_CTX_set_cipher_list(conssl->ctx, ciphers)) {
+ if(!SSL_CTX_set_cipher_list(BACKEND->ctx, ciphers)) {
failf(data, "failed setting cipher list: %s", ciphers);
return CURLE_SSL_CIPHER;
}
@@ -247,7 +267,7 @@ cyassl_connect_step1(struct connectdata *conn,
#ifndef NO_FILESYSTEM
/* load trusted cacert */
if(SSL_CONN_CONFIG(CAfile)) {
- if(1 != SSL_CTX_load_verify_locations(conssl->ctx,
+ if(1 != SSL_CTX_load_verify_locations(BACKEND->ctx,
SSL_CONN_CONFIG(CAfile),
SSL_CONN_CONFIG(CApath))) {
if(SSL_CONN_CONFIG(verifypeer)) {
@@ -284,7 +304,7 @@ cyassl_connect_step1(struct connectdata *conn,
if(SSL_SET_OPTION(cert) && SSL_SET_OPTION(key)) {
int file_type = do_file_type(SSL_SET_OPTION(cert_type));
- if(SSL_CTX_use_certificate_file(conssl->ctx, SSL_SET_OPTION(cert),
+ if(SSL_CTX_use_certificate_file(BACKEND->ctx, SSL_SET_OPTION(cert),
file_type) != 1) {
failf(data, "unable to use client certificate (no key or wrong pass"
" phrase?)");
@@ -292,7 +312,7 @@ cyassl_connect_step1(struct connectdata *conn,
}
file_type = do_file_type(SSL_SET_OPTION(key_type));
- if(SSL_CTX_use_PrivateKey_file(conssl->ctx, SSL_SET_OPTION(key),
+ if(SSL_CTX_use_PrivateKey_file(BACKEND->ctx, SSL_SET_OPTION(key),
file_type) != 1) {
failf(data, "unable to set private key");
return CURLE_SSL_CONNECT_ERROR;
@@ -304,7 +324,7 @@ cyassl_connect_step1(struct connectdata *conn,
* 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(conssl->ctx,
+ SSL_CTX_set_verify(BACKEND->ctx,
SSL_CONN_CONFIG(verifypeer)?SSL_VERIFY_PEER:
SSL_VERIFY_NONE,
NULL);
@@ -323,7 +343,7 @@ cyassl_connect_step1(struct connectdata *conn,
#ifdef ENABLE_IPV6
(0 == Curl_inet_pton(AF_INET6, hostname, &addr6)) &&
#endif
- (CyaSSL_CTX_UseSNI(conssl->ctx, CYASSL_SNI_HOST_NAME, hostname,
+ (CyaSSL_CTX_UseSNI(BACKEND->ctx, CYASSL_SNI_HOST_NAME, hostname,
(unsigned short)hostname_len) != 1)) {
infof(data, "WARNING: failed to configure server name indication (SNI) "
"TLS extension\n");
@@ -336,15 +356,15 @@ cyassl_connect_step1(struct connectdata *conn,
https://github.com/wolfSSL/wolfssl/issues/366
The supported curves below are those also supported by OpenSSL 1.0.2 and
in the same order. */
- CyaSSL_CTX_UseSupportedCurve(conssl->ctx, 0x17); /* secp256r1 */
- CyaSSL_CTX_UseSupportedCurve(conssl->ctx, 0x19); /* secp521r1 */
- CyaSSL_CTX_UseSupportedCurve(conssl->ctx, 0x18); /* secp384r1 */
+ CyaSSL_CTX_UseSupportedCurve(BACKEND->ctx, 0x17); /* secp256r1 */
+ CyaSSL_CTX_UseSupportedCurve(BACKEND->ctx, 0x19); /* secp521r1 */
+ CyaSSL_CTX_UseSupportedCurve(BACKEND->ctx, 0x18); /* secp384r1 */
#endif
/* give application a chance to interfere with SSL set up. */
if(data->set.ssl.fsslctx) {
CURLcode result = CURLE_OK;
- result = (*data->set.ssl.fsslctx)(data, conssl->ctx,
+ result = (*data->set.ssl.fsslctx)(data, BACKEND->ctx,
data->set.ssl.fsslctxp);
if(result) {
failf(data, "error signaled by ssl ctx callback");
@@ -362,10 +382,10 @@ cyassl_connect_step1(struct connectdata *conn,
#endif
/* Let's make an SSL structure */
- if(conssl->handle)
- SSL_free(conssl->handle);
- conssl->handle = SSL_new(conssl->ctx);
- if(!conssl->handle) {
+ if(BACKEND->handle)
+ SSL_free(BACKEND->handle);
+ BACKEND->handle = SSL_new(BACKEND->ctx);
+ if(!BACKEND->handle) {
failf(data, "SSL: couldn't create a context (handle)!");
return CURLE_OUT_OF_MEMORY;
}
@@ -388,7 +408,7 @@ cyassl_connect_step1(struct connectdata *conn,
strcpy(protocols + strlen(protocols), ALPN_HTTP_1_1);
infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1);
- if(wolfSSL_UseALPN(conssl->handle, protocols,
+ if(wolfSSL_UseALPN(BACKEND->handle, protocols,
(unsigned)strlen(protocols),
WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) != SSL_SUCCESS) {
failf(data, "SSL: failed setting ALPN protocols");
@@ -404,10 +424,10 @@ cyassl_connect_step1(struct connectdata *conn,
Curl_ssl_sessionid_lock(conn);
if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) {
/* we got a session id, use it! */
- if(!SSL_set_session(conssl->handle, ssl_sessionid)) {
+ if(!SSL_set_session(BACKEND->handle, ssl_sessionid)) {
Curl_ssl_sessionid_unlock(conn);
failf(data, "SSL: SSL_set_session failed: %s",
- ERR_error_string(SSL_get_error(conssl->handle, 0),
+ ERR_error_string(SSL_get_error(BACKEND->handle, 0),
error_buffer));
return CURLE_SSL_CONNECT_ERROR;
}
@@ -418,12 +438,12 @@ cyassl_connect_step1(struct connectdata *conn,
}
/* pass the raw socket into the SSL layer */
- if(!SSL_set_fd(conssl->handle, (int)sockfd)) {
+ if(!SSL_set_fd(BACKEND->handle, (int)sockfd)) {
failf(data, "SSL: SSL_set_fd failed");
return CURLE_SSL_CONNECT_ERROR;
}
- conssl->connecting_state = ssl_connect_2;
+ connssl->connecting_state = ssl_connect_2;
return CURLE_OK;
}
@@ -434,7 +454,7 @@ cyassl_connect_step2(struct connectdata *conn,
{
int ret = -1;
struct Curl_easy *data = conn->data;
- struct ssl_connect_data* conssl = &conn->ssl[sockindex];
+ struct ssl_connect_data* connssl = &conn->ssl[sockindex];
const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
conn->host.name;
const char * const dispname = SSL_IS_PROXY() ?
@@ -448,22 +468,22 @@ cyassl_connect_step2(struct connectdata *conn,
/* Enable RFC2818 checks */
if(SSL_CONN_CONFIG(verifyhost)) {
- ret = CyaSSL_check_domain_name(conssl->handle, hostname);
+ ret = CyaSSL_check_domain_name(BACKEND->handle, hostname);
if(ret == SSL_FAILURE)
return CURLE_OUT_OF_MEMORY;
}
- ret = SSL_connect(conssl->handle);
+ ret = SSL_connect(BACKEND->handle);
if(ret != 1) {
char error_buffer[CYASSL_MAX_ERROR_SZ];
- int detail = SSL_get_error(conssl->handle, ret);
+ int detail = SSL_get_error(BACKEND->handle, ret);
if(SSL_ERROR_WANT_READ == detail) {
- conssl->connecting_state = ssl_connect_2_reading;
+ connssl->connecting_state = ssl_connect_2_reading;
return CURLE_OK;
}
else if(SSL_ERROR_WANT_WRITE == detail) {
- conssl->connecting_state = ssl_connect_2_writing;
+ connssl->connecting_state = ssl_connect_2_writing;
return CURLE_OK;
}
/* There is no easy way to override only the CN matching.
@@ -524,7 +544,7 @@ cyassl_connect_step2(struct connectdata *conn,
curl_asn1Element *pubkey;
CURLcode result;
- x509 = SSL_get_peer_certificate(conssl->handle);
+ x509 = SSL_get_peer_certificate(BACKEND->handle);
if(!x509) {
failf(data, "SSL: failed retrieving server certificate");
return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
@@ -566,7 +586,7 @@ cyassl_connect_step2(struct connectdata *conn,
char *protocol = NULL;
unsigned short protocol_len = 0;
- rc = wolfSSL_ALPN_GetProtocol(conssl->handle, &protocol, &protocol_len);
+ rc = wolfSSL_ALPN_GetProtocol(BACKEND->handle, &protocol, &protocol_len);
if(rc == SSL_SUCCESS) {
infof(data, "ALPN, server accepted to use %.*s\n", protocol_len,
@@ -595,11 +615,11 @@ cyassl_connect_step2(struct connectdata *conn,
}
#endif /* HAVE_ALPN */
- conssl->connecting_state = ssl_connect_3;
+ connssl->connecting_state = ssl_connect_3;
#if (LIBCYASSL_VERSION_HEX >= 0x03009010)
infof(data, "SSL connection using %s / %s\n",
- wolfSSL_get_version(conssl->handle),
- wolfSSL_get_cipher_name(conssl->handle));
+ wolfSSL_get_version(BACKEND->handle),
+ wolfSSL_get_cipher_name(BACKEND->handle));
#else
infof(data, "SSL connected\n");
#endif
@@ -623,7 +643,7 @@ cyassl_connect_step3(struct connectdata *conn,
SSL_SESSION *our_ssl_sessionid;
void *old_ssl_sessionid = NULL;
- our_ssl_sessionid = SSL_get_session(connssl->handle);
+ our_ssl_sessionid = SSL_get_session(BACKEND->handle);
Curl_ssl_sessionid_lock(conn);
incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL,
@@ -660,12 +680,13 @@ static ssize_t cyassl_send(struct connectdata *conn,
size_t len,
CURLcode *curlcode)
{
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
char error_buffer[CYASSL_MAX_ERROR_SZ];
int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
- int rc = SSL_write(conn->ssl[sockindex].handle, mem, memlen);
+ int rc = SSL_write(BACKEND->handle, mem, memlen);
if(rc < 0) {
- int err = SSL_get_error(conn->ssl[sockindex].handle, rc);
+ int err = SSL_get_error(BACKEND->handle, rc);
switch(err) {
case SSL_ERROR_WANT_READ:
@@ -684,18 +705,18 @@ static ssize_t cyassl_send(struct connectdata *conn,
return rc;
}
-void Curl_cyassl_close(struct connectdata *conn, int sockindex)
+static void Curl_cyassl_close(struct connectdata *conn, int sockindex)
{
- struct ssl_connect_data *conssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- if(conssl->handle) {
- (void)SSL_shutdown(conssl->handle);
- SSL_free(conssl->handle);
- conssl->handle = NULL;
+ if(BACKEND->handle) {
+ (void)SSL_shutdown(BACKEND->handle);
+ SSL_free(BACKEND->handle);
+ BACKEND->handle = NULL;
}
- if(conssl->ctx) {
- SSL_CTX_free(conssl->ctx);
- conssl->ctx = NULL;
+ if(BACKEND->ctx) {
+ SSL_CTX_free(BACKEND->ctx);
+ BACKEND->ctx = NULL;
}
}
@@ -705,12 +726,13 @@ static ssize_t cyassl_recv(struct connectdata *conn,
size_t buffersize,
CURLcode *curlcode)
{
+ struct ssl_connect_data *connssl = &conn->ssl[num];
char error_buffer[CYASSL_MAX_ERROR_SZ];
int buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
- int nread = SSL_read(conn->ssl[num].handle, buf, buffsize);
+ int nread = SSL_read(BACKEND->handle, buf, buffsize);
if(nread < 0) {
- int err = SSL_get_error(conn->ssl[num].handle, nread);
+ int err = SSL_get_error(BACKEND->handle, nread);
switch(err) {
case SSL_ERROR_ZERO_RETURN: /* no more data */
@@ -732,14 +754,14 @@ static ssize_t cyassl_recv(struct connectdata *conn,
}
-void Curl_cyassl_session_free(void *ptr)
+static void Curl_cyassl_session_free(void *ptr)
{
(void)ptr;
/* CyaSSL reuses sessions on own, no free */
}
-size_t Curl_cyassl_version(char *buffer, size_t size)
+static size_t Curl_cyassl_version(char *buffer, size_t size)
{
#if LIBCYASSL_VERSION_HEX >= 0x03006000
return snprintf(buffer, size, "wolfSSL/%s", wolfSSL_lib_version());
@@ -753,16 +775,18 @@ size_t Curl_cyassl_version(char *buffer, size_t size)
}
-int Curl_cyassl_init(void)
+static int Curl_cyassl_init(void)
{
return (CyaSSL_Init() == SSL_SUCCESS);
}
-bool Curl_cyassl_data_pending(const struct connectdata* conn, int connindex)
+static bool Curl_cyassl_data_pending(const struct connectdata* conn,
+ int connindex)
{
- if(conn->ssl[connindex].handle) /* SSL is in use */
- return (0 != SSL_pending(conn->ssl[connindex].handle)) ? TRUE : FALSE;
+ const struct ssl_connect_data *connssl = &conn->ssl[connindex];
+ if(BACKEND->handle) /* SSL is in use */
+ return (0 != SSL_pending(BACKEND->handle)) ? TRUE : FALSE;
else
return FALSE;
}
@@ -772,14 +796,14 @@ bool Curl_cyassl_data_pending(const struct connectdata* conn, int connindex)
* This function is called to shut down the SSL layer but keep the
* socket open (CCC - Clear Command Channel)
*/
-int Curl_cyassl_shutdown(struct connectdata *conn, int sockindex)
+static int Curl_cyassl_shutdown(struct connectdata *conn, int sockindex)
{
int retval = 0;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- if(connssl->handle) {
- SSL_free(connssl->handle);
- connssl->handle = NULL;
+ if(BACKEND->handle) {
+ SSL_free(BACKEND->handle);
+ BACKEND->handle = NULL;
}
return retval;
}
@@ -804,7 +828,7 @@ cyassl_connect_common(struct connectdata *conn,
return CURLE_OK;
}
- if(ssl_connect_1==connssl->connecting_state) {
+ if(ssl_connect_1 == connssl->connecting_state) {
/* Find out how much more time we're allowed */
timeout_ms = Curl_timeleft(data, NULL, TRUE);
@@ -836,9 +860,9 @@ cyassl_connect_common(struct connectdata *conn,
if(connssl->connecting_state == ssl_connect_2_reading
|| connssl->connecting_state == ssl_connect_2_writing) {
- curl_socket_t writefd = ssl_connect_2_writing==
+ curl_socket_t writefd = ssl_connect_2_writing ==
connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
- curl_socket_t readfd = ssl_connect_2_reading==
+ curl_socket_t readfd = ssl_connect_2_reading ==
connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
@@ -899,18 +923,14 @@ cyassl_connect_common(struct connectdata *conn,
}
-CURLcode
-Curl_cyassl_connect_nonblocking(struct connectdata *conn,
- int sockindex,
- bool *done)
+static CURLcode Curl_cyassl_connect_nonblocking(struct connectdata *conn,
+ int sockindex, bool *done)
{
return cyassl_connect_common(conn, sockindex, TRUE, done);
}
-CURLcode
-Curl_cyassl_connect(struct connectdata *conn,
- int sockindex)
+static CURLcode Curl_cyassl_connect(struct connectdata *conn, int sockindex)
{
CURLcode result;
bool done = FALSE;
@@ -924,9 +944,8 @@ Curl_cyassl_connect(struct connectdata *conn,
return CURLE_OK;
}
-CURLcode Curl_cyassl_random(struct Curl_easy *data,
- unsigned char *entropy,
- size_t length)
+static CURLcode Curl_cyassl_random(struct Curl_easy *data,
+ unsigned char *entropy, size_t length)
{
RNG rng;
(void)data;
@@ -939,10 +958,10 @@ CURLcode Curl_cyassl_random(struct Curl_easy *data,
return CURLE_OK;
}
-void Curl_cyassl_sha256sum(const unsigned char *tmp, /* input */
- size_t tmplen,
- unsigned char *sha256sum /* output */,
- size_t unused)
+static void Curl_cyassl_sha256sum(const unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *sha256sum /* output */,
+ size_t unused)
{
Sha256 SHA256pw;
(void)unused;
@@ -951,4 +970,48 @@ void Curl_cyassl_sha256sum(const unsigned char *tmp, /* input */
Sha256Final(&SHA256pw, sha256sum);
}
+static void *Curl_cyassl_get_internals(struct ssl_connect_data *connssl,
+ CURLINFO info UNUSED_PARAM)
+{
+ (void)info;
+ return BACKEND->handle;
+}
+
+const struct Curl_ssl Curl_ssl_cyassl = {
+ { CURLSSLBACKEND_WOLFSSL, "WolfSSL" }, /* info */
+
+ 0, /* have_ca_path */
+ 0, /* have_certinfo */
+#ifdef KEEP_PEER_CERT
+ 1, /* have_pinnedpubkey */
+#else
+ 0, /* have_pinnedpubkey */
+#endif
+ 1, /* have_ssl_ctx */
+ 0, /* support_https_proxy */
+
+ sizeof(struct ssl_backend_data),
+
+ Curl_cyassl_init, /* init */
+ Curl_none_cleanup, /* cleanup */
+ Curl_cyassl_version, /* version */
+ Curl_none_check_cxn, /* check_cxn */
+ Curl_cyassl_shutdown, /* shutdown */
+ Curl_cyassl_data_pending, /* data_pending */
+ Curl_cyassl_random, /* random */
+ Curl_none_cert_status_request, /* cert_status_request */
+ Curl_cyassl_connect, /* connect */
+ Curl_cyassl_connect_nonblocking, /* connect_nonblocking */
+ Curl_cyassl_get_internals, /* get_internals */
+ Curl_cyassl_close, /* close_one */
+ Curl_none_close_all, /* close_all */
+ Curl_cyassl_session_free, /* session_free */
+ Curl_none_set_engine, /* set_engine */
+ Curl_none_set_engine_default, /* set_engine_default */
+ Curl_none_engines_list, /* engines_list */
+ Curl_none_false_start, /* false_start */
+ Curl_none_md5sum, /* md5sum */
+ Curl_cyassl_sha256sum /* sha256sum */
+};
+
#endif
diff --git a/lib/vtls/cyassl.h b/lib/vtls/cyassl.h
index f47719e4..01e11cc2 100644
--- a/lib/vtls/cyassl.h
+++ b/lib/vtls/cyassl.h
@@ -25,68 +25,7 @@
#ifdef USE_CYASSL
-/* KEEP_PEER_CERT is a product of the presence of build time symbol
- OPENSSL_EXTRA without NO_CERTS, depending on the version. KEEP_PEER_CERT is
- in wolfSSL's settings.h, and the latter two are build time symbols in
- options.h. */
-#ifndef KEEP_PEER_CERT
-#if defined(HAVE_CYASSL_GET_PEER_CERTIFICATE) || \
- defined(HAVE_WOLFSSL_GET_PEER_CERTIFICATE) || \
- (defined(OPENSSL_EXTRA) && !defined(NO_CERTS))
-#define KEEP_PEER_CERT
-#endif
-#endif
-
-CURLcode Curl_cyassl_connect(struct connectdata *conn, int sockindex);
-bool Curl_cyassl_data_pending(const struct connectdata* conn, int connindex);
-int Curl_cyassl_shutdown(struct connectdata* conn, int sockindex);
-
- /* close a SSL connection */
-void Curl_cyassl_close(struct connectdata *conn, int sockindex);
-
-void Curl_cyassl_session_free(void *ptr);
-size_t Curl_cyassl_version(char *buffer, size_t size);
-int Curl_cyassl_shutdown(struct connectdata *conn, int sockindex);
-int Curl_cyassl_init(void);
-CURLcode Curl_cyassl_connect_nonblocking(struct connectdata *conn,
- int sockindex,
- bool *done);
-CURLcode Curl_cyassl_random(struct Curl_easy *data,
- unsigned char *entropy,
- size_t length);
-void Curl_cyassl_sha256sum(const unsigned char *tmp, /* input */
- size_t tmplen,
- unsigned char *sha256sum, /* output */
- size_t unused);
-
-/* Set the API backend definition to CyaSSL */
-#define CURL_SSL_BACKEND CURLSSLBACKEND_CYASSL
-
-/* this backend supports CURLOPT_SSL_CTX_* */
-#define have_curlssl_ssl_ctx 1
-
-#ifdef KEEP_PEER_CERT
-/* this backend supports CURLOPT_PINNEDPUBLICKEY */
-#define have_curlssl_pinnedpubkey 1
-#endif
-
-/* API setup for CyaSSL */
-#define curlssl_init Curl_cyassl_init
-#define curlssl_cleanup() Curl_nop_stmt
-#define curlssl_connect Curl_cyassl_connect
-#define curlssl_connect_nonblocking Curl_cyassl_connect_nonblocking
-#define curlssl_session_free(x) Curl_cyassl_session_free(x)
-#define curlssl_close_all(x) ((void)x)
-#define curlssl_close Curl_cyassl_close
-#define curlssl_shutdown(x,y) Curl_cyassl_shutdown(x,y)
-#define curlssl_set_engine(x,y) ((void)x, (void)y, CURLE_NOT_BUILT_IN)
-#define curlssl_set_engine_default(x) ((void)x, CURLE_NOT_BUILT_IN)
-#define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL)
-#define curlssl_version Curl_cyassl_version
-#define curlssl_check_cxn(x) ((void)x, -1)
-#define curlssl_data_pending(x,y) Curl_cyassl_data_pending(x,y)
-#define curlssl_random(x,y,z) Curl_cyassl_random(x,y,z)
-#define curlssl_sha256sum(a,b,c,d) Curl_cyassl_sha256sum(a,b,c,d)
+extern const struct Curl_ssl Curl_ssl_cyassl;
#endif /* USE_CYASSL */
#endif /* HEADER_CURL_CYASSL_H */
diff --git a/lib/vtls/darwinssl.c b/lib/vtls/darwinssl.c
index 6f9c6012..31690422 100644
--- a/lib/vtls/darwinssl.c
+++ b/lib/vtls/darwinssl.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2012 - 2014, Nick Zitzmann, <nickzman@gmail.com>.
+ * Copyright (C) 2012 - 2017, Nick Zitzmann, <nickzman@gmail.com>.
* Copyright (C) 2012 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
@@ -22,7 +22,7 @@
***************************************************************************/
/*
- * Source file for all iOS and Mac OS X SecureTransport-specific code for the
+ * Source file for all iOS and macOS SecureTransport-specific code for the
* TLS/SSL layer. No code but vtls.c should ever call or use these functions.
*/
@@ -44,16 +44,20 @@
#endif
#include <Security/Security.h>
+/* For some reason, when building for iOS, the omnibus header above does
+ * not include SecureTransport.h as of iOS SDK 5.1. */
#include <Security/SecureTransport.h>
#include <CoreFoundation/CoreFoundation.h>
#include <CommonCrypto/CommonDigest.h>
-/* The Security framework has changed greatly between iOS and different OS X
+/* The Security framework has changed greatly between iOS and different macOS
versions, and we will try to support as many of them as we can (back to
Leopard and iOS 5) by using macros and weak-linking.
- IMPORTANT: If TLS 1.1 and 1.2 support are important for you on OS X, then
- you must build this project against the 10.8 SDK or later. */
+ In general, you want to build this using the most recent OS SDK, since some
+ features require curl to be built against the latest SDK. TLS 1.1 and 1.2
+ support, for instance, require the macOS 10.8 SDK or later. TLS 1.3
+ requires the macOS 10.13 or iOS 11 SDK or later. */
#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
#if MAC_OS_X_VERSION_MAX_ALLOWED < 1050
@@ -62,6 +66,7 @@
#define CURL_BUILD_IOS 0
#define CURL_BUILD_IOS_7 0
+#define CURL_BUILD_IOS_11 0
#define CURL_BUILD_MAC 1
/* This is the maximum API level we are allowed to use when building: */
#define CURL_BUILD_MAC_10_5 MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
@@ -69,10 +74,11 @@
#define CURL_BUILD_MAC_10_7 MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
#define CURL_BUILD_MAC_10_8 MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
#define CURL_BUILD_MAC_10_9 MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
+#define CURL_BUILD_MAC_10_13 MAC_OS_X_VERSION_MAX_ALLOWED >= 101300
/* These macros mean "the following code is present to allow runtime backward
compatibility with at least this cat or earlier":
- (You set this at build-time by setting the MACOSX_DEPLOYMENT_TARGET
- environmental variable.) */
+ (You set this at build-time using the compiler command line option
+ "-mmacos-version-min.") */
#define CURL_SUPPORT_MAC_10_5 MAC_OS_X_VERSION_MIN_REQUIRED <= 1050
#define CURL_SUPPORT_MAC_10_6 MAC_OS_X_VERSION_MIN_REQUIRED <= 1060
#define CURL_SUPPORT_MAC_10_7 MAC_OS_X_VERSION_MIN_REQUIRED <= 1070
@@ -82,11 +88,14 @@
#elif TARGET_OS_EMBEDDED || TARGET_OS_IPHONE
#define CURL_BUILD_IOS 1
#define CURL_BUILD_IOS_7 __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000
+#define CURL_BUILD_IOS_11 __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000
#define CURL_BUILD_MAC 0
#define CURL_BUILD_MAC_10_5 0
#define CURL_BUILD_MAC_10_6 0
#define CURL_BUILD_MAC_10_7 0
#define CURL_BUILD_MAC_10_8 0
+#define CURL_BUILD_MAC_10_9 0
+#define CURL_BUILD_MAC_10_13 0
#define CURL_SUPPORT_MAC_10_5 0
#define CURL_SUPPORT_MAC_10_6 0
#define CURL_SUPPORT_MAC_10_7 0
@@ -118,6 +127,33 @@
#define ioErr -36
#define paramErr -50
+struct ssl_backend_data {
+ SSLContextRef ssl_ctx;
+ curl_socket_t ssl_sockfd;
+ bool ssl_direction; /* true if writing, false if reading */
+ size_t ssl_write_buffered_length;
+};
+
+#define BACKEND connssl->backend
+
+/* pinned public key support tests */
+
+/* version 1 supports macOS 10.12+ and iOS 10+ */
+#if ((TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000) || \
+ (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200))
+#define DARWIN_SSL_PINNEDPUBKEY_V1 1
+#endif
+
+/* version 2 supports MacOSX 10.7+ */
+#if (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)
+#define DARWIN_SSL_PINNEDPUBKEY_V2 1
+#endif
+
+#if defined(DARWIN_SSL_PINNEDPUBKEY_V1) || defined(DARWIN_SSL_PINNEDPUBKEY_V2)
+/* this backend supports CURLOPT_PINNEDPUBLICKEY */
+#define DARWIN_SSL_PINNEDPUBKEY 1
+#endif /* DARWIN_SSL_PINNEDPUBKEY */
+
#ifdef DARWIN_SSL_PINNEDPUBKEY
/* both new and old APIs return rsa keys missing the spki header (not DER) */
static const unsigned char rsa4096SpkiHeader[] = {
@@ -161,7 +197,7 @@ static OSStatus SocketRead(SSLConnectionRef connection,
UInt8 *currData = (UInt8 *)data;
/*int sock = *(int *)connection;*/
struct ssl_connect_data *connssl = (struct ssl_connect_data *)connection;
- int sock = connssl->ssl_sockfd;
+ int sock = BACKEND->ssl_sockfd;
OSStatus rtn = noErr;
size_t bytesRead;
ssize_t rrtn;
@@ -190,7 +226,7 @@ static OSStatus SocketRead(SSLConnectionRef connection,
break;
case EAGAIN:
rtn = errSSLWouldBlock;
- connssl->ssl_direction = false;
+ BACKEND->ssl_direction = false;
break;
default:
rtn = ioErr;
@@ -221,7 +257,7 @@ static OSStatus SocketWrite(SSLConnectionRef connection,
size_t bytesSent = 0;
/*int sock = *(int *)connection;*/
struct ssl_connect_data *connssl = (struct ssl_connect_data *)connection;
- int sock = connssl->ssl_sockfd;
+ int sock = BACKEND->ssl_sockfd;
ssize_t length;
size_t dataLen = *dataLength;
const UInt8 *dataPtr = (UInt8 *)data;
@@ -241,7 +277,7 @@ static OSStatus SocketWrite(SSLConnectionRef connection,
theErr = errno;
if(theErr == EAGAIN) {
ortn = errSSLWouldBlock;
- connssl->ssl_direction = true;
+ BACKEND->ssl_direction = true;
}
else {
ortn = ioErr;
@@ -809,6 +845,30 @@ CF_INLINE const char *TLSCipherNameForNumber(SSLCipherSuite cipher)
return "TLS_RSA_PSK_WITH_NULL_SHA384";
break;
#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */
+#if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11
+ /* New ChaCha20+Poly1305 cipher-suites used by TLS 1.3: */
+ case TLS_AES_128_GCM_SHA256:
+ return "TLS_AES_128_GCM_SHA256";
+ break;
+ case TLS_AES_256_GCM_SHA384:
+ return "TLS_AES_256_GCM_SHA384";
+ break;
+ case TLS_CHACHA20_POLY1305_SHA256:
+ return "TLS_CHACHA20_POLY1305_SHA256";
+ break;
+ case TLS_AES_128_CCM_SHA256:
+ return "TLS_AES_128_CCM_SHA256";
+ break;
+ case TLS_AES_128_CCM_8_SHA256:
+ return "TLS_AES_128_CCM_8_SHA256";
+ break;
+ case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+ return "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256";
+ break;
+ case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+ return "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256";
+ break;
+#endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */
}
return "TLS_NULL_WITH_NULL_NULL";
}
@@ -849,7 +909,7 @@ CF_INLINE void GetDarwinVersionNumber(int *major, int *minor)
into a string. Some aren't available under iOS or newer cats. So here's
a unified function for getting a string describing the certificate that
ought to work in all cats starting with Leopard. */
-CF_INLINE CFStringRef CopyCertSubject(SecCertificateRef cert)
+CF_INLINE CFStringRef getsubject(SecCertificateRef cert)
{
CFStringRef server_cert_summary = CFSTR("(null)");
@@ -876,6 +936,54 @@ CF_INLINE CFStringRef CopyCertSubject(SecCertificateRef cert)
return server_cert_summary;
}
+static CURLcode CopyCertSubject(struct Curl_easy *data,
+ SecCertificateRef cert, char **certp)
+{
+ CFStringRef c = getsubject(cert);
+ CURLcode result = CURLE_OK;
+ const char *direct;
+ char *cbuf = NULL;
+ *certp = NULL;
+
+ if(!c) {
+ failf(data, "SSL: invalid CA certificate subject");
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ /* If the subject is already available as UTF-8 encoded (ie 'direct') then
+ use that, else convert it. */
+ direct = CFStringGetCStringPtr(c, kCFStringEncodingUTF8);
+ if(direct) {
+ *certp = strdup(direct);
+ if(!*certp) {
+ failf(data, "SSL: out of memory");
+ result = CURLE_OUT_OF_MEMORY;
+ }
+ }
+ else {
+ size_t cbuf_size = ((size_t)CFStringGetLength(c) * 4) + 1;
+ cbuf = calloc(cbuf_size, 1);
+ if(cbuf) {
+ if(!CFStringGetCString(c, cbuf, cbuf_size,
+ kCFStringEncodingUTF8)) {
+ failf(data, "SSL: invalid CA certificate subject");
+ result = CURLE_SSL_CACERT;
+ }
+ else
+ /* pass back the buffer */
+ *certp = cbuf;
+ }
+ else {
+ failf(data, "SSL: couldn't allocate %zu bytes of memory", cbuf_size);
+ result = CURLE_OUT_OF_MEMORY;
+ }
+ }
+ if(result)
+ free(cbuf);
+ CFRelease(c);
+ return result;
+}
+
#if CURL_SUPPORT_MAC_10_6
/* The SecKeychainSearch API was deprecated in Lion, and using it will raise
deprecation warnings, so let's not compile this unless it's necessary: */
@@ -968,7 +1076,7 @@ static OSStatus CopyIdentityWithLabel(char *label,
keys_list_count = CFArrayGetCount(keys_list);
*out_cert_and_key = NULL;
status = 1;
- for(i=0; i<keys_list_count; i++) {
+ for(i = 0; i<keys_list_count; i++) {
OSStatus err = noErr;
SecCertificateRef cert = NULL;
SecIdentityRef identity =
@@ -1094,6 +1202,15 @@ static CURLcode darwinssl_version_from_curl(SSLProtocol *darwinver,
*darwinver = kTLSProtocol12;
return CURLE_OK;
case CURL_SSLVERSION_TLSv1_3:
+ /* TLS 1.3 support first appeared in iOS 11 and macOS 10.13 */
+#if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11
+ /* We can assume __builtin_available() will always work in the
+ 10.13/11.0 SDK: */
+ if(__builtin_available(macOS 10.13, iOS 11.0, *)) {
+ *darwinver = kTLSProtocol13;
+ return CURLE_OK;
+ }
+#endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */
break;
}
return CURLE_SSL_CONNECT_ERROR;
@@ -1107,12 +1224,27 @@ set_ssl_version_min_max(struct connectdata *conn, int sockindex)
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
long ssl_version = SSL_CONN_CONFIG(version);
long ssl_version_max = SSL_CONN_CONFIG(version_max);
+ long max_supported_version_by_os;
+
+ /* macOS 10.5-10.7 supported TLS 1.0 only.
+ macOS 10.8 and later, and iOS 5 and later, added TLS 1.1 and 1.2.
+ macOS 10.13 and later, and iOS 11 and later, added TLS 1.3. */
+#if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11
+ if(__builtin_available(macOS 10.13, iOS 11.0, *)) {
+ max_supported_version_by_os = CURL_SSLVERSION_MAX_TLSv1_3;
+ }
+ else {
+ max_supported_version_by_os = CURL_SSLVERSION_MAX_TLSv1_2;
+ }
+#else
+ max_supported_version_by_os = CURL_SSLVERSION_MAX_TLSv1_2;
+#endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */
switch(ssl_version) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
ssl_version = CURL_SSLVERSION_TLSv1_0;
- ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
+ ssl_version_max = max_supported_version_by_os;
break;
}
@@ -1121,7 +1253,7 @@ set_ssl_version_min_max(struct connectdata *conn, int sockindex)
ssl_version_max = ssl_version << 16;
break;
case CURL_SSLVERSION_MAX_DEFAULT:
- ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
+ ssl_version_max = max_supported_version_by_os;
break;
}
@@ -1142,35 +1274,35 @@ set_ssl_version_min_max(struct connectdata *conn, int sockindex)
return result;
}
- (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, darwin_ver_min);
- (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, darwin_ver_max);
+ (void)SSLSetProtocolVersionMin(BACKEND->ssl_ctx, darwin_ver_min);
+ (void)SSLSetProtocolVersionMax(BACKEND->ssl_ctx, darwin_ver_max);
return result;
}
else {
#if CURL_SUPPORT_MAC_10_8
long i = ssl_version;
- (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx,
kSSLProtocolAll,
false);
for(; i <= (ssl_version_max >> 16); i++) {
switch(i) {
case CURL_SSLVERSION_TLSv1_0:
- (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx,
kTLSProtocol1,
true);
break;
case CURL_SSLVERSION_TLSv1_1:
- (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx,
kTLSProtocol11,
true);
break;
case CURL_SSLVERSION_TLSv1_2:
- (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx,
kTLSProtocol12,
true);
break;
case CURL_SSLVERSION_TLSv1_3:
- failf(data, "DarwinSSL: TLS 1.3 is not yet supported");
+ failf(data, "Your version of the OS does not support TLSv1.3");
return CURLE_SSL_CONNECT_ERROR;
}
}
@@ -1211,10 +1343,10 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
if(SSLCreateContext != NULL) { /* use the newer API if avaialble */
- if(connssl->ssl_ctx)
- CFRelease(connssl->ssl_ctx);
- connssl->ssl_ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType);
- if(!connssl->ssl_ctx) {
+ if(BACKEND->ssl_ctx)
+ CFRelease(BACKEND->ssl_ctx);
+ BACKEND->ssl_ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType);
+ if(!BACKEND->ssl_ctx) {
failf(data, "SSL: couldn't create a context!");
return CURLE_OUT_OF_MEMORY;
}
@@ -1222,9 +1354,9 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
else {
/* The old ST API does not exist under iOS, so don't compile it: */
#if CURL_SUPPORT_MAC_10_8
- if(connssl->ssl_ctx)
- (void)SSLDisposeContext(connssl->ssl_ctx);
- err = SSLNewContext(false, &(connssl->ssl_ctx));
+ if(BACKEND->ssl_ctx)
+ (void)SSLDisposeContext(BACKEND->ssl_ctx);
+ err = SSLNewContext(false, &(BACKEND->ssl_ctx));
if(err != noErr) {
failf(data, "SSL: couldn't create a context: OSStatus %d", err);
return CURLE_OUT_OF_MEMORY;
@@ -1232,15 +1364,15 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
#endif /* CURL_SUPPORT_MAC_10_8 */
}
#else
- if(connssl->ssl_ctx)
- (void)SSLDisposeContext(connssl->ssl_ctx);
- err = SSLNewContext(false, &(connssl->ssl_ctx));
+ if(BACKEND->ssl_ctx)
+ (void)SSLDisposeContext(BACKEND->ssl_ctx);
+ err = SSLNewContext(false, &(BACKEND->ssl_ctx));
if(err != noErr) {
failf(data, "SSL: couldn't create a context: OSStatus %d", err);
return CURLE_OUT_OF_MEMORY;
}
#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
- connssl->ssl_write_buffered_length = 0UL; /* reset buffered write length */
+ BACKEND->ssl_write_buffered_length = 0UL; /* reset buffered write length */
/* check to see if we've been told to use an explicit SSL/TLS version */
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
@@ -1248,8 +1380,17 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
switch(conn->ssl_config.version) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
- (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol1);
- (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol12);
+ (void)SSLSetProtocolVersionMin(BACKEND->ssl_ctx, kTLSProtocol1);
+#if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11
+ if(__builtin_available(macOS 10.13, iOS 11.0, *)) {
+ (void)SSLSetProtocolVersionMax(BACKEND->ssl_ctx, kTLSProtocol13);
+ }
+ else {
+ (void)SSLSetProtocolVersionMax(BACKEND->ssl_ctx, kTLSProtocol12);
+ }
+#else
+ (void)SSLSetProtocolVersionMax(BACKEND->ssl_ctx, kTLSProtocol12);
+#endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */
break;
case CURL_SSLVERSION_TLSv1_0:
case CURL_SSLVERSION_TLSv1_1:
@@ -1262,20 +1403,20 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
break;
}
case CURL_SSLVERSION_SSLv3:
- err = SSLSetProtocolVersionMin(connssl->ssl_ctx, kSSLProtocol3);
+ err = SSLSetProtocolVersionMin(BACKEND->ssl_ctx, kSSLProtocol3);
if(err != noErr) {
failf(data, "Your version of the OS does not support SSLv3");
return CURLE_SSL_CONNECT_ERROR;
}
- (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kSSLProtocol3);
+ (void)SSLSetProtocolVersionMax(BACKEND->ssl_ctx, kSSLProtocol3);
break;
case CURL_SSLVERSION_SSLv2:
- err = SSLSetProtocolVersionMin(connssl->ssl_ctx, kSSLProtocol2);
+ err = SSLSetProtocolVersionMin(BACKEND->ssl_ctx, kSSLProtocol2);
if(err != noErr) {
failf(data, "Your version of the OS does not support SSLv2");
return CURLE_SSL_CONNECT_ERROR;
}
- (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kSSLProtocol2);
+ (void)SSLSetProtocolVersionMax(BACKEND->ssl_ctx, kSSLProtocol2);
break;
default:
failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
@@ -1284,19 +1425,19 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
}
else {
#if CURL_SUPPORT_MAC_10_8
- (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx,
kSSLProtocolAll,
false);
switch(conn->ssl_config.version) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
- (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx,
kTLSProtocol1,
true);
- (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx,
kTLSProtocol11,
true);
- (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx,
kTLSProtocol12,
true);
break;
@@ -1311,7 +1452,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
break;
}
case CURL_SSLVERSION_SSLv3:
- err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ err = SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx,
kSSLProtocol3,
true);
if(err != noErr) {
@@ -1320,7 +1461,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
}
break;
case CURL_SSLVERSION_SSLv2:
- err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ err = SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx,
kSSLProtocol2,
true);
if(err != noErr) {
@@ -1340,12 +1481,12 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
" SSL/TLS version");
return CURLE_SSL_CONNECT_ERROR;
}
- (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, kSSLProtocolAll, false);
+ (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx, kSSLProtocolAll, false);
switch(conn->ssl_config.version) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
case CURL_SSLVERSION_TLSv1_0:
- (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ (void)SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx,
kTLSProtocol1,
true);
break;
@@ -1359,7 +1500,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
failf(data, "Your version of the OS does not support TLSv1.3");
return CURLE_SSL_CONNECT_ERROR;
case CURL_SSLVERSION_SSLv2:
- err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ err = SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx,
kSSLProtocol2,
true);
if(err != noErr) {
@@ -1368,7 +1509,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
}
break;
case CURL_SSLVERSION_SSLv3:
- err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ err = SSLSetProtocolVersionEnabled(BACKEND->ssl_ctx,
kSSLProtocol3,
true);
if(err != noErr) {
@@ -1418,25 +1559,21 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
/* If we found one, print it out: */
err = SecIdentityCopyCertificate(cert_and_key, &cert);
if(err == noErr) {
- CFStringRef cert_summary = CopyCertSubject(cert);
- char cert_summary_c[128];
-
- if(cert_summary) {
- memset(cert_summary_c, 0, 128);
- if(CFStringGetCString(cert_summary,
- cert_summary_c,
- 128,
- kCFStringEncodingUTF8)) {
- infof(data, "Client certificate: %s\n", cert_summary_c);
- }
- CFRelease(cert_summary);
- CFRelease(cert);
+ char *certp;
+ CURLcode result = CopyCertSubject(data, cert, &certp);
+ if(!result) {
+ infof(data, "Client certificate: %s\n", certp);
+ free(certp);
}
+
+ CFRelease(cert);
+ if(result)
+ return result;
}
certs_c[0] = cert_and_key;
certs = CFArrayCreate(NULL, (const void **)certs_c, 1L,
&kCFTypeArrayCallBacks);
- err = SSLSetCertificate(connssl->ssl_ctx, certs);
+ err = SSLSetCertificate(BACKEND->ssl_ctx, certs);
if(certs)
CFRelease(certs);
if(err != noErr) {
@@ -1499,7 +1636,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
if(SSLSetSessionOption != NULL) {
#endif /* CURL_BUILD_MAC */
bool break_on_auth = !conn->ssl_config.verifypeer || ssl_cafile;
- err = SSLSetSessionOption(connssl->ssl_ctx,
+ err = SSLSetSessionOption(BACKEND->ssl_ctx,
kSSLSessionOptionBreakOnServerAuth,
break_on_auth);
if(err != noErr) {
@@ -1509,7 +1646,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
}
else {
#if CURL_SUPPORT_MAC_10_8
- err = SSLSetEnableCertVerify(connssl->ssl_ctx,
+ err = SSLSetEnableCertVerify(BACKEND->ssl_ctx,
conn->ssl_config.verifypeer?true:false);
if(err != noErr) {
failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err);
@@ -1518,7 +1655,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
#endif /* CURL_SUPPORT_MAC_10_8 */
}
#else
- err = SSLSetEnableCertVerify(connssl->ssl_ctx,
+ err = SSLSetEnableCertVerify(BACKEND->ssl_ctx,
conn->ssl_config.verifypeer?true:false);
if(err != noErr) {
failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err);
@@ -1539,7 +1676,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
* Both hostname check and SNI require SSLSetPeerDomainName().
* Also: the verifyhost setting influences SNI usage */
if(conn->ssl_config.verifyhost) {
- err = SSLSetPeerDomainName(connssl->ssl_ctx, hostname,
+ err = SSLSetPeerDomainName(BACKEND->ssl_ctx, hostname,
strlen(hostname));
if(err != noErr) {
@@ -1565,11 +1702,11 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
higher priority, but it's probably better that we not connect at all than
to give the user a false sense of security if the server only supports
insecure ciphers. (Note: We don't care about SSLv2-only ciphers.) */
- (void)SSLGetNumberSupportedCiphers(connssl->ssl_ctx, &all_ciphers_count);
+ (void)SSLGetNumberSupportedCiphers(BACKEND->ssl_ctx, &all_ciphers_count);
all_ciphers = malloc(all_ciphers_count*sizeof(SSLCipherSuite));
allowed_ciphers = malloc(all_ciphers_count*sizeof(SSLCipherSuite));
if(all_ciphers && allowed_ciphers &&
- SSLGetSupportedCiphers(connssl->ssl_ctx, all_ciphers,
+ SSLGetSupportedCiphers(BACKEND->ssl_ctx, all_ciphers,
&all_ciphers_count) == noErr) {
for(i = 0UL ; i < all_ciphers_count ; i++) {
#if CURL_BUILD_MAC
@@ -1651,7 +1788,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
break;
}
}
- err = SSLSetEnabledCiphers(connssl->ssl_ctx, allowed_ciphers,
+ err = SSLSetEnabledCiphers(BACKEND->ssl_ctx, allowed_ciphers,
allowed_ciphers_count);
if(err != noErr) {
failf(data, "SSL: SSLSetEnabledCiphers() failed: OSStatus %d", err);
@@ -1672,9 +1809,9 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
specifically doesn't want us doing that: */
if(SSLSetSessionOption != NULL) {
/* TODO s/data->set.ssl.enable_beast/SSL_SET_OPTION(enable_beast)/g */
- SSLSetSessionOption(connssl->ssl_ctx, kSSLSessionOptionSendOneByteRecord,
+ SSLSetSessionOption(BACKEND->ssl_ctx, kSSLSessionOptionSendOneByteRecord,
!data->set.ssl.enable_beast);
- SSLSetSessionOption(connssl->ssl_ctx, kSSLSessionOptionFalseStart,
+ SSLSetSessionOption(BACKEND->ssl_ctx, kSSLSessionOptionFalseStart,
data->set.ssl.falsestart); /* false start support */
}
#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */
@@ -1688,7 +1825,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
if(!Curl_ssl_getsessionid(conn, (void **)&ssl_sessionid,
&ssl_sessionid_len, sockindex)) {
/* we got a session id, use it! */
- err = SSLSetPeerID(connssl->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
+ err = SSLSetPeerID(BACKEND->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
Curl_ssl_sessionid_unlock(conn);
if(err != noErr) {
failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err);
@@ -1706,7 +1843,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
verifypeer, SSL_CONN_CONFIG(verifyhost), hostname, port);
ssl_sessionid_len = strlen(ssl_sessionid);
- err = SSLSetPeerID(connssl->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
+ err = SSLSetPeerID(BACKEND->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
if(err != noErr) {
Curl_ssl_sessionid_unlock(conn);
failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err);
@@ -1723,7 +1860,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
}
}
- err = SSLSetIOFuncs(connssl->ssl_ctx, SocketRead, SocketWrite);
+ err = SSLSetIOFuncs(BACKEND->ssl_ctx, SocketRead, SocketWrite);
if(err != noErr) {
failf(data, "SSL: SSLSetIOFuncs() failed: OSStatus %d", err);
return CURLE_SSL_CONNECT_ERROR;
@@ -1733,8 +1870,8 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
/* We need to store the FD in a constant memory address, because
* SSLSetConnection() will not copy that address. I've found that
* conn->sock[sockindex] may change on its own. */
- connssl->ssl_sockfd = sockfd;
- err = SSLSetConnection(connssl->ssl_ctx, connssl);
+ BACKEND->ssl_sockfd = sockfd;
+ err = SSLSetConnection(BACKEND->ssl_ctx, connssl);
if(err != noErr) {
failf(data, "SSL: SSLSetConnection() failed: %d", err);
return CURLE_SSL_CONNECT_ERROR;
@@ -1797,7 +1934,7 @@ static int read_cert(const char *file, unsigned char **out, size_t *outlen)
{
int fd;
ssize_t n, len = 0, cap = 512;
- unsigned char buf[cap], *data;
+ unsigned char buf[512], *data;
fd = open(file, 0);
if(fd < 0)
@@ -1875,6 +2012,8 @@ static int append_cert_to_array(struct Curl_easy *data,
CFMutableArrayRef array)
{
CFDataRef certdata = CFDataCreate(kCFAllocatorDefault, buf, buflen);
+ char *certp;
+ CURLcode result;
if(!certdata) {
failf(data, "SSL: failed to allocate array for CA certificate");
return CURLE_OUT_OF_MEMORY;
@@ -1889,25 +2028,10 @@ static int append_cert_to_array(struct Curl_easy *data,
}
/* Check if cacert is valid. */
- CFStringRef subject = CopyCertSubject(cacert);
- if(subject) {
- char subject_cbuf[128];
- memset(subject_cbuf, 0, 128);
- if(!CFStringGetCString(subject,
- subject_cbuf,
- 128,
- kCFStringEncodingUTF8)) {
- CFRelease(cacert);
- failf(data, "SSL: invalid CA certificate subject");
- return CURLE_SSL_CACERT;
- }
- CFRelease(subject);
- }
- else {
- CFRelease(cacert);
- failf(data, "SSL: invalid CA certificate");
- return CURLE_SSL_CACERT;
- }
+ result = CopyCertSubject(data, cacert, &certp);
+ if(result)
+ return result;
+ free(certp);
CFArrayAppendValue(array, cacert);
CFRelease(cacert);
@@ -2155,12 +2279,12 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex)
|| ssl_connect_2_writing == connssl->connecting_state);
/* Here goes nothing: */
- err = SSLHandshake(connssl->ssl_ctx);
+ err = SSLHandshake(BACKEND->ssl_ctx);
if(err != noErr) {
switch(err) {
case errSSLWouldBlock: /* they're not done with us yet */
- connssl->connecting_state = connssl->ssl_direction ?
+ connssl->connecting_state = BACKEND->ssl_direction ?
ssl_connect_2_writing : ssl_connect_2_reading;
return CURLE_OK;
@@ -2169,7 +2293,7 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex)
case -9841:
if(SSL_CONN_CONFIG(CAfile) && SSL_CONN_CONFIG(verifypeer)) {
int res = verify_cert(SSL_CONN_CONFIG(CAfile), data,
- connssl->ssl_ctx);
+ BACKEND->ssl_ctx);
if(res != CURLE_OK)
return res;
}
@@ -2247,7 +2371,7 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex)
#ifdef DARWIN_SSL_PINNEDPUBKEY
if(data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]) {
- CURLcode result = pkp_pin_peer_pubkey(data, connssl->ssl_ctx,
+ CURLcode result = pkp_pin_peer_pubkey(data, BACKEND->ssl_ctx,
data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]);
if(result) {
failf(data, "SSL: public key does not match pinned public key!");
@@ -2257,8 +2381,8 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex)
#endif /* DARWIN_SSL_PINNEDPUBKEY */
/* Informational message */
- (void)SSLGetNegotiatedCipher(connssl->ssl_ctx, &cipher);
- (void)SSLGetNegotiatedProtocolVersion(connssl->ssl_ctx, &protocol);
+ (void)SSLGetNegotiatedCipher(BACKEND->ssl_ctx, &cipher);
+ (void)SSLGetNegotiatedProtocolVersion(BACKEND->ssl_ctx, &protocol);
switch(protocol) {
case kSSLProtocol2:
infof(data, "SSL 2.0 connection using %s\n",
@@ -2281,7 +2405,13 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex)
infof(data, "TLS 1.2 connection using %s\n",
TLSCipherNameForNumber(cipher));
break;
-#endif
+#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
+#if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11
+ case kTLSProtocol13:
+ infof(data, "TLS 1.3 connection using %s\n",
+ TLSCipherNameForNumber(cipher));
+ break;
+#endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */
default:
infof(data, "Unknown protocol connection\n");
break;
@@ -2299,36 +2429,32 @@ show_verbose_server_cert(struct connectdata *conn,
{
struct Curl_easy *data = conn->data;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- CFStringRef server_cert_summary;
- char server_cert_summary_c[128];
CFArrayRef server_certs = NULL;
SecCertificateRef server_cert;
OSStatus err;
CFIndex i, count;
SecTrustRef trust = NULL;
- if(!connssl->ssl_ctx)
+ if(!BACKEND->ssl_ctx)
return;
#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS
#if CURL_BUILD_IOS
#pragma unused(server_certs)
- err = SSLCopyPeerTrust(connssl->ssl_ctx, &trust);
+ err = SSLCopyPeerTrust(BACKEND->ssl_ctx, &trust);
/* For some reason, SSLCopyPeerTrust() can return noErr and yet return
a null trust, so be on guard for that: */
if(err == noErr && trust) {
count = SecTrustGetCertificateCount(trust);
for(i = 0L ; i < count ; i++) {
+ CURLcode result;
+ char *certp;
server_cert = SecTrustGetCertificateAtIndex(trust, i);
- server_cert_summary = CopyCertSubject(server_cert);
- memset(server_cert_summary_c, 0, 128);
- if(CFStringGetCString(server_cert_summary,
- server_cert_summary_c,
- 128,
- kCFStringEncodingUTF8)) {
- infof(data, "Server certificate: %s\n", server_cert_summary_c);
+ result = CopyCertSubject(data, server_cert, &certp);
+ if(!result) {
+ infof(data, "Server certificate: %s\n", certp);
+ free(certp);
}
- CFRelease(server_cert_summary);
}
CFRelease(trust);
}
@@ -2341,45 +2467,40 @@ show_verbose_server_cert(struct connectdata *conn,
Lion or later. */
if(SecTrustEvaluateAsync != NULL) {
#pragma unused(server_certs)
- err = SSLCopyPeerTrust(connssl->ssl_ctx, &trust);
+ err = SSLCopyPeerTrust(BACKEND->ssl_ctx, &trust);
/* For some reason, SSLCopyPeerTrust() can return noErr and yet return
a null trust, so be on guard for that: */
if(err == noErr && trust) {
count = SecTrustGetCertificateCount(trust);
for(i = 0L ; i < count ; i++) {
+ char *certp;
+ CURLcode result;
server_cert = SecTrustGetCertificateAtIndex(trust, i);
- server_cert_summary = CopyCertSubject(server_cert);
- memset(server_cert_summary_c, 0, 128);
- if(CFStringGetCString(server_cert_summary,
- server_cert_summary_c,
- 128,
- kCFStringEncodingUTF8)) {
- infof(data, "Server certificate: %s\n", server_cert_summary_c);
+ result = CopyCertSubject(data, server_cert, &certp);
+ if(!result) {
+ infof(data, "Server certificate: %s\n", certp);
+ free(certp);
}
- CFRelease(server_cert_summary);
}
CFRelease(trust);
}
}
else {
#if CURL_SUPPORT_MAC_10_8
- err = SSLCopyPeerCertificates(connssl->ssl_ctx, &server_certs);
+ err = SSLCopyPeerCertificates(BACKEND->ssl_ctx, &server_certs);
/* Just in case SSLCopyPeerCertificates() returns null too... */
if(err == noErr && server_certs) {
count = CFArrayGetCount(server_certs);
for(i = 0L ; i < count ; i++) {
+ char *certp;
+ CURLcode result;
server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs,
i);
-
- server_cert_summary = CopyCertSubject(server_cert);
- memset(server_cert_summary_c, 0, 128);
- if(CFStringGetCString(server_cert_summary,
- server_cert_summary_c,
- 128,
- kCFStringEncodingUTF8)) {
- infof(data, "Server certificate: %s\n", server_cert_summary_c);
+ result = CopyCertSubject(data, server_cert, &certp);
+ if(!result) {
+ infof(data, "Server certificate: %s\n", certp);
+ free(certp);
}
- CFRelease(server_cert_summary);
}
CFRelease(server_certs);
}
@@ -2388,20 +2509,18 @@ show_verbose_server_cert(struct connectdata *conn,
#endif /* CURL_BUILD_IOS */
#else
#pragma unused(trust)
- err = SSLCopyPeerCertificates(connssl->ssl_ctx, &server_certs);
+ err = SSLCopyPeerCertificates(BACKEND->ssl_ctx, &server_certs);
if(err == noErr) {
count = CFArrayGetCount(server_certs);
for(i = 0L ; i < count ; i++) {
+ CURLcode result;
+ char *certp;
server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs, i);
- server_cert_summary = CopyCertSubject(server_cert);
- memset(server_cert_summary_c, 0, 128);
- if(CFStringGetCString(server_cert_summary,
- server_cert_summary_c,
- 128,
- kCFStringEncodingUTF8)) {
- infof(data, "Server certificate: %s\n", server_cert_summary_c);
+ result = CopyCertSubject(data, server_cert, &certp);
+ if(!result) {
+ infof(data, "Server certificate: %s\n", certp);
+ free(certp);
}
- CFRelease(server_cert_summary);
}
CFRelease(server_certs);
}
@@ -2450,7 +2569,7 @@ darwinssl_connect_common(struct connectdata *conn,
return CURLE_OK;
}
- if(ssl_connect_1==connssl->connecting_state) {
+ if(ssl_connect_1 == connssl->connecting_state) {
/* Find out how much more time we're allowed */
timeout_ms = Curl_timeleft(data, NULL, TRUE);
@@ -2545,17 +2664,13 @@ darwinssl_connect_common(struct connectdata *conn,
return CURLE_OK;
}
-CURLcode
-Curl_darwinssl_connect_nonblocking(struct connectdata *conn,
- int sockindex,
- bool *done)
+static CURLcode Curl_darwinssl_connect_nonblocking(struct connectdata *conn,
+ int sockindex, bool *done)
{
return darwinssl_connect_common(conn, sockindex, TRUE, done);
}
-CURLcode
-Curl_darwinssl_connect(struct connectdata *conn,
- int sockindex)
+static CURLcode Curl_darwinssl_connect(struct connectdata *conn, int sockindex)
{
CURLcode result;
bool done = FALSE;
@@ -2570,28 +2685,28 @@ Curl_darwinssl_connect(struct connectdata *conn,
return CURLE_OK;
}
-void Curl_darwinssl_close(struct connectdata *conn, int sockindex)
+static void Curl_darwinssl_close(struct connectdata *conn, int sockindex)
{
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- if(connssl->ssl_ctx) {
- (void)SSLClose(connssl->ssl_ctx);
+ if(BACKEND->ssl_ctx) {
+ (void)SSLClose(BACKEND->ssl_ctx);
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
if(SSLCreateContext != NULL)
- CFRelease(connssl->ssl_ctx);
+ CFRelease(BACKEND->ssl_ctx);
#if CURL_SUPPORT_MAC_10_8
else
- (void)SSLDisposeContext(connssl->ssl_ctx);
+ (void)SSLDisposeContext(BACKEND->ssl_ctx);
#endif /* CURL_SUPPORT_MAC_10_8 */
#else
- (void)SSLDisposeContext(connssl->ssl_ctx);
+ (void)SSLDisposeContext(BACKEND->ssl_ctx);
#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
- connssl->ssl_ctx = NULL;
+ BACKEND->ssl_ctx = NULL;
}
- connssl->ssl_sockfd = 0;
+ BACKEND->ssl_sockfd = 0;
}
-int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex)
+static int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex)
{
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct Curl_easy *data = conn->data;
@@ -2600,7 +2715,7 @@ int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex)
int rc;
char buf[120];
- if(!connssl->ssl_ctx)
+ if(!BACKEND->ssl_ctx)
return 0;
if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE)
@@ -2644,7 +2759,7 @@ int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex)
return rc;
}
-void Curl_darwinssl_session_free(void *ptr)
+static void Curl_darwinssl_session_free(void *ptr)
{
/* ST, as of iOS 5 and Mountain Lion, has no public method of deleting a
cached session ID inside the Security framework. There is a private
@@ -2655,7 +2770,7 @@ void Curl_darwinssl_session_free(void *ptr)
Curl_safefree(ptr);
}
-size_t Curl_darwinssl_version(char *buffer, size_t size)
+static size_t Curl_darwinssl_version(char *buffer, size_t size)
{
return snprintf(buffer, size, "SecureTransport");
}
@@ -2668,14 +2783,14 @@ size_t Curl_darwinssl_version(char *buffer, size_t size)
* 0 means the connection has been closed
* -1 means the connection status is unknown
*/
-int Curl_darwinssl_check_cxn(struct connectdata *conn)
+static int Curl_darwinssl_check_cxn(struct connectdata *conn)
{
struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET];
OSStatus err;
SSLSessionState state;
- if(connssl->ssl_ctx) {
- err = SSLGetSessionState(connssl->ssl_ctx, &state);
+ if(BACKEND->ssl_ctx) {
+ err = SSLGetSessionState(BACKEND->ssl_ctx, &state);
if(err == noErr)
return state == kSSLConnected || state == kSSLHandshake;
return -1;
@@ -2683,15 +2798,15 @@ int Curl_darwinssl_check_cxn(struct connectdata *conn)
return 0;
}
-bool Curl_darwinssl_data_pending(const struct connectdata *conn,
- int connindex)
+static bool Curl_darwinssl_data_pending(const struct connectdata *conn,
+ int connindex)
{
const struct ssl_connect_data *connssl = &conn->ssl[connindex];
OSStatus err;
size_t buffer;
- if(connssl->ssl_ctx) { /* SSL is in use */
- err = SSLGetBufferedReadSize(connssl->ssl_ctx, &buffer);
+ if(BACKEND->ssl_ctx) { /* SSL is in use */
+ err = SSLGetBufferedReadSize(BACKEND->ssl_ctx, &buffer);
if(err == noErr)
return buffer > 0UL;
return false;
@@ -2700,14 +2815,16 @@ bool Curl_darwinssl_data_pending(const struct connectdata *conn,
return false;
}
-CURLcode Curl_darwinssl_random(unsigned char *entropy,
- size_t length)
+static CURLcode Curl_darwinssl_random(struct Curl_easy *data UNUSED_PARAM,
+ unsigned char *entropy, size_t length)
{
/* arc4random_buf() isn't available on cats older than Lion, so let's
do this manually for the benefit of the older cats. */
size_t i;
u_int32_t random_number = 0;
+ (void)data;
+
for(i = 0 ; i < length ; i++) {
if(i % sizeof(u_int32_t) == 0)
random_number = arc4random();
@@ -2718,25 +2835,26 @@ CURLcode Curl_darwinssl_random(unsigned char *entropy,
return CURLE_OK;
}
-void Curl_darwinssl_md5sum(unsigned char *tmp, /* input */
- size_t tmplen,
- unsigned char *md5sum, /* output */
- size_t md5len)
+static CURLcode Curl_darwinssl_md5sum(unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *md5sum, /* output */
+ size_t md5len)
{
(void)md5len;
(void)CC_MD5(tmp, (CC_LONG)tmplen, md5sum);
+ return CURLE_OK;
}
-void Curl_darwinssl_sha256sum(unsigned char *tmp, /* input */
- size_t tmplen,
- unsigned char *sha256sum, /* output */
- size_t sha256len)
+static void Curl_darwinssl_sha256sum(const unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *sha256sum, /* output */
+ size_t sha256len)
{
- assert(sha256len >= SHA256_DIGEST_LENGTH);
+ assert(sha256len >= CURL_SHA256_DIGEST_LENGTH);
(void)CC_SHA256(tmp, (CC_LONG)tmplen, sha256sum);
}
-bool Curl_darwinssl_false_start(void)
+static bool Curl_darwinssl_false_start(void)
{
#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
if(SSLSetSessionOption != NULL)
@@ -2771,15 +2889,15 @@ static ssize_t darwinssl_send(struct connectdata *conn,
over again with no new data until it quits returning errSSLWouldBlock. */
/* Do we have buffered data to write from the last time we were called? */
- if(connssl->ssl_write_buffered_length) {
+ if(BACKEND->ssl_write_buffered_length) {
/* Write the buffered data: */
- err = SSLWrite(connssl->ssl_ctx, NULL, 0UL, &processed);
+ err = SSLWrite(BACKEND->ssl_ctx, NULL, 0UL, &processed);
switch(err) {
case noErr:
/* processed is always going to be 0 because we didn't write to
the buffer, so return how much was written to the socket */
- processed = connssl->ssl_write_buffered_length;
- connssl->ssl_write_buffered_length = 0UL;
+ processed = BACKEND->ssl_write_buffered_length;
+ BACKEND->ssl_write_buffered_length = 0UL;
break;
case errSSLWouldBlock: /* argh, try again */
*curlcode = CURLE_AGAIN;
@@ -2792,13 +2910,13 @@ static ssize_t darwinssl_send(struct connectdata *conn,
}
else {
/* We've got new data to write: */
- err = SSLWrite(connssl->ssl_ctx, mem, len, &processed);
+ err = SSLWrite(BACKEND->ssl_ctx, mem, len, &processed);
if(err != noErr) {
switch(err) {
case errSSLWouldBlock:
/* Data was buffered but not sent, we have to tell the caller
to try sending again, and remember how much was buffered */
- connssl->ssl_write_buffered_length = len;
+ BACKEND->ssl_write_buffered_length = len;
*curlcode = CURLE_AGAIN;
return -1L;
default:
@@ -2820,7 +2938,7 @@ static ssize_t darwinssl_recv(struct connectdata *conn,
/*struct Curl_easy *data = conn->data;*/
struct ssl_connect_data *connssl = &conn->ssl[num];
size_t processed = 0UL;
- OSStatus err = SSLRead(connssl->ssl_ctx, buf, buffersize, &processed);
+ OSStatus err = SSLRead(BACKEND->ssl_ctx, buf, buffersize, &processed);
if(err != noErr) {
switch(err) {
@@ -2851,6 +2969,50 @@ static ssize_t darwinssl_recv(struct connectdata *conn,
return (ssize_t)processed;
}
+static void *Curl_darwinssl_get_internals(struct ssl_connect_data *connssl,
+ CURLINFO info UNUSED_PARAM)
+{
+ (void)info;
+ return BACKEND->ssl_ctx;
+}
+
+const struct Curl_ssl Curl_ssl_darwinssl = {
+ { CURLSSLBACKEND_DARWINSSL, "darwinssl" }, /* info */
+
+ 0, /* have_ca_path */
+ 0, /* have_certinfo */
+#ifdef DARWIN_SSL_PINNEDPUBKEY
+ 1, /* have_pinnedpubkey */
+#else
+ 0, /* have_pinnedpubkey */
+#endif /* DARWIN_SSL_PINNEDPUBKEY */
+ 0, /* have_ssl_ctx */
+ 0, /* support_https_proxy */
+
+ sizeof(struct ssl_backend_data),
+
+ Curl_none_init, /* init */
+ Curl_none_cleanup, /* cleanup */
+ Curl_darwinssl_version, /* version */
+ Curl_darwinssl_check_cxn, /* check_cxn */
+ Curl_darwinssl_shutdown, /* shutdown */
+ Curl_darwinssl_data_pending, /* data_pending */
+ Curl_darwinssl_random, /* random */
+ Curl_none_cert_status_request, /* cert_status_request */
+ Curl_darwinssl_connect, /* connect */
+ Curl_darwinssl_connect_nonblocking, /* connect_nonblocking */
+ Curl_darwinssl_get_internals, /* get_internals */
+ Curl_darwinssl_close, /* close_one */
+ Curl_none_close_all, /* close_all */
+ Curl_darwinssl_session_free, /* session_free */
+ Curl_none_set_engine, /* set_engine */
+ Curl_none_set_engine_default, /* set_engine_default */
+ Curl_none_engines_list, /* engines_list */
+ Curl_darwinssl_false_start, /* false_start */
+ Curl_darwinssl_md5sum, /* md5sum */
+ Curl_darwinssl_sha256sum /* sha256sum */
+};
+
#ifdef __clang__
#pragma clang diagnostic pop
#endif
diff --git a/lib/vtls/darwinssl.h b/lib/vtls/darwinssl.h
index 13e78515..23c7f705 100644
--- a/lib/vtls/darwinssl.h
+++ b/lib/vtls/darwinssl.h
@@ -26,76 +26,7 @@
#ifdef USE_DARWINSSL
-CURLcode Curl_darwinssl_connect(struct connectdata *conn, int sockindex);
-
-CURLcode Curl_darwinssl_connect_nonblocking(struct connectdata *conn,
- int sockindex,
- bool *done);
-
-/* close a SSL connection */
-void Curl_darwinssl_close(struct connectdata *conn, int sockindex);
-
-void Curl_darwinssl_session_free(void *ptr);
-size_t Curl_darwinssl_version(char *buffer, size_t size);
-int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex);
-int Curl_darwinssl_check_cxn(struct connectdata *conn);
-bool Curl_darwinssl_data_pending(const struct connectdata *conn,
- int connindex);
-
-CURLcode Curl_darwinssl_random(unsigned char *entropy,
- size_t length);
-void Curl_darwinssl_md5sum(unsigned char *tmp, /* input */
- size_t tmplen,
- unsigned char *md5sum, /* output */
- size_t md5len);
-void Curl_darwinssl_sha256sum(unsigned char *tmp, /* input */
- size_t tmplen,
- unsigned char *sha256sum, /* output */
- size_t sha256len);
-bool Curl_darwinssl_false_start(void);
-
-/* Set the API backend definition to SecureTransport */
-#define CURL_SSL_BACKEND CURLSSLBACKEND_DARWINSSL
-
-/* pinned public key support tests */
-
-/* version 1 supports macOS 10.12+ and iOS 10+ */
-#if ((TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000) || \
- (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200))
-#define DARWIN_SSL_PINNEDPUBKEY_V1 1
-#endif
-
-/* version 2 supports MacOSX 10.7+ */
-#if (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)
-#define DARWIN_SSL_PINNEDPUBKEY_V2 1
-#endif
-
-#if defined(DARWIN_SSL_PINNEDPUBKEY_V1) || defined(DARWIN_SSL_PINNEDPUBKEY_V2)
-/* this backend supports CURLOPT_PINNEDPUBLICKEY */
-#define DARWIN_SSL_PINNEDPUBKEY 1
-#define have_curlssl_pinnedpubkey 1
-#endif /* DARWIN_SSL_PINNEDPUBKEY */
-
-/* API setup for SecureTransport */
-#define curlssl_init() (1)
-#define curlssl_cleanup() Curl_nop_stmt
-#define curlssl_connect Curl_darwinssl_connect
-#define curlssl_connect_nonblocking Curl_darwinssl_connect_nonblocking
-#define curlssl_session_free(x) Curl_darwinssl_session_free(x)
-#define curlssl_close_all(x) ((void)x)
-#define curlssl_close Curl_darwinssl_close
-#define curlssl_shutdown(x,y) 0
-#define curlssl_set_engine(x,y) ((void)x, (void)y, CURLE_NOT_BUILT_IN)
-#define curlssl_set_engine_default(x) ((void)x, CURLE_NOT_BUILT_IN)
-#define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL)
-#define curlssl_version Curl_darwinssl_version
-#define curlssl_check_cxn Curl_darwinssl_check_cxn
-#define curlssl_data_pending(x,y) Curl_darwinssl_data_pending(x, y)
-#define curlssl_random(x,y,z) ((void)x, Curl_darwinssl_random(y,z))
-#define curlssl_md5sum(a,b,c,d) Curl_darwinssl_md5sum(a,b,c,d)
-#define curlssl_sha256sum(a,b,c,d) \
- Curl_darwinssl_sha256sum((unsigned char *)a, b, c, d)
-#define curlssl_false_start() Curl_darwinssl_false_start()
+extern const struct Curl_ssl Curl_ssl_darwinssl;
#endif /* USE_DARWINSSL */
#endif /* HEADER_CURL_DARWINSSL_H */
diff --git a/lib/vtls/gskit.c b/lib/vtls/gskit.c
index bf75bddc..de496dd1 100644
--- a/lib/vtls/gskit.c
+++ b/lib/vtls/gskit.c
@@ -98,6 +98,14 @@
#define CURL_GSKPROTO_TLSV12_MASK (1 << CURL_GSKPROTO_TLSV12)
#define CURL_GSKPROTO_LAST 5
+struct ssl_backend_data {
+ gsk_handle handle;
+ int iocport;
+ int localfd;
+ int remotefd;
+};
+
+#define BACKEND connssl->backend
/* Supported ciphers. */
typedef struct {
@@ -427,7 +435,7 @@ static CURLcode set_ciphers(struct connectdata *conn,
}
-int Curl_gskit_init(void)
+static int Curl_gskit_init(void)
{
/* No initialisation needed. */
@@ -435,7 +443,7 @@ int Curl_gskit_init(void)
}
-void Curl_gskit_cleanup(void)
+static void Curl_gskit_cleanup(void)
{
/* Nothing to do. */
}
@@ -495,14 +503,14 @@ static void cancel_async_handshake(struct connectdata *conn, int sockindex)
Qso_OverlappedIO_t cstat;
if(QsoCancelOperation(conn->sock[sockindex], 0) > 0)
- QsoWaitForIOCompletion(connssl->iocport, &cstat, (struct timeval *) NULL);
+ QsoWaitForIOCompletion(BACKEND->iocport, &cstat, (struct timeval *) NULL);
}
static void close_async_handshake(struct ssl_connect_data *connssl)
{
- QsoDestroyIOCompletionPort(connssl->iocport);
- connssl->iocport = -1;
+ QsoDestroyIOCompletionPort(BACKEND->iocport);
+ BACKEND->iocport = -1;
}
/* SSL over SSL
@@ -620,12 +628,12 @@ static int pipe_ssloverssl(struct connectdata *conn, int sockindex,
FD_ZERO(&fds_write);
n = -1;
if(directions & SOS_READ) {
- FD_SET(connssl->remotefd, &fds_write);
- n = connssl->remotefd;
+ FD_SET(BACKEND->remotefd, &fds_write);
+ n = BACKEND->remotefd;
}
if(directions & SOS_WRITE) {
- FD_SET(connssl->remotefd, &fds_read);
- n = connssl->remotefd;
+ FD_SET(BACKEND->remotefd, &fds_read);
+ n = BACKEND->remotefd;
FD_SET(conn->sock[sockindex], &fds_write);
if(n < conn->sock[sockindex])
n = conn->sock[sockindex];
@@ -634,14 +642,15 @@ static int pipe_ssloverssl(struct connectdata *conn, int sockindex,
if(i < 0)
return -1; /* Select error. */
- if(FD_ISSET(connssl->remotefd, &fds_write)) {
+ if(FD_ISSET(BACKEND->remotefd, &fds_write)) {
/* Try getting data from HTTPS proxy and pipe it upstream. */
n = 0;
- i = gsk_secure_soc_read(connproxyssl->handle, buf, sizeof buf, &n);
+ i = gsk_secure_soc_read(connproxyssl->backend->handle,
+ buf, sizeof buf, &n);
switch(i) {
case GSK_OK:
if(n) {
- i = write(connssl->remotefd, buf, n);
+ i = write(BACKEND->remotefd, buf, n);
if(i < 0)
return -1;
ret = 1;
@@ -655,14 +664,14 @@ static int pipe_ssloverssl(struct connectdata *conn, int sockindex,
}
}
- if(FD_ISSET(connssl->remotefd, &fds_read) &&
+ if(FD_ISSET(BACKEND->remotefd, &fds_read) &&
FD_ISSET(conn->sock[sockindex], &fds_write)) {
/* Pipe data to HTTPS proxy. */
- n = read(connssl->remotefd, buf, sizeof buf);
+ n = read(BACKEND->remotefd, buf, sizeof buf);
if(n < 0)
return -1;
if(n) {
- i = gsk_secure_soc_write(connproxyssl->handle, buf, n, &m);
+ i = gsk_secure_soc_write(connproxyssl->backend->handle, buf, n, &m);
if(i != GSK_OK || n != m)
return -1;
ret = 1;
@@ -676,23 +685,23 @@ static int pipe_ssloverssl(struct connectdata *conn, int sockindex,
static void close_one(struct ssl_connect_data *connssl,
struct connectdata *conn, int sockindex)
{
- if(connssl->handle) {
- gskit_status(conn->data, gsk_secure_soc_close(&connssl->handle),
+ if(BACKEND->handle) {
+ gskit_status(conn->data, gsk_secure_soc_close(&BACKEND->handle),
"gsk_secure_soc_close()", 0);
/* Last chance to drain output. */
while(pipe_ssloverssl(conn, sockindex, SOS_WRITE) > 0)
;
- connssl->handle = (gsk_handle) NULL;
- if(connssl->localfd >= 0) {
- close(connssl->localfd);
- connssl->localfd = -1;
+ BACKEND->handle = (gsk_handle) NULL;
+ if(BACKEND->localfd >= 0) {
+ close(BACKEND->localfd);
+ BACKEND->localfd = -1;
}
- if(connssl->remotefd >= 0) {
- close(connssl->remotefd);
- connssl->remotefd = -1;
+ if(BACKEND->remotefd >= 0) {
+ close(BACKEND->remotefd);
+ BACKEND->remotefd = -1;
}
}
- if(connssl->iocport >= 0)
+ if(BACKEND->iocport >= 0)
close_async_handshake(connssl);
}
@@ -700,13 +709,14 @@ static void close_one(struct ssl_connect_data *connssl,
static ssize_t gskit_send(struct connectdata *conn, int sockindex,
const void *mem, size_t len, CURLcode *curlcode)
{
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct Curl_easy *data = conn->data;
CURLcode cc = CURLE_SEND_ERROR;
int written;
if(pipe_ssloverssl(conn, sockindex, SOS_WRITE) >= 0) {
cc = gskit_status(data,
- gsk_secure_soc_write(conn->ssl[sockindex].handle,
+ gsk_secure_soc_write(BACKEND->handle,
(char *) mem, (int) len, &written),
"gsk_secure_soc_write()", CURLE_SEND_ERROR);
if(cc == CURLE_OK)
@@ -724,6 +734,7 @@ static ssize_t gskit_send(struct connectdata *conn, int sockindex,
static ssize_t gskit_recv(struct connectdata *conn, int num, char *buf,
size_t buffersize, CURLcode *curlcode)
{
+ struct ssl_connect_data *connssl = &conn->ssl[num];
struct Curl_easy *data = conn->data;
int buffsize;
int nread;
@@ -731,7 +742,7 @@ static ssize_t gskit_recv(struct connectdata *conn, int num, char *buf,
if(pipe_ssloverssl(conn, num, SOS_READ) >= 0) {
buffsize = buffersize > (size_t) INT_MAX? INT_MAX: (int) buffersize;
- cc = gskit_status(data, gsk_secure_soc_read(conn->ssl[num].handle,
+ cc = gskit_status(data, gsk_secure_soc_read(BACKEND->handle,
buf, buffsize, &nread),
"gsk_secure_soc_read()", CURLE_RECV_ERROR);
}
@@ -806,10 +817,10 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
/* Create SSL environment, start (preferably asynchronous) handshake. */
- connssl->handle = (gsk_handle) NULL;
- connssl->iocport = -1;
- connssl->localfd = -1;
- connssl->remotefd = -1;
+ BACKEND->handle = (gsk_handle) NULL;
+ BACKEND->iocport = -1;
+ BACKEND->localfd = -1;
+ BACKEND->remotefd = -1;
/* GSKit supports two ways of specifying an SSL context: either by
* application identifier (that should have been defined at the system
@@ -842,7 +853,7 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
}
/* Create secure session. */
- result = gskit_status(data, gsk_secure_soc_open(envir, &connssl->handle),
+ result = gskit_status(data, gsk_secure_soc_open(envir, &BACKEND->handle),
"gsk_secure_soc_open()", CURLE_SSL_CONNECT_ERROR);
gsk_environment_close(&envir);
if(result)
@@ -852,18 +863,18 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
if(conn->proxy_ssl[sockindex].use) {
if(inetsocketpair(sockpair))
return CURLE_SSL_CONNECT_ERROR;
- connssl->localfd = sockpair[0];
- connssl->remotefd = sockpair[1];
- setsockopt(connssl->localfd, SOL_SOCKET, SO_RCVBUF,
+ BACKEND->localfd = sockpair[0];
+ BACKEND->remotefd = sockpair[1];
+ setsockopt(BACKEND->localfd, SOL_SOCKET, SO_RCVBUF,
(void *) sobufsize, sizeof sobufsize);
- setsockopt(connssl->remotefd, SOL_SOCKET, SO_RCVBUF,
+ setsockopt(BACKEND->remotefd, SOL_SOCKET, SO_RCVBUF,
(void *) sobufsize, sizeof sobufsize);
- setsockopt(connssl->localfd, SOL_SOCKET, SO_SNDBUF,
+ setsockopt(BACKEND->localfd, SOL_SOCKET, SO_SNDBUF,
(void *) sobufsize, sizeof sobufsize);
- setsockopt(connssl->remotefd, SOL_SOCKET, SO_SNDBUF,
+ setsockopt(BACKEND->remotefd, SOL_SOCKET, SO_SNDBUF,
(void *) sobufsize, sizeof sobufsize);
- curlx_nonblock(connssl->localfd, TRUE);
- curlx_nonblock(connssl->remotefd, TRUE);
+ curlx_nonblock(BACKEND->localfd, TRUE);
+ curlx_nonblock(BACKEND->remotefd, TRUE);
}
/* Determine which SSL/TLS version should be enabled. */
@@ -897,7 +908,7 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
/* Process SNI. Ignore if not supported (on OS400 < V7R1). */
if(sni) {
- result = set_buffer(data, connssl->handle,
+ result = set_buffer(data, BACKEND->handle,
GSK_SSL_EXTN_SERVERNAME_REQUEST, sni, TRUE);
if(result == CURLE_UNSUPPORTED_PROTOCOL)
result = CURLE_OK;
@@ -911,34 +922,34 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
if(timeout < 0)
result = CURLE_OPERATION_TIMEDOUT;
else
- result = set_numeric(data, connssl->handle, GSK_HANDSHAKE_TIMEOUT,
+ result = set_numeric(data, BACKEND->handle, GSK_HANDSHAKE_TIMEOUT,
(timeout + 999) / 1000);
}
if(!result)
- result = set_numeric(data, connssl->handle, GSK_OS400_READ_TIMEOUT, 1);
+ result = set_numeric(data, BACKEND->handle, GSK_OS400_READ_TIMEOUT, 1);
if(!result)
- result = set_numeric(data, connssl->handle, GSK_FD, connssl->localfd >= 0?
- connssl->localfd: conn->sock[sockindex]);
+ result = set_numeric(data, BACKEND->handle, GSK_FD, BACKEND->localfd >= 0?
+ BACKEND->localfd: conn->sock[sockindex]);
if(!result)
- result = set_ciphers(conn, connssl->handle, &protoflags);
+ result = set_ciphers(conn, BACKEND->handle, &protoflags);
if(!protoflags) {
failf(data, "No SSL protocol/cipher combination enabled");
result = CURLE_SSL_CIPHER;
}
if(!result)
- result = set_enum(data, connssl->handle, GSK_PROTOCOL_SSLV2,
+ result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_SSLV2,
(protoflags & CURL_GSKPROTO_SSLV2_MASK)?
GSK_PROTOCOL_SSLV2_ON: GSK_PROTOCOL_SSLV2_OFF, FALSE);
if(!result)
- result = set_enum(data, connssl->handle, GSK_PROTOCOL_SSLV3,
+ result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_SSLV3,
(protoflags & CURL_GSKPROTO_SSLV3_MASK)?
GSK_PROTOCOL_SSLV3_ON: GSK_PROTOCOL_SSLV3_OFF, FALSE);
if(!result)
- result = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV1,
+ result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_TLSV1,
(protoflags & CURL_GSKPROTO_TLSV10_MASK)?
GSK_PROTOCOL_TLSV1_ON: GSK_PROTOCOL_TLSV1_OFF, FALSE);
if(!result) {
- result = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV11,
+ result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_TLSV11,
(protoflags & CURL_GSKPROTO_TLSV11_MASK)?
GSK_TRUE: GSK_FALSE, TRUE);
if(result == CURLE_UNSUPPORTED_PROTOCOL) {
@@ -950,7 +961,7 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
}
}
if(!result) {
- result = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV12,
+ result = set_enum(data, BACKEND->handle, GSK_PROTOCOL_TLSV12,
(protoflags & CURL_GSKPROTO_TLSV12_MASK)?
GSK_TRUE: GSK_FALSE, TRUE);
if(result == CURLE_UNSUPPORTED_PROTOCOL) {
@@ -962,18 +973,18 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
}
}
if(!result)
- result = set_enum(data, connssl->handle, GSK_SERVER_AUTH_TYPE,
+ result = set_enum(data, BACKEND->handle, GSK_SERVER_AUTH_TYPE,
verifypeer? GSK_SERVER_AUTH_FULL:
GSK_SERVER_AUTH_PASSTHRU, FALSE);
if(!result) {
/* Start handshake. Try asynchronous first. */
memset(&commarea, 0, sizeof commarea);
- connssl->iocport = QsoCreateIOCompletionPort();
- if(connssl->iocport != -1) {
+ BACKEND->iocport = QsoCreateIOCompletionPort();
+ if(BACKEND->iocport != -1) {
result = gskit_status(data,
- gsk_secure_soc_startInit(connssl->handle,
- connssl->iocport,
+ gsk_secure_soc_startInit(BACKEND->handle,
+ BACKEND->iocport,
&commarea),
"gsk_secure_soc_startInit()",
CURLE_SSL_CONNECT_ERROR);
@@ -993,7 +1004,7 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
}
else {
/* No more completion port available. Use synchronous IO. */
- result = gskit_status(data, gsk_secure_soc_init(connssl->handle),
+ result = gskit_status(data, gsk_secure_soc_init(BACKEND->handle),
"gsk_secure_soc_init()", CURLE_SSL_CONNECT_ERROR);
if(!result) {
connssl->connecting_state = ssl_connect_3;
@@ -1026,7 +1037,7 @@ static CURLcode gskit_connect_step2(struct connectdata *conn, int sockindex,
timeout_ms = 0;
stmv.tv_sec = timeout_ms / 1000;
stmv.tv_usec = (timeout_ms - stmv.tv_sec * 1000) * 1000;
- switch(QsoWaitForIOCompletion(connssl->iocport, &cstat, &stmv)) {
+ switch(QsoWaitForIOCompletion(BACKEND->iocport, &cstat, &stmv)) {
case 1: /* Operation complete. */
break;
case -1: /* An error occurred: handshake still in progress. */
@@ -1075,7 +1086,7 @@ static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex)
/* SSL handshake done: gather certificate info and verify host. */
- if(gskit_status(data, gsk_attribute_get_cert_info(connssl->handle,
+ if(gskit_status(data, gsk_attribute_get_cert_info(BACKEND->handle,
GSK_PARTNER_CERT_INFO,
&cdev, &cdec),
"gsk_attribute_get_cert_info()", CURLE_SSL_CONNECT_ERROR) ==
@@ -1216,9 +1227,8 @@ static CURLcode gskit_connect_common(struct connectdata *conn, int sockindex,
}
-CURLcode Curl_gskit_connect_nonblocking(struct connectdata *conn,
- int sockindex,
- bool *done)
+static CURLcode Curl_gskit_connect_nonblocking(struct connectdata *conn,
+ int sockindex, bool *done)
{
CURLcode result;
@@ -1229,7 +1239,7 @@ CURLcode Curl_gskit_connect_nonblocking(struct connectdata *conn,
}
-CURLcode Curl_gskit_connect(struct connectdata *conn, int sockindex)
+static CURLcode Curl_gskit_connect(struct connectdata *conn, int sockindex)
{
CURLcode result;
bool done;
@@ -1245,14 +1255,14 @@ CURLcode Curl_gskit_connect(struct connectdata *conn, int sockindex)
}
-void Curl_gskit_close(struct connectdata *conn, int sockindex)
+static void Curl_gskit_close(struct connectdata *conn, int sockindex)
{
close_one(&conn->ssl[sockindex], conn, sockindex);
close_one(&conn->proxy_ssl[sockindex], conn, sockindex);
}
-int Curl_gskit_shutdown(struct connectdata *conn, int sockindex)
+static int Curl_gskit_shutdown(struct connectdata *conn, int sockindex)
{
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct Curl_easy *data = conn->data;
@@ -1261,7 +1271,7 @@ int Curl_gskit_shutdown(struct connectdata *conn, int sockindex)
int rc;
char buf[120];
- if(!connssl->handle)
+ if(!BACKEND->handle)
return 0;
if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE)
@@ -1306,21 +1316,22 @@ int Curl_gskit_shutdown(struct connectdata *conn, int sockindex)
}
-size_t Curl_gskit_version(char *buffer, size_t size)
+static size_t Curl_gskit_version(char *buffer, size_t size)
{
strncpy(buffer, "GSKit", size);
return strlen(buffer);
}
-int Curl_gskit_check_cxn(struct connectdata *cxn)
+static int Curl_gskit_check_cxn(struct connectdata *cxn)
{
+ struct ssl_connect_data *connssl = &cxn->ssl[FIRSTSOCKET];
int err;
int errlen;
/* The only thing that can be tested here is at the socket level. */
- if(!cxn->ssl[FIRSTSOCKET].handle)
+ if(!BACKEND->handle)
return 0; /* connection has been closed */
err = 0;
@@ -1334,4 +1345,46 @@ int Curl_gskit_check_cxn(struct connectdata *cxn)
return -1; /* connection status unknown */
}
+static void *Curl_gskit_get_internals(struct ssl_connect_data *connssl,
+ CURLINFO info UNUSED_PARAM)
+{
+ (void)info;
+ return BACKEND->handle;
+}
+
+const struct Curl_ssl Curl_ssl_gskit = {
+ { CURLSSLBACKEND_GSKIT, "gskit" }, /* info */
+
+ 0, /* have_ca_path */
+ 1, /* have_certinfo */
+ 0, /* have_pinnedpubkey */
+ 0, /* have_ssl_ctx */
+ /* TODO: convert to 1 and fix test #1014 (if need) */
+ 0, /* support_https_proxy */
+
+ sizeof(struct ssl_backend_data),
+
+ Curl_gskit_init, /* init */
+ Curl_gskit_cleanup, /* cleanup */
+ Curl_gskit_version, /* version */
+ Curl_gskit_check_cxn, /* check_cxn */
+ Curl_gskit_shutdown, /* shutdown */
+ Curl_none_data_pending, /* data_pending */
+ Curl_none_random, /* random */
+ Curl_none_cert_status_request, /* cert_status_request */
+ Curl_gskit_connect, /* connect */
+ Curl_gskit_connect_nonblocking, /* connect_nonblocking */
+ Curl_gskit_get_internals, /* get_internals */
+ Curl_gskit_close, /* close_one */
+ Curl_none_close_all, /* close_all */
+ /* No session handling for GSKit */
+ Curl_none_session_free, /* session_free */
+ Curl_none_set_engine, /* set_engine */
+ Curl_none_set_engine_default, /* set_engine_default */
+ Curl_none_engines_list, /* engines_list */
+ Curl_none_false_start, /* false_start */
+ Curl_none_md5sum, /* md5sum */
+ NULL /* sha256sum */
+};
+
#endif /* USE_GSKIT */
diff --git a/lib/vtls/gskit.h b/lib/vtls/gskit.h
index 22975921..466ee4d9 100644
--- a/lib/vtls/gskit.h
+++ b/lib/vtls/gskit.h
@@ -30,44 +30,8 @@
#include "urldata.h"
#ifdef USE_GSKIT
-int Curl_gskit_init(void);
-void Curl_gskit_cleanup(void);
-CURLcode Curl_gskit_connect(struct connectdata *conn, int sockindex);
-CURLcode Curl_gskit_connect_nonblocking(struct connectdata *conn,
- int sockindex, bool *done);
-void Curl_gskit_close(struct connectdata *conn, int sockindex);
-int Curl_gskit_shutdown(struct connectdata *conn, int sockindex);
-size_t Curl_gskit_version(char *buffer, size_t size);
-int Curl_gskit_check_cxn(struct connectdata *cxn);
-
-/* Support HTTPS-proxy */
-/* TODO: add '#define HTTPS_PROXY_SUPPORT 1' and fix test #1014 (if need) */
-
-/* Set the API backend definition to GSKit */
-#define CURL_SSL_BACKEND CURLSSLBACKEND_GSKIT
-
-/* this backend supports CURLOPT_CERTINFO */
-#define have_curlssl_certinfo 1
-
-/* API setup for GSKit */
-#define curlssl_init Curl_gskit_init
-#define curlssl_cleanup Curl_gskit_cleanup
-#define curlssl_connect Curl_gskit_connect
-#define curlssl_connect_nonblocking Curl_gskit_connect_nonblocking
-
-/* No session handling for GSKit */
-#define curlssl_session_free(x) Curl_nop_stmt
-#define curlssl_close_all(x) ((void)x)
-#define curlssl_close Curl_gskit_close
-#define curlssl_shutdown(x,y) Curl_gskit_shutdown(x,y)
-#define curlssl_set_engine(x,y) CURLE_NOT_BUILT_IN
-#define curlssl_set_engine_default(x) CURLE_NOT_BUILT_IN
-#define curlssl_engines_list(x) NULL
-#define curlssl_version Curl_gskit_version
-#define curlssl_check_cxn(x) Curl_gskit_check_cxn(x)
-#define curlssl_data_pending(x,y) 0
-#define curlssl_random(x,y,z) (x=x, y=y, z=z, CURLE_NOT_BUILT_IN)
+extern const struct Curl_ssl Curl_ssl_gskit;
#endif /* USE_GSKIT */
diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c
index d55f995e..30b255b8 100644
--- a/lib/vtls/gtls.c
+++ b/lib/vtls/gtls.c
@@ -107,6 +107,16 @@ static bool gtls_inited = FALSE;
# include <gnutls/ocsp.h>
#endif
+struct ssl_backend_data {
+ gnutls_session_t session;
+ gnutls_certificate_credentials_t cred;
+#ifdef USE_TLS_SRP
+ gnutls_srp_client_credentials_t srp_client_cred;
+#endif
+};
+
+#define BACKEND connssl->backend
+
/*
* Custom push and pull callback functions used by GNU TLS to read and write
* to the socket. These functions are simple wrappers to send() and recv()
@@ -186,7 +196,7 @@ static ssize_t Curl_gtls_pull_ssl(void *s, void *buf, size_t len)
* must only be called from within curl_global_init() to keep the thread
* situation under control!
*/
-int Curl_gtls_init(void)
+static int Curl_gtls_init(void)
{
int ret = 1;
if(!gtls_inited) {
@@ -200,13 +210,12 @@ int Curl_gtls_init(void)
return ret;
}
-int Curl_gtls_cleanup(void)
+static void Curl_gtls_cleanup(void)
{
if(gtls_inited) {
gnutls_global_deinit();
gtls_inited = FALSE;
}
- return 1;
}
#ifndef CURL_DISABLE_VERBOSE_STRINGS
@@ -277,7 +286,7 @@ static CURLcode handshake(struct connectdata *conn,
{
struct Curl_easy *data = conn->data;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- gnutls_session_t session = conn->ssl[sockindex].session;
+ gnutls_session_t session = BACKEND->session;
curl_socket_t sockfd = conn->sock[sockindex];
time_t timeout_ms;
int rc;
@@ -297,9 +306,9 @@ static CURLcode handshake(struct connectdata *conn,
if(connssl->connecting_state == ssl_connect_2_reading
|| connssl->connecting_state == ssl_connect_2_writing) {
- curl_socket_t writefd = ssl_connect_2_writing==
+ curl_socket_t writefd = ssl_connect_2_writing ==
connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
- curl_socket_t readfd = ssl_connect_2_reading==
+ curl_socket_t readfd = ssl_connect_2_reading ==
connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
@@ -475,6 +484,7 @@ gtls_connect_step1(struct connectdata *conn,
int sockindex)
{
struct Curl_easy *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
unsigned int init_flags;
gnutls_session_t session;
int rc;
@@ -510,7 +520,7 @@ gtls_connect_step1(struct connectdata *conn,
const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
conn->host.name;
- if(conn->ssl[sockindex].state == ssl_connection_complete)
+ if(connssl->state == ssl_connection_complete)
/* to make us tolerant against being called more than once for the
same connection */
return CURLE_OK;
@@ -526,7 +536,7 @@ gtls_connect_step1(struct connectdata *conn,
sni = FALSE; /* SSLv3 has no SNI */
/* allocate a cred struct */
- rc = gnutls_certificate_allocate_credentials(&conn->ssl[sockindex].cred);
+ rc = gnutls_certificate_allocate_credentials(&BACKEND->cred);
if(rc != GNUTLS_E_SUCCESS) {
failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc));
return CURLE_SSL_CONNECT_ERROR;
@@ -537,15 +547,14 @@ gtls_connect_step1(struct connectdata *conn,
infof(data, "Using TLS-SRP username: %s\n", SSL_SET_OPTION(username));
rc = gnutls_srp_allocate_client_credentials(
- &conn->ssl[sockindex].srp_client_cred);
+ &BACKEND->srp_client_cred);
if(rc != GNUTLS_E_SUCCESS) {
failf(data, "gnutls_srp_allocate_client_cred() failed: %s",
gnutls_strerror(rc));
return CURLE_OUT_OF_MEMORY;
}
- rc = gnutls_srp_set_client_credentials(conn->ssl[sockindex].
- srp_client_cred,
+ rc = gnutls_srp_set_client_credentials(BACKEND->srp_client_cred,
SSL_SET_OPTION(username),
SSL_SET_OPTION(password));
if(rc != GNUTLS_E_SUCCESS) {
@@ -558,10 +567,10 @@ gtls_connect_step1(struct connectdata *conn,
if(SSL_CONN_CONFIG(CAfile)) {
/* set the trusted CA cert bundle file */
- gnutls_certificate_set_verify_flags(conn->ssl[sockindex].cred,
+ gnutls_certificate_set_verify_flags(BACKEND->cred,
GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
- rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred,
+ rc = gnutls_certificate_set_x509_trust_file(BACKEND->cred,
SSL_CONN_CONFIG(CAfile),
GNUTLS_X509_FMT_PEM);
if(rc < 0) {
@@ -578,7 +587,7 @@ gtls_connect_step1(struct connectdata *conn,
#ifdef HAS_CAPATH
if(SSL_CONN_CONFIG(CApath)) {
/* set the trusted CA cert directory */
- rc = gnutls_certificate_set_x509_trust_dir(conn->ssl[sockindex].cred,
+ rc = gnutls_certificate_set_x509_trust_dir(BACKEND->cred,
SSL_CONN_CONFIG(CApath),
GNUTLS_X509_FMT_PEM);
if(rc < 0) {
@@ -597,13 +606,13 @@ gtls_connect_step1(struct connectdata *conn,
/* use system ca certificate store as fallback */
if(SSL_CONN_CONFIG(verifypeer) &&
!(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(CApath))) {
- gnutls_certificate_set_x509_system_trust(conn->ssl[sockindex].cred);
+ gnutls_certificate_set_x509_system_trust(BACKEND->cred);
}
#endif
if(SSL_SET_OPTION(CRLfile)) {
/* set the CRL list file */
- rc = gnutls_certificate_set_x509_crl_file(conn->ssl[sockindex].cred,
+ rc = gnutls_certificate_set_x509_crl_file(BACKEND->cred,
SSL_SET_OPTION(CRLfile),
GNUTLS_X509_FMT_PEM);
if(rc < 0) {
@@ -624,14 +633,14 @@ gtls_connect_step1(struct connectdata *conn,
init_flags |= GNUTLS_NO_TICKETS;
#endif
- rc = gnutls_init(&conn->ssl[sockindex].session, init_flags);
+ rc = gnutls_init(&BACKEND->session, init_flags);
if(rc != GNUTLS_E_SUCCESS) {
failf(data, "gnutls_init() failed: %d", rc);
return CURLE_SSL_CONNECT_ERROR;
}
/* convenient assign */
- session = conn->ssl[sockindex].session;
+ session = BACKEND->session;
if((0 == Curl_inet_pton(AF_INET, hostname, &addr)) &&
#ifdef ENABLE_IPV6
@@ -788,7 +797,7 @@ gtls_connect_step1(struct connectdata *conn,
GNUTLS_PKCS_USE_PBES2_AES_128 | GNUTLS_PKCS_USE_PBES2_AES_192 |
GNUTLS_PKCS_USE_PBES2_AES_256;
rc = gnutls_certificate_set_x509_key_file2(
- conn->ssl[sockindex].cred,
+ BACKEND->cred,
SSL_SET_OPTION(cert),
SSL_SET_OPTION(key) ?
SSL_SET_OPTION(key) : SSL_SET_OPTION(cert),
@@ -808,7 +817,7 @@ gtls_connect_step1(struct connectdata *conn,
}
else {
if(gnutls_certificate_set_x509_key_file(
- conn->ssl[sockindex].cred,
+ BACKEND->cred,
SSL_SET_OPTION(cert),
SSL_SET_OPTION(key) ?
SSL_SET_OPTION(key) : SSL_SET_OPTION(cert),
@@ -824,7 +833,7 @@ gtls_connect_step1(struct connectdata *conn,
/* put the credentials to the current session */
if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) {
rc = gnutls_credentials_set(session, GNUTLS_CRD_SRP,
- conn->ssl[sockindex].srp_client_cred);
+ BACKEND->srp_client_cred);
if(rc != GNUTLS_E_SUCCESS) {
failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc));
return CURLE_SSL_CONNECT_ERROR;
@@ -834,7 +843,7 @@ gtls_connect_step1(struct connectdata *conn,
#endif
{
rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
- conn->ssl[sockindex].cred);
+ BACKEND->cred);
if(rc != GNUTLS_E_SUCCESS) {
failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc));
return CURLE_SSL_CONNECT_ERROR;
@@ -842,7 +851,7 @@ gtls_connect_step1(struct connectdata *conn,
}
if(conn->proxy_ssl[sockindex].use) {
- transport_ptr = conn->proxy_ssl[sockindex].session;
+ transport_ptr = conn->proxy_ssl[sockindex].backend->session;
gnutls_transport_push = Curl_gtls_push_ssl;
gnutls_transport_pull = Curl_gtls_pull_ssl;
}
@@ -967,7 +976,8 @@ gtls_connect_step3(struct connectdata *conn,
time_t certclock;
const char *ptr;
struct Curl_easy *data = conn->data;
- gnutls_session_t session = conn->ssl[sockindex].session;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ gnutls_session_t session = BACKEND->session;
int rc;
#ifdef HAS_ALPN
gnutls_datum_t proto;
@@ -1198,7 +1208,7 @@ gtls_connect_step3(struct connectdata *conn,
SSL_SET_OPTION(issuercert)?SSL_SET_OPTION(issuercert):"none");
}
- size=sizeof(certbuf);
+ size = sizeof(certbuf);
rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME,
0, /* the first and only one */
FALSE,
@@ -1238,7 +1248,7 @@ gtls_connect_step3(struct connectdata *conn,
#endif
if(addrlen) {
- for(i=0; ; i++) {
+ for(i = 0; ; i++) {
certaddrlen = sizeof(certaddr);
ret = gnutls_x509_crt_get_subject_alt_name(x509_cert, i, certaddr,
&certaddrlen, NULL);
@@ -1471,7 +1481,7 @@ gtls_connect_common(struct connectdata *conn,
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
/* Initiate the connection, if not already done */
- if(ssl_connect_1==connssl->connecting_state) {
+ if(ssl_connect_1 == connssl->connecting_state) {
rc = gtls_connect_step1(conn, sockindex);
if(rc)
return rc;
@@ -1483,29 +1493,24 @@ gtls_connect_common(struct connectdata *conn,
return rc;
/* Finish connecting once the handshake is done */
- if(ssl_connect_1==connssl->connecting_state) {
+ if(ssl_connect_1 == connssl->connecting_state) {
rc = gtls_connect_step3(conn, sockindex);
if(rc)
return rc;
}
- *done = ssl_connect_1==connssl->connecting_state;
+ *done = ssl_connect_1 == connssl->connecting_state;
return CURLE_OK;
}
-CURLcode
-Curl_gtls_connect_nonblocking(struct connectdata *conn,
- int sockindex,
- bool *done)
+static CURLcode Curl_gtls_connect_nonblocking(struct connectdata *conn,
+ int sockindex, bool *done)
{
return gtls_connect_common(conn, sockindex, TRUE, done);
}
-CURLcode
-Curl_gtls_connect(struct connectdata *conn,
- int sockindex)
-
+static CURLcode Curl_gtls_connect(struct connectdata *conn, int sockindex)
{
CURLcode result;
bool done = FALSE;
@@ -1519,15 +1524,18 @@ Curl_gtls_connect(struct connectdata *conn,
return CURLE_OK;
}
-bool Curl_gtls_data_pending(const struct connectdata *conn, int connindex)
+static bool Curl_gtls_data_pending(const struct connectdata *conn,
+ int connindex)
{
+ const struct ssl_connect_data *connssl = &conn->ssl[connindex];
bool res = FALSE;
- if(conn->ssl[connindex].session &&
- 0 != gnutls_record_check_pending(conn->ssl[connindex].session))
+ if(BACKEND->session &&
+ 0 != gnutls_record_check_pending(BACKEND->session))
res = TRUE;
- if(conn->proxy_ssl[connindex].session &&
- 0 != gnutls_record_check_pending(conn->proxy_ssl[connindex].session))
+ connssl = &conn->proxy_ssl[connindex];
+ if(BACKEND->session &&
+ 0 != gnutls_record_check_pending(BACKEND->session))
res = TRUE;
return res;
@@ -1539,7 +1547,8 @@ static ssize_t gtls_send(struct connectdata *conn,
size_t len,
CURLcode *curlcode)
{
- ssize_t rc = gnutls_record_send(conn->ssl[sockindex].session, mem, len);
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ ssize_t rc = gnutls_record_send(BACKEND->session, mem, len);
if(rc < 0) {
*curlcode = (rc == GNUTLS_E_AGAIN)
@@ -1552,26 +1561,26 @@ static ssize_t gtls_send(struct connectdata *conn,
return rc;
}
-static void close_one(struct ssl_connect_data *ssl)
+static void close_one(struct ssl_connect_data *connssl)
{
- if(ssl->session) {
- gnutls_bye(ssl->session, GNUTLS_SHUT_RDWR);
- gnutls_deinit(ssl->session);
- ssl->session = NULL;
+ if(BACKEND->session) {
+ gnutls_bye(BACKEND->session, GNUTLS_SHUT_RDWR);
+ gnutls_deinit(BACKEND->session);
+ BACKEND->session = NULL;
}
- if(ssl->cred) {
- gnutls_certificate_free_credentials(ssl->cred);
- ssl->cred = NULL;
+ if(BACKEND->cred) {
+ gnutls_certificate_free_credentials(BACKEND->cred);
+ BACKEND->cred = NULL;
}
#ifdef USE_TLS_SRP
- if(ssl->srp_client_cred) {
- gnutls_srp_free_client_credentials(ssl->srp_client_cred);
- ssl->srp_client_cred = NULL;
+ if(BACKEND->srp_client_cred) {
+ gnutls_srp_free_client_credentials(BACKEND->srp_client_cred);
+ BACKEND->srp_client_cred = NULL;
}
#endif
}
-void Curl_gtls_close(struct connectdata *conn, int sockindex)
+static void Curl_gtls_close(struct connectdata *conn, int sockindex)
{
close_one(&conn->ssl[sockindex]);
close_one(&conn->proxy_ssl[sockindex]);
@@ -1581,8 +1590,9 @@ void Curl_gtls_close(struct connectdata *conn, int sockindex)
* This function is called to shut down the SSL layer but keep the
* socket open (CCC - Clear Command Channel)
*/
-int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
+static int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
{
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
ssize_t result;
int retval = 0;
struct Curl_easy *data = conn->data;
@@ -1595,16 +1605,16 @@ int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
we do not send one. Let's hope other servers do the same... */
if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
- gnutls_bye(conn->ssl[sockindex].session, GNUTLS_SHUT_WR);
+ gnutls_bye(BACKEND->session, GNUTLS_SHUT_WR);
- if(conn->ssl[sockindex].session) {
+ if(BACKEND->session) {
while(!done) {
int what = SOCKET_READABLE(conn->sock[sockindex],
SSL_SHUTDOWN_TIMEOUT);
if(what > 0) {
/* Something to read, let's do it and hope that it is the close
notify alert from the server */
- result = gnutls_record_recv(conn->ssl[sockindex].session,
+ result = gnutls_record_recv(BACKEND->session,
buf, sizeof(buf));
switch(result) {
case 0:
@@ -1635,18 +1645,18 @@ int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
done = 1;
}
}
- gnutls_deinit(conn->ssl[sockindex].session);
+ gnutls_deinit(BACKEND->session);
}
- gnutls_certificate_free_credentials(conn->ssl[sockindex].cred);
+ gnutls_certificate_free_credentials(BACKEND->cred);
#ifdef USE_TLS_SRP
if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP
&& SSL_SET_OPTION(username) != NULL)
- gnutls_srp_free_client_credentials(conn->ssl[sockindex].srp_client_cred);
+ gnutls_srp_free_client_credentials(BACKEND->srp_client_cred);
#endif
- conn->ssl[sockindex].cred = NULL;
- conn->ssl[sockindex].session = NULL;
+ BACKEND->cred = NULL;
+ BACKEND->session = NULL;
return retval;
}
@@ -1657,9 +1667,10 @@ static ssize_t gtls_recv(struct connectdata *conn, /* connection data */
size_t buffersize, /* max amount to read */
CURLcode *curlcode)
{
+ struct ssl_connect_data *connssl = &conn->ssl[num];
ssize_t ret;
- ret = gnutls_record_recv(conn->ssl[num].session, buf, buffersize);
+ ret = gnutls_record_recv(BACKEND->session, buf, buffersize);
if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
*curlcode = CURLE_AGAIN;
return -1;
@@ -1679,6 +1690,7 @@ static ssize_t gtls_recv(struct connectdata *conn, /* connection data */
if(ret < 0) {
failf(conn->data, "GnuTLS recv error (%d): %s",
+
(int)ret, gnutls_strerror((int)ret));
*curlcode = CURLE_RECV_ERROR;
return -1;
@@ -1687,12 +1699,12 @@ static ssize_t gtls_recv(struct connectdata *conn, /* connection data */
return ret;
}
-void Curl_gtls_session_free(void *ptr)
+static void Curl_gtls_session_free(void *ptr)
{
free(ptr);
}
-size_t Curl_gtls_version(char *buffer, size_t size)
+static size_t Curl_gtls_version(char *buffer, size_t size)
{
return snprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL));
}
@@ -1722,9 +1734,8 @@ static int Curl_gtls_seed(struct Curl_easy *data)
#endif
/* data might be NULL! */
-CURLcode Curl_gtls_random(struct Curl_easy *data,
- unsigned char *entropy,
- size_t length)
+static CURLcode Curl_gtls_random(struct Curl_easy *data,
+ unsigned char *entropy, size_t length)
{
#if defined(USE_GNUTLS_NETTLE)
int rc;
@@ -1739,10 +1750,10 @@ CURLcode Curl_gtls_random(struct Curl_easy *data,
return CURLE_OK;
}
-void Curl_gtls_md5sum(unsigned char *tmp, /* input */
- size_t tmplen,
- unsigned char *md5sum, /* output */
- size_t md5len)
+static CURLcode Curl_gtls_md5sum(unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *md5sum, /* output */
+ size_t md5len)
{
#if defined(USE_GNUTLS_NETTLE)
struct md5_ctx MD5pw;
@@ -1756,12 +1767,13 @@ void Curl_gtls_md5sum(unsigned char *tmp, /* input */
memcpy(md5sum, gcry_md_read(MD5pw, 0), md5len);
gcry_md_close(MD5pw);
#endif
+ return CURLE_OK;
}
-void Curl_gtls_sha256sum(const unsigned char *tmp, /* input */
- size_t tmplen,
- unsigned char *sha256sum, /* output */
- size_t sha256len)
+static void Curl_gtls_sha256sum(const unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *sha256sum, /* output */
+ size_t sha256len)
{
#if defined(USE_GNUTLS_NETTLE)
struct sha256_ctx SHA256pw;
@@ -1777,7 +1789,7 @@ void Curl_gtls_sha256sum(const unsigned char *tmp, /* input */
#endif
}
-bool Curl_gtls_cert_status_request(void)
+static bool Curl_gtls_cert_status_request(void)
{
#ifdef HAS_OCSP
return TRUE;
@@ -1786,4 +1798,44 @@ bool Curl_gtls_cert_status_request(void)
#endif
}
+static void *Curl_gtls_get_internals(struct ssl_connect_data *connssl,
+ CURLINFO info UNUSED_PARAM)
+{
+ (void)info;
+ return BACKEND->session;
+}
+
+const struct Curl_ssl Curl_ssl_gnutls = {
+ { CURLSSLBACKEND_GNUTLS, "gnutls" }, /* info */
+
+ 1, /* have_ca_path */
+ 1, /* have_certinfo */
+ 1, /* have_pinnedpubkey */
+ 0, /* have_ssl_ctx */
+ 1, /* support_https_proxy */
+
+ sizeof(struct ssl_backend_data),
+
+ Curl_gtls_init, /* init */
+ Curl_gtls_cleanup, /* cleanup */
+ Curl_gtls_version, /* version */
+ Curl_none_check_cxn, /* check_cxn */
+ Curl_gtls_shutdown, /* shutdown */
+ Curl_gtls_data_pending, /* data_pending */
+ Curl_gtls_random, /* random */
+ Curl_gtls_cert_status_request, /* cert_status_request */
+ Curl_gtls_connect, /* connect */
+ Curl_gtls_connect_nonblocking, /* connect_nonblocking */
+ Curl_gtls_get_internals, /* get_internals */
+ Curl_gtls_close, /* close_one */
+ Curl_none_close_all, /* close_all */
+ Curl_gtls_session_free, /* session_free */
+ Curl_none_set_engine, /* set_engine */
+ Curl_none_set_engine_default, /* set_engine_default */
+ Curl_none_engines_list, /* engines_list */
+ Curl_none_false_start, /* false_start */
+ Curl_gtls_md5sum, /* md5sum */
+ Curl_gtls_sha256sum /* sha256sum */
+};
+
#endif /* USE_GNUTLS */
diff --git a/lib/vtls/gtls.h b/lib/vtls/gtls.h
index 462c0485..780fc109 100644
--- a/lib/vtls/gtls.h
+++ b/lib/vtls/gtls.h
@@ -28,69 +28,7 @@
#include "urldata.h"
-int Curl_gtls_init(void);
-int Curl_gtls_cleanup(void);
-CURLcode Curl_gtls_connect(struct connectdata *conn, int sockindex);
-CURLcode Curl_gtls_connect_nonblocking(struct connectdata *conn,
- int sockindex,
- bool *done);
-bool Curl_gtls_data_pending(const struct connectdata *conn,
- int connindex);
-
- /* close a SSL connection */
-void Curl_gtls_close(struct connectdata *conn, int sockindex);
-
-void Curl_gtls_session_free(void *ptr);
-size_t Curl_gtls_version(char *buffer, size_t size);
-int Curl_gtls_shutdown(struct connectdata *conn, int sockindex);
-CURLcode Curl_gtls_random(struct Curl_easy *data,
- unsigned char *entropy,
- size_t length);
-void Curl_gtls_md5sum(unsigned char *tmp, /* input */
- size_t tmplen,
- unsigned char *md5sum, /* output */
- size_t md5len);
-void Curl_gtls_sha256sum(const unsigned char *tmp, /* input */
- size_t tmplen,
- unsigned char *sha256sum, /* output */
- size_t sha256len);
-
-bool Curl_gtls_cert_status_request(void);
-
-/* Support HTTPS-proxy */
-#define HTTPS_PROXY_SUPPORT 1
-
-/* Set the API backend definition to GnuTLS */
-#define CURL_SSL_BACKEND CURLSSLBACKEND_GNUTLS
-
-/* this backend supports the CAPATH option */
-#define have_curlssl_ca_path 1
-
-/* this backend supports CURLOPT_CERTINFO */
-#define have_curlssl_certinfo 1
-
-/* this backend supports CURLOPT_PINNEDPUBLICKEY */
-#define have_curlssl_pinnedpubkey 1
-
-/* API setup for GnuTLS */
-#define curlssl_init Curl_gtls_init
-#define curlssl_cleanup Curl_gtls_cleanup
-#define curlssl_connect Curl_gtls_connect
-#define curlssl_connect_nonblocking Curl_gtls_connect_nonblocking
-#define curlssl_session_free(x) Curl_gtls_session_free(x)
-#define curlssl_close_all(x) ((void)x)
-#define curlssl_close Curl_gtls_close
-#define curlssl_shutdown(x,y) Curl_gtls_shutdown(x,y)
-#define curlssl_set_engine(x,y) ((void)x, (void)y, CURLE_NOT_BUILT_IN)
-#define curlssl_set_engine_default(x) ((void)x, CURLE_NOT_BUILT_IN)
-#define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL)
-#define curlssl_version Curl_gtls_version
-#define curlssl_check_cxn(x) ((void)x, -1)
-#define curlssl_data_pending(x,y) Curl_gtls_data_pending(x,y)
-#define curlssl_random(x,y,z) Curl_gtls_random(x,y,z)
-#define curlssl_md5sum(a,b,c,d) Curl_gtls_md5sum(a,b,c,d)
-#define curlssl_sha256sum(a,b,c,d) Curl_gtls_sha256sum(a,b,c,d)
-#define curlssl_cert_status_request() Curl_gtls_cert_status_request()
+extern const struct Curl_ssl Curl_ssl_gnutls;
#endif /* USE_GNUTLS */
#endif /* HEADER_CURL_GTLS_H */
diff --git a/lib/vtls/mbedtls.c b/lib/vtls/mbedtls.c
index 037babe3..28251a38 100644
--- a/lib/vtls/mbedtls.c
+++ b/lib/vtls/mbedtls.c
@@ -61,6 +61,21 @@
#include "curl_memory.h"
#include "memdebug.h"
+struct ssl_backend_data {
+ mbedtls_ctr_drbg_context ctr_drbg;
+ mbedtls_entropy_context entropy;
+ mbedtls_ssl_context ssl;
+ int server_fd;
+ mbedtls_x509_crt cacert;
+ mbedtls_x509_crt clicert;
+ mbedtls_x509_crl crl;
+ mbedtls_pk_context pk;
+ mbedtls_ssl_config config;
+ const char *protocols[3];
+};
+
+#define BACKEND connssl->backend
+
/* apply threading? */
#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
#define THREADING_SUPPORT
@@ -214,9 +229,9 @@ set_ssl_version_min_max(struct connectdata *conn, int sockindex)
return result;
}
- mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
+ mbedtls_ssl_conf_min_version(&BACKEND->config, MBEDTLS_SSL_MAJOR_VERSION_3,
mbedtls_ver_min);
- mbedtls_ssl_conf_max_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
+ mbedtls_ssl_conf_max_version(&BACKEND->config, MBEDTLS_SSL_MAJOR_VERSION_3,
mbedtls_ver_max);
return result;
@@ -238,7 +253,7 @@ mbed_connect_step1(struct connectdata *conn,
const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port;
int ret = -1;
char errorbuf[128];
- errorbuf[0]=0;
+ errorbuf[0] = 0;
/* mbedTLS only supports SSLv3 and TLSv1 */
if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) {
@@ -248,9 +263,9 @@ mbed_connect_step1(struct connectdata *conn,
#ifdef THREADING_SUPPORT
entropy_init_mutex(&ts_entropy);
- mbedtls_ctr_drbg_init(&connssl->ctr_drbg);
+ mbedtls_ctr_drbg_init(&BACKEND->ctr_drbg);
- ret = mbedtls_ctr_drbg_seed(&connssl->ctr_drbg, entropy_func_mutex,
+ ret = mbedtls_ctr_drbg_seed(&BACKEND->ctr_drbg, entropy_func_mutex,
&ts_entropy, NULL, 0);
if(ret) {
#ifdef MBEDTLS_ERROR_C
@@ -260,11 +275,11 @@ mbed_connect_step1(struct connectdata *conn,
-ret, errorbuf);
}
#else
- mbedtls_entropy_init(&connssl->entropy);
- mbedtls_ctr_drbg_init(&connssl->ctr_drbg);
+ mbedtls_entropy_init(&BACKEND->entropy);
+ mbedtls_ctr_drbg_init(&BACKEND->ctr_drbg);
- ret = mbedtls_ctr_drbg_seed(&connssl->ctr_drbg, mbedtls_entropy_func,
- &connssl->entropy, NULL, 0);
+ ret = mbedtls_ctr_drbg_seed(&BACKEND->ctr_drbg, mbedtls_entropy_func,
+ &BACKEND->entropy, NULL, 0);
if(ret) {
#ifdef MBEDTLS_ERROR_C
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
@@ -275,10 +290,10 @@ mbed_connect_step1(struct connectdata *conn,
#endif /* THREADING_SUPPORT */
/* Load the trusted CA */
- mbedtls_x509_crt_init(&connssl->cacert);
+ mbedtls_x509_crt_init(&BACKEND->cacert);
if(ssl_cafile) {
- ret = mbedtls_x509_crt_parse_file(&connssl->cacert, ssl_cafile);
+ ret = mbedtls_x509_crt_parse_file(&BACKEND->cacert, ssl_cafile);
if(ret<0) {
#ifdef MBEDTLS_ERROR_C
@@ -293,7 +308,7 @@ mbed_connect_step1(struct connectdata *conn,
}
if(ssl_capath) {
- ret = mbedtls_x509_crt_parse_path(&connssl->cacert, ssl_capath);
+ ret = mbedtls_x509_crt_parse_path(&BACKEND->cacert, ssl_capath);
if(ret<0) {
#ifdef MBEDTLS_ERROR_C
@@ -308,10 +323,10 @@ mbed_connect_step1(struct connectdata *conn,
}
/* Load the client certificate */
- mbedtls_x509_crt_init(&connssl->clicert);
+ mbedtls_x509_crt_init(&BACKEND->clicert);
if(ssl_cert) {
- ret = mbedtls_x509_crt_parse_file(&connssl->clicert, ssl_cert);
+ ret = mbedtls_x509_crt_parse_file(&BACKEND->clicert, ssl_cert);
if(ret) {
#ifdef MBEDTLS_ERROR_C
@@ -325,12 +340,12 @@ mbed_connect_step1(struct connectdata *conn,
}
/* Load the client private key */
- mbedtls_pk_init(&connssl->pk);
+ mbedtls_pk_init(&BACKEND->pk);
if(SSL_SET_OPTION(key)) {
- ret = mbedtls_pk_parse_keyfile(&connssl->pk, SSL_SET_OPTION(key),
+ ret = mbedtls_pk_parse_keyfile(&BACKEND->pk, SSL_SET_OPTION(key),
SSL_SET_OPTION(key_passwd));
- if(ret == 0 && !mbedtls_pk_can_do(&connssl->pk, MBEDTLS_PK_RSA))
+ if(ret == 0 && !mbedtls_pk_can_do(&BACKEND->pk, MBEDTLS_PK_RSA))
ret = MBEDTLS_ERR_PK_TYPE_MISMATCH;
if(ret) {
@@ -345,10 +360,10 @@ mbed_connect_step1(struct connectdata *conn,
}
/* Load the CRL */
- mbedtls_x509_crl_init(&connssl->crl);
+ mbedtls_x509_crl_init(&BACKEND->crl);
if(ssl_crlfile) {
- ret = mbedtls_x509_crl_parse_file(&connssl->crl, ssl_crlfile);
+ ret = mbedtls_x509_crl_parse_file(&BACKEND->crl, ssl_crlfile);
if(ret) {
#ifdef MBEDTLS_ERROR_C
@@ -363,14 +378,14 @@ mbed_connect_step1(struct connectdata *conn,
infof(data, "mbedTLS: Connecting to %s:%d\n", hostname, port);
- mbedtls_ssl_config_init(&connssl->config);
+ mbedtls_ssl_config_init(&BACKEND->config);
- mbedtls_ssl_init(&connssl->ssl);
- if(mbedtls_ssl_setup(&connssl->ssl, &connssl->config)) {
+ mbedtls_ssl_init(&BACKEND->ssl);
+ if(mbedtls_ssl_setup(&BACKEND->ssl, &BACKEND->config)) {
failf(data, "mbedTLS: ssl_init failed");
return CURLE_SSL_CONNECT_ERROR;
}
- ret = mbedtls_ssl_config_defaults(&connssl->config,
+ ret = mbedtls_ssl_config_defaults(&BACKEND->config,
MBEDTLS_SSL_IS_CLIENT,
MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT);
@@ -380,20 +395,20 @@ mbed_connect_step1(struct connectdata *conn,
}
/* new profile with RSA min key len = 1024 ... */
- mbedtls_ssl_conf_cert_profile(&connssl->config,
+ mbedtls_ssl_conf_cert_profile(&BACKEND->config,
&mbedtls_x509_crt_profile_fr);
switch(SSL_CONN_CONFIG(version)) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
- mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
+ mbedtls_ssl_conf_min_version(&BACKEND->config, MBEDTLS_SSL_MAJOR_VERSION_3,
MBEDTLS_SSL_MINOR_VERSION_1);
infof(data, "mbedTLS: Set min SSL version to TLS 1.0\n");
break;
case CURL_SSLVERSION_SSLv3:
- mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
+ mbedtls_ssl_conf_min_version(&BACKEND->config, MBEDTLS_SSL_MAJOR_VERSION_3,
MBEDTLS_SSL_MINOR_VERSION_0);
- mbedtls_ssl_conf_max_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
+ mbedtls_ssl_conf_max_version(&BACKEND->config, MBEDTLS_SSL_MAJOR_VERSION_3,
MBEDTLS_SSL_MINOR_VERSION_0);
infof(data, "mbedTLS: Set SSL version to SSLv3\n");
break;
@@ -412,25 +427,25 @@ mbed_connect_step1(struct connectdata *conn,
return CURLE_SSL_CONNECT_ERROR;
}
- mbedtls_ssl_conf_authmode(&connssl->config, MBEDTLS_SSL_VERIFY_OPTIONAL);
+ mbedtls_ssl_conf_authmode(&BACKEND->config, MBEDTLS_SSL_VERIFY_OPTIONAL);
- mbedtls_ssl_conf_rng(&connssl->config, mbedtls_ctr_drbg_random,
- &connssl->ctr_drbg);
- mbedtls_ssl_set_bio(&connssl->ssl, &conn->sock[sockindex],
+ mbedtls_ssl_conf_rng(&BACKEND->config, mbedtls_ctr_drbg_random,
+ &BACKEND->ctr_drbg);
+ mbedtls_ssl_set_bio(&BACKEND->ssl, &conn->sock[sockindex],
mbedtls_net_send,
mbedtls_net_recv,
NULL /* rev_timeout() */);
- mbedtls_ssl_conf_ciphersuites(&connssl->config,
+ mbedtls_ssl_conf_ciphersuites(&BACKEND->config,
mbedtls_ssl_list_ciphersuites());
#if defined(MBEDTLS_SSL_RENEGOTIATION)
- mbedtls_ssl_conf_renegotiation(&connssl->config,
+ mbedtls_ssl_conf_renegotiation(&BACKEND->config,
MBEDTLS_SSL_RENEGOTIATION_ENABLED);
#endif
#if defined(MBEDTLS_SSL_SESSION_TICKETS)
- mbedtls_ssl_conf_session_tickets(&connssl->config,
+ mbedtls_ssl_conf_session_tickets(&BACKEND->config,
MBEDTLS_SSL_SESSION_TICKETS_DISABLED);
#endif
@@ -440,7 +455,7 @@ mbed_connect_step1(struct connectdata *conn,
Curl_ssl_sessionid_lock(conn);
if(!Curl_ssl_getsessionid(conn, &old_session, NULL, sockindex)) {
- ret = mbedtls_ssl_set_session(&connssl->ssl, old_session);
+ ret = mbedtls_ssl_set_session(&BACKEND->ssl, old_session);
if(ret) {
Curl_ssl_sessionid_unlock(conn);
failf(data, "mbedtls_ssl_set_session returned -0x%x", -ret);
@@ -451,15 +466,15 @@ mbed_connect_step1(struct connectdata *conn,
Curl_ssl_sessionid_unlock(conn);
}
- mbedtls_ssl_conf_ca_chain(&connssl->config,
- &connssl->cacert,
- &connssl->crl);
+ mbedtls_ssl_conf_ca_chain(&BACKEND->config,
+ &BACKEND->cacert,
+ &BACKEND->crl);
if(SSL_SET_OPTION(key)) {
- mbedtls_ssl_conf_own_cert(&connssl->config,
- &connssl->clicert, &connssl->pk);
+ mbedtls_ssl_conf_own_cert(&BACKEND->config,
+ &BACKEND->clicert, &BACKEND->pk);
}
- if(mbedtls_ssl_set_hostname(&connssl->ssl, hostname)) {
+ if(mbedtls_ssl_set_hostname(&BACKEND->ssl, hostname)) {
/* mbedtls_ssl_set_hostname() sets the name to use in CN/SAN checks *and*
the name to set in the SNI extension. So even if curl connects to a
host specified as an IP address, this function must be used. */
@@ -469,7 +484,7 @@ mbed_connect_step1(struct connectdata *conn,
#ifdef HAS_ALPN
if(conn->bits.tls_enable_alpn) {
- const char **p = &connssl->protocols[0];
+ const char **p = &BACKEND->protocols[0];
#ifdef USE_NGHTTP2
if(data->set.httpversion >= CURL_HTTP_VERSION_2)
*p++ = NGHTTP2_PROTO_VERSION_ID;
@@ -478,19 +493,19 @@ mbed_connect_step1(struct connectdata *conn,
*p = NULL;
/* this function doesn't clone the protocols array, which is why we need
to keep it around */
- if(mbedtls_ssl_conf_alpn_protocols(&connssl->config,
- &connssl->protocols[0])) {
+ if(mbedtls_ssl_conf_alpn_protocols(&BACKEND->config,
+ &BACKEND->protocols[0])) {
failf(data, "Failed setting ALPN protocols");
return CURLE_SSL_CONNECT_ERROR;
}
- for(p = &connssl->protocols[0]; *p; ++p)
+ for(p = &BACKEND->protocols[0]; *p; ++p)
infof(data, "ALPN, offering %s\n", *p);
}
#endif
#ifdef MBEDTLS_DEBUG
/* In order to make that work in mbedtls MBEDTLS_DEBUG_C must be defined. */
- mbedtls_ssl_conf_dbg(&connssl->config, mbed_debug, data);
+ mbedtls_ssl_conf_dbg(&BACKEND->config, mbed_debug, data);
/* - 0 No debug
* - 1 Error
* - 2 State change
@@ -502,7 +517,7 @@ mbed_connect_step1(struct connectdata *conn,
/* give application a chance to interfere with mbedTLS set up. */
if(data->set.ssl.fsslctx) {
- ret = (*data->set.ssl.fsslctx)(data, &connssl->config,
+ ret = (*data->set.ssl.fsslctx)(data, &BACKEND->config,
data->set.ssl.fsslctxp);
if(ret) {
failf(data, "error signaled by ssl ctx callback");
@@ -537,7 +552,7 @@ mbed_connect_step2(struct connectdata *conn,
conn->recv[sockindex] = mbed_recv;
conn->send[sockindex] = mbed_send;
- ret = mbedtls_ssl_handshake(&connssl->ssl);
+ ret = mbedtls_ssl_handshake(&BACKEND->ssl);
if(ret == MBEDTLS_ERR_SSL_WANT_READ) {
connssl->connecting_state = ssl_connect_2_reading;
@@ -557,10 +572,10 @@ mbed_connect_step2(struct connectdata *conn,
}
infof(data, "mbedTLS: Handshake complete, cipher is %s\n",
- mbedtls_ssl_get_ciphersuite(&conn->ssl[sockindex].ssl)
+ mbedtls_ssl_get_ciphersuite(&BACKEND->ssl)
);
- ret = mbedtls_ssl_get_verify_result(&conn->ssl[sockindex].ssl);
+ ret = mbedtls_ssl_get_verify_result(&BACKEND->ssl);
if(ret && SSL_CONN_CONFIG(verifypeer)) {
if(ret & MBEDTLS_X509_BADCERT_EXPIRED)
@@ -580,7 +595,7 @@ mbed_connect_step2(struct connectdata *conn,
return CURLE_PEER_FAILED_VERIFICATION;
}
- peercert = mbedtls_ssl_get_peer_cert(&connssl->ssl);
+ peercert = mbedtls_ssl_get_peer_cert(&BACKEND->ssl);
if(peercert && data->set.verbose) {
const size_t bufsize = 16384;
@@ -650,7 +665,7 @@ mbed_connect_step2(struct connectdata *conn,
#ifdef HAS_ALPN
if(conn->bits.tls_enable_alpn) {
- next_protocol = mbedtls_ssl_get_alpn_protocol(&connssl->ssl);
+ next_protocol = mbedtls_ssl_get_alpn_protocol(&BACKEND->ssl);
if(next_protocol) {
infof(data, "ALPN, server accepted to use %s\n", next_protocol);
@@ -700,7 +715,7 @@ mbed_connect_step3(struct connectdata *conn,
mbedtls_ssl_session_init(our_ssl_sessionid);
- ret = mbedtls_ssl_get_session(&connssl->ssl, our_ssl_sessionid);
+ ret = mbedtls_ssl_get_session(&BACKEND->ssl, our_ssl_sessionid);
if(ret) {
free(our_ssl_sessionid);
failf(data, "mbedtls_ssl_get_session returned -0x%x", -ret);
@@ -730,9 +745,10 @@ static ssize_t mbed_send(struct connectdata *conn, int sockindex,
const void *mem, size_t len,
CURLcode *curlcode)
{
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
int ret = -1;
- ret = mbedtls_ssl_write(&conn->ssl[sockindex].ssl,
+ ret = mbedtls_ssl_write(&BACKEND->ssl,
(unsigned char *)mem, len);
if(ret < 0) {
@@ -744,22 +760,23 @@ static ssize_t mbed_send(struct connectdata *conn, int sockindex,
return ret;
}
-void Curl_mbedtls_close_all(struct Curl_easy *data)
+static void Curl_mbedtls_close_all(struct Curl_easy *data)
{
(void)data;
}
-void Curl_mbedtls_close(struct connectdata *conn, int sockindex)
+static void Curl_mbedtls_close(struct connectdata *conn, int sockindex)
{
- mbedtls_pk_free(&conn->ssl[sockindex].pk);
- mbedtls_x509_crt_free(&conn->ssl[sockindex].clicert);
- mbedtls_x509_crt_free(&conn->ssl[sockindex].cacert);
- mbedtls_x509_crl_free(&conn->ssl[sockindex].crl);
- mbedtls_ssl_config_free(&conn->ssl[sockindex].config);
- mbedtls_ssl_free(&conn->ssl[sockindex].ssl);
- mbedtls_ctr_drbg_free(&conn->ssl[sockindex].ctr_drbg);
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ mbedtls_pk_free(&BACKEND->pk);
+ mbedtls_x509_crt_free(&BACKEND->clicert);
+ mbedtls_x509_crt_free(&BACKEND->cacert);
+ mbedtls_x509_crl_free(&BACKEND->crl);
+ mbedtls_ssl_config_free(&BACKEND->config);
+ mbedtls_ssl_free(&BACKEND->ssl);
+ mbedtls_ctr_drbg_free(&BACKEND->ctr_drbg);
#ifndef THREADING_SUPPORT
- mbedtls_entropy_free(&conn->ssl[sockindex].entropy);
+ mbedtls_entropy_free(&BACKEND->entropy);
#endif /* THREADING_SUPPORT */
}
@@ -767,11 +784,12 @@ static ssize_t mbed_recv(struct connectdata *conn, int num,
char *buf, size_t buffersize,
CURLcode *curlcode)
{
+ struct ssl_connect_data *connssl = &conn->ssl[num];
int ret = -1;
ssize_t len = -1;
memset(buf, 0, buffersize);
- ret = mbedtls_ssl_read(&conn->ssl[num].ssl, (unsigned char *)buf,
+ ret = mbedtls_ssl_read(&BACKEND->ssl, (unsigned char *)buf,
buffersize);
if(ret <= 0) {
@@ -788,21 +806,21 @@ static ssize_t mbed_recv(struct connectdata *conn, int num,
return len;
}
-void Curl_mbedtls_session_free(void *ptr)
+static void Curl_mbedtls_session_free(void *ptr)
{
mbedtls_ssl_session_free(ptr);
free(ptr);
}
-size_t Curl_mbedtls_version(char *buffer, size_t size)
+static size_t Curl_mbedtls_version(char *buffer, size_t size)
{
unsigned int version = mbedtls_version_get_number();
return snprintf(buffer, size, "mbedTLS/%d.%d.%d", version>>24,
(version>>16)&0xff, (version>>8)&0xff);
}
-CURLcode Curl_mbedtls_random(struct Curl_easy *data, unsigned char *entropy,
- size_t length)
+static CURLcode Curl_mbedtls_random(struct Curl_easy *data,
+ unsigned char *entropy, size_t length)
{
#if defined(MBEDTLS_CTR_DRBG_C)
int ret = -1;
@@ -811,7 +829,7 @@ CURLcode Curl_mbedtls_random(struct Curl_easy *data, unsigned char *entropy,
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_entropy_init(&ctr_entropy);
mbedtls_ctr_drbg_init(&ctr_drbg);
- errorbuf[0]=0;
+ errorbuf[0] = 0;
ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func,
&ctr_entropy, NULL, 0);
@@ -869,7 +887,7 @@ mbed_connect_common(struct connectdata *conn,
return CURLE_OK;
}
- if(ssl_connect_1==connssl->connecting_state) {
+ if(ssl_connect_1 == connssl->connecting_state) {
/* Find out how much more time we're allowed */
timeout_ms = Curl_timeleft(data, NULL, TRUE);
@@ -900,9 +918,9 @@ mbed_connect_common(struct connectdata *conn,
if(connssl->connecting_state == ssl_connect_2_reading
|| connssl->connecting_state == ssl_connect_2_writing) {
- curl_socket_t writefd = ssl_connect_2_writing==
+ curl_socket_t writefd = ssl_connect_2_writing ==
connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
- curl_socket_t readfd = ssl_connect_2_reading==
+ curl_socket_t readfd = ssl_connect_2_reading ==
connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
@@ -942,13 +960,13 @@ mbed_connect_common(struct connectdata *conn,
} /* repeat step2 until all transactions are done. */
- if(ssl_connect_3==connssl->connecting_state) {
+ if(ssl_connect_3 == connssl->connecting_state) {
retcode = mbed_connect_step3(conn, sockindex);
if(retcode)
return retcode;
}
- if(ssl_connect_done==connssl->connecting_state) {
+ if(ssl_connect_done == connssl->connecting_state) {
connssl->state = ssl_connection_complete;
conn->recv[sockindex] = mbed_recv;
conn->send[sockindex] = mbed_send;
@@ -963,18 +981,14 @@ mbed_connect_common(struct connectdata *conn,
return CURLE_OK;
}
-CURLcode
-Curl_mbedtls_connect_nonblocking(struct connectdata *conn,
- int sockindex,
- bool *done)
+static CURLcode Curl_mbedtls_connect_nonblocking(struct connectdata *conn,
+ int sockindex, bool *done)
{
return mbed_connect_common(conn, sockindex, TRUE, done);
}
-CURLcode
-Curl_mbedtls_connect(struct connectdata *conn,
- int sockindex)
+static CURLcode Curl_mbedtls_connect(struct connectdata *conn, int sockindex)
{
CURLcode retcode;
bool done = FALSE;
@@ -992,19 +1006,70 @@ Curl_mbedtls_connect(struct connectdata *conn,
* return 0 error initializing SSL
* return 1 SSL initialized successfully
*/
-int Curl_mbedtls_init(void)
+static int Curl_mbedtls_init(void)
{
return Curl_polarsslthreadlock_thread_setup();
}
-void Curl_mbedtls_cleanup(void)
+static void Curl_mbedtls_cleanup(void)
{
(void)Curl_polarsslthreadlock_thread_cleanup();
}
-int Curl_mbedtls_data_pending(const struct connectdata *conn, int sockindex)
+static bool Curl_mbedtls_data_pending(const struct connectdata *conn,
+ int sockindex)
{
- return mbedtls_ssl_get_bytes_avail(&conn->ssl[sockindex].ssl) != 0;
+ const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ return mbedtls_ssl_get_bytes_avail(&BACKEND->ssl) != 0;
}
+static void Curl_mbedtls_sha256sum(const unsigned char *input,
+ size_t inputlen,
+ unsigned char *sha256sum,
+ size_t sha256len UNUSED_PARAM)
+{
+ (void)sha256len;
+ mbedtls_sha256(input, inputlen, sha256sum, 0);
+}
+
+static void *Curl_mbedtls_get_internals(struct ssl_connect_data *connssl,
+ CURLINFO info UNUSED_PARAM)
+{
+ (void)info;
+ return &BACKEND->ssl;
+}
+
+const struct Curl_ssl Curl_ssl_mbedtls = {
+ { CURLSSLBACKEND_MBEDTLS, "mbedtls" }, /* info */
+
+ 1, /* have_ca_path */
+ 0, /* have_certinfo */
+ 1, /* have_pinnedpubkey */
+ 1, /* have_ssl_ctx */
+ 0, /* support_https_proxy */
+
+ sizeof(struct ssl_backend_data),
+
+ Curl_mbedtls_init, /* init */
+ Curl_mbedtls_cleanup, /* cleanup */
+ Curl_mbedtls_version, /* version */
+ Curl_none_check_cxn, /* check_cxn */
+ Curl_none_shutdown, /* shutdown */
+ Curl_mbedtls_data_pending, /* data_pending */
+ Curl_mbedtls_random, /* random */
+ Curl_none_cert_status_request, /* cert_status_request */
+ Curl_mbedtls_connect, /* connect */
+ Curl_mbedtls_connect_nonblocking, /* connect_nonblocking */
+ Curl_mbedtls_get_internals, /* get_internals */
+ Curl_mbedtls_close, /* close_one */
+ Curl_mbedtls_close_all, /* close_all */
+ Curl_mbedtls_session_free, /* session_free */
+ Curl_none_set_engine, /* set_engine */
+ Curl_none_set_engine_default, /* set_engine_default */
+ Curl_none_engines_list, /* engines_list */
+ Curl_none_false_start, /* false_start */
+ Curl_none_md5sum, /* md5sum */
+ Curl_mbedtls_sha256sum /* sha256sum */
+};
+
#endif /* USE_MBEDTLS */
diff --git a/lib/vtls/mbedtls.h b/lib/vtls/mbedtls.h
index 71d17a49..4a938605 100644
--- a/lib/vtls/mbedtls.h
+++ b/lib/vtls/mbedtls.h
@@ -26,57 +26,7 @@
#ifdef USE_MBEDTLS
-#include <mbedtls/sha256.h>
-
-/* Called on first use mbedTLS, setup threading if supported */
-int Curl_mbedtls_init(void);
-void Curl_mbedtls_cleanup(void);
-int Curl_mbedtls_data_pending(const struct connectdata *conn, int sockindex);
-
-CURLcode Curl_mbedtls_connect(struct connectdata *conn, int sockindex);
-
-CURLcode Curl_mbedtls_connect_nonblocking(struct connectdata *conn,
- int sockindex,
- bool *done);
-
-/* tell mbedTLS to close down all open information regarding connections (and
- thus session ID caching etc) */
-void Curl_mbedtls_close_all(struct Curl_easy *data);
-
- /* close a SSL connection */
-void Curl_mbedtls_close(struct connectdata *conn, int sockindex);
-
-void Curl_mbedtls_session_free(void *ptr);
-size_t Curl_mbedtls_version(char *buffer, size_t size);
-int Curl_mbedtls_shutdown(struct connectdata *conn, int sockindex);
-
-CURLcode Curl_mbedtls_random(struct Curl_easy *data, unsigned char *entropy,
- size_t length);
-
-/* this backends supports CURLOPT_PINNEDPUBLICKEY */
-#define have_curlssl_pinnedpubkey 1
-
-/* this backend supports CURLOPT_SSL_CTX_* */
-#define have_curlssl_ssl_ctx 1
-
-/* API setup for mbedTLS */
-#define curlssl_init() Curl_mbedtls_init()
-#define curlssl_cleanup() Curl_mbedtls_cleanup()
-#define curlssl_connect Curl_mbedtls_connect
-#define curlssl_connect_nonblocking Curl_mbedtls_connect_nonblocking
-#define curlssl_session_free(x) Curl_mbedtls_session_free(x)
-#define curlssl_close_all Curl_mbedtls_close_all
-#define curlssl_close Curl_mbedtls_close
-#define curlssl_shutdown(x,y) 0
-#define curlssl_set_engine(x,y) (x=x, y=y, CURLE_NOT_BUILT_IN)
-#define curlssl_set_engine_default(x) (x=x, CURLE_NOT_BUILT_IN)
-#define curlssl_engines_list(x) (x=x, (struct curl_slist *)NULL)
-#define curlssl_version Curl_mbedtls_version
-#define curlssl_check_cxn(x) (x=x, -1)
-#define curlssl_data_pending(x,y) Curl_mbedtls_data_pending(x, y)
-#define CURL_SSL_BACKEND CURLSSLBACKEND_MBEDTLS
-#define curlssl_sha256sum(a,b,c,d) mbedtls_sha256(a,b,c,0)
-#define curlssl_random(x,y,z) Curl_mbedtls_random(x, y, z)
+extern const struct Curl_ssl Curl_ssl_mbedtls;
#endif /* USE_MBEDTLS */
#endif /* HEADER_CURL_MBEDTLS_H */
diff --git a/lib/vtls/nss.c b/lib/vtls/nss.c
index d1711d6a..a3ef37a1 100644
--- a/lib/vtls/nss.c
+++ b/lib/vtls/nss.c
@@ -78,6 +78,16 @@
/* enough to fit the string "PEM Token #[0|1]" */
#define SLOTSIZE 13
+struct ssl_backend_data {
+ PRFileDesc *handle;
+ char *client_nickname;
+ struct Curl_easy *data;
+ struct curl_llist obj_list;
+ PK11GenericObject *obj_clicert;
+};
+
+#define BACKEND connssl->backend
+
static PRLock *nss_initlock = NULL;
static PRLock *nss_crllock = NULL;
static PRLock *nss_findslot_lock = NULL;
@@ -271,7 +281,7 @@ static SECStatus set_ciphers(struct Curl_easy *data, PRFileDesc * model,
found = PR_FALSE;
- for(i=0; i<NUM_OF_CIPHERS; i++) {
+ for(i = 0; i<NUM_OF_CIPHERS; i++) {
if(strcasecompare(cipher, cipherlist[i].name)) {
cipher_state[i] = PR_TRUE;
found = PR_TRUE;
@@ -290,7 +300,7 @@ static SECStatus set_ciphers(struct Curl_easy *data, PRFileDesc * model,
}
/* Finally actually enable the selected ciphers */
- for(i=0; i<NUM_OF_CIPHERS; i++) {
+ for(i = 0; i<NUM_OF_CIPHERS; i++) {
if(!cipher_state[i])
continue;
@@ -311,7 +321,7 @@ static bool any_cipher_enabled(void)
{
unsigned int i;
- for(i=0; i<NUM_OF_CIPHERS; i++) {
+ for(i = 0; i<NUM_OF_CIPHERS; i++) {
PRInt32 policy = 0;
SSL_CipherPolicyGet(cipherlist[i].num, &policy);
if(policy)
@@ -396,7 +406,7 @@ static CURLcode insert_wrapped_ptr(struct curl_llist *list, void *ptr)
/* Call PK11_CreateGenericObject() with the given obj_class and filename. If
* the call succeeds, append the object handle to the list of objects so that
* the object can be destroyed in Curl_nss_close(). */
-static CURLcode nss_create_object(struct ssl_connect_data *ssl,
+static CURLcode nss_create_object(struct ssl_connect_data *connssl,
CK_OBJECT_CLASS obj_class,
const char *filename, bool cacert)
{
@@ -435,14 +445,14 @@ static CURLcode nss_create_object(struct ssl_connect_data *ssl,
if(!obj)
return result;
- if(insert_wrapped_ptr(&ssl->obj_list, obj) != CURLE_OK) {
+ if(insert_wrapped_ptr(&BACKEND->obj_list, obj) != CURLE_OK) {
PK11_DestroyGenericObject(obj);
return CURLE_OUT_OF_MEMORY;
}
if(!cacert && CKO_CERTIFICATE == obj_class)
/* store reference to a client certificate */
- ssl->obj_clicert = obj;
+ BACKEND->obj_clicert = obj;
return CURLE_OK;
}
@@ -992,7 +1002,7 @@ static SECStatus check_issuer_cert(PRFileDesc *sock,
char *issuer_nickname)
{
CERTCertificate *cert, *cert_issuer, *issuer;
- SECStatus res=SECSuccess;
+ SECStatus res = SECSuccess;
void *proto_win = NULL;
cert = SSL_PeerCertificate(sock);
@@ -1004,7 +1014,7 @@ static SECStatus check_issuer_cert(PRFileDesc *sock,
if((!cert_issuer) || (!issuer))
res = SECFailure;
else if(SECITEM_CompareItem(&cert_issuer->derCert,
- &issuer->derCert)!=SECEqual)
+ &issuer->derCert) != SECEqual)
res = SECFailure;
CERT_DestroyCertificate(cert);
@@ -1017,7 +1027,7 @@ static CURLcode cmp_peer_pubkey(struct ssl_connect_data *connssl,
const char *pinnedpubkey)
{
CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
- struct Curl_easy *data = connssl->data;
+ struct Curl_easy *data = BACKEND->data;
CERTCertificate *cert;
if(!pinnedpubkey)
@@ -1025,7 +1035,7 @@ static CURLcode cmp_peer_pubkey(struct ssl_connect_data *connssl,
return CURLE_OK;
/* get peer certificate */
- cert = SSL_PeerCertificate(connssl->handle);
+ cert = SSL_PeerCertificate(BACKEND->handle);
if(cert) {
/* extract public key from peer certificate */
SECKEYPublicKey *pubkey = CERT_ExtractPublicKey(cert);
@@ -1069,11 +1079,11 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
struct SECKEYPrivateKeyStr **pRetKey)
{
struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg;
- struct Curl_easy *data = connssl->data;
- const char *nickname = connssl->client_nickname;
+ struct Curl_easy *data = BACKEND->data;
+ const char *nickname = BACKEND->client_nickname;
static const char pem_slotname[] = "PEM Token #1";
- if(connssl->obj_clicert) {
+ if(BACKEND->obj_clicert) {
/* use the cert/key provided by PEM reader */
SECItem cert_der = { 0, NULL, 0 };
void *proto_win = SSL_RevealPinArg(sock);
@@ -1086,7 +1096,7 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
return SECFailure;
}
- if(PK11_ReadRawAttribute(PK11_TypeGeneric, connssl->obj_clicert, CKA_VALUE,
+ if(PK11_ReadRawAttribute(PK11_TypeGeneric, BACKEND->obj_clicert, CKA_VALUE,
&cert_der) != SECSuccess) {
failf(data, "NSS: CKA_VALUE not found in PK11 generic object");
PK11_FreeSlot(slot);
@@ -1351,7 +1361,7 @@ static CURLcode nss_init(struct Curl_easy *data)
* @retval 0 error initializing SSL
* @retval 1 SSL initialized successfully
*/
-int Curl_nss_init(void)
+static int Curl_nss_init(void)
{
/* curl_global_init() is not thread-safe so this test is ok */
if(nss_initlock == NULL) {
@@ -1386,7 +1396,7 @@ CURLcode Curl_nss_force_init(struct Curl_easy *data)
}
/* Global cleanup */
-void Curl_nss_cleanup(void)
+static void Curl_nss_cleanup(void)
{
/* This function isn't required to be threadsafe and this is only done
* as a safety feature.
@@ -1426,14 +1436,14 @@ void Curl_nss_cleanup(void)
* 0 means the connection has been closed
* -1 means the connection status is unknown
*/
-int
-Curl_nss_check_cxn(struct connectdata *conn)
+static int Curl_nss_check_cxn(struct connectdata *conn)
{
+ struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET];
int rc;
char buf;
rc =
- PR_Recv(conn->ssl[FIRSTSOCKET].handle, (void *)&buf, 1, PR_MSG_PEEK,
+ PR_Recv(BACKEND->handle, (void *)&buf, 1, PR_MSG_PEEK,
PR_SecondsToInterval(1));
if(rc > 0)
return 1; /* connection still in place */
@@ -1447,48 +1457,49 @@ Curl_nss_check_cxn(struct connectdata *conn)
static void nss_close(struct ssl_connect_data *connssl)
{
/* before the cleanup, check whether we are using a client certificate */
- const bool client_cert = (connssl->client_nickname != NULL)
- || (connssl->obj_clicert != NULL);
+ const bool client_cert = (BACKEND->client_nickname != NULL)
+ || (BACKEND->obj_clicert != NULL);
- free(connssl->client_nickname);
- connssl->client_nickname = NULL;
+ free(BACKEND->client_nickname);
+ BACKEND->client_nickname = NULL;
/* destroy all NSS objects in order to avoid failure of NSS shutdown */
- Curl_llist_destroy(&connssl->obj_list, NULL);
- connssl->obj_clicert = NULL;
+ Curl_llist_destroy(&BACKEND->obj_list, NULL);
+ BACKEND->obj_clicert = NULL;
- if(connssl->handle) {
+ if(BACKEND->handle) {
if(client_cert)
/* A server might require different authentication based on the
* particular path being requested by the client. To support this
* scenario, we must ensure that a connection will never reuse the
* authentication data from a previous connection. */
- SSL_InvalidateSession(connssl->handle);
+ SSL_InvalidateSession(BACKEND->handle);
- PR_Close(connssl->handle);
- connssl->handle = NULL;
+ PR_Close(BACKEND->handle);
+ BACKEND->handle = NULL;
}
}
/*
* This function is called when an SSL connection is closed.
*/
-void Curl_nss_close(struct connectdata *conn, int sockindex)
+static void Curl_nss_close(struct connectdata *conn, int sockindex)
{
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct ssl_connect_data *connssl_proxy = &conn->proxy_ssl[sockindex];
- if(connssl->handle || connssl_proxy->handle) {
+ if(BACKEND->handle || connssl_proxy->backend->handle) {
/* NSS closes the socket we previously handed to it, so we must mark it
as closed to avoid double close */
fake_sclose(conn->sock[sockindex]);
conn->sock[sockindex] = CURL_SOCKET_BAD;
}
- if(connssl->handle)
- /* nss_close(connssl) will transitively close also connssl_proxy->handle
- if both are used. Clear it to avoid a double close leading to crash. */
- connssl_proxy->handle = NULL;
+ if(BACKEND->handle)
+ /* nss_close(connssl) will transitively close also
+ connssl_proxy->backend->handle if both are used. Clear it to avoid
+ a double close leading to crash. */
+ connssl_proxy->backend->handle = NULL;
nss_close(connssl);
nss_close(connssl_proxy);
@@ -1732,7 +1743,7 @@ static CURLcode nss_fail_connect(struct ssl_connect_data *connssl,
}
/* cleanup on connection failure */
- Curl_llist_destroy(&connssl->obj_list, NULL);
+ Curl_llist_destroy(&BACKEND->obj_list, NULL);
return curlerr;
}
@@ -1746,7 +1757,7 @@ static CURLcode nss_set_blocking(struct ssl_connect_data *connssl,
sock_opt.option = PR_SockOpt_Nonblocking;
sock_opt.value.non_blocking = !blocking;
- if(PR_SetSocketOption(connssl->handle, &sock_opt) != PR_SUCCESS)
+ if(PR_SetSocketOption(BACKEND->handle, &sock_opt) != PR_SUCCESS)
return nss_fail_connect(connssl, data, CURLE_SSL_CONNECT_ERROR);
return CURLE_OK;
@@ -1770,10 +1781,10 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
SSL_LIBRARY_VERSION_TLS_1_0 /* max */
};
- connssl->data = data;
+ BACKEND->data = data;
/* list of all NSS objects we need to destroy in Curl_nss_close() */
- Curl_llist_init(&connssl->obj_list, nss_destroy_object);
+ Curl_llist_init(&BACKEND->obj_list, nss_destroy_object);
/* FIXME. NSS doesn't support multiple databases open at the same time. */
PR_Lock(nss_initlock);
@@ -1882,7 +1893,7 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
char *nickname = dup_nickname(data, SSL_SET_OPTION(cert));
if(nickname) {
/* we are not going to use libnsspem.so to read the client cert */
- connssl->obj_clicert = NULL;
+ BACKEND->obj_clicert = NULL;
}
else {
CURLcode rv = cert_stuff(conn, sockindex, SSL_SET_OPTION(cert),
@@ -1895,10 +1906,10 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
}
/* store the nickname for SelectClientCert() called during handshake */
- connssl->client_nickname = nickname;
+ BACKEND->client_nickname = nickname;
}
else
- connssl->client_nickname = NULL;
+ BACKEND->client_nickname = NULL;
if(SSL_GetClientAuthDataHook(model, SelectClientCert,
(void *)connssl) != SECSuccess) {
@@ -1908,8 +1919,8 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
if(conn->proxy_ssl[sockindex].use) {
DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state);
- DEBUGASSERT(conn->proxy_ssl[sockindex].handle != NULL);
- nspr_io = conn->proxy_ssl[sockindex].handle;
+ DEBUGASSERT(conn->proxy_ssl[sockindex].backend->handle != NULL);
+ nspr_io = conn->proxy_ssl[sockindex].backend->handle;
second_layer = TRUE;
}
else {
@@ -1939,8 +1950,8 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
}
/* import our model socket onto the current I/O stack */
- connssl->handle = SSL_ImportFD(model, nspr_io);
- if(!connssl->handle) {
+ BACKEND->handle = SSL_ImportFD(model, nspr_io);
+ if(!BACKEND->handle) {
if(!second_layer)
PR_Close(nspr_io);
goto error;
@@ -1951,36 +1962,36 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
/* This is the password associated with the cert that we're using */
if(SSL_SET_OPTION(key_passwd)) {
- SSL_SetPKCS11PinArg(connssl->handle, SSL_SET_OPTION(key_passwd));
+ SSL_SetPKCS11PinArg(BACKEND->handle, SSL_SET_OPTION(key_passwd));
}
#ifdef SSL_ENABLE_OCSP_STAPLING
if(SSL_CONN_CONFIG(verifystatus)) {
- if(SSL_OptionSet(connssl->handle, SSL_ENABLE_OCSP_STAPLING, PR_TRUE)
+ if(SSL_OptionSet(BACKEND->handle, SSL_ENABLE_OCSP_STAPLING, PR_TRUE)
!= SECSuccess)
goto error;
}
#endif
#ifdef SSL_ENABLE_NPN
- if(SSL_OptionSet(connssl->handle, SSL_ENABLE_NPN, conn->bits.tls_enable_npn
+ if(SSL_OptionSet(BACKEND->handle, SSL_ENABLE_NPN, conn->bits.tls_enable_npn
? PR_TRUE : PR_FALSE) != SECSuccess)
goto error;
#endif
#ifdef SSL_ENABLE_ALPN
- if(SSL_OptionSet(connssl->handle, SSL_ENABLE_ALPN, conn->bits.tls_enable_alpn
+ if(SSL_OptionSet(BACKEND->handle, SSL_ENABLE_ALPN, conn->bits.tls_enable_alpn
? PR_TRUE : PR_FALSE) != SECSuccess)
goto error;
#endif
#if NSSVERNUM >= 0x030f04 /* 3.15.4 */
if(data->set.ssl.falsestart) {
- if(SSL_OptionSet(connssl->handle, SSL_ENABLE_FALSE_START, PR_TRUE)
+ if(SSL_OptionSet(BACKEND->handle, SSL_ENABLE_FALSE_START, PR_TRUE)
!= SECSuccess)
goto error;
- if(SSL_SetCanFalseStartCallback(connssl->handle, CanFalseStartCallback,
+ if(SSL_SetCanFalseStartCallback(BACKEND->handle, CanFalseStartCallback,
conn) != SECSuccess)
goto error;
}
@@ -2004,24 +2015,24 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
memcpy(&protocols[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH);
cur += ALPN_HTTP_1_1_LENGTH;
- if(SSL_SetNextProtoNego(connssl->handle, protocols, cur) != SECSuccess)
+ if(SSL_SetNextProtoNego(BACKEND->handle, protocols, cur) != SECSuccess)
goto error;
}
#endif
/* Force handshake on next I/O */
- if(SSL_ResetHandshake(connssl->handle, /* asServer */ PR_FALSE)
+ if(SSL_ResetHandshake(BACKEND->handle, /* asServer */ PR_FALSE)
!= SECSuccess)
goto error;
/* propagate hostname to the TLS layer */
- if(SSL_SetURL(connssl->handle, SSL_IS_PROXY() ? conn->http_proxy.host.name :
+ if(SSL_SetURL(BACKEND->handle, SSL_IS_PROXY() ? conn->http_proxy.host.name :
conn->host.name) != SECSuccess)
goto error;
/* prevent NSS from re-using the session for a different hostname */
- if(SSL_SetSockPeerID(connssl->handle, SSL_IS_PROXY() ?
+ if(SSL_SetSockPeerID(BACKEND->handle, SSL_IS_PROXY() ?
conn->http_proxy.host.name : conn->host.name)
!= SECSuccess)
goto error;
@@ -2058,7 +2069,7 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex)
/* Force the handshake now */
timeout = PR_MillisecondsToInterval((PRUint32) time_left);
- if(SSL_ForceHandshakeWithTimeout(connssl->handle, timeout) != SECSuccess) {
+ if(SSL_ForceHandshakeWithTimeout(BACKEND->handle, timeout) != SECSuccess) {
if(PR_GetError() == PR_WOULD_BLOCK_ERROR)
/* blocking direction is updated by nss_update_connecting_state() */
return CURLE_AGAIN;
@@ -2069,7 +2080,7 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex)
goto error;
}
- result = display_conn_info(conn, connssl->handle);
+ result = display_conn_info(conn, BACKEND->handle);
if(result)
goto error;
@@ -2078,7 +2089,7 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex)
char *nickname = dup_nickname(data, SSL_SET_OPTION(issuercert));
if(nickname) {
/* we support only nicknames in case of issuercert for now */
- ret = check_issuer_cert(connssl->handle, nickname);
+ ret = check_issuer_cert(BACKEND->handle, nickname);
free(nickname);
}
@@ -2164,13 +2175,13 @@ static CURLcode nss_connect_common(struct connectdata *conn, int sockindex,
return CURLE_OK;
}
-CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
+static CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
{
return nss_connect_common(conn, sockindex, /* blocking */ NULL);
}
-CURLcode Curl_nss_connect_nonblocking(struct connectdata *conn,
- int sockindex, bool *done)
+static CURLcode Curl_nss_connect_nonblocking(struct connectdata *conn,
+ int sockindex, bool *done)
{
return nss_connect_common(conn, sockindex, done);
}
@@ -2186,9 +2197,9 @@ static ssize_t nss_send(struct connectdata *conn, /* connection data */
/* The SelectClientCert() hook uses this for infof() and failf() but the
handle stored in nss_setup_connect() could have already been freed. */
- connssl->data = conn->data;
+ BACKEND->data = conn->data;
- rc = PR_Send(connssl->handle, mem, (int)len, 0, PR_INTERVAL_NO_WAIT);
+ rc = PR_Send(BACKEND->handle, mem, (int)len, 0, PR_INTERVAL_NO_WAIT);
if(rc < 0) {
PRInt32 err = PR_GetError();
if(err == PR_WOULD_BLOCK_ERROR)
@@ -2223,9 +2234,9 @@ static ssize_t nss_recv(struct connectdata *conn, /* connection data */
/* The SelectClientCert() hook uses this for infof() and failf() but the
handle stored in nss_setup_connect() could have already been freed. */
- connssl->data = conn->data;
+ BACKEND->data = conn->data;
- nread = PR_Recv(connssl->handle, buf, (int)buffersize, 0,
+ nread = PR_Recv(BACKEND->handle, buf, (int)buffersize, 0,
PR_INTERVAL_NO_WAIT);
if(nread < 0) {
/* failed SSL read */
@@ -2252,22 +2263,22 @@ static ssize_t nss_recv(struct connectdata *conn, /* connection data */
return nread;
}
-size_t Curl_nss_version(char *buffer, size_t size)
+static size_t Curl_nss_version(char *buffer, size_t size)
{
return snprintf(buffer, size, "NSS/%s", NSS_VERSION);
}
/* data might be NULL */
-int Curl_nss_seed(struct Curl_easy *data)
+static int Curl_nss_seed(struct Curl_easy *data)
{
/* make sure that NSS is initialized */
return !!Curl_nss_force_init(data);
}
/* data might be NULL */
-CURLcode Curl_nss_random(struct Curl_easy *data,
- unsigned char *entropy,
- size_t length)
+static CURLcode Curl_nss_random(struct Curl_easy *data,
+ unsigned char *entropy,
+ size_t length)
{
Curl_nss_seed(data); /* Initiate the seed if not already done */
@@ -2278,10 +2289,10 @@ CURLcode Curl_nss_random(struct Curl_easy *data,
return CURLE_OK;
}
-void Curl_nss_md5sum(unsigned char *tmp, /* input */
- size_t tmplen,
- unsigned char *md5sum, /* output */
- size_t md5len)
+static CURLcode Curl_nss_md5sum(unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *md5sum, /* output */
+ size_t md5len)
{
PK11Context *MD5pw = PK11_CreateDigestContext(SEC_OID_MD5);
unsigned int MD5out;
@@ -2289,12 +2300,14 @@ void Curl_nss_md5sum(unsigned char *tmp, /* input */
PK11_DigestOp(MD5pw, tmp, curlx_uztoui(tmplen));
PK11_DigestFinal(MD5pw, md5sum, &MD5out, curlx_uztoui(md5len));
PK11_DestroyContext(MD5pw, PR_TRUE);
+
+ return CURLE_OK;
}
-void Curl_nss_sha256sum(const unsigned char *tmp, /* input */
- size_t tmplen,
- unsigned char *sha256sum, /* output */
- size_t sha256len)
+static void Curl_nss_sha256sum(const unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *sha256sum, /* output */
+ size_t sha256len)
{
PK11Context *SHA256pw = PK11_CreateDigestContext(SEC_OID_SHA256);
unsigned int SHA256out;
@@ -2304,7 +2317,7 @@ void Curl_nss_sha256sum(const unsigned char *tmp, /* input */
PK11_DestroyContext(SHA256pw, PR_TRUE);
}
-bool Curl_nss_cert_status_request(void)
+static bool Curl_nss_cert_status_request(void)
{
#ifdef SSL_ENABLE_OCSP_STAPLING
return TRUE;
@@ -2313,7 +2326,7 @@ bool Curl_nss_cert_status_request(void)
#endif
}
-bool Curl_nss_false_start(void)
+static bool Curl_nss_false_start(void)
{
#if NSSVERNUM >= 0x030f04 /* 3.15.4 */
return TRUE;
@@ -2322,4 +2335,46 @@ bool Curl_nss_false_start(void)
#endif
}
+static void *Curl_nss_get_internals(struct ssl_connect_data *connssl,
+ CURLINFO info UNUSED_PARAM)
+{
+ (void)info;
+ return BACKEND->handle;
+}
+
+const struct Curl_ssl Curl_ssl_nss = {
+ { CURLSSLBACKEND_NSS, "nss" }, /* info */
+
+ 1, /* have_ca_path */
+ 1, /* have_certinfo */
+ 1, /* have_pinnedpubkey */
+ 0, /* have_ssl_ctx */
+ 1, /* support_https_proxy */
+
+ sizeof(struct ssl_backend_data),
+
+ Curl_nss_init, /* init */
+ Curl_nss_cleanup, /* cleanup */
+ Curl_nss_version, /* version */
+ Curl_nss_check_cxn, /* check_cxn */
+ /* NSS has no shutdown function provided and thus always fail */
+ Curl_none_shutdown, /* shutdown */
+ Curl_none_data_pending, /* data_pending */
+ Curl_nss_random, /* random */
+ Curl_nss_cert_status_request, /* cert_status_request */
+ Curl_nss_connect, /* connect */
+ Curl_nss_connect_nonblocking, /* connect_nonblocking */
+ Curl_nss_get_internals, /* get_internals */
+ Curl_nss_close, /* close_one */
+ Curl_none_close_all, /* close_all */
+ /* NSS has its own session ID cache */
+ Curl_none_session_free, /* session_free */
+ Curl_none_set_engine, /* set_engine */
+ Curl_none_set_engine_default, /* set_engine_default */
+ Curl_none_engines_list, /* engines_list */
+ Curl_nss_false_start, /* false_start */
+ Curl_nss_md5sum, /* md5sum */
+ Curl_nss_sha256sum /* sha256sum */
+};
+
#endif /* USE_NSS */
diff --git a/lib/vtls/nssg.h b/lib/vtls/nssg.h
index 8c46929f..41e51b02 100644
--- a/lib/vtls/nssg.h
+++ b/lib/vtls/nssg.h
@@ -30,79 +30,10 @@
#include "urldata.h"
-CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex);
-CURLcode Curl_nss_connect_nonblocking(struct connectdata *conn,
- int sockindex,
- bool *done);
-/* close a SSL connection */
-void Curl_nss_close(struct connectdata *conn, int sockindex);
-
-int Curl_nss_init(void);
-void Curl_nss_cleanup(void);
-
-size_t Curl_nss_version(char *buffer, size_t size);
-int Curl_nss_check_cxn(struct connectdata *cxn);
-int Curl_nss_seed(struct Curl_easy *data);
-
/* initialize NSS library if not already */
CURLcode Curl_nss_force_init(struct Curl_easy *data);
-CURLcode Curl_nss_random(struct Curl_easy *data,
- unsigned char *entropy,
- size_t length);
-
-void Curl_nss_md5sum(unsigned char *tmp, /* input */
- size_t tmplen,
- unsigned char *md5sum, /* output */
- size_t md5len);
-
-void Curl_nss_sha256sum(const unsigned char *tmp, /* input */
- size_t tmplen,
- unsigned char *sha256sum, /* output */
- size_t sha256len);
-
-bool Curl_nss_cert_status_request(void);
-
-bool Curl_nss_false_start(void);
-
-/* Support HTTPS-proxy */
-#define HTTPS_PROXY_SUPPORT 1
-
-/* Set the API backend definition to NSS */
-#define CURL_SSL_BACKEND CURLSSLBACKEND_NSS
-
-/* this backend supports the CAPATH option */
-#define have_curlssl_ca_path 1
-
-/* this backend supports CURLOPT_CERTINFO */
-#define have_curlssl_certinfo 1
-
-/* this backends supports CURLOPT_PINNEDPUBLICKEY */
-#define have_curlssl_pinnedpubkey 1
-
-/* API setup for NSS */
-#define curlssl_init Curl_nss_init
-#define curlssl_cleanup Curl_nss_cleanup
-#define curlssl_connect Curl_nss_connect
-#define curlssl_connect_nonblocking Curl_nss_connect_nonblocking
-
-/* NSS has its own session ID cache */
-#define curlssl_session_free(x) Curl_nop_stmt
-#define curlssl_close_all(x) ((void)x)
-#define curlssl_close Curl_nss_close
-/* NSS has no shutdown function provided and thus always fail */
-#define curlssl_shutdown(x,y) ((void)x, (void)y, 1)
-#define curlssl_set_engine(x,y) ((void)x, (void)y, CURLE_NOT_BUILT_IN)
-#define curlssl_set_engine_default(x) ((void)x, CURLE_NOT_BUILT_IN)
-#define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL)
-#define curlssl_version Curl_nss_version
-#define curlssl_check_cxn(x) Curl_nss_check_cxn(x)
-#define curlssl_data_pending(x,y) ((void)x, (void)y, 0)
-#define curlssl_random(x,y,z) Curl_nss_random(x,y,z)
-#define curlssl_md5sum(a,b,c,d) Curl_nss_md5sum(a,b,c,d)
-#define curlssl_sha256sum(a,b,c,d) Curl_nss_sha256sum(a,b,c,d)
-#define curlssl_cert_status_request() Curl_nss_cert_status_request()
-#define curlssl_false_start() Curl_nss_false_start()
+extern const struct Curl_ssl Curl_ssl_nss;
#endif /* USE_NSS */
#endif /* HEADER_CURL_NSSG_H */
diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c
index 8c1d5a8e..7b04edfd 100644
--- a/lib/vtls/openssl.c
+++ b/lib/vtls/openssl.c
@@ -51,8 +51,10 @@
#include "strcase.h"
#include "hostcheck.h"
#include "curl_printf.h"
-
#include <openssl/ssl.h>
+#ifdef HAVE_OPENSSL_ENGINE_H
+#include <openssl/engine.h>
+#endif
#include <openssl/rand.h>
#include <openssl/x509v3.h>
#ifndef OPENSSL_NO_DSA
@@ -64,8 +66,12 @@
#include <openssl/conf.h>
#include <openssl/bn.h>
#include <openssl/rsa.h>
+#include <openssl/bio.h>
+#include <openssl/buffer.h>
-#ifdef HAVE_OPENSSL_PKCS12_H
+#ifndef OPENSSL_IS_BORINGSSL
+/* BoringSSL does not support PKCS12 */
+#define HAVE_PKCS12_SUPPORT 1
#include <openssl/pkcs12.h>
#endif
@@ -144,6 +150,19 @@ static unsigned long OpenSSL_version_num(void)
#define OPENSSL_load_builtin_modules(x)
#endif
+/*
+ * Whether SSL_CTX_set_keylog_callback is available.
+ * OpenSSL: supported since 1.1.1 https://github.com/openssl/openssl/pull/2287
+ * BoringSSL: supported since d28f59c27bac (committed 2015-11-19)
+ * LibreSSL: unsupported in at least 2.5.1 (explicitly check for it since it
+ * lies and pretends to be OpenSSL 2.0.0).
+ */
+#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && \
+ !defined(LIBRESSL_VERSION_NUMBER)) || \
+ defined(OPENSSL_IS_BORINGSSL)
+#define HAVE_KEYLOG_CALLBACK
+#endif
+
#if defined(LIBRESSL_VERSION_NUMBER)
#define OSSL_PACKAGE "LibreSSL"
#elif defined(OPENSSL_IS_BORINGSSL)
@@ -152,6 +171,38 @@ static unsigned long OpenSSL_version_num(void)
#define OSSL_PACKAGE "OpenSSL"
#endif
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+/* up2date versions of OpenSSL maintain the default reasonably secure without
+ * breaking compatibility, so it is better not to override the default by curl
+ */
+#define DEFAULT_CIPHER_SELECTION NULL
+#else
+/* ... but it is not the case with old versions of OpenSSL */
+#define DEFAULT_CIPHER_SELECTION \
+ "ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH"
+#endif
+
+#ifdef ENABLE_SSLKEYLOGFILE
+typedef struct ssl_tap_state {
+ int master_key_length;
+ unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH];
+ unsigned char client_random[SSL3_RANDOM_SIZE];
+} ssl_tap_state_t;
+#endif /* ENABLE_SSLKEYLOGFILE */
+
+struct ssl_backend_data {
+ /* these ones requires specific SSL-types */
+ SSL_CTX* ctx;
+ SSL* handle;
+ X509* server_cert;
+#ifdef ENABLE_SSLKEYLOGFILE
+ /* tap_state holds the last seen master key if we're logging them */
+ ssl_tap_state_t tap_state;
+#endif
+};
+
+#define BACKEND connssl->backend
+
/*
* Number of bytes to read from the random number seed file. This must be
* a finite value (because some entropy "files" like /dev/urandom have
@@ -160,6 +211,112 @@ static unsigned long OpenSSL_version_num(void)
*/
#define RAND_LOAD_LENGTH 1024
+#ifdef ENABLE_SSLKEYLOGFILE
+/* The fp for the open SSLKEYLOGFILE, or NULL if not open */
+static FILE *keylog_file_fp;
+
+#ifdef HAVE_KEYLOG_CALLBACK
+static void ossl_keylog_callback(const SSL *ssl, const char *line)
+{
+ (void)ssl;
+
+ /* Using fputs here instead of fprintf since libcurl's fprintf replacement
+ may not be thread-safe. */
+ if(keylog_file_fp && line && *line) {
+ char stackbuf[256];
+ char *buf;
+ size_t linelen = strlen(line);
+
+ if(linelen <= sizeof(stackbuf) - 2)
+ buf = stackbuf;
+ else {
+ buf = malloc(linelen + 2);
+ if(!buf)
+ return;
+ }
+ strncpy(buf, line, linelen);
+ buf[linelen] = '\n';
+ buf[linelen + 1] = '\0';
+
+ fputs(buf, keylog_file_fp);
+ if(buf != stackbuf)
+ free(buf);
+ }
+}
+#else
+#define KEYLOG_PREFIX "CLIENT_RANDOM "
+#define KEYLOG_PREFIX_LEN (sizeof(KEYLOG_PREFIX) - 1)
+/*
+ * tap_ssl_key is called by libcurl to make the CLIENT_RANDOMs if the OpenSSL
+ * being used doesn't have native support for doing that.
+ */
+static void tap_ssl_key(const SSL *ssl, ssl_tap_state_t *state)
+{
+ const char *hex = "0123456789ABCDEF";
+ int pos, i;
+ char line[KEYLOG_PREFIX_LEN + 2 * SSL3_RANDOM_SIZE + 1 +
+ 2 * SSL_MAX_MASTER_KEY_LENGTH + 1 + 1];
+ const SSL_SESSION *session = SSL_get_session(ssl);
+ unsigned char client_random[SSL3_RANDOM_SIZE];
+ unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH];
+ int master_key_length = 0;
+
+ if(!session || !keylog_file_fp)
+ return;
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ /* ssl->s3 is not checked in openssl 1.1.0-pre6, but let's assume that
+ * we have a valid SSL context if we have a non-NULL session. */
+ SSL_get_client_random(ssl, client_random, SSL3_RANDOM_SIZE);
+ master_key_length =
+ SSL_SESSION_get_master_key(session, master_key, SSL_MAX_MASTER_KEY_LENGTH);
+#else
+ if(ssl->s3 && session->master_key_length > 0) {
+ master_key_length = session->master_key_length;
+ memcpy(master_key, session->master_key, session->master_key_length);
+ memcpy(client_random, ssl->s3->client_random, SSL3_RANDOM_SIZE);
+ }
+#endif
+
+ if(master_key_length <= 0)
+ return;
+
+ /* Skip writing keys if there is no key or it did not change. */
+ if(state->master_key_length == master_key_length &&
+ !memcmp(state->master_key, master_key, master_key_length) &&
+ !memcmp(state->client_random, client_random, SSL3_RANDOM_SIZE)) {
+ return;
+ }
+
+ state->master_key_length = master_key_length;
+ memcpy(state->master_key, master_key, master_key_length);
+ memcpy(state->client_random, client_random, SSL3_RANDOM_SIZE);
+
+ memcpy(line, KEYLOG_PREFIX, KEYLOG_PREFIX_LEN);
+ pos = KEYLOG_PREFIX_LEN;
+
+ /* Client Random for SSLv3/TLS */
+ for(i = 0; i < SSL3_RANDOM_SIZE; i++) {
+ line[pos++] = hex[client_random[i] >> 4];
+ line[pos++] = hex[client_random[i] & 0xF];
+ }
+ line[pos++] = ' ';
+
+ /* Master Secret (size is at most SSL_MAX_MASTER_KEY_LENGTH) */
+ for(i = 0; i < master_key_length; i++) {
+ line[pos++] = hex[master_key[i] >> 4];
+ line[pos++] = hex[master_key[i] & 0xF];
+ }
+ line[pos++] = '\n';
+ line[pos] = '\0';
+
+ /* Using fputs here instead of fprintf since libcurl's fprintf replacement
+ may not be thread-safe. */
+ fputs(line, keylog_file_fp);
+}
+#endif /* !HAVE_KEYLOG_CALLBACK */
+#endif /* ENABLE_SSLKEYLOGFILE */
+
static const char *SSL_ERROR_to_str(int err)
{
switch(err) {
@@ -214,7 +371,7 @@ static int passwd_callback(char *buf, int num, int encrypting,
if(!encrypting) {
int klen = curlx_uztosi(strlen((char *)global_passwd));
if(num > klen) {
- memcpy(buf, global_passwd, klen+1);
+ memcpy(buf, global_passwd, klen + 1);
return klen;
}
}
@@ -289,14 +446,14 @@ static CURLcode Curl_ossl_seed(struct Curl_easy *data)
size_t len = sizeof(randb);
size_t i, i_max;
for(i = 0, i_max = len / sizeof(struct curltime); i < i_max; ++i) {
- struct curltime tv = curlx_tvnow();
+ struct curltime tv = Curl_now();
Curl_wait_ms(1);
tv.tv_sec *= i + 1;
tv.tv_usec *= (unsigned int)i + 2;
- tv.tv_sec ^= ((curlx_tvnow().tv_sec + curlx_tvnow().tv_usec) *
+ tv.tv_sec ^= ((Curl_now().tv_sec + Curl_now().tv_usec) *
(i + 3)) << 8;
- tv.tv_usec ^= (unsigned int) ((curlx_tvnow().tv_sec +
- curlx_tvnow().tv_usec) *
+ tv.tv_usec ^= (unsigned int) ((Curl_now().tv_sec +
+ Curl_now().tv_usec) *
(i + 4)) << 16;
memcpy(&randb[i * sizeof(struct curltime)], &tv,
sizeof(struct curltime));
@@ -305,7 +462,7 @@ static CURLcode Curl_ossl_seed(struct Curl_easy *data)
} while(!rand_enough());
/* generates a default path for the random seed file */
- fname[0]=0; /* blank it first */
+ fname[0] = 0; /* blank it first */
RAND_file_name(fname, sizeof(fname));
if(fname[0]) {
/* we got a file name to try */
@@ -393,6 +550,7 @@ int cert_stuff(struct connectdata *conn,
{
struct Curl_easy *data = conn->data;
char error_buffer[256];
+ bool check_privkey = TRUE;
int file_type = do_file_type(cert_type);
@@ -496,7 +654,7 @@ int cert_stuff(struct connectdata *conn,
case SSL_FILETYPE_PKCS12:
{
-#ifdef HAVE_OPENSSL_PKCS12_H
+#ifdef HAVE_PKCS12_SUPPORT
FILE *f;
PKCS12 *p12;
EVP_PKEY *pri;
@@ -601,7 +759,7 @@ int cert_stuff(struct connectdata *conn,
break;
if(!key_file)
/* cert & key can only be in PEM case in the same file */
- key_file=cert_file;
+ key_file = cert_file;
/* FALLTHROUGH */
case SSL_FILETYPE_ASN1:
if(SSL_CTX_use_PrivateKey_file(ctx, key_file, file_type) != 1) {
@@ -664,13 +822,13 @@ int cert_stuff(struct connectdata *conn,
return 0;
}
- ssl=SSL_new(ctx);
+ ssl = SSL_new(ctx);
if(!ssl) {
failf(data, "unable to create an SSL structure");
return 0;
}
- x509=SSL_get_certificate(ssl);
+ x509 = SSL_get_certificate(ssl);
/* This version was provided by Evan Jordan and is supposed to not
leak memory as the previous version: */
@@ -680,17 +838,38 @@ int cert_stuff(struct connectdata *conn,
EVP_PKEY_free(pktmp);
}
+#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_IS_BORINGSSL)
+ {
+ /* If RSA is used, don't check the private key if its flags indicate
+ * it doesn't support it. */
+ EVP_PKEY *priv_key = SSL_get_privatekey(ssl);
+ int pktype;
+#ifdef HAVE_OPAQUE_EVP_PKEY
+ pktype = EVP_PKEY_id(priv_key);
+#else
+ pktype = priv_key->type;
+#endif
+ if(pktype == EVP_PKEY_RSA) {
+ RSA *rsa = EVP_PKEY_get1_RSA(priv_key);
+ if(RSA_flags(rsa) & RSA_METHOD_FLAG_NO_CHECK)
+ check_privkey = FALSE;
+ RSA_free(rsa); /* Decrement reference count */
+ }
+ }
+#endif
+
SSL_free(ssl);
/* 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(ctx)) {
- failf(data, "Private key does not match the certificate public key");
- return 0;
+ if(check_privkey == TRUE) {
+ /* Now we know that a key and cert have been set against
+ * the SSL context */
+ if(!SSL_CTX_check_private_key(ctx)) {
+ failf(data, "Private key does not match the certificate public key");
+ return 0;
+ }
}
}
return 1;
@@ -718,7 +897,7 @@ static int x509_name_oneline(X509_NAME *a, char *buf, size_t size)
size--; /* don't overwrite the buffer end */
memcpy(buf, biomem->data, size);
- buf[size]=0;
+ buf[size] = 0;
BIO_free(bio_out);
@@ -732,8 +911,12 @@ static int x509_name_oneline(X509_NAME *a, char *buf, size_t size)
* @retval 0 error initializing SSL
* @retval 1 SSL initialized successfully
*/
-int Curl_ossl_init(void)
+static int Curl_ossl_init(void)
{
+#ifdef ENABLE_SSLKEYLOGFILE
+ const char *keylog_file_name;
+#endif
+
OPENSSL_load_builtin_modules();
#ifdef HAVE_ENGINE_LOAD_BUILTIN_ENGINES
@@ -770,11 +953,24 @@ int Curl_ossl_init(void)
OpenSSL_add_all_algorithms();
#endif
+#ifdef ENABLE_SSLKEYLOGFILE
+ keylog_file_name = curl_getenv("SSLKEYLOGFILE");
+ if(keylog_file_name && !keylog_file_fp) {
+ keylog_file_fp = fopen(keylog_file_name, FOPEN_APPENDTEXT);
+ if(keylog_file_fp) {
+ if(setvbuf(keylog_file_fp, NULL, _IOLBF, 4096)) {
+ fclose(keylog_file_fp);
+ keylog_file_fp = NULL;
+ }
+ }
+ }
+#endif
+
return 1;
}
/* Global cleanup */
-void Curl_ossl_cleanup(void)
+static void Curl_ossl_cleanup(void)
{
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \
!defined(LIBRESSL_VERSION_NUMBER)
@@ -806,6 +1002,13 @@ void Curl_ossl_cleanup(void)
SSL_COMP_free_compression_methods();
#endif
#endif
+
+#ifdef ENABLE_SSLKEYLOGFILE
+ if(keylog_file_fp) {
+ fclose(keylog_file_fp);
+ keylog_file_fp = NULL;
+ }
+#endif
}
/*
@@ -816,7 +1019,7 @@ void Curl_ossl_cleanup(void)
* 0 means the connection has been closed
* -1 means the connection status is unknown
*/
-int Curl_ossl_check_cxn(struct connectdata *conn)
+static int Curl_ossl_check_cxn(struct connectdata *conn)
{
/* SSL_peek takes data out of the raw recv buffer without peeking so we use
recv MSG_PEEK instead. Bug #795 */
@@ -862,7 +1065,8 @@ int Curl_ossl_check_cxn(struct connectdata *conn)
/* Selects an OpenSSL crypto engine
*/
-CURLcode Curl_ossl_set_engine(struct Curl_easy *data, const char *engine)
+static CURLcode Curl_ossl_set_engine(struct Curl_easy *data,
+ const char *engine)
{
#if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H)
ENGINE *e;
@@ -907,7 +1111,7 @@ CURLcode Curl_ossl_set_engine(struct Curl_easy *data, const char *engine)
/* Sets engine as default for all SSL operations
*/
-CURLcode Curl_ossl_set_engine_default(struct Curl_easy *data)
+static CURLcode Curl_ossl_set_engine_default(struct Curl_easy *data)
{
#ifdef HAVE_OPENSSL_ENGINE_H
if(data->state.engine) {
@@ -929,7 +1133,7 @@ CURLcode Curl_ossl_set_engine_default(struct Curl_easy *data)
/* Return list of OpenSSL crypto engine names.
*/
-struct curl_slist *Curl_ossl_engines_list(struct Curl_easy *data)
+static struct curl_slist *Curl_ossl_engines_list(struct Curl_easy *data)
{
struct curl_slist *list = NULL;
#if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H)
@@ -952,23 +1156,23 @@ struct curl_slist *Curl_ossl_engines_list(struct Curl_easy *data)
static void ossl_close(struct ssl_connect_data *connssl)
{
- if(connssl->handle) {
- (void)SSL_shutdown(connssl->handle);
- SSL_set_connect_state(connssl->handle);
+ if(BACKEND->handle) {
+ (void)SSL_shutdown(BACKEND->handle);
+ SSL_set_connect_state(BACKEND->handle);
- SSL_free(connssl->handle);
- connssl->handle = NULL;
+ SSL_free(BACKEND->handle);
+ BACKEND->handle = NULL;
}
- if(connssl->ctx) {
- SSL_CTX_free(connssl->ctx);
- connssl->ctx = NULL;
+ if(BACKEND->ctx) {
+ SSL_CTX_free(BACKEND->ctx);
+ BACKEND->ctx = NULL;
}
}
/*
* This function is called when an SSL connection is closed.
*/
-void Curl_ossl_close(struct connectdata *conn, int sockindex)
+static void Curl_ossl_close(struct connectdata *conn, int sockindex)
{
ossl_close(&conn->ssl[sockindex]);
ossl_close(&conn->proxy_ssl[sockindex]);
@@ -978,7 +1182,7 @@ void Curl_ossl_close(struct connectdata *conn, int sockindex)
* This function is called to shut down the SSL layer but keep the
* socket open (CCC - Clear Command Channel)
*/
-int Curl_ossl_shutdown(struct connectdata *conn, int sockindex)
+static int Curl_ossl_shutdown(struct connectdata *conn, int sockindex)
{
int retval = 0;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
@@ -997,9 +1201,9 @@ int Curl_ossl_shutdown(struct connectdata *conn, int sockindex)
we do not send one. Let's hope other servers do the same... */
if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
- (void)SSL_shutdown(connssl->handle);
+ (void)SSL_shutdown(BACKEND->handle);
- if(connssl->handle) {
+ if(BACKEND->handle) {
buffsize = (int)sizeof(buf);
while(!done) {
int what = SOCKET_READABLE(conn->sock[sockindex],
@@ -1009,9 +1213,8 @@ int Curl_ossl_shutdown(struct connectdata *conn, int sockindex)
/* Something to read, let's do it and hope that it is the close
notify alert from the server */
- nread = (ssize_t)SSL_read(conn->ssl[sockindex].handle, buf,
- buffsize);
- err = SSL_get_error(conn->ssl[sockindex].handle, (int)nread);
+ nread = (ssize_t)SSL_read(BACKEND->handle, buf, buffsize);
+ err = SSL_get_error(BACKEND->handle, (int)nread);
switch(err) {
case SSL_ERROR_NONE: /* this is not an error */
@@ -1056,7 +1259,7 @@ int Curl_ossl_shutdown(struct connectdata *conn, int sockindex)
if(data->set.verbose) {
#ifdef HAVE_SSL_GET_SHUTDOWN
- switch(SSL_get_shutdown(connssl->handle)) {
+ switch(SSL_get_shutdown(BACKEND->handle)) {
case SSL_SENT_SHUTDOWN:
infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN\n");
break;
@@ -1071,13 +1274,13 @@ int Curl_ossl_shutdown(struct connectdata *conn, int sockindex)
#endif
}
- SSL_free(connssl->handle);
- connssl->handle = NULL;
+ SSL_free(BACKEND->handle);
+ BACKEND->handle = NULL;
}
return retval;
}
-void Curl_ossl_session_free(void *ptr)
+static void Curl_ossl_session_free(void *ptr)
{
/* free the ID */
SSL_SESSION_free(ptr);
@@ -1087,7 +1290,7 @@ void Curl_ossl_session_free(void *ptr)
* This function is called when the 'data' struct is going away. Close
* down everything and free all resources!
*/
-void Curl_ossl_close_all(struct Curl_easy *data)
+static void Curl_ossl_close_all(struct Curl_easy *data)
{
#ifdef HAVE_OPENSSL_ENGINE_H
if(data->state.engine) {
@@ -1179,7 +1382,7 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert)
numalts = sk_GENERAL_NAME_num(altnames);
/* loop through all alternatives - until a dnsmatch */
- for(i=0; (i < numalts) && !dnsmatched; i++) {
+ for(i = 0; (i < numalts) && !dnsmatched; i++) {
/* get a handle to alternative name number i */
const GENERAL_NAME *check = sk_GENERAL_NAME_value(altnames, i);
@@ -1248,7 +1451,7 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert)
else {
/* we have to look to the last occurrence of a commonName in the
distinguished one to get the most significant one. */
- int j, i=-1;
+ int j, i = -1;
/* The following is done because of a bug in 0.9.6b */
@@ -1257,14 +1460,14 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert)
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;
+ 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) {
+ if(i >= 0) {
ASN1_STRING *tmp =
X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, i));
@@ -1277,7 +1480,7 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert)
if(ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) {
j = ASN1_STRING_length(tmp);
if(j >= 0) {
- peer_CN = OPENSSL_malloc(j+1);
+ peer_CN = OPENSSL_malloc(j + 1);
if(peer_CN) {
memcpy(peer_CN, ASN1_STRING_get0_data(tmp), j);
peer_CN[j] = '\0';
@@ -1300,7 +1503,8 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert)
peer_CN = NULL;
else {
/* convert peer_CN from UTF8 */
- CURLcode rc = Curl_convert_from_utf8(data, peer_CN, strlen(peer_CN));
+ CURLcode rc = Curl_convert_from_utf8(data, (char *)peer_CN,
+ strlen((char *)peer_CN));
/* Curl_convert_from_utf8 calls failf if unsuccessful */
if(rc) {
OPENSSL_free(peer_CN);
@@ -1346,7 +1550,7 @@ static CURLcode verifystatus(struct connectdata *conn,
X509_STORE *st = NULL;
STACK_OF(X509) *ch = NULL;
- long len = SSL_get_tlsext_status_ocsp_resp(connssl->handle, &p);
+ long len = SSL_get_tlsext_status_ocsp_resp(BACKEND->handle, &p);
if(!p) {
failf(data, "No OCSP response received");
@@ -1376,8 +1580,8 @@ static CURLcode verifystatus(struct connectdata *conn,
goto end;
}
- ch = SSL_get_peer_cert_chain(connssl->handle);
- st = SSL_CTX_get_cert_store(connssl->ctx);
+ ch = SSL_get_peer_cert_chain(BACKEND->handle);
+ st = SSL_CTX_get_cert_store(BACKEND->ctx);
#if ((OPENSSL_VERSION_NUMBER <= 0x1000201fL) /* Fixed after 1.0.2a */ || \
(defined(LIBRESSL_VERSION_NUMBER) && \
@@ -1768,7 +1972,7 @@ set_ssl_version_min_max(long *ctx_options, struct connectdata *conn,
#ifdef TLS1_3_VERSION
{
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- SSL_CTX_set_max_proto_version(connssl->ctx, TLS1_3_VERSION);
+ SSL_CTX_set_max_proto_version(BACKEND->ctx, TLS1_3_VERSION);
*ctx_options |= SSL_OP_NO_TLSv1_2;
}
#else
@@ -1919,25 +2123,25 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
return CURLE_SSL_CONNECT_ERROR;
}
- if(connssl->ctx)
- SSL_CTX_free(connssl->ctx);
- connssl->ctx = SSL_CTX_new(req_method);
+ if(BACKEND->ctx)
+ SSL_CTX_free(BACKEND->ctx);
+ BACKEND->ctx = SSL_CTX_new(req_method);
- if(!connssl->ctx) {
+ if(!BACKEND->ctx) {
failf(data, "SSL: couldn't create a context: %s",
ossl_strerror(ERR_peek_error(), error_buffer, sizeof(error_buffer)));
return CURLE_OUT_OF_MEMORY;
}
#ifdef SSL_MODE_RELEASE_BUFFERS
- SSL_CTX_set_mode(connssl->ctx, SSL_MODE_RELEASE_BUFFERS);
+ SSL_CTX_set_mode(BACKEND->ctx, SSL_MODE_RELEASE_BUFFERS);
#endif
#ifdef SSL_CTRL_SET_MSG_CALLBACK
if(data->set.fdebug && data->set.verbose) {
/* the SSL trace callback is only used for verbose logging */
- SSL_CTX_set_msg_callback(connssl->ctx, ssl_tls_trace);
- SSL_CTX_set_msg_callback_arg(connssl->ctx, conn);
+ SSL_CTX_set_msg_callback(BACKEND->ctx, ssl_tls_trace);
+ SSL_CTX_set_msg_callback_arg(BACKEND->ctx, conn);
}
#endif
@@ -2054,11 +2258,11 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
return CURLE_SSL_CONNECT_ERROR;
}
- SSL_CTX_set_options(connssl->ctx, ctx_options);
+ SSL_CTX_set_options(BACKEND->ctx, ctx_options);
#ifdef HAS_NPN
if(conn->bits.tls_enable_npn)
- SSL_CTX_set_next_proto_select_cb(connssl->ctx, select_next_proto_cb, conn);
+ SSL_CTX_set_next_proto_select_cb(BACKEND->ctx, select_next_proto_cb, conn);
#endif
#ifdef HAS_ALPN
@@ -2086,12 +2290,12 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
/* expects length prefixed preference ordered list of protocols in wire
* format
*/
- SSL_CTX_set_alpn_protos(connssl->ctx, protocols, cur);
+ SSL_CTX_set_alpn_protos(BACKEND->ctx, protocols, cur);
}
#endif
if(ssl_cert || ssl_cert_type) {
- if(!cert_stuff(conn, connssl->ctx, ssl_cert, ssl_cert_type,
+ if(!cert_stuff(conn, BACKEND->ctx, ssl_cert, ssl_cert_type,
SSL_SET_OPTION(key), SSL_SET_OPTION(key_type),
SSL_SET_OPTION(key_passwd))) {
/* failf() is already done in cert_stuff() */
@@ -2102,11 +2306,13 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
ciphers = SSL_CONN_CONFIG(cipher_list);
if(!ciphers)
ciphers = (char *)DEFAULT_CIPHER_SELECTION;
- if(!SSL_CTX_set_cipher_list(connssl->ctx, ciphers)) {
- failf(data, "failed setting cipher list: %s", ciphers);
- return CURLE_SSL_CIPHER;
+ if(ciphers) {
+ if(!SSL_CTX_set_cipher_list(BACKEND->ctx, ciphers)) {
+ failf(data, "failed setting cipher list: %s", ciphers);
+ return CURLE_SSL_CIPHER;
+ }
+ infof(data, "Cipher selection: %s\n", ciphers);
}
- infof(data, "Cipher selection: %s\n", ciphers);
#ifdef USE_TLS_SRP
if(ssl_authtype == CURL_TLSAUTH_SRP) {
@@ -2114,18 +2320,18 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
infof(data, "Using TLS-SRP username: %s\n", ssl_username);
- if(!SSL_CTX_set_srp_username(connssl->ctx, ssl_username)) {
+ if(!SSL_CTX_set_srp_username(BACKEND->ctx, ssl_username)) {
failf(data, "Unable to set SRP user name");
return CURLE_BAD_FUNCTION_ARGUMENT;
}
- if(!SSL_CTX_set_srp_password(connssl->ctx, SSL_SET_OPTION(password))) {
+ if(!SSL_CTX_set_srp_password(BACKEND->ctx, SSL_SET_OPTION(password))) {
failf(data, "failed setting SRP password");
return CURLE_BAD_FUNCTION_ARGUMENT;
}
if(!SSL_CONN_CONFIG(cipher_list)) {
infof(data, "Setting cipher list SRP\n");
- if(!SSL_CTX_set_cipher_list(connssl->ctx, "SRP")) {
+ if(!SSL_CTX_set_cipher_list(BACKEND->ctx, "SRP")) {
failf(data, "failed setting SRP cipher list");
return CURLE_SSL_CIPHER;
}
@@ -2136,7 +2342,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
if(ssl_cafile || 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, ssl_cafile, ssl_capath)) {
+ if(!SSL_CTX_load_verify_locations(BACKEND->ctx, ssl_cafile, ssl_capath)) {
if(verifypeer) {
/* Fail if we insist on successfully verifying the server. */
failf(data, "error setting certificate verify locations:\n"
@@ -2164,14 +2370,14 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
else if(verifypeer) {
/* verfying the peer without any CA certificates won't
work so use openssl's built in default as fallback */
- SSL_CTX_set_default_verify_paths(connssl->ctx);
+ SSL_CTX_set_default_verify_paths(BACKEND->ctx);
}
#endif
if(ssl_crlfile) {
/* tell SSL where to find CRL file that is used to check certificate
* revocation */
- lookup=X509_STORE_add_lookup(SSL_CTX_get_cert_store(connssl->ctx),
+ lookup = X509_STORE_add_lookup(SSL_CTX_get_cert_store(BACKEND->ctx),
X509_LOOKUP_file());
if(!lookup ||
(!X509_load_crl_file(lookup, ssl_crlfile, X509_FILETYPE_PEM)) ) {
@@ -2180,7 +2386,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
}
/* Everything is fine. */
infof(data, "successfully load CRL file:\n");
- X509_STORE_set_flags(SSL_CTX_get_cert_store(connssl->ctx),
+ X509_STORE_set_flags(SSL_CTX_get_cert_store(BACKEND->ctx),
X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL);
infof(data, " CRLfile: %s\n", ssl_crlfile);
@@ -2195,7 +2401,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
*/
#if defined(X509_V_FLAG_TRUSTED_FIRST) && !defined(X509_V_FLAG_NO_ALT_CHAINS)
if(verifypeer) {
- X509_STORE_set_flags(SSL_CTX_get_cert_store(connssl->ctx),
+ X509_STORE_set_flags(SSL_CTX_get_cert_store(BACKEND->ctx),
X509_V_FLAG_TRUSTED_FIRST);
}
#endif
@@ -2204,12 +2410,19 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
* 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,
+ SSL_CTX_set_verify(BACKEND->ctx,
verifypeer ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL);
+ /* Enable logging of secrets to the file specified in env SSLKEYLOGFILE. */
+#if defined(ENABLE_SSLKEYLOGFILE) && defined(HAVE_KEYLOG_CALLBACK)
+ if(keylog_file) {
+ SSL_CTX_set_keylog_callback(connssl->ctx, ossl_keylog_callback);
+ }
+#endif
+
/* give application a chance to interfere with SSL set up. */
if(data->set.ssl.fsslctx) {
- result = (*data->set.ssl.fsslctx)(data, connssl->ctx,
+ result = (*data->set.ssl.fsslctx)(data, BACKEND->ctx,
data->set.ssl.fsslctxp);
if(result) {
failf(data, "error signaled by ssl ctx callback");
@@ -2218,10 +2431,10 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
}
/* Lets make an SSL structure */
- if(connssl->handle)
- SSL_free(connssl->handle);
- connssl->handle = SSL_new(connssl->ctx);
- if(!connssl->handle) {
+ if(BACKEND->handle)
+ SSL_free(BACKEND->handle);
+ BACKEND->handle = SSL_new(BACKEND->ctx);
+ if(!BACKEND->handle) {
failf(data, "SSL: couldn't create a context (handle)!");
return CURLE_OUT_OF_MEMORY;
}
@@ -2229,19 +2442,19 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
!defined(OPENSSL_NO_OCSP)
if(SSL_CONN_CONFIG(verifystatus))
- SSL_set_tlsext_status_type(connssl->handle, TLSEXT_STATUSTYPE_ocsp);
+ SSL_set_tlsext_status_type(BACKEND->handle, TLSEXT_STATUSTYPE_ocsp);
#endif
- SSL_set_connect_state(connssl->handle);
+ SSL_set_connect_state(BACKEND->handle);
- connssl->server_cert = 0x0;
+ BACKEND->server_cert = 0x0;
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
if((0 == Curl_inet_pton(AF_INET, hostname, &addr)) &&
#ifdef ENABLE_IPV6
(0 == Curl_inet_pton(AF_INET6, hostname, &addr)) &&
#endif
sni &&
- !SSL_set_tlsext_host_name(connssl->handle, hostname))
+ !SSL_set_tlsext_host_name(BACKEND->handle, hostname))
infof(data, "WARNING: failed to configure server name indication (SNI) "
"TLS extension\n");
#endif
@@ -2253,7 +2466,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
Curl_ssl_sessionid_lock(conn);
if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) {
/* we got a session id, use it! */
- if(!SSL_set_session(connssl->handle, ssl_sessionid)) {
+ if(!SSL_set_session(BACKEND->handle, ssl_sessionid)) {
Curl_ssl_sessionid_unlock(conn);
failf(data, "SSL: SSL_set_session failed: %s",
ossl_strerror(ERR_get_error(), error_buffer,
@@ -2268,13 +2481,14 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
if(conn->proxy_ssl[sockindex].use) {
BIO *const bio = BIO_new(BIO_f_ssl());
+ SSL *handle = conn->proxy_ssl[sockindex].backend->handle;
DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state);
- DEBUGASSERT(conn->proxy_ssl[sockindex].handle != NULL);
+ DEBUGASSERT(handle != NULL);
DEBUGASSERT(bio != NULL);
- BIO_set_ssl(bio, conn->proxy_ssl[sockindex].handle, FALSE);
- SSL_set_bio(connssl->handle, bio, bio);
+ BIO_set_ssl(bio, handle, FALSE);
+ SSL_set_bio(BACKEND->handle, bio, bio);
}
- else if(!SSL_set_fd(connssl->handle, (int)sockfd)) {
+ else if(!SSL_set_fd(BACKEND->handle, (int)sockfd)) {
/* pass the raw socket into the SSL layers */
failf(data, "SSL: SSL_set_fd failed: %s",
ossl_strerror(ERR_get_error(), error_buffer, sizeof(error_buffer)));
@@ -2299,13 +2513,18 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex)
ERR_clear_error();
- err = SSL_connect(connssl->handle);
+ err = SSL_connect(BACKEND->handle);
+ /* If keylogging is enabled but the keylog callback is not supported then log
+ secrets here, immediately after SSL_connect by using tap_ssl_key. */
+#if defined(ENABLE_SSLKEYLOGFILE) && !defined(HAVE_KEYLOG_CALLBACK)
+ tap_ssl_key(BACKEND->handle, &BACKEND->tap_state);
+#endif
/* 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);
+ int detail = SSL_get_error(BACKEND->handle, err);
if(SSL_ERROR_WANT_READ == detail) {
connssl->connecting_state = ssl_connect_2_reading;
@@ -2339,7 +2558,7 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex)
(reason == SSL_R_CERTIFICATE_VERIFY_FAILED)) {
result = CURLE_SSL_CACERT;
- lerr = SSL_get_verify_result(connssl->handle);
+ lerr = SSL_get_verify_result(BACKEND->handle);
if(lerr != X509_V_OK) {
*certverifyresult = lerr;
snprintf(error_buffer, sizeof(error_buffer),
@@ -2383,8 +2602,8 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex)
/* Informational message */
infof(data, "SSL connection using %s / %s\n",
- get_ssl_version_txt(connssl->handle),
- SSL_get_cipher(connssl->handle));
+ get_ssl_version_txt(BACKEND->handle),
+ SSL_get_cipher(BACKEND->handle));
#ifdef HAS_ALPN
/* Sets data and len to negotiated protocol, len is 0 if no protocol was
@@ -2393,7 +2612,7 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex)
if(conn->bits.tls_enable_alpn) {
const unsigned char *neg_protocol;
unsigned int len;
- SSL_get0_alpn_selected(connssl->handle, &neg_protocol, &len);
+ SSL_get0_alpn_selected(BACKEND->handle, &neg_protocol, &len);
if(len != 0) {
infof(data, "ALPN, server accepted to use %.*s\n", len, neg_protocol);
@@ -2438,7 +2657,7 @@ static int asn1_object_dump(ASN1_OBJECT *a, char *buf, size_t len)
do { \
long info_len = BIO_get_mem_data(mem, &ptr); \
Curl_ssl_push_certinfo_len(data, _num, _label, ptr, info_len); \
- if(1!=BIO_reset(mem)) \
+ if(1 != BIO_reset(mem)) \
break; \
} WHILE_FALSE
@@ -2486,12 +2705,12 @@ static int X509V3_ext(struct Curl_easy *data,
/* no extensions, bail out */
return 1;
- for(i=0; i < (int)sk_X509_EXTENSION_num(exts); i++) {
+ for(i = 0; i < (int)sk_X509_EXTENSION_num(exts); i++) {
ASN1_OBJECT *obj;
X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i);
BUF_MEM *biomem;
char buf[512];
- char *ptr=buf;
+ char *ptr = buf;
char namebuf[128];
BIO *bio_out = BIO_new(BIO_s_mem());
@@ -2508,16 +2727,16 @@ static int X509V3_ext(struct Curl_easy *data,
BIO_get_mem_ptr(bio_out, &biomem);
for(j = 0; j < (size_t)biomem->length; j++) {
- const char *sep="";
+ const char *sep = "";
if(biomem->data[j] == '\n') {
- sep=", ";
+ sep = ", ";
j++; /* skip the newline */
};
while((j<(size_t)biomem->length) && (biomem->data[j] == ' '))
j++;
if(j<(size_t)biomem->length)
- ptr+=snprintf(ptr, sizeof(buf)-(ptr-buf), "%s%c", sep,
- biomem->data[j]);
+ ptr += snprintf(ptr, sizeof(buf)-(ptr-buf), "%s%c", sep,
+ biomem->data[j]);
}
Curl_ssl_push_certinfo(data, certnum, namebuf, buf);
@@ -2539,7 +2758,7 @@ static CURLcode get_cert_chain(struct connectdata *conn,
int numcerts;
BIO *mem;
- sk = SSL_get_peer_cert_chain(connssl->handle);
+ sk = SSL_get_peer_cert_chain(BACKEND->handle);
if(!sk) {
return CURLE_OUT_OF_MEMORY;
}
@@ -2556,7 +2775,7 @@ static CURLcode get_cert_chain(struct connectdata *conn,
for(i = 0; i < numcerts; i++) {
ASN1_INTEGER *num;
X509 *x = sk_X509_value(sk, i);
- EVP_PKEY *pubkey=NULL;
+ EVP_PKEY *pubkey = NULL;
int j;
char *ptr;
const ASN1_BIT_STRING *psig = NULL;
@@ -2829,8 +3048,8 @@ static CURLcode servercert(struct connectdata *conn,
/* we've been asked to gather certificate info! */
(void)get_cert_chain(conn, connssl);
- connssl->server_cert = SSL_get_peer_certificate(connssl->handle);
- if(!connssl->server_cert) {
+ BACKEND->server_cert = SSL_get_peer_certificate(BACKEND->handle);
+ if(!BACKEND->server_cert) {
BIO_free(mem);
if(!strict)
return CURLE_OK;
@@ -2841,32 +3060,32 @@ static CURLcode servercert(struct connectdata *conn,
infof(data, "%s certificate:\n", SSL_IS_PROXY() ? "Proxy" : "Server");
- rc = x509_name_oneline(X509_get_subject_name(connssl->server_cert),
+ rc = x509_name_oneline(X509_get_subject_name(BACKEND->server_cert),
buffer, sizeof(buffer));
infof(data, " subject: %s\n", rc?"[NONE]":buffer);
- ASN1_TIME_print(mem, X509_get0_notBefore(connssl->server_cert));
+ ASN1_TIME_print(mem, X509_get0_notBefore(BACKEND->server_cert));
len = BIO_get_mem_data(mem, (char **) &ptr);
infof(data, " start date: %.*s\n", len, ptr);
- rc = BIO_reset(mem);
+ (void)BIO_reset(mem);
- ASN1_TIME_print(mem, X509_get0_notAfter(connssl->server_cert));
+ ASN1_TIME_print(mem, X509_get0_notAfter(BACKEND->server_cert));
len = BIO_get_mem_data(mem, (char **) &ptr);
infof(data, " expire date: %.*s\n", len, ptr);
- rc = BIO_reset(mem);
+ (void)BIO_reset(mem);
BIO_free(mem);
if(SSL_CONN_CONFIG(verifyhost)) {
- result = verifyhost(conn, connssl->server_cert);
+ result = verifyhost(conn, BACKEND->server_cert);
if(result) {
- X509_free(connssl->server_cert);
- connssl->server_cert = NULL;
+ X509_free(BACKEND->server_cert);
+ BACKEND->server_cert = NULL;
return result;
}
}
- rc = x509_name_oneline(X509_get_issuer_name(connssl->server_cert),
+ rc = x509_name_oneline(X509_get_issuer_name(BACKEND->server_cert),
buffer, sizeof(buffer));
if(rc) {
if(strict)
@@ -2886,8 +3105,8 @@ static CURLcode servercert(struct connectdata *conn,
if(strict)
failf(data, "SSL: Unable to open issuer cert (%s)",
SSL_SET_OPTION(issuercert));
- X509_free(connssl->server_cert);
- connssl->server_cert = NULL;
+ X509_free(BACKEND->server_cert);
+ BACKEND->server_cert = NULL;
return CURLE_SSL_ISSUER_ERROR;
}
@@ -2896,7 +3115,7 @@ static CURLcode servercert(struct connectdata *conn,
if(strict)
failf(data, "SSL: Unable to read issuer cert (%s)",
SSL_SET_OPTION(issuercert));
- X509_free(connssl->server_cert);
+ X509_free(BACKEND->server_cert);
X509_free(issuer);
fclose(fp);
return CURLE_SSL_ISSUER_ERROR;
@@ -2904,13 +3123,13 @@ static CURLcode servercert(struct connectdata *conn,
fclose(fp);
- if(X509_check_issued(issuer, connssl->server_cert) != X509_V_OK) {
+ if(X509_check_issued(issuer, BACKEND->server_cert) != X509_V_OK) {
if(strict)
failf(data, "SSL: Certificate issuer check failed (%s)",
SSL_SET_OPTION(issuercert));
- X509_free(connssl->server_cert);
+ X509_free(BACKEND->server_cert);
X509_free(issuer);
- connssl->server_cert = NULL;
+ BACKEND->server_cert = NULL;
return CURLE_SSL_ISSUER_ERROR;
}
@@ -2919,7 +3138,7 @@ static CURLcode servercert(struct connectdata *conn,
X509_free(issuer);
}
- lerr = *certverifyresult = SSL_get_verify_result(connssl->handle);
+ lerr = *certverifyresult = SSL_get_verify_result(BACKEND->handle);
if(*certverifyresult != X509_V_OK) {
if(SSL_CONN_CONFIG(verifypeer)) {
@@ -2944,8 +3163,8 @@ static CURLcode servercert(struct connectdata *conn,
if(SSL_CONN_CONFIG(verifystatus)) {
result = verifystatus(conn, connssl);
if(result) {
- X509_free(connssl->server_cert);
- connssl->server_cert = NULL;
+ X509_free(BACKEND->server_cert);
+ BACKEND->server_cert = NULL;
return result;
}
}
@@ -2958,13 +3177,13 @@ static CURLcode servercert(struct connectdata *conn,
ptr = SSL_IS_PROXY() ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
if(!result && ptr) {
- result = pkp_pin_peer_pubkey(data, connssl->server_cert, ptr);
+ result = pkp_pin_peer_pubkey(data, BACKEND->server_cert, ptr);
if(result)
failf(data, "SSL: public key does not match pinned public key!");
}
- X509_free(connssl->server_cert);
- connssl->server_cert = NULL;
+ X509_free(BACKEND->server_cert);
+ BACKEND->server_cert = NULL;
connssl->connecting_state = ssl_connect_done;
return result;
@@ -2983,7 +3202,7 @@ static CURLcode ossl_connect_step3(struct connectdata *conn, int sockindex)
SSL_SESSION *our_ssl_sessionid;
void *old_ssl_sessionid = NULL;
- our_ssl_sessionid = SSL_get1_session(connssl->handle);
+ our_ssl_sessionid = SSL_get1_session(BACKEND->handle);
/* SSL_get1_session() will increment the reference count and the session
will stay in memory until explicitly freed with SSL_SESSION_free(3),
@@ -3088,9 +3307,9 @@ static CURLcode ossl_connect_common(struct connectdata *conn,
if(connssl->connecting_state == ssl_connect_2_reading ||
connssl->connecting_state == ssl_connect_2_writing) {
- curl_socket_t writefd = ssl_connect_2_writing==
+ curl_socket_t writefd = ssl_connect_2_writing ==
connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
- curl_socket_t readfd = ssl_connect_2_reading==
+ curl_socket_t readfd = ssl_connect_2_reading ==
connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
@@ -3148,14 +3367,14 @@ static CURLcode ossl_connect_common(struct connectdata *conn,
return CURLE_OK;
}
-CURLcode Curl_ossl_connect_nonblocking(struct connectdata *conn,
- int sockindex,
- bool *done)
+static CURLcode Curl_ossl_connect_nonblocking(struct connectdata *conn,
+ int sockindex,
+ bool *done)
{
return ossl_connect_common(conn, sockindex, TRUE, done);
}
-CURLcode Curl_ossl_connect(struct connectdata *conn, int sockindex)
+static CURLcode Curl_ossl_connect(struct connectdata *conn, int sockindex)
{
CURLcode result;
bool done = FALSE;
@@ -3169,17 +3388,22 @@ CURLcode Curl_ossl_connect(struct connectdata *conn, int sockindex)
return CURLE_OK;
}
-bool Curl_ossl_data_pending(const struct connectdata *conn, int connindex)
+static bool Curl_ossl_data_pending(const struct connectdata *conn,
+ int connindex)
{
- if(conn->ssl[connindex].handle)
+ const struct ssl_connect_data *connssl = &conn->ssl[connindex];
+ const struct ssl_connect_data *proxyssl = &conn->proxy_ssl[connindex];
+ if(BACKEND->handle)
/* SSL is in use */
- return (0 != SSL_pending(conn->ssl[connindex].handle) ||
- (conn->proxy_ssl[connindex].handle &&
- 0 != SSL_pending(conn->proxy_ssl[connindex].handle))) ?
+ return (0 != SSL_pending(BACKEND->handle) ||
+ (proxyssl->backend->handle &&
+ 0 != SSL_pending(proxyssl->backend->handle))) ?
TRUE : FALSE;
return FALSE;
}
+static size_t Curl_ossl_version(char *buffer, size_t size);
+
static ssize_t ossl_send(struct connectdata *conn,
int sockindex,
const void *mem,
@@ -3193,14 +3417,15 @@ static ssize_t ossl_send(struct connectdata *conn,
unsigned long sslerror;
int memlen;
int rc;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
ERR_clear_error();
memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
- rc = SSL_write(conn->ssl[sockindex].handle, mem, memlen);
+ rc = SSL_write(BACKEND->handle, mem, memlen);
if(rc <= 0) {
- err = SSL_get_error(conn->ssl[sockindex].handle, rc);
+ err = SSL_get_error(BACKEND->handle, rc);
switch(err) {
case SSL_ERROR_WANT_READ:
@@ -3254,14 +3479,15 @@ static ssize_t ossl_recv(struct connectdata *conn, /* connection data */
unsigned long sslerror;
ssize_t nread;
int buffsize;
+ struct ssl_connect_data *connssl = &conn->ssl[num];
ERR_clear_error();
buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
- nread = (ssize_t)SSL_read(conn->ssl[num].handle, buf, buffsize);
+ nread = (ssize_t)SSL_read(BACKEND->handle, buf, buffsize);
if(nread <= 0) {
/* failed SSL_read */
- int err = SSL_get_error(conn->ssl[num].handle, (int)nread);
+ int err = SSL_get_error(BACKEND->handle, (int)nread);
switch(err) {
case SSL_ERROR_NONE: /* this is not an error */
@@ -3293,7 +3519,7 @@ static ssize_t ossl_recv(struct connectdata *conn, /* connection data */
return nread;
}
-size_t Curl_ossl_version(char *buffer, size_t size)
+static size_t Curl_ossl_version(char *buffer, size_t size)
{
#ifdef OPENSSL_IS_BORINGSSL
return snprintf(buffer, size, OSSL_PACKAGE);
@@ -3302,9 +3528,9 @@ size_t Curl_ossl_version(char *buffer, size_t size)
unsigned long ssleay_value;
sub[2]='\0';
sub[1]='\0';
- ssleay_value=OpenSSL_version_num();
+ ssleay_value = OpenSSL_version_num();
if(ssleay_value < 0x906000) {
- ssleay_value=SSLEAY_VERSION_NUMBER;
+ ssleay_value = SSLEAY_VERSION_NUMBER;
sub[0]='\0';
}
else {
@@ -3333,8 +3559,8 @@ size_t Curl_ossl_version(char *buffer, size_t size)
}
/* can be called with data == NULL */
-CURLcode Curl_ossl_random(struct Curl_easy *data, unsigned char *entropy,
- size_t length)
+static CURLcode Curl_ossl_random(struct Curl_easy *data,
+ unsigned char *entropy, size_t length)
{
int rc;
if(data) {
@@ -3350,23 +3576,24 @@ CURLcode Curl_ossl_random(struct Curl_easy *data, unsigned char *entropy,
return (rc == 1 ? CURLE_OK : CURLE_FAILED_INIT);
}
-void Curl_ossl_md5sum(unsigned char *tmp, /* input */
- size_t tmplen,
- unsigned char *md5sum /* output */,
- size_t unused)
+static CURLcode Curl_ossl_md5sum(unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *md5sum /* output */,
+ size_t unused)
{
MD5_CTX MD5pw;
(void)unused;
MD5_Init(&MD5pw);
MD5_Update(&MD5pw, tmp, tmplen);
MD5_Final(md5sum, &MD5pw);
+ return CURLE_OK;
}
#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
-void Curl_ossl_sha256sum(const unsigned char *tmp, /* input */
- size_t tmplen,
- unsigned char *sha256sum /* output */,
- size_t unused)
+static void Curl_ossl_sha256sum(const unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *sha256sum /* output */,
+ size_t unused)
{
SHA256_CTX SHA256pw;
(void)unused;
@@ -3376,7 +3603,7 @@ void Curl_ossl_sha256sum(const unsigned char *tmp, /* input */
}
#endif
-bool Curl_ossl_cert_status_request(void)
+static bool Curl_ossl_cert_status_request(void)
{
#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
!defined(OPENSSL_NO_OCSP)
@@ -3385,4 +3612,50 @@ bool Curl_ossl_cert_status_request(void)
return FALSE;
#endif
}
+
+static void *Curl_ossl_get_internals(struct ssl_connect_data *connssl,
+ CURLINFO info)
+{
+ /* Legacy: CURLINFO_TLS_SESSION must return an SSL_CTX pointer. */
+ return info == CURLINFO_TLS_SESSION ?
+ (void *)BACKEND->ctx : (void *)BACKEND->handle;
+}
+
+const struct Curl_ssl Curl_ssl_openssl = {
+ { CURLSSLBACKEND_OPENSSL, "openssl" }, /* info */
+
+ 1, /* have_ca_path */
+ 1, /* have_certinfo */
+ 1, /* have_pinnedpubkey */
+ 1, /* have_ssl_ctx */
+ 1, /* support_https_proxy */
+
+ sizeof(struct ssl_backend_data),
+
+ Curl_ossl_init, /* init */
+ Curl_ossl_cleanup, /* cleanup */
+ Curl_ossl_version, /* version */
+ Curl_ossl_check_cxn, /* check_cxn */
+ Curl_ossl_shutdown, /* shutdown */
+ Curl_ossl_data_pending, /* data_pending */
+ Curl_ossl_random, /* random */
+ Curl_ossl_cert_status_request, /* cert_status_request */
+ Curl_ossl_connect, /* connect */
+ Curl_ossl_connect_nonblocking, /* connect_nonblocking */
+ Curl_ossl_get_internals, /* get_internals */
+ Curl_ossl_close, /* close_one */
+ Curl_ossl_close_all, /* close_all */
+ Curl_ossl_session_free, /* session_free */
+ Curl_ossl_set_engine, /* set_engine */
+ Curl_ossl_set_engine_default, /* set_engine_default */
+ Curl_ossl_engines_list, /* engines_list */
+ Curl_none_false_start, /* false_start */
+ Curl_ossl_md5sum, /* md5sum */
+#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
+ Curl_ossl_sha256sum /* sha256sum */
+#else
+ NULL /* sha256sum */
+#endif
+};
+
#endif /* USE_OPENSSL */
diff --git a/lib/vtls/openssl.h b/lib/vtls/openssl.h
index b9648d51..114dc4ba 100644
--- a/lib/vtls/openssl.h
+++ b/lib/vtls/openssl.h
@@ -31,96 +31,7 @@
#include "urldata.h"
-CURLcode Curl_ossl_connect(struct connectdata *conn, int sockindex);
-CURLcode Curl_ossl_connect_nonblocking(struct connectdata *conn,
- int sockindex,
- bool *done);
-
-/* close a SSL connection */
-void Curl_ossl_close(struct connectdata *conn, int sockindex);
-
-/* tell OpenSSL to close down all open information regarding connections (and
- thus session ID caching etc) */
-void Curl_ossl_close_all(struct Curl_easy *data);
-
-/* Sets an OpenSSL engine */
-CURLcode Curl_ossl_set_engine(struct Curl_easy *data, const char *engine);
-
-/* function provided for the generic SSL-layer, called when a session id
- should be freed */
-void Curl_ossl_session_free(void *ptr);
-
-/* Sets engine as default for all SSL operations */
-CURLcode Curl_ossl_set_engine_default(struct Curl_easy *data);
-
-/* Build list of OpenSSL engines */
-struct curl_slist *Curl_ossl_engines_list(struct Curl_easy *data);
-
-int Curl_ossl_init(void);
-void Curl_ossl_cleanup(void);
-
-size_t Curl_ossl_version(char *buffer, size_t size);
-int Curl_ossl_check_cxn(struct connectdata *cxn);
-int Curl_ossl_shutdown(struct connectdata *conn, int sockindex);
-bool Curl_ossl_data_pending(const struct connectdata *conn,
- int connindex);
-
-/* return 0 if a find random is filled in */
-CURLcode Curl_ossl_random(struct Curl_easy *data, unsigned char *entropy,
- size_t length);
-void Curl_ossl_md5sum(unsigned char *tmp, /* input */
- size_t tmplen,
- unsigned char *md5sum /* output */,
- size_t unused);
-void Curl_ossl_sha256sum(const unsigned char *tmp, /* input */
- size_t tmplen,
- unsigned char *sha256sum /* output */,
- size_t unused);
-
-bool Curl_ossl_cert_status_request(void);
-
-/* Support HTTPS-proxy */
-#define HTTPS_PROXY_SUPPORT 1
-
-/* Set the API backend definition to OpenSSL */
-#define CURL_SSL_BACKEND CURLSSLBACKEND_OPENSSL
-
-/* this backend supports the CAPATH option */
-#define have_curlssl_ca_path 1
-
-/* this backend supports CURLOPT_CERTINFO */
-#define have_curlssl_certinfo 1
-
-/* this backend supports CURLOPT_SSL_CTX_* */
-#define have_curlssl_ssl_ctx 1
-
-/* this backend supports CURLOPT_PINNEDPUBLICKEY */
-#define have_curlssl_pinnedpubkey 1
-
-/* API setup for OpenSSL */
-#define curlssl_init Curl_ossl_init
-#define curlssl_cleanup Curl_ossl_cleanup
-#define curlssl_connect Curl_ossl_connect
-#define curlssl_connect_nonblocking Curl_ossl_connect_nonblocking
-#define curlssl_session_free(x) Curl_ossl_session_free(x)
-#define curlssl_close_all Curl_ossl_close_all
-#define curlssl_close Curl_ossl_close
-#define curlssl_shutdown(x,y) Curl_ossl_shutdown(x,y)
-#define curlssl_set_engine(x,y) Curl_ossl_set_engine(x,y)
-#define curlssl_set_engine_default(x) Curl_ossl_set_engine_default(x)
-#define curlssl_engines_list(x) Curl_ossl_engines_list(x)
-#define curlssl_version Curl_ossl_version
-#define curlssl_check_cxn Curl_ossl_check_cxn
-#define curlssl_data_pending(x,y) Curl_ossl_data_pending(x,y)
-#define curlssl_random(x,y,z) Curl_ossl_random(x,y,z)
-#define curlssl_md5sum(a,b,c,d) Curl_ossl_md5sum(a,b,c,d)
-#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
-#define curlssl_sha256sum(a,b,c,d) Curl_ossl_sha256sum(a,b,c,d)
-#endif
-#define curlssl_cert_status_request() Curl_ossl_cert_status_request()
-
-#define DEFAULT_CIPHER_SELECTION \
- "ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH"
+extern const struct Curl_ssl Curl_ssl_openssl;
#endif /* USE_OPENSSL */
#endif /* HEADER_CURL_SSLUSE_H */
diff --git a/lib/vtls/polarssl.c b/lib/vtls/polarssl.c
index 669091cb..df29fa94 100644
--- a/lib/vtls/polarssl.c
+++ b/lib/vtls/polarssl.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2012 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 2010 - 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com>
*
* This software is licensed as described in the file COPYING, which
@@ -30,7 +30,6 @@
#include "curl_setup.h"
#ifdef USE_POLARSSL
-
#include <polarssl/net.h>
#include <polarssl/ssl.h>
#include <polarssl/certs.h>
@@ -70,6 +69,19 @@
#define PUB_DER_MAX_BYTES (RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \
RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES)
+struct ssl_backend_data {
+ ctr_drbg_context ctr_drbg;
+ entropy_context entropy;
+ ssl_context ssl;
+ int server_fd;
+ x509_crt cacert;
+ x509_crt clicert;
+ x509_crl crl;
+ rsa_context rsa;
+};
+
+#define BACKEND connssl->backend
+
/* apply threading? */
#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
#define THREADING_SUPPORT
@@ -197,8 +209,8 @@ set_ssl_version_min_max(struct connectdata *conn, int sockindex)
return result;
}
- ssl_set_min_version(&connssl->ssl, SSL_MAJOR_VERSION_3, ssl_min_ver);
- ssl_set_max_version(&connssl->ssl, SSL_MAJOR_VERSION_3, ssl_max_ver);
+ ssl_set_min_version(&BACKEND->ssl, SSL_MAJOR_VERSION_3, ssl_min_ver);
+ ssl_set_max_version(&BACKEND->ssl, SSL_MAJOR_VERSION_3, ssl_max_ver);
return result;
}
@@ -215,7 +227,7 @@ polarssl_connect_step1(struct connectdata *conn,
const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port;
int ret = -1;
char errorbuf[128];
- errorbuf[0]=0;
+ errorbuf[0] = 0;
/* PolarSSL only supports SSLv3 and TLSv1 */
if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) {
@@ -226,16 +238,16 @@ polarssl_connect_step1(struct connectdata *conn,
#ifdef THREADING_SUPPORT
entropy_init_mutex(&entropy);
- if((ret = ctr_drbg_init(&connssl->ctr_drbg, entropy_func_mutex, &entropy,
+ if((ret = ctr_drbg_init(&BACKEND->ctr_drbg, entropy_func_mutex, &entropy,
NULL, 0)) != 0) {
error_strerror(ret, errorbuf, sizeof(errorbuf));
failf(data, "Failed - PolarSSL: ctr_drbg_init returned (-0x%04X) %s\n",
-ret, errorbuf);
}
#else
- entropy_init(&connssl->entropy);
+ entropy_init(&BACKEND->entropy);
- if((ret = ctr_drbg_init(&connssl->ctr_drbg, entropy_func, &connssl->entropy,
+ if((ret = ctr_drbg_init(&BACKEND->ctr_drbg, entropy_func, &BACKEND->entropy,
NULL, 0)) != 0) {
error_strerror(ret, errorbuf, sizeof(errorbuf));
failf(data, "Failed - PolarSSL: ctr_drbg_init returned (-0x%04X) %s\n",
@@ -244,10 +256,10 @@ polarssl_connect_step1(struct connectdata *conn,
#endif /* THREADING_SUPPORT */
/* Load the trusted CA */
- memset(&connssl->cacert, 0, sizeof(x509_crt));
+ memset(&BACKEND->cacert, 0, sizeof(x509_crt));
if(SSL_CONN_CONFIG(CAfile)) {
- ret = x509_crt_parse_file(&connssl->cacert,
+ ret = x509_crt_parse_file(&BACKEND->cacert,
SSL_CONN_CONFIG(CAfile));
if(ret<0) {
@@ -261,7 +273,7 @@ polarssl_connect_step1(struct connectdata *conn,
}
if(capath) {
- ret = x509_crt_parse_path(&connssl->cacert, capath);
+ ret = x509_crt_parse_path(&BACKEND->cacert, capath);
if(ret<0) {
error_strerror(ret, errorbuf, sizeof(errorbuf));
@@ -274,10 +286,10 @@ polarssl_connect_step1(struct connectdata *conn,
}
/* Load the client certificate */
- memset(&connssl->clicert, 0, sizeof(x509_crt));
+ memset(&BACKEND->clicert, 0, sizeof(x509_crt));
if(SSL_SET_OPTION(cert)) {
- ret = x509_crt_parse_file(&connssl->clicert,
+ ret = x509_crt_parse_file(&BACKEND->clicert,
SSL_SET_OPTION(cert));
if(ret) {
@@ -298,9 +310,9 @@ polarssl_connect_step1(struct connectdata *conn,
if(ret == 0 && !pk_can_do(&pk, POLARSSL_PK_RSA))
ret = POLARSSL_ERR_PK_TYPE_MISMATCH;
if(ret == 0)
- rsa_copy(&connssl->rsa, pk_rsa(pk));
+ rsa_copy(&BACKEND->rsa, pk_rsa(pk));
else
- rsa_free(&connssl->rsa);
+ rsa_free(&BACKEND->rsa);
pk_free(&pk);
if(ret) {
@@ -313,10 +325,10 @@ polarssl_connect_step1(struct connectdata *conn,
}
/* Load the CRL */
- memset(&connssl->crl, 0, sizeof(x509_crl));
+ memset(&BACKEND->crl, 0, sizeof(x509_crl));
if(SSL_SET_OPTION(CRLfile)) {
- ret = x509_crl_parse_file(&connssl->crl,
+ ret = x509_crl_parse_file(&BACKEND->crl,
SSL_SET_OPTION(CRLfile));
if(ret) {
@@ -330,7 +342,7 @@ polarssl_connect_step1(struct connectdata *conn,
infof(data, "PolarSSL: Connecting to %s:%d\n", hostname, port);
- if(ssl_init(&connssl->ssl)) {
+ if(ssl_init(&BACKEND->ssl)) {
failf(data, "PolarSSL: ssl_init failed");
return CURLE_SSL_CONNECT_ERROR;
}
@@ -338,13 +350,13 @@ polarssl_connect_step1(struct connectdata *conn,
switch(SSL_CONN_CONFIG(version)) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
- ssl_set_min_version(&connssl->ssl, SSL_MAJOR_VERSION_3,
+ ssl_set_min_version(&BACKEND->ssl, SSL_MAJOR_VERSION_3,
SSL_MINOR_VERSION_1);
break;
case CURL_SSLVERSION_SSLv3:
- ssl_set_min_version(&connssl->ssl, SSL_MAJOR_VERSION_3,
+ ssl_set_min_version(&BACKEND->ssl, SSL_MAJOR_VERSION_3,
SSL_MINOR_VERSION_0);
- ssl_set_max_version(&connssl->ssl, SSL_MAJOR_VERSION_3,
+ ssl_set_max_version(&BACKEND->ssl, SSL_MAJOR_VERSION_3,
SSL_MINOR_VERSION_0);
infof(data, "PolarSSL: Forced min. SSL Version to be SSLv3\n");
break;
@@ -363,16 +375,16 @@ polarssl_connect_step1(struct connectdata *conn,
return CURLE_SSL_CONNECT_ERROR;
}
- ssl_set_endpoint(&connssl->ssl, SSL_IS_CLIENT);
- ssl_set_authmode(&connssl->ssl, SSL_VERIFY_OPTIONAL);
+ ssl_set_endpoint(&BACKEND->ssl, SSL_IS_CLIENT);
+ ssl_set_authmode(&BACKEND->ssl, SSL_VERIFY_OPTIONAL);
- ssl_set_rng(&connssl->ssl, ctr_drbg_random,
- &connssl->ctr_drbg);
- ssl_set_bio(&connssl->ssl,
+ ssl_set_rng(&BACKEND->ssl, ctr_drbg_random,
+ &BACKEND->ctr_drbg);
+ ssl_set_bio(&BACKEND->ssl,
net_recv, &conn->sock[sockindex],
net_send, &conn->sock[sockindex]);
- ssl_set_ciphersuites(&connssl->ssl, ssl_list_ciphersuites());
+ ssl_set_ciphersuites(&BACKEND->ssl, ssl_list_ciphersuites());
/* Check if there's a cached ID we can/should use here! */
if(SSL_SET_OPTION(primary.sessionid)) {
@@ -380,7 +392,7 @@ polarssl_connect_step1(struct connectdata *conn,
Curl_ssl_sessionid_lock(conn);
if(!Curl_ssl_getsessionid(conn, &old_session, NULL, sockindex)) {
- ret = ssl_set_session(&connssl->ssl, old_session);
+ ret = ssl_set_session(&BACKEND->ssl, old_session);
if(ret) {
Curl_ssl_sessionid_unlock(conn);
failf(data, "ssl_set_session returned -0x%x", -ret);
@@ -391,15 +403,15 @@ polarssl_connect_step1(struct connectdata *conn,
Curl_ssl_sessionid_unlock(conn);
}
- ssl_set_ca_chain(&connssl->ssl,
- &connssl->cacert,
- &connssl->crl,
+ ssl_set_ca_chain(&BACKEND->ssl,
+ &BACKEND->cacert,
+ &BACKEND->crl,
hostname);
- ssl_set_own_cert_rsa(&connssl->ssl,
- &connssl->clicert, &connssl->rsa);
+ ssl_set_own_cert_rsa(&BACKEND->ssl,
+ &BACKEND->clicert, &BACKEND->rsa);
- if(ssl_set_hostname(&connssl->ssl, hostname)) {
+ if(ssl_set_hostname(&BACKEND->ssl, hostname)) {
/* ssl_set_hostname() sets the name to use in CN/SAN checks *and* the name
to set in the SNI extension. So even if curl connects to a host
specified as an IP address, this function must be used. */
@@ -424,12 +436,12 @@ polarssl_connect_step1(struct connectdata *conn,
protocols[cur] = NULL;
- ssl_set_alpn_protocols(&connssl->ssl, protocols);
+ ssl_set_alpn_protocols(&BACKEND->ssl, protocols);
}
#endif
#ifdef POLARSSL_DEBUG
- ssl_set_dbg(&connssl->ssl, polarssl_debug, data);
+ ssl_set_dbg(&BACKEND->ssl, polarssl_debug, data);
#endif
connssl->connecting_state = ssl_connect_2;
@@ -456,7 +468,7 @@ polarssl_connect_step2(struct connectdata *conn,
conn->recv[sockindex] = polarssl_recv;
conn->send[sockindex] = polarssl_send;
- ret = ssl_handshake(&connssl->ssl);
+ ret = ssl_handshake(&BACKEND->ssl);
switch(ret) {
case 0:
@@ -478,9 +490,9 @@ polarssl_connect_step2(struct connectdata *conn,
}
infof(data, "PolarSSL: Handshake complete, cipher is %s\n",
- ssl_get_ciphersuite(&conn->ssl[sockindex].ssl) );
+ ssl_get_ciphersuite(&BACKEND->ssl) );
- ret = ssl_get_verify_result(&conn->ssl[sockindex].ssl);
+ ret = ssl_get_verify_result(&BACKEND->ssl);
if(ret && SSL_CONN_CONFIG(verifypeer)) {
if(ret & BADCERT_EXPIRED)
@@ -500,12 +512,12 @@ polarssl_connect_step2(struct connectdata *conn,
return CURLE_PEER_FAILED_VERIFICATION;
}
- if(ssl_get_peer_cert(&(connssl->ssl))) {
+ if(ssl_get_peer_cert(&(BACKEND->ssl))) {
/* If the session was resumed, there will be no peer certs */
memset(buffer, 0, sizeof(buffer));
if(x509_crt_info(buffer, sizeof(buffer), (char *)"* ",
- ssl_get_peer_cert(&(connssl->ssl))) != -1)
+ ssl_get_peer_cert(&(BACKEND->ssl))) != -1)
infof(data, "Dumping cert info:\n%s\n", buffer);
}
@@ -517,7 +529,7 @@ polarssl_connect_step2(struct connectdata *conn,
unsigned char pubkey[PUB_DER_MAX_BYTES];
const x509_crt *peercert;
- peercert = ssl_get_peer_cert(&connssl->ssl);
+ peercert = ssl_get_peer_cert(&BACKEND->ssl);
if(!peercert || !peercert->raw.p || !peercert->raw.len) {
failf(data, "Failed due to missing peer certificate");
@@ -566,7 +578,7 @@ polarssl_connect_step2(struct connectdata *conn,
#ifdef HAS_ALPN
if(conn->bits.tls_enable_alpn) {
- const char *next_protocol = ssl_get_alpn_protocol(&connssl->ssl);
+ const char *next_protocol = ssl_get_alpn_protocol(&BACKEND->ssl);
if(next_protocol != NULL) {
infof(data, "ALPN, server accepted to use %s\n", next_protocol);
@@ -614,7 +626,7 @@ polarssl_connect_step3(struct connectdata *conn,
memset(our_ssl_sessionid, 0, sizeof(ssl_session));
- ret = ssl_get_session(&connssl->ssl, our_ssl_sessionid);
+ ret = ssl_get_session(&BACKEND->ssl, our_ssl_sessionid);
if(ret) {
failf(data, "ssl_get_session returned -0x%x", -ret);
return CURLE_SSL_CONNECT_ERROR;
@@ -645,9 +657,10 @@ static ssize_t polarssl_send(struct connectdata *conn,
size_t len,
CURLcode *curlcode)
{
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
int ret = -1;
- ret = ssl_write(&conn->ssl[sockindex].ssl,
+ ret = ssl_write(&BACKEND->ssl,
(unsigned char *)mem, len);
if(ret < 0) {
@@ -659,13 +672,14 @@ static ssize_t polarssl_send(struct connectdata *conn,
return ret;
}
-void Curl_polarssl_close(struct connectdata *conn, int sockindex)
+static void Curl_polarssl_close(struct connectdata *conn, int sockindex)
{
- rsa_free(&conn->ssl[sockindex].rsa);
- x509_crt_free(&conn->ssl[sockindex].clicert);
- x509_crt_free(&conn->ssl[sockindex].cacert);
- x509_crl_free(&conn->ssl[sockindex].crl);
- ssl_free(&conn->ssl[sockindex].ssl);
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ rsa_free(&BACKEND->rsa);
+ x509_crt_free(&BACKEND->clicert);
+ x509_crt_free(&BACKEND->cacert);
+ x509_crl_free(&BACKEND->crl);
+ ssl_free(&BACKEND->ssl);
}
static ssize_t polarssl_recv(struct connectdata *conn,
@@ -674,11 +688,12 @@ static ssize_t polarssl_recv(struct connectdata *conn,
size_t buffersize,
CURLcode *curlcode)
{
+ struct ssl_connect_data *connssl = &conn->ssl[num];
int ret = -1;
ssize_t len = -1;
memset(buf, 0, buffersize);
- ret = ssl_read(&conn->ssl[num].ssl, (unsigned char *)buf, buffersize);
+ ret = ssl_read(&BACKEND->ssl, (unsigned char *)buf, buffersize);
if(ret <= 0) {
if(ret == POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY)
@@ -694,7 +709,7 @@ static ssize_t polarssl_recv(struct connectdata *conn,
return len;
}
-void Curl_polarssl_session_free(void *ptr)
+static void Curl_polarssl_session_free(void *ptr)
{
ssl_session_free(ptr);
free(ptr);
@@ -703,7 +718,7 @@ void Curl_polarssl_session_free(void *ptr)
/* 1.3.10 was the first rebranded version. All new releases (in 1.3 branch and
higher) will be mbed TLS branded.. */
-size_t Curl_polarssl_version(char *buffer, size_t size)
+static size_t Curl_polarssl_version(char *buffer, size_t size)
{
unsigned int version = version_get_number();
return snprintf(buffer, size, "%s/%d.%d.%d",
@@ -762,9 +777,9 @@ polarssl_connect_common(struct connectdata *conn,
if(connssl->connecting_state == ssl_connect_2_reading ||
connssl->connecting_state == ssl_connect_2_writing) {
- curl_socket_t writefd = ssl_connect_2_writing==
+ curl_socket_t writefd = ssl_connect_2_writing ==
connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
- curl_socket_t readfd = ssl_connect_2_reading==
+ curl_socket_t readfd = ssl_connect_2_reading ==
connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
@@ -825,18 +840,14 @@ polarssl_connect_common(struct connectdata *conn,
return CURLE_OK;
}
-CURLcode
-Curl_polarssl_connect_nonblocking(struct connectdata *conn,
- int sockindex,
- bool *done)
+static CURLcode Curl_polarssl_connect_nonblocking(struct connectdata *conn,
+ int sockindex, bool *done)
{
return polarssl_connect_common(conn, sockindex, TRUE, done);
}
-CURLcode
-Curl_polarssl_connect(struct connectdata *conn,
- int sockindex)
+static CURLcode Curl_polarssl_connect(struct connectdata *conn, int sockindex)
{
CURLcode result;
bool done = FALSE;
@@ -854,20 +865,73 @@ Curl_polarssl_connect(struct connectdata *conn,
* return 0 error initializing SSL
* return 1 SSL initialized successfully
*/
-int Curl_polarssl_init(void)
+static int Curl_polarssl_init(void)
{
return Curl_polarsslthreadlock_thread_setup();
}
-void Curl_polarssl_cleanup(void)
+static void Curl_polarssl_cleanup(void)
{
(void)Curl_polarsslthreadlock_thread_cleanup();
}
+static bool Curl_polarssl_data_pending(const struct connectdata *conn,
+ int sockindex)
+{
+ const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ return ssl_get_bytes_avail(&BACKEND->ssl) != 0;
+}
+
+static void Curl_polarssl_sha256sum(const unsigned char *input,
+ size_t inputlen,
+ unsigned char *sha256sum,
+ size_t sha256len UNUSED_PARAM)
+{
+ (void)sha256len;
+ sha256(input, inputlen, sha256sum, 0);
+}
-int Curl_polarssl_data_pending(const struct connectdata *conn, int sockindex)
+static void *Curl_polarssl_get_internals(struct ssl_connect_data *connssl,
+ CURLINFO info UNUSED_PARAM)
{
- return ssl_get_bytes_avail(&conn->ssl[sockindex].ssl) != 0;
+ (void)info;
+ return &BACKEND->ssl;
}
+const struct Curl_ssl Curl_ssl_polarssl = {
+ { CURLSSLBACKEND_POLARSSL, "polarssl" }, /* info */
+
+ 1, /* have_ca_path */
+ 0, /* have_certinfo */
+ 1, /* have_pinnedpubkey */
+ 0, /* have_ssl_ctx */
+ 0, /* support_https_proxy */
+
+ sizeof(struct ssl_backend_data),
+
+ Curl_polarssl_init, /* init */
+ Curl_polarssl_cleanup, /* cleanup */
+ Curl_polarssl_version, /* version */
+ Curl_none_check_cxn, /* check_cxn */
+ Curl_none_shutdown, /* shutdown */
+ Curl_polarssl_data_pending, /* data_pending */
+ /* This might cause libcurl to use a weeker random!
+ * TODO: use Polarssl's CTR-DRBG or HMAC-DRBG
+ */
+ Curl_none_random, /* random */
+ Curl_none_cert_status_request, /* cert_status_request */
+ Curl_polarssl_connect, /* connect */
+ Curl_polarssl_connect_nonblocking, /* connect_nonblocking */
+ Curl_polarssl_get_internals, /* get_internals */
+ Curl_polarssl_close, /* close_one */
+ Curl_none_close_all, /* close_all */
+ Curl_polarssl_session_free, /* session_free */
+ Curl_none_set_engine, /* set_engine */
+ Curl_none_set_engine_default, /* set_engine_default */
+ Curl_none_engines_list, /* engines_list */
+ Curl_none_false_start, /* false_start */
+ Curl_none_md5sum, /* md5sum */
+ Curl_polarssl_sha256sum /* sha256sum */
+};
+
#endif /* USE_POLARSSL */
diff --git a/lib/vtls/polarssl.h b/lib/vtls/polarssl.h
index 47af7b41..23c3636e 100644
--- a/lib/vtls/polarssl.h
+++ b/lib/vtls/polarssl.h
@@ -26,57 +26,7 @@
#ifdef USE_POLARSSL
-#include <polarssl/sha256.h>
-
-/* Called on first use PolarSSL, setup threading if supported */
-int Curl_polarssl_init(void);
-void Curl_polarssl_cleanup(void);
-int Curl_polarssl_data_pending(const struct connectdata *conn, int sockindex);
-
-
-CURLcode Curl_polarssl_connect(struct connectdata *conn, int sockindex);
-
-CURLcode Curl_polarssl_connect_nonblocking(struct connectdata *conn,
- int sockindex,
- bool *done);
-
- /* close a SSL connection */
-void Curl_polarssl_close(struct connectdata *conn, int sockindex);
-
-void Curl_polarssl_session_free(void *ptr);
-size_t Curl_polarssl_version(char *buffer, size_t size);
-int Curl_polarssl_shutdown(struct connectdata *conn, int sockindex);
-
-/* Set the API backend definition to PolarSSL */
-#define CURL_SSL_BACKEND CURLSSLBACKEND_POLARSSL
-
-/* this backend supports the CAPATH option */
-#define have_curlssl_ca_path 1
-
-/* this backends supports CURLOPT_PINNEDPUBLICKEY */
-#define have_curlssl_pinnedpubkey 1
-
-/* API setup for PolarSSL */
-#define curlssl_init() Curl_polarssl_init()
-#define curlssl_cleanup() Curl_polarssl_cleanup()
-#define curlssl_connect Curl_polarssl_connect
-#define curlssl_connect_nonblocking Curl_polarssl_connect_nonblocking
-#define curlssl_session_free(x) Curl_polarssl_session_free(x)
-#define curlssl_close_all(x) ((void)x)
-#define curlssl_close Curl_polarssl_close
-#define curlssl_shutdown(x,y) 0
-#define curlssl_set_engine(x,y) ((void)x, (void)y, CURLE_NOT_BUILT_IN)
-#define curlssl_set_engine_default(x) ((void)x, CURLE_NOT_BUILT_IN)
-#define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL)
-#define curlssl_version Curl_polarssl_version
-#define curlssl_check_cxn(x) ((void)x, -1)
-#define curlssl_data_pending(x,y) Curl_polarssl_data_pending(x, y)
-#define curlssl_sha256sum(a,b,c,d) sha256(a,b,c,0)
-
-/* This might cause libcurl to use a weeker random!
- TODO: implement proper use of Polarssl's CTR-DRBG or HMAC-DRBG and use that
-*/
-#define curlssl_random(x,y,z) ((void)x, (void)y, (void)z, CURLE_NOT_BUILT_IN)
+extern const struct Curl_ssl Curl_ssl_polarssl;
#endif /* USE_POLARSSL */
#endif /* HEADER_CURL_POLARSSL_H */
diff --git a/lib/vtls/polarssl_threadlock.c b/lib/vtls/polarssl_threadlock.c
index b1eb7b74..dd5fbd7e 100644
--- a/lib/vtls/polarssl_threadlock.c
+++ b/lib/vtls/polarssl_threadlock.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2013-2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2013-2017, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 2010, 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com>
*
* This software is licensed as described in the file COPYING, which
@@ -114,7 +114,7 @@ int Curl_polarsslthreadlock_lock_function(int n)
}
#elif defined(HAVE_PROCESS_H)
if(n < NUMT) {
- ret = (WaitForSingleObject(mutex_buf[n], INFINITE)==WAIT_FAILED?1:0);
+ ret = (WaitForSingleObject(mutex_buf[n], INFINITE) == WAIT_FAILED?1:0);
if(ret) {
DEBUGF(fprintf(stderr,
"Error: polarsslthreadlock_lock_function failed\n"));
diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c
index 94603018..85c64cf4 100644
--- a/lib/vtls/schannel.c
+++ b/lib/vtls/schannel.c
@@ -46,6 +46,8 @@
# error "Can't compile SCHANNEL support without SSPI."
#endif
+#include <schnlsp.h>
+#include <schannel.h>
#include "curl_sspi.h"
#include "schannel.h"
#include "vtls.h"
@@ -74,11 +76,92 @@
# define HAS_ALPN 1
#endif
+#ifndef UNISP_NAME_A
+#define UNISP_NAME_A "Microsoft Unified Security Protocol Provider"
+#endif
+
+#ifndef UNISP_NAME_W
+#define UNISP_NAME_W L"Microsoft Unified Security Protocol Provider"
+#endif
+
+#ifndef UNISP_NAME
+#ifdef UNICODE
+#define UNISP_NAME UNISP_NAME_W
+#else
+#define UNISP_NAME UNISP_NAME_A
+#endif
+#endif
+
+#ifndef SP_PROT_SSL2_CLIENT
+#define SP_PROT_SSL2_CLIENT 0x00000008
+#endif
+
+#ifndef SP_PROT_SSL3_CLIENT
+#define SP_PROT_SSL3_CLIENT 0x00000008
+#endif
+
+#ifndef SP_PROT_TLS1_CLIENT
+#define SP_PROT_TLS1_CLIENT 0x00000080
+#endif
+
+#ifndef SP_PROT_TLS1_0_CLIENT
+#define SP_PROT_TLS1_0_CLIENT SP_PROT_TLS1_CLIENT
+#endif
+
+#ifndef SP_PROT_TLS1_1_CLIENT
+#define SP_PROT_TLS1_1_CLIENT 0x00000200
+#endif
+
+#ifndef SP_PROT_TLS1_2_CLIENT
+#define SP_PROT_TLS1_2_CLIENT 0x00000800
+#endif
+
+#ifndef SECBUFFER_ALERT
+#define SECBUFFER_ALERT 17
+#endif
+
+/* Both schannel buffer sizes must be > 0 */
+#define CURL_SCHANNEL_BUFFER_INIT_SIZE 4096
+#define CURL_SCHANNEL_BUFFER_FREE_SIZE 1024
+
/* Uncomment to force verbose output
* #define infof(x, y, ...) printf(y, __VA_ARGS__)
* #define failf(x, y, ...) printf(y, __VA_ARGS__)
*/
+/* Structs to store Schannel handles */
+struct curl_schannel_cred {
+ CredHandle cred_handle;
+ TimeStamp time_stamp;
+ int refcount;
+};
+
+struct curl_schannel_ctxt {
+ CtxtHandle ctxt_handle;
+ TimeStamp time_stamp;
+};
+
+struct ssl_backend_data {
+ struct curl_schannel_cred *cred;
+ struct curl_schannel_ctxt *ctxt;
+ SecPkgContext_StreamSizes stream_sizes;
+ size_t encdata_length, decdata_length;
+ size_t encdata_offset, decdata_offset;
+ unsigned char *encdata_buffer, *decdata_buffer;
+ /* encdata_is_incomplete: if encdata contains only a partial record that
+ can't be decrypted without another Curl_read_plain (that is, status is
+ SEC_E_INCOMPLETE_MESSAGE) then set this true. after Curl_read_plain writes
+ more bytes into encdata then set this back to false. */
+ bool encdata_is_incomplete;
+ unsigned long req_flags, ret_flags;
+ CURLcode recv_unrecoverable_err; /* schannel_recv had an unrecoverable err */
+ bool recv_sspi_close_notify; /* true if connection closed by close_notify */
+ bool recv_connection_closed; /* true if connection closed, regardless how */
+ bool use_alpn; /* true if ALPN is used for this connection */
+};
+
+#define BACKEND connssl->backend
+
static Curl_recv schannel_recv;
static Curl_send schannel_send;
@@ -176,33 +259,33 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
#ifdef HAS_ALPN
/* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above.
Also it doesn't seem to be supported for Wine, see curl bug #983. */
- connssl->use_alpn = conn->bits.tls_enable_alpn &&
+ BACKEND->use_alpn = conn->bits.tls_enable_alpn &&
!GetProcAddress(GetModuleHandleA("ntdll"),
"wine_get_version") &&
Curl_verify_windows_version(6, 3, PLATFORM_WINNT,
VERSION_GREATER_THAN_EQUAL);
#else
- connssl->use_alpn = false;
+ BACKEND->use_alpn = false;
#endif
- connssl->cred = NULL;
+ BACKEND->cred = NULL;
/* check for an existing re-usable credential handle */
if(SSL_SET_OPTION(primary.sessionid)) {
Curl_ssl_sessionid_lock(conn);
if(!Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL, sockindex)) {
- connssl->cred = old_cred;
+ BACKEND->cred = old_cred;
infof(data, "schannel: re-using existing credential handle\n");
/* increment the reference counter of the credential/session handle */
- connssl->cred->refcount++;
+ BACKEND->cred->refcount++;
infof(data, "schannel: incremented credential handle refcount = %d\n",
- connssl->cred->refcount);
+ BACKEND->cred->refcount);
}
Curl_ssl_sessionid_unlock(conn);
}
- if(!connssl->cred) {
+ if(!BACKEND->cred) {
/* setup Schannel API options */
memset(&schannel_cred, 0, sizeof(schannel_cred));
schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
@@ -272,14 +355,14 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
}
/* allocate memory for the re-usable credential handle */
- connssl->cred = (struct curl_schannel_cred *)
+ BACKEND->cred = (struct curl_schannel_cred *)
malloc(sizeof(struct curl_schannel_cred));
- if(!connssl->cred) {
+ if(!BACKEND->cred) {
failf(data, "schannel: unable to allocate memory");
return CURLE_OUT_OF_MEMORY;
}
- memset(connssl->cred, 0, sizeof(struct curl_schannel_cred));
- connssl->cred->refcount = 1;
+ memset(BACKEND->cred, 0, sizeof(struct curl_schannel_cred));
+ BACKEND->cred->refcount = 1;
/* https://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx
*/
@@ -287,8 +370,8 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME,
SECPKG_CRED_OUTBOUND, NULL,
&schannel_cred, NULL, NULL,
- &connssl->cred->cred_handle,
- &connssl->cred->time_stamp);
+ &BACKEND->cred->cred_handle,
+ &BACKEND->cred->time_stamp);
if(sspi_status != SEC_E_OK) {
if(sspi_status == SEC_E_WRONG_PRINCIPAL)
@@ -297,7 +380,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
else
failf(data, "schannel: AcquireCredentialsHandle failed: %s",
Curl_sspi_strerror(conn, sspi_status));
- Curl_safefree(connssl->cred);
+ Curl_safefree(BACKEND->cred);
return CURLE_SSL_CONNECT_ERROR;
}
}
@@ -312,7 +395,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
}
#ifdef HAS_ALPN
- if(connssl->use_alpn) {
+ if(BACKEND->use_alpn) {
int cur = 0;
int list_start_index = 0;
unsigned int *extension_len = NULL;
@@ -370,18 +453,18 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
/* setup request flags */
- connssl->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
+ BACKEND->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY |
ISC_REQ_STREAM;
/* allocate memory for the security context handle */
- connssl->ctxt = (struct curl_schannel_ctxt *)
+ BACKEND->ctxt = (struct curl_schannel_ctxt *)
malloc(sizeof(struct curl_schannel_ctxt));
- if(!connssl->ctxt) {
+ if(!BACKEND->ctxt) {
failf(data, "schannel: unable to allocate memory");
return CURLE_OUT_OF_MEMORY;
}
- memset(connssl->ctxt, 0, sizeof(struct curl_schannel_ctxt));
+ memset(BACKEND->ctxt, 0, sizeof(struct curl_schannel_ctxt));
host_name = Curl_convert_UTF8_to_tchar(hostname);
if(!host_name)
@@ -395,10 +478,10 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
us problems with inbuf regardless. https://github.com/curl/curl/issues/983
*/
sspi_status = s_pSecFn->InitializeSecurityContext(
- &connssl->cred->cred_handle, NULL, host_name, connssl->req_flags, 0, 0,
- (connssl->use_alpn ? &inbuf_desc : NULL),
- 0, &connssl->ctxt->ctxt_handle,
- &outbuf_desc, &connssl->ret_flags, &connssl->ctxt->time_stamp);
+ &BACKEND->cred->cred_handle, NULL, host_name, BACKEND->req_flags, 0, 0,
+ (BACKEND->use_alpn ? &inbuf_desc : NULL),
+ 0, &BACKEND->ctxt->ctxt_handle,
+ &outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp);
Curl_unicodefree(host_name);
@@ -409,7 +492,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
else
failf(data, "schannel: initial InitializeSecurityContext failed: %s",
Curl_sspi_strerror(conn, sspi_status));
- Curl_safefree(connssl->ctxt);
+ Curl_safefree(BACKEND->ctxt);
return CURLE_SSL_CONNECT_ERROR;
}
@@ -429,10 +512,10 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
infof(data, "schannel: sent initial handshake data: "
"sent %zd bytes\n", written);
- connssl->recv_unrecoverable_err = CURLE_OK;
- connssl->recv_sspi_close_notify = false;
- connssl->recv_connection_closed = false;
- connssl->encdata_is_incomplete = false;
+ BACKEND->recv_unrecoverable_err = CURLE_OK;
+ BACKEND->recv_sspi_close_notify = false;
+ BACKEND->recv_connection_closed = false;
+ BACKEND->encdata_is_incomplete = false;
/* continue to second handshake step */
connssl->connecting_state = ssl_connect_2;
@@ -465,39 +548,39 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
infof(data, "schannel: SSL/TLS connection with %s port %hu (step 2/3)\n",
hostname, conn->remote_port);
- if(!connssl->cred || !connssl->ctxt)
+ if(!BACKEND->cred || !BACKEND->ctxt)
return CURLE_SSL_CONNECT_ERROR;
/* buffer to store previously received and decrypted data */
- if(connssl->decdata_buffer == NULL) {
- connssl->decdata_offset = 0;
- connssl->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
- connssl->decdata_buffer = malloc(connssl->decdata_length);
- if(connssl->decdata_buffer == NULL) {
+ if(BACKEND->decdata_buffer == NULL) {
+ BACKEND->decdata_offset = 0;
+ BACKEND->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
+ BACKEND->decdata_buffer = malloc(BACKEND->decdata_length);
+ if(BACKEND->decdata_buffer == NULL) {
failf(data, "schannel: unable to allocate memory");
return CURLE_OUT_OF_MEMORY;
}
}
/* buffer to store previously received and encrypted data */
- if(connssl->encdata_buffer == NULL) {
- connssl->encdata_is_incomplete = false;
- connssl->encdata_offset = 0;
- connssl->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
- connssl->encdata_buffer = malloc(connssl->encdata_length);
- if(connssl->encdata_buffer == NULL) {
+ if(BACKEND->encdata_buffer == NULL) {
+ BACKEND->encdata_is_incomplete = false;
+ BACKEND->encdata_offset = 0;
+ BACKEND->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
+ BACKEND->encdata_buffer = malloc(BACKEND->encdata_length);
+ if(BACKEND->encdata_buffer == NULL) {
failf(data, "schannel: unable to allocate memory");
return CURLE_OUT_OF_MEMORY;
}
}
/* if we need a bigger buffer to read a full message, increase buffer now */
- if(connssl->encdata_length - connssl->encdata_offset <
+ if(BACKEND->encdata_length - BACKEND->encdata_offset <
CURL_SCHANNEL_BUFFER_FREE_SIZE) {
/* increase internal encrypted data buffer */
- reallocated_length = connssl->encdata_offset +
+ reallocated_length = BACKEND->encdata_offset +
CURL_SCHANNEL_BUFFER_FREE_SIZE;
- reallocated_buffer = realloc(connssl->encdata_buffer,
+ reallocated_buffer = realloc(BACKEND->encdata_buffer,
reallocated_length);
if(reallocated_buffer == NULL) {
@@ -505,8 +588,8 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
return CURLE_OUT_OF_MEMORY;
}
else {
- connssl->encdata_buffer = reallocated_buffer;
- connssl->encdata_length = reallocated_length;
+ BACKEND->encdata_buffer = reallocated_buffer;
+ BACKEND->encdata_length = reallocated_length;
}
}
@@ -514,10 +597,10 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
if(doread) {
/* read encrypted handshake data from socket */
result = Curl_read_plain(conn->sock[sockindex],
- (char *) (connssl->encdata_buffer +
- connssl->encdata_offset),
- connssl->encdata_length -
- connssl->encdata_offset,
+ (char *) (BACKEND->encdata_buffer +
+ BACKEND->encdata_offset),
+ BACKEND->encdata_length -
+ BACKEND->encdata_offset,
&nread);
if(result == CURLE_AGAIN) {
if(connssl->connecting_state != ssl_connect_2_writing)
@@ -533,17 +616,17 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
}
/* increase encrypted data buffer offset */
- connssl->encdata_offset += nread;
- connssl->encdata_is_incomplete = false;
+ BACKEND->encdata_offset += nread;
+ BACKEND->encdata_is_incomplete = false;
infof(data, "schannel: encrypted data got %zd\n", nread);
}
infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
- connssl->encdata_offset, connssl->encdata_length);
+ BACKEND->encdata_offset, BACKEND->encdata_length);
/* setup input buffers */
- InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(connssl->encdata_offset),
- curlx_uztoul(connssl->encdata_offset));
+ InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(BACKEND->encdata_offset),
+ curlx_uztoul(BACKEND->encdata_offset));
InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
InitSecBufferDesc(&inbuf_desc, inbuf, 2);
@@ -559,8 +642,8 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
}
/* copy received handshake data into input buffer */
- memcpy(inbuf[0].pvBuffer, connssl->encdata_buffer,
- connssl->encdata_offset);
+ memcpy(inbuf[0].pvBuffer, BACKEND->encdata_buffer,
+ BACKEND->encdata_offset);
host_name = Curl_convert_UTF8_to_tchar(hostname);
if(!host_name)
@@ -569,9 +652,9 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
/* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx
*/
sspi_status = s_pSecFn->InitializeSecurityContext(
- &connssl->cred->cred_handle, &connssl->ctxt->ctxt_handle,
- host_name, connssl->req_flags, 0, 0, &inbuf_desc, 0, NULL,
- &outbuf_desc, &connssl->ret_flags, &connssl->ctxt->time_stamp);
+ &BACKEND->cred->cred_handle, &BACKEND->ctxt->ctxt_handle,
+ host_name, BACKEND->req_flags, 0, 0, &inbuf_desc, 0, NULL,
+ &outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp);
Curl_unicodefree(host_name);
@@ -580,7 +663,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
/* check if the handshake was incomplete */
if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
- connssl->encdata_is_incomplete = true;
+ BACKEND->encdata_is_incomplete = true;
connssl->connecting_state = ssl_connect_2_reading;
infof(data, "schannel: received incomplete message, need more data\n");
return CURLE_OK;
@@ -590,8 +673,8 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
the handshake without one. This will allow connections to servers which
request a client certificate but do not require it. */
if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS &&
- !(connssl->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) {
- connssl->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
+ !(BACKEND->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) {
+ BACKEND->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
connssl->connecting_state = ssl_connect_2_writing;
infof(data, "schannel: a client certificate has been requested\n");
return CURLE_OK;
@@ -631,7 +714,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
failf(data, "schannel: next InitializeSecurityContext failed: %s",
Curl_sspi_strerror(conn, sspi_status));
return sspi_status == SEC_E_UNTRUSTED_ROOT ?
- CURLE_SSL_CACERT_BADFILE : CURLE_SSL_CONNECT_ERROR;
+ CURLE_SSL_CACERT : CURLE_SSL_CONNECT_ERROR;
}
/* check if there was additional remaining encrypted data */
@@ -649,11 +732,11 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
*/
/* check if the remaining data is less than the total amount
and therefore begins after the already processed data */
- if(connssl->encdata_offset > inbuf[1].cbBuffer) {
- memmove(connssl->encdata_buffer,
- (connssl->encdata_buffer + connssl->encdata_offset) -
+ if(BACKEND->encdata_offset > inbuf[1].cbBuffer) {
+ memmove(BACKEND->encdata_buffer,
+ (BACKEND->encdata_buffer + BACKEND->encdata_offset) -
inbuf[1].cbBuffer, inbuf[1].cbBuffer);
- connssl->encdata_offset = inbuf[1].cbBuffer;
+ BACKEND->encdata_offset = inbuf[1].cbBuffer;
if(sspi_status == SEC_I_CONTINUE_NEEDED) {
doread = FALSE;
continue;
@@ -661,7 +744,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
}
}
else {
- connssl->encdata_offset = 0;
+ BACKEND->encdata_offset = 0;
}
break;
}
@@ -709,27 +792,27 @@ schannel_connect_step3(struct connectdata *conn, int sockindex)
infof(data, "schannel: SSL/TLS connection with %s port %hu (step 3/3)\n",
hostname, conn->remote_port);
- if(!connssl->cred)
+ if(!BACKEND->cred)
return CURLE_SSL_CONNECT_ERROR;
/* check if the required context attributes are met */
- if(connssl->ret_flags != connssl->req_flags) {
- if(!(connssl->ret_flags & ISC_RET_SEQUENCE_DETECT))
+ if(BACKEND->ret_flags != BACKEND->req_flags) {
+ if(!(BACKEND->ret_flags & ISC_RET_SEQUENCE_DETECT))
failf(data, "schannel: failed to setup sequence detection");
- if(!(connssl->ret_flags & ISC_RET_REPLAY_DETECT))
+ if(!(BACKEND->ret_flags & ISC_RET_REPLAY_DETECT))
failf(data, "schannel: failed to setup replay detection");
- if(!(connssl->ret_flags & ISC_RET_CONFIDENTIALITY))
+ if(!(BACKEND->ret_flags & ISC_RET_CONFIDENTIALITY))
failf(data, "schannel: failed to setup confidentiality");
- if(!(connssl->ret_flags & ISC_RET_ALLOCATED_MEMORY))
+ if(!(BACKEND->ret_flags & ISC_RET_ALLOCATED_MEMORY))
failf(data, "schannel: failed to setup memory allocation");
- if(!(connssl->ret_flags & ISC_RET_STREAM))
+ if(!(BACKEND->ret_flags & ISC_RET_STREAM))
failf(data, "schannel: failed to setup stream orientation");
return CURLE_SSL_CONNECT_ERROR;
}
#ifdef HAS_ALPN
- if(connssl->use_alpn) {
- sspi_status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle,
+ if(BACKEND->use_alpn) {
+ sspi_status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
SECPKG_ATTR_APPLICATION_PROTOCOL, &alpn_result);
if(sspi_status != SEC_E_OK) {
@@ -771,7 +854,7 @@ schannel_connect_step3(struct connectdata *conn, int sockindex)
incache = !(Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL,
sockindex));
if(incache) {
- if(old_cred != connssl->cred) {
+ if(old_cred != BACKEND->cred) {
infof(data, "schannel: old credential handle is stale, removing\n");
/* we're not taking old_cred ownership here, no refcount++ is needed */
Curl_ssl_delsessionid(conn, (void *)old_cred);
@@ -779,7 +862,7 @@ schannel_connect_step3(struct connectdata *conn, int sockindex)
}
}
if(!incache) {
- result = Curl_ssl_addsessionid(conn, (void *)connssl->cred,
+ result = Curl_ssl_addsessionid(conn, (void *)BACKEND->cred,
sizeof(struct curl_schannel_cred),
sockindex);
if(result) {
@@ -789,7 +872,7 @@ schannel_connect_step3(struct connectdata *conn, int sockindex)
}
else {
/* this cred session is now also referenced by sessionid cache */
- connssl->cred->refcount++;
+ BACKEND->cred->refcount++;
infof(data, "schannel: stored credential handle in session cache\n");
}
}
@@ -797,7 +880,7 @@ schannel_connect_step3(struct connectdata *conn, int sockindex)
}
if(data->set.ssl.certinfo) {
- sspi_status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle,
+ sspi_status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
SECPKG_ATTR_REMOTE_CERT_CONTEXT, &ccert_context);
if((sspi_status != SEC_E_OK) || (ccert_context == NULL)) {
@@ -951,11 +1034,11 @@ schannel_send(struct connectdata *conn, int sockindex,
CURLcode result;
/* check if the maximum stream sizes were queried */
- if(connssl->stream_sizes.cbMaximumMessage == 0) {
+ if(BACKEND->stream_sizes.cbMaximumMessage == 0) {
sspi_status = s_pSecFn->QueryContextAttributes(
- &connssl->ctxt->ctxt_handle,
+ &BACKEND->ctxt->ctxt_handle,
SECPKG_ATTR_STREAM_SIZES,
- &connssl->stream_sizes);
+ &BACKEND->stream_sizes);
if(sspi_status != SEC_E_OK) {
*err = CURLE_SEND_ERROR;
return -1;
@@ -963,14 +1046,13 @@ schannel_send(struct connectdata *conn, int sockindex,
}
/* check if the buffer is longer than the maximum message length */
- if(len > connssl->stream_sizes.cbMaximumMessage) {
- *err = CURLE_SEND_ERROR;
- return -1;
+ if(len > BACKEND->stream_sizes.cbMaximumMessage) {
+ len = BACKEND->stream_sizes.cbMaximumMessage;
}
/* calculate the complete message length and allocate a buffer for it */
- data_len = connssl->stream_sizes.cbHeader + len +
- connssl->stream_sizes.cbTrailer;
+ data_len = BACKEND->stream_sizes.cbHeader + len +
+ BACKEND->stream_sizes.cbTrailer;
data = (unsigned char *) malloc(data_len);
if(data == NULL) {
*err = CURLE_OUT_OF_MEMORY;
@@ -979,12 +1061,12 @@ schannel_send(struct connectdata *conn, int sockindex,
/* setup output buffers (header, data, trailer, empty) */
InitSecBuffer(&outbuf[0], SECBUFFER_STREAM_HEADER,
- data, connssl->stream_sizes.cbHeader);
+ data, BACKEND->stream_sizes.cbHeader);
InitSecBuffer(&outbuf[1], SECBUFFER_DATA,
- data + connssl->stream_sizes.cbHeader, curlx_uztoul(len));
+ data + BACKEND->stream_sizes.cbHeader, curlx_uztoul(len));
InitSecBuffer(&outbuf[2], SECBUFFER_STREAM_TRAILER,
- data + connssl->stream_sizes.cbHeader + len,
- connssl->stream_sizes.cbTrailer);
+ data + BACKEND->stream_sizes.cbHeader + len,
+ BACKEND->stream_sizes.cbTrailer);
InitSecBuffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0);
InitSecBufferDesc(&outbuf_desc, outbuf, 4);
@@ -992,7 +1074,7 @@ schannel_send(struct connectdata *conn, int sockindex,
memcpy(outbuf[1].pvBuffer, buf, len);
/* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */
- sspi_status = s_pSecFn->EncryptMessage(&connssl->ctxt->ctxt_handle, 0,
+ sspi_status = s_pSecFn->EncryptMessage(&BACKEND->ctxt->ctxt_handle, 0,
&outbuf_desc, 0);
/* check if the message was encrypted */
@@ -1102,7 +1184,7 @@ schannel_recv(struct connectdata *conn, int sockindex,
size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE;
/****************************************************************************
- * Don't return or set connssl->recv_unrecoverable_err unless in the cleanup.
+ * Don't return or set BACKEND->recv_unrecoverable_err unless in the cleanup.
* The pattern for return error is set *err, optional infof, goto cleanup.
*
* Our priority is to always return as much decrypted data to the caller as
@@ -1114,16 +1196,16 @@ schannel_recv(struct connectdata *conn, int sockindex,
infof(data, "schannel: client wants to read %zu bytes\n", len);
*err = CURLE_OK;
- if(len && len <= connssl->decdata_offset) {
+ if(len && len <= BACKEND->decdata_offset) {
infof(data, "schannel: enough decrypted data is already available\n");
goto cleanup;
}
- else if(connssl->recv_unrecoverable_err) {
- *err = connssl->recv_unrecoverable_err;
+ else if(BACKEND->recv_unrecoverable_err) {
+ *err = BACKEND->recv_unrecoverable_err;
infof(data, "schannel: an unrecoverable error occurred in a prior call\n");
goto cleanup;
}
- else if(connssl->recv_sspi_close_notify) {
+ else if(BACKEND->recv_sspi_close_notify) {
/* once a server has indicated shutdown there is no more encrypted data */
infof(data, "schannel: server indicated shutdown in a prior call\n");
goto cleanup;
@@ -1135,17 +1217,17 @@ schannel_recv(struct connectdata *conn, int sockindex,
*/
; /* do nothing */
}
- else if(!connssl->recv_connection_closed) {
+ else if(!BACKEND->recv_connection_closed) {
/* increase enc buffer in order to fit the requested amount of data */
- size = connssl->encdata_length - connssl->encdata_offset;
+ size = BACKEND->encdata_length - BACKEND->encdata_offset;
if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE ||
- connssl->encdata_length < min_encdata_length) {
- reallocated_length = connssl->encdata_offset +
+ BACKEND->encdata_length < min_encdata_length) {
+ reallocated_length = BACKEND->encdata_offset +
CURL_SCHANNEL_BUFFER_FREE_SIZE;
if(reallocated_length < min_encdata_length) {
reallocated_length = min_encdata_length;
}
- reallocated_buffer = realloc(connssl->encdata_buffer,
+ reallocated_buffer = realloc(BACKEND->encdata_buffer,
reallocated_length);
if(reallocated_buffer == NULL) {
*err = CURLE_OUT_OF_MEMORY;
@@ -1153,20 +1235,20 @@ schannel_recv(struct connectdata *conn, int sockindex,
goto cleanup;
}
- connssl->encdata_buffer = reallocated_buffer;
- connssl->encdata_length = reallocated_length;
- size = connssl->encdata_length - connssl->encdata_offset;
+ BACKEND->encdata_buffer = reallocated_buffer;
+ BACKEND->encdata_length = reallocated_length;
+ size = BACKEND->encdata_length - BACKEND->encdata_offset;
infof(data, "schannel: encdata_buffer resized %zu\n",
- connssl->encdata_length);
+ BACKEND->encdata_length);
}
infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
- connssl->encdata_offset, connssl->encdata_length);
+ BACKEND->encdata_offset, BACKEND->encdata_length);
/* read encrypted data from socket */
*err = Curl_read_plain(conn->sock[sockindex],
- (char *)(connssl->encdata_buffer +
- connssl->encdata_offset),
+ (char *)(BACKEND->encdata_buffer +
+ BACKEND->encdata_offset),
size, &nread);
if(*err) {
nread = -1;
@@ -1178,26 +1260,26 @@ schannel_recv(struct connectdata *conn, int sockindex,
infof(data, "schannel: Curl_read_plain returned error %d\n", *err);
}
else if(nread == 0) {
- connssl->recv_connection_closed = true;
+ BACKEND->recv_connection_closed = true;
infof(data, "schannel: server closed the connection\n");
}
else if(nread > 0) {
- connssl->encdata_offset += (size_t)nread;
- connssl->encdata_is_incomplete = false;
+ BACKEND->encdata_offset += (size_t)nread;
+ BACKEND->encdata_is_incomplete = false;
infof(data, "schannel: encrypted data got %zd\n", nread);
}
}
infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
- connssl->encdata_offset, connssl->encdata_length);
+ BACKEND->encdata_offset, BACKEND->encdata_length);
/* decrypt loop */
- while(connssl->encdata_offset > 0 && sspi_status == SEC_E_OK &&
- (!len || connssl->decdata_offset < len ||
- connssl->recv_connection_closed)) {
+ while(BACKEND->encdata_offset > 0 && sspi_status == SEC_E_OK &&
+ (!len || BACKEND->decdata_offset < len ||
+ BACKEND->recv_connection_closed)) {
/* prepare data buffer for DecryptMessage call */
- InitSecBuffer(&inbuf[0], SECBUFFER_DATA, connssl->encdata_buffer,
- curlx_uztoul(connssl->encdata_offset));
+ InitSecBuffer(&inbuf[0], SECBUFFER_DATA, BACKEND->encdata_buffer,
+ curlx_uztoul(BACKEND->encdata_offset));
/* we need 3 more empty input buffers for possible output */
InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
@@ -1207,7 +1289,7 @@ schannel_recv(struct connectdata *conn, int sockindex,
/* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx
*/
- sspi_status = s_pSecFn->DecryptMessage(&connssl->ctxt->ctxt_handle,
+ sspi_status = s_pSecFn->DecryptMessage(&BACKEND->ctxt->ctxt_handle,
&inbuf_desc, 0, NULL);
/* check if everything went fine (server may want to renegotiate
@@ -1223,36 +1305,36 @@ schannel_recv(struct connectdata *conn, int sockindex,
/* increase buffer in order to fit the received amount of data */
size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ?
inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE;
- if(connssl->decdata_length - connssl->decdata_offset < size ||
- connssl->decdata_length < len) {
+ if(BACKEND->decdata_length - BACKEND->decdata_offset < size ||
+ BACKEND->decdata_length < len) {
/* increase internal decrypted data buffer */
- reallocated_length = connssl->decdata_offset + size;
+ reallocated_length = BACKEND->decdata_offset + size;
/* make sure that the requested amount of data fits */
if(reallocated_length < len) {
reallocated_length = len;
}
- reallocated_buffer = realloc(connssl->decdata_buffer,
+ reallocated_buffer = realloc(BACKEND->decdata_buffer,
reallocated_length);
if(reallocated_buffer == NULL) {
*err = CURLE_OUT_OF_MEMORY;
failf(data, "schannel: unable to re-allocate memory");
goto cleanup;
}
- connssl->decdata_buffer = reallocated_buffer;
- connssl->decdata_length = reallocated_length;
+ BACKEND->decdata_buffer = reallocated_buffer;
+ BACKEND->decdata_length = reallocated_length;
}
/* copy decrypted data to internal buffer */
size = inbuf[1].cbBuffer;
if(size) {
- memcpy(connssl->decdata_buffer + connssl->decdata_offset,
+ memcpy(BACKEND->decdata_buffer + BACKEND->decdata_offset,
inbuf[1].pvBuffer, size);
- connssl->decdata_offset += size;
+ BACKEND->decdata_offset += size;
}
infof(data, "schannel: decrypted data added: %zu\n", size);
infof(data, "schannel: decrypted data cached: offset %zu length %zu\n",
- connssl->decdata_offset, connssl->decdata_length);
+ BACKEND->decdata_offset, BACKEND->decdata_length);
}
/* check for remaining encrypted data */
@@ -1263,21 +1345,21 @@ schannel_recv(struct connectdata *conn, int sockindex,
/* check if the remaining data is less than the total amount
* and therefore begins after the already processed data
*/
- if(connssl->encdata_offset > inbuf[3].cbBuffer) {
+ if(BACKEND->encdata_offset > inbuf[3].cbBuffer) {
/* move remaining encrypted data forward to the beginning of
buffer */
- memmove(connssl->encdata_buffer,
- (connssl->encdata_buffer + connssl->encdata_offset) -
+ memmove(BACKEND->encdata_buffer,
+ (BACKEND->encdata_buffer + BACKEND->encdata_offset) -
inbuf[3].cbBuffer, inbuf[3].cbBuffer);
- connssl->encdata_offset = inbuf[3].cbBuffer;
+ BACKEND->encdata_offset = inbuf[3].cbBuffer;
}
infof(data, "schannel: encrypted data cached: offset %zu length %zu\n",
- connssl->encdata_offset, connssl->encdata_length);
+ BACKEND->encdata_offset, BACKEND->encdata_length);
}
else {
/* reset encrypted buffer offset, because there is no data remaining */
- connssl->encdata_offset = 0;
+ BACKEND->encdata_offset = 0;
}
/* check if server wants to renegotiate the connection context */
@@ -1287,7 +1369,7 @@ schannel_recv(struct connectdata *conn, int sockindex,
infof(data, "schannel: can't renogotiate, an error is pending\n");
goto cleanup;
}
- if(connssl->encdata_offset) {
+ if(BACKEND->encdata_offset) {
*err = CURLE_RECV_ERROR;
infof(data, "schannel: can't renogotiate, "
"encrypted data available\n");
@@ -1311,16 +1393,16 @@ schannel_recv(struct connectdata *conn, int sockindex,
else if(sspi_status == SEC_I_CONTEXT_EXPIRED) {
/* In Windows 2000 SEC_I_CONTEXT_EXPIRED (close_notify) is not
returned so we have to work around that in cleanup. */
- connssl->recv_sspi_close_notify = true;
- if(!connssl->recv_connection_closed) {
- connssl->recv_connection_closed = true;
+ BACKEND->recv_sspi_close_notify = true;
+ if(!BACKEND->recv_connection_closed) {
+ BACKEND->recv_connection_closed = true;
infof(data, "schannel: server closed the connection\n");
}
goto cleanup;
}
}
else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
- connssl->encdata_is_incomplete = true;
+ BACKEND->encdata_is_incomplete = true;
if(!*err)
*err = CURLE_AGAIN;
infof(data, "schannel: failed to decrypt data, need more data\n");
@@ -1335,10 +1417,10 @@ schannel_recv(struct connectdata *conn, int sockindex,
}
infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
- connssl->encdata_offset, connssl->encdata_length);
+ BACKEND->encdata_offset, BACKEND->encdata_length);
infof(data, "schannel: decrypted data buffer: offset %zu length %zu\n",
- connssl->decdata_offset, connssl->decdata_length);
+ BACKEND->decdata_offset, BACKEND->decdata_length);
cleanup:
/* Warning- there is no guarantee the encdata state is valid at this point */
@@ -1352,13 +1434,13 @@ cleanup:
return close_notify. In that case if the connection was closed we assume it
was graceful (close_notify) since there doesn't seem to be a way to tell.
*/
- if(len && !connssl->decdata_offset && connssl->recv_connection_closed &&
- !connssl->recv_sspi_close_notify) {
+ if(len && !BACKEND->decdata_offset && BACKEND->recv_connection_closed &&
+ !BACKEND->recv_sspi_close_notify) {
bool isWin2k = Curl_verify_windows_version(5, 0, PLATFORM_WINNT,
VERSION_EQUAL);
if(isWin2k && sspi_status == SEC_E_OK)
- connssl->recv_sspi_close_notify = true;
+ BACKEND->recv_sspi_close_notify = true;
else {
*err = CURLE_RECV_ERROR;
infof(data, "schannel: server closed abruptly (missing close_notify)\n");
@@ -1367,23 +1449,23 @@ cleanup:
/* Any error other than CURLE_AGAIN is an unrecoverable error. */
if(*err && *err != CURLE_AGAIN)
- connssl->recv_unrecoverable_err = *err;
+ BACKEND->recv_unrecoverable_err = *err;
- size = len < connssl->decdata_offset ? len : connssl->decdata_offset;
+ size = len < BACKEND->decdata_offset ? len : BACKEND->decdata_offset;
if(size) {
- memcpy(buf, connssl->decdata_buffer, size);
- memmove(connssl->decdata_buffer, connssl->decdata_buffer + size,
- connssl->decdata_offset - size);
- connssl->decdata_offset -= size;
+ memcpy(buf, BACKEND->decdata_buffer, size);
+ memmove(BACKEND->decdata_buffer, BACKEND->decdata_buffer + size,
+ BACKEND->decdata_offset - size);
+ BACKEND->decdata_offset -= size;
infof(data, "schannel: decrypted data returned %zu\n", size);
infof(data, "schannel: decrypted data buffer: offset %zu length %zu\n",
- connssl->decdata_offset, connssl->decdata_length);
+ BACKEND->decdata_offset, BACKEND->decdata_length);
*err = CURLE_OK;
return (ssize_t)size;
}
- if(!*err && !connssl->recv_connection_closed)
+ if(!*err && !BACKEND->recv_connection_closed)
*err = CURLE_AGAIN;
/* It's debatable what to return when !len. We could return whatever error we
@@ -1395,15 +1477,13 @@ cleanup:
return *err ? -1 : 0;
}
-CURLcode
-Curl_schannel_connect_nonblocking(struct connectdata *conn, int sockindex,
- bool *done)
+static CURLcode Curl_schannel_connect_nonblocking(struct connectdata *conn,
+ int sockindex, bool *done)
{
return schannel_connect_common(conn, sockindex, TRUE, done);
}
-CURLcode
-Curl_schannel_connect(struct connectdata *conn, int sockindex)
+static CURLcode Curl_schannel_connect(struct connectdata *conn, int sockindex)
{
CURLcode result;
bool done = FALSE;
@@ -1417,25 +1497,38 @@ Curl_schannel_connect(struct connectdata *conn, int sockindex)
return CURLE_OK;
}
-bool Curl_schannel_data_pending(const struct connectdata *conn, int sockindex)
+static bool Curl_schannel_data_pending(const struct connectdata *conn,
+ int sockindex)
{
const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
if(connssl->use) /* SSL/TLS is in use */
- return (connssl->decdata_offset > 0 ||
- (connssl->encdata_offset > 0 && !connssl->encdata_is_incomplete));
+ return (BACKEND->decdata_offset > 0 ||
+ (BACKEND->encdata_offset > 0 && !BACKEND->encdata_is_incomplete));
else
return FALSE;
}
-void Curl_schannel_close(struct connectdata *conn, int sockindex)
+static void Curl_schannel_close(struct connectdata *conn, int sockindex)
{
if(conn->ssl[sockindex].use)
/* if the SSL/TLS channel hasn't been shut down yet, do that now. */
Curl_ssl_shutdown(conn, sockindex);
}
-int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
+static void Curl_schannel_session_free(void *ptr)
+{
+ /* this is expected to be called under sessionid lock */
+ struct curl_schannel_cred *cred = ptr;
+
+ cred->refcount--;
+ if(cred->refcount == 0) {
+ s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
+ Curl_safefree(cred);
+ }
+}
+
+static int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
{
/* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx
* Shutting Down an Schannel Connection
@@ -1448,7 +1541,7 @@ int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu\n",
hostname, conn->remote_port);
- if(connssl->cred && connssl->ctxt) {
+ if(BACKEND->cred && BACKEND->ctxt) {
SecBufferDesc BuffDesc;
SecBuffer Buffer;
SECURITY_STATUS sspi_status;
@@ -1461,7 +1554,7 @@ int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut));
InitSecBufferDesc(&BuffDesc, &Buffer, 1);
- sspi_status = s_pSecFn->ApplyControlToken(&connssl->ctxt->ctxt_handle,
+ sspi_status = s_pSecFn->ApplyControlToken(&BACKEND->ctxt->ctxt_handle,
&BuffDesc);
if(sspi_status != SEC_E_OK)
@@ -1477,18 +1570,18 @@ int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
sspi_status = s_pSecFn->InitializeSecurityContext(
- &connssl->cred->cred_handle,
- &connssl->ctxt->ctxt_handle,
+ &BACKEND->cred->cred_handle,
+ &BACKEND->ctxt->ctxt_handle,
host_name,
- connssl->req_flags,
+ BACKEND->req_flags,
0,
0,
NULL,
0,
- &connssl->ctxt->ctxt_handle,
+ &BACKEND->ctxt->ctxt_handle,
&outbuf_desc,
- &connssl->ret_flags,
- &connssl->ctxt->time_stamp);
+ &BACKEND->ret_flags,
+ &BACKEND->ctxt->time_stamp);
Curl_unicodefree(host_name);
@@ -1507,71 +1600,62 @@ int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
}
/* free SSPI Schannel API security context handle */
- if(connssl->ctxt) {
+ if(BACKEND->ctxt) {
infof(data, "schannel: clear security context handle\n");
- s_pSecFn->DeleteSecurityContext(&connssl->ctxt->ctxt_handle);
- Curl_safefree(connssl->ctxt);
+ s_pSecFn->DeleteSecurityContext(&BACKEND->ctxt->ctxt_handle);
+ Curl_safefree(BACKEND->ctxt);
}
/* free SSPI Schannel API credential handle */
- if(connssl->cred) {
+ if(BACKEND->cred) {
Curl_ssl_sessionid_lock(conn);
- Curl_schannel_session_free(connssl->cred);
+ Curl_schannel_session_free(BACKEND->cred);
Curl_ssl_sessionid_unlock(conn);
- connssl->cred = NULL;
+ BACKEND->cred = NULL;
}
/* free internal buffer for received encrypted data */
- if(connssl->encdata_buffer != NULL) {
- Curl_safefree(connssl->encdata_buffer);
- connssl->encdata_length = 0;
- connssl->encdata_offset = 0;
- connssl->encdata_is_incomplete = false;
+ if(BACKEND->encdata_buffer != NULL) {
+ Curl_safefree(BACKEND->encdata_buffer);
+ BACKEND->encdata_length = 0;
+ BACKEND->encdata_offset = 0;
+ BACKEND->encdata_is_incomplete = false;
}
/* free internal buffer for received decrypted data */
- if(connssl->decdata_buffer != NULL) {
- Curl_safefree(connssl->decdata_buffer);
- connssl->decdata_length = 0;
- connssl->decdata_offset = 0;
+ if(BACKEND->decdata_buffer != NULL) {
+ Curl_safefree(BACKEND->decdata_buffer);
+ BACKEND->decdata_length = 0;
+ BACKEND->decdata_offset = 0;
}
return CURLE_OK;
}
-void Curl_schannel_session_free(void *ptr)
-{
- /* this is expected to be called under sessionid lock */
- struct curl_schannel_cred *cred = ptr;
-
- cred->refcount--;
- if(cred->refcount == 0) {
- s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
- Curl_safefree(cred);
- }
-}
-
-int Curl_schannel_init(void)
+static int Curl_schannel_init(void)
{
return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0);
}
-void Curl_schannel_cleanup(void)
+static void Curl_schannel_cleanup(void)
{
Curl_sspi_global_cleanup();
}
-size_t Curl_schannel_version(char *buffer, size_t size)
+static size_t Curl_schannel_version(char *buffer, size_t size)
{
size = snprintf(buffer, size, "WinSSL");
return size;
}
-CURLcode Curl_schannel_random(unsigned char *entropy, size_t length)
+static CURLcode Curl_schannel_random(struct Curl_easy *data UNUSED_PARAM,
+ unsigned char *entropy, size_t length)
{
HCRYPTPROV hCryptProv = 0;
+ (void)data;
+
if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
return CURLE_FAILED_INIT;
@@ -1598,7 +1682,7 @@ static CURLcode verify_certificate(struct connectdata *conn, int sockindex)
conn->http_proxy.host.name :
conn->host.name;
- status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle,
+ status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
SECPKG_ATTR_REMOTE_CERT_CONTEXT,
&pCertContextServer);
@@ -1725,4 +1809,44 @@ static CURLcode verify_certificate(struct connectdata *conn, int sockindex)
}
#endif /* _WIN32_WCE */
+static void *Curl_schannel_get_internals(struct ssl_connect_data *connssl,
+ CURLINFO info UNUSED_PARAM)
+{
+ (void)info;
+ return &BACKEND->ctxt->ctxt_handle;
+}
+
+const struct Curl_ssl Curl_ssl_schannel = {
+ { CURLSSLBACKEND_SCHANNEL, "schannel" }, /* info */
+
+ 0, /* have_ca_path */
+ 1, /* have_certinfo */
+ 0, /* have_pinnedpubkey */
+ 0, /* have_ssl_ctx */
+ 0, /* support_https_proxy */
+
+ sizeof(struct ssl_backend_data),
+
+ Curl_schannel_init, /* init */
+ Curl_schannel_cleanup, /* cleanup */
+ Curl_schannel_version, /* version */
+ Curl_none_check_cxn, /* check_cxn */
+ Curl_schannel_shutdown, /* shutdown */
+ Curl_schannel_data_pending, /* data_pending */
+ Curl_schannel_random, /* random */
+ Curl_none_cert_status_request, /* cert_status_request */
+ Curl_schannel_connect, /* connect */
+ Curl_schannel_connect_nonblocking, /* connect_nonblocking */
+ Curl_schannel_get_internals, /* get_internals */
+ Curl_schannel_close, /* close_one */
+ Curl_none_close_all, /* close_all */
+ Curl_schannel_session_free, /* session_free */
+ Curl_none_set_engine, /* set_engine */
+ Curl_none_set_engine_default, /* set_engine_default */
+ Curl_none_engines_list, /* engines_list */
+ Curl_none_false_start, /* false_start */
+ Curl_none_md5sum, /* md5sum */
+ NULL /* sha256sum */
+};
+
#endif /* USE_SCHANNEL */
diff --git a/lib/vtls/schannel.h b/lib/vtls/schannel.h
index 8627c63c..932103da 100644
--- a/lib/vtls/schannel.h
+++ b/lib/vtls/schannel.h
@@ -28,94 +28,7 @@
#include "urldata.h"
-#ifndef UNISP_NAME_A
-#define UNISP_NAME_A "Microsoft Unified Security Protocol Provider"
-#endif
-
-#ifndef UNISP_NAME_W
-#define UNISP_NAME_W L"Microsoft Unified Security Protocol Provider"
-#endif
-
-#ifndef UNISP_NAME
-#ifdef UNICODE
-#define UNISP_NAME UNISP_NAME_W
-#else
-#define UNISP_NAME UNISP_NAME_A
-#endif
-#endif
-
-#ifndef SP_PROT_SSL2_CLIENT
-#define SP_PROT_SSL2_CLIENT 0x00000008
-#endif
-
-#ifndef SP_PROT_SSL3_CLIENT
-#define SP_PROT_SSL3_CLIENT 0x00000008
-#endif
-
-#ifndef SP_PROT_TLS1_CLIENT
-#define SP_PROT_TLS1_CLIENT 0x00000080
-#endif
-
-#ifndef SP_PROT_TLS1_0_CLIENT
-#define SP_PROT_TLS1_0_CLIENT SP_PROT_TLS1_CLIENT
-#endif
-
-#ifndef SP_PROT_TLS1_1_CLIENT
-#define SP_PROT_TLS1_1_CLIENT 0x00000200
-#endif
-
-#ifndef SP_PROT_TLS1_2_CLIENT
-#define SP_PROT_TLS1_2_CLIENT 0x00000800
-#endif
-
-#ifndef SECBUFFER_ALERT
-#define SECBUFFER_ALERT 17
-#endif
-
-/* Both schannel buffer sizes must be > 0 */
-#define CURL_SCHANNEL_BUFFER_INIT_SIZE 4096
-#define CURL_SCHANNEL_BUFFER_FREE_SIZE 1024
-
-
-CURLcode Curl_schannel_connect(struct connectdata *conn, int sockindex);
-
-CURLcode Curl_schannel_connect_nonblocking(struct connectdata *conn,
- int sockindex,
- bool *done);
-
-bool Curl_schannel_data_pending(const struct connectdata *conn, int sockindex);
-void Curl_schannel_close(struct connectdata *conn, int sockindex);
-int Curl_schannel_shutdown(struct connectdata *conn, int sockindex);
-void Curl_schannel_session_free(void *ptr);
-
-int Curl_schannel_init(void);
-void Curl_schannel_cleanup(void);
-size_t Curl_schannel_version(char *buffer, size_t size);
-
-CURLcode Curl_schannel_random(unsigned char *entropy, size_t length);
-
-/* Set the API backend definition to Schannel */
-#define CURL_SSL_BACKEND CURLSSLBACKEND_SCHANNEL
-
-/* this backend supports CURLOPT_CERTINFO */
-#define have_curlssl_certinfo 1
-
-/* API setup for Schannel */
-#define curlssl_init Curl_schannel_init
-#define curlssl_cleanup Curl_schannel_cleanup
-#define curlssl_connect Curl_schannel_connect
-#define curlssl_connect_nonblocking Curl_schannel_connect_nonblocking
-#define curlssl_session_free Curl_schannel_session_free
-#define curlssl_close_all(x) ((void)x)
-#define curlssl_close Curl_schannel_close
-#define curlssl_shutdown Curl_schannel_shutdown
-#define curlssl_set_engine(x,y) ((void)x, (void)y, CURLE_NOT_BUILT_IN)
-#define curlssl_set_engine_default(x) ((void)x, CURLE_NOT_BUILT_IN)
-#define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL)
-#define curlssl_version Curl_schannel_version
-#define curlssl_check_cxn(x) ((void)x, -1)
-#define curlssl_data_pending Curl_schannel_data_pending
-#define curlssl_random(x,y,z) ((void)x, Curl_schannel_random(y,z))
+extern const struct Curl_ssl Curl_ssl_schannel;
#endif /* USE_SCHANNEL */
#endif /* HEADER_CURL_SCHANNEL_H */
diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c
index d5d0971c..56e63177 100644
--- a/lib/vtls/vtls.c
+++ b/lib/vtls/vtls.c
@@ -28,17 +28,9 @@
to any specific SSL-layer.
Curl_ssl_ - prefix for generic ones
- Curl_ossl_ - prefix for OpenSSL ones
- Curl_gtls_ - prefix for GnuTLS ones
- Curl_nss_ - prefix for NSS ones
- Curl_gskit_ - prefix for GSKit ones
- Curl_polarssl_ - prefix for PolarSSL ones
- Curl_cyassl_ - prefix for CyaSSL ones
- Curl_schannel_ - prefix for Schannel SSPI ones
- Curl_darwinssl_ - prefix for SecureTransport (Darwin) ones
-
- Note that this source code uses curlssl_* functions, and they are all
- defines/macros #defined by the lib-specific header files.
+
+ Note that this source code uses the functions of the configured SSL
+ backend via the global Curl_ssl instance.
"SSL/TLS Strong Encryption: An Introduction"
https://httpd.apache.org/docs/2.0/ssl/ssl_intro.html
@@ -98,9 +90,12 @@ Curl_ssl_config_matches(struct ssl_primary_config* data,
(data->version_max == needle->version_max) &&
(data->verifypeer == needle->verifypeer) &&
(data->verifyhost == needle->verifyhost) &&
+ (data->verifystatus == needle->verifystatus) &&
Curl_safe_strcasecompare(data->CApath, needle->CApath) &&
Curl_safe_strcasecompare(data->CAfile, needle->CAfile) &&
Curl_safe_strcasecompare(data->clientcert, needle->clientcert) &&
+ Curl_safe_strcasecompare(data->random_file, needle->random_file) &&
+ Curl_safe_strcasecompare(data->egdsocket, needle->egdsocket) &&
Curl_safe_strcasecompare(data->cipher_list, needle->cipher_list))
return TRUE;
@@ -111,42 +106,51 @@ bool
Curl_clone_primary_ssl_config(struct ssl_primary_config *source,
struct ssl_primary_config *dest)
{
- dest->verifyhost = source->verifyhost;
- dest->verifypeer = source->verifypeer;
dest->version = source->version;
dest->version_max = source->version_max;
+ dest->verifypeer = source->verifypeer;
+ dest->verifyhost = source->verifyhost;
+ dest->verifystatus = source->verifystatus;
+ dest->sessionid = source->sessionid;
- CLONE_STRING(CAfile);
CLONE_STRING(CApath);
- CLONE_STRING(cipher_list);
- CLONE_STRING(egdsocket);
- CLONE_STRING(random_file);
+ CLONE_STRING(CAfile);
CLONE_STRING(clientcert);
+ CLONE_STRING(random_file);
+ CLONE_STRING(egdsocket);
+ CLONE_STRING(cipher_list);
- /* Disable dest sessionid cache if a client cert is used, CVE-2016-5419. */
- dest->sessionid = (dest->clientcert ? false : source->sessionid);
return TRUE;
}
void Curl_free_primary_ssl_config(struct ssl_primary_config* sslc)
{
- Curl_safefree(sslc->CAfile);
Curl_safefree(sslc->CApath);
- Curl_safefree(sslc->cipher_list);
- Curl_safefree(sslc->egdsocket);
- Curl_safefree(sslc->random_file);
+ Curl_safefree(sslc->CAfile);
Curl_safefree(sslc->clientcert);
+ Curl_safefree(sslc->random_file);
+ Curl_safefree(sslc->egdsocket);
+ Curl_safefree(sslc->cipher_list);
}
+#ifdef USE_SSL
+static int multissl_init(const struct Curl_ssl *backend);
+#endif
+
int Curl_ssl_backend(void)
{
- return (int)CURL_SSL_BACKEND;
+#ifdef USE_SSL
+ multissl_init(NULL);
+ return Curl_ssl->info.id;
+#else
+ return (int)CURLSSLBACKEND_NONE;
+#endif
}
#ifdef USE_SSL
/* "global" init done? */
-static bool init_ssl=FALSE;
+static bool init_ssl = FALSE;
/**
* Global SSL init
@@ -161,7 +165,7 @@ int Curl_ssl_init(void)
return 1;
init_ssl = TRUE; /* never again */
- return curlssl_init();
+ return Curl_ssl->init();
}
@@ -170,7 +174,7 @@ void Curl_ssl_cleanup(void)
{
if(init_ssl) {
/* only cleanup if we did a previous init */
- curlssl_cleanup();
+ Curl_ssl->cleanup();
init_ssl = FALSE;
}
}
@@ -205,12 +209,20 @@ ssl_connect_init_proxy(struct connectdata *conn, int sockindex)
DEBUGASSERT(conn->bits.proxy_ssl_connected[sockindex]);
if(ssl_connection_complete == conn->ssl[sockindex].state &&
!conn->proxy_ssl[sockindex].use) {
-#if defined(HTTPS_PROXY_SUPPORT)
+ struct ssl_backend_data *pbdata;
+
+ if(!Curl_ssl->support_https_proxy)
+ return CURLE_NOT_BUILT_IN;
+
+ /* The pointers to the ssl backend data, which is opaque here, are swapped
+ rather than move the contents. */
+ pbdata = conn->proxy_ssl[sockindex].backend;
conn->proxy_ssl[sockindex] = conn->ssl[sockindex];
+
memset(&conn->ssl[sockindex], 0, sizeof(conn->ssl[sockindex]));
-#else
- return CURLE_NOT_BUILT_IN;
-#endif
+ memset(pbdata, 0, Curl_ssl->sizeof_ssl_backend_data);
+
+ conn->ssl[sockindex].backend = pbdata;
}
return CURLE_OK;
}
@@ -233,7 +245,7 @@ Curl_ssl_connect(struct connectdata *conn, int sockindex)
conn->ssl[sockindex].use = TRUE;
conn->ssl[sockindex].state = ssl_connection_negotiating;
- result = curlssl_connect(conn, sockindex);
+ result = Curl_ssl->connect(conn, sockindex);
if(!result)
Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */
@@ -257,12 +269,7 @@ Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex,
/* mark this is being ssl requested from here on. */
conn->ssl[sockindex].use = TRUE;
-#ifdef curlssl_connect_nonblocking
- result = curlssl_connect_nonblocking(conn, sockindex, done);
-#else
- *done = TRUE; /* fallback to BLOCKING */
- result = curlssl_connect(conn, sockindex);
-#endif /* non-blocking connect support */
+ result = Curl_ssl->connect_nonblocking(conn, sockindex, done);
if(!result && *done)
Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */
return result;
@@ -361,7 +368,7 @@ void Curl_ssl_kill_session(struct curl_ssl_session *session)
/* defensive check */
/* free the ID the SSL-layer specific way */
- curlssl_session_free(session->sessionid);
+ Curl_ssl->session_free(session->sessionid);
session->sessionid = NULL;
session->age = 0; /* fresh */
@@ -379,7 +386,7 @@ void Curl_ssl_kill_session(struct curl_ssl_session *session)
void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid)
{
size_t i;
- struct Curl_easy *data=conn->data;
+ struct Curl_easy *data = conn->data;
for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) {
struct curl_ssl_session *check = &data->state.session[i];
@@ -403,9 +410,9 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
int sockindex)
{
size_t i;
- struct Curl_easy *data=conn->data; /* the mother of all structs */
+ struct Curl_easy *data = conn->data; /* the mother of all structs */
struct curl_ssl_session *store = &data->state.session[0];
- long oldest_age=data->state.session[0].age; /* zero if unused */
+ long oldest_age = data->state.session[0].age; /* zero if unused */
char *clone_host;
char *clone_conn_to_host;
int conn_to_port;
@@ -499,7 +506,7 @@ void Curl_ssl_close_all(struct Curl_easy *data)
Curl_safefree(data->state.session);
}
- curlssl_close_all(data);
+ Curl_ssl->close_all(data);
}
#if defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) || \
@@ -542,12 +549,12 @@ int Curl_ssl_getsock(struct connectdata *conn,
void Curl_ssl_close(struct connectdata *conn, int sockindex)
{
DEBUGASSERT((sockindex <= 1) && (sockindex >= -1));
- curlssl_close(conn, sockindex);
+ Curl_ssl->close_one(conn, sockindex);
}
CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex)
{
- if(curlssl_shutdown(conn, sockindex))
+ if(Curl_ssl->shutdown(conn, sockindex))
return CURLE_SSL_SHUTDOWN_FAILED;
conn->ssl[sockindex].use = FALSE; /* get back to ordinary socket usage */
@@ -563,20 +570,20 @@ CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex)
*/
CURLcode Curl_ssl_set_engine(struct Curl_easy *data, const char *engine)
{
- return curlssl_set_engine(data, engine);
+ return Curl_ssl->set_engine(data, engine);
}
/* Selects the default SSL crypto engine
*/
CURLcode Curl_ssl_set_engine_default(struct Curl_easy *data)
{
- return curlssl_set_engine_default(data);
+ return Curl_ssl->set_engine_default(data);
}
/* Return list of OpenSSL crypto engine names. */
struct curl_slist *Curl_ssl_engines_list(struct Curl_easy *data)
{
- return curlssl_engines_list(data);
+ return Curl_ssl->engines_list(data);
}
/*
@@ -602,9 +609,15 @@ CURLcode Curl_ssl_initsessions(struct Curl_easy *data, size_t amount)
return CURLE_OK;
}
+static size_t Curl_multissl_version(char *buffer, size_t size);
+
size_t Curl_ssl_version(char *buffer, size_t size)
{
- return curlssl_version(buffer, size);
+#ifdef CURL_WITH_MULTI_SSL
+ return Curl_multissl_version(buffer, size);
+#else
+ return Curl_ssl->version(buffer, size);
+#endif
}
/*
@@ -617,13 +630,13 @@ size_t Curl_ssl_version(char *buffer, size_t size)
*/
int Curl_ssl_check_cxn(struct connectdata *conn)
{
- return curlssl_check_cxn(conn);
+ return Curl_ssl->check_cxn(conn);
}
bool Curl_ssl_data_pending(const struct connectdata *conn,
int connindex)
{
- return curlssl_data_pending(conn, connindex);
+ return Curl_ssl->data_pending(conn, connindex);
}
void Curl_ssl_free_certinfo(struct Curl_easy *data)
@@ -633,7 +646,7 @@ void Curl_ssl_free_certinfo(struct Curl_easy *data)
if(ci->num_of_certs) {
/* free all individual lists used */
- for(i=0; i<ci->num_of_certs; i++) {
+ for(i = 0; i<ci->num_of_certs; i++) {
curl_slist_free_all(ci->certinfo[i]);
ci->certinfo[i] = NULL;
}
@@ -687,7 +700,7 @@ CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy *data,
snprintf(output, outlen, "%s:", label);
/* memcpy the value (it might not be zero terminated) */
- memcpy(&output[labellen+1], value, valuelen);
+ memcpy(&output[labellen + 1], value, valuelen);
/* zero terminate the output */
output[labellen + 1 + valuelen] = 0;
@@ -721,7 +734,7 @@ CURLcode Curl_ssl_random(struct Curl_easy *data,
unsigned char *entropy,
size_t length)
{
- return curlssl_random(data, entropy, length);
+ return Curl_ssl->random(data, entropy, length);
}
/*
@@ -796,12 +809,10 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
size_t size, pem_len;
CURLcode pem_read;
CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
-#ifdef curlssl_sha256sum
CURLcode encode;
size_t encodedlen, pinkeylen;
char *encoded, *pinkeycopy, *begin_pos, *end_pos;
unsigned char *sha256sumdigest = NULL;
-#endif
/* if a path wasn't specified, don't pin */
if(!pinnedpubkey)
@@ -811,15 +822,20 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
/* only do this if pinnedpubkey starts with "sha256//", length 8 */
if(strncmp(pinnedpubkey, "sha256//", 8) == 0) {
-#ifdef curlssl_sha256sum
+ if(!Curl_ssl->sha256sum) {
+ /* without sha256 support, this cannot match */
+ return result;
+ }
+
/* compute sha256sum of public key */
- sha256sumdigest = malloc(SHA256_DIGEST_LENGTH);
+ sha256sumdigest = malloc(CURL_SHA256_DIGEST_LENGTH);
if(!sha256sumdigest)
return CURLE_OUT_OF_MEMORY;
- curlssl_sha256sum(pubkey, pubkeylen,
- sha256sumdigest, SHA256_DIGEST_LENGTH);
+ Curl_ssl->sha256sum(pubkey, pubkeylen,
+ sha256sumdigest, CURL_SHA256_DIGEST_LENGTH);
encode = Curl_base64_encode(data, (char *)sha256sumdigest,
- SHA256_DIGEST_LENGTH, &encoded, &encodedlen);
+ CURL_SHA256_DIGEST_LENGTH, &encoded,
+ &encodedlen);
Curl_safefree(sha256sumdigest);
if(encode)
@@ -864,10 +880,6 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
} while(end_pos && begin_pos);
Curl_safefree(encoded);
Curl_safefree(pinkeycopy);
-#else
- /* without sha256 support, this cannot match */
- (void)data;
-#endif
return result;
}
@@ -943,45 +955,372 @@ CURLcode Curl_ssl_md5sum(unsigned char *tmp, /* input */
unsigned char *md5sum, /* output */
size_t md5len)
{
-#ifdef curlssl_md5sum
- curlssl_md5sum(tmp, tmplen, md5sum, md5len);
-#else
+ return Curl_ssl->md5sum(tmp, tmplen, md5sum, md5len);
+}
+#endif
+
+/*
+ * Check whether the SSL backend supports the status_request extension.
+ */
+bool Curl_ssl_cert_status_request(void)
+{
+ return Curl_ssl->cert_status_request();
+}
+
+/*
+ * Check whether the SSL backend supports false start.
+ */
+bool Curl_ssl_false_start(void)
+{
+ return Curl_ssl->false_start();
+}
+
+/*
+ * Default implementations for unsupported functions.
+ */
+
+int Curl_none_init(void)
+{
+ return 1;
+}
+
+void Curl_none_cleanup(void)
+{ }
+
+int Curl_none_shutdown(struct connectdata *conn UNUSED_PARAM,
+ int sockindex UNUSED_PARAM)
+{
+ (void)conn;
+ (void)sockindex;
+ return 0;
+}
+
+int Curl_none_check_cxn(struct connectdata *conn UNUSED_PARAM)
+{
+ (void)conn;
+ return -1;
+}
+
+CURLcode Curl_none_random(struct Curl_easy *data UNUSED_PARAM,
+ unsigned char *entropy UNUSED_PARAM,
+ size_t length UNUSED_PARAM)
+{
+ (void)data;
+ (void)entropy;
+ (void)length;
+ return CURLE_NOT_BUILT_IN;
+}
+
+void Curl_none_close_all(struct Curl_easy *data UNUSED_PARAM)
+{
+ (void)data;
+}
+
+void Curl_none_session_free(void *ptr UNUSED_PARAM)
+{
+ (void)ptr;
+}
+
+bool Curl_none_data_pending(const struct connectdata *conn UNUSED_PARAM,
+ int connindex UNUSED_PARAM)
+{
+ (void)conn;
+ (void)connindex;
+ return 0;
+}
+
+bool Curl_none_cert_status_request(void)
+{
+ return FALSE;
+}
+
+CURLcode Curl_none_set_engine(struct Curl_easy *data UNUSED_PARAM,
+ const char *engine UNUSED_PARAM)
+{
+ (void)data;
+ (void)engine;
+ return CURLE_NOT_BUILT_IN;
+}
+
+CURLcode Curl_none_set_engine_default(struct Curl_easy *data UNUSED_PARAM)
+{
+ (void)data;
+ return CURLE_NOT_BUILT_IN;
+}
+
+struct curl_slist *Curl_none_engines_list(struct Curl_easy *data UNUSED_PARAM)
+{
+ (void)data;
+ return (struct curl_slist *)NULL;
+}
+
+bool Curl_none_false_start(void)
+{
+ return FALSE;
+}
+
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+CURLcode Curl_none_md5sum(unsigned char *input, size_t inputlen,
+ unsigned char *md5sum, size_t md5len UNUSED_PARAM)
+{
MD5_context *MD5pw;
- (void) md5len;
+ (void)md5len;
MD5pw = Curl_MD5_init(Curl_DIGEST_MD5);
if(!MD5pw)
return CURLE_OUT_OF_MEMORY;
- Curl_MD5_update(MD5pw, tmp, curlx_uztoui(tmplen));
+ Curl_MD5_update(MD5pw, input, curlx_uztoui(inputlen));
Curl_MD5_final(MD5pw, md5sum);
-#endif
return CURLE_OK;
}
+#else
+CURLcode Curl_none_md5sum(unsigned char *input UNUSED_PARAM,
+ size_t inputlen UNUSED_PARAM,
+ unsigned char *md5sum UNUSED_PARAM,
+ size_t md5len UNUSED_PARAM)
+{
+ (void)input;
+ (void)inputlen;
+ (void)md5sum;
+ (void)md5len;
+ return CURLE_NOT_BUILT_IN;
+}
#endif
-/*
- * Check whether the SSL backend supports the status_request extension.
- */
-bool Curl_ssl_cert_status_request(void)
+static int Curl_multissl_init(void)
+{
+ if(multissl_init(NULL))
+ return 1;
+ return Curl_ssl->init();
+}
+
+static CURLcode Curl_multissl_connect(struct connectdata *conn, int sockindex)
+{
+ if(multissl_init(NULL))
+ return CURLE_FAILED_INIT;
+ return Curl_ssl->connect(conn, sockindex);
+}
+
+static CURLcode Curl_multissl_connect_nonblocking(struct connectdata *conn,
+ int sockindex, bool *done)
{
-#ifdef curlssl_cert_status_request
- return curlssl_cert_status_request();
+ if(multissl_init(NULL))
+ return CURLE_FAILED_INIT;
+ return Curl_ssl->connect_nonblocking(conn, sockindex, done);
+}
+
+static void *Curl_multissl_get_internals(struct ssl_connect_data *connssl,
+ CURLINFO info)
+{
+ if(multissl_init(NULL))
+ return NULL;
+ return Curl_ssl->get_internals(connssl, info);
+}
+
+static void Curl_multissl_close(struct connectdata *conn, int sockindex)
+{
+ if(multissl_init(NULL))
+ return;
+ Curl_ssl->close_one(conn, sockindex);
+}
+
+static const struct Curl_ssl Curl_ssl_multi = {
+ { CURLSSLBACKEND_NONE, "multi" }, /* info */
+
+ 0, /* have_ca_path */
+ 0, /* have_certinfo */
+ 0, /* have_pinnedpubkey */
+ 0, /* have_ssl_ctx */
+ 0, /* support_https_proxy */
+
+ (size_t)-1, /* something insanely large to be on the safe side */
+
+ Curl_multissl_init, /* init */
+ Curl_none_cleanup, /* cleanup */
+ Curl_multissl_version, /* version */
+ Curl_none_check_cxn, /* check_cxn */
+ Curl_none_shutdown, /* shutdown */
+ Curl_none_data_pending, /* data_pending */
+ Curl_none_random, /* random */
+ Curl_none_cert_status_request, /* cert_status_request */
+ Curl_multissl_connect, /* connect */
+ Curl_multissl_connect_nonblocking, /* connect_nonblocking */
+ Curl_multissl_get_internals, /* get_internals */
+ Curl_multissl_close, /* close_one */
+ Curl_none_close_all, /* close_all */
+ Curl_none_session_free, /* session_free */
+ Curl_none_set_engine, /* set_engine */
+ Curl_none_set_engine_default, /* set_engine_default */
+ Curl_none_engines_list, /* engines_list */
+ Curl_none_false_start, /* false_start */
+ Curl_none_md5sum, /* md5sum */
+ NULL /* sha256sum */
+};
+
+const struct Curl_ssl *Curl_ssl =
+#if defined(CURL_WITH_MULTI_SSL)
+ &Curl_ssl_multi;
+#elif defined(USE_AXTLS)
+ &Curl_ssl_axtls;
+#elif defined(USE_CYASSL)
+ &Curl_ssl_cyassl;
+#elif defined(USE_DARWINSSL)
+ &Curl_ssl_darwinssl;
+#elif defined(USE_GNUTLS)
+ &Curl_ssl_gnutls;
+#elif defined(USE_GSKIT)
+ &Curl_ssl_gskit;
+#elif defined(USE_MBEDTLS)
+ &Curl_ssl_mbedtls;
+#elif defined(USE_NSS)
+ &Curl_ssl_nss;
+#elif defined(USE_OPENSSL)
+ &Curl_ssl_openssl;
+#elif defined(USE_POLARSSL)
+ &Curl_ssl_polarssl;
+#elif defined(USE_SCHANNEL)
+ &Curl_ssl_schannel;
#else
- return FALSE;
+#error "Missing struct Curl_ssl for selected SSL backend"
+#endif
+
+static const struct Curl_ssl *available_backends[] = {
+#if defined(USE_AXTLS)
+ &Curl_ssl_axtls,
+#endif
+#if defined(USE_CYASSL)
+ &Curl_ssl_cyassl,
+#endif
+#if defined(USE_DARWINSSL)
+ &Curl_ssl_darwinssl,
#endif
+#if defined(USE_GNUTLS)
+ &Curl_ssl_gnutls,
+#endif
+#if defined(USE_GSKIT)
+ &Curl_ssl_gskit,
+#endif
+#if defined(USE_MBEDTLS)
+ &Curl_ssl_mbedtls,
+#endif
+#if defined(USE_NSS)
+ &Curl_ssl_nss,
+#endif
+#if defined(USE_OPENSSL)
+ &Curl_ssl_openssl,
+#endif
+#if defined(USE_POLARSSL)
+ &Curl_ssl_polarssl,
+#endif
+#if defined(USE_SCHANNEL)
+ &Curl_ssl_schannel,
+#endif
+ NULL
+};
+
+static size_t Curl_multissl_version(char *buffer, size_t size)
+{
+ static const struct Curl_ssl *selected;
+ static char backends[200];
+ static size_t total;
+ const struct Curl_ssl *current;
+
+ current = Curl_ssl == &Curl_ssl_multi ? available_backends[0] : Curl_ssl;
+
+ if(current != selected) {
+ char *p = backends;
+ int i;
+
+ selected = current;
+
+ for(i = 0; available_backends[i]; i++) {
+ if(i)
+ *(p++) = ' ';
+ if(selected != available_backends[i])
+ *(p++) = '(';
+ p += available_backends[i]->version(p, backends + sizeof(backends) - p);
+ if(selected != available_backends[i])
+ *(p++) = ')';
+ }
+ *p = '\0';
+ total = p - backends;
+ }
+
+ if(size < total)
+ memcpy(buffer, backends, total + 1);
+ else {
+ memcpy(buffer, backends, size - 1);
+ buffer[size - 1] = '\0';
+ }
+
+ return total;
}
-/*
- * Check whether the SSL backend supports false start.
- */
-bool Curl_ssl_false_start(void)
+static int multissl_init(const struct Curl_ssl *backend)
{
-#ifdef curlssl_false_start
- return curlssl_false_start();
-#else
- return FALSE;
+ const char *env;
+ int i;
+
+ if(Curl_ssl != &Curl_ssl_multi)
+ return 1;
+
+ if(backend) {
+ Curl_ssl = backend;
+ return 0;
+ }
+
+ if(!available_backends[0])
+ return 1;
+
+ env = getenv("CURL_SSL_BACKEND");
+#ifdef CURL_DEFAULT_SSL_BACKEND
+ if(!env)
+ env = CURL_DEFAULT_SSL_BACKEND;
#endif
+ if(env) {
+ for(i = 0; available_backends[i]; i++) {
+ if(strcasecompare(env, available_backends[i]->info.name)) {
+ Curl_ssl = available_backends[i];
+ return 0;
+ }
+ }
+ }
+
+ /* Fall back to first available backend */
+ Curl_ssl = available_backends[0];
+ return 0;
+}
+
+CURLsslset curl_global_sslset(curl_sslbackend id, const char *name,
+ const curl_ssl_backend ***avail)
+{
+ int i;
+
+ if(Curl_ssl != &Curl_ssl_multi)
+ return id == Curl_ssl->info.id ? CURLSSLSET_OK : CURLSSLSET_TOO_LATE;
+
+ for(i = 0; available_backends[i]; i++) {
+ if(available_backends[i]->info.id == id ||
+ (name && strcasecompare(available_backends[i]->info.name, name))) {
+ multissl_init(available_backends[i]);
+ return CURLSSLSET_OK;
+ }
+ }
+
+ if(avail)
+ *avail = (const curl_ssl_backend **)&available_backends;
+ return CURLSSLSET_UNKNOWN_BACKEND;
+}
+
+#else /* USE_SSL */
+CURLsslset curl_global_sslset(curl_sslbackend id, const char *name,
+ const curl_ssl_backend ***avail)
+{
+ (void)id;
+ (void)name;
+ (void)avail;
+ return CURLSSLSET_NO_BACKENDS;
}
-#endif /* USE_SSL */
+#endif /* !USE_SSL */
diff --git a/lib/vtls/vtls.h b/lib/vtls/vtls.h
index 2aabeda2..c5f9d4a3 100644
--- a/lib/vtls/vtls.h
+++ b/lib/vtls/vtls.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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,6 +23,80 @@
***************************************************************************/
#include "curl_setup.h"
+struct connectdata;
+struct ssl_connect_data;
+
+struct Curl_ssl {
+ /*
+ * This *must* be the first entry to allow returning the list of available
+ * backends in curl_global_sslset().
+ */
+ curl_ssl_backend info;
+
+ unsigned have_ca_path:1; /* supports CAPATH */
+ unsigned have_certinfo:1; /* supports CURLOPT_CERTINFO */
+ unsigned have_pinnedpubkey:1; /* supports CURLOPT_PINNEDPUBLICKEY */
+ unsigned have_ssl_ctx:1; /* supports CURLOPT_SSL_CTX_* */
+
+ unsigned support_https_proxy:1; /* supports access via HTTPS proxies */
+
+ size_t sizeof_ssl_backend_data;
+
+ int (*init)(void);
+ void (*cleanup)(void);
+
+ size_t (*version)(char *buffer, size_t size);
+ int (*check_cxn)(struct connectdata *cxn);
+ int (*shutdown)(struct connectdata *conn, int sockindex);
+ bool (*data_pending)(const struct connectdata *conn,
+ int connindex);
+
+ /* return 0 if a find random is filled in */
+ CURLcode (*random)(struct Curl_easy *data, unsigned char *entropy,
+ size_t length);
+ bool (*cert_status_request)(void);
+
+ CURLcode (*connect)(struct connectdata *conn, int sockindex);
+ CURLcode (*connect_nonblocking)(struct connectdata *conn, int sockindex,
+ bool *done);
+ void *(*get_internals)(struct ssl_connect_data *connssl, CURLINFO info);
+ void (*close_one)(struct connectdata *conn, int sockindex);
+ void (*close_all)(struct Curl_easy *data);
+ void (*session_free)(void *ptr);
+
+ CURLcode (*set_engine)(struct Curl_easy *data, const char *engine);
+ CURLcode (*set_engine_default)(struct Curl_easy *data);
+ struct curl_slist *(*engines_list)(struct Curl_easy *data);
+
+ bool (*false_start)(void);
+
+ CURLcode (*md5sum)(unsigned char *input, size_t inputlen,
+ unsigned char *md5sum, size_t md5sumlen);
+ void (*sha256sum)(const unsigned char *input, size_t inputlen,
+ unsigned char *sha256sum, size_t sha256sumlen);
+};
+
+#ifdef USE_SSL
+extern const struct Curl_ssl *Curl_ssl;
+#endif
+
+int Curl_none_init(void);
+void Curl_none_cleanup(void);
+int Curl_none_shutdown(struct connectdata *conn, int sockindex);
+int Curl_none_check_cxn(struct connectdata *conn);
+CURLcode Curl_none_random(struct Curl_easy *data, unsigned char *entropy,
+ size_t length);
+void Curl_none_close_all(struct Curl_easy *data);
+void Curl_none_session_free(void *ptr);
+bool Curl_none_data_pending(const struct connectdata *conn, int connindex);
+bool Curl_none_cert_status_request(void);
+CURLcode Curl_none_set_engine(struct Curl_easy *data, const char *engine);
+CURLcode Curl_none_set_engine_default(struct Curl_easy *data);
+struct curl_slist *Curl_none_engines_list(struct Curl_easy *data);
+bool Curl_none_false_start(void);
+CURLcode Curl_none_md5sum(unsigned char *input, size_t inputlen,
+ unsigned char *md5sum, size_t md5len);
+
#include "openssl.h" /* OpenSSL versions */
#include "gtls.h" /* GnuTLS versions */
#include "nssg.h" /* NSS versions */
@@ -42,8 +116,8 @@
#define MD5_DIGEST_LENGTH 16 /* fixed size */
#endif
-#ifndef SHA256_DIGEST_LENGTH
-#define SHA256_DIGEST_LENGTH 32 /* fixed size */
+#ifndef CURL_SHA256_DIGEST_LENGTH
+#define CURL_SHA256_DIGEST_LENGTH 32 /* fixed size */
#endif
/* see https://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg-04 */
@@ -172,8 +246,6 @@ bool Curl_ssl_false_start(void);
#define SSL_SHUTDOWN_TIMEOUT 10000 /* ms */
#else
-/* Set the API backend definition to none */
-#define CURL_SSL_BACKEND CURLSSLBACKEND_NONE
/* When SSL support is not present, just define away these function calls */
#define Curl_ssl_init() 1
diff --git a/lib/warnless.c b/lib/warnless.c
index fb085c86..05d9038d 100644
--- a/lib/warnless.c
+++ b/lib/warnless.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, 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
@@ -69,36 +69,36 @@
# error "SIZEOF_INT not defined"
#endif
-#if (CURL_SIZEOF_LONG == 2)
+#if (SIZEOF_LONG == 2)
# define CURL_MASK_SLONG 0x7FFFL
# define CURL_MASK_ULONG 0xFFFFUL
-#elif (CURL_SIZEOF_LONG == 4)
+#elif (SIZEOF_LONG == 4)
# define CURL_MASK_SLONG 0x7FFFFFFFL
# define CURL_MASK_ULONG 0xFFFFFFFFUL
-#elif (CURL_SIZEOF_LONG == 8)
+#elif (SIZEOF_LONG == 8)
# define CURL_MASK_SLONG 0x7FFFFFFFFFFFFFFFL
# define CURL_MASK_ULONG 0xFFFFFFFFFFFFFFFFUL
-#elif (CURL_SIZEOF_LONG == 16)
+#elif (SIZEOF_LONG == 16)
# define CURL_MASK_SLONG 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFL
# define CURL_MASK_ULONG 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFUL
#else
-# error "CURL_SIZEOF_LONG not defined"
+# error "SIZEOF_LONG not defined"
#endif
-#if (CURL_SIZEOF_CURL_OFF_T == 2)
+#if (SIZEOF_CURL_OFF_T == 2)
# define CURL_MASK_SCOFFT CURL_OFF_T_C(0x7FFF)
# define CURL_MASK_UCOFFT CURL_OFF_TU_C(0xFFFF)
-#elif (CURL_SIZEOF_CURL_OFF_T == 4)
+#elif (SIZEOF_CURL_OFF_T == 4)
# define CURL_MASK_SCOFFT CURL_OFF_T_C(0x7FFFFFFF)
# define CURL_MASK_UCOFFT CURL_OFF_TU_C(0xFFFFFFFF)
-#elif (CURL_SIZEOF_CURL_OFF_T == 8)
+#elif (SIZEOF_CURL_OFF_T == 8)
# define CURL_MASK_SCOFFT CURL_OFF_T_C(0x7FFFFFFFFFFFFFFF)
# define CURL_MASK_UCOFFT CURL_OFF_TU_C(0xFFFFFFFFFFFFFFFF)
-#elif (CURL_SIZEOF_CURL_OFF_T == 16)
+#elif (SIZEOF_CURL_OFF_T == 16)
# define CURL_MASK_SCOFFT CURL_OFF_T_C(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
# define CURL_MASK_UCOFFT CURL_OFF_TU_C(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
#else
-# error "CURL_SIZEOF_CURL_OFF_T not defined"
+# error "SIZEOF_CURL_OFF_T not defined"
#endif
#if (SIZEOF_SIZE_T == SIZEOF_SHORT)
@@ -107,10 +107,10 @@
#elif (SIZEOF_SIZE_T == SIZEOF_INT)
# define CURL_MASK_SSIZE_T CURL_MASK_SINT
# define CURL_MASK_USIZE_T CURL_MASK_UINT
-#elif (SIZEOF_SIZE_T == CURL_SIZEOF_LONG)
+#elif (SIZEOF_SIZE_T == SIZEOF_LONG)
# define CURL_MASK_SSIZE_T CURL_MASK_SLONG
# define CURL_MASK_USIZE_T CURL_MASK_ULONG
-#elif (SIZEOF_SIZE_T == CURL_SIZEOF_CURL_OFF_T)
+#elif (SIZEOF_SIZE_T == SIZEOF_CURL_OFF_T)
# define CURL_MASK_SSIZE_T CURL_MASK_SCOFFT
# define CURL_MASK_USIZE_T CURL_MASK_UCOFFT
#else
@@ -226,7 +226,7 @@ unsigned long curlx_uztoul(size_t uznum)
# pragma warning(disable:810) /* conversion may lose significant bits */
#endif
-#if (CURL_SIZEOF_LONG < SIZEOF_SIZE_T)
+#if (SIZEOF_LONG < SIZEOF_SIZE_T)
DEBUGASSERT(uznum <= (size_t) CURL_MASK_ULONG);
#endif
return (unsigned long)(uznum & (size_t) CURL_MASK_ULONG);
@@ -269,7 +269,7 @@ int curlx_sltosi(long slnum)
#endif
DEBUGASSERT(slnum >= 0);
-#if (SIZEOF_INT < CURL_SIZEOF_LONG)
+#if (SIZEOF_INT < SIZEOF_LONG)
DEBUGASSERT((unsigned long) slnum <= (unsigned long) CURL_MASK_SINT);
#endif
return (int)(slnum & (long) CURL_MASK_SINT);
@@ -291,7 +291,7 @@ unsigned int curlx_sltoui(long slnum)
#endif
DEBUGASSERT(slnum >= 0);
-#if (SIZEOF_INT < CURL_SIZEOF_LONG)
+#if (SIZEOF_INT < SIZEOF_LONG)
DEBUGASSERT((unsigned long) slnum <= (unsigned long) CURL_MASK_UINT);
#endif
return (unsigned int)(slnum & (long) CURL_MASK_UINT);