Update networking layer w/ CURL and emscripten impl
This commit is contained in:
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
# Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
#
|
||||
# SPDX-License-Identifier: curl
|
||||
|
||||
enable STDERR
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
#***************************************************************************
|
||||
# _ _ ____ _
|
||||
# Project ___| | | | _ \| |
|
||||
# / __| | | | |_) | |
|
||||
# | (__| |_| | _ <| |___
|
||||
# \___|\___/|_| \_\_____|
|
||||
#
|
||||
# Copyright (C) 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.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.
|
||||
#
|
||||
# SPDX-License-Identifier: curl
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS "${CURL_DEBUG_MACROS}")
|
||||
|
||||
set(_curl_cfiles_gen "")
|
||||
set(_curl_hfiles_gen "")
|
||||
set(_curl_definitions "")
|
||||
|
||||
if(ENABLE_CURL_MANUAL AND (PERL_FOUND OR EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tool_hugehelp.c"))
|
||||
if(PERL_FOUND)
|
||||
add_custom_command(OUTPUT "tool_hugehelp.c"
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "#include \"tool_setup.h\"" > "tool_hugehelp.c"
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "/* !checksrc! disable COPYRIGHT all */" >> "tool_hugehelp.c"
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "/* !checksrc! disable INCLUDEDUP all */" >> "tool_hugehelp.c"
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "/* !checksrc! disable LONGLINE all */" >> "tool_hugehelp.c"
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "#ifndef HAVE_LIBZ" >> "tool_hugehelp.c"
|
||||
COMMAND "${PERL_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/mkhelp.pl" < "${CURL_ASCIIPAGE}" >> "tool_hugehelp.c"
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "#else" >> "tool_hugehelp.c"
|
||||
COMMAND "${PERL_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/mkhelp.pl" -c < "${CURL_ASCIIPAGE}" >> "tool_hugehelp.c"
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "#endif /* HAVE_LIBZ */" >> "tool_hugehelp.c"
|
||||
DEPENDS
|
||||
generate-curl.1
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/mkhelp.pl"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/tool_hugehelp.h"
|
||||
"${CURL_ASCIIPAGE}"
|
||||
VERBATIM)
|
||||
else()
|
||||
message(STATUS "Perl not found. Using the pre-built tool_hugehelp.c found in the source tree.")
|
||||
endif()
|
||||
list(APPEND _curl_cfiles_gen "tool_hugehelp.c")
|
||||
list(APPEND _curl_hfiles_gen "tool_hugehelp.h")
|
||||
list(APPEND _curl_definitions "USE_MANUAL")
|
||||
endif()
|
||||
|
||||
if(CURL_CA_EMBED_SET)
|
||||
if(PERL_FOUND)
|
||||
add_custom_command(OUTPUT "tool_ca_embed.c"
|
||||
COMMAND "${PERL_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/mk-file-embed.pl" --var curl_ca_embed
|
||||
< "${CURL_CA_EMBED}" > "tool_ca_embed.c"
|
||||
DEPENDS
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/mk-file-embed.pl"
|
||||
"${CURL_CA_EMBED}"
|
||||
VERBATIM)
|
||||
list(APPEND _curl_cfiles_gen "tool_ca_embed.c")
|
||||
list(APPEND _curl_definitions "CURL_CA_EMBED")
|
||||
else()
|
||||
message(WARNING "Perl not found. Will not embed the CA bundle.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Get CURL_CFILES, CURL_HFILES, CURLX_CFILES, CURLX_HFILES, CURL_RCFILES variables
|
||||
curl_transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
|
||||
include("${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
|
||||
|
||||
source_group("curl source files" FILES ${CURL_CFILES} ${_curl_cfiles_gen})
|
||||
source_group("curl header files" FILES ${CURL_HFILES} ${_curl_hfiles_gen})
|
||||
source_group("curlx source files" FILES ${CURLX_CFILES})
|
||||
source_group("curlx header files" FILES ${CURLX_HFILES})
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND CURL_CFILES ${CURL_RCFILES})
|
||||
endif()
|
||||
|
||||
set(_curlx_cfiles_lib ${CURLX_CFILES})
|
||||
set(_curlx_hfiles_lib ${CURLX_HFILES})
|
||||
if(LIB_SELECTED STREQUAL LIB_STATIC)
|
||||
set(_curlx_cfiles_lib "")
|
||||
set(_curlx_hfiles_lib "")
|
||||
endif()
|
||||
|
||||
if(BUILD_STATIC_CURL)
|
||||
set(CURLX_CFILES "")
|
||||
set(CURLX_HFILES "")
|
||||
endif()
|
||||
|
||||
set_property(DIRECTORY APPEND PROPERTY INCLUDE_DIRECTORIES
|
||||
"${PROJECT_BINARY_DIR}/lib" # for "curl_config.h"
|
||||
"${PROJECT_SOURCE_DIR}/lib" # for "curl_setup.h", curlx
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}" # for "tool_hugehelp.c"
|
||||
)
|
||||
|
||||
# Build curl executable
|
||||
add_executable(${EXE_NAME} ${CURL_CFILES} ${CURL_HFILES} ${_curl_cfiles_gen} ${_curl_hfiles_gen} ${CURLX_CFILES} ${CURLX_HFILES})
|
||||
target_compile_definitions(${EXE_NAME} PRIVATE ${_curl_definitions})
|
||||
target_link_libraries(${EXE_NAME} ${LIB_SELECTED_FOR_EXE} ${CURL_LIBS})
|
||||
|
||||
add_executable(${PROJECT_NAME}::${EXE_NAME} ALIAS ${EXE_NAME})
|
||||
|
||||
add_executable(curlinfo EXCLUDE_FROM_ALL "curlinfo.c")
|
||||
set_target_properties(curlinfo PROPERTIES UNITY_BUILD OFF)
|
||||
|
||||
# special libcurltool library just for unittests
|
||||
add_library(curltool STATIC EXCLUDE_FROM_ALL ${CURL_CFILES} ${CURL_HFILES} ${_curlx_cfiles_lib} ${_curlx_hfiles_lib})
|
||||
target_compile_definitions(curltool PUBLIC "CURL_STATICLIB" "UNITTESTS")
|
||||
target_link_libraries(curltool PRIVATE ${CURL_LIBS})
|
||||
set_target_properties(curltool PROPERTIES C_CLANG_TIDY "")
|
||||
|
||||
if(CURL_HAS_LTO)
|
||||
set_target_properties(${EXE_NAME} PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE)
|
||||
endif()
|
||||
|
||||
if(ENABLE_UNICODE AND MINGW AND NOT MINGW32CE)
|
||||
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.13)
|
||||
set_property(TARGET ${EXE_NAME} APPEND PROPERTY LINK_OPTIONS "-municode")
|
||||
else()
|
||||
set_property(TARGET ${EXE_NAME} APPEND PROPERTY LINK_FLAGS "-municode")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CURL_CODE_COVERAGE)
|
||||
set_property(TARGET ${EXE_NAME} APPEND PROPERTY COMPILE_DEFINITIONS ${CURL_COVERAGE_MACROS})
|
||||
set_property(TARGET ${EXE_NAME} APPEND PROPERTY COMPILE_OPTIONS ${CURL_COVERAGE_CFLAGS})
|
||||
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.13)
|
||||
set_property(TARGET ${EXE_NAME} APPEND PROPERTY LINK_OPTIONS ${CURL_COVERAGE_LDFLAGS})
|
||||
else()
|
||||
set_property(TARGET ${EXE_NAME} APPEND PROPERTY LINK_FLAGS ${CURL_COVERAGE_LDFLAGS})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
################################################################################
|
||||
|
||||
install(TARGETS ${EXE_NAME} EXPORT ${TARGETS_EXPORT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
export(TARGETS ${EXE_NAME}
|
||||
FILE "${PROJECT_BINARY_DIR}/curl-target.cmake"
|
||||
NAMESPACE ${PROJECT_NAME}::
|
||||
)
|
||||
Vendored
+243
@@ -0,0 +1,243 @@
|
||||
#***************************************************************************
|
||||
# _ _ ____ _
|
||||
# Project ___| | | | _ \| |
|
||||
# / __| | | | |_) | |
|
||||
# | (__| |_| | _ <| |___
|
||||
# \___|\___/|_| \_\_____|
|
||||
#
|
||||
# Copyright (C) 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.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.
|
||||
#
|
||||
# SPDX-License-Identifier: curl
|
||||
#
|
||||
###########################################################################
|
||||
AUTOMAKE_OPTIONS = foreign nostdinc
|
||||
|
||||
# remove targets if the command fails
|
||||
.DELETE_ON_ERROR:
|
||||
|
||||
# Get CURL_CFILES, CURL_HFILES, CURLX_CFILES, CURLX_HFILES, CURL_RCFILES variables
|
||||
include Makefile.inc
|
||||
|
||||
EXTRA_DIST = CMakeLists.txt .checksrc mk-file-embed.pl mkhelp.pl $(CURL_RCFILES)
|
||||
|
||||
# Specify our include paths here, and do it relative to $(top_srcdir) and
|
||||
# $(top_builddir), to ensure that these paths which belong to the library
|
||||
# being currently built and tested are searched before the library which
|
||||
# might possibly already be installed in the system.
|
||||
#
|
||||
# $(top_srcdir)/include is for libcurl's external include files
|
||||
# $(top_builddir)/lib is for libcurl's generated lib/curl_config.h file
|
||||
# $(top_srcdir)/lib for libcurl's lib/curl_setup.h and other "borrowed" files
|
||||
# $(srcdir) for generated sources to find included sources
|
||||
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/include \
|
||||
-I$(top_builddir)/lib \
|
||||
-I$(top_srcdir)/lib \
|
||||
-I$(srcdir)
|
||||
|
||||
bin_PROGRAMS = curl
|
||||
|
||||
curlinfo_SOURCES = curlinfo.c
|
||||
noinst_PROGRAMS = curlinfo
|
||||
|
||||
if USE_CPPFLAG_CURL_STATICLIB
|
||||
AM_CPPFLAGS += -DCURL_STATICLIB
|
||||
endif
|
||||
if DEBUGBUILD
|
||||
AM_CPPFLAGS += -DDEBUGBUILD
|
||||
endif
|
||||
if CURLDEBUG
|
||||
AM_CPPFLAGS += -DCURLDEBUG
|
||||
endif
|
||||
|
||||
AM_LDFLAGS =
|
||||
if USE_UNICODE
|
||||
UNICODEFLAG = -municode
|
||||
endif
|
||||
|
||||
curl_cfiles_gen =
|
||||
curl_hfiles_gen =
|
||||
CLEANFILES =
|
||||
|
||||
if USE_CPPFLAG_CURL_STATICLIB
|
||||
curlx_csrc =
|
||||
curlx_hsrc =
|
||||
else
|
||||
# These are part of the libcurl static lib. Add them here when linking shared.
|
||||
curlx_csrc = $(CURLX_CFILES)
|
||||
curlx_hsrc = $(CURLX_HFILES)
|
||||
endif
|
||||
|
||||
if USE_UNITY
|
||||
curltool_unity.c: $(top_srcdir)/scripts/mk-unity.pl $(CURL_CFILES) $(curl_cfiles_gen) $(curlx_csrc)
|
||||
@PERL@ $(top_srcdir)/scripts/mk-unity.pl --include $(CURL_CFILES) $(curl_cfiles_gen) $(curlx_csrc) > curltool_unity.c
|
||||
|
||||
nodist_curl_SOURCES = curltool_unity.c
|
||||
curl_SOURCES =
|
||||
CLEANFILES += curltool_unity.c
|
||||
else
|
||||
curl_SOURCES = $(CURL_CFILES) $(CURL_HFILES) $(curl_cfiles_gen) $(curl_hfiles_gen) $(curlx_csrc) $(curlx_hsrc)
|
||||
endif
|
||||
if HAVE_WINDRES
|
||||
curl_SOURCES += $(CURL_RCFILES)
|
||||
$(CURL_RCFILES): tool_version.h
|
||||
endif
|
||||
|
||||
curl_LDFLAGS = $(AM_LDFLAGS) $(CURL_LDFLAGS_BIN) $(UNICODEFLAG)
|
||||
|
||||
# This might hold -Werror
|
||||
CFLAGS += @CURL_CFLAG_EXTRAS@
|
||||
|
||||
# Prevent LIBS from being used for all link targets
|
||||
LIBS = $(BLANK_AT_MAKETIME)
|
||||
|
||||
curl_LDADD = $(top_builddir)/lib/libcurl.la @LIBCURL_PC_LIBS_PRIVATE@
|
||||
|
||||
# if unit tests are enabled, build a static library to link them with
|
||||
if BUILD_UNITTESTS
|
||||
noinst_LTLIBRARIES = libcurltool.la
|
||||
libcurltool_la_CPPFLAGS = $(AM_CPPFLAGS) -DCURL_STATICLIB -DUNITTESTS
|
||||
libcurltool_la_CFLAGS =
|
||||
libcurltool_la_LDFLAGS = -static $(LIBCURL_PC_LIBS_PRIVATE)
|
||||
if USE_UNITY
|
||||
libcurltool_unity.c: $(top_srcdir)/scripts/mk-unity.pl $(CURL_CFILES) $(curlx_csrc)
|
||||
@PERL@ $(top_srcdir)/scripts/mk-unity.pl --include $(CURL_CFILES) $(curlx_csrc) > libcurltool_unity.c
|
||||
|
||||
nodist_libcurltool_la_SOURCES = libcurltool_unity.c
|
||||
libcurltool_la_SOURCES =
|
||||
CLEANFILES += libcurltool_unity.c
|
||||
else
|
||||
libcurltool_la_SOURCES = $(CURL_CFILES) $(CURL_HFILES) $(curlx_csrc) $(curlx_hsrc)
|
||||
endif
|
||||
endif
|
||||
|
||||
# Use absolute directory to disable VPATH
|
||||
ASCIIPAGE=$(top_builddir)/docs/cmdline-opts/curl.txt
|
||||
MKHELP=$(top_srcdir)/src/mkhelp.pl
|
||||
HUGE=tool_hugehelp.c
|
||||
|
||||
HUGECMD = $(HUGEIT_$(V))
|
||||
HUGEIT_0 = @echo " HUGE " $@;
|
||||
HUGEIT_1 =
|
||||
HUGEIT_ = $(HUGEIT_0)
|
||||
|
||||
curl_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
|
||||
if USE_MANUAL
|
||||
# Here are the stuff to create a built-in manual
|
||||
curl_CPPFLAGS += -DUSE_MANUAL
|
||||
|
||||
$(ASCIIPAGE):
|
||||
cd $(top_builddir)/docs && $(MAKE)
|
||||
|
||||
if PERL
|
||||
if HAVE_LIBZ
|
||||
# This generates the tool_hugehelp.c file in both uncompressed and
|
||||
# compressed formats.
|
||||
$(HUGE): $(ASCIIPAGE) $(MKHELP)
|
||||
$(HUGECMD)( \
|
||||
echo '/* !checksrc! disable COPYRIGHT all */' > $(HUGE); \
|
||||
echo '/* !checksrc! disable INCLUDEDUP all */' >> $(HUGE); \
|
||||
echo '/* !checksrc! disable LONGLINE all */' >> $(HUGE); \
|
||||
echo '#include "tool_setup.h"' >> $(HUGE); \
|
||||
echo '#ifndef HAVE_LIBZ' >> $(HUGE); \
|
||||
@PERL@ $(MKHELP) < $(ASCIIPAGE) >> $(HUGE); \
|
||||
echo '#else' >> $(HUGE); \
|
||||
@PERL@ $(MKHELP) -c < $(ASCIIPAGE) >> $(HUGE); \
|
||||
echo '#endif /* HAVE_LIBZ */' >> $(HUGE) )
|
||||
else # HAVE_LIBZ
|
||||
# This generates the tool_hugehelp.c file uncompressed only
|
||||
$(HUGE): $(ASCIIPAGE) $(MKHELP)
|
||||
$(HUGECMD)( \
|
||||
echo '/* !checksrc! disable COPYRIGHT all */' > $(HUGE); \
|
||||
echo '#include "tool_setup.h"' >> $(HUGE); \
|
||||
@PERL@ $(MKHELP) < $(ASCIIPAGE) >> $(HUGE) )
|
||||
endif
|
||||
else # PERL
|
||||
$(HUGE):
|
||||
$(HUGECMD)( \
|
||||
if test ! -f "$(srcdir)/$(HUGE)"; then \
|
||||
echo '/* !checksrc! disable COPYRIGHT all */' > $(HUGE); \
|
||||
echo '#include "tool_hugehelp.h"' >> $(HUGE); \
|
||||
echo 'void hugehelp(void) {}' >> $(HUGE); \
|
||||
echo 'void showhelp(const char *trigger, const char *arg, const char *endarg)' >> $(HUGE); \
|
||||
echo '{' >> $(HUGE); \
|
||||
echo ' (void)trigger; (void)arg; (void)endarg;' >> $(HUGE); \
|
||||
echo '}' >> $(HUGE); \
|
||||
fi)
|
||||
endif
|
||||
|
||||
else # USE_MANUAL
|
||||
# built-in manual has been disabled, make a blank file
|
||||
$(HUGE):
|
||||
echo '/* !checksrc! disable COPYRIGHT all */' > $(HUGE); \
|
||||
echo '#include "tool_hugehelp.h"' >> $(HUGE)
|
||||
endif
|
||||
|
||||
curl_cfiles_gen += $(HUGE)
|
||||
curl_hfiles_gen += tool_hugehelp.h
|
||||
CLEANFILES += $(HUGE)
|
||||
|
||||
CA_EMBED_CSOURCE = tool_ca_embed.c
|
||||
curl_cfiles_gen += $(CA_EMBED_CSOURCE)
|
||||
CLEANFILES += $(CA_EMBED_CSOURCE)
|
||||
if CURL_CA_EMBED_SET
|
||||
curl_CPPFLAGS += -DCURL_CA_EMBED
|
||||
MK_FILE_EMBED = $(top_srcdir)/src/mk-file-embed.pl
|
||||
$(CA_EMBED_CSOURCE): $(MK_FILE_EMBED) $(CURL_CA_EMBED)
|
||||
@PERL@ $(MK_FILE_EMBED) --var curl_ca_embed < $(CURL_CA_EMBED) > $(CA_EMBED_CSOURCE)
|
||||
else
|
||||
$(CA_EMBED_CSOURCE):
|
||||
echo '/* !checksrc! disable COPYRIGHT all */' > $(CA_EMBED_CSOURCE)
|
||||
echo 'extern const void *curl_ca_embed; const void *curl_ca_embed;' >> $(CA_EMBED_CSOURCE)
|
||||
endif
|
||||
|
||||
CHECKSRC = $(CS_$(V))
|
||||
CS_0 = @echo " RUN " $@;
|
||||
CS_1 =
|
||||
CS_ = $(CS_0)
|
||||
|
||||
# ignore generated C files since they play by slightly different rules!
|
||||
checksrc:
|
||||
$(CHECKSRC)(@PERL@ $(top_srcdir)/scripts/checksrc.pl -D$(srcdir) $(CURL_CFILES) $(CURL_HFILES))
|
||||
|
||||
if NOT_CURL_CI
|
||||
if DEBUGBUILD
|
||||
# for debug builds, we scan the sources on all regular make invokes
|
||||
all-local: checksrc
|
||||
endif
|
||||
endif
|
||||
|
||||
# disable the tests that are mostly causing false positives
|
||||
TIDYFLAGS := -checks=-clang-analyzer-security.insecureAPI.bzero,-clang-analyzer-security.insecureAPI.strcpy,-clang-analyzer-optin.performance.Padding,-clang-analyzer-security.ArrayBound,-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling -quiet
|
||||
if CURL_WERROR
|
||||
TIDYFLAGS += --warnings-as-errors=*
|
||||
endif
|
||||
|
||||
TIDY := clang-tidy
|
||||
|
||||
tidy: $(HUGE) $(CA_EMBED_CSOURCE)
|
||||
(_curl_cfiles=`echo ' $(CURL_CFILES)' | sed -e 's/ +/ /g' -e 's| | $(srcdir)/|g'`; \
|
||||
$(TIDY) $$_curl_cfiles $(curl_cfiles_gen) $(TIDYFLAGS) $(CURL_CLANG_TIDYFLAGS) -- $(curl_CPPFLAGS) $(CPPFLAGS) $(AM_CPPFLAGS) -DHAVE_CONFIG_H)
|
||||
|
||||
listhelp:
|
||||
(cd $(top_srcdir)/docs/cmdline-opts && make listhelp)
|
||||
|
||||
if HAVE_WINDRES
|
||||
.rc.o:
|
||||
$(RC) -I$(top_srcdir)/include $(RCFLAGS) -i $< -o $@
|
||||
endif
|
||||
|
||||
dist-hook:
|
||||
rm -f $(distdir)/$(CA_EMBED_CSOURCE)
|
||||
Vendored
+3010
File diff suppressed because it is too large
Load Diff
+158
@@ -0,0 +1,158 @@
|
||||
#***************************************************************************
|
||||
# _ _ ____ _
|
||||
# Project ___| | | | _ \| |
|
||||
# / __| | | | |_) | |
|
||||
# | (__| |_| | _ <| |___
|
||||
# \___|\___/|_| \_\_____|
|
||||
#
|
||||
# Copyright (C) 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.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.
|
||||
#
|
||||
# SPDX-License-Identifier: curl
|
||||
#
|
||||
###########################################################################
|
||||
# Shared between CMakeLists.txt and Makefile.am
|
||||
|
||||
# Using the backslash as line continuation character might be problematic with
|
||||
# some make flavours. If we ever want to change this in a portable manner then
|
||||
# we should consider this idea :
|
||||
# CSRC1 = file1.c file2.c file3.c
|
||||
# CSRC2 = file4.c file5.c file6.c
|
||||
# CSOURCES = $(CSRC1) $(CSRC2)
|
||||
|
||||
# libcurl has sources that provide functions named curlx_* that are not part of
|
||||
# the official API, but we reuse the code here to avoid duplication.
|
||||
CURLX_CFILES = \
|
||||
../lib/curlx/base64.c \
|
||||
../lib/curlx/dynbuf.c \
|
||||
../lib/curlx/fopen.c \
|
||||
../lib/curlx/multibyte.c \
|
||||
../lib/curlx/nonblock.c \
|
||||
../lib/curlx/strerr.c \
|
||||
../lib/curlx/strparse.c \
|
||||
../lib/curlx/timediff.c \
|
||||
../lib/curlx/timeval.c \
|
||||
../lib/curlx/version_win32.c \
|
||||
../lib/curlx/wait.c \
|
||||
../lib/curlx/warnless.c \
|
||||
../lib/curlx/winapi.c
|
||||
|
||||
CURLX_HFILES = \
|
||||
../lib/curl_setup.h \
|
||||
../lib/curlx/binmode.h \
|
||||
../lib/curlx/dynbuf.h \
|
||||
../lib/curlx/fopen.h \
|
||||
../lib/curlx/multibyte.h \
|
||||
../lib/curlx/nonblock.h \
|
||||
../lib/curlx/strerr.h \
|
||||
../lib/curlx/strparse.h \
|
||||
../lib/curlx/timediff.h \
|
||||
../lib/curlx/timeval.h \
|
||||
../lib/curlx/version_win32.h \
|
||||
../lib/curlx/wait.h \
|
||||
../lib/curlx/warnless.h \
|
||||
../lib/curlx/winapi.h
|
||||
|
||||
CURL_CFILES = \
|
||||
config2setopts.c \
|
||||
slist_wc.c \
|
||||
terminal.c \
|
||||
tool_bname.c \
|
||||
tool_cb_dbg.c \
|
||||
tool_cb_hdr.c \
|
||||
tool_cb_prg.c \
|
||||
tool_cb_rea.c \
|
||||
tool_cb_see.c \
|
||||
tool_cb_soc.c \
|
||||
tool_cb_wrt.c \
|
||||
tool_cfgable.c \
|
||||
tool_dirhie.c \
|
||||
tool_doswin.c \
|
||||
tool_easysrc.c \
|
||||
tool_filetime.c \
|
||||
tool_findfile.c \
|
||||
tool_formparse.c \
|
||||
tool_getparam.c \
|
||||
tool_getpass.c \
|
||||
tool_help.c \
|
||||
tool_helpers.c \
|
||||
tool_ipfs.c \
|
||||
tool_libinfo.c \
|
||||
tool_listhelp.c \
|
||||
tool_main.c \
|
||||
tool_msgs.c \
|
||||
tool_operate.c \
|
||||
tool_operhlp.c \
|
||||
tool_paramhlp.c \
|
||||
tool_parsecfg.c \
|
||||
tool_progress.c \
|
||||
tool_setopt.c \
|
||||
tool_ssls.c \
|
||||
tool_stderr.c \
|
||||
tool_strdup.c \
|
||||
tool_urlglob.c \
|
||||
tool_util.c \
|
||||
tool_vms.c \
|
||||
tool_writeout.c \
|
||||
tool_writeout_json.c \
|
||||
tool_xattr.c \
|
||||
var.c
|
||||
|
||||
CURL_HFILES = \
|
||||
config2setopts.h \
|
||||
slist_wc.h \
|
||||
terminal.h \
|
||||
tool_bname.h \
|
||||
tool_cb_dbg.h \
|
||||
tool_cb_hdr.h \
|
||||
tool_cb_prg.h \
|
||||
tool_cb_rea.h \
|
||||
tool_cb_see.h \
|
||||
tool_cb_soc.h \
|
||||
tool_cb_wrt.h \
|
||||
tool_cfgable.h \
|
||||
tool_dirhie.h \
|
||||
tool_doswin.h \
|
||||
tool_easysrc.h \
|
||||
tool_filetime.h \
|
||||
tool_findfile.h \
|
||||
tool_formparse.h \
|
||||
tool_getparam.h \
|
||||
tool_getpass.h \
|
||||
tool_help.h \
|
||||
tool_helpers.h \
|
||||
tool_ipfs.h \
|
||||
tool_libinfo.h \
|
||||
tool_main.h \
|
||||
tool_msgs.h \
|
||||
tool_operate.h \
|
||||
tool_operhlp.h \
|
||||
tool_paramhlp.h \
|
||||
tool_parsecfg.h \
|
||||
tool_progress.h \
|
||||
tool_sdecls.h \
|
||||
tool_setopt.h \
|
||||
tool_setup.h \
|
||||
tool_ssls.h \
|
||||
tool_stderr.h \
|
||||
tool_strdup.h \
|
||||
tool_urlglob.h \
|
||||
tool_util.h \
|
||||
tool_version.h \
|
||||
tool_vms.h \
|
||||
tool_writeout.h \
|
||||
tool_writeout_json.h \
|
||||
tool_xattr.h \
|
||||
var.h
|
||||
|
||||
CURL_RCFILES = curl.rc
|
||||
+1081
File diff suppressed because it is too large
Load Diff
+32
@@ -0,0 +1,32 @@
|
||||
#ifndef HEADER_CURL_CONFIG2SETOPTS_H
|
||||
#define HEADER_CURL_CONFIG2SETOPTS_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
CURLcode config2setopts(struct OperationConfig *config,
|
||||
struct per_transfer *per,
|
||||
CURL *curl,
|
||||
CURLSH *share);
|
||||
|
||||
#endif /* HEADER_CURL_CONFIG2SETOPTS_H */
|
||||
Vendored
+65
@@ -0,0 +1,65 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include <winver.h>
|
||||
#include "tool_version.h"
|
||||
|
||||
LANGUAGE 0, 0
|
||||
|
||||
#define RC_VERSION CURL_VERSION_MAJOR, CURL_VERSION_MINOR, CURL_VERSION_PATCH, 0
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION RC_VERSION
|
||||
PRODUCTVERSION RC_VERSION
|
||||
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
|
||||
#if defined(DEBUGBUILD) || defined(UNITTESTS) || defined(CURLDEBUG) || defined(_DEBUG)
|
||||
FILEFLAGS VS_FF_DEBUG
|
||||
#else
|
||||
FILEFLAGS 0L
|
||||
#endif
|
||||
FILEOS VOS__WINDOWS32
|
||||
FILETYPE VFT_APP
|
||||
FILESUBTYPE 0L
|
||||
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "curl, https://curl.se/\0"
|
||||
VALUE "FileDescription", "The curl executable\0"
|
||||
VALUE "FileVersion", CURL_VERSION "\0"
|
||||
VALUE "InternalName", "curl\0"
|
||||
VALUE "OriginalFilename", "curl.exe\0"
|
||||
VALUE "ProductName", "The curl executable\0"
|
||||
VALUE "ProductVersion", CURL_VERSION "\0"
|
||||
VALUE "LegalCopyright", "Copyright (C) " CURL_COPYRIGHT "\0"
|
||||
VALUE "License", "https://curl.se/docs/copyright.html\0"
|
||||
END
|
||||
END
|
||||
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
||||
Vendored
+253
@@ -0,0 +1,253 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/*
|
||||
* The purpose of this tool is to figure out which, if any, features that are
|
||||
* disabled which should otherwise exist and work. These are not visible in
|
||||
* regular curl -V output.
|
||||
*
|
||||
* Disabled protocols are visible in curl_version_info() and are not included
|
||||
* in this table.
|
||||
*/
|
||||
|
||||
#include "curl_setup.h"
|
||||
#include "multihandle.h" /* for ENABLE_WAKEUP */
|
||||
#include "tool_xattr.h" /* for USE_XATTR */
|
||||
#include "curl_sha512_256.h" /* for CURL_HAVE_SHA512_256 */
|
||||
#include "asyn.h" /* for CURLRES_ARES */
|
||||
#include "fake_addrinfo.h" /* for USE_FAKE_GETADDRINFO */
|
||||
#include <stdio.h>
|
||||
|
||||
static const char *disabled[]={
|
||||
"bindlocal: "
|
||||
#ifdef CURL_DISABLE_BINDLOCAL
|
||||
"OFF"
|
||||
#else
|
||||
"ON"
|
||||
#endif
|
||||
,
|
||||
|
||||
"cookies: "
|
||||
#ifdef CURL_DISABLE_COOKIES
|
||||
"OFF"
|
||||
#else
|
||||
"ON"
|
||||
#endif
|
||||
,
|
||||
|
||||
"basic-auth: "
|
||||
#ifdef CURL_DISABLE_BASIC_AUTH
|
||||
"OFF"
|
||||
#else
|
||||
"ON"
|
||||
#endif
|
||||
,
|
||||
"bearer-auth: "
|
||||
#ifdef CURL_DISABLE_BEARER_AUTH
|
||||
"OFF"
|
||||
#else
|
||||
"ON"
|
||||
#endif
|
||||
,
|
||||
"digest: "
|
||||
#ifdef CURL_DISABLE_DIGEST_AUTH
|
||||
"OFF"
|
||||
#else
|
||||
"ON"
|
||||
#endif
|
||||
,
|
||||
"negotiate-auth: "
|
||||
#ifdef CURL_DISABLE_NEGOTIATE_AUTH
|
||||
"OFF"
|
||||
#else
|
||||
"ON"
|
||||
#endif
|
||||
,
|
||||
"aws: "
|
||||
#ifdef CURL_DISABLE_AWS
|
||||
"OFF"
|
||||
#else
|
||||
"ON"
|
||||
#endif
|
||||
,
|
||||
"DoH: "
|
||||
#ifdef CURL_DISABLE_DOH
|
||||
"OFF"
|
||||
#else
|
||||
"ON"
|
||||
#endif
|
||||
,
|
||||
"HTTP-auth: "
|
||||
#ifdef CURL_DISABLE_HTTP_AUTH
|
||||
"OFF"
|
||||
#else
|
||||
"ON"
|
||||
#endif
|
||||
,
|
||||
"Mime: "
|
||||
#ifdef CURL_DISABLE_MIME
|
||||
"OFF"
|
||||
#else
|
||||
"ON"
|
||||
#endif
|
||||
,
|
||||
|
||||
"netrc: "
|
||||
#ifdef CURL_DISABLE_NETRC
|
||||
"OFF"
|
||||
#else
|
||||
"ON"
|
||||
#endif
|
||||
,
|
||||
"parsedate: "
|
||||
#ifdef CURL_DISABLE_PARSEDATE
|
||||
"OFF"
|
||||
#else
|
||||
"ON"
|
||||
#endif
|
||||
,
|
||||
"proxy: "
|
||||
#ifdef CURL_DISABLE_PROXY
|
||||
"OFF"
|
||||
#else
|
||||
"ON"
|
||||
#endif
|
||||
,
|
||||
"shuffle-dns: "
|
||||
#ifdef CURL_DISABLE_SHUFFLE_DNS
|
||||
"OFF"
|
||||
#else
|
||||
"ON"
|
||||
#endif
|
||||
,
|
||||
"typecheck: "
|
||||
#ifdef CURL_DISABLE_TYPECHECK
|
||||
"OFF"
|
||||
#else
|
||||
"ON"
|
||||
#endif
|
||||
,
|
||||
"verbose-strings: "
|
||||
#ifdef CURL_DISABLE_VERBOSE_STRINGS
|
||||
"OFF"
|
||||
#else
|
||||
"ON"
|
||||
#endif
|
||||
,
|
||||
"wakeup: "
|
||||
#ifndef ENABLE_WAKEUP
|
||||
"OFF"
|
||||
#else
|
||||
"ON"
|
||||
#endif
|
||||
,
|
||||
"headers-api: "
|
||||
#ifdef CURL_DISABLE_HEADERS_API
|
||||
"OFF"
|
||||
#else
|
||||
"ON"
|
||||
#endif
|
||||
,
|
||||
"xattr: "
|
||||
#ifndef USE_XATTR
|
||||
"OFF"
|
||||
#else
|
||||
"ON"
|
||||
#endif
|
||||
,
|
||||
"form-api: "
|
||||
#ifdef CURL_DISABLE_FORM_API
|
||||
"OFF"
|
||||
#else
|
||||
"ON"
|
||||
#endif
|
||||
,
|
||||
"large-time: "
|
||||
#if (SIZEOF_TIME_T < 5)
|
||||
"OFF"
|
||||
#else
|
||||
"ON"
|
||||
#endif
|
||||
,
|
||||
"large-size: "
|
||||
#if (SIZEOF_SIZE_T < 5)
|
||||
"OFF"
|
||||
#else
|
||||
"ON"
|
||||
#endif
|
||||
,
|
||||
"sha512-256: "
|
||||
#ifndef CURL_HAVE_SHA512_256
|
||||
"OFF"
|
||||
#else
|
||||
"ON"
|
||||
#endif
|
||||
,
|
||||
|
||||
"win32-ca-searchpath: "
|
||||
#if !defined(_WIN32) || \
|
||||
(defined(CURL_WINDOWS_UWP) || \
|
||||
defined(CURL_DISABLE_CA_SEARCH) || defined(CURL_CA_SEARCH_SAFE))
|
||||
"OFF"
|
||||
#else
|
||||
"ON"
|
||||
#endif
|
||||
,
|
||||
"win32-ca-search-safe: "
|
||||
#if !defined(_WIN32) || !defined(CURL_CA_SEARCH_SAFE)
|
||||
"OFF"
|
||||
#else
|
||||
"ON"
|
||||
#endif
|
||||
,
|
||||
|
||||
"--libcurl: "
|
||||
#ifdef CURL_DISABLE_LIBCURL_OPTION
|
||||
"OFF"
|
||||
#else
|
||||
"ON"
|
||||
#endif
|
||||
,
|
||||
"override-dns: "
|
||||
#if defined(CURLDEBUG) && \
|
||||
(defined(CURLRES_ARES) || defined(USE_FAKE_GETADDRINFO))
|
||||
"ON"
|
||||
#else
|
||||
"OFF"
|
||||
#endif
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
for(i = 0; i < CURL_ARRAYSIZE(disabled); i++)
|
||||
/* !checksrc! disable BANNEDFUNC 1 */
|
||||
printf("%s\n", disabled[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env perl
|
||||
#***************************************************************************
|
||||
# _ _ ____ _
|
||||
# Project ___| | | | _ \| |
|
||||
# / __| | | | |_) | |
|
||||
# | (__| |_| | _ <| |___
|
||||
# \___|\___/|_| \_\_____|
|
||||
#
|
||||
# Copyright (C) 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.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.
|
||||
#
|
||||
# SPDX-License-Identifier: curl
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
my $varname = "var";
|
||||
if(@ARGV && $ARGV[0] eq "--var") {
|
||||
shift;
|
||||
$varname = shift @ARGV;
|
||||
}
|
||||
|
||||
my $varname_upper = uc($varname);
|
||||
|
||||
print <<HEAD
|
||||
/*
|
||||
* NEVER EVER edit this manually, fix the mk-file-embed.pl script instead!
|
||||
*/
|
||||
/* !checksrc! disable COPYRIGHT all */
|
||||
#ifndef CURL_DECLARED_${varname_upper}
|
||||
#define CURL_DECLARED_${varname_upper}
|
||||
extern const unsigned char ${varname}[];
|
||||
#endif
|
||||
const unsigned char ${varname}[] = {
|
||||
HEAD
|
||||
;
|
||||
|
||||
while(<STDIN>) {
|
||||
my $line = $_;
|
||||
foreach my $n (split //, $line) {
|
||||
my $ord = ord($n);
|
||||
printf("%s,", $ord);
|
||||
if($ord == 10) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
print <<ENDLINE
|
||||
0
|
||||
};
|
||||
ENDLINE
|
||||
;
|
||||
Vendored
+262
@@ -0,0 +1,262 @@
|
||||
#!/usr/bin/env perl
|
||||
#***************************************************************************
|
||||
# _ _ ____ _
|
||||
# Project ___| | | | _ \| |
|
||||
# / __| | | | |_) | |
|
||||
# | (__| |_| | _ <| |___
|
||||
# \___|\___/|_| \_\_____|
|
||||
#
|
||||
# Copyright (C) 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.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.
|
||||
#
|
||||
# SPDX-License-Identifier: curl
|
||||
#
|
||||
###########################################################################
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
my $c = 0;
|
||||
if(@ARGV && $ARGV[0] eq "-c") {
|
||||
$c = 1;
|
||||
shift @ARGV;
|
||||
}
|
||||
|
||||
my @out;
|
||||
|
||||
push @out, " _ _ ____ _\n";
|
||||
push @out, " ___| | | | _ \\| |\n";
|
||||
push @out, " / __| | | | |_) | |\n";
|
||||
push @out, " | (__| |_| | _ <| |___\n";
|
||||
push @out, " \\___|\\___/|_| \\_\\_____|\n";
|
||||
|
||||
while(<STDIN>) {
|
||||
my $line = $_;
|
||||
push @out, $line;
|
||||
}
|
||||
|
||||
print <<HEAD
|
||||
/*
|
||||
* NEVER EVER edit this manually, fix the mkhelp.pl script instead!
|
||||
*/
|
||||
#include "tool_hugehelp.h"
|
||||
#ifdef USE_MANUAL
|
||||
#include "tool_help.h"
|
||||
|
||||
HEAD
|
||||
;
|
||||
if($c) {
|
||||
# If compression requested, check that the Gzip module is available
|
||||
# or else disable compression
|
||||
$c = eval
|
||||
{
|
||||
require IO::Compress::Gzip;
|
||||
IO::Compress::Gzip->import();
|
||||
1;
|
||||
};
|
||||
print STDERR "Warning: compression requested but Gzip is not available\n" if(!$c)
|
||||
}
|
||||
|
||||
if($c)
|
||||
{
|
||||
my $content = join("", @out);
|
||||
my $gzippedContent;
|
||||
IO::Compress::Gzip::gzip(
|
||||
\$content, \$gzippedContent, Level => 9, TextFlag => 1, Time=>0) or die "gzip failed:";
|
||||
my $gzip = length($content);
|
||||
my $gzipped = length($gzippedContent);
|
||||
|
||||
print <<HEAD
|
||||
#include <zlib.h>
|
||||
#include <memdebug.h> /* keep this as LAST include */
|
||||
static const unsigned char hugehelpgz[] = {
|
||||
/* This mumbo-jumbo is the huge help text compressed with gzip.
|
||||
Thanks to this operation, the size of this data shrank from $gzip
|
||||
to $gzipped bytes. You can disable the use of compressed help
|
||||
texts by NOT passing -c to the mkhelp.pl tool. */
|
||||
HEAD
|
||||
;
|
||||
|
||||
my $c=0;
|
||||
for(split(//, $gzippedContent)) {
|
||||
my $num=ord($_);
|
||||
if(!($c % 12)) {
|
||||
print " ";
|
||||
}
|
||||
printf(" 0x%02x,", 0+$num);
|
||||
if(!(++$c % 12)) {
|
||||
print "\n";
|
||||
}
|
||||
}
|
||||
print "\n};\n";
|
||||
|
||||
print <<EOF
|
||||
#define BUF_SIZE 0x10000
|
||||
static voidpf zalloc_func(voidpf opaque, unsigned int items, unsigned int size)
|
||||
{
|
||||
(void)opaque;
|
||||
/* not a typo, keep it calloc() */
|
||||
return (voidpf) calloc(items, size);
|
||||
}
|
||||
static void zfree_func(voidpf opaque, voidpf ptr)
|
||||
{
|
||||
(void)opaque;
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
#define HEADERLEN 10
|
||||
|
||||
/* Decompress and send to stdout a gzip-compressed buffer */
|
||||
void hugehelp(void)
|
||||
{
|
||||
unsigned char *buf;
|
||||
int status;
|
||||
z_stream z;
|
||||
|
||||
/* Make sure no gzip options are set */
|
||||
if(hugehelpgz[3] & 0xfe)
|
||||
return;
|
||||
|
||||
memset(&z, 0, sizeof(z_stream));
|
||||
z.zalloc = (alloc_func)zalloc_func;
|
||||
z.zfree = (free_func)zfree_func;
|
||||
z.avail_in = (uInt)(sizeof(hugehelpgz) - HEADERLEN);
|
||||
z.next_in = (z_const Bytef *)hugehelpgz + HEADERLEN;
|
||||
|
||||
if(inflateInit2(&z, -MAX_WBITS) != Z_OK)
|
||||
return;
|
||||
|
||||
buf = malloc(BUF_SIZE);
|
||||
if(buf) {
|
||||
while(1) {
|
||||
z.avail_out = BUF_SIZE;
|
||||
z.next_out = buf;
|
||||
status = inflate(&z, Z_SYNC_FLUSH);
|
||||
if(status == Z_OK || status == Z_STREAM_END) {
|
||||
fwrite(buf, BUF_SIZE - z.avail_out, 1, stdout);
|
||||
if(status == Z_STREAM_END)
|
||||
break;
|
||||
}
|
||||
else
|
||||
break; /* error */
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
inflateEnd(&z);
|
||||
}
|
||||
/* Show the help text for the 'arg' curl argument on stdout */
|
||||
void showhelp(const char *trigger, const char *arg, const char *endarg)
|
||||
{
|
||||
unsigned char *buf;
|
||||
int status;
|
||||
z_stream z;
|
||||
struct scan_ctx ctx;
|
||||
inithelpscan(&ctx, trigger, arg, endarg);
|
||||
|
||||
/* Make sure no gzip options are set */
|
||||
if(hugehelpgz[3] & 0xfe)
|
||||
return;
|
||||
|
||||
memset(&z, 0, sizeof(z_stream));
|
||||
z.zalloc = (alloc_func)zalloc_func;
|
||||
z.zfree = (free_func)zfree_func;
|
||||
z.avail_in = (uInt)(sizeof(hugehelpgz) - HEADERLEN);
|
||||
z.next_in = (z_const Bytef *)hugehelpgz + HEADERLEN;
|
||||
|
||||
if(inflateInit2(&z, -MAX_WBITS) != Z_OK)
|
||||
return;
|
||||
|
||||
buf = malloc(BUF_SIZE);
|
||||
if(buf) {
|
||||
while(1) {
|
||||
z.avail_out = BUF_SIZE;
|
||||
z.next_out = buf;
|
||||
status = inflate(&z, Z_SYNC_FLUSH);
|
||||
if(status == Z_OK || status == Z_STREAM_END) {
|
||||
size_t len = BUF_SIZE - z.avail_out;
|
||||
if(!helpscan(buf, len, &ctx))
|
||||
break;
|
||||
if(status == Z_STREAM_END)
|
||||
break;
|
||||
}
|
||||
else
|
||||
break; /* error */
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
inflateEnd(&z);
|
||||
}
|
||||
EOF
|
||||
;
|
||||
foot();
|
||||
exit;
|
||||
}
|
||||
else {
|
||||
print <<HEAD
|
||||
static const char * const curlman[] = {
|
||||
HEAD
|
||||
;
|
||||
}
|
||||
|
||||
my $blank;
|
||||
for my $n (@out) {
|
||||
chomp $n;
|
||||
$n =~ s/\\/\\\\/g;
|
||||
$n =~ s/\"/\\\"/g;
|
||||
$n =~ s/\t/\\t/g;
|
||||
|
||||
if(!$n) {
|
||||
$blank++;
|
||||
}
|
||||
else {
|
||||
$n =~ s/ /\\t/g;
|
||||
printf(" \"%s%s\",\n", $blank?"\\n":"", $n);
|
||||
$blank = 0;
|
||||
}
|
||||
}
|
||||
|
||||
print <<ENDLINE
|
||||
NULL
|
||||
};
|
||||
void hugehelp(void)
|
||||
{
|
||||
int i = 0;
|
||||
while(curlman[i])
|
||||
puts(curlman[i++]);
|
||||
}
|
||||
|
||||
/* Show the help text for the 'arg' curl argument on stdout */
|
||||
void showhelp(const char *trigger, const char *arg, const char *endarg)
|
||||
{
|
||||
int i = 0;
|
||||
struct scan_ctx ctx;
|
||||
inithelpscan(&ctx, trigger, arg, endarg);
|
||||
while(curlman[i]) {
|
||||
size_t len = strlen(curlman[i]);
|
||||
if(!helpscan((const unsigned char *)curlman[i], len, &ctx) ||
|
||||
!helpscan((const unsigned char *)"\\n", 1, &ctx))
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
ENDLINE
|
||||
;
|
||||
|
||||
foot();
|
||||
|
||||
sub foot {
|
||||
print <<FOOT
|
||||
#endif /* USE_MANUAL */
|
||||
FOOT
|
||||
;
|
||||
}
|
||||
Vendored
+74
@@ -0,0 +1,74 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include "tool_setup.h"
|
||||
|
||||
#ifndef CURL_DISABLE_LIBCURL_OPTION
|
||||
|
||||
#include "slist_wc.h"
|
||||
|
||||
/* The last #include files should be: */
|
||||
#include "memdebug.h"
|
||||
|
||||
/*
|
||||
* slist_wc_append() appends a string to the linked list. This function can be
|
||||
* used as an initialization function as well as an append function.
|
||||
*/
|
||||
struct slist_wc *slist_wc_append(struct slist_wc *list,
|
||||
const char *data)
|
||||
{
|
||||
struct curl_slist *new_item = curl_slist_append(NULL, data);
|
||||
|
||||
if(!new_item)
|
||||
return NULL;
|
||||
|
||||
if(!list) {
|
||||
list = malloc(sizeof(struct slist_wc));
|
||||
|
||||
if(!list) {
|
||||
curl_slist_free_all(new_item);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list->first = new_item;
|
||||
list->last = new_item;
|
||||
return list;
|
||||
}
|
||||
|
||||
list->last->next = new_item;
|
||||
list->last = list->last->next;
|
||||
return list;
|
||||
}
|
||||
|
||||
/* be nice and clean up resources */
|
||||
void slist_wc_free_all(struct slist_wc *list)
|
||||
{
|
||||
if(!list)
|
||||
return;
|
||||
|
||||
curl_slist_free_all(list->first);
|
||||
free(list);
|
||||
}
|
||||
|
||||
#endif /* CURL_DISABLE_LIBCURL_OPTION */
|
||||
Vendored
+57
@@ -0,0 +1,57 @@
|
||||
#ifndef HEADER_CURL_SLIST_WC_H
|
||||
#define HEADER_CURL_SLIST_WC_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include "tool_setup.h"
|
||||
#ifndef CURL_DISABLE_LIBCURL_OPTION
|
||||
|
||||
/* linked-list structure with last node cache for easysrc */
|
||||
struct slist_wc {
|
||||
struct curl_slist *first;
|
||||
struct curl_slist *last;
|
||||
};
|
||||
|
||||
/*
|
||||
* NAME curl_slist_wc_append()
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* Appends a string to a linked list. If no list exists, it will be created
|
||||
* first. Returns the new list, after appending.
|
||||
*/
|
||||
struct slist_wc *slist_wc_append(struct slist_wc *, const char *);
|
||||
|
||||
/*
|
||||
* NAME curl_slist_free_all()
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* free a previously built curl_slist_wc.
|
||||
*/
|
||||
void slist_wc_free_all(struct slist_wc *);
|
||||
|
||||
#endif /* CURL_DISABLE_LIBCURL_OPTION */
|
||||
|
||||
#endif /* HEADER_CURL_SLIST_WC_H */
|
||||
Vendored
+89
@@ -0,0 +1,89 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#include "terminal.h"
|
||||
#include "memdebug.h" /* keep this as LAST include */
|
||||
|
||||
#ifdef HAVE_TERMIOS_H
|
||||
# include <termios.h>
|
||||
#elif defined(HAVE_TERMIO_H)
|
||||
# include <termio.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* get_terminal_columns() returns the number of columns in the current
|
||||
* terminal. It will return 79 on failure. Also, the number can be big.
|
||||
*/
|
||||
|
||||
unsigned int get_terminal_columns(void)
|
||||
{
|
||||
unsigned int width = 0;
|
||||
char *colp = curl_getenv("COLUMNS");
|
||||
if(colp) {
|
||||
curl_off_t num;
|
||||
const char *p = colp;
|
||||
if(!curlx_str_number(&p, &num, 10000) && (num > 20))
|
||||
width = (unsigned int)num;
|
||||
curl_free(colp);
|
||||
}
|
||||
|
||||
if(!width) {
|
||||
int cols = 0;
|
||||
|
||||
#ifdef TIOCGSIZE
|
||||
struct ttysize ts;
|
||||
if(!ioctl(STDIN_FILENO, TIOCGSIZE, &ts))
|
||||
cols = ts.ts_cols;
|
||||
#elif defined(TIOCGWINSZ)
|
||||
struct winsize ts;
|
||||
if(!ioctl(STDIN_FILENO, TIOCGWINSZ, &ts))
|
||||
cols = (int)ts.ws_col;
|
||||
#elif defined(_WIN32) && !defined(CURL_WINDOWS_UWP) && !defined(UNDER_CE)
|
||||
{
|
||||
HANDLE stderr_hnd = GetStdHandle(STD_ERROR_HANDLE);
|
||||
CONSOLE_SCREEN_BUFFER_INFO console_info;
|
||||
|
||||
if((stderr_hnd != INVALID_HANDLE_VALUE) &&
|
||||
GetConsoleScreenBufferInfo(stderr_hnd, &console_info)) {
|
||||
/*
|
||||
* Do not use +1 to get the true screen-width since writing a
|
||||
* character at the right edge will cause a line wrap.
|
||||
*/
|
||||
cols = (int)
|
||||
(console_info.srWindow.Right - console_info.srWindow.Left);
|
||||
}
|
||||
}
|
||||
#endif /* TIOCGSIZE */
|
||||
if(cols >= 0 && cols < 10000)
|
||||
width = (unsigned int)cols;
|
||||
}
|
||||
if(!width)
|
||||
width = 79;
|
||||
return width; /* 79 for unknown, might also be tiny or enormous */
|
||||
}
|
||||
Vendored
+30
@@ -0,0 +1,30 @@
|
||||
#ifndef HEADER_CURL_TERMINAL_H
|
||||
#define HEADER_CURL_TERMINAL_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
unsigned int get_terminal_columns(void);
|
||||
|
||||
#endif /* HEADER_CURL_TERMINAL_H */
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#include "tool_bname.h"
|
||||
|
||||
#include "memdebug.h" /* keep this as LAST include */
|
||||
|
||||
#ifndef HAVE_BASENAME
|
||||
|
||||
char *tool_basename(char *path)
|
||||
{
|
||||
char *s1;
|
||||
char *s2;
|
||||
|
||||
s1 = strrchr(path, '/');
|
||||
s2 = strrchr(path, '\\');
|
||||
|
||||
if(s1 && s2) {
|
||||
path = (s1 > s2) ? s1 + 1 : s2 + 1;
|
||||
}
|
||||
else if(s1)
|
||||
path = s1 + 1;
|
||||
else if(s2)
|
||||
path = s2 + 1;
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
#endif /* HAVE_BASENAME */
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
#ifndef HEADER_CURL_TOOL_BNAME_H
|
||||
#define HEADER_CURL_TOOL_BNAME_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#ifndef HAVE_BASENAME
|
||||
|
||||
char *tool_basename(char *path);
|
||||
|
||||
#define basename(x) tool_basename((x))
|
||||
|
||||
#endif /* HAVE_BASENAME */
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_BNAME_H */
|
||||
+286
@@ -0,0 +1,286 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#include "tool_cfgable.h"
|
||||
#include "tool_msgs.h"
|
||||
#include "tool_cb_dbg.h"
|
||||
#include "tool_util.h"
|
||||
|
||||
#include "memdebug.h" /* keep this as LAST include */
|
||||
|
||||
static void dump(const char *timebuf, const char *idsbuf, const char *text,
|
||||
FILE *stream, const unsigned char *ptr, size_t size,
|
||||
trace tracetype, curl_infotype infotype);
|
||||
|
||||
/*
|
||||
* Return the formatted HH:MM:SS for the tv_sec given.
|
||||
* NOT thread safe.
|
||||
*/
|
||||
static const char *hms_for_sec(time_t tv_sec)
|
||||
{
|
||||
static time_t cached_tv_sec;
|
||||
static char hms_buf[12];
|
||||
|
||||
if(tv_sec != cached_tv_sec) {
|
||||
/* !checksrc! disable BANNEDFUNC 1 */
|
||||
struct tm *now = localtime(&tv_sec); /* not thread safe either */
|
||||
curl_msnprintf(hms_buf, sizeof(hms_buf), "%02d:%02d:%02d",
|
||||
now->tm_hour, now->tm_min, now->tm_sec);
|
||||
cached_tv_sec = tv_sec;
|
||||
}
|
||||
return hms_buf;
|
||||
}
|
||||
|
||||
static void log_line_start(FILE *log, const char *timebuf,
|
||||
const char *idsbuf, curl_infotype type)
|
||||
{
|
||||
/*
|
||||
* This is the trace look that is similar to what libcurl makes on its
|
||||
* own.
|
||||
*/
|
||||
static const char * const s_infotype[] = {
|
||||
"* ", "< ", "> ", "{ ", "} ", "{ ", "} "
|
||||
};
|
||||
if((timebuf && *timebuf) || (idsbuf && *idsbuf))
|
||||
curl_mfprintf(log, "%s%s%s", timebuf, idsbuf, s_infotype[type]);
|
||||
else
|
||||
fputs(s_infotype[type], log);
|
||||
}
|
||||
|
||||
#define TRC_IDS_FORMAT_IDS_1 "[%" CURL_FORMAT_CURL_OFF_T "-x] "
|
||||
#define TRC_IDS_FORMAT_IDS_2 "[%" CURL_FORMAT_CURL_OFF_T "-%" \
|
||||
CURL_FORMAT_CURL_OFF_T "] "
|
||||
/*
|
||||
** callback for CURLOPT_DEBUGFUNCTION
|
||||
*/
|
||||
int tool_debug_cb(CURL *handle, curl_infotype type,
|
||||
char *data, size_t size,
|
||||
void *userdata)
|
||||
{
|
||||
FILE *output = tool_stderr;
|
||||
const char *text;
|
||||
struct timeval tv;
|
||||
char timebuf[20];
|
||||
/* largest signed 64-bit is: 9,223,372,036,854,775,807
|
||||
* max length in decimal: 1 + (6*3) = 19
|
||||
* formatted via TRC_IDS_FORMAT_IDS_2 this becomes 2 + 19 + 1 + 19 + 2 = 43
|
||||
* negative xfer-id are not printed, negative conn-ids use TRC_IDS_FORMAT_1
|
||||
*/
|
||||
char idsbuf[60];
|
||||
curl_off_t xfer_id, conn_id;
|
||||
|
||||
(void)handle;
|
||||
(void)userdata;
|
||||
|
||||
if(global->tracetime) {
|
||||
tv = tvrealnow();
|
||||
curl_msnprintf(timebuf, sizeof(timebuf), "%s.%06ld ",
|
||||
hms_for_sec(tv.tv_sec), (long)tv.tv_usec);
|
||||
}
|
||||
else
|
||||
timebuf[0] = 0;
|
||||
|
||||
if(handle && global->traceids &&
|
||||
!curl_easy_getinfo(handle, CURLINFO_XFER_ID, &xfer_id) && xfer_id >= 0) {
|
||||
if(!curl_easy_getinfo(handle, CURLINFO_CONN_ID, &conn_id) &&
|
||||
conn_id >= 0) {
|
||||
curl_msnprintf(idsbuf, sizeof(idsbuf), TRC_IDS_FORMAT_IDS_2,
|
||||
xfer_id, conn_id);
|
||||
}
|
||||
else {
|
||||
curl_msnprintf(idsbuf, sizeof(idsbuf), TRC_IDS_FORMAT_IDS_1, xfer_id);
|
||||
}
|
||||
}
|
||||
else
|
||||
idsbuf[0] = 0;
|
||||
|
||||
if(!global->trace_stream) {
|
||||
/* open for append */
|
||||
if(!strcmp("-", global->trace_dump))
|
||||
global->trace_stream = stdout;
|
||||
else if(!strcmp("%", global->trace_dump))
|
||||
/* Ok, this is somewhat hackish but we do it undocumented for now */
|
||||
global->trace_stream = tool_stderr;
|
||||
else {
|
||||
global->trace_stream = curlx_fopen(global->trace_dump, FOPEN_WRITETEXT);
|
||||
global->trace_fopened = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if(global->trace_stream)
|
||||
output = global->trace_stream;
|
||||
|
||||
if(!output) {
|
||||
warnf("Failed to create/open output");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(global->tracetype == TRACE_PLAIN) {
|
||||
static bool newl = FALSE;
|
||||
static bool traced_data = FALSE;
|
||||
|
||||
switch(type) {
|
||||
case CURLINFO_HEADER_OUT:
|
||||
if(size > 0) {
|
||||
size_t st = 0;
|
||||
size_t i;
|
||||
for(i = 0; i < size - 1; i++) {
|
||||
if(data[i] == '\n') { /* LF */
|
||||
if(!newl) {
|
||||
log_line_start(output, timebuf, idsbuf, type);
|
||||
}
|
||||
(void)fwrite(data + st, i - st + 1, 1, output);
|
||||
st = i + 1;
|
||||
newl = FALSE;
|
||||
}
|
||||
}
|
||||
if(!newl)
|
||||
log_line_start(output, timebuf, idsbuf, type);
|
||||
(void)fwrite(data + st, i - st + 1, 1, output);
|
||||
}
|
||||
newl = (size && (data[size - 1] != '\n'));
|
||||
traced_data = FALSE;
|
||||
break;
|
||||
case CURLINFO_TEXT:
|
||||
case CURLINFO_HEADER_IN:
|
||||
if(!newl)
|
||||
log_line_start(output, timebuf, idsbuf, type);
|
||||
(void)fwrite(data, size, 1, output);
|
||||
newl = (size && (data[size - 1] != '\n'));
|
||||
traced_data = FALSE;
|
||||
break;
|
||||
case CURLINFO_DATA_OUT:
|
||||
case CURLINFO_DATA_IN:
|
||||
case CURLINFO_SSL_DATA_IN:
|
||||
case CURLINFO_SSL_DATA_OUT:
|
||||
if(!traced_data) {
|
||||
/* if the data is output to a tty and we are sending this debug trace
|
||||
to stderr or stdout, we do not display the alert about the data not
|
||||
being shown as the data _is_ shown then just not via this
|
||||
function */
|
||||
if(!global->isatty ||
|
||||
((output != tool_stderr) && (output != stdout))) {
|
||||
if(!newl)
|
||||
log_line_start(output, timebuf, idsbuf, type);
|
||||
curl_mfprintf(output, "[%zu bytes data]\n", size);
|
||||
newl = FALSE;
|
||||
traced_data = TRUE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default: /* nada */
|
||||
newl = FALSE;
|
||||
traced_data = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch(type) {
|
||||
case CURLINFO_TEXT:
|
||||
curl_mfprintf(output, "%s%s* %.*s", timebuf, idsbuf, (int)size, data);
|
||||
FALLTHROUGH();
|
||||
default: /* in case a new one is introduced to shock us */
|
||||
return 0;
|
||||
|
||||
case CURLINFO_HEADER_OUT:
|
||||
text = "=> Send header";
|
||||
break;
|
||||
case CURLINFO_DATA_OUT:
|
||||
text = "=> Send data";
|
||||
break;
|
||||
case CURLINFO_HEADER_IN:
|
||||
text = "<= Recv header";
|
||||
break;
|
||||
case CURLINFO_DATA_IN:
|
||||
text = "<= Recv data";
|
||||
break;
|
||||
case CURLINFO_SSL_DATA_IN:
|
||||
text = "<= Recv SSL data";
|
||||
break;
|
||||
case CURLINFO_SSL_DATA_OUT:
|
||||
text = "=> Send SSL data";
|
||||
break;
|
||||
}
|
||||
|
||||
dump(timebuf, idsbuf, text, output, (unsigned char *) data, size,
|
||||
global->tracetype, type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dump(const char *timebuf, const char *idsbuf, const char *text,
|
||||
FILE *stream, const unsigned char *ptr, size_t size,
|
||||
trace tracetype, curl_infotype infotype)
|
||||
{
|
||||
size_t i;
|
||||
size_t c;
|
||||
|
||||
unsigned int width = 0x10;
|
||||
|
||||
if(tracetype == TRACE_ASCII)
|
||||
/* without the hex output, we can fit more on screen */
|
||||
width = 0x40;
|
||||
|
||||
curl_mfprintf(stream, "%s%s%s, %zu bytes (0x%zx)\n", timebuf, idsbuf,
|
||||
text, size, size);
|
||||
|
||||
for(i = 0; i < size; i += width) {
|
||||
|
||||
curl_mfprintf(stream, "%04zx: ", i);
|
||||
|
||||
if(tracetype == TRACE_BIN) {
|
||||
/* hex not disabled, show it */
|
||||
for(c = 0; c < width; c++)
|
||||
if(i + c < size)
|
||||
curl_mfprintf(stream, "%02x ", ptr[i + c]);
|
||||
else
|
||||
fputs(" ", stream);
|
||||
}
|
||||
|
||||
for(c = 0; (c < width) && (i + c < size); c++) {
|
||||
/* check for 0D0A; if found, skip past and start a new line of output */
|
||||
if((tracetype == TRACE_ASCII) &&
|
||||
(i + c + 1 < size) && (ptr[i + c] == 0x0D) &&
|
||||
(ptr[i + c + 1] == 0x0A)) {
|
||||
i += (c + 2 - width);
|
||||
break;
|
||||
}
|
||||
(void)infotype;
|
||||
curl_mfprintf(stream, "%c",
|
||||
((ptr[i + c] >= 0x20) && (ptr[i + c] < 0x7F)) ?
|
||||
ptr[i + c] : UNPRINTABLE_CHAR);
|
||||
/* check again for 0D0A, to avoid an extra \n if it is at width */
|
||||
if((tracetype == TRACE_ASCII) &&
|
||||
(i + c + 2 < size) && (ptr[i + c + 1] == 0x0D) &&
|
||||
(ptr[i + c + 2] == 0x0A)) {
|
||||
i += (c + 3 - width);
|
||||
break;
|
||||
}
|
||||
}
|
||||
fputc('\n', stream); /* newline */
|
||||
}
|
||||
fflush(stream);
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
#ifndef HEADER_CURL_TOOL_CB_DBG_H
|
||||
#define HEADER_CURL_TOOL_CB_DBG_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
/*
|
||||
** callback for CURLOPT_DEBUGFUNCTION
|
||||
*/
|
||||
|
||||
int tool_debug_cb(CURL *handle, curl_infotype type,
|
||||
char *data, size_t size,
|
||||
void *userdata);
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_CB_DBG_H */
|
||||
+485
@@ -0,0 +1,485 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "tool_cfgable.h"
|
||||
#include "tool_doswin.h"
|
||||
#include "tool_msgs.h"
|
||||
#include "tool_cb_hdr.h"
|
||||
#include "tool_cb_wrt.h"
|
||||
#include "tool_operate.h"
|
||||
#include "tool_libinfo.h"
|
||||
#include "tool_strdup.h"
|
||||
|
||||
#include "memdebug.h" /* keep this as LAST include */
|
||||
|
||||
static char *parse_filename(const char *ptr, size_t len);
|
||||
|
||||
#ifdef _WIN32
|
||||
#define BOLD "\x1b[1m"
|
||||
#define BOLDOFF "\x1b[22m"
|
||||
#else
|
||||
#define BOLD "\x1b[1m"
|
||||
/* Switch off bold by setting "all attributes off" since the explicit
|
||||
bold-off code (21) is not supported everywhere - like in the mac
|
||||
Terminal. */
|
||||
#define BOLDOFF "\x1b[0m"
|
||||
/* OSC 8 hyperlink escape sequence */
|
||||
#define LINK "\x1b]8;;"
|
||||
#define LINKST "\x1b\\"
|
||||
#define LINKOFF LINK LINKST
|
||||
#endif
|
||||
|
||||
#ifdef LINK
|
||||
static void write_linked_location(CURL *curl, const char *location,
|
||||
size_t loclen, FILE *stream);
|
||||
#endif
|
||||
|
||||
int tool_write_headers(struct HdrCbData *hdrcbdata, FILE *stream)
|
||||
{
|
||||
struct curl_slist *h = hdrcbdata->headlist;
|
||||
int rc = 1;
|
||||
while(h) {
|
||||
/* not "handled", just show it */
|
||||
size_t len = strlen(h->data);
|
||||
if(len != fwrite(h->data, 1, len, stream))
|
||||
goto fail;
|
||||
h = h->next;
|
||||
}
|
||||
rc = 0; /* success */
|
||||
fail:
|
||||
curl_slist_free_all(hdrcbdata->headlist);
|
||||
hdrcbdata->headlist = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** callback for CURLOPT_HEADERFUNCTION
|
||||
*
|
||||
* 'size' is always 1
|
||||
*/
|
||||
size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata)
|
||||
{
|
||||
struct per_transfer *per = userdata;
|
||||
struct HdrCbData *hdrcbdata = &per->hdrcbdata;
|
||||
struct OutStruct *outs = &per->outs;
|
||||
struct OutStruct *heads = &per->heads;
|
||||
struct OutStruct *etag_save = &per->etag_save;
|
||||
const char *str = ptr;
|
||||
const size_t cb = size * nmemb;
|
||||
const char *end = (char *)ptr + cb;
|
||||
const char *scheme = NULL;
|
||||
|
||||
if(!per->config)
|
||||
return CURL_WRITEFUNC_ERROR;
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
if(size * nmemb > (size_t)CURL_MAX_HTTP_HEADER) {
|
||||
warnf("Header data exceeds write limit");
|
||||
return CURL_WRITEFUNC_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
/* Discard incomplete UTF-8 sequence buffered from body */
|
||||
if(outs->utf8seq[0])
|
||||
memset(outs->utf8seq, 0, sizeof(outs->utf8seq));
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Write header data when curl option --dump-header (-D) is given.
|
||||
*/
|
||||
|
||||
if(per->config->headerfile && heads->stream) {
|
||||
size_t rc = fwrite(ptr, size, nmemb, heads->stream);
|
||||
if(rc != nmemb)
|
||||
return rc;
|
||||
/* flush the stream to send off what we got earlier */
|
||||
if(fflush(heads->stream)) {
|
||||
errorf("Failed writing headers to %s", per->config->headerfile);
|
||||
return CURL_WRITEFUNC_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
curl_easy_getinfo(per->curl, CURLINFO_SCHEME, &scheme);
|
||||
scheme = proto_token(scheme);
|
||||
if((scheme == proto_http || scheme == proto_https)) {
|
||||
long response = 0;
|
||||
curl_easy_getinfo(per->curl, CURLINFO_RESPONSE_CODE, &response);
|
||||
|
||||
if((response/100 != 2) && (response/100 != 3))
|
||||
/* only care about etag and content-disposition headers in 2xx and 3xx
|
||||
responses */
|
||||
;
|
||||
/*
|
||||
* Write etag to file when --etag-save option is given.
|
||||
*/
|
||||
else if(per->config->etag_save_file && etag_save->stream &&
|
||||
/* match only header that start with etag (case insensitive) */
|
||||
checkprefix("etag:", str)) {
|
||||
const char *etag_h = &str[5];
|
||||
const char *eot = end - 1;
|
||||
if(*eot == '\n') {
|
||||
while(ISBLANK(*etag_h) && (etag_h < eot))
|
||||
etag_h++;
|
||||
while(ISSPACE(*eot))
|
||||
eot--;
|
||||
|
||||
if(eot >= etag_h) {
|
||||
size_t etag_length = eot - etag_h + 1;
|
||||
/*
|
||||
* Truncate the etag save stream, it can have an existing etag value.
|
||||
*/
|
||||
#if defined(HAVE_FTRUNCATE) && !defined(__MINGW32CE__)
|
||||
if(ftruncate(fileno(etag_save->stream), 0)) {
|
||||
return CURL_WRITEFUNC_ERROR;
|
||||
}
|
||||
#else
|
||||
if(fseek(etag_save->stream, 0, SEEK_SET)) {
|
||||
return CURL_WRITEFUNC_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
fwrite(etag_h, 1, etag_length, etag_save->stream);
|
||||
/* terminate with newline */
|
||||
fputc('\n', etag_save->stream);
|
||||
(void)fflush(etag_save->stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This callback sets the filename where output shall be written when
|
||||
* curl options --remote-name (-O) and --remote-header-name (-J) have
|
||||
* been simultaneously given and additionally server returns an HTTP
|
||||
* Content-Disposition header specifying a filename property.
|
||||
*/
|
||||
|
||||
else if(hdrcbdata->honor_cd_filename) {
|
||||
if((cb > 20) && checkprefix("Content-disposition:", str)) {
|
||||
const char *p = str + 20;
|
||||
|
||||
/* look for the 'filename=' parameter
|
||||
(encoded filenames (*=) are not supported) */
|
||||
for(;;) {
|
||||
char *filename;
|
||||
size_t len;
|
||||
|
||||
while((p < end) && *p && !ISALPHA(*p))
|
||||
p++;
|
||||
if(p > end - 9)
|
||||
break;
|
||||
|
||||
if(memcmp(p, "filename=", 9)) {
|
||||
/* no match, find next parameter */
|
||||
while((p < end) && *p && (*p != ';'))
|
||||
p++;
|
||||
if((p < end) && *p)
|
||||
continue;
|
||||
else
|
||||
break;
|
||||
}
|
||||
p += 9;
|
||||
|
||||
len = cb - (size_t)(p - str);
|
||||
filename = parse_filename(p, len);
|
||||
if(filename) {
|
||||
if(outs->stream) {
|
||||
/* indication of problem, get out! */
|
||||
free(filename);
|
||||
return CURL_WRITEFUNC_ERROR;
|
||||
}
|
||||
|
||||
if(per->config->output_dir) {
|
||||
outs->filename = curl_maprintf("%s/%s", per->config->output_dir,
|
||||
filename);
|
||||
free(filename);
|
||||
if(!outs->filename)
|
||||
return CURL_WRITEFUNC_ERROR;
|
||||
}
|
||||
else
|
||||
outs->filename = filename;
|
||||
|
||||
outs->is_cd_filename = TRUE;
|
||||
outs->s_isreg = TRUE;
|
||||
outs->fopened = FALSE;
|
||||
outs->alloc_filename = TRUE;
|
||||
hdrcbdata->honor_cd_filename = FALSE; /* done now! */
|
||||
if(!tool_create_output_file(outs, per->config))
|
||||
return CURL_WRITEFUNC_ERROR;
|
||||
if(tool_write_headers(&per->hdrcbdata, outs->stream))
|
||||
return CURL_WRITEFUNC_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(!outs->stream && !tool_create_output_file(outs, per->config))
|
||||
return CURL_WRITEFUNC_ERROR;
|
||||
if(tool_write_headers(&per->hdrcbdata, outs->stream))
|
||||
return CURL_WRITEFUNC_ERROR;
|
||||
} /* content-disposition handling */
|
||||
|
||||
if(hdrcbdata->honor_cd_filename &&
|
||||
hdrcbdata->config->show_headers) {
|
||||
/* still awaiting the Content-Disposition header, store the header in
|
||||
memory. Since it is not null-terminated, we need an extra dance. */
|
||||
char *clone = curl_maprintf("%.*s", (int)cb, str);
|
||||
if(clone) {
|
||||
struct curl_slist *old = hdrcbdata->headlist;
|
||||
hdrcbdata->headlist = curl_slist_append(old, clone);
|
||||
free(clone);
|
||||
if(!hdrcbdata->headlist) {
|
||||
curl_slist_free_all(old);
|
||||
return CURL_WRITEFUNC_ERROR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
curl_slist_free_all(hdrcbdata->headlist);
|
||||
hdrcbdata->headlist = NULL;
|
||||
return CURL_WRITEFUNC_ERROR;
|
||||
}
|
||||
return cb; /* done for now */
|
||||
}
|
||||
}
|
||||
}
|
||||
if(hdrcbdata->config->writeout) {
|
||||
char *value = memchr(ptr, ':', cb);
|
||||
if(value) {
|
||||
if(per->was_last_header_empty)
|
||||
per->num_headers = 0;
|
||||
per->was_last_header_empty = FALSE;
|
||||
per->num_headers++;
|
||||
}
|
||||
else if(ptr[0] == '\r' || ptr[0] == '\n')
|
||||
per->was_last_header_empty = TRUE;
|
||||
}
|
||||
if(hdrcbdata->config->show_headers &&
|
||||
(scheme == proto_http || scheme == proto_https ||
|
||||
scheme == proto_rtsp || scheme == proto_file)) {
|
||||
/* bold headers only for selected protocols */
|
||||
char *value = NULL;
|
||||
|
||||
if(!outs->stream && !tool_create_output_file(outs, per->config))
|
||||
return CURL_WRITEFUNC_ERROR;
|
||||
|
||||
if(global->isatty &&
|
||||
#ifdef _WIN32
|
||||
tool_term_has_bold &&
|
||||
#endif
|
||||
global->styled_output)
|
||||
value = memchr(ptr, ':', cb);
|
||||
if(value) {
|
||||
size_t namelen = value - ptr;
|
||||
curl_mfprintf(outs->stream, BOLD "%.*s" BOLDOFF ":", (int)namelen, ptr);
|
||||
#ifndef LINK
|
||||
fwrite(&value[1], cb - namelen - 1, 1, outs->stream);
|
||||
#else
|
||||
if(curl_strnequal("Location", ptr, namelen)) {
|
||||
write_linked_location(per->curl, &value[1], cb - namelen - 1,
|
||||
outs->stream);
|
||||
}
|
||||
else
|
||||
fwrite(&value[1], cb - namelen - 1, 1, outs->stream);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
/* not "handled", just show it */
|
||||
fwrite(ptr, cb, 1, outs->stream);
|
||||
}
|
||||
return cb;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copies a filename part and returns an ALLOCATED data buffer.
|
||||
*/
|
||||
static char *parse_filename(const char *ptr, size_t len)
|
||||
{
|
||||
char *copy;
|
||||
char *p;
|
||||
char *q;
|
||||
char stop = '\0';
|
||||
|
||||
copy = memdup0(ptr, len);
|
||||
if(!copy)
|
||||
return NULL;
|
||||
|
||||
p = copy;
|
||||
if(*p == '\'' || *p == '"') {
|
||||
/* store the starting quote */
|
||||
stop = *p;
|
||||
p++;
|
||||
}
|
||||
else
|
||||
stop = ';';
|
||||
|
||||
/* scan for the end letter and stop there */
|
||||
q = strchr(p, stop);
|
||||
if(q)
|
||||
*q = '\0';
|
||||
|
||||
/* if the filename contains a path, only use filename portion */
|
||||
q = strrchr(p, '/');
|
||||
if(q) {
|
||||
p = q + 1;
|
||||
if(!*p) {
|
||||
tool_safefree(copy);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the filename contains a backslash, only use filename portion. The idea
|
||||
is that even systems that do not handle backslashes as path separators
|
||||
probably want the path removed for convenience. */
|
||||
q = strrchr(p, '\\');
|
||||
if(q) {
|
||||
p = q + 1;
|
||||
if(!*p) {
|
||||
tool_safefree(copy);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* make sure the filename does not end in \r or \n */
|
||||
q = strchr(p, '\r');
|
||||
if(q)
|
||||
*q = '\0';
|
||||
|
||||
q = strchr(p, '\n');
|
||||
if(q)
|
||||
*q = '\0';
|
||||
|
||||
if(copy != p)
|
||||
memmove(copy, p, strlen(p) + 1);
|
||||
|
||||
#if defined(_WIN32) || defined(MSDOS)
|
||||
{
|
||||
char *sanitized;
|
||||
SANITIZEcode sc = sanitize_file_name(&sanitized, copy, 0);
|
||||
tool_safefree(copy);
|
||||
if(sc)
|
||||
return NULL;
|
||||
copy = sanitized;
|
||||
}
|
||||
#endif /* _WIN32 || MSDOS */
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
#ifdef LINK
|
||||
/*
|
||||
* Treat the Location: header specially, by writing a special escape
|
||||
* sequence that adds a hyperlink to the displayed text. This makes
|
||||
* the absolute URL of the redirect clickable in supported terminals,
|
||||
* which could not happen otherwise for relative URLs. The Location:
|
||||
* header is supposed to always be absolute so this theoretically
|
||||
* should not be needed but the real world returns plenty of relative
|
||||
* URLs here.
|
||||
*/
|
||||
static void write_linked_location(CURL *curl, const char *location,
|
||||
size_t loclen, FILE *stream)
|
||||
{
|
||||
/* This would so simple if CURLINFO_REDIRECT_URL were available here */
|
||||
CURLU *u = NULL;
|
||||
char *copyloc = NULL, *locurl = NULL, *scheme = NULL, *finalurl = NULL;
|
||||
const char *loc = location;
|
||||
size_t llen = loclen;
|
||||
int space_skipped = 0;
|
||||
const char *vver = getenv("VTE_VERSION");
|
||||
|
||||
if(vver) {
|
||||
curl_off_t num;
|
||||
if(curlx_str_number(&vver, &num, CURL_OFF_T_MAX) ||
|
||||
/* Skip formatting for old versions of VTE <= 0.48.1 (Mar 2017) since
|
||||
some of those versions have formatting bugs. (#10428) */
|
||||
(num <= 4801))
|
||||
goto locout;
|
||||
}
|
||||
|
||||
/* Strip leading whitespace of the redirect URL */
|
||||
while(llen && (*loc == ' ' || *loc == '\t')) {
|
||||
++loc;
|
||||
--llen;
|
||||
++space_skipped;
|
||||
}
|
||||
|
||||
/* Strip the trailing end-of-line characters, normally "\r\n" */
|
||||
while(llen && (loc[llen-1] == '\n' || loc[llen-1] == '\r'))
|
||||
--llen;
|
||||
|
||||
/* CURLU makes it easy to handle the relative URL case */
|
||||
u = curl_url();
|
||||
if(!u)
|
||||
goto locout;
|
||||
|
||||
/* Create a null-terminated and whitespace-stripped copy of Location: */
|
||||
copyloc = memdup0(loc, llen);
|
||||
if(!copyloc)
|
||||
goto locout;
|
||||
|
||||
/* The original URL to use as a base for a relative redirect URL */
|
||||
if(curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &locurl))
|
||||
goto locout;
|
||||
if(curl_url_set(u, CURLUPART_URL, locurl, 0))
|
||||
goto locout;
|
||||
|
||||
/* Redirected location. This can be either absolute or relative. */
|
||||
if(curl_url_set(u, CURLUPART_URL, copyloc, 0))
|
||||
goto locout;
|
||||
|
||||
if(curl_url_get(u, CURLUPART_URL, &finalurl, CURLU_NO_DEFAULT_PORT))
|
||||
goto locout;
|
||||
|
||||
if(curl_url_get(u, CURLUPART_SCHEME, &scheme, 0))
|
||||
goto locout;
|
||||
|
||||
if(!strcmp("http", scheme) ||
|
||||
!strcmp("https", scheme) ||
|
||||
!strcmp("ftp", scheme) ||
|
||||
!strcmp("ftps", scheme)) {
|
||||
curl_mfprintf(stream, "%.*s" LINK "%s" LINKST "%.*s" LINKOFF,
|
||||
space_skipped, location,
|
||||
finalurl,
|
||||
(int)loclen - space_skipped, loc);
|
||||
goto locdone;
|
||||
}
|
||||
|
||||
/* Not a "safe" URL: do not linkify it */
|
||||
|
||||
locout:
|
||||
/* Write the normal output in case of error or unsafe */
|
||||
fwrite(location, loclen, 1, stream);
|
||||
|
||||
locdone:
|
||||
if(u) {
|
||||
curl_free(finalurl);
|
||||
curl_free(scheme);
|
||||
curl_url_cleanup(u);
|
||||
free(copyloc);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
#ifndef HEADER_CURL_TOOL_CB_HDR_H
|
||||
#define HEADER_CURL_TOOL_CB_HDR_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
/*
|
||||
* curl operates using a single HdrCbData struct variable, a
|
||||
* pointer to this is passed as userdata pointer to tool_header_cb.
|
||||
*
|
||||
* 'outs' member is a pointer to the OutStruct variable used to keep
|
||||
* track of information relative to curl's output writing.
|
||||
*
|
||||
* 'heads' member is a pointer to the OutStruct variable used to keep
|
||||
* track of information relative to header response writing.
|
||||
*
|
||||
* 'honor_cd_filename' member is TRUE when tool_header_cb is allowed
|
||||
* to honor Content-Disposition filename property and accordingly
|
||||
* set 'outs' filename, otherwise FALSE;
|
||||
*/
|
||||
|
||||
struct HdrCbData {
|
||||
struct OperationConfig *config;
|
||||
struct OutStruct *outs;
|
||||
struct OutStruct *heads;
|
||||
struct OutStruct *etag_save;
|
||||
struct curl_slist *headlist;
|
||||
bool honor_cd_filename;
|
||||
};
|
||||
|
||||
int tool_write_headers(struct HdrCbData *hdrcbdata, FILE *stream);
|
||||
|
||||
/*
|
||||
** callback for CURLOPT_HEADERFUNCTION
|
||||
*/
|
||||
|
||||
size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata);
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_CB_HDR_H */
|
||||
+248
@@ -0,0 +1,248 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#include "tool_cfgable.h"
|
||||
#include "tool_cb_prg.h"
|
||||
#include "tool_util.h"
|
||||
#include "tool_operate.h"
|
||||
#include "terminal.h"
|
||||
|
||||
#include "memdebug.h" /* keep this as LAST include */
|
||||
|
||||
#define MAX_BARLENGTH 400
|
||||
#define MIN_BARLENGTH 20
|
||||
|
||||
/* 200 values generated by this perl code:
|
||||
|
||||
my $pi = 3.1415;
|
||||
foreach my $i (1 .. 200) {
|
||||
printf "%d, ", sin($i/200 * 2 * $pi) * 500000 + 500000;
|
||||
}
|
||||
*/
|
||||
static const int sinus[] = {
|
||||
515704, 531394, 547052, 562664, 578214, 593687, 609068, 624341, 639491,
|
||||
654504, 669364, 684057, 698568, 712883, 726989, 740870, 754513, 767906,
|
||||
781034, 793885, 806445, 818704, 830647, 842265, 853545, 864476, 875047,
|
||||
885248, 895069, 904500, 913532, 922156, 930363, 938145, 945495, 952406,
|
||||
958870, 964881, 970434, 975522, 980141, 984286, 987954, 991139, 993840,
|
||||
996054, 997778, 999011, 999752, 999999, 999754, 999014, 997783, 996060,
|
||||
993848, 991148, 987964, 984298, 980154, 975536, 970449, 964898, 958888,
|
||||
952426, 945516, 938168, 930386, 922180, 913558, 904527, 895097, 885277,
|
||||
875077, 864507, 853577, 842299, 830682, 818739, 806482, 793922, 781072,
|
||||
767945, 754553, 740910, 727030, 712925, 698610, 684100, 669407, 654548,
|
||||
639536, 624386, 609113, 593733, 578260, 562710, 547098, 531440, 515751,
|
||||
500046, 484341, 468651, 452993, 437381, 421830, 406357, 390976, 375703,
|
||||
360552, 345539, 330679, 315985, 301474, 287158, 273052, 259170, 245525,
|
||||
232132, 219003, 206152, 193590, 181331, 169386, 157768, 146487, 135555,
|
||||
124983, 114781, 104959, 95526, 86493, 77868, 69660, 61876, 54525, 47613,
|
||||
41147, 35135, 29581, 24491, 19871, 15724, 12056, 8868, 6166, 3951, 2225,
|
||||
990, 248, 0, 244, 982, 2212, 3933, 6144, 8842, 12025, 15690, 19832, 24448,
|
||||
29534, 35084, 41092, 47554, 54462, 61809, 69589, 77794, 86415, 95445,
|
||||
104873, 114692, 124891, 135460, 146389, 157667, 169282, 181224, 193480,
|
||||
206039, 218888, 232015, 245406, 259048, 272928, 287032, 301346, 315856,
|
||||
330548, 345407, 360419, 375568, 390841, 406221, 421693, 437243, 452854,
|
||||
468513, 484202, 499907
|
||||
};
|
||||
|
||||
static void fly(struct ProgressData *bar, bool moved)
|
||||
{
|
||||
char buf[MAX_BARLENGTH + 2];
|
||||
int pos;
|
||||
int check = bar->width - 2;
|
||||
|
||||
/* bar->width is range checked when assigned */
|
||||
DEBUGASSERT(bar->width <= MAX_BARLENGTH);
|
||||
buf[0] = '\r';
|
||||
memset(&buf[1], ' ', bar->width);
|
||||
buf[bar->width + 1] = '\0';
|
||||
|
||||
memcpy(&buf[bar->bar + 1], "-=O=-", 5);
|
||||
|
||||
pos = sinus[bar->tick%200] / (1000000 / check) + 1;
|
||||
buf[pos] = '#';
|
||||
pos = sinus[(bar->tick + 5)%200] / (1000000 / check) + 1;
|
||||
buf[pos] = '#';
|
||||
pos = sinus[(bar->tick + 10)%200] / (1000000 / check) + 1;
|
||||
buf[pos] = '#';
|
||||
pos = sinus[(bar->tick + 15)%200] / (1000000 / check) + 1;
|
||||
buf[pos] = '#';
|
||||
|
||||
fputs(buf, bar->out);
|
||||
bar->tick += 2;
|
||||
if(bar->tick >= 200)
|
||||
bar->tick -= 200;
|
||||
|
||||
bar->bar += (moved ? bar->barmove : 0);
|
||||
if(bar->bar >= (bar->width - 6)) {
|
||||
bar->barmove = -1;
|
||||
bar->bar = bar->width - 6;
|
||||
}
|
||||
else if(bar->bar < 0) {
|
||||
bar->barmove = 1;
|
||||
bar->bar = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** callback for CURLOPT_XFERINFOFUNCTION
|
||||
*/
|
||||
|
||||
#if (SIZEOF_CURL_OFF_T < 8)
|
||||
#error "too small curl_off_t"
|
||||
#else
|
||||
/* assume SIZEOF_CURL_OFF_T == 8 */
|
||||
# define CURL_OFF_T_MAX 0x7FFFFFFFFFFFFFFF
|
||||
#endif
|
||||
|
||||
static void update_width(struct ProgressData *bar)
|
||||
{
|
||||
int cols = get_terminal_columns();
|
||||
if(cols > MAX_BARLENGTH)
|
||||
bar->width = MAX_BARLENGTH;
|
||||
else if(cols > MIN_BARLENGTH)
|
||||
bar->width = (int)cols;
|
||||
else
|
||||
bar->width = MIN_BARLENGTH;
|
||||
}
|
||||
|
||||
int tool_progress_cb(void *clientp,
|
||||
curl_off_t dltotal, curl_off_t dlnow,
|
||||
curl_off_t ultotal, curl_off_t ulnow)
|
||||
{
|
||||
struct curltime now = curlx_now();
|
||||
struct per_transfer *per = clientp;
|
||||
struct OperationConfig *config = per->config;
|
||||
struct ProgressData *bar = &per->progressbar;
|
||||
curl_off_t total;
|
||||
curl_off_t point;
|
||||
|
||||
/* Calculate expected transfer size. initial_size can be less than zero when
|
||||
indicating that we are expecting to get the filesize from the remote */
|
||||
if(bar->initial_size < 0) {
|
||||
if(dltotal || ultotal)
|
||||
total = dltotal + ultotal;
|
||||
else
|
||||
total = CURL_OFF_T_MAX;
|
||||
}
|
||||
else if((CURL_OFF_T_MAX - bar->initial_size) < (dltotal + ultotal))
|
||||
total = CURL_OFF_T_MAX;
|
||||
else
|
||||
total = dltotal + ultotal + bar->initial_size;
|
||||
|
||||
/* Calculate the current progress. initial_size can be less than zero when
|
||||
indicating that we are expecting to get the filesize from the remote */
|
||||
if(bar->initial_size < 0) {
|
||||
if(dltotal || ultotal)
|
||||
point = dlnow + ulnow;
|
||||
else
|
||||
point = CURL_OFF_T_MAX;
|
||||
}
|
||||
else if((CURL_OFF_T_MAX - bar->initial_size) < (dlnow + ulnow))
|
||||
point = CURL_OFF_T_MAX;
|
||||
else
|
||||
point = dlnow + ulnow + bar->initial_size;
|
||||
|
||||
if(bar->calls) {
|
||||
/* after first call... */
|
||||
if(total) {
|
||||
/* we know the total data to get... */
|
||||
if(bar->prev == point)
|
||||
/* progress did not change since last invoke */
|
||||
return 0;
|
||||
else if((curlx_timediff(now, bar->prevtime) < 100L) && point < total)
|
||||
/* limit progress-bar updating to 10 Hz except when we are at 100% */
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
/* total is unknown */
|
||||
if(curlx_timediff(now, bar->prevtime) < 100L)
|
||||
/* limit progress-bar updating to 10 Hz */
|
||||
return 0;
|
||||
update_width(bar);
|
||||
fly(bar, point != bar->prev);
|
||||
}
|
||||
}
|
||||
|
||||
/* simply count invokes */
|
||||
bar->calls++;
|
||||
|
||||
update_width(bar);
|
||||
if((total > 0) && (point != bar->prev)) {
|
||||
char line[MAX_BARLENGTH + 1];
|
||||
char format[40];
|
||||
double frac;
|
||||
double percent;
|
||||
int barwidth;
|
||||
size_t num;
|
||||
if(point > total)
|
||||
/* we have got more than the expected total! */
|
||||
total = point;
|
||||
|
||||
frac = (double)point / (double)total;
|
||||
percent = frac * 100.0;
|
||||
barwidth = bar->width - 7;
|
||||
num = (size_t) (((double)barwidth) * frac);
|
||||
if(num > MAX_BARLENGTH)
|
||||
num = MAX_BARLENGTH;
|
||||
memset(line, '#', num);
|
||||
line[num] = '\0';
|
||||
curl_msnprintf(format, sizeof(format), "\r%%-%ds %%5.1f%%%%", barwidth);
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wformat-nonliteral"
|
||||
#endif
|
||||
curl_mfprintf(bar->out, format, line, percent);
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
}
|
||||
fflush(bar->out);
|
||||
bar->prev = point;
|
||||
bar->prevtime = now;
|
||||
|
||||
if(config->readbusy) {
|
||||
config->readbusy = FALSE;
|
||||
curl_easy_pause(per->curl, CURLPAUSE_CONT);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void progressbarinit(struct ProgressData *bar,
|
||||
struct OperationConfig *config)
|
||||
{
|
||||
memset(bar, 0, sizeof(struct ProgressData));
|
||||
|
||||
/* pass the resume from value through to the progress function so it can
|
||||
* display progress towards total file not just the part that is left. */
|
||||
if(config->use_resume)
|
||||
bar->initial_size = config->resume_from;
|
||||
|
||||
update_width(bar);
|
||||
|
||||
bar->out = tool_stderr;
|
||||
bar->tick = 150;
|
||||
bar->barmove = 1;
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
#ifndef HEADER_CURL_TOOL_CB_PRG_H
|
||||
#define HEADER_CURL_TOOL_CB_PRG_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#define CURL_PROGRESS_STATS 0 /* default progress display */
|
||||
#define CURL_PROGRESS_BAR 1
|
||||
|
||||
struct ProgressData {
|
||||
int calls;
|
||||
curl_off_t prev;
|
||||
struct curltime prevtime;
|
||||
int width;
|
||||
FILE *out; /* where to write everything to */
|
||||
curl_off_t initial_size;
|
||||
unsigned int tick;
|
||||
int bar;
|
||||
int barmove;
|
||||
};
|
||||
|
||||
struct OperationConfig;
|
||||
|
||||
void progressbarinit(struct ProgressData *bar,
|
||||
struct OperationConfig *config);
|
||||
|
||||
/*
|
||||
** callback for CURLOPT_PROGRESSFUNCTION
|
||||
*/
|
||||
|
||||
int tool_progress_cb(void *clientp,
|
||||
curl_off_t dltotal, curl_off_t dlnow,
|
||||
curl_off_t ultotal, curl_off_t ulnow);
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_CB_PRG_H */
|
||||
+202
@@ -0,0 +1,202 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#ifdef HAVE_SYS_SELECT_H
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
#ifdef HAVE_POLL_H
|
||||
#include <poll.h>
|
||||
#elif defined(HAVE_SYS_POLL_H)
|
||||
#include <sys/poll.h>
|
||||
#endif
|
||||
|
||||
#include "tool_cfgable.h"
|
||||
#include "tool_cb_rea.h"
|
||||
#include "tool_operate.h"
|
||||
#include "tool_util.h"
|
||||
#include "tool_msgs.h"
|
||||
|
||||
#include "memdebug.h" /* keep this as LAST include */
|
||||
|
||||
#ifndef _WIN32
|
||||
/* Wait up to a number of milliseconds for socket activity. This function
|
||||
waits on read activity on a file descriptor that is not a socket which
|
||||
makes it not work with select() or poll() on Windows. */
|
||||
static bool waitfd(int waitms, int fd)
|
||||
{
|
||||
#ifdef HAVE_POLL
|
||||
struct pollfd set;
|
||||
|
||||
set.fd = fd;
|
||||
set.events = POLLIN;
|
||||
set.revents = 0;
|
||||
if(poll(&set, 1, (int)waitms))
|
||||
return TRUE; /* timeout */
|
||||
return FALSE;
|
||||
#else
|
||||
fd_set bits;
|
||||
struct timeval timeout;
|
||||
|
||||
if(fd >= FD_SETSIZE)
|
||||
/* can't wait! */
|
||||
return FALSE;
|
||||
|
||||
/* wait this long at the most */
|
||||
timeout.tv_sec = waitms / 1000;
|
||||
timeout.tv_usec = (int)((waitms % 1000) * 1000);
|
||||
|
||||
FD_ZERO(&bits);
|
||||
#ifdef __DJGPP__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Warith-conversion"
|
||||
#endif
|
||||
FD_SET(fd, &bits);
|
||||
#ifdef __DJGPP__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
if(!select(fd + 1, &bits, NULL, NULL, &timeout))
|
||||
return TRUE; /* timeout */
|
||||
return FALSE;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** callback for CURLOPT_READFUNCTION
|
||||
*/
|
||||
|
||||
size_t tool_read_cb(char *buffer, size_t sz, size_t nmemb, void *userdata)
|
||||
{
|
||||
ssize_t rc = 0;
|
||||
struct per_transfer *per = userdata;
|
||||
struct OperationConfig *config = per->config;
|
||||
|
||||
if((per->uploadfilesize != -1) &&
|
||||
(per->uploadedsofar == per->uploadfilesize)) {
|
||||
/* done */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(config->timeout_ms) {
|
||||
struct curltime now = curlx_now();
|
||||
long msdelta = (long)curlx_timediff(now, per->start);
|
||||
|
||||
if(msdelta > config->timeout_ms)
|
||||
/* timeout */
|
||||
return 0;
|
||||
#ifndef _WIN32
|
||||
else {
|
||||
long w = config->timeout_ms - msdelta;
|
||||
if(w > INT_MAX)
|
||||
w = INT_MAX;
|
||||
waitfd((int)w, per->infd);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* If we are on Windows, and using `-T .`, then per->infd points to a socket
|
||||
connected to stdin via a reader thread, and needs to be read with recv()
|
||||
Make sure we are in non-blocking mode and infd is not regular stdin
|
||||
On Linux per->infd should be stdin (0) and the block below should not
|
||||
execute */
|
||||
if(per->uploadfile && !strcmp(per->uploadfile, ".") && per->infd > 0) {
|
||||
#if defined(_WIN32) && !defined(CURL_WINDOWS_UWP) && !defined(UNDER_CE)
|
||||
rc = CURL_RECV(per->infd, buffer, curlx_uztosi(sz * nmemb), 0);
|
||||
if(rc < 0) {
|
||||
if(SOCKERRNO == SOCKEWOULDBLOCK) {
|
||||
CURL_SETERRNO(0);
|
||||
config->readbusy = TRUE;
|
||||
return CURL_READFUNC_PAUSE;
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
}
|
||||
#else
|
||||
warnf("per->infd != 0: FD == %d. This behavior"
|
||||
" is only supported on desktop Windows", per->infd);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
rc = read(per->infd, buffer, sz*nmemb);
|
||||
if(rc < 0) {
|
||||
if(errno == EAGAIN) {
|
||||
CURL_SETERRNO(0);
|
||||
config->readbusy = TRUE;
|
||||
return CURL_READFUNC_PAUSE;
|
||||
}
|
||||
/* since size_t is unsigned we cannot return negative values fine */
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
if((per->uploadfilesize != -1) &&
|
||||
(per->uploadedsofar + rc > per->uploadfilesize)) {
|
||||
/* do not allow uploading more than originally set out to do */
|
||||
curl_off_t delta = per->uploadedsofar + rc - per->uploadfilesize;
|
||||
warnf("File size larger in the end than when "
|
||||
"started. Dropping at least %" CURL_FORMAT_CURL_OFF_T " bytes",
|
||||
delta);
|
||||
rc = (ssize_t)(per->uploadfilesize - per->uploadedsofar);
|
||||
}
|
||||
config->readbusy = FALSE;
|
||||
|
||||
/* when select() returned zero here, it timed out */
|
||||
return (size_t)rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** callback for CURLOPT_XFERINFOFUNCTION used to unpause busy reads
|
||||
*/
|
||||
|
||||
int tool_readbusy_cb(void *clientp,
|
||||
curl_off_t dltotal, curl_off_t dlnow,
|
||||
curl_off_t ultotal, curl_off_t ulnow)
|
||||
{
|
||||
struct per_transfer *per = clientp;
|
||||
struct OperationConfig *config = per->config;
|
||||
static curl_off_t ulprev;
|
||||
|
||||
(void)dltotal;
|
||||
(void)dlnow;
|
||||
(void)ultotal;
|
||||
(void)ulnow;
|
||||
|
||||
if(config->readbusy) {
|
||||
if(ulprev == ulnow) {
|
||||
#ifndef _WIN32
|
||||
waitfd(1, per->infd);
|
||||
#else
|
||||
/* sleep */
|
||||
curlx_wait_ms(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
config->readbusy = FALSE;
|
||||
curl_easy_pause(per->curl, CURLPAUSE_CONT);
|
||||
}
|
||||
|
||||
ulprev = ulnow;
|
||||
|
||||
return per->noprogress ? 0 : CURL_PROGRESSFUNC_CONTINUE;
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
#ifndef HEADER_CURL_TOOL_CB_REA_H
|
||||
#define HEADER_CURL_TOOL_CB_REA_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
/*
|
||||
** callback for CURLOPT_READFUNCTION
|
||||
*/
|
||||
|
||||
size_t tool_read_cb(char *buffer, size_t sz, size_t nmemb, void *userdata);
|
||||
|
||||
/*
|
||||
** callback for CURLOPT_XFERINFOFUNCTION used to unpause busy reads
|
||||
*/
|
||||
|
||||
int tool_readbusy_cb(void *clientp,
|
||||
curl_off_t dltotal, curl_off_t dlnow,
|
||||
curl_off_t ultotal, curl_off_t ulnow);
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_CB_REA_H */
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#include "tool_cfgable.h"
|
||||
#include "tool_operate.h"
|
||||
#include "tool_cb_see.h"
|
||||
|
||||
#include "memdebug.h" /* keep this as LAST include */
|
||||
|
||||
/*
|
||||
** callback for CURLOPT_SEEKFUNCTION
|
||||
**
|
||||
** Notice that this is not supposed to return the resulting offset. This
|
||||
** shall only return CURL_SEEKFUNC_* return codes.
|
||||
*/
|
||||
|
||||
int tool_seek_cb(void *userdata, curl_off_t offset, int whence)
|
||||
{
|
||||
struct per_transfer *per = userdata;
|
||||
|
||||
#if (SIZEOF_CURL_OFF_T > SIZEOF_OFF_T) && !defined(USE_WIN32_LARGE_FILES)
|
||||
|
||||
/* OUR_MAX_SEEK_L has 'long' data type, OUR_MAX_SEEK_O has 'curl_off_t,
|
||||
both represent the same value. Maximum offset used here when we lseek
|
||||
using a 'long' data type offset */
|
||||
|
||||
#define OUR_MAX_SEEK_L 2147483647L - 1L
|
||||
#define OUR_MAX_SEEK_O 0x7FFFFFFF - 0x1
|
||||
|
||||
/* The offset check following here is only interesting if curl_off_t is
|
||||
larger than off_t and we are not using the Win32 large file support
|
||||
macros that provide the support to do 64-bit seeks correctly */
|
||||
|
||||
if(offset > OUR_MAX_SEEK_O) {
|
||||
/* Some precaution code to work around problems with different data sizes
|
||||
to allow seeking >32-bit even if off_t is 32-bit. Should be very rare
|
||||
and is really valid on weirdo-systems. */
|
||||
curl_off_t left = offset;
|
||||
|
||||
if(whence != SEEK_SET)
|
||||
/* this code path does not support other types */
|
||||
return CURL_SEEKFUNC_FAIL;
|
||||
|
||||
if(LSEEK_ERROR == lseek(per->infd, 0, SEEK_SET))
|
||||
/* could not rewind to beginning */
|
||||
return CURL_SEEKFUNC_FAIL;
|
||||
|
||||
while(left) {
|
||||
long step = (left > OUR_MAX_SEEK_O) ? OUR_MAX_SEEK_L : (long)left;
|
||||
if(LSEEK_ERROR == lseek(per->infd, step, SEEK_CUR))
|
||||
/* could not seek forwards the desired amount */
|
||||
return CURL_SEEKFUNC_FAIL;
|
||||
left -= step;
|
||||
}
|
||||
return CURL_SEEKFUNC_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__AMIGA__) || defined(__MINGW32CE__)
|
||||
if(LSEEK_ERROR == lseek(per->infd, (off_t)offset, whence))
|
||||
#else
|
||||
if(LSEEK_ERROR == lseek(per->infd, offset, whence))
|
||||
#endif
|
||||
/* could not rewind, the reason is in errno but errno is just not portable
|
||||
enough and we do not actually care that much why we failed. We will let
|
||||
libcurl know that it may try other means if it wants to. */
|
||||
return CURL_SEEKFUNC_CANTSEEK;
|
||||
|
||||
return CURL_SEEKFUNC_OK;
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
#ifndef HEADER_CURL_TOOL_CB_SEE_H
|
||||
#define HEADER_CURL_TOOL_CB_SEE_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
/*
|
||||
** callback for CURLOPT_SEEKFUNCTION
|
||||
*/
|
||||
|
||||
int tool_seek_cb(void *userdata, curl_off_t offset, int whence);
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_CB_SEE_H */
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h> /* IPPROTO_TCP */
|
||||
#endif
|
||||
|
||||
#include "tool_cb_soc.h"
|
||||
|
||||
/*
|
||||
** callback for CURLOPT_OPENSOCKETFUNCTION
|
||||
**
|
||||
** Notice that only Linux is supported for the moment.
|
||||
*/
|
||||
|
||||
curl_socket_t tool_socket_open_mptcp_cb(void *clientp,
|
||||
curlsocktype purpose,
|
||||
struct curl_sockaddr *addr)
|
||||
{
|
||||
int protocol = addr->protocol;
|
||||
|
||||
(void)clientp;
|
||||
(void)purpose;
|
||||
|
||||
if(protocol == IPPROTO_TCP)
|
||||
#if defined(__linux__)
|
||||
# ifndef IPPROTO_MPTCP
|
||||
# define IPPROTO_MPTCP 262
|
||||
# endif
|
||||
protocol = IPPROTO_MPTCP;
|
||||
#else
|
||||
return CURL_SOCKET_BAD;
|
||||
#endif
|
||||
|
||||
return CURL_SOCKET(addr->family, addr->socktype, protocol);
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
#ifndef HEADER_CURL_TOOL_CB_SOC_H
|
||||
#define HEADER_CURL_TOOL_CB_SOC_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
/*
|
||||
** callback for CURLOPT_OPENSOCKETFUNCTION
|
||||
*/
|
||||
|
||||
curl_socket_t tool_socket_open_mptcp_cb(void *clientp,
|
||||
curlsocktype purpose,
|
||||
struct curl_sockaddr *addr);
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_CB_SOC_H */
|
||||
+365
@@ -0,0 +1,365 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#include "tool_cfgable.h"
|
||||
#include "tool_msgs.h"
|
||||
#include "tool_cb_wrt.h"
|
||||
#include "tool_operate.h"
|
||||
|
||||
#include "memdebug.h" /* keep this as LAST include */
|
||||
|
||||
#ifdef _WIN32
|
||||
#define OPENMODE S_IREAD | S_IWRITE
|
||||
#else
|
||||
#define OPENMODE S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH
|
||||
#endif
|
||||
|
||||
/* create/open a local file for writing, return TRUE on success */
|
||||
bool tool_create_output_file(struct OutStruct *outs,
|
||||
struct OperationConfig *config)
|
||||
{
|
||||
FILE *file = NULL;
|
||||
const char *fname = outs->filename;
|
||||
DEBUGASSERT(outs);
|
||||
DEBUGASSERT(config);
|
||||
DEBUGASSERT(fname && *fname);
|
||||
|
||||
if(config->file_clobber_mode == CLOBBER_ALWAYS ||
|
||||
(config->file_clobber_mode == CLOBBER_DEFAULT &&
|
||||
!outs->is_cd_filename)) {
|
||||
/* open file for writing */
|
||||
file = curlx_fopen(fname, "wb");
|
||||
}
|
||||
else {
|
||||
int fd;
|
||||
do {
|
||||
fd = curlx_open(fname, O_CREAT | O_WRONLY | O_EXCL | CURL_O_BINARY,
|
||||
OPENMODE);
|
||||
/* Keep retrying in the hope that it is not interrupted sometime */
|
||||
/* !checksrc! disable ERRNOVAR 1 */
|
||||
} while(fd == -1 && errno == EINTR);
|
||||
if(config->file_clobber_mode == CLOBBER_NEVER && fd == -1) {
|
||||
int next_num = 1;
|
||||
struct dynbuf fbuffer;
|
||||
curlx_dyn_init(&fbuffer, 1025);
|
||||
/* !checksrc! disable ERRNOVAR 1 */
|
||||
while(fd == -1 && /* have not successfully opened a file */
|
||||
(errno == EEXIST || errno == EISDIR) &&
|
||||
/* because we keep having files that already exist */
|
||||
next_num < 100 /* and we have not reached the retry limit */ ) {
|
||||
curlx_dyn_reset(&fbuffer);
|
||||
if(curlx_dyn_addf(&fbuffer, "%s.%d", fname, next_num))
|
||||
return FALSE;
|
||||
next_num++;
|
||||
do {
|
||||
fd = curlx_open(curlx_dyn_ptr(&fbuffer),
|
||||
O_CREAT | O_WRONLY | O_EXCL | CURL_O_BINARY,
|
||||
OPENMODE);
|
||||
/* Keep retrying in the hope that it is not interrupted sometime */
|
||||
} while(fd == -1 && errno == EINTR);
|
||||
}
|
||||
outs->filename = curlx_dyn_ptr(&fbuffer); /* remember the new one */
|
||||
outs->alloc_filename = TRUE;
|
||||
}
|
||||
/* An else statement to not overwrite existing files and not retry with
|
||||
new numbered names (which would cover
|
||||
config->file_clobber_mode == CLOBBER_DEFAULT && outs->is_cd_filename)
|
||||
is not needed because we would have failed earlier, in the while loop
|
||||
and `fd` would now be -1 */
|
||||
if(fd != -1) {
|
||||
file = curlx_fdopen(fd, "wb");
|
||||
if(!file)
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
if(!file) {
|
||||
char errbuf[STRERROR_LEN];
|
||||
warnf("Failed to open the file %s: %s", fname,
|
||||
curlx_strerror(errno, errbuf, sizeof(errbuf)));
|
||||
return FALSE;
|
||||
}
|
||||
outs->s_isreg = TRUE;
|
||||
outs->fopened = TRUE;
|
||||
outs->stream = file;
|
||||
outs->bytes = 0;
|
||||
outs->init = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#if defined(_WIN32) && !defined(UNDER_CE)
|
||||
static size_t win_console(intptr_t fhnd, struct OutStruct *outs,
|
||||
char *buffer, size_t bytes,
|
||||
size_t *retp)
|
||||
{
|
||||
DWORD chars_written;
|
||||
unsigned char *rbuf = (unsigned char *)buffer;
|
||||
DWORD rlen = (DWORD)bytes;
|
||||
|
||||
#define IS_TRAILING_BYTE(x) (0x80 <= (x) && (x) < 0xC0)
|
||||
|
||||
/* attempt to complete an incomplete UTF-8 sequence from previous call. the
|
||||
sequence does not have to be well-formed. */
|
||||
if(outs->utf8seq[0] && rlen) {
|
||||
bool complete = false;
|
||||
/* two byte sequence (lead byte 110yyyyy) */
|
||||
if(0xC0 <= outs->utf8seq[0] && outs->utf8seq[0] < 0xE0) {
|
||||
outs->utf8seq[1] = *rbuf++;
|
||||
--rlen;
|
||||
complete = true;
|
||||
}
|
||||
/* three byte sequence (lead byte 1110zzzz) */
|
||||
else if(0xE0 <= outs->utf8seq[0] && outs->utf8seq[0] < 0xF0) {
|
||||
if(!outs->utf8seq[1]) {
|
||||
outs->utf8seq[1] = *rbuf++;
|
||||
--rlen;
|
||||
}
|
||||
if(rlen && !outs->utf8seq[2]) {
|
||||
outs->utf8seq[2] = *rbuf++;
|
||||
--rlen;
|
||||
complete = true;
|
||||
}
|
||||
}
|
||||
/* four byte sequence (lead byte 11110uuu) */
|
||||
else if(0xF0 <= outs->utf8seq[0] && outs->utf8seq[0] < 0xF8) {
|
||||
if(!outs->utf8seq[1]) {
|
||||
outs->utf8seq[1] = *rbuf++;
|
||||
--rlen;
|
||||
}
|
||||
if(rlen && !outs->utf8seq[2]) {
|
||||
outs->utf8seq[2] = *rbuf++;
|
||||
--rlen;
|
||||
}
|
||||
if(rlen && !outs->utf8seq[3]) {
|
||||
outs->utf8seq[3] = *rbuf++;
|
||||
--rlen;
|
||||
complete = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(complete) {
|
||||
WCHAR prefix[3] = {0}; /* UTF-16 (1-2 WCHARs) + NUL */
|
||||
|
||||
if(MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)outs->utf8seq, -1,
|
||||
prefix, CURL_ARRAYSIZE(prefix))) {
|
||||
DEBUGASSERT(prefix[2] == L'\0');
|
||||
if(!WriteConsoleW((HANDLE) fhnd, prefix, prefix[1] ? 2 : 1,
|
||||
&chars_written, NULL)) {
|
||||
return CURL_WRITEFUNC_ERROR;
|
||||
}
|
||||
}
|
||||
/* else: UTF-8 input was not well formed and OS is pre-Vista which drops
|
||||
invalid characters instead of writing U+FFFD to output. */
|
||||
memset(outs->utf8seq, 0, sizeof(outs->utf8seq));
|
||||
}
|
||||
}
|
||||
|
||||
/* suppress an incomplete utf-8 sequence at end of rbuf */
|
||||
if(!outs->utf8seq[0] && rlen && (rbuf[rlen - 1] & 0x80)) {
|
||||
/* check for lead byte from a two, three or four byte sequence */
|
||||
if(0xC0 <= rbuf[rlen - 1] && rbuf[rlen - 1] < 0xF8) {
|
||||
outs->utf8seq[0] = rbuf[rlen - 1];
|
||||
rlen -= 1;
|
||||
}
|
||||
else if(rlen >= 2 && IS_TRAILING_BYTE(rbuf[rlen - 1])) {
|
||||
/* check for lead byte from a three or four byte sequence */
|
||||
if(0xE0 <= rbuf[rlen - 2] && rbuf[rlen - 2] < 0xF8) {
|
||||
outs->utf8seq[0] = rbuf[rlen - 2];
|
||||
outs->utf8seq[1] = rbuf[rlen - 1];
|
||||
rlen -= 2;
|
||||
}
|
||||
else if(rlen >= 3 && IS_TRAILING_BYTE(rbuf[rlen - 2])) {
|
||||
/* check for lead byte from a four byte sequence */
|
||||
if(0xF0 <= rbuf[rlen - 3] && rbuf[rlen - 3] < 0xF8) {
|
||||
outs->utf8seq[0] = rbuf[rlen - 3];
|
||||
outs->utf8seq[1] = rbuf[rlen - 2];
|
||||
outs->utf8seq[2] = rbuf[rlen - 1];
|
||||
rlen -= 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(rlen) {
|
||||
/* calculate buffer size for wide characters */
|
||||
DWORD len = (DWORD)MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)rbuf,
|
||||
(int)rlen, NULL, 0);
|
||||
if(!len)
|
||||
return CURL_WRITEFUNC_ERROR;
|
||||
|
||||
/* grow the buffer if needed */
|
||||
if(len > global->term.len) {
|
||||
wchar_t *buf = (wchar_t *) realloc(global->term.buf,
|
||||
len * sizeof(wchar_t));
|
||||
if(!buf)
|
||||
return CURL_WRITEFUNC_ERROR;
|
||||
global->term.len = len;
|
||||
global->term.buf = buf;
|
||||
}
|
||||
|
||||
len = (DWORD)MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)rbuf, (int)rlen,
|
||||
global->term.buf,
|
||||
(int)len);
|
||||
if(!len)
|
||||
return CURL_WRITEFUNC_ERROR;
|
||||
|
||||
if(!WriteConsoleW((HANDLE) fhnd, global->term.buf,
|
||||
len, &chars_written, NULL))
|
||||
return CURL_WRITEFUNC_ERROR;
|
||||
}
|
||||
|
||||
*retp = bytes;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** callback for CURLOPT_WRITEFUNCTION
|
||||
*/
|
||||
|
||||
size_t tool_write_cb(char *buffer, size_t sz, size_t nmemb, void *userdata)
|
||||
{
|
||||
size_t rc;
|
||||
struct per_transfer *per = userdata;
|
||||
struct OutStruct *outs = &per->outs;
|
||||
struct OperationConfig *config = per->config;
|
||||
size_t bytes = sz * nmemb;
|
||||
bool is_tty = global->isatty;
|
||||
#if defined(_WIN32) && !defined(UNDER_CE)
|
||||
CONSOLE_SCREEN_BUFFER_INFO console_info;
|
||||
intptr_t fhnd;
|
||||
#endif
|
||||
|
||||
if(outs->out_null)
|
||||
return bytes;
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
{
|
||||
char *tty = curl_getenv("CURL_ISATTY");
|
||||
if(tty) {
|
||||
is_tty = TRUE;
|
||||
curl_free(tty);
|
||||
}
|
||||
}
|
||||
|
||||
if(config->show_headers) {
|
||||
if(bytes > (size_t)CURL_MAX_HTTP_HEADER) {
|
||||
warnf("Header data size exceeds write limit");
|
||||
return CURL_WRITEFUNC_ERROR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(bytes > (size_t)CURL_MAX_WRITE_SIZE) {
|
||||
warnf("Data size exceeds write limit");
|
||||
return CURL_WRITEFUNC_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
/* Some internal congruency checks on received OutStruct */
|
||||
bool check_fails = FALSE;
|
||||
if(outs->filename) {
|
||||
/* regular file */
|
||||
if(!*outs->filename)
|
||||
check_fails = TRUE;
|
||||
if(!outs->s_isreg)
|
||||
check_fails = TRUE;
|
||||
if(outs->fopened && !outs->stream)
|
||||
check_fails = TRUE;
|
||||
if(!outs->fopened && outs->stream)
|
||||
check_fails = TRUE;
|
||||
if(!outs->fopened && outs->bytes)
|
||||
check_fails = TRUE;
|
||||
}
|
||||
else {
|
||||
/* standard stream */
|
||||
if(!outs->stream || outs->s_isreg || outs->fopened)
|
||||
check_fails = TRUE;
|
||||
if(outs->alloc_filename || outs->is_cd_filename || outs->init)
|
||||
check_fails = TRUE;
|
||||
}
|
||||
if(check_fails) {
|
||||
warnf("Invalid output struct data for write callback");
|
||||
return CURL_WRITEFUNC_ERROR;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if(!outs->stream && !tool_create_output_file(outs, per->config))
|
||||
return CURL_WRITEFUNC_ERROR;
|
||||
|
||||
if(is_tty && (outs->bytes < 2000) && !config->terminal_binary_ok) {
|
||||
/* binary output to terminal? */
|
||||
if(memchr(buffer, 0, bytes)) {
|
||||
warnf("Binary output can mess up your terminal. "
|
||||
"Use \"--output -\" to tell curl to output it to your terminal "
|
||||
"anyway, or consider \"--output <FILE>\" to save to a file.");
|
||||
config->synthetic_error = TRUE;
|
||||
return CURL_WRITEFUNC_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(_WIN32) && !defined(UNDER_CE)
|
||||
fhnd = _get_osfhandle(fileno(outs->stream));
|
||||
/* if Windows console then UTF-8 must be converted to UTF-16 */
|
||||
if(isatty(fileno(outs->stream)) &&
|
||||
GetConsoleScreenBufferInfo((HANDLE)fhnd, &console_info)) {
|
||||
size_t retval = win_console(fhnd, outs, buffer, bytes, &rc);
|
||||
if(retval)
|
||||
return retval;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if(per->hdrcbdata.headlist) {
|
||||
if(tool_write_headers(&per->hdrcbdata, outs->stream))
|
||||
return CURL_WRITEFUNC_ERROR;
|
||||
}
|
||||
rc = fwrite(buffer, sz, nmemb, outs->stream);
|
||||
}
|
||||
|
||||
if(bytes == rc)
|
||||
/* we added this amount of data to the output */
|
||||
outs->bytes += bytes;
|
||||
|
||||
if(config->readbusy) {
|
||||
config->readbusy = FALSE;
|
||||
curl_easy_pause(per->curl, CURLPAUSE_CONT);
|
||||
}
|
||||
|
||||
if(config->nobuffer) {
|
||||
/* output buffering disabled */
|
||||
int res;
|
||||
do {
|
||||
res = fflush(outs->stream);
|
||||
/* Keep retrying in the hope that it is not interrupted sometime */
|
||||
/* !checksrc! disable ERRNOVAR 1 */
|
||||
} while(res && errno == EINTR);
|
||||
if(res)
|
||||
return CURL_WRITEFUNC_ERROR;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
#ifndef HEADER_CURL_TOOL_CB_WRT_H
|
||||
#define HEADER_CURL_TOOL_CB_WRT_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
/*
|
||||
** callback for CURLOPT_WRITEFUNCTION
|
||||
*/
|
||||
|
||||
size_t tool_write_cb(char *buffer, size_t sz, size_t nmemb, void *userdata);
|
||||
|
||||
/* create a local file for writing, return TRUE on success */
|
||||
bool tool_create_output_file(struct OutStruct *outs,
|
||||
struct OperationConfig *config);
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_CB_WRT_H */
|
||||
+284
@@ -0,0 +1,284 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#include "tool_cfgable.h"
|
||||
#include "tool_formparse.h"
|
||||
#include "tool_paramhlp.h"
|
||||
#include "tool_main.h"
|
||||
#include "tool_msgs.h"
|
||||
#include "memdebug.h" /* keep this as LAST include */
|
||||
|
||||
static struct GlobalConfig globalconf;
|
||||
struct GlobalConfig *global;
|
||||
|
||||
struct OperationConfig *config_alloc(void)
|
||||
{
|
||||
struct OperationConfig *config =
|
||||
calloc(1, sizeof(struct OperationConfig));
|
||||
if(!config)
|
||||
return NULL;
|
||||
|
||||
config->use_httpget = FALSE;
|
||||
config->create_dirs = FALSE;
|
||||
config->maxredirs = DEFAULT_MAXREDIRS;
|
||||
config->proto_present = FALSE;
|
||||
config->proto_redir_present = FALSE;
|
||||
config->proto_default = NULL;
|
||||
config->tcp_nodelay = TRUE; /* enabled by default */
|
||||
config->happy_eyeballs_timeout_ms = CURL_HET_DEFAULT;
|
||||
config->http09_allowed = FALSE;
|
||||
config->ftp_skip_ip = TRUE;
|
||||
config->file_clobber_mode = CLOBBER_DEFAULT;
|
||||
config->upload_flags = CURLULFLAG_SEEN;
|
||||
curlx_dyn_init(&config->postdata, MAX_FILE2MEMORY);
|
||||
return config;
|
||||
}
|
||||
|
||||
static void free_config_fields(struct OperationConfig *config)
|
||||
{
|
||||
struct getout *urlnode;
|
||||
|
||||
tool_safefree(config->useragent);
|
||||
tool_safefree(config->altsvc);
|
||||
tool_safefree(config->hsts);
|
||||
tool_safefree(config->haproxy_clientip);
|
||||
curl_slist_free_all(config->cookies);
|
||||
tool_safefree(config->cookiejar);
|
||||
curl_slist_free_all(config->cookiefiles);
|
||||
|
||||
curlx_dyn_free(&config->postdata);
|
||||
tool_safefree(config->query);
|
||||
tool_safefree(config->referer);
|
||||
|
||||
tool_safefree(config->headerfile);
|
||||
tool_safefree(config->ftpport);
|
||||
tool_safefree(config->iface);
|
||||
|
||||
tool_safefree(config->range);
|
||||
|
||||
tool_safefree(config->userpwd);
|
||||
tool_safefree(config->tls_username);
|
||||
tool_safefree(config->tls_password);
|
||||
tool_safefree(config->tls_authtype);
|
||||
tool_safefree(config->proxy_tls_username);
|
||||
tool_safefree(config->proxy_tls_password);
|
||||
tool_safefree(config->proxy_tls_authtype);
|
||||
tool_safefree(config->proxyuserpwd);
|
||||
tool_safefree(config->proxy);
|
||||
|
||||
tool_safefree(config->dns_ipv6_addr);
|
||||
tool_safefree(config->dns_ipv4_addr);
|
||||
tool_safefree(config->dns_interface);
|
||||
tool_safefree(config->dns_servers);
|
||||
|
||||
tool_safefree(config->noproxy);
|
||||
|
||||
tool_safefree(config->mail_from);
|
||||
curl_slist_free_all(config->mail_rcpt);
|
||||
tool_safefree(config->mail_auth);
|
||||
|
||||
tool_safefree(config->netrc_file);
|
||||
tool_safefree(config->output_dir);
|
||||
tool_safefree(config->proto_str);
|
||||
tool_safefree(config->proto_redir_str);
|
||||
|
||||
urlnode = config->url_list;
|
||||
while(urlnode) {
|
||||
struct getout *next = urlnode->next;
|
||||
tool_safefree(urlnode->url);
|
||||
tool_safefree(urlnode->outfile);
|
||||
tool_safefree(urlnode->infile);
|
||||
tool_safefree(urlnode);
|
||||
urlnode = next;
|
||||
}
|
||||
config->url_list = NULL;
|
||||
config->url_last = NULL;
|
||||
config->url_get = NULL;
|
||||
config->url_out = NULL;
|
||||
|
||||
#ifndef CURL_DISABLE_IPFS
|
||||
tool_safefree(config->ipfs_gateway);
|
||||
#endif /* !CURL_DISABLE_IPFS */
|
||||
tool_safefree(config->doh_url);
|
||||
tool_safefree(config->cipher_list);
|
||||
tool_safefree(config->proxy_cipher_list);
|
||||
tool_safefree(config->cipher13_list);
|
||||
tool_safefree(config->proxy_cipher13_list);
|
||||
tool_safefree(config->cert);
|
||||
tool_safefree(config->proxy_cert);
|
||||
tool_safefree(config->cert_type);
|
||||
tool_safefree(config->proxy_cert_type);
|
||||
tool_safefree(config->cacert);
|
||||
tool_safefree(config->login_options);
|
||||
tool_safefree(config->proxy_cacert);
|
||||
tool_safefree(config->capath);
|
||||
tool_safefree(config->proxy_capath);
|
||||
tool_safefree(config->crlfile);
|
||||
tool_safefree(config->pinnedpubkey);
|
||||
tool_safefree(config->proxy_pinnedpubkey);
|
||||
tool_safefree(config->proxy_crlfile);
|
||||
tool_safefree(config->key);
|
||||
tool_safefree(config->proxy_key);
|
||||
tool_safefree(config->key_type);
|
||||
tool_safefree(config->proxy_key_type);
|
||||
tool_safefree(config->key_passwd);
|
||||
tool_safefree(config->proxy_key_passwd);
|
||||
tool_safefree(config->pubkey);
|
||||
tool_safefree(config->hostpubmd5);
|
||||
tool_safefree(config->hostpubsha256);
|
||||
tool_safefree(config->engine);
|
||||
tool_safefree(config->etag_save_file);
|
||||
tool_safefree(config->etag_compare_file);
|
||||
tool_safefree(config->ssl_ec_curves);
|
||||
tool_safefree(config->request_target);
|
||||
tool_safefree(config->customrequest);
|
||||
tool_safefree(config->krblevel);
|
||||
tool_safefree(config->oauth_bearer);
|
||||
tool_safefree(config->sasl_authzid);
|
||||
tool_safefree(config->unix_socket_path);
|
||||
tool_safefree(config->writeout);
|
||||
tool_safefree(config->proto_default);
|
||||
|
||||
curl_slist_free_all(config->quote);
|
||||
curl_slist_free_all(config->postquote);
|
||||
curl_slist_free_all(config->prequote);
|
||||
|
||||
curl_slist_free_all(config->headers);
|
||||
curl_slist_free_all(config->proxyheaders);
|
||||
|
||||
curl_mime_free(config->mimepost);
|
||||
config->mimepost = NULL;
|
||||
tool_mime_free(config->mimeroot);
|
||||
config->mimeroot = NULL;
|
||||
config->mimecurrent = NULL;
|
||||
|
||||
curl_slist_free_all(config->telnet_options);
|
||||
curl_slist_free_all(config->resolve);
|
||||
curl_slist_free_all(config->connect_to);
|
||||
|
||||
tool_safefree(config->preproxy);
|
||||
tool_safefree(config->proxy_service_name);
|
||||
tool_safefree(config->service_name);
|
||||
tool_safefree(config->ftp_account);
|
||||
tool_safefree(config->ftp_alternative_to_user);
|
||||
tool_safefree(config->aws_sigv4);
|
||||
tool_safefree(config->ech);
|
||||
tool_safefree(config->ech_config);
|
||||
tool_safefree(config->ech_public);
|
||||
tool_safefree(config->knownhosts);
|
||||
}
|
||||
|
||||
void config_free(struct OperationConfig *config)
|
||||
{
|
||||
struct OperationConfig *last = config;
|
||||
|
||||
/* Free each of the structures in reverse order */
|
||||
while(last) {
|
||||
struct OperationConfig *prev = last->prev;
|
||||
|
||||
free_config_fields(last);
|
||||
free(last);
|
||||
|
||||
last = prev;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the main global constructor for the app. Call this before
|
||||
* _any_ libcurl usage. If this fails, *NO* libcurl functions may be
|
||||
* used, or havoc may be the result.
|
||||
*/
|
||||
CURLcode globalconf_init(void)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
global = &globalconf;
|
||||
|
||||
#ifdef __DJGPP__
|
||||
/* stop stat() wasting time */
|
||||
_djstat_flags |= _STAT_INODE | _STAT_EXEC_MAGIC | _STAT_DIRSIZE;
|
||||
#endif
|
||||
|
||||
/* Initialise the global config */
|
||||
global->showerror = FALSE; /* show errors when silent */
|
||||
global->styled_output = TRUE; /* enable detection */
|
||||
global->parallel_max = PARALLEL_DEFAULT;
|
||||
|
||||
/* Allocate the initial operate config */
|
||||
global->first = global->last = config_alloc();
|
||||
if(global->first) {
|
||||
/* Perform the libcurl initialization */
|
||||
result = curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||
if(!result) {
|
||||
/* Get information about libcurl */
|
||||
result = get_libcurl_info();
|
||||
|
||||
if(result) {
|
||||
errorf("error retrieving curl library information");
|
||||
free(global->first);
|
||||
}
|
||||
}
|
||||
else {
|
||||
errorf("error initializing curl library");
|
||||
free(global->first);
|
||||
}
|
||||
}
|
||||
else {
|
||||
errorf("error initializing curl");
|
||||
result = CURLE_FAILED_INIT;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void free_globalconfig(void)
|
||||
{
|
||||
tool_safefree(global->trace_dump);
|
||||
|
||||
if(global->trace_fopened && global->trace_stream)
|
||||
curlx_fclose(global->trace_stream);
|
||||
global->trace_stream = NULL;
|
||||
|
||||
tool_safefree(global->libcurl);
|
||||
#if defined(_WIN32) && !defined(UNDER_CE)
|
||||
free(global->term.buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the main global destructor for the app. Call this after _all_
|
||||
* libcurl usage is done.
|
||||
*/
|
||||
void globalconf_free(void)
|
||||
{
|
||||
/* Cleanup the easy handle */
|
||||
/* Main cleanup */
|
||||
curl_global_cleanup();
|
||||
free_globalconfig();
|
||||
|
||||
/* Free the OperationConfig structures */
|
||||
config_free(global->last);
|
||||
global->first = NULL;
|
||||
global->last = NULL;
|
||||
}
|
||||
+379
@@ -0,0 +1,379 @@
|
||||
#ifndef HEADER_CURL_TOOL_CFGABLE_H
|
||||
#define HEADER_CURL_TOOL_CFGABLE_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include <curl/mprintf.h>
|
||||
#include "tool_setup.h"
|
||||
#include "tool_sdecls.h"
|
||||
#include "tool_urlglob.h"
|
||||
#include "var.h"
|
||||
|
||||
/* the type we use for storing a single boolean bit */
|
||||
#ifndef BIT
|
||||
#ifdef _MSC_VER
|
||||
#define BIT(x) bool x
|
||||
#else
|
||||
#define BIT(x) unsigned int x:1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define checkprefix(a,b) curl_strnequal(b, STRCONST(a))
|
||||
|
||||
#define tool_safefree(ptr) \
|
||||
do { free((ptr)); (ptr) = NULL;} while(0)
|
||||
|
||||
extern struct GlobalConfig *global;
|
||||
|
||||
struct State {
|
||||
struct getout *urlnode;
|
||||
struct URLGlob inglob;
|
||||
struct URLGlob urlglob;
|
||||
char *httpgetfields;
|
||||
char *uploadfile;
|
||||
curl_off_t upnum; /* number of files to upload */
|
||||
curl_off_t upidx; /* index for upload glob */
|
||||
curl_off_t urlnum; /* how many iterations this URL has with ranges etc */
|
||||
curl_off_t urlidx; /* index for globbed URLs */
|
||||
};
|
||||
|
||||
#define FAIL_NONE 0
|
||||
#define FAIL_WITH_BODY 1
|
||||
#define FAIL_WO_BODY 2
|
||||
|
||||
struct OperationConfig {
|
||||
struct dynbuf postdata;
|
||||
char *useragent;
|
||||
struct curl_slist *cookies; /* cookies to serialize into a single line */
|
||||
char *cookiejar; /* write to this file */
|
||||
struct curl_slist *cookiefiles; /* file(s) to load cookies from */
|
||||
char *altsvc; /* alt-svc cache filename */
|
||||
char *hsts; /* HSTS cache filename */
|
||||
char *proto_str;
|
||||
char *proto_redir_str;
|
||||
char *proto_default;
|
||||
curl_off_t resume_from;
|
||||
char *postfields;
|
||||
char *referer;
|
||||
char *query;
|
||||
curl_off_t max_filesize;
|
||||
char *output_dir;
|
||||
char *headerfile;
|
||||
char *ftpport;
|
||||
char *iface;
|
||||
char *range;
|
||||
char *dns_servers; /* dot notation: 1.1.1.1;2.2.2.2 */
|
||||
char *dns_interface; /* interface name */
|
||||
char *dns_ipv4_addr; /* dot notation */
|
||||
char *dns_ipv6_addr; /* dot notation */
|
||||
char *userpwd;
|
||||
char *login_options;
|
||||
char *tls_username;
|
||||
char *tls_password;
|
||||
char *tls_authtype;
|
||||
char *proxy_tls_username;
|
||||
char *proxy_tls_password;
|
||||
char *proxy_tls_authtype;
|
||||
char *proxyuserpwd;
|
||||
char *proxy;
|
||||
char *noproxy;
|
||||
char *knownhosts;
|
||||
char *mail_from;
|
||||
struct curl_slist *mail_rcpt;
|
||||
char *mail_auth;
|
||||
char *sasl_authzid; /* Authorization identity (identity to use) */
|
||||
char *netrc_file;
|
||||
struct getout *url_list; /* point to the first node */
|
||||
struct getout *url_last; /* point to the last/current node */
|
||||
struct getout *url_get; /* point to the node to fill in URL */
|
||||
struct getout *url_out; /* point to the node to fill in outfile */
|
||||
struct getout *url_ul; /* point to the node to fill in upload */
|
||||
size_t num_urls; /* number of URLs added to the list */
|
||||
#ifndef CURL_DISABLE_IPFS
|
||||
char *ipfs_gateway;
|
||||
#endif /* !CURL_DISABLE_IPFS */
|
||||
char *doh_url;
|
||||
char *cipher_list;
|
||||
char *proxy_cipher_list;
|
||||
char *cipher13_list;
|
||||
char *proxy_cipher13_list;
|
||||
char *cert;
|
||||
char *proxy_cert;
|
||||
char *cert_type;
|
||||
char *proxy_cert_type;
|
||||
char *cacert;
|
||||
char *proxy_cacert;
|
||||
char *capath;
|
||||
char *proxy_capath;
|
||||
char *crlfile;
|
||||
char *proxy_crlfile;
|
||||
char *pinnedpubkey;
|
||||
char *proxy_pinnedpubkey;
|
||||
char *key;
|
||||
char *proxy_key;
|
||||
char *key_type;
|
||||
char *proxy_key_type;
|
||||
char *key_passwd;
|
||||
char *proxy_key_passwd;
|
||||
char *pubkey;
|
||||
char *hostpubmd5;
|
||||
char *hostpubsha256;
|
||||
char *engine;
|
||||
char *etag_save_file;
|
||||
char *etag_compare_file;
|
||||
char *customrequest;
|
||||
char *ssl_ec_curves;
|
||||
char *ssl_signature_algorithms;
|
||||
char *krblevel;
|
||||
char *request_target;
|
||||
char *writeout; /* %-styled format string to output */
|
||||
struct curl_slist *quote;
|
||||
struct curl_slist *postquote;
|
||||
struct curl_slist *prequote;
|
||||
struct curl_slist *headers;
|
||||
struct curl_slist *proxyheaders;
|
||||
struct tool_mime *mimeroot;
|
||||
struct tool_mime *mimecurrent;
|
||||
curl_mime *mimepost;
|
||||
struct curl_slist *telnet_options;
|
||||
struct curl_slist *resolve;
|
||||
struct curl_slist *connect_to;
|
||||
char *preproxy;
|
||||
char *proxy_service_name; /* set authentication service name for HTTP and
|
||||
SOCKS5 proxies */
|
||||
char *service_name; /* set authentication service name for DIGEST-MD5,
|
||||
Kerberos 5 and SPNEGO */
|
||||
char *ftp_account; /* for ACCT */
|
||||
char *ftp_alternative_to_user; /* send command if USER/PASS fails */
|
||||
char *oauth_bearer; /* OAuth 2.0 bearer token */
|
||||
char *unix_socket_path; /* path to Unix domain socket */
|
||||
char *haproxy_clientip; /* client IP for HAProxy protocol */
|
||||
char *aws_sigv4;
|
||||
char *ech; /* Config set by --ech keywords */
|
||||
char *ech_config; /* Config set by "--ech esl:" option */
|
||||
char *ech_public; /* Config set by "--ech pn:" option */
|
||||
struct OperationConfig *prev;
|
||||
struct OperationConfig *next; /* Always last in the struct */
|
||||
curl_off_t condtime;
|
||||
/* for bandwidth limiting features: */
|
||||
curl_off_t sendpersecond; /* send to peer */
|
||||
curl_off_t recvpersecond; /* receive from peer */
|
||||
|
||||
long proxy_ssl_version;
|
||||
long ip_version;
|
||||
long create_file_mode; /* CURLOPT_NEW_FILE_PERMS */
|
||||
long low_speed_limit;
|
||||
long low_speed_time;
|
||||
long ip_tos; /* IP Type of Service */
|
||||
long vlan_priority; /* VLAN priority */
|
||||
long localport;
|
||||
long localportrange;
|
||||
unsigned long authtype; /* auth bitmask */
|
||||
long timeout_ms;
|
||||
long connecttimeout_ms;
|
||||
long maxredirs;
|
||||
long httpversion;
|
||||
unsigned long socks5_auth;/* auth bitmask for socks5 proxies */
|
||||
long req_retry; /* number of retries */
|
||||
long retry_delay_ms; /* delay between retries (in milliseconds),
|
||||
0 means increase exponentially */
|
||||
long retry_maxtime_ms; /* maximum time to keep retrying */
|
||||
|
||||
unsigned long mime_options; /* Mime option flags. */
|
||||
long tftp_blksize; /* TFTP BLKSIZE option */
|
||||
long alivetime; /* keepalive-time */
|
||||
long alivecnt; /* keepalive-cnt */
|
||||
long gssapi_delegation;
|
||||
long expect100timeout_ms;
|
||||
long happy_eyeballs_timeout_ms; /* happy eyeballs timeout in milliseconds.
|
||||
0 is valid. default: CURL_HET_DEFAULT. */
|
||||
unsigned long timecond;
|
||||
long followlocation; /* follow http redirects mode */
|
||||
HttpReq httpreq;
|
||||
long proxyver; /* set to CURLPROXY_HTTP* define */
|
||||
long ftp_ssl_ccc_mode;
|
||||
long ftp_filemethod;
|
||||
enum {
|
||||
CLOBBER_DEFAULT, /* Provides compatibility with previous versions of curl,
|
||||
by using the default behavior for -o, -O, and -J.
|
||||
If those options would have overwritten files, like
|
||||
-o and -O would, then overwrite them. In the case of
|
||||
-J, this will not overwrite any files. */
|
||||
CLOBBER_NEVER, /* If the file exists, always fail */
|
||||
CLOBBER_ALWAYS /* If the file exists, always overwrite it */
|
||||
} file_clobber_mode;
|
||||
unsigned char upload_flags; /* Bitmask for --upload-flags */
|
||||
unsigned short porttouse;
|
||||
unsigned char ssl_version; /* 0 - 4, 0 being default */
|
||||
unsigned char ssl_version_max; /* 0 - 4, 0 being default */
|
||||
unsigned char fail; /* NONE, with body, without body */
|
||||
BIT(remote_name_all); /* --remote-name-all */
|
||||
BIT(remote_time);
|
||||
BIT(cookiesession); /* new session? */
|
||||
BIT(encoding); /* Accept-Encoding please */
|
||||
BIT(tr_encoding); /* Transfer-Encoding please */
|
||||
BIT(use_resume);
|
||||
BIT(resume_from_current);
|
||||
BIT(disable_epsv);
|
||||
BIT(disable_eprt);
|
||||
BIT(ftp_pret);
|
||||
BIT(proto_present);
|
||||
BIT(proto_redir_present);
|
||||
BIT(mail_rcpt_allowfails); /* --mail-rcpt-allowfails */
|
||||
BIT(sasl_ir); /* Enable/disable SASL initial response */
|
||||
BIT(proxytunnel);
|
||||
BIT(ftp_append); /* APPE on ftp */
|
||||
BIT(use_ascii); /* select ASCII or text transfer */
|
||||
BIT(autoreferer); /* automatically set referer */
|
||||
BIT(show_headers); /* show headers to data output */
|
||||
BIT(no_body); /* do not get the body */
|
||||
BIT(dirlistonly); /* only get the FTP dir list */
|
||||
BIT(unrestricted_auth); /* Continue to send authentication (user+password)
|
||||
when following redirects, even when hostname
|
||||
changed */
|
||||
BIT(netrc_opt);
|
||||
BIT(netrc);
|
||||
BIT(crlf);
|
||||
BIT(http09_allowed);
|
||||
BIT(nobuffer);
|
||||
BIT(readbusy); /* set when reading input returns EAGAIN */
|
||||
BIT(globoff);
|
||||
BIT(use_httpget);
|
||||
BIT(insecure_ok); /* set TRUE to allow insecure SSL connects */
|
||||
BIT(doh_insecure_ok); /* set TRUE to allow insecure SSL connects
|
||||
for DoH */
|
||||
BIT(proxy_insecure_ok); /* set TRUE to allow insecure SSL connects
|
||||
for proxy */
|
||||
BIT(terminal_binary_ok);
|
||||
BIT(verifystatus);
|
||||
BIT(doh_verifystatus);
|
||||
BIT(create_dirs);
|
||||
BIT(ftp_create_dirs);
|
||||
BIT(ftp_skip_ip);
|
||||
BIT(proxynegotiate);
|
||||
BIT(proxyntlm);
|
||||
BIT(proxydigest);
|
||||
BIT(proxybasic);
|
||||
BIT(proxyanyauth);
|
||||
BIT(jsoned); /* added json content-type */
|
||||
BIT(ftp_ssl);
|
||||
BIT(ftp_ssl_reqd);
|
||||
BIT(ftp_ssl_control);
|
||||
BIT(ftp_ssl_ccc);
|
||||
BIT(socks5_gssapi_nec); /* The NEC reference server does not protect the
|
||||
encryption type exchange */
|
||||
BIT(tcp_nodelay);
|
||||
BIT(tcp_fastopen);
|
||||
BIT(retry_all_errors); /* retry on any error */
|
||||
BIT(retry_connrefused); /* set connection refused as a transient error */
|
||||
BIT(tftp_no_options); /* do not send TFTP options requests */
|
||||
BIT(ignorecl); /* --ignore-content-length */
|
||||
BIT(disable_sessionid);
|
||||
|
||||
BIT(raw);
|
||||
BIT(post301);
|
||||
BIT(post302);
|
||||
BIT(post303);
|
||||
BIT(nokeepalive); /* for keepalive needs */
|
||||
BIT(content_disposition); /* use Content-disposition filename */
|
||||
|
||||
BIT(xattr); /* store metadata in extended attributes */
|
||||
BIT(ssl_allow_beast); /* allow this SSL vulnerability */
|
||||
BIT(ssl_allow_earlydata); /* allow use of TLSv1.3 early data */
|
||||
BIT(proxy_ssl_allow_beast); /* allow this SSL vulnerability for proxy */
|
||||
BIT(ssl_no_revoke); /* disable SSL certificate revocation checks */
|
||||
BIT(ssl_revoke_best_effort); /* ignore SSL revocation offline/missing
|
||||
revocation list errors */
|
||||
|
||||
BIT(native_ca_store); /* use the native OS CA store */
|
||||
BIT(proxy_native_ca_store); /* use the native OS CA store for proxy */
|
||||
BIT(ssl_auto_client_cert); /* automatically locate and use a client
|
||||
certificate for authentication (Schannel) */
|
||||
BIT(proxy_ssl_auto_client_cert); /* proxy version of ssl_auto_client_cert */
|
||||
BIT(noalpn); /* enable/disable TLS ALPN extension */
|
||||
BIT(abstract_unix_socket); /* path to an abstract Unix domain socket */
|
||||
BIT(path_as_is);
|
||||
BIT(suppress_connect_headers); /* suppress proxy CONNECT response headers
|
||||
from user callbacks */
|
||||
BIT(synthetic_error); /* if TRUE, this is tool-internal error */
|
||||
BIT(ssh_compression); /* enable/disable SSH compression */
|
||||
BIT(haproxy_protocol); /* whether to send HAProxy protocol v1 */
|
||||
BIT(disallow_username_in_url); /* disallow usernames in URLs */
|
||||
BIT(mptcp); /* enable MPTCP support */
|
||||
BIT(rm_partial); /* on error, remove partially written output
|
||||
files */
|
||||
BIT(skip_existing);
|
||||
};
|
||||
|
||||
#if defined(_WIN32) && !defined(UNDER_CE)
|
||||
struct termout {
|
||||
wchar_t *buf;
|
||||
DWORD len;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct GlobalConfig {
|
||||
struct State state; /* for create_transfer() */
|
||||
char *trace_dump; /* file to dump the network trace to */
|
||||
FILE *trace_stream;
|
||||
char *libcurl; /* Output libcurl code to this filename */
|
||||
char *ssl_sessions; /* file to load/save SSL session tickets */
|
||||
struct tool_var *variables;
|
||||
struct OperationConfig *first;
|
||||
struct OperationConfig *current;
|
||||
struct OperationConfig *last;
|
||||
#if defined(_WIN32) && !defined(UNDER_CE)
|
||||
struct termout term;
|
||||
#endif
|
||||
timediff_t ms_per_transfer; /* start next transfer after (at least) this
|
||||
many milliseconds */
|
||||
trace tracetype;
|
||||
int progressmode; /* CURL_PROGRESS_BAR / CURL_PROGRESS_STATS */
|
||||
unsigned short parallel_host; /* MAX_PARALLEL_HOST is the maximum */
|
||||
unsigned short parallel_max; /* MAX_PARALLEL is the maximum */
|
||||
unsigned char verbosity; /* How verbose we should be */
|
||||
#ifdef DEBUGBUILD
|
||||
BIT(test_duphandle);
|
||||
BIT(test_event_based);
|
||||
#endif
|
||||
BIT(parallel);
|
||||
BIT(parallel_connect);
|
||||
BIT(fail_early); /* exit on first transfer error */
|
||||
BIT(styled_output); /* enable fancy output style detection */
|
||||
BIT(trace_fopened);
|
||||
BIT(tracetime); /* include timestamp? */
|
||||
BIT(traceids); /* include xfer-/conn-id? */
|
||||
BIT(showerror); /* show errors when silent */
|
||||
BIT(silent); /* do not show messages, --silent given */
|
||||
BIT(noprogress); /* do not show progress bar */
|
||||
BIT(isatty); /* Updated internally if output is a tty */
|
||||
BIT(trace_set); /* --trace-config has been used */
|
||||
};
|
||||
|
||||
struct OperationConfig *config_alloc(void);
|
||||
void config_free(struct OperationConfig *config);
|
||||
CURLcode globalconf_init(void);
|
||||
void globalconf_free(void);
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_CFGABLE_H */
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#if defined(_WIN32) && !defined(UNDER_CE)
|
||||
# include <direct.h>
|
||||
#endif
|
||||
|
||||
#include "tool_dirhie.h"
|
||||
#include "tool_msgs.h"
|
||||
|
||||
#include "memdebug.h" /* keep this as LAST include */
|
||||
|
||||
#if defined(_WIN32) || (defined(MSDOS) && !defined(__DJGPP__))
|
||||
# define mkdir(x,y) (mkdir)((x))
|
||||
# ifndef F_OK
|
||||
# define F_OK 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static void show_dir_errno(const char *name)
|
||||
{
|
||||
switch(errno) {
|
||||
#ifdef EACCES
|
||||
/* !checksrc! disable ERRNOVAR 1 */
|
||||
case EACCES:
|
||||
errorf("You do not have permission to create %s", name);
|
||||
break;
|
||||
#endif
|
||||
#ifdef ENAMETOOLONG
|
||||
case ENAMETOOLONG:
|
||||
errorf("The directory name %s is too long", name);
|
||||
break;
|
||||
#endif
|
||||
#ifdef EROFS
|
||||
case EROFS:
|
||||
errorf("%s resides on a read-only file system", name);
|
||||
break;
|
||||
#endif
|
||||
#ifdef ENOSPC
|
||||
case ENOSPC:
|
||||
errorf("No space left on the file system that will "
|
||||
"contain the directory %s", name);
|
||||
break;
|
||||
#endif
|
||||
#ifdef EDQUOT
|
||||
case EDQUOT:
|
||||
errorf("Cannot create directory %s because you "
|
||||
"exceeded your quota", name);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
errorf("Error creating directory %s", name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the needed directory hierarchy recursively in order to save
|
||||
* multi-GETs in file output, ie:
|
||||
* curl "http://example.org/dir[1-5]/file[1-5].txt" -o "dir#1/file#2.txt"
|
||||
* should create all the dir* automagically
|
||||
*/
|
||||
|
||||
#if defined(_WIN32) || defined(__DJGPP__)
|
||||
/* systems that may use either or when specifying a path */
|
||||
#define PATH_DELIMITERS "\\/"
|
||||
#else
|
||||
#define PATH_DELIMITERS DIR_CHAR
|
||||
#endif
|
||||
|
||||
CURLcode create_dir_hierarchy(const char *outfile)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
size_t outlen = strlen(outfile);
|
||||
struct dynbuf dirbuf;
|
||||
|
||||
curlx_dyn_init(&dirbuf, outlen + 1);
|
||||
|
||||
while(*outfile) {
|
||||
bool skip = FALSE;
|
||||
size_t seplen = strspn(outfile, PATH_DELIMITERS);
|
||||
size_t len = strcspn(&outfile[seplen], PATH_DELIMITERS);
|
||||
|
||||
/* the last path component is the file and it ends with a null byte */
|
||||
if(!outfile[len + seplen])
|
||||
break;
|
||||
|
||||
#if defined(_WIN32) || defined(MSDOS)
|
||||
if(!curlx_dyn_len(&dirbuf)) {
|
||||
/* Skip creating a drive's current directory. It may seem as though that
|
||||
would harmlessly fail but it could be a corner case if X: did not
|
||||
exist, since we would be creating it erroneously. eg if outfile is
|
||||
X:\foo\bar\filename then do not mkdir X: This logic takes into
|
||||
account unsupported drives !:, 1:, etc. */
|
||||
if(len > 1 && (outfile[1]==':'))
|
||||
skip = TRUE;
|
||||
}
|
||||
#endif
|
||||
/* insert the leading separators (possibly plural) plus the following
|
||||
directory name */
|
||||
result = curlx_dyn_addn(&dirbuf, outfile, seplen + len);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
/* Create directory. Ignore access denied error to allow traversal. */
|
||||
/* !checksrc! disable ERRNOVAR 1 */
|
||||
if(!skip && (mkdir(curlx_dyn_ptr(&dirbuf), (mode_t)0000750) == -1) &&
|
||||
(errno != EACCES) && (errno != EEXIST)) {
|
||||
show_dir_errno(curlx_dyn_ptr(&dirbuf));
|
||||
result = CURLE_WRITE_ERROR;
|
||||
break; /* get out of loop */
|
||||
}
|
||||
outfile += len + seplen;
|
||||
}
|
||||
|
||||
curlx_dyn_free(&dirbuf);
|
||||
|
||||
return result;
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
#ifndef HEADER_CURL_TOOL_DIRHIE_H
|
||||
#define HEADER_CURL_TOOL_DIRHIE_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
#include "tool_cfgable.h"
|
||||
|
||||
CURLcode create_dir_hierarchy(const char *outfileo);
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_DIRHIE_H */
|
||||
+956
@@ -0,0 +1,956 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#if defined(_WIN32) || defined(MSDOS)
|
||||
|
||||
#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
|
||||
# include <libgen.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <stdlib.h>
|
||||
# include <tlhelp32.h>
|
||||
# include "tool_cfgable.h"
|
||||
# include "tool_libinfo.h"
|
||||
#endif
|
||||
|
||||
#include "tool_bname.h"
|
||||
#include "tool_doswin.h"
|
||||
#include "tool_msgs.h"
|
||||
|
||||
#include "memdebug.h" /* keep this as LAST include */
|
||||
|
||||
#ifdef _WIN32
|
||||
# undef PATH_MAX
|
||||
# define PATH_MAX MAX_PATH
|
||||
#elif !defined(__DJGPP__) || (__DJGPP__ < 2) /* DJGPP 2.0 has _use_lfn() */
|
||||
# define CURL_USE_LFN(f) 0 /* long filenames never available */
|
||||
#elif defined(__DJGPP__)
|
||||
# include <fcntl.h> /* for _use_lfn(f) prototype */
|
||||
# define CURL_USE_LFN(f) _use_lfn(f)
|
||||
#endif
|
||||
|
||||
#ifdef MSDOS
|
||||
|
||||
#ifndef S_ISCHR
|
||||
# ifdef S_IFCHR
|
||||
# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
|
||||
# else
|
||||
# define S_ISCHR(m) (0) /* cannot tell if file is a device */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* only used by msdosify() */
|
||||
static SANITIZEcode truncate_dryrun(const char *path,
|
||||
const size_t truncate_pos);
|
||||
static SANITIZEcode msdosify(char **const sanitized, const char *file_name,
|
||||
int flags);
|
||||
#endif
|
||||
static SANITIZEcode rename_if_reserved_dos(char **const sanitized,
|
||||
const char *file_name,
|
||||
int flags);
|
||||
|
||||
|
||||
/*
|
||||
Sanitize a file or path name.
|
||||
|
||||
All banned characters are replaced by underscores, for example:
|
||||
f?*foo => f__foo
|
||||
f:foo::$DATA => f_foo__$DATA
|
||||
f:\foo:bar => f__foo_bar
|
||||
f:\foo:bar => f:\foo:bar (flag SANITIZE_ALLOW_PATH)
|
||||
|
||||
This function was implemented according to the guidelines in 'Naming Files,
|
||||
Paths, and Namespaces' section 'Naming Conventions'.
|
||||
https://learn.microsoft.com/windows/win32/fileio/naming-a-file
|
||||
|
||||
Flags
|
||||
-----
|
||||
SANITIZE_ALLOW_PATH: Allow path separators and colons.
|
||||
Without this flag path separators and colons are sanitized.
|
||||
|
||||
SANITIZE_ALLOW_RESERVED: Allow reserved device names.
|
||||
Without this flag a reserved device name is renamed (COM1 => _COM1) unless it
|
||||
is in a UNC prefixed path.
|
||||
|
||||
Success: (SANITIZE_ERR_OK) *sanitized points to a sanitized copy of file_name.
|
||||
Failure: (!= SANITIZE_ERR_OK) *sanitized is NULL.
|
||||
*/
|
||||
SANITIZEcode sanitize_file_name(char **const sanitized, const char *file_name,
|
||||
int flags)
|
||||
{
|
||||
char *p, *target;
|
||||
size_t len;
|
||||
SANITIZEcode sc;
|
||||
size_t max_sanitized_len;
|
||||
|
||||
if(!sanitized)
|
||||
return SANITIZE_ERR_BAD_ARGUMENT;
|
||||
|
||||
*sanitized = NULL;
|
||||
|
||||
if(!file_name)
|
||||
return SANITIZE_ERR_BAD_ARGUMENT;
|
||||
|
||||
if(flags & SANITIZE_ALLOW_PATH) {
|
||||
#ifndef MSDOS
|
||||
if(file_name[0] == '\\' && file_name[1] == '\\')
|
||||
/* UNC prefixed path \\ (eg \\?\C:\foo) */
|
||||
max_sanitized_len = 32767-1;
|
||||
else
|
||||
#endif
|
||||
max_sanitized_len = PATH_MAX-1;
|
||||
}
|
||||
else
|
||||
/* The maximum length of a filename. FILENAME_MAX is often the same as
|
||||
PATH_MAX, in other words it is 260 and does not discount the path
|
||||
information therefore we should not use it. */
|
||||
max_sanitized_len = (PATH_MAX-1 > 255) ? 255 : PATH_MAX-1;
|
||||
|
||||
len = strlen(file_name);
|
||||
if(len > max_sanitized_len)
|
||||
return SANITIZE_ERR_INVALID_PATH;
|
||||
|
||||
target = strdup(file_name);
|
||||
if(!target)
|
||||
return SANITIZE_ERR_OUT_OF_MEMORY;
|
||||
|
||||
#ifndef MSDOS
|
||||
if((flags & SANITIZE_ALLOW_PATH) && !strncmp(target, "\\\\?\\", 4))
|
||||
/* Skip the literal path prefix \\?\ */
|
||||
p = target + 4;
|
||||
else
|
||||
#endif
|
||||
p = target;
|
||||
|
||||
/* replace control characters and other banned characters */
|
||||
for(; *p; ++p) {
|
||||
const char *banned;
|
||||
|
||||
if((1 <= *p && *p <= 31) ||
|
||||
(!(flags & SANITIZE_ALLOW_PATH) && *p == ':') ||
|
||||
(!(flags & SANITIZE_ALLOW_PATH) && (*p == '/' || *p == '\\'))) {
|
||||
*p = '_';
|
||||
continue;
|
||||
}
|
||||
|
||||
for(banned = "|<>\"?*"; *banned; ++banned) {
|
||||
if(*p == *banned) {
|
||||
*p = '_';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* remove trailing spaces and periods if not allowing paths */
|
||||
if(!(flags & SANITIZE_ALLOW_PATH) && len) {
|
||||
char *clip = NULL;
|
||||
|
||||
p = &target[len];
|
||||
do {
|
||||
--p;
|
||||
if(*p != ' ' && *p != '.')
|
||||
break;
|
||||
clip = p;
|
||||
} while(p != target);
|
||||
|
||||
if(clip) {
|
||||
*clip = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MSDOS
|
||||
sc = msdosify(&p, target, flags);
|
||||
free(target);
|
||||
if(sc)
|
||||
return sc;
|
||||
target = p;
|
||||
len = strlen(target);
|
||||
|
||||
if(len > max_sanitized_len) {
|
||||
free(target);
|
||||
return SANITIZE_ERR_INVALID_PATH;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(!(flags & SANITIZE_ALLOW_RESERVED)) {
|
||||
sc = rename_if_reserved_dos(&p, target, flags);
|
||||
free(target);
|
||||
if(sc)
|
||||
return sc;
|
||||
target = p;
|
||||
len = strlen(target);
|
||||
|
||||
if(len > max_sanitized_len) {
|
||||
free(target);
|
||||
return SANITIZE_ERR_INVALID_PATH;
|
||||
}
|
||||
}
|
||||
|
||||
*sanitized = target;
|
||||
return SANITIZE_ERR_OK;
|
||||
}
|
||||
|
||||
#ifdef MSDOS
|
||||
/*
|
||||
Test if truncating a path to a file will leave at least a single character in
|
||||
the filename. Filenames suffixed by an alternate data stream cannot be
|
||||
truncated. This performs a dry run, nothing is modified.
|
||||
|
||||
Good truncate_pos 9: C:\foo\bar => C:\foo\ba
|
||||
Good truncate_pos 6: C:\foo => C:\foo
|
||||
Good truncate_pos 5: C:\foo => C:\fo
|
||||
Bad* truncate_pos 5: C:foo => C:foo
|
||||
Bad truncate_pos 5: C:\foo:ads => C:\fo
|
||||
Bad truncate_pos 9: C:\foo:ads => C:\foo:ad
|
||||
Bad truncate_pos 5: C:\foo\bar => C:\fo
|
||||
Bad truncate_pos 5: C:\foo\ => C:\fo
|
||||
Bad truncate_pos 7: C:\foo\ => C:\foo\
|
||||
Error truncate_pos 7: C:\foo => (pos out of range)
|
||||
Bad truncate_pos 1: C:\foo\ => C
|
||||
|
||||
* C:foo is ambiguous, C could end up being a drive or file therefore something
|
||||
like C:superlongfilename cannot be truncated.
|
||||
|
||||
Returns
|
||||
SANITIZE_ERR_OK: Good -- 'path' can be truncated
|
||||
SANITIZE_ERR_INVALID_PATH: Bad -- 'path' cannot be truncated
|
||||
!= SANITIZE_ERR_OK && != SANITIZE_ERR_INVALID_PATH: Error
|
||||
*/
|
||||
static SANITIZEcode truncate_dryrun(const char *path,
|
||||
const size_t truncate_pos)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
if(!path)
|
||||
return SANITIZE_ERR_BAD_ARGUMENT;
|
||||
|
||||
len = strlen(path);
|
||||
|
||||
if(truncate_pos > len)
|
||||
return SANITIZE_ERR_BAD_ARGUMENT;
|
||||
|
||||
if(!len || !truncate_pos)
|
||||
return SANITIZE_ERR_INVALID_PATH;
|
||||
|
||||
if(strpbrk(&path[truncate_pos - 1], "\\/:"))
|
||||
return SANITIZE_ERR_INVALID_PATH;
|
||||
|
||||
/* C:\foo can be truncated but C:\foo:ads cannot */
|
||||
if(truncate_pos > 1) {
|
||||
const char *p = &path[truncate_pos - 1];
|
||||
do {
|
||||
--p;
|
||||
if(*p == ':')
|
||||
return SANITIZE_ERR_INVALID_PATH;
|
||||
} while(p != path && *p != '\\' && *p != '/');
|
||||
}
|
||||
|
||||
return SANITIZE_ERR_OK;
|
||||
}
|
||||
|
||||
/* The functions msdosify, rename_if_dos_device_name and __crt0_glob_function
|
||||
* were taken with modification from the DJGPP port of tar 1.12. They use
|
||||
* algorithms originally from DJTAR.
|
||||
*/
|
||||
|
||||
/*
|
||||
Extra sanitization MS-DOS for file_name.
|
||||
|
||||
This is a supporting function for sanitize_file_name.
|
||||
|
||||
Warning: This is an MS-DOS legacy function and was purposely written in a way
|
||||
that some path information may pass through. For example drive letter names
|
||||
(C:, D:, etc) are allowed to pass through. For sanitizing a filename use
|
||||
sanitize_file_name.
|
||||
|
||||
Success: (SANITIZE_ERR_OK) *sanitized points to a sanitized copy of file_name.
|
||||
Failure: (!= SANITIZE_ERR_OK) *sanitized is NULL.
|
||||
*/
|
||||
static SANITIZEcode msdosify(char **const sanitized, const char *file_name,
|
||||
int flags)
|
||||
{
|
||||
char dos_name[PATH_MAX];
|
||||
static const char illegal_chars_dos[] = ".+, ;=[]" /* illegal in DOS */
|
||||
"|<>/\\\":?*"; /* illegal in DOS & W95 */
|
||||
static const char *illegal_chars_w95 = &illegal_chars_dos[8];
|
||||
int idx, dot_idx;
|
||||
const char *s = file_name;
|
||||
char *d = dos_name;
|
||||
const char *const dlimit = dos_name + sizeof(dos_name) - 1;
|
||||
const char *illegal_aliens = illegal_chars_dos;
|
||||
size_t len = sizeof(illegal_chars_dos) - 1;
|
||||
|
||||
if(!sanitized)
|
||||
return SANITIZE_ERR_BAD_ARGUMENT;
|
||||
|
||||
*sanitized = NULL;
|
||||
|
||||
if(!file_name)
|
||||
return SANITIZE_ERR_BAD_ARGUMENT;
|
||||
|
||||
if(strlen(file_name) > PATH_MAX-1)
|
||||
return SANITIZE_ERR_INVALID_PATH;
|
||||
|
||||
/* Support for Windows 9X VFAT systems, when available. */
|
||||
if(CURL_USE_LFN(file_name)) {
|
||||
illegal_aliens = illegal_chars_w95;
|
||||
len -= (illegal_chars_w95 - illegal_chars_dos);
|
||||
}
|
||||
|
||||
/* Get past the drive letter, if any. */
|
||||
if(s[0] >= 'A' && s[0] <= 'z' && s[1] == ':') {
|
||||
*d++ = *s++;
|
||||
*d = ((flags & SANITIZE_ALLOW_PATH)) ? ':' : '_';
|
||||
++d; ++s;
|
||||
}
|
||||
|
||||
for(idx = 0, dot_idx = -1; *s && d < dlimit; s++, d++) {
|
||||
if(memchr(illegal_aliens, *s, len)) {
|
||||
|
||||
if((flags & SANITIZE_ALLOW_PATH) && *s == ':')
|
||||
*d = ':';
|
||||
else if((flags & SANITIZE_ALLOW_PATH) && (*s == '/' || *s == '\\'))
|
||||
*d = *s;
|
||||
/* Dots are special: DOS does not allow them as the leading character,
|
||||
and a filename cannot have more than a single dot. We leave the
|
||||
first non-leading dot alone, unless it comes too close to the
|
||||
beginning of the name: we want sh.lex.c to become sh_lex.c, not
|
||||
sh.lex-c. */
|
||||
else if(*s == '.') {
|
||||
if((flags & SANITIZE_ALLOW_PATH) && idx == 0 &&
|
||||
(s[1] == '/' || s[1] == '\\' ||
|
||||
(s[1] == '.' && (s[2] == '/' || s[2] == '\\')))) {
|
||||
/* Copy "./" and "../" verbatim. */
|
||||
*d++ = *s++;
|
||||
if(d == dlimit)
|
||||
break;
|
||||
if(*s == '.') {
|
||||
*d++ = *s++;
|
||||
if(d == dlimit)
|
||||
break;
|
||||
}
|
||||
*d = *s;
|
||||
}
|
||||
else if(idx == 0)
|
||||
*d = '_';
|
||||
else if(dot_idx >= 0) {
|
||||
if(dot_idx < 5) { /* 5 is a heuristic ad-hoc'ery */
|
||||
d[dot_idx - idx] = '_'; /* replace previous dot */
|
||||
*d = '.';
|
||||
}
|
||||
else
|
||||
*d = '-';
|
||||
}
|
||||
else
|
||||
*d = '.';
|
||||
|
||||
if(*s == '.')
|
||||
dot_idx = idx;
|
||||
}
|
||||
else if(*s == '+' && s[1] == '+') {
|
||||
if(idx - 2 == dot_idx) { /* .c++, .h++ etc. */
|
||||
*d++ = 'x';
|
||||
if(d == dlimit)
|
||||
break;
|
||||
*d = 'x';
|
||||
}
|
||||
else {
|
||||
/* libg++ etc. */
|
||||
if(dlimit - d < 4) {
|
||||
*d++ = 'x';
|
||||
if(d == dlimit)
|
||||
break;
|
||||
*d = 'x';
|
||||
}
|
||||
else {
|
||||
memcpy(d, "plus", 4);
|
||||
d += 3;
|
||||
}
|
||||
}
|
||||
s++;
|
||||
idx++;
|
||||
}
|
||||
else
|
||||
*d = '_';
|
||||
}
|
||||
else
|
||||
*d = *s;
|
||||
if(*s == '/' || *s == '\\') {
|
||||
idx = 0;
|
||||
dot_idx = -1;
|
||||
}
|
||||
else
|
||||
idx++;
|
||||
}
|
||||
*d = '\0';
|
||||
|
||||
if(*s) {
|
||||
/* dos_name is truncated, check that truncation requirements are met,
|
||||
specifically truncating a filename suffixed by an alternate data stream
|
||||
or truncating the entire filename is not allowed. */
|
||||
if(strpbrk(s, "\\/:") || truncate_dryrun(dos_name, d - dos_name))
|
||||
return SANITIZE_ERR_INVALID_PATH;
|
||||
}
|
||||
|
||||
*sanitized = strdup(dos_name);
|
||||
return *sanitized ? SANITIZE_ERR_OK : SANITIZE_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
#endif /* MSDOS */
|
||||
|
||||
/*
|
||||
Rename file_name if it is a reserved dos device name.
|
||||
|
||||
This is a supporting function for sanitize_file_name.
|
||||
|
||||
Warning: This is an MS-DOS legacy function and was purposely written in a way
|
||||
that some path information may pass through. For example drive letter names
|
||||
(C:, D:, etc) are allowed to pass through. For sanitizing a filename use
|
||||
sanitize_file_name.
|
||||
|
||||
Success: (SANITIZE_ERR_OK) *sanitized points to a sanitized copy of file_name.
|
||||
Failure: (!= SANITIZE_ERR_OK) *sanitized is NULL.
|
||||
*/
|
||||
static SANITIZEcode rename_if_reserved_dos(char **const sanitized,
|
||||
const char *file_name,
|
||||
int flags)
|
||||
{
|
||||
/* We could have a file whose name is a device on MS-DOS. Trying to
|
||||
* retrieve such a file would fail at best and wedge us at worst. We need
|
||||
* to rename such files. */
|
||||
char *p, *base;
|
||||
char fname[PATH_MAX];
|
||||
#ifdef MSDOS
|
||||
struct_stat st_buf;
|
||||
#endif
|
||||
size_t len;
|
||||
|
||||
if(!sanitized || !file_name)
|
||||
return SANITIZE_ERR_BAD_ARGUMENT;
|
||||
|
||||
*sanitized = NULL;
|
||||
len = strlen(file_name);
|
||||
|
||||
/* Ignore UNC prefixed paths, they are allowed to contain a reserved name. */
|
||||
#ifndef MSDOS
|
||||
if((flags & SANITIZE_ALLOW_PATH) &&
|
||||
file_name[0] == '\\' && file_name[1] == '\\') {
|
||||
*sanitized = strdup(file_name);
|
||||
if(!*sanitized)
|
||||
return SANITIZE_ERR_OUT_OF_MEMORY;
|
||||
return SANITIZE_ERR_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(len > PATH_MAX-1)
|
||||
return SANITIZE_ERR_INVALID_PATH;
|
||||
|
||||
memcpy(fname, file_name, len);
|
||||
fname[len] = '\0';
|
||||
base = basename(fname);
|
||||
|
||||
/* Rename reserved device names that are known to be accessible without \\.\
|
||||
Examples: CON => _CON, CON.EXT => CON_EXT, CON:ADS => CON_ADS
|
||||
https://web.archive.org/web/20160314141551/support.microsoft.com/en-us/kb/74496
|
||||
https://learn.microsoft.com/windows/win32/fileio/naming-a-file
|
||||
*/
|
||||
for(p = fname; p; p = (p == fname && fname != base ? base : NULL)) {
|
||||
size_t p_len;
|
||||
int x = (curl_strnequal(p, "CON", 3) ||
|
||||
curl_strnequal(p, "PRN", 3) ||
|
||||
curl_strnequal(p, "AUX", 3) ||
|
||||
curl_strnequal(p, "NUL", 3)) ? 3 :
|
||||
(curl_strnequal(p, "CLOCK$", 6)) ? 6 :
|
||||
(curl_strnequal(p, "COM", 3) || curl_strnequal(p, "LPT", 3)) ?
|
||||
(('1' <= p[3] && p[3] <= '9') ? 4 : 3) : 0;
|
||||
|
||||
if(!x)
|
||||
continue;
|
||||
|
||||
/* the devices may be accessible with an extension or ADS, for
|
||||
example CON.AIR and 'CON . AIR' and CON:AIR access console */
|
||||
|
||||
for(; p[x] == ' '; ++x)
|
||||
;
|
||||
|
||||
if(p[x] == '.') {
|
||||
p[x] = '_';
|
||||
continue;
|
||||
}
|
||||
else if(p[x] == ':') {
|
||||
if(!(flags & SANITIZE_ALLOW_PATH)) {
|
||||
p[x] = '_';
|
||||
continue;
|
||||
}
|
||||
++x;
|
||||
}
|
||||
else if(p[x]) /* no match */
|
||||
continue;
|
||||
|
||||
/* p points to 'CON' or 'CON ' or 'CON:', etc */
|
||||
p_len = strlen(p);
|
||||
|
||||
/* Prepend a '_' */
|
||||
if(strlen(fname) == PATH_MAX-1)
|
||||
return SANITIZE_ERR_INVALID_PATH;
|
||||
memmove(p + 1, p, p_len + 1);
|
||||
p[0] = '_';
|
||||
++p_len;
|
||||
|
||||
/* if fname was just modified then the basename pointer must be updated */
|
||||
if(p == fname)
|
||||
base = basename(fname);
|
||||
}
|
||||
|
||||
/* This is the legacy portion from rename_if_dos_device_name that checks for
|
||||
reserved device names. It only works on MS-DOS. On Windows XP the stat
|
||||
check errors with EINVAL if the device name is reserved. On Windows
|
||||
Vista/7/8 it sets mode S_IFREG (regular file or device). According to
|
||||
MSDN stat doc the latter behavior is correct, but that does not help us
|
||||
identify whether it is a reserved device name and not a regular
|
||||
filename. */
|
||||
#ifdef MSDOS
|
||||
if(base && (curlx_stat(base, &st_buf) == 0) && S_ISCHR(st_buf.st_mode)) {
|
||||
/* Prepend a '_' */
|
||||
size_t blen = strlen(base);
|
||||
if(blen) {
|
||||
if(strlen(fname) >= PATH_MAX-1)
|
||||
return SANITIZE_ERR_INVALID_PATH;
|
||||
memmove(base + 1, base, blen + 1);
|
||||
base[0] = '_';
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
*sanitized = strdup(fname);
|
||||
return *sanitized ? SANITIZE_ERR_OK : SANITIZE_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
#ifdef __DJGPP__
|
||||
/*
|
||||
* Disable program default argument globbing. We do it on our own.
|
||||
*/
|
||||
char **__crt0_glob_function(char *arg)
|
||||
{
|
||||
(void)arg;
|
||||
return (char **)0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#if !defined(CURL_WINDOWS_UWP) && !defined(UNDER_CE) && \
|
||||
!defined(CURL_DISABLE_CA_SEARCH) && !defined(CURL_CA_SEARCH_SAFE)
|
||||
/* Search and set the CA cert file for Windows.
|
||||
*
|
||||
* Do not call this function if Schannel is the selected SSL backend. We allow
|
||||
* setting CA location for Schannel only when explicitly specified by the user
|
||||
* via CURLOPT_CAINFO / --cacert.
|
||||
*
|
||||
* Function to find CACert bundle on a Win32 platform using SearchPath.
|
||||
* (SearchPath is already declared via inclusions done in setup header file)
|
||||
* (Use the ASCII version instead of the Unicode one!)
|
||||
* The order of the directories it searches is:
|
||||
* 1. application's directory
|
||||
* 2. current working directory
|
||||
* 3. Windows System directory (e.g. C:\Windows\System32)
|
||||
* 4. Windows Directory (e.g. C:\Windows)
|
||||
* 5. all directories along %PATH%
|
||||
*
|
||||
* For WinXP and later search order actually depends on registry value:
|
||||
* HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\SafeProcessSearchMode
|
||||
*/
|
||||
CURLcode FindWin32CACert(struct OperationConfig *config,
|
||||
const TCHAR *bundle_file)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
DWORD res_len;
|
||||
TCHAR buf[PATH_MAX];
|
||||
TCHAR *ptr = NULL;
|
||||
|
||||
buf[0] = TEXT('\0');
|
||||
|
||||
res_len = SearchPath(NULL, bundle_file, NULL, PATH_MAX, buf, &ptr);
|
||||
if(res_len > 0) {
|
||||
char *mstr = curlx_convert_tchar_to_UTF8(buf);
|
||||
tool_safefree(config->cacert);
|
||||
if(mstr)
|
||||
config->cacert = strdup(mstr);
|
||||
curlx_unicodefree(mstr);
|
||||
if(!config->cacert)
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Get a list of all loaded modules with full paths.
|
||||
* Returns slist on success or NULL on error.
|
||||
*/
|
||||
struct curl_slist *GetLoadedModulePaths(void)
|
||||
{
|
||||
struct curl_slist *slist = NULL;
|
||||
#if !defined(CURL_WINDOWS_UWP) && !defined(UNDER_CE)
|
||||
HANDLE hnd = INVALID_HANDLE_VALUE;
|
||||
MODULEENTRY32 mod = {0};
|
||||
|
||||
mod.dwSize = sizeof(MODULEENTRY32);
|
||||
|
||||
do {
|
||||
hnd = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 0);
|
||||
} while(hnd == INVALID_HANDLE_VALUE && GetLastError() == ERROR_BAD_LENGTH);
|
||||
|
||||
if(hnd == INVALID_HANDLE_VALUE)
|
||||
goto error;
|
||||
|
||||
if(!Module32First(hnd, &mod))
|
||||
goto error;
|
||||
|
||||
do {
|
||||
char *path; /* points to stack allocated buffer */
|
||||
struct curl_slist *temp;
|
||||
|
||||
#ifdef UNICODE
|
||||
/* sizeof(mod.szExePath) is the max total bytes of wchars. the max total
|
||||
bytes of multibyte chars will not be more than twice that. */
|
||||
char buffer[sizeof(mod.szExePath) * 2];
|
||||
if(!WideCharToMultiByte(CP_ACP, 0, mod.szExePath, -1,
|
||||
buffer, sizeof(buffer), NULL, NULL))
|
||||
goto error;
|
||||
path = buffer;
|
||||
#else
|
||||
path = mod.szExePath;
|
||||
#endif
|
||||
temp = curl_slist_append(slist, path);
|
||||
if(!temp)
|
||||
goto error;
|
||||
slist = temp;
|
||||
} while(Module32Next(hnd, &mod));
|
||||
|
||||
goto cleanup;
|
||||
|
||||
error:
|
||||
curl_slist_free_all(slist);
|
||||
slist = NULL;
|
||||
cleanup:
|
||||
if(hnd != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(hnd);
|
||||
#endif
|
||||
return slist;
|
||||
}
|
||||
|
||||
bool tool_term_has_bold;
|
||||
|
||||
#if !defined(CURL_WINDOWS_UWP) && !defined(UNDER_CE)
|
||||
/* The terminal settings to restore on exit */
|
||||
static struct TerminalSettings {
|
||||
HANDLE hStdOut;
|
||||
DWORD dwOutputMode;
|
||||
LONG valid;
|
||||
} TerminalSettings;
|
||||
|
||||
#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
|
||||
#endif
|
||||
|
||||
static void restore_terminal(void)
|
||||
{
|
||||
if(InterlockedExchange(&TerminalSettings.valid, (LONG)FALSE))
|
||||
SetConsoleMode(TerminalSettings.hStdOut, TerminalSettings.dwOutputMode);
|
||||
}
|
||||
|
||||
/* This is the console signal handler.
|
||||
* The system calls it in a separate thread.
|
||||
*/
|
||||
static BOOL WINAPI signal_handler(DWORD type)
|
||||
{
|
||||
if(type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT)
|
||||
restore_terminal();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void init_terminal(void)
|
||||
{
|
||||
TerminalSettings.hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
/*
|
||||
* Enable VT (Virtual Terminal) output.
|
||||
* Note: VT mode flag can be set on any version of Windows, but VT
|
||||
* processing only performed on Win10 >= version 1709 (OS build 16299)
|
||||
* Creator's Update. Also, ANSI bold on/off supported since then.
|
||||
*/
|
||||
if(TerminalSettings.hStdOut == INVALID_HANDLE_VALUE ||
|
||||
!GetConsoleMode(TerminalSettings.hStdOut,
|
||||
&TerminalSettings.dwOutputMode) ||
|
||||
!curlx_verify_windows_version(10, 0, 16299, PLATFORM_WINNT,
|
||||
VERSION_GREATER_THAN_EQUAL))
|
||||
return;
|
||||
|
||||
if((TerminalSettings.dwOutputMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING))
|
||||
tool_term_has_bold = true;
|
||||
else {
|
||||
/* The signal handler is set before attempting to change the console mode
|
||||
because otherwise a signal would not be caught after the change but
|
||||
before the handler was installed. */
|
||||
(void)InterlockedExchange(&TerminalSettings.valid, (LONG)TRUE);
|
||||
if(SetConsoleCtrlHandler(signal_handler, TRUE)) {
|
||||
if(SetConsoleMode(TerminalSettings.hStdOut,
|
||||
(TerminalSettings.dwOutputMode |
|
||||
ENABLE_VIRTUAL_TERMINAL_PROCESSING))) {
|
||||
tool_term_has_bold = true;
|
||||
atexit(restore_terminal);
|
||||
}
|
||||
else {
|
||||
SetConsoleCtrlHandler(signal_handler, FALSE);
|
||||
(void)InterlockedExchange(&TerminalSettings.valid, (LONG)FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
CURLcode win32_init(void)
|
||||
{
|
||||
curlx_now_init();
|
||||
#if !defined(CURL_WINDOWS_UWP) && !defined(UNDER_CE)
|
||||
init_terminal();
|
||||
#endif
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
#if !defined(CURL_WINDOWS_UWP) && !defined(UNDER_CE)
|
||||
/* The following STDIN non - blocking read techniques are heavily inspired
|
||||
by nmap and ncat (https://nmap.org/ncat/) */
|
||||
struct win_thread_data {
|
||||
/* This is a copy of the true stdin file handle before any redirection. It is
|
||||
read by the thread. */
|
||||
HANDLE stdin_handle;
|
||||
/* This is the listen socket for the thread. It is closed after the first
|
||||
connection. */
|
||||
curl_socket_t socket_l;
|
||||
};
|
||||
|
||||
static DWORD WINAPI win_stdin_thread_func(void *thread_data)
|
||||
{
|
||||
struct win_thread_data *tdata = (struct win_thread_data *)thread_data;
|
||||
DWORD n;
|
||||
int nwritten;
|
||||
char buffer[BUFSIZ];
|
||||
BOOL r;
|
||||
|
||||
SOCKADDR_IN clientAddr;
|
||||
int clientAddrLen = sizeof(clientAddr);
|
||||
|
||||
curl_socket_t socket_w = CURL_ACCEPT(tdata->socket_l, (SOCKADDR*)&clientAddr,
|
||||
&clientAddrLen);
|
||||
|
||||
if(socket_w == CURL_SOCKET_BAD) {
|
||||
errorf("accept error: %d", SOCKERRNO);
|
||||
goto ThreadCleanup;
|
||||
}
|
||||
|
||||
sclose(tdata->socket_l);
|
||||
tdata->socket_l = CURL_SOCKET_BAD;
|
||||
if(shutdown(socket_w, SD_RECEIVE) == SOCKET_ERROR) {
|
||||
errorf("shutdown error: %d", SOCKERRNO);
|
||||
goto ThreadCleanup;
|
||||
}
|
||||
for(;;) {
|
||||
r = ReadFile(tdata->stdin_handle, buffer, sizeof(buffer), &n, NULL);
|
||||
if(r == 0)
|
||||
break;
|
||||
if(n == 0)
|
||||
break;
|
||||
nwritten = CURL_SEND(socket_w, buffer, n, 0);
|
||||
if(nwritten == SOCKET_ERROR)
|
||||
break;
|
||||
if((DWORD)nwritten != n)
|
||||
break;
|
||||
}
|
||||
ThreadCleanup:
|
||||
CloseHandle(tdata->stdin_handle);
|
||||
tdata->stdin_handle = NULL;
|
||||
if(tdata->socket_l != CURL_SOCKET_BAD) {
|
||||
sclose(tdata->socket_l);
|
||||
tdata->socket_l = CURL_SOCKET_BAD;
|
||||
}
|
||||
if(socket_w != CURL_SOCKET_BAD)
|
||||
sclose(socket_w);
|
||||
|
||||
if(tdata) {
|
||||
free(tdata);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The background thread that reads and buffers the true stdin. */
|
||||
curl_socket_t win32_stdin_read_thread(void)
|
||||
{
|
||||
int result;
|
||||
bool r;
|
||||
int rc = 0, socksize = 0;
|
||||
struct win_thread_data *tdata = NULL;
|
||||
SOCKADDR_IN selfaddr;
|
||||
static HANDLE stdin_thread = NULL;
|
||||
static curl_socket_t socket_r = CURL_SOCKET_BAD;
|
||||
|
||||
if(socket_r != CURL_SOCKET_BAD) {
|
||||
assert(stdin_thread != NULL);
|
||||
return socket_r;
|
||||
}
|
||||
assert(stdin_thread == NULL);
|
||||
|
||||
do {
|
||||
/* Prepare handles for thread */
|
||||
tdata = (struct win_thread_data*)calloc(1, sizeof(struct win_thread_data));
|
||||
if(!tdata) {
|
||||
errorf("calloc() error");
|
||||
break;
|
||||
}
|
||||
/* Create the listening socket for the thread. When it starts, it will
|
||||
* accept our connection and begin writing STDIN data to the connection. */
|
||||
tdata->socket_l = CURL_SOCKET(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if(tdata->socket_l == CURL_SOCKET_BAD) {
|
||||
errorf("socket() error: %d", SOCKERRNO);
|
||||
break;
|
||||
}
|
||||
|
||||
socksize = sizeof(selfaddr);
|
||||
memset(&selfaddr, 0, socksize);
|
||||
selfaddr.sin_family = AF_INET;
|
||||
selfaddr.sin_addr.S_un.S_addr = htonl(INADDR_LOOPBACK);
|
||||
/* Bind to any available loopback port */
|
||||
result = bind(tdata->socket_l, (SOCKADDR*)&selfaddr, socksize);
|
||||
if(result == SOCKET_ERROR) {
|
||||
errorf("bind error: %d", SOCKERRNO);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Bind to any available loopback port */
|
||||
result = getsockname(tdata->socket_l, (SOCKADDR*)&selfaddr, &socksize);
|
||||
if(result == SOCKET_ERROR) {
|
||||
errorf("getsockname error: %d", SOCKERRNO);
|
||||
break;
|
||||
}
|
||||
|
||||
result = listen(tdata->socket_l, 1);
|
||||
if(result == SOCKET_ERROR) {
|
||||
errorf("listen error: %d", SOCKERRNO);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Make a copy of the stdin handle to be used by win_stdin_thread_func */
|
||||
r = DuplicateHandle(GetCurrentProcess(), GetStdHandle(STD_INPUT_HANDLE),
|
||||
GetCurrentProcess(), &tdata->stdin_handle,
|
||||
0, FALSE, DUPLICATE_SAME_ACCESS);
|
||||
|
||||
if(!r) {
|
||||
errorf("DuplicateHandle error: 0x%08lx", GetLastError());
|
||||
break;
|
||||
}
|
||||
|
||||
/* Start up the thread. We don't bother keeping a reference to it
|
||||
because it runs until program termination. From here on out all reads
|
||||
from the stdin handle or file descriptor 0 will be reading from the
|
||||
socket that is fed by the thread. */
|
||||
stdin_thread = CreateThread(NULL, 0, win_stdin_thread_func,
|
||||
tdata, 0, NULL);
|
||||
if(!stdin_thread) {
|
||||
errorf("CreateThread error: 0x%08lx", GetLastError());
|
||||
break;
|
||||
}
|
||||
|
||||
/* Connect to the thread and rearrange our own STDIN handles */
|
||||
socket_r = CURL_SOCKET(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if(socket_r == CURL_SOCKET_BAD) {
|
||||
errorf("socket error: %d", SOCKERRNO);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Hard close the socket on closesocket() */
|
||||
setsockopt(socket_r, SOL_SOCKET, SO_DONTLINGER, 0, 0);
|
||||
|
||||
if(connect(socket_r, (SOCKADDR*)&selfaddr, socksize) == SOCKET_ERROR) {
|
||||
errorf("connect error: %d", SOCKERRNO);
|
||||
break;
|
||||
}
|
||||
|
||||
if(shutdown(socket_r, SD_SEND) == SOCKET_ERROR) {
|
||||
errorf("shutdown error: %d", SOCKERRNO);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Set the stdin handle to read from the socket. */
|
||||
if(SetStdHandle(STD_INPUT_HANDLE, (HANDLE)socket_r) == 0) {
|
||||
errorf("SetStdHandle error: 0x%08lx", GetLastError());
|
||||
break;
|
||||
}
|
||||
|
||||
rc = 1;
|
||||
} while(0);
|
||||
|
||||
if(rc != 1) {
|
||||
if(socket_r != CURL_SOCKET_BAD && tdata) {
|
||||
if(GetStdHandle(STD_INPUT_HANDLE) == (HANDLE)socket_r &&
|
||||
tdata->stdin_handle) {
|
||||
/* restore STDIN */
|
||||
SetStdHandle(STD_INPUT_HANDLE, tdata->stdin_handle);
|
||||
tdata->stdin_handle = NULL;
|
||||
}
|
||||
|
||||
sclose(socket_r);
|
||||
socket_r = CURL_SOCKET_BAD;
|
||||
}
|
||||
|
||||
if(stdin_thread) {
|
||||
TerminateThread(stdin_thread, 1);
|
||||
CloseHandle(stdin_thread);
|
||||
stdin_thread = NULL;
|
||||
}
|
||||
|
||||
if(tdata) {
|
||||
if(tdata->stdin_handle)
|
||||
CloseHandle(tdata->stdin_handle);
|
||||
if(tdata->socket_l != CURL_SOCKET_BAD)
|
||||
sclose(tdata->socket_l);
|
||||
|
||||
free(tdata);
|
||||
}
|
||||
|
||||
return CURL_SOCKET_BAD;
|
||||
}
|
||||
|
||||
assert(socket_r != CURL_SOCKET_BAD);
|
||||
return socket_r;
|
||||
}
|
||||
|
||||
#endif /* !CURL_WINDOWS_UWP && !UNDER_CE */
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#endif /* _WIN32 || MSDOS */
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
#ifndef HEADER_CURL_TOOL_DOSWIN_H
|
||||
#define HEADER_CURL_TOOL_DOSWIN_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#if defined(_WIN32) || defined(MSDOS)
|
||||
|
||||
#define SANITIZE_ALLOW_PATH (1<<1) /* Allow path separators and colons */
|
||||
#define SANITIZE_ALLOW_RESERVED (1<<2) /* Allow reserved device names */
|
||||
|
||||
typedef enum {
|
||||
SANITIZE_ERR_OK = 0, /* 0 - OK */
|
||||
SANITIZE_ERR_INVALID_PATH, /* 1 - the path is invalid */
|
||||
SANITIZE_ERR_BAD_ARGUMENT, /* 2 - bad function parameter */
|
||||
SANITIZE_ERR_OUT_OF_MEMORY, /* 3 - out of memory */
|
||||
SANITIZE_ERR_LAST /* never use! */
|
||||
} SANITIZEcode;
|
||||
|
||||
SANITIZEcode sanitize_file_name(char **const sanitized, const char *file_name,
|
||||
int flags);
|
||||
|
||||
#ifdef __DJGPP__
|
||||
char **__crt0_glob_function(char *arg);
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#if !defined(CURL_WINDOWS_UWP) && !defined(UNDER_CE) && \
|
||||
!defined(CURL_DISABLE_CA_SEARCH) && !defined(CURL_CA_SEARCH_SAFE)
|
||||
CURLcode FindWin32CACert(struct OperationConfig *config,
|
||||
const TCHAR *bundle_file);
|
||||
#endif
|
||||
struct curl_slist *GetLoadedModulePaths(void);
|
||||
CURLcode win32_init(void);
|
||||
|
||||
#if !defined(CURL_WINDOWS_UWP) && !defined(UNDER_CE)
|
||||
curl_socket_t win32_stdin_read_thread(void);
|
||||
#endif /* !CURL_WINDOWS_UWP && !UNDER_CE */
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#endif /* _WIN32 || MSDOS */
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_DOSWIN_H */
|
||||
+236
@@ -0,0 +1,236 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#include "slist_wc.h"
|
||||
|
||||
#ifndef CURL_DISABLE_LIBCURL_OPTION
|
||||
|
||||
#include "tool_cfgable.h"
|
||||
#include "tool_easysrc.h"
|
||||
#include "tool_msgs.h"
|
||||
|
||||
#include "memdebug.h" /* keep this as LAST include */
|
||||
|
||||
/* global variable definitions, for easy-interface source code generation */
|
||||
|
||||
struct slist_wc *easysrc_decl; /* Variable declarations */
|
||||
struct slist_wc *easysrc_data; /* Build slists, forms etc. */
|
||||
struct slist_wc *easysrc_code; /* Setopt calls */
|
||||
struct slist_wc *easysrc_toohard; /* Unconvertible setopt */
|
||||
struct slist_wc *easysrc_clean; /* Clean up allocated data */
|
||||
int easysrc_mime_count;
|
||||
int easysrc_slist_count;
|
||||
|
||||
static const char *const srchead[]={
|
||||
"/********* Sample code generated by the curl command line tool **********",
|
||||
" * All curl_easy_setopt() options are documented at:",
|
||||
" * https://curl.se/libcurl/c/curl_easy_setopt.html",
|
||||
" ************************************************************************/",
|
||||
"#include <curl/curl.h>",
|
||||
"",
|
||||
"int main(int argc, char *argv[])",
|
||||
"{",
|
||||
" CURLcode ret;",
|
||||
" CURL *hnd;",
|
||||
NULL
|
||||
};
|
||||
/* easysrc_decl declarations come here */
|
||||
/* easysrc_data initialization come here */
|
||||
/* easysrc_code statements come here */
|
||||
static const char *const srchard[]={
|
||||
"/* Here is a list of options the curl code used that cannot get generated",
|
||||
" as source easily. You may choose to either not use them or implement",
|
||||
" them yourself.",
|
||||
"",
|
||||
NULL
|
||||
};
|
||||
static const char *const srcend[]={
|
||||
"",
|
||||
" return (int)ret;",
|
||||
"}",
|
||||
"/**** End of sample code ****/",
|
||||
NULL
|
||||
};
|
||||
|
||||
/* Clean up all source code if we run out of memory */
|
||||
static void easysrc_free(void)
|
||||
{
|
||||
slist_wc_free_all(easysrc_decl);
|
||||
easysrc_decl = NULL;
|
||||
slist_wc_free_all(easysrc_data);
|
||||
easysrc_data = NULL;
|
||||
slist_wc_free_all(easysrc_code);
|
||||
easysrc_code = NULL;
|
||||
slist_wc_free_all(easysrc_toohard);
|
||||
easysrc_toohard = NULL;
|
||||
slist_wc_free_all(easysrc_clean);
|
||||
easysrc_clean = NULL;
|
||||
}
|
||||
|
||||
/* Add a source line to the main code or remarks */
|
||||
CURLcode easysrc_add(struct slist_wc **plist, const char *line)
|
||||
{
|
||||
CURLcode ret = CURLE_OK;
|
||||
struct slist_wc *list = slist_wc_append(*plist, line);
|
||||
if(!list) {
|
||||
easysrc_free();
|
||||
ret = CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
else
|
||||
*plist = list;
|
||||
return ret;
|
||||
}
|
||||
|
||||
CURLcode easysrc_addf(struct slist_wc **plist, const char *fmt, ...)
|
||||
{
|
||||
CURLcode ret;
|
||||
char *bufp;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
bufp = curl_mvaprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
if(!bufp) {
|
||||
ret = CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
else {
|
||||
ret = easysrc_add(plist, bufp);
|
||||
curl_free(bufp);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
CURLcode easysrc_init(void)
|
||||
{
|
||||
return easysrc_add(&easysrc_code, "hnd = curl_easy_init();");
|
||||
}
|
||||
|
||||
CURLcode easysrc_perform(void)
|
||||
{
|
||||
CURLcode ret = CURLE_OK;
|
||||
/* Note any setopt calls which we could not convert */
|
||||
if(easysrc_toohard) {
|
||||
int i;
|
||||
struct curl_slist *ptr;
|
||||
ret = easysrc_add(&easysrc_code, "");
|
||||
/* Preamble comment */
|
||||
for(i = 0; srchard[i] && !ret; i++)
|
||||
ret = easysrc_add(&easysrc_code, srchard[i]);
|
||||
/* Each unconverted option */
|
||||
if(easysrc_toohard && !ret) {
|
||||
for(ptr = easysrc_toohard->first; ptr && !ret; ptr = ptr->next)
|
||||
ret = easysrc_add(&easysrc_code, ptr->data);
|
||||
}
|
||||
if(!ret)
|
||||
ret = easysrc_add(&easysrc_code, "");
|
||||
if(!ret)
|
||||
ret = easysrc_add(&easysrc_code, "*/");
|
||||
|
||||
slist_wc_free_all(easysrc_toohard);
|
||||
easysrc_toohard = NULL;
|
||||
}
|
||||
|
||||
if(!ret)
|
||||
ret = easysrc_add(&easysrc_code, "");
|
||||
if(!ret)
|
||||
ret = easysrc_add(&easysrc_code, "ret = curl_easy_perform(hnd);");
|
||||
if(!ret)
|
||||
ret = easysrc_add(&easysrc_code, "");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
CURLcode easysrc_cleanup(void)
|
||||
{
|
||||
CURLcode ret = easysrc_add(&easysrc_code, "curl_easy_cleanup(hnd);");
|
||||
if(!ret)
|
||||
ret = easysrc_add(&easysrc_code, "hnd = NULL;");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dumpeasysrc(void)
|
||||
{
|
||||
struct curl_slist *ptr;
|
||||
char *o = global->libcurl;
|
||||
|
||||
FILE *out;
|
||||
bool fopened = FALSE;
|
||||
if(strcmp(o, "-")) {
|
||||
out = curlx_fopen(o, FOPEN_WRITETEXT);
|
||||
fopened = TRUE;
|
||||
}
|
||||
else
|
||||
out = stdout;
|
||||
if(!out)
|
||||
warnf("Failed to open %s to write libcurl code", o);
|
||||
else {
|
||||
int i;
|
||||
const char *c;
|
||||
|
||||
for(i = 0; ((c = srchead[i]) != NULL); i++)
|
||||
curl_mfprintf(out, "%s\n", c);
|
||||
|
||||
/* Declare variables used for complex setopt values */
|
||||
if(easysrc_decl) {
|
||||
for(ptr = easysrc_decl->first; ptr; ptr = ptr->next)
|
||||
curl_mfprintf(out, " %s\n", ptr->data);
|
||||
}
|
||||
|
||||
/* Set up complex values for setopt calls */
|
||||
if(easysrc_data) {
|
||||
curl_mfprintf(out, "\n");
|
||||
|
||||
for(ptr = easysrc_data->first; ptr; ptr = ptr->next)
|
||||
curl_mfprintf(out, " %s\n", ptr->data);
|
||||
}
|
||||
|
||||
curl_mfprintf(out, "\n");
|
||||
if(easysrc_code) {
|
||||
for(ptr = easysrc_code->first; ptr; ptr = ptr->next) {
|
||||
if(ptr->data[0]) {
|
||||
curl_mfprintf(out, " %s\n", ptr->data);
|
||||
}
|
||||
else {
|
||||
curl_mfprintf(out, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(easysrc_clean) {
|
||||
for(ptr = easysrc_clean->first; ptr; ptr = ptr->next)
|
||||
curl_mfprintf(out, " %s\n", ptr->data);
|
||||
}
|
||||
|
||||
for(i = 0; ((c = srcend[i]) != NULL); i++)
|
||||
curl_mfprintf(out, "%s\n", c);
|
||||
|
||||
if(fopened)
|
||||
curlx_fclose(out);
|
||||
}
|
||||
|
||||
easysrc_free();
|
||||
}
|
||||
|
||||
#endif /* CURL_DISABLE_LIBCURL_OPTION */
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
#ifndef HEADER_CURL_TOOL_EASYSRC_H
|
||||
#define HEADER_CURL_TOOL_EASYSRC_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
#ifndef CURL_DISABLE_LIBCURL_OPTION
|
||||
|
||||
/* global variable declarations, for easy-interface source code generation */
|
||||
|
||||
extern struct slist_wc *easysrc_decl; /* Variable declarations */
|
||||
extern struct slist_wc *easysrc_data; /* Build slists, forms etc. */
|
||||
extern struct slist_wc *easysrc_code; /* Setopt calls etc. */
|
||||
extern struct slist_wc *easysrc_toohard; /* Unconvertible setopt */
|
||||
extern struct slist_wc *easysrc_clean; /* Clean up (reverse order) */
|
||||
|
||||
extern int easysrc_mime_count; /* Number of curl_mime variables */
|
||||
extern int easysrc_slist_count; /* Number of curl_slist variables */
|
||||
|
||||
extern CURLcode easysrc_init(void);
|
||||
extern CURLcode easysrc_add(struct slist_wc **plist, const char *bupf);
|
||||
extern CURLcode easysrc_addf(struct slist_wc **plist,
|
||||
const char *fmt, ...) CURL_PRINTF(2, 3);
|
||||
extern CURLcode easysrc_perform(void);
|
||||
extern CURLcode easysrc_cleanup(void);
|
||||
void dumpeasysrc(void);
|
||||
|
||||
#else /* CURL_DISABLE_LIBCURL_OPTION is defined */
|
||||
|
||||
#define easysrc_init() CURLE_OK
|
||||
#define easysrc_cleanup()
|
||||
#define dumpeasysrc(x)
|
||||
#define easysrc_perform() CURLE_OK
|
||||
|
||||
#endif /* CURL_DISABLE_LIBCURL_OPTION */
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_EASYSRC_H */
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_filetime.h"
|
||||
#include "tool_cfgable.h"
|
||||
#include "tool_msgs.h"
|
||||
|
||||
#ifdef HAVE_UTIME_H
|
||||
# include <utime.h>
|
||||
#elif defined(HAVE_SYS_UTIME_H)
|
||||
# include <sys/utime.h>
|
||||
#endif
|
||||
|
||||
/* Returns 0 on success, non-zero on file problems */
|
||||
int getfiletime(const char *filename, curl_off_t *stamp)
|
||||
{
|
||||
int rc = 1;
|
||||
|
||||
/* Windows stat() may attempt to adjust the Unix GMT file time by a daylight
|
||||
saving time offset and since it is GMT that is bad behavior. When we have
|
||||
access to a 64-bit type we can bypass stat and get the times directly. */
|
||||
#if defined(_WIN32) && !defined(CURL_WINDOWS_UWP)
|
||||
HANDLE hfile;
|
||||
TCHAR *tchar_filename = curlx_convert_UTF8_to_tchar(filename);
|
||||
|
||||
hfile = CreateFile(tchar_filename, FILE_READ_ATTRIBUTES,
|
||||
(FILE_SHARE_READ | FILE_SHARE_WRITE |
|
||||
FILE_SHARE_DELETE),
|
||||
NULL, OPEN_EXISTING, 0, NULL);
|
||||
curlx_unicodefree(tchar_filename);
|
||||
if(hfile != INVALID_HANDLE_VALUE) {
|
||||
FILETIME ft;
|
||||
if(GetFileTime(hfile, NULL, NULL, &ft)) {
|
||||
curl_off_t converted = (curl_off_t)ft.dwLowDateTime
|
||||
| ((curl_off_t)ft.dwHighDateTime) << 32;
|
||||
|
||||
if(converted < 116444736000000000)
|
||||
warnf("Failed to get filetime: underflow");
|
||||
else {
|
||||
*stamp = (converted - 116444736000000000) / 10000000;
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
warnf("Failed to get filetime: GetFileTime failed: GetLastError 0x%08lx",
|
||||
GetLastError());
|
||||
}
|
||||
CloseHandle(hfile);
|
||||
}
|
||||
else if(GetLastError() != ERROR_FILE_NOT_FOUND) {
|
||||
warnf("Failed to get filetime: CreateFile failed: GetLastError 0x%08lx",
|
||||
GetLastError());
|
||||
}
|
||||
#else
|
||||
struct_stat statbuf;
|
||||
if(curlx_stat(filename, &statbuf) != -1) {
|
||||
*stamp = (curl_off_t)statbuf.st_mtime;
|
||||
rc = 0;
|
||||
}
|
||||
else {
|
||||
char errbuf[STRERROR_LEN];
|
||||
warnf("Failed to get filetime: %s",
|
||||
curlx_strerror(errno, errbuf, sizeof(errbuf)));
|
||||
}
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if defined(HAVE_UTIME) || defined(HAVE_UTIMES) || defined(_WIN32)
|
||||
void setfiletime(curl_off_t filetime, const char *filename)
|
||||
{
|
||||
/* Windows utime() may attempt to adjust the Unix GMT file time by a daylight
|
||||
saving time offset and since it is GMT that is bad behavior. When we have
|
||||
access to a 64-bit type we can bypass utime and set the times directly. */
|
||||
#if defined(_WIN32) && !defined(CURL_WINDOWS_UWP)
|
||||
HANDLE hfile;
|
||||
TCHAR *tchar_filename = curlx_convert_UTF8_to_tchar(filename);
|
||||
|
||||
/* 910670515199 is the maximum Unix filetime that can be used as a Windows
|
||||
FILETIME without overflow: 30827-12-31T23:59:59. */
|
||||
if(filetime > 910670515199) {
|
||||
filetime = 910670515199;
|
||||
warnf("Capping set filetime to max to avoid overflow");
|
||||
}
|
||||
else if(filetime < -6857222400) {
|
||||
/* dates before 14 september 1752 (pre-Gregorian calendar) are not
|
||||
accurate */
|
||||
filetime = -6857222400;
|
||||
warnf("Capping set filetime to minimum to avoid overflow");
|
||||
}
|
||||
|
||||
hfile = CreateFile(tchar_filename, FILE_WRITE_ATTRIBUTES,
|
||||
(FILE_SHARE_READ | FILE_SHARE_WRITE |
|
||||
FILE_SHARE_DELETE),
|
||||
NULL, OPEN_EXISTING, 0, NULL);
|
||||
curlx_unicodefree(tchar_filename);
|
||||
if(hfile != INVALID_HANDLE_VALUE) {
|
||||
curl_off_t converted = ((curl_off_t)filetime * 10000000) +
|
||||
116444736000000000;
|
||||
FILETIME ft;
|
||||
ft.dwLowDateTime = (DWORD)(converted & 0xFFFFFFFF);
|
||||
ft.dwHighDateTime = (DWORD)(converted >> 32);
|
||||
if(!SetFileTime(hfile, NULL, &ft, &ft)) {
|
||||
warnf("Failed to set filetime %" CURL_FORMAT_CURL_OFF_T
|
||||
" on outfile: SetFileTime failed: GetLastError 0x%08lx",
|
||||
filetime, GetLastError());
|
||||
}
|
||||
CloseHandle(hfile);
|
||||
}
|
||||
else {
|
||||
warnf("Failed to set filetime %" CURL_FORMAT_CURL_OFF_T
|
||||
" on outfile: CreateFile failed: GetLastError 0x%08lx",
|
||||
filetime, GetLastError());
|
||||
}
|
||||
|
||||
#elif defined(HAVE_UTIMES)
|
||||
struct timeval times[2];
|
||||
times[0].tv_sec = times[1].tv_sec = (time_t)filetime;
|
||||
times[0].tv_usec = times[1].tv_usec = 0;
|
||||
if(utimes(filename, times)) {
|
||||
char errbuf[STRERROR_LEN];
|
||||
warnf("Failed to set filetime %" CURL_FORMAT_CURL_OFF_T
|
||||
" on '%s': %s", filetime, filename,
|
||||
curlx_strerror(errno, errbuf, sizeof(errbuf)));
|
||||
}
|
||||
|
||||
#elif defined(HAVE_UTIME)
|
||||
struct utimbuf times;
|
||||
times.actime = (time_t)filetime;
|
||||
times.modtime = (time_t)filetime;
|
||||
if(utime(filename, ×)) {
|
||||
char errbuf[STRERROR_LEN];
|
||||
warnf("Failed to set filetime %" CURL_FORMAT_CURL_OFF_T
|
||||
" on '%s': %s", filetime, filename,
|
||||
curlx_strerror(errno, errbuf, sizeof(errbuf)));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif /* HAVE_UTIME || HAVE_UTIMES || _WIN32 */
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
#ifndef HEADER_CURL_TOOL_FILETIME_H
|
||||
#define HEADER_CURL_TOOL_FILETIME_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
int getfiletime(const char *filename, curl_off_t *stamp);
|
||||
|
||||
#if defined(HAVE_UTIME) || defined(HAVE_UTIMES) || \
|
||||
(defined(_WIN32) && (SIZEOF_CURL_OFF_T >= 8))
|
||||
void setfiletime(curl_off_t filetime, const char *filename);
|
||||
#else
|
||||
#define setfiletime(a,b,c) tool_nop_stmt
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_FILETIME_H */
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#ifdef HAVE_PWD_H
|
||||
#ifdef __AMIGA__
|
||||
#undef __NO_NET_API /* required for AmigaOS to declare getpwuid() */
|
||||
#endif
|
||||
#include <pwd.h>
|
||||
#ifdef __AMIGA__
|
||||
#define __NO_NET_API
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "tool_findfile.h"
|
||||
#include "tool_cfgable.h"
|
||||
|
||||
#include "memdebug.h" /* keep this as LAST include */
|
||||
|
||||
struct finder {
|
||||
const char *env;
|
||||
const char *append;
|
||||
bool withoutdot;
|
||||
};
|
||||
|
||||
/* The order of the variables below is important, as the index number is used
|
||||
in the findfile() function */
|
||||
static const struct finder conf_list[] = {
|
||||
{ "CURL_HOME", NULL, FALSE },
|
||||
{ "XDG_CONFIG_HOME", NULL, TRUE },
|
||||
{ "HOME", NULL, FALSE },
|
||||
#ifdef _WIN32
|
||||
{ "USERPROFILE", NULL, FALSE },
|
||||
{ "APPDATA", NULL, FALSE },
|
||||
{ "USERPROFILE", "\\Application Data", FALSE},
|
||||
#endif
|
||||
/* these are for .curlrc if XDG_CONFIG_HOME is not defined */
|
||||
{ "CURL_HOME", "/.config", TRUE },
|
||||
{ "HOME", "/.config", TRUE },
|
||||
|
||||
{ NULL, NULL, FALSE }
|
||||
};
|
||||
|
||||
static char *checkhome(const char *home, const char *fname, bool dotscore)
|
||||
{
|
||||
const char pref[2] = { '.', '_' };
|
||||
int i;
|
||||
for(i = 0; i < (dotscore ? 2 : 1); i++) {
|
||||
char *c;
|
||||
if(dotscore)
|
||||
c = curl_maprintf("%s" DIR_CHAR "%c%s", home, pref[i], &fname[1]);
|
||||
else
|
||||
c = curl_maprintf("%s" DIR_CHAR "%s", home, fname);
|
||||
if(c) {
|
||||
int fd = curlx_open(c, O_RDONLY);
|
||||
if(fd >= 0) {
|
||||
char *path = strdup(c);
|
||||
close(fd);
|
||||
curl_free(c);
|
||||
return path;
|
||||
}
|
||||
curl_free(c);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* findfile() - return the full path name of the file.
|
||||
*
|
||||
* If 'dotscore' is TRUE, then check for the file first with a leading dot
|
||||
* and then with a leading underscore.
|
||||
*
|
||||
* 1. Iterate over the environment variables in order, and if set, check for
|
||||
* the given file to be accessed there, then it is a match.
|
||||
* 2. Non-Windows: try getpwuid
|
||||
*/
|
||||
char *findfile(const char *fname, int dotscore)
|
||||
{
|
||||
int i;
|
||||
DEBUGASSERT(fname && fname[0]);
|
||||
DEBUGASSERT((dotscore != 1) || (fname[0] == '.'));
|
||||
|
||||
if(!fname[0])
|
||||
return NULL;
|
||||
|
||||
for(i = 0; conf_list[i].env; i++) {
|
||||
char *home = curl_getenv(conf_list[i].env);
|
||||
if(home) {
|
||||
char *path;
|
||||
const char *filename = fname;
|
||||
if(!home[0]) {
|
||||
curl_free(home);
|
||||
continue;
|
||||
}
|
||||
if(conf_list[i].append) {
|
||||
char *c = curl_maprintf("%s%s", home, conf_list[i].append);
|
||||
curl_free(home);
|
||||
if(!c)
|
||||
return NULL;
|
||||
home = c;
|
||||
}
|
||||
if(conf_list[i].withoutdot) {
|
||||
if(!dotscore) {
|
||||
/* this is not looking for .curlrc, or the XDG_CONFIG_HOME was
|
||||
defined so we skip the extended check */
|
||||
curl_free(home);
|
||||
continue;
|
||||
}
|
||||
filename++; /* move past the leading dot */
|
||||
dotscore = 0; /* disable it for this check */
|
||||
}
|
||||
path = checkhome(home, filename, dotscore ? dotscore - 1 : 0);
|
||||
curl_free(home);
|
||||
if(path)
|
||||
return path;
|
||||
}
|
||||
}
|
||||
#if defined(HAVE_GETPWUID) && defined(HAVE_GETEUID)
|
||||
{
|
||||
struct passwd *pw = getpwuid(geteuid());
|
||||
if(pw) {
|
||||
char *home = pw->pw_dir;
|
||||
if(home && home[0])
|
||||
return checkhome(home, fname, FALSE);
|
||||
}
|
||||
}
|
||||
#endif /* PWD-stuff */
|
||||
return NULL;
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
#ifndef HEADER_CURL_TOOL_HOMEDIR_H
|
||||
#define HEADER_CURL_TOOL_HOMEDIR_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define CURLRC_DOTSCORE 2 /* look for underscore-prefixed name too */
|
||||
#else
|
||||
#define CURLRC_DOTSCORE 1 /* regular .curlrc check */
|
||||
#endif
|
||||
|
||||
char *findfile(const char *fname, int dotscore);
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_HOMEDIR_H */
|
||||
+905
@@ -0,0 +1,905 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#include "tool_cfgable.h"
|
||||
#include "tool_msgs.h"
|
||||
#include "tool_getparam.h"
|
||||
#include "tool_paramhlp.h"
|
||||
#include "tool_formparse.h"
|
||||
#include "tool_parsecfg.h"
|
||||
|
||||
#include "memdebug.h" /* keep this as LAST include */
|
||||
|
||||
/* tool_mime functions. */
|
||||
static struct tool_mime *tool_mime_new(struct tool_mime *parent,
|
||||
toolmimekind kind)
|
||||
{
|
||||
struct tool_mime *m = (struct tool_mime *) calloc(1, sizeof(*m));
|
||||
|
||||
if(m) {
|
||||
m->kind = kind;
|
||||
m->parent = parent;
|
||||
if(parent) {
|
||||
m->prev = parent->subparts;
|
||||
parent->subparts = m;
|
||||
}
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
static struct tool_mime *tool_mime_new_parts(struct tool_mime *parent)
|
||||
{
|
||||
return tool_mime_new(parent, TOOLMIME_PARTS);
|
||||
}
|
||||
|
||||
static struct tool_mime *tool_mime_new_data(struct tool_mime *parent,
|
||||
char *mime_data)
|
||||
{
|
||||
char *mime_data_copy;
|
||||
struct tool_mime *m = NULL;
|
||||
|
||||
mime_data_copy = strdup(mime_data);
|
||||
if(mime_data_copy) {
|
||||
m = tool_mime_new(parent, TOOLMIME_DATA);
|
||||
if(!m)
|
||||
free(mime_data_copy);
|
||||
else
|
||||
m->data = mime_data_copy;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
/*
|
||||
** unsigned size_t to signed curl_off_t
|
||||
*/
|
||||
|
||||
#define CURL_MASK_UCOFFT ((unsigned CURL_TYPEOF_CURL_OFF_T)~0)
|
||||
#define CURL_MASK_SCOFFT (CURL_MASK_UCOFFT >> 1)
|
||||
|
||||
static curl_off_t uztoso(size_t uznum)
|
||||
{
|
||||
#ifdef __INTEL_COMPILER
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable:810) /* conversion may lose significant bits */
|
||||
#elif defined(_MSC_VER)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable:4310) /* cast truncates constant value */
|
||||
#endif
|
||||
|
||||
DEBUGASSERT(uznum <= (size_t) CURL_MASK_SCOFFT);
|
||||
return (curl_off_t)(uznum & (size_t) CURL_MASK_SCOFFT);
|
||||
|
||||
#if defined(__INTEL_COMPILER) || defined(_MSC_VER)
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
}
|
||||
|
||||
static struct tool_mime *tool_mime_new_filedata(struct tool_mime *parent,
|
||||
const char *filename,
|
||||
bool isremotefile,
|
||||
CURLcode *errcode)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct tool_mime *m = NULL;
|
||||
|
||||
*errcode = CURLE_OUT_OF_MEMORY;
|
||||
if(strcmp(filename, "-")) {
|
||||
/* This is a normal file. */
|
||||
char *filedup = strdup(filename);
|
||||
if(filedup) {
|
||||
m = tool_mime_new(parent, TOOLMIME_FILE);
|
||||
if(!m)
|
||||
free(filedup);
|
||||
else {
|
||||
m->data = filedup;
|
||||
if(!isremotefile)
|
||||
m->kind = TOOLMIME_FILEDATA;
|
||||
*errcode = CURLE_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
else { /* Standard input. */
|
||||
#ifdef UNDER_CE
|
||||
int fd = STDIN_FILENO;
|
||||
#else
|
||||
int fd = fileno(stdin);
|
||||
#endif
|
||||
char *data = NULL;
|
||||
curl_off_t size;
|
||||
curl_off_t origin;
|
||||
struct_stat sbuf;
|
||||
|
||||
CURLX_SET_BINMODE(stdin);
|
||||
origin = ftell(stdin);
|
||||
/* If stdin is a regular file, do not buffer data but read it
|
||||
when needed. */
|
||||
if(fd >= 0 && origin >= 0 && !fstat(fd, &sbuf) &&
|
||||
#ifdef __VMS
|
||||
sbuf.st_fab_rfm != FAB$C_VAR && sbuf.st_fab_rfm != FAB$C_VFC &&
|
||||
#endif
|
||||
S_ISREG(sbuf.st_mode)) {
|
||||
size = sbuf.st_size - origin;
|
||||
if(size < 0)
|
||||
size = 0;
|
||||
}
|
||||
else { /* Not suitable for direct use, buffer stdin data. */
|
||||
size_t stdinsize = 0;
|
||||
|
||||
switch(file2memory(&data, &stdinsize, stdin)) {
|
||||
case PARAM_NO_MEM:
|
||||
return m;
|
||||
case PARAM_READ_ERROR:
|
||||
result = CURLE_READ_ERROR;
|
||||
break;
|
||||
default:
|
||||
if(!stdinsize) {
|
||||
/* Zero-length data has been freed. Re-create it. */
|
||||
data = strdup("");
|
||||
if(!data)
|
||||
return m;
|
||||
}
|
||||
break;
|
||||
}
|
||||
size = uztoso(stdinsize);
|
||||
origin = 0;
|
||||
}
|
||||
m = tool_mime_new(parent, TOOLMIME_STDIN);
|
||||
if(!m)
|
||||
tool_safefree(data);
|
||||
else {
|
||||
m->data = data;
|
||||
m->origin = origin;
|
||||
m->size = size;
|
||||
m->curpos = 0;
|
||||
if(!isremotefile)
|
||||
m->kind = TOOLMIME_STDINDATA;
|
||||
*errcode = result;
|
||||
}
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
void tool_mime_free(struct tool_mime *mime)
|
||||
{
|
||||
if(mime) {
|
||||
if(mime->subparts)
|
||||
tool_mime_free(mime->subparts);
|
||||
if(mime->prev)
|
||||
tool_mime_free(mime->prev);
|
||||
tool_safefree(mime->name);
|
||||
tool_safefree(mime->filename);
|
||||
tool_safefree(mime->type);
|
||||
tool_safefree(mime->encoder);
|
||||
tool_safefree(mime->data);
|
||||
curl_slist_free_all(mime->headers);
|
||||
free(mime);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Mime part callbacks for stdin. */
|
||||
size_t tool_mime_stdin_read(char *buffer,
|
||||
size_t size, size_t nitems, void *arg)
|
||||
{
|
||||
struct tool_mime *sip = (struct tool_mime *) arg;
|
||||
curl_off_t bytesleft;
|
||||
(void)size; /* Always 1: ignored. */
|
||||
|
||||
if(sip->size >= 0) {
|
||||
if(sip->curpos >= sip->size)
|
||||
return 0; /* At eof. */
|
||||
bytesleft = sip->size - sip->curpos;
|
||||
if(uztoso(nitems) > bytesleft)
|
||||
nitems = curlx_sotouz(bytesleft);
|
||||
}
|
||||
if(nitems) {
|
||||
if(sip->data) {
|
||||
/* Return data from memory. */
|
||||
memcpy(buffer, sip->data + curlx_sotouz(sip->curpos), nitems);
|
||||
}
|
||||
else {
|
||||
/* Read from stdin. */
|
||||
nitems = fread(buffer, 1, nitems, stdin);
|
||||
if(ferror(stdin)) {
|
||||
char errbuf[STRERROR_LEN];
|
||||
/* Show error only once. */
|
||||
warnf("stdin: %s", curlx_strerror(errno, errbuf, sizeof(errbuf)));
|
||||
return CURL_READFUNC_ABORT;
|
||||
}
|
||||
}
|
||||
sip->curpos += uztoso(nitems);
|
||||
}
|
||||
return nitems;
|
||||
}
|
||||
|
||||
int tool_mime_stdin_seek(void *instream, curl_off_t offset, int whence)
|
||||
{
|
||||
struct tool_mime *sip = (struct tool_mime *) instream;
|
||||
|
||||
switch(whence) {
|
||||
case SEEK_CUR:
|
||||
offset += sip->curpos;
|
||||
break;
|
||||
case SEEK_END:
|
||||
offset += sip->size;
|
||||
break;
|
||||
}
|
||||
if(offset < 0)
|
||||
return CURL_SEEKFUNC_CANTSEEK;
|
||||
if(!sip->data) {
|
||||
if(curlx_fseek(stdin, offset + sip->origin, SEEK_SET))
|
||||
return CURL_SEEKFUNC_CANTSEEK;
|
||||
}
|
||||
sip->curpos = offset;
|
||||
return CURL_SEEKFUNC_OK;
|
||||
}
|
||||
|
||||
/* Translate an internal mime tree into a libcurl mime tree. */
|
||||
|
||||
static CURLcode tool2curlparts(CURL *curl, struct tool_mime *m,
|
||||
curl_mime *mime)
|
||||
{
|
||||
CURLcode ret = CURLE_OK;
|
||||
curl_mimepart *part = NULL;
|
||||
curl_mime *submime = NULL;
|
||||
const char *filename = NULL;
|
||||
|
||||
if(m) {
|
||||
ret = tool2curlparts(curl, m->prev, mime);
|
||||
if(!ret) {
|
||||
part = curl_mime_addpart(mime);
|
||||
if(!part)
|
||||
ret = CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
if(!ret) {
|
||||
filename = m->filename;
|
||||
switch(m->kind) {
|
||||
case TOOLMIME_PARTS:
|
||||
ret = tool2curlmime(curl, m, &submime);
|
||||
if(!ret) {
|
||||
ret = curl_mime_subparts(part, submime);
|
||||
if(ret)
|
||||
curl_mime_free(submime);
|
||||
}
|
||||
break;
|
||||
|
||||
case TOOLMIME_DATA:
|
||||
ret = curl_mime_data(part, m->data, CURL_ZERO_TERMINATED);
|
||||
break;
|
||||
|
||||
case TOOLMIME_FILE:
|
||||
case TOOLMIME_FILEDATA:
|
||||
ret = curl_mime_filedata(part, m->data);
|
||||
if(!ret && m->kind == TOOLMIME_FILEDATA && !filename)
|
||||
ret = curl_mime_filename(part, NULL);
|
||||
break;
|
||||
|
||||
case TOOLMIME_STDIN:
|
||||
if(!filename)
|
||||
filename = "-";
|
||||
FALLTHROUGH();
|
||||
case TOOLMIME_STDINDATA:
|
||||
ret = curl_mime_data_cb(part, m->size,
|
||||
(curl_read_callback) tool_mime_stdin_read,
|
||||
(curl_seek_callback) tool_mime_stdin_seek,
|
||||
NULL, m);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Other cases not possible in this context. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!ret && filename)
|
||||
ret = curl_mime_filename(part, filename);
|
||||
if(!ret)
|
||||
ret = curl_mime_type(part, m->type);
|
||||
if(!ret)
|
||||
ret = curl_mime_headers(part, m->headers, 0);
|
||||
if(!ret)
|
||||
ret = curl_mime_encoder(part, m->encoder);
|
||||
if(!ret)
|
||||
ret = curl_mime_name(part, m->name);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
CURLcode tool2curlmime(CURL *curl, struct tool_mime *m, curl_mime **mime)
|
||||
{
|
||||
CURLcode ret = CURLE_OK;
|
||||
|
||||
*mime = curl_mime_init(curl);
|
||||
if(!*mime)
|
||||
ret = CURLE_OUT_OF_MEMORY;
|
||||
else
|
||||
ret = tool2curlparts(curl, m->subparts, *mime);
|
||||
if(ret) {
|
||||
curl_mime_free(*mime);
|
||||
*mime = NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* helper function to get a word from form param
|
||||
* after call get_param_word, str either point to string end
|
||||
* or point to any of end chars.
|
||||
*/
|
||||
static char *get_param_word(char **str, char **end_pos, char endchar)
|
||||
{
|
||||
char *ptr = *str;
|
||||
/* the first non-space char is here */
|
||||
char *word_begin = ptr;
|
||||
char *ptr2;
|
||||
char *escape = NULL;
|
||||
|
||||
if(*ptr == '"') {
|
||||
++ptr;
|
||||
while(*ptr) {
|
||||
if(*ptr == '\\') {
|
||||
if(ptr[1] == '\\' || ptr[1] == '"') {
|
||||
/* remember the first escape position */
|
||||
if(!escape)
|
||||
escape = ptr;
|
||||
/* skip escape of back-slash or double-quote */
|
||||
ptr += 2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if(*ptr == '"') {
|
||||
bool trailing_data = FALSE;
|
||||
*end_pos = ptr;
|
||||
if(escape) {
|
||||
/* has escape, we restore the unescaped string here */
|
||||
ptr = ptr2 = escape;
|
||||
do {
|
||||
if(*ptr == '\\' && (ptr[1] == '\\' || ptr[1] == '"'))
|
||||
++ptr;
|
||||
*ptr2++ = *ptr++;
|
||||
}
|
||||
while(ptr < *end_pos);
|
||||
*end_pos = ptr2;
|
||||
}
|
||||
++ptr;
|
||||
while(*ptr && *ptr != ';' && *ptr != endchar) {
|
||||
if(!ISSPACE(*ptr))
|
||||
trailing_data = TRUE;
|
||||
++ptr;
|
||||
}
|
||||
if(trailing_data)
|
||||
warnf("Trailing data after quoted form parameter");
|
||||
*str = ptr;
|
||||
return word_begin + 1;
|
||||
}
|
||||
++ptr;
|
||||
}
|
||||
/* end quote is missing, treat it as non-quoted. */
|
||||
ptr = word_begin;
|
||||
}
|
||||
|
||||
while(*ptr && *ptr != ';' && *ptr != endchar)
|
||||
++ptr;
|
||||
*str = *end_pos = ptr;
|
||||
return word_begin;
|
||||
}
|
||||
|
||||
/* Append slist item and return -1 if failed. */
|
||||
static int slist_append(struct curl_slist **plist, const char *data)
|
||||
{
|
||||
struct curl_slist *s = curl_slist_append(*plist, data);
|
||||
|
||||
if(!s)
|
||||
return -1;
|
||||
|
||||
*plist = s;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read headers from a file and append to list. */
|
||||
static int read_field_headers(FILE *fp, struct curl_slist **pheaders)
|
||||
{
|
||||
struct dynbuf line;
|
||||
bool error = FALSE;
|
||||
int err = 0;
|
||||
|
||||
curlx_dyn_init(&line, 8092);
|
||||
while(my_get_line(fp, &line, &error)) {
|
||||
const char *ptr = curlx_dyn_ptr(&line);
|
||||
size_t len = curlx_dyn_len(&line);
|
||||
bool folded = FALSE;
|
||||
if(ptr[0] == '#') /* comment */
|
||||
continue;
|
||||
else if(ptr[0] == ' ') /* a continuation from the line before */
|
||||
folded = TRUE;
|
||||
/* trim off trailing CRLFs and whitespaces */
|
||||
while(len && (ISNEWLINE(ptr[len -1]) || ISBLANK(ptr[len - 1])))
|
||||
len--;
|
||||
|
||||
if(!len)
|
||||
continue;
|
||||
curlx_dyn_setlen(&line, len); /* set the new length */
|
||||
|
||||
if(folded && *pheaders) {
|
||||
/* append this new line onto the previous line */
|
||||
struct dynbuf amend;
|
||||
struct curl_slist *l = *pheaders;
|
||||
curlx_dyn_init(&amend, 8092);
|
||||
/* find the last node */
|
||||
while(l && l->next)
|
||||
l = l->next;
|
||||
/* add both parts */
|
||||
if(curlx_dyn_add(&amend, l->data) || curlx_dyn_addn(&amend, ptr, len)) {
|
||||
err = -1;
|
||||
break;
|
||||
}
|
||||
curl_free(l->data);
|
||||
/* we use maprintf here to make it a libcurl alloc, to match the previous
|
||||
curl_slist_append */
|
||||
l->data = curl_maprintf("%s", curlx_dyn_ptr(&amend));
|
||||
curlx_dyn_free(&amend);
|
||||
if(!l->data) {
|
||||
errorf("Out of memory for field headers");
|
||||
err = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
err = slist_append(pheaders, ptr);
|
||||
}
|
||||
if(err) {
|
||||
errorf("Out of memory for field headers");
|
||||
err = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
curlx_dyn_free(&line);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int get_param_part(char endchar,
|
||||
char **str, char **pdata, char **ptype,
|
||||
char **pfilename, char **pencoder,
|
||||
struct curl_slist **pheaders)
|
||||
{
|
||||
char *p = *str;
|
||||
char *type = NULL;
|
||||
char *filename = NULL;
|
||||
char *encoder = NULL;
|
||||
char *endpos;
|
||||
char *tp;
|
||||
char sep;
|
||||
char *endct = NULL;
|
||||
struct curl_slist *headers = NULL;
|
||||
|
||||
if(ptype)
|
||||
*ptype = NULL;
|
||||
if(pfilename)
|
||||
*pfilename = NULL;
|
||||
if(pheaders)
|
||||
*pheaders = NULL;
|
||||
if(pencoder)
|
||||
*pencoder = NULL;
|
||||
while(ISBLANK(*p))
|
||||
p++;
|
||||
tp = p;
|
||||
*pdata = get_param_word(&p, &endpos, endchar);
|
||||
/* If not quoted, strip trailing spaces. */
|
||||
if(*pdata == tp)
|
||||
while(endpos > *pdata && ISBLANK(endpos[-1]))
|
||||
endpos--;
|
||||
sep = *p;
|
||||
*endpos = '\0';
|
||||
while(sep == ';') {
|
||||
while(p++ && ISBLANK(*p))
|
||||
;
|
||||
|
||||
if(!endct && checkprefix("type=", p)) {
|
||||
size_t tlen;
|
||||
for(p += 5; ISBLANK(*p); p++)
|
||||
;
|
||||
/* set type pointer */
|
||||
type = p;
|
||||
|
||||
/* find end of content-type */
|
||||
tlen = strcspn(p, "()<>@,;:\\\"[]?=\r\n ");
|
||||
p += tlen;
|
||||
endct = p;
|
||||
sep = *p;
|
||||
}
|
||||
else if(checkprefix("filename=", p)) {
|
||||
if(endct) {
|
||||
*endct = '\0';
|
||||
endct = NULL;
|
||||
}
|
||||
for(p += 9; ISBLANK(*p); p++)
|
||||
;
|
||||
tp = p;
|
||||
filename = get_param_word(&p, &endpos, endchar);
|
||||
/* If not quoted, strip trailing spaces. */
|
||||
if(filename == tp)
|
||||
while(endpos > filename && ISBLANK(endpos[-1]))
|
||||
endpos--;
|
||||
sep = *p;
|
||||
*endpos = '\0';
|
||||
}
|
||||
else if(checkprefix("headers=", p)) {
|
||||
if(endct) {
|
||||
*endct = '\0';
|
||||
endct = NULL;
|
||||
}
|
||||
p += 8;
|
||||
if(*p == '@' || *p == '<') {
|
||||
char *hdrfile;
|
||||
FILE *fp;
|
||||
/* Read headers from a file. */
|
||||
do {
|
||||
p++;
|
||||
} while(ISBLANK(*p));
|
||||
tp = p;
|
||||
hdrfile = get_param_word(&p, &endpos, endchar);
|
||||
/* If not quoted, strip trailing spaces. */
|
||||
if(hdrfile == tp)
|
||||
while(endpos > hdrfile && ISBLANK(endpos[-1]))
|
||||
endpos--;
|
||||
sep = *p;
|
||||
*endpos = '\0';
|
||||
fp = curlx_fopen(hdrfile, FOPEN_READTEXT);
|
||||
if(!fp) {
|
||||
char errbuf[STRERROR_LEN];
|
||||
warnf("Cannot read from %s: %s", hdrfile,
|
||||
curlx_strerror(errno, errbuf, sizeof(errbuf)));
|
||||
}
|
||||
else {
|
||||
int i = read_field_headers(fp, &headers);
|
||||
|
||||
curlx_fclose(fp);
|
||||
if(i) {
|
||||
curl_slist_free_all(headers);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
char *hdr;
|
||||
|
||||
while(ISBLANK(*p))
|
||||
p++;
|
||||
tp = p;
|
||||
hdr = get_param_word(&p, &endpos, endchar);
|
||||
/* If not quoted, strip trailing spaces. */
|
||||
if(hdr == tp)
|
||||
while(endpos > hdr && ISBLANK(endpos[-1]))
|
||||
endpos--;
|
||||
sep = *p;
|
||||
*endpos = '\0';
|
||||
if(slist_append(&headers, hdr)) {
|
||||
errorf("Out of memory for field header");
|
||||
curl_slist_free_all(headers);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(checkprefix("encoder=", p)) {
|
||||
if(endct) {
|
||||
*endct = '\0';
|
||||
endct = NULL;
|
||||
}
|
||||
for(p += 8; ISBLANK(*p); p++)
|
||||
;
|
||||
tp = p;
|
||||
encoder = get_param_word(&p, &endpos, endchar);
|
||||
/* If not quoted, strip trailing spaces. */
|
||||
if(encoder == tp)
|
||||
while(endpos > encoder && ISSPACE(endpos[-1]))
|
||||
endpos--;
|
||||
sep = *p;
|
||||
*endpos = '\0';
|
||||
}
|
||||
else if(endct) {
|
||||
/* This is part of content type. */
|
||||
for(endct = p; *p && *p != ';' && *p != endchar; p++)
|
||||
if(!ISBLANK(*p))
|
||||
endct = p + 1;
|
||||
sep = *p;
|
||||
}
|
||||
else {
|
||||
/* unknown prefix, skip to next block */
|
||||
char *unknown = get_param_word(&p, &endpos, endchar);
|
||||
|
||||
sep = *p;
|
||||
*endpos = '\0';
|
||||
if(*unknown)
|
||||
warnf("skip unknown form field: %s", unknown);
|
||||
}
|
||||
}
|
||||
|
||||
/* Terminate content type. */
|
||||
if(endct)
|
||||
*endct = '\0';
|
||||
|
||||
if(ptype)
|
||||
*ptype = type;
|
||||
else if(type)
|
||||
warnf("Field content type not allowed here: %s", type);
|
||||
|
||||
if(pfilename)
|
||||
*pfilename = filename;
|
||||
else if(filename)
|
||||
warnf("Field filename not allowed here: %s", filename);
|
||||
|
||||
if(pencoder)
|
||||
*pencoder = encoder;
|
||||
else if(encoder)
|
||||
warnf("Field encoder not allowed here: %s", encoder);
|
||||
|
||||
if(pheaders)
|
||||
*pheaders = headers;
|
||||
else if(headers) {
|
||||
warnf("Field headers not allowed here: %s", headers->data);
|
||||
curl_slist_free_all(headers);
|
||||
}
|
||||
|
||||
*str = p;
|
||||
return sep & 0xFF;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* formparse()
|
||||
*
|
||||
* Reads a 'name=value' parameter and builds the appropriate linked list.
|
||||
*
|
||||
* If the value is of the form '<filename', field data is read from the
|
||||
* given file.
|
||||
|
||||
* Specify files to upload with 'name=@filename', or 'name=@"filename"'
|
||||
* in case the filename contain ',' or ';'. Supports specified
|
||||
* given Content-Type of the files. Such as ';type=<content-type>'.
|
||||
*
|
||||
* If literal_value is set, any initial '@' or '<' in the value string
|
||||
* loses its special meaning, as does any embedded ';type='.
|
||||
*
|
||||
* You may specify more than one file for a single name (field). Specify
|
||||
* multiple files by writing it like:
|
||||
*
|
||||
* 'name=@filename,filename2,filename3'
|
||||
*
|
||||
* or use double-quotes quote the filename:
|
||||
*
|
||||
* 'name=@"filename","filename2","filename3"'
|
||||
*
|
||||
* If you want content-types specified for each too, write them like:
|
||||
*
|
||||
* 'name=@filename;type=image/gif,filename2,filename3'
|
||||
*
|
||||
* If you want custom headers added for a single part, write them in a separate
|
||||
* file and do like this:
|
||||
*
|
||||
* 'name=foo;headers=@headerfile' or why not
|
||||
* 'name=@filemame;headers=@headerfile'
|
||||
*
|
||||
* To upload a file, but to fake the filename that will be included in the
|
||||
* formpost, do like this:
|
||||
*
|
||||
* 'name=@filename;filename=/dev/null' or quote the faked filename like:
|
||||
* 'name=@filename;filename="play, play, and play.txt"'
|
||||
*
|
||||
* If filename/path contains ',' or ';', it must be quoted by double-quotes,
|
||||
* else curl will fail to figure out the correct filename. if the filename
|
||||
* tobe quoted contains '"' or '\', '"' and '\' must be escaped by backslash.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#define SET_TOOL_MIME_PTR(m, field) \
|
||||
do { \
|
||||
if(field) { \
|
||||
(m)->field = strdup(field); \
|
||||
if(!(m)->field) \
|
||||
goto fail; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
int formparse(const char *input,
|
||||
struct tool_mime **mimeroot,
|
||||
struct tool_mime **mimecurrent,
|
||||
bool literal_value)
|
||||
{
|
||||
/* input MUST be a string in the format 'name=contents' and we will
|
||||
build a linked list with the info */
|
||||
char *name = NULL;
|
||||
char *contents = NULL;
|
||||
char *contp;
|
||||
char *data;
|
||||
char *type = NULL;
|
||||
char *filename = NULL;
|
||||
char *encoder = NULL;
|
||||
struct curl_slist *headers = NULL;
|
||||
struct tool_mime *part = NULL;
|
||||
CURLcode res;
|
||||
int err = 1;
|
||||
|
||||
/* Allocate the main mime structure if needed. */
|
||||
if(!*mimecurrent) {
|
||||
*mimeroot = tool_mime_new_parts(NULL);
|
||||
if(!*mimeroot)
|
||||
goto fail;
|
||||
*mimecurrent = *mimeroot;
|
||||
}
|
||||
|
||||
/* Make a copy we can overwrite. */
|
||||
contents = strdup(input);
|
||||
if(!contents)
|
||||
goto fail;
|
||||
|
||||
/* Scan for the end of the name. */
|
||||
contp = strchr(contents, '=');
|
||||
if(contp) {
|
||||
int sep = '\0';
|
||||
if(contp > contents)
|
||||
name = contents;
|
||||
*contp++ = '\0';
|
||||
|
||||
if(*contp == '(' && !literal_value) {
|
||||
/* Starting a multipart. */
|
||||
sep = get_param_part('\0', &contp, &data, &type, NULL, NULL, &headers);
|
||||
if(sep < 0)
|
||||
goto fail;
|
||||
part = tool_mime_new_parts(*mimecurrent);
|
||||
if(!part)
|
||||
goto fail;
|
||||
*mimecurrent = part;
|
||||
part->headers = headers;
|
||||
headers = NULL;
|
||||
SET_TOOL_MIME_PTR(part, type);
|
||||
}
|
||||
else if(!name && !strcmp(contp, ")") && !literal_value) {
|
||||
/* Ending a multipart. */
|
||||
if(*mimecurrent == *mimeroot) {
|
||||
warnf("no multipart to terminate");
|
||||
goto fail;
|
||||
}
|
||||
*mimecurrent = (*mimecurrent)->parent;
|
||||
}
|
||||
else if('@' == contp[0] && !literal_value) {
|
||||
|
||||
/* we use the @-letter to indicate filename(s) */
|
||||
|
||||
struct tool_mime *subparts = NULL;
|
||||
|
||||
do {
|
||||
/* since this was a file, it may have a content-type specifier
|
||||
at the end too, or a filename. Or both. */
|
||||
++contp;
|
||||
sep = get_param_part(',', &contp,
|
||||
&data, &type, &filename, &encoder, &headers);
|
||||
if(sep < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* now contp point to comma or string end.
|
||||
If more files to come, make sure we have multiparts. */
|
||||
if(!subparts) {
|
||||
if(sep != ',') /* If there is a single file. */
|
||||
subparts = *mimecurrent;
|
||||
else {
|
||||
subparts = tool_mime_new_parts(*mimecurrent);
|
||||
if(!subparts)
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* Store that file in a part. */
|
||||
part = tool_mime_new_filedata(subparts, data, TRUE, &res);
|
||||
if(!part)
|
||||
goto fail;
|
||||
part->headers = headers;
|
||||
headers = NULL;
|
||||
if(res == CURLE_READ_ERROR) {
|
||||
/* An error occurred while reading stdin: if read has started,
|
||||
issue the error now. Else, delay it until processed by
|
||||
libcurl. */
|
||||
if(part->size > 0) {
|
||||
warnf("error while reading standard input");
|
||||
goto fail;
|
||||
}
|
||||
tool_safefree(part->data);
|
||||
part->size = -1;
|
||||
res = CURLE_OK;
|
||||
}
|
||||
SET_TOOL_MIME_PTR(part, filename);
|
||||
SET_TOOL_MIME_PTR(part, type);
|
||||
SET_TOOL_MIME_PTR(part, encoder);
|
||||
|
||||
/* *contp could be '\0', so we just check with the delimiter */
|
||||
} while(sep); /* loop if there is another filename */
|
||||
part = (*mimecurrent)->subparts; /* Set name on group. */
|
||||
}
|
||||
else {
|
||||
if(*contp == '<' && !literal_value) {
|
||||
++contp;
|
||||
sep = get_param_part('\0', &contp,
|
||||
&data, &type, NULL, &encoder, &headers);
|
||||
if(sep < 0)
|
||||
goto fail;
|
||||
|
||||
part = tool_mime_new_filedata(*mimecurrent, data, FALSE,
|
||||
&res);
|
||||
if(!part)
|
||||
goto fail;
|
||||
part->headers = headers;
|
||||
headers = NULL;
|
||||
if(res == CURLE_READ_ERROR) {
|
||||
/* An error occurred while reading stdin: if read has started,
|
||||
issue the error now. Else, delay it until processed by
|
||||
libcurl. */
|
||||
if(part->size > 0) {
|
||||
warnf("error while reading standard input");
|
||||
goto fail;
|
||||
}
|
||||
tool_safefree(part->data);
|
||||
part->size = -1;
|
||||
res = CURLE_OK;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(literal_value)
|
||||
data = contp;
|
||||
else {
|
||||
sep = get_param_part('\0', &contp,
|
||||
&data, &type, &filename, &encoder, &headers);
|
||||
if(sep < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
part = tool_mime_new_data(*mimecurrent, data);
|
||||
if(!part)
|
||||
goto fail;
|
||||
part->headers = headers;
|
||||
headers = NULL;
|
||||
}
|
||||
|
||||
SET_TOOL_MIME_PTR(part, filename);
|
||||
SET_TOOL_MIME_PTR(part, type);
|
||||
SET_TOOL_MIME_PTR(part, encoder);
|
||||
|
||||
if(sep) {
|
||||
*contp = (char) sep;
|
||||
warnf("garbage at end of field specification: %s", contp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set part name. */
|
||||
SET_TOOL_MIME_PTR(part, name);
|
||||
}
|
||||
else {
|
||||
warnf("Illegally formatted input field");
|
||||
goto fail;
|
||||
}
|
||||
err = 0;
|
||||
fail:
|
||||
tool_safefree(contents);
|
||||
curl_slist_free_all(headers);
|
||||
return err;
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
#ifndef HEADER_CURL_TOOL_FORMPARSE_H
|
||||
#define HEADER_CURL_TOOL_FORMPARSE_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
/* Private structure for mime/parts. */
|
||||
|
||||
typedef enum {
|
||||
TOOLMIME_NONE = 0,
|
||||
TOOLMIME_PARTS,
|
||||
TOOLMIME_DATA,
|
||||
TOOLMIME_FILE,
|
||||
TOOLMIME_FILEDATA,
|
||||
TOOLMIME_STDIN,
|
||||
TOOLMIME_STDINDATA
|
||||
} toolmimekind;
|
||||
|
||||
struct tool_mime {
|
||||
/* Structural fields. */
|
||||
toolmimekind kind; /* Part kind. */
|
||||
struct tool_mime *parent; /* Parent item. */
|
||||
struct tool_mime *prev; /* Previous sibling (reverse order link). */
|
||||
/* Common fields. */
|
||||
char *data; /* Actual data or data filename. */
|
||||
char *name; /* Part name. */
|
||||
char *filename; /* Part's filename. */
|
||||
char *type; /* Part's mime type. */
|
||||
char *encoder; /* Part's requested encoding. */
|
||||
struct curl_slist *headers; /* User-defined headers. */
|
||||
/* TOOLMIME_PARTS fields. */
|
||||
struct tool_mime *subparts; /* Part's subparts. */
|
||||
/* TOOLMIME_STDIN/TOOLMIME_STDINDATA fields. */
|
||||
curl_off_t origin; /* Stdin read origin offset. */
|
||||
curl_off_t size; /* Stdin data size. */
|
||||
curl_off_t curpos; /* Stdin current read position. */
|
||||
};
|
||||
|
||||
size_t tool_mime_stdin_read(char *buffer,
|
||||
size_t size, size_t nitems, void *arg);
|
||||
int tool_mime_stdin_seek(void *instream, curl_off_t offset, int whence);
|
||||
|
||||
int formparse(const char *input,
|
||||
struct tool_mime **mimeroot,
|
||||
struct tool_mime **mimecurrent,
|
||||
bool literal_value);
|
||||
CURLcode tool2curlmime(CURL *curl, struct tool_mime *m, curl_mime **mime);
|
||||
void tool_mime_free(struct tool_mime *mime);
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_FORMPARSE_H */
|
||||
+3095
File diff suppressed because it is too large
Load Diff
+396
@@ -0,0 +1,396 @@
|
||||
#ifndef HEADER_CURL_TOOL_GETPARAM_H
|
||||
#define HEADER_CURL_TOOL_GETPARAM_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
/* one enum for every command line option. The name is the verbatim long
|
||||
option name, but in uppercase with periods and minuses replaced with
|
||||
underscores using a "C_" prefix. */
|
||||
typedef enum {
|
||||
C_ABSTRACT_UNIX_SOCKET,
|
||||
C_ALPN,
|
||||
C_ALT_SVC,
|
||||
C_ANYAUTH,
|
||||
C_APPEND,
|
||||
C_AWS_SIGV4,
|
||||
C_BASIC,
|
||||
C_BUFFER,
|
||||
C_CA_NATIVE,
|
||||
C_CACERT,
|
||||
C_CAPATH,
|
||||
C_CERT,
|
||||
C_CERT_STATUS,
|
||||
C_CERT_TYPE,
|
||||
C_CIPHERS,
|
||||
C_CLOBBER,
|
||||
C_COMPRESSED,
|
||||
C_COMPRESSED_SSH,
|
||||
C_CONFIG,
|
||||
C_CONNECT_TIMEOUT,
|
||||
C_CONNECT_TO,
|
||||
C_CONTINUE_AT,
|
||||
C_COOKIE,
|
||||
C_COOKIE_JAR,
|
||||
C_CREATE_DIRS,
|
||||
C_CREATE_FILE_MODE,
|
||||
C_CRLF,
|
||||
C_CRLFILE,
|
||||
C_CURVES,
|
||||
C_DATA,
|
||||
C_DATA_ASCII,
|
||||
C_DATA_BINARY,
|
||||
C_DATA_RAW,
|
||||
C_DATA_URLENCODE,
|
||||
C_DELEGATION,
|
||||
C_DIGEST,
|
||||
C_DISABLE,
|
||||
C_DISABLE_EPRT,
|
||||
C_DISABLE_EPSV,
|
||||
C_DISALLOW_USERNAME_IN_URL,
|
||||
C_DNS_INTERFACE,
|
||||
C_DNS_IPV4_ADDR,
|
||||
C_DNS_IPV6_ADDR,
|
||||
C_DNS_SERVERS,
|
||||
C_DOH_CERT_STATUS,
|
||||
C_DOH_INSECURE,
|
||||
C_DOH_URL,
|
||||
C_DUMP_CA_EMBED,
|
||||
C_DUMP_HEADER,
|
||||
C_ECH,
|
||||
C_EGD_FILE,
|
||||
C_ENGINE,
|
||||
C_EPRT,
|
||||
C_EPSV,
|
||||
C_ETAG_COMPARE,
|
||||
C_ETAG_SAVE,
|
||||
C_EXPECT100_TIMEOUT,
|
||||
C_FAIL,
|
||||
C_FAIL_EARLY,
|
||||
C_FAIL_WITH_BODY,
|
||||
C_FALSE_START,
|
||||
C_FOLLOW,
|
||||
C_FORM,
|
||||
C_FORM_ESCAPE,
|
||||
C_FORM_STRING,
|
||||
C_FTP_ACCOUNT,
|
||||
C_FTP_ALTERNATIVE_TO_USER,
|
||||
C_FTP_CREATE_DIRS,
|
||||
C_FTP_METHOD,
|
||||
C_FTP_PASV,
|
||||
C_FTP_PORT,
|
||||
C_FTP_PRET,
|
||||
C_FTP_SKIP_PASV_IP,
|
||||
C_FTP_SSL,
|
||||
C_FTP_SSL_CCC,
|
||||
C_FTP_SSL_CCC_MODE,
|
||||
C_FTP_SSL_CONTROL,
|
||||
C_FTP_SSL_REQD,
|
||||
C_GET,
|
||||
C_GLOBOFF,
|
||||
C_HAPPY_EYEBALLS_TIMEOUT_MS,
|
||||
C_HAPROXY_CLIENTIP,
|
||||
C_HAPROXY_PROTOCOL,
|
||||
C_HEAD,
|
||||
C_HEADER,
|
||||
C_HELP,
|
||||
C_HOSTPUBMD5,
|
||||
C_HOSTPUBSHA256,
|
||||
C_HSTS,
|
||||
C_HTTP0_9,
|
||||
C_HTTP1_0,
|
||||
C_HTTP1_1,
|
||||
C_HTTP2,
|
||||
C_HTTP2_PRIOR_KNOWLEDGE,
|
||||
C_HTTP3,
|
||||
C_HTTP3_ONLY,
|
||||
C_IGNORE_CONTENT_LENGTH,
|
||||
C_INCLUDE,
|
||||
C_INSECURE,
|
||||
C_INTERFACE,
|
||||
C_IPFS_GATEWAY,
|
||||
C_IPV4,
|
||||
C_IPV6,
|
||||
C_JSON,
|
||||
C_JUNK_SESSION_COOKIES,
|
||||
C_KEEPALIVE,
|
||||
C_KEEPALIVE_CNT,
|
||||
C_KEEPALIVE_TIME,
|
||||
C_KEY,
|
||||
C_KEY_TYPE,
|
||||
C_KNOWNHOSTS,
|
||||
C_KRB,
|
||||
C_KRB4,
|
||||
C_LIBCURL,
|
||||
C_LIMIT_RATE,
|
||||
C_LIST_ONLY,
|
||||
C_LOCAL_PORT,
|
||||
C_LOCATION,
|
||||
C_LOCATION_TRUSTED,
|
||||
C_LOGIN_OPTIONS,
|
||||
C_MAIL_AUTH,
|
||||
C_MAIL_FROM,
|
||||
C_MAIL_RCPT,
|
||||
C_MAIL_RCPT_ALLOWFAILS,
|
||||
C_MANUAL,
|
||||
C_MAX_FILESIZE,
|
||||
C_MAX_REDIRS,
|
||||
C_MAX_TIME,
|
||||
C_METALINK,
|
||||
C_MPTCP,
|
||||
C_NEGOTIATE,
|
||||
C_NETRC,
|
||||
C_NETRC_FILE,
|
||||
C_NETRC_OPTIONAL,
|
||||
C_NEXT,
|
||||
C_NOPROXY,
|
||||
C_NPN,
|
||||
C_NTLM,
|
||||
C_NTLM_WB,
|
||||
C_OAUTH2_BEARER,
|
||||
C_OUT_NULL,
|
||||
C_OUTPUT,
|
||||
C_OUTPUT_DIR,
|
||||
C_PARALLEL,
|
||||
C_PARALLEL_HOST,
|
||||
C_PARALLEL_IMMEDIATE,
|
||||
C_PARALLEL_MAX,
|
||||
C_PASS,
|
||||
C_PATH_AS_IS,
|
||||
C_PINNEDPUBKEY,
|
||||
C_POST301,
|
||||
C_POST302,
|
||||
C_POST303,
|
||||
C_PREPROXY,
|
||||
C_PROGRESS_BAR,
|
||||
C_PROGRESS_METER,
|
||||
C_PROTO,
|
||||
C_PROTO_DEFAULT,
|
||||
C_PROTO_REDIR,
|
||||
C_PROXY,
|
||||
C_PROXY_ANYAUTH,
|
||||
C_PROXY_BASIC,
|
||||
C_PROXY_CA_NATIVE,
|
||||
C_PROXY_CACERT,
|
||||
C_PROXY_CAPATH,
|
||||
C_PROXY_CERT,
|
||||
C_PROXY_CERT_TYPE,
|
||||
C_PROXY_CIPHERS,
|
||||
C_PROXY_CRLFILE,
|
||||
C_PROXY_DIGEST,
|
||||
C_PROXY_HEADER,
|
||||
C_PROXY_HTTP2,
|
||||
C_PROXY_INSECURE,
|
||||
C_PROXY_KEY,
|
||||
C_PROXY_KEY_TYPE,
|
||||
C_PROXY_NEGOTIATE,
|
||||
C_PROXY_NTLM,
|
||||
C_PROXY_PASS,
|
||||
C_PROXY_PINNEDPUBKEY,
|
||||
C_PROXY_SERVICE_NAME,
|
||||
C_PROXY_SSL_ALLOW_BEAST,
|
||||
C_PROXY_SSL_AUTO_CLIENT_CERT,
|
||||
C_PROXY_TLS13_CIPHERS,
|
||||
C_PROXY_TLSAUTHTYPE,
|
||||
C_PROXY_TLSPASSWORD,
|
||||
C_PROXY_TLSUSER,
|
||||
C_PROXY_TLSV1,
|
||||
C_PROXY_USER,
|
||||
C_PROXY1_0,
|
||||
C_PROXYTUNNEL,
|
||||
C_PUBKEY,
|
||||
C_QUOTE,
|
||||
C_RANDOM_FILE,
|
||||
C_RANGE,
|
||||
C_RATE,
|
||||
C_RAW,
|
||||
C_REFERER,
|
||||
C_REMOTE_HEADER_NAME,
|
||||
C_REMOTE_NAME,
|
||||
C_REMOTE_NAME_ALL,
|
||||
C_REMOTE_TIME,
|
||||
C_REMOVE_ON_ERROR,
|
||||
C_REQUEST,
|
||||
C_REQUEST_TARGET,
|
||||
C_RESOLVE,
|
||||
C_RETRY,
|
||||
C_RETRY_ALL_ERRORS,
|
||||
C_RETRY_CONNREFUSED,
|
||||
C_RETRY_DELAY,
|
||||
C_RETRY_MAX_TIME,
|
||||
C_SASL_AUTHZID,
|
||||
C_SASL_IR,
|
||||
C_SERVICE_NAME,
|
||||
C_SESSIONID,
|
||||
C_SHOW_ERROR,
|
||||
C_SHOW_HEADERS,
|
||||
C_SILENT,
|
||||
C_SIGNATURE_ALGORITHMS,
|
||||
C_SKIP_EXISTING,
|
||||
C_SOCKS4,
|
||||
C_SOCKS4A,
|
||||
C_SOCKS5,
|
||||
C_SOCKS5_BASIC,
|
||||
C_SOCKS5_GSSAPI,
|
||||
C_SOCKS5_GSSAPI_NEC,
|
||||
C_SOCKS5_GSSAPI_SERVICE,
|
||||
C_SOCKS5_HOSTNAME,
|
||||
C_SPEED_LIMIT,
|
||||
C_SPEED_TIME,
|
||||
C_SSL,
|
||||
C_SSL_ALLOW_BEAST,
|
||||
C_SSL_AUTO_CLIENT_CERT,
|
||||
C_SSL_NO_REVOKE,
|
||||
C_SSL_REQD,
|
||||
C_SSL_REVOKE_BEST_EFFORT,
|
||||
C_SSL_SESSIONS,
|
||||
C_SSLV2,
|
||||
C_SSLV3,
|
||||
C_STDERR,
|
||||
C_STYLED_OUTPUT,
|
||||
C_SUPPRESS_CONNECT_HEADERS,
|
||||
C_TCP_FASTOPEN,
|
||||
C_TCP_NODELAY,
|
||||
C_TELNET_OPTION,
|
||||
C_TEST_DUPHANDLE,
|
||||
C_TEST_EVENT,
|
||||
C_TFTP_BLKSIZE,
|
||||
C_TFTP_NO_OPTIONS,
|
||||
C_TIME_COND,
|
||||
C_TLS_EARLYDATA,
|
||||
C_TLS_MAX,
|
||||
C_TLS13_CIPHERS,
|
||||
C_TLSAUTHTYPE,
|
||||
C_TLSPASSWORD,
|
||||
C_TLSUSER,
|
||||
C_TLSV1,
|
||||
C_TLSV1_0,
|
||||
C_TLSV1_1,
|
||||
C_TLSV1_2,
|
||||
C_TLSV1_3,
|
||||
C_TR_ENCODING,
|
||||
C_TRACE,
|
||||
C_TRACE_ASCII,
|
||||
C_TRACE_CONFIG,
|
||||
C_TRACE_IDS,
|
||||
C_TRACE_TIME,
|
||||
C_IP_TOS,
|
||||
C_UNIX_SOCKET,
|
||||
C_UPLOAD_FILE,
|
||||
C_UPLOAD_FLAGS,
|
||||
C_URL,
|
||||
C_URL_QUERY,
|
||||
C_USE_ASCII,
|
||||
C_USER,
|
||||
C_USER_AGENT,
|
||||
C_VARIABLE,
|
||||
C_VERBOSE,
|
||||
C_VERSION,
|
||||
C_VLAN_PRIORITY,
|
||||
C_WDEBUG,
|
||||
C_WRITE_OUT,
|
||||
C_XATTR
|
||||
} cmdline_t;
|
||||
|
||||
#define ARG_NONE 0 /* stand-alone but not a boolean */
|
||||
#define ARG_BOOL 1 /* accepts a --no-[name] prefix */
|
||||
#define ARG_STRG 2 /* requires an argument */
|
||||
#define ARG_FILE 3 /* requires an argument, usually a filename */
|
||||
|
||||
#define ARG_TYPEMASK 0x03
|
||||
#define ARGTYPE(x) ((x) & ARG_TYPEMASK)
|
||||
|
||||
#define ARG_DEPR 0x10 /* deprecated option */
|
||||
#define ARG_CLEAR 0x20 /* clear cmdline argument */
|
||||
#define ARG_TLS 0x40 /* requires TLS support */
|
||||
#define ARG_NO 0x80 /* set if the option is documented as --no-* */
|
||||
|
||||
struct LongShort {
|
||||
const char *lname; /* long name option */
|
||||
unsigned char desc; /* type, see ARG_* */
|
||||
char letter; /* short name option or ' ' */
|
||||
unsigned short cmd;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
PARAM_OK = 0,
|
||||
PARAM_OPTION_UNKNOWN,
|
||||
PARAM_REQUIRES_PARAMETER,
|
||||
PARAM_BAD_USE,
|
||||
PARAM_HELP_REQUESTED,
|
||||
PARAM_MANUAL_REQUESTED,
|
||||
PARAM_VERSION_INFO_REQUESTED,
|
||||
PARAM_ENGINES_REQUESTED,
|
||||
PARAM_CA_EMBED_REQUESTED,
|
||||
PARAM_GOT_EXTRA_PARAMETER,
|
||||
PARAM_BAD_NUMERIC,
|
||||
PARAM_NEGATIVE_NUMERIC,
|
||||
PARAM_LIBCURL_DOESNT_SUPPORT,
|
||||
PARAM_LIBCURL_UNSUPPORTED_PROTOCOL,
|
||||
PARAM_NO_MEM,
|
||||
PARAM_NEXT_OPERATION,
|
||||
PARAM_NO_PREFIX,
|
||||
PARAM_NUMBER_TOO_LARGE,
|
||||
PARAM_CONTDISP_RESUME_FROM, /* --continue-at and --remote-header-name */
|
||||
PARAM_READ_ERROR,
|
||||
PARAM_EXPAND_ERROR, /* --expand problem */
|
||||
PARAM_BLANK_STRING,
|
||||
PARAM_VAR_SYNTAX, /* --variable syntax error */
|
||||
PARAM_RECURSION,
|
||||
PARAM_LAST
|
||||
} ParameterError;
|
||||
|
||||
struct OperationConfig;
|
||||
|
||||
const struct LongShort *findlongopt(const char *opt);
|
||||
const struct LongShort *findshortopt(char letter);
|
||||
|
||||
ParameterError getparameter(const char *flag, const char *nextarg,
|
||||
bool *usedarg,
|
||||
struct OperationConfig *config,
|
||||
int max_recursive);
|
||||
|
||||
#ifdef UNITTESTS
|
||||
void parse_cert_parameter(const char *cert_parameter,
|
||||
char **certname,
|
||||
char **passphrase);
|
||||
#endif
|
||||
|
||||
ParameterError parse_args(int argc, argv_item_t argv[]);
|
||||
|
||||
#if defined(UNICODE) && defined(_WIN32) && !defined(UNDER_CE)
|
||||
|
||||
#define convert_UTF8_to_tchar(ptr) curlx_convert_UTF8_to_wchar((ptr))
|
||||
#define convert_tchar_to_UTF8(ptr) curlx_convert_wchar_to_UTF8((ptr))
|
||||
#define unicodefree(ptr) curlx_unicodefree(ptr)
|
||||
|
||||
#else
|
||||
|
||||
#define convert_UTF8_to_tchar(ptr) (const char *)(ptr)
|
||||
#define convert_tchar_to_UTF8(ptr) (const char *)(ptr)
|
||||
#define unicodefree(ptr) do {} while(0)
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_GETPARAM_H */
|
||||
+203
@@ -0,0 +1,203 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#if defined(__AMIGA__) && !defined(__amigaos4__)
|
||||
# undef HAVE_TERMIOS_H
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GETPASS_R
|
||||
/* this file is only for systems without getpass_r() */
|
||||
|
||||
#ifdef HAVE_TERMIOS_H
|
||||
# include <termios.h>
|
||||
#elif defined(HAVE_TERMIO_H)
|
||||
# include <termio.h>
|
||||
#endif
|
||||
|
||||
#ifdef __VMS
|
||||
# include descrip
|
||||
# include starlet
|
||||
# include iodef
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && !defined(UNDER_CE)
|
||||
# include <conio.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include "tool_getpass.h"
|
||||
|
||||
#include "memdebug.h" /* keep this as LAST include */
|
||||
|
||||
#ifdef __VMS
|
||||
/* VMS implementation */
|
||||
char *getpass_r(const char *prompt, char *buffer, size_t buflen)
|
||||
{
|
||||
long sts;
|
||||
short chan;
|
||||
|
||||
/* MSK, 23-JAN-2004, iosbdef.h was not in VAX V7.2 or CC 6.4 */
|
||||
/* distribution so I created this. May revert back later to */
|
||||
/* struct _iosb iosb; */
|
||||
struct _iosb
|
||||
{
|
||||
short int iosb$w_status; /* status */
|
||||
short int iosb$w_bcnt; /* byte count */
|
||||
int unused; /* unused */
|
||||
} iosb;
|
||||
|
||||
$DESCRIPTOR(ttdesc, "TT");
|
||||
|
||||
buffer[0] = '\0';
|
||||
sts = sys$assign(&ttdesc, &chan, 0, 0);
|
||||
if(sts & 1) {
|
||||
sts = sys$qiow(0, chan,
|
||||
IO$_READPROMPT | IO$M_NOECHO,
|
||||
&iosb, 0, 0, buffer, buflen, 0, 0,
|
||||
prompt, strlen(prompt));
|
||||
|
||||
if((sts & 1) && (iosb.iosb$w_status & 1))
|
||||
buffer[iosb.iosb$w_bcnt] = '\0';
|
||||
|
||||
sys$dassgn(chan);
|
||||
}
|
||||
return buffer; /* we always return success */
|
||||
}
|
||||
#define DONE
|
||||
#endif /* __VMS */
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
char *getpass_r(const char *prompt, char *buffer, size_t buflen)
|
||||
{
|
||||
size_t i;
|
||||
fputs(prompt, tool_stderr);
|
||||
|
||||
for(i = 0; i < buflen; i++) {
|
||||
buffer[i] = (char)_getch();
|
||||
if(buffer[i] == '\r' || buffer[i] == '\n') {
|
||||
buffer[i] = '\0';
|
||||
break;
|
||||
}
|
||||
else
|
||||
if(buffer[i] == '\b')
|
||||
/* remove this letter and if this is not the first key, remove the
|
||||
previous one as well */
|
||||
i = i - (i >= 1 ? 2 : 1);
|
||||
}
|
||||
/* since echo is disabled, print a newline */
|
||||
fputs("\n", tool_stderr);
|
||||
/* if user did not hit ENTER, terminate buffer */
|
||||
if(i == buflen)
|
||||
buffer[buflen-1] = '\0';
|
||||
|
||||
return buffer; /* we always return success */
|
||||
}
|
||||
#define DONE
|
||||
#endif /* _WIN32 && !UNDER_CE */
|
||||
|
||||
#ifndef DONE /* not previously provided */
|
||||
|
||||
#ifdef HAVE_TERMIOS_H
|
||||
# define struct_term struct termios
|
||||
#elif defined(HAVE_TERMIO_H)
|
||||
# define struct_term struct termio
|
||||
#else
|
||||
# undef struct_term
|
||||
#endif
|
||||
|
||||
static bool ttyecho(bool enable, int fd)
|
||||
{
|
||||
#ifdef struct_term
|
||||
static struct_term withecho;
|
||||
static struct_term noecho;
|
||||
#endif
|
||||
if(!enable) {
|
||||
/* disable echo by extracting the current 'withecho' mode and remove the
|
||||
ECHO bit and set back the struct */
|
||||
#ifdef HAVE_TERMIOS_H
|
||||
tcgetattr(fd, &withecho);
|
||||
noecho = withecho;
|
||||
noecho.c_lflag &= ~(tcflag_t)ECHO;
|
||||
tcsetattr(fd, TCSANOW, &noecho);
|
||||
#elif defined(HAVE_TERMIO_H)
|
||||
ioctl(fd, TCGETA, &withecho);
|
||||
noecho = withecho;
|
||||
noecho.c_lflag &= ~(tcflag_t)ECHO;
|
||||
ioctl(fd, TCSETA, &noecho);
|
||||
#else
|
||||
/* neither HAVE_TERMIO_H nor HAVE_TERMIOS_H, we cannot disable echo! */
|
||||
(void)fd;
|
||||
return FALSE; /* not disabled */
|
||||
#endif
|
||||
return TRUE; /* disabled */
|
||||
}
|
||||
/* re-enable echo, assumes we disabled it before (and set the structs we
|
||||
now use to reset the terminal status) */
|
||||
#ifdef HAVE_TERMIOS_H
|
||||
tcsetattr(fd, TCSAFLUSH, &withecho);
|
||||
#elif defined(HAVE_TERMIO_H)
|
||||
ioctl(fd, TCSETA, &withecho);
|
||||
#else
|
||||
return FALSE; /* not enabled */
|
||||
#endif
|
||||
return TRUE; /* enabled */
|
||||
}
|
||||
|
||||
char *getpass_r(const char *prompt, /* prompt to display */
|
||||
char *password, /* buffer to store password in */
|
||||
size_t buflen) /* size of buffer to store password in */
|
||||
{
|
||||
ssize_t nread;
|
||||
bool disabled;
|
||||
int fd = curlx_open("/dev/tty", O_RDONLY);
|
||||
if(fd == -1)
|
||||
fd = STDIN_FILENO; /* use stdin if the tty could not be used */
|
||||
|
||||
disabled = ttyecho(FALSE, fd); /* disable terminal echo */
|
||||
|
||||
fputs(prompt, tool_stderr);
|
||||
nread = read(fd, password, buflen);
|
||||
if(nread > 0)
|
||||
password[--nread] = '\0'; /* null-terminate where enter is stored */
|
||||
else
|
||||
password[0] = '\0'; /* got nothing */
|
||||
|
||||
if(disabled) {
|
||||
/* if echo actually was disabled, add a newline */
|
||||
fputs("\n", tool_stderr);
|
||||
(void)ttyecho(TRUE, fd); /* enable echo */
|
||||
}
|
||||
|
||||
if(STDIN_FILENO != fd)
|
||||
close(fd);
|
||||
|
||||
return password; /* return pointer to buffer */
|
||||
}
|
||||
|
||||
#endif /* DONE */
|
||||
#endif /* HAVE_GETPASS_R */
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
#ifndef HEADER_CURL_TOOL_GETPASS_H
|
||||
#define HEADER_CURL_TOOL_GETPASS_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#ifndef HAVE_GETPASS_R
|
||||
/* If there is a system-provided function named like this, we trust it is
|
||||
also found in one of the standard headers. */
|
||||
|
||||
/*
|
||||
* Returning NULL will abort the continued operation!
|
||||
*/
|
||||
char *getpass_r(const char *prompt, char *buffer, size_t buflen);
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_GETPASS_H */
|
||||
Vendored
+407
@@ -0,0 +1,407 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#include "tool_help.h"
|
||||
#include "tool_libinfo.h"
|
||||
#include "tool_util.h"
|
||||
#include "tool_version.h"
|
||||
#include "tool_cb_prg.h"
|
||||
#include "tool_hugehelp.h"
|
||||
#include "tool_getparam.h"
|
||||
#include "tool_cfgable.h"
|
||||
#include "terminal.h"
|
||||
|
||||
#include "memdebug.h" /* keep this as LAST include */
|
||||
|
||||
struct category_descriptors {
|
||||
const char *opt;
|
||||
const char *desc;
|
||||
unsigned int category;
|
||||
};
|
||||
|
||||
static const struct category_descriptors categories[] = {
|
||||
/* important is left out because it is the default help page */
|
||||
{"auth", "Authentication methods", CURLHELP_AUTH},
|
||||
{"connection", "Manage connections", CURLHELP_CONNECTION},
|
||||
{"curl", "The command line tool itself", CURLHELP_CURL},
|
||||
{"deprecated", "Legacy", CURLHELP_DEPRECATED},
|
||||
{"dns", "Names and resolving", CURLHELP_DNS},
|
||||
{"file", "FILE protocol", CURLHELP_FILE},
|
||||
{"ftp", "FTP protocol", CURLHELP_FTP},
|
||||
{"global", "Global options", CURLHELP_GLOBAL},
|
||||
{"http", "HTTP and HTTPS protocol", CURLHELP_HTTP},
|
||||
{"imap", "IMAP protocol", CURLHELP_IMAP},
|
||||
{"ldap", "LDAP protocol", CURLHELP_LDAP},
|
||||
{"output", "File system output", CURLHELP_OUTPUT},
|
||||
{"pop3", "POP3 protocol", CURLHELP_POP3},
|
||||
{"post", "HTTP POST specific", CURLHELP_POST},
|
||||
{"proxy", "Options for proxies", CURLHELP_PROXY},
|
||||
{"scp", "SCP protocol", CURLHELP_SCP},
|
||||
{"sftp", "SFTP protocol", CURLHELP_SFTP},
|
||||
{"smtp", "SMTP protocol", CURLHELP_SMTP},
|
||||
{"ssh", "SSH protocol", CURLHELP_SSH},
|
||||
{"telnet", "TELNET protocol", CURLHELP_TELNET},
|
||||
{"tftp", "TFTP protocol", CURLHELP_TFTP},
|
||||
{"timeout", "Timeouts and delays", CURLHELP_TIMEOUT},
|
||||
{"tls", "TLS/SSL related", CURLHELP_TLS},
|
||||
{"upload", "Upload, sending data", CURLHELP_UPLOAD},
|
||||
{"verbose", "Tracing, logging etc", CURLHELP_VERBOSE}
|
||||
};
|
||||
|
||||
static void print_category(unsigned int category, unsigned int cols)
|
||||
{
|
||||
unsigned int i;
|
||||
size_t longopt = 5;
|
||||
size_t longdesc = 5;
|
||||
|
||||
for(i = 0; helptext[i].opt; ++i) {
|
||||
size_t len;
|
||||
if(!(helptext[i].categories & category))
|
||||
continue;
|
||||
len = strlen(helptext[i].opt);
|
||||
if(len > longopt)
|
||||
longopt = len;
|
||||
len = strlen(helptext[i].desc);
|
||||
if(len > longdesc)
|
||||
longdesc = len;
|
||||
}
|
||||
if(longopt + longdesc > cols)
|
||||
longopt = cols - longdesc;
|
||||
|
||||
for(i = 0; helptext[i].opt; ++i)
|
||||
if(helptext[i].categories & category) {
|
||||
size_t opt = longopt;
|
||||
size_t desclen = strlen(helptext[i].desc);
|
||||
if(opt + desclen >= (cols - 2)) {
|
||||
if(desclen < (cols - 2))
|
||||
opt = (cols - 3) - desclen;
|
||||
else
|
||||
opt = 0;
|
||||
}
|
||||
curl_mprintf(" %-*s %s\n", (int)opt, helptext[i].opt, helptext[i].desc);
|
||||
}
|
||||
}
|
||||
|
||||
/* Prints category if found. If not, it returns 1 */
|
||||
static int get_category_content(const char *category, unsigned int cols)
|
||||
{
|
||||
unsigned int i;
|
||||
for(i = 0; i < CURL_ARRAYSIZE(categories); ++i)
|
||||
if(curl_strequal(categories[i].opt, category)) {
|
||||
curl_mprintf("%s: %s\n", categories[i].opt, categories[i].desc);
|
||||
print_category(categories[i].category, cols);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Prints all categories and their description */
|
||||
static void get_categories(void)
|
||||
{
|
||||
unsigned int i;
|
||||
for(i = 0; i < CURL_ARRAYSIZE(categories); ++i)
|
||||
curl_mprintf(" %-11s %s\n", categories[i].opt, categories[i].desc);
|
||||
}
|
||||
|
||||
/* Prints all categories as a comma-separated list of given width */
|
||||
static void get_categories_list(unsigned int width)
|
||||
{
|
||||
unsigned int i;
|
||||
size_t col = 0;
|
||||
for(i = 0; i < CURL_ARRAYSIZE(categories); ++i) {
|
||||
size_t len = strlen(categories[i].opt);
|
||||
if(i == CURL_ARRAYSIZE(categories) - 1) {
|
||||
/* final category */
|
||||
if(col + len + 1 < width)
|
||||
curl_mprintf("%s.\n", categories[i].opt);
|
||||
else
|
||||
/* start a new line first */
|
||||
curl_mprintf("\n%s.\n", categories[i].opt);
|
||||
}
|
||||
else if(col + len + 2 < width) {
|
||||
curl_mprintf("%s, ", categories[i].opt);
|
||||
col += len + 2;
|
||||
}
|
||||
else {
|
||||
/* start a new line first */
|
||||
curl_mprintf("\n%s, ", categories[i].opt);
|
||||
col = len + 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_MANUAL
|
||||
|
||||
void inithelpscan(struct scan_ctx *ctx,
|
||||
const char *trigger,
|
||||
const char *arg,
|
||||
const char *endarg)
|
||||
{
|
||||
ctx->trigger = trigger;
|
||||
ctx->tlen = strlen(trigger);
|
||||
ctx->arg = arg;
|
||||
ctx->flen = strlen(arg);
|
||||
ctx->endarg = endarg;
|
||||
ctx->elen = strlen(endarg);
|
||||
DEBUGASSERT((ctx->elen < sizeof(ctx->rbuf)) ||
|
||||
(ctx->flen < sizeof(ctx->rbuf)));
|
||||
ctx->show = 0;
|
||||
ctx->olen = 0;
|
||||
memset(ctx->rbuf, 0, sizeof(ctx->rbuf));
|
||||
}
|
||||
|
||||
bool helpscan(const unsigned char *buf, size_t len, struct scan_ctx *ctx)
|
||||
{
|
||||
size_t i;
|
||||
for(i = 0; i < len; i++) {
|
||||
if(!ctx->show) {
|
||||
/* wait for the trigger */
|
||||
memmove(&ctx->rbuf[0], &ctx->rbuf[1], ctx->tlen - 1);
|
||||
ctx->rbuf[ctx->tlen - 1] = buf[i];
|
||||
if(!memcmp(ctx->rbuf, ctx->trigger, ctx->tlen))
|
||||
ctx->show++;
|
||||
continue;
|
||||
}
|
||||
/* past the trigger */
|
||||
if(ctx->show == 1) {
|
||||
memmove(&ctx->rbuf[0], &ctx->rbuf[1], ctx->flen - 1);
|
||||
ctx->rbuf[ctx->flen - 1] = buf[i];
|
||||
if(!memcmp(ctx->rbuf, ctx->arg, ctx->flen)) {
|
||||
/* match, now output until endarg */
|
||||
fputs(&ctx->arg[1], stdout);
|
||||
ctx->show++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
/* show until the end */
|
||||
memmove(&ctx->rbuf[0], &ctx->rbuf[1], ctx->elen - 1);
|
||||
ctx->rbuf[ctx->elen - 1] = buf[i];
|
||||
if(!memcmp(ctx->rbuf, ctx->endarg, ctx->elen))
|
||||
return FALSE;
|
||||
|
||||
if(buf[i] == '\n') {
|
||||
DEBUGASSERT(ctx->olen < sizeof(ctx->obuf));
|
||||
if(ctx->olen == sizeof(ctx->obuf))
|
||||
return FALSE; /* bail out */
|
||||
ctx->obuf[ctx->olen++] = 0;
|
||||
ctx->olen = 0;
|
||||
puts(ctx->obuf);
|
||||
}
|
||||
else {
|
||||
DEBUGASSERT(ctx->olen < sizeof(ctx->obuf));
|
||||
if(ctx->olen == sizeof(ctx->obuf))
|
||||
return FALSE; /* bail out */
|
||||
ctx->obuf[ctx->olen++] = buf[i];
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void tool_help(const char *category)
|
||||
{
|
||||
unsigned int cols = get_terminal_columns();
|
||||
/* If no category was provided */
|
||||
if(!category) {
|
||||
const char *category_note = "\nThis is not the full help; this "
|
||||
"menu is split into categories.\nUse \"--help category\" to get "
|
||||
"an overview of all categories, which are:";
|
||||
const char *category_note2 =
|
||||
"Use \"--help all\" to list all options"
|
||||
#ifdef USE_MANUAL
|
||||
"\nUse \"--help [option]\" to view documentation for a given option"
|
||||
#endif
|
||||
;
|
||||
puts("Usage: curl [options...] <url>");
|
||||
print_category(CURLHELP_IMPORTANT, cols);
|
||||
puts(category_note);
|
||||
get_categories_list(cols);
|
||||
puts(category_note2);
|
||||
}
|
||||
/* Lets print everything if "all" was provided */
|
||||
else if(curl_strequal(category, "all"))
|
||||
/* Print everything */
|
||||
print_category(CURLHELP_ALL, cols);
|
||||
/* Lets handle the string "category" differently to not print an errormsg */
|
||||
else if(curl_strequal(category, "category"))
|
||||
get_categories();
|
||||
else if(category[0] == '-') {
|
||||
#ifdef USE_MANUAL
|
||||
/* command line option help */
|
||||
const struct LongShort *a = NULL;
|
||||
if(category[1] == '-') {
|
||||
const char *lookup = &category[2];
|
||||
bool noflagged = FALSE;
|
||||
if(!strncmp(lookup, "no-", 3)) {
|
||||
lookup += 3;
|
||||
noflagged = TRUE;
|
||||
}
|
||||
a = findlongopt(lookup);
|
||||
if(a && noflagged && (ARGTYPE(a->desc) != ARG_BOOL))
|
||||
/* a --no- prefix for a non-boolean is not specifying a proper
|
||||
option */
|
||||
a = NULL;
|
||||
}
|
||||
else if(!category[2])
|
||||
a = findshortopt(category[1]);
|
||||
if(!a) {
|
||||
curl_mfprintf(tool_stderr, "Incorrect option name to show help for,"
|
||||
" see curl -h\n");
|
||||
}
|
||||
else {
|
||||
char cmdbuf[80];
|
||||
if(a->letter != ' ')
|
||||
curl_msnprintf(cmdbuf, sizeof(cmdbuf), "\n -%c, --", a->letter);
|
||||
else if(a->desc & ARG_NO)
|
||||
curl_msnprintf(cmdbuf, sizeof(cmdbuf), "\n --no-%s", a->lname);
|
||||
else
|
||||
curl_msnprintf(cmdbuf, sizeof(cmdbuf), "\n %s", category);
|
||||
#ifdef USE_MANUAL
|
||||
if(a->cmd == C_XATTR)
|
||||
/* this is the last option, which then ends when FILES starts */
|
||||
showhelp("\nALL OPTIONS\n", cmdbuf, "\nFILES");
|
||||
else
|
||||
showhelp("\nALL OPTIONS\n", cmdbuf, "\n -");
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
curl_mfprintf(tool_stderr, "Cannot comply. "
|
||||
"This curl was built without built-in manual\n");
|
||||
#endif
|
||||
}
|
||||
/* Otherwise print category and handle the case if the cat was not found */
|
||||
else if(get_category_content(category, cols)) {
|
||||
puts("Unknown category provided, here is a list of all categories:\n");
|
||||
get_categories();
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_debug(void)
|
||||
{
|
||||
const char *const *builtin;
|
||||
for(builtin = feature_names; *builtin; ++builtin)
|
||||
if(curl_strequal("debug", *builtin))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void tool_version_info(void)
|
||||
{
|
||||
const char *const *builtin;
|
||||
if(is_debug())
|
||||
curl_mfprintf(tool_stderr, "WARNING: this libcurl is Debug-enabled, "
|
||||
"do not use in production\n\n");
|
||||
|
||||
curl_mprintf(CURL_ID "%s\n", curl_version());
|
||||
#ifdef CURL_PATCHSTAMP
|
||||
curl_mprintf("Release-Date: %s, security patched: %s\n",
|
||||
LIBCURL_TIMESTAMP, CURL_PATCHSTAMP);
|
||||
#else
|
||||
curl_mprintf("Release-Date: %s\n", LIBCURL_TIMESTAMP);
|
||||
#endif
|
||||
if(built_in_protos[0]) {
|
||||
#ifndef CURL_DISABLE_IPFS
|
||||
const char *insert = NULL;
|
||||
/* we have ipfs and ipns support if libcurl has http support */
|
||||
for(builtin = built_in_protos; *builtin; ++builtin) {
|
||||
if(insert) {
|
||||
/* update insertion so ipfs will be printed in alphabetical order */
|
||||
if(strcmp(*builtin, "ipfs") < 0)
|
||||
insert = *builtin;
|
||||
else
|
||||
break;
|
||||
}
|
||||
else if(!strcmp(*builtin, "http")) {
|
||||
insert = *builtin;
|
||||
}
|
||||
}
|
||||
#endif /* !CURL_DISABLE_IPFS */
|
||||
curl_mprintf("Protocols:");
|
||||
for(builtin = built_in_protos; *builtin; ++builtin) {
|
||||
/* Special case: do not list rtmp?* protocols.
|
||||
They may only appear together with "rtmp" */
|
||||
if(!curl_strnequal(*builtin, "rtmp", 4) || !builtin[0][4])
|
||||
curl_mprintf(" %s", *builtin);
|
||||
#ifndef CURL_DISABLE_IPFS
|
||||
if(insert && insert == *builtin) {
|
||||
curl_mprintf(" ipfs ipns");
|
||||
insert = NULL;
|
||||
}
|
||||
#endif /* !CURL_DISABLE_IPFS */
|
||||
}
|
||||
puts(""); /* newline */
|
||||
}
|
||||
if(feature_names[0]) {
|
||||
const char **feat_ext;
|
||||
size_t feat_ext_count = feature_count;
|
||||
#ifdef CURL_CA_EMBED
|
||||
++feat_ext_count;
|
||||
#endif
|
||||
feat_ext = malloc(sizeof(*feature_names) * (feat_ext_count + 1));
|
||||
if(feat_ext) {
|
||||
memcpy((void *)feat_ext, feature_names,
|
||||
sizeof(*feature_names) * feature_count);
|
||||
feat_ext_count = feature_count;
|
||||
#ifdef CURL_CA_EMBED
|
||||
feat_ext[feat_ext_count++] = "CAcert";
|
||||
#endif
|
||||
feat_ext[feat_ext_count] = NULL;
|
||||
qsort((void *)feat_ext, feat_ext_count, sizeof(*feat_ext),
|
||||
struplocompare4sort);
|
||||
curl_mprintf("Features:");
|
||||
for(builtin = feat_ext; *builtin; ++builtin)
|
||||
curl_mprintf(" %s", *builtin);
|
||||
puts(""); /* newline */
|
||||
free((void *)feat_ext);
|
||||
}
|
||||
}
|
||||
if(strcmp(CURL_VERSION, curlinfo->version)) {
|
||||
curl_mprintf("WARNING: curl and libcurl versions do not match. "
|
||||
"Functionality may be affected.\n");
|
||||
}
|
||||
}
|
||||
|
||||
void tool_list_engines(void)
|
||||
{
|
||||
CURL *curl = curl_easy_init();
|
||||
struct curl_slist *engines = NULL;
|
||||
|
||||
/* Get the list of engines */
|
||||
curl_easy_getinfo(curl, CURLINFO_SSL_ENGINES, &engines);
|
||||
|
||||
puts("Build-time engines:");
|
||||
if(engines) {
|
||||
for(; engines; engines = engines->next)
|
||||
curl_mprintf(" %s\n", engines->data);
|
||||
}
|
||||
else {
|
||||
puts(" <none>");
|
||||
}
|
||||
|
||||
/* Cleanup the list of engines */
|
||||
curl_slist_free_all(engines);
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
Vendored
+93
@@ -0,0 +1,93 @@
|
||||
#ifndef HEADER_CURL_TOOL_HELP_H
|
||||
#define HEADER_CURL_TOOL_HELP_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
void tool_help(const char *category);
|
||||
void tool_list_engines(void);
|
||||
void tool_version_info(void);
|
||||
struct scan_ctx {
|
||||
const char *trigger;
|
||||
size_t tlen;
|
||||
const char *arg;
|
||||
size_t flen;
|
||||
const char *endarg;
|
||||
size_t elen;
|
||||
size_t olen;
|
||||
char rbuf[40];
|
||||
char obuf[160];
|
||||
unsigned char show; /* start as at 0.
|
||||
trigger match moves it to 1
|
||||
arg match moves it to 2
|
||||
endarg stops the search */
|
||||
};
|
||||
void inithelpscan(struct scan_ctx *ctx, const char *trigger,
|
||||
const char *arg, const char *endarg);
|
||||
bool helpscan(const unsigned char *buf, size_t len, struct scan_ctx *ctx);
|
||||
|
||||
struct helptxt {
|
||||
const char *opt;
|
||||
const char *desc;
|
||||
unsigned int categories;
|
||||
};
|
||||
|
||||
/*
|
||||
* The bitmask output is generated with the following command
|
||||
------------------------------------------------------------
|
||||
make -C docs/cmdline-opts listcats
|
||||
*/
|
||||
|
||||
#define CURLHELP_AUTH (1u << 0u)
|
||||
#define CURLHELP_CONNECTION (1u << 1u)
|
||||
#define CURLHELP_CURL (1u << 2u)
|
||||
#define CURLHELP_DEPRECATED (1u << 3u)
|
||||
#define CURLHELP_DNS (1u << 4u)
|
||||
#define CURLHELP_FILE (1u << 5u)
|
||||
#define CURLHELP_FTP (1u << 6u)
|
||||
#define CURLHELP_GLOBAL (1u << 7u)
|
||||
#define CURLHELP_HTTP (1u << 8u)
|
||||
#define CURLHELP_IMAP (1u << 9u)
|
||||
#define CURLHELP_IMPORTANT (1u << 10u)
|
||||
#define CURLHELP_LDAP (1u << 11u)
|
||||
#define CURLHELP_OUTPUT (1u << 12u)
|
||||
#define CURLHELP_POP3 (1u << 13u)
|
||||
#define CURLHELP_POST (1u << 14u)
|
||||
#define CURLHELP_PROXY (1u << 15u)
|
||||
#define CURLHELP_SCP (1u << 16u)
|
||||
#define CURLHELP_SFTP (1u << 17u)
|
||||
#define CURLHELP_SMTP (1u << 18u)
|
||||
#define CURLHELP_SSH (1u << 19u)
|
||||
#define CURLHELP_TELNET (1u << 20u)
|
||||
#define CURLHELP_TFTP (1u << 21u)
|
||||
#define CURLHELP_TIMEOUT (1u << 22u)
|
||||
#define CURLHELP_TLS (1u << 23u)
|
||||
#define CURLHELP_UPLOAD (1u << 24u)
|
||||
#define CURLHELP_VERBOSE (1u << 25u)
|
||||
|
||||
#define CURLHELP_ALL (0xfffffffu)
|
||||
|
||||
extern const struct helptxt helptext[];
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_HELP_H */
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#include "tool_cfgable.h"
|
||||
#include "tool_msgs.h"
|
||||
#include "tool_getparam.h"
|
||||
#include "tool_helpers.h"
|
||||
#include "memdebug.h" /* keep this as LAST include */
|
||||
|
||||
/*
|
||||
** Helper functions that are used from more than one source file.
|
||||
*/
|
||||
|
||||
const char *param2text(ParameterError error)
|
||||
{
|
||||
switch(error) {
|
||||
case PARAM_GOT_EXTRA_PARAMETER:
|
||||
return "had unsupported trailing garbage";
|
||||
case PARAM_OPTION_UNKNOWN:
|
||||
return "is unknown";
|
||||
case PARAM_REQUIRES_PARAMETER:
|
||||
return "requires parameter";
|
||||
case PARAM_BAD_USE:
|
||||
return "is badly used here";
|
||||
case PARAM_BAD_NUMERIC:
|
||||
return "expected a proper numerical parameter";
|
||||
case PARAM_NEGATIVE_NUMERIC:
|
||||
return "expected a positive numerical parameter";
|
||||
case PARAM_LIBCURL_DOESNT_SUPPORT:
|
||||
return "the installed libcurl version does not support this";
|
||||
case PARAM_LIBCURL_UNSUPPORTED_PROTOCOL:
|
||||
return "a specified protocol is unsupported by libcurl";
|
||||
case PARAM_NO_MEM:
|
||||
return "out of memory";
|
||||
case PARAM_NO_PREFIX:
|
||||
return "the given option cannot be reversed with a --no- prefix";
|
||||
case PARAM_NUMBER_TOO_LARGE:
|
||||
return "too large number";
|
||||
case PARAM_CONTDISP_RESUME_FROM:
|
||||
return "--continue-at and --remote-header-name cannot be combined";
|
||||
case PARAM_READ_ERROR:
|
||||
return "error encountered when reading a file";
|
||||
case PARAM_EXPAND_ERROR:
|
||||
return "variable expansion failure";
|
||||
case PARAM_BLANK_STRING:
|
||||
return "blank argument where content is expected";
|
||||
case PARAM_VAR_SYNTAX:
|
||||
return "syntax error in --variable argument";
|
||||
default:
|
||||
return "unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
int SetHTTPrequest(HttpReq req, HttpReq *store)
|
||||
{
|
||||
/* this mirrors the HttpReq enum in tool_sdecls.h */
|
||||
const char *reqname[]= {
|
||||
"", /* unspec */
|
||||
"GET (-G, --get)",
|
||||
"HEAD (-I, --head)",
|
||||
"multipart formpost (-F, --form)",
|
||||
"POST (-d, --data)",
|
||||
"PUT (-T, --upload-file)"
|
||||
};
|
||||
|
||||
if((*store == TOOL_HTTPREQ_UNSPEC) ||
|
||||
(*store == req)) {
|
||||
*store = req;
|
||||
return 0;
|
||||
}
|
||||
warnf("You can only select one HTTP request method! "
|
||||
"You asked for both %s and %s.",
|
||||
reqname[req], reqname[*store]);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void customrequest_helper(HttpReq req, char *method)
|
||||
{
|
||||
/* this mirrors the HttpReq enum in tool_sdecls.h */
|
||||
const char *dflt[]= {
|
||||
"GET",
|
||||
"GET",
|
||||
"HEAD",
|
||||
"POST",
|
||||
"POST",
|
||||
"PUT"
|
||||
};
|
||||
|
||||
if(!method)
|
||||
;
|
||||
else if(curl_strequal(method, dflt[req])) {
|
||||
notef("Unnecessary use of -X or --request, %s is already "
|
||||
"inferred.", dflt[req]);
|
||||
}
|
||||
else if(curl_strequal(method, "head")) {
|
||||
warnf("Setting custom HTTP method to HEAD with -X/--request may not work "
|
||||
"the way you want. Consider using -I/--head instead.");
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
#ifndef HEADER_CURL_TOOL_HELPERS_H
|
||||
#define HEADER_CURL_TOOL_HELPERS_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
const char *param2text(ParameterError error);
|
||||
int SetHTTPrequest(HttpReq req, HttpReq *store);
|
||||
void customrequest_helper(HttpReq req, char *method);
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_HELPERS_H */
|
||||
+12449
File diff suppressed because it is too large
Load Diff
+33
@@ -0,0 +1,33 @@
|
||||
#ifndef HEADER_CURL_TOOL_HUGEHELP_H
|
||||
#define HEADER_CURL_TOOL_HUGEHELP_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#ifdef USE_MANUAL
|
||||
void showhelp(const char *trigger, const char *arg, const char *endarg);
|
||||
void hugehelp(void);
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_HUGEHELP_H */
|
||||
Vendored
+251
@@ -0,0 +1,251 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#ifndef CURL_DISABLE_IPFS
|
||||
|
||||
#include "tool_cfgable.h"
|
||||
#include "tool_msgs.h"
|
||||
#include "tool_ipfs.h"
|
||||
#include "memdebug.h" /* keep this as LAST include */
|
||||
|
||||
/* input string ends in slash? */
|
||||
static bool has_trailing_slash(const char *input)
|
||||
{
|
||||
size_t len = strlen(input);
|
||||
return (len && input[len - 1] == '/');
|
||||
}
|
||||
|
||||
static char *ipfs_gateway(void)
|
||||
{
|
||||
char *ipfs_path_c = NULL;
|
||||
char *gateway_composed_c = NULL;
|
||||
FILE *gfile = NULL;
|
||||
char *gateway_env = getenv("IPFS_GATEWAY");
|
||||
|
||||
if(gateway_env)
|
||||
return strdup(gateway_env);
|
||||
|
||||
/* Try to find the gateway in the IPFS data folder. */
|
||||
ipfs_path_c = curl_getenv("IPFS_PATH");
|
||||
|
||||
if(!ipfs_path_c) {
|
||||
char *home = getenv("HOME");
|
||||
/* fallback to "~/.ipfs", as that is the default location. */
|
||||
if(home && *home)
|
||||
ipfs_path_c = curl_maprintf("%s/.ipfs/", home);
|
||||
if(!ipfs_path_c)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
gateway_composed_c =
|
||||
curl_maprintf("%s%sgateway", ipfs_path_c,
|
||||
has_trailing_slash(ipfs_path_c) ? "" : "/");
|
||||
|
||||
if(!gateway_composed_c)
|
||||
goto fail;
|
||||
|
||||
gfile = curlx_fopen(gateway_composed_c, FOPEN_READTEXT);
|
||||
curl_free(gateway_composed_c);
|
||||
|
||||
if(gfile) {
|
||||
int c;
|
||||
struct dynbuf dyn;
|
||||
char *gateway = NULL;
|
||||
curlx_dyn_init(&dyn, MAX_GATEWAY_URL_LEN);
|
||||
|
||||
/* get the first line of the gateway file, ignore the rest */
|
||||
while((c = getc(gfile)) != EOF && c != '\n' && c != '\r') {
|
||||
char c_char = (char)c;
|
||||
if(curlx_dyn_addn(&dyn, &c_char, 1))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if(curlx_dyn_len(&dyn))
|
||||
gateway = curlx_dyn_ptr(&dyn);
|
||||
|
||||
curl_free(ipfs_path_c);
|
||||
curlx_fclose(gfile);
|
||||
|
||||
return gateway;
|
||||
}
|
||||
fail:
|
||||
if(gfile)
|
||||
curlx_fclose(gfile);
|
||||
curl_free(ipfs_path_c);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Rewrite ipfs://<cid> and ipns://<cid> to an HTTP(S)
|
||||
* URL that can be handled by an IPFS gateway.
|
||||
*/
|
||||
CURLcode ipfs_url_rewrite(CURLU *uh, const char *protocol, char **url,
|
||||
struct OperationConfig *config)
|
||||
{
|
||||
CURLcode result = CURLE_URL_MALFORMAT;
|
||||
CURLUcode getResult;
|
||||
char *gateway = NULL;
|
||||
char *gwhost = NULL;
|
||||
char *gwpath = NULL;
|
||||
char *gwquery = NULL;
|
||||
char *gwscheme = NULL;
|
||||
char *gwport = NULL;
|
||||
char *inputpath = NULL;
|
||||
char *cid = NULL;
|
||||
char *pathbuffer = NULL;
|
||||
char *cloneurl;
|
||||
CURLU *gatewayurl = curl_url();
|
||||
|
||||
if(!gatewayurl) {
|
||||
result = CURLE_FAILED_INIT;
|
||||
goto clean;
|
||||
}
|
||||
|
||||
getResult = curl_url_get(uh, CURLUPART_HOST, &cid, CURLU_URLDECODE);
|
||||
if(getResult || !cid)
|
||||
goto clean;
|
||||
|
||||
/* We might have a --ipfs-gateway argument. Check it first and use it. Error
|
||||
* if we do have something but if it is an invalid url.
|
||||
*/
|
||||
if(config->ipfs_gateway) {
|
||||
if(!curl_url_set(gatewayurl, CURLUPART_URL, config->ipfs_gateway,
|
||||
CURLU_GUESS_SCHEME)) {
|
||||
gateway = strdup(config->ipfs_gateway);
|
||||
if(!gateway) {
|
||||
result = CURLE_URL_MALFORMAT;
|
||||
goto clean;
|
||||
}
|
||||
}
|
||||
else {
|
||||
result = CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
goto clean;
|
||||
}
|
||||
}
|
||||
else {
|
||||
gateway = ipfs_gateway();
|
||||
if(!gateway) {
|
||||
result = CURLE_FILE_COULDNT_READ_FILE;
|
||||
goto clean;
|
||||
}
|
||||
|
||||
if(curl_url_set(gatewayurl, CURLUPART_URL, gateway, 0)) {
|
||||
result = CURLE_URL_MALFORMAT;
|
||||
goto clean;
|
||||
}
|
||||
}
|
||||
|
||||
/* check for unsupported gateway parts */
|
||||
if(curl_url_get(gatewayurl, CURLUPART_QUERY, &gwquery, 0)
|
||||
!= CURLUE_NO_QUERY) {
|
||||
result = CURLE_URL_MALFORMAT;
|
||||
goto clean;
|
||||
}
|
||||
|
||||
/* get gateway parts */
|
||||
if(curl_url_get(gatewayurl, CURLUPART_HOST,
|
||||
&gwhost, CURLU_URLDECODE)) {
|
||||
goto clean;
|
||||
}
|
||||
|
||||
if(curl_url_get(gatewayurl, CURLUPART_SCHEME,
|
||||
&gwscheme, CURLU_URLDECODE)) {
|
||||
goto clean;
|
||||
}
|
||||
|
||||
curl_url_get(gatewayurl, CURLUPART_PORT, &gwport, CURLU_URLDECODE);
|
||||
|
||||
if(curl_url_get(gatewayurl, CURLUPART_PATH, &gwpath, CURLU_URLDECODE))
|
||||
goto clean;
|
||||
|
||||
/* get the path from user input */
|
||||
curl_url_get(uh, CURLUPART_PATH, &inputpath, CURLU_URLDECODE);
|
||||
/* inputpath might be NULL or a valid pointer now */
|
||||
|
||||
/* set gateway parts in input url */
|
||||
if(curl_url_set(uh, CURLUPART_SCHEME, gwscheme, CURLU_URLENCODE) ||
|
||||
curl_url_set(uh, CURLUPART_HOST, gwhost, CURLU_URLENCODE) ||
|
||||
curl_url_set(uh, CURLUPART_PORT, gwport, CURLU_URLENCODE))
|
||||
goto clean;
|
||||
|
||||
/* if the input path is just a slash, clear it */
|
||||
if(inputpath && (inputpath[0] == '/') && !inputpath[1])
|
||||
*inputpath = '\0';
|
||||
|
||||
pathbuffer = curl_maprintf("%s%s%s/%s%s", gwpath,
|
||||
has_trailing_slash(gwpath) ? "" : "/",
|
||||
protocol, cid,
|
||||
inputpath ? inputpath : "");
|
||||
if(!pathbuffer) {
|
||||
goto clean;
|
||||
}
|
||||
|
||||
if(curl_url_set(uh, CURLUPART_PATH, pathbuffer, CURLU_URLENCODE)) {
|
||||
goto clean;
|
||||
}
|
||||
|
||||
/* Free whatever it has now, rewriting is next */
|
||||
tool_safefree(*url);
|
||||
|
||||
if(curl_url_get(uh, CURLUPART_URL, &cloneurl, CURLU_URLENCODE)) {
|
||||
goto clean;
|
||||
}
|
||||
/* we need to strdup the URL so that we can call free() on it later */
|
||||
*url = strdup(cloneurl);
|
||||
curl_free(cloneurl);
|
||||
if(!*url)
|
||||
goto clean;
|
||||
|
||||
result = CURLE_OK;
|
||||
|
||||
clean:
|
||||
free(gateway);
|
||||
curl_free(gwhost);
|
||||
curl_free(gwpath);
|
||||
curl_free(gwquery);
|
||||
curl_free(inputpath);
|
||||
curl_free(gwscheme);
|
||||
curl_free(gwport);
|
||||
curl_free(cid);
|
||||
curl_free(pathbuffer);
|
||||
curl_url_cleanup(gatewayurl);
|
||||
{
|
||||
switch(result) {
|
||||
case CURLE_URL_MALFORMAT:
|
||||
helpf("malformed target URL");
|
||||
break;
|
||||
case CURLE_FILE_COULDNT_READ_FILE:
|
||||
helpf("IPFS automatic gateway detection failed");
|
||||
break;
|
||||
case CURLE_BAD_FUNCTION_ARGUMENT:
|
||||
helpf("--ipfs-gateway was given a malformed URL");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endif /* !CURL_DISABLE_IPFS */
|
||||
Vendored
+35
@@ -0,0 +1,35 @@
|
||||
#ifndef HEADER_CURL_TOOL_IPFS_H
|
||||
#define HEADER_CURL_TOOL_IPFS_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#ifndef CURL_DISABLE_IPFS
|
||||
#define MAX_GATEWAY_URL_LEN 10000
|
||||
|
||||
CURLcode ipfs_url_rewrite(CURLU *uh, const char *protocol, char **url,
|
||||
struct OperationConfig *config);
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_IPFS_H */
|
||||
#endif /* !CURL_DISABLE_IPFS */
|
||||
+212
@@ -0,0 +1,212 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#include "tool_libinfo.h"
|
||||
#include "memdebug.h" /* keep this as LAST include */
|
||||
|
||||
/* global variable definitions, for libcurl runtime info */
|
||||
|
||||
static const char *no_protos = NULL;
|
||||
|
||||
curl_version_info_data *curlinfo = NULL;
|
||||
const char * const *built_in_protos = &no_protos;
|
||||
|
||||
size_t proto_count = 0;
|
||||
|
||||
const char *proto_file = NULL;
|
||||
const char *proto_ftp = NULL;
|
||||
const char *proto_ftps = NULL;
|
||||
const char *proto_http = NULL;
|
||||
const char *proto_https = NULL;
|
||||
const char *proto_rtsp = NULL;
|
||||
const char *proto_scp = NULL;
|
||||
const char *proto_sftp = NULL;
|
||||
const char *proto_tftp = NULL;
|
||||
#ifndef CURL_DISABLE_IPFS
|
||||
const char *proto_ipfs = "ipfs";
|
||||
const char *proto_ipns = "ipns";
|
||||
#endif /* !CURL_DISABLE_IPFS */
|
||||
|
||||
static struct proto_name_tokenp {
|
||||
const char *proto_name;
|
||||
const char **proto_tokenp;
|
||||
} const possibly_built_in[] = {
|
||||
{ "file", &proto_file },
|
||||
{ "ftp", &proto_ftp },
|
||||
{ "ftps", &proto_ftps },
|
||||
{ "http", &proto_http },
|
||||
{ "https", &proto_https },
|
||||
{ "rtsp", &proto_rtsp },
|
||||
{ "scp", &proto_scp },
|
||||
{ "sftp", &proto_sftp },
|
||||
{ "tftp", &proto_tftp },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
bool feature_altsvc = FALSE;
|
||||
bool feature_brotli = FALSE;
|
||||
bool feature_hsts = FALSE;
|
||||
bool feature_http2 = FALSE;
|
||||
bool feature_http3 = FALSE;
|
||||
bool feature_httpsproxy = FALSE;
|
||||
bool feature_libz = FALSE;
|
||||
bool feature_libssh2 = FALSE;
|
||||
bool feature_ntlm = FALSE;
|
||||
bool feature_ntlm_wb = FALSE;
|
||||
bool feature_spnego = FALSE;
|
||||
bool feature_ssl = FALSE;
|
||||
bool feature_tls_srp = FALSE;
|
||||
bool feature_zstd = FALSE;
|
||||
bool feature_ech = FALSE;
|
||||
bool feature_ssls_export = FALSE;
|
||||
|
||||
static struct feature_name_presentp {
|
||||
const char *feature_name;
|
||||
bool *feature_presentp;
|
||||
int feature_bitmask;
|
||||
} const maybe_feature[] = {
|
||||
/* Keep alphabetically sorted. */
|
||||
{"alt-svc", &feature_altsvc, CURL_VERSION_ALTSVC},
|
||||
{"AsynchDNS", NULL, CURL_VERSION_ASYNCHDNS},
|
||||
{"brotli", &feature_brotli, CURL_VERSION_BROTLI},
|
||||
{"CharConv", NULL, CURL_VERSION_CONV},
|
||||
{"Debug", NULL, CURL_VERSION_DEBUG},
|
||||
{"ECH", &feature_ech, 0},
|
||||
{"gsasl", NULL, CURL_VERSION_GSASL},
|
||||
{"GSS-API", NULL, CURL_VERSION_GSSAPI},
|
||||
{"HSTS", &feature_hsts, CURL_VERSION_HSTS},
|
||||
{"HTTP2", &feature_http2, CURL_VERSION_HTTP2},
|
||||
{"HTTP3", &feature_http3, CURL_VERSION_HTTP3},
|
||||
{"HTTPS-proxy", &feature_httpsproxy, CURL_VERSION_HTTPS_PROXY},
|
||||
{"IDN", NULL, CURL_VERSION_IDN},
|
||||
{"IPv6", NULL, CURL_VERSION_IPV6},
|
||||
{"Kerberos", NULL, CURL_VERSION_KERBEROS5},
|
||||
{"Largefile", NULL, CURL_VERSION_LARGEFILE},
|
||||
{"libz", &feature_libz, CURL_VERSION_LIBZ},
|
||||
{"MultiSSL", NULL, CURL_VERSION_MULTI_SSL},
|
||||
{"NTLM", &feature_ntlm, CURL_VERSION_NTLM},
|
||||
{"NTLM_WB", &feature_ntlm_wb, CURL_VERSION_NTLM_WB},
|
||||
{"PSL", NULL, CURL_VERSION_PSL},
|
||||
{"SPNEGO", &feature_spnego, CURL_VERSION_SPNEGO},
|
||||
{"SSL", &feature_ssl, CURL_VERSION_SSL},
|
||||
{"SSPI", NULL, CURL_VERSION_SSPI},
|
||||
{"SSLS-EXPORT", &feature_ssls_export, 0},
|
||||
{"threadsafe", NULL, CURL_VERSION_THREADSAFE},
|
||||
{"TLS-SRP", &feature_tls_srp, CURL_VERSION_TLSAUTH_SRP},
|
||||
{"TrackMemory", NULL, CURL_VERSION_CURLDEBUG},
|
||||
{"Unicode", NULL, CURL_VERSION_UNICODE},
|
||||
{"UnixSockets", NULL, CURL_VERSION_UNIX_SOCKETS},
|
||||
{"zstd", &feature_zstd, CURL_VERSION_ZSTD},
|
||||
{NULL, NULL, 0}
|
||||
};
|
||||
|
||||
static const char *fnames[CURL_ARRAYSIZE(maybe_feature)];
|
||||
const char * const *feature_names = fnames;
|
||||
size_t feature_count;
|
||||
|
||||
/*
|
||||
* libcurl_info_init: retrieves runtime information about libcurl,
|
||||
* setting a global pointer 'curlinfo' to libcurl's runtime info
|
||||
* struct, count protocols and flag those we are interested in.
|
||||
* Global pointer feature_names is set to the feature names array. If
|
||||
* the latter is not returned by curl_version_info(), it is built from
|
||||
* the returned features bit mask.
|
||||
*/
|
||||
|
||||
CURLcode get_libcurl_info(void)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
const char *const *builtin;
|
||||
|
||||
/* Pointer to libcurl's runtime version information */
|
||||
curlinfo = curl_version_info(CURLVERSION_NOW);
|
||||
if(!curlinfo)
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
if(curlinfo->protocols) {
|
||||
const struct proto_name_tokenp *p;
|
||||
|
||||
built_in_protos = curlinfo->protocols;
|
||||
|
||||
for(builtin = built_in_protos; !result && *builtin; builtin++) {
|
||||
/* Identify protocols we are interested in. */
|
||||
for(p = possibly_built_in; p->proto_name; p++)
|
||||
if(curl_strequal(p->proto_name, *builtin)) {
|
||||
*p->proto_tokenp = *builtin;
|
||||
break;
|
||||
}
|
||||
}
|
||||
proto_count = builtin - built_in_protos;
|
||||
}
|
||||
|
||||
if(curlinfo->age >= CURLVERSION_ELEVENTH && curlinfo->feature_names)
|
||||
feature_names = curlinfo->feature_names;
|
||||
else {
|
||||
const struct feature_name_presentp *p;
|
||||
const char **cpp = fnames;
|
||||
|
||||
for(p = maybe_feature; p->feature_name; p++)
|
||||
if(curlinfo->features & p->feature_bitmask)
|
||||
*cpp++ = p->feature_name;
|
||||
*cpp = NULL;
|
||||
}
|
||||
|
||||
/* Identify features we are interested in. */
|
||||
for(builtin = feature_names; *builtin; builtin++) {
|
||||
const struct feature_name_presentp *p;
|
||||
|
||||
for(p = maybe_feature; p->feature_name; p++)
|
||||
if(curl_strequal(p->feature_name, *builtin)) {
|
||||
if(p->feature_presentp)
|
||||
*p->feature_presentp = TRUE;
|
||||
break;
|
||||
}
|
||||
++feature_count;
|
||||
}
|
||||
|
||||
feature_libssh2 = curlinfo->libssh_version &&
|
||||
!strncmp("libssh2", curlinfo->libssh_version, 7);
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/* Tokenize a protocol name.
|
||||
* Return the address of the protocol name listed by the library, or NULL if
|
||||
* not found.
|
||||
* Although this may seem useless, this always returns the same address for
|
||||
* a given protocol and thus allows comparing pointers rather than strings.
|
||||
* In addition, the returned pointer is not deallocated until the program ends.
|
||||
*/
|
||||
|
||||
const char *proto_token(const char *proto)
|
||||
{
|
||||
const char * const *builtin;
|
||||
|
||||
if(!proto)
|
||||
return NULL;
|
||||
for(builtin = built_in_protos; *builtin; builtin++)
|
||||
if(curl_strequal(*builtin, proto))
|
||||
break;
|
||||
return *builtin;
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
#ifndef HEADER_CURL_TOOL_LIBINFO_H
|
||||
#define HEADER_CURL_TOOL_LIBINFO_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
/* global variable declarations, for libcurl runtime info */
|
||||
|
||||
|
||||
extern curl_version_info_data *curlinfo;
|
||||
|
||||
extern const char * const *built_in_protos;
|
||||
extern size_t proto_count;
|
||||
|
||||
extern const char * const *feature_names;
|
||||
extern size_t feature_count;
|
||||
|
||||
extern const char *proto_file;
|
||||
extern const char *proto_ftp;
|
||||
extern const char *proto_ftps;
|
||||
extern const char *proto_http;
|
||||
extern const char *proto_https;
|
||||
extern const char *proto_rtsp;
|
||||
extern const char *proto_scp;
|
||||
extern const char *proto_sftp;
|
||||
extern const char *proto_tftp;
|
||||
extern const char *proto_ipfs;
|
||||
extern const char *proto_ipns;
|
||||
|
||||
extern bool feature_altsvc;
|
||||
extern bool feature_brotli;
|
||||
extern bool feature_hsts;
|
||||
extern bool feature_http2;
|
||||
extern bool feature_http3;
|
||||
extern bool feature_httpsproxy;
|
||||
extern bool feature_libz;
|
||||
extern bool feature_libssh2;
|
||||
extern bool feature_ntlm;
|
||||
extern bool feature_ntlm_wb;
|
||||
extern bool feature_spnego;
|
||||
extern bool feature_ssl;
|
||||
extern bool feature_tls_srp;
|
||||
extern bool feature_zstd;
|
||||
extern bool feature_ech;
|
||||
extern bool feature_ssls_export;
|
||||
|
||||
CURLcode get_libcurl_info(void);
|
||||
const char *proto_token(const char *proto);
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_LIBINFO_H */
|
||||
+863
@@ -0,0 +1,863 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
#include "tool_help.h"
|
||||
|
||||
/*
|
||||
* DO NOT edit tool_listhelp.c manually.
|
||||
* This source file is generated with the following command in an autotools
|
||||
* build:
|
||||
*
|
||||
* "make listhelp"
|
||||
*/
|
||||
|
||||
const struct helptxt helptext[] = {
|
||||
{" --abstract-unix-socket <path>",
|
||||
"Connect via abstract Unix domain socket",
|
||||
CURLHELP_CONNECTION},
|
||||
{" --alt-svc <filename>",
|
||||
"Enable alt-svc with this cache file",
|
||||
CURLHELP_HTTP},
|
||||
{" --anyauth",
|
||||
"Pick any authentication method",
|
||||
CURLHELP_HTTP | CURLHELP_PROXY | CURLHELP_AUTH},
|
||||
{"-a, --append",
|
||||
"Append to target file when uploading",
|
||||
CURLHELP_FTP | CURLHELP_SFTP},
|
||||
{" --aws-sigv4 <provider1[:prvdr2[:reg[:srv]]]>",
|
||||
"AWS V4 signature auth",
|
||||
CURLHELP_AUTH | CURLHELP_HTTP},
|
||||
{" --basic",
|
||||
"HTTP Basic Authentication",
|
||||
CURLHELP_AUTH},
|
||||
{" --ca-native",
|
||||
"Load CA certs from the OS",
|
||||
CURLHELP_TLS},
|
||||
{" --cacert <file>",
|
||||
"CA certificate to verify peer against",
|
||||
CURLHELP_TLS},
|
||||
{" --capath <dir>",
|
||||
"CA directory to verify peer against",
|
||||
CURLHELP_TLS},
|
||||
{"-E, --cert <certificate[:password]>",
|
||||
"Client certificate file and password",
|
||||
CURLHELP_TLS},
|
||||
{" --cert-status",
|
||||
"Verify server cert status OCSP-staple",
|
||||
CURLHELP_TLS},
|
||||
{" --cert-type <type>",
|
||||
"Certificate type (DER/PEM/ENG/PROV/P12)",
|
||||
CURLHELP_TLS},
|
||||
{" --ciphers <list>",
|
||||
"TLS 1.2 (1.1, 1.0) ciphers to use",
|
||||
CURLHELP_TLS},
|
||||
{" --compressed",
|
||||
"Request compressed response",
|
||||
CURLHELP_HTTP},
|
||||
{" --compressed-ssh",
|
||||
"Enable SSH compression",
|
||||
CURLHELP_SCP | CURLHELP_SSH},
|
||||
{"-K, --config <file>",
|
||||
"Read config from a file",
|
||||
CURLHELP_CURL},
|
||||
{" --connect-timeout <seconds>",
|
||||
"Maximum time allowed to connect",
|
||||
CURLHELP_CONNECTION | CURLHELP_TIMEOUT},
|
||||
{" --connect-to <HOST1:PORT1:HOST2:PORT2>",
|
||||
"Connect to host2 instead of host1",
|
||||
CURLHELP_CONNECTION | CURLHELP_DNS},
|
||||
{"-C, --continue-at <offset>",
|
||||
"Resumed transfer offset",
|
||||
CURLHELP_CONNECTION},
|
||||
{"-b, --cookie <data|filename>",
|
||||
"Send cookies from string/load from file",
|
||||
CURLHELP_HTTP},
|
||||
{"-c, --cookie-jar <filename>",
|
||||
"Save cookies to <filename> after operation",
|
||||
CURLHELP_HTTP},
|
||||
{" --create-dirs",
|
||||
"Create necessary local directory hierarchy",
|
||||
CURLHELP_OUTPUT},
|
||||
{" --create-file-mode <mode>",
|
||||
"File mode for created files",
|
||||
CURLHELP_SFTP | CURLHELP_SCP | CURLHELP_FILE | CURLHELP_UPLOAD},
|
||||
{" --crlf",
|
||||
"Convert LF to CRLF in upload",
|
||||
CURLHELP_FTP | CURLHELP_SMTP},
|
||||
{" --crlfile <file>",
|
||||
"Certificate Revocation list",
|
||||
CURLHELP_TLS},
|
||||
{" --curves <list>",
|
||||
"(EC) TLS key exchange algorithms to request",
|
||||
CURLHELP_TLS},
|
||||
{"-d, --data <data>",
|
||||
"HTTP POST data",
|
||||
CURLHELP_IMPORTANT | CURLHELP_HTTP | CURLHELP_POST | CURLHELP_UPLOAD},
|
||||
{" --data-ascii <data>",
|
||||
"HTTP POST ASCII data",
|
||||
CURLHELP_HTTP | CURLHELP_POST | CURLHELP_UPLOAD},
|
||||
{" --data-binary <data>",
|
||||
"HTTP POST binary data",
|
||||
CURLHELP_HTTP | CURLHELP_POST | CURLHELP_UPLOAD},
|
||||
{" --data-raw <data>",
|
||||
"HTTP POST data, '@' allowed",
|
||||
CURLHELP_HTTP | CURLHELP_POST | CURLHELP_UPLOAD},
|
||||
{" --data-urlencode <data>",
|
||||
"HTTP POST data URL encoded",
|
||||
CURLHELP_HTTP | CURLHELP_POST | CURLHELP_UPLOAD},
|
||||
{" --delegation <LEVEL>",
|
||||
"GSS-API delegation permission",
|
||||
CURLHELP_AUTH},
|
||||
{" --digest",
|
||||
"HTTP Digest Authentication",
|
||||
CURLHELP_PROXY | CURLHELP_AUTH | CURLHELP_HTTP},
|
||||
{"-q, --disable",
|
||||
"Disable .curlrc",
|
||||
CURLHELP_CURL},
|
||||
{" --disable-eprt",
|
||||
"Inhibit using EPRT or LPRT",
|
||||
CURLHELP_FTP},
|
||||
{" --disable-epsv",
|
||||
"Inhibit using EPSV",
|
||||
CURLHELP_FTP},
|
||||
{" --disallow-username-in-url",
|
||||
"Disallow username in URL",
|
||||
CURLHELP_CURL},
|
||||
{" --dns-interface <interface>",
|
||||
"Interface to use for DNS requests",
|
||||
CURLHELP_DNS},
|
||||
{" --dns-ipv4-addr <address>",
|
||||
"IPv4 address to use for DNS requests",
|
||||
CURLHELP_DNS},
|
||||
{" --dns-ipv6-addr <address>",
|
||||
"IPv6 address to use for DNS requests",
|
||||
CURLHELP_DNS},
|
||||
{" --dns-servers <addresses>",
|
||||
"DNS server addrs to use",
|
||||
CURLHELP_DNS},
|
||||
{" --doh-cert-status",
|
||||
"Verify DoH server cert status OCSP-staple",
|
||||
CURLHELP_DNS | CURLHELP_TLS},
|
||||
{" --doh-insecure",
|
||||
"Allow insecure DoH server connections",
|
||||
CURLHELP_DNS | CURLHELP_TLS},
|
||||
{" --doh-url <URL>",
|
||||
"Resolve hostnames over DoH",
|
||||
CURLHELP_DNS},
|
||||
{" --dump-ca-embed",
|
||||
"Write the embedded CA bundle to standard output",
|
||||
CURLHELP_HTTP | CURLHELP_PROXY | CURLHELP_TLS},
|
||||
{"-D, --dump-header <filename>",
|
||||
"Write the received headers to <filename>",
|
||||
CURLHELP_HTTP | CURLHELP_FTP},
|
||||
{" --ech <config>",
|
||||
"Configure ECH",
|
||||
CURLHELP_TLS},
|
||||
{" --egd-file <file>",
|
||||
"EGD socket path for random data",
|
||||
CURLHELP_DEPRECATED},
|
||||
{" --engine <name>",
|
||||
"Crypto engine to use",
|
||||
CURLHELP_TLS},
|
||||
{" --etag-compare <file>",
|
||||
"Load ETag from file",
|
||||
CURLHELP_HTTP},
|
||||
{" --etag-save <file>",
|
||||
"Parse incoming ETag and save to a file",
|
||||
CURLHELP_HTTP},
|
||||
{" --expect100-timeout <seconds>",
|
||||
"How long to wait for 100-continue",
|
||||
CURLHELP_HTTP | CURLHELP_TIMEOUT},
|
||||
{"-f, --fail",
|
||||
"Fail fast with no output on HTTP errors",
|
||||
CURLHELP_IMPORTANT | CURLHELP_HTTP},
|
||||
{" --fail-early",
|
||||
"Fail on first transfer error",
|
||||
CURLHELP_CURL | CURLHELP_GLOBAL},
|
||||
{" --fail-with-body",
|
||||
"Fail on HTTP errors but save the body",
|
||||
CURLHELP_HTTP | CURLHELP_OUTPUT},
|
||||
{" --false-start",
|
||||
"Enable TLS False Start",
|
||||
CURLHELP_DEPRECATED},
|
||||
{" --follow",
|
||||
"Follow redirects per spec",
|
||||
CURLHELP_HTTP},
|
||||
{"-F, --form <name=content>",
|
||||
"Specify multipart MIME data",
|
||||
CURLHELP_HTTP | CURLHELP_UPLOAD | CURLHELP_POST | CURLHELP_IMAP |
|
||||
CURLHELP_SMTP},
|
||||
{" --form-escape",
|
||||
"Escape form fields using backslash",
|
||||
CURLHELP_HTTP | CURLHELP_UPLOAD | CURLHELP_POST},
|
||||
{" --form-string <name=string>",
|
||||
"Specify multipart MIME data",
|
||||
CURLHELP_HTTP | CURLHELP_UPLOAD | CURLHELP_POST | CURLHELP_SMTP |
|
||||
CURLHELP_IMAP},
|
||||
{" --ftp-account <data>",
|
||||
"Account data string",
|
||||
CURLHELP_FTP | CURLHELP_AUTH},
|
||||
{" --ftp-alternative-to-user <command>",
|
||||
"String to replace USER [name]",
|
||||
CURLHELP_FTP},
|
||||
{" --ftp-create-dirs",
|
||||
"Create the remote dirs if not present",
|
||||
CURLHELP_FTP | CURLHELP_SFTP},
|
||||
{" --ftp-method <method>",
|
||||
"Control CWD usage",
|
||||
CURLHELP_FTP},
|
||||
{" --ftp-pasv",
|
||||
"Send PASV/EPSV instead of PORT",
|
||||
CURLHELP_FTP},
|
||||
{"-P, --ftp-port <address>",
|
||||
"Send PORT instead of PASV",
|
||||
CURLHELP_FTP},
|
||||
{" --ftp-pret",
|
||||
"Send PRET before PASV",
|
||||
CURLHELP_FTP},
|
||||
{" --ftp-skip-pasv-ip",
|
||||
"Skip the IP address for PASV",
|
||||
CURLHELP_FTP},
|
||||
{" --ftp-ssl-ccc",
|
||||
"Send CCC after authenticating",
|
||||
CURLHELP_FTP | CURLHELP_TLS},
|
||||
{" --ftp-ssl-ccc-mode <active/passive>",
|
||||
"Set CCC mode",
|
||||
CURLHELP_FTP | CURLHELP_TLS},
|
||||
{" --ftp-ssl-control",
|
||||
"Require TLS for login, clear for transfer",
|
||||
CURLHELP_FTP | CURLHELP_TLS},
|
||||
{"-G, --get",
|
||||
"Put the post data in the URL and use GET",
|
||||
CURLHELP_HTTP},
|
||||
{"-g, --globoff",
|
||||
"Disable URL globbing with {} and []",
|
||||
CURLHELP_CURL},
|
||||
{" --happy-eyeballs-timeout-ms <ms>",
|
||||
"Time for IPv6 before IPv4",
|
||||
CURLHELP_CONNECTION | CURLHELP_TIMEOUT},
|
||||
{" --haproxy-clientip <ip>",
|
||||
"Set address in HAProxy PROXY",
|
||||
CURLHELP_HTTP | CURLHELP_PROXY},
|
||||
{" --haproxy-protocol",
|
||||
"Send HAProxy PROXY protocol v1 header",
|
||||
CURLHELP_HTTP | CURLHELP_PROXY},
|
||||
{"-I, --head",
|
||||
"Show document info only",
|
||||
CURLHELP_HTTP | CURLHELP_FTP | CURLHELP_FILE},
|
||||
{"-H, --header <header/@file>",
|
||||
"Pass custom header(s) to server",
|
||||
CURLHELP_HTTP | CURLHELP_IMAP | CURLHELP_SMTP},
|
||||
{"-h, --help <subject>",
|
||||
"Get help for commands",
|
||||
CURLHELP_IMPORTANT | CURLHELP_CURL},
|
||||
{" --hostpubmd5 <md5>",
|
||||
"Acceptable MD5 hash of host public key",
|
||||
CURLHELP_SFTP | CURLHELP_SCP | CURLHELP_SSH},
|
||||
{" --hostpubsha256 <sha256>",
|
||||
"Acceptable SHA256 hash of host public key",
|
||||
CURLHELP_SFTP | CURLHELP_SCP | CURLHELP_SSH},
|
||||
{" --hsts <filename>",
|
||||
"Enable HSTS with this cache file",
|
||||
CURLHELP_HTTP},
|
||||
{" --http0.9",
|
||||
"Allow HTTP/0.9 responses",
|
||||
CURLHELP_HTTP},
|
||||
{"-0, --http1.0",
|
||||
"Use HTTP/1.0",
|
||||
CURLHELP_HTTP},
|
||||
{" --http1.1",
|
||||
"Use HTTP/1.1",
|
||||
CURLHELP_HTTP},
|
||||
{" --http2",
|
||||
"Use HTTP/2",
|
||||
CURLHELP_HTTP},
|
||||
{" --http2-prior-knowledge",
|
||||
"Use HTTP/2 without HTTP/1.1 Upgrade",
|
||||
CURLHELP_HTTP},
|
||||
{" --http3",
|
||||
"Use HTTP/3",
|
||||
CURLHELP_HTTP},
|
||||
{" --http3-only",
|
||||
"Use HTTP/3 only",
|
||||
CURLHELP_HTTP},
|
||||
{" --ignore-content-length",
|
||||
"Ignore the size of the remote resource",
|
||||
CURLHELP_HTTP | CURLHELP_FTP},
|
||||
{"-k, --insecure",
|
||||
"Allow insecure server connections",
|
||||
CURLHELP_TLS | CURLHELP_SFTP | CURLHELP_SCP | CURLHELP_SSH},
|
||||
{" --interface <name>",
|
||||
"Use network interface",
|
||||
CURLHELP_CONNECTION},
|
||||
{" --ip-tos <string>",
|
||||
"Set IP Type of Service or Traffic Class",
|
||||
CURLHELP_CONNECTION},
|
||||
{" --ipfs-gateway <URL>",
|
||||
"Gateway for IPFS",
|
||||
CURLHELP_CURL},
|
||||
{"-4, --ipv4",
|
||||
"Resolve names to IPv4 addresses",
|
||||
CURLHELP_CONNECTION | CURLHELP_DNS},
|
||||
{"-6, --ipv6",
|
||||
"Resolve names to IPv6 addresses",
|
||||
CURLHELP_CONNECTION | CURLHELP_DNS},
|
||||
{" --json <data>",
|
||||
"HTTP POST JSON",
|
||||
CURLHELP_HTTP | CURLHELP_POST | CURLHELP_UPLOAD},
|
||||
{"-j, --junk-session-cookies",
|
||||
"Ignore session cookies read from file",
|
||||
CURLHELP_HTTP},
|
||||
{" --keepalive-cnt <integer>",
|
||||
"Maximum number of keepalive probes",
|
||||
CURLHELP_CONNECTION},
|
||||
{" --keepalive-time <seconds>",
|
||||
"Interval time for keepalive probes",
|
||||
CURLHELP_CONNECTION | CURLHELP_TIMEOUT},
|
||||
{" --key <key>",
|
||||
"Private key filename",
|
||||
CURLHELP_TLS | CURLHELP_SSH},
|
||||
{" --key-type <type>",
|
||||
"Private key file type (DER/PEM/ENG)",
|
||||
CURLHELP_TLS},
|
||||
{" --knownhosts <file>",
|
||||
"Specify knownhosts path",
|
||||
CURLHELP_SSH},
|
||||
{" --krb <level>",
|
||||
"Enable Kerberos with security <level>",
|
||||
CURLHELP_DEPRECATED},
|
||||
{" --libcurl <file>",
|
||||
"Generate libcurl code for this command line",
|
||||
CURLHELP_CURL | CURLHELP_GLOBAL},
|
||||
{" --limit-rate <speed>",
|
||||
"Limit transfer speed to RATE",
|
||||
CURLHELP_CONNECTION},
|
||||
{"-l, --list-only",
|
||||
"List only mode",
|
||||
CURLHELP_FTP | CURLHELP_POP3 | CURLHELP_SFTP | CURLHELP_FILE},
|
||||
{" --local-port <range>",
|
||||
"Use a local port number within RANGE",
|
||||
CURLHELP_CONNECTION},
|
||||
{"-L, --location",
|
||||
"Follow redirects",
|
||||
CURLHELP_HTTP},
|
||||
{" --location-trusted",
|
||||
"As --location, but send secrets to other hosts",
|
||||
CURLHELP_HTTP | CURLHELP_AUTH},
|
||||
{" --login-options <options>",
|
||||
"Server login options",
|
||||
CURLHELP_IMAP | CURLHELP_POP3 | CURLHELP_SMTP | CURLHELP_AUTH |
|
||||
CURLHELP_LDAP},
|
||||
{" --mail-auth <address>",
|
||||
"Originator address of the original email",
|
||||
CURLHELP_SMTP},
|
||||
{" --mail-from <address>",
|
||||
"Mail from this address",
|
||||
CURLHELP_SMTP},
|
||||
{" --mail-rcpt <address>",
|
||||
"Mail to this address",
|
||||
CURLHELP_SMTP},
|
||||
{" --mail-rcpt-allowfails",
|
||||
"Allow RCPT TO command to fail",
|
||||
CURLHELP_SMTP},
|
||||
{"-M, --manual",
|
||||
"Display the full manual",
|
||||
CURLHELP_CURL},
|
||||
{" --max-filesize <bytes>",
|
||||
"Maximum file size to download",
|
||||
CURLHELP_CONNECTION},
|
||||
{" --max-redirs <num>",
|
||||
"Maximum number of redirects allowed",
|
||||
CURLHELP_HTTP},
|
||||
{"-m, --max-time <seconds>",
|
||||
"Maximum time allowed for transfer",
|
||||
CURLHELP_CONNECTION | CURLHELP_TIMEOUT},
|
||||
{" --metalink",
|
||||
"Process given URLs as metalink XML file",
|
||||
CURLHELP_DEPRECATED},
|
||||
{" --mptcp",
|
||||
"Enable Multipath TCP",
|
||||
CURLHELP_CONNECTION},
|
||||
{" --negotiate",
|
||||
"Use HTTP Negotiate (SPNEGO) authentication",
|
||||
CURLHELP_AUTH | CURLHELP_HTTP},
|
||||
{"-n, --netrc",
|
||||
"Must read .netrc for username and password",
|
||||
CURLHELP_AUTH},
|
||||
{" --netrc-file <filename>",
|
||||
"Specify FILE for netrc",
|
||||
CURLHELP_AUTH},
|
||||
{" --netrc-optional",
|
||||
"Use either .netrc or URL",
|
||||
CURLHELP_AUTH},
|
||||
{"-:, --next",
|
||||
"Make next URL use separate options",
|
||||
CURLHELP_CURL},
|
||||
{" --no-alpn",
|
||||
"Disable the ALPN TLS extension",
|
||||
CURLHELP_TLS | CURLHELP_HTTP},
|
||||
{"-N, --no-buffer",
|
||||
"Disable buffering of the output stream",
|
||||
CURLHELP_OUTPUT},
|
||||
{" --no-clobber",
|
||||
"Do not overwrite files that already exist",
|
||||
CURLHELP_OUTPUT},
|
||||
{" --no-keepalive",
|
||||
"Disable TCP keepalive on the connection",
|
||||
CURLHELP_CONNECTION},
|
||||
{" --no-npn",
|
||||
"Disable the NPN TLS extension",
|
||||
CURLHELP_DEPRECATED},
|
||||
{" --no-progress-meter",
|
||||
"Do not show the progress meter",
|
||||
CURLHELP_VERBOSE},
|
||||
{" --no-sessionid",
|
||||
"Disable SSL session-ID reusing",
|
||||
CURLHELP_TLS},
|
||||
{" --noproxy <no-proxy-list>",
|
||||
"List of hosts which do not use proxy",
|
||||
CURLHELP_PROXY},
|
||||
{" --ntlm",
|
||||
"HTTP NTLM authentication",
|
||||
CURLHELP_AUTH | CURLHELP_HTTP},
|
||||
{" --ntlm-wb",
|
||||
"HTTP NTLM authentication with winbind",
|
||||
CURLHELP_DEPRECATED},
|
||||
{" --oauth2-bearer <token>",
|
||||
"OAuth 2 Bearer Token",
|
||||
CURLHELP_AUTH | CURLHELP_IMAP | CURLHELP_POP3 | CURLHELP_SMTP |
|
||||
CURLHELP_LDAP},
|
||||
{" --out-null",
|
||||
"Discard response data into the void",
|
||||
CURLHELP_OUTPUT},
|
||||
{"-o, --output <file>",
|
||||
"Write to file instead of stdout",
|
||||
CURLHELP_IMPORTANT | CURLHELP_OUTPUT},
|
||||
{" --output-dir <dir>",
|
||||
"Directory to save files in",
|
||||
CURLHELP_OUTPUT},
|
||||
{"-Z, --parallel",
|
||||
"Perform transfers in parallel",
|
||||
CURLHELP_CONNECTION | CURLHELP_CURL | CURLHELP_GLOBAL},
|
||||
{" --parallel-immediate",
|
||||
"Do not wait for multiplexing",
|
||||
CURLHELP_CONNECTION | CURLHELP_CURL | CURLHELP_GLOBAL},
|
||||
{" --parallel-max <num>",
|
||||
"Maximum concurrency for parallel transfers",
|
||||
CURLHELP_CONNECTION | CURLHELP_CURL | CURLHELP_GLOBAL},
|
||||
{" --parallel-max-host <num>",
|
||||
"Maximum connections to a single host",
|
||||
CURLHELP_CONNECTION | CURLHELP_CURL | CURLHELP_GLOBAL},
|
||||
{" --pass <phrase>",
|
||||
"Passphrase for the private key",
|
||||
CURLHELP_SSH | CURLHELP_TLS | CURLHELP_AUTH},
|
||||
{" --path-as-is",
|
||||
"Do not squash .. sequences in URL path",
|
||||
CURLHELP_CURL},
|
||||
{" --pinnedpubkey <hashes>",
|
||||
"Public key to verify peer against",
|
||||
CURLHELP_TLS},
|
||||
{" --post301",
|
||||
"Do not switch to GET after a 301 redirect",
|
||||
CURLHELP_HTTP | CURLHELP_POST},
|
||||
{" --post302",
|
||||
"Do not switch to GET after a 302 redirect",
|
||||
CURLHELP_HTTP | CURLHELP_POST},
|
||||
{" --post303",
|
||||
"Do not switch to GET after a 303 redirect",
|
||||
CURLHELP_HTTP | CURLHELP_POST},
|
||||
{" --preproxy <[protocol://]host[:port]>",
|
||||
"Use this proxy first",
|
||||
CURLHELP_PROXY},
|
||||
{"-#, --progress-bar",
|
||||
"Display transfer progress as a bar",
|
||||
CURLHELP_VERBOSE | CURLHELP_GLOBAL},
|
||||
{" --proto <protocols>",
|
||||
"Enable/disable PROTOCOLS",
|
||||
CURLHELP_CONNECTION | CURLHELP_CURL},
|
||||
{" --proto-default <protocol>",
|
||||
"Use PROTOCOL for any URL missing a scheme",
|
||||
CURLHELP_CONNECTION | CURLHELP_CURL},
|
||||
{" --proto-redir <protocols>",
|
||||
"Enable/disable PROTOCOLS on redirect",
|
||||
CURLHELP_CONNECTION | CURLHELP_CURL},
|
||||
{"-x, --proxy <[protocol://]host[:port]>",
|
||||
"Use this proxy",
|
||||
CURLHELP_PROXY},
|
||||
{" --proxy-anyauth",
|
||||
"Pick any proxy authentication method",
|
||||
CURLHELP_PROXY | CURLHELP_AUTH},
|
||||
{" --proxy-basic",
|
||||
"Use Basic authentication on the proxy",
|
||||
CURLHELP_PROXY | CURLHELP_AUTH},
|
||||
{" --proxy-ca-native",
|
||||
"Load CA certs from the OS to verify proxy",
|
||||
CURLHELP_TLS},
|
||||
{" --proxy-cacert <file>",
|
||||
"CA certificates to verify proxy against",
|
||||
CURLHELP_PROXY | CURLHELP_TLS},
|
||||
{" --proxy-capath <dir>",
|
||||
"CA directory to verify proxy against",
|
||||
CURLHELP_PROXY | CURLHELP_TLS},
|
||||
{" --proxy-cert <cert[:passwd]>",
|
||||
"Set client certificate for proxy",
|
||||
CURLHELP_PROXY | CURLHELP_TLS},
|
||||
{" --proxy-cert-type <type>",
|
||||
"Client certificate type for HTTPS proxy",
|
||||
CURLHELP_PROXY | CURLHELP_TLS},
|
||||
{" --proxy-ciphers <list>",
|
||||
"TLS 1.2 (1.1, 1.0) ciphers to use for proxy",
|
||||
CURLHELP_PROXY | CURLHELP_TLS},
|
||||
{" --proxy-crlfile <file>",
|
||||
"Set a CRL list for proxy",
|
||||
CURLHELP_PROXY | CURLHELP_TLS},
|
||||
{" --proxy-digest",
|
||||
"Digest auth with the proxy",
|
||||
CURLHELP_PROXY | CURLHELP_TLS},
|
||||
{" --proxy-header <header/@file>",
|
||||
"Pass custom header(s) to proxy",
|
||||
CURLHELP_PROXY},
|
||||
{" --proxy-http2",
|
||||
"Use HTTP/2 with HTTPS proxy",
|
||||
CURLHELP_HTTP | CURLHELP_PROXY},
|
||||
{" --proxy-insecure",
|
||||
"Skip HTTPS proxy cert verification",
|
||||
CURLHELP_PROXY | CURLHELP_TLS},
|
||||
{" --proxy-key <key>",
|
||||
"Private key for HTTPS proxy",
|
||||
CURLHELP_PROXY | CURLHELP_TLS},
|
||||
{" --proxy-key-type <type>",
|
||||
"Private key file type for proxy",
|
||||
CURLHELP_PROXY | CURLHELP_TLS},
|
||||
{" --proxy-negotiate",
|
||||
"HTTP Negotiate (SPNEGO) auth with the proxy",
|
||||
CURLHELP_PROXY | CURLHELP_AUTH},
|
||||
{" --proxy-ntlm",
|
||||
"NTLM authentication with the proxy",
|
||||
CURLHELP_PROXY | CURLHELP_AUTH},
|
||||
{" --proxy-pass <phrase>",
|
||||
"Passphrase for private key for HTTPS proxy",
|
||||
CURLHELP_PROXY | CURLHELP_TLS | CURLHELP_AUTH},
|
||||
{" --proxy-pinnedpubkey <hashes>",
|
||||
"FILE/HASHES public key to verify proxy with",
|
||||
CURLHELP_PROXY | CURLHELP_TLS},
|
||||
{" --proxy-service-name <name>",
|
||||
"SPNEGO proxy service name",
|
||||
CURLHELP_PROXY | CURLHELP_TLS},
|
||||
{" --proxy-ssl-allow-beast",
|
||||
"Allow this security flaw for HTTPS proxy",
|
||||
CURLHELP_PROXY | CURLHELP_TLS},
|
||||
{" --proxy-ssl-auto-client-cert",
|
||||
"Auto client certificate for proxy",
|
||||
CURLHELP_PROXY | CURLHELP_TLS},
|
||||
{" --proxy-tls13-ciphers <list>",
|
||||
"TLS 1.3 proxy cipher suites",
|
||||
CURLHELP_PROXY | CURLHELP_TLS},
|
||||
{" --proxy-tlsauthtype <type>",
|
||||
"TLS authentication type for HTTPS proxy",
|
||||
CURLHELP_PROXY | CURLHELP_TLS | CURLHELP_AUTH},
|
||||
{" --proxy-tlspassword <string>",
|
||||
"TLS password for HTTPS proxy",
|
||||
CURLHELP_PROXY | CURLHELP_TLS | CURLHELP_AUTH},
|
||||
{" --proxy-tlsuser <name>",
|
||||
"TLS username for HTTPS proxy",
|
||||
CURLHELP_PROXY | CURLHELP_TLS | CURLHELP_AUTH},
|
||||
{" --proxy-tlsv1",
|
||||
"TLSv1 for HTTPS proxy",
|
||||
CURLHELP_PROXY | CURLHELP_TLS | CURLHELP_AUTH},
|
||||
{"-U, --proxy-user <user:password>",
|
||||
"Proxy user and password",
|
||||
CURLHELP_PROXY | CURLHELP_AUTH},
|
||||
{" --proxy1.0 <host[:port]>",
|
||||
"Use HTTP/1.0 proxy on given port",
|
||||
CURLHELP_PROXY},
|
||||
{"-p, --proxytunnel",
|
||||
"HTTP proxy tunnel (using CONNECT)",
|
||||
CURLHELP_PROXY},
|
||||
{" --pubkey <key>",
|
||||
"SSH Public key filename",
|
||||
CURLHELP_SFTP | CURLHELP_SCP | CURLHELP_SSH | CURLHELP_AUTH},
|
||||
{"-Q, --quote <command>",
|
||||
"Send command(s) to server before transfer",
|
||||
CURLHELP_FTP | CURLHELP_SFTP},
|
||||
{" --random-file <file>",
|
||||
"File for reading random data from",
|
||||
CURLHELP_DEPRECATED},
|
||||
{"-r, --range <range>",
|
||||
"Retrieve only the bytes within RANGE",
|
||||
CURLHELP_HTTP | CURLHELP_FTP | CURLHELP_SFTP | CURLHELP_FILE},
|
||||
{" --rate <max request rate>",
|
||||
"Request rate for serial transfers",
|
||||
CURLHELP_CONNECTION | CURLHELP_GLOBAL},
|
||||
{" --raw",
|
||||
"Do HTTP raw; no transfer decoding",
|
||||
CURLHELP_HTTP},
|
||||
{"-e, --referer <URL>",
|
||||
"Referrer URL",
|
||||
CURLHELP_HTTP},
|
||||
{"-J, --remote-header-name",
|
||||
"Use the header-provided filename",
|
||||
CURLHELP_OUTPUT},
|
||||
{"-O, --remote-name",
|
||||
"Write output to file named as remote file",
|
||||
CURLHELP_IMPORTANT | CURLHELP_OUTPUT},
|
||||
{" --remote-name-all",
|
||||
"Use the remote filename for all URLs",
|
||||
CURLHELP_OUTPUT},
|
||||
{"-R, --remote-time",
|
||||
"Set remote file's time on local output",
|
||||
CURLHELP_OUTPUT},
|
||||
{" --remove-on-error",
|
||||
"Remove output file on errors",
|
||||
CURLHELP_OUTPUT},
|
||||
{"-X, --request <method>",
|
||||
"Specify request method to use",
|
||||
CURLHELP_CONNECTION | CURLHELP_POP3 | CURLHELP_FTP | CURLHELP_IMAP |
|
||||
CURLHELP_SMTP},
|
||||
{" --request-target <path>",
|
||||
"Specify the target for this request",
|
||||
CURLHELP_HTTP},
|
||||
{" --resolve <[+]host:port:addr[,addr]...>",
|
||||
"Resolve host+port to address",
|
||||
CURLHELP_CONNECTION | CURLHELP_DNS},
|
||||
{" --retry <num>",
|
||||
"Retry request if transient problems occur",
|
||||
CURLHELP_CURL},
|
||||
{" --retry-all-errors",
|
||||
"Retry all errors (with --retry)",
|
||||
CURLHELP_CURL},
|
||||
{" --retry-connrefused",
|
||||
"Retry on connection refused (with --retry)",
|
||||
CURLHELP_CURL},
|
||||
{" --retry-delay <seconds>",
|
||||
"Wait time between retries",
|
||||
CURLHELP_CURL | CURLHELP_TIMEOUT},
|
||||
{" --retry-max-time <seconds>",
|
||||
"Retry only within this period",
|
||||
CURLHELP_CURL | CURLHELP_TIMEOUT},
|
||||
{" --sasl-authzid <identity>",
|
||||
"Identity for SASL PLAIN authentication",
|
||||
CURLHELP_AUTH},
|
||||
{" --sasl-ir",
|
||||
"Initial response in SASL authentication",
|
||||
CURLHELP_AUTH},
|
||||
{" --service-name <name>",
|
||||
"SPNEGO service name",
|
||||
CURLHELP_AUTH},
|
||||
{"-S, --show-error",
|
||||
"Show error even when -s is used",
|
||||
CURLHELP_CURL | CURLHELP_GLOBAL},
|
||||
{"-i, --show-headers",
|
||||
"Show response headers in output",
|
||||
CURLHELP_IMPORTANT | CURLHELP_VERBOSE | CURLHELP_OUTPUT},
|
||||
{" --sigalgs <list>",
|
||||
"TLS signature algorithms to use",
|
||||
CURLHELP_TLS},
|
||||
{"-s, --silent",
|
||||
"Silent mode",
|
||||
CURLHELP_IMPORTANT | CURLHELP_VERBOSE},
|
||||
{" --skip-existing",
|
||||
"Skip download if local file already exists",
|
||||
CURLHELP_CURL | CURLHELP_OUTPUT},
|
||||
{" --socks4 <host[:port]>",
|
||||
"SOCKS4 proxy on given host + port",
|
||||
CURLHELP_PROXY},
|
||||
{" --socks4a <host[:port]>",
|
||||
"SOCKS4a proxy on given host + port",
|
||||
CURLHELP_PROXY},
|
||||
{" --socks5 <host[:port]>",
|
||||
"SOCKS5 proxy on given host + port",
|
||||
CURLHELP_PROXY},
|
||||
{" --socks5-basic",
|
||||
"Username/password auth for SOCKS5 proxies",
|
||||
CURLHELP_PROXY | CURLHELP_AUTH},
|
||||
{" --socks5-gssapi",
|
||||
"Enable GSS-API auth for SOCKS5 proxies",
|
||||
CURLHELP_PROXY | CURLHELP_AUTH},
|
||||
{" --socks5-gssapi-nec",
|
||||
"Compatibility with NEC SOCKS5 server",
|
||||
CURLHELP_PROXY | CURLHELP_AUTH},
|
||||
{" --socks5-gssapi-service <name>",
|
||||
"SOCKS5 proxy service name for GSS-API",
|
||||
CURLHELP_PROXY | CURLHELP_AUTH},
|
||||
{" --socks5-hostname <host[:port]>",
|
||||
"SOCKS5 proxy, pass hostname to proxy",
|
||||
CURLHELP_PROXY},
|
||||
{"-Y, --speed-limit <speed>",
|
||||
"Stop transfers slower than this",
|
||||
CURLHELP_CONNECTION},
|
||||
{"-y, --speed-time <seconds>",
|
||||
"Trigger 'speed-limit' abort after this time",
|
||||
CURLHELP_CONNECTION | CURLHELP_TIMEOUT},
|
||||
{" --ssl",
|
||||
"Try enabling TLS",
|
||||
CURLHELP_TLS | CURLHELP_IMAP | CURLHELP_POP3 | CURLHELP_SMTP |
|
||||
CURLHELP_LDAP},
|
||||
{" --ssl-allow-beast",
|
||||
"Allow security flaw to improve interop",
|
||||
CURLHELP_TLS},
|
||||
{" --ssl-auto-client-cert",
|
||||
"Use auto client certificate (Schannel)",
|
||||
CURLHELP_TLS},
|
||||
{" --ssl-no-revoke",
|
||||
"Disable cert revocation checks (Schannel)",
|
||||
CURLHELP_TLS},
|
||||
{" --ssl-reqd",
|
||||
"Require SSL/TLS",
|
||||
CURLHELP_TLS | CURLHELP_IMAP | CURLHELP_POP3 | CURLHELP_SMTP |
|
||||
CURLHELP_LDAP},
|
||||
{" --ssl-revoke-best-effort",
|
||||
"Ignore missing cert CRL dist points",
|
||||
CURLHELP_TLS},
|
||||
{" --ssl-sessions <filename>",
|
||||
"Load/save SSL session tickets from/to this file",
|
||||
CURLHELP_TLS},
|
||||
{"-2, --sslv2",
|
||||
"SSLv2",
|
||||
CURLHELP_DEPRECATED},
|
||||
{"-3, --sslv3",
|
||||
"SSLv3",
|
||||
CURLHELP_DEPRECATED},
|
||||
{" --stderr <file>",
|
||||
"Where to redirect stderr",
|
||||
CURLHELP_VERBOSE | CURLHELP_GLOBAL},
|
||||
{" --styled-output",
|
||||
"Enable styled output for HTTP headers",
|
||||
CURLHELP_VERBOSE | CURLHELP_GLOBAL},
|
||||
{" --suppress-connect-headers",
|
||||
"Suppress proxy CONNECT response headers",
|
||||
CURLHELP_PROXY},
|
||||
{" --tcp-fastopen",
|
||||
"Use TCP Fast Open",
|
||||
CURLHELP_CONNECTION},
|
||||
{" --tcp-nodelay",
|
||||
"Set TCP_NODELAY",
|
||||
CURLHELP_CONNECTION},
|
||||
{"-t, --telnet-option <opt=val>",
|
||||
"Set telnet option",
|
||||
CURLHELP_TELNET},
|
||||
{" --tftp-blksize <value>",
|
||||
"Set TFTP BLKSIZE option",
|
||||
CURLHELP_TFTP},
|
||||
{" --tftp-no-options",
|
||||
"Do not send any TFTP options",
|
||||
CURLHELP_TFTP},
|
||||
{"-z, --time-cond <time>",
|
||||
"Transfer based on a time condition",
|
||||
CURLHELP_HTTP | CURLHELP_FTP},
|
||||
{" --tls-earlydata",
|
||||
"Allow use of TLSv1.3 early data (0RTT)",
|
||||
CURLHELP_TLS},
|
||||
{" --tls-max <VERSION>",
|
||||
"Maximum allowed TLS version",
|
||||
CURLHELP_TLS},
|
||||
{" --tls13-ciphers <list>",
|
||||
"TLS 1.3 cipher suites to use",
|
||||
CURLHELP_TLS},
|
||||
{" --tlsauthtype <type>",
|
||||
"TLS authentication type",
|
||||
CURLHELP_TLS | CURLHELP_AUTH},
|
||||
{" --tlspassword <string>",
|
||||
"TLS password",
|
||||
CURLHELP_TLS | CURLHELP_AUTH},
|
||||
{" --tlsuser <name>",
|
||||
"TLS username",
|
||||
CURLHELP_TLS | CURLHELP_AUTH},
|
||||
{"-1, --tlsv1",
|
||||
"TLSv1.0 or greater",
|
||||
CURLHELP_TLS},
|
||||
{" --tlsv1.0",
|
||||
"TLSv1.0 or greater",
|
||||
CURLHELP_TLS},
|
||||
{" --tlsv1.1",
|
||||
"TLSv1.1 or greater",
|
||||
CURLHELP_TLS},
|
||||
{" --tlsv1.2",
|
||||
"TLSv1.2 or greater",
|
||||
CURLHELP_TLS},
|
||||
{" --tlsv1.3",
|
||||
"TLSv1.3 or greater",
|
||||
CURLHELP_TLS},
|
||||
{" --tr-encoding",
|
||||
"Request compressed transfer encoding",
|
||||
CURLHELP_HTTP},
|
||||
{" --trace <file>",
|
||||
"Write a debug trace to FILE",
|
||||
CURLHELP_VERBOSE | CURLHELP_GLOBAL},
|
||||
{" --trace-ascii <file>",
|
||||
"Like --trace, but without hex output",
|
||||
CURLHELP_VERBOSE | CURLHELP_GLOBAL},
|
||||
{" --trace-config <string>",
|
||||
"Details to log in trace/verbose output",
|
||||
CURLHELP_VERBOSE | CURLHELP_GLOBAL},
|
||||
{" --trace-ids",
|
||||
"Transfer + connection ids in verbose output",
|
||||
CURLHELP_VERBOSE | CURLHELP_GLOBAL},
|
||||
{" --trace-time",
|
||||
"Add time stamps to trace/verbose output",
|
||||
CURLHELP_VERBOSE | CURLHELP_GLOBAL},
|
||||
{" --unix-socket <path>",
|
||||
"Connect through this Unix domain socket",
|
||||
CURLHELP_CONNECTION},
|
||||
{"-T, --upload-file <file>",
|
||||
"Transfer local FILE to destination",
|
||||
CURLHELP_IMPORTANT | CURLHELP_UPLOAD},
|
||||
{" --upload-flags <flags>",
|
||||
"IMAP upload behavior",
|
||||
CURLHELP_CURL | CURLHELP_OUTPUT},
|
||||
{" --url <url/file>",
|
||||
"URL(s) to work with",
|
||||
CURLHELP_CURL},
|
||||
{" --url-query <data>",
|
||||
"Add a URL query part",
|
||||
CURLHELP_HTTP | CURLHELP_POST | CURLHELP_UPLOAD},
|
||||
{"-B, --use-ascii",
|
||||
"Use ASCII/text transfer",
|
||||
CURLHELP_FTP | CURLHELP_OUTPUT | CURLHELP_LDAP | CURLHELP_TFTP},
|
||||
{"-u, --user <user:password>",
|
||||
"Server user and password",
|
||||
CURLHELP_IMPORTANT | CURLHELP_AUTH},
|
||||
{"-A, --user-agent <name>",
|
||||
"Send User-Agent <name> to server",
|
||||
CURLHELP_IMPORTANT | CURLHELP_HTTP},
|
||||
{" --variable <[%]name=text/@file>",
|
||||
"Set variable",
|
||||
CURLHELP_CURL},
|
||||
{"-v, --verbose",
|
||||
"Make the operation more talkative",
|
||||
CURLHELP_IMPORTANT | CURLHELP_VERBOSE | CURLHELP_GLOBAL},
|
||||
{"-V, --version",
|
||||
"Show version number and quit",
|
||||
CURLHELP_IMPORTANT | CURLHELP_CURL},
|
||||
{" --vlan-priority <priority>",
|
||||
"Set VLAN priority",
|
||||
CURLHELP_CONNECTION},
|
||||
{"-w, --write-out <format>",
|
||||
"Output FORMAT after completion",
|
||||
CURLHELP_VERBOSE},
|
||||
{" --xattr",
|
||||
"Store metadata in extended file attributes",
|
||||
CURLHELP_OUTPUT},
|
||||
{ NULL, NULL, 0 }
|
||||
};
|
||||
Vendored
+223
@@ -0,0 +1,223 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <tchar.h>
|
||||
#endif
|
||||
|
||||
#ifndef UNDER_CE
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include "tool_cfgable.h"
|
||||
#include "tool_doswin.h"
|
||||
#include "tool_msgs.h"
|
||||
#include "tool_operate.h"
|
||||
#include "tool_vms.h"
|
||||
#include "tool_main.h"
|
||||
#include "tool_libinfo.h"
|
||||
#include "tool_stderr.h"
|
||||
|
||||
/*
|
||||
* This is low-level hard-hacking memory leak tracking and similar. Using
|
||||
* the library level code from this client-side is ugly, but we do this
|
||||
* anyway for convenience.
|
||||
*/
|
||||
#include "memdebug.h" /* keep this as LAST include */
|
||||
|
||||
#ifdef __VMS
|
||||
/*
|
||||
* vms_show is a global variable, used in main() as parameter for
|
||||
* function vms_special_exit() to allow proper curl tool exiting.
|
||||
* Its value may be set in other tool_*.c source files thanks to
|
||||
* forward declaration present in tool_vms.h
|
||||
*/
|
||||
int vms_show = 0;
|
||||
#endif
|
||||
|
||||
#ifdef __AMIGA__
|
||||
#ifdef __GNUC__
|
||||
#define CURL_USED __attribute__((used))
|
||||
#else
|
||||
#define CURL_USED
|
||||
#endif
|
||||
static const char CURL_USED min_stack[] = "$STACK:16384";
|
||||
#endif
|
||||
|
||||
#ifdef __MINGW32__
|
||||
/*
|
||||
* There seems to be no way to escape "*" in command-line arguments with MinGW
|
||||
* when command-line argument globbing is enabled under the MSYS shell, so turn
|
||||
* it off.
|
||||
*/
|
||||
extern int _CRT_glob;
|
||||
int _CRT_glob = 0;
|
||||
#endif /* __MINGW32__ */
|
||||
|
||||
/* if we build a static library for unit tests, there is no main() function */
|
||||
#ifndef UNITTESTS
|
||||
|
||||
#if defined(HAVE_PIPE) && defined(HAVE_FCNTL)
|
||||
/*
|
||||
* Ensure that file descriptors 0, 1 and 2 (stdin, stdout, stderr) are
|
||||
* open before starting to run. Otherwise, the first three network
|
||||
* sockets opened by curl could be used for input sources, downloaded data
|
||||
* or error logs as they will effectively be stdin, stdout and/or stderr.
|
||||
*
|
||||
* fcntl's F_GETFD instruction returns -1 if the file descriptor is closed,
|
||||
* otherwise it returns "the file descriptor flags (which typically can only
|
||||
* be FD_CLOEXEC, which is not set here).
|
||||
*/
|
||||
static int main_checkfds(void)
|
||||
{
|
||||
int fd[2];
|
||||
while((fcntl(STDIN_FILENO, F_GETFD) == -1) ||
|
||||
(fcntl(STDOUT_FILENO, F_GETFD) == -1) ||
|
||||
(fcntl(STDERR_FILENO, F_GETFD) == -1))
|
||||
if(pipe(fd))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define main_checkfds() 0
|
||||
#endif
|
||||
|
||||
#ifdef CURLDEBUG
|
||||
static void memory_tracking_init(void)
|
||||
{
|
||||
char *env;
|
||||
/* if CURL_MEMDEBUG is set, this starts memory tracking message logging */
|
||||
env = curl_getenv("CURL_MEMDEBUG");
|
||||
if(env) {
|
||||
/* use the value as filename */
|
||||
char fname[512];
|
||||
if(strlen(env) >= sizeof(fname))
|
||||
env[sizeof(fname)-1] = '\0';
|
||||
strcpy(fname, env);
|
||||
curl_free(env);
|
||||
curl_dbg_memdebug(fname);
|
||||
/* this weird stuff here is to make curl_free() get called before
|
||||
curl_dbg_memdebug() as otherwise memory tracking will log a free()
|
||||
without an alloc! */
|
||||
}
|
||||
/* if CURL_MEMLIMIT is set, this enables fail-on-alloc-number-N feature */
|
||||
env = curl_getenv("CURL_MEMLIMIT");
|
||||
if(env) {
|
||||
curl_off_t num;
|
||||
const char *p = env;
|
||||
if(!curlx_str_number(&p, &num, LONG_MAX))
|
||||
curl_dbg_memlimit((long)num);
|
||||
curl_free(env);
|
||||
}
|
||||
}
|
||||
#else
|
||||
# define memory_tracking_init() tool_nop_stmt
|
||||
#endif
|
||||
|
||||
/*
|
||||
** curl tool main function.
|
||||
*/
|
||||
#if defined(_UNICODE) && !defined(UNDER_CE)
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
/* GCC does not know about wmain() */
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wmissing-prototypes"
|
||||
#pragma GCC diagnostic ignored "-Wmissing-declarations"
|
||||
#endif
|
||||
int wmain(int argc, wchar_t *argv[])
|
||||
#else
|
||||
int main(int argc, char *argv[])
|
||||
#endif
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
tool_init_stderr();
|
||||
|
||||
#if defined(_WIN32) && !defined(UNDER_CE)
|
||||
/* Undocumented diagnostic option to list the full paths of all loaded
|
||||
modules. This is purposely pre-init. */
|
||||
if(argc == 2 && !_tcscmp(argv[1], _T("--dump-module-paths"))) {
|
||||
struct curl_slist *item, *head = GetLoadedModulePaths();
|
||||
for(item = head; item; item = item->next)
|
||||
curl_mprintf("%s\n", item->data);
|
||||
curl_slist_free_all(head);
|
||||
return head ? 0 : 1;
|
||||
}
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
/* win32_init must be called before other init routines. */
|
||||
result = win32_init();
|
||||
if(result) {
|
||||
errorf("(%d) Windows-specific init failed", result);
|
||||
return (int)result;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(main_checkfds()) {
|
||||
errorf("out of file descriptors");
|
||||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
|
||||
#if defined(HAVE_SIGNAL) && defined(SIGPIPE)
|
||||
(void)signal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
|
||||
/* Initialize memory tracking */
|
||||
memory_tracking_init();
|
||||
|
||||
/* Initialize the curl library - do not call any libcurl functions before
|
||||
this point */
|
||||
result = globalconf_init();
|
||||
if(!result) {
|
||||
/* Start our curl operation */
|
||||
result = operate(argc, argv);
|
||||
|
||||
/* Perform the main cleanup */
|
||||
globalconf_free();
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
/* Flush buffers of all streams opened in write or update mode */
|
||||
fflush(NULL);
|
||||
#endif
|
||||
|
||||
#ifdef __VMS
|
||||
vms_special_exit(result, vms_show);
|
||||
#else
|
||||
return (int)result;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(_UNICODE) && !defined(UNDER_CE)
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* ndef UNITTESTS */
|
||||
Vendored
+39
@@ -0,0 +1,39 @@
|
||||
#ifndef HEADER_CURL_TOOL_MAIN_H
|
||||
#define HEADER_CURL_TOOL_MAIN_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#define DEFAULT_MAXREDIRS 50L
|
||||
|
||||
#define RETRY_SLEEP_DEFAULT 1000L /* ms */
|
||||
#define RETRY_SLEEP_MAX 600000L /* ms == 10 minutes */
|
||||
|
||||
#define MAX_PARALLEL 65535
|
||||
#define PARALLEL_DEFAULT 50
|
||||
|
||||
#define MAX_PARALLEL_HOST 65535
|
||||
#define PARALLEL_HOST_DEFAULT 0 /* means not used */
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_MAIN_H */
|
||||
Vendored
+147
@@ -0,0 +1,147 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#include "tool_cfgable.h"
|
||||
#include "tool_msgs.h"
|
||||
#include "tool_cb_prg.h"
|
||||
#include "terminal.h"
|
||||
|
||||
#include "memdebug.h" /* keep this as LAST include */
|
||||
|
||||
#define WARN_PREFIX "Warning: "
|
||||
#define NOTE_PREFIX "Note: "
|
||||
#define ERROR_PREFIX "curl: "
|
||||
|
||||
static void voutf(const char *prefix,
|
||||
const char *fmt,
|
||||
va_list ap) CURL_PRINTF(2, 0);
|
||||
|
||||
static void voutf(const char *prefix,
|
||||
const char *fmt,
|
||||
va_list ap)
|
||||
{
|
||||
size_t width = (get_terminal_columns() - strlen(prefix));
|
||||
size_t len;
|
||||
char *ptr;
|
||||
char *print_buffer;
|
||||
DEBUGASSERT(!strchr(fmt, '\n'));
|
||||
|
||||
print_buffer = curl_mvaprintf(fmt, ap);
|
||||
if(!print_buffer)
|
||||
return;
|
||||
len = strlen(print_buffer);
|
||||
|
||||
ptr = print_buffer;
|
||||
while(len > 0) {
|
||||
fputs(prefix, tool_stderr);
|
||||
|
||||
if(len > width) {
|
||||
size_t cut = width-1;
|
||||
|
||||
while(!ISBLANK(ptr[cut]) && cut) {
|
||||
cut--;
|
||||
}
|
||||
if(cut == 0)
|
||||
/* not a single cutting position was found, just cut it at the
|
||||
max text width then! */
|
||||
cut = width-1;
|
||||
|
||||
(void)fwrite(ptr, cut + 1, 1, tool_stderr);
|
||||
fputs("\n", tool_stderr);
|
||||
ptr += cut + 1; /* skip the space too */
|
||||
len -= cut + 1;
|
||||
}
|
||||
else {
|
||||
fputs(ptr, tool_stderr);
|
||||
fputs("\n", tool_stderr);
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
curl_free(print_buffer);
|
||||
}
|
||||
|
||||
/*
|
||||
* Emit 'note' formatted message on configured 'errors' stream, if verbose was
|
||||
* selected.
|
||||
*/
|
||||
void notef(const char *fmt, ...)
|
||||
{
|
||||
if(global->tracetype) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
voutf(NOTE_PREFIX, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Emit warning formatted message on configured 'errors' stream unless
|
||||
* mute (--silent) was selected.
|
||||
*/
|
||||
void warnf(const char *fmt, ...)
|
||||
{
|
||||
if(!global->silent) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
voutf(WARN_PREFIX, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Emit help formatted message on given stream. This is for errors with or
|
||||
* related to command line arguments.
|
||||
*/
|
||||
void helpf(const char *fmt, ...)
|
||||
{
|
||||
if(fmt) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
DEBUGASSERT(!strchr(fmt, '\n'));
|
||||
fputs("curl: ", tool_stderr); /* prefix it */
|
||||
curl_mvfprintf(tool_stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
fputs("\n", tool_stderr); /* newline it */
|
||||
}
|
||||
curl_mfprintf(tool_stderr, "curl: try 'curl --help' "
|
||||
#ifdef USE_MANUAL
|
||||
"or 'curl --manual' "
|
||||
#endif
|
||||
"for more information\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Emit error message on error stream if not muted. When errors are not tied
|
||||
* to command line arguments, use helpf() for such errors.
|
||||
*/
|
||||
void errorf(const char *fmt, ...)
|
||||
{
|
||||
if(!global->silent || global->showerror) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
voutf(ERROR_PREFIX, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
Vendored
+38
@@ -0,0 +1,38 @@
|
||||
#ifndef HEADER_CURL_TOOL_MSGS_H
|
||||
#define HEADER_CURL_TOOL_MSGS_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
#include "tool_cfgable.h"
|
||||
|
||||
void warnf(const char *fmt, ...)
|
||||
CURL_PRINTF(1, 2);
|
||||
void notef(const char *fmt, ...)
|
||||
CURL_PRINTF(1, 2);
|
||||
void helpf(const char *fmt, ...)
|
||||
CURL_PRINTF(1, 2);
|
||||
void errorf(const char *fmt, ...)
|
||||
CURL_PRINTF(1, 2);
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_MSGS_H */
|
||||
+2342
File diff suppressed because it is too large
Load Diff
+86
@@ -0,0 +1,86 @@
|
||||
#ifndef HEADER_CURL_TOOL_OPERATE_H
|
||||
#define HEADER_CURL_TOOL_OPERATE_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
#include "tool_cb_hdr.h"
|
||||
#include "tool_cb_prg.h"
|
||||
#include "tool_sdecls.h"
|
||||
|
||||
struct per_transfer {
|
||||
/* double linked */
|
||||
struct per_transfer *next;
|
||||
struct per_transfer *prev;
|
||||
struct OperationConfig *config; /* for this transfer */
|
||||
struct curl_certinfo *certinfo;
|
||||
CURL *curl;
|
||||
long retry_remaining;
|
||||
long retry_sleep_default;
|
||||
long retry_sleep;
|
||||
long num_retries; /* counts the performed retries */
|
||||
struct curltime start; /* start of this transfer */
|
||||
struct curltime retrystart;
|
||||
char *url;
|
||||
curl_off_t urlnum; /* the index of the given URL */
|
||||
char *outfile;
|
||||
int infd;
|
||||
struct ProgressData progressbar;
|
||||
struct OutStruct outs;
|
||||
struct OutStruct heads;
|
||||
struct OutStruct etag_save;
|
||||
struct HdrCbData hdrcbdata;
|
||||
long num_headers;
|
||||
time_t startat; /* when doing parallel transfers, this is a retry transfer
|
||||
that has been set to sleep until this time before it
|
||||
should get started (again) */
|
||||
/* for parallel progress bar */
|
||||
curl_off_t dltotal;
|
||||
curl_off_t dlnow;
|
||||
curl_off_t ultotal;
|
||||
curl_off_t ulnow;
|
||||
curl_off_t uploadfilesize; /* expected total amount */
|
||||
curl_off_t uploadedsofar; /* amount delivered from the callback */
|
||||
BIT(dltotal_added); /* if the total has been added from this */
|
||||
BIT(ultotal_added);
|
||||
|
||||
/* NULL or malloced */
|
||||
char *uploadfile;
|
||||
char errorbuffer[CURL_ERROR_SIZE];
|
||||
BIT(infdopen); /* TRUE if infd needs closing */
|
||||
BIT(noprogress);
|
||||
BIT(was_last_header_empty);
|
||||
|
||||
BIT(added); /* set TRUE when added to the multi handle */
|
||||
BIT(abort); /* when doing parallel transfers and this is TRUE then a critical
|
||||
error (eg --fail-early) has occurred in another transfer and
|
||||
this transfer will be aborted in the progress callback */
|
||||
BIT(skip); /* considered already done */
|
||||
};
|
||||
|
||||
CURLcode operate(int argc, argv_item_t argv[]);
|
||||
void single_transfer_cleanup(void);
|
||||
|
||||
extern struct per_transfer *transfers; /* first node */
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_OPERATE_H */
|
||||
+240
@@ -0,0 +1,240 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
#include "tool_operate.h"
|
||||
|
||||
#include "tool_cfgable.h"
|
||||
#include "tool_doswin.h"
|
||||
#include "tool_operhlp.h"
|
||||
#include "tool_msgs.h"
|
||||
#include "memdebug.h" /* keep this as LAST include */
|
||||
|
||||
void clean_getout(struct OperationConfig *config)
|
||||
{
|
||||
if(config) {
|
||||
struct getout *next;
|
||||
struct getout *node = config->url_list;
|
||||
|
||||
while(node) {
|
||||
next = node->next;
|
||||
tool_safefree(node->url);
|
||||
tool_safefree(node->outfile);
|
||||
tool_safefree(node->infile);
|
||||
tool_safefree(node);
|
||||
node = next;
|
||||
}
|
||||
config->url_list = NULL;
|
||||
single_transfer_cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
bool output_expected(const char *url, const char *uploadfile)
|
||||
{
|
||||
if(!uploadfile)
|
||||
return TRUE; /* download */
|
||||
if(checkprefix("http://", url) || checkprefix("https://", url))
|
||||
return TRUE; /* HTTP(S) upload */
|
||||
|
||||
return FALSE; /* non-HTTP upload, probably no output should be expected */
|
||||
}
|
||||
|
||||
bool stdin_upload(const char *uploadfile)
|
||||
{
|
||||
return !strcmp(uploadfile, "-") || !strcmp(uploadfile, ".");
|
||||
}
|
||||
|
||||
/* Convert a CURLUcode into a CURLcode */
|
||||
CURLcode urlerr_cvt(CURLUcode ucode)
|
||||
{
|
||||
if(ucode == CURLUE_OUT_OF_MEMORY)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
else if(ucode == CURLUE_UNSUPPORTED_SCHEME)
|
||||
return CURLE_UNSUPPORTED_PROTOCOL;
|
||||
else if(ucode == CURLUE_LACKS_IDN)
|
||||
return CURLE_NOT_BUILT_IN;
|
||||
else if(ucode == CURLUE_BAD_HANDLE)
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
return CURLE_URL_MALFORMAT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds the filename to the URL if it does not already have one.
|
||||
* url will be freed before return if the returned pointer is different
|
||||
*/
|
||||
CURLcode add_file_name_to_url(CURL *curl, char **inurlp, const char *filename)
|
||||
{
|
||||
CURLcode result = CURLE_URL_MALFORMAT;
|
||||
CURLUcode uerr;
|
||||
CURLU *uh = curl_url();
|
||||
char *path = NULL;
|
||||
char *query = NULL;
|
||||
if(uh) {
|
||||
char *ptr;
|
||||
uerr = curl_url_set(uh, CURLUPART_URL, *inurlp,
|
||||
CURLU_GUESS_SCHEME|CURLU_NON_SUPPORT_SCHEME);
|
||||
if(uerr) {
|
||||
result = urlerr_cvt(uerr);
|
||||
goto fail;
|
||||
}
|
||||
uerr = curl_url_get(uh, CURLUPART_PATH, &path, 0);
|
||||
if(uerr) {
|
||||
result = urlerr_cvt(uerr);
|
||||
goto fail;
|
||||
}
|
||||
uerr = curl_url_get(uh, CURLUPART_QUERY, &query, 0);
|
||||
if(!uerr && query) {
|
||||
curl_free(query);
|
||||
curl_free(path);
|
||||
curl_url_cleanup(uh);
|
||||
return CURLE_OK;
|
||||
}
|
||||
ptr = strrchr(path, '/');
|
||||
if(!ptr || !*++ptr) {
|
||||
/* The URL path has no filename part, add the local filename. In order
|
||||
to be able to do so, we have to create a new URL in another buffer.*/
|
||||
|
||||
/* We only want the part of the local path that is on the right
|
||||
side of the rightmost slash and backslash. */
|
||||
const char *filep = strrchr(filename, '/');
|
||||
char *file2 = strrchr(filep ? filep : filename, '\\');
|
||||
char *encfile;
|
||||
|
||||
if(file2)
|
||||
filep = file2 + 1;
|
||||
else if(filep)
|
||||
filep++;
|
||||
else
|
||||
filep = filename;
|
||||
|
||||
/* URL encode the filename */
|
||||
encfile = curl_easy_escape(curl, filep, 0 /* use strlen */);
|
||||
if(encfile) {
|
||||
char *newpath;
|
||||
char *newurl;
|
||||
if(ptr)
|
||||
/* there is a trailing slash on the path */
|
||||
newpath = curl_maprintf("%s%s", path, encfile);
|
||||
else
|
||||
/* there is no trailing slash on the path */
|
||||
newpath = curl_maprintf("%s/%s", path, encfile);
|
||||
|
||||
curl_free(encfile);
|
||||
|
||||
if(!newpath)
|
||||
goto fail;
|
||||
uerr = curl_url_set(uh, CURLUPART_PATH, newpath, 0);
|
||||
free(newpath);
|
||||
if(uerr) {
|
||||
result = urlerr_cvt(uerr);
|
||||
goto fail;
|
||||
}
|
||||
uerr = curl_url_get(uh, CURLUPART_URL, &newurl, CURLU_DEFAULT_SCHEME);
|
||||
if(uerr) {
|
||||
result = urlerr_cvt(uerr);
|
||||
goto fail;
|
||||
}
|
||||
free(*inurlp);
|
||||
*inurlp = newurl;
|
||||
result = CURLE_OK;
|
||||
}
|
||||
}
|
||||
else
|
||||
/* nothing to do */
|
||||
result = CURLE_OK;
|
||||
}
|
||||
fail:
|
||||
curl_url_cleanup(uh);
|
||||
curl_free(path);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Extracts the name portion of the URL.
|
||||
* Returns a pointer to a heap-allocated string or NULL if
|
||||
* no name part, at location indicated by first argument.
|
||||
*/
|
||||
CURLcode get_url_file_name(char **filename, const char *url)
|
||||
{
|
||||
CURLU *uh = curl_url();
|
||||
char *path = NULL;
|
||||
CURLUcode uerr;
|
||||
|
||||
if(!uh)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
*filename = NULL;
|
||||
|
||||
uerr = curl_url_set(uh, CURLUPART_URL, url, CURLU_GUESS_SCHEME);
|
||||
if(!uerr) {
|
||||
uerr = curl_url_get(uh, CURLUPART_PATH, &path, 0);
|
||||
curl_url_cleanup(uh);
|
||||
uh = NULL;
|
||||
if(!uerr) {
|
||||
int i;
|
||||
char *pc = NULL, *pc2 = NULL;
|
||||
for(i = 0; i < 2; i++) {
|
||||
pc = strrchr(path, '/');
|
||||
pc2 = strrchr(pc ? pc + 1 : path, '\\');
|
||||
if(pc2)
|
||||
pc = pc2;
|
||||
if(pc && !pc[1] && !i) {
|
||||
/* if the path ends with slash, try removing the trailing one
|
||||
and get the last directory part */
|
||||
*pc = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(pc) {
|
||||
/* duplicate the string beyond the slash */
|
||||
*filename = strdup(pc + 1);
|
||||
}
|
||||
else {
|
||||
/* no slash => empty string, use default */
|
||||
*filename = strdup("curl_response");
|
||||
warnf("No remote file name, uses \"%s\"", *filename);
|
||||
}
|
||||
|
||||
curl_free(path);
|
||||
if(!*filename)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
#if defined(_WIN32) || defined(MSDOS)
|
||||
{
|
||||
char *sanitized;
|
||||
SANITIZEcode sc = sanitize_file_name(&sanitized, *filename, 0);
|
||||
tool_safefree(*filename);
|
||||
if(sc) {
|
||||
if(sc == SANITIZE_ERR_OUT_OF_MEMORY)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
return CURLE_URL_MALFORMAT;
|
||||
}
|
||||
*filename = sanitized;
|
||||
}
|
||||
#endif /* _WIN32 || MSDOS */
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
}
|
||||
curl_url_cleanup(uh);
|
||||
return urlerr_cvt(uerr);
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
#ifndef HEADER_CURL_TOOL_OPERHLP_H
|
||||
#define HEADER_CURL_TOOL_OPERHLP_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
struct OperationConfig;
|
||||
|
||||
void clean_getout(struct OperationConfig *config);
|
||||
bool output_expected(const char *url, const char *uploadfile);
|
||||
bool stdin_upload(const char *uploadfile);
|
||||
CURLcode add_file_name_to_url(CURL *curl, char **inurlp, const char *filename);
|
||||
CURLcode get_url_file_name(char **filename, const char *url);
|
||||
CURLcode urlerr_cvt(CURLUcode ucode);
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_OPERHLP_H */
|
||||
+747
@@ -0,0 +1,747 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#include "tool_cfgable.h"
|
||||
#include "tool_getparam.h"
|
||||
#include "tool_getpass.h"
|
||||
#include "tool_msgs.h"
|
||||
#include "tool_paramhlp.h"
|
||||
#include "tool_libinfo.h"
|
||||
#include "tool_util.h"
|
||||
#include "tool_version.h"
|
||||
|
||||
#include "memdebug.h" /* keep this as LAST include */
|
||||
|
||||
struct getout *new_getout(struct OperationConfig *config)
|
||||
{
|
||||
struct getout *node = calloc(1, sizeof(struct getout));
|
||||
struct getout *last = config->url_last;
|
||||
if(node) {
|
||||
static int outnum = 0;
|
||||
|
||||
/* append this new node last in the list */
|
||||
if(last)
|
||||
last->next = node;
|
||||
else
|
||||
config->url_list = node; /* first node */
|
||||
|
||||
/* move the last pointer */
|
||||
config->url_last = node;
|
||||
|
||||
node->useremote = config->remote_name_all;
|
||||
node->num = outnum++;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
#define ISCRLF(x) (((x) == '\r') || ((x) == '\n') || ((x) == '\0'))
|
||||
|
||||
/* memcrlf() has two modes. Both operate on a given memory area with
|
||||
a specified size.
|
||||
|
||||
countcrlf FALSE - return number of bytes from the start that DO NOT include
|
||||
any CR or LF or NULL
|
||||
|
||||
countcrlf TRUE - return number of bytes from the start that are ONLY CR or
|
||||
LF or NULL.
|
||||
|
||||
*/
|
||||
static size_t memcrlf(char *orig,
|
||||
bool countcrlf, /* TRUE if we count CRLF, FALSE
|
||||
if we count non-CRLF */
|
||||
size_t max)
|
||||
{
|
||||
char *ptr;
|
||||
size_t total = max;
|
||||
for(ptr = orig; max; max--, ptr++) {
|
||||
bool crlf = ISCRLF(*ptr);
|
||||
if(countcrlf ^ crlf)
|
||||
return ptr - orig;
|
||||
}
|
||||
return total; /* no delimiter found */
|
||||
}
|
||||
|
||||
#define MAX_FILE2STRING MAX_FILE2MEMORY
|
||||
|
||||
ParameterError file2string(char **bufp, FILE *file)
|
||||
{
|
||||
struct dynbuf dyn;
|
||||
curlx_dyn_init(&dyn, MAX_FILE2STRING);
|
||||
if(file) {
|
||||
do {
|
||||
char buffer[4096];
|
||||
char *ptr;
|
||||
size_t nread = fread(buffer, 1, sizeof(buffer), file);
|
||||
if(ferror(file)) {
|
||||
curlx_dyn_free(&dyn);
|
||||
*bufp = NULL;
|
||||
return PARAM_READ_ERROR;
|
||||
}
|
||||
ptr = buffer;
|
||||
while(nread) {
|
||||
size_t nlen = memcrlf(ptr, FALSE, nread);
|
||||
if(curlx_dyn_addn(&dyn, ptr, nlen))
|
||||
return PARAM_NO_MEM;
|
||||
nread -= nlen;
|
||||
|
||||
if(nread) {
|
||||
ptr += nlen;
|
||||
nlen = memcrlf(ptr, TRUE, nread);
|
||||
ptr += nlen;
|
||||
nread -= nlen;
|
||||
}
|
||||
}
|
||||
} while(!feof(file));
|
||||
}
|
||||
*bufp = curlx_dyn_ptr(&dyn);
|
||||
return PARAM_OK;
|
||||
}
|
||||
|
||||
ParameterError file2memory_range(char **bufp, size_t *size, FILE *file,
|
||||
curl_off_t starto, curl_off_t endo)
|
||||
{
|
||||
if(file) {
|
||||
size_t nread;
|
||||
struct dynbuf dyn;
|
||||
curl_off_t offset = 0;
|
||||
curl_off_t throwaway = 0;
|
||||
|
||||
if(starto) {
|
||||
if(file != stdin) {
|
||||
if(curlx_fseek(file, starto, SEEK_SET))
|
||||
return PARAM_READ_ERROR;
|
||||
offset = starto;
|
||||
}
|
||||
else
|
||||
/* we can't seek stdin, read 'starto' bytes and throw them away */
|
||||
throwaway = starto;
|
||||
}
|
||||
|
||||
/* The size needs to fit in an int later */
|
||||
curlx_dyn_init(&dyn, MAX_FILE2MEMORY);
|
||||
do {
|
||||
char buffer[4096];
|
||||
size_t n_add;
|
||||
char *ptr_add;
|
||||
nread = fread(buffer, 1, sizeof(buffer), file);
|
||||
if(ferror(file)) {
|
||||
curlx_dyn_free(&dyn);
|
||||
*size = 0;
|
||||
*bufp = NULL;
|
||||
return PARAM_READ_ERROR;
|
||||
}
|
||||
n_add = nread;
|
||||
ptr_add = buffer;
|
||||
if(nread) {
|
||||
if(throwaway) {
|
||||
if(throwaway >= (curl_off_t)nread) {
|
||||
throwaway -= nread;
|
||||
offset += nread;
|
||||
n_add = 0; /* nothing to add */
|
||||
}
|
||||
else {
|
||||
/* append the trailing piece */
|
||||
n_add = (size_t)(nread - throwaway);
|
||||
ptr_add = &buffer[throwaway];
|
||||
offset += throwaway;
|
||||
throwaway = 0;
|
||||
}
|
||||
}
|
||||
if(n_add) {
|
||||
if((curl_off_t)(n_add + offset) > endo)
|
||||
n_add = (size_t)(endo - offset + 1);
|
||||
|
||||
if(curlx_dyn_addn(&dyn, ptr_add, n_add))
|
||||
return PARAM_NO_MEM;
|
||||
|
||||
offset += n_add;
|
||||
if(offset > endo)
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while(!feof(file));
|
||||
*size = curlx_dyn_len(&dyn);
|
||||
*bufp = curlx_dyn_ptr(&dyn);
|
||||
}
|
||||
else {
|
||||
*size = 0;
|
||||
*bufp = NULL;
|
||||
}
|
||||
return PARAM_OK;
|
||||
}
|
||||
|
||||
ParameterError file2memory(char **bufp, size_t *size, FILE *file)
|
||||
{
|
||||
return file2memory_range(bufp, size, file, 0, CURL_OFF_T_MAX);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the string and write the long in the given address. Return PARAM_OK
|
||||
* on success, otherwise a parameter specific error enum.
|
||||
*
|
||||
* Since this function gets called with the 'nextarg' pointer from within the
|
||||
* getparameter a lot, we must check it for NULL before accessing the str
|
||||
* data.
|
||||
*/
|
||||
static ParameterError getnum(long *val, const char *str, int base)
|
||||
{
|
||||
DEBUGASSERT((base == 8) || (base == 10));
|
||||
if(str) {
|
||||
curl_off_t num;
|
||||
bool is_neg = FALSE;
|
||||
if(base == 10) {
|
||||
is_neg = (*str == '-');
|
||||
if(is_neg)
|
||||
str++;
|
||||
if(curlx_str_number(&str, &num, LONG_MAX))
|
||||
return PARAM_BAD_NUMERIC;
|
||||
}
|
||||
else { /* base == 8 */
|
||||
if(curlx_str_octal(&str, &num, LONG_MAX))
|
||||
return PARAM_BAD_NUMERIC;
|
||||
}
|
||||
if(!curlx_str_single(&str, '\0')) {
|
||||
*val = (long)num;
|
||||
if(is_neg)
|
||||
*val = -*val;
|
||||
return PARAM_OK; /* Ok */
|
||||
}
|
||||
}
|
||||
return PARAM_BAD_NUMERIC; /* badness */
|
||||
}
|
||||
|
||||
ParameterError str2num(long *val, const char *str)
|
||||
{
|
||||
return getnum(val, str, 10);
|
||||
}
|
||||
|
||||
ParameterError oct2nummax(long *val, const char *str, long max)
|
||||
{
|
||||
ParameterError result = getnum(val, str, 8);
|
||||
if(result != PARAM_OK)
|
||||
return result;
|
||||
else if(*val > max)
|
||||
return PARAM_NUMBER_TOO_LARGE;
|
||||
else if(*val < 0)
|
||||
return PARAM_NEGATIVE_NUMERIC;
|
||||
|
||||
return PARAM_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the string and write the long in the given address. Return PARAM_OK
|
||||
* on success, otherwise a parameter error enum. ONLY ACCEPTS POSITIVE NUMBERS!
|
||||
*
|
||||
* Since this function gets called with the 'nextarg' pointer from within the
|
||||
* getparameter a lot, we must check it for NULL before accessing the str
|
||||
* data.
|
||||
*/
|
||||
|
||||
ParameterError str2unum(long *val, const char *str)
|
||||
{
|
||||
ParameterError result = getnum(val, str, 10);
|
||||
if(result != PARAM_OK)
|
||||
return result;
|
||||
if(*val < 0)
|
||||
return PARAM_NEGATIVE_NUMERIC;
|
||||
|
||||
return PARAM_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the string and write the long in the given address if it is below the
|
||||
* maximum allowed value. Return PARAM_OK on success, otherwise a parameter
|
||||
* error enum. ONLY ACCEPTS POSITIVE NUMBERS!
|
||||
*
|
||||
* Since this function gets called with the 'nextarg' pointer from within the
|
||||
* getparameter a lot, we must check it for NULL before accessing the str
|
||||
* data.
|
||||
*/
|
||||
|
||||
ParameterError str2unummax(long *val, const char *str, long max)
|
||||
{
|
||||
ParameterError result = str2unum(val, str);
|
||||
if(result != PARAM_OK)
|
||||
return result;
|
||||
if(*val > max)
|
||||
return PARAM_NUMBER_TOO_LARGE;
|
||||
|
||||
return PARAM_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the string as seconds with decimals, and write the number of
|
||||
* milliseconds that corresponds in the given address. Return PARAM_OK on
|
||||
* success, otherwise a parameter error enum. ONLY ACCEPTS POSITIVE NUMBERS!
|
||||
*
|
||||
* The 'max' argument is the maximum value allowed, as the numbers are often
|
||||
* multiplied when later used.
|
||||
*
|
||||
* Since this function gets called with the 'nextarg' pointer from within the
|
||||
* getparameter a lot, we must check it for NULL before accessing the str
|
||||
* data.
|
||||
*/
|
||||
|
||||
ParameterError secs2ms(long *valp, const char *str)
|
||||
{
|
||||
curl_off_t secs;
|
||||
long ms = 0;
|
||||
const unsigned int digs[] = { 1, 10, 100, 1000, 10000, 100000,
|
||||
1000000, 10000000, 100000000 };
|
||||
if(!str ||
|
||||
curlx_str_number(&str, &secs, LONG_MAX/1000 - 1))
|
||||
return PARAM_BAD_NUMERIC;
|
||||
if(!curlx_str_single(&str, '.')) {
|
||||
curl_off_t fracs;
|
||||
const char *s = str;
|
||||
size_t len;
|
||||
if(curlx_str_number(&str, &fracs, CURL_OFF_T_MAX))
|
||||
return PARAM_NUMBER_TOO_LARGE;
|
||||
/* how many milliseconds are in fracs ? */
|
||||
len = (str - s);
|
||||
while((len > CURL_ARRAYSIZE(digs) || (fracs > LONG_MAX/100))) {
|
||||
fracs /= 10;
|
||||
len--;
|
||||
}
|
||||
ms = ((long)fracs * 100) / digs[len - 1];
|
||||
}
|
||||
|
||||
*valp = (long)secs * 1000 + ms;
|
||||
return PARAM_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Implement protocol sets in null-terminated array of protocol name pointers.
|
||||
*/
|
||||
|
||||
/* Return index of prototype token in set, card(set) if not found.
|
||||
Can be called with proto == NULL to get card(set). */
|
||||
static size_t protoset_index(const char * const *protoset, const char *proto)
|
||||
{
|
||||
const char * const *p = protoset;
|
||||
|
||||
DEBUGASSERT(proto == proto_token(proto)); /* Ensure it is tokenized. */
|
||||
|
||||
for(; *p; p++)
|
||||
if(proto == *p)
|
||||
break;
|
||||
return p - protoset;
|
||||
}
|
||||
|
||||
/* Include protocol token in set. */
|
||||
static void protoset_set(const char **protoset, const char *proto)
|
||||
{
|
||||
if(proto) {
|
||||
size_t n = protoset_index(protoset, proto);
|
||||
|
||||
if(!protoset[n]) {
|
||||
DEBUGASSERT(n < proto_count);
|
||||
protoset[n] = proto;
|
||||
protoset[n + 1] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Exclude protocol token from set. */
|
||||
static void protoset_clear(const char **protoset, const char *proto)
|
||||
{
|
||||
if(proto) {
|
||||
size_t n = protoset_index(protoset, proto);
|
||||
|
||||
if(protoset[n]) {
|
||||
size_t m = protoset_index(protoset, NULL) - 1;
|
||||
|
||||
protoset[n] = protoset[m];
|
||||
protoset[m] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the string and provide an allocated libcurl compatible protocol
|
||||
* string output. Return non-zero on failure, zero on success.
|
||||
*
|
||||
* The string is a list of protocols
|
||||
*
|
||||
* Since this function gets called with the 'nextarg' pointer from within the
|
||||
* getparameter a lot, we must check it for NULL before accessing the str
|
||||
* data.
|
||||
*/
|
||||
|
||||
#define MAX_PROTOSTRING (64*11) /* Enough room for 64 10-chars proto names. */
|
||||
|
||||
ParameterError proto2num(const char * const *val, char **ostr, const char *str)
|
||||
{
|
||||
const char **protoset;
|
||||
struct dynbuf obuf;
|
||||
size_t proto;
|
||||
CURLcode result;
|
||||
|
||||
curlx_dyn_init(&obuf, MAX_PROTOSTRING);
|
||||
|
||||
protoset = malloc((proto_count + 1) * sizeof(*protoset));
|
||||
if(!protoset)
|
||||
return PARAM_NO_MEM;
|
||||
|
||||
/* Preset protocol set with default values. */
|
||||
protoset[0] = NULL;
|
||||
for(; *val; val++) {
|
||||
const char *p = proto_token(*val);
|
||||
|
||||
if(p)
|
||||
protoset_set(protoset, p);
|
||||
}
|
||||
|
||||
while(*str) {
|
||||
const char *next = strchr(str, ',');
|
||||
size_t plen;
|
||||
enum e_action { allow, deny, set } action = allow;
|
||||
|
||||
if(next) {
|
||||
if(str == next) {
|
||||
str++;
|
||||
continue;
|
||||
}
|
||||
plen = next - str - 1;
|
||||
}
|
||||
else
|
||||
plen = strlen(str) - 1;
|
||||
|
||||
/* Process token modifiers */
|
||||
switch(*str++) {
|
||||
case '=':
|
||||
action = set;
|
||||
break;
|
||||
case '-':
|
||||
action = deny;
|
||||
break;
|
||||
case '+':
|
||||
action = allow;
|
||||
break;
|
||||
default:
|
||||
/* no modifier */
|
||||
str--;
|
||||
plen++;
|
||||
break;
|
||||
}
|
||||
|
||||
if((plen == 3) && curl_strnequal(str, "all", 3)) {
|
||||
switch(action) {
|
||||
case deny:
|
||||
protoset[0] = NULL;
|
||||
break;
|
||||
case allow:
|
||||
case set:
|
||||
memcpy((char *) protoset,
|
||||
built_in_protos, (proto_count + 1) * sizeof(*protoset));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
char buffer[32];
|
||||
const char *p;
|
||||
curl_msnprintf(buffer, sizeof(buffer), "%.*s", (int)plen, str);
|
||||
|
||||
p = proto_token(buffer);
|
||||
|
||||
if(p)
|
||||
switch(action) {
|
||||
case deny:
|
||||
protoset_clear(protoset, p);
|
||||
break;
|
||||
case set:
|
||||
protoset[0] = NULL;
|
||||
FALLTHROUGH();
|
||||
case allow:
|
||||
protoset_set(protoset, p);
|
||||
break;
|
||||
}
|
||||
else { /* unknown protocol */
|
||||
/* If they have specified only this protocol, we say treat it as
|
||||
if no protocols are allowed */
|
||||
if(action == set)
|
||||
protoset[0] = NULL;
|
||||
warnf("unrecognized protocol '%s'", buffer);
|
||||
}
|
||||
}
|
||||
if(next)
|
||||
str = next + 1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
/* We need the protocols in alphabetic order for CI tests requirements. */
|
||||
qsort((char *) protoset, protoset_index(protoset, NULL), sizeof(*protoset),
|
||||
struplocompare4sort);
|
||||
|
||||
result = curlx_dyn_addn(&obuf, "", 0);
|
||||
for(proto = 0; protoset[proto] && !result; proto++)
|
||||
result = curlx_dyn_addf(&obuf, "%s,", protoset[proto]);
|
||||
free((char *) protoset);
|
||||
curlx_dyn_setlen(&obuf, curlx_dyn_len(&obuf) - 1);
|
||||
free(*ostr);
|
||||
*ostr = curlx_dyn_ptr(&obuf);
|
||||
|
||||
return *ostr ? PARAM_OK : PARAM_NO_MEM;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given string is a protocol supported by libcurl
|
||||
*
|
||||
* @param str the protocol name
|
||||
* @return PARAM_OK protocol supported
|
||||
* @return PARAM_LIBCURL_UNSUPPORTED_PROTOCOL protocol not supported
|
||||
* @return PARAM_REQUIRES_PARAMETER missing parameter
|
||||
*/
|
||||
ParameterError check_protocol(const char *str)
|
||||
{
|
||||
if(!str)
|
||||
return PARAM_REQUIRES_PARAMETER;
|
||||
|
||||
if(proto_token(str))
|
||||
return PARAM_OK;
|
||||
return PARAM_LIBCURL_UNSUPPORTED_PROTOCOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the given string looking for an offset (which may be a
|
||||
* larger-than-integer value). The offset CANNOT be negative!
|
||||
*
|
||||
* @param val the offset to populate
|
||||
* @param str the buffer containing the offset
|
||||
* @return PARAM_OK if successful, a parameter specific error enum if failure.
|
||||
*/
|
||||
ParameterError str2offset(curl_off_t *val, const char *str)
|
||||
{
|
||||
if(curlx_str_number(&str, val, CURL_OFF_T_MAX) ||
|
||||
curlx_str_single(&str, '\0'))
|
||||
return PARAM_BAD_NUMERIC;
|
||||
return PARAM_OK;
|
||||
}
|
||||
|
||||
#define MAX_USERPWDLENGTH (100*1024)
|
||||
static CURLcode checkpasswd(const char *kind, /* for what purpose */
|
||||
const size_t i, /* operation index */
|
||||
const bool last, /* TRUE if last operation */
|
||||
char **userpwd) /* pointer to allocated string */
|
||||
{
|
||||
char *psep;
|
||||
char *osep;
|
||||
|
||||
if(!*userpwd)
|
||||
return CURLE_OK;
|
||||
|
||||
/* Attempt to find the password separator */
|
||||
psep = strchr(*userpwd, ':');
|
||||
|
||||
/* Attempt to find the options separator */
|
||||
osep = strchr(*userpwd, ';');
|
||||
|
||||
if(!psep && **userpwd != ';') {
|
||||
/* no password present, prompt for one */
|
||||
char passwd[2048] = "";
|
||||
char prompt[256];
|
||||
struct dynbuf dyn;
|
||||
|
||||
curlx_dyn_init(&dyn, MAX_USERPWDLENGTH);
|
||||
if(osep)
|
||||
*osep = '\0';
|
||||
|
||||
/* build a nice-looking prompt */
|
||||
if(!i && last)
|
||||
curl_msnprintf(prompt, sizeof(prompt),
|
||||
"Enter %s password for user '%s':",
|
||||
kind, *userpwd);
|
||||
else
|
||||
curl_msnprintf(prompt, sizeof(prompt),
|
||||
"Enter %s password for user '%s' on URL #%zu:",
|
||||
kind, *userpwd, i + 1);
|
||||
|
||||
/* get password */
|
||||
getpass_r(prompt, passwd, sizeof(passwd));
|
||||
if(osep)
|
||||
*osep = ';';
|
||||
|
||||
if(curlx_dyn_addf(&dyn, "%s:%s", *userpwd, passwd))
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
/* return the new string */
|
||||
free(*userpwd);
|
||||
*userpwd = curlx_dyn_ptr(&dyn);
|
||||
}
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
ParameterError add2list(struct curl_slist **list, const char *ptr)
|
||||
{
|
||||
struct curl_slist *newlist = curl_slist_append(*list, ptr);
|
||||
if(newlist)
|
||||
*list = newlist;
|
||||
else
|
||||
return PARAM_NO_MEM;
|
||||
|
||||
return PARAM_OK;
|
||||
}
|
||||
|
||||
long ftpfilemethod(const char *str)
|
||||
{
|
||||
if(curl_strequal("singlecwd", str))
|
||||
return CURLFTPMETHOD_SINGLECWD;
|
||||
if(curl_strequal("nocwd", str))
|
||||
return CURLFTPMETHOD_NOCWD;
|
||||
if(curl_strequal("multicwd", str))
|
||||
return CURLFTPMETHOD_MULTICWD;
|
||||
|
||||
warnf("unrecognized ftp file method '%s', using default", str);
|
||||
|
||||
return CURLFTPMETHOD_MULTICWD;
|
||||
}
|
||||
|
||||
long ftpcccmethod(const char *str)
|
||||
{
|
||||
if(curl_strequal("passive", str))
|
||||
return CURLFTPSSL_CCC_PASSIVE;
|
||||
if(curl_strequal("active", str))
|
||||
return CURLFTPSSL_CCC_ACTIVE;
|
||||
|
||||
warnf("unrecognized ftp CCC method '%s', using default", str);
|
||||
|
||||
return CURLFTPSSL_CCC_PASSIVE;
|
||||
}
|
||||
|
||||
long delegation(const char *str)
|
||||
{
|
||||
if(curl_strequal("none", str))
|
||||
return CURLGSSAPI_DELEGATION_NONE;
|
||||
if(curl_strequal("policy", str))
|
||||
return CURLGSSAPI_DELEGATION_POLICY_FLAG;
|
||||
if(curl_strequal("always", str))
|
||||
return CURLGSSAPI_DELEGATION_FLAG;
|
||||
|
||||
warnf("unrecognized delegation method '%s', using none", str);
|
||||
|
||||
return CURLGSSAPI_DELEGATION_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
* my_useragent: returns allocated string with default user agent
|
||||
*/
|
||||
static char *my_useragent(void)
|
||||
{
|
||||
return strdup(CURL_NAME "/" CURL_VERSION);
|
||||
}
|
||||
|
||||
#define isheadersep(x) ((((x)==':') || ((x)==';')))
|
||||
|
||||
/*
|
||||
* inlist() returns true if the given 'checkfor' header is present in the
|
||||
* header list.
|
||||
*/
|
||||
static bool inlist(const struct curl_slist *head,
|
||||
const char *checkfor)
|
||||
{
|
||||
size_t thislen = strlen(checkfor);
|
||||
DEBUGASSERT(thislen);
|
||||
DEBUGASSERT(checkfor[thislen-1] != ':');
|
||||
|
||||
for(; head; head = head->next) {
|
||||
if(curl_strnequal(head->data, checkfor, thislen) &&
|
||||
isheadersep(head->data[thislen]) )
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CURLcode get_args(struct OperationConfig *config, const size_t i)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
bool last = (config->next ? FALSE : TRUE);
|
||||
|
||||
if(config->jsoned) {
|
||||
ParameterError err = PARAM_OK;
|
||||
/* --json also implies json Content-Type: and Accept: headers - if
|
||||
they are not set with -H */
|
||||
if(!inlist(config->headers, "Content-Type"))
|
||||
err = add2list(&config->headers, "Content-Type: application/json");
|
||||
if(!err && !inlist(config->headers, "Accept"))
|
||||
err = add2list(&config->headers, "Accept: application/json");
|
||||
if(err)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
/* Check if we have a password for the given host user */
|
||||
if(config->userpwd && !config->oauth_bearer)
|
||||
result = checkpasswd("host", i, last, &config->userpwd);
|
||||
|
||||
/* Check if we have a password for the given proxy user */
|
||||
if(!result && config->proxyuserpwd)
|
||||
result = checkpasswd("proxy", i, last, &config->proxyuserpwd);
|
||||
|
||||
/* Check if we have a user agent */
|
||||
if(!result && !config->useragent) {
|
||||
config->useragent = my_useragent();
|
||||
if(!config->useragent) {
|
||||
errorf("out of memory");
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the string and modify ssl_version in the val argument. Return PARAM_OK
|
||||
* on success, otherwise a parameter error enum.
|
||||
*
|
||||
* Since this function gets called with the 'nextarg' pointer from within the
|
||||
* getparameter a lot, we must check it for NULL before accessing the str
|
||||
* data.
|
||||
*/
|
||||
|
||||
ParameterError str2tls_max(unsigned char *val, const char *str)
|
||||
{
|
||||
static struct s_tls_max {
|
||||
const char *tls_max_str;
|
||||
unsigned char tls_max;
|
||||
} const tls_max_array[] = {
|
||||
{ "default", 0 }, /* lets the library decide */
|
||||
{ "1.0", 1 },
|
||||
{ "1.1", 2 },
|
||||
{ "1.2", 3 },
|
||||
{ "1.3", 4 }
|
||||
};
|
||||
size_t i = 0;
|
||||
if(!str)
|
||||
return PARAM_REQUIRES_PARAMETER;
|
||||
for(i = 0; i < CURL_ARRAYSIZE(tls_max_array); i++) {
|
||||
if(!strcmp(str, tls_max_array[i].tls_max_str)) {
|
||||
*val = tls_max_array[i].tls_max;
|
||||
return PARAM_OK;
|
||||
}
|
||||
}
|
||||
return PARAM_BAD_USE;
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
#ifndef HEADER_CURL_TOOL_PARAMHLP_H
|
||||
#define HEADER_CURL_TOOL_PARAMHLP_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
#include "tool_libinfo.h"
|
||||
|
||||
struct getout *new_getout(struct OperationConfig *config);
|
||||
|
||||
ParameterError file2string(char **bufp, FILE *file);
|
||||
|
||||
#if SIZEOF_SIZE_T > 4
|
||||
#define MAX_FILE2MEMORY (16LL*1024*1024*1024)
|
||||
#else
|
||||
#define MAX_FILE2MEMORY (INT_MAX)
|
||||
#endif
|
||||
|
||||
ParameterError file2memory(char **bufp, size_t *size, FILE *file);
|
||||
ParameterError file2memory_range(char **bufp, size_t *size, FILE *file,
|
||||
curl_off_t starto, curl_off_t endo);
|
||||
|
||||
ParameterError str2num(long *val, const char *str);
|
||||
ParameterError str2unum(long *val, const char *str);
|
||||
ParameterError oct2nummax(long *val, const char *str, long max);
|
||||
ParameterError str2unummax(long *val, const char *str, long max);
|
||||
ParameterError secs2ms(long *val, const char *str);
|
||||
ParameterError proto2num(const char * const *val, char **obuf,
|
||||
const char *str);
|
||||
ParameterError check_protocol(const char *str);
|
||||
ParameterError str2offset(curl_off_t *val, const char *str);
|
||||
CURLcode get_args(struct OperationConfig *config, const size_t i);
|
||||
ParameterError add2list(struct curl_slist **list, const char *ptr);
|
||||
long ftpfilemethod(const char *str);
|
||||
long ftpcccmethod(const char *str);
|
||||
long delegation(const char *str);
|
||||
|
||||
ParameterError str2tls_max(unsigned char *val, const char *str);
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_PARAMHLP_H */
|
||||
+338
@@ -0,0 +1,338 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#include "tool_cfgable.h"
|
||||
#include "tool_getparam.h"
|
||||
#include "tool_helpers.h"
|
||||
#include "tool_findfile.h"
|
||||
#include "tool_msgs.h"
|
||||
#include "tool_parsecfg.h"
|
||||
#include "tool_util.h"
|
||||
#include "memdebug.h" /* keep this as LAST include */
|
||||
|
||||
/* only acknowledge colon or equals as separators if the option was not
|
||||
specified with an initial dash! */
|
||||
#define ISSEP(x,dash) (!dash && (((x) == '=') || ((x) == ':')))
|
||||
|
||||
/*
|
||||
* Copies the string from line to the param dynbuf, unquoting backslash-quoted
|
||||
* characters and null-terminating the output string. Stops at the first
|
||||
* non-backslash-quoted double quote character or the end of the input string.
|
||||
* param must be at least as long as the input string. Returns 0 on success.
|
||||
*/
|
||||
static int unslashquote(const char *line, struct dynbuf *param)
|
||||
{
|
||||
curlx_dyn_reset(param);
|
||||
|
||||
while(*line && (*line != '\"')) {
|
||||
if(*line == '\\') {
|
||||
char out;
|
||||
line++;
|
||||
|
||||
/* default is to output the letter after the backslash */
|
||||
switch(out = *line) {
|
||||
case '\0':
|
||||
continue; /* this'll break out of the loop */
|
||||
case 't':
|
||||
out = '\t';
|
||||
break;
|
||||
case 'n':
|
||||
out = '\n';
|
||||
break;
|
||||
case 'r':
|
||||
out = '\r';
|
||||
break;
|
||||
case 'v':
|
||||
out = '\v';
|
||||
break;
|
||||
}
|
||||
if(curlx_dyn_addn(param, &out, 1))
|
||||
return 1;
|
||||
line++;
|
||||
}
|
||||
else if(curlx_dyn_addn(param, line++, 1))
|
||||
return 1;
|
||||
}
|
||||
return 0; /* ok */
|
||||
}
|
||||
|
||||
#define MAX_CONFIG_LINE_LENGTH (10*1024*1024)
|
||||
|
||||
/* return 0 on everything-is-fine, and non-zero otherwise */
|
||||
ParameterError parseconfig(const char *filename, int max_recursive)
|
||||
{
|
||||
FILE *file = NULL;
|
||||
bool usedarg = FALSE;
|
||||
ParameterError err = PARAM_OK;
|
||||
struct OperationConfig *config = global->last;
|
||||
char *pathalloc = NULL;
|
||||
|
||||
if(!filename) {
|
||||
/* NULL means load .curlrc from homedir! */
|
||||
char *curlrc = findfile(".curlrc", CURLRC_DOTSCORE);
|
||||
if(curlrc) {
|
||||
file = curlx_fopen(curlrc, FOPEN_READTEXT);
|
||||
if(!file) {
|
||||
free(curlrc);
|
||||
return PARAM_READ_ERROR;
|
||||
}
|
||||
filename = pathalloc = curlrc;
|
||||
}
|
||||
#if defined(_WIN32) && !defined(UNDER_CE)
|
||||
else {
|
||||
char *fullp;
|
||||
/* check for .curlrc then _curlrc in the dir of the executable */
|
||||
file = tool_execpath(".curlrc", &fullp);
|
||||
if(!file)
|
||||
file = tool_execpath("_curlrc", &fullp);
|
||||
if(file)
|
||||
/* this is the filename we read from */
|
||||
filename = fullp;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
if(strcmp(filename, "-"))
|
||||
file = curlx_fopen(filename, FOPEN_READTEXT);
|
||||
else
|
||||
file = stdin;
|
||||
}
|
||||
|
||||
if(file) {
|
||||
char *line;
|
||||
char *option;
|
||||
char *param;
|
||||
int lineno = 0;
|
||||
bool dashed_option;
|
||||
struct dynbuf buf;
|
||||
struct dynbuf pbuf;
|
||||
bool fileerror = FALSE;
|
||||
curlx_dyn_init(&buf, MAX_CONFIG_LINE_LENGTH);
|
||||
curlx_dyn_init(&pbuf, MAX_CONFIG_LINE_LENGTH);
|
||||
DEBUGASSERT(filename);
|
||||
|
||||
while(!err && my_get_line(file, &buf, &fileerror)) {
|
||||
ParameterError res;
|
||||
lineno++;
|
||||
line = curlx_dyn_ptr(&buf);
|
||||
if(!line) {
|
||||
err = PARAM_NO_MEM; /* out of memory */
|
||||
break;
|
||||
}
|
||||
|
||||
/* the option keywords starts here */
|
||||
option = line;
|
||||
|
||||
/* the option starts with a dash? */
|
||||
dashed_option = (option[0] == '-');
|
||||
|
||||
while(*line && !ISBLANK(*line) && !ISSEP(*line, dashed_option))
|
||||
line++;
|
||||
/* ... and has ended here */
|
||||
|
||||
if(*line)
|
||||
*line++ = '\0'; /* null-terminate, we have a local copy of the data */
|
||||
|
||||
#ifdef DEBUG_CONFIG
|
||||
curl_mfprintf(tool_stderr, "GOT: %s\n", option);
|
||||
#endif
|
||||
|
||||
/* pass spaces and separator(s) */
|
||||
while(ISBLANK(*line) || ISSEP(*line, dashed_option))
|
||||
line++;
|
||||
|
||||
/* the parameter starts here (unless quoted) */
|
||||
if(*line == '\"') {
|
||||
/* quoted parameter, do the quote dance */
|
||||
int rc = unslashquote(++line, &pbuf);
|
||||
if(rc) {
|
||||
err = PARAM_BAD_USE;
|
||||
break;
|
||||
}
|
||||
param = curlx_dyn_len(&pbuf) ? curlx_dyn_ptr(&pbuf) : CURL_UNCONST("");
|
||||
}
|
||||
else {
|
||||
param = line; /* parameter starts here */
|
||||
while(*line && !ISSPACE(*line)) /* stop also on CRLF */
|
||||
line++;
|
||||
|
||||
if(*line) {
|
||||
*line = '\0'; /* null-terminate */
|
||||
|
||||
/* to detect mistakes better, see if there is data following */
|
||||
line++;
|
||||
/* pass all spaces */
|
||||
while(ISBLANK(*line))
|
||||
line++;
|
||||
|
||||
switch(*line) {
|
||||
case '\0':
|
||||
case '\r':
|
||||
case '\n':
|
||||
case '#': /* comment */
|
||||
break;
|
||||
default:
|
||||
warnf("%s:%d: warning: '%s' uses unquoted whitespace. "
|
||||
"This may cause side-effects. Consider double quotes.",
|
||||
filename, lineno, option);
|
||||
}
|
||||
}
|
||||
if(!*param)
|
||||
/* do this so getparameter can check for required parameters.
|
||||
Otherwise it always thinks there is a parameter. */
|
||||
param = NULL;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CONFIG
|
||||
curl_mfprintf(tool_stderr, "PARAM: \"%s\"\n",(param ? param : "(null)"));
|
||||
#endif
|
||||
res = getparameter(option, param, &usedarg, config, max_recursive);
|
||||
config = global->last;
|
||||
|
||||
if(!res && param && *param && !usedarg)
|
||||
/* we passed in a parameter that was not used! */
|
||||
res = PARAM_GOT_EXTRA_PARAMETER;
|
||||
|
||||
if(res == PARAM_NEXT_OPERATION) {
|
||||
if(config->url_list && config->url_list->url) {
|
||||
/* Allocate the next config */
|
||||
config->next = config_alloc();
|
||||
if(config->next) {
|
||||
/* Update the last operation pointer */
|
||||
global->last = config->next;
|
||||
|
||||
/* Move onto the new config */
|
||||
config->next->prev = config;
|
||||
config = config->next;
|
||||
}
|
||||
else
|
||||
res = PARAM_NO_MEM;
|
||||
}
|
||||
}
|
||||
|
||||
if(res != PARAM_OK && res != PARAM_NEXT_OPERATION) {
|
||||
/* the help request is not really an error */
|
||||
if(!strcmp(filename, "-")) {
|
||||
filename = "<stdin>";
|
||||
}
|
||||
if(res != PARAM_HELP_REQUESTED &&
|
||||
res != PARAM_MANUAL_REQUESTED &&
|
||||
res != PARAM_VERSION_INFO_REQUESTED &&
|
||||
res != PARAM_ENGINES_REQUESTED &&
|
||||
res != PARAM_CA_EMBED_REQUESTED) {
|
||||
/* only show error in the first level config call */
|
||||
if(max_recursive == CONFIG_MAX_LEVELS) {
|
||||
const char *reason = param2text(res);
|
||||
errorf("%s:%d: '%s' %s", filename, lineno, option, reason);
|
||||
}
|
||||
err = res;
|
||||
}
|
||||
}
|
||||
}
|
||||
curlx_dyn_free(&buf);
|
||||
curlx_dyn_free(&pbuf);
|
||||
if(file != stdin)
|
||||
curlx_fclose(file);
|
||||
if(fileerror)
|
||||
err = PARAM_READ_ERROR;
|
||||
}
|
||||
else
|
||||
err = PARAM_READ_ERROR; /* could not open the file */
|
||||
|
||||
if((err == PARAM_READ_ERROR) && filename)
|
||||
errorf("cannot read config from '%s'", filename);
|
||||
|
||||
free(pathalloc);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static bool get_line(FILE *input, struct dynbuf *buf, bool *error)
|
||||
{
|
||||
CURLcode result;
|
||||
char buffer[128];
|
||||
curlx_dyn_reset(buf);
|
||||
while(1) {
|
||||
char *b = fgets(buffer, sizeof(buffer), input);
|
||||
|
||||
if(b) {
|
||||
size_t rlen = strlen(b);
|
||||
|
||||
if(!rlen)
|
||||
break;
|
||||
|
||||
result = curlx_dyn_addn(buf, b, rlen);
|
||||
if(result) {
|
||||
/* too long line or out of memory */
|
||||
*error = TRUE;
|
||||
return FALSE; /* error */
|
||||
}
|
||||
|
||||
else if(b[rlen-1] == '\n') {
|
||||
/* end of the line, drop the newline */
|
||||
size_t len = curlx_dyn_len(buf);
|
||||
if(len)
|
||||
curlx_dyn_setlen(buf, len - 1);
|
||||
return TRUE; /* all good */
|
||||
}
|
||||
|
||||
else if(feof(input))
|
||||
return TRUE; /* all good */
|
||||
}
|
||||
else if(curlx_dyn_len(buf))
|
||||
return TRUE; /* all good */
|
||||
else
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a line from the given file. Every line is null-terminated (no
|
||||
* newline). Skips #-commented and space/tabs-only lines automatically.
|
||||
*/
|
||||
bool my_get_line(FILE *input, struct dynbuf *buf, bool *error)
|
||||
{
|
||||
bool retcode;
|
||||
do {
|
||||
retcode = get_line(input, buf, error);
|
||||
if(!*error && retcode) {
|
||||
size_t len = curlx_dyn_len(buf);
|
||||
if(len) {
|
||||
const char *line = curlx_dyn_ptr(buf);
|
||||
while(ISBLANK(*line))
|
||||
line++;
|
||||
|
||||
/* a line with # in the first non-blank column is a comment! */
|
||||
if((*line == '#') || !*line)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
continue; /* avoid returning an empty line */
|
||||
}
|
||||
break;
|
||||
} while(retcode);
|
||||
return retcode;
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
#ifndef HEADER_CURL_TOOL_PARSECFG_H
|
||||
#define HEADER_CURL_TOOL_PARSECFG_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
/* only allow this many levels of recursive --config use */
|
||||
#define CONFIG_MAX_LEVELS 5
|
||||
ParameterError parseconfig(const char *filename, int max_recursive);
|
||||
bool my_get_line(FILE *fp, struct dynbuf *db, bool *error);
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_PARSECFG_H */
|
||||
+314
@@ -0,0 +1,314 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
#include "tool_operate.h"
|
||||
#include "tool_progress.h"
|
||||
#include "tool_util.h"
|
||||
|
||||
/* The point of this function would be to return a string of the input data,
|
||||
but never longer than 5 columns (+ one zero byte).
|
||||
Add suffix k, M, G when suitable... */
|
||||
static char *max5data(curl_off_t bytes, char *max5)
|
||||
{
|
||||
/* a signed 64-bit value is 8192 petabytes maximum */
|
||||
const char unit[] = { 'k', 'M', 'G', 'T', 'P', 0 };
|
||||
int k = 0;
|
||||
if(bytes < 100000) {
|
||||
curl_msnprintf(max5, 6, "%5" CURL_FORMAT_CURL_OFF_T, bytes);
|
||||
return max5;
|
||||
}
|
||||
|
||||
do {
|
||||
curl_off_t nbytes = bytes / 1024;
|
||||
if(nbytes < 100) {
|
||||
/* display with a decimal */
|
||||
curl_msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0"
|
||||
CURL_FORMAT_CURL_OFF_T "%c", bytes/1024,
|
||||
(bytes%1024) / (1024/10), unit[k]);
|
||||
break;
|
||||
}
|
||||
else if(nbytes < 10000) {
|
||||
/* no decimals */
|
||||
curl_msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "%c", nbytes,
|
||||
unit[k]);
|
||||
break;
|
||||
}
|
||||
bytes = nbytes;
|
||||
k++;
|
||||
DEBUGASSERT(unit[k]);
|
||||
} while(unit[k]);
|
||||
return max5;
|
||||
}
|
||||
|
||||
int xferinfo_cb(void *clientp,
|
||||
curl_off_t dltotal,
|
||||
curl_off_t dlnow,
|
||||
curl_off_t ultotal,
|
||||
curl_off_t ulnow)
|
||||
{
|
||||
struct per_transfer *per = clientp;
|
||||
struct OperationConfig *config = per->config;
|
||||
per->dltotal = dltotal;
|
||||
per->dlnow = dlnow;
|
||||
per->ultotal = ultotal;
|
||||
per->ulnow = ulnow;
|
||||
|
||||
if(per->abort)
|
||||
return 1;
|
||||
|
||||
if(config->readbusy) {
|
||||
config->readbusy = FALSE;
|
||||
curl_easy_pause(per->curl, CURLPAUSE_CONT);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Provide a string that is 2 + 1 + 2 + 1 + 2 = 8 letters long (plus the zero
|
||||
byte) */
|
||||
static void time2str(char *r, curl_off_t seconds)
|
||||
{
|
||||
curl_off_t h;
|
||||
if(seconds <= 0) {
|
||||
strcpy(r, "--:--:--");
|
||||
return;
|
||||
}
|
||||
h = seconds / 3600;
|
||||
if(h <= 99) {
|
||||
curl_off_t m = (seconds - (h * 3600)) / 60;
|
||||
curl_off_t s = (seconds - (h * 3600)) - (m * 60);
|
||||
curl_msnprintf(r, 9, "%2" CURL_FORMAT_CURL_OFF_T
|
||||
":%02" CURL_FORMAT_CURL_OFF_T
|
||||
":%02" CURL_FORMAT_CURL_OFF_T, h, m, s);
|
||||
}
|
||||
else {
|
||||
/* this equals to more than 99 hours, switch to a more suitable output
|
||||
format to fit within the limits. */
|
||||
curl_off_t d = seconds / 86400;
|
||||
h = (seconds - (d * 86400)) / 3600;
|
||||
if(d <= 999)
|
||||
curl_msnprintf(r, 9, "%3" CURL_FORMAT_CURL_OFF_T
|
||||
"d %02" CURL_FORMAT_CURL_OFF_T "h", d, h);
|
||||
else
|
||||
curl_msnprintf(r, 9, "%7" CURL_FORMAT_CURL_OFF_T "d", d);
|
||||
}
|
||||
}
|
||||
|
||||
static curl_off_t all_dltotal = 0;
|
||||
static curl_off_t all_ultotal = 0;
|
||||
static curl_off_t all_dlalready = 0;
|
||||
static curl_off_t all_ulalready = 0;
|
||||
|
||||
struct speedcount {
|
||||
curl_off_t dl;
|
||||
curl_off_t ul;
|
||||
struct curltime stamp;
|
||||
};
|
||||
#define SPEEDCNT 10
|
||||
static unsigned int speedindex;
|
||||
static bool indexwrapped;
|
||||
static struct speedcount speedstore[SPEEDCNT];
|
||||
|
||||
static void add_offt(curl_off_t *val, curl_off_t add)
|
||||
{
|
||||
if(CURL_OFF_T_MAX - *val < add)
|
||||
/* maxed out! */
|
||||
*val = CURL_OFF_T_MAX;
|
||||
else
|
||||
*val += add;
|
||||
}
|
||||
|
||||
/*
|
||||
|DL% UL% Dled Uled Xfers Live Total Current Left Speed
|
||||
| 6 -- 9.9G 0 2 2 0:00:40 0:00:02 0:00:37 4087M
|
||||
*/
|
||||
bool progress_meter(CURLM *multi,
|
||||
struct curltime *start,
|
||||
bool final)
|
||||
{
|
||||
static struct curltime stamp;
|
||||
static bool header = FALSE;
|
||||
struct curltime now;
|
||||
timediff_t diff;
|
||||
|
||||
if(global->noprogress || global->silent)
|
||||
return FALSE;
|
||||
|
||||
now = curlx_now();
|
||||
diff = curlx_timediff(now, stamp);
|
||||
|
||||
if(!header) {
|
||||
header = TRUE;
|
||||
fputs("DL% UL% Dled Uled Xfers Live "
|
||||
"Total Current Left Speed\n",
|
||||
tool_stderr);
|
||||
}
|
||||
if(final || (diff > 500)) {
|
||||
char time_left[10];
|
||||
char time_total[10];
|
||||
char time_spent[10];
|
||||
char buffer[3][6];
|
||||
curl_off_t spent = curlx_timediff(now, *start)/1000;
|
||||
char dlpercen[4]="--";
|
||||
char ulpercen[4]="--";
|
||||
struct per_transfer *per;
|
||||
curl_off_t all_dlnow = 0;
|
||||
curl_off_t all_ulnow = 0;
|
||||
curl_off_t xfers_added = 0;
|
||||
curl_off_t xfers_running = 0;
|
||||
bool dlknown = TRUE;
|
||||
bool ulknown = TRUE;
|
||||
curl_off_t speed = 0;
|
||||
unsigned int i;
|
||||
stamp = now;
|
||||
|
||||
/* first add the amounts of the already completed transfers */
|
||||
add_offt(&all_dlnow, all_dlalready);
|
||||
add_offt(&all_ulnow, all_ulalready);
|
||||
|
||||
for(per = transfers; per; per = per->next) {
|
||||
add_offt(&all_dlnow, per->dlnow);
|
||||
add_offt(&all_ulnow, per->ulnow);
|
||||
if(!per->dltotal)
|
||||
dlknown = FALSE;
|
||||
else if(!per->dltotal_added) {
|
||||
/* only add this amount once */
|
||||
add_offt(&all_dltotal, per->dltotal);
|
||||
per->dltotal_added = TRUE;
|
||||
}
|
||||
if(!per->ultotal)
|
||||
ulknown = FALSE;
|
||||
else if(!per->ultotal_added) {
|
||||
/* only add this amount once */
|
||||
add_offt(&all_ultotal, per->ultotal);
|
||||
per->ultotal_added = TRUE;
|
||||
}
|
||||
}
|
||||
if(dlknown && all_dltotal)
|
||||
curl_msnprintf(dlpercen, sizeof(dlpercen), "%3" CURL_FORMAT_CURL_OFF_T,
|
||||
all_dlnow < (CURL_OFF_T_MAX/100) ?
|
||||
(all_dlnow * 100 / all_dltotal) :
|
||||
(all_dlnow / (all_dltotal/100)));
|
||||
|
||||
if(ulknown && all_ultotal)
|
||||
curl_msnprintf(ulpercen, sizeof(ulpercen), "%3" CURL_FORMAT_CURL_OFF_T,
|
||||
all_ulnow < (CURL_OFF_T_MAX/100) ?
|
||||
(all_ulnow * 100 / all_ultotal) :
|
||||
(all_ulnow / (all_ultotal/100)));
|
||||
|
||||
/* get the transfer speed, the higher of the two */
|
||||
|
||||
i = speedindex;
|
||||
speedstore[i].dl = all_dlnow;
|
||||
speedstore[i].ul = all_ulnow;
|
||||
speedstore[i].stamp = now;
|
||||
if(++speedindex >= SPEEDCNT) {
|
||||
indexwrapped = TRUE;
|
||||
speedindex = 0;
|
||||
}
|
||||
|
||||
{
|
||||
timediff_t deltams;
|
||||
curl_off_t dl;
|
||||
curl_off_t ul;
|
||||
curl_off_t dls;
|
||||
curl_off_t uls;
|
||||
if(indexwrapped) {
|
||||
/* 'speedindex' is the oldest stored data */
|
||||
deltams = curlx_timediff(now, speedstore[speedindex].stamp);
|
||||
dl = all_dlnow - speedstore[speedindex].dl;
|
||||
ul = all_ulnow - speedstore[speedindex].ul;
|
||||
}
|
||||
else {
|
||||
/* since the beginning */
|
||||
deltams = curlx_timediff(now, *start);
|
||||
dl = all_dlnow;
|
||||
ul = all_ulnow;
|
||||
}
|
||||
if(!deltams) /* no division by zero please */
|
||||
deltams++;
|
||||
dls = (curl_off_t)((double)dl / ((double)deltams/1000.0));
|
||||
uls = (curl_off_t)((double)ul / ((double)deltams/1000.0));
|
||||
speed = dls > uls ? dls : uls;
|
||||
}
|
||||
|
||||
|
||||
if(dlknown && speed) {
|
||||
curl_off_t est = all_dltotal / speed;
|
||||
curl_off_t left = (all_dltotal - all_dlnow) / speed;
|
||||
time2str(time_left, left);
|
||||
time2str(time_total, est);
|
||||
}
|
||||
else {
|
||||
time2str(time_left, 0);
|
||||
time2str(time_total, 0);
|
||||
}
|
||||
time2str(time_spent, spent);
|
||||
|
||||
(void)curl_multi_get_offt(multi, CURLMINFO_XFERS_ADDED, &xfers_added);
|
||||
(void)curl_multi_get_offt(multi, CURLMINFO_XFERS_RUNNING, &xfers_running);
|
||||
curl_mfprintf(tool_stderr,
|
||||
"\r"
|
||||
"%-3s " /* percent downloaded */
|
||||
"%-3s " /* percent uploaded */
|
||||
"%s " /* Dled */
|
||||
"%s " /* Uled */
|
||||
"%5" CURL_FORMAT_CURL_OFF_T " " /* Xfers */
|
||||
"%5" CURL_FORMAT_CURL_OFF_T " " /* Live */
|
||||
" %s " /* Total time */
|
||||
"%s " /* Current time */
|
||||
"%s " /* Time left */
|
||||
"%s " /* Speed */
|
||||
"%5s" /* final newline */,
|
||||
|
||||
dlpercen, /* 3 letters */
|
||||
ulpercen, /* 3 letters */
|
||||
max5data(all_dlnow, buffer[0]),
|
||||
max5data(all_ulnow, buffer[1]),
|
||||
xfers_added,
|
||||
xfers_running,
|
||||
time_total,
|
||||
time_spent,
|
||||
time_left,
|
||||
max5data(speed, buffer[2]), /* speed */
|
||||
final ? "\n" :"");
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void progress_finalize(struct per_transfer *per)
|
||||
{
|
||||
/* get the numbers before this transfer goes away */
|
||||
add_offt(&all_dlalready, per->dlnow);
|
||||
add_offt(&all_ulalready, per->ulnow);
|
||||
if(!per->dltotal_added) {
|
||||
add_offt(&all_dltotal, per->dltotal);
|
||||
per->dltotal_added = TRUE;
|
||||
}
|
||||
if(!per->ultotal_added) {
|
||||
add_offt(&all_ultotal, per->ultotal);
|
||||
per->ultotal_added = TRUE;
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
#ifndef HEADER_CURL_TOOL_PROGRESS_H
|
||||
#define HEADER_CURL_TOOL_PROGRESS_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
int xferinfo_cb(void *clientp,
|
||||
curl_off_t dltotal,
|
||||
curl_off_t dlnow,
|
||||
curl_off_t ultotal,
|
||||
curl_off_t ulnow);
|
||||
|
||||
bool progress_meter(CURLM *multi,
|
||||
struct curltime *start,
|
||||
bool final);
|
||||
void progress_finalize(struct per_transfer *per);
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_PROGRESS_H */
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
#ifndef HEADER_CURL_TOOL_SDECLS_H
|
||||
#define HEADER_CURL_TOOL_SDECLS_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
/*
|
||||
* OutStruct variables keep track of information relative to curl's
|
||||
* output writing, which may take place to a standard stream or a file.
|
||||
*
|
||||
* 'filename' member is either a pointer to a filename string or NULL
|
||||
* when dealing with a standard stream.
|
||||
*
|
||||
* 'alloc_filename' member is TRUE when string pointed by 'filename' has been
|
||||
* dynamically allocated and 'belongs' to this OutStruct, otherwise FALSE.
|
||||
*
|
||||
* 'is_cd_filename' member is TRUE when string pointed by 'filename' has been
|
||||
* set using a server-specified Content-Disposition filename, otherwise FALSE.
|
||||
*
|
||||
* 's_isreg' member is TRUE when output goes to a regular file, this also
|
||||
* implies that output is 'seekable' and 'appendable' and also that member
|
||||
* 'filename' points to filename's string. For any standard stream member
|
||||
* 's_isreg' will be FALSE.
|
||||
*
|
||||
* 'fopened' member is TRUE when output goes to a regular file and it
|
||||
* has been fopen'ed, requiring it to be closed later on. In any other
|
||||
* case this is FALSE.
|
||||
*
|
||||
* 'stream' member is a pointer to a stream controlling object as returned
|
||||
* from a 'fopen' call or a standard stream.
|
||||
*
|
||||
* 'config' member is a pointer to associated 'OperationConfig' struct.
|
||||
*
|
||||
* 'bytes' member represents amount written so far.
|
||||
*
|
||||
* 'init' member holds original file size or offset at which truncation is
|
||||
* taking place. Always zero unless appending to a non-empty regular file.
|
||||
*
|
||||
* [Windows]
|
||||
* 'utf8seq' member holds an incomplete UTF-8 sequence destined for the console
|
||||
* until it can be completed (1-4 bytes) + NUL.
|
||||
*/
|
||||
|
||||
struct OutStruct {
|
||||
char *filename;
|
||||
FILE *stream;
|
||||
curl_off_t bytes;
|
||||
curl_off_t init;
|
||||
#ifdef _WIN32
|
||||
unsigned char utf8seq[5];
|
||||
#endif
|
||||
BIT(alloc_filename);
|
||||
BIT(is_cd_filename);
|
||||
BIT(s_isreg);
|
||||
BIT(fopened);
|
||||
BIT(out_null);
|
||||
};
|
||||
|
||||
/*
|
||||
* A linked list of these 'getout' nodes contain URL's to fetch,
|
||||
* as well as information relative to where URL contents should
|
||||
* be stored or which file should be uploaded.
|
||||
*/
|
||||
|
||||
struct getout {
|
||||
struct getout *next; /* next one */
|
||||
char *url; /* the URL we deal with */
|
||||
char *outfile; /* where to store the output */
|
||||
char *infile; /* file to upload, if GETOUT_UPLOAD is set */
|
||||
curl_off_t num; /* which URL number in an invocation */
|
||||
|
||||
BIT(outset); /* when outfile is set */
|
||||
BIT(urlset); /* when URL is set */
|
||||
BIT(uploadset); /* when -T is set */
|
||||
BIT(useremote); /* use remote filename locally */
|
||||
BIT(noupload); /* if set, -T "" has been used */
|
||||
BIT(noglob); /* disable globbing for this URL */
|
||||
BIT(out_null); /* discard output for this URL */
|
||||
};
|
||||
/*
|
||||
* 'trace' enumeration represents curl's output look'n feel possibilities.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
TRACE_NONE, /* no trace/verbose output at all */
|
||||
TRACE_BIN, /* tcpdump inspired look */
|
||||
TRACE_ASCII, /* like *BIN but without the hex output */
|
||||
TRACE_PLAIN /* -v/--verbose type */
|
||||
} trace;
|
||||
|
||||
|
||||
/*
|
||||
* 'HttpReq' enumeration represents HTTP request types.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
TOOL_HTTPREQ_UNSPEC, /* first in list */
|
||||
TOOL_HTTPREQ_GET,
|
||||
TOOL_HTTPREQ_HEAD,
|
||||
TOOL_HTTPREQ_MIMEPOST,
|
||||
TOOL_HTTPREQ_SIMPLEPOST,
|
||||
TOOL_HTTPREQ_PUT
|
||||
} HttpReq;
|
||||
|
||||
|
||||
/*
|
||||
* Complete struct declarations which have OperationConfig struct members,
|
||||
* just in case this header is directly included in some source file.
|
||||
*/
|
||||
|
||||
#include "tool_cfgable.h"
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_SDECLS_H */
|
||||
+683
@@ -0,0 +1,683 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#ifndef CURL_DISABLE_LIBCURL_OPTION
|
||||
|
||||
#include "tool_cfgable.h"
|
||||
#include "tool_easysrc.h"
|
||||
#include "tool_setopt.h"
|
||||
#include "tool_msgs.h"
|
||||
#include "memdebug.h" /* keep this as LAST include */
|
||||
|
||||
/* Lookup tables for converting setopt values back to symbols */
|
||||
/* For enums, values may be in any order. */
|
||||
/* For bit masks, put combinations first, then single bits, */
|
||||
/* and finally any "NONE" value. */
|
||||
|
||||
#define NV(e) {#e, e}
|
||||
#define NV1(e, v) {#e, (v)}
|
||||
#define NVEND {NULL, 0} /* sentinel to mark end of list */
|
||||
|
||||
const struct NameValue setopt_nv_CURLPROXY[] = {
|
||||
NV(CURLPROXY_HTTP),
|
||||
NV(CURLPROXY_HTTP_1_0),
|
||||
NV(CURLPROXY_HTTPS),
|
||||
NV(CURLPROXY_SOCKS4),
|
||||
NV(CURLPROXY_SOCKS5),
|
||||
NV(CURLPROXY_SOCKS4A),
|
||||
NV(CURLPROXY_SOCKS5_HOSTNAME),
|
||||
NVEND,
|
||||
};
|
||||
|
||||
const struct NameValue setopt_nv_CURL_SOCKS_PROXY[] = {
|
||||
NV(CURLPROXY_SOCKS4),
|
||||
NV(CURLPROXY_SOCKS5),
|
||||
NV(CURLPROXY_SOCKS4A),
|
||||
NV(CURLPROXY_SOCKS5_HOSTNAME),
|
||||
NVEND,
|
||||
};
|
||||
|
||||
const struct NameValueUnsigned setopt_nv_CURLHSTS[] = {
|
||||
NV(CURLHSTS_ENABLE),
|
||||
NVEND,
|
||||
};
|
||||
|
||||
const struct NameValueUnsigned setopt_nv_CURLAUTH[] = {
|
||||
NV(CURLAUTH_ANY), /* combination */
|
||||
NV(CURLAUTH_ANYSAFE), /* combination */
|
||||
NV(CURLAUTH_BASIC),
|
||||
NV(CURLAUTH_DIGEST),
|
||||
NV(CURLAUTH_GSSNEGOTIATE),
|
||||
NV(CURLAUTH_NTLM),
|
||||
NV(CURLAUTH_DIGEST_IE),
|
||||
NV(CURLAUTH_ONLY),
|
||||
NV(CURLAUTH_NONE),
|
||||
NVEND,
|
||||
};
|
||||
|
||||
const struct NameValue setopt_nv_CURL_HTTP_VERSION[] = {
|
||||
NV(CURL_HTTP_VERSION_NONE),
|
||||
NV(CURL_HTTP_VERSION_1_0),
|
||||
NV(CURL_HTTP_VERSION_1_1),
|
||||
NV(CURL_HTTP_VERSION_2_0),
|
||||
NV(CURL_HTTP_VERSION_2TLS),
|
||||
NV(CURL_HTTP_VERSION_3),
|
||||
NV(CURL_HTTP_VERSION_3ONLY),
|
||||
NVEND,
|
||||
};
|
||||
|
||||
const struct NameValue setopt_nv_CURL_SSLVERSION[] = {
|
||||
NV(CURL_SSLVERSION_DEFAULT),
|
||||
NV(CURL_SSLVERSION_TLSv1),
|
||||
NV(CURL_SSLVERSION_SSLv2),
|
||||
NV(CURL_SSLVERSION_SSLv3),
|
||||
NV(CURL_SSLVERSION_TLSv1_0),
|
||||
NV(CURL_SSLVERSION_TLSv1_1),
|
||||
NV(CURL_SSLVERSION_TLSv1_2),
|
||||
NV(CURL_SSLVERSION_TLSv1_3),
|
||||
NVEND,
|
||||
};
|
||||
|
||||
const struct NameValue setopt_nv_CURL_SSLVERSION_MAX[] = {
|
||||
{"", CURL_SSLVERSION_MAX_NONE},
|
||||
NV(CURL_SSLVERSION_MAX_DEFAULT),
|
||||
NV(CURL_SSLVERSION_MAX_TLSv1_0),
|
||||
NV(CURL_SSLVERSION_MAX_TLSv1_1),
|
||||
NV(CURL_SSLVERSION_MAX_TLSv1_2),
|
||||
NV(CURL_SSLVERSION_MAX_TLSv1_3),
|
||||
NVEND,
|
||||
};
|
||||
|
||||
const struct NameValue setopt_nv_CURL_TIMECOND[] = {
|
||||
NV(CURL_TIMECOND_IFMODSINCE),
|
||||
NV(CURL_TIMECOND_IFUNMODSINCE),
|
||||
NV(CURL_TIMECOND_LASTMOD),
|
||||
NV(CURL_TIMECOND_NONE),
|
||||
NVEND,
|
||||
};
|
||||
|
||||
const struct NameValue setopt_nv_CURLFTPSSL_CCC[] = {
|
||||
NV(CURLFTPSSL_CCC_NONE),
|
||||
NV(CURLFTPSSL_CCC_PASSIVE),
|
||||
NV(CURLFTPSSL_CCC_ACTIVE),
|
||||
NVEND,
|
||||
};
|
||||
|
||||
const struct NameValue setopt_nv_CURLUSESSL[] = {
|
||||
NV(CURLUSESSL_NONE),
|
||||
NV(CURLUSESSL_TRY),
|
||||
NV(CURLUSESSL_CONTROL),
|
||||
NV(CURLUSESSL_ALL),
|
||||
NVEND,
|
||||
};
|
||||
|
||||
const struct NameValueUnsigned setopt_nv_CURLSSLOPT[] = {
|
||||
NV(CURLSSLOPT_ALLOW_BEAST),
|
||||
NV(CURLSSLOPT_NO_REVOKE),
|
||||
NV(CURLSSLOPT_NO_PARTIALCHAIN),
|
||||
NV(CURLSSLOPT_REVOKE_BEST_EFFORT),
|
||||
NV(CURLSSLOPT_NATIVE_CA),
|
||||
NV(CURLSSLOPT_AUTO_CLIENT_CERT),
|
||||
NVEND,
|
||||
};
|
||||
|
||||
const struct NameValue setopt_nv_CURL_NETRC[] = {
|
||||
NV(CURL_NETRC_IGNORED),
|
||||
NV(CURL_NETRC_OPTIONAL),
|
||||
NV(CURL_NETRC_REQUIRED),
|
||||
NVEND,
|
||||
};
|
||||
|
||||
const struct NameValue setopt_nv_CURLOPT_FOLLOWLOCATION[] = {
|
||||
NV(0L),
|
||||
NV(CURLFOLLOW_ALL),
|
||||
NV(CURLFOLLOW_OBEYCODE),
|
||||
NV(CURLFOLLOW_FIRSTONLY),
|
||||
NVEND,
|
||||
};
|
||||
|
||||
/* These options have non-zero default values. */
|
||||
static const struct NameValue setopt_nv_CURLNONZERODEFAULTS[] = {
|
||||
NV1(CURLOPT_SSL_VERIFYPEER, 1),
|
||||
NV1(CURLOPT_SSL_VERIFYHOST, 1),
|
||||
NV1(CURLOPT_SSL_ENABLE_NPN, 1),
|
||||
NV1(CURLOPT_SSL_ENABLE_ALPN, 1),
|
||||
NV1(CURLOPT_TCP_NODELAY, 1),
|
||||
NV1(CURLOPT_PROXY_SSL_VERIFYPEER, 1),
|
||||
NV1(CURLOPT_PROXY_SSL_VERIFYHOST, 1),
|
||||
NV1(CURLOPT_SOCKS5_AUTH, 1),
|
||||
NV1(CURLOPT_UPLOAD_FLAGS, CURLULFLAG_SEEN),
|
||||
NVEND
|
||||
};
|
||||
|
||||
/* Escape string to C string syntax. Return NULL if out of memory. */
|
||||
#define MAX_STRING_LENGTH_OUTPUT 2000
|
||||
#define ZERO_TERMINATED -1
|
||||
|
||||
static char *c_escape(const char *str, curl_off_t len)
|
||||
{
|
||||
const char *s;
|
||||
unsigned int cutoff = 0;
|
||||
CURLcode result;
|
||||
struct dynbuf escaped;
|
||||
|
||||
curlx_dyn_init(&escaped, 4 * MAX_STRING_LENGTH_OUTPUT + 3);
|
||||
|
||||
if(len == ZERO_TERMINATED)
|
||||
len = strlen(str);
|
||||
|
||||
if(len > MAX_STRING_LENGTH_OUTPUT) {
|
||||
/* cap ridiculously long strings */
|
||||
len = MAX_STRING_LENGTH_OUTPUT;
|
||||
cutoff = 3;
|
||||
}
|
||||
|
||||
result = curlx_dyn_addn(&escaped, STRCONST(""));
|
||||
for(s = str; !result && len; s++, len--) {
|
||||
/* escape question marks as well, to prevent generating accidental
|
||||
trigraphs */
|
||||
static const char from[] = "\t\r\n?\"\\";
|
||||
static const char to[] = "\\t\\r\\n\\?\\\"\\\\";
|
||||
const char *p = strchr(from, *s);
|
||||
|
||||
if(!p && ISPRINT(*s))
|
||||
continue;
|
||||
|
||||
result = curlx_dyn_addn(&escaped, str, s - str);
|
||||
str = s + 1;
|
||||
|
||||
if(!result) {
|
||||
if(p && *p)
|
||||
result = curlx_dyn_addn(&escaped, to + 2 * (p - from), 2);
|
||||
else {
|
||||
result = curlx_dyn_addf(&escaped,
|
||||
/* Octal escape to avoid >2 digit hex. */
|
||||
(len > 1 && ISXDIGIT(s[1])) ?
|
||||
"\\%03o" : "\\x%02x",
|
||||
(unsigned int) *(const unsigned char *) s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!result)
|
||||
result = curlx_dyn_addn(&escaped, str, s - str);
|
||||
|
||||
if(!result)
|
||||
(void)!curlx_dyn_addn(&escaped, "...", cutoff);
|
||||
|
||||
return curlx_dyn_ptr(&escaped);
|
||||
}
|
||||
|
||||
/* setopt wrapper for enum types */
|
||||
CURLcode tool_setopt_enum(CURL *curl, const char *name, CURLoption tag,
|
||||
const struct NameValue *nvlist, long lval)
|
||||
{
|
||||
CURLcode ret = CURLE_OK;
|
||||
bool skip = FALSE;
|
||||
|
||||
ret = curl_easy_setopt(curl, tag, lval);
|
||||
if(!lval)
|
||||
skip = TRUE;
|
||||
|
||||
if(global->libcurl && !skip && !ret) {
|
||||
/* we only use this for real if --libcurl was used */
|
||||
const struct NameValue *nv = NULL;
|
||||
for(nv = nvlist; nv->name; nv++) {
|
||||
if(nv->value == lval)
|
||||
break; /* found it */
|
||||
}
|
||||
if(!nv->name) {
|
||||
/* If no definition was found, output an explicit value.
|
||||
* This could happen if new values are defined and used
|
||||
* but the NameValue list is not updated. */
|
||||
ret = easysrc_addf(&easysrc_code, "curl_easy_setopt(hnd, %s, %ldL);",
|
||||
name, lval);
|
||||
}
|
||||
else {
|
||||
ret = easysrc_addf(&easysrc_code, "curl_easy_setopt(hnd, %s, (long)%s);",
|
||||
name, nv->name);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
if(ret)
|
||||
warnf("option %s returned error (%d)", name, (int)ret);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* setopt wrapper for CURLOPT_SSLVERSION */
|
||||
CURLcode tool_setopt_SSLVERSION(CURL *curl, const char *name, CURLoption tag,
|
||||
long lval)
|
||||
{
|
||||
CURLcode ret = CURLE_OK;
|
||||
bool skip = FALSE;
|
||||
|
||||
ret = curl_easy_setopt(curl, tag, lval);
|
||||
if(!lval)
|
||||
skip = TRUE;
|
||||
|
||||
if(global->libcurl && !skip && !ret) {
|
||||
/* we only use this for real if --libcurl was used */
|
||||
const struct NameValue *nv = NULL;
|
||||
const struct NameValue *nv2 = NULL;
|
||||
for(nv = setopt_nv_CURL_SSLVERSION; nv->name; nv++) {
|
||||
if(nv->value == (lval & 0xffff))
|
||||
break; /* found it */
|
||||
}
|
||||
for(nv2 = setopt_nv_CURL_SSLVERSION_MAX; nv2->name; nv2++) {
|
||||
if(nv2->value == (lval & ~0xffff))
|
||||
break; /* found it */
|
||||
}
|
||||
if(!nv->name) {
|
||||
/* If no definition was found, output an explicit value.
|
||||
* This could happen if new values are defined and used
|
||||
* but the NameValue list is not updated. */
|
||||
ret = easysrc_addf(&easysrc_code, "curl_easy_setopt(hnd, %s, %ldL);",
|
||||
name, lval);
|
||||
}
|
||||
else {
|
||||
if(nv2->name && *nv2->name)
|
||||
/* if max is set */
|
||||
ret = easysrc_addf(&easysrc_code,
|
||||
"curl_easy_setopt(hnd, %s, (long)(%s | %s));",
|
||||
name, nv->name, nv2->name);
|
||||
else
|
||||
/* without a max */
|
||||
ret = easysrc_addf(&easysrc_code,
|
||||
"curl_easy_setopt(hnd, %s, (long)%s);",
|
||||
name, nv->name);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
if(ret)
|
||||
warnf("option %s returned error (%d)", name, (int)ret);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* setopt wrapper for bitmasks */
|
||||
CURLcode tool_setopt_bitmask(CURL *curl, const char *name, CURLoption tag,
|
||||
const struct NameValueUnsigned *nvlist,
|
||||
long lval)
|
||||
{
|
||||
bool skip = FALSE;
|
||||
CURLcode ret = curl_easy_setopt(curl, tag, lval);
|
||||
if(!lval)
|
||||
skip = TRUE;
|
||||
|
||||
if(global->libcurl && !skip && !ret) {
|
||||
/* we only use this for real if --libcurl was used */
|
||||
char preamble[80];
|
||||
unsigned long rest = (unsigned long)lval;
|
||||
const struct NameValueUnsigned *nv = NULL;
|
||||
curl_msnprintf(preamble, sizeof(preamble),
|
||||
"curl_easy_setopt(hnd, %s, ", name);
|
||||
for(nv = nvlist; nv->name; nv++) {
|
||||
if((nv->value & ~ rest) == 0) {
|
||||
/* all value flags contained in rest */
|
||||
rest &= ~ nv->value; /* remove bits handled here */
|
||||
ret = easysrc_addf(&easysrc_code, "%s(long)%s%s",
|
||||
preamble, nv->name, rest ? " |" : ");");
|
||||
if(!rest || ret)
|
||||
break; /* handled them all */
|
||||
/* replace with all spaces for continuation line */
|
||||
curl_msnprintf(preamble, sizeof(preamble), "%*s",
|
||||
(int)strlen(preamble), "");
|
||||
}
|
||||
}
|
||||
/* If any bits have no definition, output an explicit value.
|
||||
* This could happen if new bits are defined and used
|
||||
* but the NameValue list is not updated. */
|
||||
if(rest && !ret)
|
||||
ret = easysrc_addf(&easysrc_code, "%s%luUL);", preamble, rest);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Generate code for a struct curl_slist. */
|
||||
static CURLcode libcurl_generate_slist(struct curl_slist *slist, int *slistno)
|
||||
{
|
||||
CURLcode ret = CURLE_OK;
|
||||
|
||||
/* May need several slist variables, so invent name */
|
||||
*slistno = ++easysrc_slist_count;
|
||||
|
||||
ret = easysrc_addf(&easysrc_decl, "struct curl_slist *slist%d;", *slistno);
|
||||
if(!ret)
|
||||
ret = easysrc_addf(&easysrc_data, "slist%d = NULL;", *slistno);
|
||||
if(!ret)
|
||||
ret = easysrc_addf(&easysrc_clean, "curl_slist_free_all(slist%d);",
|
||||
*slistno);
|
||||
if(!ret)
|
||||
ret = easysrc_addf(&easysrc_clean, "slist%d = NULL;", *slistno);
|
||||
if(ret)
|
||||
return ret;
|
||||
for(; slist && !ret; slist = slist->next) {
|
||||
char *escaped = c_escape(slist->data, ZERO_TERMINATED);
|
||||
if(!escaped)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
ret = easysrc_addf(&easysrc_data,
|
||||
"slist%d = curl_slist_append(slist%d, \"%s\");",
|
||||
*slistno, *slistno, escaped);
|
||||
free(escaped);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static CURLcode libcurl_generate_mime(CURL *curl,
|
||||
struct OperationConfig *config,
|
||||
struct tool_mime *toolmime,
|
||||
int *mimeno); /* Forward. */
|
||||
|
||||
/* Wrapper to generate source code for a mime part. */
|
||||
static CURLcode libcurl_generate_mime_part(CURL *curl,
|
||||
struct OperationConfig *config,
|
||||
struct tool_mime *part,
|
||||
int mimeno)
|
||||
{
|
||||
CURLcode ret = CURLE_OK;
|
||||
int submimeno = 0;
|
||||
const char *data = NULL;
|
||||
const char *filename = part->filename;
|
||||
|
||||
/* Parts are linked in reverse order. */
|
||||
if(part->prev)
|
||||
ret = libcurl_generate_mime_part(curl, config, part->prev, mimeno);
|
||||
|
||||
/* Create the part. */
|
||||
if(!ret)
|
||||
ret = easysrc_addf(&easysrc_code, "part%d = curl_mime_addpart(mime%d);",
|
||||
mimeno, mimeno);
|
||||
if(ret)
|
||||
return ret;
|
||||
|
||||
switch(part->kind) {
|
||||
case TOOLMIME_PARTS:
|
||||
ret = libcurl_generate_mime(curl, config, part, &submimeno);
|
||||
if(!ret) {
|
||||
ret = easysrc_addf(&easysrc_code, "curl_mime_subparts(part%d, mime%d);",
|
||||
mimeno, submimeno);
|
||||
if(!ret)
|
||||
/* Avoid freeing in CLEAN. */
|
||||
ret = easysrc_addf(&easysrc_code,
|
||||
"mime%d = NULL;", submimeno);
|
||||
}
|
||||
break;
|
||||
|
||||
case TOOLMIME_DATA:
|
||||
data = part->data;
|
||||
if(!ret) {
|
||||
char *escaped = c_escape(data, ZERO_TERMINATED);
|
||||
ret =
|
||||
easysrc_addf(&easysrc_code,
|
||||
"curl_mime_data(part%d, \"%s\", CURL_ZERO_TERMINATED);",
|
||||
mimeno, escaped);
|
||||
free(escaped);
|
||||
}
|
||||
break;
|
||||
|
||||
case TOOLMIME_FILE:
|
||||
case TOOLMIME_FILEDATA: {
|
||||
char *escaped = c_escape(part->data, ZERO_TERMINATED);
|
||||
ret = easysrc_addf(&easysrc_code,
|
||||
"curl_mime_filedata(part%d, \"%s\");", mimeno, escaped);
|
||||
if(part->kind == TOOLMIME_FILEDATA && !filename && !ret) {
|
||||
ret = easysrc_addf(&easysrc_code,
|
||||
"curl_mime_filename(part%d, NULL);", mimeno);
|
||||
}
|
||||
free(escaped);
|
||||
break;
|
||||
}
|
||||
|
||||
case TOOLMIME_STDIN:
|
||||
if(!filename)
|
||||
filename = "-";
|
||||
FALLTHROUGH();
|
||||
case TOOLMIME_STDINDATA:
|
||||
/* Can only be reading stdin in the current context. */
|
||||
ret = easysrc_addf(&easysrc_code, "curl_mime_data_cb(part%d, -1, "
|
||||
"(curl_read_callback) fread, \\", mimeno);
|
||||
if(!ret)
|
||||
ret = easysrc_addf(&easysrc_code, " "
|
||||
"(curl_seek_callback) fseek, NULL, stdin);");
|
||||
break;
|
||||
default:
|
||||
/* Other cases not possible in this context. */
|
||||
break;
|
||||
}
|
||||
|
||||
if(!ret && part->encoder) {
|
||||
char *escaped = c_escape(part->encoder, ZERO_TERMINATED);
|
||||
ret = easysrc_addf(&easysrc_code, "curl_mime_encoder(part%d, \"%s\");",
|
||||
mimeno, escaped);
|
||||
free(escaped);
|
||||
}
|
||||
|
||||
if(!ret && filename) {
|
||||
char *escaped = c_escape(filename, ZERO_TERMINATED);
|
||||
ret = easysrc_addf(&easysrc_code, "curl_mime_filename(part%d, \"%s\");",
|
||||
mimeno, escaped);
|
||||
free(escaped);
|
||||
}
|
||||
|
||||
if(!ret && part->name) {
|
||||
char *escaped = c_escape(part->name, ZERO_TERMINATED);
|
||||
ret = easysrc_addf(&easysrc_code, "curl_mime_name(part%d, \"%s\");",
|
||||
mimeno, escaped);
|
||||
free(escaped);
|
||||
}
|
||||
|
||||
if(!ret && part->type) {
|
||||
char *escaped = c_escape(part->type, ZERO_TERMINATED);
|
||||
ret = easysrc_addf(&easysrc_code, "curl_mime_type(part%d, \"%s\");",
|
||||
mimeno, escaped);
|
||||
free(escaped);
|
||||
}
|
||||
|
||||
if(!ret && part->headers) {
|
||||
int slistno;
|
||||
|
||||
ret = libcurl_generate_slist(part->headers, &slistno);
|
||||
if(!ret) {
|
||||
ret = easysrc_addf(&easysrc_code,
|
||||
"curl_mime_headers(part%d, slist%d, 1);",
|
||||
mimeno, slistno);
|
||||
if(!ret)
|
||||
ret = easysrc_addf(&easysrc_code, "slist%d = NULL;", slistno);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Wrapper to generate source code for a mime structure. */
|
||||
static CURLcode libcurl_generate_mime(CURL *curl,
|
||||
struct OperationConfig *config,
|
||||
struct tool_mime *toolmime,
|
||||
int *mimeno)
|
||||
{
|
||||
CURLcode ret = CURLE_OK;
|
||||
|
||||
/* May need several mime variables, so invent name. */
|
||||
*mimeno = ++easysrc_mime_count;
|
||||
ret = easysrc_addf(&easysrc_decl, "curl_mime *mime%d;", *mimeno);
|
||||
if(!ret)
|
||||
ret = easysrc_addf(&easysrc_data, "mime%d = NULL;", *mimeno);
|
||||
if(!ret)
|
||||
ret = easysrc_addf(&easysrc_code, "mime%d = curl_mime_init(hnd);",
|
||||
*mimeno);
|
||||
if(!ret)
|
||||
ret = easysrc_addf(&easysrc_clean, "curl_mime_free(mime%d);", *mimeno);
|
||||
if(!ret)
|
||||
ret = easysrc_addf(&easysrc_clean, "mime%d = NULL;", *mimeno);
|
||||
|
||||
if(toolmime->subparts && !ret) {
|
||||
ret = easysrc_addf(&easysrc_decl, "curl_mimepart *part%d;", *mimeno);
|
||||
if(!ret)
|
||||
ret = libcurl_generate_mime_part(curl, config,
|
||||
toolmime->subparts, *mimeno);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* setopt wrapper for CURLOPT_MIMEPOST */
|
||||
CURLcode tool_setopt_mimepost(CURL *curl, struct OperationConfig *config,
|
||||
const char *name, CURLoption tag,
|
||||
curl_mime *mimepost)
|
||||
{
|
||||
CURLcode ret = curl_easy_setopt(curl, tag, mimepost);
|
||||
int mimeno = 0;
|
||||
|
||||
if(!ret && global->libcurl) {
|
||||
ret = libcurl_generate_mime(curl, config, config->mimeroot, &mimeno);
|
||||
|
||||
if(!ret)
|
||||
ret = easysrc_addf(&easysrc_code, "curl_easy_setopt(hnd, %s, mime%d);",
|
||||
name, mimeno);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* setopt wrapper for curl_slist options */
|
||||
CURLcode tool_setopt_slist(CURL *curl, const char *name, CURLoption tag,
|
||||
struct curl_slist *list)
|
||||
{
|
||||
CURLcode ret = CURLE_OK;
|
||||
|
||||
ret = curl_easy_setopt(curl, tag, list);
|
||||
|
||||
if(global->libcurl && list && !ret) {
|
||||
int i;
|
||||
|
||||
ret = libcurl_generate_slist(list, &i);
|
||||
if(!ret)
|
||||
ret = easysrc_addf(&easysrc_code, "curl_easy_setopt(hnd, %s, slist%d);",
|
||||
name, i);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* options that set long */
|
||||
CURLcode tool_setopt_long(CURL *curl, const char *name, CURLoption tag,
|
||||
long lval)
|
||||
{
|
||||
long defval = 0L;
|
||||
const struct NameValue *nv = NULL;
|
||||
CURLcode ret = CURLE_OK;
|
||||
DEBUGASSERT(tag < CURLOPTTYPE_OBJECTPOINT);
|
||||
|
||||
for(nv = setopt_nv_CURLNONZERODEFAULTS; nv->name; nv++) {
|
||||
if(!strcmp(name, nv->name)) {
|
||||
defval = nv->value;
|
||||
break; /* found it */
|
||||
}
|
||||
}
|
||||
|
||||
ret = curl_easy_setopt(curl, tag, lval);
|
||||
if((lval != defval) && global->libcurl && !ret) {
|
||||
/* we only use this for real if --libcurl was used */
|
||||
ret = easysrc_addf(&easysrc_code, "curl_easy_setopt(hnd, %s, %ldL);",
|
||||
name, lval);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* options that set curl_off_t */
|
||||
CURLcode tool_setopt_offt(CURL *curl, const char *name, CURLoption tag,
|
||||
curl_off_t lval)
|
||||
{
|
||||
CURLcode ret = CURLE_OK;
|
||||
DEBUGASSERT((tag >= CURLOPTTYPE_OFF_T) && (tag < CURLOPTTYPE_BLOB));
|
||||
|
||||
ret = curl_easy_setopt(curl, tag, lval);
|
||||
if(global->libcurl && !ret && lval) {
|
||||
/* we only use this for real if --libcurl was used */
|
||||
ret = easysrc_addf(&easysrc_code, "curl_easy_setopt(hnd, %s, (curl_off_t)%"
|
||||
CURL_FORMAT_CURL_OFF_T ");", name, lval);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* setopt wrapper for setting object and function pointer options */
|
||||
CURLcode tool_setopt(CURL *curl, struct OperationConfig *config,
|
||||
bool str, const char *name, CURLoption tag,
|
||||
...)
|
||||
{
|
||||
va_list arg;
|
||||
CURLcode ret = CURLE_OK;
|
||||
void *pval;
|
||||
|
||||
va_start(arg, tag);
|
||||
|
||||
DEBUGASSERT(tag >= CURLOPTTYPE_OBJECTPOINT);
|
||||
DEBUGASSERT((tag < CURLOPTTYPE_OFF_T) || (tag >= CURLOPTTYPE_BLOB));
|
||||
|
||||
/* we never set _BLOB options in the curl tool */
|
||||
DEBUGASSERT(tag < CURLOPTTYPE_BLOB);
|
||||
|
||||
/* argument is an object or function pointer */
|
||||
pval = va_arg(arg, void *);
|
||||
|
||||
ret = curl_easy_setopt(curl, tag, pval);
|
||||
|
||||
va_end(arg);
|
||||
|
||||
if(global->libcurl && pval && !ret) {
|
||||
/* we only use this if --libcurl was used */
|
||||
|
||||
if(!str) {
|
||||
/* function pointers are never printable */
|
||||
const char *remark = (tag >= CURLOPTTYPE_FUNCTIONPOINT) ?
|
||||
"function" : "object";
|
||||
ret = easysrc_addf(&easysrc_toohard,
|
||||
"%s was set to a%s %s pointer", name,
|
||||
(*remark == 'o' ? "n" : ""), remark);
|
||||
}
|
||||
else {
|
||||
curl_off_t len = ZERO_TERMINATED;
|
||||
char *escaped;
|
||||
if(tag == CURLOPT_POSTFIELDS)
|
||||
len = curlx_dyn_len(&config->postdata);
|
||||
escaped = c_escape(pval, len);
|
||||
if(escaped) {
|
||||
ret = easysrc_addf(&easysrc_code, "curl_easy_setopt(hnd, %s, \"%s\");",
|
||||
name, escaped);
|
||||
free(escaped);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* CURL_DISABLE_LIBCURL_OPTION */
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
#ifndef HEADER_CURL_TOOL_SETOPT_H
|
||||
#define HEADER_CURL_TOOL_SETOPT_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#include "tool_formparse.h"
|
||||
|
||||
/*
|
||||
* Macros used in operate()
|
||||
*/
|
||||
|
||||
#ifndef CURL_DISABLE_LIBCURL_OPTION
|
||||
|
||||
/* Associate symbolic names with option values */
|
||||
struct NameValue {
|
||||
const char *name;
|
||||
long value;
|
||||
};
|
||||
|
||||
struct NameValueUnsigned {
|
||||
const char *name;
|
||||
unsigned long value;
|
||||
};
|
||||
|
||||
extern const struct NameValue setopt_nv_CURLPROXY[];
|
||||
extern const struct NameValue setopt_nv_CURL_SOCKS_PROXY[];
|
||||
extern const struct NameValue setopt_nv_CURL_HTTP_VERSION[];
|
||||
extern const struct NameValue setopt_nv_CURL_SSLVERSION[];
|
||||
extern const struct NameValue setopt_nv_CURL_SSLVERSION_MAX[];
|
||||
extern const struct NameValue setopt_nv_CURL_TIMECOND[];
|
||||
extern const struct NameValue setopt_nv_CURLFTPSSL_CCC[];
|
||||
extern const struct NameValue setopt_nv_CURLUSESSL[];
|
||||
extern const struct NameValueUnsigned setopt_nv_CURLSSLOPT[];
|
||||
extern const struct NameValue setopt_nv_CURL_NETRC[];
|
||||
extern const struct NameValue setopt_nv_CURLOPT_FOLLOWLOCATION[];
|
||||
extern const struct NameValueUnsigned setopt_nv_CURLAUTH[];
|
||||
extern const struct NameValueUnsigned setopt_nv_CURLHSTS[];
|
||||
|
||||
/* Map options to NameValue sets */
|
||||
#define setopt_nv_CURLOPT_HSTS_CTRL setopt_nv_CURLHSTS
|
||||
#define setopt_nv_CURLOPT_HTTP_VERSION setopt_nv_CURL_HTTP_VERSION
|
||||
#define setopt_nv_CURLOPT_HTTPAUTH setopt_nv_CURLAUTH
|
||||
#define setopt_nv_CURLOPT_SSLVERSION setopt_nv_CURL_SSLVERSION
|
||||
#define setopt_nv_CURLOPT_PROXY_SSLVERSION setopt_nv_CURL_SSLVERSION
|
||||
#define setopt_nv_CURLOPT_TIMECONDITION setopt_nv_CURL_TIMECOND
|
||||
#define setopt_nv_CURLOPT_FTP_SSL_CCC setopt_nv_CURLFTPSSL_CCC
|
||||
#define setopt_nv_CURLOPT_USE_SSL setopt_nv_CURLUSESSL
|
||||
#define setopt_nv_CURLOPT_SSL_OPTIONS setopt_nv_CURLSSLOPT
|
||||
#define setopt_nv_CURLOPT_PROXY_SSL_OPTIONS setopt_nv_CURLSSLOPT
|
||||
#define setopt_nv_CURLOPT_NETRC setopt_nv_CURL_NETRC
|
||||
#define setopt_nv_CURLOPT_PROXYTYPE setopt_nv_CURLPROXY
|
||||
#define setopt_nv_CURLOPT_PROXYAUTH setopt_nv_CURLAUTH
|
||||
#define setopt_nv_CURLOPT_SOCKS5_AUTH setopt_nv_CURLAUTH
|
||||
|
||||
/* Intercept setopt calls for --libcurl */
|
||||
|
||||
CURLcode tool_setopt_enum(CURL *curl, const char *name, CURLoption tag,
|
||||
const struct NameValue *nv, long lval);
|
||||
CURLcode tool_setopt_SSLVERSION(CURL *curl, const char *name, CURLoption tag,
|
||||
long lval);
|
||||
CURLcode tool_setopt_flags(CURL *curl, struct OperationConfig *config,
|
||||
const char *name, CURLoption tag,
|
||||
const struct NameValue *nv, long lval);
|
||||
CURLcode tool_setopt_bitmask(CURL *curl,
|
||||
const char *name, CURLoption tag,
|
||||
const struct NameValueUnsigned *nv, long lval);
|
||||
CURLcode tool_setopt_mimepost(CURL *curl, struct OperationConfig *config,
|
||||
const char *name, CURLoption tag,
|
||||
curl_mime *mimepost);
|
||||
CURLcode tool_setopt_slist(CURL *curl, const char *name, CURLoption tag,
|
||||
struct curl_slist *list);
|
||||
CURLcode tool_setopt_long(CURL *curl, const char *name, CURLoption tag,
|
||||
long lval);
|
||||
CURLcode tool_setopt_offt(CURL *curl, const char *name, CURLoption tag,
|
||||
curl_off_t lval);
|
||||
CURLcode tool_setopt(CURL *curl, struct OperationConfig *config,
|
||||
bool str, const char *name, CURLoption tag,
|
||||
...);
|
||||
|
||||
#define my_setopt(x,y,z) \
|
||||
tool_setopt(x, config, FALSE, #y, y, z)
|
||||
|
||||
#define my_setopt_long(x,y,z) \
|
||||
tool_setopt_long(x, #y, y, z)
|
||||
|
||||
#define my_setopt_offt(x,y,z) \
|
||||
tool_setopt_offt(x, #y, y, z)
|
||||
|
||||
#define my_setopt_str(x,y,z) \
|
||||
tool_setopt(x, config, TRUE, #y, y, z)
|
||||
|
||||
#define my_setopt_enum(x,y,z) \
|
||||
tool_setopt_enum(x, #y, y, setopt_nv_ ## y, z)
|
||||
|
||||
#define my_setopt_SSLVERSION(x,y,z) \
|
||||
tool_setopt_SSLVERSION(x, #y, y, z)
|
||||
|
||||
#define my_setopt_bitmask(x,y,z) \
|
||||
tool_setopt_bitmask(x, #y, y, setopt_nv_ ## y, z)
|
||||
|
||||
#define my_setopt_mimepost(x,y,z) \
|
||||
tool_setopt_mimepost(x, config, #y, y, z)
|
||||
|
||||
#define my_setopt_slist(x,y,z) \
|
||||
tool_setopt_slist(x, #y, y, z)
|
||||
|
||||
#else /* CURL_DISABLE_LIBCURL_OPTION */
|
||||
|
||||
/* No --libcurl, so pass options directly to library */
|
||||
|
||||
#define my_setopt(x,y,z) \
|
||||
curl_easy_setopt(x, y, z)
|
||||
|
||||
#define my_setopt_long(x,y,z) \
|
||||
curl_easy_setopt(x, y, (long)(z))
|
||||
|
||||
#define my_setopt_offt(x,y,z) \
|
||||
curl_easy_setopt(x, y, (curl_off_t)(z))
|
||||
|
||||
#define my_setopt_str(x,y,z) \
|
||||
curl_easy_setopt(x, y, z)
|
||||
|
||||
#define my_setopt_enum(x,y,z) \
|
||||
curl_easy_setopt(x, y, z)
|
||||
|
||||
#define my_setopt_SSLVERSION(x,y,z) \
|
||||
curl_easy_setopt(x, y, z)
|
||||
|
||||
#define my_setopt_bitmask(x,y,z) \
|
||||
curl_easy_setopt(x, y, (long)z)
|
||||
|
||||
#define my_setopt_mimepost(x,y,z) \
|
||||
curl_easy_setopt(x, y, z)
|
||||
|
||||
#define my_setopt_slist(x,y,z) \
|
||||
curl_easy_setopt(x, y, z)
|
||||
|
||||
#endif /* CURL_DISABLE_LIBCURL_OPTION */
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_SETOPT_H */
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
#ifndef HEADER_CURL_TOOL_SETUP_H
|
||||
#define HEADER_CURL_TOOL_SETUP_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef CURL_NO_OLDIES
|
||||
#define CURL_NO_OLDIES
|
||||
#endif
|
||||
|
||||
/*
|
||||
* curl_setup.h may define preprocessor macros such as _FILE_OFFSET_BITS and
|
||||
* _LARGE_FILES in order to support files larger than 2 GB. On platforms
|
||||
* where this happens it is mandatory that these macros are defined before
|
||||
* any system header file is included, otherwise file handling function
|
||||
* prototypes will be misdeclared and curl tool may not build properly;
|
||||
* therefore we must include curl_setup.h before curl.h when building curl.
|
||||
*/
|
||||
|
||||
#include "curl_setup.h" /* from the lib directory */
|
||||
|
||||
extern FILE *tool_stderr;
|
||||
|
||||
/*
|
||||
* curl tool certainly uses libcurl's external interface.
|
||||
*/
|
||||
|
||||
#include <curl/curl.h> /* external interface */
|
||||
|
||||
#include <curlx/curlx.h>
|
||||
|
||||
/*
|
||||
* Platform specific stuff.
|
||||
*/
|
||||
|
||||
#ifdef macintosh
|
||||
# define main(x,y) curl_main(x,y)
|
||||
#endif
|
||||
|
||||
#ifndef CURL_OS
|
||||
#define CURL_OS "unknown"
|
||||
#endif
|
||||
|
||||
#ifndef UNPRINTABLE_CHAR
|
||||
/* define what to use for unprintable characters */
|
||||
#define UNPRINTABLE_CHAR '.'
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRDUP
|
||||
#include "tool_strdup.h"
|
||||
#endif
|
||||
|
||||
#ifndef tool_nop_stmt
|
||||
#define tool_nop_stmt do { } while(0)
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
# define CURL_STRICMP(p1, p2) _stricmp(p1, p2)
|
||||
#elif defined(HAVE_STRCASECMP)
|
||||
# ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
# endif
|
||||
# define CURL_STRICMP(p1, p2) strcasecmp(p1, p2)
|
||||
#elif defined(HAVE_STRCMPI)
|
||||
# define CURL_STRICMP(p1, p2) strcmpi(p1, p2)
|
||||
#elif defined(HAVE_STRICMP)
|
||||
# define CURL_STRICMP(p1, p2) stricmp(p1, p2)
|
||||
#else
|
||||
# define CURL_STRICMP(p1, p2) strcmp(p1, p2)
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
/* set in init_terminal() */
|
||||
extern bool tool_term_has_bold;
|
||||
|
||||
#ifdef UNDER_CE
|
||||
# undef isatty
|
||||
# define isatty(fd) 0 /* fd is void*, expects int */
|
||||
# undef _get_osfhandle
|
||||
# define _get_osfhandle(fd) (fd)
|
||||
# undef _getch
|
||||
# define _getch() 0
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_FTRUNCATE
|
||||
|
||||
int tool_ftruncate64(int fd, curl_off_t where);
|
||||
|
||||
#undef ftruncate
|
||||
#define ftruncate(fd,where) tool_ftruncate64(fd,where)
|
||||
|
||||
#define HAVE_FTRUNCATE 1
|
||||
#define USE_TOOL_FTRUNCATE 1
|
||||
|
||||
#endif /* ! HAVE_FTRUNCATE */
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_SETUP_H */
|
||||
Vendored
+212
@@ -0,0 +1,212 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#include "tool_cfgable.h"
|
||||
#include "tool_cb_dbg.h"
|
||||
#include "tool_msgs.h"
|
||||
#include "tool_setopt.h"
|
||||
#include "tool_ssls.h"
|
||||
#include "tool_parsecfg.h"
|
||||
|
||||
/* The maximum line length for an ecoded session ticket */
|
||||
#define MAX_SSLS_LINE (64 * 1024)
|
||||
|
||||
|
||||
static CURLcode tool_ssls_easy(struct OperationConfig *config,
|
||||
CURLSH *share, CURL **peasy)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
*peasy = curl_easy_init();
|
||||
if(!*peasy)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
result = curl_easy_setopt(*peasy, CURLOPT_SHARE, share);
|
||||
if(!result && (global->tracetype != TRACE_NONE)) {
|
||||
my_setopt(*peasy, CURLOPT_DEBUGFUNCTION, tool_debug_cb);
|
||||
my_setopt(*peasy, CURLOPT_DEBUGDATA, config);
|
||||
my_setopt_long(*peasy, CURLOPT_VERBOSE, 1L);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
CURLcode tool_ssls_load(struct OperationConfig *config,
|
||||
CURLSH *share, const char *filename)
|
||||
{
|
||||
FILE *fp;
|
||||
CURL *easy = NULL;
|
||||
struct dynbuf buf;
|
||||
unsigned char *shmac = NULL, *sdata = NULL;
|
||||
char *c, *line, *end;
|
||||
size_t shmac_len, sdata_len;
|
||||
CURLcode r = CURLE_OK;
|
||||
int i, imported;
|
||||
bool error = FALSE;
|
||||
|
||||
curlx_dyn_init(&buf, MAX_SSLS_LINE);
|
||||
fp = curlx_fopen(filename, FOPEN_READTEXT);
|
||||
if(!fp) { /* ok if it does not exist */
|
||||
notef("SSL session file does not exist (yet?): %s", filename);
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = tool_ssls_easy(config, share, &easy);
|
||||
if(r)
|
||||
goto out;
|
||||
|
||||
i = imported = 0;
|
||||
while(my_get_line(fp, &buf, &error)) {
|
||||
++i;
|
||||
curl_free(shmac);
|
||||
curl_free(sdata);
|
||||
line = curlx_dyn_ptr(&buf);
|
||||
|
||||
c = memchr(line, ':', strlen(line));
|
||||
if(!c) {
|
||||
warnf("unrecognized line %d in ssl session file %s", i, filename);
|
||||
continue;
|
||||
}
|
||||
*c = '\0';
|
||||
r = curlx_base64_decode(line, &shmac, &shmac_len);
|
||||
if(r) {
|
||||
warnf("invalid shmax base64 encoding in line %d", i);
|
||||
continue;
|
||||
}
|
||||
line = c + 1;
|
||||
end = line + strlen(line) - 1;
|
||||
while((end > line) && (*end == '\n' || *end == '\r' || ISBLANK(*line))) {
|
||||
*end = '\0';
|
||||
--end;
|
||||
}
|
||||
r = curlx_base64_decode(line, &sdata, &sdata_len);
|
||||
if(r) {
|
||||
warnf("invalid sdata base64 encoding in line %d: %s", i, line);
|
||||
continue;
|
||||
}
|
||||
|
||||
r = curl_easy_ssls_import(easy, NULL, shmac, shmac_len, sdata, sdata_len);
|
||||
if(r) {
|
||||
warnf("import of session from line %d rejected(%d)", i, r);
|
||||
continue;
|
||||
}
|
||||
++imported;
|
||||
}
|
||||
if(error)
|
||||
r = CURLE_FAILED_INIT;
|
||||
else
|
||||
r = CURLE_OK;
|
||||
|
||||
out:
|
||||
if(easy)
|
||||
curl_easy_cleanup(easy);
|
||||
if(fp)
|
||||
curlx_fclose(fp);
|
||||
curlx_dyn_free(&buf);
|
||||
curl_free(shmac);
|
||||
curl_free(sdata);
|
||||
return r;
|
||||
}
|
||||
|
||||
struct tool_ssls_ctx {
|
||||
FILE *fp;
|
||||
int exported;
|
||||
};
|
||||
|
||||
static CURLcode tool_ssls_exp(CURL *easy, void *userptr,
|
||||
const char *session_key,
|
||||
const unsigned char *shmac, size_t shmac_len,
|
||||
const unsigned char *sdata, size_t sdata_len,
|
||||
curl_off_t valid_until, int ietf_tls_id,
|
||||
const char *alpn, size_t earlydata_max)
|
||||
{
|
||||
struct tool_ssls_ctx *ctx = userptr;
|
||||
char *enc = NULL;
|
||||
size_t enc_len;
|
||||
CURLcode r;
|
||||
|
||||
(void)easy;
|
||||
(void)valid_until;
|
||||
(void)ietf_tls_id;
|
||||
(void)alpn;
|
||||
(void)earlydata_max;
|
||||
if(!ctx->exported)
|
||||
fputs("# Your SSL session cache. https://curl.se/docs/ssl-sessions.html\n"
|
||||
"# This file was generated by libcurl! Edit at your own risk.\n",
|
||||
ctx->fp);
|
||||
|
||||
r = curlx_base64_encode((const char *)shmac, shmac_len, &enc, &enc_len);
|
||||
if(r)
|
||||
goto out;
|
||||
r = CURLE_WRITE_ERROR;
|
||||
if(enc_len != fwrite(enc, 1, enc_len, ctx->fp))
|
||||
goto out;
|
||||
if(EOF == fputc(':', ctx->fp))
|
||||
goto out;
|
||||
curl_free(enc);
|
||||
r = curlx_base64_encode((const char *)sdata, sdata_len, &enc, &enc_len);
|
||||
if(r)
|
||||
goto out;
|
||||
r = CURLE_WRITE_ERROR;
|
||||
if(enc_len != fwrite(enc, 1, enc_len, ctx->fp))
|
||||
goto out;
|
||||
if(EOF == fputc('\n', ctx->fp))
|
||||
goto out;
|
||||
r = CURLE_OK;
|
||||
ctx->exported++;
|
||||
out:
|
||||
if(r)
|
||||
warnf("Warning: error saving SSL session for '%s': %d", session_key, r);
|
||||
curl_free(enc);
|
||||
return r;
|
||||
}
|
||||
|
||||
CURLcode tool_ssls_save(struct OperationConfig *config,
|
||||
CURLSH *share, const char *filename)
|
||||
{
|
||||
struct tool_ssls_ctx ctx;
|
||||
CURL *easy = NULL;
|
||||
CURLcode r = CURLE_OK;
|
||||
|
||||
ctx.exported = 0;
|
||||
ctx.fp = curlx_fopen(filename, FOPEN_WRITETEXT);
|
||||
if(!ctx.fp) {
|
||||
warnf("Warning: Failed to create SSL session file %s",
|
||||
filename);
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = tool_ssls_easy(config, share, &easy);
|
||||
if(r)
|
||||
goto out;
|
||||
|
||||
r = curl_easy_ssls_export(easy, tool_ssls_exp, &ctx);
|
||||
|
||||
out:
|
||||
if(easy)
|
||||
curl_easy_cleanup(easy);
|
||||
if(ctx.fp)
|
||||
curlx_fclose(ctx.fp);
|
||||
return r;
|
||||
}
|
||||
Vendored
+35
@@ -0,0 +1,35 @@
|
||||
#ifndef HEADER_CURL_TOOL_SSLS_H
|
||||
#define HEADER_CURL_TOOL_SSLS_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
#include "tool_operate.h"
|
||||
|
||||
|
||||
CURLcode tool_ssls_load(struct OperationConfig *config,
|
||||
CURLSH *share, const char *filename);
|
||||
CURLcode tool_ssls_save(struct OperationConfig *config,
|
||||
CURLSH *share, const char *filename);
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_SSLS_H */
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include "tool_setup.h"
|
||||
#include "tool_stderr.h"
|
||||
#include "tool_msgs.h"
|
||||
|
||||
#include "memdebug.h" /* keep this as LAST include */
|
||||
|
||||
FILE *tool_stderr;
|
||||
|
||||
void tool_init_stderr(void)
|
||||
{
|
||||
/* !checksrc! disable STDERR 1 */
|
||||
tool_stderr = stderr;
|
||||
}
|
||||
|
||||
void tool_set_stderr_file(const char *filename)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
if(!filename)
|
||||
return;
|
||||
|
||||
if(!strcmp(filename, "-")) {
|
||||
tool_stderr = stdout;
|
||||
return;
|
||||
}
|
||||
|
||||
/* precheck that filename is accessible to lessen the chance that the
|
||||
subsequent freopen will fail. */
|
||||
fp = curlx_fopen(filename, FOPEN_WRITETEXT);
|
||||
if(!fp) {
|
||||
warnf("Warning: Failed to open %s", filename);
|
||||
return;
|
||||
}
|
||||
curlx_fclose(fp);
|
||||
|
||||
/* freopen the actual stderr (stdio.h stderr) instead of tool_stderr since
|
||||
the latter may be set to stdout. */
|
||||
/* !checksrc! disable STDERR 1 */
|
||||
fp = freopen(filename, FOPEN_WRITETEXT, stderr);
|
||||
if(!fp) {
|
||||
/* stderr may have been closed by freopen. there is nothing to be done. */
|
||||
DEBUGASSERT(0);
|
||||
return;
|
||||
}
|
||||
/* !checksrc! disable STDERR 1 */
|
||||
tool_stderr = stderr;
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
#ifndef HEADER_CURL_TOOL_STDERR_H
|
||||
#define HEADER_CURL_TOOL_STDERR_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
#include "tool_cfgable.h"
|
||||
|
||||
void tool_init_stderr(void);
|
||||
void tool_set_stderr_file(const char *filename);
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_STDERR_H */
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_strdup.h"
|
||||
#include "memdebug.h" /* keep this as LAST include */
|
||||
|
||||
#ifndef HAVE_STRDUP
|
||||
char *strdup(const char *str)
|
||||
{
|
||||
size_t len;
|
||||
char *newstr;
|
||||
|
||||
if(!str)
|
||||
return (char *)NULL;
|
||||
|
||||
len = strlen(str) + 1;
|
||||
|
||||
newstr = malloc(len);
|
||||
if(!newstr)
|
||||
return (char *)NULL;
|
||||
|
||||
memcpy(newstr, str, len);
|
||||
return newstr;
|
||||
}
|
||||
#endif
|
||||
|
||||
char *memdup0(const char *data, size_t len)
|
||||
{
|
||||
char *p = malloc(len + 1);
|
||||
if(!p)
|
||||
return NULL;
|
||||
if(len)
|
||||
memcpy(p, data, len);
|
||||
p[len] = 0;
|
||||
return p;
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
#ifndef HEADER_TOOL_STRDUP_H
|
||||
#define HEADER_TOOL_STRDUP_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#ifndef HAVE_STRDUP
|
||||
extern char *strdup(const char *str);
|
||||
#endif
|
||||
char *memdup0(const char *data, size_t len);
|
||||
|
||||
#endif /* HEADER_TOOL_STRDUP_H */
|
||||
+670
@@ -0,0 +1,670 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#include "tool_cfgable.h"
|
||||
#include "tool_doswin.h"
|
||||
#include "tool_urlglob.h"
|
||||
#include "tool_vms.h"
|
||||
#include "tool_strdup.h"
|
||||
#include "memdebug.h" /* keep this as LAST include */
|
||||
|
||||
static CURLcode globerror(struct URLGlob *glob, const char *err,
|
||||
size_t pos, CURLcode error)
|
||||
{
|
||||
glob->error = err;
|
||||
glob->pos = pos;
|
||||
return error;
|
||||
}
|
||||
|
||||
static CURLcode glob_fixed(struct URLGlob *glob, char *fixed, size_t len)
|
||||
{
|
||||
struct URLPattern *pat = &glob->pattern[glob->size];
|
||||
pat->type = GLOB_SET;
|
||||
pat->c.set.size = 1;
|
||||
pat->c.set.idx = 0;
|
||||
pat->globindex = -1;
|
||||
|
||||
pat->c.set.elem = malloc(sizeof(char *));
|
||||
|
||||
if(!pat->c.set.elem)
|
||||
return globerror(glob, NULL, 0, CURLE_OUT_OF_MEMORY);
|
||||
|
||||
pat->c.set.elem[0] = memdup0(fixed, len);
|
||||
if(!pat->c.set.elem[0])
|
||||
return globerror(glob, NULL, 0, CURLE_OUT_OF_MEMORY);
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/* multiply
|
||||
*
|
||||
* Multiplies and checks for overflow.
|
||||
*/
|
||||
static int multiply(curl_off_t *amount, curl_off_t with)
|
||||
{
|
||||
curl_off_t sum;
|
||||
DEBUGASSERT(*amount >= 0);
|
||||
DEBUGASSERT(with >= 0);
|
||||
if((with <= 0) || (*amount <= 0)) {
|
||||
sum = 0;
|
||||
}
|
||||
else {
|
||||
#if (defined(__GNUC__) && \
|
||||
((__GNUC__ > 5) || ((__GNUC__ == 5) && (__GNUC_MINOR__ >= 1)))) || \
|
||||
(defined(__clang__) && __clang_major__ >= 8)
|
||||
if(__builtin_mul_overflow(*amount, with, &sum))
|
||||
return 1;
|
||||
#else
|
||||
sum = *amount * with;
|
||||
if(sum/with != *amount)
|
||||
return 1; /* did not fit, bail out */
|
||||
#endif
|
||||
}
|
||||
*amount = sum;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static CURLcode glob_set(struct URLGlob *glob, const char **patternp,
|
||||
size_t *posp, curl_off_t *amount,
|
||||
int globindex)
|
||||
{
|
||||
/* processes a set expression with the point behind the opening '{'
|
||||
','-separated elements are collected until the next closing '}'
|
||||
*/
|
||||
struct URLPattern *pat;
|
||||
bool done = FALSE;
|
||||
const char *pattern = *patternp;
|
||||
const char *opattern = pattern;
|
||||
size_t opos = *posp-1;
|
||||
|
||||
pat = &glob->pattern[glob->size];
|
||||
/* patterns 0,1,2,... correspond to size=1,3,5,... */
|
||||
pat->type = GLOB_SET;
|
||||
pat->c.set.size = 0;
|
||||
pat->c.set.idx = 0;
|
||||
pat->c.set.elem = NULL;
|
||||
pat->globindex = globindex;
|
||||
|
||||
while(!done) {
|
||||
switch(*pattern) {
|
||||
case '\0': /* URL ended while set was still open */
|
||||
return globerror(glob, "unmatched brace", opos, CURLE_URL_MALFORMAT);
|
||||
|
||||
case '{':
|
||||
case '[': /* no nested expressions at this time */
|
||||
return globerror(glob, "nested brace", *posp, CURLE_URL_MALFORMAT);
|
||||
|
||||
case '}': /* set element completed */
|
||||
if(opattern == pattern)
|
||||
return globerror(glob, "empty string within braces", *posp,
|
||||
CURLE_URL_MALFORMAT);
|
||||
|
||||
/* add 1 to size since it will be incremented below */
|
||||
if(multiply(amount, pat->c.set.size + 1))
|
||||
return globerror(glob, "range overflow", 0, CURLE_URL_MALFORMAT);
|
||||
done = TRUE;
|
||||
FALLTHROUGH();
|
||||
case ',':
|
||||
if(pat->c.set.elem) {
|
||||
char **arr;
|
||||
|
||||
if(pat->c.set.size >= (curl_off_t)(SIZE_MAX/(sizeof(char *))))
|
||||
return globerror(glob, "range overflow", 0, CURLE_URL_MALFORMAT);
|
||||
|
||||
arr = realloc(pat->c.set.elem, (size_t)(pat->c.set.size + 1) *
|
||||
sizeof(char *));
|
||||
if(!arr)
|
||||
return globerror(glob, NULL, 0, CURLE_OUT_OF_MEMORY);
|
||||
|
||||
pat->c.set.elem = arr;
|
||||
}
|
||||
else
|
||||
pat->c.set.elem = malloc(sizeof(char *));
|
||||
|
||||
if(!pat->c.set.elem)
|
||||
return globerror(glob, NULL, 0, CURLE_OUT_OF_MEMORY);
|
||||
|
||||
pat->c.set.elem[pat->c.set.size] = strdup(curlx_dyn_ptr(&glob->buf) ?
|
||||
curlx_dyn_ptr(&glob->buf): "");
|
||||
if(!pat->c.set.elem[pat->c.set.size])
|
||||
return globerror(glob, NULL, 0, CURLE_OUT_OF_MEMORY);
|
||||
++pat->c.set.size;
|
||||
curlx_dyn_reset(&glob->buf);
|
||||
|
||||
++pattern;
|
||||
if(!done)
|
||||
++(*posp);
|
||||
break;
|
||||
|
||||
case ']': /* illegal closing bracket */
|
||||
return globerror(glob, "unexpected close bracket", *posp,
|
||||
CURLE_URL_MALFORMAT);
|
||||
|
||||
case '\\': /* escaped character, skip '\' */
|
||||
if(pattern[1]) {
|
||||
++pattern;
|
||||
++(*posp);
|
||||
}
|
||||
FALLTHROUGH();
|
||||
default:
|
||||
/* copy character to set element */
|
||||
if(curlx_dyn_addn(&glob->buf, pattern++, 1))
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
++(*posp);
|
||||
}
|
||||
}
|
||||
|
||||
*patternp = pattern; /* return with the new position */
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static CURLcode glob_range(struct URLGlob *glob, const char **patternp,
|
||||
size_t *posp, curl_off_t *amount,
|
||||
int globindex)
|
||||
{
|
||||
/* processes a range expression with the point behind the opening '['
|
||||
- char range: e.g. "a-z]", "B-Q]"
|
||||
- num range: e.g. "0-9]", "17-2000]"
|
||||
- num range with leading zeros: e.g. "001-999]"
|
||||
expression is checked for well-formedness and collected until the next ']'
|
||||
*/
|
||||
struct URLPattern *pat;
|
||||
const char *pattern = *patternp;
|
||||
const char *c;
|
||||
|
||||
pat = &glob->pattern[glob->size];
|
||||
pat->globindex = globindex;
|
||||
|
||||
if(ISALPHA(*pattern)) {
|
||||
/* character range detected */
|
||||
bool pmatch = FALSE;
|
||||
char min_c = 0;
|
||||
char max_c = 0;
|
||||
char end_c = 0;
|
||||
unsigned char step = 1;
|
||||
|
||||
pat->type = GLOB_ASCII;
|
||||
|
||||
if((pattern[1] == '-') && pattern[2] && pattern[3]) {
|
||||
min_c = pattern[0];
|
||||
max_c = pattern[2];
|
||||
end_c = pattern[3];
|
||||
pmatch = TRUE;
|
||||
|
||||
if(end_c == ':') {
|
||||
curl_off_t num;
|
||||
const char *p = &pattern[4];
|
||||
if(curlx_str_number(&p, &num, 256) || curlx_str_single(&p, ']'))
|
||||
step = 0;
|
||||
else
|
||||
step = (unsigned char)num;
|
||||
pattern = p;
|
||||
}
|
||||
else if(end_c != ']')
|
||||
/* then this is wrong */
|
||||
pmatch = FALSE;
|
||||
else
|
||||
/* end_c == ']' */
|
||||
pattern += 4;
|
||||
}
|
||||
|
||||
*posp += (pattern - *patternp);
|
||||
|
||||
if(!pmatch || !step ||
|
||||
(min_c == max_c && step != 1) ||
|
||||
(min_c != max_c && (min_c > max_c || step > (unsigned)(max_c - min_c) ||
|
||||
(max_c - min_c) > ('z' - 'a'))))
|
||||
/* the pattern is not well-formed */
|
||||
return globerror(glob, "bad range", *posp, CURLE_URL_MALFORMAT);
|
||||
|
||||
/* if there was a ":[num]" thing, use that as step or else use 1 */
|
||||
pat->c.ascii.step = step;
|
||||
pat->c.ascii.letter = pat->c.ascii.min = min_c;
|
||||
pat->c.ascii.max = max_c;
|
||||
|
||||
if(multiply(amount, ((pat->c.ascii.max - pat->c.ascii.min) /
|
||||
pat->c.ascii.step + 1)))
|
||||
return globerror(glob, "range overflow", *posp, CURLE_URL_MALFORMAT);
|
||||
}
|
||||
else if(ISDIGIT(*pattern)) {
|
||||
/* numeric range detected */
|
||||
curl_off_t min_n = 0;
|
||||
curl_off_t max_n = 0;
|
||||
curl_off_t step_n = 0;
|
||||
curl_off_t num;
|
||||
|
||||
pat->type = GLOB_NUM;
|
||||
pat->c.num.npad = 0;
|
||||
|
||||
if(*pattern == '0') {
|
||||
/* leading zero specified, count them! */
|
||||
c = pattern;
|
||||
while(ISDIGIT(*c)) {
|
||||
c++;
|
||||
++pat->c.num.npad; /* padding length is set for all instances of this
|
||||
pattern */
|
||||
}
|
||||
}
|
||||
|
||||
if(!curlx_str_number(&pattern, &num, CURL_OFF_T_MAX)) {
|
||||
min_n = num;
|
||||
if(!curlx_str_single(&pattern, '-')) {
|
||||
curlx_str_passblanks(&pattern);
|
||||
if(!curlx_str_number(&pattern, &num, CURL_OFF_T_MAX)) {
|
||||
max_n = num;
|
||||
if(!curlx_str_single(&pattern, ']'))
|
||||
step_n = 1;
|
||||
else if(!curlx_str_single(&pattern, ':') &&
|
||||
!curlx_str_number(&pattern, &num, CURL_OFF_T_MAX) &&
|
||||
!curlx_str_single(&pattern, ']')) {
|
||||
step_n = num;
|
||||
}
|
||||
/* else bad syntax */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*posp += (pattern - *patternp);
|
||||
|
||||
if(!step_n ||
|
||||
(min_n == max_n && step_n != 1) ||
|
||||
(min_n != max_n && (min_n > max_n || step_n > (max_n - min_n))))
|
||||
/* the pattern is not well-formed */
|
||||
return globerror(glob, "bad range", *posp, CURLE_URL_MALFORMAT);
|
||||
|
||||
/* typecasting to ints are fine here since we make sure above that we
|
||||
are within 31 bits */
|
||||
pat->c.num.idx = pat->c.num.min = min_n;
|
||||
pat->c.num.max = max_n;
|
||||
pat->c.num.step = step_n;
|
||||
|
||||
if(multiply(amount, ((pat->c.num.max - pat->c.num.min) /
|
||||
pat->c.num.step + 1)))
|
||||
return globerror(glob, "range overflow", *posp, CURLE_URL_MALFORMAT);
|
||||
}
|
||||
else
|
||||
return globerror(glob, "bad range specification", *posp,
|
||||
CURLE_URL_MALFORMAT);
|
||||
|
||||
*patternp = pattern;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
#define MAX_IP6LEN 128
|
||||
|
||||
static bool peek_ipv6(const char *str, size_t *skip)
|
||||
{
|
||||
/*
|
||||
* Scan for a potential IPv6 literal.
|
||||
* - Valid globs contain a hyphen and <= 1 colon.
|
||||
* - IPv6 literals contain no hyphens and >= 2 colons.
|
||||
*/
|
||||
char hostname[MAX_IP6LEN];
|
||||
CURLU *u;
|
||||
char *endbr = strchr(str, ']');
|
||||
size_t hlen;
|
||||
CURLUcode rc;
|
||||
if(!endbr)
|
||||
return FALSE;
|
||||
|
||||
hlen = endbr - str + 1;
|
||||
if(hlen >= MAX_IP6LEN)
|
||||
return FALSE;
|
||||
|
||||
u = curl_url();
|
||||
if(!u)
|
||||
return FALSE;
|
||||
|
||||
memcpy(hostname, str, hlen);
|
||||
hostname[hlen] = 0;
|
||||
|
||||
/* ask to "guess scheme" as then it works without an https:// prefix */
|
||||
rc = curl_url_set(u, CURLUPART_URL, hostname, CURLU_GUESS_SCHEME);
|
||||
|
||||
curl_url_cleanup(u);
|
||||
if(!rc)
|
||||
*skip = hlen;
|
||||
return rc ? FALSE : TRUE;
|
||||
}
|
||||
|
||||
static CURLcode glob_parse(struct URLGlob *glob, const char *pattern,
|
||||
size_t pos, curl_off_t *amount)
|
||||
{
|
||||
/* processes a literal string component of a URL
|
||||
special characters '{' and '[' branch to set/range processing functions
|
||||
*/
|
||||
CURLcode res = CURLE_OK;
|
||||
int globindex = 0; /* count "actual" globs */
|
||||
|
||||
*amount = 1;
|
||||
|
||||
while(*pattern && !res) {
|
||||
while(*pattern && *pattern != '{') {
|
||||
if(*pattern == '[') {
|
||||
/* skip over IPv6 literals and [] */
|
||||
size_t skip = 0;
|
||||
if(!peek_ipv6(pattern, &skip) && (pattern[1] == ']'))
|
||||
skip = 2;
|
||||
if(skip) {
|
||||
if(curlx_dyn_addn(&glob->buf, pattern, skip))
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
pattern += skip;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(*pattern == '}' || *pattern == ']')
|
||||
return globerror(glob, "unmatched close brace/bracket", pos,
|
||||
CURLE_URL_MALFORMAT);
|
||||
|
||||
/* only allow \ to escape known "special letters" */
|
||||
if(*pattern == '\\' &&
|
||||
(*(pattern + 1) == '{' || *(pattern + 1) == '[' ||
|
||||
*(pattern + 1) == '}' || *(pattern + 1) == ']') ) {
|
||||
|
||||
/* escape character, skip '\' */
|
||||
++pattern;
|
||||
++pos;
|
||||
}
|
||||
/* copy character to literal */
|
||||
if(curlx_dyn_addn(&glob->buf, pattern++, 1))
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
++pos;
|
||||
}
|
||||
if(curlx_dyn_len(&glob->buf)) {
|
||||
/* we got a literal string, add it as a single-item list */
|
||||
res = glob_fixed(glob, curlx_dyn_ptr(&glob->buf),
|
||||
curlx_dyn_len(&glob->buf));
|
||||
curlx_dyn_reset(&glob->buf);
|
||||
}
|
||||
else {
|
||||
switch(*pattern) {
|
||||
case '\0': /* done */
|
||||
break;
|
||||
|
||||
case '{':
|
||||
/* process set pattern */
|
||||
pattern++;
|
||||
pos++;
|
||||
res = glob_set(glob, &pattern, &pos, amount, globindex++);
|
||||
break;
|
||||
|
||||
case '[':
|
||||
/* process range pattern */
|
||||
pattern++;
|
||||
pos++;
|
||||
res = glob_range(glob, &pattern, &pos, amount, globindex++);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(++glob->size >= glob->palloc) {
|
||||
struct URLPattern *np = NULL;
|
||||
glob->palloc *= 2;
|
||||
if(glob->size < 255) { /* avoid ridiculous amounts */
|
||||
np = realloc(glob->pattern, glob->palloc * sizeof(struct URLPattern));
|
||||
if(!np)
|
||||
return globerror(glob, NULL, pos, CURLE_OUT_OF_MEMORY);
|
||||
}
|
||||
else
|
||||
return globerror(glob, "too many {} sets", pos, CURLE_URL_MALFORMAT);
|
||||
glob->pattern = np;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool glob_inuse(struct URLGlob *glob)
|
||||
{
|
||||
return glob->palloc ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
CURLcode glob_url(struct URLGlob *glob, char *url, curl_off_t *urlnum,
|
||||
FILE *error)
|
||||
{
|
||||
/*
|
||||
* We can deal with any-size, just make a buffer with the same length
|
||||
* as the specified URL!
|
||||
*/
|
||||
curl_off_t amount = 0;
|
||||
CURLcode res;
|
||||
|
||||
memset(glob, 0, sizeof(struct URLGlob));
|
||||
curlx_dyn_init(&glob->buf, 1024*1024);
|
||||
glob->pattern = malloc(2 * sizeof(struct URLPattern));
|
||||
if(!glob->pattern)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
glob->palloc = 2;
|
||||
|
||||
res = glob_parse(glob, url, 1, &amount);
|
||||
if(!res)
|
||||
*urlnum = amount;
|
||||
else {
|
||||
if(error && glob->error) {
|
||||
char text[512];
|
||||
const char *t;
|
||||
if(glob->pos) {
|
||||
curl_msnprintf(text, sizeof(text), "%s in URL position %zu:\n%s\n%*s^",
|
||||
glob->error,
|
||||
glob->pos, url, (int)glob->pos - 1, " ");
|
||||
t = text;
|
||||
}
|
||||
else
|
||||
t = glob->error;
|
||||
|
||||
/* send error description to the error-stream */
|
||||
curl_mfprintf(error, "curl: (%d) %s\n", res, t);
|
||||
}
|
||||
/* it failed, we cleanup */
|
||||
glob_cleanup(glob);
|
||||
*urlnum = 1;
|
||||
return res;
|
||||
}
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
void glob_cleanup(struct URLGlob *glob)
|
||||
{
|
||||
size_t i;
|
||||
curl_off_t elem;
|
||||
|
||||
if(glob->pattern) {
|
||||
for(i = 0; i < glob->size; i++) {
|
||||
if((glob->pattern[i].type == GLOB_SET) &&
|
||||
(glob->pattern[i].c.set.elem)) {
|
||||
for(elem = glob->pattern[i].c.set.size - 1; elem >= 0; --elem)
|
||||
tool_safefree(glob->pattern[i].c.set.elem[elem]);
|
||||
tool_safefree(glob->pattern[i].c.set.elem);
|
||||
}
|
||||
}
|
||||
tool_safefree(glob->pattern);
|
||||
glob->palloc = 0;
|
||||
curlx_dyn_free(&glob->buf);
|
||||
}
|
||||
}
|
||||
|
||||
CURLcode glob_next_url(char **globbed, struct URLGlob *glob)
|
||||
{
|
||||
struct URLPattern *pat;
|
||||
size_t i;
|
||||
|
||||
*globbed = NULL;
|
||||
curlx_dyn_reset(&glob->buf);
|
||||
|
||||
if(!glob->beenhere)
|
||||
glob->beenhere = 1;
|
||||
else {
|
||||
bool carry = TRUE;
|
||||
|
||||
/* implement a counter over the index ranges of all patterns, starting
|
||||
with the rightmost pattern */
|
||||
for(i = 0; carry && (i < glob->size); i++) {
|
||||
carry = FALSE;
|
||||
pat = &glob->pattern[glob->size - 1 - i];
|
||||
switch(pat->type) {
|
||||
case GLOB_SET:
|
||||
if((pat->c.set.elem) && (++pat->c.set.idx == pat->c.set.size)) {
|
||||
pat->c.set.idx = 0;
|
||||
carry = TRUE;
|
||||
}
|
||||
break;
|
||||
case GLOB_ASCII:
|
||||
pat->c.ascii.letter += pat->c.ascii.step;
|
||||
if(pat->c.ascii.letter > pat->c.ascii.max) {
|
||||
pat->c.ascii.letter = pat->c.ascii.min;
|
||||
carry = TRUE;
|
||||
}
|
||||
break;
|
||||
case GLOB_NUM:
|
||||
pat->c.num.idx += pat->c.num.step;
|
||||
if(pat->c.num.idx > pat->c.num.max) {
|
||||
pat->c.num.idx = pat->c.num.min;
|
||||
carry = TRUE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEBUGASSERT(0);
|
||||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
}
|
||||
if(carry) { /* first pattern ptr has run into overflow, done! */
|
||||
return CURLE_OK;
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < glob->size; ++i) {
|
||||
pat = &glob->pattern[i];
|
||||
switch(pat->type) {
|
||||
case GLOB_SET:
|
||||
if(pat->c.set.elem) {
|
||||
if(curlx_dyn_add(&glob->buf, pat->c.set.elem[pat->c.set.idx]))
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
break;
|
||||
case GLOB_ASCII: {
|
||||
char letter = (char)pat->c.ascii.letter;
|
||||
if(curlx_dyn_addn(&glob->buf, &letter, 1))
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
break;
|
||||
}
|
||||
case GLOB_NUM:
|
||||
if(curlx_dyn_addf(&glob->buf, "%0*" CURL_FORMAT_CURL_OFF_T,
|
||||
pat->c.num.npad, pat->c.num.idx))
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
break;
|
||||
default:
|
||||
DEBUGASSERT(0);
|
||||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
}
|
||||
|
||||
*globbed = strdup(curlx_dyn_ptr(&glob->buf));
|
||||
if(!*globbed)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
#define MAX_OUTPUT_GLOB_LENGTH (1024*1024)
|
||||
|
||||
CURLcode glob_match_url(char **output, const char *filename,
|
||||
struct URLGlob *glob)
|
||||
{
|
||||
struct dynbuf dyn;
|
||||
*output = NULL;
|
||||
|
||||
curlx_dyn_init(&dyn, MAX_OUTPUT_GLOB_LENGTH);
|
||||
|
||||
while(*filename) {
|
||||
CURLcode result = CURLE_OK;
|
||||
if(*filename == '#' && ISDIGIT(filename[1])) {
|
||||
const char *ptr = filename;
|
||||
curl_off_t num;
|
||||
struct URLPattern *pat = NULL;
|
||||
filename++;
|
||||
if(!curlx_str_number(&filename, &num, glob->size) && num) {
|
||||
size_t i;
|
||||
num--; /* make it zero based */
|
||||
/* find the correct glob entry */
|
||||
for(i = 0; i < glob->size; i++) {
|
||||
if(glob->pattern[i].globindex == (int)num) {
|
||||
pat = &glob->pattern[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(pat) {
|
||||
switch(pat->type) {
|
||||
case GLOB_SET:
|
||||
if(pat->c.set.elem)
|
||||
result = curlx_dyn_add(&dyn, pat->c.set.elem[pat->c.set.idx]);
|
||||
break;
|
||||
case GLOB_ASCII: {
|
||||
char letter = (char)pat->c.ascii.letter;
|
||||
result = curlx_dyn_addn(&dyn, &letter, 1);
|
||||
break;
|
||||
}
|
||||
case GLOB_NUM:
|
||||
result = curlx_dyn_addf(&dyn, "%0*" CURL_FORMAT_CURL_OFF_T,
|
||||
pat->c.num.npad, pat->c.num.idx);
|
||||
break;
|
||||
default:
|
||||
DEBUGASSERT(0);
|
||||
curlx_dyn_free(&dyn);
|
||||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
}
|
||||
else
|
||||
/* #[num] out of range, use the #[num] in the output */
|
||||
result = curlx_dyn_addn(&dyn, ptr, filename - ptr);
|
||||
}
|
||||
else
|
||||
result = curlx_dyn_addn(&dyn, filename++, 1);
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
|
||||
if(curlx_dyn_addn(&dyn, "", 0))
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
#if defined(_WIN32) || defined(MSDOS)
|
||||
{
|
||||
char *sanitized;
|
||||
SANITIZEcode sc = sanitize_file_name(&sanitized, curlx_dyn_ptr(&dyn),
|
||||
(SANITIZE_ALLOW_PATH |
|
||||
SANITIZE_ALLOW_RESERVED));
|
||||
curlx_dyn_free(&dyn);
|
||||
if(sc)
|
||||
return CURLE_URL_MALFORMAT;
|
||||
*output = sanitized;
|
||||
return CURLE_OK;
|
||||
}
|
||||
#else
|
||||
*output = curlx_dyn_ptr(&dyn);
|
||||
return CURLE_OK;
|
||||
#endif /* _WIN32 || MSDOS */
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
#ifndef HEADER_CURL_TOOL_URLGLOB_H
|
||||
#define HEADER_CURL_TOOL_URLGLOB_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
typedef enum {
|
||||
GLOB_SET = 1,
|
||||
GLOB_ASCII,
|
||||
GLOB_NUM
|
||||
} globtype;
|
||||
|
||||
struct URLPattern {
|
||||
globtype type;
|
||||
int globindex; /* the number of this particular glob or -1 if not used
|
||||
within {} or [] */
|
||||
union {
|
||||
struct {
|
||||
char **elem;
|
||||
curl_off_t size;
|
||||
curl_off_t idx;
|
||||
} set;
|
||||
struct {
|
||||
int min;
|
||||
int max;
|
||||
int letter;
|
||||
unsigned char step;
|
||||
} ascii;
|
||||
struct {
|
||||
curl_off_t min;
|
||||
curl_off_t max;
|
||||
curl_off_t idx;
|
||||
curl_off_t step;
|
||||
int npad;
|
||||
} num;
|
||||
} c;
|
||||
};
|
||||
|
||||
/* the total number of globs supported */
|
||||
#define GLOB_PATTERN_NUM 30
|
||||
|
||||
struct URLGlob {
|
||||
struct dynbuf buf;
|
||||
struct URLPattern *pattern;
|
||||
size_t palloc; /* number of pattern entries allocated */
|
||||
size_t size;
|
||||
char beenhere;
|
||||
const char *error; /* error message */
|
||||
size_t pos; /* column position of error or 0 */
|
||||
};
|
||||
|
||||
CURLcode glob_url(struct URLGlob *, char *, curl_off_t *, FILE *);
|
||||
CURLcode glob_next_url(char **, struct URLGlob *);
|
||||
CURLcode glob_match_url(char **, const char *, struct URLGlob *);
|
||||
void glob_cleanup(struct URLGlob *glob);
|
||||
bool glob_inuse(struct URLGlob *glob);
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_URLGLOB_H */
|
||||
Vendored
+137
@@ -0,0 +1,137 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#include "tool_util.h"
|
||||
#include "memdebug.h" /* keep this as LAST include */
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
struct timeval tvrealnow(void)
|
||||
{
|
||||
/* UNIX EPOCH (1970-01-01) in FILETIME (1601-01-01) as 64-bit value */
|
||||
static const curl_uint64_t EPOCH = (curl_uint64_t)116444736000000000ULL;
|
||||
SYSTEMTIME systime;
|
||||
FILETIME ftime; /* 100ns since 1601-01-01, as double 32-bit value */
|
||||
curl_uint64_t time; /* 100ns since 1601-01-01, as 64-bit value */
|
||||
struct timeval now;
|
||||
|
||||
GetSystemTime(&systime);
|
||||
SystemTimeToFileTime(&systime, &ftime);
|
||||
time = ((curl_uint64_t)ftime.dwLowDateTime);
|
||||
time += ((curl_uint64_t)ftime.dwHighDateTime) << 32;
|
||||
|
||||
now.tv_sec = (long)((time - EPOCH) / 10000000L); /* unit is 100ns */
|
||||
now.tv_usec = (long)(systime.wMilliseconds * 1000);
|
||||
return now;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
struct timeval tvrealnow(void)
|
||||
{
|
||||
struct timeval now;
|
||||
#ifdef HAVE_GETTIMEOFDAY
|
||||
(void)gettimeofday(&now, NULL);
|
||||
#else
|
||||
now.tv_sec = time(NULL);
|
||||
now.tv_usec = 0;
|
||||
#endif
|
||||
return now;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Case insensitive compare. Accept NULL pointers. */
|
||||
int struplocompare(const char *p1, const char *p2)
|
||||
{
|
||||
if(!p1)
|
||||
return p2 ? -1 : 0;
|
||||
if(!p2)
|
||||
return 1;
|
||||
return CURL_STRICMP(p1, p2);
|
||||
}
|
||||
|
||||
/* Indirect version to use as qsort callback. */
|
||||
int struplocompare4sort(const void *p1, const void *p2)
|
||||
{
|
||||
return struplocompare(* (char * const *) p1, * (char * const *) p2);
|
||||
}
|
||||
|
||||
#ifdef USE_TOOL_FTRUNCATE
|
||||
|
||||
#ifdef UNDER_CE
|
||||
/* 64-bit lseek-like function unavailable */
|
||||
# undef _lseeki64
|
||||
# define _lseeki64(hnd,ofs,whence) lseek(hnd,ofs,whence)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Truncate a file handle at a 64-bit position 'where'.
|
||||
*/
|
||||
|
||||
int tool_ftruncate64(int fd, curl_off_t where)
|
||||
{
|
||||
intptr_t handle = _get_osfhandle(fd);
|
||||
|
||||
if(_lseeki64(fd, where, SEEK_SET) < 0)
|
||||
return -1;
|
||||
|
||||
if(!SetEndOfFile((HANDLE)handle))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* USE_TOOL_FTRUNCATE */
|
||||
|
||||
#if defined(_WIN32) && !defined(UNDER_CE)
|
||||
FILE *tool_execpath(const char *filename, char **pathp)
|
||||
{
|
||||
static char filebuffer[512];
|
||||
unsigned long len;
|
||||
/* Get the filename of our executable. GetModuleFileName is already declared
|
||||
* via inclusions done in setup header file. We assume that we are using
|
||||
* the ASCII version here.
|
||||
*/
|
||||
len = GetModuleFileNameA(0, filebuffer, sizeof(filebuffer));
|
||||
if(len > 0 && len < sizeof(filebuffer)) {
|
||||
/* We got a valid filename - get the directory part */
|
||||
char *lastdirchar = strrchr(filebuffer, DIR_CHAR[0]);
|
||||
if(lastdirchar) {
|
||||
size_t remaining;
|
||||
*lastdirchar = 0;
|
||||
/* If we have enough space, build the RC filename */
|
||||
remaining = sizeof(filebuffer) - strlen(filebuffer);
|
||||
if(strlen(filename) < remaining - 1) {
|
||||
curl_msnprintf(lastdirchar, remaining, "%s%s", DIR_CHAR, filename);
|
||||
*pathp = filebuffer;
|
||||
return curlx_fopen(filebuffer, FOPEN_READTEXT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
Vendored
+41
@@ -0,0 +1,41 @@
|
||||
#ifndef HEADER_CURL_TOOL_UTIL_H
|
||||
#define HEADER_CURL_TOOL_UTIL_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
/**
|
||||
* Return timeval of the REALTIME clock.
|
||||
*/
|
||||
struct timeval tvrealnow(void);
|
||||
|
||||
/* Case insensitive comparison support. */
|
||||
int struplocompare(const char *p1, const char *p2);
|
||||
int struplocompare4sort(const void *p1, const void *p2);
|
||||
|
||||
#if defined(_WIN32) && !defined(UNDER_CE)
|
||||
FILE *tool_execpath(const char *filename, char **pathp);
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_UTIL_H */
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
#ifndef HEADER_CURL_TOOL_VERSION_H
|
||||
#define HEADER_CURL_TOOL_VERSION_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include <curl/curlver.h>
|
||||
|
||||
#define CURL_NAME "curl"
|
||||
#define CURL_COPYRIGHT LIBCURL_COPYRIGHT
|
||||
#define CURL_VERSION "8.17.0"
|
||||
#define CURL_VERSION_MAJOR LIBCURL_VERSION_MAJOR
|
||||
#define CURL_VERSION_MINOR LIBCURL_VERSION_MINOR
|
||||
#define CURL_VERSION_PATCH LIBCURL_VERSION_PATCH
|
||||
#define CURL_ID CURL_NAME " " CURL_VERSION " (" CURL_OS ") "
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_VERSION_H */
|
||||
Vendored
+216
@@ -0,0 +1,216 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#ifdef __VMS
|
||||
|
||||
#if defined(__DECC) && !defined(__VAX) && \
|
||||
defined(__CRTL_VER) && (__CRTL_VER >= 70301000)
|
||||
#include <unixlib.h>
|
||||
#endif
|
||||
|
||||
#include "curlmsg_vms.h"
|
||||
#include "tool_vms.h"
|
||||
#include "memdebug.h" /* keep this as LAST include */
|
||||
|
||||
void decc$__posix_exit(int __status);
|
||||
void decc$exit(int __status);
|
||||
|
||||
static int vms_shell = -1;
|
||||
|
||||
/* VMS has a DCL shell and also has Unix shells ported to it.
|
||||
* When curl is running under a Unix shell, we want it to be as much
|
||||
* like Unix as possible.
|
||||
*/
|
||||
int is_vms_shell(void)
|
||||
{
|
||||
char *shell;
|
||||
|
||||
/* Have we checked the shell yet? */
|
||||
if(vms_shell >= 0)
|
||||
return vms_shell;
|
||||
|
||||
shell = getenv("SHELL");
|
||||
|
||||
/* No shell, means DCL */
|
||||
if(!shell) {
|
||||
vms_shell = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Have to make sure some one did not set shell to DCL */
|
||||
if(strcmp(shell, "DCL") == 0) {
|
||||
vms_shell = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
vms_shell = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* VMS has two exit() routines. When running under a Unix style shell, then
|
||||
* Unix style and the __posix_exit() routine is used.
|
||||
*
|
||||
* When running under the DCL shell, then the VMS encoded codes and decc$exit()
|
||||
* is used.
|
||||
*
|
||||
* We can not use exit() or return a code from main() because the actual
|
||||
* routine called depends on both the compiler version, compile options, and
|
||||
* feature macro settings, and one of the exit routines is hidden at compile
|
||||
* time.
|
||||
*
|
||||
* Since we want curl to work properly under the VMS DCL shell and Unix
|
||||
* shells under VMS, this routine should compile correctly regardless of
|
||||
* the settings.
|
||||
*/
|
||||
|
||||
void vms_special_exit(int code, int vms_show)
|
||||
{
|
||||
int vms_code;
|
||||
|
||||
/* The POSIX exit mode is only available after VMS 7.0 */
|
||||
#if __CRTL_VER >= 70000000
|
||||
if(is_vms_shell() == 0) {
|
||||
decc$__posix_exit(code);
|
||||
}
|
||||
#endif
|
||||
|
||||
if(code > CURL_LAST) { /* If CURL_LAST exceeded then */
|
||||
vms_code = CURL_LAST; /* curlmsg.h is out of sync. */
|
||||
}
|
||||
else {
|
||||
vms_code = vms_cond[code] | vms_show;
|
||||
}
|
||||
decc$exit(vms_code);
|
||||
}
|
||||
|
||||
#if defined(__DECC) && !defined(__VAX) && \
|
||||
defined(__CRTL_VER) && (__CRTL_VER >= 70301000)
|
||||
|
||||
/*
|
||||
* 2004-09-19 SMS.
|
||||
*
|
||||
* decc_init()
|
||||
*
|
||||
* On non-VAX systems, use LIB$INITIALIZE to set a collection of C
|
||||
* RTL features without using the DECC$* logical name method, nor
|
||||
* requiring the user to define the corresponding logical names.
|
||||
*/
|
||||
|
||||
/* Structure to hold a DECC$* feature name and its desired value. */
|
||||
struct decc_feat_t {
|
||||
char *name;
|
||||
int value;
|
||||
};
|
||||
|
||||
/* Array of DECC$* feature names and their desired values. */
|
||||
static const struct decc_feat_t decc_feat_array[] = {
|
||||
/* Preserve command-line case with SET PROCESS/PARSE_STYLE=EXTENDED */
|
||||
{ "DECC$ARGV_PARSE_STYLE", 1 },
|
||||
/* Preserve case for filenames on ODS5 disks. */
|
||||
{ "DECC$EFS_CASE_PRESERVE", 1 },
|
||||
/* Enable multiple dots (and most characters) in ODS5 filenames,
|
||||
while preserving VMS-ness of ";version". */
|
||||
{ "DECC$EFS_CHARSET", 1 },
|
||||
/* List terminator. */
|
||||
{ (char *)NULL, 0 }
|
||||
};
|
||||
|
||||
/* Flag to sense if decc_init() was called. */
|
||||
static int decc_init_done = -1;
|
||||
|
||||
/* LIB$INITIALIZE initialization function. */
|
||||
static void decc_init(void)
|
||||
{
|
||||
int feat_index;
|
||||
int feat_value;
|
||||
int feat_value_max;
|
||||
int feat_value_min;
|
||||
int i;
|
||||
int sts;
|
||||
|
||||
/* Set the global flag to indicate that LIB$INITIALIZE worked. */
|
||||
decc_init_done = 1;
|
||||
|
||||
/* Loop through all items in the decc_feat_array[]. */
|
||||
for(i = 0; decc_feat_array[i].name != NULL; i++) {
|
||||
|
||||
/* Get the feature index. */
|
||||
feat_index = decc$feature_get_index(decc_feat_array[i].name);
|
||||
|
||||
if(feat_index >= 0) {
|
||||
/* Valid item. Collect its properties. */
|
||||
feat_value = decc$feature_get_value(feat_index, 1);
|
||||
feat_value_min = decc$feature_get_value(feat_index, 2);
|
||||
feat_value_max = decc$feature_get_value(feat_index, 3);
|
||||
|
||||
if((decc_feat_array[i].value >= feat_value_min) &&
|
||||
(decc_feat_array[i].value <= feat_value_max)) {
|
||||
/* Valid value. Set it if necessary. */
|
||||
if(feat_value != decc_feat_array[i].value) {
|
||||
sts = decc$feature_set_value(feat_index, 1,
|
||||
decc_feat_array[i].value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Invalid DECC feature value. */
|
||||
curl_mprintf(" INVALID DECC FEATURE VALUE, %d: %d <= %s <= %d.\n",
|
||||
feat_value,
|
||||
feat_value_min, decc_feat_array[i].name, feat_value_max);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Invalid DECC feature name. */
|
||||
curl_mprintf(" UNKNOWN DECC FEATURE: %s.\n", decc_feat_array[i].name);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* Get "decc_init()" into a valid, loaded LIB$INITIALIZE PSECT. */
|
||||
|
||||
#pragma nostandard
|
||||
|
||||
/* Establish the LIB$INITIALIZE PSECTs, with proper alignment and
|
||||
other attributes. Note that "nopic" is significant only on VAX. */
|
||||
#pragma extern_model save
|
||||
#pragma extern_model strict_refdef "LIB$INITIALIZ" 2, nopic, nowrt
|
||||
const int spare[8] = {0};
|
||||
#pragma extern_model strict_refdef "LIB$INITIALIZE" 2, nopic, nowrt
|
||||
void (*const x_decc_init)() = decc_init;
|
||||
#pragma extern_model restore
|
||||
|
||||
/* Fake reference to ensure loading the LIB$INITIALIZE PSECT. */
|
||||
#pragma extern_model save
|
||||
int LIB$INITIALIZE(void);
|
||||
#pragma extern_model strict_refdef
|
||||
int dmy_lib$initialize = (int) LIB$INITIALIZE;
|
||||
#pragma extern_model restore
|
||||
|
||||
#pragma standard
|
||||
|
||||
#endif /* __DECC && !__VAX && __CRTL_VER && __CRTL_VER >= 70301000 */
|
||||
|
||||
#endif /* __VMS */
|
||||
Vendored
+48
@@ -0,0 +1,48 @@
|
||||
#ifndef HEADER_CURL_TOOL_VMS_H
|
||||
#define HEADER_CURL_TOOL_VMS_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#ifdef __VMS
|
||||
|
||||
/*
|
||||
* Forward-declaration of global variable vms_show defined
|
||||
* in tool_main.c, used in main() as parameter for function
|
||||
* vms_special_exit() to allow proper curl tool exiting.
|
||||
*/
|
||||
extern int vms_show;
|
||||
|
||||
int is_vms_shell(void);
|
||||
void vms_special_exit(int code, int vms_show);
|
||||
|
||||
#undef exit
|
||||
#define exit(__code) vms_special_exit((__code), (0))
|
||||
|
||||
#define VMS_STS(c,f,e,s) (((c&0xF)<<28)|((f&0xFFF)<<16)|((e&0x1FFF)<3)|(s&7))
|
||||
#define VMSSTS_HIDE VMS_STS(1,0,0,0)
|
||||
|
||||
#endif /* __VMS */
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_VMS_H */
|
||||
+877
@@ -0,0 +1,877 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#include "tool_cfgable.h"
|
||||
#include "tool_writeout.h"
|
||||
#include "tool_writeout_json.h"
|
||||
#include "memdebug.h" /* keep this as LAST include */
|
||||
|
||||
static int writeTime(FILE *stream, const struct writeoutvar *wovar,
|
||||
struct per_transfer *per, CURLcode per_result,
|
||||
bool use_json);
|
||||
|
||||
static int writeString(FILE *stream, const struct writeoutvar *wovar,
|
||||
struct per_transfer *per, CURLcode per_result,
|
||||
bool use_json);
|
||||
|
||||
static int writeLong(FILE *stream, const struct writeoutvar *wovar,
|
||||
struct per_transfer *per, CURLcode per_result,
|
||||
bool use_json);
|
||||
|
||||
static int writeOffset(FILE *stream, const struct writeoutvar *wovar,
|
||||
struct per_transfer *per, CURLcode per_result,
|
||||
bool use_json);
|
||||
|
||||
struct httpmap {
|
||||
const char *str;
|
||||
int num;
|
||||
};
|
||||
|
||||
static const struct httpmap http_version[] = {
|
||||
{ "0", CURL_HTTP_VERSION_NONE},
|
||||
{ "1", CURL_HTTP_VERSION_1_0},
|
||||
{ "1.1", CURL_HTTP_VERSION_1_1},
|
||||
{ "2", CURL_HTTP_VERSION_2},
|
||||
{ "3", CURL_HTTP_VERSION_3},
|
||||
{ NULL, 0} /* end of list */
|
||||
};
|
||||
|
||||
/* The designated write function should be the same as the CURLINFO return type
|
||||
with exceptions special cased in the respective function. For example,
|
||||
http_version uses CURLINFO_HTTP_VERSION which returns the version as a long,
|
||||
however it is output as a string and therefore is handled in writeString.
|
||||
|
||||
Yes: "http_version": "1.1"
|
||||
No: "http_version": 1.1
|
||||
|
||||
Variable names MUST be in alphabetical order.
|
||||
*/
|
||||
static const struct writeoutvar variables[] = {
|
||||
{"certs", VAR_CERT, CURLINFO_NONE, writeString},
|
||||
{"conn_id", VAR_CONN_ID, CURLINFO_CONN_ID, writeOffset},
|
||||
{"content_type", VAR_CONTENT_TYPE, CURLINFO_CONTENT_TYPE, writeString},
|
||||
{"errormsg", VAR_ERRORMSG, CURLINFO_NONE, writeString},
|
||||
{"exitcode", VAR_EXITCODE, CURLINFO_NONE, writeLong},
|
||||
{"filename_effective", VAR_EFFECTIVE_FILENAME, CURLINFO_NONE, writeString},
|
||||
{"ftp_entry_path", VAR_FTP_ENTRY_PATH, CURLINFO_FTP_ENTRY_PATH, writeString},
|
||||
{"header_json", VAR_HEADER_JSON, CURLINFO_NONE, NULL},
|
||||
{"http_code", VAR_HTTP_CODE, CURLINFO_RESPONSE_CODE, writeLong},
|
||||
{"http_connect", VAR_HTTP_CODE_PROXY, CURLINFO_HTTP_CONNECTCODE, writeLong},
|
||||
{"http_version", VAR_HTTP_VERSION, CURLINFO_HTTP_VERSION, writeString},
|
||||
{"json", VAR_JSON, CURLINFO_NONE, NULL},
|
||||
{"local_ip", VAR_LOCAL_IP, CURLINFO_LOCAL_IP, writeString},
|
||||
{"local_port", VAR_LOCAL_PORT, CURLINFO_LOCAL_PORT, writeLong},
|
||||
{"method", VAR_EFFECTIVE_METHOD, CURLINFO_EFFECTIVE_METHOD, writeString},
|
||||
{"num_certs", VAR_NUM_CERTS, CURLINFO_NONE, writeLong},
|
||||
{"num_connects", VAR_NUM_CONNECTS, CURLINFO_NUM_CONNECTS, writeLong},
|
||||
{"num_headers", VAR_NUM_HEADERS, CURLINFO_NONE, writeLong},
|
||||
{"num_redirects", VAR_REDIRECT_COUNT, CURLINFO_REDIRECT_COUNT, writeLong},
|
||||
{"num_retries", VAR_NUM_RETRY, CURLINFO_NONE, writeLong},
|
||||
{"onerror", VAR_ONERROR, CURLINFO_NONE, NULL},
|
||||
{"proxy_ssl_verify_result", VAR_PROXY_SSL_VERIFY_RESULT,
|
||||
CURLINFO_PROXY_SSL_VERIFYRESULT, writeLong},
|
||||
{"proxy_used", VAR_PROXY_USED, CURLINFO_USED_PROXY, writeLong},
|
||||
{"redirect_url", VAR_REDIRECT_URL, CURLINFO_REDIRECT_URL, writeString},
|
||||
{"referer", VAR_REFERER, CURLINFO_REFERER, writeString},
|
||||
{"remote_ip", VAR_PRIMARY_IP, CURLINFO_PRIMARY_IP, writeString},
|
||||
{"remote_port", VAR_PRIMARY_PORT, CURLINFO_PRIMARY_PORT, writeLong},
|
||||
{"response_code", VAR_HTTP_CODE, CURLINFO_RESPONSE_CODE, writeLong},
|
||||
{"scheme", VAR_SCHEME, CURLINFO_SCHEME, writeString},
|
||||
{"size_download", VAR_SIZE_DOWNLOAD, CURLINFO_SIZE_DOWNLOAD_T, writeOffset},
|
||||
{"size_header", VAR_HEADER_SIZE, CURLINFO_HEADER_SIZE, writeLong},
|
||||
{"size_request", VAR_REQUEST_SIZE, CURLINFO_REQUEST_SIZE, writeLong},
|
||||
{"size_upload", VAR_SIZE_UPLOAD, CURLINFO_SIZE_UPLOAD_T, writeOffset},
|
||||
{"speed_download", VAR_SPEED_DOWNLOAD, CURLINFO_SPEED_DOWNLOAD_T,
|
||||
writeOffset},
|
||||
{"speed_upload", VAR_SPEED_UPLOAD, CURLINFO_SPEED_UPLOAD_T, writeOffset},
|
||||
{"ssl_verify_result", VAR_SSL_VERIFY_RESULT, CURLINFO_SSL_VERIFYRESULT,
|
||||
writeLong},
|
||||
{"stderr", VAR_STDERR, CURLINFO_NONE, NULL},
|
||||
{"stdout", VAR_STDOUT, CURLINFO_NONE, NULL},
|
||||
{"time_appconnect", VAR_APPCONNECT_TIME, CURLINFO_APPCONNECT_TIME_T,
|
||||
writeTime},
|
||||
{"time_connect", VAR_CONNECT_TIME, CURLINFO_CONNECT_TIME_T, writeTime},
|
||||
{"time_namelookup", VAR_NAMELOOKUP_TIME, CURLINFO_NAMELOOKUP_TIME_T,
|
||||
writeTime},
|
||||
{"time_posttransfer", VAR_POSTTRANSFER_TIME, CURLINFO_POSTTRANSFER_TIME_T,
|
||||
writeTime},
|
||||
{"time_pretransfer", VAR_PRETRANSFER_TIME, CURLINFO_PRETRANSFER_TIME_T,
|
||||
writeTime},
|
||||
{"time_queue", VAR_QUEUE_TIME, CURLINFO_QUEUE_TIME_T, writeTime},
|
||||
{"time_redirect", VAR_REDIRECT_TIME, CURLINFO_REDIRECT_TIME_T, writeTime},
|
||||
{"time_starttransfer", VAR_STARTTRANSFER_TIME, CURLINFO_STARTTRANSFER_TIME_T,
|
||||
writeTime},
|
||||
{"time_total", VAR_TOTAL_TIME, CURLINFO_TOTAL_TIME_T, writeTime},
|
||||
{"tls_earlydata", VAR_TLS_EARLYDATA_SENT, CURLINFO_EARLYDATA_SENT_T,
|
||||
writeOffset},
|
||||
{"url", VAR_INPUT_URL, CURLINFO_NONE, writeString},
|
||||
{"url.fragment", VAR_INPUT_URLFRAGMENT, CURLINFO_NONE, writeString},
|
||||
{"url.host", VAR_INPUT_URLHOST, CURLINFO_NONE, writeString},
|
||||
{"url.options", VAR_INPUT_URLOPTIONS, CURLINFO_NONE, writeString},
|
||||
{"url.password", VAR_INPUT_URLPASSWORD, CURLINFO_NONE, writeString},
|
||||
{"url.path", VAR_INPUT_URLPATH, CURLINFO_NONE, writeString},
|
||||
{"url.port", VAR_INPUT_URLPORT, CURLINFO_NONE, writeString},
|
||||
{"url.query", VAR_INPUT_URLQUERY, CURLINFO_NONE, writeString},
|
||||
{"url.scheme", VAR_INPUT_URLSCHEME, CURLINFO_NONE, writeString},
|
||||
{"url.user", VAR_INPUT_URLUSER, CURLINFO_NONE, writeString},
|
||||
{"url.zoneid", VAR_INPUT_URLZONEID, CURLINFO_NONE, writeString},
|
||||
{"url_effective", VAR_EFFECTIVE_URL, CURLINFO_EFFECTIVE_URL, writeString},
|
||||
{"urle.fragment", VAR_INPUT_URLEFRAGMENT, CURLINFO_NONE, writeString},
|
||||
{"urle.host", VAR_INPUT_URLEHOST, CURLINFO_NONE, writeString},
|
||||
{"urle.options", VAR_INPUT_URLEOPTIONS, CURLINFO_NONE, writeString},
|
||||
{"urle.password", VAR_INPUT_URLEPASSWORD, CURLINFO_NONE, writeString},
|
||||
{"urle.path", VAR_INPUT_URLEPATH, CURLINFO_NONE, writeString},
|
||||
{"urle.port", VAR_INPUT_URLEPORT, CURLINFO_NONE, writeString},
|
||||
{"urle.query", VAR_INPUT_URLEQUERY, CURLINFO_NONE, writeString},
|
||||
{"urle.scheme", VAR_INPUT_URLESCHEME, CURLINFO_NONE, writeString},
|
||||
{"urle.user", VAR_INPUT_URLEUSER, CURLINFO_NONE, writeString},
|
||||
{"urle.zoneid", VAR_INPUT_URLEZONEID, CURLINFO_NONE, writeString},
|
||||
{"urlnum", VAR_URLNUM, CURLINFO_NONE, writeOffset},
|
||||
{"xfer_id", VAR_EASY_ID, CURLINFO_XFER_ID, writeOffset}
|
||||
};
|
||||
|
||||
static int writeTime(FILE *stream, const struct writeoutvar *wovar,
|
||||
struct per_transfer *per, CURLcode per_result,
|
||||
bool use_json)
|
||||
{
|
||||
bool valid = false;
|
||||
curl_off_t us = 0;
|
||||
|
||||
(void)per;
|
||||
(void)per_result;
|
||||
DEBUGASSERT(wovar->writefunc == writeTime);
|
||||
|
||||
if(wovar->ci) {
|
||||
if(!curl_easy_getinfo(per->curl, wovar->ci, &us))
|
||||
valid = true;
|
||||
}
|
||||
else {
|
||||
DEBUGASSERT(0);
|
||||
}
|
||||
|
||||
if(valid) {
|
||||
curl_off_t secs = us / 1000000;
|
||||
us %= 1000000;
|
||||
|
||||
if(use_json)
|
||||
curl_mfprintf(stream, "\"%s\":", wovar->name);
|
||||
|
||||
curl_mfprintf(stream, "%" CURL_FORMAT_CURL_OFF_TU
|
||||
".%06" CURL_FORMAT_CURL_OFF_TU, secs, us);
|
||||
}
|
||||
else {
|
||||
if(use_json)
|
||||
curl_mfprintf(stream, "\"%s\":null", wovar->name);
|
||||
}
|
||||
|
||||
return 1; /* return 1 if anything was written */
|
||||
}
|
||||
|
||||
static int urlpart(struct per_transfer *per, writeoutid vid,
|
||||
const char **contentp)
|
||||
{
|
||||
CURLU *uh = curl_url();
|
||||
int rc = 0;
|
||||
if(uh) {
|
||||
CURLUPart cpart = CURLUPART_HOST;
|
||||
char *part = NULL;
|
||||
const char *url = NULL;
|
||||
|
||||
if(vid >= VAR_INPUT_URLESCHEME) {
|
||||
if(curl_easy_getinfo(per->curl, CURLINFO_EFFECTIVE_URL, &url))
|
||||
rc = 5;
|
||||
}
|
||||
else
|
||||
url = per->url;
|
||||
|
||||
if(!rc) {
|
||||
switch(vid) {
|
||||
case VAR_INPUT_URLSCHEME:
|
||||
case VAR_INPUT_URLESCHEME:
|
||||
cpart = CURLUPART_SCHEME;
|
||||
break;
|
||||
case VAR_INPUT_URLUSER:
|
||||
case VAR_INPUT_URLEUSER:
|
||||
cpart = CURLUPART_USER;
|
||||
break;
|
||||
case VAR_INPUT_URLPASSWORD:
|
||||
case VAR_INPUT_URLEPASSWORD:
|
||||
cpart = CURLUPART_PASSWORD;
|
||||
break;
|
||||
case VAR_INPUT_URLOPTIONS:
|
||||
case VAR_INPUT_URLEOPTIONS:
|
||||
cpart = CURLUPART_OPTIONS;
|
||||
break;
|
||||
case VAR_INPUT_URLHOST:
|
||||
case VAR_INPUT_URLEHOST:
|
||||
cpart = CURLUPART_HOST;
|
||||
break;
|
||||
case VAR_INPUT_URLPORT:
|
||||
case VAR_INPUT_URLEPORT:
|
||||
cpart = CURLUPART_PORT;
|
||||
break;
|
||||
case VAR_INPUT_URLPATH:
|
||||
case VAR_INPUT_URLEPATH:
|
||||
cpart = CURLUPART_PATH;
|
||||
break;
|
||||
case VAR_INPUT_URLQUERY:
|
||||
case VAR_INPUT_URLEQUERY:
|
||||
cpart = CURLUPART_QUERY;
|
||||
break;
|
||||
case VAR_INPUT_URLFRAGMENT:
|
||||
case VAR_INPUT_URLEFRAGMENT:
|
||||
cpart = CURLUPART_FRAGMENT;
|
||||
break;
|
||||
case VAR_INPUT_URLZONEID:
|
||||
case VAR_INPUT_URLEZONEID:
|
||||
cpart = CURLUPART_ZONEID;
|
||||
break;
|
||||
default:
|
||||
/* not implemented */
|
||||
rc = 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!rc && curl_url_set(uh, CURLUPART_URL, url,
|
||||
CURLU_GUESS_SCHEME|CURLU_NON_SUPPORT_SCHEME))
|
||||
rc = 2;
|
||||
|
||||
if(!rc && curl_url_get(uh, cpart, &part, CURLU_DEFAULT_PORT))
|
||||
rc = 3;
|
||||
|
||||
if(!rc && part)
|
||||
*contentp = part;
|
||||
curl_url_cleanup(uh);
|
||||
}
|
||||
else
|
||||
return 1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void certinfo(struct per_transfer *per)
|
||||
{
|
||||
if(!per->certinfo) {
|
||||
struct curl_certinfo *certinfo;
|
||||
CURLcode res = curl_easy_getinfo(per->curl, CURLINFO_CERTINFO, &certinfo);
|
||||
per->certinfo = (!res && certinfo) ? certinfo : NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int writeString(FILE *stream, const struct writeoutvar *wovar,
|
||||
struct per_transfer *per, CURLcode per_result,
|
||||
bool use_json)
|
||||
{
|
||||
bool valid = false;
|
||||
const char *strinfo = NULL;
|
||||
const char *freestr = NULL;
|
||||
struct dynbuf buf;
|
||||
curlx_dyn_init(&buf, 256*1024);
|
||||
|
||||
DEBUGASSERT(wovar->writefunc == writeString);
|
||||
|
||||
if(wovar->ci) {
|
||||
if(wovar->ci == CURLINFO_HTTP_VERSION) {
|
||||
long version = 0;
|
||||
if(!curl_easy_getinfo(per->curl, CURLINFO_HTTP_VERSION, &version)) {
|
||||
const struct httpmap *m = &http_version[0];
|
||||
while(m->str) {
|
||||
if(m->num == version) {
|
||||
strinfo = m->str;
|
||||
valid = true;
|
||||
break;
|
||||
}
|
||||
m++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(!curl_easy_getinfo(per->curl, wovar->ci, &strinfo) && strinfo)
|
||||
valid = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch(wovar->id) {
|
||||
case VAR_CERT:
|
||||
certinfo(per);
|
||||
if(per->certinfo) {
|
||||
int i;
|
||||
bool error = FALSE;
|
||||
for(i = 0; (i < per->certinfo->num_of_certs) && !error; i++) {
|
||||
struct curl_slist *slist;
|
||||
|
||||
for(slist = per->certinfo->certinfo[i]; slist; slist = slist->next) {
|
||||
size_t len;
|
||||
if(curl_strnequal(slist->data, "cert:", 5)) {
|
||||
if(curlx_dyn_add(&buf, &slist->data[5])) {
|
||||
error = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(curlx_dyn_add(&buf, slist->data)) {
|
||||
error = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
len = curlx_dyn_len(&buf);
|
||||
if(len) {
|
||||
char *ptr = curlx_dyn_ptr(&buf);
|
||||
if(ptr[len -1] != '\n') {
|
||||
/* add a newline to make things look better */
|
||||
if(curlx_dyn_addn(&buf, "\n", 1)) {
|
||||
error = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!error) {
|
||||
strinfo = curlx_dyn_ptr(&buf);
|
||||
if(!strinfo)
|
||||
/* maybe not a TLS protocol */
|
||||
strinfo = "";
|
||||
valid = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
strinfo = ""; /* no cert info */
|
||||
break;
|
||||
case VAR_ERRORMSG:
|
||||
if(per_result) {
|
||||
strinfo = (per->errorbuffer[0]) ? per->errorbuffer :
|
||||
curl_easy_strerror(per_result);
|
||||
valid = true;
|
||||
}
|
||||
break;
|
||||
case VAR_EFFECTIVE_FILENAME:
|
||||
if(per->outs.filename) {
|
||||
strinfo = per->outs.filename;
|
||||
valid = true;
|
||||
}
|
||||
break;
|
||||
case VAR_INPUT_URL:
|
||||
if(per->url) {
|
||||
strinfo = per->url;
|
||||
valid = true;
|
||||
}
|
||||
break;
|
||||
case VAR_INPUT_URLSCHEME:
|
||||
case VAR_INPUT_URLUSER:
|
||||
case VAR_INPUT_URLPASSWORD:
|
||||
case VAR_INPUT_URLOPTIONS:
|
||||
case VAR_INPUT_URLHOST:
|
||||
case VAR_INPUT_URLPORT:
|
||||
case VAR_INPUT_URLPATH:
|
||||
case VAR_INPUT_URLQUERY:
|
||||
case VAR_INPUT_URLFRAGMENT:
|
||||
case VAR_INPUT_URLZONEID:
|
||||
case VAR_INPUT_URLESCHEME:
|
||||
case VAR_INPUT_URLEUSER:
|
||||
case VAR_INPUT_URLEPASSWORD:
|
||||
case VAR_INPUT_URLEOPTIONS:
|
||||
case VAR_INPUT_URLEHOST:
|
||||
case VAR_INPUT_URLEPORT:
|
||||
case VAR_INPUT_URLEPATH:
|
||||
case VAR_INPUT_URLEQUERY:
|
||||
case VAR_INPUT_URLEFRAGMENT:
|
||||
case VAR_INPUT_URLEZONEID:
|
||||
if(per->url) {
|
||||
if(!urlpart(per, wovar->id, &strinfo)) {
|
||||
freestr = strinfo;
|
||||
valid = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEBUGASSERT(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUGASSERT(!valid || strinfo);
|
||||
if(valid && strinfo) {
|
||||
if(use_json) {
|
||||
curl_mfprintf(stream, "\"%s\":", wovar->name);
|
||||
jsonWriteString(stream, strinfo, FALSE);
|
||||
}
|
||||
else
|
||||
fputs(strinfo, stream);
|
||||
}
|
||||
else {
|
||||
if(use_json)
|
||||
curl_mfprintf(stream, "\"%s\":null", wovar->name);
|
||||
}
|
||||
curl_free((char *)CURL_UNCONST(freestr));
|
||||
|
||||
curlx_dyn_free(&buf);
|
||||
return 1; /* return 1 if anything was written */
|
||||
}
|
||||
|
||||
static int writeLong(FILE *stream, const struct writeoutvar *wovar,
|
||||
struct per_transfer *per, CURLcode per_result,
|
||||
bool use_json)
|
||||
{
|
||||
bool valid = false;
|
||||
long longinfo = 0;
|
||||
|
||||
DEBUGASSERT(wovar->writefunc == writeLong);
|
||||
|
||||
if(wovar->ci) {
|
||||
if(!curl_easy_getinfo(per->curl, wovar->ci, &longinfo))
|
||||
valid = true;
|
||||
}
|
||||
else {
|
||||
switch(wovar->id) {
|
||||
case VAR_NUM_RETRY:
|
||||
longinfo = per->num_retries;
|
||||
valid = true;
|
||||
break;
|
||||
case VAR_NUM_CERTS:
|
||||
certinfo(per);
|
||||
longinfo = per->certinfo ? per->certinfo->num_of_certs : 0;
|
||||
valid = true;
|
||||
break;
|
||||
case VAR_NUM_HEADERS:
|
||||
longinfo = per->num_headers;
|
||||
valid = true;
|
||||
break;
|
||||
case VAR_EXITCODE:
|
||||
longinfo = (long)per_result;
|
||||
valid = true;
|
||||
break;
|
||||
default:
|
||||
DEBUGASSERT(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(valid) {
|
||||
if(use_json)
|
||||
curl_mfprintf(stream, "\"%s\":%ld", wovar->name, longinfo);
|
||||
else {
|
||||
if(wovar->id == VAR_HTTP_CODE || wovar->id == VAR_HTTP_CODE_PROXY)
|
||||
curl_mfprintf(stream, "%03ld", longinfo);
|
||||
else
|
||||
curl_mfprintf(stream, "%ld", longinfo);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(use_json)
|
||||
curl_mfprintf(stream, "\"%s\":null", wovar->name);
|
||||
}
|
||||
|
||||
return 1; /* return 1 if anything was written */
|
||||
}
|
||||
|
||||
static int writeOffset(FILE *stream, const struct writeoutvar *wovar,
|
||||
struct per_transfer *per, CURLcode per_result,
|
||||
bool use_json)
|
||||
{
|
||||
bool valid = false;
|
||||
curl_off_t offinfo = 0;
|
||||
|
||||
(void)per;
|
||||
(void)per_result;
|
||||
DEBUGASSERT(wovar->writefunc == writeOffset);
|
||||
|
||||
if(wovar->ci) {
|
||||
if(!curl_easy_getinfo(per->curl, wovar->ci, &offinfo))
|
||||
valid = true;
|
||||
}
|
||||
else {
|
||||
switch(wovar->id) {
|
||||
case VAR_URLNUM:
|
||||
if(per->urlnum <= INT_MAX) {
|
||||
offinfo = per->urlnum;
|
||||
valid = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEBUGASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
if(valid) {
|
||||
if(use_json)
|
||||
curl_mfprintf(stream, "\"%s\":", wovar->name);
|
||||
|
||||
curl_mfprintf(stream, "%" CURL_FORMAT_CURL_OFF_T, offinfo);
|
||||
}
|
||||
else {
|
||||
if(use_json)
|
||||
curl_mfprintf(stream, "\"%s\":null", wovar->name);
|
||||
}
|
||||
|
||||
return 1; /* return 1 if anything was written */
|
||||
}
|
||||
|
||||
static int
|
||||
matchvar(const void *m1, const void *m2)
|
||||
{
|
||||
const struct writeoutvar *v1 = m1;
|
||||
const struct writeoutvar *v2 = m2;
|
||||
|
||||
return strcmp(v1->name, v2->name);
|
||||
}
|
||||
|
||||
#define MAX_WRITEOUT_NAME_LENGTH 24
|
||||
|
||||
/* return the position after %time{} */
|
||||
static const char *outtime(const char *ptr, /* %time{ ... */
|
||||
FILE *stream)
|
||||
{
|
||||
const char *end;
|
||||
ptr += 6;
|
||||
end = strchr(ptr, '}');
|
||||
if(end) {
|
||||
struct tm *utc;
|
||||
struct dynbuf format;
|
||||
char output[256]; /* max output time length */
|
||||
#ifdef HAVE_GETTIMEOFDAY
|
||||
struct timeval cnow;
|
||||
#else
|
||||
struct curltime cnow;
|
||||
#endif
|
||||
time_t secs;
|
||||
unsigned int usecs;
|
||||
size_t i;
|
||||
size_t vlen;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
#ifdef HAVE_GETTIMEOFDAY
|
||||
gettimeofday(&cnow, NULL);
|
||||
#else
|
||||
cnow.tv_sec = time(NULL);
|
||||
cnow.tv_usec = 0;
|
||||
#endif
|
||||
secs = cnow.tv_sec;
|
||||
usecs = (unsigned int)cnow.tv_usec;
|
||||
#ifdef DEBUGBUILD
|
||||
{
|
||||
const char *timestr = getenv("CURL_TIME");
|
||||
if(timestr) {
|
||||
curl_off_t val;
|
||||
curlx_str_number(×tr, &val, TIME_T_MAX);
|
||||
secs = (time_t)val;
|
||||
usecs = (unsigned int)(val % 1000000);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
vlen = end - ptr;
|
||||
curlx_dyn_init(&format, 1024);
|
||||
|
||||
/* insert sub-seconds for %f */
|
||||
/* insert +0000 for %z because it is otherwise not portable */
|
||||
/* insert UTC for %Z because it is otherwise not portable */
|
||||
for(i = 0; !result && i < vlen; i++) {
|
||||
if((i < vlen - 1) && ptr[i] == '%' &&
|
||||
((ptr[i + 1] == 'f') || ((ptr[i + 1] | 0x20) == 'z'))) {
|
||||
if(ptr[i + 1] == 'f')
|
||||
result = curlx_dyn_addf(&format, "%06u", usecs);
|
||||
else if(ptr[i + 1] == 'Z')
|
||||
result = curlx_dyn_addn(&format, "UTC", 3);
|
||||
else
|
||||
result = curlx_dyn_addn(&format, "+0000", 5);
|
||||
i++;
|
||||
}
|
||||
else
|
||||
result = curlx_dyn_addn(&format, &ptr[i], 1);
|
||||
}
|
||||
if(!result) {
|
||||
/* !checksrc! disable BANNEDFUNC 1 */
|
||||
utc = gmtime(&secs);
|
||||
if(curlx_dyn_len(&format) && utc &&
|
||||
strftime(output, sizeof(output), curlx_dyn_ptr(&format), utc))
|
||||
fputs(output, stream);
|
||||
curlx_dyn_free(&format);
|
||||
}
|
||||
ptr = end + 1;
|
||||
}
|
||||
else
|
||||
fputs("%time{", stream);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static void separator(const char *sep, size_t seplen, FILE *stream)
|
||||
{
|
||||
while(seplen) {
|
||||
if(*sep == '\\') {
|
||||
switch(sep[1]) {
|
||||
case 'r':
|
||||
fputc('\r', stream);
|
||||
break;
|
||||
case 'n':
|
||||
fputc('\n', stream);
|
||||
break;
|
||||
case 't':
|
||||
fputc('\t', stream);
|
||||
break;
|
||||
case '}':
|
||||
fputc('}', stream);
|
||||
break;
|
||||
case '\0':
|
||||
break;
|
||||
default:
|
||||
/* unknown, just output this */
|
||||
fputc(sep[0], stream);
|
||||
fputc(sep[1], stream);
|
||||
break;
|
||||
}
|
||||
sep += 2;
|
||||
seplen -= 2;
|
||||
}
|
||||
else {
|
||||
fputc(*sep, stream);
|
||||
sep++;
|
||||
seplen--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void output_header(struct per_transfer *per,
|
||||
FILE *stream,
|
||||
const char **pptr)
|
||||
{
|
||||
const char *ptr = *pptr;
|
||||
const char *end;
|
||||
end = strchr(ptr, '}');
|
||||
do {
|
||||
if(!end || (end[-1] != '\\'))
|
||||
break;
|
||||
end = strchr(&end[1], '}');
|
||||
} while(end);
|
||||
if(end) {
|
||||
char hname[256]; /* holds the longest header field name */
|
||||
struct curl_header *header;
|
||||
const char *instr;
|
||||
const char *sep = NULL;
|
||||
size_t seplen = 0;
|
||||
size_t vlen = end - ptr;
|
||||
instr = memchr(ptr, ':', vlen);
|
||||
if(instr) {
|
||||
/* instructions follow */
|
||||
if(!strncmp(&instr[1], "all:", 4)) {
|
||||
sep = &instr[5];
|
||||
seplen = end - sep;
|
||||
vlen -= (seplen + 5);
|
||||
}
|
||||
}
|
||||
if(vlen < sizeof(hname)) {
|
||||
memcpy(hname, ptr, vlen);
|
||||
hname[vlen] = 0;
|
||||
if(sep) {
|
||||
/* get headers from all requests */
|
||||
int reqno = 0;
|
||||
size_t indno = 0;
|
||||
bool output = FALSE;
|
||||
do {
|
||||
if(CURLHE_OK == curl_easy_header(per->curl, hname, indno,
|
||||
CURLH_HEADER, reqno,
|
||||
&header)) {
|
||||
if(output)
|
||||
/* output separator */
|
||||
separator(sep, seplen, stream);
|
||||
fputs(header->value, stream);
|
||||
output = TRUE;
|
||||
}
|
||||
else
|
||||
break;
|
||||
if((header->index + 1) < header->amount)
|
||||
indno++;
|
||||
else {
|
||||
++reqno;
|
||||
indno = 0;
|
||||
}
|
||||
} while(1);
|
||||
}
|
||||
else {
|
||||
if(CURLHE_OK == curl_easy_header(per->curl, hname, 0,
|
||||
CURLH_HEADER, -1, &header))
|
||||
fputs(header->value, stream);
|
||||
}
|
||||
}
|
||||
ptr = end + 1;
|
||||
}
|
||||
else
|
||||
fputs("%header{", stream);
|
||||
*pptr = ptr;
|
||||
}
|
||||
|
||||
void ourWriteOut(struct OperationConfig *config, struct per_transfer *per,
|
||||
CURLcode per_result)
|
||||
{
|
||||
FILE *stream = stdout;
|
||||
const char *writeinfo = config->writeout;
|
||||
const char *ptr = writeinfo;
|
||||
bool done = FALSE;
|
||||
bool fclose_stream = FALSE;
|
||||
struct dynbuf name;
|
||||
|
||||
if(!writeinfo)
|
||||
return;
|
||||
|
||||
curlx_dyn_init(&name, MAX_WRITEOUT_NAME_LENGTH);
|
||||
while(ptr && *ptr && !done) {
|
||||
if('%' == *ptr && ptr[1]) {
|
||||
if('%' == ptr[1]) {
|
||||
/* an escaped %-letter */
|
||||
fputc('%', stream);
|
||||
ptr += 2;
|
||||
}
|
||||
else {
|
||||
/* this is meant as a variable to output */
|
||||
char *end;
|
||||
size_t vlen;
|
||||
if('{' == ptr[1]) {
|
||||
struct writeoutvar *wv = NULL;
|
||||
struct writeoutvar find = { 0 };
|
||||
end = strchr(ptr, '}');
|
||||
ptr += 2; /* pass the % and the { */
|
||||
if(!end) {
|
||||
fputs("%{", stream);
|
||||
continue;
|
||||
}
|
||||
vlen = end - ptr;
|
||||
|
||||
curlx_dyn_reset(&name);
|
||||
if(!curlx_dyn_addn(&name, ptr, vlen)) {
|
||||
find.name = curlx_dyn_ptr(&name);
|
||||
wv = bsearch(&find,
|
||||
variables, CURL_ARRAYSIZE(variables),
|
||||
sizeof(variables[0]), matchvar);
|
||||
}
|
||||
if(wv) {
|
||||
switch(wv->id) {
|
||||
case VAR_ONERROR:
|
||||
if(per_result == CURLE_OK)
|
||||
/* this is not error so skip the rest */
|
||||
done = TRUE;
|
||||
break;
|
||||
case VAR_STDOUT:
|
||||
if(fclose_stream)
|
||||
curlx_fclose(stream);
|
||||
fclose_stream = FALSE;
|
||||
stream = stdout;
|
||||
break;
|
||||
case VAR_STDERR:
|
||||
if(fclose_stream)
|
||||
curlx_fclose(stream);
|
||||
fclose_stream = FALSE;
|
||||
stream = tool_stderr;
|
||||
break;
|
||||
case VAR_JSON:
|
||||
ourWriteOutJSON(stream, variables,
|
||||
CURL_ARRAYSIZE(variables),
|
||||
per, per_result);
|
||||
break;
|
||||
case VAR_HEADER_JSON:
|
||||
headerJSON(stream, per);
|
||||
break;
|
||||
default:
|
||||
(void)wv->writefunc(stream, wv, per, per_result, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
curl_mfprintf(tool_stderr,
|
||||
"curl: unknown --write-out variable: '%.*s'\n",
|
||||
(int)vlen, ptr);
|
||||
}
|
||||
ptr = end + 1; /* pass the end */
|
||||
}
|
||||
else if(!strncmp("header{", &ptr[1], 7)) {
|
||||
ptr += 8;
|
||||
output_header(per, stream, &ptr);
|
||||
}
|
||||
else if(!strncmp("time{", &ptr[1], 5)) {
|
||||
ptr = outtime(ptr, stream);
|
||||
}
|
||||
else if(!strncmp("output{", &ptr[1], 7)) {
|
||||
bool append = FALSE;
|
||||
ptr += 8;
|
||||
if((ptr[0] == '>') && (ptr[1] == '>')) {
|
||||
append = TRUE;
|
||||
ptr += 2;
|
||||
}
|
||||
end = strchr(ptr, '}');
|
||||
if(end) {
|
||||
char fname[512]; /* holds the longest filename */
|
||||
size_t flen = end - ptr;
|
||||
if(flen < sizeof(fname)) {
|
||||
FILE *stream2;
|
||||
memcpy(fname, ptr, flen);
|
||||
fname[flen] = 0;
|
||||
stream2 = curlx_fopen(fname, append ? FOPEN_APPENDTEXT :
|
||||
FOPEN_WRITETEXT);
|
||||
if(stream2) {
|
||||
/* only change if the open worked */
|
||||
if(fclose_stream)
|
||||
curlx_fclose(stream);
|
||||
stream = stream2;
|
||||
fclose_stream = TRUE;
|
||||
}
|
||||
}
|
||||
ptr = end + 1;
|
||||
}
|
||||
else
|
||||
fputs("%output{", stream);
|
||||
}
|
||||
else {
|
||||
/* illegal syntax, then just output the characters that are used */
|
||||
fputc('%', stream);
|
||||
fputc(ptr[1], stream);
|
||||
ptr += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if('\\' == *ptr && ptr[1]) {
|
||||
switch(ptr[1]) {
|
||||
case 'r':
|
||||
fputc('\r', stream);
|
||||
break;
|
||||
case 'n':
|
||||
fputc('\n', stream);
|
||||
break;
|
||||
case 't':
|
||||
fputc('\t', stream);
|
||||
break;
|
||||
default:
|
||||
/* unknown, just output this */
|
||||
fputc(*ptr, stream);
|
||||
fputc(ptr[1], stream);
|
||||
break;
|
||||
}
|
||||
ptr += 2;
|
||||
}
|
||||
else {
|
||||
fputc(*ptr, stream);
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
if(fclose_stream)
|
||||
curlx_fclose(stream);
|
||||
curlx_dyn_free(&name);
|
||||
}
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
#ifndef HEADER_CURL_TOOL_WRITEOUT_H
|
||||
#define HEADER_CURL_TOOL_WRITEOUT_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
#include "tool_operate.h"
|
||||
|
||||
typedef enum {
|
||||
VAR_NONE, /* must be the first */
|
||||
VAR_APPCONNECT_TIME,
|
||||
VAR_CERT,
|
||||
VAR_CONNECT_TIME,
|
||||
VAR_CONTENT_TYPE,
|
||||
VAR_CONN_ID,
|
||||
VAR_EASY_ID,
|
||||
VAR_EFFECTIVE_FILENAME,
|
||||
VAR_EFFECTIVE_METHOD,
|
||||
VAR_EFFECTIVE_URL,
|
||||
VAR_ERRORMSG,
|
||||
VAR_EXITCODE,
|
||||
VAR_FTP_ENTRY_PATH,
|
||||
VAR_HEADER_JSON,
|
||||
VAR_HEADER_SIZE,
|
||||
VAR_HTTP_CODE,
|
||||
VAR_HTTP_CODE_PROXY,
|
||||
VAR_HTTP_VERSION,
|
||||
VAR_INPUT_URL,
|
||||
VAR_INPUT_URLSCHEME,
|
||||
VAR_INPUT_URLUSER,
|
||||
VAR_INPUT_URLPASSWORD,
|
||||
VAR_INPUT_URLOPTIONS,
|
||||
VAR_INPUT_URLHOST,
|
||||
VAR_INPUT_URLPORT,
|
||||
VAR_INPUT_URLPATH,
|
||||
VAR_INPUT_URLQUERY,
|
||||
VAR_INPUT_URLFRAGMENT,
|
||||
VAR_INPUT_URLZONEID,
|
||||
/* the same ones again for url *effective* */
|
||||
VAR_INPUT_URLESCHEME, /* keep this the first URLE* variable */
|
||||
VAR_INPUT_URLEUSER,
|
||||
VAR_INPUT_URLEPASSWORD,
|
||||
VAR_INPUT_URLEOPTIONS,
|
||||
VAR_INPUT_URLEHOST,
|
||||
VAR_INPUT_URLEPORT,
|
||||
VAR_INPUT_URLEPATH,
|
||||
VAR_INPUT_URLEQUERY,
|
||||
VAR_INPUT_URLEFRAGMENT,
|
||||
VAR_INPUT_URLEZONEID,
|
||||
VAR_JSON,
|
||||
VAR_LOCAL_IP,
|
||||
VAR_LOCAL_PORT,
|
||||
VAR_NAMELOOKUP_TIME,
|
||||
VAR_NUM_CERTS,
|
||||
VAR_NUM_CONNECTS,
|
||||
VAR_NUM_HEADERS,
|
||||
VAR_NUM_RETRY,
|
||||
VAR_ONERROR,
|
||||
VAR_PRETRANSFER_TIME,
|
||||
VAR_POSTTRANSFER_TIME,
|
||||
VAR_PRIMARY_IP,
|
||||
VAR_PRIMARY_PORT,
|
||||
VAR_PROXY_SSL_VERIFY_RESULT,
|
||||
VAR_PROXY_USED,
|
||||
VAR_QUEUE_TIME,
|
||||
VAR_REDIRECT_COUNT,
|
||||
VAR_REDIRECT_TIME,
|
||||
VAR_REDIRECT_URL,
|
||||
VAR_REFERER,
|
||||
VAR_REQUEST_SIZE,
|
||||
VAR_SCHEME,
|
||||
VAR_SIZE_DOWNLOAD,
|
||||
VAR_SIZE_UPLOAD,
|
||||
VAR_SPEED_DOWNLOAD,
|
||||
VAR_SPEED_UPLOAD,
|
||||
VAR_SSL_VERIFY_RESULT,
|
||||
VAR_STARTTRANSFER_TIME,
|
||||
VAR_STDERR,
|
||||
VAR_STDOUT,
|
||||
VAR_TLS_EARLYDATA_SENT,
|
||||
VAR_TOTAL_TIME,
|
||||
VAR_URLNUM,
|
||||
VAR_NUM_OF_VARS /* must be the last */
|
||||
} writeoutid;
|
||||
|
||||
struct writeoutvar {
|
||||
const char *name;
|
||||
writeoutid id;
|
||||
CURLINFO ci;
|
||||
int (*writefunc)(FILE *stream, const struct writeoutvar *wovar,
|
||||
struct per_transfer *per, CURLcode per_result,
|
||||
bool use_json);
|
||||
};
|
||||
|
||||
void ourWriteOut(struct OperationConfig *config, struct per_transfer *per,
|
||||
CURLcode per_result);
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_WRITEOUT_H */
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#include "tool_cfgable.h"
|
||||
#include "tool_writeout_json.h"
|
||||
#include "tool_writeout.h"
|
||||
|
||||
#define MAX_JSON_STRING 100000
|
||||
|
||||
/* provide the given string in dynbuf as a quoted json string, but without the
|
||||
outer quotes. The buffer is not inited by this function.
|
||||
|
||||
Return 0 on success, non-zero on error.
|
||||
*/
|
||||
int jsonquoted(const char *in, size_t len,
|
||||
struct dynbuf *out, bool lowercase)
|
||||
{
|
||||
const unsigned char *i = (const unsigned char *)in;
|
||||
const unsigned char *in_end = &i[len];
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
for(; (i < in_end) && !result; i++) {
|
||||
switch(*i) {
|
||||
case '\\':
|
||||
result = curlx_dyn_addn(out, "\\\\", 2);
|
||||
break;
|
||||
case '\"':
|
||||
result = curlx_dyn_addn(out, "\\\"", 2);
|
||||
break;
|
||||
case '\b':
|
||||
result = curlx_dyn_addn(out, "\\b", 2);
|
||||
break;
|
||||
case '\f':
|
||||
result = curlx_dyn_addn(out, "\\f", 2);
|
||||
break;
|
||||
case '\n':
|
||||
result = curlx_dyn_addn(out, "\\n", 2);
|
||||
break;
|
||||
case '\r':
|
||||
result = curlx_dyn_addn(out, "\\r", 2);
|
||||
break;
|
||||
case '\t':
|
||||
result = curlx_dyn_addn(out, "\\t", 2);
|
||||
break;
|
||||
default:
|
||||
if(*i < 32)
|
||||
result = curlx_dyn_addf(out, "\\u%04x", *i);
|
||||
else {
|
||||
char o = (char)*i;
|
||||
if(lowercase && (o >= 'A' && o <= 'Z'))
|
||||
/* do not use tolower() since that is locale specific */
|
||||
o |= ('a' - 'A');
|
||||
result = curlx_dyn_addn(out, &o, 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(result)
|
||||
return (int)result;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void jsonWriteString(FILE *stream, const char *in, bool lowercase)
|
||||
{
|
||||
struct dynbuf out;
|
||||
curlx_dyn_init(&out, MAX_JSON_STRING);
|
||||
|
||||
if(!jsonquoted(in, strlen(in), &out, lowercase)) {
|
||||
fputc('\"', stream);
|
||||
if(curlx_dyn_len(&out))
|
||||
fputs(curlx_dyn_ptr(&out), stream);
|
||||
fputc('\"', stream);
|
||||
}
|
||||
curlx_dyn_free(&out);
|
||||
}
|
||||
|
||||
void ourWriteOutJSON(FILE *stream, const struct writeoutvar mappings[],
|
||||
size_t nentries,
|
||||
struct per_transfer *per, CURLcode per_result)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
fputs("{", stream);
|
||||
|
||||
for(i = 0; i < nentries; i++) {
|
||||
if(mappings[i].writefunc &&
|
||||
mappings[i].writefunc(stream, &mappings[i], per, per_result, true))
|
||||
fputs(",", stream);
|
||||
}
|
||||
|
||||
/* The variables are sorted in alphabetical order but as a special case
|
||||
curl_version (which is not actually a --write-out variable) is last. */
|
||||
curl_mfprintf(stream, "\"curl_version\":");
|
||||
jsonWriteString(stream, curl_version(), FALSE);
|
||||
curl_mfprintf(stream, "}");
|
||||
}
|
||||
|
||||
void headerJSON(FILE *stream, struct per_transfer *per)
|
||||
{
|
||||
struct curl_header *header;
|
||||
struct curl_header *prev = NULL;
|
||||
|
||||
fputc('{', stream);
|
||||
while((header = curl_easy_nextheader(per->curl, CURLH_HEADER, -1,
|
||||
prev)) != NULL) {
|
||||
if(header->amount > 1) {
|
||||
if(!header->index) {
|
||||
/* act on the 0-index entry and pull the others in, then output in a
|
||||
JSON list */
|
||||
size_t a = header->amount;
|
||||
size_t i = 0;
|
||||
char *name = header->name;
|
||||
if(prev)
|
||||
fputs(",\n", stream);
|
||||
jsonWriteString(stream, header->name, TRUE);
|
||||
fputc(':', stream);
|
||||
prev = header;
|
||||
fputc('[', stream);
|
||||
do {
|
||||
jsonWriteString(stream, header->value, FALSE);
|
||||
if(++i >= a)
|
||||
break;
|
||||
fputc(',', stream);
|
||||
if(curl_easy_header(per->curl, name, i, CURLH_HEADER,
|
||||
-1, &header))
|
||||
break;
|
||||
} while(1);
|
||||
fputc(']', stream);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(prev)
|
||||
fputs(",\n", stream);
|
||||
jsonWriteString(stream, header->name, TRUE);
|
||||
fputc(':', stream);
|
||||
fputc('[', stream);
|
||||
jsonWriteString(stream, header->value, FALSE);
|
||||
fputc(']', stream);
|
||||
prev = header;
|
||||
}
|
||||
}
|
||||
fputs("\n}", stream);
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
#ifndef HEADER_CURL_TOOL_WRITEOUT_JSON_H
|
||||
#define HEADER_CURL_TOOL_WRITEOUT_JSON_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
#include "tool_writeout.h"
|
||||
|
||||
int jsonquoted(const char *in, size_t len,
|
||||
struct dynbuf *out, bool lowercase);
|
||||
|
||||
void ourWriteOutJSON(FILE *stream, const struct writeoutvar mappings[],
|
||||
size_t nentries,
|
||||
struct per_transfer *per, CURLcode per_result);
|
||||
void headerJSON(FILE *stream, struct per_transfer *per);
|
||||
void jsonWriteString(FILE *stream, const char *in, bool lowercase);
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_WRITEOUT_H */
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
#include "tool_xattr.h"
|
||||
|
||||
#include "memdebug.h" /* keep this as LAST include */
|
||||
|
||||
#ifdef USE_XATTR
|
||||
|
||||
/* mapping table of curl metadata to extended attribute names */
|
||||
static const struct xattr_mapping {
|
||||
const char *attr; /* name of the xattr */
|
||||
CURLINFO info;
|
||||
} mappings[] = {
|
||||
/* mappings proposed by
|
||||
* https://freedesktop.org/wiki/CommonExtendedAttributes/
|
||||
*/
|
||||
{ "user.xdg.referrer.url", CURLINFO_REFERER },
|
||||
{ "user.mime_type", CURLINFO_CONTENT_TYPE },
|
||||
{ NULL, CURLINFO_NONE } /* last element, abort here */
|
||||
};
|
||||
|
||||
/* returns a new URL that needs to be freed */
|
||||
/* @unittest: 1621 */
|
||||
UNITTEST char *stripcredentials(const char *url)
|
||||
{
|
||||
CURLU *u;
|
||||
CURLUcode uc;
|
||||
char *nurl;
|
||||
u = curl_url();
|
||||
if(u) {
|
||||
uc = curl_url_set(u, CURLUPART_URL, url, CURLU_GUESS_SCHEME);
|
||||
if(uc)
|
||||
goto error;
|
||||
|
||||
uc = curl_url_set(u, CURLUPART_USER, NULL, 0);
|
||||
if(uc)
|
||||
goto error;
|
||||
|
||||
uc = curl_url_set(u, CURLUPART_PASSWORD, NULL, 0);
|
||||
if(uc)
|
||||
goto error;
|
||||
|
||||
uc = curl_url_get(u, CURLUPART_URL, &nurl, 0);
|
||||
if(uc)
|
||||
goto error;
|
||||
|
||||
curl_url_cleanup(u);
|
||||
|
||||
return nurl;
|
||||
}
|
||||
error:
|
||||
curl_url_cleanup(u);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int xattr(int fd,
|
||||
const char *attr, /* name of the xattr */
|
||||
const char *value)
|
||||
{
|
||||
int err = 0;
|
||||
if(value) {
|
||||
#ifdef DEBUGBUILD
|
||||
if(getenv("CURL_FAKE_XATTR")) {
|
||||
curl_mprintf("%s => %s\n", attr, value);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_FSETXATTR_6
|
||||
err = fsetxattr(fd, attr, value, strlen(value), 0, 0);
|
||||
#elif defined(HAVE_FSETXATTR_5)
|
||||
err = fsetxattr(fd, attr, value, strlen(value), 0);
|
||||
#elif defined(__FreeBSD_version) || defined(__MidnightBSD_version)
|
||||
{
|
||||
ssize_t rc = extattr_set_fd(fd, EXTATTR_NAMESPACE_USER,
|
||||
attr, value, strlen(value));
|
||||
/* FreeBSD's extattr_set_fd returns the length of the extended
|
||||
attribute */
|
||||
err = (rc < 0 ? -1 : 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return err;
|
||||
}
|
||||
/* store metadata from the curl request alongside the downloaded
|
||||
* file using extended attributes
|
||||
*/
|
||||
int fwrite_xattr(CURL *curl, const char *url, int fd)
|
||||
{
|
||||
int i = 0;
|
||||
int err = xattr(fd, "user.creator", "curl");
|
||||
|
||||
/* loop through all xattr-curlinfo pairs and abort on a set error */
|
||||
while(!err && mappings[i].attr) {
|
||||
char *value = NULL;
|
||||
CURLcode result = curl_easy_getinfo(curl, mappings[i].info, &value);
|
||||
if(!result && value)
|
||||
err = xattr(fd, mappings[i].attr, value);
|
||||
i++;
|
||||
}
|
||||
if(!err) {
|
||||
char *nurl = stripcredentials(url);
|
||||
if(!nurl)
|
||||
return 1;
|
||||
err = xattr(fd, "user.xdg.origin.url", nurl);
|
||||
curl_free(nurl);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
#ifndef HEADER_CURL_TOOL_XATTR_H
|
||||
#define HEADER_CURL_TOOL_XATTR_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#ifdef HAVE_FSETXATTR
|
||||
# include <sys/xattr.h> /* header from libc, not from libattr */
|
||||
# define USE_XATTR
|
||||
#elif (defined(__FreeBSD_version) && (__FreeBSD_version > 500000)) || \
|
||||
defined(__MidnightBSD_version)
|
||||
# include <sys/types.h>
|
||||
# include <sys/extattr.h>
|
||||
# define USE_XATTR
|
||||
#endif
|
||||
|
||||
#ifdef USE_XATTR
|
||||
int fwrite_xattr(CURL *curl, const char *url, int fd);
|
||||
|
||||
#ifdef UNITTESTS
|
||||
UNITTEST char *stripcredentials(const char *url);
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define fwrite_xattr(a,b,c) 0
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_XATTR_H */
|
||||
Vendored
+502
@@ -0,0 +1,502 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "tool_setup.h"
|
||||
|
||||
#include "tool_cfgable.h"
|
||||
#include "tool_getparam.h"
|
||||
#include "tool_helpers.h"
|
||||
#include "tool_findfile.h"
|
||||
#include "tool_msgs.h"
|
||||
#include "tool_parsecfg.h"
|
||||
#include "tool_paramhlp.h"
|
||||
#include "tool_writeout_json.h"
|
||||
#include "tool_strdup.h"
|
||||
#include "var.h"
|
||||
#include "memdebug.h" /* keep this as LAST include */
|
||||
|
||||
#define MAX_EXPAND_CONTENT 10000000
|
||||
#define MAX_VAR_LEN 128 /* max length of a name */
|
||||
|
||||
/* free everything */
|
||||
void varcleanup(void)
|
||||
{
|
||||
struct tool_var *list = global->variables;
|
||||
while(list) {
|
||||
struct tool_var *t = list;
|
||||
list = list->next;
|
||||
free(CURL_UNCONST(t->content));
|
||||
free(t);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct tool_var *varcontent(const char *name, size_t nlen)
|
||||
{
|
||||
struct tool_var *list = global->variables;
|
||||
while(list) {
|
||||
if((strlen(list->name) == nlen) &&
|
||||
!strncmp(name, list->name, nlen)) {
|
||||
return list;
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define ENDOFFUNC(x) (((x) == '}') || ((x) == ':'))
|
||||
#define FUNCMATCH(ptr,name,len) \
|
||||
(!strncmp(ptr, name, len) && ENDOFFUNC(ptr[len]))
|
||||
|
||||
#define FUNC_TRIM "trim"
|
||||
#define FUNC_TRIM_LEN (sizeof(FUNC_TRIM) - 1)
|
||||
#define FUNC_JSON "json"
|
||||
#define FUNC_JSON_LEN (sizeof(FUNC_JSON) - 1)
|
||||
#define FUNC_URL "url"
|
||||
#define FUNC_URL_LEN (sizeof(FUNC_URL) - 1)
|
||||
#define FUNC_B64 "b64"
|
||||
#define FUNC_B64_LEN (sizeof(FUNC_B64) - 1)
|
||||
#define FUNC_64DEC "64dec" /* base64 decode */
|
||||
#define FUNC_64DEC_LEN (sizeof(FUNC_64DEC) - 1)
|
||||
|
||||
static ParameterError varfunc(char *c, /* content */
|
||||
size_t clen, /* content length */
|
||||
char *f, /* functions */
|
||||
size_t flen, /* function string length */
|
||||
struct dynbuf *out)
|
||||
{
|
||||
bool alloc = FALSE;
|
||||
ParameterError err = PARAM_OK;
|
||||
const char *finput = f;
|
||||
|
||||
/* The functions are independent and runs left to right */
|
||||
while(*f && !err) {
|
||||
if(*f == '}')
|
||||
/* end of functions */
|
||||
break;
|
||||
/* On entry, this is known to be a colon already. In subsequent laps, it
|
||||
is also known to be a colon since that is part of the FUNCMATCH()
|
||||
checks */
|
||||
f++;
|
||||
if(FUNCMATCH(f, FUNC_TRIM, FUNC_TRIM_LEN)) {
|
||||
size_t len = clen;
|
||||
f += FUNC_TRIM_LEN;
|
||||
if(clen) {
|
||||
/* skip leading white space, including CRLF */
|
||||
while(ISSPACE(*c)) {
|
||||
c++;
|
||||
len--;
|
||||
}
|
||||
while(len && ISSPACE(c[len-1]))
|
||||
len--;
|
||||
}
|
||||
/* put it in the output */
|
||||
curlx_dyn_reset(out);
|
||||
if(curlx_dyn_addn(out, c, len)) {
|
||||
err = PARAM_NO_MEM;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(FUNCMATCH(f, FUNC_JSON, FUNC_JSON_LEN)) {
|
||||
f += FUNC_JSON_LEN;
|
||||
curlx_dyn_reset(out);
|
||||
if(clen) {
|
||||
if(jsonquoted(c, clen, out, FALSE)) {
|
||||
err = PARAM_NO_MEM;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(FUNCMATCH(f, FUNC_URL, FUNC_URL_LEN)) {
|
||||
f += FUNC_URL_LEN;
|
||||
curlx_dyn_reset(out);
|
||||
if(clen) {
|
||||
char *enc = curl_easy_escape(NULL, c, (int)clen);
|
||||
if(!enc) {
|
||||
err = PARAM_NO_MEM;
|
||||
break;
|
||||
}
|
||||
|
||||
/* put it in the output */
|
||||
if(curlx_dyn_add(out, enc))
|
||||
err = PARAM_NO_MEM;
|
||||
curl_free(enc);
|
||||
if(err)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(FUNCMATCH(f, FUNC_B64, FUNC_B64_LEN)) {
|
||||
f += FUNC_B64_LEN;
|
||||
curlx_dyn_reset(out);
|
||||
if(clen) {
|
||||
char *enc;
|
||||
size_t elen;
|
||||
CURLcode result = curlx_base64_encode(c, clen, &enc, &elen);
|
||||
if(result) {
|
||||
err = PARAM_NO_MEM;
|
||||
break;
|
||||
}
|
||||
|
||||
/* put it in the output */
|
||||
if(curlx_dyn_addn(out, enc, elen))
|
||||
err = PARAM_NO_MEM;
|
||||
curl_free(enc);
|
||||
if(err)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(FUNCMATCH(f, FUNC_64DEC, FUNC_64DEC_LEN)) {
|
||||
f += FUNC_64DEC_LEN;
|
||||
curlx_dyn_reset(out);
|
||||
if(clen) {
|
||||
unsigned char *enc;
|
||||
size_t elen;
|
||||
CURLcode result = curlx_base64_decode(c, &enc, &elen);
|
||||
/* put it in the output */
|
||||
if(result) {
|
||||
if(curlx_dyn_add(out, "[64dec-fail]"))
|
||||
err = PARAM_NO_MEM;
|
||||
}
|
||||
else {
|
||||
if(curlx_dyn_addn(out, enc, elen))
|
||||
err = PARAM_NO_MEM;
|
||||
curl_free(enc);
|
||||
}
|
||||
if(err)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* unsupported function */
|
||||
errorf("unknown variable function in '%.*s'", (int)flen, finput);
|
||||
err = PARAM_EXPAND_ERROR;
|
||||
break;
|
||||
}
|
||||
if(alloc)
|
||||
free(c);
|
||||
|
||||
clen = curlx_dyn_len(out);
|
||||
c = memdup0(curlx_dyn_ptr(out), clen);
|
||||
if(!c) {
|
||||
err = PARAM_NO_MEM;
|
||||
break;
|
||||
}
|
||||
alloc = TRUE;
|
||||
}
|
||||
if(alloc)
|
||||
free(c);
|
||||
if(err)
|
||||
curlx_dyn_free(out);
|
||||
return err;
|
||||
}
|
||||
|
||||
ParameterError varexpand(const char *line, struct dynbuf *out,
|
||||
bool *replaced)
|
||||
{
|
||||
CURLcode result;
|
||||
char *envp;
|
||||
bool added = FALSE;
|
||||
const char *input = line;
|
||||
*replaced = FALSE;
|
||||
curlx_dyn_init(out, MAX_EXPAND_CONTENT);
|
||||
do {
|
||||
envp = strstr(line, "{{");
|
||||
if((envp > line) && envp[-1] == '\\') {
|
||||
/* preceding backslash, we want this verbatim */
|
||||
|
||||
/* insert the text up to this point, minus the backslash */
|
||||
result = curlx_dyn_addn(out, line, envp - line - 1);
|
||||
if(result)
|
||||
return PARAM_NO_MEM;
|
||||
|
||||
/* output '{{' then continue from here */
|
||||
result = curlx_dyn_addn(out, "{{", 2);
|
||||
if(result)
|
||||
return PARAM_NO_MEM;
|
||||
line = &envp[2];
|
||||
}
|
||||
else if(envp) {
|
||||
char name[MAX_VAR_LEN];
|
||||
size_t nlen;
|
||||
size_t i;
|
||||
char *funcp;
|
||||
char *clp = strstr(envp, "}}");
|
||||
size_t prefix;
|
||||
|
||||
if(!clp) {
|
||||
/* uneven braces */
|
||||
warnf("missing close '}}' in '%s'", input);
|
||||
break;
|
||||
}
|
||||
|
||||
prefix = 2;
|
||||
envp += 2; /* move over the {{ */
|
||||
|
||||
/* if there is a function, it ends the name with a colon */
|
||||
funcp = memchr(envp, ':', clp - envp);
|
||||
if(funcp)
|
||||
nlen = funcp - envp;
|
||||
else
|
||||
nlen = clp - envp;
|
||||
if(!nlen || (nlen >= sizeof(name))) {
|
||||
warnf("bad variable name length '%s'", input);
|
||||
/* insert the text as-is since this is not an env variable */
|
||||
result = curlx_dyn_addn(out, line, clp - line + prefix);
|
||||
if(result)
|
||||
return PARAM_NO_MEM;
|
||||
}
|
||||
else {
|
||||
/* insert the text up to this point */
|
||||
result = curlx_dyn_addn(out, line, envp - prefix - line);
|
||||
if(result)
|
||||
return PARAM_NO_MEM;
|
||||
|
||||
/* copy the name to separate buffer */
|
||||
memcpy(name, envp, nlen);
|
||||
name[nlen] = 0;
|
||||
|
||||
/* verify that the name looks sensible */
|
||||
for(i = 0; (i < nlen) &&
|
||||
(ISALNUM(name[i]) || (name[i] == '_')); i++);
|
||||
if(i != nlen) {
|
||||
warnf("bad variable name: %s", name);
|
||||
/* insert the text as-is since this is not an env variable */
|
||||
result = curlx_dyn_addn(out, envp - prefix,
|
||||
clp - envp + prefix + 2);
|
||||
if(result)
|
||||
return PARAM_NO_MEM;
|
||||
}
|
||||
else {
|
||||
char *value;
|
||||
size_t vlen = 0;
|
||||
struct dynbuf buf;
|
||||
const struct tool_var *v = varcontent(name, nlen);
|
||||
if(v) {
|
||||
value = (char *)CURL_UNCONST(v->content);
|
||||
vlen = v->clen;
|
||||
}
|
||||
else
|
||||
value = NULL;
|
||||
|
||||
curlx_dyn_init(&buf, MAX_EXPAND_CONTENT);
|
||||
if(funcp) {
|
||||
/* apply the list of functions on the value */
|
||||
size_t flen = clp - funcp;
|
||||
ParameterError err = varfunc(value, vlen, funcp, flen, &buf);
|
||||
if(err)
|
||||
return err;
|
||||
value = curlx_dyn_ptr(&buf);
|
||||
vlen = curlx_dyn_len(&buf);
|
||||
}
|
||||
|
||||
if(value && vlen > 0) {
|
||||
/* A variable might contain null bytes. Such bytes cannot be shown
|
||||
using normal means, this is an error. */
|
||||
char *nb = memchr(value, '\0', vlen);
|
||||
if(nb) {
|
||||
errorf("variable contains null byte");
|
||||
return PARAM_EXPAND_ERROR;
|
||||
}
|
||||
}
|
||||
/* insert the value */
|
||||
result = curlx_dyn_addn(out, value, vlen);
|
||||
curlx_dyn_free(&buf);
|
||||
if(result)
|
||||
return PARAM_NO_MEM;
|
||||
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
line = &clp[2];
|
||||
}
|
||||
|
||||
} while(envp);
|
||||
if(added && *line) {
|
||||
/* add the "suffix" as well */
|
||||
result = curlx_dyn_add(out, line);
|
||||
if(result)
|
||||
return PARAM_NO_MEM;
|
||||
}
|
||||
*replaced = added;
|
||||
if(!added)
|
||||
curlx_dyn_free(out);
|
||||
return PARAM_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Created in a way that is not revealing how variables are actually stored so
|
||||
* that we can improve this if we want better performance when managing many
|
||||
* at a later point.
|
||||
*/
|
||||
static ParameterError addvariable(const char *name,
|
||||
size_t nlen,
|
||||
const char *content,
|
||||
size_t clen,
|
||||
bool contalloc)
|
||||
{
|
||||
struct tool_var *p;
|
||||
const struct tool_var *check = varcontent(name, nlen);
|
||||
DEBUGASSERT(nlen);
|
||||
if(check)
|
||||
notef("Overwriting variable '%s'", check->name);
|
||||
|
||||
p = calloc(1, sizeof(struct tool_var) + nlen);
|
||||
if(p) {
|
||||
memcpy(p->name, name, nlen);
|
||||
/* the null termination byte is already present from above */
|
||||
|
||||
p->content = contalloc ? content : memdup0(content, clen);
|
||||
if(p->content) {
|
||||
p->clen = clen;
|
||||
|
||||
p->next = global->variables;
|
||||
global->variables = p;
|
||||
return PARAM_OK;
|
||||
}
|
||||
free(p);
|
||||
}
|
||||
return PARAM_NO_MEM;
|
||||
}
|
||||
|
||||
#define MAX_FILENAME 10000
|
||||
|
||||
ParameterError setvariable(const char *input)
|
||||
{
|
||||
const char *name;
|
||||
size_t nlen;
|
||||
char *content = NULL;
|
||||
size_t clen = 0;
|
||||
bool contalloc = FALSE;
|
||||
const char *line = input;
|
||||
ParameterError err = PARAM_OK;
|
||||
bool import = FALSE;
|
||||
char *ge = NULL;
|
||||
char buf[MAX_VAR_LEN];
|
||||
curl_off_t startoffset = 0;
|
||||
curl_off_t endoffset = CURL_OFF_T_MAX;
|
||||
|
||||
if(*input == '%') {
|
||||
import = TRUE;
|
||||
line++;
|
||||
}
|
||||
name = line;
|
||||
while(*line && (ISALNUM(*line) || (*line == '_')))
|
||||
line++;
|
||||
nlen = line - name;
|
||||
if(!nlen || (nlen >= MAX_VAR_LEN)) {
|
||||
warnf("Bad variable name length (%zd), skipping", nlen);
|
||||
return PARAM_OK;
|
||||
}
|
||||
if(import) {
|
||||
/* this does not use curl_getenv() because we want "" support for blank
|
||||
content */
|
||||
if(*line) {
|
||||
/* if there is a default action, we need to copy the name */
|
||||
memcpy(buf, name, nlen);
|
||||
buf[nlen] = 0;
|
||||
name = buf;
|
||||
}
|
||||
ge = getenv(name);
|
||||
if(!*line && !ge) {
|
||||
/* no assign, no variable, fail */
|
||||
errorf("Variable '%s' import fail, not set", name);
|
||||
return PARAM_EXPAND_ERROR;
|
||||
}
|
||||
else if(ge) {
|
||||
/* there is a value to use */
|
||||
content = ge;
|
||||
clen = strlen(ge);
|
||||
}
|
||||
}
|
||||
if(*line == '[' && ISDIGIT(line[1])) {
|
||||
/* is there a byte range specified? [num-num] */
|
||||
line++;
|
||||
if(curlx_str_number(&line, &startoffset, CURL_OFF_T_MAX) ||
|
||||
curlx_str_single(&line, '-'))
|
||||
return PARAM_VAR_SYNTAX;
|
||||
if(curlx_str_single(&line, ']')) {
|
||||
if(curlx_str_number(&line, &endoffset, CURL_OFF_T_MAX) ||
|
||||
curlx_str_single(&line, ']'))
|
||||
return PARAM_VAR_SYNTAX;
|
||||
}
|
||||
if(startoffset > endoffset)
|
||||
return PARAM_VAR_SYNTAX;
|
||||
}
|
||||
if(content)
|
||||
;
|
||||
else if(*line == '@') {
|
||||
/* read from file or stdin */
|
||||
FILE *file;
|
||||
bool use_stdin;
|
||||
line++;
|
||||
|
||||
use_stdin = !strcmp(line, "-");
|
||||
if(use_stdin)
|
||||
file = stdin;
|
||||
else {
|
||||
file = curlx_fopen(line, "rb");
|
||||
if(!file) {
|
||||
char errbuf[STRERROR_LEN];
|
||||
errorf("Failed to open %s: %s", line,
|
||||
curlx_strerror(errno, errbuf, sizeof(errbuf)));
|
||||
err = PARAM_READ_ERROR;
|
||||
}
|
||||
}
|
||||
if(!err) {
|
||||
err = file2memory_range(&content, &clen, file, startoffset, endoffset);
|
||||
/* in case of out of memory, this should fail the entire operation */
|
||||
if(clen)
|
||||
contalloc = TRUE;
|
||||
}
|
||||
if(!use_stdin && file)
|
||||
curlx_fclose(file);
|
||||
if(err)
|
||||
return err;
|
||||
}
|
||||
else if(*line == '=') {
|
||||
line++;
|
||||
clen = strlen(line);
|
||||
/* this is the exact content */
|
||||
content = (char *)CURL_UNCONST(line);
|
||||
if(startoffset || (endoffset != CURL_OFF_T_MAX)) {
|
||||
if(startoffset >= (curl_off_t)clen)
|
||||
clen = 0;
|
||||
else {
|
||||
/* make the end offset no larger than the last byte */
|
||||
if(endoffset >= (curl_off_t)clen)
|
||||
endoffset = clen - 1;
|
||||
clen = (size_t)(endoffset - startoffset) + 1;
|
||||
content += startoffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
warnf("Bad --variable syntax, skipping: %s", input);
|
||||
return PARAM_OK;
|
||||
}
|
||||
err = addvariable(name, nlen, content, clen, contalloc);
|
||||
if(err) {
|
||||
if(contalloc)
|
||||
free(content);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
Vendored
+43
@@ -0,0 +1,43 @@
|
||||
#ifndef HEADER_CURL_VAR_H
|
||||
#define HEADER_CURL_VAR_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 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.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.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include "tool_getparam.h"
|
||||
|
||||
struct tool_var {
|
||||
struct tool_var *next;
|
||||
const char *content;
|
||||
size_t clen; /* content length */
|
||||
char name[1]; /* allocated as part of the struct */
|
||||
};
|
||||
|
||||
ParameterError setvariable(const char *input);
|
||||
ParameterError varexpand(const char *line, struct dynbuf *out,
|
||||
bool *replaced);
|
||||
|
||||
/* free everything */
|
||||
void varcleanup(void);
|
||||
|
||||
#endif /* HEADER_CURL_VAR_H */
|
||||
Reference in New Issue
Block a user