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
parent
fe5ffe06a9
commit
851cc904a0
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
2
COPYING
2
COPYING
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 \
|
||||
|
|
11
lib/altsvc.c
11
lib/altsvc.c
|
@ -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;
|
||||
}
|
||||
|
|
156
lib/asyn-ares.c
156
lib/asyn-ares.c
|
@ -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! */
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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]",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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. */
|
||||
|
||||
|
|
10
lib/cookie.c
10
lib/cookie.c
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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, ...)
|
||||
{
|
||||
|
|
25
lib/doh.c
25
lib/doh.c
|
@ -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 */
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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);
|
||||
|
|
52
lib/easy.c
52
lib/easy.c
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
38
lib/file.c
38
lib/file.c
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
201
lib/ftp.c
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
24
lib/hostip.c
24
lib/hostip.c
|
@ -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;
|
||||
}
|
||||
|
|
32
lib/hsts.c
32
lib/hsts.c
|
@ -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;
|
||||
|
|
331
lib/http.c
331
lib/http.c
|
@ -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));
|
||||
|
|
24
lib/http.h
24
lib/http.h
|
@ -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
|
||||
|
|
74
lib/http2.c
74
lib/http2.c
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
93
lib/imap.c
93
lib/imap.c
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
41
lib/krb5.c
41
lib/krb5.c
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
|
|
21
lib/mime.c
21
lib/mime.c
|
@ -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;
|
||||
|
|
|
@ -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) || \
|
||||
|
|
1203
lib/mprintf.c
1203
lib/mprintf.c
File diff suppressed because it is too large
Load Diff
29
lib/mqtt.c
29
lib/mqtt.c
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
146
lib/multi.c
146
lib/multi.c
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
276
lib/pingpong.c
276
lib/pingpong.c
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
104
lib/pop3.c
104
lib/pop3.c
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
177
lib/rtsp.c
177
lib/rtsp.c
|
@ -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)) {
|
||||
|
|
85
lib/sendf.c
85
lib/sendf.c
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
44
lib/setopt.c
44
lib/setopt.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
32
lib/smtp.c
32
lib/smtp.c
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
79
lib/socks.c
79
lib/socks.c
|
@ -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");
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
|
|
12
lib/strdup.c
12
lib/strdup.c
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
117
lib/telnet.c
117
lib/telnet.c
|
@ -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;
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue