curl 2024-01-31 (5ce164e0)

Code extracted from:

    https://github.com/curl/curl.git

at commit 5ce164e0e9290c96eb7d502173426c0a135ec008 (curl-8_6_0).
stage/master/nightly/2024/02/01
Curl Upstream 2024-01-31 08:03:52 +01:00 committed by Brad King
parent fe5ffe06a9
commit 851cc904a0
137 changed files with 7356 additions and 4568 deletions

View File

@ -164,14 +164,11 @@ int main(void) { ; return 0; }
#ifdef HAVE_IOCTLSOCKET
/* includes start */
#ifdef HAVE_WINDOWS_H
#ifdef _WIN32
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# endif
# ifdef HAVE_WINSOCK2_H
# include <winsock2.h>
# endif
# include <windows.h>
# include <winsock2.h>
#endif
int main(void)
{
@ -186,14 +183,11 @@ int main(void)
#ifdef HAVE_IOCTLSOCKET_CAMEL
/* includes start */
#ifdef HAVE_WINDOWS_H
#ifdef _WIN32
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# endif
# ifdef HAVE_WINSOCK2_H
# include <winsock2.h>
# endif
# include <windows.h>
# include <winsock2.h>
#endif
int main(void)
{
@ -207,14 +201,11 @@ int main(void)
#ifdef HAVE_IOCTLSOCKET_CAMEL_FIONBIO
/* includes start */
#ifdef HAVE_WINDOWS_H
#ifdef _WIN32
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# endif
# ifdef HAVE_WINSOCK2_H
# include <winsock2.h>
# endif
# include <windows.h>
# include <winsock2.h>
#endif
int main(void)
{
@ -229,14 +220,11 @@ int main(void)
#ifdef HAVE_IOCTLSOCKET_FIONBIO
/* includes start */
#ifdef HAVE_WINDOWS_H
#ifdef _WIN32
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# endif
# ifdef HAVE_WINSOCK2_H
# include <winsock2.h>
# endif
# include <windows.h>
# include <winsock2.h>
#endif
int main(void)
{
@ -307,14 +295,11 @@ int main(void)
#ifdef HAVE_SETSOCKOPT_SO_NONBLOCK
/* includes start */
#ifdef HAVE_WINDOWS_H
#ifdef _WIN32
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# endif
# ifdef HAVE_WINSOCK2_H
# include <winsock2.h>
# endif
# include <windows.h>
# include <winsock2.h>
#endif
/* includes start */
#ifdef HAVE_SYS_TYPES_H

View File

@ -45,7 +45,7 @@ macro(curl_internal_test CURL_TEST)
"-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}")
endif()
message(STATUS "Performing Curl Test ${CURL_TEST}")
message(STATUS "Performing Test ${CURL_TEST}")
try_compile(${CURL_TEST}
${CMAKE_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/CMake/CurlTests.c
@ -54,15 +54,15 @@ macro(curl_internal_test CURL_TEST)
OUTPUT_VARIABLE OUTPUT)
if(${CURL_TEST})
set(${CURL_TEST} 1 CACHE INTERNAL "Curl test ${FUNCTION}")
message(STATUS "Performing Curl Test ${CURL_TEST} - Success")
message(STATUS "Performing Test ${CURL_TEST} - Success")
file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
"Performing Curl Test ${CURL_TEST} passed with the following output:\n"
"Performing Test ${CURL_TEST} passed with the following output:\n"
"${OUTPUT}\n")
else()
message(STATUS "Performing Curl Test ${CURL_TEST} - Failed")
message(STATUS "Performing Test ${CURL_TEST} - Failed")
set(${CURL_TEST} "" CACHE INTERNAL "Curl test ${FUNCTION}")
file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
"Performing Curl Test ${CURL_TEST} failed with the following output:\n"
"Performing Test ${CURL_TEST} failed with the following output:\n"
"${OUTPUT}\n")
endif()
endif()

View File

@ -23,115 +23,89 @@
###########################################################################
include(CheckCSourceCompiles)
include(CheckCSourceRuns)
# The begin of the sources (macros and includes)
set(_source_epilogue "#undef inline")
include(CheckTypeSize)
macro(add_header_include check header)
if(${check})
set(_source_epilogue "${_source_epilogue}\n#include <${header}>")
set(_source_epilogue "${_source_epilogue}
#include <${header}>")
endif()
endmacro()
set(signature_call_conv)
if(HAVE_WINDOWS_H)
set(_source_epilogue
"${_source_epilogue}\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN\n#endif")
add_header_include(HAVE_WINSOCK2_H "winsock2.h")
add_header_include(HAVE_WINDOWS_H "windows.h")
set(signature_call_conv "PASCAL")
if(WIN32)
set(CMAKE_REQUIRED_LIBRARIES "ws2_32")
endif()
else()
add_header_include(HAVE_SYS_TYPES_H "sys/types.h")
add_header_include(HAVE_SYS_SOCKET_H "sys/socket.h")
endif()
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
check_c_source_compiles("${_source_epilogue}
int main(void) {
int flag = MSG_NOSIGNAL;
(void)flag;
return 0;
}" HAVE_MSG_NOSIGNAL)
if(NOT HAVE_WINDOWS_H)
add_header_include(HAVE_SYS_TIME_H "sys/time.h")
endif()
check_c_source_compiles("${_source_epilogue}
#include <time.h>
int main(void) {
struct timeval ts;
ts.tv_sec = 0;
ts.tv_usec = 0;
(void)ts;
return 0;
}" HAVE_STRUCT_TIMEVAL)
if(HAVE_WINDOWS_H)
set(CMAKE_EXTRA_INCLUDE_FILES "winsock2.h")
else()
if(NOT DEFINED HAVE_STRUCT_SOCKADDR_STORAGE)
set(CMAKE_EXTRA_INCLUDE_FILES)
if(HAVE_SYS_SOCKET_H)
if(WIN32)
set(CMAKE_EXTRA_INCLUDE_FILES "winsock2.h")
set(CMAKE_REQUIRED_DEFINITIONS "-DWIN32_LEAN_AND_MEAN")
set(CMAKE_REQUIRED_LIBRARIES "ws2_32")
elseif(HAVE_SYS_SOCKET_H)
set(CMAKE_EXTRA_INCLUDE_FILES "sys/socket.h")
endif()
check_type_size("struct sockaddr_storage" SIZEOF_STRUCT_SOCKADDR_STORAGE)
set(HAVE_STRUCT_SOCKADDR_STORAGE ${HAVE_SIZEOF_STRUCT_SOCKADDR_STORAGE})
endif()
check_type_size("struct sockaddr_storage" SIZEOF_STRUCT_SOCKADDR_STORAGE)
if(HAVE_SIZEOF_STRUCT_SOCKADDR_STORAGE)
set(HAVE_STRUCT_SOCKADDR_STORAGE 1)
if(NOT WIN32)
set(_source_epilogue "#undef inline")
add_header_include(HAVE_SYS_TYPES_H "sys/types.h")
add_header_include(HAVE_SYS_SOCKET_H "sys/socket.h")
check_c_source_compiles("${_source_epilogue}
int main(void)
{
int flag = MSG_NOSIGNAL;
(void)flag;
return 0;
}" HAVE_MSG_NOSIGNAL)
endif()
set(_source_epilogue "#undef inline")
add_header_include(HAVE_SYS_TIME_H "sys/time.h")
check_c_source_compiles("${_source_epilogue}
#include <time.h>
int main(void)
{
struct timeval ts;
ts.tv_sec = 0;
ts.tv_usec = 0;
(void)ts;
return 0;
}" HAVE_STRUCT_TIMEVAL)
unset(CMAKE_TRY_COMPILE_TARGET_TYPE)
if(NOT CMAKE_CROSSCOMPILING)
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin" AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "iOS")
# only try this on non-apple platforms
if(NOT CMAKE_CROSSCOMPILING AND NOT APPLE)
set(_source_epilogue "#undef inline")
add_header_include(HAVE_SYS_POLL_H "sys/poll.h")
add_header_include(HAVE_POLL_H "poll.h")
check_c_source_runs("${_source_epilogue}
#include <stdlib.h>
#include <sys/time.h>
int main(void)
{
if(0 != poll(0, 0, 10)) {
return 1; /* fail */
}
else {
/* detect the 10.12 poll() breakage */
struct timeval before, after;
int rc;
size_t us;
# if not cross-compilation...
set(CMAKE_REQUIRED_FLAGS "")
if(HAVE_SYS_POLL_H)
set(CMAKE_REQUIRED_FLAGS "-DHAVE_SYS_POLL_H")
elseif(HAVE_POLL_H)
set(CMAKE_REQUIRED_FLAGS "-DHAVE_POLL_H")
endif()
check_c_source_runs("
#include <stdlib.h>
#include <sys/time.h>
gettimeofday(&before, NULL);
rc = poll(NULL, 0, 500);
gettimeofday(&after, NULL);
#ifdef HAVE_SYS_POLL_H
# include <sys/poll.h>
#elif HAVE_POLL_H
# include <poll.h>
#endif
us = (after.tv_sec - before.tv_sec) * 1000000 +
(after.tv_usec - before.tv_usec);
int main(void)
{
if(0 != poll(0, 0, 10)) {
return 1; /* fail */
}
else {
/* detect the 10.12 poll() breakage */
struct timeval before, after;
int rc;
size_t us;
gettimeofday(&before, NULL);
rc = poll(NULL, 0, 500);
gettimeofday(&after, NULL);
us = (after.tv_sec - before.tv_sec) * 1000000 +
(after.tv_usec - before.tv_usec);
if(us < 400000) {
return 1;
}
}
return 0;
if(us < 400000) {
return 1;
}
}
return 0;
}" HAVE_POLL_FINE)
endif()
endif()
# Detect HAVE_GETADDRINFO_THREADSAFE
@ -140,8 +114,8 @@ if(WIN32)
set(HAVE_GETADDRINFO_THREADSAFE ${HAVE_GETADDRINFO})
elseif(NOT HAVE_GETADDRINFO)
set(HAVE_GETADDRINFO_THREADSAFE FALSE)
elseif(CMAKE_SYSTEM_NAME STREQUAL "AIX" OR
CMAKE_SYSTEM_NAME STREQUAL "Darwin" OR
elseif(APPLE OR
CMAKE_SYSTEM_NAME STREQUAL "AIX" OR
CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "HP-UX" OR
CMAKE_SYSTEM_NAME STREQUAL "MidnightBSD" OR
@ -153,14 +127,10 @@ elseif(CMAKE_SYSTEM_NAME MATCHES "BSD")
endif()
if(NOT DEFINED HAVE_GETADDRINFO_THREADSAFE)
set(_save_epilogue "${_source_epilogue}")
set(_source_epilogue "#undef inline")
add_header_include(HAVE_SYS_SOCKET_H "sys/socket.h")
add_header_include(HAVE_SYS_TIME_H "sys/time.h")
add_header_include(HAVE_NETDB_H "netdb.h")
check_c_source_compiles("${_source_epilogue}
int main(void)
{
@ -197,17 +167,12 @@ if(NOT DEFINED HAVE_GETADDRINFO_THREADSAFE)
if(HAVE_H_ERRNO OR HAVE_H_ERRNO_ASSIGNABLE OR HAVE_H_ERRNO_SBS_ISSUE_7)
set(HAVE_GETADDRINFO_THREADSAFE TRUE)
endif()
set(_source_epilogue "${_save_epilogue}")
endif()
if(NOT WIN32 AND NOT DEFINED HAVE_CLOCK_GETTIME_MONOTONIC_RAW)
set(_save_epilogue "${_source_epilogue}")
set(_source_epilogue "#undef inline")
add_header_include(HAVE_SYS_TYPES_H "sys/types.h")
add_header_include(HAVE_SYS_TIME_H "sys/time.h")
check_c_source_compiles("${_source_epilogue}
#include <time.h>
int main(void)
@ -216,6 +181,4 @@ if(NOT WIN32 AND NOT DEFINED HAVE_CLOCK_GETTIME_MONOTONIC_RAW)
(void)clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
return 0;
}" HAVE_CLOCK_GETTIME_MONOTONIC_RAW)
set(_source_epilogue "${_save_epilogue}")
endif()

View File

@ -23,6 +23,12 @@
###########################################################################
include(CheckCCompilerFlag)
unset(WPICKY)
if(CURL_WERROR AND CMAKE_COMPILER_IS_GNUCC AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 5.0)
set(WPICKY "${WPICKY} -pedantic-errors")
endif()
if(PICKY_COMPILER)
if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
@ -83,11 +89,12 @@ if(PICKY_COMPILER)
-Wmissing-field-initializers # clang 2.7 gcc 4.1
-Wmissing-noreturn # clang 2.7 gcc 4.1
-Wno-format-nonliteral # clang 1.0 gcc 2.96 (3.0)
-Wno-sign-conversion # clang 2.9 gcc 4.3
-Wno-system-headers # clang 1.0 gcc 3.0
# -Wpadded # clang 2.9 gcc 4.1 # Not used because we cannot change public structs
-Wredundant-decls # clang 2.7 gcc 4.1
-Wold-style-definition # clang 2.7 gcc 3.4
-Wredundant-decls # clang 2.7 gcc 4.1
-Wsign-conversion # clang 2.9 gcc 4.3
-Wno-error=sign-conversion # FIXME
-Wstrict-prototypes # clang 1.0 gcc 3.3
# -Wswitch-enum # clang 2.7 gcc 4.1 # Not used because this basically disallows default case
-Wtype-limits # clang 2.7 gcc 4.3
@ -110,6 +117,7 @@ if(PICKY_COMPILER)
-Wshift-sign-overflow # clang 2.9
-Wshorten-64-to-32 # clang 1.0
-Wlanguage-extension-token # clang 3.0
-Wformat=2 # clang 3.0 gcc 4.8
)
# Enable based on compiler version
if((CMAKE_C_COMPILER_ID STREQUAL "Clang" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.6) OR
@ -135,6 +143,12 @@ if(PICKY_COMPILER)
-Wextra-semi-stmt # clang 7.0 appleclang 10.3
)
endif()
if((CMAKE_C_COMPILER_ID STREQUAL "Clang" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 10.0) OR
(CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 12.4))
list(APPEND WPICKY_ENABLE
-Wimplicit-fallthrough # clang 4.0 gcc 7.0 appleclang 12.4 # we have silencing markup for clang 10.0 and above only
)
endif()
else() # gcc
list(APPEND WPICKY_DETECT
${WPICKY_COMMON}
@ -147,6 +161,7 @@ if(PICKY_COMPILER)
-Wmissing-parameter-type # gcc 4.3
-Wold-style-declaration # gcc 4.3
-Wstrict-aliasing=3 # gcc 4.0
-Wtrampolines # gcc 4.3
)
endif()
if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.5 AND MINGW)
@ -156,7 +171,7 @@ if(PICKY_COMPILER)
endif()
if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.8)
list(APPEND WPICKY_ENABLE
-Wformat=2 # clang 3.0 gcc 4.8 (clang part-default, enabling it fully causes -Wformat-nonliteral warnings)
-Wformat=2 # clang 3.0 gcc 4.8
)
endif()
if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 5.0)
@ -179,6 +194,7 @@ if(PICKY_COMPILER)
-Wduplicated-branches # gcc 7.0
-Wformat-overflow=2 # gcc 7.0
-Wformat-truncation=2 # gcc 7.0
-Wimplicit-fallthrough # clang 4.0 gcc 7.0
-Wrestrict # gcc 7.0
)
endif()
@ -191,8 +207,6 @@ if(PICKY_COMPILER)
#
unset(WPICKY)
foreach(_CCOPT IN LISTS WPICKY_ENABLE)
set(WPICKY "${WPICKY} ${_CCOPT}")
endforeach()
@ -209,8 +223,10 @@ if(PICKY_COMPILER)
set(WPICKY "${WPICKY} ${_CCOPT}")
endif()
endforeach()
message(STATUS "Picky compiler options:${WPICKY}")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WPICKY}")
endif()
endif()
if(WPICKY)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WPICKY}")
message(STATUS "Picky compiler options:${WPICKY}")
endif()

View File

@ -171,6 +171,7 @@ set(HAVE_POSIX_STRERROR_R 0)
set(HAVE_BUILTIN_AVAILABLE 0)
set(HAVE_MSG_NOSIGNAL 0)
set(HAVE_STRUCT_TIMEVAL 1)
set(HAVE_STRUCT_SOCKADDR_STORAGE 1)
set(HAVE_GETHOSTBYNAME_R_3 0)
set(HAVE_GETHOSTBYNAME_R_3_REENTRANT 0)

View File

@ -21,25 +21,8 @@
# SPDX-License-Identifier: curl
#
###########################################################################
# curl/libcurl CMake script
# by Tetetest and Sukender (Benoit Neil)
# TODO:
# The output .so file lacks the soname number which we currently have within the lib/Makefile.am file
# Add full (4 or 5 libs) SSL support
# Add INSTALL target (EXTRA_DIST variables in Makefile.am may be moved to Makefile.inc so that CMake/CPack is aware of what's to include).
# Check on all possible platforms
# Test with as many configurations possible (With or without any option)
# Create scripts that help keeping the CMake build system up to date (to reduce maintenance). According to Tetetest:
# - lists of headers that 'configure' checks for;
# - curl-specific tests (the ones that are in m4/curl-*.m4 files);
# - (most obvious thing:) curl version numbers.
# Add documentation subproject
#
# To check:
# (From Daniel Stenberg) The cmake build selected to run gcc with -fPIC on my box while the plain configure script did not.
# (From Daniel Stenberg) The gcc command line use neither -g nor any -O options. As a developer, I also treasure our configure scripts's --enable-debug option that sets a long range of "picky" compiler options.
# Note: By default this CMake build script detects the version of some
# dependencies using `check_symbol_exists`. Those checks do not work
# in the case that both CURL and its dependency are included as
@ -105,7 +88,7 @@ option(BUILD_SHARED_LIBS "Build shared libraries" ON)
option(BUILD_STATIC_LIBS "Build static libraries" OFF)
option(BUILD_STATIC_CURL "Build curl executable with static libcurl" OFF)
option(ENABLE_ARES "Set to ON to enable c-ares support" OFF)
option(CURL_DISABLE_INSTALL "Set to ON to disable instalation targets" OFF)
option(CURL_DISABLE_INSTALL "Set to ON to disable installation targets" OFF)
if(WIN32)
option(CURL_STATIC_CRT "Set to ON to build libcurl with static CRT on Windows (/MT)." OFF)
@ -321,18 +304,22 @@ if(ENABLE_IPV6 AND NOT WIN32)
endif()
endif()
if(USE_MANUAL)
#nroff is currently only used when USE_MANUAL is set, so we can prevent the warning of no *NROFF if USE_MANUAL is OFF (or not defined), by not even looking for NROFF..
curl_nroff_check()
endif()
find_package(Perl)
cmake_dependent_option(ENABLE_MANUAL "to provide the built-in manual"
ON "NROFF_USEFUL;PERL_FOUND"
OFF)
option(BUILD_LIBCURL_DOCS "to build libcurl man pages" ON)
# curl source release tarballs come with the curl man page pre-built.
option(ENABLE_CURL_MANUAL "to build the man page for curl and enable its -M/--manual option" OFF)
if(ENABLE_MANUAL)
set(USE_MANUAL ON)
if(ENABLE_CURL_MANUAL OR BUILD_LIBCURL_DOCS)
if(PERL_FOUND)
curl_nroff_check()
if(NROFF_USEFUL)
set(HAVE_MANUAL_TOOLS ON)
endif()
endif()
if(NOT HAVE_MANUAL_TOOLS)
message(WARNING "Perl not found, or nroff not useful. Will not build manuals.")
endif()
endif()
if(CURL_STATIC_CRT)
@ -368,9 +355,6 @@ include(CheckCSourceCompiles)
# On windows preload settings
if(WIN32)
set(HAVE_WINDOWS_H 1)
set(HAVE_WS2TCPIP_H 1)
set(HAVE_WINSOCK2_H 1)
include(${CMAKE_CURRENT_SOURCE_DIR}/CMake/Platforms/WindowsCache.cmake)
endif()
@ -736,6 +720,10 @@ if(USE_MSH3)
list(APPEND CURL_LIBS ${MSH3_LIBRARIES})
endif()
if(CURL_WITH_MULTI_SSL AND (USE_NGTCP2 OR USE_QUICHE OR USE_MSH3))
message(FATAL_ERROR "MultiSSL cannot be enabled with HTTP/3 and vice versa.")
endif()
if(NOT CURL_DISABLE_SRP AND (HAVE_GNUTLS_SRP OR HAVE_OPENSSL_SRP))
set(USE_TLS_SRP 1)
endif()
@ -787,7 +775,7 @@ if(NOT CURL_DISABLE_LDAP)
endif()
set(NEED_LBER_H ON)
set(_HEADER_LIST)
if(HAVE_WINDOWS_H)
if(WIN32)
list(APPEND _HEADER_LIST "windows.h")
endif()
if(HAVE_SYS_TYPES_H)
@ -927,10 +915,8 @@ if(CURL_USE_GSSAPI)
check_include_file_concat("gssapi/gssapi_generic.h" HAVE_GSSAPI_GSSAPI_GENERIC_H)
check_include_file_concat("gssapi/gssapi_krb5.h" HAVE_GSSAPI_GSSAPI_KRB5_H)
if(GSS_FLAVOUR STREQUAL "Heimdal")
set(HAVE_GSSHEIMDAL ON)
else() # MIT
set(HAVE_GSSMIT ON)
if(NOT GSS_FLAVOUR STREQUAL "Heimdal")
# MIT
set(_INCLUDE_LIST "")
if(HAVE_GSSAPI_GSSAPI_H)
list(APPEND _INCLUDE_LIST "gssapi/gssapi.h")
@ -1070,9 +1056,9 @@ endif()
# Check for header files
if(WIN32)
check_include_file_concat("winsock2.h" HAVE_WINSOCK2_H)
check_include_file_concat("ws2tcpip.h" HAVE_WS2TCPIP_H)
check_include_file_concat("windows.h" HAVE_WINDOWS_H)
set(CURL_INCLUDES ${CURL_INCLUDES} "winsock2.h")
set(CURL_INCLUDES ${CURL_INCLUDES} "ws2tcpip.h")
set(CURL_INCLUDES ${CURL_INCLUDES} "windows.h")
endif()
if(WIN32)
@ -1266,7 +1252,7 @@ set(HAVE_SA_FAMILY_T ${HAVE_SIZEOF_SA_FAMILY_T})
set(CMAKE_EXTRA_INCLUDE_FILES "")
if(WIN32)
set(CMAKE_EXTRA_INCLUDE_FILES "ws2def.h")
set(CMAKE_EXTRA_INCLUDE_FILES "winsock2.h")
check_type_size("ADDRESS_FAMILY" SIZEOF_ADDRESS_FAMILY)
set(HAVE_ADDRESS_FAMILY ${HAVE_SIZEOF_ADDRESS_FAMILY})
set(CMAKE_EXTRA_INCLUDE_FILES "")
@ -1406,15 +1392,6 @@ if(CMAKE_COMPILER_IS_GNUCC AND APPLE)
endif()
endif()
# TODO test which of these headers are required
if(WIN32)
set(CURL_PULL_WS2TCPIP_H ${HAVE_WS2TCPIP_H})
else()
set(CURL_PULL_SYS_TYPES_H ${HAVE_SYS_TYPES_H})
set(CURL_PULL_SYS_SOCKET_H ${HAVE_SYS_SOCKET_H})
set(CURL_PULL_SYS_POLL_H ${HAVE_SYS_POLL_H})
endif()
include(CMake/OtherTests.cmake)
add_definitions(-DHAVE_CONFIG_H)
@ -1504,7 +1481,7 @@ set(generated_dir "${CMAKE_CURRENT_BINARY_DIR}/generated")
set(project_config "${generated_dir}/${PROJECT_NAME}Config.cmake")
set(version_config "${generated_dir}/${PROJECT_NAME}ConfigVersion.cmake")
if(USE_MANUAL)
if(HAVE_MANUAL_TOOLS)
add_subdirectory(docs)
endif()
@ -1533,7 +1510,6 @@ if(NOT CURL_DISABLE_INSTALL)
endmacro()
# NTLM support requires crypto function adaptions from various SSL libs
# TODO alternative SSL libs tests for SSP1, GnuTLS, NSS
if(NOT (CURL_DISABLE_NTLM) AND
(USE_OPENSSL OR USE_MBEDTLS OR USE_DARWINSSL OR USE_WIN32_CRYPTO OR USE_GNUTLS))
set(use_curl_ntlm_core ON)
@ -1551,26 +1527,20 @@ if(NOT CURL_DISABLE_INSTALL)
_add_if("IDN" HAVE_LIBIDN2 OR USE_WIN32_IDN)
_add_if("Largefile" (SIZEOF_CURL_OFF_T GREATER 4) AND
((SIZEOF_OFF_T GREATER 4) OR USE_WIN32_LARGE_FILES))
# TODO SSP1 (Schannel) check is missing
_add_if("SSPI" USE_WINDOWS_SSPI)
_add_if("GSS-API" HAVE_GSSAPI)
_add_if("alt-svc" NOT CURL_DISABLE_ALTSVC)
_add_if("HSTS" NOT CURL_DISABLE_HSTS)
# TODO SSP1 missing for SPNEGO
_add_if("SPNEGO" NOT CURL_DISABLE_NEGOTIATE_AUTH AND
(HAVE_GSSAPI OR USE_WINDOWS_SSPI))
_add_if("Kerberos" NOT CURL_DISABLE_KERBEROS_AUTH AND
(HAVE_GSSAPI OR USE_WINDOWS_SSPI))
# NTLM support requires crypto function adaptions from various SSL libs
# TODO alternative SSL libs tests for SSP1, GnuTLS, NSS
_add_if("NTLM" NOT (CURL_DISABLE_NTLM) AND
(use_curl_ntlm_core OR USE_WINDOWS_SSPI))
# TODO missing option (autoconf: --enable-ntlm-wb)
_add_if("NTLM_WB" NOT (CURL_DISABLE_NTLM) AND
(use_curl_ntlm_core OR USE_WINDOWS_SSPI) AND
NOT CURL_DISABLE_HTTP AND NTLM_WB_ENABLED)
_add_if("TLS-SRP" USE_TLS_SRP)
# TODO option --with-nghttp2 tests for nghttp2 lib and nghttp2/nghttp2.h header
_add_if("HTTP2" USE_NGHTTP2)
_add_if("HTTP3" USE_NGTCP2 OR USE_QUICHE)
_add_if("MultiSSL" CURL_WITH_MULTI_SSL)
@ -1589,6 +1559,8 @@ if(NOT CURL_DISABLE_INSTALL)
# Clear list and try to detect available protocols
set(_items)
_add_if("HTTP" NOT CURL_DISABLE_HTTP)
_add_if("IPFS" NOT CURL_DISABLE_HTTP)
_add_if("IPNS" NOT CURL_DISABLE_HTTP)
_add_if("HTTPS" NOT CURL_DISABLE_HTTP AND SSL_ENABLED)
_add_if("FTP" NOT CURL_DISABLE_FTP)
_add_if("FTPS" NOT CURL_DISABLE_FTP AND SSL_ENABLED)

View File

@ -1,6 +1,6 @@
COPYRIGHT AND PERMISSION NOTICE
Copyright (c) 1996 - 2023, Daniel Stenberg, <daniel@haxx.se>, and many
Copyright (c) 1996 - 2024, Daniel Stenberg, <daniel@haxx.se>, and many
contributors, see the THANKS file.
All rights reserved.

View File

@ -631,6 +631,7 @@ typedef enum {
CURLE_PROXY, /* 97 - proxy handshake error */
CURLE_SSL_CLIENTCERT, /* 98 - client-side certificate required */
CURLE_UNRECOVERABLE_POLL, /* 99 - poll/select returned fatal error */
CURLE_TOO_LARGE, /* 100 - a value/data met its maximum */
CURL_LAST /* never use! */
} CURLcode;
@ -1845,7 +1846,8 @@ typedef enum {
/* allow GSSAPI credential delegation */
CURLOPT(CURLOPT_GSSAPI_DELEGATION, CURLOPTTYPE_VALUES, 210),
/* Set the name servers to use for DNS resolution */
/* Set the name servers to use for DNS resolution.
* Only supported by the c-ares DNS backend */
CURLOPT(CURLOPT_DNS_SERVERS, CURLOPTTYPE_STRINGPOINT, 211),
/* Time-out accept operations (currently for FTP only) after this amount
@ -2201,6 +2203,9 @@ typedef enum {
/* set a specific client IP for HAProxy PROXY protocol header? */
CURLOPT(CURLOPT_HAPROXY_CLIENT_IP, CURLOPTTYPE_STRINGPOINT, 323),
/* millisecond version */
CURLOPT(CURLOPT_SERVER_RESPONSE_TIMEOUT_MS, CURLOPTTYPE_LONG, 324),
CURLOPT_LASTENTRY /* the last unused */
} CURLoption;
@ -2932,7 +2937,8 @@ typedef enum {
CURLINFO_CAPATH = CURLINFO_STRING + 62,
CURLINFO_XFER_ID = CURLINFO_OFF_T + 63,
CURLINFO_CONN_ID = CURLINFO_OFF_T + 64,
CURLINFO_LASTONE = 64
CURLINFO_QUEUE_TIME_T = CURLINFO_OFF_T + 65,
CURLINFO_LASTONE = 65
} CURLINFO;
/* CURLINFO_RESPONSE_CODE is the new name for the option previously known as

View File

@ -32,12 +32,12 @@
/* This is the version number of the libcurl package from which this header
file origins: */
#define LIBCURL_VERSION "8.5.0-DEV"
#define LIBCURL_VERSION "8.6.0-DEV"
/* The numeric version number is also available "in parts" by using these
defines: */
#define LIBCURL_VERSION_MAJOR 8
#define LIBCURL_VERSION_MINOR 5
#define LIBCURL_VERSION_MINOR 6
#define LIBCURL_VERSION_PATCH 0
/* This is the numeric version of the libcurl version number, meant for easier
@ -59,7 +59,7 @@
CURL_VERSION_BITS() macro since curl's own configure script greps for it
and needs it to contain the full number.
*/
#define LIBCURL_VERSION_NUM 0x080500
#define LIBCURL_VERSION_NUM 0x080600
/*
* This is the date and time when the full source package was created. The

View File

@ -34,19 +34,27 @@ extern "C" {
#if (defined(__GNUC__) || defined(__clang__)) && \
defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \
!defined(__MINGW32__) && !defined(CURL_NO_FMT_CHECKS)
#define CURL_TEMP_PRINTF(a,b) __attribute__ ((format(printf, a, b)))
!defined(CURL_NO_FMT_CHECKS)
#if defined(__MINGW32__) && !defined(__clang__)
#define CURL_TEMP_PRINTF(fmt, arg) \
__attribute__((format(gnu_printf, fmt, arg)))
#else
#define CURL_TEMP_PRINTF(a,b)
#define CURL_TEMP_PRINTF(fmt, arg) \
__attribute__((format(printf, fmt, arg)))
#endif
#else
#define CURL_TEMP_PRINTF(fmt, arg)
#endif
CURL_EXTERN int curl_mprintf(const char *format, ...) CURL_TEMP_PRINTF(1, 2);
CURL_EXTERN int curl_mprintf(const char *format, ...)
CURL_TEMP_PRINTF(1, 2);
CURL_EXTERN int curl_mfprintf(FILE *fd, const char *format, ...)
CURL_TEMP_PRINTF(2, 3);
CURL_EXTERN int curl_msprintf(char *buffer, const char *format, ...)
CURL_TEMP_PRINTF(2, 3);
CURL_EXTERN int curl_msnprintf(char *buffer, size_t maxlength,
const char *format, ...) CURL_TEMP_PRINTF(3, 4);
const char *format, ...)
CURL_TEMP_PRINTF(3, 4);
CURL_EXTERN int curl_mvprintf(const char *format, va_list args)
CURL_TEMP_PRINTF(1, 0);
CURL_EXTERN int curl_mvfprintf(FILE *fd, const char *format, va_list args)

View File

@ -184,9 +184,8 @@
# define CURL_FORMAT_CURL_OFF_TU PRIu64
# define CURL_SUFFIX_CURL_OFF_T LL
# define CURL_SUFFIX_CURL_OFF_TU ULL
# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
# define CURL_TYPEOF_CURL_SOCKLEN_T int
# define CURL_PULL_SYS_TYPES_H 1
# define CURL_PULL_WS2TCPIP_H 1
#elif defined(__VMS)
# if defined(__VAX)
@ -417,15 +416,6 @@
#define CURL_PULL_SYS_POLL_H
#endif
/* CURL_PULL_WS2TCPIP_H is defined above when inclusion of header file */
/* ws2tcpip.h is required here to properly make type definitions below. */
#ifdef CURL_PULL_WS2TCPIP_H
# include <winsock2.h>
# include <windows.h>
# include <ws2tcpip.h>
#endif
/* CURL_PULL_SYS_TYPES_H is defined above when inclusion of header file */
/* sys/types.h is required here to properly make type definitions below. */
#ifdef CURL_PULL_SYS_TYPES_H

View File

@ -63,6 +63,7 @@ typedef enum {
CURLUE_BAD_SLASHES, /* 28 */
CURLUE_BAD_USER, /* 29 */
CURLUE_LACKS_IDN, /* 30 */
CURLUE_TOO_LARGE, /* 31 */
CURLUE_LAST
} CURLUcode;

View File

@ -78,15 +78,19 @@ LIB_VTLS_HFILES = \
LIB_VQUIC_CFILES = \
vquic/curl_msh3.c \
vquic/curl_ngtcp2.c \
vquic/curl_osslq.c \
vquic/curl_quiche.c \
vquic/vquic.c
vquic/vquic.c \
vquic/vquic-tls.c
LIB_VQUIC_HFILES = \
vquic/curl_msh3.h \
vquic/curl_ngtcp2.h \
vquic/curl_osslq.h \
vquic/curl_quiche.h \
vquic/vquic.h \
vquic/vquic_int.h
vquic/vquic_int.h \
vquic/vquic-tls.h
LIB_VSSH_CFILES = \
vssh/libssh.c \

View File

@ -106,9 +106,11 @@ static struct altsvc *altsvc_createid(const char *srchost,
dlen = strlen(dsthost);
DEBUGASSERT(hlen);
DEBUGASSERT(dlen);
if(!hlen || !dlen)
if(!hlen || !dlen) {
/* bad input */
free(as);
return NULL;
}
if((hlen > 2) && srchost[0] == '[') {
/* IPv6 address, strip off brackets */
srchost++;
@ -123,11 +125,11 @@ static struct altsvc *altsvc_createid(const char *srchost,
dlen -= 2;
}
as->src.host = Curl_strndup(srchost, hlen);
as->src.host = Curl_memdup0(srchost, hlen);
if(!as->src.host)
goto error;
as->dst.host = Curl_strndup(dsthost, dlen);
as->dst.host = Curl_memdup0(dsthost, dlen);
if(!as->dst.host)
goto error;
@ -333,9 +335,6 @@ CURLcode Curl_altsvc_load(struct altsvcinfo *asi, const char *file)
CURLcode Curl_altsvc_ctrl(struct altsvcinfo *asi, const long ctrl)
{
DEBUGASSERT(asi);
if(!ctrl)
/* unexpected */
return CURLE_BAD_FUNCTION_ARGUMENT;
asi->flags = ctrl;
return CURLE_OK;
}

View File

@ -173,10 +173,26 @@ CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver)
int status;
struct ares_options options;
int optmask = ARES_OPT_SOCK_STATE_CB;
static int ares_ver = 0;
options.sock_state_cb = sock_state_cb;
options.sock_state_cb_data = easy;
options.timeout = CARES_TIMEOUT_PER_ATTEMPT;
optmask |= ARES_OPT_TIMEOUTMS;
if(ares_ver == 0)
ares_version(&ares_ver);
if(ares_ver < 0x011400) { /* c-ares included similar change since 1.20.0 */
options.timeout = CARES_TIMEOUT_PER_ATTEMPT;
optmask |= ARES_OPT_TIMEOUTMS;
}
/*
if c ares < 1.20.0: curl set timeout to CARES_TIMEOUT_PER_ATTEMPT (2s)
if c-ares >= 1.20.0 it already has the timeout to 2s, curl does not need
to set the timeout value;
if c-ares >= 1.24.0, user can set the timeout via /etc/resolv.conf to
overwrite c-ares' timeout.
*/
status = ares_init_options((ares_channel*)resolver, &options, optmask);
if(status != ARES_SUCCESS) {
@ -228,9 +244,9 @@ static void destroy_async_data(struct Curl_async *async);
void Curl_resolver_cancel(struct Curl_easy *data)
{
DEBUGASSERT(data);
if(data->conn->resolve_async.resolver)
ares_cancel((ares_channel)data->conn->resolve_async.resolver);
destroy_async_data(&data->conn->resolve_async);
if(data->state.async.resolver)
ares_cancel((ares_channel)data->state.async.resolver);
destroy_async_data(&data->state.async);
}
/*
@ -278,14 +294,14 @@ int Curl_resolver_getsock(struct Curl_easy *data,
struct timeval timebuf;
struct timeval *timeout;
long milli;
int max = ares_getsock((ares_channel)data->conn->resolve_async.resolver,
int max = ares_getsock((ares_channel)data->state.async.resolver,
(ares_socket_t *)socks, MAX_SOCKSPEREASYHANDLE);
maxtime.tv_sec = CURL_TIMEOUT_RESOLVE;
maxtime.tv_usec = 0;
timeout = ares_timeout((ares_channel)data->conn->resolve_async.resolver,
&maxtime, &timebuf);
timeout = ares_timeout((ares_channel)data->state.async.resolver, &maxtime,
&timebuf);
milli = (long)curlx_tvtoms(timeout);
if(milli == 0)
milli += 10;
@ -313,8 +329,8 @@ static int waitperform(struct Curl_easy *data, timediff_t timeout_ms)
int i;
int num = 0;
bitmask = ares_getsock((ares_channel)data->conn->resolve_async.resolver,
socks, ARES_GETSOCK_MAXNUM);
bitmask = ares_getsock((ares_channel)data->state.async.resolver, socks,
ARES_GETSOCK_MAXNUM);
for(i = 0; i < ARES_GETSOCK_MAXNUM; i++) {
pfd[i].events = 0;
@ -344,12 +360,12 @@ static int waitperform(struct Curl_easy *data, timediff_t timeout_ms)
if(!nfds)
/* Call ares_process() unconditionally here, even if we simply timed out
above, as otherwise the ares name resolve won't timeout! */
ares_process_fd((ares_channel)data->conn->resolve_async.resolver,
ARES_SOCKET_BAD, ARES_SOCKET_BAD);
ares_process_fd((ares_channel)data->state.async.resolver, ARES_SOCKET_BAD,
ARES_SOCKET_BAD);
else {
/* move through the descriptors and ask for processing on them */
for(i = 0; i < num; i++)
ares_process_fd((ares_channel)data->conn->resolve_async.resolver,
ares_process_fd((ares_channel)data->state.async.resolver,
(pfd[i].revents & (POLLRDNORM|POLLIN))?
pfd[i].fd:ARES_SOCKET_BAD,
(pfd[i].revents & (POLLWRNORM|POLLOUT))?
@ -368,7 +384,7 @@ static int waitperform(struct Curl_easy *data, timediff_t timeout_ms)
CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
struct Curl_dns_entry **dns)
{
struct thread_data *res = data->conn->resolve_async.tdata;
struct thread_data *res = data->state.async.tdata;
CURLcode result = CURLE_OK;
DEBUGASSERT(dns);
@ -397,7 +413,7 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
ARES_ECANCELLED synchronously for all pending responses. This will
leave us with res->num_pending == 0, which is perfect for the next
block. */
ares_cancel((ares_channel)data->conn->resolve_async.resolver);
ares_cancel((ares_channel)data->state.async.resolver);
DEBUGASSERT(res->num_pending == 0);
}
#endif
@ -408,12 +424,12 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
them */
res->temp_ai = NULL;
if(!data->conn->resolve_async.dns)
if(!data->state.async.dns)
result = Curl_resolver_error(data);
else
*dns = data->conn->resolve_async.dns;
*dns = data->state.async.dns;
destroy_async_data(&data->conn->resolve_async);
destroy_async_data(&data->state.async);
}
return result;
@ -464,8 +480,7 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
store.tv_sec = itimeout/1000;
store.tv_usec = (itimeout%1000)*1000;
tvp = ares_timeout((ares_channel)data->conn->resolve_async.resolver,
&store, &tv);
tvp = ares_timeout((ares_channel)data->state.async.resolver, &store, &tv);
/* use the timeout period ares returned to us above if less than one
second is left, otherwise just use 1000ms to make sure the progress
@ -479,7 +494,7 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
return CURLE_UNRECOVERABLE_POLL;
result = Curl_resolver_is_resolved(data, entry);
if(result || data->conn->resolve_async.done)
if(result || data->state.async.done)
break;
if(Curl_pgrsUpdate(data))
@ -500,12 +515,12 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
}
if(result)
/* failure, so we cancel the ares operation */
ares_cancel((ares_channel)data->conn->resolve_async.resolver);
ares_cancel((ares_channel)data->state.async.resolver);
/* Operation complete, if the lookup was successful we now have the entry
in the cache. */
if(entry)
*entry = data->conn->resolve_async.dns;
*entry = data->state.async.dns;
if(result)
/* close the connection, since we can't return failure here without
@ -572,13 +587,12 @@ static void query_completed_cb(void *arg, /* (struct connectdata *) */
be valid so only defer it when we know the 'status' says its fine! */
return;
res = data->conn->resolve_async.tdata;
res = data->state.async.tdata;
if(res) {
res->num_pending--;
if(CURL_ASYNC_SUCCESS == status) {
struct Curl_addrinfo *ai = Curl_he2ai(hostent,
data->conn->resolve_async.port);
struct Curl_addrinfo *ai = Curl_he2ai(hostent, data->state.async.port);
if(ai) {
compound_results(res, ai);
}
@ -729,16 +743,14 @@ static void addrinfo_cb(void *arg, int status, int timeouts,
struct ares_addrinfo *result)
{
struct Curl_easy *data = (struct Curl_easy *)arg;
if(data->conn) {
struct thread_data *res = data->conn->resolve_async.tdata;
(void)timeouts;
if(ARES_SUCCESS == status) {
res->temp_ai = ares2addr(result->nodes);
res->last_status = CURL_ASYNC_SUCCESS;
ares_freeaddrinfo(result);
}
res->num_pending--;
struct thread_data *res = data->state.async.tdata;
(void)timeouts;
if(ARES_SUCCESS == status) {
res->temp_ai = ares2addr(result->nodes);
res->last_status = CURL_ASYNC_SUCCESS;
ares_freeaddrinfo(result);
}
res->num_pending--;
}
#endif
@ -762,12 +774,12 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
res = calloc(1, sizeof(struct thread_data) + namelen);
if(res) {
strcpy(res->hostname, hostname);
data->conn->resolve_async.hostname = res->hostname;
data->conn->resolve_async.port = port;
data->conn->resolve_async.done = FALSE; /* not done */
data->conn->resolve_async.status = 0; /* clear */
data->conn->resolve_async.dns = NULL; /* clear */
data->conn->resolve_async.tdata = res;
data->state.async.hostname = res->hostname;
data->state.async.port = port;
data->state.async.done = FALSE; /* not done */
data->state.async.status = 0; /* clear */
data->state.async.dns = NULL; /* clear */
data->state.async.tdata = res;
/* initial status - failed */
res->last_status = ARES_ENOTFOUND;
@ -797,8 +809,8 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
hints.ai_flags = ARES_AI_NUMERICSERV;
msnprintf(service, sizeof(service), "%d", port);
res->num_pending = 1;
ares_getaddrinfo((ares_channel)data->conn->resolve_async.resolver,
hostname, service, &hints, addrinfo_cb, data);
ares_getaddrinfo((ares_channel)data->state.async.resolver, hostname,
service, &hints, addrinfo_cb, data);
}
#else
@ -808,10 +820,10 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
res->num_pending = 2;
/* areschannel is already setup in the Curl_open() function */
ares_gethostbyname((ares_channel)data->conn->resolve_async.resolver,
hostname, PF_INET, query_completed_cb, data);
ares_gethostbyname((ares_channel)data->conn->resolve_async.resolver,
hostname, PF_INET6, query_completed_cb, data);
ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
PF_INET, query_completed_cb, data);
ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
PF_INET6, query_completed_cb, data);
}
else
#endif
@ -819,7 +831,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
res->num_pending = 1;
/* areschannel is already setup in the Curl_open() function */
ares_gethostbyname((ares_channel)data->conn->resolve_async.resolver,
ares_gethostbyname((ares_channel)data->state.async.resolver,
hostname, PF_INET,
query_completed_cb, data);
}
@ -833,7 +845,6 @@ CURLcode Curl_set_dns_servers(struct Curl_easy *data,
char *servers)
{
CURLcode result = CURLE_NOT_BUILT_IN;
ares_channel channel, lchannel = NULL;
int ares_result;
/* If server is NULL or empty, this would purge all DNS servers
@ -846,23 +857,11 @@ CURLcode Curl_set_dns_servers(struct Curl_easy *data,
return CURLE_OK;
#ifdef HAVE_CARES_SERVERS_CSV
if(data->conn)
channel = data->conn->resolve_async.resolver;
else {
/* we are called by setopt on a data without a connection (yet). In that
* case we set the value on a local instance for checking.
* The configured data options are set when the connection for this
* transfer is created. */
result = Curl_resolver_init(data, (void **)&lchannel);
if(result)
goto out;
channel = lchannel;
}
#ifdef HAVE_CARES_PORTS_CSV
ares_result = ares_set_servers_ports_csv(channel, servers);
ares_result = ares_set_servers_ports_csv(data->state.async.resolver,
servers);
#else
ares_result = ares_set_servers_csv(channel, servers);
ares_result = ares_set_servers_csv(data->state.async.resolver, servers);
#endif
switch(ares_result) {
case ARES_SUCCESS:
@ -875,12 +874,10 @@ CURLcode Curl_set_dns_servers(struct Curl_easy *data,
case ARES_ENODATA:
case ARES_EBADSTR:
default:
DEBUGF(infof(data, "bad servers set"));
result = CURLE_BAD_FUNCTION_ARGUMENT;
break;
}
out:
if(lchannel)
Curl_resolver_cleanup(lchannel);
#else /* too old c-ares version! */
(void)data;
(void)(ares_result);
@ -892,14 +889,11 @@ CURLcode Curl_set_dns_interface(struct Curl_easy *data,
const char *interf)
{
#ifdef HAVE_CARES_LOCAL_DEV
if(data->conn) {
/* not a setopt test run, set the value */
if(!interf)
interf = "";
if(!interf)
interf = "";
ares_set_local_dev((ares_channel)data->state.async.resolver, interf);
ares_set_local_dev((ares_channel)data->conn->resolve_async.resolver,
interf);
}
return CURLE_OK;
#else /* c-ares version too old! */
(void)data;
@ -919,15 +913,13 @@ CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
}
else {
if(Curl_inet_pton(AF_INET, local_ip4, &a4) != 1) {
DEBUGF(infof(data, "bad DNS IPv4 address"));
return CURLE_BAD_FUNCTION_ARGUMENT;
}
}
if(data->conn) {
/* not a setopt test run, set the value */
ares_set_local_ip4((ares_channel)data->conn->resolve_async.resolver,
ntohl(a4.s_addr));
}
ares_set_local_ip4((ares_channel)data->state.async.resolver,
ntohl(a4.s_addr));
return CURLE_OK;
#else /* c-ares version too old! */
@ -949,14 +941,12 @@ CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
}
else {
if(Curl_inet_pton(AF_INET6, local_ip6, a6) != 1) {
DEBUGF(infof(data, "bad DNS IPv6 address"));
return CURLE_BAD_FUNCTION_ARGUMENT;
}
}
if(data->conn) {
/* not a setopt test run, set the value */
ares_set_local_ip6((ares_channel)data->conn->resolve_async.resolver, a6);
}
ares_set_local_ip6((ares_channel)data->state.async.resolver, a6);
return CURLE_OK;
#else /* c-ares version too old! */

View File

@ -54,6 +54,7 @@
# define RESOLVER_ENOMEM ENOMEM
#endif
#include "system_win32.h"
#include "urldata.h"
#include "sendf.h"
#include "hostip.h"
@ -136,7 +137,7 @@ static void destroy_async_data(struct Curl_async *);
*/
void Curl_resolver_cancel(struct Curl_easy *data)
{
destroy_async_data(&data->conn->resolve_async);
destroy_async_data(&data->state.async);
}
/* This function is used to init a threaded resolve */
@ -144,9 +145,22 @@ static bool init_resolve_thread(struct Curl_easy *data,
const char *hostname, int port,
const struct addrinfo *hints);
#ifdef _WIN32
/* Thread sync data used by GetAddrInfoExW for win8+ */
struct thread_sync_data_w8
{
OVERLAPPED overlapped;
ADDRINFOEXW_ *res;
HANDLE cancel_ev;
ADDRINFOEXW_ hints;
};
#endif
/* Data for synchronization between resolver thread and its parent */
struct thread_sync_data {
#ifdef _WIN32
struct thread_sync_data_w8 w8;
#endif
curl_mutex_t *mtx;
int done;
int port;
@ -165,6 +179,9 @@ struct thread_sync_data {
};
struct thread_data {
#ifdef _WIN32
HANDLE complete_ev;
#endif
curl_thread_t thread_hnd;
unsigned int poll_interval;
timediff_t interval_end;
@ -173,7 +190,7 @@ struct thread_data {
static struct thread_sync_data *conn_thread_sync_data(struct Curl_easy *data)
{
return &(data->conn->resolve_async.tdata->tsd);
return &(data->state.async.tdata->tsd);
}
/* Destroy resolver thread synchronization data */
@ -276,6 +293,151 @@ static CURLcode getaddrinfo_complete(struct Curl_easy *data)
return result;
}
#ifdef _WIN32
static VOID WINAPI
query_complete(DWORD err, DWORD bytes, LPWSAOVERLAPPED overlapped)
{
size_t ss_size;
const ADDRINFOEXW_ *ai;
struct Curl_addrinfo *ca;
struct Curl_addrinfo *cafirst = NULL;
struct Curl_addrinfo *calast = NULL;
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wcast-align"
#endif
struct thread_sync_data *tsd =
CONTAINING_RECORD(overlapped, struct thread_sync_data, w8.overlapped);
#ifdef __clang__
#pragma clang diagnostic pop
#endif
struct thread_data *td = tsd->td;
const ADDRINFOEXW_ *res = tsd->w8.res;
int error = (int)err;
(void)bytes;
if(error == ERROR_SUCCESS) {
/* traverse the addrinfo list */
for(ai = res; ai != NULL; ai = ai->ai_next) {
size_t namelen = ai->ai_canonname ? wcslen(ai->ai_canonname) + 1 : 0;
/* ignore elements with unsupported address family, */
/* settle family-specific sockaddr structure size. */
if(ai->ai_family == AF_INET)
ss_size = sizeof(struct sockaddr_in);
#ifdef ENABLE_IPV6
else if(ai->ai_family == AF_INET6)
ss_size = sizeof(struct sockaddr_in6);
#endif
else
continue;
/* ignore elements without required address info */
if(!ai->ai_addr || !(ai->ai_addrlen > 0))
continue;
/* ignore elements with bogus address size */
if((size_t)ai->ai_addrlen < ss_size)
continue;
ca = malloc(sizeof(struct Curl_addrinfo) + ss_size + namelen);
if(!ca) {
error = EAI_MEMORY;
break;
}
/* copy each structure member individually, member ordering, */
/* size, or padding might be different for each platform. */
ca->ai_flags = ai->ai_flags;
ca->ai_family = ai->ai_family;
ca->ai_socktype = ai->ai_socktype;
ca->ai_protocol = ai->ai_protocol;
ca->ai_addrlen = (curl_socklen_t)ss_size;
ca->ai_addr = NULL;
ca->ai_canonname = NULL;
ca->ai_next = NULL;
ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo));
memcpy(ca->ai_addr, ai->ai_addr, ss_size);
if(namelen) {
size_t i;
ca->ai_canonname = (void *)((char *)ca->ai_addr + ss_size);
for(i = 0; i < namelen; ++i) /* convert wide string to ascii */
ca->ai_canonname[i] = (char)ai->ai_canonname[i];
ca->ai_canonname[namelen] = '\0';
}
/* if the return list is empty, this becomes the first element */
if(!cafirst)
cafirst = ca;
/* add this element last in the return list */
if(calast)
calast->ai_next = ca;
calast = ca;
}
/* if we failed, also destroy the Curl_addrinfo list */
if(error) {
Curl_freeaddrinfo(cafirst);
cafirst = NULL;
}
else if(!cafirst) {
#ifdef EAI_NONAME
/* rfc3493 conformant */
error = EAI_NONAME;
#else
/* rfc3493 obsoleted */
error = EAI_NODATA;
#endif
#ifdef USE_WINSOCK
SET_SOCKERRNO(error);
#endif
}
tsd->res = cafirst;
}
if(tsd->w8.res) {
Curl_FreeAddrInfoExW(tsd->w8.res);
tsd->w8.res = NULL;
}
if(error) {
tsd->sock_error = SOCKERRNO?SOCKERRNO:error;
if(tsd->sock_error == 0)
tsd->sock_error = RESOLVER_ENOMEM;
}
else {
Curl_addrinfo_set_port(tsd->res, tsd->port);
}
Curl_mutex_acquire(tsd->mtx);
if(tsd->done) {
/* too late, gotta clean up the mess */
Curl_mutex_release(tsd->mtx);
destroy_thread_sync_data(tsd);
free(td);
}
else {
#ifndef CURL_DISABLE_SOCKETPAIR
char buf[1];
if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
/* DNS has been resolved, signal client task */
buf[0] = 1;
if(swrite(tsd->sock_pair[1], buf, sizeof(buf)) < 0) {
/* update sock_erro to errno */
tsd->sock_error = SOCKERRNO;
}
}
#endif
tsd->done = 1;
Curl_mutex_release(tsd->mtx);
if(td->complete_ev)
SetEvent(td->complete_ev); /* Notify caller that the query completed */
}
}
#endif
#ifdef HAVE_GETADDRINFO
@ -391,9 +553,21 @@ static void destroy_async_data(struct Curl_async *async)
Curl_mutex_release(td->tsd.mtx);
if(!done) {
#ifdef _WIN32
if(td->complete_ev)
CloseHandle(td->complete_ev);
else
#endif
Curl_thread_destroy(td->thread_hnd);
}
else {
#ifdef _WIN32
if(td->complete_ev) {
Curl_GetAddrInfoExCancel(&td->tsd.w8.cancel_ev);
WaitForSingleObject(td->complete_ev, INFINITE);
CloseHandle(td->complete_ev);
}
#endif
if(td->thread_hnd != curl_thread_t_null)
Curl_thread_join(&td->thread_hnd);
@ -428,9 +602,9 @@ static bool init_resolve_thread(struct Curl_easy *data,
{
struct thread_data *td = calloc(1, sizeof(struct thread_data));
int err = ENOMEM;
struct Curl_async *asp = &data->conn->resolve_async;
struct Curl_async *asp = &data->state.async;
data->conn->resolve_async.tdata = td;
data->state.async.tdata = td;
if(!td)
goto errno_exit;
@ -439,6 +613,9 @@ static bool init_resolve_thread(struct Curl_easy *data,
asp->status = 0;
asp->dns = NULL;
td->thread_hnd = curl_thread_t_null;
#ifdef _WIN32
td->complete_ev = NULL;
#endif
if(!init_thread_sync_data(td, hostname, port, hints)) {
asp->tdata = NULL;
@ -454,6 +631,41 @@ static bool init_resolve_thread(struct Curl_easy *data,
/* The thread will set this to 1 when complete. */
td->tsd.done = 0;
#ifdef _WIN32
if(Curl_isWindows8OrGreater && Curl_FreeAddrInfoExW &&
Curl_GetAddrInfoExCancel && Curl_GetAddrInfoExW) {
#define MAX_NAME_LEN 256 /* max domain name is 253 chars */
#define MAX_PORT_LEN 8
WCHAR namebuf[MAX_NAME_LEN];
WCHAR portbuf[MAX_PORT_LEN];
/* calculate required length */
int w_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, hostname,
-1, NULL, 0);
if((w_len > 0) && (w_len < MAX_NAME_LEN)) {
/* do utf8 conversion */
w_len = MultiByteToWideChar(CP_UTF8, 0, hostname, -1, namebuf, w_len);
if((w_len > 0) && (w_len < MAX_NAME_LEN)) {
swprintf(portbuf, MAX_PORT_LEN, L"%d", port);
td->tsd.w8.hints.ai_family = hints->ai_family;
td->tsd.w8.hints.ai_socktype = hints->ai_socktype;
td->complete_ev = CreateEvent(NULL, TRUE, FALSE, NULL);
if(!td->complete_ev) {
/* failed to start, mark it as done here for proper cleanup. */
td->tsd.done = 1;
goto err_exit;
}
err = Curl_GetAddrInfoExW(namebuf, portbuf, NS_DNS,
NULL, &td->tsd.w8.hints, &td->tsd.w8.res,
NULL, &td->tsd.w8.overlapped,
&query_complete, &td->tsd.w8.cancel_ev);
if(err != WSA_IO_PENDING)
query_complete(err, 0, &td->tsd.w8.overlapped);
return TRUE;
}
}
}
#endif
#ifdef HAVE_GETADDRINFO
td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd);
#else
@ -488,11 +700,24 @@ static CURLcode thread_wait_resolv(struct Curl_easy *data,
CURLcode result = CURLE_OK;
DEBUGASSERT(data);
td = data->conn->resolve_async.tdata;
td = data->state.async.tdata;
DEBUGASSERT(td);
#ifdef _WIN32
DEBUGASSERT(td->complete_ev || td->thread_hnd != curl_thread_t_null);
#else
DEBUGASSERT(td->thread_hnd != curl_thread_t_null);
#endif
/* wait for the thread to resolve the name */
#ifdef _WIN32
if(td->complete_ev) {
WaitForSingleObject(td->complete_ev, INFINITE);
CloseHandle(td->complete_ev);
if(entry)
result = getaddrinfo_complete(data);
}
else
#endif
if(Curl_thread_join(&td->thread_hnd)) {
if(entry)
result = getaddrinfo_complete(data);
@ -500,18 +725,18 @@ static CURLcode thread_wait_resolv(struct Curl_easy *data,
else
DEBUGASSERT(0);
data->conn->resolve_async.done = TRUE;
data->state.async.done = TRUE;
if(entry)
*entry = data->conn->resolve_async.dns;
*entry = data->state.async.dns;
if(!data->conn->resolve_async.dns && report)
if(!data->state.async.dns && report)
/* a name was not resolved, report error */
result = Curl_resolver_error(data);
destroy_async_data(&data->conn->resolve_async);
destroy_async_data(&data->state.async);
if(!data->conn->resolve_async.dns && report)
if(!data->state.async.dns && report)
connclose(data->conn, "asynch resolve failed");
return result;
@ -524,7 +749,7 @@ static CURLcode thread_wait_resolv(struct Curl_easy *data,
*/
void Curl_resolver_kill(struct Curl_easy *data)
{
struct thread_data *td = data->conn->resolve_async.tdata;
struct thread_data *td = data->state.async.tdata;
/* If we're still resolving, we must wait for the threads to fully clean up,
unfortunately. Otherwise, we can simply cancel to clean up any resolver
@ -563,7 +788,7 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
struct Curl_dns_entry **entry)
{
struct thread_data *td = data->conn->resolve_async.tdata;
struct thread_data *td = data->state.async.tdata;
int done = 0;
DEBUGASSERT(entry);
@ -581,13 +806,13 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
if(done) {
getaddrinfo_complete(data);
if(!data->conn->resolve_async.dns) {
if(!data->state.async.dns) {
CURLcode result = Curl_resolver_error(data);
destroy_async_data(&data->conn->resolve_async);
destroy_async_data(&data->state.async);
return result;
}
destroy_async_data(&data->conn->resolve_async);
*entry = data->conn->resolve_async.dns;
destroy_async_data(&data->state.async);
*entry = data->state.async.dns;
}
else {
/* poll for name lookup done with exponential backoff up to 250ms */
@ -619,9 +844,9 @@ int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks)
int ret_val = 0;
timediff_t milli;
timediff_t ms;
struct resdata *reslv = (struct resdata *)data->conn->resolve_async.resolver;
struct resdata *reslv = (struct resdata *)data->state.async.resolver;
#ifndef CURL_DISABLE_SOCKETPAIR
struct thread_data *td = data->conn->resolve_async.tdata;
struct thread_data *td = data->state.async.tdata;
#else
(void)socks;
#endif
@ -662,7 +887,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
int port,
int *waitp)
{
struct resdata *reslv = (struct resdata *)data->conn->resolve_async.resolver;
struct resdata *reslv = (struct resdata *)data->state.async.resolver;
*waitp = 0; /* default to synchronous response */
@ -691,7 +916,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
{
struct addrinfo hints;
int pf = PF_INET;
struct resdata *reslv = (struct resdata *)data->conn->resolve_async.resolver;
struct resdata *reslv = (struct resdata *)data->state.async.resolver;
*waitp = 0; /* default to synchronous response */

View File

@ -25,6 +25,7 @@
#include "curl_setup.h"
#include "urldata.h"
#include "bufref.h"
#include "strdup.h"
#include "curl_memory.h"
#include "memdebug.h"
@ -116,12 +117,9 @@ CURLcode Curl_bufref_memdup(struct bufref *br, const void *ptr, size_t len)
DEBUGASSERT(len <= CURL_MAX_INPUT_LENGTH);
if(ptr) {
cpy = malloc(len + 1);
cpy = Curl_memdup0(ptr, len);
if(!cpy)
return CURLE_OUT_OF_MEMORY;
if(len)
memcpy(cpy, ptr, len);
cpy[len] = '\0';
}
Curl_bufref_set(br, cpy, len, curl_free);

View File

@ -148,7 +148,7 @@ static int hyper_each_header(void *userdata,
if(name_len + value_len + 2 > CURL_MAX_HTTP_HEADER) {
failf(data, "Too long response header");
data->state.hresult = CURLE_OUT_OF_MEMORY;
data->state.hresult = CURLE_TOO_LARGE;
return HYPER_ITER_BREAK;
}
@ -325,6 +325,9 @@ static CURLcode empty_header(struct Curl_easy *data)
CURLE_WRITE_ERROR : CURLE_OK;
if(result)
failf(data, "hyperstream: couldn't pass blank header");
/* Hyper does chunked decoding itself. If it was added during
* response header processing, remove it again. */
Curl_cwriter_remove_by_name(data, "chunked");
}
return result;
}

View File

@ -70,6 +70,7 @@ struct h1_tunnel_state {
struct dynbuf request_data;
size_t nsent;
size_t headerlines;
struct Curl_chunker ch;
enum keeponval {
KEEPON_DONE,
KEEPON_CONNECT,
@ -133,6 +134,7 @@ static CURLcode tunnel_init(struct Curl_cfilter *cf,
Curl_dyn_init(&ts->rcvbuf, DYN_PROXY_CONNECT_HEADERS);
Curl_dyn_init(&ts->request_data, DYN_HTTP_REQUEST);
Curl_httpchunk_init(data, &ts->ch, TRUE);
*pts = ts;
connkeep(cf->conn, "HTTP proxy CONNECT");
@ -146,14 +148,6 @@ static void h1_tunnel_go_state(struct Curl_cfilter *cf,
{
if(ts->tunnel_state == new_state)
return;
/* leaving this one */
switch(ts->tunnel_state) {
case H1_TUNNEL_CONNECT:
data->req.ignorebody = FALSE;
break;
default:
break;
}
/* entering this one */
switch(new_state) {
case H1_TUNNEL_INIT:
@ -183,7 +177,7 @@ static void h1_tunnel_go_state(struct Curl_cfilter *cf,
infof(data, "CONNECT phase completed");
data->state.authproxy.done = TRUE;
data->state.authproxy.multipass = FALSE;
/* FALLTHROUGH */
FALLTHROUGH();
case H1_TUNNEL_FAILED:
if(new_state == H1_TUNNEL_FAILED)
CURL_TRC_CF(data, cf, "new tunnel state 'failed'");
@ -212,6 +206,7 @@ static void tunnel_free(struct Curl_cfilter *cf,
h1_tunnel_go_state(cf, ts, H1_TUNNEL_FAILED, data);
Curl_dyn_free(&ts->rcvbuf);
Curl_dyn_free(&ts->request_data);
Curl_httpchunk_free(data, &ts->ch);
free(ts);
cf->ctx = NULL;
}
@ -344,8 +339,8 @@ static CURLcode on_resp_header(struct Curl_cfilter *cf,
STRCONST("chunked"))) {
infof(data, "CONNECT responded chunked");
ts->chunked_encoding = TRUE;
/* init our chunky engine */
Curl_httpchunk_init(data);
/* reset our chunky engine */
Curl_httpchunk_reset(data, &ts->ch, TRUE);
}
}
else if(Curl_compareheader(header,
@ -373,7 +368,7 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
struct SingleRequest *k = &data->req;
curl_socket_t tunnelsocket = Curl_conn_cf_get_socket(cf, data);
char *linep;
size_t perline;
size_t line_len;
int error, writetype;
#define SELECT_OK 0
@ -432,17 +427,17 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
break;
}
}
else {
else if(ts->chunked_encoding) {
/* chunked-encoded body, so we need to do the chunked dance
properly to know when the end of the body is reached */
CHUNKcode r;
CURLcode extra;
size_t consumed = 0;
/* now parse the chunked piece of data so that we can
properly tell when the stream ends */
r = Curl_httpchunk_read(data, &byte, 1, &consumed, &extra);
if(r == CHUNKE_STOP) {
result = Curl_httpchunk_read(data, &ts->ch, &byte, 1, &consumed);
if(result)
return result;
if(Curl_httpchunk_is_done(data, &ts->ch)) {
/* we're done reading chunks! */
infof(data, "chunk reading DONE");
ts->keepon = KEEPON_DONE;
@ -462,19 +457,19 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
ts->headerlines++;
linep = Curl_dyn_ptr(&ts->rcvbuf);
perline = Curl_dyn_len(&ts->rcvbuf); /* amount of bytes in this line */
line_len = Curl_dyn_len(&ts->rcvbuf); /* amount of bytes in this line */
/* output debug if that is requested */
Curl_debug(data, CURLINFO_HEADER_IN, linep, perline);
Curl_debug(data, CURLINFO_HEADER_IN, linep, line_len);
/* send the header to the callback */
writetype = CLIENTWRITE_HEADER | CLIENTWRITE_CONNECT |
(ts->headerlines == 1 ? CLIENTWRITE_STATUS : 0);
result = Curl_client_write(data, writetype, linep, perline);
result = Curl_client_write(data, writetype, linep, line_len);
if(result)
return result;
result = Curl_bump_headersize(data, perline, TRUE);
result = Curl_bump_headersize(data, line_len, TRUE);
if(result)
return result;
@ -497,29 +492,7 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
" bytes of response-body", ts->cl);
}
else if(ts->chunked_encoding) {
CHUNKcode r;
CURLcode extra;
size_t consumed = 0;
infof(data, "Ignore chunked response-body");
/* We set ignorebody true here since the chunked decoder
function will acknowledge that. Pay attention so that this is
cleared again when this function returns! */
k->ignorebody = TRUE;
if(linep[1] == '\n')
/* this can only be a LF if the letter at index 0 was a CR */
linep++;
/* now parse the chunked piece of data so that we can properly
tell when the stream ends */
r = Curl_httpchunk_read(data, linep + 1, 1, &consumed, &extra);
if(r == CHUNKE_STOP) {
/* we're done reading chunks! */
infof(data, "chunk reading DONE");
ts->keepon = KEEPON_DONE;
}
}
else {
/* without content-length or chunked encoding, we
@ -752,7 +725,7 @@ static CURLcode start_CONNECT(struct Curl_cfilter *cf,
}
if(!Curl_checkProxyheaders(data, conn, STRCONST("User-Agent")) &&
data->set.str[STRING_USERAGENT]) {
data->set.str[STRING_USERAGENT] && *data->set.str[STRING_USERAGENT]) {
struct dynbuf ua;
Curl_dyn_init(&ua, DYN_HTTP_REQUEST);
result = Curl_dyn_addf(&ua, "User-Agent: %s\r\n",
@ -912,7 +885,7 @@ static CURLcode H1_CONNECT(struct Curl_cfilter *cf,
if(result)
goto out;
h1_tunnel_go_state(cf, ts, H1_TUNNEL_CONNECT, data);
/* FALLTHROUGH */
FALLTHROUGH();
case H1_TUNNEL_CONNECT:
/* see that the request is completely sent */
@ -921,7 +894,7 @@ static CURLcode H1_CONNECT(struct Curl_cfilter *cf,
if(result || !done)
goto out;
h1_tunnel_go_state(cf, ts, H1_TUNNEL_RECEIVE, data);
/* FALLTHROUGH */
FALLTHROUGH();
case H1_TUNNEL_RECEIVE:
/* read what is there */
@ -936,7 +909,7 @@ static CURLcode H1_CONNECT(struct Curl_cfilter *cf,
goto out;
/* got it */
h1_tunnel_go_state(cf, ts, H1_TUNNEL_RESPONSE, data);
/* FALLTHROUGH */
FALLTHROUGH();
case H1_TUNNEL_RESPONSE:
CURL_TRC_CF(data, cf, "CONNECT response");
@ -1030,6 +1003,14 @@ out:
*done = (result == CURLE_OK) && tunnel_is_established(cf->ctx);
if(*done) {
cf->connected = TRUE;
/* Restore `data->req` fields that may habe been touched */
data->req.header = TRUE; /* assume header */
data->req.bytecount = 0;
data->req.ignorebody = FALSE;
Curl_client_cleanup(data);
Curl_pgrsSetUploadCounter(data, 0);
Curl_pgrsSetDownloadCounter(data, 0);
tunnel_free(cf, data);
}
return result;

View File

@ -155,7 +155,7 @@ static void h2_tunnel_go_state(struct Curl_cfilter *cf,
infof(data, "CONNECT phase completed");
data->state.authproxy.done = TRUE;
data->state.authproxy.multipass = FALSE;
/* FALLTHROUGH */
FALLTHROUGH();
case H2_TUNNEL_FAILED:
if(new_state == H2_TUNNEL_FAILED)
CURL_TRC_CF(data, cf, "[%d] new tunnel state 'failed'", ts->stream_id);
@ -221,10 +221,10 @@ static void drain_tunnel(struct Curl_cfilter *cf,
bits = CURL_CSELECT_IN;
if(!tunnel->closed && !tunnel->reset && tunnel->upload_blocked_len)
bits |= CURL_CSELECT_OUT;
if(data->state.dselect_bits != bits) {
CURL_TRC_CF(data, cf, "[%d] DRAIN dselect_bits=%x",
if(data->state.select_bits != bits) {
CURL_TRC_CF(data, cf, "[%d] DRAIN select_bits=%x",
tunnel->stream_id, bits);
data->state.dselect_bits = bits;
data->state.select_bits = bits;
Curl_expire(data, 0, EXPIRE_RUN_NOW);
}
}
@ -1033,7 +1033,7 @@ static CURLcode H2_CONNECT(struct Curl_cfilter *cf,
if(result)
goto out;
h2_tunnel_go_state(cf, ts, H2_TUNNEL_CONNECT, data);
/* FALLTHROUGH */
FALLTHROUGH();
case H2_TUNNEL_CONNECT:
/* see that the request is completely sent */
@ -1052,7 +1052,7 @@ static CURLcode H2_CONNECT(struct Curl_cfilter *cf,
result = CURLE_OK;
goto out;
}
/* FALLTHROUGH */
FALLTHROUGH();
case H2_TUNNEL_RESPONSE:
DEBUGASSERT(ts->has_final_response);

View File

@ -125,7 +125,7 @@ static CURLcode cf_haproxy_connect(struct Curl_cfilter *cf,
if(result)
goto out;
ctx->state = HAPROXY_SEND;
/* FALLTHROUGH */
FALLTHROUGH();
case HAPROXY_SEND:
len = Curl_dyn_len(&ctx->data_out);
if(len > 0) {
@ -141,7 +141,7 @@ static CURLcode cf_haproxy_connect(struct Curl_cfilter *cf,
}
}
ctx->state = HAPROXY_DONE;
/* FALLTHROUGH */
FALLTHROUGH();
default:
Curl_dyn_free(&ctx->data_out);
break;

View File

@ -266,7 +266,7 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
cf_hc_baller_init(&ctx->h21_baller, cf, data, "h21",
cf->conn->transport);
ctx->state = CF_HC_CONNECT;
/* FALLTHROUGH */
FALLTHROUGH();
case CF_HC_CONNECT:
if(cf_hc_baller_is_active(&ctx->h3_baller)) {

View File

@ -137,14 +137,14 @@ static void nosigpipe(struct Curl_easy *data,
#define nosigpipe(x,y) Curl_nop_stmt
#endif
#if defined(__DragonFly__) || defined(HAVE_WINSOCK2_H)
#if defined(__DragonFly__) || defined(USE_WINSOCK)
/* DragonFlyBSD and Windows use millisecond units */
#define KEEPALIVE_FACTOR(x) (x *= 1000)
#else
#define KEEPALIVE_FACTOR(x)
#endif
#if defined(HAVE_WINSOCK2_H) && !defined(SIO_KEEPALIVE_VALS)
#if defined(USE_WINSOCK) && !defined(SIO_KEEPALIVE_VALS)
#define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4)
struct tcp_keepalive {
@ -163,7 +163,9 @@ tcpkeepalive(struct Curl_easy *data,
/* only set IDLE and INTVL if setting KEEPALIVE is successful */
if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
(void *)&optval, sizeof(optval)) < 0) {
infof(data, "Failed to set SO_KEEPALIVE on fd %d", sockfd);
infof(data, "Failed to set SO_KEEPALIVE on fd "
"%" CURL_FORMAT_SOCKET_T ": errno %d",
sockfd, SOCKERRNO);
}
else {
#if defined(SIO_KEEPALIVE_VALS)
@ -178,8 +180,9 @@ tcpkeepalive(struct Curl_easy *data,
vals.keepaliveinterval = optval;
if(WSAIoctl(sockfd, SIO_KEEPALIVE_VALS, (LPVOID) &vals, sizeof(vals),
NULL, 0, &dummy, NULL, NULL) != 0) {
infof(data, "Failed to set SIO_KEEPALIVE_VALS on fd %d: %d",
(int)sockfd, WSAGetLastError());
infof(data, "Failed to set SIO_KEEPALIVE_VALS on fd "
"%" CURL_FORMAT_SOCKET_T ": errno %d",
sockfd, SOCKERRNO);
}
#else
#ifdef TCP_KEEPIDLE
@ -187,7 +190,9 @@ tcpkeepalive(struct Curl_easy *data,
KEEPALIVE_FACTOR(optval);
if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
(void *)&optval, sizeof(optval)) < 0) {
infof(data, "Failed to set TCP_KEEPIDLE on fd %d", sockfd);
infof(data, "Failed to set TCP_KEEPIDLE on fd "
"%" CURL_FORMAT_SOCKET_T ": errno %d",
sockfd, SOCKERRNO);
}
#elif defined(TCP_KEEPALIVE)
/* Mac OS X style */
@ -195,7 +200,9 @@ tcpkeepalive(struct Curl_easy *data,
KEEPALIVE_FACTOR(optval);
if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE,
(void *)&optval, sizeof(optval)) < 0) {
infof(data, "Failed to set TCP_KEEPALIVE on fd %d", sockfd);
infof(data, "Failed to set TCP_KEEPALIVE on fd "
"%" CURL_FORMAT_SOCKET_T ": errno %d",
sockfd, SOCKERRNO);
}
#endif
#ifdef TCP_KEEPINTVL
@ -203,7 +210,9 @@ tcpkeepalive(struct Curl_easy *data,
KEEPALIVE_FACTOR(optval);
if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
(void *)&optval, sizeof(optval)) < 0) {
infof(data, "Failed to set TCP_KEEPINTVL on fd %d", sockfd);
infof(data, "Failed to set TCP_KEEPINTVL on fd "
"%" CURL_FORMAT_SOCKET_T ": errno %d",
sockfd, SOCKERRNO);
}
#endif
#endif
@ -783,6 +792,7 @@ struct cf_socket_ctx {
#endif
BIT(got_first_byte); /* if first byte was received */
BIT(accepted); /* socket was accepted, not connected */
BIT(sock_connected); /* socket is "connected", e.g. in UDP */
BIT(active);
BIT(buffer_recv);
};
@ -983,20 +993,14 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf,
if(result)
goto out;
#ifndef CURL_DISABLE_VERBOSE_STRINGS
{
const char *ipmsg;
#ifdef ENABLE_IPV6
if(ctx->addr.family == AF_INET6) {
set_ipv6_v6only(ctx->sock, 0);
ipmsg = " Trying [%s]:%d...";
}
else
#endif
ipmsg = " Trying %s:%d...";
infof(data, ipmsg, ctx->r_ip, ctx->r_port);
if(ctx->addr.family == AF_INET6) {
set_ipv6_v6only(ctx->sock, 0);
infof(data, " Trying [%s]:%d...", ctx->r_ip, ctx->r_port);
}
else
#endif
infof(data, " Trying %s:%d...", ctx->r_ip, ctx->r_port);
#ifdef ENABLE_IPV6
is_tcp = (ctx->addr.family == AF_INET
@ -1054,7 +1058,7 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf,
/* set socket non-blocking */
(void)curlx_nonblock(ctx->sock, TRUE);
ctx->sock_connected = (ctx->addr.socktype != SOCK_DGRAM);
out:
if(result) {
if(ctx->sock != CURL_SOCKET_BAD) {
@ -1242,11 +1246,14 @@ static void cf_socket_adjust_pollset(struct Curl_cfilter *cf,
struct cf_socket_ctx *ctx = cf->ctx;
if(ctx->sock != CURL_SOCKET_BAD) {
if(!cf->connected)
if(!cf->connected) {
Curl_pollset_set_out_only(data, ps, ctx->sock);
else
CURL_TRC_CF(data, cf, "adjust_pollset(!connected) -> %d socks", ps->num);
}
else if(!ctx->active) {
Curl_pollset_add_in(data, ps, ctx->sock);
CURL_TRC_CF(data, cf, "adjust_pollset -> %d socks", ps->num);
CURL_TRC_CF(data, cf, "adjust_pollset(!active) -> %d socks", ps->num);
}
}
}
@ -1429,36 +1436,11 @@ out:
static void conn_set_primary_ip(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
#ifdef HAVE_GETPEERNAME
struct cf_socket_ctx *ctx = cf->ctx;
if(!(data->conn->handler->protocol & CURLPROTO_TFTP)) {
/* TFTP does not connect the endpoint: getpeername() failed with errno
107: Transport endpoint is not connected */
char buffer[STRERROR_LEN];
struct Curl_sockaddr_storage ssrem;
curl_socklen_t plen;
int port;
plen = sizeof(ssrem);
memset(&ssrem, 0, plen);
if(getpeername(ctx->sock, (struct sockaddr*) &ssrem, &plen)) {
int error = SOCKERRNO;
failf(data, "getpeername() failed with errno %d: %s",
error, Curl_strerror(error, buffer, sizeof(buffer)));
return;
}
if(!Curl_addr2string((struct sockaddr*)&ssrem, plen,
cf->conn->primary_ip, &port)) {
failf(data, "ssrem inet_ntop() failed with errno %d: %s",
errno, Curl_strerror(errno, buffer, sizeof(buffer)));
return;
}
}
#else
cf->conn->primary_ip[0] = 0;
(void)data;
#endif
DEBUGASSERT(sizeof(ctx->r_ip) == sizeof(cf->conn->primary_ip));
memcpy(cf->conn->primary_ip, ctx->r_ip, sizeof(cf->conn->primary_ip));
}
static void cf_socket_active(struct Curl_cfilter *cf, struct Curl_easy *data)
@ -1574,7 +1556,7 @@ static CURLcode cf_socket_query(struct Curl_cfilter *cf,
*when = ctx->first_byte_at;
break;
}
/* FALLTHROUGH */
FALLTHROUGH();
default:
*when = ctx->connected_at;
break;
@ -1648,10 +1630,17 @@ static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
/* QUIC needs a connected socket, nonblocking */
DEBUGASSERT(ctx->sock != CURL_SOCKET_BAD);
#if defined(__APPLE__) && defined(USE_OPENSSL_QUIC)
(void)rc;
/* On macOS OpenSSL QUIC fails on connected sockets.
* see: <https://github.com/openssl/openssl/issues/23251> */
#else
rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
if(-1 == rc) {
return socket_connect_result(data, ctx->r_ip, SOCKERRNO);
}
ctx->sock_connected = TRUE;
#endif
set_local_ip(cf, data);
CURL_TRC_CF(data, cf, "%s socket %" CURL_FORMAT_SOCKET_T
" connected: [%s:%d] -> [%s:%d]",

View File

@ -34,23 +34,6 @@ struct Curl_easy;
struct connectdata;
struct Curl_sockaddr_ex;
#ifndef SIZEOF_CURL_SOCKET_T
/* configure and cmake check and set the define */
# ifdef _WIN64
# define SIZEOF_CURL_SOCKET_T 8
# else
/* default guess */
# define SIZEOF_CURL_SOCKET_T 4
# endif
#endif
#if SIZEOF_CURL_SOCKET_T < 8
# define CURL_FORMAT_SOCKET_T "d"
#else
# define CURL_FORMAT_SOCKET_T "qd"
#endif
/*
* The Curl_sockaddr_ex structure is basically libcurl's external API
* curl_sockaddr structure with enough space available to directly hold any

View File

@ -760,25 +760,11 @@ static void ps_add(struct Curl_easy *data, struct easy_pollset *ps,
void Curl_pollset_add_socks(struct Curl_easy *data,
struct easy_pollset *ps,
int (*get_socks_cb)(struct Curl_easy *data,
struct connectdata *conn,
curl_socket_t *socks))
{
curl_socket_t socks[MAX_SOCKSPEREASYHANDLE];
int bitmap;
DEBUGASSERT(data->conn);
bitmap = get_socks_cb(data, data->conn, socks);
ps_add(data, ps, bitmap, socks);
}
void Curl_pollset_add_socks2(struct Curl_easy *data,
struct easy_pollset *ps,
int (*get_socks_cb)(struct Curl_easy *data,
curl_socket_t *socks))
{
curl_socket_t socks[MAX_SOCKSPEREASYHANDLE];
int bitmap;
bitmap = get_socks_cb(data, socks);
ps_add(data, ps, bitmap, socks);
}

View File

@ -530,12 +530,7 @@ void Curl_pollset_set(struct Curl_easy *data,
void Curl_pollset_add_socks(struct Curl_easy *data,
struct easy_pollset *ps,
int (*get_socks_cb)(struct Curl_easy *data,
struct connectdata *conn,
curl_socket_t *socks));
void Curl_pollset_add_socks2(struct Curl_easy *data,
struct easy_pollset *ps,
int (*get_socks_cb)(struct Curl_easy *data,
curl_socket_t *socks));
/**
* Check if the pollset, as is, wants to read and/or write regarding

View File

@ -93,25 +93,17 @@
* transfer/connection. If the value is 0, there's no timeout (ie there's
* infinite time left). If the value is negative, the timeout time has already
* elapsed.
*
* If 'nowp' is non-NULL, it points to the current time.
* 'duringconnect' is FALSE if not during a connect, as then of course the
* connect timeout is not taken into account!
*
* @param data the transfer to check on
* @param nowp timestamp to use for calculdation, NULL to use Curl_now()
* @param duringconnect TRUE iff connect timeout is also taken into account.
* @unittest: 1303
*/
#define TIMEOUT_CONNECT 1
#define TIMEOUT_MAXTIME 2
timediff_t Curl_timeleft(struct Curl_easy *data,
struct curltime *nowp,
bool duringconnect)
{
unsigned int timeout_set = 0;
timediff_t connect_timeout_ms = 0;
timediff_t maxtime_timeout_ms = 0;
timediff_t timeout_ms = 0;
timediff_t timeleft_ms = 0;
timediff_t ctimeleft_ms = 0;
struct curltime now;
/* The duration of a connect and the total transfer are calculated from two
@ -119,43 +111,35 @@ timediff_t Curl_timeleft(struct Curl_easy *data,
before the connect timeout expires and we must acknowledge whichever
timeout that is reached first. The total timeout is set per entire
operation, while the connect timeout is set per connect. */
if(data->set.timeout > 0) {
timeout_set = TIMEOUT_MAXTIME;
maxtime_timeout_ms = data->set.timeout;
}
if(duringconnect) {
timeout_set |= TIMEOUT_CONNECT;
connect_timeout_ms = (data->set.connecttimeout > 0) ?
data->set.connecttimeout : DEFAULT_CONNECT_TIMEOUT;
}
if(!timeout_set)
/* no timeout */
return 0;
if(data->set.timeout <= 0 && !duringconnect)
return 0; /* no timeout in place or checked, return "no limit" */
if(!nowp) {
now = Curl_now();
nowp = &now;
}
if(timeout_set & TIMEOUT_MAXTIME) {
maxtime_timeout_ms -= Curl_timediff(*nowp, data->progress.t_startop);
timeout_ms = maxtime_timeout_ms;
if(data->set.timeout > 0) {
timeleft_ms = data->set.timeout -
Curl_timediff(*nowp, data->progress.t_startop);
if(!timeleft_ms)
timeleft_ms = -1; /* 0 is "no limit", fake 1 ms expiry */
if(!duringconnect)
return timeleft_ms; /* no connect check, this is it */
}
if(timeout_set & TIMEOUT_CONNECT) {
connect_timeout_ms -= Curl_timediff(*nowp, data->progress.t_startsingle);
if(!(timeout_set & TIMEOUT_MAXTIME) ||
(connect_timeout_ms < maxtime_timeout_ms))
timeout_ms = connect_timeout_ms;
if(duringconnect) {
timediff_t ctimeout_ms = (data->set.connecttimeout > 0) ?
data->set.connecttimeout : DEFAULT_CONNECT_TIMEOUT;
ctimeleft_ms = ctimeout_ms -
Curl_timediff(*nowp, data->progress.t_startsingle);
if(!ctimeleft_ms)
ctimeleft_ms = -1; /* 0 is "no limit", fake 1 ms expiry */
if(!timeleft_ms)
return ctimeleft_ms; /* no general timeout, this is it */
}
if(!timeout_ms)
/* avoid returning 0 as that means no timeout! */
return -1;
return timeout_ms;
/* return minimal time left or max amount already expired */
return (ctimeleft_ms < timeleft_ms)? ctimeleft_ms : timeleft_ms;
}
/* Copies connection info into the transfer handle to make it available when
@ -405,7 +389,7 @@ static CURLcode eyeballer_new(struct eyeballer **pballer,
struct eyeballer *baller;
*pballer = NULL;
baller = calloc(1, sizeof(*baller) + 1000);
baller = calloc(1, sizeof(*baller));
if(!baller)
return CURLE_OUT_OF_MEMORY;
@ -908,7 +892,7 @@ static CURLcode cf_he_connect(struct Curl_cfilter *cf,
if(result)
return result;
ctx->state = SCFST_WAITING;
/* FALLTHROUGH */
FALLTHROUGH();
case SCFST_WAITING:
result = is_connected(cf, data, done);
if(!result && *done) {

View File

@ -365,11 +365,14 @@ static CURLcode gzip_do_init(struct Curl_easy *data,
#ifdef OLD_ZLIB_SUPPORT
/* Skip over the gzip header */
static enum {
typedef enum {
GZIP_OK,
GZIP_BAD,
GZIP_UNDERFLOW
} check_gzip_header(unsigned char const *data, ssize_t len, ssize_t *headerlen)
} gzip_status;
static gzip_status check_gzip_header(unsigned char const *data, ssize_t len,
ssize_t *headerlen)
{
int method, flags;
const ssize_t totallen = len;
@ -832,8 +835,8 @@ static const struct Curl_cwtype identity_encoding = {
};
/* supported content encodings table. */
static const struct Curl_cwtype * const encodings[] = {
/* supported general content decoders. */
static const struct Curl_cwtype * const general_unencoders[] = {
&identity_encoding,
#ifdef HAVE_LIBZ
&deflate_encoding,
@ -848,6 +851,13 @@ static const struct Curl_cwtype * const encodings[] = {
NULL
};
/* supported content decoders only for transfer encodings */
static const struct Curl_cwtype * const transfer_unencoders[] = {
#ifndef CURL_DISABLE_HTTP
&Curl_httpchunk_unencoder,
#endif
NULL
};
/* Provide a list of comma-separated names of supported encodings.
*/
@ -861,7 +871,7 @@ void Curl_all_content_encodings(char *buf, size_t blen)
DEBUGASSERT(blen);
buf[0] = 0;
for(cep = encodings; *cep; cep++) {
for(cep = general_unencoders; *cep; cep++) {
ce = *cep;
if(!strcasecompare(ce->name, CONTENT_ENCODING_DEFAULT))
len += strlen(ce->name) + 2;
@ -873,7 +883,7 @@ void Curl_all_content_encodings(char *buf, size_t blen)
}
else if(blen > len) {
char *p = buf;
for(cep = encodings; *cep; cep++) {
for(cep = general_unencoders; *cep; cep++) {
ce = *cep;
if(!strcasecompare(ce->name, CONTENT_ENCODING_DEFAULT)) {
strcpy(p, ce->name);
@ -931,12 +941,23 @@ static const struct Curl_cwtype error_writer = {
};
/* Find the content encoding by name. */
static const struct Curl_cwtype *find_encoding(const char *name,
size_t len)
static const struct Curl_cwtype *find_unencode_writer(const char *name,
size_t len,
Curl_cwriter_phase phase)
{
const struct Curl_cwtype * const *cep;
for(cep = encodings; *cep; cep++) {
if(phase == CURL_CW_TRANSFER_DECODE) {
for(cep = transfer_unencoders; *cep; cep++) {
const struct Curl_cwtype *ce = *cep;
if((strncasecompare(name, ce->name, len) && !ce->name[len]) ||
(ce->alias && strncasecompare(name, ce->alias, len)
&& !ce->alias[len]))
return ce;
}
}
/* look among the general decoders */
for(cep = general_unencoders; *cep; cep++) {
const struct Curl_cwtype *ce = *cep;
if((strncasecompare(name, ce->name, len) && !ce->name[len]) ||
(ce->alias && strncasecompare(name, ce->alias, len) && !ce->alias[len]))
@ -950,7 +971,6 @@ static const struct Curl_cwtype *find_encoding(const char *name,
CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
const char *enclist, int is_transfer)
{
struct SingleRequest *k = &data->req;
Curl_cwriter_phase phase = is_transfer?
CURL_CW_TRANSFER_DECODE:CURL_CW_CONTENT_DECODE;
CURLcode result;
@ -969,16 +989,14 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
if(!ISSPACE(*enclist))
namelen = enclist - name + 1;
/* Special case: chunked encoding is handled at the reader level. */
if(is_transfer && namelen == 7 && strncasecompare(name, "chunked", 7)) {
k->chunk = TRUE; /* chunks coming our way. */
Curl_httpchunk_init(data); /* init our chunky engine. */
}
else if(namelen) {
if(namelen) {
const struct Curl_cwtype *cwt;
struct Curl_cwriter *writer;
if((is_transfer && !data->set.http_transfer_encoding) ||
/* if we skip the decoding in this phase, do not look further.
* Exception is "chunked" transfer-encoding which always must happen */
if((is_transfer && !data->set.http_transfer_encoding &&
(namelen != 7 || !strncasecompare(name, "chunked", 7))) ||
(!is_transfer && data->set.http_ce_skip)) {
/* not requested, ignore */
return CURLE_OK;
@ -990,7 +1008,7 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
return CURLE_BAD_CONTENT_ENCODING;
}
cwt = find_encoding(name, namelen);
cwt = find_unencode_writer(name, namelen, phase);
if(!cwt)
cwt = &error_writer; /* Defer error at use. */

View File

@ -365,7 +365,7 @@ static void strstore(char **str, const char *newstr, size_t len)
DEBUGASSERT(newstr);
DEBUGASSERT(str);
free(*str);
*str = Curl_strndup(newstr, len);
*str = Curl_memdup0(newstr, len);
}
/*
@ -821,10 +821,8 @@ Curl_cookie_add(struct Curl_easy *data,
endslash = memrchr(path, '/', (queryp - path));
if(endslash) {
size_t pathlen = (endslash-path + 1); /* include end slash */
co->path = malloc(pathlen + 1); /* one extra for the zero byte */
co->path = Curl_memdup0(path, pathlen);
if(co->path) {
memcpy(co->path, path, pathlen);
co->path[pathlen] = 0; /* null-terminate */
co->spath = sanitize_cookie_path(co->path);
if(!co->spath)
badcookie = TRUE; /* out of memory bad */
@ -927,7 +925,7 @@ Curl_cookie_add(struct Curl_easy *data,
if(!co->spath)
badcookie = TRUE;
fields++; /* add a field and fall down to secure */
/* FALLTHROUGH */
FALLTHROUGH();
case 3:
co->secure = FALSE;
if(strcasecompare(ptr, "TRUE")) {
@ -1229,7 +1227,7 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
if(data) {
FILE *fp = NULL;
if(file) {
if(file && *file) {
if(!strcmp(file, "-"))
fp = stdin;
else {

View File

@ -298,12 +298,6 @@
/* if you have the GNU gssapi libraries */
#cmakedefine HAVE_GSSGNU 1
/* if you have the Heimdal gssapi libraries */
#cmakedefine HAVE_GSSHEIMDAL 1
/* if you have the MIT gssapi libraries */
#cmakedefine HAVE_GSSMIT 1
/* Define to 1 if you have the `idna_strerror' function. */
#cmakedefine HAVE_IDNA_STRERROR 1
@ -599,18 +593,9 @@
/* Define to 1 if you have the <utime.h> header file. */
#cmakedefine HAVE_UTIME_H 1
/* Define to 1 if you have the windows.h header file. */
#cmakedefine HAVE_WINDOWS_H 1
/* Define to 1 if you have the winsock2.h header file. */
#cmakedefine HAVE_WINSOCK2_H 1
/* Define this symbol if your OS supports changing the contents of argv */
#cmakedefine HAVE_WRITABLE_ARGV 1
/* Define to 1 if you have the ws2tcpip.h header file. */
#cmakedefine HAVE_WS2TCPIP_H 1
/* Define to 1 if you need the lber.h header file even with ldap.h */
#cmakedefine NEED_LBER_H 1
@ -713,9 +698,6 @@ ${SIZEOF_TIME_T_CODE}
/* if libPSL is in use */
#cmakedefine USE_LIBPSL 1
/* If you want to build curl with the built-in manual */
#cmakedefine USE_MANUAL 1
/* if you want to use OpenLDAP code instead of legacy ldap implementation */
#cmakedefine USE_OPENLDAP 1

View File

@ -266,7 +266,7 @@ static CURLcode ntlm_wb_response(struct Curl_easy *data, struct ntlmdata *ntlm,
size_t len_in = strlen(input), len_out = 0;
struct dynbuf b;
char *ptr = NULL;
unsigned char *buf = (unsigned char *)data->state.buffer;
usigned char buf[1024]
Curl_dyn_init(&b, MAX_NTLM_WB_RESPONSE);
while(len_in > 0) {
@ -284,7 +284,7 @@ static CURLcode ntlm_wb_response(struct Curl_easy *data, struct ntlmdata *ntlm,
/* Read one line */
while(1) {
ssize_t size =
wakeup_read(ntlm->ntlm_auth_hlpr_socket, buf, data->set.buffer_size);
wakeup_read(ntlm->ntlm_auth_hlpr_socket, buf, sizeof(buf));
if(size == -1) {
if(errno == EINTR)
continue;
@ -481,7 +481,7 @@ CURLcode Curl_output_ntlm_wb(struct Curl_easy *data, struct connectdata *conn,
/* connection is already authenticated,
* don't send a header in future requests */
*state = NTLMSTATE_LAST;
/* FALLTHROUGH */
FALLTHROUGH();
case NTLMSTATE_LAST:
Curl_safefree(*allocuserpwd);
authp->done = TRUE;

View File

@ -31,6 +31,10 @@
#include <curl/mprintf.h>
#define MERR_OK 0
#define MERR_MEM 1
#define MERR_TOO_LARGE 2
# undef printf
# undef fprintf
# undef msnprintf

View File

@ -79,7 +79,7 @@ const struct Curl_handler Curl_handler_rtmp = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
rtmp_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_RTMP, /* defport */
@ -102,7 +102,7 @@ const struct Curl_handler Curl_handler_rtmpt = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
rtmp_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_RTMPT, /* defport */
@ -125,7 +125,7 @@ const struct Curl_handler Curl_handler_rtmpe = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
rtmp_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_RTMP, /* defport */
@ -148,7 +148,7 @@ const struct Curl_handler Curl_handler_rtmpte = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
rtmp_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_RTMPT, /* defport */
@ -171,7 +171,7 @@ const struct Curl_handler Curl_handler_rtmps = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
rtmp_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_RTMPS, /* defport */
@ -194,7 +194,7 @@ const struct Curl_handler Curl_handler_rtmpts = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
rtmp_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_RTMPS, /* defport */

View File

@ -205,18 +205,23 @@ void Curl_sasl_init(struct SASL *sasl, struct Curl_easy *data,
sasl->force_ir = FALSE; /* Respect external option */
if(auth != CURLAUTH_BASIC) {
sasl->resetprefs = FALSE;
sasl->prefmech = SASL_AUTH_NONE;
unsigned short mechs = SASL_AUTH_NONE;
/* If some usable http authentication options have been set, determine
new defaults from them. */
if(auth & CURLAUTH_BASIC)
sasl->prefmech |= SASL_MECH_PLAIN | SASL_MECH_LOGIN;
mechs |= SASL_MECH_PLAIN | SASL_MECH_LOGIN;
if(auth & CURLAUTH_DIGEST)
sasl->prefmech |= SASL_MECH_DIGEST_MD5;
mechs |= SASL_MECH_DIGEST_MD5;
if(auth & CURLAUTH_NTLM)
sasl->prefmech |= SASL_MECH_NTLM;
mechs |= SASL_MECH_NTLM;
if(auth & CURLAUTH_BEARER)
sasl->prefmech |= SASL_MECH_OAUTHBEARER | SASL_MECH_XOAUTH2;
mechs |= SASL_MECH_OAUTHBEARER | SASL_MECH_XOAUTH2;
if(auth & CURLAUTH_GSSAPI)
sasl->prefmech |= SASL_MECH_GSSAPI;
mechs |= SASL_MECH_GSSAPI;
if(mechs != SASL_AUTH_NONE)
sasl->prefmech = mechs;
}
}

View File

@ -28,6 +28,13 @@
#define CURL_NO_OLDIES
#endif
/* FIXME: Delete this once the warnings have been fixed. */
#if !defined(CURL_WARN_SIGN_CONVERSION)
#ifdef __GNUC__
#pragma GCC diagnostic ignored "-Wsign-conversion"
#endif
#endif
/* Set default _WIN32_WINNT */
#ifdef __MINGW32__
#include <_mingw.h>
@ -253,12 +260,39 @@
* Windows setup file includes some system headers.
*/
#ifdef HAVE_WINDOWS_H
#ifdef _WIN32
# include "setup-win32.h"
#endif
#include <curl/system.h>
/* curl uses its own printf() function internally. It understands the GNU
* format. Use this format, so that is matches the GNU format attribute we
* use with the mingw compiler, allowing it to verify them at compile-time.
*/
#ifdef __MINGW32__
# undef CURL_FORMAT_CURL_OFF_T
# undef CURL_FORMAT_CURL_OFF_TU
# define CURL_FORMAT_CURL_OFF_T "lld"
# define CURL_FORMAT_CURL_OFF_TU "llu"
#endif
/* based on logic in "curl/mprintf.h" */
#if (defined(__GNUC__) || defined(__clang__)) && \
defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \
!defined(CURL_NO_FMT_CHECKS)
#if defined(__MINGW32__) && !defined(__clang__)
#define CURL_PRINTF(fmt, arg) \
__attribute__((format(gnu_printf, fmt, arg)))
#else
#define CURL_PRINTF(fmt, arg) \
__attribute__((format(__printf__, fmt, arg)))
#endif
#else
#define CURL_PRINTF(fmt, arg)
#endif
/*
* Use getaddrinfo to resolve the IPv4 address literal. If the current network
* interface doesn't support IPv4, but supports IPv6, NAT64, and DNS64,
@ -408,6 +442,24 @@
#define SIZEOF_TIME_T 4
#endif
#ifndef SIZEOF_CURL_SOCKET_T
/* configure and cmake check and set the define */
# ifdef _WIN64
# define SIZEOF_CURL_SOCKET_T 8
# else
/* default guess */
# define SIZEOF_CURL_SOCKET_T 4
# endif
#endif
#if SIZEOF_CURL_SOCKET_T < 8
# define CURL_FORMAT_SOCKET_T "d"
#elif defined(__MINGW32__)
# define CURL_FORMAT_SOCKET_T "zd"
#else
# define CURL_FORMAT_SOCKET_T "qd"
#endif
/*
* Default sizeof(off_t) in case it hasn't been defined in config file.
*/
@ -648,6 +700,17 @@
#endif
#endif
/* fallthrough attribute */
#if !defined(FALLTHROUGH)
#if (defined(__GNUC__) && __GNUC__ >= 7) || \
(defined(__clang__) && __clang_major__ >= 10)
# define FALLTHROUGH() __attribute__((fallthrough))
#else
# define FALLTHROUGH() do {} while (0)
#endif
#endif
/*
* Include macros and defines that should only be processed once.
*/
@ -669,10 +732,7 @@
*/
#if defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H)
# if defined(SOCKET) || \
defined(USE_WINSOCK) || \
defined(HAVE_WINSOCK2_H) || \
defined(HAVE_WS2TCPIP_H)
# if defined(SOCKET) || defined(USE_WINSOCK)
# error "WinSock and lwIP TCP/IP stack definitions shall not coexist!"
# endif
#endif
@ -767,7 +827,13 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
#endif
#if (defined(USE_NGTCP2) && defined(USE_NGHTTP3)) || \
(defined(USE_OPENSSL_QUIC) && defined(USE_NGHTTP3)) || \
defined(USE_QUICHE) || defined(USE_MSH3)
#ifdef CURL_WITH_MULTI_SSL
#error "Multi-SSL combined with QUIC is not supported"
#endif
#define ENABLE_QUIC
#define USE_HTTP3
#endif

View File

@ -157,8 +157,10 @@ static struct Curl_cftype *cf_types[] = {
#endif
#ifdef USE_SSL
&Curl_cft_ssl,
#ifndef CURL_DISABLE_PROXY
&Curl_cft_ssl_proxy,
#endif
#endif
#if !defined(CURL_DISABLE_PROXY)
#if !defined(CURL_DISABLE_HTTP)
&Curl_cft_h1_proxy,

View File

@ -58,14 +58,7 @@ void Curl_debug(struct Curl_easy *data, curl_infotype type,
* Output a failure message on registered callbacks for transfer.
*/
void Curl_failf(struct Curl_easy *data,
#if defined(__GNUC__) && !defined(printf) && \
defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \
!defined(__MINGW32__)
const char *fmt, ...)
__attribute__((format(printf, 2, 3)));
#else
const char *fmt, ...);
#endif
const char *fmt, ...) CURL_PRINTF(2, 3);
#define failf Curl_failf
@ -102,26 +95,14 @@ void Curl_failf(struct Curl_easy *data,
* Output an informational message when transfer's verbose logging is enabled.
*/
void Curl_infof(struct Curl_easy *data,
#if defined(__GNUC__) && !defined(printf) && defined(CURL_HAVE_C99) && \
!defined(__MINGW32__)
const char *fmt, ...)
__attribute__((format(printf, 2, 3)));
#else
const char *fmt, ...);
#endif
const char *fmt, ...) CURL_PRINTF(2, 3);
/**
* Output an informational message when both transfer's verbose logging
* and connection filters verbose logging are enabled.
*/
void Curl_trc_cf_infof(struct Curl_easy *data, struct Curl_cfilter *cf,
#if defined(__GNUC__) && !defined(printf) && defined(CURL_HAVE_C99) && \
!defined(__MINGW32__)
const char *fmt, ...)
__attribute__((format(printf, 3, 4)));
#else
const char *fmt, ...);
#endif
const char *fmt, ...) CURL_PRINTF(3, 4);
#else /* defined(CURL_DISABLE_VERBOSE_STRINGS) */
/* All informational messages are not compiled in for size savings */

View File

@ -89,7 +89,7 @@ const struct Curl_handler Curl_handler_dict = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_DICT, /* defport */
@ -122,6 +122,9 @@ static char *unescape_word(const char *input)
}
/* sendf() sends formatted data to the server */
static CURLcode sendf(curl_socket_t sockfd, struct Curl_easy *data,
const char *fmt, ...) CURL_PRINTF(3, 4);
static CURLcode sendf(curl_socket_t sockfd, struct Curl_easy *data,
const char *fmt, ...)
{

View File

@ -218,7 +218,6 @@ static CURLcode dohprobe(struct Curl_easy *data,
struct curl_slist *headers)
{
struct Curl_easy *doh = NULL;
char *nurl = NULL;
CURLcode result = CURLE_OK;
timediff_t timeout_ms;
DOHcode d = doh_encode(host, dnstype, p->dohbuffer, sizeof(p->dohbuffer),
@ -351,11 +350,9 @@ static CURLcode dohprobe(struct Curl_easy *data,
}
else
goto error;
free(nurl);
return CURLE_OK;
error:
free(nurl);
Curl_close(&doh);
return result;
}
@ -447,7 +444,7 @@ static DOHcode skipqname(const unsigned char *doh, size_t dohlen,
return DOH_DNS_BAD_LABEL;
if(dohlen < (*indexp + 1 + length))
return DOH_DNS_OUT_OF_RANGE;
*indexp += 1 + length;
*indexp += (unsigned int)(1 + length);
} while(length);
return DOH_OK;
}
@ -459,14 +456,15 @@ static unsigned short get16bit(const unsigned char *doh, int index)
static unsigned int get32bit(const unsigned char *doh, int index)
{
/* make clang and gcc optimize this to bswap by incrementing
the pointer first. */
doh += index;
/* make clang and gcc optimize this to bswap by incrementing
the pointer first. */
doh += index;
/* avoid undefined behavior by casting to unsigned before shifting
24 bits, possibly into the sign bit. codegen is same, but
ub sanitizer won't be upset */
return ( (unsigned)doh[0] << 24) | (doh[1] << 16) |(doh[2] << 8) | doh[3];
/* avoid undefined behavior by casting to unsigned before shifting
24 bits, possibly into the sign bit. codegen is same, but
ub sanitizer won't be upset */
return ((unsigned)doh[0] << 24) | ((unsigned)doh[1] << 16) |
((unsigned)doh[2] << 8) | doh[3];
}
static DOHcode store_a(const unsigned char *doh, int index, struct dohentry *d)
@ -904,7 +902,6 @@ UNITTEST void de_cleanup(struct dohentry *d)
CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
struct Curl_dns_entry **dnsp)
{
struct connectdata *conn = data->conn;
CURLcode result;
struct dohdata *dohp = data->req.doh;
*dnsp = NULL; /* defaults to no response */
@ -913,7 +910,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
if(!dohp->probe[DOH_PROBE_SLOT_IPADDR_V4].easy &&
!dohp->probe[DOH_PROBE_SLOT_IPADDR_V6].easy) {
failf(data, "Could not DoH-resolve: %s", conn->resolve_async.hostname);
failf(data, "Could not DoH-resolve: %s", data->state.async.hostname);
return CONN_IS_PROXIED(data->conn)?CURLE_COULDNT_RESOLVE_PROXY:
CURLE_COULDNT_RESOLVE_HOST;
}
@ -976,7 +973,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
Curl_freeaddrinfo(ai);
}
else {
conn->resolve_async.dns = dns;
data->state.async.dns = dns;
*dnsp = dns;
result = CURLE_OK; /* address resolution OK */
}

View File

@ -81,7 +81,7 @@ static CURLcode dyn_nappend(struct dynbuf *s,
if(fit > s->toobig) {
Curl_dyn_free(s);
return CURLE_OUT_OF_MEMORY;
return CURLE_TOO_LARGE;
}
else if(!a) {
DEBUGASSERT(!indx);
@ -199,6 +199,9 @@ CURLcode Curl_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap)
if(!rc)
return CURLE_OK;
else if(rc == MERR_TOO_LARGE)
return CURLE_TOO_LARGE;
return CURLE_OUT_OF_MEMORY;
#else
char *str;
str = vaprintf(fmt, ap); /* this allocs a new string to append */
@ -210,8 +213,8 @@ CURLcode Curl_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap)
}
/* If we failed, we cleanup the whole buffer and return error */
Curl_dyn_free(s);
return CURLE_OK;
#endif
return CURLE_OUT_OF_MEMORY;
}
/*

View File

@ -61,9 +61,9 @@ CURLcode Curl_dyn_addn(struct dynbuf *s, const void *mem, size_t len)
CURLcode Curl_dyn_add(struct dynbuf *s, const char *str)
WARN_UNUSED_RESULT;
CURLcode Curl_dyn_addf(struct dynbuf *s, const char *fmt, ...)
WARN_UNUSED_RESULT;
WARN_UNUSED_RESULT CURL_PRINTF(2, 3);
CURLcode Curl_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap)
WARN_UNUSED_RESULT;
WARN_UNUSED_RESULT CURL_PRINTF(2, 0);
void Curl_dyn_reset(struct dynbuf *s);
CURLcode Curl_dyn_tail(struct dynbuf *s, size_t trail);
CURLcode Curl_dyn_setlen(struct dynbuf *s, size_t set);

View File

@ -480,13 +480,15 @@ static int events_socket(struct Curl_easy *easy, /* easy handle */
ev->list = nxt;
free(m);
m = nxt;
infof(easy, "socket cb: socket %d REMOVED", s);
infof(easy, "socket cb: socket %" CURL_FORMAT_SOCKET_T
" REMOVED", s);
}
else {
/* The socket 's' is already being monitored, update the activity
mask. Convert from libcurl bitmask to the poll one. */
m->socket.events = socketcb2poll(what);
infof(easy, "socket cb: socket %d UPDATED as %s%s", s,
infof(easy, "socket cb: socket %" CURL_FORMAT_SOCKET_T
" UPDATED as %s%s", s,
(what&CURL_POLL_IN)?"IN":"",
(what&CURL_POLL_OUT)?"OUT":"");
}
@ -510,7 +512,8 @@ static int events_socket(struct Curl_easy *easy, /* easy handle */
m->socket.events = socketcb2poll(what);
m->socket.revents = 0;
ev->list = m;
infof(easy, "socket cb: socket %d ADDED as %s%s", s,
infof(easy, "socket cb: socket %" CURL_FORMAT_SOCKET_T
" ADDED as %s%s", s,
(what&CURL_POLL_IN)?"IN":"",
(what&CURL_POLL_OUT)?"OUT":"");
}
@ -599,8 +602,9 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
if(fds[i].revents) {
/* socket activity, tell libcurl */
int act = poll2cselect(fds[i].revents); /* convert */
infof(multi->easyp, "call curl_multi_socket_action(socket %d)",
fds[i].fd);
infof(multi->easyp,
"call curl_multi_socket_action(socket "
"%" CURL_FORMAT_SOCKET_T ")", fds[i].fd);
mcode = curl_multi_socket_action(multi, fds[i].fd, act,
&ev->running_handles);
}
@ -684,9 +688,9 @@ static CURLcode easy_transfer(struct Curl_multi *multi)
/* Make sure to return some kind of error if there was a multi problem */
if(mcode) {
result = (mcode == CURLM_OUT_OF_MEMORY) ? CURLE_OUT_OF_MEMORY :
/* The other multi errors should never happen, so return
something suitably generic */
CURLE_BAD_FUNCTION_ARGUMENT;
/* The other multi errors should never happen, so return
something suitably generic */
CURLE_BAD_FUNCTION_ARGUMENT;
}
return result;
@ -973,6 +977,36 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
}
#endif
#ifdef CURLRES_ASYNCH
/* Clone the resolver handle, if present, for the new handle */
if(Curl_resolver_duphandle(outcurl,
&outcurl->state.async.resolver,
data->state.async.resolver))
goto fail;
#endif
#ifdef USE_ARES
{
CURLcode rc;
rc = Curl_set_dns_servers(outcurl, data->set.str[STRING_DNS_SERVERS]);
if(rc && rc != CURLE_NOT_BUILT_IN)
goto fail;
rc = Curl_set_dns_interface(outcurl, data->set.str[STRING_DNS_INTERFACE]);
if(rc && rc != CURLE_NOT_BUILT_IN)
goto fail;
rc = Curl_set_dns_local_ip4(outcurl, data->set.str[STRING_DNS_LOCAL_IP4]);
if(rc && rc != CURLE_NOT_BUILT_IN)
goto fail;
rc = Curl_set_dns_local_ip6(outcurl, data->set.str[STRING_DNS_LOCAL_IP6]);
if(rc && rc != CURLE_NOT_BUILT_IN)
goto fail;
}
#endif /* USE_ARES */
Curl_initinfo(outcurl);
outcurl->magic = CURLEASY_MAGIC_NUMBER;
@ -1111,7 +1145,7 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action)
if(!data->state.tempcount)
/* if not pausing again, force a recv/send check of this connection as
the data might've been read off the socket already */
data->conn->cselect_bits = CURL_CSELECT_IN | CURL_CSELECT_OUT;
data->state.select_bits = CURL_CSELECT_IN | CURL_CSELECT_OUT;
if(data->multi) {
if(Curl_update_timer(data->multi))
return CURLE_ABORTED_BY_CALLBACK;

View File

@ -274,6 +274,8 @@ struct curl_easyoption Curl_easyopts[] = {
{"SEEKFUNCTION", CURLOPT_SEEKFUNCTION, CURLOT_FUNCTION, 0},
{"SERVER_RESPONSE_TIMEOUT", CURLOPT_SERVER_RESPONSE_TIMEOUT,
CURLOT_LONG, 0},
{"SERVER_RESPONSE_TIMEOUT_MS", CURLOPT_SERVER_RESPONSE_TIMEOUT_MS,
CURLOT_LONG, 0},
{"SERVICE_NAME", CURLOPT_SERVICE_NAME, CURLOT_STRING, 0},
{"SHARE", CURLOPT_SHARE, CURLOT_OBJECT, 0},
{"SOCKOPTDATA", CURLOPT_SOCKOPTDATA, CURLOT_CBPTR, 0},
@ -373,6 +375,6 @@ struct curl_easyoption Curl_easyopts[] = {
*/
int Curl_easyopts_check(void)
{
return ((CURLOPT_LASTENTRY%10000) != (323 + 1));
return ((CURLOPT_LASTENTRY%10000) != (324 + 1));
}
#endif

View File

@ -113,7 +113,7 @@ const struct Curl_handler Curl_handler_file = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
file_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
0, /* defport */
@ -290,16 +290,15 @@ static CURLcode file_upload(struct Curl_easy *data)
int fd;
int mode;
CURLcode result = CURLE_OK;
char *buf = data->state.buffer;
char buffer[8*1024], *uphere_save;
curl_off_t bytecount = 0;
struct_stat file_stat;
const char *buf2;
const char *sendbuf;
/*
* Since FILE: doesn't do the full init, we need to provide some extra
* assignments here.
*/
data->req.upload_fromhere = buf;
if(!dir)
return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */
@ -338,11 +337,15 @@ static CURLcode file_upload(struct Curl_easy *data)
data->state.resume_from = (curl_off_t)file_stat.st_size;
}
/* Yikes! Curl_fillreadbuffer uses data->req.upload_fromhere to READ
* client data to! Please, someone fix... */
uphere_save = data->req.upload_fromhere;
while(!result) {
size_t nread;
ssize_t nwrite;
size_t readcount;
result = Curl_fillreadbuffer(data, data->set.buffer_size, &readcount);
data->req.upload_fromhere = buffer;
result = Curl_fillreadbuffer(data, sizeof(buffer), &readcount);
if(result)
break;
@ -356,19 +359,19 @@ static CURLcode file_upload(struct Curl_easy *data)
if((curl_off_t)nread <= data->state.resume_from) {
data->state.resume_from -= nread;
nread = 0;
buf2 = buf;
sendbuf = buffer;
}
else {
buf2 = buf + data->state.resume_from;
sendbuf = buffer + data->state.resume_from;
nread -= (size_t)data->state.resume_from;
data->state.resume_from = 0;
}
}
else
buf2 = buf;
sendbuf = buffer;
/* write the data to the target */
nwrite = write(fd, buf2, nread);
nwrite = write(fd, sendbuf, nread);
if((size_t)nwrite != nread) {
result = CURLE_SEND_ERROR;
break;
@ -387,6 +390,7 @@ static CURLcode file_upload(struct Curl_easy *data)
result = CURLE_ABORTED_BY_CALLBACK;
close(fd);
data->req.upload_fromhere = uphere_save;
return result;
}
@ -413,14 +417,11 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
curl_off_t expected_size = -1;
bool size_known;
bool fstated = FALSE;
char *buf = data->state.buffer;
int fd;
struct FILEPROTO *file;
*done = TRUE; /* unconditionally */
Curl_pgrsStartNow(data);
if(data->state.upload)
return file_upload(data);
@ -543,21 +544,22 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
Curl_pgrsTime(data, TIMER_STARTTRANSFER);
while(!result) {
char tmpbuf[8*1024];
ssize_t nread;
/* Don't fill a whole buffer if we want less than all data */
size_t bytestoread;
if(size_known) {
bytestoread = (expected_size < data->set.buffer_size) ?
curlx_sotouz(expected_size) : (size_t)data->set.buffer_size;
bytestoread = (expected_size < (curl_off_t)(sizeof(tmpbuf)-1)) ?
curlx_sotouz(expected_size) : (sizeof(tmpbuf)-1);
}
else
bytestoread = data->set.buffer_size-1;
bytestoread = sizeof(tmpbuf)-1;
nread = read(fd, buf, bytestoread);
nread = read(fd, tmpbuf, bytestoread);
if(nread > 0)
buf[nread] = 0;
tmpbuf[nread] = 0;
if(nread <= 0 || (size_known && (expected_size == 0)))
break;
@ -565,7 +567,7 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
if(size_known)
expected_size -= nread;
result = Curl_client_write(data, CLIENTWRITE_BODY, buf, nread);
result = Curl_client_write(data, CLIENTWRITE_BODY, tmpbuf, nread);
if(result)
return result;

View File

@ -277,7 +277,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
case CURLFORM_PTRNAME:
current_form->flags |= HTTPPOST_PTRNAME; /* fall through */
/* FALLTHROUGH */
FALLTHROUGH();
case CURLFORM_COPYNAME:
if(current_form->name)
return_value = CURL_FORMADD_OPTION_TWICE;
@ -303,7 +303,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
*/
case CURLFORM_PTRCONTENTS:
current_form->flags |= HTTPPOST_PTRCONTENTS;
/* FALLTHROUGH */
FALLTHROUGH();
case CURLFORM_COPYCONTENTS:
if(current_form->value)
return_value = CURL_FORMADD_OPTION_TWICE;
@ -603,7 +603,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
app passed in a bad combo, so we better check for that first. */
if(form->name) {
/* copy name (without strdup; possibly not null-terminated) */
form->name = Curl_strndup(form->name, form->namelength?
form->name = Curl_memdup0(form->name, form->namelength?
form->namelength:
strlen(form->name));
}
@ -779,11 +779,9 @@ static CURLcode setname(curl_mimepart *part, const char *name, size_t len)
if(!name || !len)
return curl_mime_name(part, name);
zname = malloc(len + 1);
zname = Curl_memdup0(name, len);
if(!zname)
return CURLE_OUT_OF_MEMORY;
memcpy(zname, name, len);
zname[len] = '\0';
res = curl_mime_name(part, zname);
free(zname);
return res;

201
lib/ftp.c
View File

@ -72,6 +72,7 @@
#include "warnless.h"
#include "http_proxy.h"
#include "socks.h"
#include "strdup.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
@ -167,7 +168,7 @@ const struct Curl_handler Curl_handler_ftp = {
ftp_domore_getsock, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ftp_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_FTP, /* defport */
@ -198,7 +199,7 @@ const struct Curl_handler Curl_handler_ftps = {
ftp_domore_getsock, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ftp_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_FTPS, /* defport */
@ -362,10 +363,11 @@ static CURLcode ReceivedServerConnect(struct Curl_easy *data, bool *received)
curl_socket_t data_sock = conn->sock[SECONDARYSOCKET];
struct ftp_conn *ftpc = &conn->proto.ftpc;
struct pingpong *pp = &ftpc->pp;
int result;
int socketstate = 0;
timediff_t timeout_ms;
ssize_t nread;
int ftpcode;
bool response = FALSE;
*received = FALSE;
@ -378,17 +380,21 @@ static CURLcode ReceivedServerConnect(struct Curl_easy *data, bool *received)
}
/* First check whether there is a cached response from server */
if(pp->cache_size && pp->cache && pp->cache[0] > '3') {
if(Curl_dyn_len(&pp->recvbuf) && (*Curl_dyn_ptr(&pp->recvbuf) > '3')) {
/* Data connection could not be established, let's return */
infof(data, "There is negative response in cache while serv connect");
(void)Curl_GetFTPResponse(data, &nread, &ftpcode);
return CURLE_FTP_ACCEPT_FAILED;
}
result = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0);
if(pp->overflow)
/* there is pending control data still in the buffer to read */
response = TRUE;
else
socketstate = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0);
/* see if the connection request is already here */
switch(result) {
switch(socketstate) {
case -1: /* error */
/* let's die here */
failf(data, "Error while waiting for server connect");
@ -396,23 +402,23 @@ static CURLcode ReceivedServerConnect(struct Curl_easy *data, bool *received)
case 0: /* Server connect is not received yet */
break; /* loop */
default:
if(result & CURL_CSELECT_IN2) {
if(socketstate & CURL_CSELECT_IN2) {
infof(data, "Ready to accept data connection from server");
*received = TRUE;
}
else if(result & CURL_CSELECT_IN) {
infof(data, "Ctrl conn has data while waiting for data conn");
(void)Curl_GetFTPResponse(data, &nread, &ftpcode);
if(ftpcode/100 > 3)
return CURLE_FTP_ACCEPT_FAILED;
return CURLE_WEIRD_SERVER_REPLY;
}
else if(socketstate & CURL_CSELECT_IN)
response = TRUE;
break;
} /* switch() */
}
if(response) {
infof(data, "Ctrl conn has data while waiting for data conn");
(void)Curl_GetFTPResponse(data, &nread, &ftpcode);
if(ftpcode/100 > 3)
return CURLE_FTP_ACCEPT_FAILED;
return CURLE_WEIRD_SERVER_REPLY;
}
return CURLE_OK;
}
@ -553,7 +559,7 @@ static CURLcode ftp_readresp(struct Curl_easy *data,
#ifdef HAVE_GSSAPI
{
struct connectdata *conn = data->conn;
char * const buf = data->state.buffer;
char * const buf = Curl_dyn_ptr(&data->conn->proto.ftpc.pp.recvbuf);
/* handle the security-oriented responses 6xx ***/
switch(code) {
@ -659,7 +665,7 @@ CURLcode Curl_GetFTPResponse(struct Curl_easy *data,
*
*/
if(pp->cache && (cache_skip < 2)) {
if(Curl_dyn_len(&pp->recvbuf) && (cache_skip < 2)) {
/*
* There's a cache left since before. We then skipping the wait for
* socket action, unless this is the same cache like the previous round
@ -687,7 +693,7 @@ CURLcode Curl_GetFTPResponse(struct Curl_easy *data,
if(result)
break;
if(!nread && pp->cache)
if(!nread && Curl_dyn_len(&pp->recvbuf))
/* bump cache skip counter as on repeated skips we must wait for more
data */
cache_skip++;
@ -926,6 +932,8 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
bool possibly_non_local = TRUE;
char buffer[STRERROR_LEN];
char *addr = NULL;
size_t addrlen = 0;
char ipstr[50];
/* Step 1, figure out what is requested,
* accepted format :
@ -934,32 +942,17 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
if(data->set.str[STRING_FTPPORT] &&
(strlen(data->set.str[STRING_FTPPORT]) > 1)) {
#ifdef ENABLE_IPV6
size_t addrlen = INET6_ADDRSTRLEN > strlen(string_ftpport) ?
INET6_ADDRSTRLEN : strlen(string_ftpport);
#else
size_t addrlen = INET_ADDRSTRLEN > strlen(string_ftpport) ?
INET_ADDRSTRLEN : strlen(string_ftpport);
#endif
char *ip_start = string_ftpport;
char *ip_end = NULL;
char *port_start = NULL;
char *port_sep = NULL;
addr = calloc(1, addrlen + 1);
if(!addr) {
result = CURLE_OUT_OF_MEMORY;
goto out;
}
#ifdef ENABLE_IPV6
if(*string_ftpport == '[') {
/* [ipv6]:port(-range) */
ip_start = string_ftpport + 1;
ip_end = strchr(string_ftpport, ']');
if(ip_end)
strncpy(addr, ip_start, ip_end - ip_start);
char *ip_start = string_ftpport + 1;
ip_end = strchr(ip_start, ']');
if(ip_end) {
addrlen = ip_end - ip_start;
addr = ip_start;
}
}
else
#endif
@ -969,28 +962,27 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
}
else {
ip_end = strchr(string_ftpport, ':');
addr = string_ftpport;
if(ip_end) {
/* either ipv6 or (ipv4|domain|interface):port(-range) */
addrlen = ip_end - string_ftpport;
#ifdef ENABLE_IPV6
if(Curl_inet_pton(AF_INET6, string_ftpport, &sa6->sin6_addr) == 1) {
/* ipv6 */
port_min = port_max = 0;
strcpy(addr, string_ftpport);
ip_end = NULL; /* this got no port ! */
}
else
#endif
/* (ipv4|domain|interface):port(-range) */
strncpy(addr, string_ftpport, ip_end - ip_start);
}
else
/* ipv4|interface */
strcpy(addr, string_ftpport);
addrlen = strlen(string_ftpport);
}
/* parse the port */
if(ip_end) {
port_start = strchr(ip_end, ':');
char *port_sep = NULL;
char *port_start = strchr(ip_end, ':');
if(port_start) {
port_min = curlx_ultous(strtoul(port_start + 1, NULL, 10));
port_sep = strchr(port_start, '-');
@ -1011,22 +1003,29 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
if(port_min > port_max)
port_min = port_max = 0;
if(*addr != '\0') {
if(addrlen) {
DEBUGASSERT(addr);
if(addrlen >= sizeof(ipstr))
goto out;
memcpy(ipstr, addr, addrlen);
ipstr[addrlen] = 0;
/* attempt to get the address of the given interface name */
switch(Curl_if2ip(conn->remote_addr->family,
#ifdef ENABLE_IPV6
Curl_ipv6_scope(&conn->remote_addr->sa_addr),
conn->scope_id,
#endif
addr, hbuf, sizeof(hbuf))) {
ipstr, hbuf, sizeof(hbuf))) {
case IF2IP_NOT_FOUND:
/* not an interface, use the given string as host name instead */
host = addr;
host = ipstr;
break;
case IF2IP_AF_NOT_SUPPORTED:
goto out;
case IF2IP_FOUND:
host = hbuf; /* use the hbuf for host name */
break;
}
}
else
@ -1266,7 +1265,6 @@ out:
}
if(portsock != CURL_SOCKET_BAD)
Curl_socket_close(data, conn, portsock);
free(addr);
return result;
}
@ -1589,13 +1587,14 @@ static CURLcode ftp_state_ul_setup(struct Curl_easy *data,
}
/* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
do {
char scratch[4*1024];
size_t readthisamountnow =
(data->state.resume_from - passed > data->set.buffer_size) ?
(size_t)data->set.buffer_size :
(data->state.resume_from - passed > (curl_off_t)sizeof(scratch)) ?
sizeof(scratch) :
curlx_sotouz(data->state.resume_from - passed);
size_t actuallyread =
data->state.fread_func(data->state.buffer, 1, readthisamountnow,
data->state.fread_func(scratch, 1, readthisamountnow,
data->state.in);
passed += actuallyread;
@ -1828,7 +1827,9 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
struct Curl_dns_entry *addr = NULL;
enum resolve_t rc;
unsigned short connectport; /* the local port connect() should use! */
char *str = &data->state.buffer[4]; /* start on the first letter */
struct pingpong *pp = &ftpc->pp;
char *str =
Curl_dyn_ptr(&pp->recvbuf) + 4; /* start on the first letter */
/* if we come here again, make sure the former name is cleared */
Curl_safefree(ftpc->newhost);
@ -2106,8 +2107,9 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
/* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
last .sss part is optional and means fractions of a second */
int year, month, day, hour, minute, second;
if(ftp_213_date(&data->state.buffer[4],
&year, &month, &day, &hour, &minute, &second)) {
struct pingpong *pp = &ftpc->pp;
char *resp = Curl_dyn_ptr(&pp->recvbuf) + 4;
if(ftp_213_date(resp, &year, &month, &day, &hour, &minute, &second)) {
/* we have a time, reformat it */
char timebuf[24];
msnprintf(timebuf, sizeof(timebuf),
@ -2318,7 +2320,8 @@ static CURLcode ftp_state_size_resp(struct Curl_easy *data,
{
CURLcode result = CURLE_OK;
curl_off_t filesize = -1;
char *buf = data->state.buffer;
char *buf = Curl_dyn_ptr(&data->conn->proto.ftpc.pp.recvbuf);
size_t len = data->conn->proto.ftpc.pp.nfinal;
/* get the size from the ascii string: */
if(ftpcode == 213) {
@ -2326,13 +2329,13 @@ static CURLcode ftp_state_size_resp(struct Curl_easy *data,
for all the digits at the end of the response and parse only those as a
number. */
char *start = &buf[4];
char *fdigit = strchr(start, '\r');
char *fdigit = memchr(start, '\r', len);
if(fdigit) {
do
fdigit--;
if(*fdigit == '\n')
fdigit--;
while(ISDIGIT(fdigit[-1]) && (fdigit > start))
fdigit--;
while(ISDIGIT(*fdigit) && (fdigit > start));
if(!ISDIGIT(*fdigit))
fdigit++;
}
else
fdigit = start;
@ -2501,7 +2504,7 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data,
*
* Example D above makes this parsing a little tricky */
char *bytes;
char *buf = data->state.buffer;
char *buf = Curl_dyn_ptr(&conn->proto.ftpc.pp.recvbuf);
bytes = strstr(buf, " bytes");
if(bytes) {
long in = (long)(--bytes-buf);
@ -2770,7 +2773,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
case FTP_AUTH:
/* we have gotten the response to a previous AUTH command */
if(pp->cache_size)
if(pp->overflow)
return CURLE_WEIRD_SERVER_REPLY; /* Forbid pipelining in response. */
/* RFC2228 (page 5) says:
@ -2868,14 +2871,11 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
case FTP_PWD:
if(ftpcode == 257) {
char *ptr = &data->state.buffer[4]; /* start on the first letter */
const size_t buf_size = data->set.buffer_size;
char *dir;
char *ptr = Curl_dyn_ptr(&pp->recvbuf) + 4; /* start on the first
letter */
bool entry_extracted = FALSE;
dir = malloc(nread + 1);
if(!dir)
return CURLE_OUT_OF_MEMORY;
struct dynbuf out;
Curl_dyn_init(&out, 1000);
/* Reply format is like
257<space>[rubbish]"<directory-name>"<space><commentary> and the
@ -2887,33 +2887,30 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
*/
/* scan for the first double-quote for non-standard responses */
while(ptr < &data->state.buffer[buf_size]
&& *ptr != '\n' && *ptr != '\0' && *ptr != '"')
while(*ptr != '\n' && *ptr != '\0' && *ptr != '"')
ptr++;
if('\"' == *ptr) {
/* it started good */
char *store;
ptr++;
for(store = dir; *ptr;) {
for(ptr++; *ptr; ptr++) {
if('\"' == *ptr) {
if('\"' == ptr[1]) {
/* "quote-doubling" */
*store = ptr[1];
result = Curl_dyn_addn(&out, &ptr[1], 1);
ptr++;
}
else {
/* end of path */
entry_extracted = TRUE;
if(Curl_dyn_len(&out))
entry_extracted = TRUE;
break; /* get out of this loop */
}
}
else
*store = *ptr;
store++;
ptr++;
result = Curl_dyn_addn(&out, ptr, 1);
if(result)
return result;
}
*store = '\0'; /* null-terminate */
}
if(entry_extracted) {
/* If the path name does not look like an absolute path (i.e.: it
@ -2927,6 +2924,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
The method used here is to check the server OS: we do it only
if the path name looks strange to minimize overhead on other
systems. */
char *dir = Curl_dyn_ptr(&out);
if(!ftpc->server_os && dir[0] != '/') {
result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SYST");
@ -2951,7 +2949,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
}
else {
/* couldn't get the path */
free(dir);
Curl_dyn_free(&out);
infof(data, "Failed to figure out path");
}
}
@ -2961,25 +2959,23 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
case FTP_SYST:
if(ftpcode == 215) {
char *ptr = &data->state.buffer[4]; /* start on the first letter */
char *ptr = Curl_dyn_ptr(&pp->recvbuf) + 4; /* start on the first
letter */
char *os;
char *store;
os = malloc(nread + 1);
if(!os)
return CURLE_OUT_OF_MEMORY;
char *start;
/* Reply format is like
215<space><OS-name><space><commentary>
*/
while(*ptr == ' ')
ptr++;
for(store = os; *ptr && *ptr != ' ';)
*store++ = *ptr++;
*store = '\0'; /* null-terminate */
for(start = ptr; *ptr && *ptr != ' '; ptr++)
;
os = Curl_memdup0(start, ptr - start);
if(!os)
return CURLE_OUT_OF_MEMORY;
/* Check for special servers here. */
if(strcasecompare(os, "OS/400")) {
/* Force OS400 name format 1. */
result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SITE NAMEFMT 1");
@ -3131,7 +3127,6 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
break;
case FTP_QUIT:
/* fallthrough, just stop! */
default:
/* internal error */
ftp_state(data, FTP_STOP);
@ -3206,8 +3201,7 @@ static CURLcode ftp_connect(struct Curl_easy *data,
conn->bits.ftp_use_control_ssl = TRUE;
}
Curl_pp_setup(pp); /* once per transfer */
Curl_pp_init(data, pp); /* init the generic pingpong data */
Curl_pp_init(pp); /* once per transfer */
/* When we connect, we start in the state where we await the 220
response */
@ -3258,14 +3252,13 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
case CURLE_REMOTE_FILE_NOT_FOUND:
case CURLE_WRITE_ERROR:
/* the connection stays alive fine even though this happened */
/* fall-through */
case CURLE_OK: /* doesn't affect the control connection's status */
if(!premature)
break;
/* until we cope better with prematurely ended requests, let them
* fallback as if in complete failure */
/* FALLTHROUGH */
FALLTHROUGH();
default: /* by default, an error means the control connection is
wedged and should not be used anymore */
ftpc->ctl_valid = FALSE;
@ -4177,13 +4170,12 @@ CURLcode ftp_parse_url_path(struct Curl_easy *data)
return CURLE_OUT_OF_MEMORY;
}
ftpc->dirs[0] = calloc(1, dirlen + 1);
ftpc->dirs[0] = Curl_memdup0(rawPath, dirlen);
if(!ftpc->dirs[0]) {
free(rawPath);
return CURLE_OUT_OF_MEMORY;
}
strncpy(ftpc->dirs[0], rawPath, dirlen);
ftpc->dirdepth = 1; /* we consider it to be a single dir */
fileName = slashPos + 1; /* rest is file name */
}
@ -4222,12 +4214,11 @@ CURLcode ftp_parse_url_path(struct Curl_easy *data)
CWD requires a parameter and a non-existent parameter a) doesn't
work on many servers and b) has no effect on the others. */
if(compLen > 0) {
char *comp = calloc(1, compLen + 1);
char *comp = Curl_memdup0(curPos, compLen);
if(!comp) {
free(rawPath);
return CURLE_OUT_OF_MEMORY;
}
strncpy(comp, curPos, compLen);
ftpc->dirs[ftpc->dirdepth++] = comp;
}
curPos = slashPos + 1;

View File

@ -409,6 +409,9 @@ static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info,
case CURLINFO_STARTTRANSFER_TIME_T:
*param_offt = data->progress.t_starttransfer;
break;
case CURLINFO_QUEUE_TIME_T:
*param_offt = data->progress.t_postqueue;
break;
case CURLINFO_REDIRECT_TIME_T:
*param_offt = data->progress.t_redirect;
break;
@ -420,7 +423,7 @@ static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info,
break;
case CURLINFO_CONN_ID:
*param_offt = data->conn?
data->conn->connection_id : data->state.recent_conn_id;
data->conn->connection_id : data->state.recent_conn_id;
break;
default:
return CURLE_UNKNOWN_OPTION;

View File

@ -75,7 +75,7 @@ const struct Curl_handler Curl_handler_gopher = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_GOPHER, /* defport */
@ -99,7 +99,7 @@ const struct Curl_handler Curl_handler_gophers = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_GOPHER, /* defport */

View File

@ -185,7 +185,7 @@ struct curl_header *curl_easy_nextheader(CURL *easy,
}
static CURLcode namevalue(char *header, size_t hlen, unsigned int type,
char **name, char **value)
char **name, char **value)
{
char *end = header + hlen - 1; /* point to the last byte */
DEBUGASSERT(hlen);
@ -292,9 +292,10 @@ CURLcode Curl_headers_push(struct Curl_easy *data, const char *header,
if(!end) {
end = strchr(header, '\n');
if(!end)
return CURLE_BAD_FUNCTION_ARGUMENT;
/* neither CR nor LF as terminator is not a valid header */
return CURLE_WEIRD_SERVER_REPLY;
}
hlen = end - header + 1;
hlen = end - header;
if((header[0] == ' ') || (header[0] == '\t')) {
if(data->state.prevhead)
@ -319,21 +320,19 @@ CURLcode Curl_headers_push(struct Curl_easy *data, const char *header,
hs->buffer[hlen] = 0; /* nul terminate */
result = namevalue(hs->buffer, hlen, type, &name, &value);
if(result)
goto fail;
if(!result) {
hs->name = name;
hs->value = value;
hs->type = type;
hs->request = data->state.requests;
hs->name = name;
hs->value = value;
hs->type = type;
hs->request = data->state.requests;
/* insert this node into the list of headers */
Curl_llist_insert_next(&data->state.httphdrs, data->state.httphdrs.tail,
hs, &hs->node);
data->state.prevhead = hs;
return CURLE_OK;
fail:
free(hs);
/* insert this node into the list of headers */
Curl_llist_insert_next(&data->state.httphdrs, data->state.httphdrs.tail,
hs, &hs->node);
data->state.prevhead = hs;
}
else
free(hs);
return result;
}

View File

@ -67,11 +67,10 @@ CURLcode Curl_addrinfo_callback(struct Curl_easy *data,
int status,
struct Curl_addrinfo *ai)
{
struct connectdata *conn = data->conn;
struct Curl_dns_entry *dns = NULL;
CURLcode result = CURLE_OK;
conn->resolve_async.status = status;
data->state.async.status = status;
if(CURL_ASYNC_SUCCESS == status) {
if(ai) {
@ -79,8 +78,8 @@ CURLcode Curl_addrinfo_callback(struct Curl_easy *data,
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
dns = Curl_cache_addr(data, ai,
conn->resolve_async.hostname, 0,
conn->resolve_async.port);
data->state.async.hostname, 0,
data->state.async.port);
if(data->share)
Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
@ -95,12 +94,12 @@ CURLcode Curl_addrinfo_callback(struct Curl_easy *data,
}
}
conn->resolve_async.dns = dns;
data->state.async.dns = dns;
/* Set async.done TRUE last in this function since it may be used multi-
threaded and once this is TRUE the other thread may read fields from the
async struct */
conn->resolve_async.done = TRUE;
data->state.async.done = TRUE;
/* IPv4: The input hostent struct will be freed by ares when we return from
this function */

View File

@ -741,7 +741,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
Curl_set_in_callback(data, true);
st = data->set.resolver_start(
#ifdef USE_CURL_ASYNC
conn->resolve_async.resolver,
data->state.async.resolver,
#else
NULL,
#endif
@ -754,16 +754,22 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
#ifndef USE_RESOLVE_ON_IPS
/* First check if this is an IPv4 address string */
if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
if(Curl_inet_pton(AF_INET, hostname, &in) > 0) {
/* This is a dotted IP address 123.123.123.123-style */
addr = Curl_ip2addr(AF_INET, &in, hostname, port);
if(!addr)
return CURLRESOLV_ERROR;
}
#ifdef ENABLE_IPV6
if(!addr) {
else {
struct in6_addr in6;
/* check if this is an IPv6 address string */
if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0)
if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0) {
/* This is an IPv6 address literal */
addr = Curl_ip2addr(AF_INET6, &in6, hostname, port);
if(!addr)
return CURLRESOLV_ERROR;
}
}
#endif /* ENABLE_IPV6 */
@ -1415,9 +1421,9 @@ CURLcode Curl_once_resolved(struct Curl_easy *data, bool *protocol_done)
struct connectdata *conn = data->conn;
#ifdef USE_CURL_ASYNC
if(conn->resolve_async.dns) {
conn->dns_entry = conn->resolve_async.dns;
conn->resolve_async.dns = NULL;
if(data->state.async.dns) {
conn->dns_entry = data->state.async.dns;
data->state.async.dns = NULL;
}
#endif
@ -1439,11 +1445,11 @@ CURLcode Curl_once_resolved(struct Curl_easy *data, bool *protocol_done)
#ifdef USE_CURL_ASYNC
CURLcode Curl_resolver_error(struct Curl_easy *data)
{
struct connectdata *conn = data->conn;
const char *host_or_proxy;
CURLcode result;
#ifndef CURL_DISABLE_PROXY
struct connectdata *conn = data->conn;
if(conn->bits.httpproxy) {
host_or_proxy = "proxy";
result = CURLE_COULDNT_RESOLVE_PROXY;
@ -1456,7 +1462,7 @@ CURLcode Curl_resolver_error(struct Curl_easy *data)
}
failf(data, "Could not resolve %s: %s", host_or_proxy,
conn->resolve_async.hostname);
data->state.async.hostname);
return result;
}

View File

@ -117,8 +117,6 @@ static CURLcode hsts_create(struct hsts *h,
bool subdomains,
curl_off_t expires)
{
struct stsentry *sts;
char *duphost;
size_t hlen;
DEBUGASSERT(h);
DEBUGASSERT(hostname);
@ -127,24 +125,23 @@ static CURLcode hsts_create(struct hsts *h,
if(hlen && (hostname[hlen - 1] == '.'))
/* strip off any trailing dot */
--hlen;
if(!hlen)
/* no host name left */
return CURLE_BAD_FUNCTION_ARGUMENT;
if(hlen) {
char *duphost;
struct stsentry *sts = hsts_entry();
if(!sts)
return CURLE_OUT_OF_MEMORY;
sts = hsts_entry();
if(!sts)
return CURLE_OUT_OF_MEMORY;
duphost = Curl_memdup0(hostname, hlen);
if(!duphost) {
free(sts);
return CURLE_OUT_OF_MEMORY;
}
duphost = Curl_strndup(hostname, hlen);
if(!duphost) {
free(sts);
return CURLE_OUT_OF_MEMORY;
sts->host = duphost;
sts->expires = expires;
sts->includeSubDomains = subdomains;
Curl_llist_insert_next(&h->list, h->list.tail, sts, &sts->node);
}
sts->host = duphost;
sts->expires = expires;
sts->includeSubDomains = subdomains;
Curl_llist_insert_next(&h->list, h->list.tail, sts, &sts->node);
return CURLE_OK;
}
@ -481,6 +478,7 @@ static CURLcode hsts_pull(struct Curl_easy *data, struct hsts *h)
if(sc == CURLSTS_OK) {
time_t expires;
CURLcode result;
DEBUGASSERT(e.name[0]);
if(!e.name[0])
/* bail out if no name was stored */
return CURLE_BAD_FUNCTION_ARGUMENT;

View File

@ -100,24 +100,14 @@
* Forward declarations.
*/
static int http_getsock_do(struct Curl_easy *data,
struct connectdata *conn,
curl_socket_t *socks);
static bool http_should_fail(struct Curl_easy *data);
static CURLcode http_setup_conn(struct Curl_easy *data,
struct connectdata *conn);
#ifdef USE_WEBSOCKETS
static CURLcode ws_setup_conn(struct Curl_easy *data,
struct connectdata *conn);
#endif
/*
* HTTP handler interface.
*/
const struct Curl_handler Curl_handler_http = {
"HTTP", /* scheme */
http_setup_conn, /* setup_connection */
Curl_http_setup_conn, /* setup_connection */
Curl_http, /* do_it */
Curl_http_done, /* done */
ZERO_NULL, /* do_more */
@ -125,11 +115,11 @@ const struct Curl_handler Curl_handler_http = {
ZERO_NULL, /* connecting */
ZERO_NULL, /* doing */
ZERO_NULL, /* proto_getsock */
http_getsock_do, /* doing_getsock */
Curl_http_getsock_do, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* disconnect */
ZERO_NULL, /* readwrite */
Curl_http_write_resp, /* write_resp */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_HTTP, /* defport */
@ -139,39 +129,13 @@ const struct Curl_handler Curl_handler_http = {
PROTOPT_USERPWDCTRL
};
#ifdef USE_WEBSOCKETS
const struct Curl_handler Curl_handler_ws = {
"WS", /* scheme */
ws_setup_conn, /* setup_connection */
Curl_http, /* do_it */
Curl_http_done, /* done */
ZERO_NULL, /* do_more */
Curl_http_connect, /* connect_it */
ZERO_NULL, /* connecting */
ZERO_NULL, /* doing */
ZERO_NULL, /* proto_getsock */
http_getsock_do, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
Curl_ws_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_HTTP, /* defport */
CURLPROTO_WS, /* protocol */
CURLPROTO_HTTP, /* family */
PROTOPT_CREDSPERREQUEST | /* flags */
PROTOPT_USERPWDCTRL
};
#endif
#ifdef USE_SSL
/*
* HTTPS handler interface.
*/
const struct Curl_handler Curl_handler_https = {
"HTTPS", /* scheme */
http_setup_conn, /* setup_connection */
Curl_http_setup_conn, /* setup_connection */
Curl_http, /* do_it */
Curl_http_done, /* done */
ZERO_NULL, /* do_more */
@ -179,11 +143,11 @@ const struct Curl_handler Curl_handler_https = {
NULL, /* connecting */
ZERO_NULL, /* doing */
NULL, /* proto_getsock */
http_getsock_do, /* doing_getsock */
Curl_http_getsock_do, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* disconnect */
ZERO_NULL, /* readwrite */
Curl_http_write_resp, /* write_resp */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_HTTPS, /* defport */
@ -193,36 +157,10 @@ const struct Curl_handler Curl_handler_https = {
PROTOPT_USERPWDCTRL
};
#ifdef USE_WEBSOCKETS
const struct Curl_handler Curl_handler_wss = {
"WSS", /* scheme */
ws_setup_conn, /* setup_connection */
Curl_http, /* do_it */
Curl_http_done, /* done */
ZERO_NULL, /* do_more */
Curl_http_connect, /* connect_it */
NULL, /* connecting */
ZERO_NULL, /* doing */
NULL, /* proto_getsock */
http_getsock_do, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
Curl_ws_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_HTTPS, /* defport */
CURLPROTO_WSS, /* protocol */
CURLPROTO_HTTP, /* family */
PROTOPT_SSL | PROTOPT_CREDSPERREQUEST | /* flags */
PROTOPT_USERPWDCTRL
};
#endif
#endif
static CURLcode http_setup_conn(struct Curl_easy *data,
struct connectdata *conn)
CURLcode Curl_http_setup_conn(struct Curl_easy *data,
struct connectdata *conn)
{
/* allocate the HTTP-specific struct for the Curl_easy, only to survive
during this request */
@ -245,16 +183,6 @@ static CURLcode http_setup_conn(struct Curl_easy *data,
return CURLE_OK;
}
#ifdef USE_WEBSOCKETS
static CURLcode ws_setup_conn(struct Curl_easy *data,
struct connectdata *conn)
{
/* websockets is 1.1 only (for now) */
data->state.httpwant = CURL_HTTP_VERSION_1_1;
return http_setup_conn(data, conn);
}
#endif
#ifndef CURL_DISABLE_PROXY
/*
* checkProxyHeaders() checks the linked list of custom proxy headers
@ -297,7 +225,6 @@ char *Curl_copy_header_value(const char *header)
{
const char *start;
const char *end;
char *value;
size_t len;
/* Find the end of the header name */
@ -330,14 +257,7 @@ char *Curl_copy_header_value(const char *header)
/* get length of the type */
len = end - start + 1;
value = malloc(len + 1);
if(!value)
return NULL;
memcpy(value, start, len);
value[len] = 0; /* null-terminate */
return value;
return Curl_memdup0(start, len);
}
#ifndef CURL_DISABLE_HTTP_AUTH
@ -1597,9 +1517,9 @@ CURLcode Curl_http_connect(struct Curl_easy *data, bool *done)
/* this returns the socket to wait for in the DO and DOING state for the multi
interface and then we're always _sending_ a request and thus we wait for
the single socket to become writable only */
static int http_getsock_do(struct Curl_easy *data,
struct connectdata *conn,
curl_socket_t *socks)
int Curl_http_getsock_do(struct Curl_easy *data,
struct connectdata *conn,
curl_socket_t *socks)
{
/* write mode */
(void)conn;
@ -2103,6 +2023,7 @@ CURLcode Curl_add_timecondition(struct Curl_easy *data,
switch(data->set.timecondition) {
default:
DEBUGF(infof(data, "invalid time condition"));
return CURLE_BAD_FUNCTION_ARGUMENT;
case CURL_TIMECOND_IFMODSINCE:
@ -2271,7 +2192,7 @@ CURLcode Curl_http_host(struct Curl_easy *data, struct connectdata *conn)
}
#endif
if(strcmp("Host:", ptr)) {
if(!strcasecompare("Host:", ptr)) {
aptr->host = aprintf("Host:%s\r\n", &ptr[5]);
if(!aptr->host)
return CURLE_OUT_OF_MEMORY;
@ -2359,9 +2280,7 @@ CURLcode Curl_http_target(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
}
}
/* Extract the URL to use in the request. Store in STRING_TEMP_URL for
clean-up reasons if the function returns before the free() further
down. */
/* Extract the URL to use in the request. */
uc = curl_url_get(h, CURLUPART_URL, &url, CURLU_NO_DEFAULT_PORT);
if(uc) {
curl_url_cleanup(h);
@ -3021,13 +2940,14 @@ CURLcode Curl_http_resume(struct Curl_easy *data,
}
/* when seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
do {
char scratch[4*1024];
size_t readthisamountnow =
(data->state.resume_from - passed > data->set.buffer_size) ?
(size_t)data->set.buffer_size :
(data->state.resume_from - passed > (curl_off_t)sizeof(scratch)) ?
sizeof(scratch) :
curlx_sotouz(data->state.resume_from - passed);
size_t actuallyread =
data->state.fread_func(data->state.buffer, 1, readthisamountnow,
data->state.fread_func(scratch, 1, readthisamountnow,
data->state.in);
passed += actuallyread;
@ -3062,6 +2982,7 @@ CURLcode Curl_http_firstwrite(struct Curl_easy *data,
{
struct SingleRequest *k = &data->req;
*done = FALSE;
if(data->req.newurl) {
if(conn->bits.close) {
/* Abort after the headers if "follow Location" is set
@ -3187,7 +3108,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
) {
result = Curl_http2_switch(data, conn, FIRSTSOCKET);
if(result)
return result;
goto fail;
}
else
#endif
@ -3202,7 +3123,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
DEBUGF(infof(data, "HTTP/2 over clean TCP"));
result = Curl_http2_switch(data, conn, FIRSTSOCKET);
if(result)
return result;
goto fail;
}
break;
}
@ -3212,11 +3133,11 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
result = Curl_http_host(data, conn);
if(result)
return result;
goto fail;
result = Curl_http_useragent(data);
if(result)
return result;
goto fail;
Curl_http_method(data, conn, &request, &httpreq);
@ -3232,7 +3153,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
(pq ? pq : data->state.up.path), FALSE);
free(pq);
if(result)
return result;
goto fail;
}
Curl_safefree(data->state.aptr.ref);
@ -3257,23 +3178,23 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
/* we only consider transfer-encoding magic if libz support is built-in */
result = Curl_transferencode(data);
if(result)
return result;
goto fail;
#endif
result = Curl_http_body(data, conn, httpreq, &te);
if(result)
return result;
goto fail;
p_accept = Curl_checkheaders(data,
STRCONST("Accept"))?NULL:"Accept: */*\r\n";
result = Curl_http_resume(data, conn, httpreq);
if(result)
return result;
goto fail;
result = Curl_http_range(data, httpreq);
if(result)
return result;
goto fail;
httpstring = get_http_string(data, conn);
@ -3291,7 +3212,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
result = Curl_http_target(data, conn, &req);
if(result) {
Curl_dyn_free(&req);
return result;
goto fail;
}
#ifndef CURL_DISABLE_ALTSVC
@ -3362,7 +3283,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
if(result) {
Curl_dyn_free(&req);
return result;
goto fail;
}
if(!(conn->handler->flags&PROTOPT_SSL) &&
@ -3398,7 +3319,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
}
if(result) {
Curl_dyn_free(&req);
return result;
goto fail;
}
if((http->postsize > -1) &&
@ -3434,6 +3355,9 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
but is disabled here again to avoid that the chunked encoded version is
actually used when sending the request body over h2 */
data->req.upload_chunky = FALSE;
fail:
if(CURLE_TOO_LARGE == result)
failf(data, "HTTP request too large");
return result;
}
@ -3896,7 +3820,7 @@ CURLcode Curl_http_statusline(struct Curl_easy *data,
* fields. */
if(data->set.timecondition)
data->info.timecond = TRUE;
/* FALLTHROUGH */
FALLTHROUGH();
case 204:
/* (quote from RFC2616, section 10.2.5): The server has
* fulfilled the request but does not need to return an
@ -3995,15 +3919,16 @@ CURLcode Curl_bump_headersize(struct Curl_easy *data,
/*
* Read any HTTP header lines from the server and pass them to the client app.
*/
CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
struct connectdata *conn,
const char *buf, size_t blen,
size_t *pconsumed)
static CURLcode http_rw_headers(struct Curl_easy *data,
const char *buf, size_t blen,
size_t *pconsumed)
{
CURLcode result;
struct connectdata *conn = data->conn;
CURLcode result = CURLE_OK;
struct SingleRequest *k = &data->req;
char *headp;
char *end_ptr;
bool leftover_body = FALSE;
/* header line within buffer loop */
*pconsumed = 0;
@ -4032,12 +3957,12 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
if(st == STATUS_BAD) {
/* this is not the beginning of a protocol first header line */
k->header = FALSE;
k->badheader = TRUE;
streamclose(conn, "bad HTTP: No end-of-message indicator");
if(!data->set.http09_allowed) {
failf(data, "Received HTTP/0.9 when not allowed");
return CURLE_UNSUPPORTED_PROTOCOL;
}
leftover_body = TRUE;
goto out;
}
}
@ -4071,15 +3996,8 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
return CURLE_UNSUPPORTED_PROTOCOL;
}
k->header = FALSE;
if(blen)
/* since there's more, this is a partial bad header */
k->badheader = TRUE;
else {
/* this was all we read so it's all a bad header */
k->badheader = TRUE;
return CURLE_OK;
}
break;
leftover_body = TRUE;
goto out;
}
}
@ -4088,6 +4006,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
headp = Curl_dyn_ptr(&data->state.headerb);
if((0x0a == *headp) || (0x0d == *headp)) {
size_t headerlen;
bool switch_to_h2 = FALSE;
/* Zero-length header line means end of headers! */
if('\r' == *headp)
@ -4117,42 +4036,40 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
}
break;
case 101:
/* Switching Protocols */
if(k->upgr101 == UPGR101_H2) {
/* Switching to HTTP/2 */
DEBUGASSERT(conn->httpversion < 20);
infof(data, "Received 101, Switching to HTTP/2");
k->upgr101 = UPGR101_RECEIVED;
if(conn->httpversion == 11) {
/* Switching Protocols only allowed from HTTP/1.1 */
if(k->upgr101 == UPGR101_H2) {
/* Switching to HTTP/2 */
infof(data, "Received 101, Switching to HTTP/2");
k->upgr101 = UPGR101_RECEIVED;
/* we'll get more headers (HTTP/2 response) */
k->header = TRUE;
k->headerline = 0; /* restart the header line counter */
/* switch to http2 now. The bytes after response headers
are also processed here, otherwise they are lost. */
result = Curl_http2_upgrade(data, conn, FIRSTSOCKET, buf, blen);
if(result)
return result;
*pconsumed += blen;
blen = 0;
}
/* we'll get more headers (HTTP/2 response) */
k->header = TRUE;
k->headerline = 0; /* restart the header line counter */
switch_to_h2 = TRUE;
}
#ifdef USE_WEBSOCKETS
else if(k->upgr101 == UPGR101_WS) {
/* verify the response */
result = Curl_ws_accept(data, buf, blen);
if(result)
return result;
k->header = FALSE; /* no more header to parse! */
if(data->set.connect_only) {
k->keepon &= ~KEEP_RECV; /* read no more content */
*pconsumed += blen;
else if(k->upgr101 == UPGR101_WS) {
/* verify the response */
result = Curl_ws_accept(data, buf, blen);
if(result)
return result;
k->header = FALSE; /* no more header to parse! */
*pconsumed += blen; /* ws accept handled the data */
blen = 0;
if(data->set.connect_only)
k->keepon &= ~KEEP_RECV; /* read no more content */
}
#endif
else {
/* Not switching to another protocol */
k->header = FALSE; /* no more header to parse! */
}
}
#endif
else {
/* Not switching to another protocol */
k->header = FALSE; /* no more header to parse! */
/* invalid for other HTTP versions */
failf(data, "unexpected 101 response code");
return CURLE_WEIRD_SERVER_REPLY;
}
break;
default:
@ -4359,16 +4276,6 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
*/
if(data->req.no_body)
k->download_done = TRUE;
#ifndef CURL_DISABLE_RTSP
else if((conn->handler->protocol & CURLPROTO_RTSP) &&
(data->set.rtspreq == RTSPREQ_DESCRIBE) &&
(k->size <= -1))
/* Respect section 4.4 of rfc2326: If the Content-Length header is
absent, a length 0 must be assumed. It will prevent libcurl from
hanging on DESCRIBE request that got refused for whatever
reason */
k->download_done = TRUE;
#endif
/* If max download size is *zero* (nothing) we already have
nothing and can safely return ok now! But for HTTP/2, we'd
@ -4388,6 +4295,17 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
/* We continue reading headers, reset the line-based header */
Curl_dyn_reset(&data->state.headerb);
if(switch_to_h2) {
/* Having handled the headers, we can do the HTTP/2 switch.
* Any remaining `buf` bytes are already HTTP/2 and passed to
* be processed. */
result = Curl_http2_upgrade(data, conn, FIRSTSOCKET, buf, blen);
if(result)
return result;
*pconsumed += blen;
blen = 0;
}
continue;
}
@ -4578,9 +4496,78 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
there might be a non-header part left in the end of the read
buffer. */
out:
if(!k->header && !leftover_body) {
Curl_dyn_free(&data->state.headerb);
}
return CURLE_OK;
}
/*
* HTTP protocol `write_resp` implementation. Will parse headers
* when not done yet and otherwise return without consuming data.
*/
CURLcode Curl_http_write_resp_hds(struct Curl_easy *data,
const char *buf, size_t blen,
size_t *pconsumed,
bool *done)
{
*done = FALSE;
if(!data->req.header) {
*pconsumed = 0;
return CURLE_OK;
}
else {
CURLcode result;
result = http_rw_headers(data, buf, blen, pconsumed);
if(!result && !data->req.header) {
/* we have successfully finished parsing the HEADERs */
result = Curl_http_firstwrite(data, data->conn, done);
if(!data->req.no_body && Curl_dyn_len(&data->state.headerb)) {
/* leftover from parsing something that turned out not
* to be a header, only happens if we allow for
* HTTP/0.9 like responses */
result = Curl_client_write(data, CLIENTWRITE_BODY,
Curl_dyn_ptr(&data->state.headerb),
Curl_dyn_len(&data->state.headerb));
}
Curl_dyn_free(&data->state.headerb);
}
return result;
}
}
CURLcode Curl_http_write_resp(struct Curl_easy *data,
const char *buf, size_t blen,
bool is_eos,
bool *done)
{
CURLcode result;
size_t consumed;
int flags;
*done = FALSE;
result = Curl_http_write_resp_hds(data, buf, blen, &consumed, done);
if(result || *done)
goto out;
DEBUGASSERT(consumed <= blen);
blen -= consumed;
buf += consumed;
/* either all was consumed in header parsing, or we have data left
* and are done with heders, e.g. it is BODY data */
DEBUGASSERT(!blen || !data->req.header);
if(!data->req.header && (blen || is_eos)) {
/* BODY data after header been parsed, write and consume */
flags = CLIENTWRITE_BODY;
if(is_eos)
flags |= CLIENTWRITE_EOS;
result = Curl_client_write(data, flags, (char *)buf, blen);
}
out:
return result;
}
/* Decode HTTP status code string. */
CURLcode Curl_http_decode_status(int *pstatus, const char *s, size_t len)
@ -4617,7 +4604,7 @@ CURLcode Curl_http_req_make(struct httpreq **preq,
CURLcode result = CURLE_OUT_OF_MEMORY;
DEBUGASSERT(method);
if(m_len + 1 >= sizeof(req->method))
if(m_len + 1 > sizeof(req->method))
return CURLE_BAD_FUNCTION_ARGUMENT;
req = calloc(1, sizeof(*req));
@ -4625,17 +4612,17 @@ CURLcode Curl_http_req_make(struct httpreq **preq,
goto out;
memcpy(req->method, method, m_len);
if(scheme) {
req->scheme = Curl_strndup(scheme, s_len);
req->scheme = Curl_memdup0(scheme, s_len);
if(!req->scheme)
goto out;
}
if(authority) {
req->authority = Curl_strndup(authority, a_len);
req->authority = Curl_memdup0(authority, a_len);
if(!req->authority)
goto out;
}
if(path) {
req->path = Curl_strndup(path, p_len);
req->path = Curl_memdup0(path, p_len);
if(!req->path)
goto out;
}
@ -4773,7 +4760,7 @@ CURLcode Curl_http_req_make2(struct httpreq **preq,
CURLUcode uc;
DEBUGASSERT(method);
if(m_len + 1 >= sizeof(req->method))
if(m_len + 1 > sizeof(req->method))
return CURLE_BAD_FUNCTION_ARGUMENT;
req = calloc(1, sizeof(*req));

View File

@ -54,14 +54,6 @@ extern const struct Curl_handler Curl_handler_http;
extern const struct Curl_handler Curl_handler_https;
#endif
#ifdef USE_WEBSOCKETS
extern const struct Curl_handler Curl_handler_ws;
#ifdef USE_SSL
extern const struct Curl_handler Curl_handler_wss;
#endif
#endif /* websockets */
struct dynhds;
CURLcode Curl_bump_headersize(struct Curl_easy *data,
@ -147,9 +139,17 @@ CURLcode Curl_http_firstwrite(struct Curl_easy *data,
bool *done);
/* protocol-specific functions set up to be called by the main engine */
CURLcode Curl_http_setup_conn(struct Curl_easy *data,
struct connectdata *conn);
CURLcode Curl_http(struct Curl_easy *data, bool *done);
CURLcode Curl_http_done(struct Curl_easy *data, CURLcode, bool premature);
CURLcode Curl_http_connect(struct Curl_easy *data, bool *done);
int Curl_http_getsock_do(struct Curl_easy *data, struct connectdata *conn,
curl_socket_t *socks);
CURLcode Curl_http_write_resp(struct Curl_easy *data,
const char *buf, size_t blen,
bool is_eos,
bool *done);
/* These functions are in http.c */
CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
@ -225,10 +225,10 @@ struct HTTP {
CURLcode Curl_http_size(struct Curl_easy *data);
CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
struct connectdata *conn,
const char *buf, size_t blen,
size_t *pconsumed);
CURLcode Curl_http_write_resp_hds(struct Curl_easy *data,
const char *buf, size_t blen,
size_t *pconsumed,
bool *done);
/**
* Curl_http_output_auth() setups the authentication headers for the

View File

@ -219,10 +219,10 @@ static void drain_stream(struct Curl_cfilter *cf,
if(!stream->send_closed &&
(stream->upload_left || stream->upload_blocked_len))
bits |= CURL_CSELECT_OUT;
if(data->state.dselect_bits != bits) {
CURL_TRC_CF(data, cf, "[%d] DRAIN dselect_bits=%x",
if(data->state.select_bits != bits) {
CURL_TRC_CF(data, cf, "[%d] DRAIN select_bits=%x",
stream->id, bits);
data->state.dselect_bits = bits;
data->state.select_bits = bits;
Curl_expire(data, 0, EXPIRE_RUN_NOW);
}
}
@ -283,13 +283,20 @@ static void http2_data_done(struct Curl_cfilter *cf,
return;
if(ctx->h2) {
bool flush_egress = FALSE;
/* returns error if stream not known, which is fine here */
(void)nghttp2_session_set_stream_user_data(ctx->h2, stream->id, NULL);
if(!stream->closed && stream->id > 0) {
/* RST_STREAM */
CURL_TRC_CF(data, cf, "[%d] premature DATA_DONE, RST stream",
stream->id);
if(!nghttp2_submit_rst_stream(ctx->h2, NGHTTP2_FLAG_NONE,
stream->id, NGHTTP2_STREAM_CLOSED))
(void)nghttp2_session_send(ctx->h2);
stream->closed = TRUE;
stream->reset = TRUE;
stream->send_closed = TRUE;
nghttp2_submit_rst_stream(ctx->h2, NGHTTP2_FLAG_NONE,
stream->id, NGHTTP2_STREAM_CLOSED);
flush_egress = TRUE;
}
if(!Curl_bufq_is_empty(&stream->recvbuf)) {
/* Anything in the recvbuf is still being counted
@ -299,19 +306,11 @@ static void http2_data_done(struct Curl_cfilter *cf,
nghttp2_session_consume(ctx->h2, stream->id,
Curl_bufq_len(&stream->recvbuf));
/* give WINDOW_UPATE a chance to be sent, but ignore any error */
(void)h2_progress_egress(cf, data);
flush_egress = TRUE;
}
/* -1 means unassigned and 0 means cleared */
if(nghttp2_session_get_stream_user_data(ctx->h2, stream->id)) {
int rv = nghttp2_session_set_stream_user_data(ctx->h2,
stream->id, 0);
if(rv) {
infof(data, "http/2: failed to clear user_data for stream %u",
stream->id);
DEBUGASSERT(0);
}
}
if(flush_egress)
nghttp2_session_send(ctx->h2);
}
Curl_bufq_free(&stream->sendbuf);
@ -1316,26 +1315,43 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id,
uint32_t error_code, void *userp)
{
struct Curl_cfilter *cf = userp;
struct Curl_easy *data_s;
struct Curl_easy *data_s, *call_data = CF_DATA_CURRENT(cf);
struct stream_ctx *stream;
int rv;
(void)session;
DEBUGASSERT(call_data);
/* get the stream from the hash based on Stream ID, stream ID zero is for
connection-oriented stuff */
data_s = stream_id?
nghttp2_session_get_stream_user_data(session, stream_id) : NULL;
if(!data_s) {
CURL_TRC_CF(call_data, cf,
"[%d] on_stream_close, no easy set on stream", stream_id);
return 0;
}
stream = H2_STREAM_CTX(data_s);
if(!stream)
if(!GOOD_EASY_HANDLE(data_s)) {
/* nghttp2 still has an easy registered for the stream which has
* been freed be libcurl. This points to a code path that does not
* trigger DONE or DETACH events as it must. */
CURL_TRC_CF(call_data, cf,
"[%d] on_stream_close, not a GOOD easy on stream", stream_id);
(void)nghttp2_session_set_stream_user_data(session, stream_id, 0);
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
stream = H2_STREAM_CTX(data_s);
if(!stream) {
CURL_TRC_CF(data_s, cf,
"[%d] on_stream_close, GOOD easy but no stream", stream_id);
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
stream->closed = TRUE;
stream->error = error_code;
if(stream->error)
if(stream->error) {
stream->reset = TRUE;
stream->send_closed = TRUE;
}
if(stream->error)
CURL_TRC_CF(data_s, cf, "[%d] RESET: %s (err %d)",
@ -2315,18 +2331,22 @@ static void cf_h2_adjust_pollset(struct Curl_cfilter *cf,
struct easy_pollset *ps)
{
struct cf_h2_ctx *ctx = cf->ctx;
bool want_recv = CURL_WANT_RECV(data);
bool want_send = CURL_WANT_SEND(data);
curl_socket_t sock;
bool want_recv, want_send;
if(ctx->h2 && (want_recv || want_send)) {
if(!ctx->h2)
return;
sock = Curl_conn_cf_get_socket(cf, data);
Curl_pollset_check(data, ps, sock, &want_recv, &want_send);
if(want_recv || want_send) {
struct stream_ctx *stream = H2_STREAM_CTX(data);
curl_socket_t sock = Curl_conn_cf_get_socket(cf, data);
struct cf_call_data save;
bool c_exhaust, s_exhaust;
CF_DATA_SAVE(save, cf, data);
c_exhaust = !nghttp2_session_get_remote_window_size(ctx->h2);
s_exhaust = stream && stream->id >= 0 &&
c_exhaust = want_send && !nghttp2_session_get_remote_window_size(ctx->h2);
s_exhaust = want_send && stream && stream->id >= 0 &&
!nghttp2_session_get_stream_remote_window_size(ctx->h2,
stream->id);
want_recv = (want_recv || c_exhaust || s_exhaust);

View File

@ -247,7 +247,7 @@ static CURLcode make_headers(struct Curl_easy *data,
}
else {
char *value;
char *endp;
value = strchr(*date_header, ':');
if(!value) {
*date_header = NULL;
@ -256,8 +256,17 @@ static CURLcode make_headers(struct Curl_easy *data,
++value;
while(ISBLANK(*value))
++value;
strncpy(timestamp, value, TIMESTAMP_SIZE - 1);
timestamp[TIMESTAMP_SIZE - 1] = 0;
endp = value;
while(*endp && ISALNUM(*endp))
++endp;
/* 16 bytes => "19700101T000000Z" */
if((endp - value) == TIMESTAMP_SIZE - 1) {
memcpy(timestamp, value, TIMESTAMP_SIZE - 1);
timestamp[TIMESTAMP_SIZE - 1] = 0;
}
else
/* bad timestamp length */
timestamp[0] = 0;
*date_header = NULL;
}
@ -605,7 +614,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
result = CURLE_URL_MALFORMAT;
goto fail;
}
strncpy(service, hostname, len);
memcpy(service, hostname, len);
service[len] = '\0';
infof(data, "aws_sigv4: picked service %s from host", service);
@ -624,7 +633,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
result = CURLE_URL_MALFORMAT;
goto fail;
}
strncpy(region, reg, len);
memcpy(region, reg, len);
region[len] = '\0';
infof(data, "aws_sigv4: picked region %s from host", region);
}

View File

@ -75,47 +75,67 @@
*/
void Curl_httpchunk_init(struct Curl_easy *data)
void Curl_httpchunk_init(struct Curl_easy *data, struct Curl_chunker *ch,
bool ignore_body)
{
struct connectdata *conn = data->conn;
struct Curl_chunker *chunk = &conn->chunk;
chunk->hexindex = 0; /* start at 0 */
chunk->state = CHUNK_HEX; /* we get hex first! */
Curl_dyn_init(&conn->trailer, DYN_H1_TRAILER);
(void)data;
ch->hexindex = 0; /* start at 0 */
ch->state = CHUNK_HEX; /* we get hex first! */
ch->last_code = CHUNKE_OK;
Curl_dyn_init(&ch->trailer, DYN_H1_TRAILER);
ch->ignore_body = ignore_body;
}
/*
* chunk_read() returns a OK for normal operations, or a positive return code
* for errors. STOP means this sequence of chunks is complete. The 'wrote'
* argument is set to tell the caller how many bytes we actually passed to the
* client (for byte-counting and whatever).
*
* The states and the state-machine is further explained in the header file.
*
* This function always uses ASCII hex values to accommodate non-ASCII hosts.
* For example, 0x0d and 0x0a are used instead of '\r' and '\n'.
*/
CHUNKcode Curl_httpchunk_read(struct Curl_easy *data,
char *buf,
size_t blen,
size_t *pconsumed,
CURLcode *extrap)
void Curl_httpchunk_reset(struct Curl_easy *data, struct Curl_chunker *ch,
bool ignore_body)
{
(void)data;
ch->hexindex = 0; /* start at 0 */
ch->state = CHUNK_HEX; /* we get hex first! */
ch->last_code = CHUNKE_OK;
Curl_dyn_reset(&ch->trailer);
ch->ignore_body = ignore_body;
}
void Curl_httpchunk_free(struct Curl_easy *data, struct Curl_chunker *ch)
{
(void)data;
Curl_dyn_free(&ch->trailer);
}
bool Curl_httpchunk_is_done(struct Curl_easy *data, struct Curl_chunker *ch)
{
(void)data;
return ch->state == CHUNK_DONE;
}
static CURLcode httpchunk_readwrite(struct Curl_easy *data,
struct Curl_chunker *ch,
struct Curl_cwriter *cw_next,
const char *buf, size_t blen,
size_t *pconsumed)
{
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
struct Curl_chunker *ch = &conn->chunk;
struct SingleRequest *k = &data->req;
size_t piece;
*pconsumed = 0; /* nothing's written yet */
/* first check terminal states that will not progress anywhere */
if(ch->state == CHUNK_DONE)
return CURLE_OK;
if(ch->state == CHUNK_FAILED)
return CURLE_RECV_ERROR;
/* the original data is written to the client, but we go on with the
chunk read process, to properly calculate the content length */
if(data->set.http_te_skip && !k->ignorebody) {
result = Curl_client_write(data, CLIENTWRITE_BODY, buf, blen);
if(data->set.http_te_skip && !ch->ignore_body) {
if(cw_next)
result = Curl_cwriter_write(data, cw_next, CLIENTWRITE_BODY, buf, blen);
else
result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)buf, blen);
if(result) {
*extrap = result;
return CHUNKE_PASSTHRU_ERROR;
ch->state = CHUNK_FAILED;
ch->last_code = CHUNKE_PASSTHRU_ERROR;
return result;
}
}
@ -123,28 +143,35 @@ CHUNKcode Curl_httpchunk_read(struct Curl_easy *data,
switch(ch->state) {
case CHUNK_HEX:
if(ISXDIGIT(*buf)) {
if(ch->hexindex < CHUNK_MAXNUM_LEN) {
ch->hexbuffer[ch->hexindex] = *buf;
buf++;
blen--;
ch->hexindex++;
}
else {
return CHUNKE_TOO_LONG_HEX; /* longer hex than we support */
if(ch->hexindex >= CHUNK_MAXNUM_LEN) {
failf(data, "chunk hex-length longer than %d", CHUNK_MAXNUM_LEN);
ch->state = CHUNK_FAILED;
ch->last_code = CHUNKE_TOO_LONG_HEX; /* longer than we support */
return CURLE_RECV_ERROR;
}
ch->hexbuffer[ch->hexindex++] = *buf;
buf++;
blen--;
}
else {
char *endptr;
if(0 == ch->hexindex)
if(0 == ch->hexindex) {
/* This is illegal data, we received junk where we expected
a hexadecimal digit. */
return CHUNKE_ILLEGAL_HEX;
failf(data, "chunk hex-length char not a hex digit: 0x%x", *buf);
ch->state = CHUNK_FAILED;
ch->last_code = CHUNKE_ILLEGAL_HEX;
return CURLE_RECV_ERROR;
}
/* blen and buf are unmodified */
ch->hexbuffer[ch->hexindex] = 0;
if(curlx_strtoofft(ch->hexbuffer, &endptr, 16, &ch->datasize))
return CHUNKE_ILLEGAL_HEX;
if(curlx_strtoofft(ch->hexbuffer, &endptr, 16, &ch->datasize)) {
failf(data, "chunk hex-length not valid: '%s'", ch->hexbuffer);
ch->state = CHUNK_FAILED;
ch->last_code = CHUNKE_ILLEGAL_HEX;
return CURLE_RECV_ERROR;
}
ch->state = CHUNK_LF; /* now wait for the CRLF */
}
break;
@ -173,12 +200,17 @@ CHUNKcode Curl_httpchunk_read(struct Curl_easy *data,
piece = curlx_sotouz(ch->datasize);
/* Write the data portion available */
if(!data->set.http_te_skip && !k->ignorebody) {
result = Curl_client_write(data, CLIENTWRITE_BODY, buf, piece);
if(!data->set.http_te_skip && !ch->ignore_body) {
if(cw_next)
result = Curl_cwriter_write(data, cw_next, CLIENTWRITE_BODY,
buf, piece);
else
result = Curl_client_write(data, CLIENTWRITE_BODY,
(char *)buf, piece);
if(result) {
*extrap = result;
return CHUNKE_PASSTHRU_ERROR;
ch->state = CHUNK_FAILED;
ch->last_code = CHUNKE_PASSTHRU_ERROR;
return result;
}
}
@ -195,38 +227,51 @@ CHUNKcode Curl_httpchunk_read(struct Curl_easy *data,
case CHUNK_POSTLF:
if(*buf == 0x0a) {
/* The last one before we go back to hex state and start all over. */
Curl_httpchunk_init(data); /* sets state back to CHUNK_HEX */
Curl_httpchunk_reset(data, ch, ch->ignore_body);
}
else if(*buf != 0x0d) {
ch->state = CHUNK_FAILED;
ch->last_code = CHUNKE_BAD_CHUNK;
return CURLE_RECV_ERROR;
}
else if(*buf != 0x0d)
return CHUNKE_BAD_CHUNK;
buf++;
blen--;
break;
case CHUNK_TRAILER:
if((*buf == 0x0d) || (*buf == 0x0a)) {
char *tr = Curl_dyn_ptr(&conn->trailer);
char *tr = Curl_dyn_ptr(&ch->trailer);
/* this is the end of a trailer, but if the trailer was zero bytes
there was no trailer and we move on */
if(tr) {
size_t trlen;
result = Curl_dyn_addn(&conn->trailer, (char *)STRCONST("\x0d\x0a"));
if(result)
return CHUNKE_OUT_OF_MEMORY;
tr = Curl_dyn_ptr(&conn->trailer);
trlen = Curl_dyn_len(&conn->trailer);
result = Curl_dyn_addn(&ch->trailer, (char *)STRCONST("\x0d\x0a"));
if(result) {
ch->state = CHUNK_FAILED;
ch->last_code = CHUNKE_OUT_OF_MEMORY;
return result;
}
tr = Curl_dyn_ptr(&ch->trailer);
trlen = Curl_dyn_len(&ch->trailer);
if(!data->set.http_te_skip) {
result = Curl_client_write(data,
CLIENTWRITE_HEADER|CLIENTWRITE_TRAILER,
tr, trlen);
if(cw_next)
result = Curl_cwriter_write(data, cw_next,
CLIENTWRITE_HEADER|
CLIENTWRITE_TRAILER,
tr, trlen);
else
result = Curl_client_write(data,
CLIENTWRITE_HEADER|
CLIENTWRITE_TRAILER,
tr, trlen);
if(result) {
*extrap = result;
return CHUNKE_PASSTHRU_ERROR;
ch->state = CHUNK_FAILED;
ch->last_code = CHUNKE_PASSTHRU_ERROR;
return result;
}
}
Curl_dyn_reset(&conn->trailer);
Curl_dyn_reset(&ch->trailer);
ch->state = CHUNK_TRAILER_CR;
if(*buf == 0x0a)
/* already on the LF */
@ -239,9 +284,12 @@ CHUNKcode Curl_httpchunk_read(struct Curl_easy *data,
}
}
else {
result = Curl_dyn_addn(&conn->trailer, buf, 1);
if(result)
return CHUNKE_OUT_OF_MEMORY;
result = Curl_dyn_addn(&ch->trailer, buf, 1);
if(result) {
ch->state = CHUNK_FAILED;
ch->last_code = CHUNKE_OUT_OF_MEMORY;
return result;
}
}
buf++;
blen--;
@ -253,8 +301,11 @@ CHUNKcode Curl_httpchunk_read(struct Curl_easy *data,
buf++;
blen--;
}
else
return CHUNKE_BAD_CHUNK;
else {
ch->state = CHUNK_FAILED;
ch->last_code = CHUNKE_BAD_CHUNK;
return CURLE_RECV_ERROR;
}
break;
case CHUNK_TRAILER_POSTCR:
@ -277,21 +328,29 @@ CHUNKcode Curl_httpchunk_read(struct Curl_easy *data,
case CHUNK_STOP:
if(*buf == 0x0a) {
blen--;
/* Record the length of any data left in the end of the buffer
even if there's no more chunks to read */
ch->datasize = blen;
return CHUNKE_STOP; /* return stop */
ch->state = CHUNK_DONE;
return CURLE_OK;
}
else
return CHUNKE_BAD_CHUNK;
else {
ch->state = CHUNK_FAILED;
ch->last_code = CHUNKE_BAD_CHUNK;
return CURLE_RECV_ERROR;
}
case CHUNK_DONE:
return CURLE_OK;
case CHUNK_FAILED:
return CURLE_RECV_ERROR;
}
}
return CHUNKE_OK;
return CURLE_OK;
}
const char *Curl_chunked_strerror(CHUNKcode code)
static const char *Curl_chunked_strerror(CHUNKcode code)
{
switch(code) {
default:
@ -303,8 +362,7 @@ const char *Curl_chunked_strerror(CHUNKcode code)
case CHUNKE_BAD_CHUNK:
return "Malformed encoding found";
case CHUNKE_PASSTHRU_ERROR:
DEBUGASSERT(0); /* never used */
return "";
return "Error writing data to client";
case CHUNKE_BAD_ENCODING:
return "Bad content-encoding found";
case CHUNKE_OUT_OF_MEMORY:
@ -312,4 +370,86 @@ const char *Curl_chunked_strerror(CHUNKcode code)
}
}
CURLcode Curl_httpchunk_read(struct Curl_easy *data,
struct Curl_chunker *ch,
char *buf, size_t blen,
size_t *pconsumed)
{
return httpchunk_readwrite(data, ch, NULL, buf, blen, pconsumed);
}
struct chunked_writer {
struct Curl_cwriter super;
struct Curl_chunker ch;
};
static CURLcode cw_chunked_init(struct Curl_easy *data,
struct Curl_cwriter *writer)
{
struct chunked_writer *ctx = (struct chunked_writer *)writer;
data->req.chunk = TRUE; /* chunks coming our way. */
Curl_httpchunk_init(data, &ctx->ch, FALSE);
return CURLE_OK;
}
static void cw_chunked_close(struct Curl_easy *data,
struct Curl_cwriter *writer)
{
struct chunked_writer *ctx = (struct chunked_writer *)writer;
Curl_httpchunk_free(data, &ctx->ch);
}
static CURLcode cw_chunked_write(struct Curl_easy *data,
struct Curl_cwriter *writer, int type,
const char *buf, size_t blen)
{
struct chunked_writer *ctx = (struct chunked_writer *)writer;
CURLcode result;
size_t consumed;
if(!(type & CLIENTWRITE_BODY))
return Curl_cwriter_write(data, writer->next, type, buf, blen);
consumed = 0;
result = httpchunk_readwrite(data, &ctx->ch, writer->next, buf, blen,
&consumed);
if(result) {
if(CHUNKE_PASSTHRU_ERROR == ctx->ch.last_code) {
failf(data, "Failed reading the chunked-encoded stream");
}
else {
failf(data, "%s in chunked-encoding",
Curl_chunked_strerror(ctx->ch.last_code));
}
return result;
}
blen -= consumed;
if(CHUNK_DONE == ctx->ch.state) {
/* chunks read successfully, download is complete */
data->req.download_done = TRUE;
if(blen) {
infof(data, "Leftovers after chunking: %zu bytes", blen);
}
}
else if((type & CLIENTWRITE_EOS) && !data->req.no_body) {
failf(data, "transfer closed with outstanding read data remaining");
return CURLE_PARTIAL_FILE;
}
return CURLE_OK;
}
/* HTTP chunked Transfer-Encoding decoder */
const struct Curl_cwtype Curl_httpchunk_unencoder = {
"chunked",
NULL,
cw_chunked_init,
cw_chunked_write,
cw_chunked_close,
sizeof(struct chunked_writer)
};
#endif /* CURL_DISABLE_HTTP */

View File

@ -24,6 +24,10 @@
*
***************************************************************************/
#ifndef CURL_DISABLE_HTTP
#include "dynbuf.h"
struct connectdata;
/*
@ -67,34 +71,68 @@ typedef enum {
signalled If this is an empty trailer CHUNKE_STOP will be signalled.
Otherwise the trailer will be broadcasted via Curl_client_write() and the
next state will be CHUNK_TRAILER */
CHUNK_TRAILER_POSTCR
CHUNK_TRAILER_POSTCR,
/* Successfully de-chunked everything */
CHUNK_DONE,
/* Failed on seeing a bad or not correctly terminated chunk */
CHUNK_FAILED
} ChunkyState;
typedef enum {
CHUNKE_STOP = -1,
CHUNKE_OK = 0,
CHUNKE_TOO_LONG_HEX = 1,
CHUNKE_ILLEGAL_HEX,
CHUNKE_BAD_CHUNK,
CHUNKE_BAD_ENCODING,
CHUNKE_OUT_OF_MEMORY,
CHUNKE_PASSTHRU_ERROR, /* Curl_httpchunk_read() returns a CURLcode to use */
CHUNKE_LAST
CHUNKE_PASSTHRU_ERROR /* Curl_httpchunk_read() returns a CURLcode to use */
} CHUNKcode;
const char *Curl_chunked_strerror(CHUNKcode code);
struct Curl_chunker {
curl_off_t datasize;
ChunkyState state;
CHUNKcode last_code;
struct dynbuf trailer; /* for chunked-encoded trailer */
unsigned char hexindex;
char hexbuffer[ CHUNK_MAXNUM_LEN + 1]; /* +1 for null-terminator */
char hexbuffer[CHUNK_MAXNUM_LEN + 1]; /* +1 for null-terminator */
BIT(ignore_body); /* never write response body data */
};
/* The following functions are defined in http_chunks.c */
void Curl_httpchunk_init(struct Curl_easy *data);
CHUNKcode Curl_httpchunk_read(struct Curl_easy *data, char *buf,
size_t blen, size_t *pconsumed,
CURLcode *passthru);
void Curl_httpchunk_init(struct Curl_easy *data, struct Curl_chunker *ch,
bool ignore_body);
void Curl_httpchunk_free(struct Curl_easy *data, struct Curl_chunker *ch);
void Curl_httpchunk_reset(struct Curl_easy *data, struct Curl_chunker *ch,
bool ignore_body);
/*
* Read BODY bytes in HTTP/1.1 chunked encoding from `buf` and return
* the amount of bytes consumed. The actual response bytes and trailer
* headers are written out to the client.
* On success, this will consume all bytes up to the end of the response,
* e.g. the last chunk, has been processed.
* @param data the transfer involved
* @param ch the chunker instance keeping state across calls
* @param buf the response data
* @param blen amount of bytes in `buf`
* @param pconsumed on successful return, the number of bytes in `buf`
* consumed
*
* This function always uses ASCII hex values to accommodate non-ASCII hosts.
* For example, 0x0d and 0x0a are used instead of '\r' and '\n'.
*/
CURLcode Curl_httpchunk_read(struct Curl_easy *data, struct Curl_chunker *ch,
char *buf, size_t blen, size_t *pconsumed);
/**
* @return TRUE iff chunked decoded has finished successfully.
*/
bool Curl_httpchunk_is_done(struct Curl_easy *data, struct Curl_chunker *ch);
extern const struct Curl_cwtype Curl_httpchunk_unencoder;
#endif /* !CURL_DISABLE_HTTP */
#endif /* HEADER_CURL_HTTP_CHUNKS_H */

View File

@ -131,8 +131,8 @@ CURLcode Curl_http_proxy_create_CONNECT(struct httpreq **preq,
goto out;
}
if(!Curl_checkProxyheaders(data, cf->conn, STRCONST("User-Agent"))
&& data->set.str[STRING_USERAGENT]) {
if(!Curl_checkProxyheaders(data, cf->conn, STRCONST("User-Agent")) &&
data->set.str[STRING_USERAGENT] && *data->set.str[STRING_USERAGENT]) {
result = Curl_dynhds_cadd(&req->headers, "User-Agent",
data->set.str[STRING_USERAGENT]);
if(result)

View File

@ -97,7 +97,8 @@ static CURLcode imap_doing(struct Curl_easy *data, bool *dophase_done);
static CURLcode imap_setup_connection(struct Curl_easy *data,
struct connectdata *conn);
static char *imap_atom(const char *str, bool escape_only);
static CURLcode imap_sendf(struct Curl_easy *data, const char *fmt, ...);
static CURLcode imap_sendf(struct Curl_easy *data, const char *fmt, ...)
CURL_PRINTF(2, 3);
static CURLcode imap_parse_url_options(struct connectdata *conn);
static CURLcode imap_parse_url_path(struct Curl_easy *data);
static CURLcode imap_parse_custom_request(struct Curl_easy *data);
@ -129,7 +130,7 @@ const struct Curl_handler Curl_handler_imap = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
imap_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_IMAP, /* defport */
@ -158,7 +159,7 @@ const struct Curl_handler Curl_handler_imaps = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
imap_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_IMAPS, /* defport */
@ -354,8 +355,8 @@ static bool imap_endofresp(struct Curl_easy *data, struct connectdata *conn,
*/
static CURLcode imap_get_message(struct Curl_easy *data, struct bufref *out)
{
char *message = data->state.buffer;
size_t len = strlen(message);
char *message = Curl_dyn_ptr(&data->conn->proto.imapc.pp.recvbuf);
size_t len = data->conn->proto.imapc.pp.nfinal;
if(len > 2) {
/* Find the start of the message */
@ -895,7 +896,7 @@ static CURLcode imap_state_capability_resp(struct Curl_easy *data,
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
struct imap_conn *imapc = &conn->proto.imapc;
const char *line = data->state.buffer;
const char *line = Curl_dyn_ptr(&imapc->pp.recvbuf);
(void)instate; /* no use for this yet */
@ -981,7 +982,7 @@ static CURLcode imap_state_starttls_resp(struct Curl_easy *data,
(void)instate; /* no use for this yet */
/* Pipelining in response is forbidden. */
if(data->conn->proto.imapc.pp.cache_size)
if(data->conn->proto.imapc.pp.overflow)
return CURLE_WEIRD_SERVER_REPLY;
if(imapcode != IMAP_RESP_OK) {
@ -1057,17 +1058,13 @@ static CURLcode imap_state_listsearch_resp(struct Curl_easy *data,
imapstate instate)
{
CURLcode result = CURLE_OK;
char *line = data->state.buffer;
size_t len = strlen(line);
char *line = Curl_dyn_ptr(&data->conn->proto.imapc.pp.recvbuf);
size_t len = data->conn->proto.imapc.pp.nfinal;
(void)instate; /* No use for this yet */
if(imapcode == '*') {
/* Temporarily add the LF character back and send as body to the client */
line[len] = '\n';
result = Curl_client_write(data, CLIENTWRITE_BODY, line, len + 1);
line[len] = '\0';
}
if(imapcode == '*')
result = Curl_client_write(data, CLIENTWRITE_BODY, line, len);
else if(imapcode != IMAP_RESP_OK)
result = CURLE_QUOTE_ERROR;
else
@ -1085,7 +1082,7 @@ static CURLcode imap_state_select_resp(struct Curl_easy *data, int imapcode,
struct connectdata *conn = data->conn;
struct IMAP *imap = data->req.p.imap;
struct imap_conn *imapc = &conn->proto.imapc;
const char *line = data->state.buffer;
const char *line = Curl_dyn_ptr(&data->conn->proto.imapc.pp.recvbuf);
(void)instate; /* no use for this yet */
@ -1144,7 +1141,8 @@ static CURLcode imap_state_fetch_resp(struct Curl_easy *data,
CURLcode result = CURLE_OK;
struct imap_conn *imapc = &conn->proto.imapc;
struct pingpong *pp = &imapc->pp;
const char *ptr = data->state.buffer;
const char *ptr = Curl_dyn_ptr(&data->conn->proto.imapc.pp.recvbuf);
size_t len = data->conn->proto.imapc.pp.nfinal;
bool parsed = FALSE;
curl_off_t size = 0;
@ -1158,16 +1156,12 @@ static CURLcode imap_state_fetch_resp(struct Curl_easy *data,
/* Something like this is received "* 1 FETCH (BODY[TEXT] {2021}\r" so parse
the continuation data contained within the curly brackets */
while(*ptr && (*ptr != '{'))
ptr++;
if(*ptr == '{') {
ptr = memchr(ptr, '{', len);
if(ptr) {
char *endptr;
if(!curlx_strtoofft(ptr + 1, &endptr, 10, &size)) {
if(endptr - ptr > 1 && endptr[0] == '}' &&
endptr[1] == '\r' && endptr[2] == '\0')
parsed = TRUE;
}
if(!curlx_strtoofft(ptr + 1, &endptr, 10, &size) &&
(endptr - ptr > 1 && *endptr == '}'))
parsed = TRUE;
}
if(parsed) {
@ -1175,11 +1169,15 @@ static CURLcode imap_state_fetch_resp(struct Curl_easy *data,
size);
Curl_pgrsSetDownloadSize(data, size);
if(pp->cache) {
/* At this point there is a bunch of data in the header "cache" that is
actually body content, send it as body and then skip it. Do note
that there may even be additional "headers" after the body. */
size_t chunk = pp->cache_size;
if(pp->overflow) {
/* At this point there is a data in the receive buffer that is body
content, send it as body and then skip it. Do note that there may
even be additional "headers" after the body. */
size_t chunk = pp->overflow;
/* keep only the overflow */
Curl_dyn_tail(&pp->recvbuf, chunk);
pp->nfinal = 0; /* done */
if(chunk > (size_t)size)
/* The conversion from curl_off_t to size_t is always fine here */
@ -1190,25 +1188,24 @@ static CURLcode imap_state_fetch_resp(struct Curl_easy *data,
imap_state(data, IMAP_STOP);
return CURLE_OK;
}
result = Curl_client_write(data, CLIENTWRITE_BODY, pp->cache, chunk);
result = Curl_client_write(data, CLIENTWRITE_BODY,
Curl_dyn_ptr(&pp->recvbuf), chunk);
if(result)
return result;
infof(data, "Written %zu bytes, %" CURL_FORMAT_CURL_OFF_TU
" bytes are left for transfer", chunk, size - chunk);
/* Have we used the entire cache or just part of it?*/
if(pp->cache_size > chunk) {
/* Only part of it so shrink the cache to fit the trailing data */
memmove(pp->cache, pp->cache + chunk, pp->cache_size - chunk);
pp->cache_size -= chunk;
/* Have we used the entire overflow or just part of it?*/
if(pp->overflow > chunk) {
/* remember the remaining trailing overflow data */
pp->overflow -= chunk;
Curl_dyn_tail(&pp->recvbuf, pp->overflow);
}
else {
pp->overflow = 0; /* handled */
/* Free the cache */
Curl_safefree(pp->cache);
/* Reset the cache size */
pp->cache_size = 0;
Curl_dyn_reset(&pp->recvbuf);
}
}
@ -1220,7 +1217,7 @@ static CURLcode imap_state_fetch_resp(struct Curl_easy *data,
data->req.maxdownload = size;
/* force a recv/send check of this connection, as the data might've been
read off the socket already */
data->conn->cselect_bits = CURL_CSELECT_IN;
data->state.select_bits = CURL_CSELECT_IN;
Curl_setup_transfer(data, FIRSTSOCKET, size, FALSE, -1);
}
}
@ -1376,7 +1373,6 @@ static CURLcode imap_statemachine(struct Curl_easy *data,
break;
case IMAP_LOGOUT:
/* fallthrough, just stop! */
default:
/* internal error */
imap_state(data, IMAP_STOP);
@ -1472,9 +1468,7 @@ static CURLcode imap_connect(struct Curl_easy *data, bool *done)
Curl_sasl_init(&imapc->sasl, data, &saslimap);
Curl_dyn_init(&imapc->dyn, DYN_IMAP_CMD);
/* Initialise the pingpong layer */
Curl_pp_setup(pp);
Curl_pp_init(data, pp);
Curl_pp_init(pp);
/* Parse the URL options */
result = imap_parse_url_options(conn);
@ -1795,7 +1789,14 @@ static CURLcode imap_sendf(struct Curl_easy *data, const char *fmt, ...)
if(!result) {
va_list ap;
va_start(ap, fmt);
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wformat-nonliteral"
#endif
result = Curl_pp_vsendf(data, &imapc->pp, Curl_dyn_ptr(&imapc->dyn), ap);
#ifdef __clang__
#pragma clang diagnostic pop
#endif
va_end(ap);
}
return result;

View File

@ -112,7 +112,8 @@ inet_pton4(const char *src, unsigned char *dst)
pch = strchr(digits, ch);
if(pch) {
unsigned int val = *tp * 10 + (unsigned int)(pch - digits);
unsigned int val = (unsigned int)(*tp * 10) +
(unsigned int)(pch - digits);
if(saw_digit && *tp == 0)
return (0);

View File

@ -31,9 +31,6 @@ int Curl_inet_pton(int, const char *, void *);
#ifdef HAVE_INET_PTON
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#elif defined(HAVE_WS2TCPIP_H)
/* inet_pton() exists in Vista or later */
#include <ws2tcpip.h>
#endif
#define Curl_inet_pton(x,y,z) inet_pton(x,y,z)
#endif

View File

@ -1,6 +1,6 @@
/* GSSAPI/krb5 support for FTP - loosely based on old krb4.c
*
* Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska HÃgskolan
* Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* Copyright (C) Daniel Stenberg
* All rights reserved.
@ -75,8 +75,7 @@ static CURLcode ftpsend(struct Curl_easy *data, struct connectdata *conn,
unsigned char data_sec = conn->data_prot;
#endif
if(!cmd)
return CURLE_BAD_FUNCTION_ARGUMENT;
DEBUGASSERT(cmd);
write_len = strlen(cmd);
if(!write_len || write_len > (sizeof(s) -3))
@ -236,9 +235,12 @@ krb5_auth(void *app_data, struct Curl_easy *data, struct connectdata *conn)
if(Curl_GetFTPResponse(data, &nread, NULL))
return -1;
if(data->state.buffer[0] != '3')
return -1;
else {
struct pingpong *pp = &conn->proto.ftpc.pp;
char *line = Curl_dyn_ptr(&pp->recvbuf);
if(line[0] != '3')
return -1;
}
}
stringp = aprintf("%s@%s", service, host);
@ -322,15 +324,19 @@ krb5_auth(void *app_data, struct Curl_easy *data, struct connectdata *conn)
ret = -1;
break;
}
if(data->state.buffer[0] != '2' && data->state.buffer[0] != '3') {
infof(data, "Server didn't accept auth data");
ret = AUTH_ERROR;
break;
else {
struct pingpong *pp = &conn->proto.ftpc.pp;
size_t len = Curl_dyn_len(&pp->recvbuf);
p = Curl_dyn_ptr(&pp->recvbuf);
if((len < 4) || (p[0] != '2' && p[0] != '3')) {
infof(data, "Server didn't accept auth data");
ret = AUTH_ERROR;
break;
}
}
_gssresp.value = NULL; /* make sure it is initialized */
p = data->state.buffer + 4;
p += 4; /* over '789 ' */
p = strstr(p, "ADAT=");
if(p) {
result = Curl_base64_decode(p + 5,
@ -417,7 +423,6 @@ static char level_to_char(int level)
case PROT_PRIVATE:
return 'P';
case PROT_CMD:
/* Fall through */
default:
/* Those 2 cases should not be reached! */
break;
@ -429,6 +434,9 @@ static char level_to_char(int level)
/* Send an FTP command defined by |message| and the optional arguments. The
function returns the ftp_code. If an error occurs, -1 is returned. */
static int ftp_send_command(struct Curl_easy *data, const char *message, ...)
CURL_PRINTF(2, 3);
static int ftp_send_command(struct Curl_easy *data, const char *message, ...)
{
int ftp_code;
@ -750,6 +758,8 @@ static int sec_set_protection_level(struct Curl_easy *data)
if(level) {
char *pbsz;
unsigned int buffer_size = 1 << 20; /* 1048576 */
struct pingpong *pp = &conn->proto.ftpc.pp;
char *line;
code = ftp_send_command(data, "PBSZ %u", buffer_size);
if(code < 0)
@ -761,10 +771,11 @@ static int sec_set_protection_level(struct Curl_easy *data)
}
conn->buffer_size = buffer_size;
pbsz = strstr(data->state.buffer, "PBSZ=");
line = Curl_dyn_ptr(&pp->recvbuf);
pbsz = strstr(line, "PBSZ=");
if(pbsz) {
/* stick to default value if the check fails */
if(!strncmp(pbsz, "PBSZ=", 5) && ISDIGIT(pbsz[5]))
if(ISDIGIT(pbsz[5]))
buffer_size = atoi(&pbsz[5]);
if(buffer_size < conn->buffer_size)
conn->buffer_size = buffer_size;

View File

@ -137,7 +137,7 @@ static void _ldap_free_urldesc(LDAPURLDesc *ludp);
_ldap_trace x; \
} while(0)
static void _ldap_trace(const char *fmt, ...);
static void _ldap_trace(const char *fmt, ...) CURL_PRINTF(1, 2);
#else
#define LDAP_TRACE(x) Curl_nop_stmt
#endif
@ -177,7 +177,7 @@ const struct Curl_handler Curl_handler_ldap = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_LDAP, /* defport */
@ -205,7 +205,7 @@ const struct Curl_handler Curl_handler_ldaps = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_LDAPS, /* defport */

View File

@ -194,11 +194,9 @@ static int MD4_Init(MD4_CTX *ctx)
static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size)
{
if(!ctx->data) {
ctx->data = malloc(size);
if(ctx->data) {
memcpy(ctx->data, data, size);
ctx->data = Curl_memdup(data, size);
if(ctx->data)
ctx->size = size;
}
}
}

View File

@ -304,12 +304,6 @@ void curl_dbg_free(void *ptr, int line, const char *source)
curl_socket_t curl_dbg_socket(int domain, int type, int protocol,
int line, const char *source)
{
const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ?
"FD %s:%d socket() = %d\n" :
(sizeof(curl_socket_t) == sizeof(long)) ?
"FD %s:%d socket() = %ld\n" :
"FD %s:%d socket() = %zd\n";
curl_socket_t sockfd;
if(countcheck("socket", line, source))
@ -318,7 +312,8 @@ curl_socket_t curl_dbg_socket(int domain, int type, int protocol,
sockfd = socket(domain, type, protocol);
if(source && (sockfd != CURL_SOCKET_BAD))
curl_dbg_log(fmt, source, line, sockfd);
curl_dbg_log("FD %s:%d socket() = %" CURL_FORMAT_SOCKET_T "\n",
source, line, sockfd);
return sockfd;
}
@ -357,16 +352,12 @@ int curl_dbg_socketpair(int domain, int type, int protocol,
curl_socket_t socket_vector[2],
int line, const char *source)
{
const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ?
"FD %s:%d socketpair() = %d %d\n" :
(sizeof(curl_socket_t) == sizeof(long)) ?
"FD %s:%d socketpair() = %ld %ld\n" :
"FD %s:%d socketpair() = %zd %zd\n";
int res = socketpair(domain, type, protocol, socket_vector);
if(source && (0 == res))
curl_dbg_log(fmt, source, line, socket_vector[0], socket_vector[1]);
curl_dbg_log("FD %s:%d socketpair() = "
"%" CURL_FORMAT_SOCKET_T " %" CURL_FORMAT_SOCKET_T "\n",
source, line, socket_vector[0], socket_vector[1]);
return res;
}
@ -375,19 +366,14 @@ int curl_dbg_socketpair(int domain, int type, int protocol,
curl_socket_t curl_dbg_accept(curl_socket_t s, void *saddr, void *saddrlen,
int line, const char *source)
{
const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ?
"FD %s:%d accept() = %d\n" :
(sizeof(curl_socket_t) == sizeof(long)) ?
"FD %s:%d accept() = %ld\n" :
"FD %s:%d accept() = %zd\n";
struct sockaddr *addr = (struct sockaddr *)saddr;
curl_socklen_t *addrlen = (curl_socklen_t *)saddrlen;
curl_socket_t sockfd = accept(s, addr, addrlen);
if(source && (sockfd != CURL_SOCKET_BAD))
curl_dbg_log(fmt, source, line, sockfd);
curl_dbg_log("FD %s:%d accept() = %" CURL_FORMAT_SOCKET_T "\n",
source, line, sockfd);
return sockfd;
}
@ -395,14 +381,9 @@ curl_socket_t curl_dbg_accept(curl_socket_t s, void *saddr, void *saddrlen,
/* separate function to allow libcurl to mark a "faked" close */
void curl_dbg_mark_sclose(curl_socket_t sockfd, int line, const char *source)
{
const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ?
"FD %s:%d sclose(%d)\n":
(sizeof(curl_socket_t) == sizeof(long)) ?
"FD %s:%d sclose(%ld)\n":
"FD %s:%d sclose(%zd)\n";
if(source)
curl_dbg_log(fmt, source, line, sockfd);
curl_dbg_log("FD %s:%d sclose(%" CURL_FORMAT_SOCKET_T ")\n",
source, line, sockfd);
}
/* this is our own defined way to close sockets on *ALL* platforms */

View File

@ -72,7 +72,7 @@ CURL_EXTERN ALLOC_FUNC wchar_t *curl_dbg_wcsdup(const wchar_t *str,
CURL_EXTERN void curl_dbg_memdebug(const char *logname);
CURL_EXTERN void curl_dbg_memlimit(long limit);
CURL_EXTERN void curl_dbg_log(const char *format, ...);
CURL_EXTERN void curl_dbg_log(const char *format, ...) CURL_PRINTF(1, 2);
/* file descriptor manipulators */
CURL_EXTERN curl_socket_t curl_dbg_socket(int domain, int type, int protocol,

View File

@ -30,6 +30,7 @@
#include "warnless.h"
#include "urldata.h"
#include "sendf.h"
#include "strdup.h"
#if !defined(CURL_DISABLE_MIME) && (!defined(CURL_DISABLE_HTTP) || \
!defined(CURL_DISABLE_SMTP) || \
@ -817,7 +818,7 @@ static size_t read_part_content(curl_mimepart *part,
case MIMEKIND_FILE:
if(part->fp && feof(part->fp))
break; /* At EOF. */
/* FALLTHROUGH */
FALLTHROUGH();
default:
if(part->readfunc) {
if(!(part->flags & MIME_FAST_READ)) {
@ -936,7 +937,7 @@ static size_t readback_part(curl_mimepart *part,
mimesetstate(&part->state, MIMESTATE_USERHEADERS, hdr->next);
break;
}
/* FALLTHROUGH */
FALLTHROUGH();
case MIMESTATE_CURLHEADERS:
if(!hdr)
mimesetstate(&part->state, MIMESTATE_USERHEADERS, part->userheaders);
@ -970,7 +971,7 @@ static size_t readback_part(curl_mimepart *part,
fclose(part->fp);
part->fp = NULL;
}
/* FALLTHROUGH */
FALLTHROUGH();
case CURL_READFUNC_ABORT:
case CURL_READFUNC_PAUSE:
case READ_ERROR:
@ -1235,6 +1236,7 @@ CURLcode Curl_mime_duppart(struct Curl_easy *data,
}
break;
default: /* Invalid kind: should not occur. */
DEBUGF(infof(data, "invalid MIMEKIND* attempt"));
res = CURLE_BAD_FUNCTION_ARGUMENT; /* Internal error? */
break;
}
@ -1370,27 +1372,22 @@ CURLcode curl_mime_filename(curl_mimepart *part, const char *filename)
/* Set mime part content from memory data. */
CURLcode curl_mime_data(curl_mimepart *part,
const char *data, size_t datasize)
const char *ptr, size_t datasize)
{
if(!part)
return CURLE_BAD_FUNCTION_ARGUMENT;
cleanup_part_content(part);
if(data) {
if(ptr) {
if(datasize == CURL_ZERO_TERMINATED)
datasize = strlen(data);
datasize = strlen(ptr);
part->data = malloc(datasize + 1);
part->data = Curl_memdup0(ptr, datasize);
if(!part->data)
return CURLE_OUT_OF_MEMORY;
part->datasize = datasize;
if(datasize)
memcpy(part->data, data, datasize);
part->data[datasize] = '\0'; /* Set a null terminator as sentinel. */
part->readfunc = mime_mem_read;
part->seekfunc = mime_mem_seek;
part->freefunc = mime_mem_free;

View File

@ -130,7 +130,8 @@ struct curl_mimepart {
size_t lastreadstatus; /* Last read callback returned status. */
};
CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...);
CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...)
CURL_PRINTF(2, 3);
#if !defined(CURL_DISABLE_MIME) && (!defined(CURL_DISABLE_HTTP) || \
!defined(CURL_DISABLE_SMTP) || \

File diff suppressed because it is too large Load Diff

View File

@ -88,7 +88,7 @@ const struct Curl_handler Curl_handler_mqtt = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_MQTT, /* defport */
@ -524,8 +524,10 @@ static CURLcode mqtt_publish(struct Curl_easy *data)
char encodedbytes[4];
curl_off_t postfieldsize = data->set.postfieldsize;
if(!payload)
if(!payload) {
DEBUGF(infof(data, "mqtt_publish without payload, return bad arg"));
return CURLE_BAD_FUNCTION_ARGUMENT;
}
if(postfieldsize < 0)
payloadlen = strlen(payload);
else
@ -622,7 +624,6 @@ static CURLcode mqtt_read_publish(struct Curl_easy *data, bool *done)
struct connectdata *conn = data->conn;
curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
ssize_t nread;
unsigned char *pkt = (unsigned char *)data->state.buffer;
size_t remlen;
struct mqtt_conn *mqtt = &conn->proto.mqtt;
struct MQTT *mq = data->req.p.mqtt;
@ -671,13 +672,14 @@ MQTT_SUBACK_COMING:
data->req.bytecount = 0;
data->req.size = remlen;
mq->npacket = remlen; /* get this many bytes */
/* FALLTHROUGH */
FALLTHROUGH();
case MQTT_PUB_REMAIN: {
/* read rest of packet, but no more. Cap to buffer size */
char buffer[4*1024];
size_t rest = mq->npacket;
if(rest > (size_t)data->set.buffer_size)
rest = (size_t)data->set.buffer_size;
result = Curl_read(data, sockfd, (char *)pkt, rest, &nread);
if(rest > sizeof(buffer))
rest = sizeof(buffer);
result = Curl_read(data, sockfd, buffer, rest, &nread);
if(result) {
if(CURLE_AGAIN == result) {
infof(data, "EEEE AAAAGAIN");
@ -690,14 +692,12 @@ MQTT_SUBACK_COMING:
goto end;
}
mq->npacket -= nread;
/* if QoS is set, message contains packet id */
result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)pkt, nread);
result = Curl_client_write(data, CLIENTWRITE_BODY, buffer, nread);
if(result)
goto end;
mq->npacket -= nread;
if(!mq->npacket)
/* no more PUBLISH payload, back to subscribe wait state */
mqstate(data, MQTT_FIRST, MQTT_PUBWAIT);
@ -745,7 +745,6 @@ static CURLcode mqtt_doing(struct Curl_easy *data, bool *done)
struct MQTT *mq = data->req.p.mqtt;
ssize_t nread;
curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
unsigned char *pkt = (unsigned char *)data->state.buffer;
unsigned char byte;
*done = FALSE;
@ -776,14 +775,14 @@ static CURLcode mqtt_doing(struct Curl_easy *data, bool *done)
/* remember the first byte */
mq->npacket = 0;
mqstate(data, MQTT_REMAINING_LENGTH, MQTT_NOSTATE);
/* FALLTHROUGH */
FALLTHROUGH();
case MQTT_REMAINING_LENGTH:
do {
result = Curl_read(data, sockfd, (char *)&byte, 1, &nread);
if(!nread)
break;
Curl_debug(data, CURLINFO_HEADER_IN, (char *)&byte, 1);
pkt[mq->npacket++] = byte;
mq->pkt_hd[mq->npacket++] = byte;
} while((byte & 0x80) && (mq->npacket < 4));
if(nread && (byte & 0x80))
/* MQTT supports up to 127 * 128^0 + 127 * 128^1 + 127 * 128^2 +
@ -791,7 +790,7 @@ static CURLcode mqtt_doing(struct Curl_easy *data, bool *done)
result = CURLE_WEIRD_SERVER_REPLY;
if(result)
break;
mq->remaining_length = mqtt_decode_len(&pkt[0], mq->npacket, NULL);
mq->remaining_length = mqtt_decode_len(mq->pkt_hd, mq->npacket, NULL);
mq->npacket = 0;
if(mq->remaining_length) {
mqstate(data, mqtt->nextstate, MQTT_NOSTATE);

View File

@ -57,6 +57,7 @@ struct MQTT {
unsigned char firstbyte;
size_t remaining_length;
struct dynbuf recvbuf;
unsigned char pkt_hd[4]; /* for decoding the arriving packet length */
};
#endif /* HEADER_CURL_MQTT_H */

View File

@ -672,6 +672,7 @@ static CURLcode multi_done(struct Curl_easy *data,
many callbacks and protocols work differently, we could potentially do
this more fine-grained in the future. */
premature = TRUE;
FALLTHROUGH();
default:
break;
}
@ -993,31 +994,92 @@ void Curl_attach_connection(struct Curl_easy *data,
Curl_conn_ev_data_attach(conn, data);
}
static int domore_getsock(struct Curl_easy *data,
struct connectdata *conn,
curl_socket_t *socks)
static int connecting_getsock(struct Curl_easy *data, curl_socket_t *socks)
{
struct connectdata *conn = data->conn;
(void)socks;
/* Not using `conn->sockfd` as `Curl_setup_transfer()` initializes
* that *after* the connect. */
if(conn && conn->sock[FIRSTSOCKET] != CURL_SOCKET_BAD) {
/* Default is to wait to something from the server */
socks[0] = conn->sock[FIRSTSOCKET];
return GETSOCK_READSOCK(0);
}
return GETSOCK_BLANK;
}
static int protocol_getsock(struct Curl_easy *data, curl_socket_t *socks)
{
struct connectdata *conn = data->conn;
if(conn && conn->handler->proto_getsock)
return conn->handler->proto_getsock(data, conn, socks);
else if(conn && conn->sockfd != CURL_SOCKET_BAD) {
/* Default is to wait to something from the server */
socks[0] = conn->sockfd;
return GETSOCK_READSOCK(0);
}
return GETSOCK_BLANK;
}
static int domore_getsock(struct Curl_easy *data, curl_socket_t *socks)
{
struct connectdata *conn = data->conn;
if(conn && conn->handler->domore_getsock)
return conn->handler->domore_getsock(data, conn, socks);
else if(conn && conn->sockfd != CURL_SOCKET_BAD) {
/* Default is that we want to send something to the server */
socks[0] = conn->sockfd;
return GETSOCK_WRITESOCK(0);
}
return GETSOCK_BLANK;
}
static int doing_getsock(struct Curl_easy *data,
struct connectdata *conn,
curl_socket_t *socks)
static int doing_getsock(struct Curl_easy *data, curl_socket_t *socks)
{
struct connectdata *conn = data->conn;
if(conn && conn->handler->doing_getsock)
return conn->handler->doing_getsock(data, conn, socks);
else if(conn && conn->sockfd != CURL_SOCKET_BAD) {
/* Default is that we want to send something to the server */
socks[0] = conn->sockfd;
return GETSOCK_WRITESOCK(0);
}
return GETSOCK_BLANK;
}
static int protocol_getsock(struct Curl_easy *data,
struct connectdata *conn,
curl_socket_t *socks)
static int perform_getsock(struct Curl_easy *data, curl_socket_t *sock)
{
if(conn->handler->proto_getsock)
return conn->handler->proto_getsock(data, conn, socks);
return GETSOCK_BLANK;
struct connectdata *conn = data->conn;
if(!conn)
return GETSOCK_BLANK;
else if(conn->handler->perform_getsock)
return conn->handler->perform_getsock(data, conn, sock);
else {
/* Default is to obey the data->req.keepon flags for send/recv */
int bitmap = GETSOCK_BLANK;
unsigned sockindex = 0;
if(CURL_WANT_RECV(data)) {
DEBUGASSERT(conn->sockfd != CURL_SOCKET_BAD);
bitmap |= GETSOCK_READSOCK(sockindex);
sock[sockindex] = conn->sockfd;
}
if(CURL_WANT_SEND(data)) {
if((conn->sockfd != conn->writesockfd) ||
bitmap == GETSOCK_BLANK) {
/* only if they are not the same socket and we have a readable
one, we increase index */
if(bitmap != GETSOCK_BLANK)
sockindex++; /* increase index if we need two entries */
DEBUGASSERT(conn->writesockfd != CURL_SOCKET_BAD);
sock[sockindex] = conn->writesockfd;
}
bitmap |= GETSOCK_WRITESOCK(sockindex);
}
return bitmap;
}
}
/* Initializes `poll_set` with the current socket poll actions needed
@ -1033,45 +1095,61 @@ static void multi_getsock(struct Curl_easy *data,
return;
switch(data->mstate) {
default:
case MSTATE_INIT:
case MSTATE_PENDING:
case MSTATE_CONNECT:
/* nothing to poll for yet */
break;
case MSTATE_RESOLVING:
Curl_pollset_add_socks2(data, ps, Curl_resolv_getsock);
Curl_pollset_add_socks(data, ps, Curl_resolv_getsock);
/* connection filters are not involved in this phase */
return;
break;
case MSTATE_CONNECTING:
case MSTATE_TUNNELING:
Curl_pollset_add_socks(data, ps, connecting_getsock);
Curl_conn_adjust_pollset(data, ps);
break;
case MSTATE_PROTOCONNECTING:
case MSTATE_PROTOCONNECT:
case MSTATE_PROTOCONNECTING:
Curl_pollset_add_socks(data, ps, protocol_getsock);
Curl_conn_adjust_pollset(data, ps);
break;
case MSTATE_DO:
case MSTATE_DOING:
Curl_pollset_add_socks(data, ps, doing_getsock);
break;
case MSTATE_TUNNELING:
case MSTATE_CONNECTING:
Curl_conn_adjust_pollset(data, ps);
break;
case MSTATE_DOING_MORE:
Curl_pollset_add_socks(data, ps, domore_getsock);
Curl_conn_adjust_pollset(data, ps);
break;
case MSTATE_DID: /* since is set after DO is completed, we switch to
waiting for the same as the PERFORMING state */
case MSTATE_DID: /* same as PERFORMING in regard to polling */
case MSTATE_PERFORMING:
Curl_pollset_add_socks(data, ps, Curl_single_getsock);
Curl_pollset_add_socks(data, ps, perform_getsock);
Curl_conn_adjust_pollset(data, ps);
break;
case MSTATE_RATELIMITING:
/* nothing to wait for */
return;
}
/* we need to let time pass, ignore socket(s) */
break;
/* Let connection filters add/remove as needed */
Curl_conn_adjust_pollset(data, ps);
case MSTATE_DONE:
case MSTATE_COMPLETED:
case MSTATE_MSGSENT:
/* nothing more to poll for */
break;
default:
failf(data, "multi_getsock: unexpected multi state %d", data->mstate);
DEBUGASSERT(0);
break;
}
}
CURLMcode curl_multi_fdset(struct Curl_multi *multi,
@ -1942,6 +2020,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
if(!result) {
*nowp = Curl_pgrsTime(data, TIMER_POSTQUEUE);
if(async)
/* We're now waiting for an asynchronous name lookup */
multistate(data, MSTATE_RESOLVING);
@ -1983,8 +2062,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(dns) {
#ifdef CURLRES_ASYNCH
conn->resolve_async.dns = dns;
conn->resolve_async.done = TRUE;
data->state.async.dns = dns;
data->state.async.done = TRUE;
#endif
result = CURLE_OK;
infof(data, "Hostname '%s' was found in DNS cache", hostname);
@ -2371,7 +2450,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
{
char *newurl = NULL;
bool retry = FALSE;
bool comeback = FALSE;
DEBUGASSERT(data->state.buffer);
/* check if over send speed */
send_timeout_ms = 0;
@ -2402,7 +2480,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
/* read/write data if it is ready to do so */
result = Curl_readwrite(data->conn, data, &done, &comeback);
result = Curl_readwrite(data, &done);
if(done || (result == CURLE_RECV_ERROR)) {
/* If CURLE_RECV_ERROR happens early enough, we assume it was a race
@ -2512,7 +2590,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
}
}
else if(comeback) {
else if(data->state.select_bits) {
/* This avoids CURLM_CALL_MULTI_PERFORM so that a very fast transfer
won't get stuck on this transfer at the expense of other concurrent
transfers */
@ -3164,7 +3242,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
if(data->conn && !(data->conn->handler->flags & PROTOPT_DIRLOCK))
/* set socket event bitmask if they're not locked */
data->conn->cselect_bits = (unsigned char)ev_bitmask;
data->state.select_bits = (unsigned char)ev_bitmask;
Curl_expire(data, 0, EXPIRE_RUN_NOW);
}

View File

@ -216,7 +216,6 @@ bool Curl_check_noproxy(const char *name, const char *no_proxy,
/* case C passes through, not a match */
break;
case TYPE_IPV4:
/* FALLTHROUGH */
case TYPE_IPV6: {
const char *check = token;
char *slash;

View File

@ -130,7 +130,7 @@ const struct Curl_handler Curl_handler_ldap = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
oldap_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_LDAP, /* defport */
@ -158,7 +158,7 @@ const struct Curl_handler Curl_handler_ldaps = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
oldap_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_LDAPS, /* defport */
@ -645,7 +645,7 @@ static CURLcode oldap_state_mechs_resp(struct Curl_easy *data,
switch(code) {
case LDAP_SIZELIMIT_EXCEEDED:
infof(data, "Too many authentication mechanisms\n");
/* FALLTHROUGH */
FALLTHROUGH();
case LDAP_SUCCESS:
case LDAP_NO_RESULTS_RETURNED:
if(Curl_sasl_can_authenticate(&li->sasl, data))
@ -793,10 +793,13 @@ static CURLcode oldap_connecting(struct Curl_easy *data, bool *done)
result = oldap_perform_bind(data, OLDAP_BIND);
break;
}
/* FALLTHROUGH */
result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET);
if(result)
break;
FALLTHROUGH();
case OLDAP_TLS:
result = oldap_ssl_connect(data, OLDAP_TLS);
if(result && data->set.use_ssl != CURLUSESSL_TRY)
if(result)
result = oldap_map_error(code, CURLE_USE_SSL_FAILED);
else if(ssl_installed(conn)) {
conn->bits.tls_upgraded = TRUE;
@ -887,10 +890,14 @@ static CURLcode oldap_do(struct Curl_easy *data, bool *done)
result = oldap_url_parse(data, &lud);
if(!result) {
Sockbuf *sb;
/* re-install the libcurl SSL handlers into the sockbuf. */
ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb);
ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data);
#ifdef USE_SSL
if(ssl_installed(conn)) {
Sockbuf *sb;
/* re-install the libcurl SSL handlers into the sockbuf. */
ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb);
ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data);
}
#endif
rc = ldap_search_ext(li->ld, lud->lud_dn, lud->lud_scope,
lud->lud_filter, lud->lud_attrs, 0,
@ -1014,7 +1021,7 @@ static ssize_t oldap_recv(struct Curl_easy *data, int sockindex, char *buf,
switch(code) {
case LDAP_SIZELIMIT_EXCEEDED:
infof(data, "There are more than %d entries", lr->nument);
/* FALLTHROUGH */
FALLTHROUGH();
case LDAP_SUCCESS:
data->req.size = data->req.bytecount;
break;

View File

@ -36,6 +36,7 @@
#include "pingpong.h"
#include "multiif.h"
#include "vtls/vtls.h"
#include "strdup.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@ -105,7 +106,7 @@ CURLcode Curl_pp_statemach(struct Curl_easy *data,
if(Curl_conn_data_pending(data, FIRSTSOCKET))
rc = 1;
else if(Curl_pp_moredata(pp))
else if(pp->overflow)
/* We are receiving and there is data in the cache so just read it */
rc = 1;
else if(!pp->sendleft && Curl_conn_data_pending(data, FIRSTSOCKET))
@ -139,19 +140,13 @@ CURLcode Curl_pp_statemach(struct Curl_easy *data,
}
/* initialize stuff to prepare for reading a fresh new response */
void Curl_pp_init(struct Curl_easy *data, struct pingpong *pp)
void Curl_pp_init(struct pingpong *pp)
{
DEBUGASSERT(data);
pp->nread_resp = 0;
pp->linestart_resp = data->state.buffer;
pp->pending_resp = TRUE;
pp->response = Curl_now(); /* start response time-out now! */
}
/* setup for the coming transfer */
void Curl_pp_setup(struct pingpong *pp)
{
pp->pending_resp = TRUE;
Curl_dyn_init(&pp->sendbuf, DYN_PINGPPONG_CMD);
Curl_dyn_init(&pp->recvbuf, DYN_PINGPPONG_CMD);
}
/***********************************************************************
@ -197,9 +192,9 @@ CURLcode Curl_pp_vsendf(struct Curl_easy *data,
if(result)
return result;
pp->pending_resp = TRUE;
write_len = Curl_dyn_len(&pp->sendbuf);
s = Curl_dyn_ptr(&pp->sendbuf);
Curl_pp_init(data, pp);
#ifdef HAVE_GSSAPI
conn->data_prot = PROT_CMD;
@ -255,6 +250,25 @@ CURLcode Curl_pp_sendf(struct Curl_easy *data, struct pingpong *pp,
return result;
}
static CURLcode pingpong_read(struct Curl_easy *data,
curl_socket_t sockfd,
char *buffer,
size_t buflen,
ssize_t *nread)
{
CURLcode result;
#ifdef HAVE_GSSAPI
enum protection_level prot = data->conn->data_prot;
data->conn->data_prot = PROT_CLEAR;
#endif
result = Curl_read(data, sockfd, buffer, buflen, nread);
#ifdef HAVE_GSSAPI
DEBUGASSERT(prot > PROT_NONE && prot < PROT_LAST);
data->conn->data_prot = (unsigned char)prot;
#endif
return result;
}
/*
* Curl_pp_readresp()
*
@ -266,181 +280,96 @@ CURLcode Curl_pp_readresp(struct Curl_easy *data,
int *code, /* return the server code if done */
size_t *size) /* size of the response */
{
ssize_t perline; /* count bytes per line */
bool keepon = TRUE;
ssize_t gotbytes;
char *ptr;
struct connectdata *conn = data->conn;
char * const buf = data->state.buffer;
CURLcode result = CURLE_OK;
*code = 0; /* 0 for errors or not done */
*size = 0;
ptr = buf + pp->nread_resp;
if(pp->nfinal) {
/* a previous call left this many bytes in the beginning of the buffer as
that was the final line; now ditch that */
size_t full = Curl_dyn_len(&pp->recvbuf);
/* number of bytes in the current line, so far */
perline = (ssize_t)(ptr-pp->linestart_resp);
/* trim off the "final" leading part */
Curl_dyn_tail(&pp->recvbuf, full - pp->nfinal);
while((pp->nread_resp < (size_t)data->set.buffer_size) &&
(keepon && !result)) {
pp->nfinal = 0; /* now gone */
}
if(!pp->overflow) {
ssize_t gotbytes = 0;
char buffer[900];
if(pp->cache) {
/* we had data in the "cache", copy that instead of doing an actual
* read
*
* pp->cache_size is cast to ssize_t here. This should be safe, because
* it would have been populated with something of size int to begin
* with, even though its datatype may be larger than an int.
*/
if((ptr + pp->cache_size) > (buf + data->set.buffer_size + 1)) {
failf(data, "cached response data too big to handle");
return CURLE_WEIRD_SERVER_REPLY;
}
memcpy(ptr, pp->cache, pp->cache_size);
gotbytes = (ssize_t)pp->cache_size;
free(pp->cache); /* free the cache */
pp->cache = NULL; /* clear the pointer */
pp->cache_size = 0; /* zero the size just in case */
}
else {
#ifdef HAVE_GSSAPI
enum protection_level prot = conn->data_prot;
conn->data_prot = PROT_CLEAR;
#endif
DEBUGASSERT((ptr + data->set.buffer_size - pp->nread_resp) <=
(buf + data->set.buffer_size + 1));
result = Curl_read(data, sockfd, ptr,
data->set.buffer_size - pp->nread_resp,
&gotbytes);
#ifdef HAVE_GSSAPI
DEBUGASSERT(prot > PROT_NONE && prot < PROT_LAST);
conn->data_prot = (unsigned char)prot;
#endif
if(result == CURLE_AGAIN)
return CURLE_OK; /* return */
result = pingpong_read(data, sockfd, buffer, sizeof(buffer), &gotbytes);
if(result == CURLE_AGAIN)
return CURLE_OK;
if(result)
/* Set outer result variable to this error. */
keepon = FALSE;
}
if(result)
return result;
if(!keepon)
;
else if(gotbytes <= 0) {
keepon = FALSE;
result = CURLE_RECV_ERROR;
if(gotbytes <= 0) {
failf(data, "response reading failed (errno: %d)", SOCKERRNO);
return CURLE_RECV_ERROR;
}
result = Curl_dyn_addn(&pp->recvbuf, buffer, gotbytes);
if(result)
return result;
data->req.headerbytecount += (unsigned int)gotbytes;
pp->nread_resp += gotbytes;
}
do {
char *line = Curl_dyn_ptr(&pp->recvbuf);
char *nl = memchr(line, '\n', Curl_dyn_len(&pp->recvbuf));
if(nl) {
/* a newline is CRLF in pp-talk, so the CR is ignored as
the line isn't really terminated until the LF comes */
size_t length = nl - line + 1;
/* output debug output if that is requested */
#ifdef HAVE_GSSAPI
if(!conn->sec_complete)
#endif
Curl_debug(data, CURLINFO_HEADER_IN, line, length);
/*
* Pass all response-lines to the callback function registered for
* "headers". The response lines can be seen as a kind of headers.
*/
result = Curl_client_write(data, CLIENTWRITE_INFO, line, length);
if(result)
return result;
if(pp->endofresp(data, conn, line, length, code)) {
/* When at "end of response", keep the endofresp line first in the
buffer since it will be accessed outside (by pingpong
parsers). Store the overflow counter to inform about additional
data in this buffer after the endofresp line. */
pp->nfinal = length;
if(Curl_dyn_len(&pp->recvbuf) > length)
pp->overflow = Curl_dyn_len(&pp->recvbuf) - length;
else
pp->overflow = 0;
*size = pp->nread_resp; /* size of the response */
pp->nread_resp = 0; /* restart */
break;
}
if(Curl_dyn_len(&pp->recvbuf) > length)
/* keep the remaining piece */
Curl_dyn_tail((&pp->recvbuf), Curl_dyn_len(&pp->recvbuf) - length);
else
Curl_dyn_reset(&pp->recvbuf);
}
else {
/* we got a whole chunk of data, which can be anything from one
* byte to a set of lines and possible just a piece of the last
* line */
ssize_t i;
ssize_t clipamount = 0;
bool restart = FALSE;
/* without a newline, there is no overflow */
pp->overflow = 0;
break;
}
data->req.headerbytecount += (unsigned int)gotbytes;
pp->nread_resp += gotbytes;
for(i = 0; i < gotbytes; ptr++, i++) {
perline++;
if(*ptr == '\n') {
/* a newline is CRLF in pp-talk, so the CR is ignored as
the line isn't really terminated until the LF comes */
/* output debug output if that is requested */
#ifdef HAVE_GSSAPI
if(!conn->sec_complete)
#endif
Curl_debug(data, CURLINFO_HEADER_IN,
pp->linestart_resp, (size_t)perline);
/*
* We pass all response-lines to the callback function registered
* for "headers". The response lines can be seen as a kind of
* headers.
*/
result = Curl_client_write(data, CLIENTWRITE_INFO,
pp->linestart_resp, perline);
if(result)
return result;
if(pp->endofresp(data, conn, pp->linestart_resp, perline, code)) {
/* This is the end of the last line, copy the last line to the
start of the buffer and null-terminate, for old times sake */
size_t n = ptr - pp->linestart_resp;
memmove(buf, pp->linestart_resp, n);
buf[n] = 0; /* null-terminate */
keepon = FALSE;
pp->linestart_resp = ptr + 1; /* advance pointer */
i++; /* skip this before getting out */
*size = pp->nread_resp; /* size of the response */
pp->nread_resp = 0; /* restart */
break;
}
perline = 0; /* line starts over here */
pp->linestart_resp = ptr + 1;
}
}
if(!keepon && (i != gotbytes)) {
/* We found the end of the response lines, but we didn't parse the
full chunk of data we have read from the server. We therefore need
to store the rest of the data to be checked on the next invoke as
it may actually contain another end of response already! */
clipamount = gotbytes - i;
restart = TRUE;
DEBUGF(infof(data, "Curl_pp_readresp_ %d bytes of trailing "
"server response left",
(int)clipamount));
}
else if(keepon) {
if((perline == gotbytes) &&
(gotbytes > (ssize_t)data->set.buffer_size/2)) {
/* We got an excessive line without newlines and we need to deal
with it. We keep the first bytes of the line then we throw
away the rest. */
infof(data, "Excessive server response line length received, "
"%zd bytes. Stripping", gotbytes);
restart = TRUE;
/* we keep 40 bytes since all our pingpong protocols are only
interested in the first piece */
clipamount = 40;
}
else if(pp->nread_resp > (size_t)data->set.buffer_size/2) {
/* We got a large chunk of data and there's potentially still
trailing data to take care of, so we put any such part in the
"cache", clear the buffer to make space and restart. */
clipamount = perline;
restart = TRUE;
}
}
else if(i == gotbytes)
restart = TRUE;
if(clipamount) {
pp->cache_size = clipamount;
pp->cache = malloc(pp->cache_size);
if(pp->cache)
memcpy(pp->cache, pp->linestart_resp, pp->cache_size);
else
return CURLE_OUT_OF_MEMORY;
}
if(restart) {
/* now reset a few variables to start over nicely from the start of
the big buffer */
pp->nread_resp = 0; /* start over from scratch in the buffer */
ptr = pp->linestart_resp = buf;
perline = 0;
}
} /* there was data */
} /* while there's buffer left and loop is requested */
} while(1); /* while there's buffer left to scan */
pp->pending_resp = FALSE;
@ -488,14 +417,13 @@ CURLcode Curl_pp_flushsend(struct Curl_easy *data,
CURLcode Curl_pp_disconnect(struct pingpong *pp)
{
Curl_dyn_free(&pp->sendbuf);
Curl_safefree(pp->cache);
Curl_dyn_free(&pp->recvbuf);
return CURLE_OK;
}
bool Curl_pp_moredata(struct pingpong *pp)
{
return (!pp->sendleft && pp->cache && pp->nread_resp < pp->cache_size) ?
TRUE : FALSE;
return (!pp->sendleft && Curl_dyn_len(&pp->recvbuf));
}
#endif

View File

@ -47,16 +47,11 @@ typedef enum {
* It holds response cache and non-blocking sending data.
*/
struct pingpong {
char *cache; /* data cache between getresponse()-calls */
size_t cache_size; /* size of cache in bytes */
size_t nread_resp; /* number of bytes currently read of a server response */
char *linestart_resp; /* line start pointer for the server response
reader function */
bool pending_resp; /* set TRUE when a server response is pending or in
progress, and is cleared once the last response is
read */
char *sendthis; /* allocated pointer to a buffer that is to be sent to the
server */
char *sendthis; /* pointer to a buffer that is to be sent to the server */
size_t sendleft; /* number of bytes left to send from the sendthis buffer */
size_t sendsize; /* total size of the sendthis buffer */
struct curltime response; /* set to Curl_now() when a command has been sent
@ -64,6 +59,10 @@ struct pingpong {
timediff_t response_time; /* When no timeout is given, this is the amount of
milliseconds we await for a server response. */
struct dynbuf sendbuf;
struct dynbuf recvbuf;
size_t overflow; /* number of bytes left after a final response line */
size_t nfinal; /* number of bytes in the final response line, which
after a match is first in the receice buffer */
/* Function pointers the protocols MUST implement and provide for the
pingpong layer to function */
@ -90,10 +89,7 @@ CURLcode Curl_pp_statemach(struct Curl_easy *data, struct pingpong *pp,
bool block, bool disconnecting);
/* initialize stuff to prepare for reading a fresh new response */
void Curl_pp_init(struct Curl_easy *data, struct pingpong *pp);
/* setup for the transfer */
void Curl_pp_setup(struct pingpong *pp);
void Curl_pp_init(struct pingpong *pp);
/* Returns timeout in ms. 0 or negative number means the timeout has already
triggered */
@ -113,7 +109,7 @@ timediff_t Curl_pp_state_timeout(struct Curl_easy *data,
*/
CURLcode Curl_pp_sendf(struct Curl_easy *data,
struct pingpong *pp,
const char *fmt, ...);
const char *fmt, ...) CURL_PRINTF(3, 4);
/***********************************************************************
*
@ -128,7 +124,7 @@ CURLcode Curl_pp_sendf(struct Curl_easy *data,
CURLcode Curl_pp_vsendf(struct Curl_easy *data,
struct pingpong *pp,
const char *fmt,
va_list args);
va_list args) CURL_PRINTF(3, 0);
/*
* Curl_pp_readresp()

View File

@ -77,6 +77,7 @@
#include "curl_sasl.h"
#include "curl_md5.h"
#include "warnless.h"
#include "strdup.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
@ -124,7 +125,7 @@ const struct Curl_handler Curl_handler_pop3 = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
pop3_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_POP3, /* defport */
@ -153,7 +154,7 @@ const struct Curl_handler Curl_handler_pop3s = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
pop3_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_POP3S, /* defport */
@ -251,8 +252,8 @@ static bool pop3_endofresp(struct Curl_easy *data, struct connectdata *conn,
*/
static CURLcode pop3_get_message(struct Curl_easy *data, struct bufref *out)
{
char *message = data->state.buffer;
size_t len = strlen(message);
char *message = Curl_dyn_ptr(&data->conn->proto.pop3c.pp.recvbuf);
size_t len = data->conn->proto.pop3c.pp.nfinal;
if(len > 2) {
/* Find the start of the message */
@ -648,8 +649,8 @@ static CURLcode pop3_state_servergreet_resp(struct Curl_easy *data,
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
struct pop3_conn *pop3c = &conn->proto.pop3c;
const char *line = data->state.buffer;
size_t len = strlen(line);
const char *line = Curl_dyn_ptr(&data->conn->proto.pop3c.pp.recvbuf);
size_t len = data->conn->proto.pop3c.pp.nfinal;
(void)instate; /* no use for this yet */
@ -657,44 +658,35 @@ static CURLcode pop3_state_servergreet_resp(struct Curl_easy *data,
failf(data, "Got unexpected pop3-server response");
result = CURLE_WEIRD_SERVER_REPLY;
}
else {
else if(len > 3) {
/* Does the server support APOP authentication? */
if(len >= 4 && line[len - 2] == '>') {
/* Look for the APOP timestamp */
size_t i;
for(i = 3; i < len - 2; ++i) {
if(line[i] == '<') {
/* Calculate the length of the timestamp */
size_t timestamplen = len - 1 - i;
char *at;
if(!timestamplen)
break;
char *lt;
char *gt = NULL;
/* Allocate some memory for the timestamp */
pop3c->apoptimestamp = (char *)calloc(1, timestamplen + 1);
if(!pop3c->apoptimestamp)
break;
/* Copy the timestamp */
memcpy(pop3c->apoptimestamp, line + i, timestamplen);
pop3c->apoptimestamp[timestamplen] = '\0';
/* If the timestamp does not contain '@' it is not (as required by
RFC-1939) conformant to the RFC-822 message id syntax, and we
therefore do not use APOP authentication. */
at = strchr(pop3c->apoptimestamp, '@');
if(!at)
Curl_safefree(pop3c->apoptimestamp);
else
/* Store the APOP capability */
pop3c->authtypes |= POP3_TYPE_APOP;
break;
}
/* Look for the APOP timestamp */
lt = memchr(line, '<', len);
if(lt)
/* search the remainder for '>' */
gt = memchr(lt, '>', len - (lt - line));
if(gt) {
/* the length of the timestamp, including the brackets */
size_t timestamplen = gt - lt + 1;
char *at = memchr(lt, '@', timestamplen);
/* If the timestamp does not contain '@' it is not (as required by
RFC-1939) conformant to the RFC-822 message id syntax, and we
therefore do not use APOP authentication. */
if(at) {
/* dupe the timestamp */
pop3c->apoptimestamp = Curl_memdup0(lt, timestamplen);
if(!pop3c->apoptimestamp)
return CURLE_OUT_OF_MEMORY;
/* Store the APOP capability */
pop3c->authtypes |= POP3_TYPE_APOP;
}
}
result = pop3_perform_capa(data, conn);
if(!result)
result = pop3_perform_capa(data, conn);
}
return result;
@ -707,8 +699,8 @@ static CURLcode pop3_state_capa_resp(struct Curl_easy *data, int pop3code,
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
struct pop3_conn *pop3c = &conn->proto.pop3c;
const char *line = data->state.buffer;
size_t len = strlen(line);
const char *line = Curl_dyn_ptr(&data->conn->proto.pop3c.pp.recvbuf);
size_t len = data->conn->proto.pop3c.pp.nfinal;
(void)instate; /* no use for this yet */
@ -795,7 +787,7 @@ static CURLcode pop3_state_starttls_resp(struct Curl_easy *data,
(void)instate; /* no use for this yet */
/* Pipelining in response is forbidden. */
if(data->conn->proto.pop3c.pp.cache_size)
if(data->conn->proto.pop3c.pp.overflow)
return CURLE_WEIRD_SERVER_REPLY;
if(pop3code != '+') {
@ -944,24 +936,29 @@ static CURLcode pop3_state_command_resp(struct Curl_easy *data,
/* POP3 download */
Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
if(pp->cache) {
/* The header "cache" contains a bunch of data that is actually body
content so send it as such. Note that there may even be additional
"headers" after the body */
if(pp->overflow) {
/* The recv buffer contains data that is actually body content so send
it as such. Note that there may even be additional "headers" after
the body */
/* keep only the overflow */
Curl_dyn_tail(&pp->recvbuf, pp->overflow);
pp->nfinal = 0; /* done */
if(!data->req.no_body) {
result = Curl_pop3_write(data, pp->cache, pp->cache_size);
result = Curl_pop3_write(data, Curl_dyn_ptr(&pp->recvbuf),
Curl_dyn_len(&pp->recvbuf));
if(result)
return result;
}
/* Free the cache */
Curl_safefree(pp->cache);
/* Reset the cache size */
pp->cache_size = 0;
/* reset the buffer */
Curl_dyn_reset(&pp->recvbuf);
pp->overflow = 0;
}
}
else
pp->overflow = 0;
/* End of DO phase */
pop3_state(data, POP3_STOP);
@ -1131,8 +1128,7 @@ static CURLcode pop3_connect(struct Curl_easy *data, bool *done)
Curl_sasl_init(&pop3c->sasl, data, &saslpop3);
/* Initialise the pingpong layer */
Curl_pp_setup(pp);
Curl_pp_init(data, pp);
Curl_pp_init(pp);
/* Parse the URL options */
result = pop3_parse_url_options(conn);

View File

@ -174,10 +174,18 @@ void Curl_pgrsTimeWas(struct Curl_easy *data, timerid timer,
data->progress.t_startop = timestamp;
break;
case TIMER_STARTSINGLE:
/* This is set at the start of each single fetch */
/* This is set at the start of each single transfer */
data->progress.t_startsingle = timestamp;
data->progress.is_t_startransfer_set = false;
break;
case TIMER_POSTQUEUE:
/* Set when the transfer starts (after potentially having been brought
back from the waiting queue). It needs to count from t_startop and not
t_startsingle since the latter is reset when a connection is brought
back from the pending queue. */
data->progress.t_postqueue =
Curl_timediff_us(timestamp, data->progress.t_startop);
break;
case TIMER_STARTACCEPT:
data->progress.t_acceptdata = timestamp;
break;

View File

@ -30,7 +30,8 @@
typedef enum {
TIMER_NONE,
TIMER_STARTOP,
TIMER_STARTSINGLE,
TIMER_STARTSINGLE, /* start of transfer, might get queued */
TIMER_POSTQUEUE, /* start, immediately after dequeue */
TIMER_NAMELOOKUP,
TIMER_CONNECT,
TIMER_APPCONNECT,

View File

@ -201,7 +201,7 @@ CURLcode Curl_rand(struct Curl_easy *data, unsigned char *rnd, size_t num)
{
CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
DEBUGASSERT(num > 0);
DEBUGASSERT(num);
while(num) {
unsigned int r;
@ -241,9 +241,11 @@ CURLcode Curl_rand_hex(struct Curl_easy *data, unsigned char *rnd,
memset(buffer, 0, sizeof(buffer));
#endif
if((num/2 >= sizeof(buffer)) || !(num&1))
if((num/2 >= sizeof(buffer)) || !(num&1)) {
/* make sure it fits in the local buffer and that it is an odd number! */
DEBUGF(infof(data, "invalid buffer size with Curl_rand_hex"));
return CURLE_BAD_FUNCTION_ARGUMENT;
}
num--; /* save one for null-termination */

View File

@ -58,21 +58,20 @@ static int rtsp_getsock_do(struct Curl_easy *data,
struct connectdata *conn, curl_socket_t *socks);
/*
* Parse and write out any available RTP data.
* Parse and write out an RTSP response.
* @param data the transfer
* @param conn the connection
* @param buf data read from connection
* @param blen amount of data in buf
* @param consumed out, number of blen consumed
* @param is_eos TRUE iff this is the last write
* @param readmore out, TRUE iff complete buf was consumed and more data
* is needed
*/
static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data,
struct connectdata *conn,
const char *buf,
size_t blen,
size_t *pconsumed,
bool *readmore);
static CURLcode rtsp_rtp_write_resp(struct Curl_easy *data,
const char *buf,
size_t blen,
bool is_eos,
bool *done);
static CURLcode rtsp_setup_connection(struct Curl_easy *data,
struct connectdata *conn);
@ -115,7 +114,7 @@ const struct Curl_handler Curl_handler_rtsp = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
rtsp_disconnect, /* disconnect */
rtsp_rtp_readwrite, /* readwrite */
rtsp_rtp_write_resp, /* write_resp */
rtsp_conncheck, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_RTSP, /* defport */
@ -590,26 +589,48 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
return result;
}
/**
* write any BODY bytes missing to the client, ignore the rest.
*/
static CURLcode rtp_write_body_junk(struct Curl_easy *data,
const char *buf,
size_t blen)
{
struct rtsp_conn *rtspc = &(data->conn->proto.rtspc);
curl_off_t body_remain;
bool in_body;
in_body = (data->req.headerline && !rtspc->in_header) &&
(data->req.size >= 0) &&
(data->req.bytecount < data->req.size);
body_remain = in_body? (data->req.size - data->req.bytecount) : 0;
DEBUGASSERT(body_remain >= 0);
if(body_remain) {
if((curl_off_t)blen > body_remain)
blen = (size_t)body_remain;
return Curl_client_write(data, CLIENTWRITE_BODY, (char *)buf, blen);
}
return CURLE_OK;
}
static CURLcode rtsp_filter_rtp(struct Curl_easy *data,
struct connectdata *conn,
const char *buf,
size_t blen,
bool in_body,
size_t *pconsumed)
{
struct rtsp_conn *rtspc = &(conn->proto.rtspc);
struct rtsp_conn *rtspc = &(data->conn->proto.rtspc);
CURLcode result = CURLE_OK;
size_t skip_len = 0;
*pconsumed = 0;
while(blen) {
bool in_body = (data->req.headerline && !rtspc->in_header) &&
(data->req.size >= 0) &&
(data->req.bytecount < data->req.size);
switch(rtspc->state) {
case RTP_PARSE_SKIP: {
DEBUGASSERT(Curl_dyn_len(&rtspc->buf) == 0);
if(in_body && buf[0] != '$') {
/* in BODY and no valid start, do not consume and return */
goto out;
}
while(blen && buf[0] != '$') {
if(!in_body && buf[0] == 'R' &&
data->set.rtspreq != RTSPREQ_RECEIVE) {
@ -624,13 +645,22 @@ static CURLcode rtsp_filter_rtp(struct Curl_easy *data,
goto out;
}
}
/* junk, consume without buffering */
/* junk/BODY, consume without buffering */
*pconsumed += 1;
++buf;
--blen;
++skip_len;
}
if(blen && buf[0] == '$') {
/* possible start of an RTP message, buffer */
if(skip_len) {
/* end of junk/BODY bytes, flush */
result = rtp_write_body_junk(data,
(char *)(buf - skip_len), skip_len);
skip_len = 0;
if(result)
goto out;
}
if(Curl_dyn_addn(&rtspc->buf, buf, 1)) {
result = CURLE_OUT_OF_MEMORY;
goto out;
@ -650,35 +680,22 @@ static CURLcode rtsp_filter_rtp(struct Curl_easy *data,
if(!(data->state.rtp_channel_mask[idx] & (1 << off))) {
/* invalid channel number, junk or BODY data */
rtspc->state = RTP_PARSE_SKIP;
if(in_body) {
/* we do not consume this byte, it is BODY data */
DEBUGF(infof(data, "RTSP: invalid RTP channel %d in BODY, "
"treating as BODY data", idx));
if(*pconsumed == 0) {
/* We did not consume the initial '$' in our buffer, but had
* it from an earlier call. We cannot un-consume it and have
* to write it directly as BODY data */
result = Curl_client_write(data, CLIENTWRITE_BODY,
Curl_dyn_ptr(&rtspc->buf), 1);
Curl_dyn_free(&rtspc->buf);
if(result)
goto out;
}
else {
/* un-consume the '$' and leave */
Curl_dyn_free(&rtspc->buf);
*pconsumed -= 1;
--buf;
++blen;
DEBUGASSERT(skip_len == 0);
/* we do not consume this byte, it is BODY data */
DEBUGF(infof(data, "RTSP: invalid RTP channel %d, skipping", idx));
if(*pconsumed == 0) {
/* We did not consume the initial '$' in our buffer, but had
* it from an earlier call. We cannot un-consume it and have
* to write it directly as BODY data */
result = rtp_write_body_junk(data, Curl_dyn_ptr(&rtspc->buf), 1);
if(result)
goto out;
}
}
else {
/* not BODY, forget the junk '$'. Do not consume this byte,
* it might be a start */
infof(data, "RTSP: invalid RTP channel %d, skipping", idx);
Curl_dyn_free(&rtspc->buf);
/* count the '$' as skip and continue */
skip_len = 1;
}
Curl_dyn_free(&rtspc->buf);
break;
}
/* a valid channel, so we expect this to be a real RTP message */
@ -754,52 +771,51 @@ static CURLcode rtsp_filter_rtp(struct Curl_easy *data,
}
}
out:
if(!result && skip_len)
result = rtp_write_body_junk(data, (char *)(buf - skip_len), skip_len);
return result;
}
static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data,
struct connectdata *conn,
const char *buf,
size_t blen,
size_t *pconsumed,
bool *readmore)
static CURLcode rtsp_rtp_write_resp(struct Curl_easy *data,
const char *buf,
size_t blen,
bool is_eos,
bool *done)
{
struct rtsp_conn *rtspc = &(conn->proto.rtspc);
struct rtsp_conn *rtspc = &(data->conn->proto.rtspc);
CURLcode result = CURLE_OK;
size_t consumed = 0;
bool in_body;
if(!data->req.header)
rtspc->in_header = FALSE;
in_body = (data->req.headerline && !rtspc->in_header) &&
(data->req.size >= 0) &&
(data->req.bytecount < data->req.size);
*readmore = FALSE;
*pconsumed = 0;
*done = FALSE;
if(!blen) {
goto out;
}
DEBUGF(infof(data, "rtsp_rtp_write_resp(len=%zu, in_header=%d, eos=%d)",
blen, rtspc->in_header, is_eos));
/* If header parsing is not onging, extract RTP messages */
if(!rtspc->in_header) {
result = rtsp_filter_rtp(data, conn, buf, blen, in_body, &consumed);
result = rtsp_filter_rtp(data, buf, blen, &consumed);
if(result)
goto out;
*pconsumed += consumed;
buf += consumed;
blen -= consumed;
/* either we consumed all or are at the start of header parsing */
if(blen && !data->req.header)
DEBUGF(infof(data, "RTSP: %zu bytes, possibly excess in response body",
blen));
}
/* we want to parse headers, do so */
if(data->req.header && blen) {
rtspc->in_header = TRUE;
result = Curl_http_readwrite_headers(data, conn, buf, blen,
&consumed);
result = Curl_http_write_resp_hds(data, buf, blen, &consumed, done);
if(result)
goto out;
*pconsumed += consumed;
buf += consumed;
blen -= consumed;
@ -807,26 +823,41 @@ static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data,
rtspc->in_header = FALSE;
if(!rtspc->in_header) {
/* If header parsing is done and data left, extract RTP messages */
in_body = (data->req.headerline && !rtspc->in_header) &&
(data->req.size >= 0) &&
(data->req.bytecount < data->req.size);
result = rtsp_filter_rtp(data, conn, buf, blen, in_body, &consumed);
/* If header parsing is done, extract interleaved RTP messages */
if(data->req.size <= -1) {
/* Respect section 4.4 of rfc2326: If the Content-Length header is
absent, a length 0 must be assumed. */
data->req.size = 0;
data->req.download_done = TRUE;
}
result = rtsp_filter_rtp(data, buf, blen, &consumed);
if(result)
goto out;
*pconsumed += consumed;
blen -= consumed;
}
}
if(rtspc->state != RTP_PARSE_SKIP)
*readmore = TRUE;
*done = FALSE;
/* we SHOULD have consumed all bytes, unless the response is borked.
* In which case we write out the left over bytes, letting the client
* writer deal with it (it will report EXCESS and fail the transfer). */
DEBUGF(infof(data, "rtsp_rtp_write_resp(len=%zu, in_header=%d, done=%d "
" rtspc->state=%d, req.size=%" CURL_FORMAT_CURL_OFF_T ")",
blen, rtspc->in_header, *done, rtspc->state, data->req.size));
if(!result && (is_eos || blen)) {
result = Curl_client_write(data, CLIENTWRITE_BODY|
(is_eos? CLIENTWRITE_EOS:0),
(char *)buf, blen);
}
out:
if(!*readmore && data->set.rtspreq == RTSPREQ_RECEIVE) {
if((data->set.rtspreq == RTSPREQ_RECEIVE) &&
(rtspc->state == RTP_PARSE_SKIP)) {
/* In special mode RECEIVE, we just process one chunk of network
* data, so we stop the transfer here, if we have no incomplete
* RTP message pending. */
data->req.keepon &= ~KEEP_RECV;
data->req.download_done = TRUE;
}
return result;
}
@ -922,7 +953,7 @@ CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header)
/* If the Session ID is set, then compare */
if(strlen(data->set.str[STRING_RTSP_SESSION_ID]) != idlen ||
strncmp(start, data->set.str[STRING_RTSP_SESSION_ID], idlen) != 0) {
strncmp(start, data->set.str[STRING_RTSP_SESSION_ID], idlen)) {
failf(data, "Got RTSP Session ID Line [%s], but wanted ID [%s]",
start, data->set.str[STRING_RTSP_SESSION_ID]);
return CURLE_RTSP_SESSION_ERROR;
@ -934,11 +965,9 @@ CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header)
*/
/* Copy the id substring into a new buffer */
data->set.str[STRING_RTSP_SESSION_ID] = malloc(idlen + 1);
data->set.str[STRING_RTSP_SESSION_ID] = Curl_memdup0(start, idlen);
if(!data->set.str[STRING_RTSP_SESSION_ID])
return CURLE_OUT_OF_MEMORY;
memcpy(data->set.str[STRING_RTSP_SESSION_ID], start, idlen);
(data->set.str[STRING_RTSP_SESSION_ID])[idlen] = '\0';
}
}
else if(checkprefix("Transport:", header)) {

View File

@ -296,13 +296,6 @@ static CURLcode chop_write(struct Curl_easy *data,
if(!skip_body_write &&
((type & CLIENTWRITE_BODY) ||
((type & CLIENTWRITE_HEADER) && data->set.include_header))) {
#ifdef USE_WEBSOCKETS
if(conn->handler->protocol & (CURLPROTO_WS|CURLPROTO_WSS)) {
writebody = Curl_ws_writecb;
writebody_ptr = data;
}
else
#endif
writebody = data->set.fwrite_func;
}
if((type & (CLIENTWRITE_HEADER|CLIENTWRITE_INFO)) &&
@ -345,7 +338,7 @@ static CURLcode chop_write(struct Curl_easy *data,
len -= chunklen;
}
#ifndef CURL_DISABLE_HTTP
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_HEADERS_API)
/* HTTP header, but not status-line */
if((conn->handler->protocol & PROTO_FAMILY_HTTP) &&
(type & CLIENTWRITE_HEADER) && !(type & CLIENTWRITE_STATUS) ) {
@ -404,10 +397,12 @@ CURLcode Curl_client_write(struct Curl_easy *data,
#endif
/* it is one of those, at least */
DEBUGASSERT(type & (CLIENTWRITE_BODY|CLIENTWRITE_HEADER|CLIENTWRITE_INFO));
/* BODY is only BODY */
DEBUGASSERT(!(type & CLIENTWRITE_BODY) || (type == CLIENTWRITE_BODY));
/* INFO is only INFO */
DEBUGASSERT(!(type & CLIENTWRITE_INFO) || (type == CLIENTWRITE_INFO));
/* BODY is only BODY (with optional EOS) */
DEBUGASSERT(!(type & CLIENTWRITE_BODY) ||
((type & ~(CLIENTWRITE_BODY|CLIENTWRITE_EOS)) == 0));
/* INFO is only INFO (with optional EOS) */
DEBUGASSERT(!(type & CLIENTWRITE_INFO) ||
((type & ~(CLIENTWRITE_INFO|CLIENTWRITE_EOS)) == 0));
if(!data->req.writer_stack) {
result = do_init_stack(data);
@ -477,8 +472,6 @@ CURLcode Curl_cwriter_write(struct Curl_easy *data,
struct Curl_cwriter *writer, int type,
const char *buf, size_t nbytes)
{
if(!nbytes)
return CURLE_OK;
if(!writer)
return CURLE_WRITE_ERROR;
return writer->cwt->do_write(data, writer, type, buf, nbytes);
@ -556,7 +549,6 @@ static CURLcode cw_download_write(struct Curl_easy *data,
{
CURLcode result;
size_t nwrite, excess_len = 0;
const char *excess_data = NULL;
if(!(type & CLIENTWRITE_BODY)) {
if((type & CLIENTWRITE_CONNECT) && data->set.suppress_connect_headers)
@ -564,13 +556,38 @@ static CURLcode cw_download_write(struct Curl_easy *data,
return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
}
if(!data->req.bytecount) {
Curl_pgrsTime(data, TIMER_STARTTRANSFER);
if(data->req.exp100 > EXP100_SEND_DATA)
/* set time stamp to compare with when waiting for the 100 */
data->req.start100 = Curl_now();
}
/* Here, we deal with REAL BODY bytes. All filtering and transfer
* encodings have been applied and only the true content, e.g. BODY,
* bytes are passed here.
* This allows us to check sizes, update stats, etc. independent
* from the protocol in play. */
if(data->req.no_body && nbytes > 0) {
/* BODY arrives although we want none, bail out */
streamclose(data->conn, "ignoring body");
DEBUGF(infof(data, "did not want a BODY, but seeing %zu bytes",
nbytes));
data->req.download_done = TRUE;
return CURLE_WEIRD_SERVER_REPLY;
}
/* Determine if we see any bytes in excess to what is allowed.
* We write the allowed bytes and handle excess further below.
* This gives deterministic BODY writes on varying buffer receive
* lengths. */
nwrite = nbytes;
if(-1 != data->req.maxdownload) {
size_t wmax = get_max_body_write_len(data, data->req.maxdownload);
if(nwrite > wmax) {
excess_len = nbytes - wmax;
nwrite = wmax;
excess_data = buf + nwrite;
}
if(nwrite == wmax) {
@ -578,6 +595,8 @@ static CURLcode cw_download_write(struct Curl_easy *data,
}
}
/* Error on too large filesize is handled below, after writing
* the permitted bytes */
if(data->set.max_filesize) {
size_t wmax = get_max_body_write_len(data, data->set.max_filesize);
if(nwrite > wmax) {
@ -585,6 +604,7 @@ static CURLcode cw_download_write(struct Curl_easy *data,
}
}
/* Update stats, write and report progress */
data->req.bytecount += nwrite;
++data->req.bodywrites;
if(!data->req.ignorebody && nwrite) {
@ -597,23 +617,7 @@ static CURLcode cw_download_write(struct Curl_easy *data,
return result;
if(excess_len) {
if(data->conn->handler->readwrite) {
/* RTSP hack moved from transfer loop to here */
bool readmore = FALSE; /* indicates data is incomplete, need more */
size_t consumed = 0;
result = data->conn->handler->readwrite(data, data->conn,
excess_data, excess_len,
&consumed, &readmore);
if(result)
return result;
DEBUGASSERT(consumed <= excess_len);
excess_len -= consumed;
if(readmore) {
data->req.download_done = FALSE;
data->req.keepon |= KEEP_RECV; /* we're not done reading */
}
}
if(excess_len && !data->req.ignorebody) {
if(!data->req.ignorebody) {
infof(data,
"Excess found writing body:"
" excess = %zu"
@ -762,6 +766,21 @@ CURLcode Curl_cwriter_add(struct Curl_easy *data,
return CURLE_OK;
}
void Curl_cwriter_remove_by_name(struct Curl_easy *data,
const char *name)
{
struct Curl_cwriter **anchor = &data->req.writer_stack;
while(*anchor) {
if(!strcmp(name, (*anchor)->cwt->name)) {
struct Curl_cwriter *w = (*anchor);
*anchor = w->next;
Curl_cwriter_free(data, w);
continue;
}
anchor = &((*anchor)->next);
}
}
/*
* Internal read-from-socket function. This is meant to deal with plain

View File

@ -49,6 +49,7 @@
#define CLIENTWRITE_CONNECT (1<<4) /* a CONNECT related HEADER */
#define CLIENTWRITE_1XX (1<<5) /* a 1xx response related HEADER */
#define CLIENTWRITE_TRAILER (1<<6) /* a trailer HEADER */
#define CLIENTWRITE_EOS (1<<7) /* End Of transfer download Stream */
/**
* Write `len` bytes at `prt` to the client. `type` indicates what
@ -147,6 +148,9 @@ size_t Curl_cwriter_count(struct Curl_easy *data, Curl_cwriter_phase phase);
CURLcode Curl_cwriter_add(struct Curl_easy *data,
struct Curl_cwriter *writer);
void Curl_cwriter_remove_by_name(struct Curl_easy *data,
const char *name);
/**
* Convenience method for calling `writer->do_write()` that
* checks for NULL writer.

View File

@ -51,7 +51,7 @@
#include "altsvc.h"
#include "hsts.h"
#include "tftp.h"
#include "strdup.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
@ -366,6 +366,17 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
else
return CURLE_BAD_FUNCTION_ARGUMENT;
break;
case CURLOPT_SERVER_RESPONSE_TIMEOUT_MS:
/*
* Option that specifies how quickly a server response must be obtained
* before it is considered failure. For pingpong protocols.
*/
arg = va_arg(param, long);
if((arg >= 0) && (arg <= INT_MAX))
data->set.server_response_timeout = (unsigned int)arg;
else
return CURLE_BAD_FUNCTION_ARGUMENT;
break;
#ifndef CURL_DISABLE_TFTP
case CURLOPT_TFTP_NO_OPTIONS:
/*
@ -497,26 +508,17 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
(data->set.postfieldsize > (curl_off_t)((size_t)-1))))
result = CURLE_OUT_OF_MEMORY;
else {
char *p;
(void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
/* Allocate even when size == 0. This satisfies the need of possible
later address compare to detect the COPYPOSTFIELDS mode, and
to mark that postfields is used rather than read function or
form data.
later address compare to detect the COPYPOSTFIELDS mode, and to
mark that postfields is used rather than read function or form
data.
*/
p = malloc((size_t)(data->set.postfieldsize?
data->set.postfieldsize:1));
char *p = Curl_memdup0(argptr, (size_t)data->set.postfieldsize);
(void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
if(!p)
result = CURLE_OUT_OF_MEMORY;
else {
if(data->set.postfieldsize)
memcpy(p, argptr, (size_t)data->set.postfieldsize);
else
data->set.str[STRING_COPYPOSTFIELDS] = p;
}
}
}
@ -670,6 +672,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
data->set.opt_no_body = FALSE; /* this is implied */
Curl_mime_cleanpart(data->state.formp);
Curl_safefree(data->state.formp);
data->state.mimepost = NULL;
break;
#endif
@ -977,6 +980,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
#ifndef CURL_DISABLE_FORM_API
Curl_mime_cleanpart(data->state.formp);
Curl_safefree(data->state.formp);
data->state.mimepost = NULL;
#endif
}
break;
@ -3109,6 +3113,10 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
return CURLE_OUT_OF_MEMORY;
}
arg = va_arg(param, long);
if(!arg) {
DEBUGF(infof(data, "bad CURLOPT_ALTSVC_CTRL input"));
return CURLE_BAD_FUNCTION_ARGUMENT;
}
result = Curl_altsvc_ctrl(data->asi, arg);
if(result)
return result;
@ -3163,5 +3171,9 @@ CURLcode curl_easy_setopt(struct Curl_easy *data, CURLoption tag, ...)
result = Curl_vsetopt(data, tag, arg);
va_end(arg);
#ifdef DEBUGBUILD
if(result == CURLE_BAD_FUNCTION_ARGUMENT)
infof(data, "setopt arg 0x%x returned CURLE_BAD_FUNCTION_ARGUMENT", tag);
#endif
return result;
}

View File

@ -24,18 +24,53 @@
*
***************************************************************************/
#undef USE_WINSOCK
/* ---------------------------------------------------------------- */
/* Watt-32 TCP/IP SPECIFIC */
/* ---------------------------------------------------------------- */
#ifdef USE_WATT32
# include <tcp.h>
# undef byte
# undef word
# define HAVE_SYS_IOCTL_H
# define HAVE_SYS_SOCKET_H
# define HAVE_NETINET_IN_H
# define HAVE_NETDB_H
# define HAVE_ARPA_INET_H
# define SOCKET int
/* ---------------------------------------------------------------- */
/* BSD-style lwIP TCP/IP stack SPECIFIC */
/* ---------------------------------------------------------------- */
#elif defined(USE_LWIPSOCK)
/* Define to use BSD-style lwIP TCP/IP stack. */
/* #define USE_LWIPSOCK 1 */
# undef HAVE_GETHOSTNAME
# undef LWIP_POSIX_SOCKETS_IO_NAMES
# undef RECV_TYPE_ARG1
# undef RECV_TYPE_ARG3
# undef SEND_TYPE_ARG1
# undef SEND_TYPE_ARG3
# define HAVE_GETHOSTBYNAME_R
# define HAVE_GETHOSTBYNAME_R_6
# define LWIP_POSIX_SOCKETS_IO_NAMES 0
# define RECV_TYPE_ARG1 int
# define RECV_TYPE_ARG3 size_t
# define SEND_TYPE_ARG1 int
# define SEND_TYPE_ARG3 size_t
#elif defined(_WIN32)
# define USE_WINSOCK 2
#endif
/*
* Include header files for windows builds before redefining anything.
* Use this preprocessor block only to include or exclude windows.h,
* winsock2.h or ws2tcpip.h. Any other windows thing belongs
* to any other further and independent block. Under Cygwin things work
* just as under linux (e.g. <sys/socket.h>) and the winsock headers should
* never be included when __CYGWIN__ is defined. configure script takes
* care of this, not defining HAVE_WINDOWS_H, HAVE_WINSOCK2_H,
* neither HAVE_WS2TCPIP_H when __CYGWIN__ is defined.
* never be included when __CYGWIN__ is defined.
*/
#ifdef HAVE_WINDOWS_H
#ifdef _WIN32
# if defined(UNICODE) && !defined(_UNICODE)
# error "UNICODE is defined but _UNICODE is not defined"
# endif
@ -53,12 +88,8 @@
# ifndef NOGDI
# define NOGDI
# endif
# ifdef HAVE_WINSOCK2_H
# include <winsock2.h>
# ifdef HAVE_WS2TCPIP_H
# include <ws2tcpip.h>
# endif
# endif
# include <winsock2.h>
# include <ws2tcpip.h>
# include <windows.h>
# include <winerror.h>
# include <tchar.h>
@ -67,17 +98,6 @@
# endif
#endif
/*
* Define USE_WINSOCK to 2 if we have and use WINSOCK2 API, else
* undefine USE_WINSOCK.
*/
#undef USE_WINSOCK
#ifdef HAVE_WINSOCK2_H
# define USE_WINSOCK 2
#endif
/*
* Define _WIN32_WINNT_[OS] symbols because not all Windows build systems have
* those symbols to compare against, and even those that do may be missing

View File

@ -133,13 +133,13 @@ curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...)
res = CURLSHE_BAD_OPTION;
}
if(!res)
share->specifier |= (1<<type);
share->specifier |= (unsigned int)(1<<type);
break;
case CURLSHOPT_UNSHARE:
/* this is a type this share will no longer share */
type = va_arg(param, int);
share->specifier &= ~(1<<type);
share->specifier &= ~(unsigned int)(1<<type);
switch(type) {
case CURL_LOCK_DATA_DNS:
break;
@ -264,7 +264,7 @@ Curl_share_lock(struct Curl_easy *data, curl_lock_data type,
if(!share)
return CURLSHE_INVALID;
if(share->specifier & (1<<type)) {
if(share->specifier & (unsigned int)(1<<type)) {
if(share->lockfunc) /* only call this if set! */
share->lockfunc(data, type, accesstype, share->clientdata);
}
@ -281,7 +281,7 @@ Curl_share_unlock(struct Curl_easy *data, curl_lock_data type)
if(!share)
return CURLSHE_INVALID;
if(share->specifier & (1<<type)) {
if(share->specifier & (unsigned int)(1<<type)) {
if(share->unlockfunc) /* only call this if set! */
share->unlockfunc (data, type, share->clientdata);
}

View File

@ -272,7 +272,7 @@ const struct Curl_handler Curl_handler_smb = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
smb_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_SMB, /* defport */
@ -299,7 +299,7 @@ const struct Curl_handler Curl_handler_smbs = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
smb_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_SMBS, /* defport */

View File

@ -130,7 +130,7 @@ const struct Curl_handler Curl_handler_smtp = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
smtp_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_SMTP, /* defport */
@ -159,7 +159,7 @@ const struct Curl_handler Curl_handler_smtps = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
smtp_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_SMTPS, /* defport */
@ -250,8 +250,8 @@ static bool smtp_endofresp(struct Curl_easy *data, struct connectdata *conn,
*/
static CURLcode smtp_get_message(struct Curl_easy *data, struct bufref *out)
{
char *message = data->state.buffer;
size_t len = strlen(message);
char *message = Curl_dyn_ptr(&data->conn->proto.smtpc.pp.recvbuf);
size_t len = data->conn->proto.smtpc.pp.nfinal;
if(len > 4) {
/* Find the start of the message */
@ -859,7 +859,7 @@ static CURLcode smtp_state_starttls_resp(struct Curl_easy *data,
(void)instate; /* no use for this yet */
/* Pipelining in response is forbidden. */
if(data->conn->proto.smtpc.pp.cache_size)
if(data->conn->proto.smtpc.pp.overflow)
return CURLE_WEIRD_SERVER_REPLY;
if(smtpcode != 220) {
@ -883,8 +883,8 @@ static CURLcode smtp_state_ehlo_resp(struct Curl_easy *data,
{
CURLcode result = CURLE_OK;
struct smtp_conn *smtpc = &conn->proto.smtpc;
const char *line = data->state.buffer;
size_t len = strlen(line);
const char *line = Curl_dyn_ptr(&smtpc->pp.recvbuf);
size_t len = smtpc->pp.nfinal;
(void)instate; /* no use for this yet */
@ -1033,8 +1033,8 @@ static CURLcode smtp_state_command_resp(struct Curl_easy *data, int smtpcode,
{
CURLcode result = CURLE_OK;
struct SMTP *smtp = data->req.p.smtp;
char *line = data->state.buffer;
size_t len = strlen(line);
char *line = Curl_dyn_ptr(&data->conn->proto.smtpc.pp.recvbuf);
size_t len = data->conn->proto.smtpc.pp.nfinal;
(void)instate; /* no use for this yet */
@ -1044,12 +1044,8 @@ static CURLcode smtp_state_command_resp(struct Curl_easy *data, int smtpcode,
result = CURLE_WEIRD_SERVER_REPLY;
}
else {
/* Temporarily add the LF character back and send as body to the client */
if(!data->req.no_body) {
line[len] = '\n';
result = Curl_client_write(data, CLIENTWRITE_BODY, line, len + 1);
line[len] = '\0';
}
if(!data->req.no_body)
result = Curl_client_write(data, CLIENTWRITE_BODY, line, len);
if(smtpcode != 1) {
if(smtp->rcpt) {
@ -1268,7 +1264,6 @@ static CURLcode smtp_statemachine(struct Curl_easy *data,
break;
case SMTP_QUIT:
/* fallthrough, just stop! */
default:
/* internal error */
smtp_state(data, SMTP_STOP);
@ -1362,8 +1357,7 @@ static CURLcode smtp_connect(struct Curl_easy *data, bool *done)
Curl_sasl_init(&smtpc->sasl, data, &saslsmtp);
/* Initialise the pingpong layer */
Curl_pp_setup(pp);
Curl_pp_init(data, pp);
Curl_pp_init(pp);
/* Parse the URL options */
result = smtp_parse_url_options(conn);
@ -1541,6 +1535,8 @@ static CURLcode smtp_perform(struct Curl_easy *data, bool *connected,
static CURLcode smtp_do(struct Curl_easy *data, bool *done)
{
CURLcode result = CURLE_OK;
DEBUGASSERT(data);
DEBUGASSERT(data->conn);
*done = FALSE; /* default to false */
/* Parse the custom request */

View File

@ -33,9 +33,6 @@
* This is a socketpair() implementation for Windows.
*/
#include <string.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#include <io.h>
#else
#ifdef HAVE_NETDB_H

View File

@ -71,9 +71,18 @@ enum connect_t {
CONNECT_DONE /* 17 connected fine to the remote or the SOCKS proxy */
};
#define CURL_SOCKS_BUF_SIZE 600
/* make sure we configure it not too low */
#if CURL_SOCKS_BUF_SIZE < 600
#error CURL_SOCKS_BUF_SIZE must be at least 600
#endif
struct socks_state {
enum connect_t state;
ssize_t outstanding; /* send this many bytes more */
unsigned char buffer[CURL_SOCKS_BUF_SIZE];
unsigned char *outp; /* send from this pointer */
const char *hostname;
@ -249,7 +258,7 @@ static CURLproxycode socks_state_recv(struct Curl_cfilter *cf,
failf(data, "connection to proxy closed");
return CURLPX_CLOSED;
}
failf(data, "SOCKS4: Failed receiving %s: %s", description,
failf(data, "SOCKS: Failed receiving %s: %s", description,
curl_easy_strerror(result));
return failcode;
}
@ -278,14 +287,11 @@ static CURLproxycode do_SOCKS4(struct Curl_cfilter *cf,
struct connectdata *conn = cf->conn;
const bool protocol4a =
(conn->socks_proxy.proxytype == CURLPROXY_SOCKS4A) ? TRUE : FALSE;
unsigned char *socksreq = (unsigned char *)data->state.buffer;
unsigned char *socksreq = sx->buffer;
CURLcode result;
CURLproxycode presult;
struct Curl_dns_entry *dns = NULL;
/* make sure that the buffer is at least 600 bytes */
DEBUGASSERT(READBUFFER_MIN >= 600);
switch(sx->state) {
case CONNECT_SOCKS_INIT:
/* SOCKS4 can only do IPv4, insist! */
@ -339,8 +345,8 @@ static CURLproxycode do_SOCKS4(struct Curl_cfilter *cf,
if(dns) {
#ifdef CURLRES_ASYNCH
conn->resolve_async.dns = dns;
conn->resolve_async.done = TRUE;
data->state.async.dns = dns;
data->state.async.done = TRUE;
#endif
infof(data, "Hostname '%s' was found", sx->hostname);
sxstate(sx, data, CONNECT_RESOLVED);
@ -353,9 +359,10 @@ static CURLproxycode do_SOCKS4(struct Curl_cfilter *cf,
return CURLPX_OK;
}
}
/* FALLTHROUGH */
FALLTHROUGH();
case CONNECT_RESOLVED:
CONNECT_RESOLVED:
case CONNECT_RESOLVED: {
{
struct Curl_addrinfo *hp = NULL;
/*
* We cannot use 'hostent' as a struct that Curl_resolv() returns. It
@ -393,9 +400,9 @@ CONNECT_RESOLVED:
if(!hp)
return CURLPX_RESOLVE_HOST;
}
/* FALLTHROUGH */
CONNECT_REQ_INIT:
FALLTHROUGH();
case CONNECT_REQ_INIT:
CONNECT_REQ_INIT:
/*
* This is currently not supporting "Identification Protocol (RFC1413)".
*/
@ -430,7 +437,7 @@ CONNECT_REQ_INIT:
/* append hostname */
hostnamelen = strlen(sx->hostname) + 1; /* length including NUL */
if((hostnamelen <= 255) &&
(packetsize + hostnamelen < data->set.buffer_size))
(packetsize + hostnamelen < sizeof(sx->buffer)))
strcpy((char *)socksreq + packetsize, sx->hostname);
else {
failf(data, "SOCKS4: too long host name");
@ -439,10 +446,11 @@ CONNECT_REQ_INIT:
packetsize += hostnamelen;
}
sx->outp = socksreq;
DEBUGASSERT(packetsize <= sizeof(sx->buffer));
sx->outstanding = packetsize;
sxstate(sx, data, CONNECT_REQ_SENDING);
}
/* FALLTHROUGH */
FALLTHROUGH();
case CONNECT_REQ_SENDING:
/* Send request */
presult = socks_state_send(cf, sx, data, CURLPX_SEND_CONNECT,
@ -458,7 +466,7 @@ CONNECT_REQ_INIT:
sx->outp = socksreq;
sxstate(sx, data, CONNECT_SOCKS_READ);
/* FALLTHROUGH */
FALLTHROUGH();
case CONNECT_SOCKS_READ:
/* Receive response */
presult = socks_state_recv(cf, sx, data, CURLPX_RECV_CONNECT,
@ -570,14 +578,14 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf,
o X'00' succeeded
*/
struct connectdata *conn = cf->conn;
unsigned char *socksreq = (unsigned char *)data->state.buffer;
int idx;
unsigned char *socksreq = sx->buffer;
size_t idx;
CURLcode result;
CURLproxycode presult;
bool socks5_resolve_local =
(conn->socks_proxy.proxytype == CURLPROXY_SOCKS5) ? TRUE : FALSE;
const size_t hostname_len = strlen(sx->hostname);
ssize_t len = 0;
size_t len = 0;
const unsigned char auth = data->set.socks5auth;
bool allow_gssapi = FALSE;
struct Curl_dns_entry *dns = NULL;
@ -620,6 +628,7 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf,
socksreq[1] = (unsigned char) (idx - 2);
sx->outp = socksreq;
DEBUGASSERT(idx <= sizeof(sx->buffer));
sx->outstanding = idx;
presult = socks_state_send(cf, sx, data, CURLPX_SEND_CONNECT,
"initial SOCKS5 request");
@ -640,12 +649,12 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf,
/* remain in sending state */
return CURLPX_OK;
}
/* FALLTHROUGH */
CONNECT_SOCKS_READ_INIT:
FALLTHROUGH();
case CONNECT_SOCKS_READ_INIT:
CONNECT_SOCKS_READ_INIT:
sx->outstanding = 2; /* expect two bytes */
sx->outp = socksreq; /* store it here */
/* FALLTHROUGH */
FALLTHROUGH();
case CONNECT_SOCKS_READ:
presult = socks_state_recv(cf, sx, data, CURLPX_RECV_CONNECT,
"initial SOCKS5 response");
@ -746,10 +755,11 @@ CONNECT_AUTH_INIT:
}
len += proxy_password_len;
sxstate(sx, data, CONNECT_AUTH_SEND);
DEBUGASSERT(len <= sizeof(sx->buffer));
sx->outstanding = len;
sx->outp = socksreq;
}
/* FALLTHROUGH */
FALLTHROUGH();
case CONNECT_AUTH_SEND:
presult = socks_state_send(cf, sx, data, CURLPX_SEND_AUTH,
"SOCKS5 sub-negotiation request");
@ -762,7 +772,7 @@ CONNECT_AUTH_INIT:
sx->outp = socksreq;
sx->outstanding = 2;
sxstate(sx, data, CONNECT_AUTH_READ);
/* FALLTHROUGH */
FALLTHROUGH();
case CONNECT_AUTH_READ:
presult = socks_state_recv(cf, sx, data, CURLPX_RECV_AUTH,
"SOCKS5 sub-negotiation response");
@ -781,9 +791,9 @@ CONNECT_AUTH_INIT:
/* Everything is good so far, user was authenticated! */
sxstate(sx, data, CONNECT_REQ_INIT);
/* FALLTHROUGH */
CONNECT_REQ_INIT:
FALLTHROUGH();
case CONNECT_REQ_INIT:
CONNECT_REQ_INIT:
if(socks5_resolve_local) {
enum resolve_t rc = Curl_resolv(data, sx->hostname, sx->remote_port,
TRUE, &dns);
@ -806,8 +816,8 @@ CONNECT_REQ_INIT:
if(dns) {
#ifdef CURLRES_ASYNCH
conn->resolve_async.dns = dns;
conn->resolve_async.done = TRUE;
data->state.async.dns = dns;
data->state.async.done = TRUE;
#endif
infof(data, "SOCKS5: hostname '%s' found", sx->hostname);
}
@ -820,9 +830,10 @@ CONNECT_REQ_INIT:
return CURLPX_OK;
}
}
/* FALLTHROUGH */
FALLTHROUGH();
case CONNECT_RESOLVED:
CONNECT_RESOLVED:
case CONNECT_RESOLVED: {
{
char dest[MAX_IPADR_LEN]; /* printable address */
struct Curl_addrinfo *hp = NULL;
if(dns)
@ -923,10 +934,10 @@ CONNECT_RESOLVE_REMOTE:
infof(data, "SOCKS5 connect to %s:%d (remotely resolved)",
sx->hostname, sx->remote_port);
}
/* FALLTHROUGH */
FALLTHROUGH();
CONNECT_REQ_SEND:
case CONNECT_REQ_SEND:
CONNECT_REQ_SEND:
/* PORT MSB */
socksreq[len++] = (unsigned char)((sx->remote_port >> 8) & 0xff);
/* PORT LSB */
@ -939,9 +950,10 @@ CONNECT_REQ_SEND:
}
#endif
sx->outp = socksreq;
DEBUGASSERT(len <= sizeof(sx->buffer));
sx->outstanding = len;
sxstate(sx, data, CONNECT_REQ_SENDING);
/* FALLTHROUGH */
FALLTHROUGH();
case CONNECT_REQ_SENDING:
presult = socks_state_send(cf, sx, data, CURLPX_SEND_REQUEST,
"SOCKS5 connect request");
@ -960,7 +972,7 @@ CONNECT_REQ_SEND:
sx->outstanding = 10; /* minimum packet size is 10 */
sx->outp = socksreq;
sxstate(sx, data, CONNECT_REQ_READ);
/* FALLTHROUGH */
FALLTHROUGH();
case CONNECT_REQ_READ:
presult = socks_state_recv(cf, sx, data, CURLPX_RECV_REQACK,
"SOCKS5 connect request ack");
@ -1038,6 +1050,7 @@ CONNECT_REQ_SEND:
/* decrypt_gssapi_blockread already read the whole packet */
#endif
if(len > 10) {
DEBUGASSERT(len <= sizeof(sx->buffer));
sx->outstanding = len - 10; /* get the rest */
sx->outp = &socksreq[10];
sxstate(sx, data, CONNECT_REQ_READ_MORE);
@ -1049,7 +1062,7 @@ CONNECT_REQ_SEND:
#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
}
#endif
/* FALLTHROUGH */
FALLTHROUGH();
case CONNECT_REQ_READ_MORE:
presult = socks_state_recv(cf, sx, data, CURLPX_RECV_ADDRESS,
"SOCKS5 connect request address");

View File

@ -35,6 +35,7 @@
#include "timeval.h"
#include "socks.h"
#include "warnless.h"
#include "strdup.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@ -139,10 +140,9 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
/* prepare service name */
if(strchr(serviceptr, '/')) {
service.length = serviceptr_length;
service.value = malloc(service.length);
service.value = Curl_memdup(serviceptr, service.length);
if(!service.value)
return CURLE_OUT_OF_MEMORY;
memcpy(service.value, serviceptr, service.length);
gss_major_status = gss_import_name(&gss_minor_status, &service,
(gss_OID) GSS_C_NULL_OID, &server);
@ -387,12 +387,11 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
}
else {
gss_send_token.length = 1;
gss_send_token.value = malloc(1);
gss_send_token.value = Curl_memdup(&gss_enc, 1);
if(!gss_send_token.value) {
gss_delete_sec_context(&gss_status, &gss_context, NULL);
return CURLE_OUT_OF_MEMORY;
}
memcpy(gss_send_token.value, &gss_enc, 1);
gss_major_status = gss_wrap(&gss_minor_status, gss_context, 0,
GSS_C_QOP_DEFAULT, &gss_send_token,

View File

@ -331,9 +331,15 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
failf(data, "Failed to determine user name.");
return CURLE_COULDNT_CONNECT;
}
infof(data, "SOCKS5 server authenticated user %s with GSS-API.",
names.sUserName);
s_pSecFn->FreeContextBuffer(names.sUserName);
else {
#ifndef CURL_DISABLE_VERBOSE_STRINGS
char *user_utf8 = curlx_convert_tchar_to_UTF8(names.sUserName);
infof(data, "SOCKS5 server authenticated user %s with GSS-API.",
(user_utf8 ? user_utf8 : "(unknown)"));
curlx_unicodefree(user_utf8);
#endif
s_pSecFn->FreeContextBuffer(names.sUserName);
}
/* Do encryption */
socksreq[0] = 1; /* GSS-API subnegotiation version */

View File

@ -101,21 +101,17 @@ void *Curl_memdup(const void *src, size_t length)
/***************************************************************************
*
* Curl_strndup(source, length)
* Curl_memdup0(source, length)
*
* Copies the 'source' string to a newly allocated buffer (that is returned).
* Copies not more than 'length' bytes (up to a null terminator) then adds a
* null terminator.
* Copies 'length' bytes then adds a null terminator.
*
* Returns the new pointer or NULL on failure.
*
***************************************************************************/
void *Curl_strndup(const char *src, size_t length)
void *Curl_memdup0(const char *src, size_t length)
{
char *buf = memchr(src, '\0', length);
if(buf)
length = buf - src;
buf = malloc(length + 1);
char *buf = malloc(length + 1);
if(!buf)
return NULL;
memcpy(buf, src, length);

View File

@ -33,6 +33,6 @@ wchar_t* Curl_wcsdup(const wchar_t* src);
#endif
void *Curl_memdup(const void *src, size_t buffer_length);
void *Curl_saferealloc(void *ptr, size_t size);
void *Curl_strndup(const char *src, size_t length);
void *Curl_memdup0(const char *src, size_t length);
#endif /* HEADER_CURL_STRDUP_H */

View File

@ -319,6 +319,9 @@ curl_easy_strerror(CURLcode error)
case CURLE_UNRECOVERABLE_POLL:
return "Unrecoverable error in select/poll";
case CURLE_TOO_LARGE:
return "A value or data field grew larger than allowed";
/* error codes not used by current libcurl */
case CURLE_OBSOLETE20:
case CURLE_OBSOLETE24:
@ -553,6 +556,9 @@ curl_url_strerror(CURLUcode error)
case CURLUE_LACKS_IDN:
return "libcurl lacks IDN support";
case CURLUE_TOO_LARGE:
return "A value or data field is larger than allowed";
case CURLUE_LAST:
break;
}
@ -572,10 +578,11 @@ curl_url_strerror(CURLUcode error)
* Returns NULL if no error message was found for error code.
*/
static const char *
get_winsock_error (int err, char *buf, size_t len)
get_winsock_error(int err, char *buf, size_t len)
{
#ifndef CURL_DISABLE_VERBOSE_STRINGS
const char *p;
size_t alen;
#endif
if(!len)
@ -755,8 +762,9 @@ get_winsock_error (int err, char *buf, size_t len)
default:
return NULL;
}
strncpy(buf, p, len);
buf [len-1] = '\0';
alen = strlen(p);
if(alen < len)
strcpy(buf, p);
return buf;
#endif
}
@ -832,7 +840,6 @@ const char *Curl_strerror(int err, char *buf, size_t buflen)
#endif
int old_errno = errno;
char *p;
size_t max;
if(!buflen)
return NULL;
@ -841,23 +848,22 @@ const char *Curl_strerror(int err, char *buf, size_t buflen)
DEBUGASSERT(err >= 0);
#endif
max = buflen - 1;
*buf = '\0';
#if defined(_WIN32) || defined(_WIN32_WCE)
#if defined(_WIN32)
/* 'sys_nerr' is the maximum errno number, it is not widely portable */
if(err >= 0 && err < sys_nerr)
strncpy(buf, sys_errlist[err], max);
msnprintf(buf, buflen, "%s", sys_errlist[err]);
else
#endif
{
if(
#ifdef USE_WINSOCK
!get_winsock_error(err, buf, max) &&
!get_winsock_error(err, buf, buflen) &&
#endif
!get_winapi_error((DWORD)err, buf, max))
msnprintf(buf, max, "Unknown error %d (%#x)", err, err);
!get_winapi_error((DWORD)err, buf, buflen))
msnprintf(buf, buflen, "Unknown error %d (%#x)", err, err);
}
#else /* not Windows coming up */
@ -867,9 +873,9 @@ const char *Curl_strerror(int err, char *buf, size_t buflen)
* storage is supplied via 'strerrbuf' and 'buflen' to hold the generated
* message string, or EINVAL if 'errnum' is not a valid error number.
*/
if(0 != strerror_r(err, buf, max)) {
if(0 != strerror_r(err, buf, buflen)) {
if('\0' == buf[0])
msnprintf(buf, max, "Unknown error %d", err);
msnprintf(buf, buflen, "Unknown error %d", err);
}
#elif defined(HAVE_STRERROR_R) && defined(HAVE_GLIBC_STRERROR_R)
/*
@ -881,25 +887,23 @@ const char *Curl_strerror(int err, char *buf, size_t buflen)
char buffer[256];
char *msg = strerror_r(err, buffer, sizeof(buffer));
if(msg)
strncpy(buf, msg, max);
msnprintf(buf, buflen, "%s", msg);
else
msnprintf(buf, max, "Unknown error %d", err);
msnprintf(buf, buflen, "Unknown error %d", err);
}
#else
{
/* !checksrc! disable STRERROR 1 */
const char *msg = strerror(err);
if(msg)
strncpy(buf, msg, max);
msnprintf(buf, buflen, "%s", msg);
else
msnprintf(buf, max, "Unknown error %d", err);
msnprintf(buf, buflen, "Unknown error %d", err);
}
#endif
#endif /* end of not Windows */
buf[max] = '\0'; /* make sure the string is null-terminated */
/* strip trailing '\r\n' or '\n'. */
p = strrchr(buf, '\n');
if(p && (p - buf) >= 2)
@ -943,8 +947,8 @@ const char *Curl_winapi_strerror(DWORD err, char *buf, size_t buflen)
#else
{
const char *txt = (err == ERROR_SUCCESS) ? "No error" : "Error";
strncpy(buf, txt, buflen);
buf[buflen - 1] = '\0';
if(strlen(txt) < buflen)
strcpy(buf, txt);
}
#endif
@ -1081,17 +1085,11 @@ const char *Curl_sspi_strerror(int err, char *buf, size_t buflen)
err);
}
else {
char txtbuf[80];
char msgbuf[256];
msnprintf(txtbuf, sizeof(txtbuf), "%s (0x%08X)", txt, err);
if(get_winapi_error(err, msgbuf, sizeof(msgbuf)))
msnprintf(buf, buflen, "%s - %s", txtbuf, msgbuf);
else {
strncpy(buf, txtbuf, buflen);
buf[buflen - 1] = '\0';
}
msnprintf(buf, buflen, "%s (0x%08X) - %s", txt, err, msgbuf);
else
msnprintf(buf, buflen, "%s (0x%08X)", txt, err);
}
#else
@ -1099,8 +1097,8 @@ const char *Curl_sspi_strerror(int err, char *buf, size_t buflen)
txt = "No error";
else
txt = "Error";
strncpy(buf, txt, buflen);
buf[buflen - 1] = '\0';
if(buflen > strlen(txt))
strcpy(buf, txt);
#endif
if(errno != old_errno)

View File

@ -38,16 +38,23 @@
LARGE_INTEGER Curl_freq;
bool Curl_isVistaOrGreater;
bool Curl_isWindows8OrGreater;
/* Handle of iphlpapp.dll */
static HMODULE s_hIpHlpApiDll = NULL;
/* Pointer to the if_nametoindex function */
/* Function pointers */
IF_NAMETOINDEX_FN Curl_if_nametoindex = NULL;
FREEADDRINFOEXW_FN Curl_FreeAddrInfoExW = NULL;
GETADDRINFOEXCANCEL_FN Curl_GetAddrInfoExCancel = NULL;
GETADDRINFOEXW_FN Curl_GetAddrInfoExW = NULL;
/* Curl_win32_init() performs win32 global initialization */
CURLcode Curl_win32_init(long flags)
{
#ifdef USE_WINSOCK
HMODULE ws2_32Dll;
#endif
/* CURL_GLOBAL_WIN32 controls the *optional* part of the initialization which
is just for Winsock at the moment. Any required win32 initialization
should take place after this block. */
@ -104,6 +111,18 @@ CURLcode Curl_win32_init(long flags)
Curl_if_nametoindex = pIfNameToIndex;
}
#ifdef USE_WINSOCK
ws2_32Dll = GetModuleHandleA("ws2_32");
if(ws2_32Dll) {
Curl_FreeAddrInfoExW = CURLX_FUNCTION_CAST(FREEADDRINFOEXW_FN,
GetProcAddress(ws2_32Dll, "FreeAddrInfoExW"));
Curl_GetAddrInfoExCancel = CURLX_FUNCTION_CAST(GETADDRINFOEXCANCEL_FN,
GetProcAddress(ws2_32Dll, "GetAddrInfoExCancel"));
Curl_GetAddrInfoExW = CURLX_FUNCTION_CAST(GETADDRINFOEXW_FN,
GetProcAddress(ws2_32Dll, "GetAddrInfoExW"));
}
#endif
/* curlx_verify_windows_version must be called during init at least once
because it has its own initialization routine. */
if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT,
@ -113,6 +132,13 @@ CURLcode Curl_win32_init(long flags)
else
Curl_isVistaOrGreater = FALSE;
if(curlx_verify_windows_version(6, 2, 0, PLATFORM_WINNT,
VERSION_GREATER_THAN_EQUAL)) {
Curl_isWindows8OrGreater = TRUE;
}
else
Curl_isWindows8OrGreater = FALSE;
QueryPerformanceFrequency(&Curl_freq);
return CURLE_OK;
}
@ -120,6 +146,9 @@ CURLcode Curl_win32_init(long flags)
/* Curl_win32_cleanup() is the opposite of Curl_win32_init() */
void Curl_win32_cleanup(long init_flags)
{
Curl_FreeAddrInfoExW = NULL;
Curl_GetAddrInfoExCancel = NULL;
Curl_GetAddrInfoExW = NULL;
if(s_hIpHlpApiDll) {
FreeLibrary(s_hIpHlpApiDll);
s_hIpHlpApiDll = NULL;

View File

@ -26,10 +26,11 @@
#include "curl_setup.h"
#if defined(_WIN32)
#ifdef _WIN32
extern LARGE_INTEGER Curl_freq;
extern bool Curl_isVistaOrGreater;
extern bool Curl_isWindows8OrGreater;
CURLcode Curl_win32_init(long flags);
void Curl_win32_cleanup(long init_flags);
@ -40,6 +41,33 @@ typedef unsigned int(WINAPI *IF_NAMETOINDEX_FN)(const char *);
/* This is used instead of if_nametoindex if available on Windows */
extern IF_NAMETOINDEX_FN Curl_if_nametoindex;
/* Identical copy of addrinfoexW/ADDRINFOEXW */
typedef struct addrinfoexW_
{
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
size_t ai_addrlen;
PWSTR ai_canonname;
struct sockaddr *ai_addr;
void *ai_blob;
size_t ai_bloblen;
LPGUID ai_provider;
struct addrinfoexW_ *ai_next;
} ADDRINFOEXW_;
typedef void (CALLBACK *LOOKUP_COMPLETION_FN)(DWORD, DWORD, LPWSAOVERLAPPED);
typedef void (WSAAPI *FREEADDRINFOEXW_FN)(ADDRINFOEXW_*);
typedef int (WSAAPI *GETADDRINFOEXCANCEL_FN)(LPHANDLE);
typedef int (WSAAPI *GETADDRINFOEXW_FN)(PCWSTR, PCWSTR, DWORD, LPGUID,
const ADDRINFOEXW_*, ADDRINFOEXW_**, struct timeval*, LPOVERLAPPED,
LOOKUP_COMPLETION_FN, LPHANDLE);
extern FREEADDRINFOEXW_FN Curl_FreeAddrInfoExW;
extern GETADDRINFOEXCANCEL_FN Curl_GetAddrInfoExCancel;
extern GETADDRINFOEXW_FN Curl_GetAddrInfoExW;
/* This is used to dynamically load DLLs */
HMODULE Curl_load_library(LPCTSTR filename);
#else /* _WIN32 */

View File

@ -160,6 +160,7 @@ struct TELNET {
unsigned short subopt_wsy; /* Set with suboption NAWS */
TelnetReceive telrcv_state;
struct curl_slist *telnet_vars; /* Environment variables */
struct dynbuf out; /* output buffer */
/* suboptions */
unsigned char subbuffer[SUBBUFSIZE];
@ -185,7 +186,7 @@ const struct Curl_handler Curl_handler_telnet = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_TELNET, /* defport */
@ -204,6 +205,7 @@ CURLcode init_telnet(struct Curl_easy *data)
if(!tn)
return CURLE_OUT_OF_MEMORY;
Curl_dyn_init(&tn->out, 0xffff);
data->req.p.telnet = tn; /* make us known */
tn->telrcv_state = CURL_TS_DATA;
@ -799,8 +801,10 @@ static CURLcode check_telnet_options(struct Curl_easy *data)
was given on the command line */
if(data->state.aptr.user) {
char buffer[256];
if(str_is_nonascii(data->conn->user))
if(str_is_nonascii(data->conn->user)) {
DEBUGF(infof(data, "set a non ASCII user name in telnet"));
return CURLE_BAD_FUNCTION_ARGUMENT;
}
msnprintf(buffer, sizeof(buffer), "USER,%s", data->conn->user);
beg = curl_slist_append(tn->telnet_vars, buffer);
if(!beg) {
@ -826,23 +830,27 @@ static CURLcode check_telnet_options(struct Curl_easy *data)
case 5:
/* Terminal type */
if(strncasecompare(option, "TTYPE", 5)) {
strncpy(tn->subopt_ttype, arg, 31);
tn->subopt_ttype[31] = 0; /* String termination */
tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
size_t l = strlen(arg);
if(l < sizeof(tn->subopt_ttype)) {
strcpy(tn->subopt_ttype, arg);
tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
break;
}
}
else
result = CURLE_UNKNOWN_OPTION;
result = CURLE_UNKNOWN_OPTION;
break;
case 8:
/* Display variable */
if(strncasecompare(option, "XDISPLOC", 8)) {
strncpy(tn->subopt_xdisploc, arg, 127);
tn->subopt_xdisploc[127] = 0; /* String termination */
tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
size_t l = strlen(arg);
if(l < sizeof(tn->subopt_xdisploc)) {
strcpy(tn->subopt_xdisploc, arg);
tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
break;
}
}
else
result = CURLE_UNKNOWN_OPTION;
result = CURLE_UNKNOWN_OPTION;
break;
case 7:
@ -1223,37 +1231,33 @@ process_iac:
static CURLcode send_telnet_data(struct Curl_easy *data,
char *buffer, ssize_t nread)
{
ssize_t escapes, i, outlen;
unsigned char *outbuf = NULL;
ssize_t i, outlen;
unsigned char *outbuf;
CURLcode result = CURLE_OK;
ssize_t bytes_written, total_written;
ssize_t bytes_written, total_written = 0;
struct connectdata *conn = data->conn;
struct TELNET *tn = data->req.p.telnet;
/* Determine size of new buffer after escaping */
escapes = 0;
for(i = 0; i < nread; i++)
if((unsigned char)buffer[i] == CURL_IAC)
escapes++;
outlen = nread + escapes;
DEBUGASSERT(tn);
if(outlen == nread)
outbuf = (unsigned char *)buffer;
else {
ssize_t j;
outbuf = malloc(nread + escapes + 1);
if(!outbuf)
return CURLE_OUT_OF_MEMORY;
if(memchr(buffer, CURL_IAC, nread)) {
/* only use the escape buffer when necessary */
Curl_dyn_reset(&tn->out);
j = 0;
for(i = 0; i < nread; i++) {
outbuf[j++] = (unsigned char)buffer[i];
if((unsigned char)buffer[i] == CURL_IAC)
outbuf[j++] = CURL_IAC;
for(i = 0; i < nread && !result; i++) {
result = Curl_dyn_addn(&tn->out, &buffer[i], 1);
if(!result && ((unsigned char)buffer[i] == CURL_IAC))
/* IAC is FF in hex */
result = Curl_dyn_addn(&tn->out, "\xff", 1);
}
outbuf[j] = '\0';
}
total_written = 0;
outlen = Curl_dyn_len(&tn->out);
outbuf = Curl_dyn_uptr(&tn->out);
}
else {
outlen = nread;
outbuf = (unsigned char *)buffer;
}
while(!result && total_written < outlen) {
/* Make sure socket is writable to avoid EWOULDBLOCK condition */
struct pollfd pfd[1];
@ -1266,19 +1270,13 @@ static CURLcode send_telnet_data(struct Curl_easy *data,
break;
default: /* write! */
bytes_written = 0;
result = Curl_nwrite(data, FIRSTSOCKET,
outbuf + total_written,
outlen - total_written,
&bytes_written);
result = Curl_nwrite(data, FIRSTSOCKET, outbuf + total_written,
outlen - total_written, &bytes_written);
total_written += bytes_written;
break;
}
}
/* Free malloc copy if escaped */
if(outbuf != (unsigned char *)buffer)
free(outbuf);
return result;
}
@ -1294,6 +1292,7 @@ static CURLcode telnet_done(struct Curl_easy *data,
curl_slist_free_all(tn->telnet_vars);
tn->telnet_vars = NULL;
Curl_dyn_free(&tn->out);
return CURLE_OK;
}
@ -1321,7 +1320,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
ssize_t nread;
struct curltime now;
bool keepon = TRUE;
char *buf = data->state.buffer;
char buffer[4*1024];
struct TELNET *tn;
*done = TRUE; /* unconditionally */
@ -1378,7 +1377,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
/* Keep on listening and act on events */
while(keepon) {
const DWORD buf_size = (DWORD)data->set.buffer_size;
const DWORD buf_size = (DWORD)sizeof(buffer);
DWORD waitret = WaitForMultipleObjects(obj_count, objs,
FALSE, wait_timeout);
switch(waitret) {
@ -1389,7 +1388,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
if(data->set.is_fread_set) {
size_t n;
/* read from user-supplied method */
n = data->state.fread_func(buf, 1, buf_size, data->state.in);
n = data->state.fread_func(buffer, 1, buf_size, data->state.in);
if(n == CURL_READFUNC_ABORT) {
keepon = FALSE;
result = CURLE_READ_ERROR;
@ -1417,7 +1416,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
if(!readfile_read)
break;
if(!ReadFile(stdin_handle, buf, buf_size,
if(!ReadFile(stdin_handle, buffer, buf_size,
&readfile_read, NULL)) {
keepon = FALSE;
result = CURLE_READ_ERROR;
@ -1425,7 +1424,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
}
}
result = send_telnet_data(data, buf, readfile_read);
result = send_telnet_data(data, buffer, readfile_read);
if(result) {
keepon = FALSE;
break;
@ -1436,14 +1435,14 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
case WAIT_OBJECT_0 + 1:
{
if(!ReadFile(stdin_handle, buf, buf_size,
if(!ReadFile(stdin_handle, buffer, buf_size,
&readfile_read, NULL)) {
keepon = FALSE;
result = CURLE_READ_ERROR;
break;
}
result = send_telnet_data(data, buf, readfile_read);
result = send_telnet_data(data, buffer, readfile_read);
if(result) {
keepon = FALSE;
break;
@ -1465,7 +1464,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
}
if(events.lNetworkEvents & FD_READ) {
/* read data from network */
result = Curl_read(data, sockfd, buf, data->set.buffer_size, &nread);
result = Curl_read(data, sockfd, buffer, sizeof(buffer), &nread);
/* read would've blocked. Loop again */
if(result == CURLE_AGAIN)
break;
@ -1481,7 +1480,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
break;
}
result = telrcv(data, (unsigned char *) buf, nread);
result = telrcv(data, (unsigned char *) buffer, nread);
if(result) {
keepon = FALSE;
break;
@ -1542,11 +1541,11 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
case 0: /* timeout */
pfd[0].revents = 0;
pfd[1].revents = 0;
/* FALLTHROUGH */
FALLTHROUGH();
default: /* read! */
if(pfd[0].revents & POLLIN) {
/* read data from network */
result = Curl_read(data, sockfd, buf, data->set.buffer_size, &nread);
result = Curl_read(data, sockfd, buffer, sizeof(buffer), &nread);
/* read would've blocked. Loop again */
if(result == CURLE_AGAIN)
break;
@ -1572,7 +1571,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
total_dl += nread;
result = Curl_pgrsSetDownloadCounter(data, total_dl);
if(!result)
result = telrcv(data, (unsigned char *)buf, nread);
result = telrcv(data, (unsigned char *)buffer, nread);
if(result) {
keepon = FALSE;
break;
@ -1590,12 +1589,12 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
nread = 0;
if(poll_cnt == 2) {
if(pfd[1].revents & POLLIN) { /* read from in file */
nread = read(pfd[1].fd, buf, data->set.buffer_size);
nread = read(pfd[1].fd, buffer, sizeof(buffer));
}
}
else {
/* read from user-supplied method */
nread = (int)data->state.fread_func(buf, 1, data->set.buffer_size,
nread = (int)data->state.fread_func(buffer, 1, sizeof(buffer),
data->state.in);
if(nread == CURL_READFUNC_ABORT) {
keepon = FALSE;
@ -1606,7 +1605,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
}
if(nread > 0) {
result = send_telnet_data(data, buf, nread);
result = send_telnet_data(data, buffer, nread);
if(result) {
keepon = FALSE;
break;

View File

@ -181,7 +181,7 @@ const struct Curl_handler Curl_handler_tftp = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
tftp_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_TFTP, /* defport */

Some files were not shown because too many files have changed in this diff Show More