Update networking layer w/ CURL and emscripten impl

This commit is contained in:
2025-11-08 01:50:36 +11:00
parent a17925904d
commit f6874dc55a
4105 changed files with 694617 additions and 179 deletions
+5
View File
@@ -0,0 +1,5 @@
# Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
#
# SPDX-License-Identifier: curl
enable STDERR
+148
View File
@@ -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}::
)
+243
View File
@@ -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)
File diff suppressed because it is too large Load Diff
+158
View File
@@ -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
File diff suppressed because it is too large Load Diff
+32
View File
@@ -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 */
+65
View File
@@ -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
+253
View File
@@ -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
View File
@@ -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
;
+262
View File
@@ -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
;
}
+74
View File
@@ -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 */
+57
View File
@@ -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 */
+89
View File
@@ -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 */
}
+30
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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, &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)));
}
#endif
}
#endif /* HAVE_UTIME || HAVE_UTIMES || _WIN32 */
+37
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 */
File diff suppressed because it is too large Load Diff
+396
View File
@@ -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
View File
@@ -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
View File
@@ -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 */
+407
View File
@@ -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);
}
+93
View File
@@ -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
View File
@@ -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
View File
@@ -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 */
File diff suppressed because it is too large Load Diff
+33
View File
@@ -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 */
+251
View File
@@ -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 */
+35
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 }
};
+223
View File
@@ -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 */
+39
View File
@@ -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 */
+147
View File
@@ -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);
}
}
+38
View File
@@ -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 */
File diff suppressed because it is too large Load Diff
+86
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 */
+212
View File
@@ -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;
}
+35
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 */
+137
View File
@@ -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
+41
View File
@@ -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
View File
@@ -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 */
+216
View File
@@ -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 */
+48
View File
@@ -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
View File
@@ -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(&timestr, &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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 */
+502
View File
@@ -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;
}
+43
View File
@@ -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 */