aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorElliott Hughes <enh@google.com>2018-12-12 14:22:48 -0800
committerTao Bao <tbao@google.com>2018-12-12 17:16:20 -0800
commita93fb051349a5907b547a8f41c23a4b45bc82c0e (patch)
tree15ffc0718b7d289dc407c0d3851234b7f71286b0 /lib
parent849332cb73701636b19b97f3d82e8e9fa0d51a30 (diff)
downloadexternal_curl-a93fb051349a5907b547a8f41c23a4b45bc82c0e.tar.gz
external_curl-a93fb051349a5907b547a8f41c23a4b45bc82c0e.tar.bz2
external_curl-a93fb051349a5907b547a8f41c23a4b45bc82c0e.zip
Update to curl 7.62.0 - October 31 2018.
Bug: N/A Test: builds, boots, `vendor/google/tools/fake-ota on streaming` works Change-Id: If5e3aa0ced1b9d13cc4f2217f381ab9df8d16dcc
Diffstat (limited to 'lib')
-rw-r--r--lib/CMakeLists.txt18
-rw-r--r--lib/Makefile.Watcom1
-rw-r--r--lib/Makefile.am22
-rw-r--r--lib/Makefile.inc9
-rw-r--r--lib/Makefile.m3264
-rw-r--r--lib/Makefile.netware255
-rw-r--r--lib/amigaos.h1
-rw-r--r--lib/arpa_telnet.h6
-rwxr-xr-xlib/checksrc.pl37
-rw-r--r--lib/config-dos.h1
-rw-r--r--lib/config-vxworks.h3
-rw-r--r--lib/config-win32.h1
-rw-r--r--lib/cookie.c26
-rw-r--r--lib/curl_config.h24
-rw-r--r--lib/curl_config.h.cmake6
-rw-r--r--lib/curl_config.h.in6
-rw-r--r--lib/curl_ldap.h1
-rw-r--r--lib/curl_ntlm_wb.c18
-rw-r--r--lib/curl_path.c4
-rw-r--r--lib/curl_path.h2
-rw-r--r--lib/curl_rtmp.c4
-rw-r--r--lib/curl_setup.h5
-rw-r--r--lib/curl_setup_once.h1
-rw-r--r--lib/curl_sspi.c7
-rw-r--r--lib/curl_threads.c14
-rw-r--r--lib/curl_threads.h3
-rw-r--r--lib/curlx.h1
-rw-r--r--lib/dict.c2
-rw-r--r--lib/doh.c920
-rw-r--r--lib/doh.h105
-rw-r--r--lib/dotdot.c2
-rw-r--r--lib/dotdot.h2
-rw-r--r--lib/easy.c23
-rw-r--r--lib/easyif.h1
-rw-r--r--lib/escape.c20
-rw-r--r--lib/escape.h4
-rw-r--r--lib/file.c33
-rw-r--r--lib/file.h1
-rw-r--r--lib/firefox-db2pem.sh1
-rw-r--r--lib/ftp.c46
-rw-r--r--lib/ftp.h2
-rw-r--r--lib/getinfo.c1
-rw-r--r--lib/gopher.c2
-rw-r--r--lib/hostasyn.c25
-rw-r--r--lib/hostcheck.h1
-rw-r--r--lib/hostip.c78
-rw-r--r--lib/hostip.h13
-rw-r--r--lib/http.c245
-rw-r--r--lib/http.h19
-rw-r--r--lib/http2.c135
-rw-r--r--lib/http2.h1
-rw-r--r--lib/http_chunks.h1
-rw-r--r--lib/http_proxy.c14
-rw-r--r--lib/imap.c84
-rw-r--r--lib/imap.h1
-rw-r--r--lib/inet_ntop.h1
-rw-r--r--lib/inet_pton.h1
-rw-r--r--lib/krb5.c6
-rw-r--r--lib/ldap.c18
-rw-r--r--lib/libcurl.plist6
-rw-r--r--lib/llist.h1
-rw-r--r--lib/makefile.amiga8
-rw-r--r--lib/makefile.dj1
-rw-r--r--lib/md4.c2
-rw-r--r--lib/md5.c2
-rw-r--r--lib/multi.c77
-rw-r--r--lib/netrc.c48
-rw-r--r--lib/nonblock.c3
-rw-r--r--lib/nonblock.h1
-rw-r--r--lib/nwlib.c7
-rw-r--r--lib/parsedate.h1
-rw-r--r--lib/pop3.c5
-rw-r--r--lib/progress.h1
-rw-r--r--lib/rand.c4
-rw-r--r--lib/rtsp.c27
-rw-r--r--lib/rtsp.h1
-rw-r--r--lib/security.c6
-rw-r--r--lib/select.h1
-rw-r--r--lib/sendf.h2
-rw-r--r--lib/setopt.c31
-rw-r--r--lib/slist.c1
-rw-r--r--lib/slist.h1
-rw-r--r--lib/smb.c5
-rw-r--r--lib/smtp.c9
-rw-r--r--lib/sockaddr.h1
-rw-r--r--lib/socks.c3
-rw-r--r--lib/socks.h1
-rw-r--r--lib/splay.c1
-rw-r--r--lib/ssh.c2
-rw-r--r--lib/strdup.c2
-rw-r--r--lib/strerror.c9
-rw-r--r--lib/telnet.h1
-rw-r--r--lib/tftp.c4
-rw-r--r--lib/tftp.h1
-rw-r--r--lib/timeval.c23
-rw-r--r--lib/transfer.c368
-rw-r--r--lib/transfer.h1
-rw-r--r--lib/url.c1096
-rw-r--r--lib/url.h25
-rw-r--r--lib/urlapi-int.h33
-rw-r--r--lib/urlapi.c1340
-rw-r--r--lib/urldata.h83
-rw-r--r--lib/vauth/cleartext.c4
-rw-r--r--lib/vauth/cram.c2
-rw-r--r--lib/vauth/digest.c10
-rw-r--r--lib/vauth/digest_sspi.c4
-rw-r--r--lib/vauth/krb5_gssapi.c2
-rw-r--r--lib/vauth/krb5_sspi.c2
-rw-r--r--lib/vauth/ntlm.c4
-rw-r--r--lib/vauth/ntlm_sspi.c4
-rw-r--r--lib/vauth/spnego_gssapi.c2
-rw-r--r--lib/vauth/spnego_sspi.c4
-rw-r--r--lib/vtls/axtls.h1
-rw-r--r--lib/vtls/darwinssl.c429
-rw-r--r--lib/vtls/gskit.c5
-rw-r--r--lib/vtls/gtls.c91
-rw-r--r--lib/vtls/mbedtls.c3
-rw-r--r--lib/vtls/mesalink.c627
-rw-r--r--lib/vtls/mesalink.h32
-rw-r--r--lib/vtls/nss.c17
-rw-r--r--lib/vtls/openssl.c75
-rw-r--r--lib/vtls/polarssl.c3
-rw-r--r--lib/vtls/schannel.c105
-rw-r--r--lib/vtls/schannel.h2
-rw-r--r--lib/vtls/schannel_verify.c8
-rw-r--r--lib/vtls/vtls.c5
-rw-r--r--lib/vtls/vtls.h1
-rw-r--r--lib/x509asn1.c144
128 files changed, 5045 insertions, 2134 deletions
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 87cbe817..eca9a8af 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -105,23 +105,17 @@ if(WIN32)
endif()
target_include_directories(${LIB_NAME} INTERFACE
- $<INSTALL_INTERFACE:include>)
+ $<INSTALL_INTERFACE:include>
+ $<BUILD_INTERFACE:${CURL_SOURCE_DIR}/include>)
install(TARGETS ${LIB_NAME}
- EXPORT libcurl-target
- ARCHIVE DESTINATION lib
- LIBRARY DESTINATION lib
- RUNTIME DESTINATION bin
+ EXPORT ${TARGETS_EXPORT_NAME}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
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.Watcom b/lib/Makefile.Watcom
index 77e5a6e0..5f335ced 100644
--- a/lib/Makefile.Watcom
+++ b/lib/Makefile.Watcom
@@ -272,4 +272,3 @@ $(RESOURCE): libcurl.rc
.c{$(OBJ_STAT)}.obj:
$(CC) $(CFLAGS) -DCURL_STATICLIB $[@ -fo=$^@
-
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 7e82d467..a7b5262b 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -23,13 +23,13 @@ AUTOMAKE_OPTIONS = foreign nostdinc
CMAKE_DIST = CMakeLists.txt curl_config.h.cmake
-EXTRA_DIST = Makefile.m32 config-win32.h \
- config-win32ce.h config-riscos.h config-mac.h curl_config.h.in \
- makefile.dj config-dos.h libcurl.plist libcurl.rc config-amigaos.h \
- makefile.amiga Makefile.netware nwlib.c nwos.c config-win32ce.h \
- config-os400.h setup-os400.h config-symbian.h Makefile.Watcom \
- config-tpf.h mk-ca-bundle.pl mk-ca-bundle.vbs $(CMAKE_DIST) \
- firefox-db2pem.sh config-vxworks.h Makefile.vxworks checksrc.pl \
+EXTRA_DIST = Makefile.m32 config-win32.h \
+ config-win32ce.h config-riscos.h config-mac.h curl_config.h.in \
+ makefile.dj config-dos.h libcurl.plist libcurl.rc config-amigaos.h \
+ makefile.amiga Makefile.netware nwlib.c nwos.c config-win32ce.h \
+ config-os400.h setup-os400.h config-symbian.h Makefile.Watcom \
+ config-tpf.h mk-ca-bundle.pl mk-ca-bundle.vbs $(CMAKE_DIST) \
+ firefox-db2pem.sh config-vxworks.h Makefile.vxworks checksrc.pl \
objnames-test08.sh objnames-test10.sh objnames.inc
lib_LTLIBRARIES = libcurl.la
@@ -144,3 +144,11 @@ if CURLDEBUG
# for debug builds, we scan the sources on all regular make invokes
all-local: checksrc
endif
+
+# disable the tests that are mostly causing false positives
+TIDYFLAGS=-checks=-clang-analyzer-security.insecureAPI.strcpy,-clang-analyzer-optin.performance.Padding,-clang-analyzer-valist.Uninitialized,-clang-analyzer-core.NonNullParamChecker,-clang-analyzer-core.NullDereference -quiet
+
+TIDY:=clang-tidy
+
+tidy:
+ $(TIDY) $(CSOURCES) $(TIDYFLAGS) -- $(AM_CPPFLAGS) $(CPPFLAGS) -DHAVE_CONFIG_H
diff --git a/lib/Makefile.inc b/lib/Makefile.inc
index 76ca6d04..4aa04225 100644
--- a/lib/Makefile.inc
+++ b/lib/Makefile.inc
@@ -30,12 +30,12 @@ LIB_VAUTH_HFILES = vauth/vauth.h vauth/digest.h vauth/ntlm.h
LIB_VTLS_CFILES = vtls/openssl.c vtls/gtls.c vtls/vtls.c vtls/nss.c \
vtls/polarssl.c vtls/polarssl_threadlock.c vtls/axtls.c \
vtls/cyassl.c vtls/schannel.c vtls/schannel_verify.c \
- vtls/darwinssl.c vtls/gskit.c vtls/mbedtls.c
+ vtls/darwinssl.c vtls/gskit.c vtls/mbedtls.c vtls/mesalink.c
LIB_VTLS_HFILES = vtls/openssl.h vtls/vtls.h vtls/gtls.h \
vtls/nssg.h vtls/polarssl.h vtls/polarssl_threadlock.h vtls/axtls.h \
vtls/cyassl.h vtls/schannel.h vtls/darwinssl.h vtls/gskit.h \
- vtls/mbedtls.h
+ vtls/mbedtls.h vtls/mesalink.h
LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \
cookie.c http.c sendf.c ftp.c url.c dict.c if2ip.c speedcheck.c \
@@ -54,7 +54,8 @@ LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.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 \
- mime.c sha256.c setopt.c curl_path.c curl_ctype.c curl_range.c psl.c
+ mime.c sha256.c setopt.c curl_path.c curl_ctype.c curl_range.c psl.c \
+ doh.c urlapi.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 \
@@ -74,7 +75,7 @@ LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.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 mime.h curl_sha256.h setopt.h \
- curl_path.h curl_ctype.h curl_range.h psl.h
+ curl_path.h curl_ctype.h curl_range.h psl.h doh.h urlapi-int.h
LIB_RCFILES = libcurl.rc
diff --git a/lib/Makefile.m32 b/lib/Makefile.m32
index 773187ad..ae88f4dc 100644
--- a/lib/Makefile.m32
+++ b/lib/Makefile.m32
@@ -91,23 +91,23 @@ ifeq ($(CURL_RANLIB),)
CURL_RANLIB := $(CROSSPREFIX)ranlib
endif
-CC = $(CURL_CC)
-CFLAGS = $(CURL_CFLAG_EXTRAS) -g -O2 -Wall -W
-CFLAGS += -fno-strict-aliasing
+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 = $(CURL_AR)
-RANLIB = $(CURL_RANLIB)
-RC = $(CROSSPREFIX)windres
-RCFLAGS = --include-dir=$(PROOT)/include -DDEBUGBUILD=0 -O COFF
-STRIP = $(CROSSPREFIX)strip -g
+LDFLAGS = $(CURL_LDFLAG_EXTRAS) $(CURL_LDFLAG_EXTRAS_DLL) -s
+AR = $(CURL_AR)
+RANLIB = $(CURL_RANLIB)
+RC = $(CROSSPREFIX)windres
+RCFLAGS = --include-dir=$(PROOT)/include -DDEBUGBUILD=0 -O COFF
+STRIP = $(CROSSPREFIX)strip -g
# Set environment var ARCH to your architecture to override autodetection.
ifndef ARCH
ifeq ($(findstring x86_64,$(shell $(CC) -dumpmachine)),x86_64)
-ARCH = w64
+ARCH = w64
else
-ARCH = w32
+ARCH = w32
endif
endif
@@ -123,30 +123,30 @@ endif
# Platform-dependent helper tool macros
ifeq ($(findstring /sh,$(SHELL)),/sh)
-DEL = rm -f $1
-RMDIR = rm -fr $1
-MKDIR = mkdir -p $1
-COPY = -cp -afv $1 $2
-#COPYR = -cp -afr $1/* $2
-COPYR = -rsync -aC $1/* $2
-TOUCH = touch $1
-CAT = cat
-ECHONL = echo ""
-DL = '
+DEL = rm -f $1
+RMDIR = rm -fr $1
+MKDIR = mkdir -p $1
+COPY = -cp -afv $1 $2
+#COPYR = -cp -afr $1/* $2
+COPYR = -rsync -aC $1/* $2
+TOUCH = touch $1
+CAT = cat
+ECHONL = echo ""
+DL = '
else
ifeq "$(OS)" "Windows_NT"
-DEL = -del 2>NUL /q /f $(subst /,\,$1)
-RMDIR = -rd 2>NUL /q /s $(subst /,\,$1)
+DEL = -del 2>NUL /q /f $(subst /,\,$1)
+RMDIR = -rd 2>NUL /q /s $(subst /,\,$1)
else
-DEL = -del 2>NUL $(subst /,\,$1)
-RMDIR = -deltree 2>NUL /y $(subst /,\,$1)
-endif
-MKDIR = -md 2>NUL $(subst /,\,$1)
-COPY = -copy 2>NUL /y $(subst /,\,$1) $(subst /,\,$2)
-COPYR = -xcopy 2>NUL /q /y /e $(subst /,\,$1) $(subst /,\,$2)
-TOUCH = copy 2>&1>NUL /b $(subst /,\,$1) +,,
-CAT = type
-ECHONL = $(ComSpec) /c echo.
+DEL = -del 2>NUL $(subst /,\,$1)
+RMDIR = -deltree 2>NUL /y $(subst /,\,$1)
+endif
+MKDIR = -md 2>NUL $(subst /,\,$1)
+COPY = -copy 2>NUL /y $(subst /,\,$1) $(subst /,\,$2)
+COPYR = -xcopy 2>NUL /q /y /e $(subst /,\,$1) $(subst /,\,$2)
+TOUCH = copy 2>&1>NUL /b $(subst /,\,$1) +,,
+CAT = type
+ECHONL = $(ComSpec) /c echo.
endif
########################################################
diff --git a/lib/Makefile.netware b/lib/Makefile.netware
index 2b392f3f..fa6beec0 100644
--- a/lib/Makefile.netware
+++ b/lib/Makefile.netware
@@ -5,7 +5,7 @@
# | (__| |_| | _ <| |___
# \___|\___/|_| \_\_____|
#
-# Copyright (C) 2004 - 2015, Guenter Knauf, <http://www.gknw.net/phpbb>.
+# Copyright (C) 2004 - 2015, Guenter Knauf
# Copyright (C) 2001 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
#
# This software is licensed as described in the file COPYING, which
@@ -31,7 +31,7 @@
# Edit the path below to point to the base of your Novell NDK.
ifndef NDKBASE
-NDKBASE = c:/novell
+NDKBASE = c:/novell
endif
# Edit the path below to point to the base of your Zlib sources.
@@ -80,19 +80,19 @@ LIBCARES_PATH = ../ares
endif
ifndef INSTDIR
-INSTDIR = ..$(DS)curl-$(LIBCURL_VERSION_STR)-bin-nw
+INSTDIR = ..$(DS)curl-$(LIBCURL_VERSION_STR)-bin-nw
endif
# Edit the vars below to change NLM target settings.
TARGET = libcurl
-VERSION = $(LIBCURL_VERSION)
-COPYR = Copyright (C) $(LIBCURL_COPYRIGHT_STR)
-DESCR = curl libcurl $(LIBCURL_VERSION_STR) ($(LIBARCH)) - https://curl.haxx.se
-MTSAFE = YES
-STACK = 64000
-SCREEN = none
-EXPORTF = $(TARGET).imp
-EXPORTS = @$(EXPORTF)
+VERSION = $(LIBCURL_VERSION)
+COPYR = Copyright (C) $(LIBCURL_COPYRIGHT_STR)
+DESCR = curl libcurl $(LIBCURL_VERSION_STR) ($(LIBARCH)) - https://curl.haxx.se
+MTSAFE = YES
+STACK = 64000
+SCREEN = none
+EXPORTF = $(TARGET).imp
+EXPORTS = @$(EXPORTF)
# Uncomment the next line to enable linking with POSIX semantics.
# POSIXFL = 1
@@ -104,39 +104,39 @@ endif
# must be equal to NDEBUG or DEBUG, CURLDEBUG
ifndef DB
-DB = NDEBUG
+DB = NDEBUG
endif
# Optimization: -O<n> or debugging: -g
ifeq ($(DB),NDEBUG)
- OPT = -O2
- OBJDIR = release
+ OPT = -O2
+ OBJDIR = release
else
- OPT = -g
- OBJDIR = debug
+ OPT = -g
+ OBJDIR = debug
endif
# The following lines defines your compiler.
ifdef CWFolder
- METROWERKS = $(CWFolder)
+ METROWERKS = $(CWFolder)
endif
ifdef METROWERKS
- # MWCW_PATH = $(subst \,/,$(METROWERKS))/Novell Support
- MWCW_PATH = $(subst \,/,$(METROWERKS))/Novell Support/Metrowerks Support
- CC = mwccnlm
+ # MWCW_PATH = $(subst \,/,$(METROWERKS))/Novell Support
+ MWCW_PATH = $(subst \,/,$(METROWERKS))/Novell Support/Metrowerks Support
+ CC = mwccnlm
else
- CC = gcc
+ CC = gcc
endif
-PERL = perl
+PERL = perl
# Here you can find a native Win32 binary of the original awk:
# http://www.gknw.net/development/prgtools/awk-20100523.zip
-AWK = awk
-CP = cp -afv
-MKDIR = mkdir
-# RM = rm -f
+AWK = awk
+CP = cp -afv
+MKDIR = mkdir
+# RM = rm -f
# If you want to mark the target as MTSAFE you will need a tool for
# generating the xdc data for the linker; here's a minimal tool:
# http://www.gknw.net/development/prgtools/mkxdc.zip
-MPKXDC = mkxdc
+MPKXDC = mkxdc
# LIBARCH_U = $(shell $(AWK) 'BEGIN {print toupper(ARGV[1])}' $(LIBARCH))
LIBARCH_L = $(shell $(AWK) 'BEGIN {print tolower(ARGV[1])}' $(LIBARCH))
@@ -145,58 +145,58 @@ LIBARCH_L = $(shell $(AWK) 'BEGIN {print tolower(ARGV[1])}' $(LIBARCH))
-include $(OBJDIR)/version.inc
# Global flags for all compilers
-CFLAGS += $(OPT) -D$(DB) -DNETWARE -DHAVE_CONFIG_H -nostdinc
+CFLAGS += $(OPT) -D$(DB) -DNETWARE -DHAVE_CONFIG_H -nostdinc
ifeq ($(CC),mwccnlm)
-LD = mwldnlm
-LDFLAGS = -nostdlib $(PRELUDE) $(OBJL) -o $@ -commandfile
-AR = mwldnlm
-ARFLAGS = -nostdlib -type library -o
-LIBEXT = lib
-#RANLIB =
-CFLAGS += -msgstyle gcc -gccinc -inline off -opt nointrinsics -proc 586
-CFLAGS += -relax_pointers
-#CFLAGS += -w on
-ifeq ($(LIBARCH),LIBC)
-ifeq ($(POSIXFL),1)
- PRELUDE = $(NDK_LIBC)/imports/posixpre.o
-else
- PRELUDE = $(NDK_LIBC)/imports/libcpre.o
-endif
- CFLAGS += -align 4
-else
- # PRELUDE = $(NDK_CLIB)/imports/clibpre.o
- # to avoid the __init_* / __deinit_* woes don't use prelude from NDK
- PRELUDE = "$(MWCW_PATH)/libraries/runtime/prelude.obj"
- # CFLAGS += -include "$(MWCW_PATH)/headers/nlm_clib_prefix.h"
- CFLAGS += -align 1
-endif
+ LD = mwldnlm
+ LDFLAGS = -nostdlib $(PRELUDE) $(OBJL) -o $@ -commandfile
+ AR = mwldnlm
+ ARFLAGS = -nostdlib -type library -o
+ LIBEXT = lib
+ #RANLIB =
+ CFLAGS += -msgstyle gcc -gccinc -inline off -opt nointrinsics -proc 586
+ CFLAGS += -relax_pointers
+ #CFLAGS += -w on
+ ifeq ($(LIBARCH),LIBC)
+ ifeq ($(POSIXFL),1)
+ PRELUDE = $(NDK_LIBC)/imports/posixpre.o
+ else
+ PRELUDE = $(NDK_LIBC)/imports/libcpre.o
+ endif
+ CFLAGS += -align 4
+ else
+ # PRELUDE = $(NDK_CLIB)/imports/clibpre.o
+ # to avoid the __init_* / __deinit_* woes don't use prelude from NDK
+ PRELUDE = "$(MWCW_PATH)/libraries/runtime/prelude.obj"
+ # CFLAGS += -include "$(MWCW_PATH)/headers/nlm_clib_prefix.h"
+ CFLAGS += -align 1
+ endif
else
-LD = nlmconv
-LDFLAGS = -T
-AR = ar
-ARFLAGS = -cq
-LIBEXT = a
-RANLIB = ranlib
-CFLAGS += -m32
-CFLAGS += -fno-builtin -fno-strict-aliasing
-ifeq ($(findstring gcc,$(CC)),gcc)
-CFLAGS += -fpcc-struct-return
-endif
-CFLAGS += -Wall # -pedantic
-ifeq ($(LIBARCH),LIBC)
-ifeq ($(POSIXFL),1)
- PRELUDE = $(NDK_LIBC)/imports/posixpre.gcc.o
-else
- PRELUDE = $(NDK_LIBC)/imports/libcpre.gcc.o
-endif
-else
- PRELUDE = $(NDK_CLIB)/imports/clibpre.gcc.o
- # to avoid the __init_* / __deinit_* woes don't use prelude from NDK
- # http://www.gknw.net/development/mk_nlm/gcc_pre.zip
- # PRELUDE = $(NDK_ROOT)/pre/prelude.o
- CFLAGS += -include $(NDKBASE)/nlmconv/genlm.h
-endif
+ LD = nlmconv
+ LDFLAGS = -T
+ AR = ar
+ ARFLAGS = -cq
+ LIBEXT = a
+ RANLIB = ranlib
+ CFLAGS += -m32
+ CFLAGS += -fno-builtin -fno-strict-aliasing
+ ifeq ($(findstring gcc,$(CC)),gcc)
+ CFLAGS += -fpcc-struct-return
+ endif
+ CFLAGS += -Wall # -pedantic
+ ifeq ($(LIBARCH),LIBC)
+ ifeq ($(POSIXFL),1)
+ PRELUDE = $(NDK_LIBC)/imports/posixpre.gcc.o
+ else
+ PRELUDE = $(NDK_LIBC)/imports/libcpre.gcc.o
+ endif
+ else
+ PRELUDE = $(NDK_CLIB)/imports/clibpre.gcc.o
+ # to avoid the __init_* / __deinit_* woes don't use prelude from NDK
+ # http://www.gknw.net/development/mk_nlm/gcc_pre.zip
+ # PRELUDE = $(NDK_ROOT)/pre/prelude.o
+ CFLAGS += -include $(NDKBASE)/nlmconv/genlm.h
+ endif
endif
NDK_ROOT = $(NDKBASE)/ndk
@@ -257,99 +257,99 @@ ENABLE_IPV6 = 1
endif
ifdef WITH_ARES
- INCLUDES += -I$(LIBCARES_PATH)
- LDLIBS += $(LIBCARES_PATH)/libcares.$(LIBEXT)
+ INCLUDES += -I$(LIBCARES_PATH)
+ LDLIBS += $(LIBCARES_PATH)/libcares.$(LIBEXT)
endif
ifdef WITH_SSH2
- INCLUDES += -I$(LIBSSH2_PATH)/include
+ INCLUDES += -I$(LIBSSH2_PATH)/include
ifdef LINK_STATIC
- LDLIBS += $(LIBSSH2_PATH)/nw/libssh2.$(LIBEXT)
+ LDLIBS += $(LIBSSH2_PATH)/nw/libssh2.$(LIBEXT)
else
- MODULES += libssh2.nlm
- IMPORTS += @$(LIBSSH2_PATH)/nw/libssh2.imp
+ MODULES += libssh2.nlm
+ IMPORTS += @$(LIBSSH2_PATH)/nw/libssh2.imp
endif
endif
ifdef WITH_RTMP
- INCLUDES += -I$(LIBRTMP_PATH)
- LDLIBS += $(LIBRTMP_PATH)/librtmp/librtmp.$(LIBEXT)
+ INCLUDES += -I$(LIBRTMP_PATH)
+ LDLIBS += $(LIBRTMP_PATH)/librtmp/librtmp.$(LIBEXT)
endif
ifdef WITH_SSL
- INCLUDES += -I$(OPENSSL_PATH)/outinc_nw_$(LIBARCH_L)
- LDLIBS += $(OPENSSL_PATH)/out_nw_$(LIBARCH_L)/ssl.$(LIBEXT)
- LDLIBS += $(OPENSSL_PATH)/out_nw_$(LIBARCH_L)/crypto.$(LIBEXT)
- IMPORTS += GetProcessSwitchCount RunningProcess
- INSTDEP += ca-bundle.crt
+ INCLUDES += -I$(OPENSSL_PATH)/outinc_nw_$(LIBARCH_L)
+ LDLIBS += $(OPENSSL_PATH)/out_nw_$(LIBARCH_L)/ssl.$(LIBEXT)
+ LDLIBS += $(OPENSSL_PATH)/out_nw_$(LIBARCH_L)/crypto.$(LIBEXT)
+ IMPORTS += GetProcessSwitchCount RunningProcess
+ INSTDEP += ca-bundle.crt
else
ifdef WITH_AXTLS
- INCLUDES += -I$(AXTLS_PATH)/inc
-ifdef LINK_STATIC
- LDLIBS += $(AXTLS_PATH)/lib/libaxtls.$(LIBEXT)
-else
- MODULES += libaxtls.nlm
- IMPORTS += $(AXTLS_PATH)/lib/libaxtls.imp
-endif
- INSTDEP += ca-bundle.crt
+ INCLUDES += -I$(AXTLS_PATH)/inc
+ ifdef LINK_STATIC
+ LDLIBS += $(AXTLS_PATH)/lib/libaxtls.$(LIBEXT)
+ else
+ MODULES += libaxtls.nlm
+ IMPORTS += $(AXTLS_PATH)/lib/libaxtls.imp
+ endif
+ INSTDEP += ca-bundle.crt
endif
endif
ifdef WITH_ZLIB
- INCLUDES += -I$(ZLIB_PATH)
-ifdef LINK_STATIC
- LDLIBS += $(ZLIB_PATH)/nw/$(LIBARCH)/libz.$(LIBEXT)
-else
- MODULES += libz.nlm
- IMPORTS += @$(ZLIB_PATH)/nw/$(LIBARCH)/libz.imp
-endif
+ INCLUDES += -I$(ZLIB_PATH)
+ ifdef LINK_STATIC
+ LDLIBS += $(ZLIB_PATH)/nw/$(LIBARCH)/libz.$(LIBEXT)
+ else
+ MODULES += libz.nlm
+ IMPORTS += @$(ZLIB_PATH)/nw/$(LIBARCH)/libz.imp
+ endif
endif
ifdef WITH_IDN
- INCLUDES += -I$(LIBIDN_PATH)/include
- LDLIBS += $(LIBIDN_PATH)/lib/libidn.$(LIBEXT)
+ INCLUDES += -I$(LIBIDN_PATH)/include
+ LDLIBS += $(LIBIDN_PATH)/lib/libidn.$(LIBEXT)
endif
ifdef WITH_NGHTTP2
- INCLUDES += -I$(NGHTTP2_PATH)/include
- LDLIBS += $(NGHTTP2_PATH)/lib/libnghttp2.$(LIBEXT)
+ INCLUDES += -I$(NGHTTP2_PATH)/include
+ LDLIBS += $(NGHTTP2_PATH)/lib/libnghttp2.$(LIBEXT)
endif
ifeq ($(LIBARCH),LIBC)
- INCLUDES += -I$(NDK_LIBC)/include
- # INCLUDES += -I$(NDK_LIBC)/include/nks
- # INCLUDES += -I$(NDK_LIBC)/include/winsock
- CFLAGS += -D_POSIX_SOURCE
+ INCLUDES += -I$(NDK_LIBC)/include
+ # INCLUDES += -I$(NDK_LIBC)/include/nks
+ # INCLUDES += -I$(NDK_LIBC)/include/winsock
+ CFLAGS += -D_POSIX_SOURCE
else
- INCLUDES += -I$(NDK_CLIB)/include/nlm
- # INCLUDES += -I$(NDK_CLIB)/include/nlm/obsolete
- # INCLUDES += -I$(NDK_CLIB)/include
+ INCLUDES += -I$(NDK_CLIB)/include/nlm
+ # INCLUDES += -I$(NDK_CLIB)/include/nlm/obsolete
+ # INCLUDES += -I$(NDK_CLIB)/include
endif
ifndef DISABLE_LDAP
- INCLUDES += -I$(NDK_LDAP)/$(LIBARCH_L)/inc
+ INCLUDES += -I$(NDK_LDAP)/$(LIBARCH_L)/inc
endif
-CFLAGS += $(INCLUDES)
+CFLAGS += $(INCLUDES)
ifeq ($(MTSAFE),YES)
- XDCOPT = -n
+ XDCOPT = -n
endif
ifeq ($(MTSAFE),NO)
- XDCOPT = -u
+ XDCOPT = -u
endif
ifdef XDCOPT
- XDCDATA = $(OBJDIR)/$(TARGET).xdc
+ XDCDATA = $(OBJDIR)/$(TARGET).xdc
endif
ifeq ($(findstring /sh,$(SHELL)),/sh)
-DL = '
-DS = /
-PCT = %
+DL = '
+DS = /
+PCT = %
#-include $(NDKBASE)/nlmconv/ncpfs.inc
else
-DS = \\
-PCT = %%
+DS = \\
+PCT = %%
endif
# Makefile.inc provides the CSOURCES and HHEADERS defines
include Makefile.inc
-OBJS := $(patsubst %.c,$(OBJDIR)/%.o,$(strip $(notdir $(CSOURCES)))) $(OBJDIR)/nwos.o
+OBJS := $(patsubst %.c,$(OBJDIR)/%.o,$(strip $(notdir $(CSOURCES)))) $(OBJDIR)/nwos.o
-OBJL = $(OBJS) $(OBJDIR)/nwlib.o $(LDLIBS)
+OBJL = $(OBJS) $(OBJDIR)/nwlib.o $(LDLIBS)
vpath %.c . vauth vtls
@@ -757,4 +757,3 @@ $(LIBCARES_PATH)/libcares.$(LIBEXT):
ca-bundle.crt: mk-ca-bundle.pl
@echo Creating $@
@-$(PERL) $< -b -n $@
-
diff --git a/lib/amigaos.h b/lib/amigaos.h
index 02bee161..7c0926cc 100644
--- a/lib/amigaos.h
+++ b/lib/amigaos.h
@@ -36,4 +36,3 @@ void Curl_amiga_cleanup();
#endif
#endif /* HEADER_CURL_AMIGAOS_H */
-
diff --git a/lib/arpa_telnet.h b/lib/arpa_telnet.h
index ec238729..232680e7 100644
--- a/lib/arpa_telnet.h
+++ b/lib/arpa_telnet.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2018, 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,6 +37,7 @@
#define CURL_NEW_ENV_VAR 0
#define CURL_NEW_ENV_VALUE 1
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
/*
* The telnet options represented as strings
*/
@@ -53,6 +54,7 @@ static const char * const telnetoptions[]=
"TERM SPEED", "LFLOW", "LINEMODE", "XDISPLOC",
"OLD-ENVIRON", "AUTHENTICATION", "ENCRYPT", "NEW-ENVIRON"
};
+#endif
#define CURL_TELOPT_MAXIMUM CURL_TELOPT_NEW_ENVIRON
@@ -76,6 +78,7 @@ static const char * const telnetoptions[]=
#define CURL_DONT 254 /* DON'T use this option! */
#define CURL_IAC 255 /* Interpret As Command */
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
/*
* Then those numbers represented as strings:
*/
@@ -86,6 +89,7 @@ static const char * const telnetcmds[]=
"AYT", "EC", "EL", "GA", "SB",
"WILL", "WONT", "DO", "DONT", "IAC"
};
+#endif
#define CURL_TELCMD_MINIMUM CURL_xEOF /* the first one */
#define CURL_TELCMD_MAXIMUM CURL_IAC /* surprise, 255 is the last one! ;-) */
diff --git a/lib/checksrc.pl b/lib/checksrc.pl
index daff07bf..15e9aff8 100755
--- a/lib/checksrc.pl
+++ b/lib/checksrc.pl
@@ -21,19 +21,29 @@
#
###########################################################################
+use strict;
+use warnings;
+
my $max_column = 79;
my $indent = 2;
-my $warnings;
-my $errors;
+my $warnings = 0;
+my $swarnings = 0;
+my $errors = 0;
+my $serrors = 0;
my $suppressed; # whitelisted problems
my $file;
my $dir=".";
-my $wlist;
+my $wlist="";
my $windows_os = $^O eq 'MSWin32' || $^O eq 'msys' || $^O eq 'cygwin';
my $verbose;
my %whitelist;
+my %ignore;
+my %ignore_set;
+my %ignore_used;
+my @ignore_line;
+
my %warnings = (
'LONGLINE' => "Line longer than $max_column",
'TABS' => 'TAB characters not allowed',
@@ -67,7 +77,7 @@ my %warnings = (
);
sub readwhitelist {
- open(W, "<$dir/checksrc.whitelist");
+ open(W, "<$dir/checksrc.whitelist") or return;
my @all=<W>;
for(@all) {
$windows_os ? $_ =~ s/\r?\n$// : chomp;
@@ -97,7 +107,7 @@ sub checkwarn {
$nowarn = 1;
if(!$ignore{$name}) {
# reached zero, enable again
- enable_warn($name, $line, $file, $l);
+ enable_warn($name, $num, $file, $line);
}
}
@@ -239,7 +249,16 @@ sub checksrc {
$scope=999999;
}
- if($ignore_set{$warn}) {
+ # Comparing for a literal zero rather than the scalar value zero
+ # covers the case where $scope contains the ending '*' from the
+ # comment. If we use a scalar comparison (==) we induce warnings
+ # on non-scalar contents.
+ if($scope eq "0") {
+ checkwarn("BADCOMMAND",
+ $line, 0, $file, $l,
+ "Disable zero not supported, did you mean to enable?");
+ }
+ elsif($ignore_set{$warn}) {
checkwarn("BADCOMMAND",
$line, 0, $file, $l,
"$warn already disabled from line $ignore_set{$warn}");
@@ -271,7 +290,7 @@ sub scanfile {
my ($file) = @_;
my $line = 1;
- my $prevl;
+ my $prevl="";
my $l;
open(R, "<$file") || die "failed to open $file";
@@ -359,10 +378,10 @@ sub scanfile {
if($1 =~ / *\#/) {
# this is a #if, treat it differently
}
- elsif($3 eq "return") {
+ elsif(defined $3 && $3 eq "return") {
# return must have a space
}
- elsif($3 eq "case") {
+ elsif(defined $3 && $3 eq "case") {
# case must have a space
}
elsif($4 eq "*") {
diff --git a/lib/config-dos.h b/lib/config-dos.h
index ff1ea155..3e973de0 100644
--- a/lib/config-dos.h
+++ b/lib/config-dos.h
@@ -181,4 +181,3 @@
#undef byte
#endif /* HEADER_CURL_CONFIG_DOS_H */
-
diff --git a/lib/config-vxworks.h b/lib/config-vxworks.h
index 19f2d235..a03e341e 100644
--- a/lib/config-vxworks.h
+++ b/lib/config-vxworks.h
@@ -847,9 +847,6 @@
/* The size of `time_t', as computed by sizeof. */
#define SIZEOF_TIME_T 4
-/* The size of `void*', as computed by sizeof. */
-#define SIZEOF_VOIDP 4
-
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
diff --git a/lib/config-win32.h b/lib/config-win32.h
index fdac6f9a..76b00b9b 100644
--- a/lib/config-win32.h
+++ b/lib/config-win32.h
@@ -691,6 +691,7 @@ Vista
#define HAVE_LDAP_URL_PARSE 1
#else
#undef HAVE_LDAP_URL_PARSE
+#define HAVE_LDAP_SSL 1
#define USE_WIN32_LDAP 1
#endif
diff --git a/lib/cookie.c b/lib/cookie.c
index fd7341f0..5b7ab663 100644
--- a/lib/cookie.c
+++ b/lib/cookie.c
@@ -1218,7 +1218,6 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
{
struct Cookie *newco;
struct Cookie *co;
- time_t now = time(NULL);
struct Cookie *mainco = NULL;
size_t matches = 0;
bool is_ip;
@@ -1236,11 +1235,8 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
co = c->cookies[myhash];
while(co) {
- /* only process this cookie if it is not expired or had no expire
- date AND that if the cookie requires we're secure we must only
- continue if we are! */
- if((!co->expires || (co->expires > now)) &&
- (co->secure?secure:TRUE)) {
+ /* if the cookie requires we're secure we must only continue if we are! */
+ if(co->secure?secure:TRUE) {
/* now check if the domain is correct */
if(!co->domain ||
@@ -1266,12 +1262,8 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
matches++;
}
- else {
- fail:
- /* failure, clear up the allocated chain and return NULL */
- Curl_cookie_freelist(mainco);
- return NULL;
- }
+ else
+ goto fail;
}
}
}
@@ -1309,6 +1301,11 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
}
return mainco; /* return the new list */
+
+fail:
+ /* failure, clear up the allocated chain and return NULL */
+ Curl_cookie_freelist(mainco);
+ return NULL;
}
/*****************************************************************************
@@ -1508,10 +1505,9 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere)
format_ptr = get_netscape_format(array[i]);
if(format_ptr == NULL) {
fprintf(out, "#\n# Fatal libcurl error\n");
- if(!use_stdout) {
- free(array);
+ free(array);
+ if(!use_stdout)
fclose(out);
- }
return 1;
}
fprintf(out, "%s\n", format_ptr);
diff --git a/lib/curl_config.h b/lib/curl_config.h
index da99a74c..853c6728 100644
--- a/lib/curl_config.h
+++ b/lib/curl_config.h
@@ -49,6 +49,9 @@
/* to disable --libcurl C code generation option */
/* #undef CURL_DISABLE_LIBCURL_OPTION */
+/* if the OpenSSL configuration won't be loaded automatically */
+/* #undef CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG */
+
/* to disable POP3 */
#define CURL_DISABLE_POP3 1
@@ -95,7 +98,7 @@
#define ENABLE_IPV6 1
/* Define to the type of arg 2 for gethostname. */
-#define GETHOSTNAME_TYPE_ARG2 unsigned int
+#define GETHOSTNAME_TYPE_ARG2 size_t
/* Specifies the number of arguments to getservbyport_r */
/* #undef GETSERVBYPORT_R_ARGS */
@@ -134,7 +137,7 @@
/* #undef HAVE_BROTLI_DECODE_H */
/* Define to 1 if you have the __builtin_available function. */
-/* #undef HAVE_BUILTIN_AVAILABLE */
+#define HAVE_BUILTIN_AVAILABLE 1
/* Define to 1 if you have the clock_gettime function and monotonic timer. */
#define HAVE_CLOCK_GETTIME_MONOTONIC 1
@@ -513,13 +516,13 @@
/* #undef HAVE_PK11_CREATEMANAGEDGENERICOBJECT */
/* Define to 1 if you have a working poll function. */
-/* #undef HAVE_POLL */
+#define HAVE_POLL 1
/* If you have a fine poll */
-/* #undef HAVE_POLL_FINE */
+#define HAVE_POLL_FINE 1
/* Define to 1 if you have the <poll.h> header file. */
-/* #undef HAVE_POLL_H */
+#define HAVE_POLL_H 1
/* Define to 1 if you have a working POSIX-style strerror_r function. */
#define HAVE_POSIX_STRERROR_R 1
@@ -531,7 +534,7 @@
#define HAVE_PWD_H 1
/* Define to 1 if you have the `RAND_egd' function. */
-#define HAVE_RAND_EGD 1
+/* #undef HAVE_RAND_EGD */
/* Define to 1 if you have the recv function. */
#define HAVE_RECV 1
@@ -579,7 +582,7 @@
#define HAVE_SIGNAL_H 1
/* Define to 1 if you have the sigsetjmp function or macro. */
-#define HAVE_SIGSETJMP 1
+/* #undef HAVE_SIGSETJMP */
/* Define to 1 if sig_atomic_t is an available typedef. */
#define HAVE_SIG_ATOMIC_T 1
@@ -678,7 +681,7 @@
#define HAVE_SYS_PARAM_H 1
/* Define to 1 if you have the <sys/poll.h> header file. */
-/* #undef HAVE_SYS_POLL_H */
+#define HAVE_SYS_POLL_H 1
/* Define to 1 if you have the <sys/resource.h> header file. */
#define HAVE_SYS_RESOURCE_H 1
@@ -738,7 +741,7 @@
#define HAVE_UTIMES 1
/* Define to 1 if you have the <utime.h> header file. */
-/* #undef HAVE_UTIME_H */
+#define HAVE_UTIME_H 1
/* Define to 1 if compiler supports C99 variadic macro style. */
#define HAVE_VARIADIC_MACROS_C99 1
@@ -941,6 +944,9 @@
/* if mbedTLS is enabled */
/* #undef USE_MBEDTLS */
+/* if MesaLink is enabled */
+/* #undef USE_MESALINK */
+
/* Define to enable metalink support */
/* #undef USE_METALINK */
diff --git a/lib/curl_config.h.cmake b/lib/curl_config.h.cmake
index ab0094be..5308eb57 100644
--- a/lib/curl_config.h.cmake
+++ b/lib/curl_config.h.cmake
@@ -127,6 +127,9 @@
/* Define to 1 if bool is an available type. */
#cmakedefine HAVE_BOOL_T 1
+/* Define to 1 if you have the __builtin_available function. */
+#cmakedefine HAVE_BUILTIN_AVAILABLE 1
+
/* Define to 1 if you have the clock_gettime function and monotonic timer. */
#cmakedefine HAVE_CLOCK_GETTIME_MONOTONIC 1
@@ -900,9 +903,6 @@
/* The size of `time_t', as computed by sizeof. */
#cmakedefine SIZEOF_TIME_T ${SIZEOF_TIME_T}
-/* The size of `void*', as computed by sizeof. */
-#cmakedefine SIZEOF_VOIDP ${SIZEOF_VOIDP}
-
/* Define to 1 if you have the ANSI C header files. */
#cmakedefine STDC_HEADERS 1
diff --git a/lib/curl_config.h.in b/lib/curl_config.h.in
index 9c9e2d9a..477d61eb 100644
--- a/lib/curl_config.h.in
+++ b/lib/curl_config.h.in
@@ -48,6 +48,9 @@
/* to disable --libcurl C code generation option */
#undef CURL_DISABLE_LIBCURL_OPTION
+/* if the OpenSSL configuration won't be loaded automatically */
+#undef CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG
+
/* to disable POP3 */
#undef CURL_DISABLE_POP3
@@ -958,6 +961,9 @@
/* if mbedTLS is enabled */
#undef USE_MBEDTLS
+/* if MesaLink is enabled */
+#undef USE_MESALINK
+
/* Define to enable metalink support */
#undef USE_METALINK
diff --git a/lib/curl_ldap.h b/lib/curl_ldap.h
index 27d03810..94c00294 100644
--- a/lib/curl_ldap.h
+++ b/lib/curl_ldap.h
@@ -32,4 +32,3 @@ extern const struct Curl_handler Curl_handler_ldaps;
#endif
#endif /* HEADER_CURL_LDAP_H */
-
diff --git a/lib/curl_ntlm_wb.c b/lib/curl_ntlm_wb.c
index 353a6564..a4791eb4 100644
--- a/lib/curl_ntlm_wb.c
+++ b/lib/curl_ntlm_wb.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2018, 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
@@ -249,6 +249,9 @@ done:
return CURLE_REMOTE_ACCESS_DENIED;
}
+/* if larger than this, something is seriously wrong */
+#define MAX_NTLM_WB_RESPONSE 100000
+
static CURLcode ntlm_wb_response(struct connectdata *conn,
const char *input, curlntlm state)
{
@@ -289,6 +292,13 @@ static CURLcode ntlm_wb_response(struct connectdata *conn,
buf[len_out - 1] = '\0';
break;
}
+
+ if(len_out > MAX_NTLM_WB_RESPONSE) {
+ failf(conn->data, "too large ntlm_wb response!");
+ free(buf);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
newbuf = Curl_saferealloc(buf, len_out + NTLM_BUFSIZE);
if(!newbuf)
return CURLE_OUT_OF_MEMORY;
@@ -314,6 +324,8 @@ static CURLcode ntlm_wb_response(struct connectdata *conn,
conn->response_header = aprintf("NTLM %.*s", len_out - 4, buf + 3);
free(buf);
+ if(!conn->response_header)
+ return CURLE_OUT_OF_MEMORY;
return CURLE_OK;
done:
free(buf);
@@ -389,6 +401,8 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn,
conn->response_header);
DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd));
free(conn->response_header);
+ if(!*allocuserpwd)
+ return CURLE_OUT_OF_MEMORY;
conn->response_header = NULL;
break;
case NTLMSTATE_TYPE2:
@@ -409,6 +423,8 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn,
ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */
authp->done = TRUE;
Curl_ntlm_wb_cleanup(conn);
+ if(!*allocuserpwd)
+ return CURLE_OUT_OF_MEMORY;
break;
case NTLMSTATE_TYPE3:
/* connection is already authenticated,
diff --git a/lib/curl_path.c b/lib/curl_path.c
index e843deac..68f3e44b 100644
--- a/lib/curl_path.c
+++ b/lib/curl_path.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2018, 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
@@ -39,7 +39,7 @@ CURLcode Curl_getworkingpath(struct connectdata *conn,
char *working_path;
size_t working_path_len;
CURLcode result =
- Curl_urldecode(data, data->state.path, 0, &working_path,
+ Curl_urldecode(data, data->state.up.path, 0, &working_path,
&working_path_len, FALSE);
if(result)
return result;
diff --git a/lib/curl_path.h b/lib/curl_path.h
index 5ee4ff36..636c37f2 100644
--- a/lib/curl_path.h
+++ b/lib/curl_path.h
@@ -44,4 +44,4 @@ CURLcode Curl_getworkingpath(struct connectdata *conn,
char **path);
CURLcode Curl_get_pathname(const char **cpp, char **path, char *homedir);
-#endif
+#endif /* HEADER_CURL_PATH_H */
diff --git a/lib/curl_rtmp.c b/lib/curl_rtmp.c
index 97430647..f09f2f33 100644
--- a/lib/curl_rtmp.c
+++ b/lib/curl_rtmp.c
@@ -37,9 +37,11 @@
/* The last #include file should be: */
#include "memdebug.h"
-#ifdef _WIN32
+#if defined(WIN32) && !defined(USE_LWIPSOCK)
#define setsockopt(a,b,c,d,e) (setsockopt)(a,b,c,(const char *)d,(int)e)
#define SET_RCVTIMEO(tv,s) int tv = s*1000
+#elif defined(LWIP_SO_SNDRCVTIMEO_NONSTANDARD)
+#define SET_RCVTIMEO(tv,s) int tv = s*1000
#else
#define SET_RCVTIMEO(tv,s) struct timeval tv = {s,0}
#endif
diff --git a/lib/curl_setup.h b/lib/curl_setup.h
index 24989874..b8450155 100644
--- a/lib/curl_setup.h
+++ b/lib/curl_setup.h
@@ -44,6 +44,9 @@
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# endif
+# ifndef NOGDI
+# define NOGDI
+# endif
#endif
/*
@@ -645,7 +648,7 @@ int netware_init(void);
#if defined(USE_GNUTLS) || defined(USE_OPENSSL) || defined(USE_NSS) || \
defined(USE_POLARSSL) || defined(USE_AXTLS) || defined(USE_MBEDTLS) || \
defined(USE_CYASSL) || defined(USE_SCHANNEL) || \
- defined(USE_DARWINSSL) || defined(USE_GSKIT)
+ defined(USE_DARWINSSL) || defined(USE_GSKIT) || defined(USE_MESALINK)
#define USE_SSL /* SSL support has been enabled */
#endif
diff --git a/lib/curl_setup_once.h b/lib/curl_setup_once.h
index 6d01ea15..413ccea9 100644
--- a/lib/curl_setup_once.h
+++ b/lib/curl_setup_once.h
@@ -515,4 +515,3 @@ typedef int sig_atomic_t;
#endif /* HEADER_CURL_SETUP_ONCE_H */
-
diff --git a/lib/curl_sspi.c b/lib/curl_sspi.c
index 11a7120a..1d0de4ed 100644
--- a/lib/curl_sspi.c
+++ b/lib/curl_sspi.c
@@ -90,8 +90,9 @@ CURLcode Curl_sspi_global_init(void)
return CURLE_FAILED_INIT;
/* Get address of the InitSecurityInterfaceA function from the SSPI dll */
- pInitSecurityInterface = (INITSECURITYINTERFACE_FN)
- GetProcAddress(s_hSecDll, SECURITYENTRYPOINT);
+ pInitSecurityInterface =
+ CURLX_FUNCTION_CAST(INITSECURITYINTERFACE_FN,
+ (GetProcAddress(s_hSecDll, SECURITYENTRYPOINT)));
if(!pInitSecurityInterface)
return CURLE_FAILED_INIT;
@@ -131,7 +132,7 @@ void Curl_sspi_global_cleanup(void)
* Parameters:
*
* userp [in] - The user name in the format User or Domain\User.
- * passdwp [in] - The user's password.
+ * passwdp [in] - The user's password.
* identity [in/out] - The identity structure.
*
* Returns CURLE_OK on success.
diff --git a/lib/curl_threads.c b/lib/curl_threads.c
index b8f0cd35..8e5937aa 100644
--- a/lib/curl_threads.c
+++ b/lib/curl_threads.c
@@ -104,13 +104,21 @@ int Curl_thread_join(curl_thread_t *hnd)
curl_thread_t Curl_thread_create(unsigned int (CURL_STDCALL *func) (void *),
void *arg)
{
+#ifdef _WIN32_WCE
+ typedef HANDLE curl_win_thread_handle_t;
+#elif defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
+ typedef unsigned long curl_win_thread_handle_t;
+#else
+ typedef uintptr_t curl_win_thread_handle_t;
+#endif
curl_thread_t t;
+ curl_win_thread_handle_t thread_handle;
#ifdef _WIN32_WCE
- t = CreateThread(NULL, 0, func, arg, 0, NULL);
+ thread_handle = CreateThread(NULL, 0, func, arg, 0, NULL);
#else
- uintptr_t thread_handle = _beginthreadex(NULL, 0, func, arg, 0, NULL);
- t = (curl_thread_t)thread_handle;
+ thread_handle = _beginthreadex(NULL, 0, func, arg, 0, NULL);
#endif
+ t = (curl_thread_t)thread_handle;
if((t == 0) || (t == LongToHandle(-1L))) {
#ifdef _WIN32_WCE
DWORD gle = GetLastError();
diff --git a/lib/curl_threads.h b/lib/curl_threads.h
index 9e0d14a3..2a93644c 100644
--- a/lib/curl_threads.h
+++ b/lib/curl_threads.h
@@ -38,7 +38,8 @@
# define curl_thread_t HANDLE
# define curl_thread_t_null (HANDLE)0
# if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_VISTA) || \
- (_WIN32_WINNT < _WIN32_WINNT_VISTA)
+ (_WIN32_WINNT < _WIN32_WINNT_VISTA) || \
+ (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR))
# define Curl_mutex_init(m) InitializeCriticalSection(m)
# else
# define Curl_mutex_init(m) InitializeCriticalSectionEx(m, 0, 1)
diff --git a/lib/curlx.h b/lib/curlx.h
index 6e418266..4c77d4f2 100644
--- a/lib/curlx.h
+++ b/lib/curlx.h
@@ -102,4 +102,3 @@
#endif /* ENABLE_CURLX_PRINTF */
#endif /* HEADER_CURL_CURLX_H */
-
diff --git a/lib/dict.c b/lib/dict.c
index 408d57b9..78ef046d 100644
--- a/lib/dict.c
+++ b/lib/dict.c
@@ -136,7 +136,7 @@ static CURLcode dict_do(struct connectdata *conn, bool *done)
struct Curl_easy *data = conn->data;
curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
- char *path = data->state.path;
+ char *path = data->state.up.path;
curl_off_t *bytecount = &data->req.bytecount;
*done = TRUE; /* unconditionally */
diff --git a/lib/doh.c b/lib/doh.c
new file mode 100644
index 00000000..ef6013db
--- /dev/null
+++ b/lib/doh.c
@@ -0,0 +1,920 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2018, 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 "urldata.h"
+#include "curl_addrinfo.h"
+#include "doh.h"
+
+#ifdef USE_NGHTTP2
+#include "sendf.h"
+#include "multiif.h"
+#include "url.h"
+#include "share.h"
+#include "curl_base64.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 DNS_CLASS_IN 0x01
+#define DOH_MAX_RESPONSE_SIZE 3000 /* bytes */
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+static const char * const errors[]={
+ "",
+ "Bad label",
+ "Out of range",
+ "Label loop",
+ "Too small",
+ "Out of memory",
+ "RDATA length",
+ "Malformat",
+ "Bad RCODE",
+ "Unexpected TYPE",
+ "Unexpected CLASS",
+ "No content",
+ "Bad ID"
+};
+
+static const char *doh_strerror(DOHcode code)
+{
+ if((code >= DOH_OK) && (code <= DOH_DNS_BAD_ID))
+ return errors[code];
+ return "bad error code";
+}
+#endif
+
+#ifdef DEBUGBUILD
+#define UNITTEST
+#else
+#define UNITTEST static
+#endif
+
+UNITTEST DOHcode doh_encode(const char *host,
+ DNStype dnstype,
+ unsigned char *dnsp, /* buffer */
+ size_t len, /* buffer size */
+ size_t *olen) /* output length */
+{
+ size_t hostlen = strlen(host);
+ unsigned char *orig = dnsp;
+ const char *hostp = host;
+
+ if(len < (12 + hostlen + 4))
+ return DOH_TOO_SMALL_BUFFER;
+
+ *dnsp++ = 0; /* 16 bit id */
+ *dnsp++ = 0;
+ *dnsp++ = 0x01; /* |QR| Opcode |AA|TC|RD| Set the RD bit */
+ *dnsp++ = '\0'; /* |RA| Z | RCODE | */
+ *dnsp++ = '\0';
+ *dnsp++ = 1; /* QDCOUNT (number of entries in the question section) */
+ *dnsp++ = '\0';
+ *dnsp++ = '\0'; /* ANCOUNT */
+ *dnsp++ = '\0';
+ *dnsp++ = '\0'; /* NSCOUNT */
+ *dnsp++ = '\0';
+ *dnsp++ = '\0'; /* ARCOUNT */
+
+ /* store a QNAME */
+ do {
+ char *dot = strchr(hostp, '.');
+ size_t labellen;
+ bool found = false;
+ if(dot) {
+ found = true;
+ labellen = dot - hostp;
+ }
+ else
+ labellen = strlen(hostp);
+ if(labellen > 63) {
+ /* too long label, error out */
+ *olen = 0;
+ return DOH_DNS_BAD_LABEL;
+ }
+ *dnsp++ = (unsigned char)labellen;
+ memcpy(dnsp, hostp, labellen);
+ dnsp += labellen;
+ hostp += labellen + 1;
+ if(!found) {
+ *dnsp++ = 0; /* terminating zero */
+ break;
+ }
+ } while(1);
+
+ *dnsp++ = '\0'; /* upper 8 bit TYPE */
+ *dnsp++ = (unsigned char)dnstype;
+ *dnsp++ = '\0'; /* upper 8 bit CLASS */
+ *dnsp++ = DNS_CLASS_IN; /* IN - "the Internet" */
+
+ *olen = dnsp - orig;
+ return DOH_OK;
+}
+
+static size_t
+doh_write_cb(void *contents, size_t size, size_t nmemb, void *userp)
+{
+ size_t realsize = size * nmemb;
+ struct dohresponse *mem = (struct dohresponse *)userp;
+
+ if((mem->size + realsize) > DOH_MAX_RESPONSE_SIZE)
+ /* suspiciously much for us */
+ return 0;
+
+ mem->memory = realloc(mem->memory, mem->size + realsize);
+ if(mem->memory == NULL)
+ /* out of memory! */
+ return 0;
+
+ memcpy(&(mem->memory[mem->size]), contents, realsize);
+ mem->size += realsize;
+
+ return realsize;
+}
+
+/* called from multi.c when this DOH transfer is complete */
+static int Curl_doh_done(struct Curl_easy *doh, CURLcode result)
+{
+ struct Curl_easy *data = doh->set.dohfor;
+ /* so one of the DOH request done for the 'data' transfer is now complete! */
+ data->req.doh.pending--;
+ infof(data, "a DOH request is completed, %d to go\n", data->req.doh.pending);
+ if(result)
+ infof(data, "DOH request %s\n", curl_easy_strerror(result));
+
+ if(!data->req.doh.pending) {
+ /* DOH completed */
+ curl_slist_free_all(data->req.doh.headers);
+ data->req.doh.headers = NULL;
+ Curl_expire(data, 0, EXPIRE_RUN_NOW);
+ }
+ return 0;
+}
+
+#define ERROR_CHECK_SETOPT(x,y) result = curl_easy_setopt(doh, x, y); \
+ if(result) goto error
+
+static CURLcode dohprobe(struct Curl_easy *data,
+ struct dnsprobe *p, DNStype dnstype,
+ const char *host,
+ const char *url, CURLM *multi,
+ struct curl_slist *headers)
+{
+ struct Curl_easy *doh = NULL;
+ char *nurl = NULL;
+ CURLcode result = CURLE_OK;
+ timediff_t timeout_ms;
+ DOHcode d = doh_encode(host, dnstype, p->dohbuffer, sizeof(p->dohbuffer),
+ &p->dohlen);
+ if(d) {
+ failf(data, "Failed to encode DOH packet [%d]\n", d);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ p->dnstype = dnstype;
+ p->serverdoh.memory = NULL;
+ /* the memory will be grown as needed by realloc in the doh_write_cb
+ function */
+ p->serverdoh.size = 0;
+
+ /* Note: this is code for sending the DoH request with GET but there's still
+ no logic that actually enables this. We should either add that ability or
+ yank out the GET code. Discuss! */
+ if(data->set.doh_get) {
+ char *b64;
+ size_t b64len;
+ result = Curl_base64url_encode(data, (char *)p->dohbuffer, p->dohlen,
+ &b64, &b64len);
+ if(result)
+ goto error;
+ nurl = aprintf("%s?dns=%s", url, b64);
+ free(b64);
+ if(!nurl) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto error;
+ }
+ url = nurl;
+ }
+
+ timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+ /* Curl_open() is the internal version of curl_easy_init() */
+ result = Curl_open(&doh);
+ if(!result) {
+ /* pass in the struct pointer via a local variable to please coverity and
+ the gcc typecheck helpers */
+ struct dohresponse *resp = &p->serverdoh;
+ ERROR_CHECK_SETOPT(CURLOPT_URL, url);
+ ERROR_CHECK_SETOPT(CURLOPT_WRITEFUNCTION, doh_write_cb);
+ ERROR_CHECK_SETOPT(CURLOPT_WRITEDATA, resp);
+ if(!data->set.doh_get) {
+ ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDS, p->dohbuffer);
+ ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDSIZE, (long)p->dohlen);
+ }
+ ERROR_CHECK_SETOPT(CURLOPT_HTTPHEADER, headers);
+ ERROR_CHECK_SETOPT(CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
+#ifndef CURLDEBUG
+ /* enforce HTTPS if not debug */
+ ERROR_CHECK_SETOPT(CURLOPT_PROTOCOLS, CURLPROTO_HTTPS);
+#endif
+ ERROR_CHECK_SETOPT(CURLOPT_TIMEOUT_MS, (long)timeout_ms);
+ ERROR_CHECK_SETOPT(CURLOPT_VERBOSE, 1L);
+ doh->set.fmultidone = Curl_doh_done;
+ doh->set.dohfor = data; /* identify for which transfer this is done */
+ p->easy = doh;
+
+ /* add this transfer to the multi handle */
+ if(curl_multi_add_handle(multi, doh))
+ goto error;
+ }
+ else
+ goto error;
+ free(nurl);
+ return CURLE_OK;
+
+ error:
+ free(nurl);
+ Curl_close(doh);
+ return result;
+}
+
+/*
+ * Curl_doh() resolves a name using DOH. It resolves a name and returns a
+ * 'Curl_addrinfo *' with the address information.
+ */
+
+Curl_addrinfo *Curl_doh(struct connectdata *conn,
+ const char *hostname,
+ int port,
+ int *waitp)
+{
+ struct Curl_easy *data = conn->data;
+ CURLcode result = CURLE_OK;
+ *waitp = TRUE; /* this never returns synchronously */
+ (void)conn;
+ (void)hostname;
+ (void)port;
+
+ /* start clean, consider allocating this struct on demand */
+ memset(&data->req.doh, 0, sizeof(struct dohdata));
+
+ data->req.doh.host = hostname;
+ data->req.doh.port = port;
+ data->req.doh.headers =
+ curl_slist_append(NULL,
+ "Content-Type: application/dns-message");
+ if(!data->req.doh.headers)
+ goto error;
+
+ if(conn->ip_version != CURL_IPRESOLVE_V6) {
+ /* create IPv4 DOH request */
+ result = dohprobe(data, &data->req.doh.probe[0], DNS_TYPE_A,
+ hostname, data->set.str[STRING_DOH],
+ data->multi, data->req.doh.headers);
+ if(result)
+ goto error;
+ data->req.doh.pending++;
+ }
+
+ if(conn->ip_version != CURL_IPRESOLVE_V4) {
+ /* create IPv6 DOH request */
+ result = dohprobe(data, &data->req.doh.probe[1], DNS_TYPE_AAAA,
+ hostname, data->set.str[STRING_DOH],
+ data->multi, data->req.doh.headers);
+ if(result)
+ goto error;
+ data->req.doh.pending++;
+ }
+ return NULL;
+
+ error:
+ curl_slist_free_all(data->req.doh.headers);
+ data->req.doh.headers = NULL;
+ curl_easy_cleanup(data->req.doh.probe[0].easy);
+ data->req.doh.probe[0].easy = NULL;
+ curl_easy_cleanup(data->req.doh.probe[1].easy);
+ data->req.doh.probe[1].easy = NULL;
+ return NULL;
+}
+
+static DOHcode skipqname(unsigned char *doh, size_t dohlen,
+ unsigned int *indexp)
+{
+ unsigned char length;
+ do {
+ if(dohlen < (*indexp + 1))
+ return DOH_DNS_OUT_OF_RANGE;
+ length = doh[*indexp];
+ if((length & 0xc0) == 0xc0) {
+ /* name pointer, advance over it and be done */
+ if(dohlen < (*indexp + 2))
+ return DOH_DNS_OUT_OF_RANGE;
+ *indexp += 2;
+ break;
+ }
+ if(length & 0xc0)
+ return DOH_DNS_BAD_LABEL;
+ if(dohlen < (*indexp + 1 + length))
+ return DOH_DNS_OUT_OF_RANGE;
+ *indexp += 1 + length;
+ } while(length);
+ return DOH_OK;
+}
+
+static unsigned short get16bit(unsigned char *doh, int index)
+{
+ return (unsigned short)((doh[index] << 8) | doh[index + 1]);
+}
+
+static unsigned int get32bit(unsigned char *doh, int index)
+{
+ return (doh[index] << 24) | (doh[index + 1] << 16) |
+ (doh[index + 2] << 8) | doh[index + 3];
+}
+
+static DOHcode store_a(unsigned char *doh, int index, struct dohentry *d)
+{
+ /* silently ignore addresses over the limit */
+ if(d->numaddr < DOH_MAX_ADDR) {
+ struct dohaddr *a = &d->addr[d->numaddr];
+ a->type = DNS_TYPE_A;
+ memcpy(&a->ip.v4, &doh[index], 4);
+ d->numaddr++;
+ }
+ return DOH_OK;
+}
+
+static DOHcode store_aaaa(unsigned char *doh, int index, struct dohentry *d)
+{
+ /* silently ignore addresses over the limit */
+ if(d->numaddr < DOH_MAX_ADDR) {
+ struct dohaddr *a = &d->addr[d->numaddr];
+ a->type = DNS_TYPE_AAAA;
+ memcpy(&a->ip.v6, &doh[index], 16);
+ d->numaddr++;
+ }
+ return DOH_OK;
+}
+
+static DOHcode cnameappend(struct cnamestore *c,
+ unsigned char *src,
+ size_t len)
+{
+ if(!c->alloc) {
+ c->allocsize = len + 1;
+ c->alloc = malloc(c->allocsize);
+ if(!c->alloc)
+ return DOH_OUT_OF_MEM;
+ }
+ else if(c->allocsize < (c->allocsize + len + 1)) {
+ char *ptr;
+ c->allocsize += len + 1;
+ ptr = realloc(c->alloc, c->allocsize);
+ if(!ptr) {
+ free(c->alloc);
+ return DOH_OUT_OF_MEM;
+ }
+ c->alloc = ptr;
+ }
+ memcpy(&c->alloc[c->len], src, len);
+ c->len += len;
+ c->alloc[c->len] = 0; /* keep it zero terminated */
+ return DOH_OK;
+}
+
+static DOHcode store_cname(unsigned char *doh,
+ size_t dohlen,
+ unsigned int index,
+ struct dohentry *d)
+{
+ struct cnamestore *c;
+ unsigned int loop = 128; /* a valid DNS name can never loop this much */
+ unsigned char length;
+
+ if(d->numcname == DOH_MAX_CNAME)
+ return DOH_OK; /* skip! */
+
+ c = &d->cname[d->numcname++];
+ do {
+ if(index >= dohlen)
+ return DOH_DNS_OUT_OF_RANGE;
+ length = doh[index];
+ if((length & 0xc0) == 0xc0) {
+ int newpos;
+ /* name pointer, get the new offset (14 bits) */
+ if((index + 1) >= dohlen)
+ return DOH_DNS_OUT_OF_RANGE;
+
+ /* move to the the new index */
+ newpos = (length & 0x3f) << 8 | doh[index + 1];
+ index = newpos;
+ continue;
+ }
+ else if(length & 0xc0)
+ return DOH_DNS_BAD_LABEL; /* bad input */
+ else
+ index++;
+
+ if(length) {
+ DOHcode rc;
+ if(c->len) {
+ rc = cnameappend(c, (unsigned char *)".", 1);
+ if(rc)
+ return rc;
+ }
+ if((index + length) > dohlen)
+ return DOH_DNS_BAD_LABEL;
+
+ rc = cnameappend(c, &doh[index], length);
+ if(rc)
+ return rc;
+ index += length;
+ }
+ } while(length && --loop);
+
+ if(!loop)
+ return DOH_DNS_LABEL_LOOP;
+ return DOH_OK;
+}
+
+static DOHcode rdata(unsigned char *doh,
+ size_t dohlen,
+ unsigned short rdlength,
+ unsigned short type,
+ int index,
+ struct dohentry *d)
+{
+ /* RDATA
+ - A (TYPE 1): 4 bytes
+ - AAAA (TYPE 28): 16 bytes
+ - NS (TYPE 2): N bytes */
+ DOHcode rc;
+
+ switch(type) {
+ case DNS_TYPE_A:
+ if(rdlength != 4)
+ return DOH_DNS_RDATA_LEN;
+ rc = store_a(doh, index, d);
+ if(rc)
+ return rc;
+ break;
+ case DNS_TYPE_AAAA:
+ if(rdlength != 16)
+ return DOH_DNS_RDATA_LEN;
+ rc = store_aaaa(doh, index, d);
+ if(rc)
+ return rc;
+ break;
+ case DNS_TYPE_CNAME:
+ rc = store_cname(doh, dohlen, index, d);
+ if(rc)
+ return rc;
+ break;
+ default:
+ /* unsupported type, just skip it */
+ break;
+ }
+ return DOH_OK;
+}
+
+static void init_dohentry(struct dohentry *de)
+{
+ memset(de, 0, sizeof(*de));
+ de->ttl = INT_MAX;
+}
+
+
+UNITTEST DOHcode doh_decode(unsigned char *doh,
+ size_t dohlen,
+ DNStype dnstype,
+ struct dohentry *d)
+{
+ unsigned char rcode;
+ unsigned short qdcount;
+ unsigned short ancount;
+ unsigned short type = 0;
+ unsigned short class;
+ unsigned short rdlength;
+ unsigned short nscount;
+ unsigned short arcount;
+ unsigned int index = 12;
+ DOHcode rc;
+
+ if(dohlen < 12)
+ return DOH_TOO_SMALL_BUFFER; /* too small */
+ if(doh[0] || doh[1])
+ return DOH_DNS_BAD_ID; /* bad ID */
+ rcode = doh[3] & 0x0f;
+ if(rcode)
+ return DOH_DNS_BAD_RCODE; /* bad rcode */
+
+ qdcount = get16bit(doh, 4);
+ while(qdcount) {
+ rc = skipqname(doh, dohlen, &index);
+ if(rc)
+ return rc; /* bad qname */
+ if(dohlen < (index + 4))
+ return DOH_DNS_OUT_OF_RANGE;
+ index += 4; /* skip question's type and class */
+ qdcount--;
+ }
+
+ ancount = get16bit(doh, 6);
+ while(ancount) {
+ unsigned int ttl;
+
+ rc = skipqname(doh, dohlen, &index);
+ if(rc)
+ return rc; /* bad qname */
+
+ if(dohlen < (index + 2))
+ return DOH_DNS_OUT_OF_RANGE;
+
+ type = get16bit(doh, index);
+ if((type != DNS_TYPE_CNAME) && (type != dnstype))
+ /* Not the same type as was asked for nor CNAME */
+ return DOH_DNS_UNEXPECTED_TYPE;
+ index += 2;
+
+ if(dohlen < (index + 2))
+ return DOH_DNS_OUT_OF_RANGE;
+ class = get16bit(doh, index);
+ if(DNS_CLASS_IN != class)
+ return DOH_DNS_UNEXPECTED_CLASS; /* unsupported */
+ index += 2;
+
+ if(dohlen < (index + 4))
+ return DOH_DNS_OUT_OF_RANGE;
+
+ ttl = get32bit(doh, index);
+ if(ttl < d->ttl)
+ d->ttl = ttl;
+ index += 4;
+
+ if(dohlen < (index + 2))
+ return DOH_DNS_OUT_OF_RANGE;
+
+ rdlength = get16bit(doh, index);
+ index += 2;
+ if(dohlen < (index + rdlength))
+ return DOH_DNS_OUT_OF_RANGE;
+
+ rc = rdata(doh, dohlen, rdlength, type, index, d);
+ if(rc)
+ return rc; /* bad rdata */
+ index += rdlength;
+ ancount--;
+ }
+
+ nscount = get16bit(doh, 8);
+ while(nscount) {
+ rc = skipqname(doh, dohlen, &index);
+ if(rc)
+ return rc; /* bad qname */
+
+ if(dohlen < (index + 8))
+ return DOH_DNS_OUT_OF_RANGE;
+
+ index += 2 + 2 + 4; /* type, class and ttl */
+
+ if(dohlen < (index + 2))
+ return DOH_DNS_OUT_OF_RANGE;
+
+ rdlength = get16bit(doh, index);
+ index += 2;
+ if(dohlen < (index + rdlength))
+ return DOH_DNS_OUT_OF_RANGE;
+ index += rdlength;
+ nscount--;
+ }
+
+ arcount = get16bit(doh, 10);
+ while(arcount) {
+ rc = skipqname(doh, dohlen, &index);
+ if(rc)
+ return rc; /* bad qname */
+
+ if(dohlen < (index + 8))
+ return DOH_DNS_OUT_OF_RANGE;
+
+ index += 2 + 2 + 4; /* type, class and ttl */
+
+ if(dohlen < (index + 2))
+ return DOH_DNS_OUT_OF_RANGE;
+
+ rdlength = get16bit(doh, index);
+ index += 2;
+ if(dohlen < (index + rdlength))
+ return DOH_DNS_OUT_OF_RANGE;
+ index += rdlength;
+ arcount--;
+ }
+
+ if(index != dohlen)
+ return DOH_DNS_MALFORMAT; /* something is wrong */
+
+ if((type != DNS_TYPE_NS) && !d->numcname && !d->numaddr)
+ /* nothing stored! */
+ return DOH_NO_CONTENT;
+
+ return DOH_OK; /* ok */
+}
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+static void showdoh(struct Curl_easy *data,
+ struct dohentry *d)
+{
+ int i;
+ infof(data, "TTL: %u seconds\n", d->ttl);
+ for(i = 0; i < d->numaddr; i++) {
+ struct dohaddr *a = &d->addr[i];
+ if(a->type == DNS_TYPE_A) {
+ infof(data, "DOH A: %u.%u.%u.%u\n",
+ a->ip.v4[0], a->ip.v4[1],
+ a->ip.v4[2], a->ip.v4[3]);
+ }
+ else if(a->type == DNS_TYPE_AAAA) {
+ int j;
+ char buffer[128];
+ char *ptr;
+ size_t len;
+ snprintf(buffer, 128, "DOH AAAA: ");
+ ptr = &buffer[10];
+ len = 118;
+ for(j = 0; j < 16; j += 2) {
+ size_t l;
+ snprintf(ptr, len, "%s%02x%02x", j?":":"", d->addr[i].ip.v6[j],
+ d->addr[i].ip.v6[j + 1]);
+ l = strlen(ptr);
+ len -= l;
+ ptr += l;
+ }
+ infof(data, "%s\n", buffer);
+ }
+ }
+ for(i = 0; i < d->numcname; i++) {
+ infof(data, "CNAME: %s\n", d->cname[i].alloc);
+ }
+}
+#else
+#define showdoh(x,y)
+#endif
+
+/*
+ * doh2ai()
+ *
+ * This function returns a pointer to the first element of a newly allocated
+ * Curl_addrinfo struct linked list filled with the data from a set of DOH
+ * lookups. Curl_addrinfo is meant to work like the addrinfo struct does for
+ * a IPv6 stack, but usable also for IPv4, all hosts and environments.
+ *
+ * The memory allocated by this function *MUST* be free'd later on calling
+ * Curl_freeaddrinfo(). For each successful call to this function there
+ * must be an associated call later to Curl_freeaddrinfo().
+ */
+
+static Curl_addrinfo *
+doh2ai(const struct dohentry *de, const char *hostname, int port)
+{
+ Curl_addrinfo *ai;
+ Curl_addrinfo *prevai = NULL;
+ Curl_addrinfo *firstai = NULL;
+ struct sockaddr_in *addr;
+#ifdef ENABLE_IPV6
+ struct sockaddr_in6 *addr6;
+#endif
+ CURLcode result = CURLE_OK;
+ int i;
+
+ if(!de)
+ /* no input == no output! */
+ return NULL;
+
+ for(i = 0; i < de->numaddr; i++) {
+ size_t ss_size;
+ CURL_SA_FAMILY_T addrtype;
+ if(de->addr[i].type == DNS_TYPE_AAAA) {
+#ifndef ENABLE_IPV6
+ /* we can't handle IPv6 addresses */
+ continue;
+#else
+ ss_size = sizeof(struct sockaddr_in6);
+ addrtype = AF_INET6;
+#endif
+ }
+ else {
+ ss_size = sizeof(struct sockaddr_in);
+ addrtype = AF_INET;
+ }
+
+ ai = calloc(1, sizeof(Curl_addrinfo));
+ if(!ai) {
+ result = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+ ai->ai_canonname = strdup(hostname);
+ if(!ai->ai_canonname) {
+ result = CURLE_OUT_OF_MEMORY;
+ free(ai);
+ break;
+ }
+ ai->ai_addr = calloc(1, ss_size);
+ if(!ai->ai_addr) {
+ result = CURLE_OUT_OF_MEMORY;
+ free(ai->ai_canonname);
+ free(ai);
+ break;
+ }
+
+ if(!firstai)
+ /* store the pointer we want to return from this function */
+ firstai = ai;
+
+ if(prevai)
+ /* make the previous entry point to this */
+ prevai->ai_next = ai;
+
+ ai->ai_family = addrtype;
+
+ /* we return all names as STREAM, so when using this address for TFTP
+ the type must be ignored and conn->socktype be used instead! */
+ ai->ai_socktype = SOCK_STREAM;
+
+ ai->ai_addrlen = (curl_socklen_t)ss_size;
+
+ /* leave the rest of the struct filled with zero */
+
+ switch(ai->ai_family) {
+ case AF_INET:
+ addr = (void *)ai->ai_addr; /* storage area for this info */
+ DEBUGASSERT(sizeof(struct in_addr) == sizeof(de->addr[i].ip.v4));
+ memcpy(&addr->sin_addr, &de->addr[i].ip.v4, sizeof(struct in_addr));
+ addr->sin_family = (CURL_SA_FAMILY_T)addrtype;
+ addr->sin_port = htons((unsigned short)port);
+ break;
+
+#ifdef ENABLE_IPV6
+ case AF_INET6:
+ addr6 = (void *)ai->ai_addr; /* storage area for this info */
+ DEBUGASSERT(sizeof(struct in6_addr) == sizeof(de->addr[i].ip.v6));
+ memcpy(&addr6->sin6_addr, &de->addr[i].ip.v6, sizeof(struct in6_addr));
+ addr6->sin6_family = (CURL_SA_FAMILY_T)addrtype;
+ addr6->sin6_port = htons((unsigned short)port);
+ break;
+#endif
+ }
+
+ prevai = ai;
+ }
+
+ if(result) {
+ Curl_freeaddrinfo(firstai);
+ firstai = NULL;
+ }
+
+ return firstai;
+}
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+static const char *type2name(DNStype dnstype)
+{
+ return (dnstype == DNS_TYPE_A)?"A":"AAAA";
+}
+#endif
+
+UNITTEST void de_cleanup(struct dohentry *d)
+{
+ int i = 0;
+ for(i = 0; i < d->numcname; i++) {
+ free(d->cname[i].alloc);
+ }
+}
+
+CURLcode Curl_doh_is_resolved(struct connectdata *conn,
+ struct Curl_dns_entry **dnsp)
+{
+ struct Curl_easy *data = conn->data;
+ *dnsp = NULL; /* defaults to no response */
+
+ if(!data->req.doh.probe[0].easy && !data->req.doh.probe[1].easy) {
+ failf(data, "Could not DOH-resolve: %s", conn->async.hostname);
+ return conn->bits.proxy?CURLE_COULDNT_RESOLVE_PROXY:
+ CURLE_COULDNT_RESOLVE_HOST;
+ }
+ else if(!data->req.doh.pending) {
+ DOHcode rc;
+ DOHcode rc2;
+ struct dohentry de;
+ struct Curl_dns_entry *dns;
+ struct Curl_addrinfo *ai;
+ /* remove DOH handles from multi handle and close them */
+ curl_multi_remove_handle(data->multi, data->req.doh.probe[0].easy);
+ Curl_close(data->req.doh.probe[0].easy);
+ curl_multi_remove_handle(data->multi, data->req.doh.probe[1].easy);
+ Curl_close(data->req.doh.probe[1].easy);
+
+ /* parse the responses, create the struct and return it! */
+ init_dohentry(&de);
+ rc = doh_decode(data->req.doh.probe[0].serverdoh.memory,
+ data->req.doh.probe[0].serverdoh.size,
+ data->req.doh.probe[0].dnstype,
+ &de);
+ free(data->req.doh.probe[0].serverdoh.memory);
+ if(rc) {
+ infof(data, "DOH: %s type %s for %s\n", doh_strerror(rc),
+ type2name(data->req.doh.probe[0].dnstype),
+ data->req.doh.host);
+ }
+ rc2 = doh_decode(data->req.doh.probe[1].serverdoh.memory,
+ data->req.doh.probe[1].serverdoh.size,
+ data->req.doh.probe[1].dnstype,
+ &de);
+ free(data->req.doh.probe[1].serverdoh.memory);
+ if(rc2) {
+ infof(data, "DOG: %s type %s for %s\n", doh_strerror(rc2),
+ type2name(data->req.doh.probe[1].dnstype),
+ data->req.doh.host);
+ }
+ if(!rc || !rc2) {
+ infof(data, "DOH Host name: %s\n", data->req.doh.host);
+ showdoh(data, &de);
+
+ ai = doh2ai(&de, data->req.doh.host, data->req.doh.port);
+ if(!ai) {
+ de_cleanup(&de);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ if(data->share)
+ Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+ /* we got a response, store it in the cache */
+ dns = Curl_cache_addr(data, ai, data->req.doh.host, data->req.doh.port);
+
+ if(data->share)
+ Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+
+ de_cleanup(&de);
+ if(!dns)
+ /* returned failure, bail out nicely */
+ Curl_freeaddrinfo(ai);
+ else {
+ conn->async.dns = dns;
+ *dnsp = dns;
+ return CURLE_OK;
+ }
+ }
+ de_cleanup(&de);
+
+ return CURLE_COULDNT_RESOLVE_HOST;
+ }
+
+ return CURLE_OK;
+}
+
+#else /* !USE_NGHTTP2 */
+/*
+ */
+Curl_addrinfo *Curl_doh(struct connectdata *conn,
+ const char *hostname,
+ int port,
+ int *waitp)
+{
+ (void)conn;
+ (void)hostname;
+ (void)port;
+ (void)waitp;
+ return NULL;
+}
+
+CURLcode Curl_doh_is_resolved(struct connectdata *conn,
+ struct Curl_dns_entry **dnsp)
+{
+ (void)conn;
+ (void)dnsp;
+ return CURLE_NOT_BUILT_IN;
+}
+
+#endif /* USE_NGHTTP2 */
diff --git a/lib/doh.h b/lib/doh.h
new file mode 100644
index 00000000..83c79bc5
--- /dev/null
+++ b/lib/doh.h
@@ -0,0 +1,105 @@
+#ifndef HEADER_CURL_DOH_H
+#define HEADER_CURL_DOH_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2018, 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 "urldata.h"
+#include "curl_addrinfo.h"
+
+/*
+ * Curl_doh() resolve a name using DoH (DNS-over-HTTPS). It resolves a name
+ * and returns a 'Curl_addrinfo *' with the address information.
+ */
+
+Curl_addrinfo *Curl_doh(struct connectdata *conn,
+ const char *hostname,
+ int port,
+ int *waitp);
+
+CURLcode Curl_doh_is_resolved(struct connectdata *conn,
+ struct Curl_dns_entry **dns);
+
+int Curl_doh_getsock(struct connectdata *conn, curl_socket_t *socks,
+ int numsocks);
+
+typedef enum {
+ DOH_OK,
+ DOH_DNS_BAD_LABEL, /* 1 */
+ DOH_DNS_OUT_OF_RANGE, /* 2 */
+ DOH_DNS_LABEL_LOOP, /* 3 */
+ DOH_TOO_SMALL_BUFFER, /* 4 */
+ DOH_OUT_OF_MEM, /* 5 */
+ DOH_DNS_RDATA_LEN, /* 6 */
+ DOH_DNS_MALFORMAT, /* 7 */
+ DOH_DNS_BAD_RCODE, /* 8 - no such name */
+ DOH_DNS_UNEXPECTED_TYPE, /* 9 */
+ DOH_DNS_UNEXPECTED_CLASS, /* 10 */
+ DOH_NO_CONTENT, /* 11 */
+ DOH_DNS_BAD_ID /* 12 */
+} DOHcode;
+
+typedef enum {
+ DNS_TYPE_A = 1,
+ DNS_TYPE_NS = 2,
+ DNS_TYPE_CNAME = 5,
+ DNS_TYPE_AAAA = 28
+} DNStype;
+
+#define DOH_MAX_ADDR 24
+#define DOH_MAX_CNAME 4
+
+struct cnamestore {
+ size_t len; /* length of cname */
+ char *alloc; /* allocated pointer */
+ size_t allocsize; /* allocated size */
+};
+
+struct dohaddr {
+ int type;
+ union {
+ unsigned char v4[4]; /* network byte order */
+ unsigned char v6[16];
+ } ip;
+};
+
+struct dohentry {
+ unsigned int ttl;
+ int numaddr;
+ struct dohaddr addr[DOH_MAX_ADDR];
+ int numcname;
+ struct cnamestore cname[DOH_MAX_CNAME];
+};
+
+
+#ifdef DEBUGBUILD
+DOHcode doh_encode(const char *host,
+ DNStype dnstype,
+ unsigned char *dnsp, /* buffer */
+ size_t len, /* buffer size */
+ size_t *olen); /* output length */
+DOHcode doh_decode(unsigned char *doh,
+ size_t dohlen,
+ DNStype dnstype,
+ struct dohentry *d);
+void de_cleanup(struct dohentry *d);
+#endif
+#endif /* HEADER_CURL_DOH_H */
diff --git a/lib/dotdot.c b/lib/dotdot.c
index cbb308d7..2c6177ae 100644
--- a/lib/dotdot.c
+++ b/lib/dotdot.c
@@ -62,6 +62,8 @@ char *Curl_dedotdotify(const char *input)
if(!out)
return NULL; /* out of memory */
+ *out = 0; /* zero terminates, for inputs like "./" */
+
/* get a cloned copy of the input */
clone = strdup(input);
if(!clone) {
diff --git a/lib/dotdot.h b/lib/dotdot.h
index fac8e6f2..125af436 100644
--- a/lib/dotdot.h
+++ b/lib/dotdot.h
@@ -22,4 +22,4 @@
*
***************************************************************************/
char *Curl_dedotdotify(const char *input);
-#endif
+#endif /* HEADER_CURL_DOTDOT_H */
diff --git a/lib/easy.c b/lib/easy.c
index 027d0bef..4de4e652 100644
--- a/lib/easy.c
+++ b/lib/easy.c
@@ -1002,10 +1002,6 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
*/
void curl_easy_reset(struct Curl_easy *data)
{
- Curl_safefree(data->state.pathbuffer);
-
- data->state.path = NULL;
-
Curl_free_request_state(data);
/* zero out UserDefined data: */
@@ -1197,3 +1193,22 @@ CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer,
return result;
}
+
+/*
+ * Performs connection upkeep for the given session handle.
+ */
+CURLcode curl_easy_upkeep(struct Curl_easy *data)
+{
+ /* Verify that we got an easy handle we can work with. */
+ if(!GOOD_EASY_HANDLE(data))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
+ if(data->multi_easy) {
+ /* Use the common function to keep connections alive. */
+ return Curl_upkeep(&data->multi_easy->conn_cache, data);
+ }
+ else {
+ /* No connections, so just return success */
+ return CURLE_OK;
+ }
+}
diff --git a/lib/easyif.h b/lib/easyif.h
index f6132cc7..6ba7e549 100644
--- a/lib/easyif.h
+++ b/lib/easyif.h
@@ -30,4 +30,3 @@ CURL_EXTERN CURLcode curl_easy_perform_ev(struct Curl_easy *easy);
#endif
#endif /* HEADER_CURL_EASYIF_H */
-
diff --git a/lib/escape.c b/lib/escape.c
index 10774f05..afd3899f 100644
--- a/lib/escape.c
+++ b/lib/escape.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -41,7 +41,7 @@
its behavior is altered by the current locale.
See https://tools.ietf.org/html/rfc3986#section-2.3
*/
-static bool Curl_isunreserved(unsigned char in)
+bool Curl_isunreserved(unsigned char in)
{
switch(in) {
case '0': case '1': case '2': case '3': case '4':
@@ -141,6 +141,8 @@ char *curl_easy_escape(struct Curl_easy *data, const char *string,
* Returns a pointer to a malloced string in *ostring with length given in
* *olen. If length == 0, the length is assumed to be strlen(string).
*
+ * 'data' can be set to NULL but then this function can't convert network
+ * data to host for non-ascii.
*/
CURLcode Curl_urldecode(struct Curl_easy *data,
const char *string, size_t length,
@@ -151,7 +153,7 @@ CURLcode Curl_urldecode(struct Curl_easy *data,
char *ns = malloc(alloc);
size_t strindex = 0;
unsigned long hex;
- CURLcode result;
+ CURLcode result = CURLE_OK;
if(!ns)
return CURLE_OUT_OF_MEMORY;
@@ -171,11 +173,13 @@ 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, (char *)&in, 1);
- if(result) {
- /* Curl_convert_from_network calls failf if unsuccessful */
- free(ns);
- return result;
+ if(data) {
+ 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;
diff --git a/lib/escape.h b/lib/escape.h
index 638666f0..d8bbe5cb 100644
--- a/lib/escape.h
+++ b/lib/escape.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -24,10 +24,10 @@
/* Escape and unescape URL encoding in strings. The functions return a new
* allocated string or NULL if an error occurred. */
+bool Curl_isunreserved(unsigned char in);
CURLcode Curl_urldecode(struct Curl_easy *data,
const char *string, size_t length,
char **ostring, size_t *olen,
bool reject_crlf);
#endif /* HEADER_CURL_ESCAPE_H */
-
diff --git a/lib/file.c b/lib/file.c
index e50e9887..722b55e9 100644
--- a/lib/file.c
+++ b/lib/file.c
@@ -143,7 +143,7 @@ static CURLcode file_connect(struct connectdata *conn, bool *done)
#endif
size_t real_path_len;
- CURLcode result = Curl_urldecode(data, data->state.path, 0, &real_path,
+ CURLcode result = Curl_urldecode(data, data->state.up.path, 0, &real_path,
&real_path_len, FALSE);
if(result)
return result;
@@ -197,7 +197,7 @@ static CURLcode file_connect(struct connectdata *conn, bool *done)
file->fd = fd;
if(!data->set.upload && (fd == -1)) {
- failf(data, "Couldn't open file %s", data->state.path);
+ failf(data, "Couldn't open file %s", data->state.up.path);
file_done(conn, CURLE_FILE_COULDNT_READ_FILE, FALSE);
return CURLE_FILE_COULDNT_READ_FILE;
}
@@ -307,7 +307,7 @@ static CURLcode file_upload(struct connectdata *conn)
size_t nread;
size_t nwrite;
size_t readcount;
- result = Curl_fillreadbuffer(conn, (int)data->set.buffer_size, &readcount);
+ result = Curl_fillreadbuffer(conn, data->set.buffer_size, &readcount);
if(result)
break;
@@ -386,7 +386,6 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
*done = TRUE; /* unconditionally */
- Curl_initinfo(data);
Curl_pgrsStartNow(data);
if(data->set.upload)
@@ -413,21 +412,18 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
}
}
- /* If we have selected NOBODY and HEADER, it means that we only want file
- information. Which for FILE can't be much more than the file size and
- date. */
- if(data->set.opt_no_body && data->set.include_header && fstated) {
+ if(fstated) {
time_t filetime;
struct tm buffer;
const struct tm *tm = &buffer;
char header[80];
snprintf(header, sizeof(header),
"Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", expected_size);
- result = Curl_client_write(conn, CLIENTWRITE_BOTH, header, 0);
+ result = Curl_client_write(conn, CLIENTWRITE_HEADER, header, 0);
if(result)
return result;
- result = Curl_client_write(conn, CLIENTWRITE_BOTH,
+ result = Curl_client_write(conn, CLIENTWRITE_HEADER,
(char *)"Accept-ranges: bytes\r\n", 0);
if(result)
return result;
@@ -439,19 +435,22 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
/* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
snprintf(header, sizeof(header),
- "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
+ "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n%s",
Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
tm->tm_mday,
Curl_month[tm->tm_mon],
tm->tm_year + 1900,
tm->tm_hour,
tm->tm_min,
- tm->tm_sec);
- result = Curl_client_write(conn, CLIENTWRITE_BOTH, header, 0);
- if(!result)
- /* set the file size to make it available post transfer */
- Curl_pgrsSetDownloadSize(data, expected_size);
- return result;
+ tm->tm_sec,
+ data->set.opt_no_body ? "": "\r\n");
+ result = Curl_client_write(conn, CLIENTWRITE_HEADER, header, 0);
+ if(result)
+ return result;
+ /* set the file size to make it available post transfer */
+ Curl_pgrsSetDownloadSize(data, expected_size);
+ if(data->set.opt_no_body)
+ return result;
}
/* Check whether file range has been specified */
diff --git a/lib/file.h b/lib/file.h
index c12ae0e0..20828ad4 100644
--- a/lib/file.h
+++ b/lib/file.h
@@ -38,4 +38,3 @@ extern const struct Curl_handler Curl_handler_file;
#endif
#endif /* HEADER_CURL_FILE_H */
-
diff --git a/lib/firefox-db2pem.sh b/lib/firefox-db2pem.sh
index 7d691ff6..45489324 100644
--- a/lib/firefox-db2pem.sh
+++ b/lib/firefox-db2pem.sh
@@ -51,4 +51,3 @@ while read nickname; \
do echo $nickname | sed -e "s/Builtin Object Token://g"; \
eval certutil -d $db -L -n "$nickname" -a ; \
done >> $out
-
diff --git a/lib/ftp.c b/lib/ftp.c
index 7dbf0800..793d991c 100644
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -1444,6 +1444,7 @@ static CURLcode ftp_state_list(struct connectdata *conn)
{
CURLcode result = CURLE_OK;
struct Curl_easy *data = conn->data;
+ struct FTP *ftp = data->req.protop;
/* If this output is to be machine-parsed, the NLST command might be better
to use, since the LIST command output is not specified or standard in any
@@ -1460,7 +1461,7 @@ 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;
+ const char *inpath = ftp->path;
lstArg = NULL;
if((data->set.ftp_filemethod == FTPFILE_NOCWD) &&
@@ -3141,7 +3142,6 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
int ftpcode;
CURLcode result = CURLE_OK;
char *path = NULL;
- const char *path_to_use = data->state.path;
if(!ftp)
return CURLE_OK;
@@ -3193,7 +3193,7 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
if(!result)
/* get the "raw" path */
- result = Curl_urldecode(data, path_to_use, 0, &path, NULL, TRUE);
+ result = Curl_urldecode(data, ftp->path, 0, &path, NULL, TRUE);
if(result) {
/* We can limp along anyway (and should try to since we may already be in
* the error path) */
@@ -3213,9 +3213,11 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
ftpc->prevpath[dlen] = 0; /* terminate */
}
else {
+ free(path);
/* we never changed dir */
ftpc->prevpath = strdup("");
- free(path);
+ if(!ftpc->prevpath)
+ return CURLE_OUT_OF_MEMORY;
}
if(ftpc->prevpath)
infof(data, "Remembering we are in dir \"%s\"\n", ftpc->prevpath);
@@ -3346,7 +3348,7 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
/* Send any post-transfer QUOTE strings? */
if(!status && !result && !premature && data->set.postquote)
result = ftp_sendquote(conn, data->set.postquote);
-
+ Curl_safefree(ftp->pathalloc);
return result;
}
@@ -3695,12 +3697,13 @@ static void wc_data_dtor(void *ptr)
static CURLcode init_wc_data(struct connectdata *conn)
{
char *last_slash;
- char *path = conn->data->state.path;
+ struct FTP *ftp = conn->data->req.protop;
+ char *path = ftp->path;
struct WildcardData *wildcard = &(conn->data->wildcard);
CURLcode result = CURLE_OK;
struct ftp_wc *ftpwc = NULL;
- last_slash = strrchr(conn->data->state.path, '/');
+ last_slash = strrchr(ftp->path, '/');
if(last_slash) {
last_slash++;
if(last_slash[0] == '\0') {
@@ -3757,7 +3760,7 @@ static CURLcode init_wc_data(struct connectdata *conn)
goto fail;
}
- wildcard->path = strdup(conn->data->state.path);
+ wildcard->path = strdup(ftp->path);
if(!wildcard->path) {
result = CURLE_OUT_OF_MEMORY;
goto fail;
@@ -3828,16 +3831,15 @@ static CURLcode wc_statemach(struct connectdata *conn)
/* filelist has at least one file, lets get first one */
struct ftp_conn *ftpc = &conn->proto.ftpc;
struct curl_fileinfo *finfo = wildcard->filelist.head->ptr;
+ struct FTP *ftp = conn->data->req.protop;
char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
if(!tmp_path)
return CURLE_OUT_OF_MEMORY;
- /* switch default "state.pathbuffer" and tmp_path, good to see
- ftp_parse_url_path function to understand this trick */
- Curl_safefree(conn->data->state.pathbuffer);
- conn->data->state.pathbuffer = tmp_path;
- conn->data->state.path = tmp_path;
+ /* switch default ftp->path and tmp_path */
+ free(ftp->pathalloc);
+ ftp->pathalloc = ftp->path = tmp_path;
infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
if(conn->data->set.chunk_bgn) {
@@ -3963,10 +3965,14 @@ CURLcode Curl_ftpsend(struct connectdata *conn, const char *cmd)
enum protection_level data_sec = conn->data_prot;
#endif
+ if(!cmd)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
write_len = strlen(cmd);
- if(write_len > (sizeof(s) -3))
+ if(!write_len || write_len > (sizeof(s) -3))
return CURLE_BAD_FUNCTION_ARGUMENT;
+ memcpy(&s, cmd, write_len);
strcpy(&s[write_len], "\r\n"); /* append a trailing CRLF */
write_len += 2;
bytes_written = 0;
@@ -4101,7 +4107,7 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
struct FTP *ftp = data->req.protop;
struct ftp_conn *ftpc = &conn->proto.ftpc;
const char *slash_pos; /* position of the first '/' char in curpos */
- const char *path_to_use = data->state.path;
+ const char *path_to_use = ftp->path;
const char *cur_pos;
const char *filename = NULL;
@@ -4187,7 +4193,7 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
/* parse the URL path into separate path components */
while((slash_pos = strchr(cur_pos, '/')) != NULL) {
/* 1 or 0 pointer offset to indicate absolute directory */
- ssize_t absolute_dir = ((cur_pos - data->state.path > 0) &&
+ ssize_t absolute_dir = ((cur_pos - ftp->path > 0) &&
(ftpc->dirdepth == 0))?1:0;
/* seek out the next path component */
@@ -4264,7 +4270,7 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
size_t dlen;
char *path;
CURLcode result =
- Curl_urldecode(conn->data, data->state.path, 0, &path, &dlen, TRUE);
+ Curl_urldecode(conn->data, ftp->path, 0, &path, &dlen, TRUE);
if(result) {
freedirs(ftpc);
return result;
@@ -4384,16 +4390,16 @@ static CURLcode ftp_setup_connection(struct connectdata *conn)
char *type;
struct FTP *ftp;
- conn->data->req.protop = ftp = malloc(sizeof(struct FTP));
+ conn->data->req.protop = ftp = calloc(sizeof(struct FTP), 1);
if(NULL == ftp)
return CURLE_OUT_OF_MEMORY;
- data->state.path++; /* don't include the initial slash */
+ ftp->path = &data->state.up.path[1]; /* don't include the initial slash */
data->state.slash_removed = TRUE; /* we've skipped the slash */
/* FTP URLs support an extension like ";type=<typecode>" that
* we'll try to get now! */
- type = strstr(data->state.path, ";type=");
+ type = strstr(ftp->path, ";type=");
if(!type)
type = strstr(conn->host.rawalloc, ";type=");
diff --git a/lib/ftp.h b/lib/ftp.h
index 7ec33911..38d03223 100644
--- a/lib/ftp.h
+++ b/lib/ftp.h
@@ -105,6 +105,8 @@ struct FTP {
curl_off_t *bytecountp;
char *user; /* user name string */
char *passwd; /* password string */
+ char *path; /* points to the urlpieces struct field */
+ char *pathalloc; /* if non-NULL a pointer to an allocated path */
/* transfer a file/body or not, done as a typedefed enum just to make
debuggers display the full symbol and not just the numerical value */
diff --git a/lib/getinfo.c b/lib/getinfo.c
index 14b45627..54c2c2f1 100644
--- a/lib/getinfo.c
+++ b/lib/getinfo.c
@@ -85,7 +85,6 @@ CURLcode Curl_initinfo(struct Curl_easy *data)
#ifdef USE_SSL
Curl_ssl_free_certinfo(data);
#endif
-
return CURLE_OK;
}
diff --git a/lib/gopher.c b/lib/gopher.c
index 3ecee9bd..b441a641 100644
--- a/lib/gopher.c
+++ b/lib/gopher.c
@@ -78,7 +78,7 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done)
curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
curl_off_t *bytecount = &data->req.bytecount;
- char *path = data->state.path;
+ char *path = data->state.up.path;
char *sel = NULL;
char *sel_org = NULL;
ssize_t amount, k;
diff --git a/lib/hostasyn.c b/lib/hostasyn.c
index e7b399ed..6ff60ba6 100644
--- a/lib/hostasyn.c
+++ b/lib/hostasyn.c
@@ -111,31 +111,6 @@ CURLcode Curl_addrinfo_callback(struct connectdata *conn,
return result;
}
-/* Call this function after Curl_connect() has returned async=TRUE and
- then a successful name resolve has been received.
-
- Note: this function disconnects and frees the conn data in case of
- resolve failure */
-CURLcode Curl_async_resolved(struct connectdata *conn,
- bool *protocol_done)
-{
- CURLcode result;
-
- if(conn->async.dns) {
- conn->dns_entry = conn->async.dns;
- conn->async.dns = NULL;
- }
-
- result = Curl_setup_conn(conn, protocol_done);
-
- if(result)
- /* We're not allowed to return failure with memory left allocated
- in the connectdata struct, free those here */
- Curl_disconnect(conn->data, conn, TRUE); /* close the connection */
-
- return result;
-}
-
/*
* Curl_getaddrinfo() is the generic low-level name resolve API within this
* source file. There are several versions of this function - for different
diff --git a/lib/hostcheck.h b/lib/hostcheck.h
index 86e3b96a..f562df9a 100644
--- a/lib/hostcheck.h
+++ b/lib/hostcheck.h
@@ -29,4 +29,3 @@
int Curl_cert_hostcheck(const char *match_pattern, const char *hostname);
#endif /* HEADER_CURL_HOSTCHECK_H */
-
diff --git a/lib/hostip.c b/lib/hostip.c
index bc20f715..f589a0b2 100644
--- a/lib/hostip.c
+++ b/lib/hostip.c
@@ -60,6 +60,7 @@
#include "url.h"
#include "inet_ntop.h"
#include "multiif.h"
+#include "doh.h"
#include "warnless.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -454,7 +455,7 @@ Curl_cache_addr(struct Curl_easy *data,
/* shuffle addresses if requested */
if(data->set.dns_shuffle_addresses) {
CURLcode result = Curl_shuffle_addr(data, &addr);
- if(!result)
+ if(result)
return NULL;
}
@@ -565,23 +566,27 @@ int Curl_resolv(struct connectdata *conn,
return CURLRESOLV_ERROR;
}
- /* If Curl_getaddrinfo() returns NULL, 'respwait' might be set to a
- non-zero value indicating that we need to wait for the response to the
- resolve call */
- addr = Curl_getaddrinfo(conn,
+ if(data->set.doh) {
+ addr = Curl_doh(conn, hostname, port, &respwait);
+ }
+ else {
+ /* If Curl_getaddrinfo() returns NULL, 'respwait' might be set to a
+ non-zero value indicating that we need to wait for the response to the
+ resolve call */
+ addr = Curl_getaddrinfo(conn,
#ifdef DEBUGBUILD
- (data->set.str[STRING_DEVICE]
- && !strcmp(data->set.str[STRING_DEVICE],
- "LocalHost"))?"localhost":
+ (data->set.str[STRING_DEVICE]
+ && !strcmp(data->set.str[STRING_DEVICE],
+ "LocalHost"))?"localhost":
#endif
- hostname, port, &respwait);
-
+ hostname, port, &respwait);
+ }
if(!addr) {
if(respwait) {
/* the response to our resolve call will come asynchronously at
a later time, good or bad */
/* First, check that we haven't received the info by now */
- result = Curl_resolver_is_resolved(conn, &dns);
+ result = Curl_resolv_check(conn, &dns);
if(result) /* error detected */
return CURLRESOLV_ERROR;
if(dns)
@@ -1053,3 +1058,54 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
return CURLE_OK;
}
+
+CURLcode Curl_resolv_check(struct connectdata *conn,
+ struct Curl_dns_entry **dns)
+{
+ if(conn->data->set.doh)
+ return Curl_doh_is_resolved(conn, dns);
+ return Curl_resolver_is_resolved(conn, dns);
+}
+
+int Curl_resolv_getsock(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks)
+{
+#ifdef CURLRES_ASYNCH
+ if(conn->data->set.doh)
+ /* nothing to wait for during DOH resolve, those handles have their own
+ sockets */
+ return GETSOCK_BLANK;
+ return Curl_resolver_getsock(conn, socks, numsocks);
+#else
+ (void)conn;
+ (void)socks;
+ (void)numsocks;
+ return GETSOCK_BLANK;
+#endif
+}
+
+/* Call this function after Curl_connect() has returned async=TRUE and
+ then a successful name resolve has been received.
+
+ Note: this function disconnects and frees the conn data in case of
+ resolve failure */
+CURLcode Curl_once_resolved(struct connectdata *conn,
+ bool *protocol_done)
+{
+ CURLcode result;
+
+ if(conn->async.dns) {
+ conn->dns_entry = conn->async.dns;
+ conn->async.dns = NULL;
+ }
+
+ result = Curl_setup_conn(conn, protocol_done);
+
+ if(result)
+ /* We're not allowed to return failure with memory left allocated
+ in the connectdata struct, free those here */
+ Curl_disconnect(conn->data, conn, TRUE); /* close the connection */
+
+ return result;
+}
diff --git a/lib/hostip.h b/lib/hostip.h
index 1de4bee8..29fd1ef7 100644
--- a/lib/hostip.h
+++ b/lib/hostip.h
@@ -145,12 +145,7 @@ int curl_dogetnameinfo(GETNAMEINFO_QUAL_ARG1 GETNAMEINFO_TYPE_ARG1 sa,
/* IPv4 threadsafe resolve function used for synch and asynch builds */
Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, int port);
-CURLcode Curl_async_resolved(struct connectdata *conn,
- bool *protocol_connect);
-
-#ifndef CURLRES_ASYNCH
-#define Curl_async_resolved(x,y) CURLE_OK
-#endif
+CURLcode Curl_once_resolved(struct connectdata *conn, bool *protocol_connect);
/*
* Curl_addrinfo_callback() is used when we build with any asynch specialty.
@@ -258,4 +253,10 @@ void Curl_hostcache_destroy(struct Curl_easy *data);
*/
CURLcode Curl_loadhostpairs(struct Curl_easy *data);
+CURLcode Curl_resolv_check(struct connectdata *conn,
+ struct Curl_dns_entry **dns);
+int Curl_resolv_getsock(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks);
+
#endif /* HEADER_CURL_HOSTIP_H */
diff --git a/lib/http.c b/lib/http.c
index e727ed82..46ac15a6 100644
--- a/lib/http.c
+++ b/lib/http.c
@@ -169,7 +169,7 @@ CURLcode Curl_http_setup_conn(struct connectdata *conn)
data->req.protop = http;
if(!CONN_INUSE(conn))
- /* if not alredy multi-using, setup connection details */
+ /* if not already multi-using, setup connection details */
Curl_http2_setup_conn(conn);
Curl_http2_setup_req(data);
return CURLE_OK;
@@ -537,14 +537,6 @@ CURLcode Curl_http_auth_act(struct connectdata *conn)
}
if(pickhost || pickproxy) {
- /* In case this is GSS auth, the newurl field is already allocated so
- we must make sure to free it before allocating a new one. As figured
- out in bug #2284386 */
- Curl_safefree(data->req.newurl);
- data->req.newurl = strdup(data->change.url); /* clone URL */
- if(!data->req.newurl)
- return CURLE_OUT_OF_MEMORY;
-
if((data->set.httpreq != HTTPREQ_GET) &&
(data->set.httpreq != HTTPREQ_HEAD) &&
!conn->bits.rewindaftersend) {
@@ -552,6 +544,13 @@ CURLcode Curl_http_auth_act(struct connectdata *conn)
if(result)
return result;
}
+ /* In case this is GSS auth, the newurl field is already allocated so
+ we must make sure to free it before allocating a new one. As figured
+ out in bug #2284386 */
+ Curl_safefree(data->req.newurl);
+ data->req.newurl = strdup(data->change.url); /* clone URL */
+ if(!data->req.newurl)
+ return CURLE_OUT_OF_MEMORY;
}
else if((data->req.httpcode < 300) &&
(!data->state.authhost.done) &&
@@ -1094,11 +1093,13 @@ Curl_send_buffer *Curl_add_buffer_init(void)
/*
* Curl_add_buffer_free() frees all associated resources.
*/
-void Curl_add_buffer_free(Curl_send_buffer *buff)
+void Curl_add_buffer_free(Curl_send_buffer **inp)
{
- if(buff) /* deal with NULL input */
- free(buff->buffer);
- free(buff);
+ Curl_send_buffer *in = *inp;
+ if(in) /* deal with NULL input */
+ free(in->buffer);
+ free(in);
+ *inp = NULL;
}
/*
@@ -1107,7 +1108,7 @@ void Curl_add_buffer_free(Curl_send_buffer *buff)
*
* Returns CURLcode
*/
-CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
+CURLcode Curl_add_buffer_send(Curl_send_buffer **inp,
struct connectdata *conn,
/* add the number of sent bytes to this
@@ -1128,6 +1129,7 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
size_t sendsize;
curl_socket_t sockfd;
size_t headersize;
+ Curl_send_buffer *in = *inp;
DEBUGASSERT(socketindex <= SECONDARYSOCKET);
@@ -1148,7 +1150,7 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
/* Curl_convert_to_network calls failf if unsuccessful */
if(result) {
/* conversion failed, free memory and return to the caller */
- Curl_add_buffer_free(in);
+ Curl_add_buffer_free(inp);
return result;
}
@@ -1172,7 +1174,7 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
result = Curl_get_upload_buffer(data);
if(result) {
/* malloc failed, free memory and return to the caller */
- Curl_add_buffer_free(in);
+ Curl_add_buffer_free(&in);
return result;
}
memcpy(data->state.ulbuf, ptr, sendsize);
@@ -1256,7 +1258,7 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
Curl_pipeline_leave_write(conn);
}
}
- Curl_add_buffer_free(in);
+ Curl_add_buffer_free(&in);
return result;
}
@@ -1265,31 +1267,35 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
/*
* add_bufferf() add the formatted input to the buffer.
*/
-CURLcode Curl_add_bufferf(Curl_send_buffer *in, const char *fmt, ...)
+CURLcode Curl_add_bufferf(Curl_send_buffer **inp, const char *fmt, ...)
{
char *s;
va_list ap;
+ Curl_send_buffer *in = *inp;
va_start(ap, fmt);
s = vaprintf(fmt, ap); /* this allocs a new string to append */
va_end(ap);
if(s) {
- CURLcode result = Curl_add_buffer(in, s, strlen(s));
+ CURLcode result = Curl_add_buffer(inp, s, strlen(s));
free(s);
return result;
}
/* If we failed, we cleanup the whole buffer and return error */
free(in->buffer);
free(in);
+ *inp = NULL;
return CURLE_OUT_OF_MEMORY;
}
/*
- * add_buffer() appends a memory chunk to the existing buffer
+ * Curl_add_buffer() appends a memory chunk to the existing buffer
*/
-CURLcode Curl_add_buffer(Curl_send_buffer *in, const void *inptr, size_t size)
+CURLcode Curl_add_buffer(Curl_send_buffer **inp, const void *inptr,
+ size_t size)
{
char *new_rb;
+ Curl_send_buffer *in = *inp;
if(~size < in->size_used) {
/* If resulting used size of send buffer would wrap size_t, cleanup
@@ -1297,6 +1303,7 @@ CURLcode Curl_add_buffer(Curl_send_buffer *in, const void *inptr, size_t size)
size will fit into a single allocatable memory chunk */
Curl_safefree(in->buffer);
free(in);
+ *inp = NULL;
return CURLE_OUT_OF_MEMORY;
}
@@ -1323,6 +1330,7 @@ CURLcode Curl_add_buffer(Curl_send_buffer *in, const void *inptr, size_t size)
if(!new_rb) {
/* If we failed, we cleanup the whole buffer and return error */
free(in);
+ *inp = NULL;
return CURLE_OUT_OF_MEMORY;
}
@@ -1484,11 +1492,11 @@ static CURLcode add_haproxy_protocol_header(struct connectdata *conn)
if(!req_buffer)
return CURLE_OUT_OF_MEMORY;
- result = Curl_add_bufferf(req_buffer, proxy_header);
+ result = Curl_add_bufferf(&req_buffer, proxy_header);
if(result)
return result;
- result = Curl_add_buffer_send(req_buffer,
+ result = Curl_add_buffer_send(&req_buffer,
conn,
&conn->data->info.request_size,
0,
@@ -1561,8 +1569,7 @@ CURLcode Curl_http_done(struct connectdata *conn,
return CURLE_OK;
if(http->send_buffer) {
- Curl_add_buffer_free(http->send_buffer);
- http->send_buffer = NULL; /* clear the pointer */
+ Curl_add_buffer_free(&http->send_buffer);
}
Curl_http2_done(conn, premature);
@@ -1653,8 +1660,8 @@ static CURLcode expect100(struct Curl_easy *data,
Curl_compareheader(ptr, "Expect:", "100-continue");
}
else {
- result = Curl_add_bufferf(req_buffer,
- "Expect: 100-continue\r\n");
+ result = Curl_add_bufferf(&req_buffer,
+ "Expect: 100-continue\r\n");
if(!result)
data->state.expect100header = TRUE;
}
@@ -1785,7 +1792,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
!strcasecompare(data->state.first_host, conn->host.name)))
;
else {
- result = Curl_add_bufferf(req_buffer, "%s\r\n", headers->data);
+ result = Curl_add_bufferf(&req_buffer, "%s\r\n", headers->data);
}
if(semicolonp)
*semicolonp = ';'; /* put back the semicolon */
@@ -1854,7 +1861,7 @@ CURLcode Curl_add_timecondition(struct Curl_easy *data,
tm->tm_min,
tm->tm_sec);
- result = Curl_add_buffer(req_buffer, datestr, strlen(datestr));
+ result = Curl_add_buffer(&req_buffer, datestr, strlen(datestr));
return result;
}
@@ -1869,7 +1876,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
struct Curl_easy *data = conn->data;
CURLcode result = CURLE_OK;
struct HTTP *http;
- const char *ppath = data->state.path;
+ const char *path = data->state.up.path;
+ const char *query = data->state.up.query;
bool paste_ftp_userpwd = FALSE;
char ftp_typecode[sizeof("/;type=?")] = "";
const char *host = conn->host.name;
@@ -1987,7 +1995,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
}
/* setup the authentication headers */
- result = Curl_http_output_auth(conn, request, ppath, FALSE);
+ result = Curl_http_output_auth(conn, request, path, FALSE);
if(result)
return result;
@@ -2215,47 +2223,59 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
/* The path sent to the proxy is in fact the entire URL. But if the remote
host is a IDN-name, we must make sure that the request we produce only
uses the encoded host name! */
+
+ /* and no fragment part */
+ CURLUcode uc;
+ char *url;
+ CURLU *h = curl_url_dup(data->state.uh);
+ if(!h)
+ return CURLE_OUT_OF_MEMORY;
+
if(conn->host.dispname != conn->host.name) {
- char *url = data->change.url;
- ptr = strstr(url, conn->host.dispname);
- if(ptr) {
- /* This is where the display name starts in the URL, now replace this
- part with the encoded name. TODO: This method of replacing the host
- name is rather crude as I believe there's a slight risk that the
- user has entered a user name or password that contain the host name
- string. */
- size_t currlen = strlen(conn->host.dispname);
- size_t newlen = strlen(conn->host.name);
- size_t urllen = strlen(url);
-
- char *newurl;
-
- newurl = malloc(urllen + newlen - currlen + 1);
- if(newurl) {
- /* copy the part before the host name */
- memcpy(newurl, url, ptr - url);
- /* append the new host name instead of the old */
- memcpy(newurl + (ptr - url), conn->host.name, newlen);
- /* append the piece after the host name */
- memcpy(newurl + newlen + (ptr - url),
- ptr + currlen, /* copy the trailing zero byte too */
- urllen - (ptr-url) - currlen + 1);
- if(data->change.url_alloc) {
- Curl_safefree(data->change.url);
- data->change.url_alloc = FALSE;
- }
- data->change.url = newurl;
- data->change.url_alloc = TRUE;
- }
- else
- return CURLE_OUT_OF_MEMORY;
+ uc = curl_url_set(h, CURLUPART_HOST, conn->host.name, 0);
+ if(uc) {
+ curl_url_cleanup(h);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+ uc = curl_url_set(h, CURLUPART_FRAGMENT, NULL, 0);
+ if(uc) {
+ curl_url_cleanup(h);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ if(strcasecompare("http", data->state.up.scheme)) {
+ /* when getting HTTP, we don't want the userinfo the URL */
+ uc = curl_url_set(h, CURLUPART_USER, NULL, 0);
+ if(uc) {
+ curl_url_cleanup(h);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ uc = curl_url_set(h, CURLUPART_PASSWORD, NULL, 0);
+ if(uc) {
+ curl_url_cleanup(h);
+ return CURLE_OUT_OF_MEMORY;
}
}
- ppath = data->change.url;
- if(checkprefix("ftp://", ppath)) {
+ /* now extract the new version of the URL */
+ uc = curl_url_get(h, CURLUPART_URL, &url, 0);
+ if(uc) {
+ curl_url_cleanup(h);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ if(data->change.url_alloc)
+ free(data->change.url);
+
+ data->change.url = url;
+ data->change.url_alloc = TRUE;
+
+ curl_url_cleanup(h);
+
+ if(strcasecompare("ftp", data->state.up.scheme)) {
if(data->set.proxy_transfer_mode) {
/* when doing ftp, append ;type=<a|i> if not present */
- char *type = strstr(ppath, ";type=");
+ char *type = strstr(path, ";type=");
if(type && type[6] && type[7] == 0) {
switch(Curl_raw_toupper(type[6])) {
case 'A':
@@ -2270,7 +2290,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
char *p = ftp_typecode;
/* avoid sending invalid URLs like ftp://example.com;type=i if the
* user specified ftp://example.com without the slash */
- if(!*data->state.path && ppath[strlen(ppath) - 1] != '/') {
+ if(!*data->state.up.path && path[strlen(path) - 1] != '/') {
*p++ = '/';
}
snprintf(p, sizeof(ftp_typecode) - 1, ";type=%c",
@@ -2419,25 +2439,36 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
/* add the main request stuff */
/* GET/HEAD/POST/PUT */
- result = Curl_add_bufferf(req_buffer, "%s ", request);
+ result = Curl_add_bufferf(&req_buffer, "%s ", request);
if(result)
return result;
- if(data->set.str[STRING_TARGET])
- ppath = data->set.str[STRING_TARGET];
+ if(data->set.str[STRING_TARGET]) {
+ path = data->set.str[STRING_TARGET];
+ query = NULL;
+ }
/* url */
- if(paste_ftp_userpwd)
- result = Curl_add_bufferf(req_buffer, "ftp://%s:%s@%s",
+ if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
+ char *url = data->change.url;
+ result = Curl_add_buffer(&req_buffer, url, strlen(url));
+ }
+ else if(paste_ftp_userpwd)
+ result = Curl_add_bufferf(&req_buffer, "ftp://%s:%s@%s",
conn->user, conn->passwd,
- ppath + sizeof("ftp://") - 1);
- else
- result = Curl_add_buffer(req_buffer, ppath, strlen(ppath));
+ path + sizeof("ftp://") - 1);
+ else {
+ result = Curl_add_buffer(&req_buffer, path, strlen(path));
+ if(result)
+ return result;
+ if(query)
+ result = Curl_add_bufferf(&req_buffer, "?%s", query);
+ }
if(result)
return result;
result =
- Curl_add_bufferf(req_buffer,
+ Curl_add_bufferf(&req_buffer,
"%s" /* ftp typecode (;type=x) */
" HTTP/%s\r\n" /* HTTP version */
"%s" /* host */
@@ -2507,7 +2538,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
co = Curl_cookie_getlist(data->cookies,
conn->allocptr.cookiehost?
conn->allocptr.cookiehost:host,
- data->state.path,
+ data->state.up.path,
(conn->handler->protocol&CURLPROTO_HTTPS)?
TRUE:FALSE);
Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
@@ -2518,11 +2549,11 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
while(co) {
if(co->value) {
if(0 == count) {
- result = Curl_add_bufferf(req_buffer, "Cookie: ");
+ result = Curl_add_bufferf(&req_buffer, "Cookie: ");
if(result)
break;
}
- result = Curl_add_bufferf(req_buffer,
+ result = Curl_add_bufferf(&req_buffer,
"%s%s=%s", count?"; ":"",
co->name, co->value);
if(result)
@@ -2535,15 +2566,15 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
}
if(addcookies && !result) {
if(!count)
- result = Curl_add_bufferf(req_buffer, "Cookie: ");
+ result = Curl_add_bufferf(&req_buffer, "Cookie: ");
if(!result) {
- result = Curl_add_bufferf(req_buffer, "%s%s", count?"; ":"",
+ result = Curl_add_bufferf(&req_buffer, "%s%s", count?"; ":"",
addcookies);
count++;
}
}
if(count && !result)
- result = Curl_add_buffer(req_buffer, "\r\n", 2);
+ result = Curl_add_buffer(&req_buffer, "\r\n", 2);
if(result)
return result;
@@ -2577,7 +2608,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
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,
+ result = Curl_add_bufferf(&req_buffer,
"Content-Length: %" CURL_FORMAT_CURL_OFF_T
"\r\n", postsize);
if(result)
@@ -2590,7 +2621,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
return result;
}
- result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers */
+ result = Curl_add_buffer(&req_buffer, "\r\n", 2); /* end of headers */
if(result)
return result;
@@ -2598,7 +2629,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
Curl_pgrsSetUploadSize(data, postsize);
/* this sends the buffer and frees all the buffer resources */
- result = Curl_add_buffer_send(req_buffer, conn,
+ result = Curl_add_buffer_send(&req_buffer, conn,
&data->info.request_size, 0, FIRSTSOCKET);
if(result)
failf(data, "Failed sending PUT request");
@@ -2616,11 +2647,11 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
/* 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");
+ 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,
+ result = Curl_add_buffer_send(&req_buffer, conn,
&data->info.request_size, 0, FIRSTSOCKET);
if(result)
failf(data, "Failed sending POST request");
@@ -2640,7 +2671,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
(conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length"))) {
/* we allow replacing this header if not during auth negotiation,
although it isn't very wise to actually set your own */
- result = Curl_add_bufferf(req_buffer,
+ result = Curl_add_bufferf(&req_buffer,
"Content-Length: %" CURL_FORMAT_CURL_OFF_T
"\r\n", postsize);
if(result)
@@ -2652,7 +2683,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
struct curl_slist *hdr;
for(hdr = http->sendit->curlheaders; hdr; hdr = hdr->next) {
- result = Curl_add_bufferf(req_buffer, "%s\r\n", hdr->data);
+ result = Curl_add_bufferf(&req_buffer, "%s\r\n", hdr->data);
if(result)
return result;
}
@@ -2676,7 +2707,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
data->state.expect100header = FALSE;
/* 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);
if(result)
return result;
@@ -2689,7 +2720,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
http->sending = HTTPSEND_BODY;
/* this sends the buffer and frees all the buffer resources */
- result = Curl_add_buffer_send(req_buffer, conn,
+ result = Curl_add_buffer_send(&req_buffer, conn,
&data->info.request_size, 0, FIRSTSOCKET);
if(result)
failf(data, "Failed sending POST request");
@@ -2719,7 +2750,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
(conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length"))) {
/* we allow replacing this header if not during auth negotiation,
although it isn't very wise to actually set your own */
- result = Curl_add_bufferf(req_buffer,
+ result = Curl_add_bufferf(&req_buffer,
"Content-Length: %" CURL_FORMAT_CURL_OFF_T
"\r\n", postsize);
if(result)
@@ -2727,7 +2758,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
}
if(!Curl_checkheaders(conn, "Content-Type")) {
- result = Curl_add_bufferf(req_buffer,
+ result = Curl_add_bufferf(&req_buffer,
"Content-Type: application/"
"x-www-form-urlencoded\r\n");
if(result)
@@ -2765,31 +2796,31 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
is no magic limit but only set to prevent really huge POSTs to
get the data duplicated with malloc() and family. */
- result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
+ result = Curl_add_buffer(&req_buffer, "\r\n", 2); /* end of headers! */
if(result)
return result;
if(!data->req.upload_chunky) {
/* We're not sending it 'chunked', append it to the request
already now to reduce the number if send() calls */
- result = Curl_add_buffer(req_buffer, data->set.postfields,
+ result = Curl_add_buffer(&req_buffer, data->set.postfields,
(size_t)postsize);
included_body = postsize;
}
else {
if(postsize) {
/* Append the POST data chunky-style */
- result = Curl_add_bufferf(req_buffer, "%x\r\n", (int)postsize);
+ result = Curl_add_bufferf(&req_buffer, "%x\r\n", (int)postsize);
if(!result) {
- result = Curl_add_buffer(req_buffer, data->set.postfields,
+ result = Curl_add_buffer(&req_buffer, data->set.postfields,
(size_t)postsize);
if(!result)
- result = Curl_add_buffer(req_buffer, "\r\n", 2);
+ result = Curl_add_buffer(&req_buffer, "\r\n", 2);
included_body = postsize + 2;
}
}
if(!result)
- result = Curl_add_buffer(req_buffer, "\x30\x0d\x0a\x0d\x0a", 5);
+ result = Curl_add_buffer(&req_buffer, "\x30\x0d\x0a\x0d\x0a", 5);
/* 0 CR LF CR LF */
included_body += 5;
}
@@ -2811,20 +2842,20 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
/* set the upload size to the progress meter */
Curl_pgrsSetUploadSize(data, http->postsize);
- result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
+ result = Curl_add_buffer(&req_buffer, "\r\n", 2); /* end of headers! */
if(result)
return result;
}
}
else {
- result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
+ result = Curl_add_buffer(&req_buffer, "\r\n", 2); /* end of headers! */
if(result)
return result;
if(data->req.upload_chunky && conn->bits.authneg) {
/* Chunky upload is selected and we're negotiating auth still, send
end-of-data only */
- result = Curl_add_buffer(req_buffer,
+ result = Curl_add_buffer(&req_buffer,
"\x30\x0d\x0a\x0d\x0a", 5);
/* 0 CR LF CR LF */
if(result)
@@ -2845,7 +2876,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
}
}
/* issue the request */
- result = Curl_add_buffer_send(req_buffer, conn, &data->info.request_size,
+ result = Curl_add_buffer_send(&req_buffer, conn, &data->info.request_size,
(size_t)included_body, FIRSTSOCKET);
if(result)
@@ -2857,12 +2888,12 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
break;
default:
- result = Curl_add_buffer(req_buffer, "\r\n", 2);
+ result = Curl_add_buffer(&req_buffer, "\r\n", 2);
if(result)
return result;
/* issue the request */
- result = Curl_add_buffer_send(req_buffer, conn,
+ result = Curl_add_buffer_send(&req_buffer, conn,
&data->info.request_size, 0, FIRSTSOCKET);
if(result)
@@ -3828,7 +3859,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
here, or else use real peer host name. */
conn->allocptr.cookiehost?
conn->allocptr.cookiehost:conn->host.name,
- data->state.path);
+ data->state.up.path);
Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
}
#endif
diff --git a/lib/http.h b/lib/http.h
index 1d373e8f..21fa701a 100644
--- a/lib/http.h
+++ b/lib/http.h
@@ -58,10 +58,12 @@ struct Curl_send_buffer {
typedef struct Curl_send_buffer Curl_send_buffer;
Curl_send_buffer *Curl_add_buffer_init(void);
-void Curl_add_buffer_free(Curl_send_buffer *buff);
-CURLcode Curl_add_bufferf(Curl_send_buffer *in, const char *fmt, ...);
-CURLcode Curl_add_buffer(Curl_send_buffer *in, const void *inptr, size_t size);
-CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
+void Curl_add_buffer_free(Curl_send_buffer **inp);
+CURLcode Curl_add_bufferf(Curl_send_buffer **inp, const char *fmt, ...)
+ WARN_UNUSED_RESULT;
+CURLcode Curl_add_buffer(Curl_send_buffer **inp, const void *inptr,
+ size_t size) WARN_UNUSED_RESULT;
+CURLcode Curl_add_buffer_send(Curl_send_buffer **inp,
struct connectdata *conn,
long *bytes_written,
size_t included_body_bytes,
@@ -154,9 +156,11 @@ struct HTTP {
HTTPSEND_LAST /* never use this */
} sending;
- void *send_buffer; /* used if the request couldn't be sent in one chunk,
- points to an allocated send_buffer struct */
-
+#ifndef CURL_DISABLE_HTTP
+ Curl_send_buffer *send_buffer; /* used if the request couldn't be sent in
+ one chunk, points to an allocated
+ send_buffer struct */
+#endif
#ifdef USE_NGHTTP2
/*********** for HTTP/2 we store stream-local data here *************/
int32_t stream_id; /* stream we are interested in */
@@ -253,4 +257,3 @@ Curl_http_output_auth(struct connectdata *conn,
up the proxy tunnel */
#endif /* HEADER_CURL_HTTP_H */
-
diff --git a/lib/http2.c b/lib/http2.c
index d7691930..0c5f6db0 100644
--- a/lib/http2.c
+++ b/lib/http2.c
@@ -141,10 +141,8 @@ static int http2_getsock(struct connectdata *conn,
static void http2_stream_free(struct HTTP *http)
{
if(http) {
- Curl_add_buffer_free(http->header_recvbuf);
- http->header_recvbuf = NULL; /* clear the pointer */
- Curl_add_buffer_free(http->trailer_recvbuf);
- http->trailer_recvbuf = NULL; /* clear the pointer */
+ Curl_add_buffer_free(&http->header_recvbuf);
+ Curl_add_buffer_free(&http->trailer_recvbuf);
for(; http->push_headers_used > 0; --http->push_headers_used) {
free(http->push_headers[http->push_headers_used - 1]);
}
@@ -203,7 +201,7 @@ static bool http2_connisdead(struct connectdata *conn)
dead = !Curl_connalive(conn);
if(!dead) {
/* This happens before we've sent off a request and the connection is
- not in use by any other thransfer, there shouldn't be any data here,
+ not in use by any other transfer, there shouldn't be any data here,
only "protocol frames" */
CURLcode result;
struct http_conn *httpc = &conn->proto.httpc;
@@ -233,12 +231,43 @@ static unsigned int http2_conncheck(struct connectdata *check,
unsigned int checks_to_perform)
{
unsigned int ret_val = CONNRESULT_NONE;
+ struct http_conn *c = &check->proto.httpc;
+ int rc;
+ bool send_frames = false;
if(checks_to_perform & CONNCHECK_ISDEAD) {
if(http2_connisdead(check))
ret_val |= CONNRESULT_DEAD;
}
+ if(checks_to_perform & CONNCHECK_KEEPALIVE) {
+ struct curltime now = Curl_now();
+ time_t elapsed = Curl_timediff(now, check->keepalive);
+
+ if(elapsed > check->upkeep_interval_ms) {
+ /* Perform an HTTP/2 PING */
+ rc = nghttp2_submit_ping(c->h2, 0, ZERO_NULL);
+ if(!rc) {
+ /* Successfully added a PING frame to the session. Need to flag this
+ so the frame is sent. */
+ send_frames = true;
+ }
+ else {
+ failf(check->data, "nghttp2_submit_ping() failed: %s(%d)",
+ nghttp2_strerror(rc), rc);
+ }
+
+ check->keepalive = now;
+ }
+ }
+
+ if(send_frames) {
+ rc = nghttp2_session_send(c->h2);
+ if(rc)
+ failf(check->data, "nghttp2_session_send() failed: %s(%d)",
+ nghttp2_strerror(rc), rc);
+ }
+
return ret_val;
}
@@ -599,6 +628,7 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
int rv;
size_t left, ncopy;
int32_t stream_id = frame->hd.stream_id;
+ CURLcode result;
if(!stream_id) {
/* stream ID zero is for connection-oriented stuff */
@@ -674,7 +704,9 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
stream->status_code = -1;
}
- Curl_add_buffer(stream->header_recvbuf, "\r\n", 2);
+ result = Curl_add_buffer(&stream->header_recvbuf, "\r\n", 2);
+ if(result)
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
left = stream->header_recvbuf->size_used - stream->nread_header_recvbuf;
ncopy = CURLMIN(stream->len, left);
@@ -898,6 +930,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
struct Curl_easy *data_s;
int32_t stream_id = frame->hd.stream_id;
struct connectdata *conn = (struct connectdata *)userp;
+ CURLcode result;
(void)flags;
DEBUGASSERT(stream_id); /* should never be a zero stream ID here */
@@ -924,6 +957,8 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
stream->push_headers_alloc = 10;
stream->push_headers = malloc(stream->push_headers_alloc *
sizeof(char *));
+ if(!stream->push_headers)
+ return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
stream->push_headers_used = 0;
}
else if(stream->push_headers_used ==
@@ -952,11 +987,21 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
H2BUGF(infof(data_s, "h2 trailer: %.*s: %.*s\n", namelen, name, valuelen,
value));
- Curl_add_buffer(stream->trailer_recvbuf, &n, sizeof(n));
- Curl_add_buffer(stream->trailer_recvbuf, name, namelen);
- Curl_add_buffer(stream->trailer_recvbuf, ": ", 2);
- Curl_add_buffer(stream->trailer_recvbuf, value, valuelen);
- Curl_add_buffer(stream->trailer_recvbuf, "\r\n\0", 3);
+ result = Curl_add_buffer(&stream->trailer_recvbuf, &n, sizeof(n));
+ if(result)
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ result = Curl_add_buffer(&stream->trailer_recvbuf, name, namelen);
+ if(result)
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ result = Curl_add_buffer(&stream->trailer_recvbuf, ": ", 2);
+ if(result)
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ result = Curl_add_buffer(&stream->trailer_recvbuf, value, valuelen);
+ if(result)
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ result = Curl_add_buffer(&stream->trailer_recvbuf, "\r\n\0", 3);
+ if(result)
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
return 0;
}
@@ -969,10 +1014,16 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
stream->status_code = decode_status_code(value, valuelen);
DEBUGASSERT(stream->status_code != -1);
- Curl_add_buffer(stream->header_recvbuf, "HTTP/2 ", 7);
- Curl_add_buffer(stream->header_recvbuf, value, valuelen);
+ result = Curl_add_buffer(&stream->header_recvbuf, "HTTP/2 ", 7);
+ if(result)
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ result = Curl_add_buffer(&stream->header_recvbuf, value, valuelen);
+ if(result)
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
/* the space character after the status code is mandatory */
- Curl_add_buffer(stream->header_recvbuf, " \r\n", 3);
+ result = Curl_add_buffer(&stream->header_recvbuf, " \r\n", 3);
+ if(result)
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
/* if we receive data for another handle, wake that up */
if(conn->data != data_s)
Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
@@ -985,10 +1036,18 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
/* nghttp2 guarantees that namelen > 0, and :status was already
received, and this is not pseudo-header field . */
/* convert to a HTTP1-style header */
- Curl_add_buffer(stream->header_recvbuf, name, namelen);
- Curl_add_buffer(stream->header_recvbuf, ": ", 2);
- Curl_add_buffer(stream->header_recvbuf, value, valuelen);
- Curl_add_buffer(stream->header_recvbuf, "\r\n", 2);
+ result = Curl_add_buffer(&stream->header_recvbuf, name, namelen);
+ if(result)
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ result = Curl_add_buffer(&stream->header_recvbuf, ": ", 2);
+ if(result)
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ result = Curl_add_buffer(&stream->header_recvbuf, value, valuelen);
+ if(result)
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ result = Curl_add_buffer(&stream->header_recvbuf, "\r\n", 2);
+ if(result)
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
/* if we receive data for another handle, wake that up */
if(conn->data != data_s)
Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
@@ -1049,7 +1108,8 @@ static ssize_t data_source_read_callback(nghttp2_session *session,
return nread;
}
-#ifdef NGHTTP2_HAS_ERROR_CALLBACK
+#if defined(NGHTTP2_HAS_ERROR_CALLBACK) && \
+ !defined(CURL_DISABLE_VERBOSE_STRINGS)
static int error_callback(nghttp2_session *session,
const char *msg,
size_t len,
@@ -1085,17 +1145,11 @@ void Curl_http2_done(struct connectdata *conn, bool premature)
struct HTTP *http = data->req.protop;
struct http_conn *httpc = &conn->proto.httpc;
- if(!httpc->h2) /* not HTTP/2 ? */
- return;
-
- if(data->state.drain)
- drained_transfer(data, httpc);
-
+ /* there might be allocated resources done before this got the 'h2' pointer
+ setup */
if(http->header_recvbuf) {
- Curl_add_buffer_free(http->header_recvbuf);
- http->header_recvbuf = NULL; /* clear the pointer */
- Curl_add_buffer_free(http->trailer_recvbuf);
- http->trailer_recvbuf = NULL; /* clear the pointer */
+ Curl_add_buffer_free(&http->header_recvbuf);
+ Curl_add_buffer_free(&http->trailer_recvbuf);
if(http->push_headers) {
/* if they weren't used and then freed before */
for(; http->push_headers_used > 0; --http->push_headers_used) {
@@ -1106,6 +1160,12 @@ void Curl_http2_done(struct connectdata *conn, bool premature)
}
}
+ if(!httpc->h2) /* not HTTP/2 ? */
+ return;
+
+ if(data->state.drain)
+ drained_transfer(data, httpc);
+
if(premature) {
/* RST_STREAM */
if(!nghttp2_submit_rst_stream(httpc->h2, NGHTTP2_FLAG_NONE,
@@ -1167,7 +1227,9 @@ CURLcode Curl_http2_init(struct connectdata *conn)
/* nghttp2_on_header_callback */
nghttp2_session_callbacks_set_on_header_callback(callbacks, on_header);
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
nghttp2_session_callbacks_set_error_callback(callbacks, error_callback);
+#endif
/* The nghttp2 session is not yet setup, do it */
rc = nghttp2_session_client_new(&conn->proto.httpc.h2, callbacks, conn);
@@ -1204,7 +1266,7 @@ 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);
+ Curl_add_buffer_free(&req);
return CURLE_FAILED_INIT;
}
conn->proto.httpc.binlen = binlen;
@@ -1212,11 +1274,11 @@ CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req,
result = Curl_base64url_encode(conn->data, (const char *)binsettings, binlen,
&base64, &blen);
if(result) {
- Curl_add_buffer_free(req);
+ Curl_add_buffer_free(&req);
return result;
}
- result = Curl_add_bufferf(req,
+ result = Curl_add_bufferf(&req,
"Connection: Upgrade, HTTP2-Settings\r\n"
"Upgrade: %s\r\n"
"HTTP2-Settings: %s\r\n",
@@ -2060,8 +2122,11 @@ CURLcode Curl_http2_setup(struct connectdata *conn)
stream->stream_id = -1;
- if(!stream->header_recvbuf)
+ if(!stream->header_recvbuf) {
stream->header_recvbuf = Curl_add_buffer_init();
+ if(!stream->header_recvbuf)
+ return CURLE_OUT_OF_MEMORY;
+ }
if((conn->handler == &Curl_handler_http2_ssl) ||
(conn->handler == &Curl_handler_http2))
@@ -2073,8 +2138,10 @@ CURLcode Curl_http2_setup(struct connectdata *conn)
conn->handler = &Curl_handler_http2;
result = Curl_http2_init(conn);
- if(result)
+ if(result) {
+ Curl_add_buffer_free(&stream->header_recvbuf);
return result;
+ }
infof(conn->data, "Using HTTP2, server supports multi-use\n");
stream->upload_left = 0;
diff --git a/lib/http2.h b/lib/http2.h
index 21cd9b84..4492ec21 100644
--- a/lib/http2.h
+++ b/lib/http2.h
@@ -77,4 +77,3 @@ void Curl_http2_cleanup_dependencies(struct Curl_easy *data);
#endif
#endif /* HEADER_CURL_HTTP2_H */
-
diff --git a/lib/http_chunks.h b/lib/http_chunks.h
index 3a8b4ddf..b969c559 100644
--- a/lib/http_chunks.h
+++ b/lib/http_chunks.h
@@ -88,4 +88,3 @@ struct Curl_chunker {
};
#endif /* HEADER_CURL_HTTP_CHUNKS_H */
-
diff --git a/lib/http_proxy.c b/lib/http_proxy.c
index c8c445b8..2e0d92ed 100644
--- a/lib/http_proxy.c
+++ b/lib/http_proxy.c
@@ -222,7 +222,7 @@ static CURLcode CONNECT(struct connectdata *conn,
host_port = aprintf("%s:%d", hostname, remote_port);
if(!host_port) {
- Curl_add_buffer_free(req_buffer);
+ Curl_add_buffer_free(&req_buffer);
return CURLE_OUT_OF_MEMORY;
}
@@ -247,7 +247,7 @@ static CURLcode CONNECT(struct connectdata *conn,
aprintf("%s%s%s:%d", ipv6_ip?"[":"", hostname, ipv6_ip?"]":"",
remote_port);
if(!hostheader) {
- Curl_add_buffer_free(req_buffer);
+ Curl_add_buffer_free(&req_buffer);
return CURLE_OUT_OF_MEMORY;
}
@@ -255,7 +255,7 @@ static CURLcode CONNECT(struct connectdata *conn,
host = aprintf("Host: %s\r\n", hostheader);
if(!host) {
free(hostheader);
- Curl_add_buffer_free(req_buffer);
+ Curl_add_buffer_free(&req_buffer);
return CURLE_OUT_OF_MEMORY;
}
}
@@ -267,7 +267,7 @@ static CURLcode CONNECT(struct connectdata *conn,
useragent = conn->allocptr.uagent;
result =
- Curl_add_bufferf(req_buffer,
+ Curl_add_bufferf(&req_buffer,
"CONNECT %s HTTP/%s\r\n"
"%s" /* Host: */
"%s" /* Proxy-Authorization */
@@ -290,13 +290,13 @@ static CURLcode CONNECT(struct connectdata *conn,
if(!result)
/* CRLF terminate the request */
- result = Curl_add_bufferf(req_buffer, "\r\n");
+ result = Curl_add_bufferf(&req_buffer, "\r\n");
if(!result) {
/* Send the connect request to the proxy */
/* BLOCKING */
result =
- Curl_add_buffer_send(req_buffer, conn,
+ Curl_add_buffer_send(&req_buffer, conn,
&data->info.request_size, 0, sockindex);
}
req_buffer = NULL;
@@ -304,7 +304,7 @@ static CURLcode CONNECT(struct connectdata *conn,
failf(data, "Failed sending CONNECT to proxy");
}
- Curl_add_buffer_free(req_buffer);
+ Curl_add_buffer_free(&req_buffer);
if(result)
return result;
diff --git a/lib/imap.c b/lib/imap.c
index 942fe7d1..3ef89097 100644
--- a/lib/imap.c
+++ b/lib/imap.c
@@ -159,7 +159,8 @@ const struct Curl_handler Curl_handler_imaps = {
ZERO_NULL, /* connection_check */
PORT_IMAPS, /* defport */
CURLPROTO_IMAPS, /* protocol */
- PROTOPT_CLOSEACTION | PROTOPT_SSL /* flags */
+ PROTOPT_CLOSEACTION | PROTOPT_SSL | /* flags */
+ PROTOPT_URLOPTIONS
};
#endif
@@ -421,7 +422,6 @@ static CURLcode imap_perform_capability(struct connectdata *conn)
{
CURLcode result = CURLE_OK;
struct imap_conn *imapc = &conn->proto.imapc;
-
imapc->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanisms yet */
imapc->sasl.authused = SASL_AUTH_NONE; /* Clear the auth. mechanism used */
imapc->tls_supported = FALSE; /* Clear the TLS capability */
@@ -683,24 +683,37 @@ static CURLcode imap_perform_fetch(struct connectdata *conn)
{
CURLcode result = CURLE_OK;
struct IMAP *imap = conn->data->req.protop;
-
/* Check we have a UID */
- if(!imap->uid) {
- failf(conn->data, "Cannot FETCH without a UID.");
- return CURLE_URL_MALFORMAT;
+ if(imap->uid) {
+
+ /* Send the FETCH command */
+ if(imap->partial)
+ result = imap_sendf(conn, "UID FETCH %s BODY[%s]<%s>",
+ imap->uid,
+ imap->section ? imap->section : "",
+ imap->partial);
+ else
+ result = imap_sendf(conn, "UID FETCH %s BODY[%s]",
+ imap->uid,
+ imap->section ? imap->section : "");
+ }
+ else if(imap->mindex) {
+
+ /* Send the FETCH command */
+ if(imap->partial)
+ result = imap_sendf(conn, "FETCH %s BODY[%s]<%s>",
+ imap->mindex,
+ imap->section ? imap->section : "",
+ imap->partial);
+ else
+ result = imap_sendf(conn, "FETCH %s BODY[%s]",
+ imap->mindex,
+ imap->section ? imap->section : "");
+ }
+ else {
+ failf(conn->data, "Cannot FETCH without a UID.");
+ return CURLE_URL_MALFORMAT;
}
-
- /* Send the FETCH command */
- if(imap->partial)
- result = imap_sendf(conn, "FETCH %s BODY[%s]<%s>",
- imap->uid,
- imap->section ? imap->section : "",
- imap->partial);
- else
- result = imap_sendf(conn, "FETCH %s BODY[%s]",
- imap->uid,
- imap->section ? imap->section : "");
-
if(!result)
state(conn, IMAP_FETCH);
@@ -1464,9 +1477,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 || imap->mindex || data->set.upload ||
data->set.mimepost.kind != MIMEKIND_NONE)) {
/* Handle responses after FETCH or APPEND transfer has finished */
+
if(!data->set.upload && data->set.mimepost.kind == MIMEKIND_NONE)
state(conn, IMAP_FETCH_FINAL);
else {
@@ -1490,6 +1504,7 @@ static CURLcode imap_done(struct connectdata *conn, CURLcode status,
Curl_safefree(imap->mailbox);
Curl_safefree(imap->uidvalidity);
Curl_safefree(imap->uid);
+ Curl_safefree(imap->mindex);
Curl_safefree(imap->section);
Curl_safefree(imap->partial);
Curl_safefree(imap->query);
@@ -1543,14 +1558,14 @@ static CURLcode imap_perform(struct connectdata *conn, bool *connected,
else if(imap->custom && (selected || !imap->mailbox))
/* Custom command using the same mailbox or no mailbox */
result = imap_perform_list(conn);
- else if(!imap->custom && selected && imap->uid)
+ else if(!imap->custom && selected && (imap->uid || imap->mindex))
/* FETCH from the same mailbox */
result = imap_perform_fetch(conn);
else if(!imap->custom && selected && imap->query)
/* SEARCH the current mailbox */
result = imap_perform_search(conn);
else if(imap->mailbox && !selected &&
- (imap->custom || imap->uid || imap->query))
+ (imap->custom || imap->uid || imap->mindex || imap->query))
/* SELECT the mailbox */
result = imap_perform_select(conn);
else
@@ -1702,8 +1717,6 @@ static CURLcode imap_regular_transfer(struct connectdata *conn,
static CURLcode imap_setup_connection(struct connectdata *conn)
{
- struct Curl_easy *data = conn->data;
-
/* Initialise the IMAP layer */
CURLcode result = imap_init(conn);
if(result)
@@ -1711,7 +1724,6 @@ static CURLcode imap_setup_connection(struct connectdata *conn)
/* Clear the TLS upgraded flag */
conn->tls_upgraded = FALSE;
- data->state.path++; /* don't include the initial slash */
return CURLE_OK;
}
@@ -1944,7 +1956,7 @@ static CURLcode imap_parse_url_path(struct connectdata *conn)
CURLcode result = CURLE_OK;
struct Curl_easy *data = conn->data;
struct IMAP *imap = data->req.protop;
- const char *begin = data->state.path;
+ const char *begin = &data->state.up.path[1]; /* skip leading slash */
const char *ptr = begin;
/* See how much of the URL is a valid path and decode it */
@@ -2016,6 +2028,13 @@ static CURLcode imap_parse_url_path(struct connectdata *conn)
imap->uid = value;
value = NULL;
}
+ else if(strcasecompare(name, "MAILINDEX") && !imap->mindex) {
+ if(valuelen > 0 && value[valuelen - 1] == '/')
+ value[valuelen - 1] = '\0';
+
+ imap->mindex = value;
+ value = NULL;
+ }
else if(strcasecompare(name, "SECTION") && !imap->section) {
if(valuelen > 0 && value[valuelen - 1] == '/')
value[valuelen - 1] = '\0';
@@ -2043,17 +2062,10 @@ static CURLcode imap_parse_url_path(struct connectdata *conn)
/* Does the URL contain a query parameter? Only valid when we have a mailbox
and no UID as per RFC-5092 */
- if(imap->mailbox && !imap->uid && *ptr == '?') {
- /* Find the length of the query parameter */
- begin = ++ptr;
- while(imap_is_bchar(*ptr))
- ptr++;
-
- /* Decode the query parameter */
- result = Curl_urldecode(data, begin, ptr - begin, &imap->query, NULL,
- TRUE);
- if(result)
- return result;
+ if(imap->mailbox && !imap->uid && !imap->mindex) {
+ /* Get the query parameter, URL decoded */
+ (void)curl_url_get(data->state.uh, CURLUPART_QUERY, &imap->query,
+ CURLU_URLDECODE);
}
/* Any extra stuff at the end of the URL is an error */
diff --git a/lib/imap.h b/lib/imap.h
index 9fc4ff5a..0efcfd29 100644
--- a/lib/imap.h
+++ b/lib/imap.h
@@ -58,6 +58,7 @@ struct IMAP {
char *mailbox; /* Mailbox to select */
char *uidvalidity; /* UIDVALIDITY to check in select */
char *uid; /* Message UID to fetch */
+ char *mindex; /* Index in mail box of mail to fetch */
char *section; /* Message SECTION to fetch */
char *partial; /* Message PARTIAL to fetch */
char *query; /* Query to search for */
diff --git a/lib/inet_ntop.h b/lib/inet_ntop.h
index 9f446127..d150bb69 100644
--- a/lib/inet_ntop.h
+++ b/lib/inet_ntop.h
@@ -35,4 +35,3 @@ char *Curl_inet_ntop(int af, const void *addr, char *buf, size_t size);
#endif
#endif /* HEADER_CURL_INET_NTOP_H */
-
diff --git a/lib/inet_pton.h b/lib/inet_pton.h
index e216f4ef..0209b9b7 100644
--- a/lib/inet_pton.h
+++ b/lib/inet_pton.h
@@ -37,4 +37,3 @@ int Curl_inet_pton(int, const char *, void *);
#endif
#endif /* HEADER_CURL_INET_PTON_H */
-
diff --git a/lib/krb5.c b/lib/krb5.c
index 8b5a2472..e51dcd1c 100644
--- a/lib/krb5.c
+++ b/lib/krb5.c
@@ -206,7 +206,7 @@ krb5_auth(void *app_data, struct connectdata *conn)
if(maj != GSS_S_COMPLETE) {
gss_release_name(&min, &gssname);
if(service == srv_host) {
- Curl_failf(data, "Error importing service name %s@%s", service, host);
+ failf(data, "Error importing service name %s@%s", service, host);
return AUTH_ERROR;
}
service = srv_host;
@@ -265,6 +265,7 @@ krb5_auth(void *app_data, struct connectdata *conn)
result = CURLE_OUT_OF_MEMORY;
free(p);
+ free(cmd);
if(result) {
ret = -2;
@@ -290,8 +291,7 @@ krb5_auth(void *app_data, struct connectdata *conn)
(unsigned char **)&_gssresp.value,
&_gssresp.length);
if(result) {
- Curl_failf(data, "base64-decoding: %s",
- curl_easy_strerror(result));
+ failf(data, "base64-decoding: %s", curl_easy_strerror(result));
ret = AUTH_CONTINUE;
break;
}
diff --git a/lib/ldap.c b/lib/ldap.c
index 4d8f4fa2..ceaa71d0 100644
--- a/lib/ldap.c
+++ b/lib/ldap.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2018, 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
@@ -474,7 +474,13 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
#endif
}
if(rc != 0) {
- failf(data, "LDAP local: ldap_simple_bind_s %s", ldap_err2string(rc));
+#ifdef USE_WIN32_LDAP
+ failf(data, "LDAP local: bind via ldap_win_bind %s",
+ ldap_err2string(rc));
+#else
+ failf(data, "LDAP local: bind via ldap_simple_bind_s %s",
+ ldap_err2string(rc));
+#endif
result = CURLE_LDAP_CANNOT_BIND;
goto quit;
}
@@ -838,9 +844,9 @@ static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp)
size_t i;
if(!conn->data ||
- !conn->data->state.path ||
- conn->data->state.path[0] != '/' ||
- !checkprefix("LDAP", conn->data->change.url))
+ !conn->data->state.up.path ||
+ conn->data->state.up.path[0] != '/' ||
+ !strcasecompare("LDAP", conn->data->state.up.scheme))
return LDAP_INVALID_SYNTAX;
ludp->lud_scope = LDAP_SCOPE_BASE;
@@ -848,7 +854,7 @@ static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp)
ludp->lud_host = conn->host.name;
/* Duplicate the path */
- p = path = strdup(conn->data->state.path + 1);
+ p = path = strdup(conn->data->state.up.path + 1);
if(!path)
return LDAP_NO_MEMORY;
diff --git a/lib/libcurl.plist b/lib/libcurl.plist
index dfe6921a..54d0480b 100644
--- a/lib/libcurl.plist
+++ b/lib/libcurl.plist
@@ -15,7 +15,7 @@
<string>se.haxx.curl.libcurl</string>
<key>CFBundleVersion</key>
- <string>7.61.1</string>
+ <string>7.62.0</string>
<key>CFBundleName</key>
<string>libcurl</string>
@@ -27,9 +27,9 @@
<string>????</string>
<key>CFBundleShortVersionString</key>
- <string>libcurl 7.61.1</string>
+ <string>libcurl 7.62.0</string>
<key>CFBundleGetInfoString</key>
- <string>libcurl.plist 7.61.1</string>
+ <string>libcurl.plist 7.62.0</string>
</dict>
</plist>
diff --git a/lib/llist.h b/lib/llist.h
index 6b644b99..b9d4c89a 100644
--- a/lib/llist.h
+++ b/lib/llist.h
@@ -51,4 +51,3 @@ void Curl_llist_move(struct curl_llist *, struct curl_llist_element *,
struct curl_llist *, struct curl_llist_element *);
#endif /* HEADER_CURL_LLIST_H */
-
diff --git a/lib/makefile.amiga b/lib/makefile.amiga
index c692e5eb..673b147c 100644
--- a/lib/makefile.amiga
+++ b/lib/makefile.amiga
@@ -4,16 +4,16 @@
# change the follow to where you have the AmiTCP SDK v4.3 includes:
-ATCPSDKI= /GG/netinclude
+ATCPSDKI= /GG/netinclude
-CC = m68k-amigaos-gcc
-CFLAGS = -I$(ATCPSDKI) -m68020-60 -O2 -msoft-float -noixemul -g -I. -I../include -W -Wall
+CC = m68k-amigaos-gcc
+CFLAGS = -I$(ATCPSDKI) -m68020-60 -O2 -msoft-float -noixemul -g -I. -I../include -W -Wall
include Makefile.inc
OBJS = $(CSOURCES:.c=.o)
-all: $(OBJS)
+all: $(OBJS)
ar cru libcurl.a $(OBJS)
ranlib libcurl.a
diff --git a/lib/makefile.dj b/lib/makefile.dj
index 8ab2d575..941f8ce6 100644
--- a/lib/makefile.dj
+++ b/lib/makefile.dj
@@ -69,4 +69,3 @@ realclean vclean: clean
- $(DELETE) $(CURL_LIB)
-include depend.dj
-
diff --git a/lib/md4.c b/lib/md4.c
index 2bb7dcc2..d3506021 100644
--- a/lib/md4.c
+++ b/lib/md4.c
@@ -3,7 +3,7 @@
* MD4 Message-Digest Algorithm (RFC 1320).
*
* Homepage:
- http://openwall.info/wiki/people/solar/software/public-domain-source-code/md4
+ https://openwall.info/wiki/people/solar/software/public-domain-source-code/md4
*
* Author:
* Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
diff --git a/lib/md5.c b/lib/md5.c
index b819d392..45f45bbd 100644
--- a/lib/md5.c
+++ b/lib/md5.c
@@ -177,7 +177,7 @@ static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
* MD5 Message-Digest Algorithm (RFC 1321).
*
* Homepage:
- http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
+ https://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
*
* Author:
* Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
diff --git a/lib/multi.c b/lib/multi.c
index 0caf9432..0db2a973 100644
--- a/lib/multi.c
+++ b/lib/multi.c
@@ -347,6 +347,7 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
Curl_llist_init(&multi->pending, multi_freeamsg);
multi->max_pipeline_length = 5;
+ multi->pipelining = CURLPIPE_MULTIPLEX;
/* -1 means it not set by user, use the default value */
multi->maxconnects = -1;
@@ -491,6 +492,8 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
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;
+ data->state.conn_cache->closure_handle->set.no_signal =
+ data->set.no_signal;
update_timer(multi);
return CURLM_OK;
@@ -541,10 +544,8 @@ static CURLcode multi_done(struct connectdata **connp,
Curl_getoff_all_pipelines(data, conn);
/* Cleanup possible redirect junk */
- free(data->req.newurl);
- data->req.newurl = NULL;
- free(data->req.location);
- data->req.location = NULL;
+ Curl_safefree(data->req.newurl);
+ Curl_safefree(data->req.location);
switch(status) {
case CURLE_ABORTED_BY_CALLBACK:
@@ -656,7 +657,6 @@ static CURLcode multi_done(struct connectdata **connp,
cache here, and therefore cannot be used from this point on
*/
Curl_free_request_state(data);
-
return result;
}
@@ -905,7 +905,7 @@ static int multi_getsock(struct Curl_easy *data,
return 0;
case CURLM_STATE_WAITRESOLVE:
- return Curl_resolver_getsock(data->easy_conn, socks, numsocks);
+ return Curl_resolv_getsock(data->easy_conn, socks, numsocks);
case CURLM_STATE_PROTOCONNECT:
case CURLM_STATE_SENDPROTOCONNECT:
@@ -1009,13 +1009,6 @@ CURLMcode curl_multi_wait(struct Curl_multi *multi,
if(multi->in_callback)
return CURLM_RECURSIVE_API_CALL;
- /* If the internally desired timeout is actually shorter than requested from
- the outside, then use the shorter time! But only if the internal timer
- is actually larger than -1! */
- (void)multi_timeout(multi, &timeout_internal);
- if((timeout_internal >= 0) && (timeout_internal < (long)timeout_ms))
- timeout_ms = (int)timeout_internal;
-
/* Count up how many fds we have from the multi handle */
data = multi->easyp;
while(data) {
@@ -1040,6 +1033,13 @@ CURLMcode curl_multi_wait(struct Curl_multi *multi,
data = data->next; /* check next handle */
}
+ /* If the internally desired timeout is actually shorter than requested from
+ the outside, then use the shorter time! But only if the internal timer
+ is actually larger than -1! */
+ (void)multi_timeout(multi, &timeout_internal);
+ if((timeout_internal >= 0) && (timeout_internal < (long)timeout_ms))
+ timeout_ms = (int)timeout_internal;
+
curlfds = nfds; /* number of internal file descriptors */
nfds += extra_nfds; /* add the externally provided ones */
@@ -1235,7 +1235,7 @@ static CURLcode multi_reconnect_request(struct connectdata **connp)
return result;
/* Resolved, continue with the connection */
- result = Curl_async_resolved(conn, &protocol_done);
+ result = Curl_once_resolved(conn, &protocol_done);
if(result)
return result;
}
@@ -1511,7 +1511,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
if(!dns)
- result = Curl_resolver_is_resolved(data->easy_conn, &dns);
+ result = Curl_resolv_check(data->easy_conn, &dns);
/* Update sockets here, because the socket(s) may have been
closed and the application thus needs to be told, even if it
@@ -1524,10 +1524,10 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(dns) {
/* Perform the next step in the connection phase, and then move on
to the WAITCONNECT state */
- result = Curl_async_resolved(data->easy_conn, &protocol_connect);
+ result = Curl_once_resolved(data->easy_conn, &protocol_connect);
if(result)
- /* if Curl_async_resolved() returns failure, the connection struct
+ /* if Curl_once_resolved() returns failure, the connection struct
is already freed and gone */
data->easy_conn = NULL; /* no more connection */
else {
@@ -1608,7 +1608,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
case CURLM_STATE_SENDPROTOCONNECT:
result = Curl_protocol_connect(data->easy_conn, &protocol_connect);
- if(!protocol_connect)
+ if(!result && !protocol_connect)
/* switch to waiting state */
multistate(data, CURLM_STATE_PROTOCONNECT);
else if(!result) {
@@ -1707,7 +1707,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
char *newurl = NULL;
followtype follow = FOLLOW_NONE;
CURLcode drc;
- bool retry = FALSE;
drc = Curl_retry_request(data->easy_conn, &newurl);
if(drc) {
@@ -1715,15 +1714,13 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
result = drc;
stream_error = TRUE;
}
- else
- retry = (newurl)?TRUE:FALSE;
Curl_posttransfer(data);
drc = multi_done(&data->easy_conn, result, FALSE);
/* When set to retry the connection, we must to go back to
* the CONNECT state */
- if(retry) {
+ if(newurl) {
if(!drc || (drc == CURLE_SEND_ERROR)) {
follow = FOLLOW_RETRY;
drc = Curl_follow(data, newurl, follow);
@@ -1993,6 +1990,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
rc = CURLM_CALL_MULTI_PERFORM;
}
}
+ free(newurl);
}
else {
/* after the transfer is done, go DONE */
@@ -2004,18 +2002,21 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
newurl = data->req.location;
data->req.location = NULL;
result = Curl_follow(data, newurl, FOLLOW_FAKE);
- if(result)
+ free(newurl);
+ if(result) {
stream_error = TRUE;
+ result = multi_done(&data->easy_conn, result, TRUE);
+ }
}
- multistate(data, CURLM_STATE_DONE);
- rc = CURLM_CALL_MULTI_PERFORM;
+ if(!result) {
+ multistate(data, CURLM_STATE_DONE);
+ rc = CURLM_CALL_MULTI_PERFORM;
+ }
}
}
else if(comeback)
rc = CURLM_CALL_MULTI_PERFORM;
-
- free(newurl);
break;
}
@@ -2131,15 +2132,21 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
if(CURLM_STATE_COMPLETED == data->mstate) {
- /* now fill in the Curl_message with this info */
- msg = &data->msg;
+ if(data->set.fmultidone) {
+ /* signal via callback instead */
+ data->set.fmultidone(data, result);
+ }
+ else {
+ /* now fill in the Curl_message with this info */
+ msg = &data->msg;
- msg->extmsg.msg = CURLMSG_DONE;
- msg->extmsg.easy_handle = data;
- msg->extmsg.data.result = result;
+ msg->extmsg.msg = CURLMSG_DONE;
+ msg->extmsg.easy_handle = data;
+ msg->extmsg.data.result = result;
- rc = multi_addmsg(multi, msg);
- DEBUGASSERT(!data->easy_conn);
+ rc = multi_addmsg(multi, msg);
+ DEBUGASSERT(!data->easy_conn);
+ }
multistate(data, CURLM_STATE_MSGSENT);
}
} while((rc == CURLM_CALL_MULTI_PERFORM) || multi_ischanged(multi, FALSE));
@@ -2705,7 +2712,7 @@ CURLMcode curl_multi_setopt(struct Curl_multi *multi,
multi->push_userp = va_arg(param, void *);
break;
case CURLMOPT_PIPELINING:
- multi->pipelining = va_arg(param, long);
+ multi->pipelining = va_arg(param, long) & CURLPIPE_MULTIPLEX;
break;
case CURLMOPT_TIMERFUNCTION:
multi->timer_cb = va_arg(param, curl_multi_timer_callback);
diff --git a/lib/netrc.c b/lib/netrc.c
index a407bdaa..1724b35b 100644
--- a/lib/netrc.c
+++ b/lib/netrc.c
@@ -57,7 +57,11 @@ int Curl_parsenetrc(const char *host,
{
FILE *file;
int retcode = 1;
- int specific_login = (*loginp && **loginp != 0);
+ char *login = *loginp;
+ char *password = *passwordp;
+ bool specific_login = (login && *login != 0);
+ bool login_alloc = FALSE;
+ bool password_alloc = FALSE;
bool netrc_alloc = FALSE;
enum host_lookup_state state = NOTHING;
@@ -125,7 +129,7 @@ int Curl_parsenetrc(const char *host,
continue;
while(!done && tok) {
- if((*loginp && **loginp) && (*passwordp && **passwordp)) {
+ if((login && *login) && (password && *password)) {
done = TRUE;
break;
}
@@ -158,26 +162,34 @@ int Curl_parsenetrc(const char *host,
/* we are now parsing sub-keywords concerning "our" host */
if(state_login) {
if(specific_login) {
- state_our_login = strcasecompare(*loginp, tok);
+ state_our_login = strcasecompare(login, tok);
}
else {
- free(*loginp);
- *loginp = strdup(tok);
- if(!*loginp) {
+ if(login_alloc) {
+ free(login);
+ login_alloc = FALSE;
+ }
+ login = strdup(tok);
+ if(!login) {
retcode = -1; /* allocation failed */
goto out;
}
+ login_alloc = TRUE;
}
state_login = 0;
}
else if(state_password) {
if(state_our_login || !specific_login) {
- free(*passwordp);
- *passwordp = strdup(tok);
- if(!*passwordp) {
+ if(password_alloc) {
+ free(password);
+ password_alloc = FALSE;
+ }
+ password = strdup(tok);
+ if(!password) {
retcode = -1; /* allocation failed */
goto out;
}
+ password_alloc = TRUE;
}
state_password = 0;
}
@@ -198,6 +210,24 @@ int Curl_parsenetrc(const char *host,
} /* while fgets() */
out:
+ if(!retcode) {
+ if(login_alloc) {
+ if(*loginp)
+ free(*loginp);
+ *loginp = login;
+ }
+ if(password_alloc) {
+ if(*passwordp)
+ free(*passwordp);
+ *passwordp = password;
+ }
+ }
+ else {
+ if(login_alloc)
+ free(login);
+ if(password_alloc)
+ free(password);
+ }
fclose(file);
}
diff --git a/lib/nonblock.c b/lib/nonblock.c
index 5959281e..4d105c1f 100644
--- a/lib/nonblock.c
+++ b/lib/nonblock.c
@@ -48,7 +48,8 @@ int curlx_nonblock(curl_socket_t sockfd, /* operate on this */
int nonblock /* TRUE or FALSE */)
{
#if defined(USE_BLOCKING_SOCKETS)
-
+ (void)sockfd;
+ (void)nonblock;
return 0; /* returns success */
#elif defined(HAVE_FCNTL_O_NONBLOCK)
diff --git a/lib/nonblock.h b/lib/nonblock.h
index 98cdc25a..eb18ea1c 100644
--- a/lib/nonblock.h
+++ b/lib/nonblock.h
@@ -28,4 +28,3 @@ int curlx_nonblock(curl_socket_t sockfd, /* operate on this */
int nonblock /* TRUE or FALSE */);
#endif /* HEADER_CURL_NONBLOCK_H */
-
diff --git a/lib/nwlib.c b/lib/nwlib.c
index 215d933a..7bf5f51c 100644
--- a/lib/nwlib.c
+++ b/lib/nwlib.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2018, 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
@@ -195,7 +195,7 @@ int GetOrSetUpData(int id, libdata_t **appData,
if(!app_data->tenbytes || !app_data->lock) {
if(app_data->lock)
NXMutexFree(app_data->lock);
-
+ free(app_data->tenbytes);
free(app_data);
app_data = (libdata_t *) NULL;
err = ENOMEM;
@@ -213,6 +213,9 @@ int GetOrSetUpData(int id, libdata_t **appData,
err = set_app_data(gLibId, app_data);
if(err) {
+ if(app_data->lock)
+ NXMutexFree(app_data->lock);
+ free(app_data->tenbytes);
free(app_data);
app_data = (libdata_t *) NULL;
err = ENOMEM;
diff --git a/lib/parsedate.h b/lib/parsedate.h
index 2e59eb17..8dc3b90e 100644
--- a/lib/parsedate.h
+++ b/lib/parsedate.h
@@ -28,4 +28,3 @@ extern const char * const Curl_month[12];
CURLcode Curl_gmtime(time_t intime, struct tm *store);
#endif /* HEADER_CURL_PARSEDATE_H */
-
diff --git a/lib/pop3.c b/lib/pop3.c
index cd994f63..5e0fd229 100644
--- a/lib/pop3.c
+++ b/lib/pop3.c
@@ -1303,8 +1303,6 @@ static CURLcode pop3_regular_transfer(struct connectdata *conn,
static CURLcode pop3_setup_connection(struct connectdata *conn)
{
- struct Curl_easy *data = conn->data;
-
/* Initialise the POP3 layer */
CURLcode result = pop3_init(conn);
if(result)
@@ -1312,7 +1310,6 @@ static CURLcode pop3_setup_connection(struct connectdata *conn)
/* Clear the TLS upgraded flag */
conn->tls_upgraded = FALSE;
- data->state.path++; /* don't include the initial slash */
return CURLE_OK;
}
@@ -1387,7 +1384,7 @@ static CURLcode pop3_parse_url_path(struct connectdata *conn)
/* The POP3 struct is already initialised in pop3_connect() */
struct Curl_easy *data = conn->data;
struct POP3 *pop3 = data->req.protop;
- const char *path = data->state.path;
+ const char *path = &data->state.up.path[1]; /* skip leading path */
/* URL decode the path for the message ID */
return Curl_urldecode(data, path, 0, &pop3->id, NULL, TRUE);
diff --git a/lib/progress.h b/lib/progress.h
index 92dbcbd9..3515ac6d 100644
--- a/lib/progress.h
+++ b/lib/progress.h
@@ -62,4 +62,3 @@ timediff_t Curl_pgrsLimitWaitTime(curl_off_t cursize,
#define PGRS_HEADERS_OUT (1<<7) /* set when the headers have been written */
#endif /* HEADER_CURL_PROGRESS_H */
-
diff --git a/lib/rand.c b/lib/rand.c
index 1dc2504a..6ee45feb 100644
--- a/lib/rand.c
+++ b/lib/rand.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2018, 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
@@ -174,6 +174,8 @@ CURLcode Curl_rand_hex(struct Curl_easy *data, unsigned char *rnd,
return result;
while(num) {
+ /* clang-tidy warns on this line without this comment: */
+ /* NOLINTNEXTLINE(clang-analyzer-core.UndefinedBinaryOperatorResult) */
*rnd++ = hex[(*bufp & 0xF0)>>4];
*rnd++ = hex[*bufp & 0x0F];
bufp++;
diff --git a/lib/rtsp.c b/lib/rtsp.c
index 182ee295..01dfce64 100644
--- a/lib/rtsp.c
+++ b/lib/rtsp.c
@@ -462,7 +462,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
return CURLE_OUT_OF_MEMORY;
result =
- Curl_add_bufferf(req_buffer,
+ Curl_add_bufferf(&req_buffer,
"%s %s RTSP/1.0\r\n" /* Request Stream-URI RTSP/1.0 */
"CSeq: %ld\r\n", /* CSeq */
p_request, p_stream_uri, rtsp->CSeq_sent);
@@ -474,7 +474,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
* to make comparison easier
*/
if(p_session_id) {
- result = Curl_add_bufferf(req_buffer, "Session: %s\r\n", p_session_id);
+ result = Curl_add_bufferf(&req_buffer, "Session: %s\r\n", p_session_id);
if(result)
return result;
}
@@ -482,7 +482,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
/*
* Shared HTTP-like options
*/
- result = Curl_add_bufferf(req_buffer,
+ result = Curl_add_bufferf(&req_buffer,
"%s" /* transport */
"%s" /* accept */
"%s" /* accept-encoding */
@@ -541,9 +541,10 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
/* As stated in the http comments, it is probably not wise to
* actually set a custom Content-Length in the headers */
if(!Curl_checkheaders(conn, "Content-Length")) {
- result = Curl_add_bufferf(req_buffer,
- "Content-Length: %" CURL_FORMAT_CURL_OFF_T"\r\n",
- (data->set.upload ? putsize : postsize));
+ result =
+ Curl_add_bufferf(&req_buffer,
+ "Content-Length: %" CURL_FORMAT_CURL_OFF_T"\r\n",
+ (data->set.upload ? putsize : postsize));
if(result)
return result;
}
@@ -551,8 +552,8 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
if(rtspreq == RTSPREQ_SET_PARAMETER ||
rtspreq == RTSPREQ_GET_PARAMETER) {
if(!Curl_checkheaders(conn, "Content-Type")) {
- result = Curl_add_bufferf(req_buffer,
- "Content-Type: text/parameters\r\n");
+ result = Curl_add_bufferf(&req_buffer,
+ "Content-Type: text/parameters\r\n");
if(result)
return result;
}
@@ -560,8 +561,8 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
if(rtspreq == RTSPREQ_ANNOUNCE) {
if(!Curl_checkheaders(conn, "Content-Type")) {
- result = Curl_add_bufferf(req_buffer,
- "Content-Type: application/sdp\r\n");
+ result = Curl_add_bufferf(&req_buffer,
+ "Content-Type: application/sdp\r\n");
if(result)
return result;
}
@@ -579,19 +580,19 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
/* RTSP never allows chunked transfer */
data->req.forbidchunk = TRUE;
/* Finish the request buffer */
- result = Curl_add_buffer(req_buffer, "\r\n", 2);
+ result = Curl_add_buffer(&req_buffer, "\r\n", 2);
if(result)
return result;
if(postsize > 0) {
- result = Curl_add_buffer(req_buffer, data->set.postfields,
+ result = Curl_add_buffer(&req_buffer, data->set.postfields,
(size_t)postsize);
if(result)
return result;
}
/* issue the request */
- result = Curl_add_buffer_send(req_buffer, conn,
+ result = Curl_add_buffer_send(&req_buffer, conn,
&data->info.request_size, 0, FIRSTSOCKET);
if(result) {
failf(data, "Failed sending RTSP request");
diff --git a/lib/rtsp.h b/lib/rtsp.h
index 8375a531..2f9cc32c 100644
--- a/lib/rtsp.h
+++ b/lib/rtsp.h
@@ -64,4 +64,3 @@ struct RTSP {
#endif /* HEADER_CURL_RTSP_H */
-
diff --git a/lib/security.c b/lib/security.c
index abf242c3..6165d0af 100644
--- a/lib/security.c
+++ b/lib/security.c
@@ -61,7 +61,9 @@
#include "strcase.h"
#include "warnless.h"
#include "strdup.h"
-/* The last #include file should be: */
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
#include "memdebug.h"
static const struct {
@@ -422,7 +424,7 @@ static int sec_set_protection_level(struct connectdata *conn)
if(!conn->sec_complete) {
infof(conn->data, "Trying to change the protection level after the"
- "completion of the data exchange.\n");
+ " completion of the data exchange.\n");
return -1;
}
diff --git a/lib/select.h b/lib/select.h
index 4351786c..9a1ba45a 100644
--- a/lib/select.h
+++ b/lib/select.h
@@ -113,4 +113,3 @@ int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes,
#endif
#endif /* HEADER_CURL_SELECT_H */
-
diff --git a/lib/sendf.h b/lib/sendf.h
index 7627fe6c..c68b017d 100644
--- a/lib/sendf.h
+++ b/lib/sendf.h
@@ -36,7 +36,7 @@ void Curl_failf(struct Curl_easy *, const char *fmt, ...);
#elif defined(HAVE_VARIADIC_MACROS_GCC)
#define infof(x...) Curl_nop_stmt
#else
-#define infof (void)
+#error "missing VARIADIC macro define, fix and rebuild!"
#endif
#else /* CURL_DISABLE_VERBOSE_STRINGS */
diff --git a/lib/setopt.c b/lib/setopt.c
index 5c5f4b38..22956a20 100644
--- a/lib/setopt.c
+++ b/lib/setopt.c
@@ -127,9 +127,11 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
data->set.dns_cache_timeout = arg;
break;
case CURLOPT_DNS_USE_GLOBAL_CACHE:
+#if 0 /* deprecated */
/* remember we want this enabled */
arg = va_arg(param, long);
data->set.global_dns_cache = (0 != arg) ? TRUE : FALSE;
+#endif
break;
case CURLOPT_SSL_CIPHER_LIST:
/* set a list of cipher we want to use in the SSL connection */
@@ -841,6 +843,8 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
#else
if(arg > CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE)
return CURLE_UNSUPPORTED_PROTOCOL;
+ if(arg == CURL_HTTP_VERSION_NONE)
+ arg = CURL_HTTP_VERSION_2TLS;
#endif
data->set.httpversion = arg;
break;
@@ -1936,6 +1940,22 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
break;
+ case CURLOPT_UPLOAD_BUFFERSIZE:
+ /*
+ * The application kindly asks for a differently sized upload buffer.
+ * Cap it to sensible.
+ */
+ arg = va_arg(param, long);
+
+ if(arg > UPLOADBUFFER_MAX)
+ arg = UPLOADBUFFER_MAX;
+ else if(arg < UPLOADBUFFER_MIN)
+ arg = UPLOADBUFFER_MIN;
+
+ data->set.upload_buffer_size = arg;
+ Curl_safefree(data->state.ulbuf); /* force a realloc next opportunity */
+ break;
+
case CURLOPT_NOSIGNAL:
/*
* The application asks not to set any signal() or alarm() handlers,
@@ -2599,6 +2619,17 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
data->set.disallow_username_in_url =
(0 != va_arg(param, long)) ? TRUE : FALSE;
break;
+ case CURLOPT_DOH_URL:
+ result = Curl_setstropt(&data->set.str[STRING_DOH],
+ va_arg(param, char *));
+ data->set.doh = data->set.str[STRING_DOH]?TRUE:FALSE;
+ break;
+ case CURLOPT_UPKEEP_INTERVAL_MS:
+ arg = va_arg(param, long);
+ if(arg < 0)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.upkeep_interval_ms = arg;
+ break;
default:
/* unknown tag and its companion, just ignore: */
result = CURLE_UNKNOWN_OPTION;
diff --git a/lib/slist.c b/lib/slist.c
index e5adc0e7..392b84d1 100644
--- a/lib/slist.c
+++ b/lib/slist.c
@@ -142,4 +142,3 @@ void curl_slist_free_all(struct curl_slist *list)
item = next;
} while(next);
}
-
diff --git a/lib/slist.h b/lib/slist.h
index b3f498c3..d73dbf67 100644
--- a/lib/slist.h
+++ b/lib/slist.h
@@ -37,4 +37,3 @@ struct curl_slist *Curl_slist_append_nodup(struct curl_slist *list,
char *data);
#endif /* HEADER_CURL_SLIST_H */
-
diff --git a/lib/smb.c b/lib/smb.c
index e4b18fcf..e4f266e1 100644
--- a/lib/smb.c
+++ b/lib/smb.c
@@ -610,7 +610,8 @@ static CURLcode smb_send_and_recv(struct connectdata *conn, void **msg)
/* Check if there is data in the transfer buffer */
if(!smbc->send_size && smbc->upload_size) {
- size_t nread = smbc->upload_size > UPLOAD_BUFSIZE ? UPLOAD_BUFSIZE :
+ size_t nread = smbc->upload_size > conn->data->set.upload_buffer_size ?
+ conn->data->set.upload_buffer_size :
smbc->upload_size;
conn->data->req.upload_fromhere = conn->data->state.ulbuf;
result = Curl_fillreadbuffer(conn, nread, &nread);
@@ -968,7 +969,7 @@ static CURLcode smb_parse_url_path(struct connectdata *conn)
char *slash;
/* URL decode the path */
- result = Curl_urldecode(data, data->state.path, 0, &path, NULL, TRUE);
+ result = Curl_urldecode(data, data->state.up.path, 0, &path, NULL, TRUE);
if(result)
return result;
diff --git a/lib/smtp.c b/lib/smtp.c
index ecf10a41..58756230 100644
--- a/lib/smtp.c
+++ b/lib/smtp.c
@@ -1441,7 +1441,6 @@ static CURLcode smtp_regular_transfer(struct connectdata *conn,
static CURLcode smtp_setup_connection(struct connectdata *conn)
{
- struct Curl_easy *data = conn->data;
CURLcode result;
/* Clear the TLS upgraded flag */
@@ -1452,8 +1451,6 @@ static CURLcode smtp_setup_connection(struct connectdata *conn)
if(result)
return result;
- data->state.path++; /* don't include the initial slash */
-
return CURLE_OK;
}
@@ -1507,7 +1504,7 @@ static CURLcode smtp_parse_url_path(struct connectdata *conn)
/* The SMTP struct is already initialised in smtp_connect() */
struct Curl_easy *data = conn->data;
struct smtp_conn *smtpc = &conn->proto.smtpc;
- const char *path = data->state.path;
+ const char *path = &data->state.up.path[1]; /* skip leading path */
char localhost[HOSTNAME_MAX + 1];
/* Calculate the path if necessary */
@@ -1563,14 +1560,14 @@ CURLcode Curl_smtp_escape_eob(struct connectdata *conn, const ssize_t nread)
if(!scratch || data->set.crlf) {
oldscratch = scratch;
- scratch = newscratch = malloc(2 * UPLOAD_BUFSIZE);
+ scratch = newscratch = malloc(2 * data->set.upload_buffer_size);
if(!newscratch) {
failf(data, "Failed to alloc scratch buffer!");
return CURLE_OUT_OF_MEMORY;
}
}
- DEBUGASSERT(UPLOAD_BUFSIZE >= nread);
+ DEBUGASSERT(data->set.upload_buffer_size >= (size_t)nread);
/* Have we already sent part of the EOB? */
eob_sent = smtp->eob;
diff --git a/lib/sockaddr.h b/lib/sockaddr.h
index 95ba4c3c..db146803 100644
--- a/lib/sockaddr.h
+++ b/lib/sockaddr.h
@@ -40,4 +40,3 @@ struct Curl_sockaddr_storage {
};
#endif /* HEADER_CURL_SOCKADDR_H */
-
diff --git a/lib/socks.c b/lib/socks.c
index 81f3eda2..d2209ad8 100644
--- a/lib/socks.c
+++ b/lib/socks.c
@@ -98,7 +98,7 @@ int Curl_blockread_all(struct connectdata *conn, /* connection data */
* destination server.
*
* Reference :
-* http://socks.permeo.com/protocol/socks4.protocol
+* https://www.openssh.com/txt/socks4.protocol
*
* Note :
* Set protocol4a=true for "SOCKS 4A (Simple Extension to SOCKS 4 Protocol)"
@@ -789,4 +789,3 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
}
#endif /* CURL_DISABLE_PROXY */
-
diff --git a/lib/socks.h b/lib/socks.h
index 348707e7..daa07c12 100644
--- a/lib/socks.h
+++ b/lib/socks.h
@@ -73,4 +73,3 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
#endif /* CURL_DISABLE_PROXY */
#endif /* HEADER_CURL_SOCKS_H */
-
diff --git a/lib/splay.c b/lib/splay.c
index c54a63bb..baf07e00 100644
--- a/lib/splay.c
+++ b/lib/splay.c
@@ -274,4 +274,3 @@ int Curl_splayremovebyaddr(struct Curl_tree *t,
return 0;
}
-
diff --git a/lib/ssh.c b/lib/ssh.c
index a4b2ca43..da896196 100644
--- a/lib/ssh.c
+++ b/lib/ssh.c
@@ -2926,7 +2926,7 @@ static CURLcode ssh_connect(struct connectdata *conn, bool *done)
int rc;
ssh->kh = libssh2_knownhost_init(ssh->ssh_session);
if(!ssh->kh) {
- /* eeek. TODO: free the ssh_session! */
+ libssh2_session_free(ssh->ssh_session);
return CURLE_FAILED_INIT;
}
diff --git a/lib/strdup.c b/lib/strdup.c
index 19cb0441..51e7978b 100644
--- a/lib/strdup.c
+++ b/lib/strdup.c
@@ -81,7 +81,7 @@ void *Curl_memdup(const void *src, size_t length)
* Curl_saferealloc(ptr, size)
*
* Does a normal realloc(), but will free the data pointer if the realloc
- * fails. If 'size' is zero, it will free the data and return a failure.
+ * fails. If 'size' is non-zero, it will free the data and return a failure.
*
* This convenience function is provided and used to help us avoid a common
* mistake pattern when we could pass in a zero, catch the NULL return and end
diff --git a/lib/strerror.c b/lib/strerror.c
index 0295d6c2..47ef44a6 100644
--- a/lib/strerror.c
+++ b/lib/strerror.c
@@ -191,9 +191,6 @@ curl_easy_strerror(CURLcode error)
case CURLE_TELNET_OPTION_SYNTAX :
return "Malformed telnet option";
- case CURLE_PEER_FAILED_VERIFICATION:
- return "SSL peer certificate or SSH remote key was not OK";
-
case CURLE_GOT_NOTHING:
return "Server returned nothing (no headers, no data)";
@@ -218,9 +215,8 @@ curl_easy_strerror(CURLcode error)
case CURLE_SSL_CIPHER:
return "Couldn't use specified SSL cipher";
- case CURLE_SSL_CACERT:
- return "Peer certificate cannot be authenticated with given CA "
- "certificates";
+ case CURLE_PEER_FAILED_VERIFICATION:
+ return "SSL peer certificate or SSH remote key was not OK";
case CURLE_SSL_CACERT_BADFILE:
return "Problem with the SSL CA cert (path? access rights?)";
@@ -324,6 +320,7 @@ curl_easy_strerror(CURLcode error)
case CURLE_OBSOLETE44:
case CURLE_OBSOLETE46:
case CURLE_OBSOLETE50:
+ case CURLE_OBSOLETE51:
case CURLE_OBSOLETE57:
case CURL_LAST:
break;
diff --git a/lib/telnet.h b/lib/telnet.h
index 419a399b..668a78a1 100644
--- a/lib/telnet.h
+++ b/lib/telnet.h
@@ -26,4 +26,3 @@ extern const struct Curl_handler Curl_handler_telnet;
#endif
#endif /* HEADER_CURL_TELNET_H */
-
diff --git a/lib/tftp.c b/lib/tftp.c
index e5bc80b0..5b74e8e0 100644
--- a/lib/tftp.c
+++ b/lib/tftp.c
@@ -485,7 +485,7 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
/* As RFC3617 describes the separator slash is not actually part of the
file name so we skip the always-present first letter of the path
string. */
- result = Curl_urldecode(data, &state->conn->data->state.path[1], 0,
+ result = Curl_urldecode(data, &state->conn->data->state.up.path[1], 0,
&filename, NULL, FALSE);
if(result)
return result;
@@ -1374,7 +1374,7 @@ static CURLcode tftp_setup_connection(struct connectdata * conn)
/* TFTP URLs support an extension like ";mode=<typecode>" that
* we'll try to get now! */
- type = strstr(data->state.path, ";mode=");
+ type = strstr(data->state.up.path, ";mode=");
if(!type)
type = strstr(conn->host.rawalloc, ";mode=");
diff --git a/lib/tftp.h b/lib/tftp.h
index c2325b23..1335f64b 100644
--- a/lib/tftp.h
+++ b/lib/tftp.h
@@ -26,4 +26,3 @@ extern const struct Curl_handler Curl_handler_tftp;
#endif
#endif /* HEADER_CURL_TFTP_H */
-
diff --git a/lib/timeval.c b/lib/timeval.c
index f4bf8353..dce1a761 100644
--- a/lib/timeval.c
+++ b/lib/timeval.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -33,7 +33,8 @@ struct curltime Curl_now(void)
*/
struct curltime now;
#if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_VISTA) || \
- (_WIN32_WINNT < _WIN32_WINNT_VISTA)
+ (_WIN32_WINNT < _WIN32_WINNT_VISTA) || \
+ (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR))
DWORD milliseconds = GetTickCount();
now.tv_sec = milliseconds / 1000;
now.tv_usec = (milliseconds % 1000) * 1000;
@@ -60,7 +61,23 @@ struct curltime Curl_now(void)
struct timeval now;
struct curltime cnow;
struct timespec tsnow;
- if(0 == clock_gettime(CLOCK_MONOTONIC, &tsnow)) {
+
+ /*
+ ** clock_gettime() may be defined by Apple's SDK as weak symbol thus
+ ** code compiles but fails during run-time if clock_gettime() is
+ ** called on unsupported OS version.
+ */
+#if defined(__APPLE__) && (HAVE_BUILTIN_AVAILABLE == 1)
+ bool have_clock_gettime = FALSE;
+ if(__builtin_available(macOS 10.12, iOS 10, tvOS 10, watchOS 3, *))
+ have_clock_gettime = TRUE;
+#endif
+
+ if(
+#if defined(__APPLE__) && (HAVE_BUILTIN_AVAILABLE == 1)
+ have_clock_gettime &&
+#endif
+ (0 == clock_gettime(CLOCK_MONOTONIC, &tsnow))) {
cnow.tv_sec = tsnow.tv_sec;
cnow.tv_usec = (unsigned int)(tsnow.tv_nsec / 1000);
}
diff --git a/lib/transfer.c b/lib/transfer.c
index 7159d5c8..b73f94d9 100644
--- a/lib/transfer.c
+++ b/lib/transfer.c
@@ -75,6 +75,7 @@
#include "http2.h"
#include "mime.h"
#include "strcase.h"
+#include "urlapi-int.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -362,7 +363,7 @@ static int data_pending(const struct connectdata *conn)
return conn->handler->protocol&(CURLPROTO_SCP|CURLPROTO_SFTP) ||
#if defined(USE_NGHTTP2)
Curl_ssl_data_pending(conn, FIRSTSOCKET) ||
- /* For HTTP/2, we may read up everything including responde body
+ /* For HTTP/2, we may read up everything including response body
with header fields in Curl_http_readwrite_headers. If no
content-length is provided, curl waits for the connection
close, which we emulate it using conn->proto.httpc.closed =
@@ -566,7 +567,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
infof(data,
"Rewinding stream by : %zd"
" bytes on url %s (zero-length body)\n",
- nread, data->state.path);
+ nread, data->state.up.path);
read_rewind(conn, (size_t)nread);
}
else {
@@ -574,7 +575,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
"Excess found in a non pipelined read:"
" excess = %zd"
" url = %s (zero-length body)\n",
- nread, data->state.path);
+ nread, data->state.up.path);
}
}
@@ -743,7 +744,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
" bytes on url %s (size = %" CURL_FORMAT_CURL_OFF_T
", maxdownload = %" CURL_FORMAT_CURL_OFF_T
", bytecount = %" CURL_FORMAT_CURL_OFF_T ", nread = %zd)\n",
- excess, data->state.path,
+ excess, data->state.up.path,
k->size, k->maxdownload, k->bytecount, nread);
read_rewind(conn, excess);
}
@@ -878,7 +879,7 @@ static CURLcode done_sending(struct connectdata *conn,
return CURLE_OK;
}
-#ifdef WIN32
+#if defined(WIN32) && !defined(USE_LWIPSOCK)
#ifndef SIO_IDEAL_SEND_BACKLOG_QUERY
#define SIO_IDEAL_SEND_BACKLOG_QUERY 0x4004747B
#endif
@@ -959,7 +960,8 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
sending_http_headers = FALSE;
}
- result = Curl_fillreadbuffer(conn, UPLOAD_BUFSIZE, &fillcount);
+ result = Curl_fillreadbuffer(conn, data->set.upload_buffer_size,
+ &fillcount);
if(result)
return result;
@@ -991,7 +993,7 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
(data->set.crlf))) {
/* Do we need to allocate a scratch buffer? */
if(!data->state.scratch) {
- data->state.scratch = malloc(2 * UPLOAD_BUFSIZE);
+ data->state.scratch = malloc(2 * data->set.upload_buffer_size);
if(!data->state.scratch) {
failf(data, "Failed to alloc scratch buffer!");
@@ -1453,314 +1455,11 @@ CURLcode Curl_posttransfer(struct Curl_easy *data)
return CURLE_OK;
}
-#ifndef CURL_DISABLE_HTTP
-/*
- * Find the separator at the end of the host name, or the '?' in cases like
- * http://www.url.com?id=2380
- */
-static const char *find_host_sep(const char *url)
-{
- const char *sep;
- const char *query;
-
- /* Find the start of the hostname */
- sep = strstr(url, "//");
- if(!sep)
- sep = url;
- else
- sep += 2;
-
- query = strchr(sep, '?');
- sep = strchr(sep, '/');
-
- if(!sep)
- sep = url + strlen(url);
-
- if(!query)
- query = url + strlen(url);
-
- return sep < query ? sep : query;
-}
-
-/*
- * Decide in an encoding-independent manner whether a character in an
- * URL must be escaped. The same criterion must be used in strlen_url()
- * and strcpy_url().
- */
-static bool urlchar_needs_escaping(int c)
-{
- return !(ISCNTRL(c) || ISSPACE(c) || ISGRAPH(c));
-}
-
-/*
- * strlen_url() returns the length of the given URL if the spaces within the
- * URL were properly URL encoded.
- * URL encoding should be skipped for host names, otherwise IDN resolution
- * will fail.
- */
-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 ? */
- 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++) {
-
- if(ptr < host_sep) {
- ++newlen;
- continue;
- }
-
- switch(*ptr) {
- case '?':
- left = FALSE;
- /* FALLTHROUGH */
- default:
- if(urlchar_needs_escaping(*ptr))
- newlen += 2;
- newlen++;
- break;
- case ' ':
- if(left)
- newlen += 3;
- else
- newlen++;
- break;
- }
- }
- return newlen;
-}
-
-/* strcpy_url() copies a url to a output buffer and URL-encodes the spaces in
- * the source URL accordingly.
- * URL encoding should be skipped for host names, otherwise IDN resolution
- * will fail.
- */
-static void strcpy_url(char *output, const char *url, bool relative)
-{
- /* we must add this with whitespace-replacing */
- bool left = TRUE;
- const unsigned char *iptr;
- char *optr = output;
- const unsigned char *host_sep = (const unsigned char *) url;
-
- if(!relative)
- host_sep = (const unsigned char *) find_host_sep(url);
-
- for(iptr = (unsigned char *)url; /* read from here */
- *iptr; /* until zero byte */
- iptr++) {
-
- if(iptr < host_sep) {
- *optr++ = *iptr;
- continue;
- }
-
- switch(*iptr) {
- case '?':
- left = FALSE;
- /* FALLTHROUGH */
- default:
- if(urlchar_needs_escaping(*iptr)) {
- snprintf(optr, 4, "%%%02x", *iptr);
- optr += 3;
- }
- else
- *optr++=*iptr;
- break;
- case ' ':
- if(left) {
- *optr++='%'; /* add a '%' */
- *optr++='2'; /* add a '2' */
- *optr++='0'; /* add a '0' */
- }
- else
- *optr++='+'; /* add a '+' here */
- break;
- }
- }
- *optr = 0; /* zero terminate output buffer */
-
-}
-
-/*
- * Returns true if the given URL is absolute (as opposed to relative)
- */
-static bool is_absolute_url(const char *url)
-{
- char prot[16]; /* URL protocol string storage */
- char letter; /* used for a silly sscanf */
-
- return (2 == sscanf(url, "%15[^?&/:]://%c", prot, &letter)) ? TRUE : FALSE;
-}
-
-/*
- * Concatenate a relative URL to a base URL making it absolute.
- * URL-encodes any spaces.
- * The returned pointer must be freed by the caller unless NULL
- * (returns NULL on out of memory).
- */
-static char *concat_url(const char *base, const char *relurl)
-{
- /***
- TRY to append this new path to the old URL
- to the right of the host part. Oh crap, this is doomed to cause
- problems in the future...
- */
- char *newest;
- char *protsep;
- char *pathsep;
- size_t newlen;
- bool host_changed = FALSE;
-
- const char *useurl = relurl;
- size_t urllen;
-
- /* 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);
-
- if(!url_clone)
- return NULL; /* skip out of this NOW */
-
- /* protsep points to the start of the host name */
- protsep = strstr(url_clone, "//");
- if(!protsep)
- protsep = url_clone;
- else
- protsep += 2; /* pass the slashes */
-
- if('/' != relurl[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;
-
- /* 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
- '?') we append the new one at the end of the entire currently worked
- out URL */
- if(useurl[0] != '?') {
- pathsep = strrchr(protsep, '/');
- if(pathsep)
- *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;
- else
- protsep = NULL;
-
- /* now deal with one "./" or any amount of "../" in the newurl
- and act accordingly */
-
- if((useurl[0] == '.') && (useurl[1] == '/'))
- useurl += 2; /* just skip the "./" */
-
- while((useurl[0] == '.') &&
- (useurl[1] == '.') &&
- (useurl[2] == '/')) {
- level++;
- useurl += 3; /* pass the "../" */
- }
-
- if(protsep) {
- while(level--) {
- /* cut off one more level from the right of the original URL */
- pathsep = strrchr(protsep, '/');
- if(pathsep)
- *pathsep = 0;
- else {
- *protsep = 0;
- break;
- }
- }
- }
- }
- else {
- /* We got a new absolute path for this server */
-
- if((relurl[0] == '/') && (relurl[1] == '/')) {
- /* the new URL starts with //, just keep the protocol part from the
- original one */
- *protsep = 0;
- useurl = &relurl[2]; /* we keep the slashes from the original, so we
- skip the new ones */
- host_changed = TRUE;
- }
- else {
- /* cut off the original URL from the first slash, or deal with URLs
- without slash */
- pathsep = strchr(protsep, '/');
- if(pathsep) {
- /* When people use badly formatted URLs, such as
- "http://www.url.com?dir=/home/daniel" we must not use the first
- slash, if there's a ?-letter before it! */
- char *sep = strchr(protsep, '?');
- if(sep && (sep < pathsep))
- pathsep = sep;
- *pathsep = 0;
- }
- else {
- /* There was no slash. Now, since we might be operating on a badly
- formatted URL, such as "http://www.url.com?id=2380" which doesn't
- use a slash separator as it is supposed to, we need to check for a
- ?-letter as well! */
- pathsep = strchr(protsep, '?');
- if(pathsep)
- *pathsep = 0;
- }
- }
- }
-
- /* If the new part contains a space, this is a mighty stupid redirect
- but we still make an effort to do "right". To the left of a '?'
- letter we replace each space with %20 while it is replaced with '+'
- on the right side of the '?' letter.
- */
- newlen = strlen_url(useurl, !host_changed);
-
- urllen = strlen(url_clone);
-
- newest = malloc(urllen + 1 + /* possible slash */
- newlen + 1 /* zero byte */);
-
- if(!newest) {
- free(url_clone); /* don't leak this */
- return NULL;
- }
-
- /* copy over the root url part */
- memcpy(newest, url_clone, urllen);
-
- /* check if we need to append a slash */
- if(('/' == useurl[0]) || (protsep && !*protsep) || ('?' == useurl[0]))
- ;
- else
- newest[urllen++]='/';
-
- /* then append the new piece on the right side */
- strcpy_url(&newest[urllen], useurl, !host_changed);
-
- free(url_clone);
-
- return newest;
-}
-#endif /* CURL_DISABLE_HTTP */
-
/*
* Curl_follow() handles the URL redirect magic. Pass in the 'newurl' string
* as given by the remote server and set up the new URL to request.
+ *
+ * This function DOES NOT FREE the given url.
*/
CURLcode Curl_follow(struct Curl_easy *data,
char *newurl, /* the Location: string */
@@ -1777,6 +1476,7 @@ CURLcode Curl_follow(struct Curl_easy *data,
/* Location: redirect */
bool disallowport = FALSE;
bool reachedmax = FALSE;
+ CURLUcode uc;
if(type == FOLLOW_REDIR) {
if((data->set.maxredirs != -1) &&
@@ -1809,33 +1509,18 @@ CURLcode Curl_follow(struct Curl_easy *data,
}
}
- 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!
- */
- char *absolute = concat_url(data->change.url, newurl);
- if(!absolute)
- return CURLE_OUT_OF_MEMORY;
- newurl = absolute;
- }
- else {
- /* The new URL MAY contain space or high byte values, that means a mighty
- stupid redirect URL but we still make an effort to do "right". */
- char *newest;
- size_t newlen = strlen_url(newurl, FALSE);
-
+ if(Curl_is_absolute_url(newurl, NULL, MAX_SCHEME_LEN))
/* This is an absolute URL, don't allow the custom port number */
disallowport = TRUE;
- newest = malloc(newlen + 1); /* get memory for this */
- if(!newest)
- return CURLE_OUT_OF_MEMORY;
-
- strcpy_url(newest, newurl, FALSE); /* create a space-free URL */
- newurl = newest; /* use this instead now */
+ DEBUGASSERT(data->state.uh);
+ uc = curl_url_set(data->state.uh, CURLUPART_URL, newurl, 0);
+ if(uc)
+ return Curl_uc_to_curlcode(uc);
- }
+ uc = curl_url_get(data->state.uh, CURLUPART_URL, &newurl, 0);
+ if(uc)
+ return Curl_uc_to_curlcode(uc);
if(type == FOLLOW_FAKE) {
/* we're only figuring out the new url if we would've followed locations
@@ -1852,10 +1537,8 @@ CURLcode Curl_follow(struct Curl_easy *data,
if(disallowport)
data->state.allow_port = FALSE;
- if(data->change.url_alloc) {
+ if(data->change.url_alloc)
Curl_safefree(data->change.url);
- data->change.url_alloc = FALSE;
- }
data->change.url = newurl;
data->change.url_alloc = TRUE;
@@ -2021,8 +1704,13 @@ CURLcode Curl_retry_request(struct connectdata *conn,
if(conn->handler->protocol&PROTO_FAMILY_HTTP) {
struct HTTP *http = data->req.protop;
- if(http->writebytecount)
- return Curl_readrewind(conn);
+ if(http->writebytecount) {
+ CURLcode result = Curl_readrewind(conn);
+ if(result) {
+ Curl_safefree(*url);
+ return result;
+ }
+ }
}
}
return CURLE_OK;
diff --git a/lib/transfer.h b/lib/transfer.h
index 9263e5b6..9742455a 100644
--- a/lib/transfer.h
+++ b/lib/transfer.h
@@ -71,4 +71,3 @@ Curl_setup_transfer (struct connectdata *data,
);
#endif /* HEADER_CURL_TRANSFER_H */
-
diff --git a/lib/url.c b/lib/url.c
index f1590088..0d5a13f9 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -92,6 +92,7 @@ bool curl_win32_idn_to_ascii(const char *in, char **out);
#include "non-ascii.h"
#include "inet_pton.h"
#include "getinfo.h"
+#include "urlapi-int.h"
/* And now for the protocols */
#include "ftp.h"
@@ -127,10 +128,6 @@ bool curl_win32_idn_to_ascii(const char *in, char **out);
static void conn_free(struct connectdata *conn);
static void free_fixed_hostname(struct hostname *host);
-static CURLcode parse_url_login(struct Curl_easy *data,
- struct connectdata *conn,
- char **userptr, char **passwdptr,
- char **optionsptr);
static unsigned int get_protocol_family(unsigned int protocol);
/* Some parts of the code (e.g. chunked encoding) assume this buffer has at
@@ -294,6 +291,22 @@ void Curl_freeset(struct Curl_easy *data)
Curl_mime_cleanpart(&data->set.mimepost);
}
+/* free the URL pieces */
+void Curl_up_free(struct Curl_easy *data)
+{
+ struct urlpieces *up = &data->state.up;
+ Curl_safefree(up->scheme);
+ Curl_safefree(up->hostname);
+ Curl_safefree(up->port);
+ Curl_safefree(up->user);
+ Curl_safefree(up->password);
+ Curl_safefree(up->options);
+ Curl_safefree(up->path);
+ Curl_safefree(up->query);
+ curl_url_cleanup(data->state.uh);
+ data->state.uh = NULL;
+}
+
/*
* This is the internal function curl_easy_cleanup() calls. This should
* cleanup and free all resources associated with this sessionhandle.
@@ -313,16 +326,17 @@ CURLcode Curl_close(struct Curl_easy *data)
Curl_expire_clear(data); /* shut off timers */
m = data->multi;
-
if(m)
/* This handle is still part of a multi handle, take care of this first
and detach this handle from there. */
curl_multi_remove_handle(data->multi, data);
- if(data->multi_easy)
+ if(data->multi_easy) {
/* when curl_easy_perform() is used, it creates its own multi handle to
use and this is the one */
curl_multi_cleanup(data->multi_easy);
+ data->multi_easy = NULL;
+ }
/* Destroy the timeout list that is held in the easy handle. It is
/normally/ done by curl_multi_remove_handle() but this is "just in
@@ -336,10 +350,6 @@ CURLcode Curl_close(struct Curl_easy *data)
if(data->state.rangestringalloc)
free(data->state.range);
- /* Free the pathbuffer */
- Curl_safefree(data->state.pathbuffer);
- data->state.path = NULL;
-
/* freed here just in case DONE wasn't called */
Curl_free_request_state(data);
@@ -359,12 +369,7 @@ CURLcode Curl_close(struct Curl_easy *data)
}
data->change.referer = NULL;
- if(data->change.url_alloc) {
- Curl_safefree(data->change.url);
- data->change.url_alloc = FALSE;
- }
- data->change.url = NULL;
-
+ Curl_up_free(data);
Curl_safefree(data->state.buffer);
Curl_safefree(data->state.headerbuff);
Curl_safefree(data->state.ulbuf);
@@ -516,25 +521,28 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
set->wildcard_enabled = FALSE;
set->chunk_bgn = ZERO_NULL;
set->chunk_end = ZERO_NULL;
-
- /* tcp keepalives are disabled by default, but provide reasonable values for
- * the interval and idle times.
- */
set->tcp_keepalive = FALSE;
set->tcp_keepintvl = 60;
set->tcp_keepidle = 60;
set->tcp_fastopen = FALSE;
set->tcp_nodelay = TRUE;
-
set->ssl_enable_npn = TRUE;
set->ssl_enable_alpn = TRUE;
-
set->expect_100_timeout = 1000L; /* Wait for a second by default. */
set->sep_headers = TRUE; /* separated header lists by default */
set->buffer_size = READBUFFER_SIZE;
- set->upload_buffer_size = UPLOAD_BUFSIZE;
+ set->upload_buffer_size = UPLOADBUFFER_DEFAULT;
set->happy_eyeballs_timeout = CURL_HET_DEFAULT;
-
+ set->fnmatch = ZERO_NULL;
+ set->upkeep_interval_ms = CURL_UPKEEP_INTERVAL_DEFAULT;
+ set->maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */
+ set->httpversion =
+#ifdef USE_NGHTTP2
+ CURL_HTTP_VERSION_2TLS
+#else
+ CURL_HTTP_VERSION_1_1
+#endif
+ ;
Curl_http2_init_userset(set);
return result;
}
@@ -594,8 +602,6 @@ CURLcode Curl_open(struct Curl_easy **curl)
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);
}
@@ -1831,6 +1837,12 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
/* Store creation time to help future close decision making */
conn->created = Curl_now();
+ /* Store current time to give a baseline to keepalive connection times. */
+ conn->keepalive = Curl_now();
+
+ /* Store off the configured connection upkeep time. */
+ conn->upkeep_interval_ms = data->set.upkeep_interval_ms;
+
conn->data = data; /* Setup the association between this connection
and the Curl_easy */
@@ -1937,30 +1949,37 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
return NULL;
}
-static CURLcode findprotocol(struct Curl_easy *data,
- struct connectdata *conn,
- const char *protostr)
+/* returns the handler if the given scheme is built-in */
+const struct Curl_handler *Curl_builtin_scheme(const char *scheme)
{
const struct Curl_handler * const *pp;
const struct Curl_handler *p;
-
- /* Scan protocol handler table and match against 'protostr' to set a few
- variables based on the URL. Now that the handler may be changed later
- when the protocol specific setup function is called. */
- for(pp = protocols; (p = *pp) != NULL; pp++) {
- if(strcasecompare(p->scheme, protostr)) {
+ /* Scan protocol handler table and match against 'scheme'. The handler may
+ be changed later when the protocol specific setup function is called. */
+ for(pp = protocols; (p = *pp) != NULL; pp++)
+ if(strcasecompare(p->scheme, scheme))
/* Protocol found in table. Check if allowed */
- if(!(data->set.allowed_protocols & p->protocol))
- /* nope, get out */
- break;
+ return p;
+ return NULL; /* not found */
+}
+
+
+static CURLcode findprotocol(struct Curl_easy *data,
+ struct connectdata *conn,
+ const char *protostr)
+{
+ const struct Curl_handler *p = Curl_builtin_scheme(protostr);
- /* it is allowed for "normal" request, now do an extra check if this is
- the result of a redirect */
- if(data->state.this_is_a_follow &&
- !(data->set.redir_protocols & p->protocol))
- /* nope, get out */
- break;
+ if(p && /* Protocol found in table. Check if allowed */
+ (data->set.allowed_protocols & p->protocol)) {
+ /* it is allowed for "normal" request, now do an extra check if this is
+ the result of a redirect */
+ if(data->state.this_is_a_follow &&
+ !(data->set.redir_protocols & p->protocol))
+ /* nope, get out */
+ ;
+ else {
/* Perform setup complement if some. */
conn->handler = conn->given = p;
@@ -1969,7 +1988,6 @@ static CURLcode findprotocol(struct Curl_easy *data,
}
}
-
/* The protocol was not found in the table, but we don't have to assign it
to anything since it is already assigned to a dummy-struct in the
create_conn() function when the connectdata struct is allocated. */
@@ -1979,379 +1997,134 @@ static CURLcode findprotocol(struct Curl_easy *data,
return CURLE_UNSUPPORTED_PROTOCOL;
}
+
+CURLcode Curl_uc_to_curlcode(CURLUcode uc)
+{
+ switch(uc) {
+ default:
+ return CURLE_URL_MALFORMAT;
+ case CURLUE_UNSUPPORTED_SCHEME:
+ return CURLE_UNSUPPORTED_PROTOCOL;
+ case CURLUE_OUT_OF_MEMORY:
+ return CURLE_OUT_OF_MEMORY;
+ case CURLUE_USER_NOT_ALLOWED:
+ return CURLE_LOGIN_DENIED;
+ }
+}
+
/*
* Parse URL and fill in the relevant members of the connection struct.
*/
static CURLcode parseurlandfillconn(struct Curl_easy *data,
- struct connectdata *conn,
- bool *prot_missing,
- char **userp, char **passwdp,
- char **optionsp)
+ struct connectdata *conn)
{
- char *at;
- char *fragment;
- char *path = data->state.path;
- char *query;
- int rc;
- const char *protop = "";
CURLcode result;
- bool rebuild_url = FALSE;
- bool url_has_scheme = FALSE;
- char protobuf[16];
-
- *prot_missing = FALSE;
+ CURLU *uh;
+ CURLUcode uc;
+ char *hostname;
- /* We might pass the entire URL into the request so we need to make sure
- * there are no bad characters in there.*/
- if(strpbrk(data->change.url, "\r\n")) {
- failf(data, "Illegal characters found in URL");
- return CURLE_URL_MALFORMAT;
- }
+ Curl_up_free(data); /* cleanup previous leftovers first */
- /*************************************************************
- * Parse the URL.
- *
- * We need to parse the url even when using the proxy, because we will need
- * the hostname and port in case we are trying to SSL connect through the
- * proxy -- and we don't know if we will need to use SSL until we parse the
- * url ...
- ************************************************************/
- if(data->change.url[0] == ':') {
- failf(data, "Bad URL, colon is first character");
- return CURLE_URL_MALFORMAT;
- }
+ /* parse the URL */
+ uh = data->state.uh = curl_url();
+ if(!uh)
+ return CURLE_OUT_OF_MEMORY;
- /* MSDOS/Windows style drive prefix, eg c: in c:foo */
-#define STARTS_WITH_DRIVE_PREFIX(str) \
- ((('a' <= str[0] && str[0] <= 'z') || \
- ('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] == '\\' || (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) &&
- data->set.str[STRING_DEFAULT_PROTOCOL] &&
- strcasecompare(data->set.str[STRING_DEFAULT_PROTOCOL], "file")) {
- ; /* do nothing */
- }
- else { /* check for a scheme */
- int i;
- for(i = 0; i < 16 && data->change.url[i]; ++i) {
- if(data->change.url[i] == '/')
- break;
- if(data->change.url[i] == ':') {
- url_has_scheme = TRUE;
- break;
- }
- }
+ if(data->set.str[STRING_DEFAULT_PROTOCOL] &&
+ !Curl_is_absolute_url(data->change.url, NULL, MAX_SCHEME_LEN)) {
+ char *url;
+ if(data->change.url_alloc)
+ free(data->change.url);
+ url = aprintf("%s://%s", data->set.str[STRING_DEFAULT_PROTOCOL],
+ data->change.url);
+ if(!url)
+ return CURLE_OUT_OF_MEMORY;
+ data->change.url = url;
+ data->change.url_alloc = TRUE;
}
- /* handle the file: scheme */
- if((url_has_scheme && strncasecompare(data->change.url, "file:", 5)) ||
- (!url_has_scheme && data->set.str[STRING_DEFAULT_PROTOCOL] &&
- strcasecompare(data->set.str[STRING_DEFAULT_PROTOCOL], "file"))) {
- if(url_has_scheme)
- rc = sscanf(data->change.url, "%*15[^\n/:]:%[^\n]", path);
- else
- rc = sscanf(data->change.url, "%[^\n]", path);
-
- if(rc != 1) {
- failf(data, "Bad URL");
- return CURLE_URL_MALFORMAT;
- }
+ uc = curl_url_set(uh, CURLUPART_URL, data->change.url,
+ CURLU_GUESS_SCHEME |
+ CURLU_NON_SUPPORT_SCHEME |
+ (data->set.disallow_username_in_url ?
+ CURLU_DISALLOW_USER : 0) |
+ (data->set.path_as_is ? CURLU_PATH_AS_IS : 0));
+ if(uc)
+ return Curl_uc_to_curlcode(uc);
- /* 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(url_has_scheme && path[0] == '/' && path[1] == '/') {
- /* swallow the two slashes */
- char *ptr = &path[2];
+ uc = curl_url_get(uh, CURLUPART_SCHEME, &data->state.up.scheme, 0);
+ if(uc)
+ return Curl_uc_to_curlcode(uc);
- /*
- * 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 */
- }
-
- /* This cannot be done with strcpy, as the memory chunks overlap! */
- memmove(path, ptr, strlen(ptr) + 1);
- }
-
-#if !defined(MSDOS) && !defined(WIN32) && !defined(__CYGWIN__)
- /* 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
+ result = findprotocol(data, conn, data->state.up.scheme);
+ if(result)
+ return result;
- protop = "file"; /* protocol string */
- *prot_missing = !url_has_scheme;
+ uc = curl_url_get(uh, CURLUPART_USER, &data->state.up.user,
+ CURLU_URLDECODE);
+ if(!uc) {
+ conn->user = strdup(data->state.up.user);
+ if(!conn->user)
+ return CURLE_OUT_OF_MEMORY;
+ conn->bits.user_passwd = TRUE;
}
- else {
- /* clear path */
- char slashbuf[4];
- path[0] = 0;
-
- rc = sscanf(data->change.url,
- "%15[^\n/:]:%3[/]%[^\n/?#]%[^\n]",
- protobuf, slashbuf, conn->host.name, path);
- if(2 == rc) {
- failf(data, "Bad URL");
- return CURLE_URL_MALFORMAT;
- }
- if(3 > rc) {
-
- /*
- * The URL was badly formatted, let's try the browser-style _without_
- * protocol specified like 'http://'.
- */
- rc = sscanf(data->change.url, "%[^\n/?#]%[^\n]", conn->host.name, path);
- if(1 > rc) {
- /*
- * We couldn't even get this format.
- * djgpp 2.04 has a sscanf() bug where 'conn->host.name' is
- * assigned, but the return value is EOF!
- */
-#if defined(__DJGPP__) && (DJGPP_MINOR == 4)
- if(!(rc == -1 && *conn->host.name))
-#endif
- {
- failf(data, "<url> malformed");
- return CURLE_URL_MALFORMAT;
- }
- }
-
- /*
- * Since there was no protocol part specified in the URL use the
- * user-specified default protocol. If we weren't given a default make a
- * guess by matching some protocols against the host's outermost
- * sub-domain name. Finally if there was no match use HTTP.
- */
+ else if(uc != CURLUE_NO_USER)
+ return Curl_uc_to_curlcode(uc);
- protop = data->set.str[STRING_DEFAULT_PROTOCOL];
- if(!protop) {
- /* Note: if you add a new protocol, please update the list in
- * lib/version.c too! */
- if(checkprefix("FTP.", conn->host.name))
- protop = "ftp";
- else if(checkprefix("DICT.", conn->host.name))
- protop = "DICT";
- else if(checkprefix("LDAP.", conn->host.name))
- protop = "LDAP";
- else if(checkprefix("IMAP.", conn->host.name))
- protop = "IMAP";
- else if(checkprefix("SMTP.", conn->host.name))
- protop = "smtp";
- else if(checkprefix("POP3.", conn->host.name))
- protop = "pop3";
- else
- protop = "http";
- }
-
- *prot_missing = TRUE; /* not given in URL */
- }
- else {
- size_t s = strlen(slashbuf);
- protop = protobuf;
- if(s != 2) {
- infof(data, "Unwillingly accepted illegal URL using %zu slash%s!\n",
- s, s>1?"es":"");
-
- if(data->change.url_alloc)
- free(data->change.url);
- /* repair the URL to use two slashes */
- data->change.url = aprintf("%s://%s%s",
- protobuf, conn->host.name, path);
- if(!data->change.url)
- return CURLE_OUT_OF_MEMORY;
- data->change.url_alloc = TRUE;
- }
- }
+ uc = curl_url_get(uh, CURLUPART_PASSWORD, &data->state.up.password,
+ CURLU_URLDECODE);
+ if(!uc) {
+ conn->passwd = strdup(data->state.up.password);
+ if(!conn->passwd)
+ return CURLE_OUT_OF_MEMORY;
+ conn->bits.user_passwd = TRUE;
}
+ else if(uc != CURLUE_NO_PASSWORD)
+ return Curl_uc_to_curlcode(uc);
- /* We search for '?' in the host name (but only on the right side of a
- * @-letter to allow ?-letters in username and password) to handle things
- * like http://example.com?param= (notice the missing '/').
- */
- at = strchr(conn->host.name, '@');
- if(at)
- query = strchr(at + 1, '?');
- else
- query = strchr(conn->host.name, '?');
-
- if(query) {
- /* We must insert a slash before the '?'-letter in the URL. If the URL had
- a slash after the '?', that is where the path currently begins and the
- '?string' is still part of the host name.
-
- We must move the trailing part from the host name and put it first in
- the path. And have it all prefixed with a slash.
- */
-
- size_t hostlen = strlen(query);
- size_t pathlen = strlen(path);
-
- /* move the existing path plus the zero byte forward, to make room for
- the host-name part */
- memmove(path + hostlen + 1, path, pathlen + 1);
-
- /* now copy the trailing host part in front of the existing path */
- memcpy(path + 1, query, hostlen);
-
- path[0]='/'; /* prepend the missing slash */
- rebuild_url = TRUE;
-
- *query = 0; /* now cut off the hostname at the ? */
- }
- else if(!path[0]) {
- /* if there's no path set, use a single slash */
- strcpy(path, "/");
- rebuild_url = TRUE;
+ uc = curl_url_get(uh, CURLUPART_OPTIONS, &data->state.up.options,
+ CURLU_URLDECODE);
+ if(!uc) {
+ conn->options = strdup(data->state.up.options);
+ if(!conn->options)
+ return CURLE_OUT_OF_MEMORY;
}
+ else if(uc != CURLUE_NO_OPTIONS)
+ return Curl_uc_to_curlcode(uc);
- /* If the URL is malformatted (missing a '/' after hostname before path) we
- * insert a slash here. The only letters except '/' that can start a path is
- * '?' and '#' - as controlled by the two sscanf() patterns above.
- */
- if(path[0] != '/') {
- /* We need this function to deal with overlapping memory areas. We know
- that the memory area 'path' points to is 'urllen' bytes big and that
- is bigger than the path. Use +1 to move the zero byte too. */
- memmove(&path[1], path, strlen(path) + 1);
- path[0] = '/';
- rebuild_url = TRUE;
- }
- else if(!data->set.path_as_is) {
- /* sanitise paths and remove ../ and ./ sequences according to RFC3986 */
- char *newp = Curl_dedotdotify(path);
- if(!newp)
+ uc = curl_url_get(uh, CURLUPART_HOST, &data->state.up.hostname, 0);
+ if(uc) {
+ if(!strcasecompare("file", data->state.up.scheme))
return CURLE_OUT_OF_MEMORY;
-
- if(strcmp(newp, path)) {
- rebuild_url = TRUE;
- free(data->state.pathbuffer);
- data->state.pathbuffer = newp;
- data->state.path = newp;
- path = newp;
- }
- else
- free(newp);
}
- /*
- * "rebuild_url" means that one or more URL components have been modified so
- * we need to generate an updated full version. We need the corrected URL
- * when communicating over HTTP proxy and we don't know at this point if
- * we're using a proxy or not.
- */
- if(rebuild_url) {
- char *reurl;
-
- size_t plen = strlen(path); /* new path, should be 1 byte longer than
- the original */
- size_t prefixlen = strlen(conn->host.name);
-
- if(!*prot_missing) {
- size_t protolen = strlen(protop);
-
- if(curl_strnequal(protop, data->change.url, protolen))
- prefixlen += protolen;
- else {
- failf(data, "<url> malformed");
- return CURLE_URL_MALFORMAT;
- }
-
- if(curl_strnequal("://", &data->change.url[protolen], 3))
- prefixlen += 3;
- /* only file: is allowed to omit one or both slashes */
- else if(curl_strnequal("file:", data->change.url, 5))
- prefixlen += 1 + (data->change.url[5] == '/');
- else {
- failf(data, "<url> malformed");
- return CURLE_URL_MALFORMAT;
- }
- }
+ uc = curl_url_get(uh, CURLUPART_PATH, &data->state.up.path, 0);
+ if(uc)
+ return Curl_uc_to_curlcode(uc);
- reurl = malloc(prefixlen + plen + 1);
- if(!reurl)
+ uc = curl_url_get(uh, CURLUPART_PORT, &data->state.up.port,
+ CURLU_DEFAULT_PORT);
+ if(uc) {
+ if(!strcasecompare("file", data->state.up.scheme))
return CURLE_OUT_OF_MEMORY;
-
- /* copy the prefix */
- memcpy(reurl, data->change.url, prefixlen);
-
- /* append the trailing piece + zerobyte */
- memcpy(&reurl[prefixlen], path, plen + 1);
-
- /* possible free the old one */
- if(data->change.url_alloc) {
- Curl_safefree(data->change.url);
- data->change.url_alloc = FALSE;
- }
-
- infof(data, "Rebuilt URL to: %s\n", reurl);
-
- data->change.url = reurl;
- data->change.url_alloc = TRUE; /* free this later */
+ }
+ else {
+ unsigned long port = strtoul(data->state.up.port, NULL, 10);
+ conn->remote_port = curlx_ultous(port);
}
- result = findprotocol(data, conn, protop);
- if(result)
- return result;
+ (void)curl_url_get(uh, CURLUPART_QUERY, &data->state.up.query, 0);
- /*
- * Parse the login details from the URL and strip them out of
- * the host name
- */
- result = parse_url_login(data, conn, userp, passwdp, optionsp);
- if(result)
- return result;
+ hostname = data->state.up.hostname;
+ if(!hostname)
+ /* this is for file:// transfers, get a dummy made */
+ hostname = (char *)"";
- if(conn->host.name[0] == '[') {
+ if(hostname[0] == '[') {
/* This looks like an IPv6 address literal. See if there is an address
- scope if there is no location header */
- char *percent = strchr(conn->host.name, '%');
+ scope. */
+ char *percent = strchr(++hostname, '%');
+ conn->bits.ipv6_ip = TRUE;
if(percent) {
unsigned int identifier_offset = 3;
char *endp;
@@ -2399,33 +2172,22 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
infof(data, "Invalid IPv6 address format\n");
}
}
+ percent = strchr(hostname, ']');
+ if(percent)
+ /* terminate IPv6 numerical at end bracket */
+ *percent = 0;
}
+ /* make sure the connect struct gets its own copy of the host name */
+ conn->host.rawalloc = strdup(hostname);
+ if(!conn->host.rawalloc)
+ return CURLE_OUT_OF_MEMORY;
+ conn->host.name = conn->host.rawalloc;
+
if(data->set.scope_id)
/* Override any scope that was set above. */
conn->scope_id = data->set.scope_id;
- /* Remove the fragment part of the path. Per RFC 2396, this is always the
- last part of the URI. We are looking for the first '#' so that we deal
- gracefully with non conformant URI such as http://example.com#foo#bar. */
- fragment = strchr(path, '#');
- if(fragment) {
- *fragment = 0;
-
- /* we know the path part ended with a fragment, so we know the full URL
- string does too and we need to cut it off from there so it isn't used
- over proxy */
- fragment = strchr(data->change.url, '#');
- if(fragment)
- *fragment = 0;
- }
-
- /*
- * So if the URL was A://B/C#D,
- * protop is A
- * conn->host.name is B
- * data->state.path is /C
- */
return CURLE_OK;
}
@@ -2540,11 +2302,8 @@ static bool check_noproxy(const char *name, const char *no_proxy)
if(!endptr)
return FALSE;
name++;
- }
- else
- endptr = strchr(name, ':');
- if(endptr)
namelen = endptr - name;
+ }
else
namelen = strlen(name);
@@ -3077,131 +2836,6 @@ out:
#endif /* CURL_DISABLE_PROXY */
/*
- * parse_url_login()
- *
- * Parse the login details (user name, password and options) from the URL and
- * strip them out of the host name
- *
- * Inputs: data->set.use_netrc (CURLOPT_NETRC)
- * conn->host.name
- *
- * Outputs: (almost :- all currently undefined)
- * conn->bits.user_passwd - non-zero if non-default passwords exist
- * user - non-zero length if defined
- * passwd - non-zero length if defined
- * options - non-zero length if defined
- * conn->host.name - remove user name and password
- */
-static CURLcode parse_url_login(struct Curl_easy *data,
- struct connectdata *conn,
- char **user, char **passwd, char **options)
-{
- CURLcode result = CURLE_OK;
- char *userp = NULL;
- char *passwdp = NULL;
- char *optionsp = NULL;
-
- /* At this point, we're hoping all the other special cases have
- * been taken care of, so conn->host.name is at most
- * [user[:password][;options]]@]hostname
- *
- * We need somewhere to put the embedded details, so do that first.
- */
-
- char *ptr = strchr(conn->host.name, '@');
- char *login = conn->host.name;
-
- DEBUGASSERT(!**user);
- DEBUGASSERT(!**passwd);
- DEBUGASSERT(!**options);
- DEBUGASSERT(conn->handler);
-
- if(!ptr)
- goto out;
-
- /* We will now try to extract the
- * possible login information in a string like:
- * ftp://user:password@ftp.my.site:8021/README */
- conn->host.name = ++ptr;
-
- /* So the hostname is sane. Only bother interpreting the
- * results if we could care. It could still be wasted
- * work because it might be overtaken by the programmatically
- * set user/passwd, but doing that first adds more cases here :-(
- */
-
- if(data->set.use_netrc == CURL_NETRC_REQUIRED)
- goto out;
-
- /* We could use the login information in the URL so extract it. Only parse
- options if the handler says we should. */
- result =
- Curl_parse_login_details(login, ptr - login - 1,
- &userp, &passwdp,
- (conn->handler->flags & PROTOPT_URLOPTIONS)?
- &optionsp:NULL);
- if(result)
- goto out;
-
- if(userp) {
- char *newname;
-
- if(data->set.disallow_username_in_url) {
- failf(data, "Option DISALLOW_USERNAME_IN_URL is set "
- "and url contains username.");
- result = CURLE_LOGIN_DENIED;
- goto out;
- }
-
- /* We have a user in the URL */
- conn->bits.userpwd_in_url = TRUE;
- conn->bits.user_passwd = TRUE; /* enable user+password */
-
- /* Decode the user */
- result = Curl_urldecode(data, userp, 0, &newname, NULL, FALSE);
- if(result) {
- goto out;
- }
-
- free(*user);
- *user = newname;
- }
-
- if(passwdp) {
- /* We have a password in the URL so decode it */
- char *newpasswd;
- result = Curl_urldecode(data, passwdp, 0, &newpasswd, NULL, FALSE);
- if(result) {
- goto out;
- }
-
- free(*passwd);
- *passwd = newpasswd;
- }
-
- if(optionsp) {
- /* We have an options list in the URL so decode it */
- char *newoptions;
- result = Curl_urldecode(data, optionsp, 0, &newoptions, NULL, FALSE);
- if(result) {
- goto out;
- }
-
- free(*options);
- *options = newoptions;
- }
-
-
- out:
-
- free(userp);
- free(passwdp);
- free(optionsp);
-
- return result;
-}
-
-/*
* Curl_parse_login_details()
*
* This is used to parse a login string for user name, password and options in
@@ -3223,7 +2857,7 @@ static CURLcode parse_url_login(struct Curl_easy *data,
* len [in] - The length of the login string.
* userp [in/out] - The address where a pointer to newly allocated memory
* holding the user will be stored upon completion.
- * passdwp [in/out] - The address where a pointer to newly allocated memory
+ * passwdp [in/out] - The address where a pointer to newly allocated memory
* holding the password will be stored upon completion.
* optionsp [in/out] - The address where a pointer to newly allocated memory
* holding the options will be stored upon completion.
@@ -3334,131 +2968,23 @@ CURLcode Curl_parse_login_details(const char *login, const size_t len,
* No matter if we use a proxy or not, we have to figure out the remote
* port number of various reasons.
*
- * To be able to detect port number flawlessly, we must not confuse them
- * IPv6-specified addresses in the [0::1] style. (RFC2732)
- *
- * The conn->host.name is currently [user:passwd@]host[:port] where host
- * could be a hostname, IPv4 address or IPv6 address.
- *
* The port number embedded in the URL is replaced, if necessary.
*************************************************************/
static CURLcode parse_remote_port(struct Curl_easy *data,
struct connectdata *conn)
{
- char *portptr;
- char endbracket;
-
- /* Note that at this point, the IPv6 address cannot contain any scope
- suffix as that has already been removed in the parseurlandfillconn()
- function */
- if((1 == sscanf(conn->host.name, "[%*45[0123456789abcdefABCDEF:.]%c",
- &endbracket)) &&
- (']' == endbracket)) {
- /* this is a RFC2732-style specified IP-address */
- conn->bits.ipv6_ip = TRUE;
-
- conn->host.name++; /* skip over the starting bracket */
- portptr = strchr(conn->host.name, ']');
- if(portptr) {
- *portptr++ = '\0'; /* zero terminate, killing the bracket */
- if(*portptr) {
- if (*portptr != ':') {
- failf(data, "IPv6 closing bracket followed by '%c'", *portptr);
- return CURLE_URL_MALFORMAT;
- }
- }
- else
- portptr = NULL; /* no port number available */
- }
- }
- else {
-#ifdef ENABLE_IPV6
- struct in6_addr in6;
- if(Curl_inet_pton(AF_INET6, conn->host.name, &in6) > 0) {
- /* This is a numerical IPv6 address, meaning this is a wrongly formatted
- URL */
- failf(data, "IPv6 numerical address used in URL without brackets");
- return CURLE_URL_MALFORMAT;
- }
-#endif
-
- portptr = strchr(conn->host.name, ':');
- }
if(data->set.use_port && data->state.allow_port) {
- /* if set, we use this and ignore the port possibly given in the URL */
+ /* if set, we use this instead of the port possibly given in the URL */
+ char portbuf[16];
+ CURLUcode uc;
conn->remote_port = (unsigned short)data->set.use_port;
- if(portptr)
- *portptr = '\0'; /* cut off the name there anyway - if there was a port
- number - since the port number is to be ignored! */
- if(conn->bits.httpproxy) {
- /* we need to create new URL with the new port number */
- char *url;
- char type[12]="";
-
- if(conn->bits.type_set)
- snprintf(type, sizeof(type), ";type=%c",
- data->set.prefer_ascii?'A':
- (data->set.ftp_list_only?'D':'I'));
-
- /*
- * This synthesized URL isn't always right--suffixes like ;type=A are
- * stripped off. It would be better to work directly from the original
- * URL and simply replace the port part of it.
- */
- url = aprintf("%s://%s%s%s:%d%s%s%s", conn->given->scheme,
- conn->bits.ipv6_ip?"[":"", conn->host.name,
- conn->bits.ipv6_ip?"]":"", conn->remote_port,
- data->state.slash_removed?"/":"", data->state.path,
- type);
- if(!url)
- return CURLE_OUT_OF_MEMORY;
-
- if(data->change.url_alloc) {
- Curl_safefree(data->change.url);
- data->change.url_alloc = FALSE;
- }
-
- data->change.url = url;
- data->change.url_alloc = TRUE;
- }
- }
- else if(portptr) {
- /* no CURLOPT_PORT given, extract the one from the URL */
-
- char *rest;
- long port;
-
- 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 */
- failf(data, "Port number out of range");
- return CURLE_URL_MALFORMAT;
- }
-
- if(rest[0]) {
- failf(data, "Port number ended with '%c'", rest[0]);
- return CURLE_URL_MALFORMAT;
- }
-
- if(rest != &portptr[1]) {
- *portptr = '\0'; /* cut off the name there */
- conn->remote_port = curlx_ultous(port);
- }
- else {
- /* Browser behavior adaptation. If there's a colon with no digits after,
- just cut off the name there which makes us ignore the colon and just
- use the default port. Firefox and Chrome both do that. */
- *portptr = '\0';
- }
+ snprintf(portbuf, sizeof(portbuf), "%u", conn->remote_port);
+ uc = curl_url_set(data->state.uh, CURLUPART_PORT, portbuf, 0);
+ if(uc)
+ return CURLE_OUT_OF_MEMORY;
}
- /* only if remote_port was not already parsed off the URL we use the
- default port number */
- if(conn->remote_port < 0)
- conn->remote_port = (unsigned short)conn->given->defport;
-
return CURLE_OK;
}
@@ -3470,11 +2996,16 @@ static CURLcode override_login(struct Curl_easy *data,
struct connectdata *conn,
char **userp, char **passwdp, char **optionsp)
{
+ bool user_changed = FALSE;
+ bool passwd_changed = FALSE;
+ CURLUcode uc;
if(data->set.str[STRING_USERNAME]) {
free(*userp);
*userp = strdup(data->set.str[STRING_USERNAME]);
if(!*userp)
return CURLE_OUT_OF_MEMORY;
+ conn->bits.user_passwd = TRUE; /* enable user+password */
+ user_changed = TRUE;
}
if(data->set.str[STRING_PASSWORD]) {
@@ -3482,6 +3013,8 @@ static CURLcode override_login(struct Curl_easy *data,
*passwdp = strdup(data->set.str[STRING_PASSWORD]);
if(!*passwdp)
return CURLE_OUT_OF_MEMORY;
+ conn->bits.user_passwd = TRUE; /* enable user+password */
+ passwd_changed = TRUE;
}
if(data->set.str[STRING_OPTIONS]) {
@@ -3493,9 +3026,16 @@ static CURLcode override_login(struct Curl_easy *data,
conn->bits.netrc = FALSE;
if(data->set.use_netrc != CURL_NETRC_IGNORED) {
- int ret = Curl_parsenetrc(conn->host.name,
- userp, passwdp,
- data->set.str[STRING_NETRC_FILE]);
+ char *nuser = NULL;
+ char *npasswd = NULL;
+ int ret;
+
+ if(data->set.use_netrc == CURL_NETRC_OPTIONAL)
+ nuser = *userp; /* to separate otherwise identical machines */
+
+ ret = Curl_parsenetrc(conn->host.name,
+ &nuser, &npasswd,
+ data->set.str[STRING_NETRC_FILE]);
if(ret > 0) {
infof(data, "Couldn't find host %s in the "
DOT_CHAR "netrc file; using defaults\n",
@@ -3509,55 +3049,85 @@ static CURLcode override_login(struct Curl_easy *data,
file, so that it is safe to use even if we followed a Location: to a
different host or similar. */
conn->bits.netrc = TRUE;
-
conn->bits.user_passwd = TRUE; /* enable user+password */
+
+ if(data->set.use_netrc == CURL_NETRC_OPTIONAL) {
+ /* prefer credentials outside netrc */
+ if(nuser && !*userp) {
+ free(*userp);
+ *userp = nuser;
+ user_changed = TRUE;
+ }
+ if(npasswd && !*passwdp) {
+ free(*passwdp);
+ *passwdp = npasswd;
+ passwd_changed = TRUE;
+ }
+ }
+ else {
+ /* prefer netrc credentials */
+ if(nuser) {
+ free(*userp);
+ *userp = nuser;
+ user_changed = TRUE;
+ }
+ if(npasswd) {
+ free(*passwdp);
+ *passwdp = npasswd;
+ passwd_changed = TRUE;
+ }
+ }
}
}
+ /* for updated strings, we update them in the URL */
+ if(user_changed) {
+ uc = curl_url_set(data->state.uh, CURLUPART_USER, *userp, 0);
+ if(uc)
+ return Curl_uc_to_curlcode(uc);
+ }
+ if(passwd_changed) {
+ uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD, *passwdp, 0);
+ if(uc)
+ return Curl_uc_to_curlcode(uc);
+ }
return CURLE_OK;
}
/*
* Set the login details so they're available in the connection
*/
-static CURLcode set_login(struct connectdata *conn,
- const char *user, const char *passwd,
- const char *options)
+static CURLcode set_login(struct connectdata *conn)
{
CURLcode result = CURLE_OK;
+ const char *setuser = CURL_DEFAULT_USER;
+ const char *setpasswd = CURL_DEFAULT_PASSWORD;
/* If our protocol needs a password and we have none, use the defaults */
- if((conn->handler->flags & PROTOPT_NEEDSPWD) && !conn->bits.user_passwd) {
- /* Store the default user */
- conn->user = strdup(CURL_DEFAULT_USER);
-
- /* Store the default password */
- if(conn->user)
- conn->passwd = strdup(CURL_DEFAULT_PASSWORD);
- else
- conn->passwd = NULL;
-
- /* This is the default password, so DON'T set conn->bits.user_passwd */
- }
+ if((conn->handler->flags & PROTOPT_NEEDSPWD) && !conn->bits.user_passwd)
+ ;
else {
- /* Store the user, zero-length if not set */
- conn->user = strdup(user);
-
- /* Store the password (only if user is present), zero-length if not set */
- if(conn->user)
- conn->passwd = strdup(passwd);
- else
- conn->passwd = NULL;
+ setuser = "";
+ setpasswd = "";
+ }
+ /* Store the default user */
+ if(!conn->user) {
+ conn->user = strdup(setuser);
+ if(!conn->user)
+ return CURLE_OUT_OF_MEMORY;
}
- if(!conn->user || !conn->passwd)
- result = CURLE_OUT_OF_MEMORY;
-
- /* Store the options, null if not set */
- if(!result && options[0]) {
- conn->options = strdup(options);
+ /* Store the default password */
+ if(!conn->passwd) {
+ conn->passwd = strdup(setpasswd);
+ if(!conn->passwd)
+ result = CURLE_OUT_OF_MEMORY;
+ }
- if(!conn->options)
+ /* if there's a user without password, consider password blank */
+ if(conn->user && !conn->passwd) {
+ conn->passwd = strdup("");
+ if(!conn->passwd)
result = CURLE_OUT_OF_MEMORY;
}
@@ -4009,12 +3579,7 @@ static CURLcode create_conn(struct Curl_easy *data,
CURLcode result = CURLE_OK;
struct connectdata *conn;
struct connectdata *conn_temp = NULL;
- size_t urllen;
- char *user = NULL;
- char *passwd = NULL;
- char *options = NULL;
bool reuse;
- bool prot_missing = FALSE;
bool connections_available = TRUE;
bool force_reuse = FALSE;
bool waitpipe = FALSE;
@@ -4026,7 +3591,6 @@ static CURLcode create_conn(struct Curl_easy *data,
/*************************************************************
* Check input data
*************************************************************/
-
if(!data->change.url) {
result = CURLE_URL_MALFORMAT;
goto out;
@@ -4048,107 +3612,10 @@ static CURLcode create_conn(struct Curl_easy *data,
any failure */
*in_connect = conn;
- /* This initing continues below, see the comment "Continue connectdata
- * initialization here" */
-
- /***********************************************************
- * We need to allocate memory to store the path in. We get the size of the
- * full URL to be sure, and we need to make it at least 256 bytes since
- * other parts of the code will rely on this fact
- ***********************************************************/
-#define LEAST_PATH_ALLOC 256
- urllen = strlen(data->change.url);
- if(urllen < LEAST_PATH_ALLOC)
- urllen = LEAST_PATH_ALLOC;
-
- /*
- * We malloc() the buffers below urllen+2 to make room for 2 possibilities:
- * 1 - an extra terminating zero
- * 2 - an extra slash (in case a syntax like "www.host.com?moo" is used)
- */
-
- Curl_safefree(data->state.pathbuffer);
- data->state.path = NULL;
-
- 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);
- if(NULL == conn->host.rawalloc) {
- Curl_safefree(data->state.pathbuffer);
- data->state.path = NULL;
- result = CURLE_OUT_OF_MEMORY;
- goto out;
- }
-
- conn->host.name = conn->host.rawalloc;
- conn->host.name[0] = 0;
-
- user = strdup("");
- passwd = strdup("");
- options = strdup("");
- if(!user || !passwd || !options) {
- result = CURLE_OUT_OF_MEMORY;
- goto out;
- }
-
- result = parseurlandfillconn(data, conn, &prot_missing, &user, &passwd,
- &options);
+ result = parseurlandfillconn(data, conn);
if(result)
goto out;
- /*************************************************************
- * No protocol part in URL was used, add it!
- *************************************************************/
- if(prot_missing) {
- /* We're guessing prefixes here and if we're told to use a proxy or if
- we're going to follow a Location: later or... then we need the protocol
- part added so that we have a valid URL. */
- char *reurl;
- char *ch_lower;
-
- reurl = aprintf("%s://%s", conn->handler->scheme, data->change.url);
-
- if(!reurl) {
- result = CURLE_OUT_OF_MEMORY;
- goto out;
- }
-
- /* Change protocol prefix to lower-case */
- for(ch_lower = reurl; *ch_lower != ':'; ch_lower++)
- *ch_lower = (char)TOLOWER(*ch_lower);
-
- if(data->change.url_alloc) {
- Curl_safefree(data->change.url);
- data->change.url_alloc = FALSE;
- }
-
- data->change.url = reurl;
- data->change.url_alloc = TRUE; /* free this later */
- }
-
- /*************************************************************
- * If the protocol can't handle url query strings, then cut
- * off the unhandable part
- *************************************************************/
- if((conn->given->flags&PROTOPT_NOURLQUERY)) {
- char *path_q_sep = strchr(conn->data->state.path, '?');
- if(path_q_sep) {
- /* according to rfc3986, allow the query (?foo=bar)
- also on protocols that can't handle it.
-
- cut the string-part after '?'
- */
-
- /* terminate the string */
- path_q_sep[0] = 0;
- }
- }
-
if(data->set.str[STRING_BEARER]) {
conn->oauth_bearer = strdup(data->set.str[STRING_BEARER]);
if(!conn->oauth_bearer) {
@@ -4192,10 +3659,12 @@ static CURLcode create_conn(struct Curl_easy *data,
/* Check for overridden login details and set them accordingly so they
they are known when protocol->setup_connection is called! */
- result = override_login(data, conn, &user, &passwd, &options);
+ result = override_login(data, conn, &conn->user, &conn->passwd,
+ &conn->options);
if(result)
goto out;
- result = set_login(conn, user, passwd, options);
+
+ result = set_login(conn); /* default credentials */
if(result)
goto out;
@@ -4278,6 +3747,7 @@ static CURLcode create_conn(struct Curl_easy *data,
/* this is supposed to be the connect function so we better at least check
that the file is present here! */
DEBUGASSERT(conn->handler->connect_it);
+ Curl_persistconninfo(conn);
result = conn->handler->connect_it(conn, &done);
/* Setup a "faked" transfer that'll do nothing */
@@ -4381,6 +3851,9 @@ static CURLcode create_conn(struct Curl_easy *data,
* new one.
*************************************************************/
+ DEBUGASSERT(conn->user);
+ DEBUGASSERT(conn->passwd);
+
/* reuse_fresh is TRUE if we are told to use a new connection by force, but
we only acknowledge this option if this is not a re-used connection
already (which happens due to follow-location or during a HTTP
@@ -4556,10 +4029,6 @@ static CURLcode create_conn(struct Curl_easy *data,
result = resolve_server(data, conn, async);
out:
-
- free(options);
- free(passwd);
- free(user);
return result;
}
@@ -4843,3 +4312,34 @@ static unsigned int get_protocol_family(unsigned int protocol)
return family;
}
+
+
+/*
+ * Wrapper to call functions in Curl_conncache_foreach()
+ *
+ * Returns always 0.
+ */
+static int conn_upkeep(struct connectdata *conn,
+ void *param)
+{
+ /* Param is unused. */
+ (void)param;
+
+ if(conn->handler->connection_check) {
+ /* Do a protocol-specific keepalive check on the connection. */
+ conn->handler->connection_check(conn, CONNCHECK_KEEPALIVE);
+ }
+
+ return 0; /* continue iteration */
+}
+
+CURLcode Curl_upkeep(struct conncache *conn_cache,
+ void *data)
+{
+ /* Loop over every connection and make connection alive. */
+ Curl_conncache_foreach(data,
+ conn_cache,
+ data,
+ conn_upkeep);
+ return CURLE_OK;
+}
diff --git a/lib/url.h b/lib/url.h
index ef3ebf03..095d6383 100644
--- a/lib/url.h
+++ b/lib/url.h
@@ -27,6 +27,18 @@
#define READBUFFER_MAX CURL_MAX_READ_SIZE
#define READBUFFER_MIN 1024
+/* The default upload buffer size, should not be smaller than
+ CURL_MAX_WRITE_SIZE, as it needs to hold a full buffer as could be sent in
+ a write callback.
+
+ The size was 16KB for many years but was bumped to 64KB because it makes
+ libcurl able to do significantly faster uploads in some circumstances. Even
+ larger buffers can help further, but this is deemed a fair memory/speed
+ compromise. */
+#define UPLOADBUFFER_DEFAULT 65536
+#define UPLOADBUFFER_MAX (2*1024*1024)
+#define UPLOADBUFFER_MIN CURL_MAX_WRITE_SIZE
+
/*
* Prototypes for library-wide functions provided by url.c
*/
@@ -34,8 +46,11 @@
CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn);
CURLcode Curl_open(struct Curl_easy **curl);
CURLcode Curl_init_userdefined(struct Curl_easy *data);
-CURLcode Curl_dupset(struct Curl_easy * dst, struct Curl_easy * src);
+
void Curl_freeset(struct Curl_easy * data);
+/* free the URL pieces */
+void Curl_up_free(struct Curl_easy *data);
+CURLcode Curl_uc_to_curlcode(CURLUcode uc);
CURLcode Curl_close(struct Curl_easy *data); /* opposite of curl_open() */
CURLcode Curl_connect(struct Curl_easy *, struct connectdata **,
bool *async, bool *protocol_connect);
@@ -57,9 +72,7 @@ int Curl_doing_getsock(struct connectdata *conn,
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);
/* remove the specified connection from all (possible) pipelines and related
@@ -67,7 +80,9 @@ int Curl_removeHandleFromPipeline(struct Curl_easy *handle,
void Curl_getoff_all_pipelines(struct Curl_easy *data,
struct connectdata *conn);
-void Curl_close_connections(struct Curl_easy *data);
+CURLcode Curl_upkeep(struct conncache *conn_cache, void *data);
+
+const struct Curl_handler *Curl_builtin_scheme(const char *scheme);
#define CURL_DEFAULT_PROXY_PORT 1080 /* default proxy port unless specified */
#define CURL_DEFAULT_HTTPS_PROXY_PORT 443 /* default https proxy port unless
diff --git a/lib/urlapi-int.h b/lib/urlapi-int.h
new file mode 100644
index 00000000..a57d2e22
--- /dev/null
+++ b/lib/urlapi-int.h
@@ -0,0 +1,33 @@
+#ifndef HEADER_CURL_URLAPI_INT_H
+#define HEADER_CURL_URLAPI_INT_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2018, 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"
+/* scheme is not URL encoded, the longest libcurl supported ones are 6
+ letters */
+#define MAX_SCHEME_LEN 8
+
+bool Curl_is_absolute_url(const char *url, char *scheme, size_t buflen);
+char *Curl_concat_url(const char *base, const char *relurl);
+size_t Curl_strlen_url(const char *url, bool relative);
+void Curl_strcpy_url(char *output, const char *url, bool relative);
+#endif /* HEADER_CURL_URLAPI_INT_H */
diff --git a/lib/urlapi.c b/lib/urlapi.c
new file mode 100644
index 00000000..c53e5234
--- /dev/null
+++ b/lib/urlapi.c
@@ -0,0 +1,1340 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2018, 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 "urldata.h"
+#include "urlapi-int.h"
+#include "strcase.h"
+#include "dotdot.h"
+#include "url.h"
+#include "escape.h"
+#include "curl_ctype.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+ /* MSDOS/Windows style drive prefix, eg c: in c:foo */
+#define STARTS_WITH_DRIVE_PREFIX(str) \
+ ((('a' <= str[0] && str[0] <= 'z') || \
+ ('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] == '\\' || (str)[2] == 0))
+
+/* Internal representation of CURLU. Point to URL-encoded strings. */
+struct Curl_URL {
+ char *scheme;
+ char *user;
+ char *password;
+ char *options; /* IMAP only? */
+ char *host;
+ char *port;
+ char *path;
+ char *query;
+ char *fragment;
+
+ char *scratch; /* temporary scratch area */
+ long portnum; /* the numerical version */
+};
+
+#define DEFAULT_SCHEME "https"
+
+static void free_urlhandle(struct Curl_URL *u)
+{
+ free(u->scheme);
+ free(u->user);
+ free(u->password);
+ free(u->options);
+ free(u->host);
+ free(u->port);
+ free(u->path);
+ free(u->query);
+ free(u->fragment);
+ free(u->scratch);
+}
+
+/* move the full contents of one handle onto another and
+ free the original */
+static void mv_urlhandle(struct Curl_URL *from,
+ struct Curl_URL *to)
+{
+ free_urlhandle(to);
+ *to = *from;
+ free(from);
+}
+
+/*
+ * Find the separator at the end of the host name, or the '?' in cases like
+ * http://www.url.com?id=2380
+ */
+static const char *find_host_sep(const char *url)
+{
+ const char *sep;
+ const char *query;
+
+ /* Find the start of the hostname */
+ sep = strstr(url, "//");
+ if(!sep)
+ sep = url;
+ else
+ sep += 2;
+
+ query = strchr(sep, '?');
+ sep = strchr(sep, '/');
+
+ if(!sep)
+ sep = url + strlen(url);
+
+ if(!query)
+ query = url + strlen(url);
+
+ return sep < query ? sep : query;
+}
+
+/*
+ * Decide in an encoding-independent manner whether a character in an
+ * URL must be escaped. The same criterion must be used in strlen_url()
+ * and strcpy_url().
+ */
+static bool urlchar_needs_escaping(int c)
+{
+ return !(ISCNTRL(c) || ISSPACE(c) || ISGRAPH(c));
+}
+
+/*
+ * strlen_url() returns the length of the given URL if the spaces within the
+ * URL were properly URL encoded.
+ * URL encoding should be skipped for host names, otherwise IDN resolution
+ * will fail.
+ */
+size_t Curl_strlen_url(const char *url, bool relative)
+{
+ const unsigned char *ptr;
+ 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++) {
+
+ if(ptr < host_sep) {
+ ++newlen;
+ continue;
+ }
+
+ switch(*ptr) {
+ case '?':
+ left = FALSE;
+ /* FALLTHROUGH */
+ default:
+ if(urlchar_needs_escaping(*ptr))
+ newlen += 2;
+ newlen++;
+ break;
+ case ' ':
+ if(left)
+ newlen += 3;
+ else
+ newlen++;
+ break;
+ }
+ }
+ return newlen;
+}
+
+/* strcpy_url() copies a url to a output buffer and URL-encodes the spaces in
+ * the source URL accordingly.
+ * URL encoding should be skipped for host names, otherwise IDN resolution
+ * will fail.
+ */
+void Curl_strcpy_url(char *output, const char *url, bool relative)
+{
+ /* we must add this with whitespace-replacing */
+ bool left = TRUE;
+ const unsigned char *iptr;
+ char *optr = output;
+ const unsigned char *host_sep = (const unsigned char *) url;
+
+ if(!relative)
+ host_sep = (const unsigned char *) find_host_sep(url);
+
+ for(iptr = (unsigned char *)url; /* read from here */
+ *iptr; /* until zero byte */
+ iptr++) {
+
+ if(iptr < host_sep) {
+ *optr++ = *iptr;
+ continue;
+ }
+
+ switch(*iptr) {
+ case '?':
+ left = FALSE;
+ /* FALLTHROUGH */
+ default:
+ if(urlchar_needs_escaping(*iptr)) {
+ snprintf(optr, 4, "%%%02x", *iptr);
+ optr += 3;
+ }
+ else
+ *optr++=*iptr;
+ break;
+ case ' ':
+ if(left) {
+ *optr++='%'; /* add a '%' */
+ *optr++='2'; /* add a '2' */
+ *optr++='0'; /* add a '0' */
+ }
+ else
+ *optr++='+'; /* add a '+' here */
+ break;
+ }
+ }
+ *optr = 0; /* zero terminate output buffer */
+
+}
+
+/*
+ * Returns true if the given URL is absolute (as opposed to relative) within
+ * the buffer size. Returns the scheme in the buffer if TRUE and 'buf' is
+ * non-NULL.
+ */
+bool Curl_is_absolute_url(const char *url, char *buf, size_t buflen)
+{
+ size_t i;
+#ifdef WIN32
+ if(STARTS_WITH_DRIVE_PREFIX(url))
+ return FALSE;
+#endif
+ for(i = 0; i < buflen && url[i]; ++i) {
+ char s = url[i];
+ if(s == ':') {
+ if(buf)
+ buf[i] = 0;
+ return TRUE;
+ }
+ /* RFC 3986 3.1 explains:
+ scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+ */
+ else if(ISALNUM(s) || (s == '+') || (s == '-') || (s == '.') ) {
+ if(buf)
+ buf[i] = (char)TOLOWER(s);
+ }
+ else
+ break;
+ }
+ return FALSE;
+}
+
+/*
+ * Concatenate a relative URL to a base URL making it absolute.
+ * URL-encodes any spaces.
+ * The returned pointer must be freed by the caller unless NULL
+ * (returns NULL on out of memory).
+ */
+char *Curl_concat_url(const char *base, const char *relurl)
+{
+ /***
+ TRY to append this new path to the old URL
+ to the right of the host part. Oh crap, this is doomed to cause
+ problems in the future...
+ */
+ char *newest;
+ char *protsep;
+ char *pathsep;
+ size_t newlen;
+ bool host_changed = FALSE;
+
+ const char *useurl = relurl;
+ size_t urllen;
+
+ /* 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);
+
+ if(!url_clone)
+ return NULL; /* skip out of this NOW */
+
+ /* protsep points to the start of the host name */
+ protsep = strstr(url_clone, "//");
+ if(!protsep)
+ protsep = url_clone;
+ else
+ protsep += 2; /* pass the slashes */
+
+ if('/' != relurl[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;
+
+ /* 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
+ '?') we append the new one at the end of the entire currently worked
+ out URL */
+ if(useurl[0] != '?') {
+ pathsep = strrchr(protsep, '/');
+ if(pathsep)
+ *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;
+ else
+ protsep = NULL;
+
+ /* now deal with one "./" or any amount of "../" in the newurl
+ and act accordingly */
+
+ if((useurl[0] == '.') && (useurl[1] == '/'))
+ useurl += 2; /* just skip the "./" */
+
+ while((useurl[0] == '.') &&
+ (useurl[1] == '.') &&
+ (useurl[2] == '/')) {
+ level++;
+ useurl += 3; /* pass the "../" */
+ }
+
+ if(protsep) {
+ while(level--) {
+ /* cut off one more level from the right of the original URL */
+ pathsep = strrchr(protsep, '/');
+ if(pathsep)
+ *pathsep = 0;
+ else {
+ *protsep = 0;
+ break;
+ }
+ }
+ }
+ }
+ else {
+ /* We got a new absolute path for this server */
+
+ if((relurl[0] == '/') && (relurl[1] == '/')) {
+ /* the new URL starts with //, just keep the protocol part from the
+ original one */
+ *protsep = 0;
+ useurl = &relurl[2]; /* we keep the slashes from the original, so we
+ skip the new ones */
+ host_changed = TRUE;
+ }
+ else {
+ /* cut off the original URL from the first slash, or deal with URLs
+ without slash */
+ pathsep = strchr(protsep, '/');
+ if(pathsep) {
+ /* When people use badly formatted URLs, such as
+ "http://www.url.com?dir=/home/daniel" we must not use the first
+ slash, if there's a ?-letter before it! */
+ char *sep = strchr(protsep, '?');
+ if(sep && (sep < pathsep))
+ pathsep = sep;
+ *pathsep = 0;
+ }
+ else {
+ /* There was no slash. Now, since we might be operating on a badly
+ formatted URL, such as "http://www.url.com?id=2380" which doesn't
+ use a slash separator as it is supposed to, we need to check for a
+ ?-letter as well! */
+ pathsep = strchr(protsep, '?');
+ if(pathsep)
+ *pathsep = 0;
+ }
+ }
+ }
+
+ /* If the new part contains a space, this is a mighty stupid redirect
+ but we still make an effort to do "right". To the left of a '?'
+ letter we replace each space with %20 while it is replaced with '+'
+ on the right side of the '?' letter.
+ */
+ newlen = Curl_strlen_url(useurl, !host_changed);
+
+ urllen = strlen(url_clone);
+
+ newest = malloc(urllen + 1 + /* possible slash */
+ newlen + 1 /* zero byte */);
+
+ if(!newest) {
+ free(url_clone); /* don't leak this */
+ return NULL;
+ }
+
+ /* copy over the root url part */
+ memcpy(newest, url_clone, urllen);
+
+ /* check if we need to append a slash */
+ if(('/' == useurl[0]) || (protsep && !*protsep) || ('?' == useurl[0]))
+ ;
+ else
+ newest[urllen++]='/';
+
+ /* then append the new piece on the right side */
+ Curl_strcpy_url(&newest[urllen], useurl, !host_changed);
+
+ free(url_clone);
+
+ return newest;
+}
+
+/*
+ * parse_hostname_login()
+ *
+ * Parse the login details (user name, password and options) from the URL and
+ * strip them out of the host name
+ *
+ */
+static CURLUcode parse_hostname_login(struct Curl_URL *u,
+ const struct Curl_handler *h,
+ char **hostname,
+ unsigned int flags)
+{
+ CURLUcode result = CURLUE_OK;
+ CURLcode ccode;
+ char *userp = NULL;
+ char *passwdp = NULL;
+ char *optionsp = NULL;
+
+ /* At this point, we're hoping all the other special cases have
+ * been taken care of, so conn->host.name is at most
+ * [user[:password][;options]]@]hostname
+ *
+ * We need somewhere to put the embedded details, so do that first.
+ */
+
+ char *ptr = strchr(*hostname, '@');
+ char *login = *hostname;
+
+ if(!ptr)
+ goto out;
+
+ /* We will now try to extract the
+ * possible login information in a string like:
+ * ftp://user:password@ftp.my.site:8021/README */
+ *hostname = ++ptr;
+
+ /* We could use the login information in the URL so extract it. Only parse
+ options if the handler says we should. Note that 'h' might be NULL! */
+ ccode = Curl_parse_login_details(login, ptr - login - 1,
+ &userp, &passwdp,
+ (h && (h->flags & PROTOPT_URLOPTIONS)) ?
+ &optionsp:NULL);
+ if(ccode) {
+ result = CURLUE_MALFORMED_INPUT;
+ goto out;
+ }
+
+ if(userp) {
+ if(flags & CURLU_DISALLOW_USER) {
+ /* Option DISALLOW_USER is set and url contains username. */
+ result = CURLUE_USER_NOT_ALLOWED;
+ goto out;
+ }
+
+ u->user = userp;
+ }
+
+ if(passwdp)
+ u->password = passwdp;
+
+ if(optionsp)
+ u->options = optionsp;
+
+ return CURLUE_OK;
+ out:
+
+ free(userp);
+ free(passwdp);
+ free(optionsp);
+
+ return result;
+}
+
+static CURLUcode parse_port(struct Curl_URL *u, char *hostname)
+{
+ char *portptr;
+ char endbracket;
+ int len;
+
+ if((1 == sscanf(hostname, "[%*45[0123456789abcdefABCDEF:.%%]%c%n",
+ &endbracket, &len)) &&
+ (']' == endbracket)) {
+ /* this is a RFC2732-style specified IP-address */
+ portptr = &hostname[len];
+ if (*portptr != ':')
+ return CURLUE_MALFORMED_INPUT;
+ }
+ else
+ portptr = strchr(hostname, ':');
+
+ if(portptr) {
+ char *rest;
+ long port;
+ char portbuf[7];
+
+ if(!ISDIGIT(portptr[1]))
+ return CURLUE_BAD_PORT_NUMBER;
+
+ 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, but we don't
+ treat port zero as OK. */
+ return CURLUE_BAD_PORT_NUMBER;
+
+ if(rest[0])
+ return CURLUE_BAD_PORT_NUMBER;
+
+ if(rest != &portptr[1]) {
+ *portptr++ = '\0'; /* cut off the name there */
+ *rest = 0;
+ /* generate a new to get rid of leading zeroes etc */
+ snprintf(portbuf, sizeof(portbuf), "%ld", port);
+ u->portnum = port;
+ u->port = strdup(portbuf);
+ if(!u->port)
+ return CURLUE_OUT_OF_MEMORY;
+ }
+ else {
+ /* Browser behavior adaptation. If there's a colon with no digits after,
+ just cut off the name there which makes us ignore the colon and just
+ use the default port. Firefox and Chrome both do that. */
+ *portptr = '\0';
+ }
+ }
+
+ return CURLUE_OK;
+}
+
+/* scan for byte values < 31 or 127 */
+static CURLUcode junkscan(char *part)
+{
+ char badbytes[]={
+ /* */ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x7f,
+ 0x00 /* zero terminate */
+ };
+ if(part) {
+ size_t n = strlen(part);
+ size_t nfine = strcspn(part, badbytes);
+ if(nfine != n)
+ /* since we don't know which part is scanned, return a generic error
+ code */
+ return CURLUE_MALFORMED_INPUT;
+ }
+ return CURLUE_OK;
+}
+
+static CURLUcode hostname_check(char *hostname, unsigned int flags)
+{
+ const char *l = NULL; /* accepted characters */
+ size_t len;
+ size_t hlen = strlen(hostname);
+ (void)flags;
+
+ if(hostname[0] == '[') {
+ hostname++;
+ l = "0123456789abcdefABCDEF::.%";
+ hlen -= 2;
+ }
+
+ if(l) {
+ /* only valid letters are ok */
+ len = strspn(hostname, l);
+ if(hlen != len)
+ /* hostname with bad content */
+ return CURLUE_MALFORMED_INPUT;
+ }
+ else {
+ /* letters from the second string is not ok */
+ len = strcspn(hostname, " ");
+ if(hlen != len)
+ /* hostname with bad content */
+ return CURLUE_MALFORMED_INPUT;
+ }
+ return CURLUE_OK;
+}
+
+#define HOSTNAME_END(x) (((x) == '/') || ((x) == '?') || ((x) == '#'))
+
+static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
+{
+ char *path;
+ bool path_alloced = FALSE;
+ char *hostname;
+ char *query = NULL;
+ char *fragment = NULL;
+ CURLUcode result;
+ bool url_has_scheme = FALSE;
+ char schemebuf[MAX_SCHEME_LEN];
+ char *schemep = NULL;
+ size_t schemelen = 0;
+ size_t urllen;
+ const struct Curl_handler *h = NULL;
+
+ if(!url)
+ return CURLUE_MALFORMED_INPUT;
+
+ /*************************************************************
+ * Parse the URL.
+ ************************************************************/
+ /* allocate scratch area */
+ urllen = strlen(url);
+ path = u->scratch = malloc(urllen * 2 + 2);
+ if(!path)
+ return CURLUE_OUT_OF_MEMORY;
+
+ hostname = &path[urllen + 1];
+ hostname[0] = 0;
+
+ if(Curl_is_absolute_url(url, schemebuf, sizeof(schemebuf))) {
+ url_has_scheme = TRUE;
+ schemelen = strlen(schemebuf);
+ }
+
+ /* handle the file: scheme */
+ if(url_has_scheme && strcasecompare(schemebuf, "file")) {
+ /* path has been allocated large enough to hold this */
+ strcpy(path, &url[5]);
+
+ hostname = NULL; /* no host for file: URLs */
+ u->scheme = strdup("file");
+ if(!u->scheme)
+ return CURLUE_OUT_OF_MEMORY;
+
+ /* 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] == '/' && path[1] == '/') {
+ /* swallow the two slashes */
+ char *ptr = &path[2];
+
+ /*
+ * 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)) {
+ /* Invalid file://hostname/, expected localhost or 127.0.0.1 or
+ none */
+ return CURLUE_MALFORMED_INPUT;
+ }
+ ptr += 9; /* now points to the slash after the host */
+ }
+
+ path = ptr;
+ }
+
+#if !defined(MSDOS) && !defined(WIN32) && !defined(__CYGWIN__)
+ /* 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)) {
+ /* File drive letters are only accepted in MSDOS/Windows */
+ return CURLUE_MALFORMED_INPUT;
+ }
+#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
+
+ }
+ else {
+ /* clear path */
+ const char *p;
+ const char *hostp;
+ size_t len;
+ path[0] = 0;
+
+ if(url_has_scheme) {
+ int i = 0;
+ p = &url[schemelen + 1];
+ while(p && (*p == '/') && (i < 4)) {
+ p++;
+ i++;
+ }
+ if((i < 1) || (i>3))
+ /* less than one or more than three slashes */
+ return CURLUE_MALFORMED_INPUT;
+
+ schemep = schemebuf;
+ if(!Curl_builtin_scheme(schemep) &&
+ !(flags & CURLU_NON_SUPPORT_SCHEME))
+ return CURLUE_UNSUPPORTED_SCHEME;
+
+ if(junkscan(schemep))
+ return CURLUE_MALFORMED_INPUT;
+ }
+ else {
+ /* no scheme! */
+
+ if(!(flags & (CURLU_DEFAULT_SCHEME|CURLU_GUESS_SCHEME)))
+ return CURLUE_MALFORMED_INPUT;
+ if(flags & CURLU_DEFAULT_SCHEME)
+ schemep = (char *) DEFAULT_SCHEME;
+
+ /*
+ * The URL was badly formatted, let's try without scheme specified.
+ */
+ p = url;
+ }
+ hostp = p; /* host name starts here */
+
+ while(*p && !HOSTNAME_END(*p)) /* find end of host name */
+ p++;
+
+ len = p - hostp;
+ if(!len)
+ return CURLUE_MALFORMED_INPUT;
+
+ memcpy(hostname, hostp, len);
+ hostname[len] = 0;
+
+ if((flags & CURLU_GUESS_SCHEME) && !schemep) {
+ /* legacy curl-style guess based on host name */
+ if(checkprefix("ftp.", hostname))
+ schemep = (char *)"ftp";
+ else if(checkprefix("dict.", hostname))
+ schemep = (char *)"dict";
+ else if(checkprefix("ldap.", hostname))
+ schemep = (char *)"ldap";
+ else if(checkprefix("imap.", hostname))
+ schemep = (char *)"imap";
+ else if(checkprefix("smtp.", hostname))
+ schemep = (char *)"smtp";
+ else if(checkprefix("pop3.", hostname))
+ schemep = (char *)"pop3";
+ else
+ schemep = (char *)"http";
+ }
+
+ len = strlen(p);
+ memcpy(path, p, len);
+ path[len] = 0;
+
+ u->scheme = strdup(schemep);
+ if(!u->scheme)
+ return CURLUE_OUT_OF_MEMORY;
+ }
+
+ /* if this is a known scheme, get some details */
+ h = Curl_builtin_scheme(u->scheme);
+
+ if(junkscan(path))
+ return CURLUE_MALFORMED_INPUT;
+
+ query = strchr(path, '?');
+ if(query)
+ *query++ = 0;
+
+ fragment = strchr(query?query:path, '#');
+ if(fragment)
+ *fragment++ = 0;
+
+ if(!path[0])
+ /* if there's no path set, unset */
+ path = NULL;
+ else if(!(flags & CURLU_PATH_AS_IS)) {
+ /* sanitise paths and remove ../ and ./ sequences according to RFC3986 */
+ char *newp = Curl_dedotdotify(path);
+ if(!newp)
+ return CURLUE_OUT_OF_MEMORY;
+
+ if(strcmp(newp, path)) {
+ /* if we got a new version */
+ path = newp;
+ path_alloced = TRUE;
+ }
+ else
+ free(newp);
+ }
+ if(path) {
+ u->path = path_alloced?path:strdup(path);
+ if(!u->path)
+ return CURLUE_OUT_OF_MEMORY;
+ }
+
+ if(hostname) {
+ /*
+ * Parse the login details and strip them out of the host name.
+ */
+ if(junkscan(hostname))
+ return CURLUE_MALFORMED_INPUT;
+
+ result = parse_hostname_login(u, h, &hostname, flags);
+ if(result)
+ return result;
+
+ result = parse_port(u, hostname);
+ if(result)
+ return result;
+
+ result = hostname_check(hostname, flags);
+ if(result)
+ return result;
+
+ u->host = strdup(hostname);
+ if(!u->host)
+ return CURLUE_OUT_OF_MEMORY;
+ }
+
+ if(query && query[0]) {
+ u->query = strdup(query);
+ if(!u->query)
+ return CURLUE_OUT_OF_MEMORY;
+ }
+ if(fragment && fragment[0]) {
+ u->fragment = strdup(fragment);
+ if(!u->fragment)
+ return CURLUE_OUT_OF_MEMORY;
+ }
+
+ free(u->scratch);
+ u->scratch = NULL;
+
+ return CURLUE_OK;
+}
+
+/*
+ * Parse the URL and set the relevant members of the Curl_URL struct.
+ */
+static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
+{
+ CURLUcode result = seturl(url, u, flags);
+ if(result) {
+ free_urlhandle(u);
+ memset(u, 0, sizeof(struct Curl_URL));
+ }
+ return result;
+}
+
+/*
+ */
+CURLU *curl_url(void)
+{
+ return calloc(sizeof(struct Curl_URL), 1);
+}
+
+void curl_url_cleanup(CURLU *u)
+{
+ if(u) {
+ free_urlhandle(u);
+ free(u);
+ }
+}
+
+#define DUP(dest, src, name) \
+ if(src->name) { \
+ dest->name = strdup(src->name); \
+ if(!dest->name) \
+ goto fail; \
+ }
+
+CURLU *curl_url_dup(CURLU *in)
+{
+ struct Curl_URL *u = calloc(sizeof(struct Curl_URL), 1);
+ if(u) {
+ DUP(u, in, scheme);
+ DUP(u, in, user);
+ DUP(u, in, password);
+ DUP(u, in, options);
+ DUP(u, in, host);
+ DUP(u, in, port);
+ DUP(u, in, path);
+ DUP(u, in, query);
+ DUP(u, in, fragment);
+ u->portnum = in->portnum;
+ }
+ return u;
+ fail:
+ curl_url_cleanup(u);
+ return NULL;
+}
+
+CURLUcode curl_url_get(CURLU *u, CURLUPart what,
+ char **part, unsigned int flags)
+{
+ char *ptr;
+ CURLUcode ifmissing = CURLUE_UNKNOWN_PART;
+ char portbuf[7];
+ bool urldecode = (flags & CURLU_URLDECODE)?1:0;
+ bool plusdecode = FALSE;
+ (void)flags;
+ if(!u)
+ return CURLUE_BAD_HANDLE;
+ if(!part)
+ return CURLUE_BAD_PARTPOINTER;
+ *part = NULL;
+
+ switch(what) {
+ case CURLUPART_SCHEME:
+ ptr = u->scheme;
+ ifmissing = CURLUE_NO_SCHEME;
+ urldecode = FALSE; /* never for schemes */
+ break;
+ case CURLUPART_USER:
+ ptr = u->user;
+ ifmissing = CURLUE_NO_USER;
+ break;
+ case CURLUPART_PASSWORD:
+ ptr = u->password;
+ ifmissing = CURLUE_NO_PASSWORD;
+ break;
+ case CURLUPART_OPTIONS:
+ ptr = u->options;
+ ifmissing = CURLUE_NO_OPTIONS;
+ break;
+ case CURLUPART_HOST:
+ ptr = u->host;
+ ifmissing = CURLUE_NO_HOST;
+ break;
+ case CURLUPART_PORT:
+ ptr = u->port;
+ ifmissing = CURLUE_NO_PORT;
+ urldecode = FALSE; /* never for port */
+ if(!ptr && (flags & CURLU_DEFAULT_PORT) && u->scheme) {
+ /* there's no stored port number, but asked to deliver
+ a default one for the scheme */
+ const struct Curl_handler *h =
+ Curl_builtin_scheme(u->scheme);
+ if(h) {
+ snprintf(portbuf, sizeof(portbuf), "%ld", h->defport);
+ ptr = portbuf;
+ }
+ }
+ else if(ptr && u->scheme) {
+ /* there is a stored port number, but ask to inhibit if
+ it matches the default one for the scheme */
+ const struct Curl_handler *h =
+ Curl_builtin_scheme(u->scheme);
+ if(h && (h->defport == u->portnum) &&
+ (flags & CURLU_NO_DEFAULT_PORT))
+ ptr = NULL;
+ }
+ break;
+ case CURLUPART_PATH:
+ ptr = u->path;
+ if(!ptr) {
+ ptr = u->path = strdup("/");
+ if(!u->path)
+ return CURLUE_OUT_OF_MEMORY;
+ }
+ break;
+ case CURLUPART_QUERY:
+ ptr = u->query;
+ ifmissing = CURLUE_NO_QUERY;
+ plusdecode = urldecode;
+ break;
+ case CURLUPART_FRAGMENT:
+ ptr = u->fragment;
+ ifmissing = CURLUE_NO_FRAGMENT;
+ break;
+ case CURLUPART_URL: {
+ char *url;
+ char *scheme;
+ char *options = u->options;
+ char *port = u->port;
+ if(u->scheme && strcasecompare("file", u->scheme)) {
+ url = aprintf("file://%s%s%s",
+ u->path,
+ u->fragment? "#": "",
+ u->fragment? u->fragment : "");
+ }
+ else if(!u->host)
+ return CURLUE_NO_HOST;
+ else {
+ const struct Curl_handler *h = NULL;
+ if(u->scheme)
+ scheme = u->scheme;
+ else if(flags & CURLU_DEFAULT_SCHEME)
+ scheme = (char *) DEFAULT_SCHEME;
+ else
+ return CURLUE_NO_SCHEME;
+
+ if(scheme) {
+ h = Curl_builtin_scheme(scheme);
+ if(!port && (flags & CURLU_DEFAULT_PORT)) {
+ /* there's no stored port number, but asked to deliver
+ a default one for the scheme */
+ if(h) {
+ snprintf(portbuf, sizeof(portbuf), "%ld", h->defport);
+ port = portbuf;
+ }
+ }
+ else if(port) {
+ /* there is a stored port number, but asked to inhibit if it matches
+ the default one for the scheme */
+ if(h && (h->defport == u->portnum) &&
+ (flags & CURLU_NO_DEFAULT_PORT))
+ port = NULL;
+ }
+ }
+ if(h && !(h->flags & PROTOPT_URLOPTIONS))
+ options = NULL;
+
+ url = aprintf("%s://%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ scheme,
+ u->user ? u->user : "",
+ u->password ? ":": "",
+ u->password ? u->password : "",
+ options ? ";" : "",
+ options ? options : "",
+ (u->user || u->password || options) ? "@": "",
+ u->host,
+ port ? ":": "",
+ port ? port : "",
+ (u->path && (u->path[0] != '/')) ? "/": "",
+ u->path ? u->path : "/",
+ u->query? "?": "",
+ u->query? u->query : "",
+ u->fragment? "#": "",
+ u->fragment? u->fragment : "");
+ }
+ if(!url)
+ return CURLUE_OUT_OF_MEMORY;
+ *part = url;
+ return CURLUE_OK;
+ break;
+ }
+ default:
+ ptr = NULL;
+ }
+ if(ptr) {
+ *part = strdup(ptr);
+ if(!*part)
+ return CURLUE_OUT_OF_MEMORY;
+ if(plusdecode) {
+ /* convert + to space */
+ char *plus;
+ for(plus = *part; *plus; ++plus) {
+ if(*plus == '+')
+ *plus = ' ';
+ }
+ }
+ if(urldecode) {
+ char *decoded;
+ size_t dlen;
+ CURLcode res = Curl_urldecode(NULL, *part, 0, &decoded, &dlen, TRUE);
+ free(*part);
+ if(res) {
+ *part = NULL;
+ return CURLUE_URLDECODE;
+ }
+ *part = decoded;
+ }
+ return CURLUE_OK;
+ }
+ else
+ return ifmissing;
+}
+
+CURLUcode curl_url_set(CURLU *u, CURLUPart what,
+ const char *part, unsigned int flags)
+{
+ char **storep = NULL;
+ long port = 0;
+ bool urlencode = (flags & CURLU_URLENCODE)? 1 : 0;
+ bool plusencode = FALSE;
+ bool urlskipslash = FALSE;
+ bool appendquery = FALSE;
+
+ if(!u)
+ return CURLUE_BAD_HANDLE;
+ if(!part) {
+ /* setting a part to NULL clears it */
+ switch(what) {
+ case CURLUPART_URL:
+ break;
+ case CURLUPART_SCHEME:
+ storep = &u->scheme;
+ break;
+ case CURLUPART_USER:
+ storep = &u->user;
+ break;
+ case CURLUPART_PASSWORD:
+ storep = &u->password;
+ break;
+ case CURLUPART_OPTIONS:
+ storep = &u->options;
+ break;
+ case CURLUPART_HOST:
+ storep = &u->host;
+ break;
+ case CURLUPART_PORT:
+ storep = &u->port;
+ break;
+ case CURLUPART_PATH:
+ storep = &u->path;
+ break;
+ case CURLUPART_QUERY:
+ storep = &u->query;
+ break;
+ case CURLUPART_FRAGMENT:
+ storep = &u->fragment;
+ break;
+ default:
+ return CURLUE_UNKNOWN_PART;
+ }
+ if(storep && *storep) {
+ free(*storep);
+ *storep = NULL;
+ }
+ return CURLUE_OK;
+ }
+
+ switch(what) {
+ case CURLUPART_SCHEME:
+ if(!(flags & CURLU_NON_SUPPORT_SCHEME) &&
+ /* verify that it is a fine scheme */
+ !Curl_builtin_scheme(part))
+ return CURLUE_UNSUPPORTED_SCHEME;
+ storep = &u->scheme;
+ urlencode = FALSE; /* never */
+ break;
+ case CURLUPART_USER:
+ storep = &u->user;
+ break;
+ case CURLUPART_PASSWORD:
+ storep = &u->password;
+ break;
+ case CURLUPART_OPTIONS:
+ storep = &u->options;
+ break;
+ case CURLUPART_HOST:
+ storep = &u->host;
+ break;
+ case CURLUPART_PORT:
+ urlencode = FALSE; /* never */
+ port = strtol(part, NULL, 10); /* Port number must be decimal */
+ if((port <= 0) || (port > 0xffff))
+ return CURLUE_BAD_PORT_NUMBER;
+ storep = &u->port;
+ break;
+ case CURLUPART_PATH:
+ urlskipslash = TRUE;
+ storep = &u->path;
+ break;
+ case CURLUPART_QUERY:
+ plusencode = urlencode;
+ appendquery = (flags & CURLU_APPENDQUERY)?1:0;
+ storep = &u->query;
+ break;
+ case CURLUPART_FRAGMENT:
+ storep = &u->fragment;
+ break;
+ case CURLUPART_URL: {
+ /*
+ * Allow a new URL to replace the existing (if any) contents.
+ *
+ * If the existing contents is enough for a URL, allow a relative URL to
+ * replace it.
+ */
+ CURLUcode result;
+ char *oldurl;
+ char *redired_url;
+ CURLU *handle2;
+
+ if(Curl_is_absolute_url(part, NULL, MAX_SCHEME_LEN)) {
+ handle2 = curl_url();
+ if(!handle2)
+ return CURLUE_OUT_OF_MEMORY;
+ result = parseurl(part, handle2, flags);
+ if(!result)
+ mv_urlhandle(handle2, u);
+ else
+ curl_url_cleanup(handle2);
+ return result;
+ }
+ /* extract the full "old" URL to do the redirect on */
+ result = curl_url_get(u, CURLUPART_URL, &oldurl, flags);
+ if(result) {
+ /* couldn't get the old URL, just use the new! */
+ handle2 = curl_url();
+ if(!handle2)
+ return CURLUE_OUT_OF_MEMORY;
+ result = parseurl(part, handle2, flags);
+ if(!result)
+ mv_urlhandle(handle2, u);
+ else
+ curl_url_cleanup(handle2);
+ return result;
+ }
+
+ /* apply the relative part to create a new URL */
+ redired_url = Curl_concat_url(oldurl, part);
+ free(oldurl);
+ if(!redired_url)
+ return CURLUE_OUT_OF_MEMORY;
+
+ /* now parse the new URL */
+ handle2 = curl_url();
+ if(!handle2) {
+ free(redired_url);
+ return CURLUE_OUT_OF_MEMORY;
+ }
+ result = parseurl(redired_url, handle2, flags);
+ free(redired_url);
+ if(!result)
+ mv_urlhandle(handle2, u);
+ else
+ curl_url_cleanup(handle2);
+ return result;
+ }
+ default:
+ return CURLUE_UNKNOWN_PART;
+ }
+ if(storep) {
+ const char *newp = part;
+ size_t nalloc = strlen(part);
+
+ if(urlencode) {
+ const char *i;
+ char *o;
+ bool free_part = FALSE;
+ char *enc = malloc(nalloc * 3 + 1); /* for worst case! */
+ if(!enc)
+ return CURLUE_OUT_OF_MEMORY;
+ if(plusencode) {
+ /* space to plus */
+ i = part;
+ for(o = enc; *i; ++o, ++i)
+ *o = (*i == ' ') ? '+' : *i;
+ *o = 0; /* zero terminate */
+ part = strdup(enc);
+ if(!part) {
+ free(enc);
+ return CURLUE_OUT_OF_MEMORY;
+ }
+ free_part = TRUE;
+ }
+ for(i = part, o = enc; *i; i++) {
+ if(Curl_isunreserved(*i) ||
+ ((*i == '/') && urlskipslash) ||
+ ((*i == '=') && appendquery) ||
+ ((*i == '+') && plusencode)) {
+ *o = *i;
+ o++;
+ }
+ else {
+ snprintf(o, 4, "%%%02x", *i);
+ o += 3;
+ }
+ }
+ *o = 0; /* zero terminate */
+ newp = enc;
+ if(free_part)
+ free((char *)part);
+ }
+ else {
+ char *p;
+ newp = strdup(part);
+ if(!newp)
+ return CURLUE_OUT_OF_MEMORY;
+ p = (char *)newp;
+ while(*p) {
+ /* make sure percent encoded are lower case */
+ if((*p == '%') && ISXDIGIT(p[1]) && ISXDIGIT(p[2]) &&
+ (ISUPPER(p[1]) || ISUPPER(p[2]))) {
+ p[1] = (char)TOLOWER(p[1]);
+ p[2] = (char)TOLOWER(p[2]);
+ p += 3;
+ }
+ else
+ p++;
+ }
+ }
+
+ if(appendquery) {
+ /* Append the string onto the old query. Add a '&' separator if none is
+ present at the end of the exsting query already */
+ size_t querylen = u->query ? strlen(u->query) : 0;
+ bool addamperand = querylen && (u->query[querylen -1] != '&');
+ if(querylen) {
+ size_t newplen = strlen(newp);
+ char *p = malloc(querylen + addamperand + newplen + 1);
+ if(!p) {
+ free((char *)newp);
+ return CURLUE_OUT_OF_MEMORY;
+ }
+ strcpy(p, u->query); /* original query */
+ if(addamperand)
+ p[querylen] = '&'; /* ampersand */
+ strcpy(&p[querylen + addamperand], newp); /* new suffix */
+ free((char *)newp);
+ free(*storep);
+ *storep = p;
+ return CURLUE_OK;
+ }
+ }
+
+ free(*storep);
+ *storep = (char *)newp;
+ }
+ /* set after the string, to make it not assigned if the allocation above
+ fails */
+ if(port)
+ u->portnum = port;
+ return CURLUE_OK;
+}
diff --git a/lib/urldata.h b/lib/urldata.h
index 67db3b2f..11a6a22c 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -142,14 +142,6 @@ typedef ssize_t (Curl_recv)(struct connectdata *conn, /* connection data */
#include <libssh2_sftp.h>
#endif /* HAVE_LIBSSH2_H */
-/* The upload buffer size, should not be smaller than CURL_MAX_WRITE_SIZE, as
- it needs to hold a full buffer as could be sent in a write callback.
-
- The size was 16KB for many years but was bumped to 64KB because it makes
- libcurl able to do significantly faster uploads in some circumstances. Even
- larger buffers can help further, but this is deemed a fair memory/speed
- compromise. */
-#define UPLOAD_BUFSIZE 65536
/* The "master buffer" is for HTTP pipelining */
#define MASTERBUF_SIZE 16384
@@ -476,7 +468,6 @@ struct hostname {
#define KEEP_SENDBITS (KEEP_SEND | KEEP_SEND_HOLD | KEEP_SEND_PAUSE)
-#ifdef CURLRES_ASYNCH
struct Curl_async {
char *hostname;
int port;
@@ -485,7 +476,6 @@ struct Curl_async {
int status; /* if done is TRUE, this is the status from the callback */
void *os_specific; /* 'struct thread_data' for Windows */
};
-#endif
#define FIRSTSOCKET 0
#define SECONDARYSOCKET 1
@@ -511,6 +501,28 @@ enum upgrade101 {
UPGR101_WORKING /* talking upgraded protocol */
};
+struct dohresponse {
+ unsigned char *memory;
+ size_t size;
+};
+
+/* one of these for each DoH request */
+struct dnsprobe {
+ CURL *easy;
+ int dnstype;
+ unsigned char dohbuffer[512];
+ size_t dohlen;
+ struct dohresponse serverdoh;
+};
+
+struct dohdata {
+ struct curl_slist *headers;
+ struct dnsprobe probe[2];
+ unsigned int pending; /* still outstanding requests */
+ const char *host;
+ int port;
+};
+
/*
* Request specific data in the easy handle (Curl_easy). Previously,
* these members were on the connectdata struct but since a conn struct may
@@ -606,6 +618,7 @@ struct SingleRequest {
void *protop; /* Allocated protocol-specific data. Each protocol
handler makes sure this points to data it needs. */
+ struct dohdata doh; /* DoH specific data for this request */
};
/*
@@ -636,7 +649,7 @@ struct Curl_handler {
*/
CURLcode (*connect_it)(struct connectdata *, bool *done);
- /* See above. Currently only used for FTP. */
+ /* See above. */
CURLcode (*connecting)(struct connectdata *, bool *done);
CURLcode (*doing)(struct connectdata *, bool *done);
@@ -716,6 +729,7 @@ struct Curl_handler {
#define CONNCHECK_NONE 0 /* No checks */
#define CONNCHECK_ISDEAD (1<<0) /* Check if the connection is dead. */
+#define CONNCHECK_KEEPALIVE (1<<1) /* Perform any keepalive function. */
#define CONNRESULT_NONE 0 /* No extra information. */
#define CONNRESULT_DEAD (1<<0) /* The connection is dead. */
@@ -892,6 +906,13 @@ struct connectdata {
long ip_version; /* copied from the Curl_easy at creation time */
+ /* Protocols can use a custom keepalive mechanism to keep connections alive.
+ This allows those protocols to track the last time the keepalive mechanism
+ was used on this connection. */
+ struct curltime keepalive;
+
+ long upkeep_interval_ms; /* Time between calls for connection upkeep. */
+
/**** curl_get() phase fields */
curl_socket_t sockfd; /* socket to read from or CURL_SOCKET_BAD */
@@ -969,11 +990,8 @@ struct connectdata {
#endif
char syserr_buf [256]; /* buffer for Curl_strerror() */
-
-#ifdef CURLRES_ASYNCH
/* data used for the asynch name resolve callback */
struct Curl_async async;
-#endif
/* These three are used for chunked-encoding trailer support */
char *trailer; /* allocated buffer to store trailer in */
@@ -1206,6 +1224,18 @@ struct time_node {
expire_id eid;
};
+/* individual pieces of the URL */
+struct urlpieces {
+ char *scheme;
+ char *hostname;
+ char *port;
+ char *user;
+ char *password;
+ char *options;
+ char *path;
+ char *query;
+};
+
struct UrlState {
/* Points to the connection cache */
@@ -1225,7 +1255,7 @@ struct UrlState {
size_t headersize; /* size of the allocation */
char *buffer; /* download buffer */
- char *ulbuf; /* alloced upload buffer or NULL */
+ char *ulbuf; /* allocated upload buffer or NULL */
curl_off_t current_speed; /* the ProgressShow() function sets this,
bytes / second */
bool this_is_a_follow; /* this is a followed Location: request */
@@ -1296,9 +1326,6 @@ struct UrlState {
/* for FTP downloads: how many CRLFs did we converted to LFs? */
curl_off_t crlf_conversions;
#endif
- char *pathbuffer;/* allocated buffer to store the URL's path part in */
- char *path; /* path to use, points to somewhere within the pathbuffer
- area */
bool slash_removed; /* set TRUE if the 'path' points to a path where the
initial URL slash separator has been taken off */
bool use_range;
@@ -1332,6 +1359,8 @@ struct UrlState {
#ifdef CURLDEBUG
bool conncache_lock;
#endif
+ CURLU *uh; /* URL handle for the current parsed URL */
+ struct urlpieces up;
};
@@ -1442,18 +1471,23 @@ enum dupstring {
STRING_UNIX_SOCKET_PATH, /* path to Unix socket, if used */
#endif
STRING_TARGET, /* CURLOPT_REQUEST_TARGET */
+ STRING_DOH, /* CURLOPT_DOH_URL */
/* -- end of zero-terminated strings -- */
STRING_LASTZEROTERMINATED,
- /* -- below this are pointers to binary data that cannot be strdup'ed.
- Each such pointer must be added manually to Curl_dupset() --- */
+ /* -- below this are pointers to binary data that cannot be strdup'ed. --- */
STRING_COPYPOSTFIELDS, /* if POST, set the fields' values here */
STRING_LAST /* not used, just an end-of-list marker */
};
+/* callback that gets called when this easy handle is completed within a multi
+ handle. Only used for internally created transfers, like for example
+ DoH. */
+typedef int (*multidone_func)(struct Curl_easy *easy, CURLcode result);
+
struct UserDefined {
FILE *err; /* the stderr user data goes here */
void *debugdata; /* the data that will be passed to fdebug */
@@ -1562,8 +1596,8 @@ struct UserDefined {
curl_proxytype proxytype; /* what kind of proxy that is in use */
long dns_cache_timeout; /* DNS cache timeout */
long buffer_size; /* size of receive buffer to use */
- long upload_buffer_size; /* size of upload buffer to use,
- keep it >= CURL_MAX_WRITE_SIZE */
+ size_t upload_buffer_size; /* size of upload buffer to use,
+ keep it >= CURL_MAX_WRITE_SIZE */
void *private_data; /* application-private data */
struct curl_slist *http200aliases; /* linked list of aliases for http200 */
@@ -1689,6 +1723,11 @@ struct UserDefined {
before resolver start */
void *resolver_start_client; /* pointer to pass to resolver start callback */
bool disallow_username_in_url; /* disallow username in url */
+ long upkeep_interval_ms; /* Time between calls for connection upkeep. */
+ bool doh; /* DNS-over-HTTPS enabled */
+ bool doh_get; /* use GET for DoH requests, instead of POST */
+ multidone_func fmultidone;
+ struct Curl_easy *dohfor; /* this is a DoH request for that transfer */
};
struct Names {
diff --git a/lib/vauth/cleartext.c b/lib/vauth/cleartext.c
index 5d61ce6d..be6d6111 100644
--- a/lib/vauth/cleartext.c
+++ b/lib/vauth/cleartext.c
@@ -50,7 +50,7 @@
*
* data [in] - The session handle.
* userp [in] - The user name.
- * passdwp [in] - The user's password.
+ * passwdp [in] - The user's password.
* outptr [in/out] - The address where a pointer to newly allocated memory
* holding the result will be stored upon completion.
* outlen [out] - The length of the output message.
@@ -74,7 +74,7 @@ CURLcode Curl_auth_create_plain_message(struct Curl_easy *data,
plen = strlen(passwdp);
/* Compute binary message length. Check for overflows. */
- if((ulen > SIZE_T_MAX/2) || (plen > (SIZE_T_MAX/2 - 2)))
+ if((ulen > SIZE_T_MAX/4) || (plen > (SIZE_T_MAX/2 - 2)))
return CURLE_OUT_OF_MEMORY;
plainlen = 2 * ulen + plen + 2;
diff --git a/lib/vauth/cram.c b/lib/vauth/cram.c
index 3074a163..d148618b 100644
--- a/lib/vauth/cram.c
+++ b/lib/vauth/cram.c
@@ -81,7 +81,7 @@ CURLcode Curl_auth_decode_cram_md5_message(const char *chlg64, char **outptr,
* data [in] - The session handle.
* chlg [in] - The challenge.
* userp [in] - The user name.
- * passdwp [in] - The user's password.
+ * passwdp [in] - The user's password.
* outptr [in/out] - The address where a pointer to newly allocated memory
* holding the result will be stored upon completion.
* outlen [out] - The length of the output message.
diff --git a/lib/vauth/digest.c b/lib/vauth/digest.c
index cc6f1697..ab5156eb 100644
--- a/lib/vauth/digest.c
+++ b/lib/vauth/digest.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2018, 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
@@ -342,7 +342,7 @@ bool Curl_auth_is_digest_supported(void)
* data [in] - The session handle.
* chlg64 [in] - The base64 encoded challenge message.
* userp [in] - The user name.
- * passdwp [in] - The user's password.
+ * passwdp [in] - The user's password.
* service [in] - The service type such as http, smtp, pop or imap.
* outptr [in/out] - The address where a pointer to newly allocated memory
* holding the result will be stored upon completion.
@@ -668,7 +668,7 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
*
* data [in] - The session handle.
* userp [in] - The user name.
- * passdwp [in] - The user's password.
+ * passwdp [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.
@@ -781,6 +781,8 @@ static CURLcode _Curl_auth_create_digest_http_message(
*/
hashthis = (unsigned char *) aprintf("%s:%s", request, uripath);
+ if(!hashthis)
+ return CURLE_OUT_OF_MEMORY;
if(digest->qop && strcasecompare(digest->qop, "auth-int")) {
/* We don't support auth-int for PUT or POST at the moment.
@@ -932,7 +934,7 @@ static CURLcode _Curl_auth_create_digest_http_message(
*
* data [in] - The session handle.
* userp [in] - The user name.
- * passdwp [in] - The user's password.
+ * passwdp [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.
diff --git a/lib/vauth/digest_sspi.c b/lib/vauth/digest_sspi.c
index a3f96ed2..92875573 100644
--- a/lib/vauth/digest_sspi.c
+++ b/lib/vauth/digest_sspi.c
@@ -75,7 +75,7 @@ bool Curl_auth_is_digest_supported(void)
* data [in] - The session handle.
* chlg64 [in] - The base64 encoded challenge message.
* userp [in] - The user name in the format User or Domain\User.
- * passdwp [in] - The user's password.
+ * passwdp [in] - The user's password.
* service [in] - The service type such as http, smtp, pop or imap.
* outptr [in/out] - The address where a pointer to newly allocated memory
* holding the result will be stored upon completion.
@@ -391,7 +391,7 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
*
* data [in] - The session handle.
* userp [in] - The user name in the format User or Domain\User.
- * passdwp [in] - The user's password.
+ * passwdp [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.
diff --git a/lib/vauth/krb5_gssapi.c b/lib/vauth/krb5_gssapi.c
index 560ecc5b..55daec1f 100644
--- a/lib/vauth/krb5_gssapi.c
+++ b/lib/vauth/krb5_gssapi.c
@@ -65,7 +65,7 @@ bool Curl_auth_is_gssapi_supported(void)
*
* data [in] - The session handle.
* userp [in] - The user name.
- * passdwp [in] - The user's password.
+ * passwdp [in] - The user's password.
* service [in] - The service type such as http, smtp, pop or imap.
* host [in[ - The host name.
* mutual_auth [in] - Flag specifying whether or not mutual authentication
diff --git a/lib/vauth/krb5_sspi.c b/lib/vauth/krb5_sspi.c
index 9afb971f..cb11ed90 100644
--- a/lib/vauth/krb5_sspi.c
+++ b/lib/vauth/krb5_sspi.c
@@ -71,7 +71,7 @@ bool Curl_auth_is_gssapi_supported(void)
*
* data [in] - The session handle.
* userp [in] - The user name in the format User or Domain\User.
- * passdwp [in] - The user's password.
+ * passwdp [in] - The user's password.
* service [in] - The service type such as http, smtp, pop or imap.
* host [in] - The host name.
* mutual_auth [in] - Flag specifying whether or not mutual authentication
diff --git a/lib/vauth/ntlm.c b/lib/vauth/ntlm.c
index cdb8d8f0..11f42f50 100644
--- a/lib/vauth/ntlm.c
+++ b/lib/vauth/ntlm.c
@@ -354,7 +354,7 @@ static void unicodecpy(unsigned char *dest, const char *src, size_t length)
*
* data [in] - The session handle.
* userp [in] - The user name in the format User or Domain\User.
- * passdwp [in] - The user's password.
+ * passwdp [in] - The user's password.
* service [in] - The service type such as http, smtp, pop or imap.
* host [in] - The host name.
* ntlm [in/out] - The NTLM data struct being used and modified.
@@ -481,7 +481,7 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
*
* data [in] - The session handle.
* userp [in] - The user name in the format User or Domain\User.
- * passdwp [in] - The user's password.
+ * passwdp [in] - The user's password.
* ntlm [in/out] - The NTLM data struct being used and modified.
* outptr [in/out] - The address where a pointer to newly allocated memory
* holding the result will be stored upon completion.
diff --git a/lib/vauth/ntlm_sspi.c b/lib/vauth/ntlm_sspi.c
index 089c1a6d..b66cfe73 100644
--- a/lib/vauth/ntlm_sspi.c
+++ b/lib/vauth/ntlm_sspi.c
@@ -69,7 +69,7 @@ bool Curl_auth_is_ntlm_supported(void)
*
* data [in] - The session handle.
* userp [in] - The user name in the format User or Domain\User.
- * passdwp [in] - The user's password.
+ * passwdp [in] - The user's password.
* service [in] - The service type such as http, smtp, pop or imap.
* host [in] - The host name.
* ntlm [in/out] - The NTLM data struct being used and modified.
@@ -234,7 +234,7 @@ CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data,
*
* data [in] - The session handle.
* userp [in] - The user name in the format User or Domain\User.
- * passdwp [in] - The user's password.
+ * passwdp [in] - The user's password.
* ntlm [in/out] - The NTLM data struct being used and modified.
* outptr [in/out] - The address where a pointer to newly allocated memory
* holding the result will be stored upon completion.
diff --git a/lib/vauth/spnego_gssapi.c b/lib/vauth/spnego_gssapi.c
index 5196c270..4a48bdd2 100644
--- a/lib/vauth/spnego_gssapi.c
+++ b/lib/vauth/spnego_gssapi.c
@@ -64,7 +64,7 @@ bool Curl_auth_is_spnego_supported(void)
*
* data [in] - The session handle.
* userp [in] - The user name in the format User or Domain\User.
- * passdwp [in] - The user's password.
+ * passwdp [in] - The user's password.
* service [in] - The service type such as http, smtp, pop or imap.
* host [in] - The host name.
* chlg64 [in] - The optional base64 encoded challenge message.
diff --git a/lib/vauth/spnego_sspi.c b/lib/vauth/spnego_sspi.c
index 1fe19e3f..77d1895a 100644
--- a/lib/vauth/spnego_sspi.c
+++ b/lib/vauth/spnego_sspi.c
@@ -71,8 +71,8 @@ bool Curl_auth_is_spnego_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.
+ * user [in] - The user name in the format User or Domain\User.
+ * password [in] - The user's password.
* service [in] - The service type such as http, smtp, pop or imap.
* host [in] - The host name.
* chlg64 [in] - The optional base64 encoded challenge message.
diff --git a/lib/vtls/axtls.h b/lib/vtls/axtls.h
index 3f1e129c..cb818727 100644
--- a/lib/vtls/axtls.h
+++ b/lib/vtls/axtls.h
@@ -31,4 +31,3 @@ extern const struct Curl_ssl Curl_ssl_axtls;
#endif /* USE_AXTLS */
#endif /* HEADER_CURL_AXTLS_H */
-
diff --git a/lib/vtls/darwinssl.c b/lib/vtls/darwinssl.c
index 1aea0dc3..e8116b8a 100644
--- a/lib/vtls/darwinssl.c
+++ b/lib/vtls/darwinssl.c
@@ -64,6 +64,7 @@
#define CURL_BUILD_IOS 0
#define CURL_BUILD_IOS_7 0
+#define CURL_BUILD_IOS_9 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: */
@@ -72,6 +73,7 @@
#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_11 MAC_OS_X_VERSION_MAX_ALLOWED >= 101100
#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":
@@ -86,6 +88,7 @@
#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_9 __IPHONE_OS_VERSION_MAX_ALLOWED >= 90000
#define CURL_BUILD_IOS_11 __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000
#define CURL_BUILD_MAC 0
#define CURL_BUILD_MAC_10_5 0
@@ -93,6 +96,7 @@
#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_11 0
#define CURL_BUILD_MAC_10_13 0
#define CURL_SUPPORT_MAC_10_5 0
#define CURL_SUPPORT_MAC_10_6 0
@@ -116,6 +120,7 @@
#include "vtls.h"
#include "darwinssl.h"
#include "curl_printf.h"
+#include "strdup.h"
#include "curl_memory.h"
/* The last #include file should be: */
@@ -945,7 +950,7 @@ static CURLcode CopyCertSubject(struct Curl_easy *data,
if(!c) {
failf(data, "SSL: invalid CA certificate subject");
- return CURLE_OUT_OF_MEMORY;
+ return CURLE_SSL_CACERT;
}
/* If the subject is already available as UTF-8 encoded (ie 'direct') then
@@ -1299,8 +1304,6 @@ set_ssl_version_min_max(struct connectdata *conn, int sockindex)
switch(ssl_version_max) {
case CURL_SSLVERSION_MAX_NONE:
- ssl_version_max = ssl_version << 16;
- break;
case CURL_SSLVERSION_MAX_DEFAULT:
ssl_version_max = max_supported_version_by_os;
break;
@@ -1646,6 +1649,8 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
}
CFRelease(cert);
+ if(result == CURLE_SSL_CACERT)
+ return CURLE_SSL_CERTPROBLEM;
if(result)
return result;
}
@@ -1781,107 +1786,118 @@ 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(BACKEND->ssl_ctx, &all_ciphers_count);
+ err = SSLGetNumberSupportedCiphers(BACKEND->ssl_ctx, &all_ciphers_count);
+ if(err != noErr) {
+ failf(data, "SSL: SSLGetNumberSupportedCiphers() failed: OSStatus %d",
+ err);
+ return CURLE_SSL_CIPHER;
+ }
all_ciphers = malloc(all_ciphers_count*sizeof(SSLCipherSuite));
- allowed_ciphers = malloc(all_ciphers_count*sizeof(SSLCipherSuite));
- if(all_ciphers && allowed_ciphers &&
- SSLGetSupportedCiphers(BACKEND->ssl_ctx, all_ciphers,
- &all_ciphers_count) == noErr) {
- for(i = 0UL ; i < all_ciphers_count ; i++) {
-#if CURL_BUILD_MAC
- /* There's a known bug in early versions of Mountain Lion where ST's ECC
- ciphers (cipher suite 0xC001 through 0xC032) simply do not work.
- Work around the problem here by disabling those ciphers if we are
- running in an affected version of OS X. */
- if(darwinver_maj == 12 && darwinver_min <= 3 &&
- all_ciphers[i] >= 0xC001 && all_ciphers[i] <= 0xC032) {
- continue;
- }
-#endif /* CURL_BUILD_MAC */
- switch(all_ciphers[i]) {
- /* Disable NULL ciphersuites: */
- case SSL_NULL_WITH_NULL_NULL:
- case SSL_RSA_WITH_NULL_MD5:
- case SSL_RSA_WITH_NULL_SHA:
- case 0x003B: /* TLS_RSA_WITH_NULL_SHA256 */
- case SSL_FORTEZZA_DMS_WITH_NULL_SHA:
- case 0xC001: /* TLS_ECDH_ECDSA_WITH_NULL_SHA */
- case 0xC006: /* TLS_ECDHE_ECDSA_WITH_NULL_SHA */
- case 0xC00B: /* TLS_ECDH_RSA_WITH_NULL_SHA */
- case 0xC010: /* TLS_ECDHE_RSA_WITH_NULL_SHA */
- case 0x002C: /* TLS_PSK_WITH_NULL_SHA */
- case 0x002D: /* TLS_DHE_PSK_WITH_NULL_SHA */
- case 0x002E: /* TLS_RSA_PSK_WITH_NULL_SHA */
- case 0x00B0: /* TLS_PSK_WITH_NULL_SHA256 */
- case 0x00B1: /* TLS_PSK_WITH_NULL_SHA384 */
- case 0x00B4: /* TLS_DHE_PSK_WITH_NULL_SHA256 */
- case 0x00B5: /* TLS_DHE_PSK_WITH_NULL_SHA384 */
- case 0x00B8: /* TLS_RSA_PSK_WITH_NULL_SHA256 */
- case 0x00B9: /* TLS_RSA_PSK_WITH_NULL_SHA384 */
- /* Disable anonymous ciphersuites: */
- case SSL_DH_anon_EXPORT_WITH_RC4_40_MD5:
- case SSL_DH_anon_WITH_RC4_128_MD5:
- case SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA:
- case SSL_DH_anon_WITH_DES_CBC_SHA:
- case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA:
- case TLS_DH_anon_WITH_AES_128_CBC_SHA:
- case TLS_DH_anon_WITH_AES_256_CBC_SHA:
- case 0xC015: /* TLS_ECDH_anon_WITH_NULL_SHA */
- case 0xC016: /* TLS_ECDH_anon_WITH_RC4_128_SHA */
- case 0xC017: /* TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA */
- case 0xC018: /* TLS_ECDH_anon_WITH_AES_128_CBC_SHA */
- case 0xC019: /* TLS_ECDH_anon_WITH_AES_256_CBC_SHA */
- case 0x006C: /* TLS_DH_anon_WITH_AES_128_CBC_SHA256 */
- case 0x006D: /* TLS_DH_anon_WITH_AES_256_CBC_SHA256 */
- case 0x00A6: /* TLS_DH_anon_WITH_AES_128_GCM_SHA256 */
- case 0x00A7: /* TLS_DH_anon_WITH_AES_256_GCM_SHA384 */
- /* Disable weak key ciphersuites: */
- case SSL_RSA_EXPORT_WITH_RC4_40_MD5:
- case SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5:
- case SSL_RSA_EXPORT_WITH_DES40_CBC_SHA:
- case SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA:
- case SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA:
- case SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA:
- case SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA:
- case SSL_RSA_WITH_DES_CBC_SHA:
- case SSL_DH_DSS_WITH_DES_CBC_SHA:
- case SSL_DH_RSA_WITH_DES_CBC_SHA:
- case SSL_DHE_DSS_WITH_DES_CBC_SHA:
- case SSL_DHE_RSA_WITH_DES_CBC_SHA:
- /* Disable IDEA: */
- case SSL_RSA_WITH_IDEA_CBC_SHA:
- case SSL_RSA_WITH_IDEA_CBC_MD5:
- /* Disable RC4: */
- case SSL_RSA_WITH_RC4_128_MD5:
- case SSL_RSA_WITH_RC4_128_SHA:
- case 0xC002: /* TLS_ECDH_ECDSA_WITH_RC4_128_SHA */
- case 0xC007: /* TLS_ECDHE_ECDSA_WITH_RC4_128_SHA*/
- case 0xC00C: /* TLS_ECDH_RSA_WITH_RC4_128_SHA */
- case 0xC011: /* TLS_ECDHE_RSA_WITH_RC4_128_SHA */
- case 0x008A: /* TLS_PSK_WITH_RC4_128_SHA */
- case 0x008E: /* TLS_DHE_PSK_WITH_RC4_128_SHA */
- case 0x0092: /* TLS_RSA_PSK_WITH_RC4_128_SHA */
- break;
- default: /* enable everything else */
- allowed_ciphers[allowed_ciphers_count++] = all_ciphers[i];
- break;
- }
- }
- err = SSLSetEnabledCiphers(BACKEND->ssl_ctx, allowed_ciphers,
- allowed_ciphers_count);
- if(err != noErr) {
- failf(data, "SSL: SSLSetEnabledCiphers() failed: OSStatus %d", err);
- return CURLE_SSL_CONNECT_ERROR;
- }
+ if(!all_ciphers) {
+ failf(data, "SSL: Failed to allocate memory for all ciphers");
+ return CURLE_OUT_OF_MEMORY;
}
- else {
+ allowed_ciphers = malloc(all_ciphers_count*sizeof(SSLCipherSuite));
+ if(!allowed_ciphers) {
Curl_safefree(all_ciphers);
- Curl_safefree(allowed_ciphers);
failf(data, "SSL: Failed to allocate memory for allowed ciphers");
return CURLE_OUT_OF_MEMORY;
}
+ err = SSLGetSupportedCiphers(BACKEND->ssl_ctx, all_ciphers,
+ &all_ciphers_count);
+ if(err != noErr) {
+ Curl_safefree(all_ciphers);
+ Curl_safefree(allowed_ciphers);
+ return CURLE_SSL_CIPHER;
+ }
+ for(i = 0UL ; i < all_ciphers_count ; i++) {
+#if CURL_BUILD_MAC
+ /* There's a known bug in early versions of Mountain Lion where ST's ECC
+ ciphers (cipher suite 0xC001 through 0xC032) simply do not work.
+ Work around the problem here by disabling those ciphers if we are
+ running in an affected version of OS X. */
+ if(darwinver_maj == 12 && darwinver_min <= 3 &&
+ all_ciphers[i] >= 0xC001 && all_ciphers[i] <= 0xC032) {
+ continue;
+ }
+#endif /* CURL_BUILD_MAC */
+ switch(all_ciphers[i]) {
+ /* Disable NULL ciphersuites: */
+ case SSL_NULL_WITH_NULL_NULL:
+ case SSL_RSA_WITH_NULL_MD5:
+ case SSL_RSA_WITH_NULL_SHA:
+ case 0x003B: /* TLS_RSA_WITH_NULL_SHA256 */
+ case SSL_FORTEZZA_DMS_WITH_NULL_SHA:
+ case 0xC001: /* TLS_ECDH_ECDSA_WITH_NULL_SHA */
+ case 0xC006: /* TLS_ECDHE_ECDSA_WITH_NULL_SHA */
+ case 0xC00B: /* TLS_ECDH_RSA_WITH_NULL_SHA */
+ case 0xC010: /* TLS_ECDHE_RSA_WITH_NULL_SHA */
+ case 0x002C: /* TLS_PSK_WITH_NULL_SHA */
+ case 0x002D: /* TLS_DHE_PSK_WITH_NULL_SHA */
+ case 0x002E: /* TLS_RSA_PSK_WITH_NULL_SHA */
+ case 0x00B0: /* TLS_PSK_WITH_NULL_SHA256 */
+ case 0x00B1: /* TLS_PSK_WITH_NULL_SHA384 */
+ case 0x00B4: /* TLS_DHE_PSK_WITH_NULL_SHA256 */
+ case 0x00B5: /* TLS_DHE_PSK_WITH_NULL_SHA384 */
+ case 0x00B8: /* TLS_RSA_PSK_WITH_NULL_SHA256 */
+ case 0x00B9: /* TLS_RSA_PSK_WITH_NULL_SHA384 */
+ /* Disable anonymous ciphersuites: */
+ case SSL_DH_anon_EXPORT_WITH_RC4_40_MD5:
+ case SSL_DH_anon_WITH_RC4_128_MD5:
+ case SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA:
+ case SSL_DH_anon_WITH_DES_CBC_SHA:
+ case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA:
+ case TLS_DH_anon_WITH_AES_128_CBC_SHA:
+ case TLS_DH_anon_WITH_AES_256_CBC_SHA:
+ case 0xC015: /* TLS_ECDH_anon_WITH_NULL_SHA */
+ case 0xC016: /* TLS_ECDH_anon_WITH_RC4_128_SHA */
+ case 0xC017: /* TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA */
+ case 0xC018: /* TLS_ECDH_anon_WITH_AES_128_CBC_SHA */
+ case 0xC019: /* TLS_ECDH_anon_WITH_AES_256_CBC_SHA */
+ case 0x006C: /* TLS_DH_anon_WITH_AES_128_CBC_SHA256 */
+ case 0x006D: /* TLS_DH_anon_WITH_AES_256_CBC_SHA256 */
+ case 0x00A6: /* TLS_DH_anon_WITH_AES_128_GCM_SHA256 */
+ case 0x00A7: /* TLS_DH_anon_WITH_AES_256_GCM_SHA384 */
+ /* Disable weak key ciphersuites: */
+ case SSL_RSA_EXPORT_WITH_RC4_40_MD5:
+ case SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5:
+ case SSL_RSA_EXPORT_WITH_DES40_CBC_SHA:
+ case SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA:
+ case SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA:
+ case SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA:
+ case SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA:
+ case SSL_RSA_WITH_DES_CBC_SHA:
+ case SSL_DH_DSS_WITH_DES_CBC_SHA:
+ case SSL_DH_RSA_WITH_DES_CBC_SHA:
+ case SSL_DHE_DSS_WITH_DES_CBC_SHA:
+ case SSL_DHE_RSA_WITH_DES_CBC_SHA:
+ /* Disable IDEA: */
+ case SSL_RSA_WITH_IDEA_CBC_SHA:
+ case SSL_RSA_WITH_IDEA_CBC_MD5:
+ /* Disable RC4: */
+ case SSL_RSA_WITH_RC4_128_MD5:
+ case SSL_RSA_WITH_RC4_128_SHA:
+ case 0xC002: /* TLS_ECDH_ECDSA_WITH_RC4_128_SHA */
+ case 0xC007: /* TLS_ECDHE_ECDSA_WITH_RC4_128_SHA*/
+ case 0xC00C: /* TLS_ECDH_RSA_WITH_RC4_128_SHA */
+ case 0xC011: /* TLS_ECDHE_RSA_WITH_RC4_128_SHA */
+ case 0x008A: /* TLS_PSK_WITH_RC4_128_SHA */
+ case 0x008E: /* TLS_DHE_PSK_WITH_RC4_128_SHA */
+ case 0x0092: /* TLS_RSA_PSK_WITH_RC4_128_SHA */
+ break;
+ default: /* enable everything else */
+ allowed_ciphers[allowed_ciphers_count++] = all_ciphers[i];
+ break;
+ }
+ }
+ err = SSLSetEnabledCiphers(BACKEND->ssl_ctx, allowed_ciphers,
+ allowed_ciphers_count);
Curl_safefree(all_ciphers);
Curl_safefree(allowed_ciphers);
+ if(err != noErr) {
+ failf(data, "SSL: SSLSetEnabledCiphers() failed: OSStatus %d", err);
+ return CURLE_SSL_CIPHER;
+ }
#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
/* We want to enable 1/n-1 when using a CBC cipher unless the user
@@ -2039,7 +2055,7 @@ static int read_cert(const char *file, unsigned char **out, size_t *outlen)
if(len + n >= cap) {
cap *= 2;
- data = realloc(data, cap);
+ data = Curl_saferealloc(data, cap);
if(!data) {
close(fd);
return -1;
@@ -2057,35 +2073,6 @@ static int read_cert(const char *file, unsigned char **out, size_t *outlen)
return 0;
}
-static int sslerr_to_curlerr(struct Curl_easy *data, int err)
-{
- switch(err) {
- case errSSLXCertChainInvalid:
- failf(data, "SSL certificate problem: Invalid certificate chain");
- return CURLE_SSL_CACERT;
- case errSSLUnknownRootCert:
- failf(data, "SSL certificate problem: Untrusted root certificate");
- return CURLE_SSL_CACERT;
- case errSSLNoRootCert:
- failf(data, "SSL certificate problem: No root certificate");
- return CURLE_SSL_CACERT;
- case errSSLCertExpired:
- failf(data, "SSL certificate problem: Certificate chain had an "
- "expired certificate");
- return CURLE_SSL_CACERT;
- case errSSLBadCert:
- failf(data, "SSL certificate problem: Couldn't understand the server "
- "certificate format");
- return CURLE_SSL_CONNECT_ERROR;
- case errSSLHostNameMismatch:
- failf(data, "SSL certificate peer hostname mismatch");
- return CURLE_PEER_FAILED_VERIFICATION;
- default:
- failf(data, "SSL unexpected certificate error %d", err);
- return CURLE_SSL_CACERT;
- }
-}
-
static int append_cert_to_array(struct Curl_easy *data,
unsigned char *buf, size_t buflen,
CFMutableArrayRef array)
@@ -2103,13 +2090,20 @@ static int append_cert_to_array(struct Curl_easy *data,
CFRelease(certdata);
if(!cacert) {
failf(data, "SSL: failed to create SecCertificate from CA certificate");
- return CURLE_SSL_CACERT;
+ return CURLE_SSL_CACERT_BADFILE;
}
/* Check if cacert is valid. */
result = CopyCertSubject(data, cacert, &certp);
- if(result)
- return result;
+ switch(result) {
+ case CURLE_OK:
+ break;
+ case CURLE_PEER_FAILED_VERIFICATION:
+ return CURLE_SSL_CACERT_BADFILE;
+ case CURLE_OUT_OF_MEMORY:
+ default:
+ return result;
+ }
free(certp);
CFArrayAppendValue(array, cacert);
@@ -2128,7 +2122,7 @@ static int verify_cert(const char *cafile, struct Curl_easy *data,
if(read_cert(cafile, &certbuf, &buflen) < 0) {
failf(data, "SSL: failed to read or invalid CA certificate");
- return CURLE_SSL_CACERT;
+ return CURLE_SSL_CACERT_BADFILE;
}
/*
@@ -2161,7 +2155,7 @@ static int verify_cert(const char *cafile, struct Curl_easy *data,
CFRelease(array);
failf(data, "SSL: invalid CA certificate #%d (offset %d) in bundle",
n, offset);
- return CURLE_SSL_CACERT;
+ return CURLE_SSL_CACERT_BADFILE;
}
offset += res;
@@ -2195,22 +2189,27 @@ static int verify_cert(const char *cafile, struct Curl_easy *data,
if(trust == NULL) {
failf(data, "SSL: error getting certificate chain");
CFRelease(array);
- return CURLE_OUT_OF_MEMORY;
+ return CURLE_PEER_FAILED_VERIFICATION;
}
else if(ret != noErr) {
CFRelease(array);
- return sslerr_to_curlerr(data, ret);
+ failf(data, "SSLCopyPeerTrust() returned error %d", ret);
+ return CURLE_PEER_FAILED_VERIFICATION;
}
ret = SecTrustSetAnchorCertificates(trust, array);
if(ret != noErr) {
+ CFRelease(array);
CFRelease(trust);
- return sslerr_to_curlerr(data, ret);
+ failf(data, "SecTrustSetAnchorCertificates() returned error %d", ret);
+ return CURLE_PEER_FAILED_VERIFICATION;
}
ret = SecTrustSetAnchorCertificatesOnly(trust, true);
if(ret != noErr) {
+ CFRelease(array);
CFRelease(trust);
- return sslerr_to_curlerr(data, ret);
+ failf(data, "SecTrustSetAnchorCertificatesOnly() returned error %d", ret);
+ return CURLE_PEER_FAILED_VERIFICATION;
}
SecTrustResultType trust_eval = 0;
@@ -2218,7 +2217,8 @@ static int verify_cert(const char *cafile, struct Curl_easy *data,
CFRelease(array);
CFRelease(trust);
if(ret != noErr) {
- return sslerr_to_curlerr(data, ret);
+ failf(data, "SecTrustEvaluate() returned error %d", ret);
+ return CURLE_PEER_FAILED_VERIFICATION;
}
switch(trust_eval) {
@@ -2379,6 +2379,53 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex)
/* the documentation says we need to call SSLHandshake() again */
return darwinssl_connect_step2(conn, sockindex);
+ /* Problem with encrypt / decrypt */
+ case errSSLPeerDecodeError:
+ failf(data, "Decode failed");
+ break;
+ case errSSLDecryptionFail:
+ case errSSLPeerDecryptionFail:
+ failf(data, "Decryption failed");
+ break;
+ case errSSLPeerDecryptError:
+ failf(data, "A decryption error occurred");
+ break;
+ case errSSLBadCipherSuite:
+ failf(data, "A bad SSL cipher suite was encountered");
+ break;
+ case errSSLCrypto:
+ failf(data, "An underlying cryptographic error was encountered");
+ break;
+#if CURL_BUILD_MAC_10_11 || CURL_BUILD_IOS_9
+ case errSSLWeakPeerEphemeralDHKey:
+ failf(data, "Indicates a weak ephemeral Diffie-Hellman key");
+ break;
+#endif
+
+ /* Problem with the message record validation */
+ case errSSLBadRecordMac:
+ case errSSLPeerBadRecordMac:
+ failf(data, "A record with a bad message authentication code (MAC) "
+ "was encountered");
+ break;
+ case errSSLRecordOverflow:
+ case errSSLPeerRecordOverflow:
+ failf(data, "A record overflow occurred");
+ break;
+
+ /* Problem with zlib decompression */
+ case errSSLPeerDecompressFail:
+ failf(data, "Decompression failed");
+ break;
+
+ /* Problem with access */
+ case errSSLPeerAccessDenied:
+ failf(data, "Access was denied");
+ break;
+ case errSSLPeerInsufficientSecurity:
+ failf(data, "There is insufficient security for this operation");
+ break;
+
/* These are all certificate problems with the server: */
case errSSLXCertChainInvalid:
failf(data, "SSL certificate problem: Invalid certificate chain");
@@ -2389,28 +2436,44 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex)
case errSSLNoRootCert:
failf(data, "SSL certificate problem: No root certificate");
return CURLE_SSL_CACERT;
+ case errSSLCertNotYetValid:
+ failf(data, "SSL certificate problem: The certificate chain had a "
+ "certificate that is not yet valid");
+ return CURLE_SSL_CACERT;
case errSSLCertExpired:
+ case errSSLPeerCertExpired:
failf(data, "SSL certificate problem: Certificate chain had an "
"expired certificate");
return CURLE_SSL_CACERT;
case errSSLBadCert:
+ case errSSLPeerBadCert:
failf(data, "SSL certificate problem: Couldn't understand the server "
"certificate format");
- return CURLE_SSL_CONNECT_ERROR;
+ return CURLE_SSL_CACERT;
+ case errSSLPeerUnsupportedCert:
+ failf(data, "SSL certificate problem: An unsupported certificate "
+ "format was encountered");
+ return CURLE_SSL_CACERT;
+ case errSSLPeerCertRevoked:
+ failf(data, "SSL certificate problem: The certificate was revoked");
+ return CURLE_SSL_CACERT;
+ case errSSLPeerCertUnknown:
+ failf(data, "SSL certificate problem: The certificate is unknown");
+ return CURLE_SSL_CACERT;
/* These are all certificate problems with the client: */
case errSecAuthFailed:
failf(data, "SSL authentication failed");
- return CURLE_SSL_CONNECT_ERROR;
+ break;
case errSSLPeerHandshakeFail:
failf(data, "SSL peer handshake failed, the server most likely "
"requires a client certificate to connect");
- return CURLE_SSL_CONNECT_ERROR;
+ break;
case errSSLPeerUnknownCA:
failf(data, "SSL server rejected the client certificate due to "
"the certificate being signed by an unknown certificate "
"authority");
- return CURLE_SSL_CONNECT_ERROR;
+ break;
/* This error is raised if the server's cert didn't match the server's
host name: */
@@ -2419,30 +2482,98 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex)
"certificate did not match \"%s\"\n", conn->host.dispname);
return CURLE_PEER_FAILED_VERIFICATION;
+ /* Problem with SSL / TLS negotiation */
+ case errSSLNegotiation:
+ failf(data, "Could not negotiate an SSL cipher suite with the server");
+ break;
+ case errSSLBadConfiguration:
+ failf(data, "A configuration error occurred");
+ break;
+ case errSSLProtocol:
+ failf(data, "SSL protocol error");
+ break;
+ case errSSLPeerProtocolVersion:
+ failf(data, "A bad protocol version was encountered");
+ break;
+ case errSSLPeerNoRenegotiation:
+ failf(data, "No renegotiation is allowed");
+ break;
+
/* Generic handshake errors: */
case errSSLConnectionRefused:
failf(data, "Server dropped the connection during the SSL handshake");
- return CURLE_SSL_CONNECT_ERROR;
+ break;
case errSSLClosedAbort:
failf(data, "Server aborted the SSL handshake");
- return CURLE_SSL_CONNECT_ERROR;
- case errSSLNegotiation:
- failf(data, "Could not negotiate an SSL cipher suite with the server");
- return CURLE_SSL_CONNECT_ERROR;
+ break;
+ case errSSLClosedGraceful:
+ failf(data, "The connection closed gracefully");
+ break;
+ case errSSLClosedNoNotify:
+ failf(data, "The server closed the session with no notification");
+ break;
/* Sometimes paramErr happens with buggy ciphers: */
- case paramErr: case errSSLInternal:
+ case paramErr:
+ case errSSLInternal:
+ case errSSLPeerInternalError:
failf(data, "Internal SSL engine error encountered during the "
"SSL handshake");
- return CURLE_SSL_CONNECT_ERROR;
+ break;
case errSSLFatalAlert:
failf(data, "Fatal SSL engine error encountered during the SSL "
"handshake");
- return CURLE_SSL_CONNECT_ERROR;
+ break;
+ /* Unclassified error */
+ case errSSLBufferOverflow:
+ failf(data, "An insufficient buffer was provided");
+ break;
+ case errSSLIllegalParam:
+ failf(data, "An illegal parameter was encountered");
+ break;
+ case errSSLModuleAttach:
+ failf(data, "Module attach failure");
+ break;
+ case errSSLSessionNotFound:
+ failf(data, "An attempt to restore an unknown session failed");
+ break;
+ case errSSLPeerExportRestriction:
+ failf(data, "An export restriction occurred");
+ break;
+ case errSSLPeerUserCancelled:
+ failf(data, "The user canceled the operation");
+ break;
+ case errSSLPeerUnexpectedMsg:
+ failf(data, "Peer rejected unexpected message");
+ break;
+#if CURL_BUILD_MAC_10_11 || CURL_BUILD_IOS_9
+ /* Treaing non-fatal error as fatal like before */
+ case errSSLClientHelloReceived:
+ failf(data, "A non-fatal result for providing a server name "
+ "indication");
+ break;
+#endif
+
+ /* Error codes defined in the enum but should never be returned.
+ We list them here just in case. */
+#if CURL_BUILD_MAC_10_6
+ /* Only returned when kSSLSessionOptionBreakOnCertRequested is set */
+ case errSSLClientCertRequested:
+ failf(data, "The server has requested a client certificate");
+ break;
+#endif
+#if CURL_BUILD_MAC_10_9
+ /* Alias for errSSLLast, end of error range */
+ case errSSLUnexpectedRecord:
+ failf(data, "Unexpected (skipped) record in DTLS");
+ break;
+#endif
default:
+ /* May also return codes listed in Security Framework Result Codes */
failf(data, "Unknown SSL protocol error in connection to %s:%d",
hostname, err);
- return CURLE_SSL_CONNECT_ERROR;
+ break;
}
+ return CURLE_SSL_CONNECT_ERROR;
}
else {
/* we have been connected fine, we're not waiting for anything else. */
diff --git a/lib/vtls/gskit.c b/lib/vtls/gskit.c
index a0b49601..8d1b3d6a 100644
--- a/lib/vtls/gskit.c
+++ b/lib/vtls/gskit.c
@@ -766,8 +766,6 @@ set_ssl_version_min_max(unsigned int *protoflags, struct connectdata *conn)
long i = ssl_version;
switch(ssl_version_max) {
case CURL_SSLVERSION_MAX_NONE:
- ssl_version_max = ssl_version;
- break;
case CURL_SSLVERSION_MAX_DEFAULT:
ssl_version_max = CURL_SSLVERSION_TLSv1_2;
break;
@@ -1316,8 +1314,7 @@ static int Curl_gskit_shutdown(struct connectdata *conn, int sockindex)
static size_t Curl_gskit_version(char *buffer, size_t size)
{
- strncpy(buffer, "GSKit", size);
- return strlen(buffer);
+ return snprintf(buffer, size, "GSKit");
}
diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c
index 207b0fd1..37662a74 100644
--- a/lib/vtls/gtls.c
+++ b/lib/vtls/gtls.c
@@ -94,6 +94,10 @@ static bool gtls_inited = FALSE;
# endif
#endif
+#if (GNUTLS_VERSION_NUMBER >= 0x030603)
+#define HAS_TLS13
+#endif
+
#ifdef HAS_OCSP
# include <gnutls/ocsp.h>
#endif
@@ -390,9 +394,10 @@ set_ssl_version_min_max(int *list, size_t list_size, struct connectdata *conn)
switch(ssl_version_max) {
case CURL_SSLVERSION_MAX_NONE:
- ssl_version_max = ssl_version << 16;
- break;
case CURL_SSLVERSION_MAX_DEFAULT:
+#ifdef HAS_TLS13
+ ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_3;
+#endif
ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
break;
}
@@ -410,8 +415,13 @@ set_ssl_version_min_max(int *list, size_t list_size, struct connectdata *conn)
protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_2;
break;
case CURL_SSLVERSION_TLSv1_3:
+#ifdef HAS_TLS13
+ protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_3;
+ break;
+#else
failf(data, "GnuTLS: TLS 1.3 is not yet supported");
return CURLE_SSL_CONNECT_ERROR;
+#endif
}
}
return CURLE_OK;
@@ -429,13 +439,9 @@ set_ssl_version_min_max(const char **prioritylist, struct connectdata *conn)
struct Curl_easy *data = conn->data;
long ssl_version = SSL_CONN_CONFIG(version);
long ssl_version_max = SSL_CONN_CONFIG(version_max);
- if(ssl_version == CURL_SSLVERSION_TLSv1_3 ||
- ssl_version_max == CURL_SSLVERSION_MAX_TLSv1_3) {
- failf(data, "GnuTLS: TLS 1.3 is not yet supported");
- return CURLE_SSL_CONNECT_ERROR;
- }
+
if(ssl_version_max == CURL_SSLVERSION_MAX_NONE) {
- ssl_version_max = ssl_version << 16;
+ ssl_version_max = CURL_SSLVERSION_MAX_DEFAULT;
}
switch(ssl_version | ssl_version_max) {
case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_0:
@@ -447,7 +453,6 @@ set_ssl_version_min_max(const char **prioritylist, struct connectdata *conn)
"+VERS-TLS1.0:+VERS-TLS1.1:" GNUTLS_SRP;
return CURLE_OK;
case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_2:
- case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_DEFAULT:
*prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
"+VERS-TLS1.0:+VERS-TLS1.1:+VERS-TLS1.2:" GNUTLS_SRP;
return CURLE_OK;
@@ -456,15 +461,54 @@ set_ssl_version_min_max(const char **prioritylist, struct connectdata *conn)
"+VERS-TLS1.1:" GNUTLS_SRP;
return CURLE_OK;
case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_2:
- case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_DEFAULT:
*prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
"+VERS-TLS1.1:+VERS-TLS1.2:" GNUTLS_SRP;
return CURLE_OK;
case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_TLSv1_2:
- case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT:
*prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
"+VERS-TLS1.2:" GNUTLS_SRP;
return CURLE_OK;
+ case CURL_SSLVERSION_TLSv1_3 | CURL_SSLVERSION_MAX_TLSv1_3:
+#ifdef HAS_TLS13
+ *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
+ "+VERS-TLS1.3:" GNUTLS_SRP;
+ return CURLE_OK;
+#else
+ failf(data, "GnuTLS: TLS 1.3 is not yet supported");
+ return CURLE_SSL_CONNECT_ERROR;
+#endif
+ case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_DEFAULT:
+ *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
+ "+VERS-TLS1.0:+VERS-TLS1.1:+VERS-TLS1.2:"
+#ifdef HAS_TLS13
+ "+VERS-TLS1.3:"
+#endif
+ GNUTLS_SRP;
+ return CURLE_OK;
+ case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_DEFAULT:
+ *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
+ "+VERS-TLS1.1:+VERS-TLS1.2:"
+#ifdef HAS_TLS13
+ "+VERS-TLS1.3:"
+#endif
+ GNUTLS_SRP;
+ return CURLE_OK;
+ case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT:
+ *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
+ "+VERS-TLS1.2:"
+#ifdef HAS_TLS13
+ "+VERS-TLS1.3:"
+#endif
+ GNUTLS_SRP;
+ return CURLE_OK;
+ case CURL_SSLVERSION_TLSv1_3 | CURL_SSLVERSION_MAX_DEFAULT:
+ *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
+ "+VERS-TLS1.2:"
+#ifdef HAS_TLS13
+ "+VERS-TLS1.3:"
+#endif
+ GNUTLS_SRP;
+ return CURLE_OK;
}
failf(data, "GnuTLS: cannot set ssl protocol");
@@ -677,6 +721,9 @@ gtls_connect_step1(struct connectdata *conn,
protocol_priority[0] = GNUTLS_TLS1_0;
protocol_priority[1] = GNUTLS_TLS1_1;
protocol_priority[2] = GNUTLS_TLS1_2;
+#ifdef HAS_TLS13
+ protocol_priority[3] = GNUTLS_TLS1_3;
+#endif
break;
case CURL_SSLVERSION_TLSv1_0:
case CURL_SSLVERSION_TLSv1_1:
@@ -709,11 +756,14 @@ gtls_connect_step1(struct connectdata *conn,
switch(SSL_CONN_CONFIG(version)) {
case CURL_SSLVERSION_SSLv3:
prioritylist = GNUTLS_CIPHERS ":-VERS-TLS-ALL:+VERS-SSL3.0";
- sni = false;
break;
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
- prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:" GNUTLS_SRP;
+ prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:"
+#ifdef HAS_TLS13
+ "+VERS-TLS1.3:"
+#endif
+ GNUTLS_SRP;
break;
case CURL_SSLVERSION_TLSv1_0:
case CURL_SSLVERSION_TLSv1_1:
@@ -1102,8 +1152,8 @@ gtls_connect_step3(struct connectdata *conn,
return CURLE_SSL_INVALIDCERTSTATUS;
}
- rc = gnutls_ocsp_resp_get_single(ocsp_resp, 0, NULL, NULL, NULL, NULL,
- &status, NULL, NULL, NULL, &reason);
+ (void)gnutls_ocsp_resp_get_single(ocsp_resp, 0, NULL, NULL, NULL, NULL,
+ &status, NULL, NULL, NULL, &reason);
switch(status) {
case GNUTLS_OCSP_CERT_GOOD:
@@ -1589,7 +1639,7 @@ static int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
ssize_t result;
int retval = 0;
struct Curl_easy *data = conn->data;
- int done = 0;
+ bool done = FALSE;
char buf[120];
/* This has only been tested on the proftpd server, and the mod_tls code
@@ -1613,7 +1663,7 @@ static int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
case 0:
/* This is the expected response. There was no data but only
the close notify alert */
- done = 1;
+ done = TRUE;
break;
case GNUTLS_E_AGAIN:
case GNUTLS_E_INTERRUPTED:
@@ -1621,21 +1671,20 @@ static int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
break;
default:
retval = -1;
- done = 1;
+ done = TRUE;
break;
}
}
else if(0 == what) {
/* timeout */
failf(data, "SSL shutdown timeout");
- done = 1;
- break;
+ done = TRUE;
}
else {
/* anything that gets here is fatally bad */
failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
retval = -1;
- done = 1;
+ done = TRUE;
}
}
gnutls_deinit(BACKEND->session);
diff --git a/lib/vtls/mbedtls.c b/lib/vtls/mbedtls.c
index d7759dc8..c5ed8872 100644
--- a/lib/vtls/mbedtls.c
+++ b/lib/vtls/mbedtls.c
@@ -205,14 +205,11 @@ set_ssl_version_min_max(struct connectdata *conn, int sockindex)
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
ssl_version = CURL_SSLVERSION_TLSv1_0;
- ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
break;
}
switch(ssl_version_max) {
case CURL_SSLVERSION_MAX_NONE:
- ssl_version_max = ssl_version << 16;
- break;
case CURL_SSLVERSION_MAX_DEFAULT:
ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
break;
diff --git a/lib/vtls/mesalink.c b/lib/vtls/mesalink.c
new file mode 100644
index 00000000..6a2b67e6
--- /dev/null
+++ b/lib/vtls/mesalink.c
@@ -0,0 +1,627 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2017-2018, Yiming Jing, <jingyiming@baidu.com>
+ * 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.
+ *
+ ***************************************************************************/
+
+/*
+ * Source file for all MesaLink-specific code for the TLS/SSL layer. No code
+ * but vtls.c should ever call or use these functions.
+ *
+ */
+
+/*
+ * Based upon the CyaSSL implementation in cyassl.c and cyassl.h:
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * Thanks for code and inspiration!
+ */
+
+#include "curl_setup.h"
+
+#ifdef USE_MESALINK
+
+#include <mesalink/options.h>
+#include <mesalink/version.h>
+
+#include "urldata.h"
+#include "sendf.h"
+#include "inet_pton.h"
+#include "vtls.h"
+#include "parsedate.h"
+#include "connect.h" /* for the connect timeout */
+#include "select.h"
+#include "strcase.h"
+#include "x509asn1.h"
+#include "curl_printf.h"
+
+#include "mesalink.h"
+#include <mesalink/openssl/ssl.h>
+#include <mesalink/openssl/err.h>
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#define MESALINK_MAX_ERROR_SZ 80
+
+struct ssl_backend_data
+{
+ SSL_CTX *ctx;
+ SSL *handle;
+};
+
+#define BACKEND connssl->backend
+
+static Curl_recv mesalink_recv;
+static Curl_send mesalink_send;
+
+/*
+ * This function loads all the client/CA certificates and CRLs. Setup the TLS
+ * layer and do all necessary magic.
+ */
+static CURLcode
+mesalink_connect_step1(struct connectdata *conn, int sockindex)
+{
+ char *ciphers;
+ struct Curl_easy *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
+ const char *const ssl_cafile = SSL_CONN_CONFIG(CAfile);
+ const char *const ssl_capath = SSL_CONN_CONFIG(CApath);
+ struct in_addr addr4;
+#ifdef ENABLE_IPV6
+ struct in6_addr addr6;
+#endif
+ const char *const hostname =
+ SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name;
+ size_t hostname_len = strlen(hostname);
+
+ SSL_METHOD *req_method = NULL;
+ curl_socket_t sockfd = conn->sock[sockindex];
+
+ if(connssl->state == ssl_connection_complete)
+ return CURLE_OK;
+
+ if(SSL_CONN_CONFIG(version_max) != CURL_SSLVERSION_MAX_NONE) {
+ failf(data, "MesaLink does not support to set maximum SSL/TLS version");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ switch(SSL_CONN_CONFIG(version)) {
+ case CURL_SSLVERSION_SSLv3:
+ case CURL_SSLVERSION_TLSv1:
+ case CURL_SSLVERSION_TLSv1_0:
+ case CURL_SSLVERSION_TLSv1_1:
+ failf(data, "MesaLink does not support SSL 3.0, TLS 1.0, or TLS 1.1");
+ return CURLE_NOT_BUILT_IN;
+ case CURL_SSLVERSION_DEFAULT:
+ case CURL_SSLVERSION_TLSv1_2:
+ req_method = TLSv1_2_client_method();
+ break;
+ case CURL_SSLVERSION_TLSv1_3:
+ req_method = TLSv1_3_client_method();
+ break;
+ case CURL_SSLVERSION_SSLv2:
+ failf(data, "MesaLink does not support SSLv2");
+ return CURLE_SSL_CONNECT_ERROR;
+ default:
+ failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ if(!req_method) {
+ failf(data, "SSL: couldn't create a method!");
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ if(BACKEND->ctx)
+ SSL_CTX_free(BACKEND->ctx);
+ BACKEND->ctx = SSL_CTX_new(req_method);
+
+ if(!BACKEND->ctx) {
+ failf(data, "SSL: couldn't create a context!");
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ SSL_CTX_set_verify(
+ BACKEND->ctx, verifypeer ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL);
+
+ if(ssl_cafile || ssl_capath) {
+ if(!SSL_CTX_load_verify_locations(BACKEND->ctx, ssl_cafile, ssl_capath)) {
+ if(verifypeer) {
+ failf(data,
+ "error setting certificate verify locations:\n"
+ " CAfile: %s\n CApath: %s",
+ ssl_cafile ? ssl_cafile : "none",
+ ssl_capath ? ssl_capath : "none");
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+ infof(data,
+ "error setting certificate verify locations,"
+ " continuing anyway:\n");
+ }
+ else {
+ infof(data, "successfully set certificate verify locations:\n");
+ }
+ infof(data,
+ " CAfile: %s\n"
+ " CApath: %s\n",
+ ssl_cafile ? ssl_cafile : "none",
+ ssl_capath ? ssl_capath : "none");
+ }
+
+ ciphers = SSL_CONN_CONFIG(cipher_list);
+ if(ciphers) {
+#ifdef MESALINK_HAVE_CIPHER
+ if(!SSL_CTX_set_cipher_list(BACKEND->ctx, ciphers)) {
+ failf(data, "failed setting cipher list: %s", ciphers);
+ return CURLE_SSL_CIPHER;
+ }
+#endif
+ infof(data, "Cipher selection: %s\n", ciphers);
+ }
+
+ 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;
+ }
+
+ if((hostname_len < USHRT_MAX) &&
+ (0 == Curl_inet_pton(AF_INET, hostname, &addr4))
+#ifdef ENABLE_IPV6
+ && (0 == Curl_inet_pton(AF_INET6, hostname, &addr6))
+#endif
+ ) {
+ /* hostname is not a valid IP address */
+ if(SSL_set_tlsext_host_name(BACKEND->handle, hostname) != SSL_SUCCESS) {
+ failf(data,
+ "WARNING: failed to configure server name indication (SNI) "
+ "TLS extension\n");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+ else {
+#ifdef CURLDEBUG
+ /* Check if the hostname is 127.0.0.1 or [::1];
+ * otherwise reject because MesaLink always wants a valid DNS Name
+ * specified in RFC 5280 Section 7.2 */
+ if(strncmp(hostname, "127.0.0.1", 9) == 0
+#ifdef ENABLE_IPV6
+ || strncmp(hostname, "[::1]", 5) == 0
+#endif
+ ) {
+ SSL_set_tlsext_host_name(BACKEND->handle, "localhost");
+ }
+ else
+#endif
+ {
+ failf(data,
+ "ERROR: MesaLink does not accept an IP address as a hostname\n");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+
+#ifdef MESALINK_HAVE_SESSION
+ if(SSL_SET_OPTION(primary.sessionid)) {
+ void *ssl_sessionid = NULL;
+
+ 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(BACKEND->handle, ssl_sessionid)) {
+ Curl_ssl_sessionid_unlock(conn);
+ failf(
+ data,
+ "SSL: SSL_set_session failed: %s",
+ ERR_error_string(SSL_get_error(BACKEND->handle, 0), error_buffer));
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ /* Informational message */
+ infof(data, "SSL re-using session ID\n");
+ }
+ Curl_ssl_sessionid_unlock(conn);
+ }
+#endif /* MESALINK_HAVE_SESSION */
+
+ if(SSL_set_fd(BACKEND->handle, (int)sockfd) != SSL_SUCCESS) {
+ failf(data, "SSL: SSL_set_fd failed");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ connssl->connecting_state = ssl_connect_2;
+ return CURLE_OK;
+}
+
+static CURLcode
+mesalink_connect_step2(struct connectdata *conn, int sockindex)
+{
+ int ret = -1;
+ struct Curl_easy *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+
+ conn->recv[sockindex] = mesalink_recv;
+ conn->send[sockindex] = mesalink_send;
+
+ ret = SSL_connect(BACKEND->handle);
+ if(ret != SSL_SUCCESS) {
+ char error_buffer[MESALINK_MAX_ERROR_SZ];
+ int detail = SSL_get_error(BACKEND->handle, ret);
+
+ if(SSL_ERROR_WANT_CONNECT == detail) {
+ connssl->connecting_state = ssl_connect_2_reading;
+ return CURLE_OK;
+ }
+ else {
+ failf(data,
+ "SSL_connect failed with error %d: %s",
+ detail,
+ ERR_error_string_n(detail, error_buffer, sizeof(error_buffer)));
+ ERR_print_errors_fp(stderr);
+ if(detail && SSL_CONN_CONFIG(verifypeer)) {
+ detail &= ~0xFF;
+ if(detail == TLS_ERROR_WEBPKI_ERRORS) {
+ failf(data, "Cert verify failed");
+ return CURLE_PEER_FAILED_VERIFICATION;
+ }
+ }
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+
+ connssl->connecting_state = ssl_connect_3;
+ infof(data,
+ "SSL connection using %s / %s\n",
+ SSL_get_version(BACKEND->handle),
+ SSL_get_cipher_name(BACKEND->handle));
+
+ return CURLE_OK;
+}
+
+static CURLcode
+mesalink_connect_step3(struct connectdata *conn, int sockindex)
+{
+ CURLcode result = CURLE_OK;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+
+ DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
+
+#ifdef MESALINK_HAVE_SESSION
+ if(SSL_SET_OPTION(primary.sessionid)) {
+ bool incache;
+ SSL_SESSION *our_ssl_sessionid;
+ void *old_ssl_sessionid = NULL;
+
+ our_ssl_sessionid = SSL_get_session(BACKEND->handle);
+
+ Curl_ssl_sessionid_lock(conn);
+ incache =
+ !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, sockindex));
+ if(incache) {
+ if(old_ssl_sessionid != our_ssl_sessionid) {
+ infof(data, "old SSL session ID is stale, removing\n");
+ Curl_ssl_delsessionid(conn, old_ssl_sessionid);
+ incache = FALSE;
+ }
+ }
+
+ if(!incache) {
+ result = Curl_ssl_addsessionid(
+ conn, our_ssl_sessionid, 0 /* unknown size */, sockindex);
+ if(result) {
+ Curl_ssl_sessionid_unlock(conn);
+ failf(data, "failed to store ssl session");
+ return result;
+ }
+ }
+ Curl_ssl_sessionid_unlock(conn);
+ }
+#endif /* MESALINK_HAVE_SESSION */
+
+ connssl->connecting_state = ssl_connect_done;
+
+ return result;
+}
+
+static ssize_t
+mesalink_send(struct connectdata *conn, int sockindex, const void *mem,
+ size_t len, CURLcode *curlcode)
+{
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ char error_buffer[MESALINK_MAX_ERROR_SZ];
+ int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
+ int rc = SSL_write(BACKEND->handle, mem, memlen);
+
+ if(rc < 0) {
+ int err = SSL_get_error(BACKEND->handle, rc);
+ switch(err) {
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ /* there's data pending, re-invoke SSL_write() */
+ *curlcode = CURLE_AGAIN;
+ return -1;
+ default:
+ failf(conn->data,
+ "SSL write: %s, errno %d",
+ ERR_error_string_n(err, error_buffer, sizeof(error_buffer)),
+ SOCKERRNO);
+ *curlcode = CURLE_SEND_ERROR;
+ return -1;
+ }
+ }
+ return rc;
+}
+
+static void
+Curl_mesalink_close(struct connectdata *conn, int sockindex)
+{
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+
+ if(BACKEND->handle) {
+ (void)SSL_shutdown(BACKEND->handle);
+ SSL_free(BACKEND->handle);
+ BACKEND->handle = NULL;
+ }
+ if(BACKEND->ctx) {
+ SSL_CTX_free(BACKEND->ctx);
+ BACKEND->ctx = NULL;
+ }
+}
+
+static ssize_t
+mesalink_recv(struct connectdata *conn, int num, char *buf, size_t buffersize,
+ CURLcode *curlcode)
+{
+ struct ssl_connect_data *connssl = &conn->ssl[num];
+ char error_buffer[MESALINK_MAX_ERROR_SZ];
+ int buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
+ int nread = SSL_read(BACKEND->handle, buf, buffsize);
+
+ if(nread <= 0) {
+ int err = SSL_get_error(BACKEND->handle, nread);
+
+ switch(err) {
+ case SSL_ERROR_ZERO_RETURN: /* no more data */
+ case IO_ERROR_CONNECTION_ABORTED:
+ break;
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ /* there's data pending, re-invoke SSL_read() */
+ *curlcode = CURLE_AGAIN;
+ return -1;
+ default:
+ failf(conn->data,
+ "SSL read: %s, errno %d",
+ ERR_error_string_n(err, error_buffer, sizeof(error_buffer)),
+ SOCKERRNO);
+ *curlcode = CURLE_RECV_ERROR;
+ return -1;
+ }
+ }
+ return nread;
+}
+
+static size_t
+Curl_mesalink_version(char *buffer, size_t size)
+{
+ return snprintf(buffer, size, "MesaLink/%s", MESALINK_VERSION_STRING);
+}
+
+static int
+Curl_mesalink_init(void)
+{
+ return (SSL_library_init() == SSL_SUCCESS);
+}
+
+/*
+ * This function is called to shut down the SSL layer but keep the
+ * socket open (CCC - Clear Command Channel)
+ */
+static int
+Curl_mesalink_shutdown(struct connectdata *conn, int sockindex)
+{
+ int retval = 0;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+
+ if(BACKEND->handle) {
+ SSL_free(BACKEND->handle);
+ BACKEND->handle = NULL;
+ }
+ return retval;
+}
+
+static CURLcode
+mesalink_connect_common(struct connectdata *conn, int sockindex,
+ bool nonblocking, bool *done)
+{
+ CURLcode result;
+ struct Curl_easy *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ curl_socket_t sockfd = conn->sock[sockindex];
+ time_t timeout_ms;
+ int what;
+
+ /* check if the connection has already been established */
+ if(ssl_connection_complete == connssl->state) {
+ *done = TRUE;
+ return CURLE_OK;
+ }
+
+ if(ssl_connect_1 == connssl->connecting_state) {
+ /* Find out how much more time we're allowed */
+ timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+ if(timeout_ms < 0) {
+ /* no need to continue if time already is up */
+ failf(data, "SSL connection timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ result = mesalink_connect_step1(conn, sockindex);
+ if(result)
+ return result;
+ }
+
+ while(ssl_connect_2 == connssl->connecting_state ||
+ ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state) {
+
+ /* check allowed time left */
+ timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+ if(timeout_ms < 0) {
+ /* no need to continue if time already is up */
+ failf(data, "SSL connection timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ /* if ssl is expecting something, check if it's available. */
+ if(connssl->connecting_state == ssl_connect_2_reading ||
+ connssl->connecting_state == ssl_connect_2_writing) {
+
+ curl_socket_t writefd =
+ ssl_connect_2_writing == connssl->connecting_state ? sockfd
+ : CURL_SOCKET_BAD;
+ curl_socket_t readfd = ssl_connect_2_reading == connssl->connecting_state
+ ? sockfd
+ : CURL_SOCKET_BAD;
+
+ what = Curl_socket_check(
+ readfd, CURL_SOCKET_BAD, writefd, nonblocking ? 0 : timeout_ms);
+ if(what < 0) {
+ /* fatal error */
+ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ else if(0 == what) {
+ if(nonblocking) {
+ *done = FALSE;
+ return CURLE_OK;
+ }
+ else {
+ /* timeout */
+ failf(data, "SSL connection timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+ }
+ /* socket is readable or writable */
+ }
+
+ /* Run transaction, and return to the caller if it failed or if
+ * this connection is part of a multi handle and this loop would
+ * execute again. This permits the owner of a multi handle to
+ * abort a connection attempt before step2 has completed while
+ * ensuring that a client using select() or epoll() will always
+ * have a valid fdset to wait on.
+ */
+ result = mesalink_connect_step2(conn, sockindex);
+
+ if(result ||
+ (nonblocking && (ssl_connect_2 == connssl->connecting_state ||
+ ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state))) {
+ return result;
+ }
+ } /* repeat step2 until all transactions are done. */
+
+ if(ssl_connect_3 == connssl->connecting_state) {
+ result = mesalink_connect_step3(conn, sockindex);
+ if(result)
+ return result;
+ }
+
+ if(ssl_connect_done == connssl->connecting_state) {
+ connssl->state = ssl_connection_complete;
+ conn->recv[sockindex] = mesalink_recv;
+ conn->send[sockindex] = mesalink_send;
+ *done = TRUE;
+ }
+ else
+ *done = FALSE;
+
+ /* Reset our connect state machine */
+ connssl->connecting_state = ssl_connect_1;
+
+ return CURLE_OK;
+}
+
+static CURLcode
+Curl_mesalink_connect_nonblocking(struct connectdata *conn, int sockindex,
+ bool *done)
+{
+ return mesalink_connect_common(conn, sockindex, TRUE, done);
+}
+
+static CURLcode
+Curl_mesalink_connect(struct connectdata *conn, int sockindex)
+{
+ CURLcode result;
+ bool done = FALSE;
+
+ result = mesalink_connect_common(conn, sockindex, FALSE, &done);
+ if(result)
+ return result;
+
+ DEBUGASSERT(done);
+
+ return CURLE_OK;
+}
+
+static void *
+Curl_mesalink_get_internals(struct ssl_connect_data *connssl,
+ CURLINFO info UNUSED_PARAM)
+{
+ (void)info;
+ return BACKEND->handle;
+}
+
+const struct Curl_ssl Curl_ssl_mesalink = {
+ { CURLSSLBACKEND_MESALINK, "MesaLink" }, /* info */
+
+ SSLSUPP_SSL_CTX,
+
+ sizeof(struct ssl_backend_data),
+
+ Curl_mesalink_init, /* init */
+ Curl_none_cleanup, /* cleanup */
+ Curl_mesalink_version, /* version */
+ Curl_none_check_cxn, /* check_cxn */
+ Curl_mesalink_shutdown, /* shutdown */
+ Curl_none_data_pending, /* data_pending */
+ Curl_none_random, /* random */
+ Curl_none_cert_status_request, /* cert_status_request */
+ Curl_mesalink_connect, /* connect */
+ Curl_mesalink_connect_nonblocking, /* connect_nonblocking */
+ Curl_mesalink_get_internals, /* get_internals */
+ Curl_mesalink_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 */
+};
+
+#endif
diff --git a/lib/vtls/mesalink.h b/lib/vtls/mesalink.h
new file mode 100644
index 00000000..54cb94ad
--- /dev/null
+++ b/lib/vtls/mesalink.h
@@ -0,0 +1,32 @@
+#ifndef HEADER_CURL_MESALINK_H
+#define HEADER_CURL_MESALINK_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2017-2018, Yiming Jing, <jingyiming@baidu.com>
+ * 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 USE_MESALINK
+
+extern const struct Curl_ssl Curl_ssl_mesalink;
+
+#endif /* USE_MESALINK */
+#endif /* HEADER_CURL_MESALINK_H */
diff --git a/lib/vtls/nss.c b/lib/vtls/nss.c
index 89f81839..a3d3e58b 100644
--- a/lib/vtls/nss.c
+++ b/lib/vtls/nss.c
@@ -217,10 +217,15 @@ static const cipher_s cipherlist[] = {
#endif
};
+#ifdef WIN32
+static const char *pem_library = "nsspem.dll";
+static const char *trust_library = "nssckbi.dll";
+#else
static const char *pem_library = "libnsspem.so";
-static SECMODModule *pem_module = NULL;
-
static const char *trust_library = "libnssckbi.so";
+#endif
+
+static SECMODModule *pem_module = NULL;
static SECMODModule *trust_module = NULL;
/* NSPR I/O layer we use to detect blocking direction during SSL handshake */
@@ -1522,7 +1527,6 @@ static bool is_nss_error(CURLcode err)
{
switch(err) {
case CURLE_PEER_FAILED_VERIFICATION:
- case CURLE_SSL_CACERT:
case CURLE_SSL_CERTPROBLEM:
case CURLE_SSL_CONNECT_ERROR:
case CURLE_SSL_ISSUER_ERROR:
@@ -1579,8 +1583,9 @@ static CURLcode nss_load_ca_certificates(struct connectdata *conn,
infof(data, "%s %s\n", (result) ? "failed to load" : "loaded",
trust_library);
if(result == CURLE_FAILED_INIT)
- /* make the error non-fatal if we are not going to verify peer */
- result = CURLE_SSL_CACERT_BADFILE;
+ /* If libnssckbi.so is not available (or fails to load), one can still
+ use CA certificates stored in NSS database. Ignore the failure. */
+ result = CURLE_OK;
}
else if(!use_trust_module && trust_module) {
/* libnssckbi.so not needed but already loaded --> unload it! */
@@ -1715,8 +1720,6 @@ static CURLcode nss_init_sslver(SSLVersionRange *sslver,
failf(data, "unsupported min version passed via CURLOPT_SSLVERSION");
return result;
}
- if(max == CURL_SSLVERSION_MAX_NONE)
- sslver->max = sslver->min;
}
switch(max) {
diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c
index a487f553..4c5e8c19 100644
--- a/lib/vtls/openssl.c
+++ b/lib/vtls/openssl.c
@@ -69,7 +69,7 @@
#include <openssl/ocsp.h>
#endif
-#if (OPENSSL_VERSION_NUMBER >= 0x10000000L) && /* 1.0.0 or later */ \
+#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && /* 0.9.8 or later */ \
!defined(OPENSSL_NO_ENGINE)
#define USE_OPENSSL_ENGINE
#include <openssl/engine.h>
@@ -129,16 +129,15 @@
#define X509_get0_notBefore(x) X509_get_notBefore(x)
#define X509_get0_notAfter(x) X509_get_notAfter(x)
#define CONST_EXTS /* nope */
-#ifdef LIBRESSL_VERSION_NUMBER
-static unsigned long OpenSSL_version_num(void)
-{
- return LIBRESSL_VERSION_NUMBER;
-}
-#else
+#ifndef LIBRESSL_VERSION_NUMBER
#define OpenSSL_version_num() SSLeay()
#endif
#endif
+#ifdef LIBRESSL_VERSION_NUMBER
+#define OpenSSL_version_num() LIBRESSL_VERSION_NUMBER
+#endif
+
#if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) && /* 1.0.2 or later */ \
!(defined(LIBRESSL_VERSION_NUMBER) && \
LIBRESSL_VERSION_NUMBER < 0x20700000L)
@@ -178,6 +177,7 @@ static unsigned long OpenSSL_version_num(void)
!defined(LIBRESSL_VERSION_NUMBER) && \
!defined(OPENSSL_IS_BORINGSSL))
#define HAVE_SSL_CTX_SET_CIPHERSUITES
+#define HAVE_SSL_CTX_SET_POST_HANDSHAKE_AUTH
#endif
#if defined(LIBRESSL_VERSION_NUMBER)
@@ -253,7 +253,7 @@ static void ossl_keylog_callback(const SSL *ssl, const char *line)
if(!buf)
return;
}
- strncpy(buf, line, linelen);
+ memcpy(buf, line, linelen);
buf[linelen] = '\n';
buf[linelen + 1] = '\0';
@@ -978,7 +978,7 @@ static int Curl_ossl_init(void)
OPENSSL_load_builtin_modules();
-#ifdef HAVE_ENGINE_LOAD_BUILTIN_ENGINES
+#ifdef USE_OPENSSL_ENGINE
ENGINE_load_builtin_engines();
#endif
@@ -994,9 +994,11 @@ static int Curl_ossl_init(void)
#define CONF_MFLAGS_DEFAULT_SECTION 0x0
#endif
+#ifndef CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG
CONF_modules_load_file(NULL, NULL,
CONF_MFLAGS_DEFAULT_SECTION|
CONF_MFLAGS_IGNORE_MISSING_FILE);
+#endif
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \
!defined(LIBRESSL_VERSION_NUMBER)
@@ -1260,7 +1262,7 @@ static int Curl_ossl_shutdown(struct connectdata *conn, int sockindex)
ssize_t nread;
int buffsize;
int err;
- int done = 0;
+ bool done = FALSE;
/* This has only been tested on the proftpd server, and the mod_tls code
sends a close notify alert without waiting for a close notify alert in
@@ -1288,7 +1290,7 @@ static int Curl_ossl_shutdown(struct connectdata *conn, int sockindex)
case SSL_ERROR_ZERO_RETURN: /* no more data */
/* This is the expected response. There was no data but only
the close notify alert */
- done = 1;
+ done = TRUE;
break;
case SSL_ERROR_WANT_READ:
/* there's data pending, re-invoke SSL_read() */
@@ -1297,7 +1299,7 @@ static int Curl_ossl_shutdown(struct connectdata *conn, int sockindex)
case SSL_ERROR_WANT_WRITE:
/* SSL wants a write. Really odd. Let's bail out. */
infof(data, "SSL_ERROR_WANT_WRITE\n");
- done = 1;
+ done = TRUE;
break;
default:
/* openssl/ssl.h says "look at error stack/return value/errno" */
@@ -1307,20 +1309,20 @@ static int Curl_ossl_shutdown(struct connectdata *conn, int sockindex)
ossl_strerror(sslerror, buf, sizeof(buf)) :
SSL_ERROR_to_str(err)),
SOCKERRNO);
- done = 1;
+ done = TRUE;
break;
}
}
else if(0 == what) {
/* timeout */
failf(data, "SSL shutdown timeout");
- done = 1;
+ done = TRUE;
}
else {
/* anything that gets here is fatally bad */
failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
retval = -1;
- done = 1;
+ done = TRUE;
}
} /* while()-loop for the select() */
@@ -1416,6 +1418,10 @@ static bool subj_alt_hostcheck(struct Curl_easy *data,
}
#else
{
+#ifdef CURL_DISABLE_VERBOSE_STRINGS
+ (void)dispname;
+ (void)data;
+#endif
if(Curl_cert_hostcheck(match_pattern, hostname)) {
infof(data, " subjectAltName: host \"%s\" matched cert's \"%s\"\n",
dispname, match_pattern);
@@ -2080,6 +2086,7 @@ select_next_proto_cb(SSL *ssl,
}
#endif /* HAS_NPN */
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
static const char *
get_ssl_version_txt(SSL *ssl)
{
@@ -2106,6 +2113,7 @@ get_ssl_version_txt(SSL *ssl)
}
return "unknown";
}
+#endif
static CURLcode
set_ssl_version_min_max(long *ctx_options, struct connectdata *conn,
@@ -2171,7 +2179,6 @@ set_ssl_version_min_max(long *ctx_options, struct connectdata *conn,
#endif
break;
case CURL_SSLVERSION_MAX_TLSv1_3:
- case CURL_SSLVERSION_MAX_DEFAULT:
#ifdef TLS1_3_VERSION
break;
#else
@@ -2459,7 +2466,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
char *ciphers13 = SSL_CONN_CONFIG(cipher_list13);
if(ciphers13) {
if(!SSL_CTX_set_ciphersuites(BACKEND->ctx, ciphers13)) {
- failf(data, "failed setting TLS 1.3 cipher suite: %s", ciphers);
+ failf(data, "failed setting TLS 1.3 cipher suite: %s", ciphers13);
return CURLE_SSL_CIPHER;
}
infof(data, "TLS 1.3 cipher selection: %s\n", ciphers13);
@@ -2467,6 +2474,11 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
}
#endif
+#ifdef HAVE_SSL_CTX_SET_POST_HANDSHAKE_AUTH
+ /* OpenSSL 1.1.1 requires clients to opt-in for PHA */
+ SSL_CTX_set_post_handshake_auth(BACKEND->ctx, 1);
+#endif
+
#ifdef USE_TLS_SRP
if(ssl_authtype == CURL_TLSAUTH_SRP) {
char * const ssl_username = SSL_SET_OPTION(username);
@@ -2521,7 +2533,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
}
#ifdef CURL_CA_FALLBACK
else if(verifypeer) {
- /* verfying the peer without any CA certificates won't
+ /* verifying the peer without any CA certificates won't
work so use openssl's built in default as fallback */
SSL_CTX_set_default_verify_paths(BACKEND->ctx);
}
@@ -3187,7 +3199,7 @@ static CURLcode servercert(struct connectdata *conn,
{
CURLcode result = CURLE_OK;
int rc;
- long lerr, len;
+ long lerr;
struct Curl_easy *data = conn->data;
X509 *issuer;
BIO *fp = NULL;
@@ -3210,7 +3222,7 @@ static CURLcode servercert(struct connectdata *conn,
ossl_strerror(ERR_get_error(), error_buffer,
sizeof(error_buffer)) );
BIO_free(mem);
- return 0;
+ return CURLE_OUT_OF_MEMORY;
}
BACKEND->server_cert = SSL_get_peer_certificate(BACKEND->handle);
@@ -3230,15 +3242,20 @@ static CURLcode servercert(struct connectdata *conn,
buffer, sizeof(buffer));
infof(data, " subject: %s\n", rc?"[NONE]":buffer);
- 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);
- (void)BIO_reset(mem);
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+ {
+ long len;
+ 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);
+ (void)BIO_reset(mem);
- 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);
- (void)BIO_reset(mem);
+ 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);
+ (void)BIO_reset(mem);
+ }
+#endif
BIO_free(mem);
@@ -3257,7 +3274,7 @@ static CURLcode servercert(struct connectdata *conn,
if(rc) {
if(strict)
failf(data, "SSL: couldn't get X509-issuer name!");
- result = CURLE_SSL_CONNECT_ERROR;
+ result = CURLE_PEER_FAILED_VERIFICATION;
}
else {
infof(data, " issuer: %s\n", buffer);
diff --git a/lib/vtls/polarssl.c b/lib/vtls/polarssl.c
index 604cb4c8..27af0ccf 100644
--- a/lib/vtls/polarssl.c
+++ b/lib/vtls/polarssl.c
@@ -185,14 +185,11 @@ set_ssl_version_min_max(struct connectdata *conn, int sockindex)
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
ssl_version = CURL_SSLVERSION_TLSv1_0;
- ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
break;
}
switch(ssl_version_max) {
case CURL_SSLVERSION_MAX_NONE:
- ssl_version_max = ssl_version << 16;
- break;
case CURL_SSLVERSION_MAX_DEFAULT:
ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
break;
diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c
index 8f6c301d..e4426924 100644
--- a/lib/vtls/schannel.c
+++ b/lib/vtls/schannel.c
@@ -180,8 +180,6 @@ set_ssl_version_min_max(SCHANNEL_CRED *schannel_cred, struct connectdata *conn)
switch(ssl_version_max) {
case CURL_SSLVERSION_MAX_NONE:
- ssl_version_max = ssl_version << 16;
- break;
case CURL_SSLVERSION_MAX_DEFAULT:
ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
break;
@@ -363,7 +361,7 @@ get_cert_location(TCHAR *path, DWORD *store_name, TCHAR **store_path,
sep = _tcschr(path, TEXT('\\'));
if(sep == NULL)
- return CURLE_SSL_CONNECT_ERROR;
+ return CURLE_SSL_CERTPROBLEM;
store_name_len = sep - path;
@@ -387,19 +385,19 @@ get_cert_location(TCHAR *path, DWORD *store_name, TCHAR **store_path,
store_name_len) == 0)
*store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE;
else
- return CURLE_SSL_CONNECT_ERROR;
+ return CURLE_SSL_CERTPROBLEM;
*store_path = sep + 1;
sep = _tcschr(*store_path, TEXT('\\'));
if(sep == NULL)
- return CURLE_SSL_CONNECT_ERROR;
+ return CURLE_SSL_CERTPROBLEM;
*sep = 0;
*thumbprint = sep + 1;
if(_tcslen(*thumbprint) != CERT_THUMBPRINT_STR_LEN)
- return CURLE_SSL_CONNECT_ERROR;
+ return CURLE_SSL_CERTPROBLEM;
return CURLE_OK;
}
@@ -612,7 +610,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
"last error is %x",
cert_store_name, cert_store_path, GetLastError());
Curl_unicodefree(cert_path);
- return CURLE_SSL_CONNECT_ERROR;
+ return CURLE_SSL_CERTPROBLEM;
}
cert_thumbprint.pbData = cert_thumbprint_data;
@@ -623,7 +621,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
cert_thumbprint_data, &cert_thumbprint.cbData,
NULL, NULL)) {
Curl_unicodefree(cert_path);
- return CURLE_SSL_CONNECT_ERROR;
+ return CURLE_SSL_CERTPROBLEM;
}
client_certs[0] = CertFindCertificateInStore(
@@ -636,6 +634,10 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
schannel_cred.cCreds = 1;
schannel_cred.paCred = client_certs;
}
+ else {
+ /* CRYPT_E_NOT_FOUND / E_INVALIDARG */
+ return CURLE_SSL_CERTPROBLEM;
+ }
CertCloseStore(cert_store, 0);
}
@@ -672,14 +674,20 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
CertFreeCertificateContext(client_certs[0]);
if(sspi_status != SEC_E_OK) {
- if(sspi_status == SEC_E_WRONG_PRINCIPAL)
- failf(data, "schannel: SNI or certificate check failed: %s",
- Curl_sspi_strerror(conn, sspi_status));
- else
- failf(data, "schannel: AcquireCredentialsHandle failed: %s",
- Curl_sspi_strerror(conn, sspi_status));
+ failf(data, "schannel: AcquireCredentialsHandle failed: %s",
+ Curl_sspi_strerror(conn, sspi_status));
Curl_safefree(BACKEND->cred);
- return CURLE_SSL_CONNECT_ERROR;
+ switch(sspi_status) {
+ case SEC_E_INSUFFICIENT_MEMORY:
+ return CURLE_OUT_OF_MEMORY;
+ case SEC_E_NO_CREDENTIALS:
+ case SEC_E_SECPKG_NOT_FOUND:
+ case SEC_E_NOT_OWNER:
+ case SEC_E_UNKNOWN_CREDENTIALS:
+ case SEC_E_INTERNAL_ERROR:
+ default:
+ return CURLE_SSL_CONNECT_ERROR;
+ }
}
}
@@ -782,14 +790,32 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
Curl_unicodefree(host_name);
if(sspi_status != SEC_I_CONTINUE_NEEDED) {
- if(sspi_status == SEC_E_WRONG_PRINCIPAL)
- failf(data, "schannel: SNI or certificate check failed: %s",
- Curl_sspi_strerror(conn, sspi_status));
- else
- failf(data, "schannel: initial InitializeSecurityContext failed: %s",
- Curl_sspi_strerror(conn, sspi_status));
Curl_safefree(BACKEND->ctxt);
- return CURLE_SSL_CONNECT_ERROR;
+ switch(sspi_status) {
+ case SEC_E_INSUFFICIENT_MEMORY:
+ failf(data, "schannel: initial InitializeSecurityContext failed: %s",
+ Curl_sspi_strerror(conn, sspi_status));
+ return CURLE_OUT_OF_MEMORY;
+ case SEC_E_WRONG_PRINCIPAL:
+ failf(data, "schannel: SNI or certificate check failed: %s",
+ Curl_sspi_strerror(conn, sspi_status));
+ return CURLE_PEER_FAILED_VERIFICATION;
+ /*
+ case SEC_E_INVALID_HANDLE:
+ case SEC_E_INVALID_TOKEN:
+ case SEC_E_LOGON_DENIED:
+ case SEC_E_TARGET_UNKNOWN:
+ case SEC_E_NO_AUTHENTICATING_AUTHORITY:
+ case SEC_E_INTERNAL_ERROR:
+ case SEC_E_NO_CREDENTIALS:
+ case SEC_E_UNSUPPORTED_FUNCTION:
+ case SEC_E_APPLICATION_PROTOCOL_MISMATCH:
+ */
+ default:
+ failf(data, "schannel: initial InitializeSecurityContext failed: %s",
+ Curl_sspi_strerror(conn, sspi_status));
+ return CURLE_SSL_CONNECT_ERROR;
+ }
}
infof(data, "schannel: sending initial handshake data: "
@@ -1004,14 +1030,31 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
}
}
else {
- if(sspi_status == SEC_E_WRONG_PRINCIPAL)
- failf(data, "schannel: SNI or certificate check failed: %s",
- Curl_sspi_strerror(conn, sspi_status));
- else
- failf(data, "schannel: next InitializeSecurityContext failed: %s",
- Curl_sspi_strerror(conn, sspi_status));
- return sspi_status == SEC_E_UNTRUSTED_ROOT ?
- CURLE_SSL_CACERT : CURLE_SSL_CONNECT_ERROR;
+ switch(sspi_status) {
+ case SEC_E_INSUFFICIENT_MEMORY:
+ failf(data, "schannel: next InitializeSecurityContext failed: %s",
+ Curl_sspi_strerror(conn, sspi_status));
+ return CURLE_OUT_OF_MEMORY;
+ case SEC_E_WRONG_PRINCIPAL:
+ failf(data, "schannel: SNI or certificate check failed: %s",
+ Curl_sspi_strerror(conn, sspi_status));
+ return CURLE_PEER_FAILED_VERIFICATION;
+ /*
+ case SEC_E_INVALID_HANDLE:
+ case SEC_E_INVALID_TOKEN:
+ case SEC_E_LOGON_DENIED:
+ case SEC_E_TARGET_UNKNOWN:
+ case SEC_E_NO_AUTHENTICATING_AUTHORITY:
+ case SEC_E_INTERNAL_ERROR:
+ case SEC_E_NO_CREDENTIALS:
+ case SEC_E_UNSUPPORTED_FUNCTION:
+ case SEC_E_APPLICATION_PROTOCOL_MISMATCH:
+ */
+ default:
+ failf(data, "schannel: next InitializeSecurityContext failed: %s",
+ Curl_sspi_strerror(conn, sspi_status));
+ return CURLE_SSL_CONNECT_ERROR;
+ }
}
/* check if there was additional remaining encrypted data */
@@ -1192,7 +1235,7 @@ schannel_connect_step3(struct connectdata *conn, int sockindex)
if((sspi_status != SEC_E_OK) || (ccert_context == NULL)) {
failf(data, "schannel: failed to retrieve remote cert context");
- return CURLE_SSL_CONNECT_ERROR;
+ return CURLE_PEER_FAILED_VERIFICATION;
}
result = Curl_ssl_init_certinfo(data, 1);
diff --git a/lib/vtls/schannel.h b/lib/vtls/schannel.h
index 51417aff..e491bd43 100644
--- a/lib/vtls/schannel.h
+++ b/lib/vtls/schannel.h
@@ -41,7 +41,7 @@
* typedef struct X509_name_st X509_NAME;
* etc.
*
- * this wil cause all kinds of C-preprocessing paste errors in
+ * this will cause all kinds of C-preprocessing paste errors in
* BoringSSL's <openssl/x509.h>: So just undefine those defines here
* (and only here).
*/
diff --git a/lib/vtls/schannel_verify.c b/lib/vtls/schannel_verify.c
index 5a7092a2..2516f566 100644
--- a/lib/vtls/schannel_verify.c
+++ b/lib/vtls/schannel_verify.c
@@ -135,7 +135,7 @@ static CURLcode add_certs_to_store(HCERTSTORE trust_store,
failf(data,
"schannel: CA file exceeds max size of %u bytes",
MAX_CAFILE_SIZE);
- result = CURLE_OUT_OF_MEMORY;
+ result = CURLE_SSL_CACERT_BADFILE;
goto cleanup;
}
@@ -244,7 +244,7 @@ static CURLcode add_certs_to_store(HCERTSTORE trust_store,
CertFreeCertificateContext(cert_context);
if(!add_cert_result) {
failf(data,
- "schannel: failed to add certificate from CA file '%s'"
+ "schannel: failed to add certificate from CA file '%s' "
"to certificate store: %s",
ca_file, Curl_strerror(conn, GetLastError()));
result = CURLE_SSL_CACERT_BADFILE;
@@ -319,6 +319,10 @@ static CURLcode verify_host(struct Curl_easy *data,
* embedded null bytes. This appears to be undocumented behavior.
*/
cert_hostname_buff = (LPTSTR)malloc(len * sizeof(TCHAR));
+ if(!cert_hostname_buff) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto cleanup;
+ }
actual_len = CertGetNameString(pCertContextServer,
CERT_NAME_DNS_TYPE,
name_flags,
diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c
index b61c6403..6af39fea 100644
--- a/lib/vtls/vtls.c
+++ b/lib/vtls/vtls.c
@@ -1190,6 +1190,8 @@ const struct Curl_ssl *Curl_ssl =
&Curl_ssl_polarssl;
#elif defined(USE_SCHANNEL)
&Curl_ssl_schannel;
+#elif defined(USE_MESALINK)
+ &Curl_ssl_mesalink;
#else
#error "Missing struct Curl_ssl for selected SSL backend"
#endif
@@ -1225,6 +1227,9 @@ static const struct Curl_ssl *available_backends[] = {
#if defined(USE_SCHANNEL)
&Curl_ssl_schannel,
#endif
+#if defined(USE_MESALINK)
+ &Curl_ssl_mesalink,
+#endif
NULL
};
diff --git a/lib/vtls/vtls.h b/lib/vtls/vtls.h
index 40f9d747..5cd11602 100644
--- a/lib/vtls/vtls.h
+++ b/lib/vtls/vtls.h
@@ -108,6 +108,7 @@ CURLcode Curl_none_md5sum(unsigned char *input, size_t inputlen,
#include "schannel.h" /* Schannel SSPI version */
#include "darwinssl.h" /* SecureTransport (Darwin) version */
#include "mbedtls.h" /* mbedTLS versions */
+#include "mesalink.h" /* MesaLink versions */
#ifndef MAX_PINNED_PUBKEY_SIZE
#define MAX_PINNED_PUBKEY_SIZE 1048576 /* 1MB */
diff --git a/lib/x509asn1.c b/lib/x509asn1.c
index 72a0b4a0..a576fc70 100644
--- a/lib/x509asn1.c
+++ b/lib/x509asn1.c
@@ -103,6 +103,9 @@ static const curl_OID OIDtable[] = {
* Please note there is no pretention here to rewrite a full SSL library.
*/
+static const char *getASN1Element(curl_asn1Element *elem,
+ const char *beg, const char *end)
+ WARN_UNUSED_RESULT;
static const char *getASN1Element(curl_asn1Element *elem,
const char *beg, const char *end)
@@ -223,7 +226,7 @@ static const char *bit2str(const char *beg, const char *end)
static const char *int2str(const char *beg, const char *end)
{
- long val = 0;
+ unsigned long val = 0;
size_t n = end - beg;
/* Convert an ASN.1 integer value into its string representation.
@@ -243,7 +246,7 @@ static const char *int2str(const char *beg, const char *end)
do
val = (val << 8) | *(const unsigned char *) beg++;
while(beg < end);
- return curl_maprintf("%s%lx", (val < 0 || val >= 10)? "0x": "", val);
+ return curl_maprintf("%s%lx", val >= 10? "0x": "", val);
}
static ssize_t
@@ -602,10 +605,17 @@ static ssize_t encodeDN(char *buf, size_t n, curl_asn1Element *dn)
for(p1 = dn->beg; p1 < dn->end;) {
p1 = getASN1Element(&rdn, p1, dn->end);
+ if(!p1)
+ return -1;
for(p2 = rdn.beg; p2 < rdn.end;) {
p2 = getASN1Element(&atv, p2, rdn.end);
+ if(!p2)
+ return -1;
p3 = getASN1Element(&oid, atv.beg, atv.end);
- getASN1Element(&value, p3, atv.end);
+ if(!p3)
+ return -1;
+ if(!getASN1Element(&value, p3, atv.end))
+ return -1;
str = ASN1tostr(&oid, 0);
if(!str)
return -1;
@@ -697,10 +707,15 @@ int Curl_parseX509(curl_X509certificate *cert,
/* Get tbsCertificate. */
beg = getASN1Element(&tbsCertificate, beg, end);
+ if(!beg)
+ return -1;
/* Skip the signatureAlgorithm. */
beg = getASN1Element(&cert->signatureAlgorithm, beg, end);
+ if(!beg)
+ return -1;
/* Get the signatureValue. */
- getASN1Element(&cert->signature, beg, end);
+ if(!getASN1Element(&cert->signature, beg, end))
+ return -1;
/* Parse TBSCertificate. */
beg = tbsCertificate.beg;
@@ -710,28 +725,47 @@ int Curl_parseX509(curl_X509certificate *cert,
cert->version.beg = &defaultVersion;
cert->version.end = &defaultVersion + sizeof(defaultVersion);
beg = getASN1Element(&elem, beg, end);
+ if(!beg)
+ return -1;
if(elem.tag == 0) {
- getASN1Element(&cert->version, elem.beg, elem.end);
+ if(!getASN1Element(&cert->version, elem.beg, elem.end))
+ return -1;
beg = getASN1Element(&elem, beg, end);
+ if(!beg)
+ return -1;
}
cert->serialNumber = elem;
/* Get signature algorithm. */
beg = getASN1Element(&cert->signatureAlgorithm, beg, end);
/* Get issuer. */
beg = getASN1Element(&cert->issuer, beg, end);
+ if(!beg)
+ return -1;
/* Get notBefore and notAfter. */
beg = getASN1Element(&elem, beg, end);
+ if(!beg)
+ return -1;
ccp = getASN1Element(&cert->notBefore, elem.beg, elem.end);
- getASN1Element(&cert->notAfter, ccp, elem.end);
+ if(!ccp)
+ return -1;
+ if(!getASN1Element(&cert->notAfter, ccp, elem.end))
+ return -1;
/* Get subject. */
beg = getASN1Element(&cert->subject, beg, end);
+ if(!beg)
+ return -1;
/* Get subjectPublicKeyAlgorithm and subjectPublicKey. */
beg = getASN1Element(&cert->subjectPublicKeyInfo, beg, end);
+ if(!beg)
+ return -1;
ccp = getASN1Element(&cert->subjectPublicKeyAlgorithm,
- cert->subjectPublicKeyInfo.beg,
- cert->subjectPublicKeyInfo.end);
- getASN1Element(&cert->subjectPublicKey, ccp,
- cert->subjectPublicKeyInfo.end);
+ cert->subjectPublicKeyInfo.beg,
+ cert->subjectPublicKeyInfo.end);
+ if(!ccp)
+ return -1;
+ if(!getASN1Element(&cert->subjectPublicKey, ccp,
+ cert->subjectPublicKeyInfo.end))
+ return -1;
/* Get optional issuerUiqueID, subjectUniqueID and extensions. */
cert->issuerUniqueID.tag = cert->subjectUniqueID.tag = 0;
cert->extensions.tag = elem.tag = 0;
@@ -740,20 +774,30 @@ int Curl_parseX509(curl_X509certificate *cert,
cert->subjectUniqueID.beg = cert->subjectUniqueID.end = "";
cert->extensions.header = NULL;
cert->extensions.beg = cert->extensions.end = "";
- if(beg < end)
+ if(beg < end) {
beg = getASN1Element(&elem, beg, end);
+ if(!beg)
+ return -1;
+ }
if(elem.tag == 1) {
cert->issuerUniqueID = elem;
- if(beg < end)
+ if(beg < end) {
beg = getASN1Element(&elem, beg, end);
+ if(!beg)
+ return -1;
+ }
}
if(elem.tag == 2) {
cert->subjectUniqueID = elem;
- if(beg < end)
+ if(beg < end) {
beg = getASN1Element(&elem, beg, end);
+ if(!beg)
+ return -1;
+ }
}
if(elem.tag == 3)
- getASN1Element(&cert->extensions, elem.beg, elem.end);
+ if(!getASN1Element(&cert->extensions, elem.beg, elem.end))
+ return -1;
return 0;
}
@@ -782,11 +826,14 @@ static const char *dumpAlgo(curl_asn1Element *param,
/* Get algorithm parameters and return algorithm name. */
beg = getASN1Element(&oid, beg, end);
+ if(!beg)
+ return NULL;
param->header = NULL;
param->tag = 0;
param->beg = param->end = end;
if(beg < end)
- getASN1Element(param, beg, end);
+ if(!getASN1Element(param, beg, end))
+ return NULL;
return OID2str(oid.beg, oid.end, TRUE);
}
@@ -821,10 +868,14 @@ static void do_pubkey(struct Curl_easy *data, int certnum,
/* Generate all information records for the public key. */
/* Get the public key (single element). */
- getASN1Element(&pk, pubkey->beg + 1, pubkey->end);
+ if(!getASN1Element(&pk, pubkey->beg + 1, pubkey->end))
+ return;
if(strcasecompare(algo, "rsaEncryption")) {
p = getASN1Element(&elem, pk.beg, pk.end);
+ if(!p)
+ return;
+
/* Compute key length. */
for(q = elem.beg; !*q && q < elem.end; q++)
;
@@ -845,30 +896,34 @@ static void do_pubkey(struct Curl_easy *data, int certnum,
}
/* Generate coefficients. */
do_pubkey_field(data, certnum, "rsa(n)", &elem);
- getASN1Element(&elem, p, pk.end);
+ if(!getASN1Element(&elem, p, pk.end))
+ return;
do_pubkey_field(data, certnum, "rsa(e)", &elem);
}
else if(strcasecompare(algo, "dsa")) {
p = getASN1Element(&elem, param->beg, param->end);
- do_pubkey_field(data, certnum, "dsa(p)", &elem);
- p = getASN1Element(&elem, p, param->end);
- do_pubkey_field(data, certnum, "dsa(q)", &elem);
- getASN1Element(&elem, p, param->end);
- do_pubkey_field(data, certnum, "dsa(g)", &elem);
- do_pubkey_field(data, certnum, "dsa(pub_key)", &pk);
+ if(p) {
+ do_pubkey_field(data, certnum, "dsa(p)", &elem);
+ p = getASN1Element(&elem, p, param->end);
+ if(p) {
+ do_pubkey_field(data, certnum, "dsa(q)", &elem);
+ if(getASN1Element(&elem, p, param->end)) {
+ do_pubkey_field(data, certnum, "dsa(g)", &elem);
+ do_pubkey_field(data, certnum, "dsa(pub_key)", &pk);
+ }
+ }
+ }
}
else if(strcasecompare(algo, "dhpublicnumber")) {
p = getASN1Element(&elem, param->beg, param->end);
- do_pubkey_field(data, certnum, "dh(p)", &elem);
- getASN1Element(&elem, param->beg, param->end);
- do_pubkey_field(data, certnum, "dh(g)", &elem);
- do_pubkey_field(data, certnum, "dh(pub_key)", &pk);
- }
-#if 0 /* Patent-encumbered. */
- else if(strcasecompare(algo, "ecPublicKey")) {
- /* Left TODO. */
+ if(p) {
+ do_pubkey_field(data, certnum, "dh(p)", &elem);
+ if(getASN1Element(&elem, param->beg, param->end)) {
+ do_pubkey_field(data, certnum, "dh(g)", &elem);
+ do_pubkey_field(data, certnum, "dh(pub_key)", &pk);
+ }
+ }
}
-#endif
}
CURLcode Curl_extract_certinfo(struct connectdata *conn,
@@ -896,7 +951,7 @@ CURLcode Curl_extract_certinfo(struct connectdata *conn,
/* Extract the certificate ASN.1 elements. */
if(Curl_parseX509(&cert, beg, end))
- return CURLE_OUT_OF_MEMORY;
+ return CURLE_PEER_FAILED_VERIFICATION;
/* Subject. */
ccp = DNtostr(&cert.subject);
@@ -1107,18 +1162,29 @@ CURLcode Curl_verifyhost(struct connectdata *conn,
/* Process extensions. */
for(p = cert.extensions.beg; p < cert.extensions.end && matched != 1;) {
p = getASN1Element(&ext, p, cert.extensions.end);
+ if(!p)
+ return CURLE_PEER_FAILED_VERIFICATION;
+
/* Check if extension is a subjectAlternativeName. */
ext.beg = checkOID(ext.beg, ext.end, sanOID);
if(ext.beg) {
ext.beg = getASN1Element(&elem, ext.beg, ext.end);
+ if(!ext.beg)
+ return CURLE_PEER_FAILED_VERIFICATION;
/* Skip critical if present. */
- if(elem.tag == CURL_ASN1_BOOLEAN)
+ if(elem.tag == CURL_ASN1_BOOLEAN) {
ext.beg = getASN1Element(&elem, ext.beg, ext.end);
+ if(!ext.beg)
+ return CURLE_PEER_FAILED_VERIFICATION;
+ }
/* Parse the octet string contents: is a single sequence. */
- getASN1Element(&elem, elem.beg, elem.end);
+ if(!getASN1Element(&elem, elem.beg, elem.end))
+ return CURLE_PEER_FAILED_VERIFICATION;
/* Check all GeneralNames. */
for(q = elem.beg; matched != 1 && q < elem.end;) {
q = getASN1Element(&name, q, elem.end);
+ if(!q)
+ break;
switch(name.tag) {
case 2: /* DNS name. */
len = utf8asn1str(&dnsname, CURL_ASN1_IA5_STRING,
@@ -1131,8 +1197,8 @@ CURLcode Curl_verifyhost(struct connectdata *conn,
break;
case 7: /* IP address. */
- matched = (size_t) (name.end - q) == addrlen &&
- !memcmp(&addr, q, addrlen);
+ matched = (size_t) (name.end - name.beg) == addrlen &&
+ !memcmp(&addr, name.beg, addrlen);
break;
}
}
@@ -1159,8 +1225,12 @@ CURLcode Curl_verifyhost(struct connectdata *conn,
distinguished one to get the most significant one. */
while(q < cert.subject.end) {
q = getASN1Element(&dn, q, cert.subject.end);
+ if(!q)
+ break;
for(p = dn.beg; p < dn.end;) {
p = getASN1Element(&elem, p, dn.end);
+ if(!p)
+ return CURLE_PEER_FAILED_VERIFICATION;
/* We have a DN's AttributeTypeAndValue: check it in case it's a CN. */
elem.beg = checkOID(elem.beg, elem.end, cnOID);
if(elem.beg)