Merge topic 'update-curl'

82ac700f78 ci: Drop nightly job that builds CMake with vendored curl on macOS
8d8283642a curl: Set build options the way we need for CMake
c8f51c1d21 Merge branch 'upstream-curl' into update-curl
71e5adbcc9 curl 2025-07-16 (cfbfb650)
bf8360ddad curl: Update script to get curl 8.15.0

Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: buildbot <buildbot@kitware.com>
Merge-request: !10961
This commit is contained in:
Brad King
2025-07-22 16:04:14 +00:00
committed by Kitware Robot
204 changed files with 7390 additions and 10927 deletions
-21
View File
@@ -948,16 +948,6 @@ b:macos-arm64-ninja-symlinked:
variables:
CMAKE_CI_JOB_NIGHTLY: "true"
b:macos-arm64-curl:
extends:
- .macos_arm64_curl
- .cmake_build_macos
- .cmake_build_artifacts
- .macos_arm64_tags
- .run_manually
variables:
CMAKE_CI_JOB_NIGHTLY: "true"
b:macos-arm64-pch:
extends:
- .macos_arm64_pch
@@ -1005,17 +995,6 @@ t:macos-arm64-ninja-symlinked:
CMAKE_CI_JOB_NIGHTLY: "true"
CMAKE_CI_JOB_NIGHTLY_NINJA: "true"
t:macos-arm64-curl:
extends:
- .macos_arm64_curl
- .cmake_test_macos
- .macos_arm64_tags
- .run_dependent
needs:
- b:macos-arm64-curl
variables:
CMAKE_CI_JOB_NIGHTLY: "true"
b:macos-x86_64-makefiles:
extends:
- .macos_x86_64_makefiles
@@ -1,10 +0,0 @@
# Build with our vendored curl instead of the default system version.
set(CMAKE_USE_SYSTEM_CURL "OFF" CACHE BOOL "")
set(CMake_TEST_TLS_VERIFY_URL "https://gitlab.kitware.com" CACHE STRING "")
set(CMake_TEST_TLS_VERIFY_URL_BAD "https://badtls-expired.kitware.com" CACHE STRING "")
set(CMake_TEST_TLS_VERSION "1.2" CACHE STRING "")
set(CMake_TEST_TLS_VERSION_URL_BAD "https://badtls-v1-1.kitware.com:8011" CACHE STRING "")
include("${CMAKE_CURRENT_LIST_DIR}/configure_macos_common.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/configure_common.cmake")
-7
View File
@@ -49,13 +49,6 @@
CMAKE_CI_IN_SYMLINK_TREE: 1
CMAKE_CI_BUILD_DIR: "real_work/work/build"
.macos_arm64_curl:
extends: .macos_build
variables:
CMAKE_CONFIGURATION: macos_arm64_curl
CTEST_NO_WARNINGS_ALLOWED: 1
.macos_arm64_pch:
extends: .macos_arm64_ninja
+1 -1
View File
@@ -8,7 +8,7 @@ readonly name="curl"
readonly ownership="Curl Upstream <curl-library@lists.haxx.se>"
readonly subtree="Utilities/cmcurl"
readonly repo="https://github.com/curl/curl.git"
readonly tag="curl-8_14_1"
readonly tag="curl-8_15_0"
readonly shortlog=false
readonly paths="
CMake/*
+3 -3
View File
@@ -203,7 +203,7 @@ int main(void)
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#ifndef _WIN32
# include <sys/socket.h>
#endif
#ifdef HAVE_SYS_IOCTL_H
@@ -230,7 +230,7 @@ int main(void)
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#ifndef _WIN32
# include <sys/socket.h>
#endif
#ifdef HAVE_SYS_IOCTL_H
@@ -257,7 +257,7 @@ int main(void)
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#ifndef _WIN32
# include <sys/socket.h>
#endif
int main(void)
-58
View File
@@ -1,58 +0,0 @@
#***************************************************************************
# _ _ ____ _
# Project ___| | | | _ \| |
# / __| | | | |_) | |
# | (__| |_| | _ <| |___
# \___|\___/|_| \_\_____|
#
# Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at https://curl.se/docs/copyright.html.
#
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
# copies of the Software, and permit persons to whom the Software is
# furnished to do so, under the terms of the COPYING file.
#
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
# SPDX-License-Identifier: curl
#
###########################################################################
# Find the BearSSL library
#
# Input variables:
#
# - `BEARSSL_INCLUDE_DIR`: The BearSSL include directory.
# - `BEARSSL_LIBRARY`: Path to `bearssl` library.
#
# Result variables:
#
# - `BEARSSL_FOUND`: System has BearSSL.
# - `BEARSSL_INCLUDE_DIRS`: The BearSSL include directories.
# - `BEARSSL_LIBRARIES`: The BearSSL library names.
if(DEFINED BEARSSL_INCLUDE_DIRS AND NOT DEFINED BEARSSL_INCLUDE_DIR)
message(WARNING "BEARSSL_INCLUDE_DIRS is deprecated, use BEARSSL_INCLUDE_DIR instead.")
set(BEARSSL_INCLUDE_DIR "${BEARSSL_INCLUDE_DIRS}")
unset(BEARSSL_INCLUDE_DIRS)
endif()
find_path(BEARSSL_INCLUDE_DIR NAMES "bearssl.h")
find_library(BEARSSL_LIBRARY NAMES "bearssl")
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(BearSSL
REQUIRED_VARS
BEARSSL_INCLUDE_DIR
BEARSSL_LIBRARY
)
if(BEARSSL_FOUND)
set(BEARSSL_INCLUDE_DIRS ${BEARSSL_INCLUDE_DIR})
set(BEARSSL_LIBRARIES ${BEARSSL_LIBRARY})
endif()
mark_as_advanced(BEARSSL_INCLUDE_DIR BEARSSL_LIBRARY)
+61 -53
View File
@@ -52,19 +52,23 @@ set(_gss_root_hints
"$ENV{GSS_ROOT_DIR}"
)
set(_gss_CFLAGS "")
set(_gss_LIBRARY_DIRS "")
# Try to find library using system pkg-config if user did not specify root dir
if(NOT GSS_ROOT_DIR AND NOT "$ENV{GSS_ROOT_DIR}")
if(CURL_USE_PKGCONFIG)
find_package(PkgConfig QUIET)
pkg_search_module(_GSS ${_gnu_modname} ${_mit_modname} ${_heimdal_modname})
list(APPEND _gss_root_hints "${_GSS_PREFIX}")
pkg_search_module(_gss ${_gnu_modname} ${_mit_modname} ${_heimdal_modname})
list(APPEND _gss_root_hints "${_gss_PREFIX}")
set(_gss_version "${_gss_VERSION}")
endif()
if(WIN32)
list(APPEND _gss_root_hints "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MIT\\Kerberos;InstallDir]")
endif()
endif()
if(NOT _GSS_FOUND) # Not found by pkg-config. Let us take more traditional approach.
if(NOT _gss_FOUND) # Not found by pkg-config. Let us take more traditional approach.
find_file(_gss_configure_script
NAMES
"krb5-config"
@@ -85,25 +89,29 @@ if(NOT _GSS_FOUND) # Not found by pkg-config. Let us take more traditional appr
)
if(_gss_configure_script)
set(_gss_INCLUDE_DIRS "")
set(_gss_LIBRARIES "")
execute_process(
COMMAND ${_gss_configure_script} "--cflags" "gssapi"
OUTPUT_VARIABLE _GSS_CFLAGS
OUTPUT_VARIABLE _gss_cflags_raw
RESULT_VARIABLE _gss_configure_failed
OUTPUT_STRIP_TRAILING_WHITESPACE
)
message(STATUS "FindGSS krb5-config --cflags: ${_GSS_CFLAGS}")
message(STATUS "FindGSS krb5-config --cflags: ${_gss_cflags_raw}")
if(NOT _gss_configure_failed) # 0 means success
# Should also work in an odd case when multiple directories are given
string(STRIP "${_GSS_CFLAGS}" _GSS_CFLAGS)
string(REGEX REPLACE " +-I" ";" _GSS_CFLAGS "${_GSS_CFLAGS}")
string(REGEX REPLACE " +-([^I][^ \\t;]*)" ";-\\1" _GSS_CFLAGS "${_GSS_CFLAGS}")
# Should also work in an odd case when multiple directories are given.
string(STRIP "${_gss_cflags_raw}" _gss_cflags_raw)
string(REGEX REPLACE " +-(I)" ";-\\1" _gss_cflags_raw "${_gss_cflags_raw}")
string(REGEX REPLACE " +-([^I][^ \\t;]*)" ";-\\1" _gss_cflags_raw "${_gss_cflags_raw}")
foreach(_flag IN LISTS _GSS_CFLAGS)
foreach(_flag IN LISTS _gss_cflags_raw)
if(_flag MATCHES "^-I")
string(REGEX REPLACE "^-I" "" _val "${_flag}")
list(APPEND _GSS_INCLUDE_DIRS "${_val}")
string(REGEX REPLACE "^-I" "" _flag "${_flag}")
list(APPEND _gss_INCLUDE_DIRS "${_flag}")
else()
list(APPEND _GSS_CFLAGS "${_flag}")
list(APPEND _gss_CFLAGS "${_flag}")
endif()
endforeach()
endif()
@@ -117,32 +125,32 @@ if(NOT _GSS_FOUND) # Not found by pkg-config. Let us take more traditional appr
message(STATUS "FindGSS krb5-config --libs: ${_gss_lib_flags}")
if(NOT _gss_configure_failed) # 0 means success
# This script gives us libraries and link directories. Blah. We have to deal with it.
# This script gives us libraries and link directories.
string(STRIP "${_gss_lib_flags}" _gss_lib_flags)
string(REGEX REPLACE " +-(L|l)" ";-\\1" _gss_lib_flags "${_gss_lib_flags}")
string(REGEX REPLACE " +-([^Ll][^ \\t;]*)" ";-\\1" _gss_lib_flags "${_gss_lib_flags}")
foreach(_flag IN LISTS _gss_lib_flags)
if(_flag MATCHES "^-l")
string(REGEX REPLACE "^-l" "" _val "${_flag}")
list(APPEND _GSS_LIBRARIES "${_val}")
string(REGEX REPLACE "^-l" "" _flag "${_flag}")
list(APPEND _gss_LIBRARIES "${_flag}")
elseif(_flag MATCHES "^-L")
string(REGEX REPLACE "^-L" "" _val "${_flag}")
list(APPEND _GSS_LIBRARY_DIRS "${_val}")
string(REGEX REPLACE "^-L" "" _flag "${_flag}")
list(APPEND _gss_LIBRARY_DIRS "${_flag}")
endif()
endforeach()
endif()
execute_process(
COMMAND ${_gss_configure_script} "--version"
OUTPUT_VARIABLE _GSS_VERSION
OUTPUT_VARIABLE _gss_version
RESULT_VARIABLE _gss_configure_failed
OUTPUT_STRIP_TRAILING_WHITESPACE
)
# Older versions may not have the "--version" parameter. In this case we just do not care.
if(_gss_configure_failed)
set(_GSS_VERSION 0)
set(_gss_version 0)
endif()
execute_process(
@@ -165,7 +173,7 @@ if(NOT _GSS_FOUND) # Not found by pkg-config. Let us take more traditional appr
else() # Either there is no config script or we are on a platform that does not provide one (Windows?)
find_path(_GSS_INCLUDE_DIRS NAMES "gssapi/gssapi.h"
find_path(_gss_INCLUDE_DIRS NAMES "gssapi/gssapi.h"
HINTS
${_gss_root_hints}
PATH_SUFFIXES
@@ -173,9 +181,9 @@ if(NOT _GSS_FOUND) # Not found by pkg-config. Let us take more traditional appr
"inc"
)
if(_GSS_INCLUDE_DIRS) # jay, we have found something
if(_gss_INCLUDE_DIRS) # jay, we have found something
cmake_push_check_state()
list(APPEND CMAKE_REQUIRED_INCLUDES "${_GSS_INCLUDE_DIRS}")
list(APPEND CMAKE_REQUIRED_INCLUDES "${_gss_INCLUDE_DIRS}")
check_include_files("gssapi/gssapi_generic.h;gssapi/gssapi_krb5.h" _gss_have_mit_headers)
if(_gss_have_mit_headers)
@@ -193,7 +201,7 @@ if(NOT _GSS_FOUND) # Not found by pkg-config. Let us take more traditional appr
cmake_pop_check_state()
else()
# I am not convinced if this is the right way but this is what autotools do at the moment
find_path(_GSS_INCLUDE_DIRS NAMES "gssapi.h"
find_path(_gss_INCLUDE_DIRS NAMES "gssapi.h"
HINTS
${_gss_root_hints}
PATH_SUFFIXES
@@ -201,17 +209,17 @@ if(NOT _GSS_FOUND) # Not found by pkg-config. Let us take more traditional appr
"inc"
)
if(_GSS_INCLUDE_DIRS)
if(_gss_INCLUDE_DIRS)
set(GSS_FLAVOUR "Heimdal")
else()
find_path(_GSS_INCLUDE_DIRS NAMES "gss.h"
find_path(_gss_INCLUDE_DIRS NAMES "gss.h"
HINTS
${_gss_root_hints}
PATH_SUFFIXES
"include"
)
if(_GSS_INCLUDE_DIRS)
if(_gss_INCLUDE_DIRS)
set(GSS_FLAVOUR "GNU")
set(GSS_PC_REQUIRES "gss")
endif()
@@ -222,7 +230,7 @@ if(NOT _GSS_FOUND) # Not found by pkg-config. Let us take more traditional appr
if(GSS_FLAVOUR)
set(_gss_libdir_suffixes "")
set(_gss_libdir_hints ${_gss_root_hints})
get_filename_component(_gss_calculated_potential_root "${_GSS_INCLUDE_DIRS}" DIRECTORY)
get_filename_component(_gss_calculated_potential_root "${_gss_INCLUDE_DIRS}" DIRECTORY)
list(APPEND _gss_libdir_hints ${_gss_calculated_potential_root})
if(WIN32)
@@ -256,7 +264,7 @@ if(NOT _GSS_FOUND) # Not found by pkg-config. Let us take more traditional appr
endif()
endif()
find_library(_GSS_LIBRARIES NAMES ${_gss_libname}
find_library(_gss_LIBRARIES NAMES ${_gss_libname}
HINTS
${_gss_libdir_hints}
PATH_SUFFIXES
@@ -265,36 +273,36 @@ if(NOT _GSS_FOUND) # Not found by pkg-config. Let us take more traditional appr
endif()
endif()
else()
# _GSS_MODULE_NAME set since CMake 3.16
if(_GSS_MODULE_NAME STREQUAL _gnu_modname OR _GSS_${_gnu_modname}_VERSION)
# _gss_MODULE_NAME set since CMake 3.16
if(_gss_MODULE_NAME STREQUAL _gnu_modname OR _gss_${_gnu_modname}_VERSION)
set(GSS_FLAVOUR "GNU")
set(GSS_PC_REQUIRES "gss")
if(NOT _GSS_VERSION) # for old CMake versions?
set(_GSS_VERSION ${_GSS_${_gnu_modname}_VERSION})
if(NOT _gss_version) # for old CMake versions?
set(_gss_version ${_gss_${_gnu_modname}_VERSION})
endif()
elseif(_GSS_MODULE_NAME STREQUAL _mit_modname OR _GSS_${_mit_modname}_VERSION)
elseif(_gss_MODULE_NAME STREQUAL _mit_modname OR _gss_${_mit_modname}_VERSION)
set(GSS_FLAVOUR "MIT")
set(GSS_PC_REQUIRES "mit-krb5-gssapi")
if(NOT _GSS_VERSION) # for old CMake versions?
set(_GSS_VERSION ${_GSS_${_mit_modname}_VERSION})
if(NOT _gss_version) # for old CMake versions?
set(_gss_version ${_gss_${_mit_modname}_VERSION})
endif()
else()
set(GSS_FLAVOUR "Heimdal")
set(GSS_PC_REQUIRES "heimdal-gssapi")
if(NOT _GSS_VERSION) # for old CMake versions?
set(_GSS_VERSION ${_GSS_${_heimdal_modname}_VERSION})
if(NOT _gss_version) # for old CMake versions?
set(_gss_version ${_gss_${_heimdal_modname}_VERSION})
endif()
endif()
message(STATUS "Found GSS/${GSS_FLAVOUR} (via pkg-config): ${_GSS_INCLUDE_DIRS} (found version \"${_GSS_VERSION}\")")
message(STATUS "Found GSS/${GSS_FLAVOUR} (via pkg-config): ${_gss_INCLUDE_DIRS} (found version \"${_gss_version}\")")
endif()
string(REPLACE ";" " " _GSS_CFLAGS "${_GSS_CFLAGS}")
string(REPLACE ";" " " _gss_CFLAGS "${_gss_CFLAGS}")
set(GSS_INCLUDE_DIRS ${_GSS_INCLUDE_DIRS})
set(GSS_LIBRARIES ${_GSS_LIBRARIES})
set(GSS_LIBRARY_DIRS ${_GSS_LIBRARY_DIRS})
set(GSS_CFLAGS ${_GSS_CFLAGS})
set(GSS_VERSION ${_GSS_VERSION})
set(GSS_INCLUDE_DIRS ${_gss_INCLUDE_DIRS})
set(GSS_LIBRARIES ${_gss_LIBRARIES})
set(GSS_LIBRARY_DIRS ${_gss_LIBRARY_DIRS})
set(GSS_CFLAGS ${_gss_CFLAGS})
set(GSS_VERSION ${_gss_version})
if(GSS_FLAVOUR)
if(NOT GSS_VERSION AND GSS_FLAVOUR STREQUAL "Heimdal")
@@ -346,12 +354,12 @@ find_package_handle_standard_args(GSS
)
mark_as_advanced(
_GSS_CFLAGS
_GSS_FOUND
_GSS_INCLUDE_DIRS
_GSS_LIBRARIES
_GSS_LIBRARY_DIRS
_GSS_MODULE_NAME
_GSS_PREFIX
_GSS_VERSION
_gss_CFLAGS
_gss_FOUND
_gss_INCLUDE_DIRS
_gss_LIBRARIES
_gss_LIBRARY_DIRS
_gss_MODULE_NAME
_gss_PREFIX
_gss_version
)
+6 -6
View File
@@ -66,12 +66,12 @@ else()
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Libgsasl
REQUIRED_VARS
LIBGSASL_INCLUDE_DIR
LIBGSASL_LIBRARY
VERSION_VAR
LIBGSASL_VERSION
find_package_handle_standard_args(Libgsasl
REQUIRED_VARS
LIBGSASL_INCLUDE_DIR
LIBGSASL_LIBRARY
VERSION_VAR
LIBGSASL_VERSION
)
if(LIBGSASL_FOUND)
+15 -10
View File
@@ -34,23 +34,28 @@
#
# Input variables:
#
# - `NGTCP2_INCLUDE_DIR`: The ngtcp2 include directory.
# - `NGTCP2_LIBRARY`: Path to `ngtcp2` library.
# - `NGTCP2_INCLUDE_DIR`: The ngtcp2 include directory.
# - `NGTCP2_LIBRARY`: Path to `ngtcp2` library.
# - `NGTCP2_CRYPTO_BORINGSSL_LIBRARY`: Path to `ngtcp2_crypto_boringssl` library.
# - `NGTCP2_CRYPTO_GNUTLS_LIBRARY`: Path to `ngtcp2_crypto_gnutls` library.
# - `NGTCP2_CRYPTO_OSSL_LIBRARY`: Path to `ngtcp2_crypto_ossl` library.
# - `NGTCP2_CRYPTO_QUICTLS_LIBRARY`: Path to `ngtcp2_crypto_quictls` library.
# - `NGTCP2_CRYPTO_WOLFSSL_LIBRARY`: Path to `ngtcp2_crypto_wolfssl` library.
#
# Result variables:
#
# - `NGTCP2_FOUND`: System has ngtcp2.
# - `NGTCP2_INCLUDE_DIRS`: The ngtcp2 include directories.
# - `NGTCP2_LIBRARIES`: The ngtcp2 library names.
# - `NGTCP2_LIBRARY_DIRS`: The ngtcp2 library directories.
# - `NGTCP2_PC_REQUIRES`: The ngtcp2 pkg-config packages.
# - `NGTCP2_CFLAGS`: Required compiler flags.
# - `NGTCP2_VERSION`: Version of ngtcp2.
# - `NGTCP2_FOUND`: System has ngtcp2.
# - `NGTCP2_INCLUDE_DIRS`: The ngtcp2 include directories.
# - `NGTCP2_LIBRARIES`: The ngtcp2 library names.
# - `NGTCP2_LIBRARY_DIRS`: The ngtcp2 library directories.
# - `NGTCP2_PC_REQUIRES`: The ngtcp2 pkg-config packages.
# - `NGTCP2_CFLAGS`: Required compiler flags.
# - `NGTCP2_VERSION`: Version of ngtcp2.
if(NGTCP2_FIND_COMPONENTS)
set(_ngtcp2_crypto_backend "")
foreach(_component IN LISTS NGTCP2_FIND_COMPONENTS)
if(_component MATCHES "^(BoringSSL|quictls|wolfSSL|GnuTLS|ossl)")
if(_component MATCHES "^(BoringSSL|GnuTLS|ossl|quictls|wolfSSL)")
if(_ngtcp2_crypto_backend)
message(FATAL_ERROR "NGTCP2: Only one crypto library can be selected")
endif()
+78
View File
@@ -65,6 +65,7 @@ macro(curl_internal_test _curl_test)
endif()
endmacro()
# Option for dependencies that accepts an 'AUTO' value, which enables the dependency if detected.
macro(curl_dependency_option _option_name _find_name _desc_name)
set(${_option_name} "AUTO" CACHE STRING "Build curl with ${_desc_name} support (AUTO, ON or OFF)")
set_property(CACHE ${_option_name} PROPERTY STRINGS "AUTO" "ON" "OFF")
@@ -94,3 +95,80 @@ macro(curl_prefill_type_size _type _size)
set(SIZEOF_${_type} ${_size})
set(SIZEOF_${_type}_CODE "#define SIZEOF_${_type} ${_size}")
endmacro()
# Internal: Recurse into target libraries and collect their include directories
# and macro definitions.
macro(curl_collect_target_options _target)
get_target_property(_val ${_target} INTERFACE_INCLUDE_DIRECTORIES)
if(_val)
list(APPEND _includes ${_val})
endif()
get_target_property(_val ${_target} INCLUDE_DIRECTORIES)
if(_val)
list(APPEND _includes ${_val})
endif()
get_target_property(_val ${_target} COMPILE_DEFINITIONS)
if(_val)
list(APPEND _definitions ${_val})
endif()
get_target_property(_val ${_target} LINK_LIBRARIES)
if(_val)
foreach(_lib IN LISTS _val)
if(TARGET "${_lib}")
curl_collect_target_options(${_lib})
endif()
endforeach()
endif()
unset(_val)
endmacro()
# Create a clang-tidy target for test targets
macro(curl_add_clang_tidy_test_target _target_clang_tidy _target)
if(CURL_CLANG_TIDY)
set(_includes "")
set(_definitions "")
# Collect header directories and macro definitions applying to the directory
get_directory_property(_val INCLUDE_DIRECTORIES)
if(_val)
list(APPEND _includes ${_val})
endif()
get_directory_property(_val COMPILE_DEFINITIONS)
if(_val)
list(APPEND _definitions ${_val})
endif()
unset(_val)
# Collect header directories and macro definitions from lib dependencies
curl_collect_target_options(${_target})
list(REMOVE_ITEM _includes "")
string(REPLACE ";" ";-I" _includes ";${_includes}")
list(REMOVE_DUPLICATES _includes)
list(REMOVE_ITEM _definitions "")
string(REPLACE ";" ";-D" _definitions ";${_definitions}")
list(REMOVE_DUPLICATES _definitions)
list(SORT _definitions) # Sort like CMake does
# Assemble source list
set(_sources "")
foreach(_source IN ITEMS ${ARGN})
if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${_source}") # if not in source tree
set(_source "${CMAKE_CURRENT_BINARY_DIR}/${_source}") # look in the build tree, for generated files, e.g. lib1521.c
endif()
list(APPEND _sources "${_source}")
endforeach()
add_custom_target(${_target_clang_tidy} USES_TERMINAL
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
COMMAND ${CMAKE_C_CLANG_TIDY} ${_sources} -- ${_includes} ${_definitions}
DEPENDS ${_sources})
add_dependencies(tests-clang-tidy ${_target_clang_tidy})
unset(_includes)
unset(_definitions)
unset(_sources)
endif()
endmacro()
+12 -7
View File
@@ -25,6 +25,7 @@ include(CheckCSourceCompiles)
include(CheckCSourceRuns)
include(CheckTypeSize)
# #include header if condition is true
macro(curl_add_header_include _check _header)
if(${_check})
set(_source_epilogue "${_source_epilogue}
@@ -41,7 +42,7 @@ if(NOT DEFINED HAVE_STRUCT_SOCKADDR_STORAGE)
if(WIN32)
set(CMAKE_EXTRA_INCLUDE_FILES "winsock2.h")
list(APPEND CMAKE_REQUIRED_LIBRARIES "ws2_32")
elseif(HAVE_SYS_SOCKET_H)
else()
set(CMAKE_EXTRA_INCLUDE_FILES "sys/socket.h")
endif()
check_type_size("struct sockaddr_storage" SIZEOF_STRUCT_SOCKADDR_STORAGE)
@@ -52,8 +53,8 @@ endif()
if(NOT WIN32)
set(_source_epilogue "#undef inline")
curl_add_header_include(HAVE_SYS_TYPES_H "sys/types.h")
curl_add_header_include(HAVE_SYS_SOCKET_H "sys/socket.h")
check_c_source_compiles("${_source_epilogue}
#include <sys/socket.h>
int main(void)
{
int flag = MSG_NOSIGNAL;
@@ -63,11 +64,13 @@ if(NOT WIN32)
endif()
set(_source_epilogue "#undef inline")
curl_add_header_include(HAVE_SYS_TIME_H "sys/time.h")
check_c_source_compiles("${_source_epilogue}
#ifdef _MSC_VER
#include <winsock2.h>
#endif
#ifndef _WIN32
#include <sys/time.h>
#endif
#include <time.h>
int main(void)
{
@@ -100,9 +103,11 @@ elseif(BSD OR CMAKE_SYSTEM_NAME MATCHES "BSD")
endif()
if(NOT DEFINED HAVE_GETADDRINFO_THREADSAFE)
set(_source_epilogue "#undef inline")
curl_add_header_include(HAVE_SYS_SOCKET_H "sys/socket.h")
curl_add_header_include(HAVE_SYS_TIME_H "sys/time.h")
set(_source_epilogue "#undef inline
#ifndef _WIN32
#include <sys/socket.h>
#include <sys/time.h>
#endif")
curl_add_header_include(HAVE_NETDB_H "netdb.h")
check_c_source_compiles("${_source_epilogue}
int main(void)
@@ -143,8 +148,8 @@ endif()
if(NOT WIN32 AND NOT DEFINED HAVE_CLOCK_GETTIME_MONOTONIC_RAW)
set(_source_epilogue "#undef inline")
curl_add_header_include(HAVE_SYS_TYPES_H "sys/types.h")
curl_add_header_include(HAVE_SYS_TIME_H "sys/time.h")
check_c_source_compiles("${_source_epilogue}
#include <sys/time.h>
#include <time.h>
int main(void)
{
+4 -3
View File
@@ -316,8 +316,9 @@ if(PICKY_COMPILER)
list(APPEND _picky "-wd4668") # 'M' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' (in winbase.h)
list(APPEND _picky "-wd4710") # 'snprintf': function not inlined
list(APPEND _picky "-wd4711") # function 'A' selected for automatic inline expansion
list(APPEND _picky "-wd4746") # volatile access of '<expression>' is subject to /volatile:<iso|ms> setting;
# consider using __iso_volatile_load/store intrinsic functions (ARM64)
# volatile access of '<expression>' is subject to /volatile:<iso|ms> setting;
# consider using __iso_volatile_load/store intrinsic functions (ARM64)
list(APPEND _picky "-wd4746")
list(APPEND _picky "-wd4774") # 'snprintf': format string expected in argument 3 is not a string literal
list(APPEND _picky "-wd4820") # 'A': 'N' bytes padding added after data member 'B'
if(MSVC_VERSION GREATER_EQUAL 1900)
@@ -340,7 +341,7 @@ if(CMAKE_C_COMPILER_ID STREQUAL "Clang" AND MSVC)
list(APPEND _picky_tmp "-clang:${_ccopt}")
endif()
endforeach()
set("${_wlist}" ${_picky_tmp})
set("${_wlist}" ${_picky_tmp}) # cmake-lint: disable=C0103
endforeach()
endif()
+28
View File
@@ -51,3 +51,31 @@ function(curl_dumpvars)
endforeach()
message("::endgroup::")
endfunction()
# Dump all target properties
function(curl_dumptargetprops _target)
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.19 AND TARGET "${_target}")
execute_process(COMMAND "${CMAKE_COMMAND}" "--help-property-list" OUTPUT_VARIABLE _cmake_property_list)
string(REPLACE "\n" ";" _cmake_property_list "${_cmake_property_list}")
list(REMOVE_DUPLICATES _cmake_property_list)
list(REMOVE_ITEM _cmake_property_list "")
foreach(_prop IN LISTS _cmake_property_list)
if(_prop MATCHES "<CONFIG>")
foreach(_config IN ITEMS "DEBUG" "RELEASE" "MINSIZEREL" "RELWITHDEBINFO")
string(REPLACE "<CONFIG>" "${_config}" _propconfig "${_prop}")
get_property(_is_set TARGET "${_target}" PROPERTY "${_propconfig}" SET)
if(_is_set)
get_target_property(_val "${_target}" "${_propconfig}")
message("${_target}.${_propconfig} = '${_val}'")
endif()
endforeach()
else()
get_property(_is_set TARGET "${_target}" PROPERTY "${_prop}" SET)
if(_is_set)
get_target_property(_val "${_target}" "${_prop}")
message("${_target}.${_prop} = '${_val}'")
endif()
endif()
endforeach()
endif()
endfunction()
-3
View File
@@ -284,15 +284,12 @@ set(HAVE_SYS_PARAM_H 1)
set(HAVE_SYS_POLL_H 1)
set(HAVE_SYS_RESOURCE_H 1)
set(HAVE_SYS_SELECT_H 1)
set(HAVE_SYS_SOCKET_H 1)
if(CYGWIN OR
CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(HAVE_SYS_SOCKIO_H 0)
else()
set(HAVE_SYS_SOCKIO_H 1)
endif()
set(HAVE_SYS_STAT_H 1)
set(HAVE_SYS_TIME_H 1)
set(HAVE_SYS_TYPES_H 1)
set(HAVE_SYS_UN_H 1)
if(CYGWIN)
-5
View File
@@ -39,7 +39,6 @@ if(MINGW)
set(HAVE_STDINT_H 1) # detected by CMake internally in check_type_size()
set(HAVE_STRINGS_H 1) # wrapper to string.h
set(HAVE_SYS_PARAM_H 1)
set(HAVE_SYS_TIME_H 1)
set(HAVE_UNISTD_H 1)
set(HAVE_UTIME_H 1) # wrapper to sys/utime.h
else()
@@ -50,7 +49,6 @@ else()
set(HAVE_OPENDIR 0)
set(HAVE_STRINGS_H 0)
set(HAVE_SYS_PARAM_H 0)
set(HAVE_SYS_TIME_H 0)
set(HAVE_UTIME_H 0)
if(MSVC)
set(HAVE_UNISTD_H 0)
@@ -118,7 +116,6 @@ set(HAVE_GETSOCKNAME 1)
set(HAVE_GLIBC_STRERROR_R 0)
set(HAVE_GMTIME_R 0)
set(HAVE_IFADDRS_H 0)
set(HAVE_IF_NAMETOINDEX 0)
set(HAVE_INET_NTOP 0)
set(HAVE_INET_PTON 0)
set(HAVE_IOCTLSOCKET 1)
@@ -171,9 +168,7 @@ set(HAVE_SYS_IOCTL_H 0)
set(HAVE_SYS_POLL_H 0)
set(HAVE_SYS_RESOURCE_H 0)
set(HAVE_SYS_SELECT_H 0)
set(HAVE_SYS_SOCKET_H 0)
set(HAVE_SYS_SOCKIO_H 0)
set(HAVE_SYS_STAT_H 1)
set(HAVE_SYS_TYPES_H 1)
set(HAVE_SYS_UN_H 0)
set(HAVE_SYS_UTIME_H 1)
+38 -88
View File
@@ -11,7 +11,6 @@ set(BUILD_SHARED_LIBS OFF)
set(BUILD_STATIC_LIBS ON)
set(BUILD_STATIC_CURL OFF)
set(CURL_CA_SEARCH_SAFE OFF)
set(CURL_USE_BEARSSL OFF)
set(CURL_USE_GSASL OFF)
set(CURL_USE_GSSAPI OFF)
set(CURL_USE_LIBPSL OFF)
@@ -24,7 +23,6 @@ set(CURL_USE_OPENLDAP OFF)
set(CURL_USE_OPENSSL "${CMAKE_USE_OPENSSL}")
set(CURL_USE_PKGCONFIG OFF)
set(CURL_USE_SCHANNEL OFF)
set(CURL_USE_SECTRANSP OFF)
set(CURL_USE_WOLFSSH OFF)
set(CURL_USE_WOLFSSL OFF)
set(CURL_BROTLI "OFF" CACHE INTERNAL "Build curl with BROTLI support (AUTO, ON or OFF)")
@@ -90,7 +88,6 @@ set(ENABLE_DEBUG OFF CACHE INTERNAL "No curl debug features")
set(ENABLE_INET_PTON OFF CACHE INTERNAL "Set to OFF to prevent usage of inet_pton when building against modern SDKs while still requiring compatibility with older Windows versions, such as Windows XP, Windows Server 2003 etc.")
set(ENABLE_IPV6 ON CACHE INTERNAL "Enable curl IPv6 support detection")
set(ENABLE_MANUAL OFF CACHE INTERNAL "No curl built-in manual")
set(ENABLE_SERVER_DEBUG OFF)
set(ENABLE_THREADED_RESOLVER OFF CACHE INTERNAL "No curl POSIX threaded DNS lookup")
set(ENABLE_UNICODE OFF)
set(ENABLE_UNIX_SOCKETS OFF CACHE INTERNAL "No curl Unix domain sockets support")
@@ -121,23 +118,6 @@ if(CURL_USE_OPENSSL)
elseif(WIN32)
set(CURL_USE_SCHANNEL ON)
set(CURL_WINDOWS_SSPI ON)
elseif(APPLE)
# Use OS X SSL/TLS native implementation if available on target version.
if(CMAKE_OSX_DEPLOYMENT_TARGET)
set(OSX_VERSION ${CMAKE_OSX_DEPLOYMENT_TARGET})
else()
execute_process(
COMMAND sw_vers -productVersion
OUTPUT_VARIABLE OSX_VERSION
OUTPUT_STRIP_TRAILING_WHITESPACE
)
endif()
if(NOT OSX_VERSION VERSION_LESS 10.6 AND
CMAKE_C_COMPILER_ID MATCHES "GNU|LCC|Clang|AppleClang")
set(CURL_USE_SECTRANSP ON)
else()
set(CURL_USE_SECTRANSP OFF)
endif()
endif()
# Windows Vista and above have inet_pton, but this will link on
@@ -473,7 +453,6 @@ if(ENABLE_DEBUG)
message(WARNING "This curl build is Debug-enabled and insecure, do not use in production.")
endif()
option(ENABLE_CURLDEBUG "Enable TrackMemory debug feature" ${ENABLE_DEBUG})
option(ENABLE_SERVER_DEBUG "Apply curl debug options to test servers" OFF)
set(CURL_DEBUG_MACROS "")
if(ENABLE_DEBUG)
@@ -484,15 +463,11 @@ if(ENABLE_CURLDEBUG)
endif()
if(0) # XXX(cmake): not needed for build within cmake
option(CURL_TEST_BUNDLES "Build tests into single-binary bundles" OFF)
option(CURL_CLANG_TIDY "Run the build through clang-tidy" OFF)
if(CURL_CLANG_TIDY)
# clang-tidy is not looking into #included sources, thus not compatible with
# unity builds and test bundles.
set(CMAKE_UNITY_BUILD OFF)
set(CURL_TEST_BUNDLES OFF)
set(CMAKE_UNITY_BUILD OFF) # clang-tidy is not looking into #included sources, thus not compatible with unity builds.
set(_tidy_checks "")
list(APPEND _tidy_checks "-clang-analyzer-security.insecureAPI.bzero") # for FD_ZERO() (seen on macOS)
list(APPEND _tidy_checks "-clang-analyzer-security.insecureAPI.strcpy")
list(APPEND _tidy_checks "-clang-analyzer-optin.performance.Padding")
list(APPEND _tidy_checks "-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling")
@@ -574,6 +549,7 @@ if(ENABLE_ARES)
list(APPEND CURL_LIBS ${CARES_LIBRARIES})
list(APPEND CURL_LIBDIRS ${CARES_LIBRARY_DIRS})
list(APPEND LIBCURL_PC_REQUIRES_PRIVATE ${CARES_PC_REQUIRES})
include_directories(SYSTEM ${CARES_INCLUDE_DIRS})
link_directories(${CARES_LIBRARY_DIRS})
if(CARES_CFLAGS)
string(APPEND CMAKE_C_FLAGS " ${CARES_CFLAGS}")
@@ -723,7 +699,7 @@ if(PERL_EXECUTABLE)
DEPENDS "${PROJECT_SOURCE_DIR}/scripts/mk-ca-bundle.pl"
)
add_custom_target(curl-ca-firefox
COMMENT "generating a fresh ca-bundle.crt" VERBATIM USES_TERMINAL
COMMENT "Generating a fresh ca-bundle.crt" VERBATIM USES_TERMINAL
COMMAND "${PERL_EXECUTABLE}" "${PROJECT_SOURCE_DIR}/scripts/firefox-db2pem.sh" "lib/ca-bundle.crt"
DEPENDS "${PROJECT_SOURCE_DIR}/scripts/firefox-db2pem.sh"
)
@@ -813,10 +789,12 @@ if(WIN32)
set(_win32_winsock "ws2_32")
endif()
set(_win32_crypt32 "crypt32")
set(_win32_secur32 "secur32")
if(MINGW32CE) # FIXME upstream: must specify the full path to avoid CMake converting "ws2" to "ws2.lib"
set(_win32_winsock "${MINGW32CE_LIBRARY_DIR}/lib${_win32_winsock}.a")
set(_win32_crypt32 "${MINGW32CE_LIBRARY_DIR}/lib${_win32_crypt32}.a")
set(_win32_secur32 "${MINGW32CE_LIBRARY_DIR}/lib${_win32_secur32}.a")
endif()
elseif(DOS)
if(WATT_ROOT)
@@ -886,24 +864,18 @@ if(CURL_DEFAULT_SSL_BACKEND)
set(_valid_default_ssl_backend FALSE)
endif()
if(APPLE)
cmake_dependent_option(CURL_USE_SECTRANSP "Enable Apple OS native SSL/TLS (Secure Transport)" OFF CURL_ENABLE_SSL OFF)
endif()
if(WIN32)
cmake_dependent_option(CURL_USE_SCHANNEL "Enable Windows native SSL/TLS (Schannel)" OFF CURL_ENABLE_SSL OFF)
option(CURL_WINDOWS_SSPI "Enable SSPI on Windows" ${CURL_USE_SCHANNEL})
endif()
cmake_dependent_option(CURL_USE_MBEDTLS "Enable mbedTLS for SSL/TLS" OFF CURL_ENABLE_SSL OFF)
cmake_dependent_option(CURL_USE_BEARSSL "Enable BearSSL for SSL/TLS" OFF CURL_ENABLE_SSL OFF)
cmake_dependent_option(CURL_USE_WOLFSSL "Enable wolfSSL for SSL/TLS" OFF CURL_ENABLE_SSL OFF)
cmake_dependent_option(CURL_USE_GNUTLS "Enable GnuTLS for SSL/TLS" OFF CURL_ENABLE_SSL OFF)
cmake_dependent_option(CURL_USE_RUSTLS "Enable Rustls for SSL/TLS" OFF CURL_ENABLE_SSL OFF)
if(WIN32 OR
CURL_USE_SECTRANSP OR
CURL_USE_SCHANNEL OR
CURL_USE_MBEDTLS OR
CURL_USE_BEARSSL OR
CURL_USE_WOLFSSL OR
CURL_USE_GNUTLS OR
CURL_USE_RUSTLS)
@@ -922,10 +894,8 @@ endif() # XXX(cmake): end
curl_count_true(_enabled_ssl_options_count
CURL_USE_SCHANNEL
CURL_USE_SECTRANSP
CURL_USE_OPENSSL
CURL_USE_MBEDTLS
CURL_USE_BEARSSL
CURL_USE_WOLFSSL
CURL_USE_GNUTLS
CURL_USE_RUSTLS
@@ -949,28 +919,6 @@ if(CURL_WINDOWS_SSPI)
set(USE_WINDOWS_SSPI ON)
endif()
if(CURL_USE_SECTRANSP)
set(_use_core_foundation_and_core_services ON)
find_library(SECURITY_FRAMEWORK NAMES "Security")
mark_as_advanced(SECURITY_FRAMEWORK)
if(NOT SECURITY_FRAMEWORK)
message(FATAL_ERROR "Security framework not found")
endif()
list(APPEND CURL_LIBS "-framework Security")
set(_ssl_enabled ON)
set(USE_SECTRANSP ON)
if(CURL_DEFAULT_SSL_BACKEND AND CURL_DEFAULT_SSL_BACKEND STREQUAL "secure-transport")
set(_valid_default_ssl_backend TRUE)
endif()
if(0) # XXX(cmake): not needed for build within cmake
message(WARNING "Secure Transport does not support TLS 1.3.")
endif() # XXX(cmake): end
endif()
if(_use_core_foundation_and_core_services)
find_library(COREFOUNDATION_FRAMEWORK NAMES "CoreFoundation")
mark_as_advanced(COREFOUNDATION_FRAMEWORK)
@@ -1068,23 +1016,6 @@ if(CURL_USE_MBEDTLS)
set(_curl_ca_bundle_supported TRUE)
endif()
if(CURL_USE_BEARSSL)
find_package(BearSSL REQUIRED)
set(_ssl_enabled ON)
set(USE_BEARSSL ON)
list(APPEND CURL_LIBS ${BEARSSL_LIBRARIES})
include_directories(SYSTEM ${BEARSSL_INCLUDE_DIRS})
if(CURL_DEFAULT_SSL_BACKEND AND CURL_DEFAULT_SSL_BACKEND STREQUAL "bearssl")
set(_valid_default_ssl_backend TRUE)
endif()
set(_curl_ca_bundle_supported TRUE)
if(0) # XXX(cmake): not needed for build within cmake
message(WARNING "BearSSL does not support TLS 1.3.")
endif() # XXX(cmake): end
endif()
if(CURL_USE_WOLFSSL)
find_package(WolfSSL REQUIRED)
set(_ssl_enabled ON)
@@ -1889,6 +1820,23 @@ if(WIN32)
# Windows XP is required for freeaddrinfo, getaddrinfo
message(FATAL_ERROR "Building for Windows XP or newer is required.")
endif()
# Pre-fill detection results based on target OS version
if(HAVE_WIN32_WINNT AND HAVE_WIN32_WINNT GREATER_EQUAL 0x0600 AND # Windows Vista or newer
(MINGW OR MSVC) AND
NOT WINCE AND NOT WINDOWS_STORE)
set(HAVE_IF_NAMETOINDEX 1)
else()
set(HAVE_IF_NAMETOINDEX 0)
endif()
unset(HAVE_IF_NAMETOINDEX CACHE)
endif()
if(NOT WIN32)
list(APPEND CURL_INCLUDES "sys/socket.h")
endif()
if(NOT WIN32 OR MINGW)
list(APPEND CURL_INCLUDES "sys/time.h")
endif()
# Detect headers
@@ -1903,10 +1851,7 @@ check_include_file("sys/param.h" HAVE_SYS_PARAM_H)
check_include_file("sys/poll.h" HAVE_SYS_POLL_H)
check_include_file("sys/resource.h" HAVE_SYS_RESOURCE_H)
check_include_file_concat_curl("sys/select.h" HAVE_SYS_SELECT_H)
check_include_file_concat_curl("sys/socket.h" HAVE_SYS_SOCKET_H)
check_include_file("sys/sockio.h" HAVE_SYS_SOCKIO_H)
check_include_file("sys/stat.h" HAVE_SYS_STAT_H)
check_include_file_concat_curl("sys/time.h" HAVE_SYS_TIME_H)
check_include_file_concat_curl("sys/types.h" HAVE_SYS_TYPES_H)
check_include_file("sys/un.h" HAVE_SYS_UN_H)
check_include_file_concat_curl("sys/utime.h" HAVE_SYS_UTIME_H) # sys/types.h (AmigaOS)
@@ -1948,10 +1893,9 @@ foreach(_variable IN ITEMS
HAVE_STDBOOL_H
HAVE_STROPTS_H
HAVE_SYS_IOCTL_H
HAVE_SYS_SOCKET_H
HAVE_SYS_TYPES_H
HAVE_UNISTD_H
)
)
if(${_variable})
string(APPEND CURL_TEST_DEFINES " -D${_variable}")
endif()
@@ -1971,6 +1915,9 @@ endif()
# Apply to all feature checks
if(WIN32)
list(APPEND CMAKE_REQUIRED_LIBRARIES "${_win32_winsock}")
if(NOT WINCE AND NOT WINDOWS_STORE)
list(APPEND CMAKE_REQUIRED_LIBRARIES "iphlpapi")
endif()
elseif(HAVE_LIBSOCKET)
list(APPEND CMAKE_REQUIRED_LIBRARIES "socket")
elseif(HAVE_LIBNETWORK)
@@ -2024,12 +1971,12 @@ check_function_exists("eventfd" HAVE_EVENTFD)
check_symbol_exists("ftruncate" "unistd.h" HAVE_FTRUNCATE)
check_symbol_exists("getpeername" "${CURL_INCLUDES}" HAVE_GETPEERNAME) # winsock2.h unistd.h proto/bsdsocket.h
check_symbol_exists("getsockname" "${CURL_INCLUDES}" HAVE_GETSOCKNAME) # winsock2.h unistd.h proto/bsdsocket.h
check_function_exists("if_nametoindex" HAVE_IF_NAMETOINDEX) # iphlpapi.h (Windows Vista+ non-UWP), net/if.h
check_function_exists("getrlimit" HAVE_GETRLIMIT)
check_function_exists("setlocale" HAVE_SETLOCALE)
check_function_exists("setrlimit" HAVE_SETRLIMIT)
if(NOT WIN32)
check_function_exists("if_nametoindex" HAVE_IF_NAMETOINDEX) # iphlpapi.h (Windows non-UWP), net/if.h
check_function_exists("realpath" HAVE_REALPATH)
check_function_exists("sched_yield" HAVE_SCHED_YIELD)
check_symbol_exists("strcasecmp" "string.h" HAVE_STRCASECMP)
@@ -2076,7 +2023,7 @@ if(WIN32)
list(APPEND CMAKE_EXTRA_INCLUDE_FILES "winsock2.h")
check_type_size("ADDRESS_FAMILY" SIZEOF_ADDRESS_FAMILY)
set(HAVE_ADDRESS_FAMILY ${HAVE_SIZEOF_ADDRESS_FAMILY})
elseif(HAVE_SYS_SOCKET_H)
else()
list(APPEND CMAKE_EXTRA_INCLUDE_FILES "sys/socket.h")
check_type_size("sa_family_t" SIZEOF_SA_FAMILY_T)
set(HAVE_SA_FAMILY_T ${HAVE_SIZEOF_SA_FAMILY_T})
@@ -2099,7 +2046,7 @@ foreach(_curl_test IN ITEMS
HAVE_BOOL_T
STDC_HEADERS
HAVE_ATOMIC
)
)
curl_internal_test(${_curl_test})
endforeach()
@@ -2210,6 +2157,9 @@ set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS "HAVE_CONFIG_H")
if(WIN32)
list(APPEND CURL_LIBS "${_win32_winsock}")
if(NOT WINCE AND NOT WINDOWS_STORE)
list(APPEND CURL_LIBS "iphlpapi")
endif()
if(NOT WINCE)
list(APPEND CURL_LIBS "bcrypt")
endif()
@@ -2230,6 +2180,9 @@ if(WIN32)
endif()
list(APPEND CURL_LIBS "${_win32_crypt32}")
endif()
if(USE_WINDOWS_SSPI)
list(APPEND CURL_LIBS "${_win32_secur32}")
endif()
endif()
if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") # MSVC but exclude clang-cl
@@ -2257,6 +2210,7 @@ endif()
# (= regenerate it).
function(curl_transform_makefile_inc _input_file _output_file)
file(READ ${_input_file} _makefile_inc_text)
# cmake-lint: disable=W0106
string(REPLACE "$(top_srcdir)" "\${PROJECT_SOURCE_DIR}" _makefile_inc_text ${_makefile_inc_text})
string(REPLACE "$(top_builddir)" "\${PROJECT_BINARY_DIR}" _makefile_inc_text ${_makefile_inc_text})
@@ -2345,7 +2299,6 @@ if(NOT CURL_DISABLE_NTLM AND
(USE_OPENSSL OR
USE_MBEDTLS OR
USE_GNUTLS OR
USE_SECTRANSP OR
USE_WIN32_CRYPTO OR
(USE_WOLFSSL AND HAVE_WOLFSSL_DES_ECB_ENCRYPT)))
set(_use_curl_ntlm_core ON)
@@ -2426,8 +2379,7 @@ curl_add_if("HTTP2" USE_NGHTTP2)
curl_add_if("HTTP3" USE_NGTCP2 OR USE_QUICHE OR USE_MSH3 OR USE_OPENSSL_QUIC)
curl_add_if("MultiSSL" CURL_WITH_MULTI_SSL)
curl_add_if("HTTPS-proxy" NOT CURL_DISABLE_PROXY AND _ssl_enabled AND (USE_OPENSSL OR USE_GNUTLS
OR USE_SCHANNEL OR USE_RUSTLS OR USE_BEARSSL OR
USE_MBEDTLS OR USE_SECTRANSP OR
OR USE_SCHANNEL OR USE_RUSTLS OR USE_MBEDTLS OR
(USE_WOLFSSL AND HAVE_WOLFSSL_BIO_NEW)))
curl_add_if("Unicode" ENABLE_UNICODE)
curl_add_if("threadsafe" HAVE_ATOMIC OR
@@ -2456,9 +2408,7 @@ set(_items "")
curl_add_if("Schannel" _ssl_enabled AND USE_SCHANNEL)
curl_add_if("${_openssl}" _ssl_enabled AND USE_OPENSSL AND OPENSSL_VERSION VERSION_LESS 3.0.0)
curl_add_if("${_openssl} v3+" _ssl_enabled AND USE_OPENSSL AND OPENSSL_VERSION VERSION_GREATER_EQUAL 3.0.0)
curl_add_if("Secure Transport" _ssl_enabled AND USE_SECTRANSP)
curl_add_if("mbedTLS" _ssl_enabled AND USE_MBEDTLS)
curl_add_if("BearSSL" _ssl_enabled AND USE_BEARSSL)
curl_add_if("wolfSSL" _ssl_enabled AND USE_WOLFSSL)
curl_add_if("GnuTLS" _ssl_enabled AND USE_GNUTLS)
curl_add_if("rustls" _ssl_enabled AND USE_RUSTLS)
+15 -27
View File
@@ -158,11 +158,11 @@ typedef enum {
CURLSSLBACKEND_POLARSSL CURL_DEPRECATED(7.69.0, "") = 6,
CURLSSLBACKEND_WOLFSSL = 7,
CURLSSLBACKEND_SCHANNEL = 8,
CURLSSLBACKEND_SECURETRANSPORT = 9,
CURLSSLBACKEND_SECURETRANSPORT CURL_DEPRECATED(8.15.0, "") = 9,
CURLSSLBACKEND_AXTLS CURL_DEPRECATED(7.61.0, "") = 10,
CURLSSLBACKEND_MBEDTLS = 11,
CURLSSLBACKEND_MESALINK CURL_DEPRECATED(7.82.0, "") = 12,
CURLSSLBACKEND_BEARSSL = 13,
CURLSSLBACKEND_BEARSSL CURL_DEPRECATED(8.15.0, "") = 13,
CURLSSLBACKEND_RUSTLS = 14
} curl_sslbackend;
@@ -645,20 +645,7 @@ typedef enum {
CURLE_UNRECOVERABLE_POLL, /* 99 - poll/select returned fatal error */
CURLE_TOO_LARGE, /* 100 - a value/data met its maximum */
CURLE_ECH_REQUIRED, /* 101 - ECH tried but failed */
CURL_LAST, /* never use! */
CURLE_RESERVED115 = 115, /* 115-126 - used in tests */
CURLE_RESERVED116 = 116,
CURLE_RESERVED117 = 117,
CURLE_RESERVED118 = 118,
CURLE_RESERVED119 = 119,
CURLE_RESERVED120 = 120,
CURLE_RESERVED121 = 121,
CURLE_RESERVED122 = 122,
CURLE_RESERVED123 = 123,
CURLE_RESERVED124 = 124,
CURLE_RESERVED125 = 125,
CURLE_RESERVED126 = 126
CURL_LAST /* never use! */
} CURLcode;
#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
@@ -943,31 +930,31 @@ typedef enum {
have introduced work-arounds for this flaw but those work-arounds sometimes
make the SSL communication fail. To regain functionality with those broken
servers, a user can this way allow the vulnerability back. */
#define CURLSSLOPT_ALLOW_BEAST (1<<0)
#define CURLSSLOPT_ALLOW_BEAST (1L<<0)
/* - NO_REVOKE tells libcurl to disable certificate revocation checks for those
SSL backends where such behavior is present. */
#define CURLSSLOPT_NO_REVOKE (1<<1)
#define CURLSSLOPT_NO_REVOKE (1L<<1)
/* - NO_PARTIALCHAIN tells libcurl to *NOT* accept a partial certificate chain
if possible. The OpenSSL backend has this ability. */
#define CURLSSLOPT_NO_PARTIALCHAIN (1<<2)
#define CURLSSLOPT_NO_PARTIALCHAIN (1L<<2)
/* - REVOKE_BEST_EFFORT tells libcurl to ignore certificate revocation offline
checks and ignore missing revocation list for those SSL backends where such
behavior is present. */
#define CURLSSLOPT_REVOKE_BEST_EFFORT (1<<3)
#define CURLSSLOPT_REVOKE_BEST_EFFORT (1L<<3)
/* - CURLSSLOPT_NATIVE_CA tells libcurl to use standard certificate store of
operating system. Currently implemented under MS-Windows. */
#define CURLSSLOPT_NATIVE_CA (1<<4)
#define CURLSSLOPT_NATIVE_CA (1L<<4)
/* - CURLSSLOPT_AUTO_CLIENT_CERT tells libcurl to automatically locate and use
a client certificate for authentication. (Schannel) */
#define CURLSSLOPT_AUTO_CLIENT_CERT (1<<5)
#define CURLSSLOPT_AUTO_CLIENT_CERT (1L<<5)
/* If possible, send data using TLS 1.3 early data */
#define CURLSSLOPT_EARLYDATA (1<<6)
#define CURLSSLOPT_EARLYDATA (1L<<6)
/* The default connection attempt delay in milliseconds for happy eyeballs.
CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS.3 and happy-eyeballs-timeout-ms.d document
@@ -1967,7 +1954,8 @@ typedef enum {
CURLOPT(CURLOPT_SSL_VERIFYSTATUS, CURLOPTTYPE_LONG, 232),
/* Set if we should enable TLS false start. */
CURLOPT(CURLOPT_SSL_FALSESTART, CURLOPTTYPE_LONG, 233),
CURLOPTDEPRECATED(CURLOPT_SSL_FALSESTART, CURLOPTTYPE_LONG, 233,
8.15.0, "Has no function"),
/* Do not squash dot-dot sequences */
CURLOPT(CURLOPT_PATH_AS_IS, CURLOPTTYPE_LONG, 234),
@@ -2301,10 +2289,10 @@ typedef enum {
/* Below here follows defines for the CURLOPT_IPRESOLVE option. If a host
name resolves addresses using more than one IP protocol version, this
option might be handy to force libcurl to use a specific IP version. */
#define CURL_IPRESOLVE_WHATEVER 0 /* default, uses addresses to all IP
#define CURL_IPRESOLVE_WHATEVER 0L /* default, uses addresses to all IP
versions that your system allows */
#define CURL_IPRESOLVE_V4 1 /* uses only IPv4 addresses/connections */
#define CURL_IPRESOLVE_V6 2 /* uses only IPv6 addresses/connections */
#define CURL_IPRESOLVE_V4 1L /* uses only IPv4 addresses/connections */
#define CURL_IPRESOLVE_V6 2L /* uses only IPv6 addresses/connections */
/* Convenient "aliases" */
#define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER
+4 -4
View File
@@ -32,13 +32,13 @@
/* This is the version number of the libcurl package from which this header
file origins: */
#define LIBCURL_VERSION "8.14.1"
#define LIBCURL_VERSION "8.15.0"
/* The numeric version number is also available "in parts" by using these
defines: */
#define LIBCURL_VERSION_MAJOR 8
#define LIBCURL_VERSION_MINOR 14
#define LIBCURL_VERSION_PATCH 1
#define LIBCURL_VERSION_MINOR 15
#define LIBCURL_VERSION_PATCH 0
/* This is the numeric version of the libcurl version number, meant for easier
parsing and comparisons by programs. The LIBCURL_VERSION_NUM define will
@@ -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 0x080e01
#define LIBCURL_VERSION_NUM 0x080f00
/*
* This is the date and time when the full source package was created. The
+6 -54
View File
@@ -329,7 +329,7 @@
defined(__ppc__) || defined(__powerpc__) || defined(__arm__) || \
defined(__sparc__) || defined(__mips__) || defined(__sh__) || \
defined(__XTENSA__) || \
(defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 4) || \
(defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 4) || \
(defined(__LONG_MAX__) && __LONG_MAX__ == 2147483647L))
# define CURL_TYPEOF_CURL_OFF_T long long
# define CURL_FORMAT_CURL_OFF_T "lld"
@@ -357,11 +357,11 @@
#else
/* generic "safe guess" on old 32-bit style */
# define CURL_TYPEOF_CURL_OFF_T long
# define CURL_FORMAT_CURL_OFF_T "ld"
# define CURL_FORMAT_CURL_OFF_TU "lu"
# define CURL_SUFFIX_CURL_OFF_T L
# define CURL_SUFFIX_CURL_OFF_TU UL
# define CURL_TYPEOF_CURL_OFF_T long long
# define CURL_FORMAT_CURL_OFF_T "lld"
# define CURL_FORMAT_CURL_OFF_TU "llu"
# define CURL_SUFFIX_CURL_OFF_T LL
# define CURL_SUFFIX_CURL_OFF_TU ULL
# define CURL_TYPEOF_CURL_SOCKLEN_T int
#endif
@@ -399,52 +399,4 @@
typedef CURL_TYPEOF_CURL_OFF_T curl_off_t;
#endif
/*
* CURL_ISOCPP and CURL_OFF_T_C definitions are done here in order to allow
* these to be visible and exported by the external libcurl interface API,
* while also making them visible to the library internals, simply including
* curl_setup.h, without actually needing to include curl.h internally.
* If some day this section would grow big enough, all this should be moved
* to its own header file.
*/
/*
* Figure out if we can use the ## preprocessor operator, which is supported
* by ISO/ANSI C and C++. Some compilers support it without setting __STDC__
* or __cplusplus so we need to carefully check for them too.
*/
#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \
defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \
defined(__POCC__) || defined(__HIGHC__) || \
defined(__ILEC400__)
/* This compiler is believed to have an ISO compatible preprocessor */
#define CURL_ISOCPP
#else
/* This compiler is believed NOT to have an ISO compatible preprocessor */
#undef CURL_ISOCPP
#endif
/*
* Macros for minimum-width signed and unsigned curl_off_t integer constants.
*/
#if defined(__BORLANDC__) && (__BORLANDC__ == 0x0551)
# define CURLINC_OFF_T_C_HLPR2(x) x
# define CURLINC_OFF_T_C_HLPR1(x) CURLINC_OFF_T_C_HLPR2(x)
# define CURL_OFF_T_C(Val) CURLINC_OFF_T_C_HLPR1(Val) ## \
CURLINC_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_T)
# define CURL_OFF_TU_C(Val) CURLINC_OFF_T_C_HLPR1(Val) ## \
CURLINC_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_TU)
#else
# ifdef CURL_ISOCPP
# define CURLINC_OFF_T_C_HLPR2(Val,Suffix) Val ## Suffix
# else
# define CURLINC_OFF_T_C_HLPR2(Val,Suffix) Val/**/Suffix
# endif
# define CURLINC_OFF_T_C_HLPR1(Val,Suffix) CURLINC_OFF_T_C_HLPR2(Val,Suffix)
# define CURL_OFF_T_C(Val) CURLINC_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_T)
# define CURL_OFF_TU_C(Val) CURLINC_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_TU)
#endif
#endif /* CURLINC_SYSTEM_H */
+14 -21
View File
@@ -29,7 +29,7 @@ set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS "${CURL_DEBUG_MACROS}
configure_file("curl_config.h.cmake" "${CMAKE_CURRENT_BINARY_DIR}/curl_config.h")
# Get 'CSOURCES', 'HHEADERS' variables
# Get CSOURCES, HHEADERS, LIB_RCFILES variables
curl_transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
include("${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
@@ -41,10 +41,6 @@ set_property(DIRECTORY APPEND PROPERTY INCLUDE_DIRECTORIES
"${PROJECT_BINARY_DIR}/lib" # for "curl_config.h"
)
if(USE_ARES)
include_directories(SYSTEM ${CARES_INCLUDE_DIRS})
endif()
#-----------------------------------------------------------------------------
# XXX(cmake): begin cmake-specific curl code
unset(LIBCURL_OUTPUT_NAME CACHE)
@@ -85,23 +81,21 @@ return() # The rest of this file is not needed for building within CMake.
#-----------------------------------------------------------------------------
if(CURL_BUILD_TESTING)
add_library(
curlu # special libcurlu library just for unittests
STATIC
EXCLUDE_FROM_ALL
${HHEADERS} ${CSOURCES}
)
# special libcurlu library just for unittests
add_library(curlu STATIC EXCLUDE_FROM_ALL ${HHEADERS} ${CSOURCES})
target_compile_definitions(curlu PUBLIC "CURL_STATICLIB" "UNITTESTS")
target_link_libraries(curlu PRIVATE ${CURL_LIBS})
# There is plenty of parallelism when building the testdeps target.
# Override the curlu batch size with the maximum to optimize performance.
set_target_properties(curlu PROPERTIES UNITY_BUILD_BATCH_SIZE 0)
endif()
set_target_properties(curlu PROPERTIES UNITY_BUILD_BATCH_SIZE 0 C_CLANG_TIDY "")
if(ENABLE_CURLDEBUG)
# We must compile this source separately to avoid memdebug.h redefinitions
# applying to it.
set_source_files_properties("memdebug.c" PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/unitprotos.h"
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
COMMAND ${PERL_EXECUTABLE} "${PROJECT_SOURCE_DIR}/scripts/extract-unit-protos"
${CSOURCES} > "${CMAKE_CURRENT_BINARY_DIR}/unitprotos.h"
DEPENDS "${PROJECT_SOURCE_DIR}/scripts/extract-unit-protos" ${CSOURCES}
VERBATIM)
add_custom_target(curlu-unitprotos ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/unitprotos.h")
endif()
## Library definition
@@ -220,7 +214,7 @@ if(BUILD_SHARED_LIBS)
add_library(${PROJECT_NAME}::${LIB_SHARED} ALIAS ${LIB_SHARED})
if(WIN32)
set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES "dllmain.c")
set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES "libcurl.rc")
set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES ${LIB_RCFILES})
if(CURL_HIDES_PRIVATE_SYMBOLS)
set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES "${PROJECT_SOURCE_DIR}/lib/libcurl.def")
endif()
@@ -256,6 +250,7 @@ if(BUILD_SHARED_LIBS)
CMAKE_SYSTEM_NAME STREQUAL "Linux" OR
CMAKE_SYSTEM_NAME STREQUAL "SunOS" OR
CMAKE_SYSTEM_NAME STREQUAL "Haiku" OR
CMAKE_SYSTEM_NAME STREQUAL "OHOS" OR # OpenHarmony
CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
set(_soversion_default TRUE)
else()
@@ -266,7 +261,7 @@ if(BUILD_SHARED_LIBS)
option(CURL_LIBCURL_VERSIONED_SYMBOLS "Enable libcurl versioned symbols" OFF)
if(CURL_LIBCURL_SOVERSION OR CURL_LIBCURL_VERSIONED_SYMBOLS)
# Get 'VERSIONCHANGE', 'VERSIONADD', 'VERSIONDEL', 'VERSIONINFO' variables
# Get VERSIONCHANGE, VERSIONADD, VERSIONDEL, VERSIONINFO variables
curl_transform_makefile_inc("Makefile.soname" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake")
include("${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake")
@@ -290,8 +285,6 @@ if(BUILD_SHARED_LIBS)
set(CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX "OPENSSL_")
elseif(CURL_USE_MBEDTLS)
set(CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX "MBEDTLS_")
elseif(CURL_USE_BEARSSL)
set(CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX "BEARSSL_")
elseif(CURL_USE_WOLFSSL)
set(CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX "WOLFSSL_")
elseif(CURL_USE_GNUTLS)
+6 -6
View File
@@ -21,10 +21,12 @@
# SPDX-License-Identifier: curl
#
###########################################################################
# Shared between CMakeLists.txt and Makefile.am
LIB_CURLX_CFILES = \
curlx/base64.c \
curlx/dynbuf.c \
curlx/inet_ntop.c \
curlx/inet_pton.c \
curlx/multibyte.c \
curlx/nonblock.c \
@@ -32,13 +34,16 @@ LIB_CURLX_CFILES = \
curlx/timediff.c \
curlx/timeval.c \
curlx/version_win32.c \
curlx/wait.c \
curlx/warnless.c \
curlx/winapi.c
LIB_CURLX_HFILES = \
curlx/binmode.h \
curlx/base64.h \
curlx/curlx.h \
curlx/dynbuf.h \
curlx/inet_ntop.h \
curlx/inet_pton.h \
curlx/multibyte.h \
curlx/nonblock.h \
@@ -46,6 +51,7 @@ LIB_CURLX_HFILES = \
curlx/timediff.h \
curlx/timeval.h \
curlx/version_win32.h \
curlx/wait.h \
curlx/warnless.h \
curlx/winapi.h
@@ -69,7 +75,6 @@ LIB_VAUTH_HFILES = \
vauth/vauth.h
LIB_VTLS_CFILES = \
vtls/bearssl.c \
vtls/cipher_suite.c \
vtls/gtls.c \
vtls/hostcheck.c \
@@ -80,7 +85,6 @@ LIB_VTLS_CFILES = \
vtls/rustls.c \
vtls/schannel.c \
vtls/schannel_verify.c \
vtls/sectransp.c \
vtls/vtls.c \
vtls/vtls_scache.c \
vtls/vtls_spack.c \
@@ -88,7 +92,6 @@ LIB_VTLS_CFILES = \
vtls/x509asn1.c
LIB_VTLS_HFILES = \
vtls/bearssl.h \
vtls/cipher_suite.h \
vtls/gtls.h \
vtls/hostcheck.h \
@@ -99,7 +102,6 @@ LIB_VTLS_HFILES = \
vtls/rustls.h \
vtls/schannel.h \
vtls/schannel_int.h \
vtls/sectransp.h \
vtls/vtls.h \
vtls/vtls_int.h \
vtls/vtls_scache.h \
@@ -208,7 +210,6 @@ LIB_CFILES = \
idn.c \
if2ip.c \
imap.c \
inet_ntop.c \
krb5.c \
ldap.c \
llist.c \
@@ -345,7 +346,6 @@ LIB_HFILES = \
idn.h \
if2ip.h \
imap.h \
inet_ntop.h \
llist.h \
macos.h \
memdebug.h \
+6 -4
View File
@@ -32,7 +32,6 @@
#include "urldata.h"
#include "altsvc.h"
#include "curl_get_line.h"
#include "strcase.h"
#include "parsedate.h"
#include "sendf.h"
#include "curlx/warnless.h"
@@ -416,7 +415,7 @@ static bool hostcompare(const char *host, const char *check)
if(hlen != clen)
/* they cannot match if they have different lengths */
return FALSE;
return strncasecompare(host, check, hlen);
return curl_strnequal(host, check, hlen);
}
/* altsvc_flush() removes all alternatives for this source origin from the
@@ -487,8 +486,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
DEBUGASSERT(asi);
/* initial check for "clear" */
if(!curlx_str_until(&p, &alpn, MAX_ALTSVC_LINE, ';') &&
!curlx_str_single(&p, ';')) {
if(!curlx_str_cspn(&p, &alpn, ";\n\r")) {
curlx_str_trimblanks(&alpn);
/* "clear" is a magic keyword */
if(curlx_str_casecompare(&alpn, "clear")) {
@@ -666,4 +664,8 @@ bool Curl_altsvc_lookup(struct altsvcinfo *asi,
return FALSE;
}
#if defined(DEBUGBUILD) || defined(UNITTESTS)
#undef time
#endif
#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_ALTSVC */
+4 -3
View File
@@ -48,6 +48,7 @@
#endif
#include "urldata.h"
#include "cfilters.h"
#include "sendf.h"
#include "hostip.h"
#include "hash.h"
@@ -451,8 +452,7 @@ CURLcode Curl_async_await(struct Curl_easy *data,
/* Operation complete, if the lookup was successful we now have the entry
in the cache. */
data->state.async.done = TRUE;
if(entry)
*entry = data->state.async.dns;
*entry = data->state.async.dns;
if(result)
ares_cancel(ares->channel);
@@ -758,7 +758,8 @@ struct Curl_addrinfo *Curl_async_getaddrinfo(struct Curl_easy *data,
(pf == PF_UNSPEC) ? "A+AAAA" :
((pf == PF_INET) ? "A" : "AAAA"));
hints.ai_family = pf;
hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP) ?
hints.ai_socktype =
(Curl_conn_get_transport(data, data->conn) == TRNSPRT_TCP) ?
SOCK_STREAM : SOCK_DGRAM;
/* Since the service is a numerical one, set the hint flags
* accordingly to save a call to getservbyname in inside C-Ares
+4 -2
View File
@@ -55,13 +55,13 @@
#endif
#include "urldata.h"
#include "cfilters.h"
#include "sendf.h"
#include "hostip.h"
#include "hash.h"
#include "share.h"
#include "url.h"
#include "multiif.h"
#include "inet_ntop.h"
#include "curl_threads.h"
#include "strdup.h"
@@ -423,6 +423,7 @@ static bool async_thrdd_init(struct Curl_easy *data,
data->state.async.done = FALSE;
data->state.async.port = port;
data->state.async.ip_version = ip_version;
free(data->state.async.hostname);
data->state.async.hostname = strdup(hostname);
if(!data->state.async.hostname)
goto err_exit;
@@ -741,7 +742,8 @@ struct Curl_addrinfo *Curl_async_getaddrinfo(struct Curl_easy *data,
memset(&hints, 0, sizeof(hints));
hints.ai_family = pf;
hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP) ?
hints.ai_socktype =
(Curl_conn_get_transport(data, data->conn) == TRNSPRT_TCP) ?
SOCK_STREAM : SOCK_DGRAM;
/* fire up a new resolver thread! */
+101 -209
View File
@@ -86,44 +86,26 @@ static size_t chunk_read(struct buf_chunk *chunk,
}
}
static size_t chunk_unwrite(struct buf_chunk *chunk, size_t len)
{
size_t n = chunk->w_offset - chunk->r_offset;
DEBUGASSERT(chunk->w_offset >= chunk->r_offset);
if(!n) {
return 0;
}
else if(n <= len) {
chunk->r_offset = chunk->w_offset = 0;
return n;
}
else {
chunk->w_offset -= len;
return len;
}
}
static ssize_t chunk_slurpn(struct buf_chunk *chunk, size_t max_len,
Curl_bufq_reader *reader,
void *reader_ctx, CURLcode *err)
static CURLcode chunk_slurpn(struct buf_chunk *chunk, size_t max_len,
Curl_bufq_reader *reader,
void *reader_ctx, size_t *pnread)
{
unsigned char *p = &chunk->x.data[chunk->w_offset];
size_t n = chunk->dlen - chunk->w_offset; /* free amount */
ssize_t nread;
CURLcode result;
*pnread = 0;
DEBUGASSERT(chunk->dlen >= chunk->w_offset);
if(!n) {
*err = CURLE_AGAIN;
return -1;
}
if(!n)
return CURLE_AGAIN;
if(max_len && n > max_len)
n = max_len;
nread = reader(reader_ctx, p, n, err);
if(nread > 0) {
DEBUGASSERT((size_t)nread <= n);
chunk->w_offset += nread;
result = reader(reader_ctx, p, n, pnread);
if(!result) {
DEBUGASSERT(*pnread <= n);
chunk->w_offset += *pnread;
}
return nread;
return result;
}
static void chunk_peek(const struct buf_chunk *chunk,
@@ -357,49 +339,6 @@ static void prune_head(struct bufq *q)
}
}
static struct buf_chunk *chunk_prev(struct buf_chunk *head,
struct buf_chunk *chunk)
{
while(head) {
if(head == chunk)
return NULL;
if(head->next == chunk)
return head;
head = head->next;
}
return NULL;
}
static void prune_tail(struct bufq *q)
{
struct buf_chunk *chunk;
while(q->tail && chunk_is_empty(q->tail)) {
chunk = q->tail;
q->tail = chunk_prev(q->head, chunk);
if(q->tail)
q->tail->next = NULL;
if(q->head == chunk)
q->head = q->tail;
if(q->pool) {
bufcp_put(q->pool, chunk);
--q->chunk_count;
}
else if((q->chunk_count > q->max_chunks) ||
(q->opts & BUFQ_OPT_NO_SPARES)) {
/* SOFT_LIMIT allowed us more than max. free spares until
* we are at max again. Or free them if we are configured
* to not use spares. */
free(chunk);
--q->chunk_count;
}
else {
chunk->next = q->spare;
q->spare = chunk;
}
}
}
static struct buf_chunk *get_non_full_tail(struct bufq *q)
{
struct buf_chunk *chunk;
@@ -421,90 +360,60 @@ static struct buf_chunk *get_non_full_tail(struct bufq *q)
return chunk;
}
ssize_t Curl_bufq_write(struct bufq *q,
const unsigned char *buf, size_t len,
CURLcode *err)
CURLcode Curl_bufq_write(struct bufq *q,
const unsigned char *buf, size_t len,
size_t *pnwritten)
{
struct buf_chunk *tail;
ssize_t nwritten = 0;
size_t n;
DEBUGASSERT(q->max_chunks > 0);
*pnwritten = 0;
while(len) {
tail = get_non_full_tail(q);
if(!tail) {
if((q->chunk_count < q->max_chunks) || (q->opts & BUFQ_OPT_SOFT_LIMIT)) {
*err = CURLE_OUT_OF_MEMORY;
return -1;
}
if((q->chunk_count < q->max_chunks) || (q->opts & BUFQ_OPT_SOFT_LIMIT))
/* should have gotten a tail, but did not */
return CURLE_OUT_OF_MEMORY;
break;
}
n = chunk_append(tail, buf, len);
if(!n)
break;
nwritten += n;
*pnwritten += n;
buf += n;
len -= n;
}
if(nwritten == 0 && len) {
*err = CURLE_AGAIN;
return -1;
}
*err = CURLE_OK;
return nwritten;
return (!*pnwritten && len) ? CURLE_AGAIN : CURLE_OK;
}
CURLcode Curl_bufq_cwrite(struct bufq *q,
const char *buf, size_t len,
size_t *pnwritten)
{
ssize_t n;
CURLcode result;
n = Curl_bufq_write(q, (const unsigned char *)buf, len, &result);
*pnwritten = (n < 0) ? 0 : (size_t)n;
return result;
return Curl_bufq_write(q, (const unsigned char *)buf, len, pnwritten);
}
CURLcode Curl_bufq_unwrite(struct bufq *q, size_t len)
CURLcode Curl_bufq_read(struct bufq *q, unsigned char *buf, size_t len,
size_t *pnread)
{
while(len && q->tail) {
len -= chunk_unwrite(q->tail, len);
prune_tail(q);
}
return len ? CURLE_AGAIN : CURLE_OK;
}
ssize_t Curl_bufq_read(struct bufq *q, unsigned char *buf, size_t len,
CURLcode *err)
{
ssize_t nread = 0;
size_t n;
*err = CURLE_OK;
*pnread = 0;
while(len && q->head) {
n = chunk_read(q->head, buf, len);
size_t n = chunk_read(q->head, buf, len);
if(n) {
nread += n;
*pnread += n;
buf += n;
len -= n;
}
prune_head(q);
}
if(nread == 0) {
*err = CURLE_AGAIN;
return -1;
}
return nread;
return (!*pnread) ? CURLE_AGAIN : CURLE_OK;
}
CURLcode Curl_bufq_cread(struct bufq *q, char *buf, size_t len,
size_t *pnread)
{
ssize_t n;
CURLcode result;
n = Curl_bufq_read(q, (unsigned char *)buf, len, &result);
*pnread = (n < 0) ? 0 : (size_t)n;
return result;
return Curl_bufq_read(q, (unsigned char *)buf, len, pnread);
}
bool Curl_bufq_peek(struct bufq *q,
@@ -556,156 +465,139 @@ void Curl_bufq_skip(struct bufq *q, size_t amount)
}
}
ssize_t Curl_bufq_pass(struct bufq *q, Curl_bufq_writer *writer,
void *writer_ctx, CURLcode *err)
CURLcode Curl_bufq_pass(struct bufq *q, Curl_bufq_writer *writer,
void *writer_ctx, size_t *pwritten)
{
const unsigned char *buf;
size_t blen;
ssize_t nwritten = 0;
CURLcode result = CURLE_OK;
*pwritten = 0;
while(Curl_bufq_peek(q, &buf, &blen)) {
ssize_t chunk_written;
size_t chunk_written;
chunk_written = writer(writer_ctx, buf, blen, err);
if(chunk_written < 0) {
if(!nwritten || *err != CURLE_AGAIN) {
/* blocked on first write or real error, fail */
nwritten = -1;
result = writer(writer_ctx, buf, blen, &chunk_written);
if(result) {
if((result == CURLE_AGAIN) && *pwritten) {
/* blocked on subsequent write, report success */
result = CURLE_OK;
}
break;
}
if(!chunk_written) {
if(!nwritten) {
if(!*pwritten) {
/* treat as blocked */
*err = CURLE_AGAIN;
nwritten = -1;
result = CURLE_AGAIN;
}
break;
}
Curl_bufq_skip(q, (size_t)chunk_written);
nwritten += chunk_written;
*pwritten += chunk_written;
Curl_bufq_skip(q, chunk_written);
}
return nwritten;
return result;
}
ssize_t Curl_bufq_write_pass(struct bufq *q,
const unsigned char *buf, size_t len,
Curl_bufq_writer *writer, void *writer_ctx,
CURLcode *err)
CURLcode Curl_bufq_write_pass(struct bufq *q,
const unsigned char *buf, size_t len,
Curl_bufq_writer *writer, void *writer_ctx,
size_t *pwritten)
{
ssize_t nwritten = 0, n;
CURLcode result = CURLE_OK;
size_t n;
*err = CURLE_OK;
*pwritten = 0;
while(len) {
if(Curl_bufq_is_full(q)) {
/* try to make room in case we are full */
n = Curl_bufq_pass(q, writer, writer_ctx, err);
if(n < 0) {
if(*err != CURLE_AGAIN) {
result = Curl_bufq_pass(q, writer, writer_ctx, &n);
if(result) {
if(result != CURLE_AGAIN) {
/* real error, fail */
return -1;
return result;
}
/* would block, bufq is full, give up */
break;
}
}
/* Add whatever is remaining now to bufq */
n = Curl_bufq_write(q, buf, len, err);
if(n < 0) {
if(*err != CURLE_AGAIN) {
/* Add to bufq as much as there is room for */
result = Curl_bufq_write(q, buf, len, &n);
if(result) {
if(result != CURLE_AGAIN)
/* real error, fail */
return -1;
}
/* no room in bufq */
break;
return result;
if((result == CURLE_AGAIN) && *pwritten)
/* we did write successfully before */
result = CURLE_OK;
return result;
}
/* edge case of writer returning 0 (and len is >0)
* break or we might enter an infinite loop here */
if(n == 0)
else if(n == 0)
/* edge case of writer returning 0 (and len is >0)
* break or we might enter an infinite loop here */
break;
/* Maybe only part of `data` has been added, continue to loop */
buf += (size_t)n;
len -= (size_t)n;
nwritten += (size_t)n;
/* Track what we added to bufq */
buf += n;
len -= n;
*pwritten += n;
}
if(!nwritten && len) {
*err = CURLE_AGAIN;
return -1;
}
*err = CURLE_OK;
return nwritten;
return (!*pwritten && len) ? CURLE_AGAIN : CURLE_OK;
}
ssize_t Curl_bufq_sipn(struct bufq *q, size_t max_len,
Curl_bufq_reader *reader, void *reader_ctx,
CURLcode *err)
CURLcode Curl_bufq_sipn(struct bufq *q, size_t max_len,
Curl_bufq_reader *reader, void *reader_ctx,
size_t *pnread)
{
struct buf_chunk *tail = NULL;
ssize_t nread;
*err = CURLE_AGAIN;
*pnread = 0;
tail = get_non_full_tail(q);
if(!tail) {
if(q->chunk_count < q->max_chunks) {
*err = CURLE_OUT_OF_MEMORY;
return -1;
}
if(q->chunk_count < q->max_chunks)
return CURLE_OUT_OF_MEMORY;
/* full, blocked */
*err = CURLE_AGAIN;
return -1;
return CURLE_AGAIN;
}
nread = chunk_slurpn(tail, max_len, reader, reader_ctx, err);
if(nread < 0) {
return -1;
}
else if(nread == 0) {
/* eof */
*err = CURLE_OK;
}
return nread;
return chunk_slurpn(tail, max_len, reader, reader_ctx, pnread);
}
/**
* Read up to `max_len` bytes and append it to the end of the buffer queue.
* if `max_len` is 0, no limit is imposed and the call behaves exactly
* the same as `Curl_bufq_slurp()`.
* Returns the total amount of buf read (may be 0) or -1 on other
* reader errors.
* Note that even in case of a -1 chunks may have been read and
* Returns the total amount of buf read (may be 0) in `pnread` or error
* Note that even in case of an error chunks may have been read and
* the buffer queue will have different length than before.
*/
static ssize_t bufq_slurpn(struct bufq *q, size_t max_len,
Curl_bufq_reader *reader, void *reader_ctx,
CURLcode *err)
static CURLcode bufq_slurpn(struct bufq *q, size_t max_len,
Curl_bufq_reader *reader, void *reader_ctx,
size_t *pnread)
{
ssize_t nread = 0, n;
CURLcode result;
*err = CURLE_AGAIN;
*pnread = 0;
while(1) {
n = Curl_bufq_sipn(q, max_len, reader, reader_ctx, err);
if(n < 0) {
if(!nread || *err != CURLE_AGAIN) {
size_t n;
result = Curl_bufq_sipn(q, max_len, reader, reader_ctx, &n);
if(result) {
if(!*pnread || result != CURLE_AGAIN) {
/* blocked on first read or real error, fail */
nread = -1;
return result;
}
else
*err = CURLE_OK;
result = CURLE_OK;
break;
}
else if(n == 0) {
/* eof */
*err = CURLE_OK;
result = CURLE_OK;
break;
}
nread += (size_t)n;
*pnread += n;
if(max_len) {
DEBUGASSERT((size_t)n <= max_len);
max_len -= (size_t)n;
DEBUGASSERT(n <= max_len);
max_len -= n;
if(!max_len)
break;
}
@@ -713,11 +605,11 @@ static ssize_t bufq_slurpn(struct bufq *q, size_t max_len,
if(q->tail && !chunk_is_full(q->tail))
break;
}
return nread;
return result;
}
ssize_t Curl_bufq_slurp(struct bufq *q, Curl_bufq_reader *reader,
void *reader_ctx, CURLcode *err)
CURLcode Curl_bufq_slurp(struct bufq *q, Curl_bufq_reader *reader,
void *reader_ctx, size_t *pnread)
{
return bufq_slurpn(q, 0, reader, reader_ctx, err);
return bufq_slurpn(q, 0, reader, reader_ctx, pnread);
}
+28 -38
View File
@@ -163,31 +163,22 @@ bool Curl_bufq_is_full(const struct bufq *q);
/**
* Write buf to the end of the buffer queue. The buf is copied
* and the amount of copied bytes is returned.
* A return code of -1 indicates an error, setting `err` to the
* cause. An err of CURLE_AGAIN is returned if the buffer queue is full.
* CURLE_AGAIN is returned if the buffer queue is full.
*/
ssize_t Curl_bufq_write(struct bufq *q,
const unsigned char *buf, size_t len,
CURLcode *err);
CURLcode Curl_bufq_cwrite(struct bufq *q,
const char *buf, size_t len,
CURLcode Curl_bufq_write(struct bufq *q,
const unsigned char *buf, size_t len,
size_t *pnwritten);
/**
* Remove `len` bytes from the end of the buffer queue again.
* Returns CURLE_AGAIN if less than `len` bytes were in the queue.
*/
CURLcode Curl_bufq_unwrite(struct bufq *q, size_t len);
CURLcode Curl_bufq_cwrite(struct bufq *q,
const char *buf, size_t len,
size_t *pnwritten);
/**
* Read buf from the start of the buffer queue. The buf is copied
* and the amount of copied bytes is returned.
* A return code of -1 indicates an error, setting `err` to the
* cause. An err of CURLE_AGAIN is returned if the buffer queue is empty.
*/
ssize_t Curl_bufq_read(struct bufq *q, unsigned char *buf, size_t len,
CURLcode *err);
CURLcode Curl_bufq_read(struct bufq *q, unsigned char *buf, size_t len,
size_t *pnread);
CURLcode Curl_bufq_cread(struct bufq *q, char *buf, size_t len,
size_t *pnread);
@@ -214,9 +205,9 @@ bool Curl_bufq_peek_at(struct bufq *q, size_t offset,
*/
void Curl_bufq_skip(struct bufq *q, size_t amount);
typedef ssize_t Curl_bufq_writer(void *writer_ctx,
const unsigned char *buf, size_t len,
CURLcode *err);
typedef CURLcode Curl_bufq_writer(void *writer_ctx,
const unsigned char *buf, size_t len,
size_t *pwritten);
/**
* Passes the chunks in the buffer queue to the writer and returns
* the amount of buf written. A writer may return -1 and CURLE_AGAIN
@@ -226,24 +217,23 @@ typedef ssize_t Curl_bufq_writer(void *writer_ctx,
* Note that in case of a -1 chunks may have been written and
* the buffer queue will have different length than before.
*/
ssize_t Curl_bufq_pass(struct bufq *q, Curl_bufq_writer *writer,
void *writer_ctx, CURLcode *err);
CURLcode Curl_bufq_pass(struct bufq *q, Curl_bufq_writer *writer,
void *writer_ctx, size_t *pwritten);
typedef ssize_t Curl_bufq_reader(void *reader_ctx,
unsigned char *buf, size_t len,
CURLcode *err);
typedef CURLcode Curl_bufq_reader(void *reader_ctx,
unsigned char *buf, size_t len,
size_t *pnread);
/**
* Read date and append it to the end of the buffer queue until the
* reader returns blocking or the queue is full. A reader returns
* -1 and CURLE_AGAIN to indicate blocking.
* Returns the total amount of buf read (may be 0) or -1 on other
* reader errors.
* Note that in case of a -1 chunks may have been read and
* CURLE_AGAIN to indicate blocking.
* Returns the total amount of buf read (may be 0) in `pnread` on success.
* Note that in case of an error chunks may have been read and
* the buffer queue will have different length than before.
*/
ssize_t Curl_bufq_slurp(struct bufq *q, Curl_bufq_reader *reader,
void *reader_ctx, CURLcode *err);
CURLcode Curl_bufq_slurp(struct bufq *q, Curl_bufq_reader *reader,
void *reader_ctx, size_t *pnread);
/**
* Read *once* up to `max_len` bytes and append it to the buffer.
@@ -251,9 +241,9 @@ ssize_t Curl_bufq_slurp(struct bufq *q, Curl_bufq_reader *reader,
* Returns the total amount of buf read (may be 0) or -1 on other
* reader errors.
*/
ssize_t Curl_bufq_sipn(struct bufq *q, size_t max_len,
Curl_bufq_reader *reader, void *reader_ctx,
CURLcode *err);
CURLcode Curl_bufq_sipn(struct bufq *q, size_t max_len,
Curl_bufq_reader *reader, void *reader_ctx,
size_t *pnread);
/**
* Write buf to the end of the buffer queue.
@@ -262,9 +252,9 @@ ssize_t Curl_bufq_sipn(struct bufq *q, size_t max_len,
* on or is placed into the buffer, depending on `len` and current
* amount buffered, chunk size, etc.
*/
ssize_t Curl_bufq_write_pass(struct bufq *q,
const unsigned char *buf, size_t len,
Curl_bufq_writer *writer, void *writer_ctx,
CURLcode *err);
CURLcode Curl_bufq_write_pass(struct bufq *q,
const unsigned char *buf, size_t len,
Curl_bufq_writer *writer, void *writer_ctx,
size_t *pwritten);
#endif /* HEADER_CURL_BUFQ_H */
+11 -16
View File
@@ -252,7 +252,7 @@ static CURLcode send_CONNECT(struct Curl_cfilter *cf,
size_t request_len = curlx_dyn_len(&ts->request_data);
size_t blen = request_len;
CURLcode result = CURLE_OK;
ssize_t nwritten;
size_t nwritten;
if(blen <= ts->nsent)
goto out; /* we are done */
@@ -260,16 +260,15 @@ static CURLcode send_CONNECT(struct Curl_cfilter *cf,
blen -= ts->nsent;
buf += ts->nsent;
nwritten = cf->next->cft->do_send(cf->next, data, buf, blen, FALSE, &result);
if(nwritten < 0) {
if(result == CURLE_AGAIN) {
result = cf->next->cft->do_send(cf->next, data, buf, blen, FALSE, &nwritten);
if(result) {
if(result == CURLE_AGAIN)
result = CURLE_OK;
}
goto out;
}
DEBUGASSERT(blen >= (size_t)nwritten);
ts->nsent += (size_t)nwritten;
DEBUGASSERT(blen >= nwritten);
ts->nsent += nwritten;
Curl_debug(data, CURLINFO_HEADER_OUT, buf, (size_t)nwritten);
out:
@@ -375,11 +374,8 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
error = SELECT_OK;
*done = FALSE;
if(!Curl_conn_data_pending(data, cf->sockindex))
return CURLE_OK;
while(ts->keepon) {
ssize_t nread;
size_t nread;
char byte;
/* Read one byte at a time to avoid a race condition. Wait at most one
@@ -397,7 +393,7 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
break;
}
if(nread <= 0) {
if(!nread) {
if(data->set.proxyauth && data->state.authproxy.avail &&
data->state.aptr.proxyuserpwd) {
/* proxy auth was requested and there was proxy auth available,
@@ -687,8 +683,8 @@ out:
}
static void cf_h1_proxy_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
struct Curl_easy *data,
struct easy_pollset *ps)
{
struct h1_tunnel_state *ts = cf->ctx;
@@ -741,7 +737,6 @@ struct Curl_cftype Curl_cft_h1_proxy = {
cf_h1_proxy_connect,
cf_h1_proxy_close,
Curl_cf_def_shutdown,
Curl_cf_http_proxy_get_host,
cf_h1_proxy_adjust_pollset,
Curl_cf_def_data_pending,
Curl_cf_def_send,
@@ -749,7 +744,7 @@ struct Curl_cftype Curl_cft_h1_proxy = {
Curl_cf_def_cntrl,
Curl_cf_def_conn_is_alive,
Curl_cf_def_conn_keep_alive,
Curl_cf_def_query,
Curl_cf_http_proxy_query,
};
CURLcode Curl_cf_h1_proxy_insert_after(struct Curl_cfilter *cf_at,
+125 -179
View File
@@ -28,6 +28,7 @@
#include <nghttp2/nghttp2.h>
#include "urldata.h"
#include "url.h"
#include "cfilters.h"
#include "connect.h"
#include "curl_trc.h"
@@ -80,7 +81,7 @@ struct tunnel_stream {
};
static CURLcode tunnel_stream_init(struct Curl_cfilter *cf,
struct tunnel_stream *ts)
struct tunnel_stream *ts)
{
const char *hostname;
int port;
@@ -218,58 +219,28 @@ static void drain_tunnel(struct Curl_cfilter *cf,
struct tunnel_stream *tunnel)
{
struct cf_h2_proxy_ctx *ctx = cf->ctx;
unsigned char bits;
(void)cf;
bits = CURL_CSELECT_IN;
if(!tunnel->closed && !tunnel->reset &&
!Curl_bufq_is_empty(&ctx->tunnel.sendbuf))
bits |= CURL_CSELECT_OUT;
if(data->state.select_bits != bits) {
CURL_TRC_CF(data, cf, "[%d] DRAIN select_bits=%x",
tunnel->stream_id, bits);
data->state.select_bits = bits;
Curl_expire(data, 0, EXPIRE_RUN_NOW);
}
Curl_multi_mark_dirty(data);
}
static ssize_t proxy_nw_in_reader(void *reader_ctx,
unsigned char *buf, size_t buflen,
CURLcode *err)
{
struct Curl_cfilter *cf = reader_ctx;
ssize_t nread;
if(cf) {
struct Curl_easy *data = CF_DATA_CURRENT(cf);
nread = Curl_conn_cf_recv(cf->next, data, (char *)buf, buflen, err);
CURL_TRC_CF(data, cf, "[0] nw_in_reader(len=%zu) -> %zd, %d",
buflen, nread, *err);
}
else {
nread = 0;
}
return nread;
}
static ssize_t proxy_h2_nw_out_writer(void *writer_ctx,
const unsigned char *buf, size_t buflen,
CURLcode *err)
static CURLcode proxy_h2_nw_out_writer(void *writer_ctx,
const unsigned char *buf, size_t buflen,
size_t *pnwritten)
{
struct Curl_cfilter *cf = writer_ctx;
ssize_t nwritten;
*pnwritten = 0;
if(cf) {
struct Curl_easy *data = CF_DATA_CURRENT(cf);
nwritten = Curl_conn_cf_send(cf->next, data, (const char *)buf, buflen,
FALSE, err);
CURL_TRC_CF(data, cf, "[0] nw_out_writer(len=%zu) -> %zd, %d",
buflen, nwritten, *err);
CURLcode result;
result = Curl_conn_cf_send(cf->next, data, (const char *)buf, buflen,
FALSE, pnwritten);
CURL_TRC_CF(data, cf, "[0] nw_out_writer(len=%zu) -> %d, %zu",
buflen, result, *pnwritten);
return result;
}
else {
nwritten = 0;
}
return nwritten;
return CURLE_FAILED_INIT;
}
static int proxy_h2_client_new(struct Curl_cfilter *cf,
@@ -297,8 +268,8 @@ static int proxy_h2_client_new(struct Curl_cfilter *cf,
}
static ssize_t on_session_send(nghttp2_session *h2,
const uint8_t *buf, size_t blen,
int flags, void *userp);
const uint8_t *buf, size_t blen,
int flags, void *userp);
static int proxy_h2_on_frame_recv(nghttp2_session *session,
const nghttp2_frame *frame,
void *userp);
@@ -414,16 +385,16 @@ static CURLcode proxy_h2_nw_out_flush(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_h2_proxy_ctx *ctx = cf->ctx;
ssize_t nwritten;
size_t nwritten;
CURLcode result;
(void)data;
if(Curl_bufq_is_empty(&ctx->outbufq))
return CURLE_OK;
nwritten = Curl_bufq_pass(&ctx->outbufq, proxy_h2_nw_out_writer, cf,
&result);
if(nwritten < 0) {
result = Curl_bufq_pass(&ctx->outbufq, proxy_h2_nw_out_writer, cf,
&nwritten);
if(result) {
if(result == CURLE_AGAIN) {
CURL_TRC_CF(data, cf, "[0] flush nw send buffer(%zu) -> EAGAIN",
Curl_bufq_len(&ctx->outbufq));
@@ -479,7 +450,7 @@ static CURLcode proxy_h2_progress_ingress(struct Curl_cfilter *cf,
{
struct cf_h2_proxy_ctx *ctx = cf->ctx;
CURLcode result = CURLE_OK;
ssize_t nread;
size_t nread;
/* Process network input buffer fist */
if(!Curl_bufq_is_empty(&ctx->inbufq)) {
@@ -496,10 +467,10 @@ static CURLcode proxy_h2_progress_ingress(struct Curl_cfilter *cf,
Curl_bufq_is_empty(&ctx->inbufq) && /* and we consumed our input */
!Curl_bufq_is_full(&ctx->tunnel.recvbuf)) {
nread = Curl_bufq_slurp(&ctx->inbufq, proxy_nw_in_reader, cf, &result);
CURL_TRC_CF(data, cf, "[0] read %zu bytes nw data -> %zd, %d",
Curl_bufq_len(&ctx->inbufq), nread, result);
if(nread < 0) {
result = Curl_cf_recv_bufq(cf->next, data, &ctx->inbufq, 0, &nread);
CURL_TRC_CF(data, cf, "[0] read %zu bytes nw data -> %d, %zu",
Curl_bufq_len(&ctx->inbufq), result, nread);
if(result) {
if(result != CURLE_AGAIN) {
failf(data, "Failed receiving HTTP2 data");
return result;
@@ -547,17 +518,18 @@ static ssize_t on_session_send(nghttp2_session *h2,
struct Curl_cfilter *cf = userp;
struct cf_h2_proxy_ctx *ctx = cf->ctx;
struct Curl_easy *data = CF_DATA_CURRENT(cf);
ssize_t nwritten;
size_t nwritten;
CURLcode result = CURLE_OK;
(void)h2;
(void)flags;
DEBUGASSERT(data);
nwritten = Curl_bufq_write_pass(&ctx->outbufq, buf, blen,
proxy_h2_nw_out_writer, cf, &result);
if(nwritten < 0) {
result = Curl_bufq_write_pass(&ctx->outbufq, buf, blen,
proxy_h2_nw_out_writer, cf, &nwritten);
if(result) {
if(result == CURLE_AGAIN) {
ctx->nw_out_blocked = 1;
return NGHTTP2_ERR_WOULDBLOCK;
}
failf(data, "Failed sending HTTP2 data");
@@ -567,7 +539,8 @@ static ssize_t on_session_send(nghttp2_session *h2,
if(!nwritten)
return NGHTTP2_ERR_WOULDBLOCK;
return nwritten;
return (nwritten > SSIZE_T_MAX) ?
NGHTTP2_ERR_CALLBACK_FAILURE : (ssize_t)nwritten;
}
#ifndef CURL_DISABLE_VERBOSE_STRINGS
@@ -817,7 +790,7 @@ static ssize_t tunnel_send_callback(nghttp2_session *session,
struct Curl_easy *data = CF_DATA_CURRENT(cf);
struct tunnel_stream *ts;
CURLcode result;
ssize_t nread;
size_t nread;
(void)source;
(void)data;
@@ -831,8 +804,8 @@ static ssize_t tunnel_send_callback(nghttp2_session *session,
return NGHTTP2_ERR_CALLBACK_FAILURE;
DEBUGASSERT(ts == &ctx->tunnel);
nread = Curl_bufq_read(&ts->sendbuf, buf, length, &result);
if(nread < 0) {
result = Curl_bufq_read(&ts->sendbuf, buf, length, &nread);
if(result) {
if(result != CURLE_AGAIN)
return NGHTTP2_ERR_CALLBACK_FAILURE;
return NGHTTP2_ERR_DEFERRED;
@@ -842,7 +815,8 @@ static ssize_t tunnel_send_callback(nghttp2_session *session,
CURL_TRC_CF(data, cf, "[%d] tunnel_send_callback -> %zd",
ts->stream_id, nread);
return nread;
return (nread > SSIZE_T_MAX) ?
NGHTTP2_ERR_CALLBACK_FAILURE : (ssize_t)nread;
}
static int tunnel_recv_callback(nghttp2_session *session, uint8_t flags,
@@ -851,7 +825,7 @@ static int tunnel_recv_callback(nghttp2_session *session, uint8_t flags,
{
struct Curl_cfilter *cf = userp;
struct cf_h2_proxy_ctx *ctx = cf->ctx;
ssize_t nwritten;
size_t nwritten;
CURLcode result;
(void)flags;
@@ -861,14 +835,15 @@ static int tunnel_recv_callback(nghttp2_session *session, uint8_t flags,
if(stream_id != ctx->tunnel.stream_id)
return NGHTTP2_ERR_CALLBACK_FAILURE;
nwritten = Curl_bufq_write(&ctx->tunnel.recvbuf, mem, len, &result);
if(nwritten < 0) {
result = Curl_bufq_write(&ctx->tunnel.recvbuf, mem, len, &nwritten);
if(result) {
if(result != CURLE_AGAIN)
return NGHTTP2_ERR_CALLBACK_FAILURE;
#ifdef DEBUGBUILD
nwritten = 0;
#endif
}
/* tunnel.recbuf has soft limit, any success MUST add all data */
DEBUGASSERT((size_t)nwritten == len);
return 0;
}
@@ -1277,212 +1252,179 @@ static void cf_h2_proxy_adjust_pollset(struct Curl_cfilter *cf,
}
}
static ssize_t h2_handle_tunnel_close(struct Curl_cfilter *cf,
struct Curl_easy *data,
CURLcode *err)
static CURLcode h2_handle_tunnel_close(struct Curl_cfilter *cf,
struct Curl_easy *data,
size_t *pnread)
{
struct cf_h2_proxy_ctx *ctx = cf->ctx;
ssize_t rv = 0;
*pnread = 0;
if(ctx->tunnel.error == NGHTTP2_REFUSED_STREAM) {
CURL_TRC_CF(data, cf, "[%d] REFUSED_STREAM, try again on a new "
"connection", ctx->tunnel.stream_id);
connclose(cf->conn, "REFUSED_STREAM"); /* do not use this anymore */
*err = CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */
return -1;
return CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */
}
else if(ctx->tunnel.error != NGHTTP2_NO_ERROR) {
failf(data, "HTTP/2 stream %u was not closed cleanly: %s (err %u)",
ctx->tunnel.stream_id, nghttp2_http2_strerror(ctx->tunnel.error),
ctx->tunnel.error);
*err = CURLE_HTTP2_STREAM;
return -1;
return CURLE_HTTP2_STREAM;
}
else if(ctx->tunnel.reset) {
failf(data, "HTTP/2 stream %u was reset", ctx->tunnel.stream_id);
*err = CURLE_RECV_ERROR;
return -1;
return CURLE_RECV_ERROR;
}
*err = CURLE_OK;
rv = 0;
CURL_TRC_CF(data, cf, "[%d] handle_tunnel_close -> %zd, %d",
ctx->tunnel.stream_id, rv, *err);
return rv;
CURL_TRC_CF(data, cf, "[%d] handle_tunnel_close -> 0",
ctx->tunnel.stream_id);
return CURLE_OK;
}
static ssize_t tunnel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, CURLcode *err)
static CURLcode tunnel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, size_t *pnread)
{
struct cf_h2_proxy_ctx *ctx = cf->ctx;
ssize_t nread = -1;
CURLcode result = CURLE_AGAIN;
*err = CURLE_AGAIN;
if(!Curl_bufq_is_empty(&ctx->tunnel.recvbuf)) {
nread = Curl_bufq_read(&ctx->tunnel.recvbuf,
(unsigned char *)buf, len, err);
if(nread < 0)
goto out;
DEBUGASSERT(nread > 0);
}
if(nread < 0) {
*pnread = 0;
if(!Curl_bufq_is_empty(&ctx->tunnel.recvbuf))
result = Curl_bufq_cread(&ctx->tunnel.recvbuf, buf, len, pnread);
else {
if(ctx->tunnel.closed) {
nread = h2_handle_tunnel_close(cf, data, err);
result = h2_handle_tunnel_close(cf, data, pnread);
}
else if(ctx->tunnel.reset ||
(ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) ||
(ctx->rcvd_goaway &&
ctx->last_stream_id < ctx->tunnel.stream_id)) {
*err = CURLE_RECV_ERROR;
nread = -1;
result = CURLE_RECV_ERROR;
}
}
else if(nread == 0) {
*err = CURLE_AGAIN;
nread = -1;
else
result = CURLE_AGAIN;
}
out:
CURL_TRC_CF(data, cf, "[%d] tunnel_recv(len=%zu) -> %zd, %d",
ctx->tunnel.stream_id, len, nread, *err);
return nread;
CURL_TRC_CF(data, cf, "[%d] tunnel_recv(len=%zu) -> %d, %zu",
ctx->tunnel.stream_id, len, result, *pnread);
return result;
}
static ssize_t cf_h2_proxy_recv(struct Curl_cfilter *cf,
struct Curl_easy *data,
char *buf, size_t len, CURLcode *err)
static CURLcode cf_h2_proxy_recv(struct Curl_cfilter *cf,
struct Curl_easy *data,
char *buf, size_t len,
size_t *pnread)
{
struct cf_h2_proxy_ctx *ctx = cf->ctx;
ssize_t nread = -1;
struct cf_call_data save;
CURLcode result;
if(ctx->tunnel.state != H2_TUNNEL_ESTABLISHED) {
*err = CURLE_RECV_ERROR;
return -1;
}
*pnread = 0;
CF_DATA_SAVE(save, cf, data);
if(ctx->tunnel.state != H2_TUNNEL_ESTABLISHED) {
result = CURLE_RECV_ERROR;
goto out;
}
if(Curl_bufq_is_empty(&ctx->tunnel.recvbuf)) {
*err = proxy_h2_progress_ingress(cf, data);
if(*err)
result = proxy_h2_progress_ingress(cf, data);
if(result)
goto out;
}
nread = tunnel_recv(cf, data, buf, len, err);
result = tunnel_recv(cf, data, buf, len, pnread);
if(nread > 0) {
CURL_TRC_CF(data, cf, "[%d] increase window by %zd",
ctx->tunnel.stream_id, nread);
nghttp2_session_consume(ctx->h2, ctx->tunnel.stream_id, (size_t)nread);
if(!result) {
CURL_TRC_CF(data, cf, "[%d] increase window by %zu",
ctx->tunnel.stream_id, *pnread);
nghttp2_session_consume(ctx->h2, ctx->tunnel.stream_id, *pnread);
}
result = proxy_h2_progress_egress(cf, data);
if(result && (result != CURLE_AGAIN)) {
*err = result;
nread = -1;
}
result = Curl_1st_fatal(result, proxy_h2_progress_egress(cf, data));
out:
if(!Curl_bufq_is_empty(&ctx->tunnel.recvbuf) &&
(nread >= 0 || *err == CURLE_AGAIN)) {
(!result || (result == CURLE_AGAIN))) {
/* data pending and no fatal error to report. Need to trigger
* draining to avoid stalling when no socket events happen. */
drain_tunnel(cf, data, &ctx->tunnel);
}
CURL_TRC_CF(data, cf, "[%d] cf_recv(len=%zu) -> %zd %d",
ctx->tunnel.stream_id, len, nread, *err);
CURL_TRC_CF(data, cf, "[%d] cf_recv(len=%zu) -> %d, %zu",
ctx->tunnel.stream_id, len, result, *pnread);
CF_DATA_RESTORE(cf, save);
return nread;
return result;
}
static ssize_t cf_h2_proxy_send(struct Curl_cfilter *cf,
struct Curl_easy *data,
const void *buf, size_t len, bool eos,
CURLcode *err)
static CURLcode cf_h2_proxy_send(struct Curl_cfilter *cf,
struct Curl_easy *data,
const void *buf, size_t len, bool eos,
size_t *pnwritten)
{
struct cf_h2_proxy_ctx *ctx = cf->ctx;
struct cf_call_data save;
int rv;
ssize_t nwritten;
CURLcode result;
(void)eos;
if(ctx->tunnel.state != H2_TUNNEL_ESTABLISHED) {
*err = CURLE_SEND_ERROR;
return -1;
}
*pnwritten = 0;
CF_DATA_SAVE(save, cf, data);
if(ctx->tunnel.closed) {
nwritten = -1;
*err = CURLE_SEND_ERROR;
if(ctx->tunnel.state != H2_TUNNEL_ESTABLISHED) {
result = CURLE_SEND_ERROR;
goto out;
}
else {
nwritten = Curl_bufq_write(&ctx->tunnel.sendbuf, buf, len, err);
if(nwritten < 0 && (*err != CURLE_AGAIN))
goto out;
if(ctx->tunnel.closed) {
result = CURLE_SEND_ERROR;
goto out;
}
result = Curl_bufq_write(&ctx->tunnel.sendbuf, buf, len, pnwritten);
CURL_TRC_CF(data, cf, "cf_send(), bufq_write %d, %zd", result, *pnwritten);
if(result && (result != CURLE_AGAIN))
goto out;
if(!Curl_bufq_is_empty(&ctx->tunnel.sendbuf)) {
/* req body data is buffered, resume the potentially suspended stream */
rv = nghttp2_session_resume_data(ctx->h2, ctx->tunnel.stream_id);
if(nghttp2_is_fatal(rv)) {
*err = CURLE_SEND_ERROR;
nwritten = -1;
result = CURLE_SEND_ERROR;
goto out;
}
}
result = proxy_h2_progress_ingress(cf, data);
if(result) {
*err = result;
nwritten = -1;
goto out;
}
result = Curl_1st_fatal(result, proxy_h2_progress_ingress(cf, data));
result = Curl_1st_fatal(result, proxy_h2_progress_egress(cf, data));
/* Call the nghttp2 send loop and flush to write ALL buffered data,
* headers and/or request body completely out to the network */
result = proxy_h2_progress_egress(cf, data);
if(result && (result != CURLE_AGAIN)) {
*err = result;
nwritten = -1;
goto out;
}
if(proxy_h2_should_close_session(ctx)) {
if(!result && proxy_h2_should_close_session(ctx)) {
/* nghttp2 thinks this session is done. If the stream has not been
* closed, this is an error state for out transfer */
if(ctx->tunnel.closed) {
*err = CURLE_SEND_ERROR;
nwritten = -1;
result = CURLE_SEND_ERROR;
}
else {
CURL_TRC_CF(data, cf, "[0] send: nothing to do in this session");
*err = CURLE_HTTP2;
nwritten = -1;
result = CURLE_HTTP2;
}
}
out:
if(!Curl_bufq_is_empty(&ctx->tunnel.recvbuf) &&
(nwritten >= 0 || *err == CURLE_AGAIN)) {
(!result || (result == CURLE_AGAIN))) {
/* data pending and no fatal error to report. Need to trigger
* draining to avoid stalling when no socket events happen. */
drain_tunnel(cf, data, &ctx->tunnel);
}
CURL_TRC_CF(data, cf, "[%d] cf_send(len=%zu) -> %zd, %d, "
CURL_TRC_CF(data, cf, "[%d] cf_send(len=%zu) -> %d, %zu, "
"h2 windows %d-%d (stream-conn), buffers %zu-%zu (stream-conn)",
ctx->tunnel.stream_id, len, nwritten, *err,
ctx->tunnel.stream_id, len, result, *pnwritten,
nghttp2_session_get_stream_remote_window_size(
ctx->h2, ctx->tunnel.stream_id),
nghttp2_session_get_remote_window_size(ctx->h2),
Curl_bufq_len(&ctx->tunnel.sendbuf),
Curl_bufq_len(&ctx->outbufq));
CF_DATA_RESTORE(cf, save);
return nwritten;
return result;
}
static CURLcode cf_h2_proxy_flush(struct Curl_cfilter *cf,
@@ -1533,11 +1475,11 @@ static bool proxy_h2_connisalive(struct Curl_cfilter *cf,
not in use by any other transfer, there should not be any data here,
only "protocol frames" */
CURLcode result;
ssize_t nread = -1;
size_t nread;
*input_pending = FALSE;
nread = Curl_bufq_slurp(&ctx->inbufq, proxy_nw_in_reader, cf, &result);
if(nread != -1) {
result = Curl_cf_recv_bufq(cf->next, data, &ctx->inbufq, 0, &nread);
if(!result) {
if(proxy_h2_process_pending_input(cf, data, &result) < 0)
/* immediate error, considered dead */
alive = FALSE;
@@ -1559,15 +1501,16 @@ static bool cf_h2_proxy_is_alive(struct Curl_cfilter *cf,
bool *input_pending)
{
struct cf_h2_proxy_ctx *ctx = cf->ctx;
CURLcode result;
bool alive;
struct cf_call_data save;
*input_pending = FALSE;
CF_DATA_SAVE(save, cf, data);
result = (ctx && ctx->h2 && proxy_h2_connisalive(cf, data, input_pending));
alive = (ctx && ctx->h2 && proxy_h2_connisalive(cf, data, input_pending));
CURL_TRC_CF(data, cf, "[0] conn alive -> %d, input_pending=%d",
result, *input_pending);
alive, *input_pending);
CF_DATA_RESTORE(cf, save);
return result;
return alive;
}
static CURLcode cf_h2_proxy_query(struct Curl_cfilter *cf,
@@ -1577,6 +1520,10 @@ static CURLcode cf_h2_proxy_query(struct Curl_cfilter *cf,
struct cf_h2_proxy_ctx *ctx = cf->ctx;
switch(query) {
case CF_QUERY_HOST_PORT:
*pres1 = (int)cf->conn->http_proxy.port;
*((const char **)pres2) = cf->conn->http_proxy.host.name;
return CURLE_OK;
case CF_QUERY_NEED_FLUSH: {
if(!Curl_bufq_is_empty(&ctx->outbufq) ||
!Curl_bufq_is_empty(&ctx->tunnel.sendbuf)) {
@@ -1624,7 +1571,6 @@ struct Curl_cftype Curl_cft_h2_proxy = {
cf_h2_proxy_connect,
cf_h2_proxy_close,
cf_h2_proxy_shutdown,
Curl_cf_http_proxy_get_host,
cf_h2_proxy_adjust_pollset,
cf_h2_proxy_data_pending,
cf_h2_proxy_send,
+6 -7
View File
@@ -131,17 +131,17 @@ static CURLcode cf_haproxy_connect(struct Curl_cfilter *cf,
case HAPROXY_SEND:
len = curlx_dyn_len(&ctx->data_out);
if(len > 0) {
ssize_t nwritten;
nwritten = Curl_conn_cf_send(cf->next, data,
curlx_dyn_ptr(&ctx->data_out), len, FALSE,
&result);
if(nwritten < 0) {
size_t nwritten;
result = Curl_conn_cf_send(cf->next, data,
curlx_dyn_ptr(&ctx->data_out), len, FALSE,
&nwritten);
if(result) {
if(result != CURLE_AGAIN)
goto out;
result = CURLE_OK;
nwritten = 0;
}
curlx_dyn_tail(&ctx->data_out, len - (size_t)nwritten);
curlx_dyn_tail(&ctx->data_out, len - nwritten);
if(curlx_dyn_len(&ctx->data_out) > 0) {
result = CURLE_OK;
goto out;
@@ -197,7 +197,6 @@ struct Curl_cftype Curl_cft_haproxy = {
cf_haproxy_connect,
cf_haproxy_close,
Curl_cf_def_shutdown,
Curl_cf_def_get_host,
cf_haproxy_adjust_pollset,
Curl_cf_def_data_pending,
Curl_cf_def_send,
+29 -20
View File
@@ -55,6 +55,7 @@ struct cf_hc_baller {
CURLcode result;
struct curltime started;
int reply_ms;
unsigned char transport;
enum alpnid alpn_id;
BIT(shutdown);
};
@@ -117,17 +118,20 @@ struct cf_hc_ctx {
CURLcode result; /* overall result */
struct cf_hc_baller ballers[2];
size_t baller_count;
unsigned int soft_eyeballs_timeout_ms;
unsigned int hard_eyeballs_timeout_ms;
timediff_t soft_eyeballs_timeout_ms;
timediff_t hard_eyeballs_timeout_ms;
};
static void cf_hc_baller_assign(struct cf_hc_baller *b,
enum alpnid alpn_id)
enum alpnid alpn_id,
unsigned char def_transport)
{
b->alpn_id = alpn_id;
b->transport = def_transport;
switch(b->alpn_id) {
case ALPN_h3:
b->name = "h3";
b->transport = TRNSPRT_QUIC;
break;
case ALPN_h2:
b->name = "h2";
@@ -218,6 +222,7 @@ static CURLcode baller_connected(struct Curl_cfilter *cf,
winner->name, (int)curlx_timediff(curlx_now(),
winner->started));
/* install the winning filter below this one. */
cf->next = winner->cf;
winner->cf = NULL;
@@ -268,15 +273,16 @@ static bool time_to_start_next(struct Curl_cfilter *cf,
}
elapsed_ms = curlx_timediff(now, ctx->started);
if(elapsed_ms >= ctx->hard_eyeballs_timeout_ms) {
CURL_TRC_CF(data, cf, "hard timeout of %dms reached, starting %s",
CURL_TRC_CF(data, cf, "hard timeout of %" FMT_TIMEDIFF_T "ms reached, "
"starting %s",
ctx->hard_eyeballs_timeout_ms, ctx->ballers[idx].name);
return TRUE;
}
if((idx > 0) && (elapsed_ms >= ctx->soft_eyeballs_timeout_ms)) {
if(cf_hc_baller_reply_ms(&ctx->ballers[idx - 1], data) < 0) {
CURL_TRC_CF(data, cf, "soft timeout of %dms reached, %s has not "
"seen any data, starting %s",
CURL_TRC_CF(data, cf, "soft timeout of %" FMT_TIMEDIFF_T "ms reached, "
"%s has not seen any data, starting %s",
ctx->soft_eyeballs_timeout_ms,
ctx->ballers[idx - 1].name, ctx->ballers[idx].name);
return TRUE;
@@ -311,11 +317,11 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
DEBUGASSERT(!ctx->ballers[i].cf);
CURL_TRC_CF(data, cf, "connect, init");
ctx->started = now;
cf_hc_baller_init(&ctx->ballers[0], cf, data, cf->conn->transport);
cf_hc_baller_init(&ctx->ballers[0], cf, data, ctx->ballers[0].transport);
if(ctx->baller_count > 1) {
Curl_expire(data, ctx->soft_eyeballs_timeout_ms, EXPIRE_ALPN_EYEBALLS);
CURL_TRC_CF(data, cf, "set next attempt to start in %ums",
ctx->soft_eyeballs_timeout_ms);
CURL_TRC_CF(data, cf, "set next attempt to start in %" FMT_TIMEDIFF_T
"ms", ctx->soft_eyeballs_timeout_ms);
}
ctx->state = CF_HC_CONNECT;
FALLTHROUGH();
@@ -330,7 +336,7 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
}
if(time_to_start_next(cf, data, 1, now)) {
cf_hc_baller_init(&ctx->ballers[1], cf, data, cf->conn->transport);
cf_hc_baller_init(&ctx->ballers[1], cf, data, ctx->ballers[1].transport);
}
if((ctx->baller_count > 1) && cf_hc_baller_is_active(&ctx->ballers[1])) {
@@ -423,8 +429,8 @@ static CURLcode cf_hc_shutdown(struct Curl_cfilter *cf,
}
static void cf_hc_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
struct Curl_easy *data,
struct easy_pollset *ps)
{
if(!cf->connected) {
struct cf_hc_ctx *ctx = cf->ctx;
@@ -561,7 +567,6 @@ struct Curl_cftype Curl_cft_http_connect = {
cf_hc_connect,
cf_hc_close,
cf_hc_shutdown,
Curl_cf_def_get_host,
cf_hc_adjust_pollset,
cf_hc_data_pending,
Curl_cf_def_send,
@@ -574,7 +579,8 @@ struct Curl_cftype Curl_cft_http_connect = {
static CURLcode cf_hc_create(struct Curl_cfilter **pcf,
struct Curl_easy *data,
enum alpnid *alpnids, size_t alpn_count)
enum alpnid *alpnids, size_t alpn_count,
unsigned char def_transport)
{
struct Curl_cfilter *cf = NULL;
struct cf_hc_ctx *ctx;
@@ -596,7 +602,7 @@ static CURLcode cf_hc_create(struct Curl_cfilter **pcf,
goto out;
}
for(i = 0; i < alpn_count; ++i)
cf_hc_baller_assign(&ctx->ballers[i], alpnids[i]);
cf_hc_baller_assign(&ctx->ballers[i], alpnids[i], def_transport);
for(; i < CURL_ARRAYSIZE(ctx->ballers); ++i)
ctx->ballers[i].alpn_id = ALPN_none;
ctx->baller_count = alpn_count;
@@ -616,13 +622,14 @@ out:
static CURLcode cf_http_connect_add(struct Curl_easy *data,
struct connectdata *conn,
int sockindex,
enum alpnid *alpn_ids, size_t alpn_count)
enum alpnid *alpn_ids, size_t alpn_count,
unsigned char def_transport)
{
struct Curl_cfilter *cf;
CURLcode result = CURLE_OK;
DEBUGASSERT(data);
result = cf_hc_create(&cf, data, alpn_ids, alpn_count);
result = cf_hc_create(&cf, data, alpn_ids, alpn_count, def_transport);
if(result)
goto out;
Curl_conn_cf_add(data, conn, sockindex, cf);
@@ -679,7 +686,7 @@ CURLcode Curl_cf_https_setup(struct Curl_easy *data,
continue;
switch(alpn) {
case ALPN_h3:
if(Curl_conn_may_http3(data, conn))
if(Curl_conn_may_http3(data, conn, conn->transport_wanted))
break; /* not possible */
if(data->state.http_neg.allowed & CURL_HTTP_V3x) {
CURL_TRC_CF(data, cf, "adding h3 via HTTPS-RR");
@@ -708,7 +715,7 @@ CURLcode Curl_cf_https_setup(struct Curl_easy *data,
if((alpn_count < CURL_ARRAYSIZE(alpn_ids)) &&
(data->state.http_neg.wanted & CURL_HTTP_V3x) &&
!cf_https_alpns_contain(ALPN_h3, alpn_ids, alpn_count)) {
result = Curl_conn_may_http3(data, conn);
result = Curl_conn_may_http3(data, conn, conn->transport_wanted);
if(!result) {
CURL_TRC_CF(data, cf, "adding wanted h3");
alpn_ids[alpn_count++] = ALPN_h3;
@@ -733,7 +740,9 @@ CURLcode Curl_cf_https_setup(struct Curl_easy *data,
/* If we identified ALPNs to use, install our filter. Otherwise,
* install nothing, so our call will use a default connect setup. */
if(alpn_count) {
result = cf_http_connect_add(data, conn, sockindex, alpn_ids, alpn_count);
result = cf_http_connect_add(data, conn, sockindex,
alpn_ids, alpn_count,
conn->transport_wanted);
}
out:
+51 -76
View File
@@ -73,7 +73,6 @@
#include "url.h" /* for Curl_safefree() */
#include "multiif.h"
#include "sockaddr.h" /* required for Curl_sockaddr_storage */
#include "inet_ntop.h"
#include "curlx/inet_pton.h"
#include "progress.h"
#include "curlx/warnless.h"
@@ -395,10 +394,10 @@ static CURLcode socket_open(struct Curl_easy *data,
*
*/
CURLcode Curl_socket_open(struct Curl_easy *data,
const struct Curl_addrinfo *ai,
struct Curl_sockaddr_ex *addr,
int transport,
curl_socket_t *sockfd)
const struct Curl_addrinfo *ai,
struct Curl_sockaddr_ex *addr,
int transport,
curl_socket_t *sockfd)
{
struct Curl_sockaddr_ex dummy;
CURLcode result;
@@ -996,8 +995,6 @@ static void cf_socket_close(struct Curl_cfilter *cf, struct Curl_easy *data)
cf->conn->sock[cf->sockindex] = CURL_SOCKET_BAD;
socket_close(data, cf->conn, !ctx->accepted, ctx->sock);
ctx->sock = CURL_SOCKET_BAD;
if(ctx->active && cf->sockindex == FIRSTSOCKET)
cf->conn->remote_addr = NULL;
ctx->active = FALSE;
memset(&ctx->started_at, 0, sizeof(ctx->started_at));
memset(&ctx->connected_at, 0, sizeof(ctx->connected_at));
@@ -1095,7 +1092,7 @@ static CURLcode set_remote_ip(struct Curl_cfilter *cf,
}
static CURLcode cf_socket_open(struct Curl_cfilter *cf,
struct Curl_easy *data)
struct Curl_easy *data)
{
struct cf_socket_ctx *ctx = cf->ctx;
int error = 0;
@@ -1378,22 +1375,9 @@ out:
return result;
}
static void cf_socket_get_host(struct Curl_cfilter *cf,
struct Curl_easy *data,
const char **phost,
const char **pdisplay_host,
int *pport)
{
struct cf_socket_ctx *ctx = cf->ctx;
(void)data;
*phost = cf->conn->host.name;
*pdisplay_host = cf->conn->host.dispname;
*pport = ctx->ip.remote_port;
}
static void cf_socket_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
struct Curl_easy *data,
struct easy_pollset *ps)
{
struct cf_socket_ctx *ctx = cf->ctx;
@@ -1420,17 +1404,6 @@ static void cf_socket_adjust_pollset(struct Curl_cfilter *cf,
}
}
static bool cf_socket_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
struct cf_socket_ctx *ctx = cf->ctx;
int readable;
(void)data;
readable = SOCKET_READABLE(ctx->sock, 0);
return readable > 0 && (readable & CURL_CSELECT_IN);
}
#ifdef USE_WINSOCK
#ifndef SIO_IDEAL_SEND_BACKLOG_QUERY
@@ -1457,17 +1430,18 @@ static void win_update_sndbuf_size(struct cf_socket_ctx *ctx)
#endif /* USE_WINSOCK */
static ssize_t cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const void *buf, size_t len, bool eos,
CURLcode *err)
static CURLcode cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const void *buf, size_t len, bool eos,
size_t *pnwritten)
{
struct cf_socket_ctx *ctx = cf->ctx;
curl_socket_t fdsave;
ssize_t nwritten;
size_t orig_len = len;
CURLcode result = CURLE_OK;
(void)eos; /* unused */
*err = CURLE_OK;
*pnwritten = 0;
fdsave = cf->conn->sock[cf->sockindex];
cf->conn->sock[cf->sockindex] = ctx->sock;
@@ -1478,10 +1452,8 @@ static ssize_t cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
Curl_rand_bytes(data, FALSE, &c, 1);
if(c >= ((100-ctx->wblock_percent)*256/100)) {
CURL_TRC_CF(data, cf, "send(len=%zu) SIMULATE EWOULDBLOCK", orig_len);
*err = CURLE_AGAIN;
nwritten = -1;
cf->conn->sock[cf->sockindex] = fdsave;
return nwritten;
return CURLE_AGAIN;
}
}
if(cf->cft != &Curl_cft_udp && ctx->wpartial_percent > 0 && len > 8) {
@@ -1496,15 +1468,14 @@ static ssize_t cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
#if defined(MSG_FASTOPEN) && !defined(TCP_FASTOPEN_CONNECT) /* Linux */
if(cf->conn->bits.tcp_fastopen) {
nwritten = sendto(ctx->sock, buf, len, MSG_FASTOPEN,
&cf->conn->remote_addr->curl_sa_addr,
cf->conn->remote_addr->addrlen);
&ctx->addr.curl_sa_addr, ctx->addr.addrlen);
cf->conn->bits.tcp_fastopen = FALSE;
}
else
#endif
nwritten = swrite(ctx->sock, buf, len);
if(-1 == nwritten) {
if(nwritten < 0) {
int sockerr = SOCKERRNO;
if(
@@ -1521,36 +1492,38 @@ static ssize_t cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
#endif
) {
/* this is just a case of EWOULDBLOCK */
*err = CURLE_AGAIN;
result = CURLE_AGAIN;
}
else {
char buffer[STRERROR_LEN];
failf(data, "Send failure: %s",
Curl_strerror(sockerr, buffer, sizeof(buffer)));
data->state.os_errno = sockerr;
*err = CURLE_SEND_ERROR;
result = CURLE_SEND_ERROR;
}
}
else
*pnwritten = (size_t)nwritten;
#if defined(USE_WINSOCK)
if(!*err)
if(!result)
win_update_sndbuf_size(ctx);
#endif
CURL_TRC_CF(data, cf, "send(len=%zu) -> %d, err=%d",
orig_len, (int)nwritten, *err);
CURL_TRC_CF(data, cf, "send(len=%zu) -> %d, %zu",
orig_len, result, *pnwritten);
cf->conn->sock[cf->sockindex] = fdsave;
return nwritten;
return result;
}
static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, CURLcode *err)
static CURLcode cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, size_t *pnread)
{
struct cf_socket_ctx *ctx = cf->ctx;
CURLcode result = CURLE_OK;
ssize_t nread;
*err = CURLE_OK;
*pnread = 0;
#ifdef DEBUGBUILD
/* simulate network blocking/partial reads */
if(cf->cft != &Curl_cft_udp && ctx->rblock_percent > 0) {
@@ -1558,8 +1531,7 @@ static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
Curl_rand(data, &c, 1);
if(c >= ((100-ctx->rblock_percent)*256/100)) {
CURL_TRC_CF(data, cf, "recv(len=%zu) SIMULATE EWOULDBLOCK", len);
*err = CURLE_AGAIN;
return -1;
return CURLE_AGAIN;
}
}
if(cf->cft != &Curl_cft_udp && ctx->recv_max && ctx->recv_max < len) {
@@ -1570,10 +1542,9 @@ static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
}
#endif
*err = CURLE_OK;
nread = sread(ctx->sock, buf, len);
if(-1 == nread) {
if(nread < 0) {
int sockerr = SOCKERRNO;
if(
@@ -1589,25 +1560,25 @@ static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
#endif
) {
/* this is just a case of EWOULDBLOCK */
*err = CURLE_AGAIN;
result = CURLE_AGAIN;
}
else {
char buffer[STRERROR_LEN];
failf(data, "Recv failure: %s",
Curl_strerror(sockerr, buffer, sizeof(buffer)));
data->state.os_errno = sockerr;
*err = CURLE_RECV_ERROR;
result = CURLE_RECV_ERROR;
}
}
else
*pnread = (size_t)nread;
CURL_TRC_CF(data, cf, "recv(len=%zu) -> %d, err=%d", len, (int)nread,
*err);
if(nread > 0 && !ctx->got_first_byte) {
CURL_TRC_CF(data, cf, "recv(len=%zu) -> %d, %zu", len, result, *pnread);
if(!result && !ctx->got_first_byte) {
ctx->first_byte_at = curlx_now();
ctx->got_first_byte = TRUE;
}
return nread;
return result;
}
static void cf_socket_update_data(struct Curl_cfilter *cf,
@@ -1631,7 +1602,6 @@ static void cf_socket_active(struct Curl_cfilter *cf, struct Curl_easy *data)
set_local_ip(cf, data);
if(cf->sockindex == FIRSTSOCKET) {
cf->conn->primary = ctx->ip;
cf->conn->remote_addr = &ctx->addr;
#ifdef USE_IPV6
cf->conn->bits.ipv6 = (ctx->addr.family == AF_INET6);
#endif
@@ -1713,6 +1683,15 @@ static CURLcode cf_socket_query(struct Curl_cfilter *cf,
DEBUGASSERT(pres2);
*((curl_socket_t *)pres2) = ctx->sock;
return CURLE_OK;
case CF_QUERY_TRANSPORT:
DEBUGASSERT(pres1);
*pres1 = ctx->transport;
return CURLE_OK;
case CF_QUERY_REMOTE_ADDR:
DEBUGASSERT(pres2);
*((const struct Curl_sockaddr_ex **)pres2) = cf->connected ?
&ctx->addr : NULL;
return CURLE_OK;
case CF_QUERY_CONNECT_REPLY_MS:
if(ctx->got_first_byte) {
timediff_t ms = curlx_timediff(ctx->first_byte_at, ctx->started_at);
@@ -1763,9 +1742,8 @@ struct Curl_cftype Curl_cft_tcp = {
cf_tcp_connect,
cf_socket_close,
cf_socket_shutdown,
cf_socket_get_host,
cf_socket_adjust_pollset,
cf_socket_data_pending,
Curl_cf_def_data_pending,
cf_socket_send,
cf_socket_recv,
cf_socket_cntrl,
@@ -1918,9 +1896,8 @@ struct Curl_cftype Curl_cft_udp = {
cf_udp_connect,
cf_socket_close,
cf_socket_shutdown,
cf_socket_get_host,
cf_socket_adjust_pollset,
cf_socket_data_pending,
Curl_cf_def_data_pending,
cf_socket_send,
cf_socket_recv,
cf_socket_cntrl,
@@ -1973,9 +1950,8 @@ struct Curl_cftype Curl_cft_unix = {
cf_tcp_connect,
cf_socket_close,
cf_socket_shutdown,
cf_socket_get_host,
cf_socket_adjust_pollset,
cf_socket_data_pending,
Curl_cf_def_data_pending,
cf_socket_send,
cf_socket_recv,
cf_socket_cntrl,
@@ -2020,7 +1996,7 @@ out:
}
static timediff_t cf_tcp_accept_timeleft(struct Curl_cfilter *cf,
struct Curl_easy *data)
struct Curl_easy *data)
{
struct cf_socket_ctx *ctx = cf->ctx;
timediff_t timeout_ms = DEFAULT_ACCEPT_TIMEOUT;
@@ -2194,9 +2170,8 @@ struct Curl_cftype Curl_cft_tcp_accept = {
cf_tcp_accept_connect,
cf_socket_close,
cf_socket_shutdown,
cf_socket_get_host,
cf_socket_adjust_pollset,
cf_socket_data_pending,
Curl_cf_def_data_pending,
cf_socket_send,
cf_socket_recv,
cf_socket_cntrl,
@@ -2222,7 +2197,7 @@ CURLcode Curl_conn_tcp_listen_set(struct Curl_easy *data,
result = CURLE_OUT_OF_MEMORY;
goto out;
}
ctx->transport = conn->transport;
ctx->transport = TRNSPRT_TCP;
ctx->sock = *s;
ctx->listening = TRUE;
ctx->accepted = FALSE;
+4 -4
View File
@@ -68,10 +68,10 @@ CURLcode Curl_parse_interface(const char *input,
*
*/
CURLcode Curl_socket_open(struct Curl_easy *data,
const struct Curl_addrinfo *ai,
struct Curl_sockaddr_ex *addr,
int transport,
curl_socket_t *sockfd);
const struct Curl_addrinfo *ai,
struct Curl_sockaddr_ex *addr,
int transport,
curl_socket_t *sockfd);
int Curl_socket_close(struct Curl_easy *data, struct connectdata *conn,
curl_socket_t sock);
+194 -99
View File
@@ -67,22 +67,9 @@ CURLcode Curl_cf_def_shutdown(struct Curl_cfilter *cf,
static void conn_report_connect_stats(struct Curl_easy *data,
struct connectdata *conn);
void Curl_cf_def_get_host(struct Curl_cfilter *cf, struct Curl_easy *data,
const char **phost, const char **pdisplay_host,
int *pport)
{
if(cf->next)
cf->next->cft->get_host(cf->next, data, phost, pdisplay_host, pport);
else {
*phost = cf->conn->host.name;
*pdisplay_host = cf->conn->host.dispname;
*pport = cf->conn->primary.remote_port;
}
}
void Curl_cf_def_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
struct Curl_easy *data,
struct easy_pollset *ps)
{
/* NOP */
(void)cf;
@@ -97,21 +84,23 @@ bool Curl_cf_def_data_pending(struct Curl_cfilter *cf,
cf->next->cft->has_data_pending(cf->next, data) : FALSE;
}
ssize_t Curl_cf_def_send(struct Curl_cfilter *cf, struct Curl_easy *data,
CURLcode Curl_cf_def_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const void *buf, size_t len, bool eos,
CURLcode *err)
size_t *pnwritten)
{
return cf->next ?
cf->next->cft->do_send(cf->next, data, buf, len, eos, err) :
CURLE_RECV_ERROR;
if(cf->next)
return cf->next->cft->do_send(cf->next, data, buf, len, eos, pnwritten);
*pnwritten = 0;
return CURLE_RECV_ERROR;
}
ssize_t Curl_cf_def_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, CURLcode *err)
CURLcode Curl_cf_def_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, size_t *pnread)
{
return cf->next ?
cf->next->cft->do_recv(cf->next, data, buf, len, err) :
CURLE_SEND_ERROR;
if(cf->next)
return cf->next->cft->do_recv(cf->next, data, buf, len, pnread);
*pnread = 0;
return CURLE_SEND_ERROR;
}
bool Curl_cf_def_conn_is_alive(struct Curl_cfilter *cf,
@@ -234,52 +223,102 @@ CURLcode Curl_conn_shutdown(struct Curl_easy *data, int sockindex, bool *done)
return result;
}
ssize_t Curl_cf_recv(struct Curl_easy *data, int num, char *buf,
size_t len, CURLcode *code)
CURLcode Curl_cf_recv(struct Curl_easy *data, int num, char *buf,
size_t len, size_t *pnread)
{
struct Curl_cfilter *cf;
DEBUGASSERT(data);
DEBUGASSERT(data->conn);
*code = CURLE_OK;
cf = data->conn->cfilter[num];
while(cf && !cf->connected) {
while(cf && !cf->connected)
cf = cf->next;
}
if(cf) {
ssize_t nread = cf->cft->do_recv(cf, data, buf, len, code);
DEBUGASSERT(nread >= 0 || *code);
DEBUGASSERT(nread < 0 || !*code);
return nread;
}
if(cf)
return cf->cft->do_recv(cf, data, buf, len, pnread);
failf(data, "recv: no filter connected");
*code = CURLE_FAILED_INIT;
return -1;
DEBUGASSERT(0);
*pnread = 0;
return CURLE_FAILED_INIT;
}
ssize_t Curl_cf_send(struct Curl_easy *data, int num,
const void *mem, size_t len, bool eos,
CURLcode *code)
CURLcode Curl_cf_send(struct Curl_easy *data, int num,
const void *mem, size_t len, bool eos,
size_t *pnwritten)
{
struct Curl_cfilter *cf;
DEBUGASSERT(data);
DEBUGASSERT(data->conn);
*code = CURLE_OK;
cf = data->conn->cfilter[num];
while(cf && !cf->connected) {
while(cf && !cf->connected)
cf = cf->next;
}
if(cf) {
ssize_t nwritten = cf->cft->do_send(cf, data, mem, len, eos, code);
DEBUGASSERT(nwritten >= 0 || *code);
DEBUGASSERT(nwritten < 0 || !*code || !len);
return nwritten;
return cf->cft->do_send(cf, data, mem, len, eos, pnwritten);
}
failf(data, "send: no filter connected");
DEBUGASSERT(0);
*code = CURLE_FAILED_INIT;
return -1;
*pnwritten = 0;
return CURLE_FAILED_INIT;
}
struct cf_io_ctx {
struct Curl_easy *data;
struct Curl_cfilter *cf;
};
static CURLcode cf_bufq_reader(void *writer_ctx,
unsigned char *buf, size_t blen,
size_t *pnread)
{
struct cf_io_ctx *io = writer_ctx;
return Curl_conn_cf_recv(io->cf, io->data, (char *)buf, blen, pnread);
}
CURLcode Curl_cf_recv_bufq(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct bufq *bufq,
size_t maxlen,
size_t *pnread)
{
struct cf_io_ctx io;
if(!cf || !data) {
*pnread = 0;
return CURLE_BAD_FUNCTION_ARGUMENT;
}
io.data = data;
io.cf = cf;
return Curl_bufq_sipn(bufq, maxlen, cf_bufq_reader, &io, pnread);
}
static CURLcode cf_bufq_writer(void *writer_ctx,
const unsigned char *buf, size_t buflen,
size_t *pnwritten)
{
struct cf_io_ctx *io = writer_ctx;
return Curl_conn_cf_send(io->cf, io->data, (const char *)buf,
buflen, FALSE, pnwritten);
}
CURLcode Curl_cf_send_bufq(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct bufq *bufq,
const unsigned char *buf, size_t blen,
size_t *pnwritten)
{
struct cf_io_ctx io;
if(!cf || !data) {
*pnwritten = 0;
return CURLE_BAD_FUNCTION_ARGUMENT;
}
io.data = data;
io.cf = cf;
if(buf && blen)
return Curl_bufq_write_pass(bufq, buf, blen, cf_bufq_writer, &io,
pnwritten);
else
return Curl_bufq_pass(bufq, cf_bufq_writer, &io, pnwritten);
}
CURLcode Curl_cf_create(struct Curl_cfilter **pcf,
@@ -381,23 +420,23 @@ void Curl_conn_cf_close(struct Curl_cfilter *cf, struct Curl_easy *data)
cf->cft->do_close(cf, data);
}
ssize_t Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const void *buf, size_t len, bool eos,
CURLcode *err)
CURLcode Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const void *buf, size_t len, bool eos,
size_t *pnwritten)
{
if(cf)
return cf->cft->do_send(cf, data, buf, len, eos, err);
*err = CURLE_SEND_ERROR;
return -1;
return cf->cft->do_send(cf, data, buf, len, eos, pnwritten);
*pnwritten = 0;
return CURLE_SEND_ERROR;
}
ssize_t Curl_conn_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, CURLcode *err)
CURLcode Curl_conn_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, size_t *pnread)
{
if(cf)
return cf->cft->do_recv(cf, data, buf, len, err);
*err = CURLE_RECV_ERROR;
return -1;
return cf->cft->do_recv(cf, data, buf, len, pnread);
*pnread = 0;
return CURLE_RECV_ERROR;
}
CURLcode Curl_conn_connect(struct Curl_easy *data,
@@ -541,6 +580,19 @@ bool Curl_conn_is_ssl(struct connectdata *conn, int sockindex)
return conn ? Curl_conn_cf_is_ssl(conn->cfilter[sockindex]) : FALSE;
}
bool Curl_conn_get_ssl_info(struct Curl_easy *data,
struct connectdata *conn, int sockindex,
struct curl_tlssessioninfo *info)
{
if(Curl_conn_is_ssl(conn, sockindex)) {
struct Curl_cfilter *cf = conn->cfilter[sockindex];
CURLcode result = cf ? cf->cft->query(cf, data, CF_QUERY_SSL_INFO,
NULL, (void *)info) : CURLE_UNKNOWN_OPTION;
return !result;
}
return FALSE;
}
bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex)
{
struct Curl_cfilter *cf = conn ? conn->cfilter[sockindex] : NULL;
@@ -554,6 +606,13 @@ bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex)
return FALSE;
}
unsigned char Curl_conn_get_transport(struct Curl_easy *data,
struct connectdata *conn)
{
struct Curl_cfilter *cf = conn->cfilter[FIRSTSOCKET];
return Curl_conn_cf_get_transport(cf, data);
}
unsigned char Curl_conn_http_version(struct Curl_easy *data,
struct connectdata *conn)
{
@@ -678,31 +737,35 @@ int Curl_conn_cf_poll(struct Curl_cfilter *cf,
return Curl_poll(pfds, npfds, timeout_ms);
}
void Curl_conn_get_host(struct Curl_easy *data, int sockindex,
const char **phost, const char **pdisplay_host,
int *pport)
void Curl_conn_get_current_host(struct Curl_easy *data, int sockindex,
const char **phost, int *pport)
{
struct Curl_cfilter *cf;
struct Curl_cfilter *cf, *cf_proxy = NULL;
DEBUGASSERT(data->conn);
cf = data->conn->cfilter[sockindex];
if(cf) {
cf->cft->get_host(cf, data, phost, pdisplay_host, pport);
/* Find the "lowest" tunneling proxy filter that has not connected yet. */
while(cf && !cf->connected) {
if((cf->cft->flags & (CF_TYPE_IP_CONNECT|CF_TYPE_PROXY)) ==
(CF_TYPE_IP_CONNECT|CF_TYPE_PROXY))
cf_proxy = cf;
cf = cf->next;
}
else {
/* Some filter ask during shutdown for this, mainly for debugging
* purposes. We hand out the defaults, however this is not always
* accurate, as the connection might be tunneled, etc. But all that
* state is already gone here. */
/* cf_proxy (!= NULL) is not connected yet. It is talking
* to an interim host and any authentication or other things apply
* to this interim host and port. */
if(!cf_proxy || cf_proxy->cft->query(cf_proxy, data, CF_QUERY_HOST_PORT,
pport, CURL_UNCONST(phost))) {
/* Everything connected or query unsuccessful, the overall
* connection's destination is the answer */
*phost = data->conn->host.name;
*pdisplay_host = data->conn->host.dispname;
*pport = data->conn->remote_port;
}
}
CURLcode Curl_cf_def_cntrl(struct Curl_cfilter *cf,
struct Curl_easy *data,
int event, int arg1, void *arg2)
struct Curl_easy *data,
int event, int arg1, void *arg2)
{
(void)cf;
(void)data;
@@ -738,6 +801,26 @@ curl_socket_t Curl_conn_cf_get_socket(struct Curl_cfilter *cf,
return CURL_SOCKET_BAD;
}
unsigned char Curl_conn_cf_get_transport(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
int transport = 0;
if(cf && !cf->cft->query(cf, data, CF_QUERY_TRANSPORT, &transport, NULL))
return (unsigned char)transport;
return (unsigned char)(data->conn ? data->conn->transport_wanted : 0);
}
static const struct Curl_sockaddr_ex *
cf_get_remote_addr(struct Curl_cfilter *cf, struct Curl_easy *data)
{
const struct Curl_sockaddr_ex *remote_addr = NULL;
if(cf &&
!cf->cft->query(cf, data, CF_QUERY_REMOTE_ADDR, NULL,
CURL_UNCONST(&remote_addr)))
return remote_addr;
return NULL;
}
CURLcode Curl_conn_cf_get_ip_info(struct Curl_cfilter *cf,
struct Curl_easy *data,
int *is_ipv6, struct ip_quadruple *ipquad)
@@ -760,6 +843,13 @@ curl_socket_t Curl_conn_get_socket(struct Curl_easy *data, int sockindex)
return data->conn ? data->conn->sock[sockindex] : CURL_SOCKET_BAD;
}
const struct Curl_sockaddr_ex *
Curl_conn_get_remote_addr(struct Curl_easy *data, int sockindex)
{
struct Curl_cfilter *cf = data->conn ? data->conn->cfilter[sockindex] : NULL;
return cf ? cf_get_remote_addr(cf, data) : NULL;
}
void Curl_conn_forget_socket(struct Curl_easy *data, int sockindex)
{
if(data->conn) {
@@ -878,8 +968,8 @@ CURLcode Curl_conn_keep_alive(struct Curl_easy *data,
}
size_t Curl_conn_get_max_concurrent(struct Curl_easy *data,
struct connectdata *conn,
int sockindex)
struct connectdata *conn,
int sockindex)
{
CURLcode result;
int n = 0;
@@ -912,17 +1002,14 @@ int Curl_conn_sockindex(struct Curl_easy *data, curl_socket_t sockfd)
}
CURLcode Curl_conn_recv(struct Curl_easy *data, int sockindex,
char *buf, size_t blen, ssize_t *n)
char *buf, size_t blen, size_t *pnread)
{
CURLcode result = CURLE_OK;
ssize_t nread;
DEBUGASSERT(data);
DEBUGASSERT(data->conn);
nread = data->conn->recv[sockindex](data, sockindex, buf, blen, &result);
DEBUGASSERT(nread >= 0 || result);
DEBUGASSERT(nread < 0 || !result);
*n = (nread >= 0) ? (size_t)nread : 0;
return result;
if(data && data->conn && data->conn->recv[sockindex])
return data->conn->recv[sockindex](data, sockindex, buf, blen, pnread);
*pnread = 0;
return CURLE_FAILED_INIT;
}
CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex,
@@ -930,15 +1017,10 @@ CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex,
size_t *pnwritten)
{
size_t write_len = blen;
ssize_t nwritten;
CURLcode result = CURLE_OK;
struct connectdata *conn;
DEBUGASSERT(sockindex >= 0 && sockindex < 2);
DEBUGASSERT(pnwritten);
DEBUGASSERT(data);
DEBUGASSERT(data->conn);
conn = data->conn;
DEBUGASSERT(sockindex >= 0 && sockindex < 2);
#ifdef DEBUGBUILD
if(write_len) {
/* Allow debug builds to override this logic to force short sends
@@ -953,11 +1035,11 @@ CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex,
#endif
if(write_len != blen)
eos = FALSE;
nwritten = conn->send[sockindex](data, sockindex, buf, write_len, eos,
&result);
DEBUGASSERT((nwritten >= 0) || result);
*pnwritten = (nwritten < 0) ? 0 : (size_t)nwritten;
return result;
if(data && data->conn && data->conn->send[sockindex])
return data->conn->send[sockindex](data, sockindex, buf, write_len, eos,
pnwritten);
*pnwritten = 0;
return CURLE_FAILED_INIT;
}
void Curl_pollset_reset(struct Curl_easy *data,
@@ -974,8 +1056,8 @@ void Curl_pollset_reset(struct Curl_easy *data,
*
*/
void Curl_pollset_change(struct Curl_easy *data,
struct easy_pollset *ps, curl_socket_t sock,
int add_flags, int remove_flags)
struct easy_pollset *ps, curl_socket_t sock,
int add_flags, int remove_flags)
{
unsigned int i;
@@ -1085,3 +1167,16 @@ void Curl_pollset_check(struct Curl_easy *data,
}
*pwant_read = *pwant_write = FALSE;
}
bool Curl_pollset_want_read(struct Curl_easy *data,
struct easy_pollset *ps,
curl_socket_t sock)
{
unsigned int i;
(void)data;
for(i = 0; i < ps->num; ++i) {
if((ps->sockets[i] == sock) && (ps->actions[i] & CURL_POLL_IN))
return TRUE;
}
return FALSE;
}
+98 -47
View File
@@ -26,11 +26,13 @@
#include "curlx/timediff.h"
struct bufq;
struct Curl_cfilter;
struct Curl_easy;
struct Curl_dns_entry;
struct connectdata;
struct ip_quadruple;
struct curl_tlssessioninfo;
/* Callback to destroy resources held by this filter instance.
* Implementations MUST NOT chain calls to cf->next.
@@ -53,23 +55,6 @@ typedef CURLcode Curl_cft_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
bool *done);
/* Return the hostname and port the connection goes to.
* This may change with the connection state of filters when tunneling
* is involved.
* @param cf the filter to ask
* @param data the easy handle currently active
* @param phost on return, points to the relevant, real hostname.
* this is owned by the connection.
* @param pdisplay_host on return, points to the printable hostname.
* this is owned by the connection.
* @param pport on return, contains the port number
*/
typedef void Curl_cft_get_host(struct Curl_cfilter *cf,
struct Curl_easy *data,
const char **phost,
const char **pdisplay_host,
int *pport);
struct easy_pollset;
/* Passing in an easy_pollset for monitoring of sockets, let
@@ -102,18 +87,18 @@ typedef void Curl_cft_adjust_pollset(struct Curl_cfilter *cf,
typedef bool Curl_cft_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data);
typedef ssize_t Curl_cft_send(struct Curl_cfilter *cf,
typedef CURLcode Curl_cft_send(struct Curl_cfilter *cf,
struct Curl_easy *data, /* transfer */
const void *buf, /* data to write */
size_t len, /* amount to write */
bool eos, /* last chunk */
CURLcode *err); /* error to return */
size_t *pnwritten); /* how much sent */
typedef ssize_t Curl_cft_recv(struct Curl_cfilter *cf,
typedef CURLcode Curl_cft_recv(struct Curl_cfilter *cf,
struct Curl_easy *data, /* transfer */
char *buf, /* store data here */
size_t len, /* amount to read */
CURLcode *err); /* error to return */
size_t *pnread); /* how much received */
typedef bool Curl_cft_conn_is_alive(struct Curl_cfilter *cf,
struct Curl_easy *data,
@@ -166,6 +151,13 @@ typedef CURLcode Curl_cft_cntrl(struct Curl_cfilter *cf,
* - CF_QUERY_NEED_FLUSH: TRUE iff any of the filters have unsent data
* - CF_QUERY_IP_INFO: res1 says if connection used IPv6, res2 is the
* ip quadruple
* - CF_QUERY_HOST_PORT: the remote hostname and port a filter talks to
* - CF_QUERY_SSL_INFO: fill out the passed curl_tlssessioninfo with the
* internal from the SSL secured connection when
* available.
* - CF_QUERY_SSL_CTX_INFO: same as CF_QUERY_SSL_INFO, but give the SSL_CTX
* when available, or the same internal pointer
* when the TLS stack does not differentiate.
*/
/* query res1 res2 */
#define CF_QUERY_MAX_CONCURRENT 1 /* number - */
@@ -177,6 +169,13 @@ typedef CURLcode Curl_cft_cntrl(struct Curl_cfilter *cf,
#define CF_QUERY_NEED_FLUSH 7 /* TRUE/FALSE - */
#define CF_QUERY_IP_INFO 8 /* TRUE/FALSE struct ip_quadruple */
#define CF_QUERY_HTTP_VERSION 9 /* number (10/11/20/30) - */
/* pass in a `const struct Curl_sockaddr_ex **` as `pres2`. Gets set
* to NULL when not connected. */
#define CF_QUERY_REMOTE_ADDR 10 /* - `Curl_sockaddr_ex *` */
#define CF_QUERY_HOST_PORT 11 /* port const char * */
#define CF_QUERY_SSL_INFO 12 /* - struct curl_tlssessioninfo * */
#define CF_QUERY_SSL_CTX_INFO 13 /* - struct curl_tlssessioninfo * */
#define CF_QUERY_TRANSPORT 14 /* TRNSPRT_* - * */
/**
* Query the cfilter for properties. Filters ignorant of a query will
@@ -213,7 +212,6 @@ struct Curl_cftype {
Curl_cft_connect *do_connect; /* establish connection */
Curl_cft_close *do_close; /* close conn */
Curl_cft_shutdown *do_shutdown; /* shutdown conn */
Curl_cft_get_host *get_host; /* host filter talks to */
Curl_cft_adjust_pollset *adjust_pollset; /* adjust transfer poll set */
Curl_cft_data_pending *has_data_pending;/* conn has data pending */
Curl_cft_send *do_send; /* send data */
@@ -241,19 +239,16 @@ void Curl_cf_def_destroy_this(struct Curl_cfilter *cf,
/* Default implementations for the type functions, implementing pass-through
* the filter chain. */
void Curl_cf_def_get_host(struct Curl_cfilter *cf, struct Curl_easy *data,
const char **phost, const char **pdisplay_host,
int *pport);
void Curl_cf_def_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps);
bool Curl_cf_def_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data);
ssize_t Curl_cf_def_send(struct Curl_cfilter *cf, struct Curl_easy *data,
CURLcode Curl_cf_def_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const void *buf, size_t len, bool eos,
CURLcode *err);
ssize_t Curl_cf_def_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, CURLcode *err);
size_t *pnwritten);
CURLcode Curl_cf_def_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, size_t *pnread);
CURLcode Curl_cf_def_cntrl(struct Curl_cfilter *cf,
struct Curl_easy *data,
int event, int arg1, void *arg2);
@@ -326,11 +321,11 @@ CURLcode Curl_conn_cf_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
bool *done);
void Curl_conn_cf_close(struct Curl_cfilter *cf, struct Curl_easy *data);
ssize_t Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const void *buf, size_t len, bool eos,
CURLcode *err);
ssize_t Curl_conn_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, CURLcode *err);
CURLcode Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const void *buf, size_t len, bool eos,
size_t *pnwritten);
CURLcode Curl_conn_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, size_t *pnread);
CURLcode Curl_conn_cf_cntrl(struct Curl_cfilter *cf,
struct Curl_easy *data,
bool ignore_result,
@@ -356,6 +351,9 @@ CURLcode Curl_conn_cf_get_ip_info(struct Curl_cfilter *cf,
bool Curl_conn_cf_needs_flush(struct Curl_cfilter *cf,
struct Curl_easy *data);
unsigned char Curl_conn_cf_get_transport(struct Curl_cfilter *cf,
struct Curl_easy *data);
#define CURL_CF_SSL_DEFAULT -1
#define CURL_CF_SSL_DISABLE 0
#define CURL_CF_SSL_ENABLE 1
@@ -395,6 +393,15 @@ bool Curl_conn_is_ip_connected(struct Curl_easy *data, int sockindex);
*/
bool Curl_conn_is_ssl(struct connectdata *conn, int sockindex);
/*
* Fill `info` with information about the TLS instance securing
* the connection when available, otherwise e.g. when
* Curl_conn_is_ssl() is FALSE, return FALSE.
*/
bool Curl_conn_get_ssl_info(struct Curl_easy *data,
struct connectdata *conn, int sockindex,
struct curl_tlssessioninfo *info);
/**
* Connection provides multiplexing of easy handles at `socketindex`.
*/
@@ -407,6 +414,10 @@ bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex);
unsigned char Curl_conn_http_version(struct Curl_easy *data,
struct connectdata *conn);
/* Get the TRNSPRT_* the connection is using */
unsigned char Curl_conn_get_transport(struct Curl_easy *data,
struct connectdata *conn);
/**
* Close the filter chain at `sockindex` for connection `data->conn`.
* Filters remain in place and may be connected again afterwards.
@@ -444,13 +455,17 @@ CURLcode Curl_conn_flush(struct Curl_easy *data, int sockindex);
*/
curl_socket_t Curl_conn_get_socket(struct Curl_easy *data, int sockindex);
/* Return a pointer to the connected socket address or NULL. */
const struct Curl_sockaddr_ex *
Curl_conn_get_remote_addr(struct Curl_easy *data, int sockindex);
/**
* Tell filters to forget about the socket at sockindex.
*/
void Curl_conn_forget_socket(struct Curl_easy *data, int sockindex);
/**
* Adjust the pollset for the filter chain startgin at `cf`.
* Adjust the pollset for the filter chain starting at `cf`.
*/
void Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
@@ -475,20 +490,41 @@ int Curl_conn_cf_poll(struct Curl_cfilter *cf,
/**
* Receive data through the filter chain at `sockindex` for connection
* `data->conn`. Copy at most `len` bytes into `buf`. Return the
* actual number of bytes copied or a negative value on error.
* The error code is placed into `*code`.
* actual number of bytes copied in `*pnread`or an error.
*/
ssize_t Curl_cf_recv(struct Curl_easy *data, int sockindex, char *buf,
size_t len, CURLcode *code);
CURLcode Curl_cf_recv(struct Curl_easy *data, int sockindex, char *buf,
size_t len, size_t *pnread);
/**
* Send `len` bytes of data from `buf` through the filter chain `sockindex`
* at connection `data->conn`. Return the actual number of bytes written
* or a negative value on error.
* The error code is placed into `*code`.
* in `*pnwritten` or on error.
*/
ssize_t Curl_cf_send(struct Curl_easy *data, int sockindex,
const void *buf, size_t len, bool eos, CURLcode *code);
CURLcode Curl_cf_send(struct Curl_easy *data, int sockindex,
const void *buf, size_t len, bool eos,
size_t *pnwritten);
/**
* Receive bytes from connection filter `cf` into `bufq`.
* Convenience wrappter around `Curl_bufq_sipn()`,
* so users do not have to implement a callback.
*/
CURLcode Curl_cf_recv_bufq(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct bufq *bufq,
size_t maxlen,
size_t *pnread);
/**
* Send bytes in `bufq` using connection filter `cf`.
* A convenience wrapper around `Curl_bufq_write_pass()`,
* so users do not have to implement a callback.
*/
CURLcode Curl_cf_send_bufq(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct bufq *bufq,
const unsigned char *buf, size_t blen,
size_t *pnwritten);
/**
* Notify connection filters that they need to setup data for
@@ -535,9 +571,17 @@ CURLcode Curl_conn_keep_alive(struct Curl_easy *data,
#ifdef UNITTESTS
void Curl_cf_def_close(struct Curl_cfilter *cf, struct Curl_easy *data);
#endif
void Curl_conn_get_host(struct Curl_easy *data, int sockindex,
const char **phost, const char **pdisplay_host,
int *pport);
/**
* Get the remote hostname and port that the connection is currently
* talking to (or will talk to).
* Once connected or before connect starts,
* it is `conn->host.name` and `conn->remote_port`.
* During connect, when tunneling proxies are involved (http or socks),
* it will be the name and port the proxy currently negotiates with.
*/
void Curl_conn_get_current_host(struct Curl_easy *data, int sockindex,
const char **phost, int *pport);
/**
* Get the maximum number of parallel transfers the connection
@@ -567,7 +611,7 @@ int Curl_conn_sockindex(struct Curl_easy *data, curl_socket_t sockfd);
*/
CURLcode Curl_conn_recv(struct Curl_easy *data, int sockindex,
char *buf, size_t buffersize,
ssize_t *pnread);
size_t *pnread);
/*
* Send data on the connection, using FIRSTSOCKET/SECONDARYSOCKET.
@@ -621,6 +665,13 @@ void Curl_pollset_check(struct Curl_easy *data,
struct easy_pollset *ps, curl_socket_t sock,
bool *pwant_read, bool *pwant_write);
/**
* Return TRUE if the pollset contains socket with CURL_POLL_IN.
*/
bool Curl_pollset_want_read(struct Curl_easy *data,
struct easy_pollset *ps,
curl_socket_t sock);
/**
* Types and macros used to keep the current easy handle in filter calls,
* allowing for nested invocations. See #10336.
-1
View File
@@ -42,7 +42,6 @@
#include "sigpipe.h"
#include "connect.h"
#include "select.h"
#include "strcase.h"
#include "curlx/strparse.h"
#include "uint-table.h"
+1 -1
View File
@@ -106,7 +106,7 @@ typedef bool Curl_cpool_done_match_cb(bool result, void *userdata);
* Find a connection in the pool matching `destination`.
* All callbacks are invoked while the pool's lock is held.
* @param data current transfer
* @param destination match agaonst `conn->destination` in pool
* @param destination match against `conn->destination` in pool
* @param conn_cb must be present, called for each connection in the
* bundle until it returns TRUE
* @return combined result of last conn_db and result_cb or FALSE if no
+27 -29
View File
@@ -66,7 +66,7 @@
#include "url.h" /* for Curl_safefree() */
#include "multiif.h"
#include "sockaddr.h" /* required for Curl_sockaddr_storage */
#include "inet_ntop.h"
#include "curlx/inet_ntop.h"
#include "curlx/inet_pton.h"
#include "vtls/vtls.h" /* for vtsl cfilters */
#include "progress.h"
@@ -78,7 +78,6 @@
#include "vquic/vquic.h" /* for quic cfilters */
#include "http_proxy.h"
#include "socks.h"
#include "strcase.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -90,15 +89,15 @@
enum alpnid Curl_alpn2alpnid(const char *name, size_t len)
{
if(len == 2) {
if(strncasecompare(name, "h1", 2))
if(curl_strnequal(name, "h1", 2))
return ALPN_h1;
if(strncasecompare(name, "h2", 2))
if(curl_strnequal(name, "h2", 2))
return ALPN_h2;
if(strncasecompare(name, "h3", 2))
if(curl_strnequal(name, "h3", 2))
return ALPN_h3;
}
else if(len == 8) {
if(strncasecompare(name, "http/1.1", 8))
if(curl_strnequal(name, "http/1.1", 8))
return ALPN_h1;
}
return ALPN_none; /* unknown, probably rubbish input */
@@ -172,11 +171,11 @@ void Curl_shutdown_start(struct Curl_easy *data, int sockindex,
}
data->conn->shutdown.start[sockindex] = *nowp;
data->conn->shutdown.timeout_ms = (timeout_ms > 0) ?
(unsigned int)timeout_ms :
(timediff_t)timeout_ms :
((data->set.shutdowntimeout > 0) ?
data->set.shutdowntimeout : DEFAULT_SHUTDOWN_TIMEOUT_MS);
/* Set a timer, unless we operate on the admin handle */
if(data->mid && data->conn->shutdown.timeout_ms)
if(data->mid && (data->conn->shutdown.timeout_ms > 0))
Curl_expire_ex(data, nowp, data->conn->shutdown.timeout_ms,
EXPIRE_SHUTDOWN);
}
@@ -187,7 +186,8 @@ timediff_t Curl_shutdown_timeleft(struct connectdata *conn, int sockindex,
struct curltime now;
timediff_t left_ms;
if(!conn->shutdown.start[sockindex].tv_sec || !conn->shutdown.timeout_ms)
if(!conn->shutdown.start[sockindex].tv_sec ||
(conn->shutdown.timeout_ms <= 0))
return 0; /* not started or no limits */
if(!nowp) {
@@ -254,8 +254,8 @@ addr_next_match(const struct Curl_addrinfo *addr, int family)
return NULL;
}
/* retrieves ip address and port from a sockaddr structure.
note it calls Curl_inet_ntop which sets errno on fail, not SOCKERRNO. */
/* retrieves ip address and port from a sockaddr structure. note it calls
curlx_inet_ntop which sets errno on fail, not SOCKERRNO. */
bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
char *addr, int *port)
{
@@ -272,7 +272,7 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
switch(sa->sa_family) {
case AF_INET:
si = (struct sockaddr_in *)(void *) sa;
if(Curl_inet_ntop(sa->sa_family, &si->sin_addr, addr, MAX_IPADR_LEN)) {
if(curlx_inet_ntop(sa->sa_family, &si->sin_addr, addr, MAX_IPADR_LEN)) {
unsigned short us_port = ntohs(si->sin_port);
*port = us_port;
return TRUE;
@@ -281,7 +281,8 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
#ifdef USE_IPV6
case AF_INET6:
si6 = (struct sockaddr_in6 *)(void *) sa;
if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr, addr, MAX_IPADR_LEN)) {
if(curlx_inet_ntop(sa->sa_family, &si6->sin6_addr, addr,
MAX_IPADR_LEN)) {
unsigned short us_port = ntohs(si6->sin6_port);
*port = us_port;
return TRUE;
@@ -389,7 +390,6 @@ struct eyeballer {
expire_id timeout_id; /* ID for Curl_expire() */
CURLcode result;
int error;
BIT(rewinded); /* if we rewinded the addr list */
BIT(has_started); /* attempts have started */
BIT(is_done); /* out of addresses/time */
BIT(connected); /* cf has connected */
@@ -455,7 +455,7 @@ static CURLcode eyeballer_new(struct eyeballer **pballer,
}
static void baller_close(struct eyeballer *baller,
struct Curl_easy *data)
struct Curl_easy *data)
{
if(baller && baller->cf) {
Curl_conn_cf_discard_chain(&baller->cf, data);
@@ -463,7 +463,7 @@ static void baller_close(struct eyeballer *baller,
}
static void baller_free(struct eyeballer *baller,
struct Curl_easy *data)
struct Curl_easy *data)
{
if(baller) {
baller_close(baller, data);
@@ -473,7 +473,6 @@ static void baller_free(struct eyeballer *baller,
static void baller_rewind(struct eyeballer *baller)
{
baller->rewinded = TRUE;
baller->addr = baller->first;
baller->inconclusive = FALSE;
}
@@ -682,7 +681,7 @@ evaluate:
/* next attempt was started */
CURL_TRC_CF(data, cf, "%s trying next", baller->name);
++ongoing;
Curl_expire(data, 0, EXPIRE_RUN_NOW);
Curl_multi_mark_dirty(data);
}
}
}
@@ -832,7 +831,7 @@ static CURLcode start_connect(struct Curl_cfilter *cf,
addr1 = addr_first_match(dns->addr, ai_family1);
/* no ip address families, probably AF_UNIX or something, use the
* address family given to us */
if(!addr1 && !addr0 && dns->addr) {
if(!addr1 && !addr0 && dns->addr) {
ai_family0 = dns->addr->ai_family;
addr0 = addr_first_match(dns->addr, ai_family0);
}
@@ -932,8 +931,8 @@ static CURLcode cf_he_shutdown(struct Curl_cfilter *cf,
}
static void cf_he_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
struct Curl_easy *data,
struct easy_pollset *ps)
{
struct cf_he_ctx *ctx = cf->ctx;
size_t i;
@@ -993,11 +992,11 @@ static CURLcode cf_he_connect(struct Curl_cfilter *cf,
struct ip_quadruple ipquad;
int is_ipv6;
if(!Curl_conn_cf_get_ip_info(cf->next, data, &is_ipv6, &ipquad)) {
const char *host, *disphost;
const char *host;
int port;
cf->next->cft->get_host(cf->next, data, &host, &disphost, &port);
Curl_conn_get_current_host(data, cf->sockindex, &host, &port);
CURL_TRC_CF(data, cf, "Connected to %s (%s) port %u",
disphost, ipquad.remote_ip, ipquad.remote_port);
host, ipquad.remote_ip, ipquad.remote_port);
}
}
data->info.numconnects++; /* to track the # of connections made */
@@ -1046,8 +1045,8 @@ static bool cf_he_data_pending(struct Curl_cfilter *cf,
}
static struct curltime get_max_baller_time(struct Curl_cfilter *cf,
struct Curl_easy *data,
int query)
struct Curl_easy *data,
int query)
{
struct cf_he_ctx *ctx = cf->ctx;
struct curltime t, tmax;
@@ -1134,7 +1133,6 @@ struct Curl_cftype Curl_cft_happy_eyeballs = {
cf_he_connect,
cf_he_close,
cf_he_shutdown,
Curl_cf_def_get_host,
cf_he_adjust_pollset,
cf_he_data_pending,
Curl_cf_def_send,
@@ -1398,7 +1396,6 @@ struct Curl_cftype Curl_cft_setup = {
cf_setup_connect,
cf_setup_close,
Curl_cf_def_shutdown,
Curl_cf_def_get_host,
Curl_cf_def_adjust_pollset,
Curl_cf_def_data_pending,
Curl_cf_def_send,
@@ -1518,7 +1515,8 @@ CURLcode Curl_conn_setup(struct Curl_easy *data,
/* Still no cfilter set, apply default. */
if(!conn->cfilter[sockindex]) {
result = cf_setup_add(data, conn, sockindex, conn->transport, ssl_mode);
result = cf_setup_add(data, conn, sockindex,
conn->transport_wanted, ssl_mode);
if(result)
goto out;
}
+12 -13
View File
@@ -52,7 +52,6 @@
#include "http.h"
#include "content_encoding.h"
#include "strdup.h"
#include "strcase.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -343,7 +342,7 @@ static CURLcode gzip_do_write(struct Curl_easy *data,
}
static void gzip_do_close(struct Curl_easy *data,
struct Curl_cwriter *writer)
struct Curl_cwriter *writer)
{
struct zlib_writer *zp = (struct zlib_writer *) writer;
z_stream *z = &zp->z; /* zlib state structure */
@@ -464,7 +463,7 @@ static CURLcode brotli_do_write(struct Curl_easy *data,
}
static void brotli_do_close(struct Curl_easy *data,
struct Curl_cwriter *writer)
struct Curl_cwriter *writer)
{
struct brotli_writer *bp = (struct brotli_writer *) writer;
(void) data;
@@ -567,7 +566,7 @@ static CURLcode zstd_do_write(struct Curl_easy *data,
}
static void zstd_do_close(struct Curl_easy *data,
struct Curl_cwriter *writer)
struct Curl_cwriter *writer)
{
struct zstd_writer *zp = (struct zstd_writer *) writer;
(void)data;
@@ -636,7 +635,7 @@ void Curl_all_content_encodings(char *buf, size_t blen)
for(cep = general_unencoders; *cep; cep++) {
ce = *cep;
if(!strcasecompare(ce->name, CONTENT_ENCODING_DEFAULT))
if(!curl_strequal(ce->name, CONTENT_ENCODING_DEFAULT))
len += strlen(ce->name) + 2;
}
@@ -648,7 +647,7 @@ void Curl_all_content_encodings(char *buf, size_t blen)
char *p = buf;
for(cep = general_unencoders; *cep; cep++) {
ce = *cep;
if(!strcasecompare(ce->name, CONTENT_ENCODING_DEFAULT)) {
if(!curl_strequal(ce->name, CONTENT_ENCODING_DEFAULT)) {
strcpy(p, ce->name);
p += strlen(p);
*p++ = ',';
@@ -688,7 +687,7 @@ static CURLcode error_do_write(struct Curl_easy *data,
}
static void error_do_close(struct Curl_easy *data,
struct Curl_cwriter *writer)
struct Curl_cwriter *writer)
{
(void) data;
(void) writer;
@@ -713,8 +712,8 @@ static const struct Curl_cwtype *find_unencode_writer(const char *name,
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)
if((curl_strnequal(name, ce->name, len) && !ce->name[len]) ||
(ce->alias && curl_strnequal(name, ce->alias, len)
&& !ce->alias[len]))
return ce;
}
@@ -722,8 +721,8 @@ static const struct Curl_cwtype *find_unencode_writer(const char *name,
/* 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]))
if((curl_strnequal(name, ce->name, len) && !ce->name[len]) ||
(ce->alias && curl_strnequal(name, ce->alias, len) && !ce->alias[len]))
return ce;
}
return NULL;
@@ -761,12 +760,12 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
CURL_TRC_WRITE(data, "looking for %s decoder: %.*s",
is_transfer ? "transfer" : "content", (int)namelen, name);
is_chunked = (is_transfer && (namelen == 7) &&
strncasecompare(name, "chunked", 7));
curl_strnequal(name, "chunked", 7));
/* 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 && !is_chunked) ||
(!is_transfer && data->set.http_ce_skip)) {
bool is_identity = strncasecompare(name, "identity", 8);
bool is_identity = curl_strnequal(name, "identity", 8);
/* not requested, ignore */
CURL_TRC_WRITE(data, "decoder not requested, ignored: %.*s",
(int)namelen, name);
+14 -14
View File
@@ -135,9 +135,9 @@ static bool cookie_tailmatch(const char *cookie_domain,
if(hostname_len < cookie_domain_len)
return FALSE;
if(!strncasecompare(cookie_domain,
hostname + hostname_len-cookie_domain_len,
cookie_domain_len))
if(!curl_strnequal(cookie_domain,
hostname + hostname_len-cookie_domain_len,
cookie_domain_len))
return FALSE;
/*
@@ -409,7 +409,7 @@ static void remove_expired(struct CookieInfo *ci)
/* Make sure domain contains a dot or is localhost. */
static bool bad_domain(const char *domain, size_t len)
{
if((len == 9) && strncasecompare(domain, "localhost", 9))
if((len == 9) && curl_strnequal(domain, "localhost", 9))
return FALSE;
else {
/* there must be a dot present, but that dot must not be a trailing dot */
@@ -815,7 +815,7 @@ parse_netscape(struct Cookie *co,
* domain can access the variable. Set TRUE when the cookie says
* .example.com and to false when the domain is complete www.example.com
*/
co->tailmatch = !!strncasecompare(ptr, "TRUE", len);
co->tailmatch = !!curl_strnequal(ptr, "TRUE", len);
break;
case 2:
/* The file format allows the path field to remain not filled in */
@@ -842,7 +842,7 @@ parse_netscape(struct Cookie *co,
FALLTHROUGH();
case 3:
co->secure = FALSE;
if(strncasecompare(ptr, "TRUE", len)) {
if(curl_strnequal(ptr, "TRUE", len)) {
if(secure || ci->running)
co->secure = TRUE;
else
@@ -859,9 +859,9 @@ parse_netscape(struct Cookie *co,
return CERR_OUT_OF_MEMORY;
else {
/* For Netscape file format cookies we check prefix on the name */
if(strncasecompare("__Secure-", co->name, 9))
if(curl_strnequal("__Secure-", co->name, 9))
co->prefix_secure = TRUE;
else if(strncasecompare("__Host-", co->name, 7))
else if(curl_strnequal("__Host-", co->name, 7))
co->prefix_host = TRUE;
}
break;
@@ -917,7 +917,7 @@ is_public_suffix(struct Curl_easy *data,
Curl_psl_release(data);
}
else
infof(data, "libpsl problem, rejecting cookie for satety");
infof(data, "libpsl problem, rejecting cookie for safety");
}
if(!acceptable) {
@@ -954,7 +954,7 @@ replace_existing(struct Curl_easy *data,
bool matching_domains = FALSE;
if(clist->domain && co->domain) {
if(strcasecompare(clist->domain, co->domain))
if(curl_strequal(clist->domain, co->domain))
/* The domains are identical */
matching_domains = TRUE;
}
@@ -981,7 +981,7 @@ replace_existing(struct Curl_easy *data,
else
cllen = strlen(clist->spath);
if(strncasecompare(clist->spath, co->spath, cllen)) {
if(curl_strnequal(clist->spath, co->spath, cllen)) {
infof(data, "cookie '%s' for domain '%s' dropped, would "
"overlay an existing cookie", co->name, co->domain);
return CERR_BAD_SECURE;
@@ -993,7 +993,7 @@ replace_existing(struct Curl_easy *data,
/* the names are identical */
if(clist->domain && co->domain) {
if(strcasecompare(clist->domain, co->domain) &&
if(curl_strequal(clist->domain, co->domain) &&
(clist->tailmatch == co->tailmatch))
/* The domains are identical */
replace_old = TRUE;
@@ -1005,7 +1005,7 @@ replace_existing(struct Curl_easy *data,
/* the domains were identical */
if(clist->spath && co->spath &&
!strcasecompare(clist->spath, co->spath))
!curl_strequal(clist->spath, co->spath))
replace_old = FALSE;
else if(!clist->spath != !co->spath)
replace_old = FALSE;
@@ -1337,7 +1337,7 @@ int Curl_cookie_getlist(struct Curl_easy *data,
if(!co->domain ||
(co->tailmatch && !is_ip &&
cookie_tailmatch(co->domain, strlen(co->domain), host)) ||
((!co->tailmatch || is_ip) && strcasecompare(host, co->domain)) ) {
((!co->tailmatch || is_ip) && curl_strequal(host, co->domain)) ) {
/*
* the right part of the host matches the domain stuff in the
* cookie data
+11 -18
View File
@@ -40,7 +40,6 @@
#include "sigpipe.h"
#include "connect.h"
#include "select.h"
#include "strcase.h"
#include "curlx/strparse.h"
/* The last 3 #include files should be in this order */
@@ -54,12 +53,6 @@ static void cshutdn_run_conn_handler(struct Curl_easy *data,
{
if(!conn->bits.shutdown_handler) {
/* Cleanup NTLM connection-related data */
Curl_http_auth_cleanup_ntlm(conn);
/* Cleanup NEGOTIATE connection-related data */
Curl_http_auth_cleanup_negotiate(conn);
if(conn->handler && conn->handler->disconnect) {
/* Some disconnect handlers do a blocking wait on server responses.
* FTP/IMAP/SMTP and SFTP are among them. When using the internal
@@ -121,8 +114,8 @@ static void cshutdn_run_once(struct Curl_easy *data,
}
void Curl_cshutdn_run_once(struct Curl_easy *data,
struct connectdata *conn,
bool *done)
struct connectdata *conn,
bool *done)
{
DEBUGASSERT(!data->conn);
Curl_attach_connection(data, conn);
@@ -219,8 +212,8 @@ bool Curl_cshutdn_close_oldest(struct Curl_easy *data,
#define NUM_POLLS_ON_STACK 10
static CURLcode cshutdn_wait(struct cshutdn *cshutdn,
struct Curl_easy *data,
int timeout_ms)
struct Curl_easy *data,
int timeout_ms)
{
struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK];
struct curl_pollfds cpfds;
@@ -241,7 +234,7 @@ out:
static void cshutdn_perform(struct cshutdn *cshutdn,
struct Curl_easy *data)
struct Curl_easy *data)
{
struct Curl_llist_node *e = Curl_llist_head(&cshutdn->list);
struct Curl_llist_node *enext;
@@ -402,8 +395,8 @@ size_t Curl_cshutdn_dest_count(struct Curl_easy *data,
static CURLMcode cshutdn_update_ev(struct cshutdn *cshutdn,
struct Curl_easy *data,
struct connectdata *conn)
struct Curl_easy *data,
struct connectdata *conn)
{
CURLMcode mresult;
@@ -418,8 +411,8 @@ static CURLMcode cshutdn_update_ev(struct cshutdn *cshutdn,
void Curl_cshutdn_add(struct cshutdn *cshutdn,
struct connectdata *conn,
size_t conns_in_pool)
struct connectdata *conn,
size_t conns_in_pool)
{
struct Curl_easy *data = cshutdn->multi->admin;
size_t max_total = (cshutdn->multi->max_total_connections > 0) ?
@@ -451,8 +444,8 @@ void Curl_cshutdn_add(struct cshutdn *cshutdn,
static void cshutdn_multi_socket(struct cshutdn *cshutdn,
struct Curl_easy *data,
curl_socket_t s)
struct Curl_easy *data,
curl_socket_t s)
{
struct Curl_llist_node *e;
struct connectdata *conn;
-27
View File
@@ -581,18 +581,9 @@
/* Define to 1 if you have the <sys/select.h> header file. */
#cmakedefine HAVE_SYS_SELECT_H 1
/* Define to 1 if you have the <sys/socket.h> header file. */
#cmakedefine HAVE_SYS_SOCKET_H 1
/* Define to 1 if you have the <sys/sockio.h> header file. */
#cmakedefine HAVE_SYS_SOCKIO_H 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#cmakedefine HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/time.h> header file. */
#cmakedefine HAVE_SYS_TIME_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#cmakedefine HAVE_SYS_TYPES_H 1
@@ -694,18 +685,12 @@ ${SIZEOF_TIME_T_CODE}
/* if GnuTLS is enabled */
#cmakedefine USE_GNUTLS 1
/* if Secure Transport is enabled */
#cmakedefine USE_SECTRANSP 1
/* if SSL session export support is available */
#cmakedefine USE_SSLS_EXPORT 1
/* if mbedTLS is enabled */
#cmakedefine USE_MBEDTLS 1
/* if BearSSL is enabled */
#cmakedefine USE_BEARSSL 1
/* if Rustls is enabled */
#cmakedefine USE_RUSTLS 1
@@ -806,18 +791,6 @@ ${SIZEOF_TIME_T_CODE}
/* Number of bits in a file offset, on hosts where this is settable. */
#cmakedefine _FILE_OFFSET_BITS ${_FILE_OFFSET_BITS}
/* Define for large files, on AIX-style hosts. */
#cmakedefine _LARGE_FILES ${_LARGE_FILES}
/* define this if you need it to compile thread-safe code */
#cmakedefine _THREAD_SAFE ${_THREAD_SAFE}
/* Define to empty if `const' does not conform to ANSI C. */
#cmakedefine const ${const}
/* Define to `unsigned int' if <sys/types.h> does not define. */
#cmakedefine size_t ${size_t}
/* the signed version of size_t */
#ifndef SIZEOF_SSIZE_T
# if SIZEOF_LONG == SIZEOF_SIZE_T
-1
View File
@@ -26,7 +26,6 @@
#if defined(USE_CURL_NTLM_CORE) && \
(defined(USE_GNUTLS) || \
defined(USE_SECTRANSP) || \
defined(USE_OS400CRYPTO) || \
defined(USE_WIN32_CRYPTO))
-1
View File
@@ -28,7 +28,6 @@
#if defined(USE_CURL_NTLM_CORE) && \
(defined(USE_GNUTLS) || \
defined(USE_SECTRANSP) || \
defined(USE_OS400CRYPTO) || \
defined(USE_WIN32_CRYPTO))
+25 -10
View File
@@ -32,6 +32,15 @@
/* The last #include file should be: */
#include "memdebug.h"
static int appendnl(struct dynbuf *buf)
{
CURLcode result = curlx_dyn_addn(buf, "\n", 1);
if(result)
/* too long line or out of memory */
return 0; /* error */
return 1; /* all good */
}
/*
* Curl_get_line() makes sure to only return complete whole lines that end
* newlines.
@@ -43,9 +52,10 @@ int Curl_get_line(struct dynbuf *buf, FILE *input)
curlx_dyn_reset(buf);
while(1) {
char *b = fgets(buffer, sizeof(buffer), input);
size_t rlen;
if(b) {
size_t rlen = strlen(b);
rlen = strlen(b);
if(!rlen)
break;
@@ -59,19 +69,24 @@ int Curl_get_line(struct dynbuf *buf, FILE *input)
/* end of the line */
return 1; /* all good */
else if(feof(input)) {
else if(feof(input))
/* append a newline */
result = curlx_dyn_addn(buf, "\n", 1);
if(result)
/* too long line or out of memory */
return 0; /* error */
return appendnl(buf);
}
else {
rlen = curlx_dyn_len(buf);
if(rlen) {
b = curlx_dyn_ptr(buf);
if(b[rlen-1] != '\n')
/* append a newline */
return appendnl(buf);
return 1; /* all good */
}
else
break;
}
else if(curlx_dyn_len(buf))
return 1; /* all good */
else
break;
}
return 0;
}
+286 -12
View File
@@ -52,17 +52,260 @@ gss_OID_desc Curl_krb5_mech_oid CURL_ALIGN8 = {
9, CURL_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02")
};
OM_uint32 Curl_gss_init_sec_context(
struct Curl_easy *data,
OM_uint32 *minor_status,
gss_ctx_id_t *context,
gss_name_t target_name,
gss_OID mech_type,
gss_channel_bindings_t input_chan_bindings,
gss_buffer_t input_token,
gss_buffer_t output_token,
const bool mutual_auth,
OM_uint32 *ret_flags)
#ifdef DEBUGBUILD
enum min_err_code {
STUB_GSS_OK = 0,
STUB_GSS_NO_MEMORY,
STUB_GSS_INVALID_ARGS,
STUB_GSS_INVALID_CREDS,
STUB_GSS_INVALID_CTX,
STUB_GSS_SERVER_ERR,
STUB_GSS_NO_MECH,
STUB_GSS_LAST
};
/* libcurl is also passing this struct to these functions, which are not yet
* stubbed:
* gss_inquire_context()
* gss_unwrap()
* gss_wrap()
*/
struct stub_gss_ctx_id_t_desc {
enum { STUB_GSS_NONE, STUB_GSS_KRB5, STUB_GSS_NTLM1, STUB_GSS_NTLM3 } sent;
int have_krb5;
int have_ntlm;
OM_uint32 flags;
char creds[250];
};
static OM_uint32
stub_gss_init_sec_context(OM_uint32 *min,
gss_cred_id_t initiator_cred_handle,
struct stub_gss_ctx_id_t_desc **context,
gss_name_t target_name,
const gss_OID mech_type,
OM_uint32 req_flags,
OM_uint32 time_req,
const gss_channel_bindings_t input_chan_bindings,
gss_buffer_desc *input_token,
gss_OID *actual_mech_type,
gss_buffer_desc *output_token,
OM_uint32 *ret_flags,
OM_uint32 *time_rec)
{
struct stub_gss_ctx_id_t_desc *ctx = NULL;
/* The token will be encoded in base64 */
size_t length = sizeof(ctx->creds) * 3 / 4;
size_t used = 0;
char *token = NULL;
const char *creds = NULL;
(void)initiator_cred_handle;
(void)mech_type;
(void)time_req;
(void)input_chan_bindings;
(void)actual_mech_type;
if(!min)
return GSS_S_FAILURE;
*min = 0;
if(!context || !target_name || !output_token) {
*min = STUB_GSS_INVALID_ARGS;
return GSS_S_FAILURE;
}
creds = getenv("CURL_STUB_GSS_CREDS");
if(!creds || strlen(creds) >= sizeof(ctx->creds)) {
*min = STUB_GSS_INVALID_CREDS;
return GSS_S_FAILURE;
}
ctx = *context;
if(ctx && strcmp(ctx->creds, creds)) {
*min = STUB_GSS_INVALID_CREDS;
return GSS_S_FAILURE;
}
output_token->length = 0;
output_token->value = NULL;
if(input_token && input_token->length) {
if(!ctx) {
*min = STUB_GSS_INVALID_CTX;
return GSS_S_FAILURE;
}
/* Server response, either D (RA==) or C (Qw==) */
if(((char *) input_token->value)[0] == 'D') {
/* Done */
switch(ctx->sent) {
case STUB_GSS_KRB5:
case STUB_GSS_NTLM3:
if(ret_flags)
*ret_flags = ctx->flags;
if(time_rec)
*time_rec = GSS_C_INDEFINITE;
return GSS_S_COMPLETE;
default:
*min = STUB_GSS_SERVER_ERR;
return GSS_S_FAILURE;
}
}
if(((char *) input_token->value)[0] != 'C') {
/* We only support Done or Continue */
*min = STUB_GSS_SERVER_ERR;
return GSS_S_FAILURE;
}
/* Continue */
switch(ctx->sent) {
case STUB_GSS_KRB5:
/* We sent KRB5 and it failed, let's try NTLM */
if(ctx->have_ntlm) {
ctx->sent = STUB_GSS_NTLM1;
break;
}
else {
*min = STUB_GSS_SERVER_ERR;
return GSS_S_FAILURE;
}
case STUB_GSS_NTLM1:
ctx->sent = STUB_GSS_NTLM3;
break;
default:
*min = STUB_GSS_SERVER_ERR;
return GSS_S_FAILURE;
}
}
else {
if(ctx) {
*min = STUB_GSS_INVALID_CTX;
return GSS_S_FAILURE;
}
ctx = calloc(1, sizeof(*ctx));
if(!ctx) {
*min = STUB_GSS_NO_MEMORY;
return GSS_S_FAILURE;
}
if(strstr(creds, "KRB5"))
ctx->have_krb5 = 1;
if(strstr(creds, "NTLM"))
ctx->have_ntlm = 1;
if(ctx->have_krb5)
ctx->sent = STUB_GSS_KRB5;
else if(ctx->have_ntlm)
ctx->sent = STUB_GSS_NTLM1;
else {
free(ctx);
*min = STUB_GSS_NO_MECH;
return GSS_S_FAILURE;
}
strcpy(ctx->creds, creds);
ctx->flags = req_flags;
}
/* To avoid memdebug macro replacement, wrap the name in parentheses to call
the original version. It is freed via the GSS API gss_release_buffer(). */
token = (malloc)(length);
if(!token) {
free(ctx);
*min = STUB_GSS_NO_MEMORY;
return GSS_S_FAILURE;
}
{
gss_buffer_desc target_desc;
gss_OID name_type = GSS_C_NO_OID;
OM_uint32 minor_status;
OM_uint32 major_status;
major_status = gss_display_name(&minor_status, target_name,
&target_desc, &name_type);
if(GSS_ERROR(major_status)) {
(free)(token);
free(ctx);
*min = STUB_GSS_NO_MEMORY;
return GSS_S_FAILURE;
}
if(strlen(creds) + target_desc.length + 5 >= sizeof(ctx->creds)) {
(free)(token);
free(ctx);
*min = STUB_GSS_NO_MEMORY;
return GSS_S_FAILURE;
}
/* Token format: creds:target:type:padding */
used = msnprintf(token, length, "%s:%.*s:%d:", creds,
(int)target_desc.length, (const char *)target_desc.value,
ctx->sent);
gss_release_buffer(&minor_status, &target_desc);
}
if(used >= length) {
(free)(token);
free(ctx);
*min = STUB_GSS_NO_MEMORY;
return GSS_S_FAILURE;
}
/* Overwrite null-terminator */
memset(token + used, 'A', length - used);
*context = ctx;
output_token->value = token;
output_token->length = length;
return GSS_S_CONTINUE_NEEDED;
}
static OM_uint32
stub_gss_delete_sec_context(OM_uint32 *min,
struct stub_gss_ctx_id_t_desc **context,
gss_buffer_t output_token)
{
(void)output_token;
if(!min)
return GSS_S_FAILURE;
if(!context) {
*min = STUB_GSS_INVALID_CTX;
return GSS_S_FAILURE;
}
if(!*context) {
*min = STUB_GSS_INVALID_CTX;
return GSS_S_FAILURE;
}
free(*context);
*context = NULL;
*min = 0;
return GSS_S_COMPLETE;
}
#endif /* DEBUGBUILD */
OM_uint32 Curl_gss_init_sec_context(struct Curl_easy *data,
OM_uint32 *minor_status,
gss_ctx_id_t *context,
gss_name_t target_name,
gss_OID mech_type,
gss_channel_bindings_t input_chan_bindings,
gss_buffer_t input_token,
gss_buffer_t output_token,
const bool mutual_auth,
OM_uint32 *ret_flags)
{
OM_uint32 req_flags = GSS_C_REPLAY_FLAG;
@@ -74,13 +317,30 @@ OM_uint32 Curl_gss_init_sec_context(
req_flags |= GSS_C_DELEG_POLICY_FLAG;
#else
infof(data, "WARNING: support for CURLGSSAPI_DELEGATION_POLICY_FLAG not "
"compiled in");
"compiled in");
#endif
}
if(data->set.gssapi_delegation & CURLGSSAPI_DELEGATION_FLAG)
req_flags |= GSS_C_DELEG_FLAG;
#ifdef DEBUGBUILD
if(getenv("CURL_STUB_GSS_CREDS"))
return stub_gss_init_sec_context(minor_status,
GSS_C_NO_CREDENTIAL, /* cred_handle */
(struct stub_gss_ctx_id_t_desc **)context,
target_name,
mech_type,
req_flags,
0, /* time_req */
input_chan_bindings,
input_token,
NULL, /* actual_mech_type */
output_token,
ret_flags,
NULL /* time_rec */);
#endif /* DEBUGBUILD */
return gss_init_sec_context(minor_status,
GSS_C_NO_CREDENTIAL, /* cred_handle */
context,
@@ -96,6 +356,20 @@ OM_uint32 Curl_gss_init_sec_context(
NULL /* time_rec */);
}
OM_uint32 Curl_gss_delete_sec_context(OM_uint32 *min,
gss_ctx_id_t *context,
gss_buffer_t output_token)
{
#ifdef DEBUGBUILD
if(getenv("CURL_STUB_GSS_CREDS"))
return stub_gss_delete_sec_context(min,
(struct stub_gss_ctx_id_t_desc **)context,
output_token);
#endif /* DEBUGBUILD */
return gss_delete_sec_context(min, context, output_token);
}
#define GSS_LOG_BUFFER_LEN 1024
static size_t display_gss_error(OM_uint32 status, int type,
char *buf, size_t len) {
+14 -11
View File
@@ -32,17 +32,20 @@ extern gss_OID_desc Curl_spnego_mech_oid;
extern gss_OID_desc Curl_krb5_mech_oid;
/* Common method for using GSS-API */
OM_uint32 Curl_gss_init_sec_context(
struct Curl_easy *data,
OM_uint32 *minor_status,
gss_ctx_id_t *context,
gss_name_t target_name,
gss_OID mech_type,
gss_channel_bindings_t input_chan_bindings,
gss_buffer_t input_token,
gss_buffer_t output_token,
const bool mutual_auth,
OM_uint32 *ret_flags);
OM_uint32 Curl_gss_init_sec_context(struct Curl_easy *data,
OM_uint32 *minor_status,
gss_ctx_id_t *context,
gss_name_t target_name,
gss_OID mech_type,
gss_channel_bindings_t input_chan_bindings,
gss_buffer_t input_token,
gss_buffer_t output_token,
const bool mutual_auth,
OM_uint32 *ret_flags);
OM_uint32 Curl_gss_delete_sec_context(OM_uint32 *min,
gss_ctx_id_t *context_handle,
gss_buffer_t output_token);
/* Helper to log a GSS-API error status */
void Curl_gss_log_error(struct Curl_easy *data, const char *prefix,
+14 -23
View File
@@ -57,7 +57,6 @@
#ifdef HEADER_CURL_MEMDEBUG_H
/* cleanup after memdebug.h */
#ifdef MEMDEBUG_NODEFINES
#ifdef CURLDEBUG
#undef strdup
@@ -69,28 +68,28 @@
#undef recv
#ifdef _WIN32
# ifdef UNICODE
# undef wcsdup
# undef _wcsdup
# undef _tcsdup
# else
# undef _tcsdup
# endif
#undef _tcsdup
#endif
#undef socket
#undef accept
#ifdef HAVE_ACCEPT4
#undef accept4
#endif
#ifdef HAVE_SOCKETPAIR
#undef socketpair
#endif
/* sclose is probably already defined, redefine it! */
#undef sclose
#define sclose(x) CURL_SCLOSE(x)
#undef fopen
#ifdef CURL_FOPEN
#define fopen(fname, mode) CURL_FOPEN(fname, mode)
#endif
#undef fdopen
#undef fclose
#endif /* MEMDEBUG_NODEFINES */
#endif /* CURLDEBUG */
#undef HEADER_CURL_MEMDEBUG_H
@@ -122,9 +121,6 @@ extern curl_free_callback Curl_cfree;
extern curl_realloc_callback Curl_crealloc;
extern curl_strdup_callback Curl_cstrdup;
extern curl_calloc_callback Curl_ccalloc;
#if defined(_WIN32) && defined(UNICODE)
extern curl_wcsdup_callback Curl_cwcsdup;
#endif
#ifndef CURLDEBUG
@@ -149,18 +145,13 @@ extern curl_wcsdup_callback Curl_cwcsdup;
#define free(ptr) Curl_cfree(ptr)
#ifdef _WIN32
# ifdef UNICODE
# undef wcsdup
# define wcsdup(ptr) Curl_cwcsdup(ptr)
# undef _wcsdup
# define _wcsdup(ptr) Curl_cwcsdup(ptr)
# undef _tcsdup
# define _tcsdup(ptr) Curl_cwcsdup(ptr)
# else
# undef _tcsdup
# define _tcsdup(ptr) Curl_cstrdup(ptr)
# endif
#undef _tcsdup
#ifdef UNICODE
#define _tcsdup(ptr) Curl_wcsdup(ptr)
#else
#define _tcsdup(ptr) Curl_cstrdup(ptr)
#endif
#endif /* _WIN32 */
#endif /* CURLDEBUG */
#endif /* HEADER_CURL_MEMORY_H */
+7 -36
View File
@@ -40,9 +40,8 @@
3. USE_GNUTLS
4. -
5. USE_MBEDTLS
6. USE_SECTRANSP
7. USE_OS400CRYPTO
8. USE_WIN32_CRYPTO
6. USE_OS400CRYPTO
7. USE_WIN32_CRYPTO
This ensures that:
- the same SSL branch gets activated throughout this source
@@ -107,11 +106,6 @@
# include <mbedtls/des.h>
#elif defined(USE_SECTRANSP)
# include <CommonCrypto/CommonCryptor.h>
# include <CommonCrypto/CommonDigest.h>
#elif defined(USE_OS400CRYPTO)
# include "cipher.mih" /* mih/cipher */
#elif defined(USE_WIN32_CRYPTO)
@@ -209,29 +203,6 @@ static bool encrypt_des(const unsigned char *in, unsigned char *out,
return mbedtls_des_crypt_ecb(&ctx, in, out) == 0;
}
#elif defined(USE_SECTRANSP)
static bool encrypt_des(const unsigned char *in, unsigned char *out,
const unsigned char *key_56)
{
char key[8];
size_t out_len;
CCCryptorStatus err;
/* Expand the 56-bit key to 64 bits */
extend_key_56_to_64(key_56, key);
/* Set the key parity to odd */
Curl_des_set_odd_parity((unsigned char *) key, sizeof(key));
/* Perform the encryption */
err = CCCrypt(kCCEncrypt, kCCAlgorithmDES, kCCOptionECBMode, key,
kCCKeySizeDES, NULL, in, 8 /* inbuflen */, out,
8 /* outbuflen */, &out_len);
return err == kCCSuccess;
}
#elif defined(USE_OS400CRYPTO)
static bool encrypt_des(const unsigned char *in, unsigned char *out,
@@ -339,8 +310,8 @@ void Curl_ntlm_core_lm_resp(const unsigned char *keys,
des_encrypt(&des, 8, results + 8, plaintext);
setup_des_key(keys + 14, &des);
des_encrypt(&des, 8, results + 16, plaintext);
#elif defined(USE_MBEDTLS) || defined(USE_SECTRANSP) \
|| defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO)
#elif defined(USE_MBEDTLS) || defined(USE_OS400CRYPTO) || \
defined(USE_WIN32_CRYPTO)
encrypt_des(plaintext, results, keys);
encrypt_des(plaintext, results + 8, keys + 7);
encrypt_des(plaintext, results + 16, keys + 14);
@@ -387,8 +358,8 @@ CURLcode Curl_ntlm_core_mk_lm_hash(const char *password,
des_encrypt(&des, 8, lmbuffer, magic);
setup_des_key(pw + 7, &des);
des_encrypt(&des, 8, lmbuffer + 8, magic);
#elif defined(USE_MBEDTLS) || defined(USE_SECTRANSP) \
|| defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO)
#elif defined(USE_MBEDTLS) || defined(USE_OS400CRYPTO) || \
defined(USE_WIN32_CRYPTO)
encrypt_des(magic, lmbuffer, pw);
encrypt_des(magic, lmbuffer + 8, pw + 7);
#endif
@@ -466,7 +437,7 @@ struct ms_filetime {
static void time2filetime(struct ms_filetime *ft, time_t t)
{
#if SIZEOF_TIME_T > 4
t = (t + CURL_OFF_T_C(11644473600)) * 10000000;
t = (t + (curl_off_t)11644473600) * 10000000;
ft->dwLowDateTime = (unsigned int) (t & 0xFFFFFFFF);
ft->dwHighDateTime = (unsigned int) (t >> 32);
#else
+4
View File
@@ -28,6 +28,10 @@
#if defined(USE_CURL_NTLM_CORE)
#include "vauth/vauth.h"
struct ntlmdata;
/* Helpers to generate function byte arguments in little endian order */
#define SHORTPAIR(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff))
#define LONGQUARTET(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff)), \
+23 -20
View File
@@ -326,51 +326,54 @@ static CURLcode rtmp_disconnect(struct Curl_easy *data,
return CURLE_OK;
}
static ssize_t rtmp_recv(struct Curl_easy *data, int sockindex, char *buf,
size_t len, CURLcode *err)
static CURLcode rtmp_recv(struct Curl_easy *data, int sockindex, char *buf,
size_t len, size_t *pnread)
{
struct connectdata *conn = data->conn;
RTMP *r = Curl_conn_meta_get(conn, CURL_META_RTMP_CONN);
CURLcode result = CURLE_OK;
ssize_t nread;
(void)sockindex; /* unused */
if(!r) {
*err = CURLE_FAILED_INIT;
return -1;
}
*pnread = 0;
if(!r)
return CURLE_FAILED_INIT;
nread = RTMP_Read(r, buf, curlx_uztosi(len));
if(nread < 0) {
if(r->m_read.status == RTMP_READ_COMPLETE ||
r->m_read.status == RTMP_READ_EOF) {
data->req.size = data->req.bytecount;
nread = 0;
}
else
*err = CURLE_RECV_ERROR;
result = CURLE_RECV_ERROR;
}
return nread;
else
*pnread = (size_t)nread;
return result;
}
static ssize_t rtmp_send(struct Curl_easy *data, int sockindex,
const void *buf, size_t len, bool eos, CURLcode *err)
static CURLcode rtmp_send(struct Curl_easy *data, int sockindex,
const void *buf, size_t len, bool eos,
size_t *pnwritten)
{
struct connectdata *conn = data->conn;
RTMP *r = Curl_conn_meta_get(conn, CURL_META_RTMP_CONN);
ssize_t num;
ssize_t nwritten;
(void)sockindex; /* unused */
(void)eos; /* unused */
if(!r) {
*err = CURLE_FAILED_INIT;
return -1;
}
*pnwritten = 0;
if(!r)
return CURLE_FAILED_INIT;
num = RTMP_Write(r, (const char *)buf, curlx_uztosi(len));
if(num < 0)
*err = CURLE_SEND_ERROR;
nwritten = RTMP_Write(r, (const char *)buf, curlx_uztosi(len));
if(nwritten < 0)
return CURLE_SEND_ERROR;
return num;
*pnwritten = (size_t)nwritten;
return CURLE_OK;
}
void Curl_rtmp_version(char *version, size_t len)
+315 -224
View File
@@ -76,44 +76,6 @@ static const struct {
{ ZERO_NULL, 0, 0 }
};
/*
* Curl_sasl_cleanup()
*
* This is used to cleanup any libraries or curl modules used by the sasl
* functions.
*
* Parameters:
*
* conn [in] - The connection data.
* authused [in] - The authentication mechanism used.
*/
void Curl_sasl_cleanup(struct connectdata *conn, unsigned short authused)
{
(void)conn;
(void)authused;
#if defined(USE_KERBEROS5)
/* Cleanup the gssapi structure */
if(authused == SASL_MECH_GSSAPI) {
Curl_auth_cleanup_gssapi(&conn->krb5);
}
#endif
#if defined(USE_GSASL)
/* Cleanup the GSASL structure */
if(authused & (SASL_MECH_SCRAM_SHA_1 | SASL_MECH_SCRAM_SHA_256)) {
Curl_auth_gsasl_cleanup(&conn->gsasl);
}
#endif
#if defined(USE_NTLM)
/* Cleanup the NTLM structure */
if(authused == SASL_MECH_NTLM) {
Curl_auth_cleanup_ntlm(&conn->ntlm);
}
#endif
}
/*
* Curl_sasl_decode_mech()
*
@@ -334,6 +296,241 @@ bool Curl_sasl_can_authenticate(struct SASL *sasl, struct Curl_easy *data)
return FALSE;
}
struct sasl_ctx {
struct SASL *sasl;
struct connectdata *conn;
const char *user;
unsigned short enabledmechs;
const char *mech;
saslstate state1;
saslstate state2;
struct bufref resp;
CURLcode result;
};
static bool sasl_choose_external(struct Curl_easy *data, struct sasl_ctx *sctx)
{
if((sctx->enabledmechs & SASL_MECH_EXTERNAL) && !sctx->conn->passwd[0]) {
sctx->mech = SASL_MECH_STRING_EXTERNAL;
sctx->state1 = SASL_EXTERNAL;
sctx->sasl->authused = SASL_MECH_EXTERNAL;
if(sctx->sasl->force_ir || data->set.sasl_ir)
Curl_auth_create_external_message(sctx->conn->user, &sctx->resp);
return TRUE;
}
return FALSE;
}
#ifdef USE_KERBEROS5
static bool sasl_choose_krb5(struct Curl_easy *data, struct sasl_ctx *sctx)
{
if(sctx->user &&
(sctx->enabledmechs & SASL_MECH_GSSAPI) &&
Curl_auth_is_gssapi_supported() &&
Curl_auth_user_contains_domain(sctx->conn->user)) {
const char *service = data->set.str[STRING_SERVICE_NAME] ?
data->set.str[STRING_SERVICE_NAME] :
sctx->sasl->params->service;
sctx->sasl->mutual_auth = FALSE;
sctx->mech = SASL_MECH_STRING_GSSAPI;
sctx->state1 = SASL_GSSAPI;
sctx->state2 = SASL_GSSAPI_TOKEN;
sctx->sasl->authused = SASL_MECH_GSSAPI;
if(sctx->sasl->force_ir || data->set.sasl_ir) {
struct kerberos5data *krb5 = Curl_auth_krb5_get(sctx->conn);
sctx->result = !krb5 ? CURLE_OUT_OF_MEMORY :
Curl_auth_create_gssapi_user_message(data, sctx->conn->user,
sctx->conn->passwd,
service, sctx->conn->host.name,
sctx->sasl->mutual_auth, NULL,
krb5, &sctx->resp);
}
return TRUE;
}
return FALSE;
}
#endif /* USE_KERBEROS5 */
#ifdef USE_GSASL
static bool sasl_choose_gsasl(struct Curl_easy *data, struct sasl_ctx *sctx)
{
struct gsasldata *gsasl;
struct bufref nullmsg;
if(sctx->user &&
(sctx->enabledmechs & (SASL_MECH_SCRAM_SHA_256|SASL_MECH_SCRAM_SHA_1))) {
gsasl = Curl_auth_gsasl_get(sctx->conn);
if(!gsasl) {
sctx->result = CURLE_OUT_OF_MEMORY;
return TRUE; /* attempted, but failed */
}
if((sctx->enabledmechs & SASL_MECH_SCRAM_SHA_256) &&
Curl_auth_gsasl_is_supported(data, SASL_MECH_STRING_SCRAM_SHA_256,
gsasl)) {
sctx->mech = SASL_MECH_STRING_SCRAM_SHA_256;
sctx->sasl->authused = SASL_MECH_SCRAM_SHA_256;
}
else if((sctx->enabledmechs & SASL_MECH_SCRAM_SHA_1) &&
Curl_auth_gsasl_is_supported(data, SASL_MECH_STRING_SCRAM_SHA_1,
gsasl)) {
sctx->mech = SASL_MECH_STRING_SCRAM_SHA_1;
sctx->sasl->authused = SASL_MECH_SCRAM_SHA_1;
}
else
return FALSE;
Curl_bufref_init(&nullmsg);
sctx->state1 = SASL_GSASL;
sctx->state2 = SASL_GSASL;
sctx->result = Curl_auth_gsasl_start(data, sctx->conn->user,
sctx->conn->passwd, gsasl);
if(!sctx->result && (sctx->sasl->force_ir || data->set.sasl_ir))
sctx->result = Curl_auth_gsasl_token(data, &nullmsg, gsasl, &sctx->resp);
return TRUE;
}
return FALSE;
}
#endif /* USE_GSASL */
#ifndef CURL_DISABLE_DIGEST_AUTH
static bool sasl_choose_digest(struct Curl_easy *data, struct sasl_ctx *sctx)
{
(void)data;
if(!sctx->user)
return FALSE;
else if((sctx->enabledmechs & SASL_MECH_DIGEST_MD5) &&
Curl_auth_is_digest_supported()) {
sctx->mech = SASL_MECH_STRING_DIGEST_MD5;
sctx->state1 = SASL_DIGESTMD5;
sctx->sasl->authused = SASL_MECH_DIGEST_MD5;
return TRUE;
}
else if(sctx->enabledmechs & SASL_MECH_CRAM_MD5) {
sctx->mech = SASL_MECH_STRING_CRAM_MD5;
sctx->state1 = SASL_CRAMMD5;
sctx->sasl->authused = SASL_MECH_CRAM_MD5;
return TRUE;
}
return FALSE;
}
#endif /* !CURL_DISABLE_DIGEST_AUTH */
#ifdef USE_NTLM
static bool sasl_choose_ntlm(struct Curl_easy *data, struct sasl_ctx *sctx)
{
if(!sctx->user)
return FALSE;
else if((sctx->enabledmechs & SASL_MECH_NTLM) &&
Curl_auth_is_ntlm_supported()) {
const char *service = data->set.str[STRING_SERVICE_NAME] ?
data->set.str[STRING_SERVICE_NAME] :
sctx->sasl->params->service;
const char *hostname;
int port;
Curl_conn_get_current_host(data, FIRSTSOCKET, &hostname, &port);
sctx->mech = SASL_MECH_STRING_NTLM;
sctx->state1 = SASL_NTLM;
sctx->state2 = SASL_NTLM_TYPE2MSG;
sctx->sasl->authused = SASL_MECH_NTLM;
if(sctx->sasl->force_ir || data->set.sasl_ir) {
struct ntlmdata *ntlm = Curl_auth_ntlm_get(sctx->conn, FALSE);
sctx->result = !ntlm ? CURLE_OUT_OF_MEMORY :
Curl_auth_create_ntlm_type1_message(data,
sctx->conn->user,
sctx->conn->passwd,
service, hostname,
ntlm, &sctx->resp);
}
return TRUE;
}
return FALSE;
}
#endif /* USE_NTLM */
static bool sasl_choose_oauth(struct Curl_easy *data, struct sasl_ctx *sctx)
{
const char *oauth_bearer = data->set.str[STRING_BEARER];
if(sctx->user && oauth_bearer &&
(sctx->enabledmechs & SASL_MECH_OAUTHBEARER)) {
const char *hostname;
int port;
Curl_conn_get_current_host(data, FIRSTSOCKET, &hostname, &port);
sctx->mech = SASL_MECH_STRING_OAUTHBEARER;
sctx->state1 = SASL_OAUTH2;
sctx->state2 = SASL_OAUTH2_RESP;
sctx->sasl->authused = SASL_MECH_OAUTHBEARER;
if(sctx->sasl->force_ir || data->set.sasl_ir)
sctx->result =
Curl_auth_create_oauth_bearer_message(sctx->conn->user,
hostname, port,
oauth_bearer, &sctx->resp);
return TRUE;
}
return FALSE;
}
static bool sasl_choose_oauth2(struct Curl_easy *data, struct sasl_ctx *sctx)
{
const char *oauth_bearer = data->set.str[STRING_BEARER];
if(sctx->user && oauth_bearer &&
(sctx->enabledmechs & SASL_MECH_XOAUTH2)) {
sctx->mech = SASL_MECH_STRING_XOAUTH2;
sctx->state1 = SASL_OAUTH2;
sctx->sasl->authused = SASL_MECH_XOAUTH2;
if(sctx->sasl->force_ir || data->set.sasl_ir)
sctx->result = Curl_auth_create_xoauth_bearer_message(sctx->conn->user,
oauth_bearer,
&sctx->resp);
return TRUE;
}
return FALSE;
}
static bool sasl_choose_plain(struct Curl_easy *data, struct sasl_ctx *sctx)
{
if(sctx->user && (sctx->enabledmechs & SASL_MECH_PLAIN)) {
sctx->mech = SASL_MECH_STRING_PLAIN;
sctx->state1 = SASL_PLAIN;
sctx->sasl->authused = SASL_MECH_PLAIN;
if(sctx->sasl->force_ir || data->set.sasl_ir)
sctx->result =
Curl_auth_create_plain_message(sctx->conn->sasl_authzid,
sctx->conn->user, sctx->conn->passwd,
&sctx->resp);
return TRUE;
}
return FALSE;
}
static bool sasl_choose_login(struct Curl_easy *data, struct sasl_ctx *sctx)
{
if(sctx->user && (sctx->enabledmechs & SASL_MECH_LOGIN)) {
sctx->mech = SASL_MECH_STRING_LOGIN;
sctx->state1 = SASL_LOGIN;
sctx->state2 = SASL_LOGIN_PASSWD;
sctx->sasl->authused = SASL_MECH_LOGIN;
if(sctx->sasl->force_ir || data->set.sasl_ir)
Curl_auth_create_login_message(sctx->conn->user, &sctx->resp);
return TRUE;
}
return FALSE;
}
/*
* Curl_sasl_start()
*
@@ -342,185 +539,66 @@ bool Curl_sasl_can_authenticate(struct SASL *sasl, struct Curl_easy *data)
CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
bool force_ir, saslprogress *progress)
{
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
unsigned short enabledmechs;
const char *mech = NULL;
struct bufref resp;
saslstate state1 = SASL_STOP;
saslstate state2 = SASL_FINAL;
const char *hostname, *disp_hostname;
int port;
#if defined(USE_KERBEROS5) || defined(USE_NTLM)
const char *service = data->set.str[STRING_SERVICE_NAME] ?
data->set.str[STRING_SERVICE_NAME] :
sasl->params->service;
#endif
const char *oauth_bearer = data->set.str[STRING_BEARER];
struct bufref nullmsg;
struct sasl_ctx sctx;
Curl_conn_get_host(data, FIRSTSOCKET, &hostname, &disp_hostname, &port);
Curl_bufref_init(&nullmsg);
Curl_bufref_init(&resp);
sasl->force_ir = force_ir; /* Latch for future use */
sasl->authused = 0; /* No mechanism used yet */
enabledmechs = sasl->authmechs & sasl->prefmech;
*progress = SASL_IDLE;
memset(&sctx, 0, sizeof(sctx));
sctx.sasl = sasl;
sctx.conn = data->conn;
sctx.user = data->state.aptr.user;
Curl_bufref_init(&sctx.resp);
sctx.enabledmechs = sasl->authmechs & sasl->prefmech;
sctx.state1 = SASL_STOP;
sctx.state2 = SASL_FINAL;
/* Calculate the supported authentication mechanism, by decreasing order of
security, as well as the initial response where appropriate */
if((enabledmechs & SASL_MECH_EXTERNAL) && !conn->passwd[0]) {
mech = SASL_MECH_STRING_EXTERNAL;
state1 = SASL_EXTERNAL;
sasl->authused = SASL_MECH_EXTERNAL;
if(force_ir || data->set.sasl_ir)
Curl_auth_create_external_message(conn->user, &resp);
}
else if(data->state.aptr.user) {
if(sasl_choose_external(data, &sctx) ||
#if defined(USE_KERBEROS5)
if((enabledmechs & SASL_MECH_GSSAPI) && Curl_auth_is_gssapi_supported() &&
Curl_auth_user_contains_domain(conn->user)) {
sasl->mutual_auth = FALSE;
mech = SASL_MECH_STRING_GSSAPI;
state1 = SASL_GSSAPI;
state2 = SASL_GSSAPI_TOKEN;
sasl->authused = SASL_MECH_GSSAPI;
if(force_ir || data->set.sasl_ir)
result = Curl_auth_create_gssapi_user_message(data, conn->user,
conn->passwd,
service,
conn->host.name,
sasl->mutual_auth,
NULL, &conn->krb5,
&resp);
}
else
sasl_choose_krb5(data, &sctx) ||
#endif
#ifdef USE_GSASL
if((enabledmechs & SASL_MECH_SCRAM_SHA_256) &&
Curl_auth_gsasl_is_supported(data, SASL_MECH_STRING_SCRAM_SHA_256,
&conn->gsasl)) {
mech = SASL_MECH_STRING_SCRAM_SHA_256;
sasl->authused = SASL_MECH_SCRAM_SHA_256;
state1 = SASL_GSASL;
state2 = SASL_GSASL;
result = Curl_auth_gsasl_start(data, conn->user,
conn->passwd, &conn->gsasl);
if(result == CURLE_OK && (force_ir || data->set.sasl_ir))
result = Curl_auth_gsasl_token(data, &nullmsg, &conn->gsasl, &resp);
}
else if((enabledmechs & SASL_MECH_SCRAM_SHA_1) &&
Curl_auth_gsasl_is_supported(data, SASL_MECH_STRING_SCRAM_SHA_1,
&conn->gsasl)) {
mech = SASL_MECH_STRING_SCRAM_SHA_1;
sasl->authused = SASL_MECH_SCRAM_SHA_1;
state1 = SASL_GSASL;
state2 = SASL_GSASL;
result = Curl_auth_gsasl_start(data, conn->user,
conn->passwd, &conn->gsasl);
if(result == CURLE_OK && (force_ir || data->set.sasl_ir))
result = Curl_auth_gsasl_token(data, &nullmsg, &conn->gsasl, &resp);
}
else
sasl_choose_gsasl(data, &sctx) ||
#endif
#ifndef CURL_DISABLE_DIGEST_AUTH
if((enabledmechs & SASL_MECH_DIGEST_MD5) &&
Curl_auth_is_digest_supported()) {
mech = SASL_MECH_STRING_DIGEST_MD5;
state1 = SASL_DIGESTMD5;
sasl->authused = SASL_MECH_DIGEST_MD5;
}
else if(enabledmechs & SASL_MECH_CRAM_MD5) {
mech = SASL_MECH_STRING_CRAM_MD5;
state1 = SASL_CRAMMD5;
sasl->authused = SASL_MECH_CRAM_MD5;
}
else
sasl_choose_digest(data, &sctx) ||
#endif
#ifdef USE_NTLM
if((enabledmechs & SASL_MECH_NTLM) && Curl_auth_is_ntlm_supported()) {
mech = SASL_MECH_STRING_NTLM;
state1 = SASL_NTLM;
state2 = SASL_NTLM_TYPE2MSG;
sasl->authused = SASL_MECH_NTLM;
if(force_ir || data->set.sasl_ir)
result = Curl_auth_create_ntlm_type1_message(data,
conn->user, conn->passwd,
service,
hostname,
&conn->ntlm, &resp);
}
else
sasl_choose_ntlm(data, &sctx) ||
#endif
if((enabledmechs & SASL_MECH_OAUTHBEARER) && oauth_bearer) {
mech = SASL_MECH_STRING_OAUTHBEARER;
state1 = SASL_OAUTH2;
state2 = SASL_OAUTH2_RESP;
sasl->authused = SASL_MECH_OAUTHBEARER;
if(force_ir || data->set.sasl_ir)
result = Curl_auth_create_oauth_bearer_message(conn->user,
hostname,
port,
oauth_bearer,
&resp);
}
else if((enabledmechs & SASL_MECH_XOAUTH2) && oauth_bearer) {
mech = SASL_MECH_STRING_XOAUTH2;
state1 = SASL_OAUTH2;
sasl->authused = SASL_MECH_XOAUTH2;
if(force_ir || data->set.sasl_ir)
result = Curl_auth_create_xoauth_bearer_message(conn->user,
oauth_bearer,
&resp);
}
else if(enabledmechs & SASL_MECH_PLAIN) {
mech = SASL_MECH_STRING_PLAIN;
state1 = SASL_PLAIN;
sasl->authused = SASL_MECH_PLAIN;
if(force_ir || data->set.sasl_ir)
result = Curl_auth_create_plain_message(conn->sasl_authzid,
conn->user, conn->passwd,
&resp);
}
else if(enabledmechs & SASL_MECH_LOGIN) {
mech = SASL_MECH_STRING_LOGIN;
state1 = SASL_LOGIN;
state2 = SASL_LOGIN_PASSWD;
sasl->authused = SASL_MECH_LOGIN;
if(force_ir || data->set.sasl_ir)
Curl_auth_create_login_message(conn->user, &resp);
}
sasl_choose_oauth(data, &sctx) ||
sasl_choose_oauth2(data, &sctx) ||
sasl_choose_plain(data, &sctx) ||
sasl_choose_login(data, &sctx)) {
/* selected, either we have a mechanism or a failure */
DEBUGASSERT(sctx.mech || sctx.result);
}
if(!result && mech) {
sasl->curmech = mech;
if(Curl_bufref_ptr(&resp))
result = build_message(sasl, &resp);
if(!sctx.result && sctx.mech) {
sasl->curmech = sctx.mech;
if(Curl_bufref_ptr(&sctx.resp))
sctx.result = build_message(sasl, &sctx.resp);
if(sasl->params->maxirlen &&
strlen(mech) + Curl_bufref_len(&resp) > sasl->params->maxirlen)
Curl_bufref_free(&resp);
strlen(sctx.mech) + Curl_bufref_len(&sctx.resp) >
sasl->params->maxirlen)
Curl_bufref_free(&sctx.resp);
if(!result)
result = sasl->params->sendauth(data, mech, &resp);
if(!sctx.result)
sctx.result = sasl->params->sendauth(data, sctx.mech, &sctx.resp);
if(!result) {
if(!sctx.result) {
*progress = SASL_INPROGRESS;
sasl_state(sasl, data, Curl_bufref_ptr(&resp) ? state2 : state1);
sasl_state(sasl, data, Curl_bufref_ptr(&sctx.resp) ?
sctx.state2 : sctx.state1);
}
}
Curl_bufref_free(&resp);
return result;
Curl_bufref_free(&sctx.resp);
return sctx.result;
}
/*
@@ -535,7 +613,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
struct connectdata *conn = data->conn;
saslstate newstate = SASL_FINAL;
struct bufref resp;
const char *hostname, *disp_hostname;
const char *hostname;
int port;
#if defined(USE_KERBEROS5) || defined(USE_NTLM) \
|| !defined(CURL_DISABLE_DIGEST_AUTH)
@@ -546,7 +624,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
const char *oauth_bearer = data->set.str[STRING_BEARER];
struct bufref serverdata;
Curl_conn_get_host(data, FIRSTSOCKET, &hostname, &disp_hostname, &port);
Curl_conn_get_current_host(data, FIRSTSOCKET, &hostname, &port);
Curl_bufref_init(&serverdata);
Curl_bufref_init(&resp);
*progress = SASL_INPROGRESS;
@@ -587,8 +665,11 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
#ifdef USE_GSASL
case SASL_GSASL:
result = get_server_message(sasl, data, &serverdata);
if(!result)
result = Curl_auth_gsasl_token(data, &serverdata, &conn->gsasl, &resp);
if(!result) {
struct gsasldata *gsasl = Curl_auth_gsasl_get(conn);
result = !gsasl ? CURLE_OUT_OF_MEMORY :
Curl_auth_gsasl_token(data, &serverdata, gsasl, &resp);
}
if(!result && Curl_bufref_len(&resp) > 0)
newstate = SASL_GSASL;
break;
@@ -615,50 +696,57 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
#endif
#ifdef USE_NTLM
case SASL_NTLM:
case SASL_NTLM: {
/* Create the type-1 message */
result = Curl_auth_create_ntlm_type1_message(data,
conn->user, conn->passwd,
service, hostname,
&conn->ntlm, &resp);
struct ntlmdata *ntlm = Curl_auth_ntlm_get(conn, FALSE);
result = !ntlm ? CURLE_OUT_OF_MEMORY :
Curl_auth_create_ntlm_type1_message(data,
conn->user, conn->passwd,
service, hostname,
ntlm, &resp);
newstate = SASL_NTLM_TYPE2MSG;
break;
case SASL_NTLM_TYPE2MSG:
}
case SASL_NTLM_TYPE2MSG: {
/* Decode the type-2 message */
result = get_server_message(sasl, data, &serverdata);
struct ntlmdata *ntlm = Curl_auth_ntlm_get(conn, FALSE);
result = !ntlm ? CURLE_FAILED_INIT :
get_server_message(sasl, data, &serverdata);
if(!result)
result = Curl_auth_decode_ntlm_type2_message(data, &serverdata,
&conn->ntlm);
result = Curl_auth_decode_ntlm_type2_message(data, &serverdata, ntlm);
if(!result)
result = Curl_auth_create_ntlm_type3_message(data, conn->user,
conn->passwd, &conn->ntlm,
conn->passwd, ntlm,
&resp);
break;
}
#endif
#if defined(USE_KERBEROS5)
case SASL_GSSAPI:
result = Curl_auth_create_gssapi_user_message(data, conn->user,
conn->passwd,
service,
conn->host.name,
case SASL_GSSAPI: {
struct kerberos5data *krb5 = Curl_auth_krb5_get(conn);
result = !krb5 ? CURLE_OUT_OF_MEMORY :
Curl_auth_create_gssapi_user_message(data, conn->user, conn->passwd,
service, conn->host.name,
sasl->mutual_auth, NULL,
&conn->krb5,
&resp);
krb5, &resp);
newstate = SASL_GSSAPI_TOKEN;
break;
}
case SASL_GSSAPI_TOKEN:
result = get_server_message(sasl, data, &serverdata);
if(!result) {
if(sasl->mutual_auth) {
struct kerberos5data *krb5 = Curl_auth_krb5_get(conn);
if(!krb5)
result = CURLE_OUT_OF_MEMORY;
else if(sasl->mutual_auth) {
/* Decode the user token challenge and create the optional response
message */
result = Curl_auth_create_gssapi_user_message(data, NULL, NULL,
NULL, NULL,
sasl->mutual_auth,
&serverdata,
&conn->krb5,
&resp);
krb5, &resp);
newstate = SASL_GSSAPI_NO_DATA;
}
else
@@ -666,19 +754,22 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
result = Curl_auth_create_gssapi_security_message(data,
conn->sasl_authzid,
&serverdata,
&conn->krb5,
&resp);
krb5, &resp);
}
break;
case SASL_GSSAPI_NO_DATA:
/* Decode the security challenge and create the response message */
result = get_server_message(sasl, data, &serverdata);
if(!result)
result = Curl_auth_create_gssapi_security_message(data,
conn->sasl_authzid,
&serverdata,
&conn->krb5,
&resp);
if(!result) {
struct kerberos5data *krb5 = Curl_auth_krb5_get(conn);
if(!krb5)
result = CURLE_OUT_OF_MEMORY;
else
result = Curl_auth_create_gssapi_security_message(data,
conn->sasl_authzid,
&serverdata,
krb5, &resp);
}
break;
#endif
-4
View File
@@ -135,10 +135,6 @@ struct SASL {
(wordlen == (sizeof(mech) - 1) / sizeof(char) && \
!memcmp(line, mech, wordlen))
/* This is used to cleanup any libraries or curl modules used by the sasl
functions */
void Curl_sasl_cleanup(struct connectdata *conn, unsigned short authused);
/* Convert a mechanism name to a token */
unsigned short Curl_sasl_decode_mech(const char *ptr,
size_t maxlen, size_t *len);
+53 -73
View File
@@ -228,46 +228,46 @@
#ifdef HTTP_ONLY
# ifndef CURL_DISABLE_DICT
# define CURL_DISABLE_DICT
# define CURL_DISABLE_DICT
# endif
# ifndef CURL_DISABLE_FILE
# define CURL_DISABLE_FILE
# define CURL_DISABLE_FILE
# endif
# ifndef CURL_DISABLE_FTP
# define CURL_DISABLE_FTP
# define CURL_DISABLE_FTP
# endif
# ifndef CURL_DISABLE_GOPHER
# define CURL_DISABLE_GOPHER
# define CURL_DISABLE_GOPHER
# endif
# ifndef CURL_DISABLE_IMAP
# define CURL_DISABLE_IMAP
# define CURL_DISABLE_IMAP
# endif
# ifndef CURL_DISABLE_LDAP
# define CURL_DISABLE_LDAP
# define CURL_DISABLE_LDAP
# endif
# ifndef CURL_DISABLE_LDAPS
# define CURL_DISABLE_LDAPS
# define CURL_DISABLE_LDAPS
# endif
# ifndef CURL_DISABLE_MQTT
# define CURL_DISABLE_MQTT
# define CURL_DISABLE_MQTT
# endif
# ifndef CURL_DISABLE_POP3
# define CURL_DISABLE_POP3
# define CURL_DISABLE_POP3
# endif
# ifndef CURL_DISABLE_RTSP
# define CURL_DISABLE_RTSP
# define CURL_DISABLE_RTSP
# endif
# ifndef CURL_DISABLE_SMB
# define CURL_DISABLE_SMB
# define CURL_DISABLE_SMB
# endif
# ifndef CURL_DISABLE_SMTP
# define CURL_DISABLE_SMTP
# define CURL_DISABLE_SMTP
# endif
# ifndef CURL_DISABLE_TELNET
# define CURL_DISABLE_TELNET
# define CURL_DISABLE_TELNET
# endif
# ifndef CURL_DISABLE_TFTP
# define CURL_DISABLE_TFTP
# define CURL_DISABLE_TFTP
# endif
#endif
@@ -485,64 +485,48 @@
# endif
#endif
/*
* Large file (>2Gb) support using Win32 functions.
*/
#ifdef USE_WIN32_LARGE_FILES
#ifdef _WIN32
# ifdef HAVE_IO_H
# include <io.h>
# endif
# include <sys/types.h>
# include <sys/stat.h>
# undef lseek
# define lseek(fdes,offset,whence) _lseeki64(fdes, offset, whence)
# undef fstat
# define fstat(fdes,stp) _fstati64(fdes, stp)
# undef stat
# define stat(fname,stp) curlx_win32_stat(fname, stp)
# define struct_stat struct _stati64
# define LSEEK_ERROR (__int64)-1
# define open curlx_win32_open
# define fopen(fname,mode) curlx_win32_fopen(fname, mode)
int curlx_win32_open(const char *filename, int oflag, ...);
int curlx_win32_stat(const char *path, struct_stat *buffer);
FILE *curlx_win32_fopen(const char *filename, const char *mode);
#endif
#ifdef __DJGPP__
/* Requires DJGPP 2.04 */
# ifdef USE_WIN32_LARGE_FILES
/* Large file (>2Gb) support using Win32 functions. */
# undef lseek
# define lseek(fdes, offset, whence) _lseeki64(fdes, offset, whence)
# undef fstat
# define fstat(fdes,stp) _fstati64(fdes, stp)
# undef stat
# define struct_stat struct _stati64
# define LSEEK_ERROR (__int64)-1
# else
/* Small file (<2Gb) support using Win32 functions. */
# ifndef UNDER_CE
# undef lseek
# define lseek(fdes, offset, whence) _lseek(fdes, (long)offset, whence)
# define fstat(fdes, stp) _fstat(fdes, stp)
# define struct_stat struct _stat
# endif
# define LSEEK_ERROR (long)-1
# endif
# ifndef UNDER_CE
int curlx_win32_stat(const char *path, struct_stat *buffer);
int curlx_win32_open(const char *filename, int oflag, ...);
FILE *curlx_win32_fopen(const char *filename, const char *mode);
# define stat(fname, stp) curlx_win32_stat(fname, stp)
# define open curlx_win32_open
# define CURL_FOPEN(fname, mode) curlx_win32_fopen(fname, mode)
# define fopen(fname, mode) CURL_FOPEN(fname, mode)
# endif
#elif defined(__DJGPP__)
/* Requires DJGPP 2.04 */
# include <unistd.h>
# undef lseek
# define lseek(fdes,offset,whence) llseek(fdes, offset, whence)
# define LSEEK_ERROR (offset_t)-1
#endif
/*
* Small file (<2Gb) support using Win32 functions.
*/
#if defined(_WIN32) && !defined(USE_WIN32_LARGE_FILES)
# ifdef HAVE_IO_H
# include <io.h>
# endif
# include <sys/types.h>
# include <sys/stat.h>
# ifndef UNDER_CE
# undef lseek
# define lseek(fdes,offset,whence) _lseek(fdes, (long)offset, whence)
# define fstat(fdes,stp) _fstat(fdes, stp)
# define stat(fname,stp) curlx_win32_stat(fname, stp)
# define struct_stat struct _stat
# define open curlx_win32_open
# define fopen(fname,mode) curlx_win32_fopen(fname, mode)
int curlx_win32_stat(const char *path, struct_stat *buffer);
int curlx_win32_open(const char *filename, int oflag, ...);
FILE *curlx_win32_fopen(const char *filename, const char *mode);
# endif
# define LSEEK_ERROR (long)-1
#endif
#ifndef struct_stat
#define struct_stat struct stat
#endif
@@ -597,7 +581,7 @@
# endif
# endif
# ifndef SIZEOF_OFF_T
# define SIZEOF_OFF_T 4
# define SIZEOF_OFF_T 4
# endif
#endif
@@ -605,9 +589,9 @@
#error "too small curl_off_t"
#else
/* assume SIZEOF_CURL_OFF_T == 8 */
# define CURL_OFF_T_MAX CURL_OFF_T_C(0x7FFFFFFFFFFFFFFF)
# define CURL_OFF_T_MAX 0x7FFFFFFFFFFFFFFF
#endif
#define CURL_OFF_T_MIN (-CURL_OFF_T_MAX - CURL_OFF_T_C(1))
#define CURL_OFF_T_MIN (-CURL_OFF_T_MAX - 1)
#if (SIZEOF_CURL_OFF_T != 8)
# error "curl_off_t must be exactly 64 bits"
@@ -692,12 +676,8 @@
# define select(n,r,w,x,t) select_s(n,r,w,x,t)
# define ioctl(x,y,z) ioctlsocket(x,y,(char *)(z))
# include <tcp.h>
# ifdef word
# undef word
# endif
# ifdef byte
# undef byte
# endif
# undef word
# undef byte
# endif /* MSDOS */
@@ -754,8 +734,8 @@
#endif
#if defined(USE_GNUTLS) || defined(USE_OPENSSL) || defined(USE_MBEDTLS) || \
defined(USE_WOLFSSL) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \
defined(USE_BEARSSL) || defined(USE_RUSTLS)
defined(USE_WOLFSSL) || defined(USE_SCHANNEL) || \
defined(USE_RUSTLS)
#define USE_SSL /* SSL support has been enabled */
#endif
@@ -790,7 +770,7 @@
/* Single point where USE_NTLM definition might be defined */
#ifndef CURL_DISABLE_NTLM
# if defined(USE_OPENSSL) || defined(USE_MBEDTLS) || \
defined(USE_GNUTLS) || defined(USE_SECTRANSP) || \
defined(USE_GNUTLS) || \
defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) || \
(defined(USE_WOLFSSL) && defined(HAVE_WOLFSSL_DES_ECB_ENCRYPT))
# define USE_CURL_NTLM_CORE
+9 -9
View File
@@ -41,11 +41,9 @@
#include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifdef HAVE_SYS_TIME_H
#if !defined(_WIN32) || defined(__MINGW32__)
#include <sys/time.h>
#endif
@@ -96,7 +94,7 @@
# endif
#endif
#ifdef HAVE_SYS_SOCKET_H
#ifndef _WIN32
#include <sys/socket.h>
#endif
@@ -197,17 +195,19 @@ struct timeval {
*/
#ifdef HAVE_CLOSESOCKET
# define sclose(x) closesocket((x))
# define CURL_SCLOSE(x) closesocket((x))
#elif defined(HAVE_CLOSESOCKET_CAMEL)
# define sclose(x) CloseSocket((x))
# define CURL_SCLOSE(x) CloseSocket((x))
#elif defined(MSDOS) /* Watt-32 */
# define sclose(x) close_s((x))
# define CURL_SCLOSE(x) close_s((x))
#elif defined(USE_LWIPSOCK)
# define sclose(x) lwip_close((x))
# define CURL_SCLOSE(x) lwip_close((x))
#else
# define sclose(x) close((x))
# define CURL_SCLOSE(x) close((x))
#endif
#define sclose(x) CURL_SCLOSE(x)
/*
* Stack-independent version of fcntl() on sockets:
*/
-2
View File
@@ -34,9 +34,7 @@
* * GnuTLS
* * wolfSSL
* * Schannel SSPI
* * Secure Transport (Darwin)
* * mbedTLS
* * BearSSL
* * Rustls
* Skip the backend if it does not support the required algorithm */
+8 -43
View File
@@ -28,6 +28,7 @@
#include <curl/curl.h>
#include "curl_sspi.h"
#include "strdup.h"
#include "curlx/multibyte.h"
#include "system_win32.h"
#include "curlx/version_win32.h"
@@ -37,23 +38,6 @@
#include "curl_memory.h"
#include "memdebug.h"
/* We use our own typedef here since some headers might lack these */
typedef PSecurityFunctionTable (APIENTRY *INITSECURITYINTERFACE_FN)(VOID);
/* See definition of SECURITY_ENTRYPOINT in sspi.h */
#ifdef UNICODE
# ifdef UNDER_CE
# define SECURITYENTRYPOINT L"InitSecurityInterfaceW"
# else
# define SECURITYENTRYPOINT "InitSecurityInterfaceW"
# endif
#else
# define SECURITYENTRYPOINT "InitSecurityInterfaceA"
#endif
/* Handle of security.dll or secur32.dll, depending on Windows version */
HMODULE Curl_hSecDll = NULL;
/* Pointer to SSPI dispatch table */
PSecurityFunctionTable Curl_pSecFn = NULL;
@@ -76,31 +60,14 @@ PSecurityFunctionTable Curl_pSecFn = NULL;
*/
CURLcode Curl_sspi_global_init(void)
{
INITSECURITYINTERFACE_FN pInitSecurityInterface;
/* If security interface is not yet initialized try to do this */
if(!Curl_hSecDll) {
/* Security Service Provider Interface (SSPI) functions are located in
* security.dll on WinNT 4.0 and in secur32.dll on Win9x. Win2K and XP
* have both these DLLs (security.dll forwards calls to secur32.dll) */
/* Load SSPI dll into the address space of the calling process */
if(curlx_verify_windows_version(4, 0, 0, PLATFORM_WINNT, VERSION_EQUAL))
Curl_hSecDll = Curl_load_library(TEXT("security.dll"));
else
Curl_hSecDll = Curl_load_library(TEXT("secur32.dll"));
if(!Curl_hSecDll)
return CURLE_FAILED_INIT;
/* Get address of the InitSecurityInterfaceA function from the SSPI dll */
pInitSecurityInterface =
CURLX_FUNCTION_CAST(INITSECURITYINTERFACE_FN,
(GetProcAddress(Curl_hSecDll, SECURITYENTRYPOINT)));
if(!pInitSecurityInterface)
return CURLE_FAILED_INIT;
if(!Curl_pSecFn) {
/* Get pointer to Security Service Provider Interface dispatch table */
Curl_pSecFn = pInitSecurityInterface();
#ifdef __MINGW32CE__
Curl_pSecFn = InitSecurityInterfaceW();
#else
Curl_pSecFn = InitSecurityInterface();
#endif
if(!Curl_pSecFn)
return CURLE_FAILED_INIT;
}
@@ -119,9 +86,7 @@ CURLcode Curl_sspi_global_init(void)
*/
void Curl_sspi_global_cleanup(void)
{
if(Curl_hSecDll) {
FreeLibrary(Curl_hSecDll);
Curl_hSecDll = NULL;
if(Curl_pSecFn) {
Curl_pSecFn = NULL;
}
}
-1
View File
@@ -57,7 +57,6 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp,
void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY *identity);
/* Forward-declaration of global variables defined in curl_sspi.c */
extern HMODULE Curl_hSecDll;
extern PSecurityFunctionTable Curl_pSecFn;
/* Provide some definitions missing in old headers */
+1 -2
View File
@@ -31,7 +31,6 @@
#include "easyif.h"
#include "cfilters.h"
#include "multiif.h"
#include "strcase.h"
#include "cf-socket.h"
#include "connect.h"
@@ -206,7 +205,7 @@ void Curl_failf(struct Curl_easy *data, const char *fmt, ...)
static void trc_infof(struct Curl_easy *data,
struct curl_trc_feat *feat,
const char *opt_id, int opt_id_idx,
const char * const fmt, va_list ap) CURL_PRINTF(5, 0);
const char * const fmt, va_list ap) CURL_PRINTF(5, 0);
static void trc_infof(struct Curl_easy *data,
struct curl_trc_feat *feat,
@@ -1,5 +1,5 @@
#ifndef HEADER_CURL_BEARSSL_H
#define HEADER_CURL_BEARSSL_H
#ifndef HEADER_CURL_TOOL_BINMODE_H
#define HEADER_CURL_TOOL_BINMODE_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) Michael Forney, <mforney@mforney.org>
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -23,12 +23,17 @@
* SPDX-License-Identifier: curl
*
***************************************************************************/
#include "../curl_setup.h"
#ifdef USE_BEARSSL
#if (defined(HAVE_SETMODE) || defined(HAVE__SETMODE)) && defined(O_BINARY)
/* Requires io.h and/or fcntl.h when available */
#ifdef HAVE__SETMODE
# define CURLX_SET_BINMODE(stream) (void)_setmode(fileno(stream), O_BINARY)
#else
# define CURLX_SET_BINMODE(stream) (void)setmode(fileno(stream), O_BINARY)
#endif
#else
# define CURLX_SET_BINMODE(stream) (void)stream; Curl_nop_stmt
#endif
extern const struct Curl_ssl Curl_ssl_bearssl;
#endif /* USE_BEARSSL */
#endif /* HEADER_CURL_BEARSSL_H */
#endif /* HEADER_CURL_TOOL_BINMODE_H */
+9
View File
@@ -31,6 +31,9 @@
* be.
*/
#include "binmode.h"
/* "binmode.h" provides macro CURLX_SET_BINMODE() */
#include "nonblock.h"
/* "nonblock.h" provides curlx_nonblock() */
@@ -65,10 +68,16 @@
#include "timeval.h"
#include "timediff.h"
#include "wait.h"
/* for curlx_wait_ms */
#include "winapi.h"
/* for curlx_winapi_strerror */
#include "inet_pton.h"
/* for curlx_inet_pton */
#include "inet_ntop.h"
/* for curlx_inet_ntop */
#endif /* HEADER_CURL_CURLX_H */
@@ -20,7 +20,7 @@
* Original code by Paul Vixie. "curlified" by Gisle Vanem.
*/
#include "curl_setup.h"
#include "../curl_setup.h"
#ifndef HAVE_INET_NTOP
@@ -35,7 +35,6 @@
#endif
#include "inet_ntop.h"
#include "curl_printf.h"
#define IN6ADDRSZ 16
/* #define INADDRSZ 4 */
@@ -65,8 +64,9 @@ static char *inet_ntop4(const unsigned char *src, char *dst, size_t size)
DEBUGASSERT(size >= 16);
tmp[0] = '\0';
(void)msnprintf(tmp, sizeof(tmp), "%d.%d.%d.%d",
/* this sprintf() does not overflow the buffer. Avoids snprintf to work more
widely. Avoids the msnprintf family to work as a curlx function. */
(void)(sprintf)(tmp, "%d.%d.%d.%d",
((int)((unsigned char)src[0])) & 0xff,
((int)((unsigned char)src[1])) & 0xff,
((int)((unsigned char)src[2])) & 0xff,
@@ -162,7 +162,21 @@ static char *inet_ntop6(const unsigned char *src, char *dst, size_t size)
tp += strlen(tp);
break;
}
tp += msnprintf(tp, 5, "%x", words[i]);
else {
/* Lower-case digits. Can't use the set from mprintf.c since this
needs to work as a curlx function */
static const unsigned char ldigits[] = "0123456789abcdef";
unsigned int w = words[i];
/* output lowercase 16bit hex number but ignore leading zeroes */
if(w & 0xf000)
*tp++ = ldigits[(w & 0xf000) >> 12];
if(w & 0xff00)
*tp++ = ldigits[(w & 0x0f00) >> 8];
if(w & 0xfff0)
*tp++ = ldigits[(w & 0x00f0) >> 4];
*tp++ = ldigits[(w & 0x000f)];
}
}
/* Was it a trailing run of 0x00's?
@@ -196,7 +210,7 @@ static char *inet_ntop6(const unsigned char *src, char *dst, size_t size)
* code. This is to avoid losing the actual last Winsock error. When this
* function returns NULL, check errno not SOCKERRNO.
*/
char *Curl_inet_ntop(int af, const void *src, char *buf, size_t size)
char *curlx_inet_ntop(int af, const void *src, char *buf, size_t size)
{
switch(af) {
case AF_INET:
@@ -24,26 +24,26 @@
*
***************************************************************************/
#include "curl_setup.h"
#include "../curl_setup.h"
char *Curl_inet_ntop(int af, const void *addr, char *buf, size_t size);
char *curlx_inet_ntop(int af, const void *addr, char *buf, size_t size);
#ifdef HAVE_INET_NTOP
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#ifndef _WIN32
#include <sys/socket.h>
#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#ifdef __AMIGA__
#define Curl_inet_ntop(af,addr,buf,size) \
#define curlx_inet_ntop(af,addr,buf,size) \
(char *)inet_ntop(af, CURL_UNCONST(addr), (unsigned char *)buf, \
(curl_socklen_t)(size))
#else
#define Curl_inet_ntop(af,addr,buf,size) \
#define curlx_inet_ntop(af,addr,buf,size) \
inet_ntop(af, addr, buf, (curl_socklen_t)(size))
#endif
#endif
+1 -1
View File
@@ -32,7 +32,7 @@ int curlx_inet_pton(int, const char *, void *);
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#ifndef _WIN32
#include <sys/socket.h>
#endif
#ifdef HAVE_ARPA_INET_H
+9 -6
View File
@@ -23,7 +23,10 @@
***************************************************************************/
#include "strparse.h"
#include "../strcase.h"
#ifndef WITHOUT_LIBCURL
#include <curl/curl.h> /* for curl_strnequal() */
#endif
void curlx_str_init(struct Curl_str *out)
{
@@ -40,7 +43,7 @@ void curlx_str_assign(struct Curl_str *out, const char *str, size_t len)
/* Get a word until the first DELIM or end of string. At least one byte long.
return non-zero on error */
int curlx_str_until(const char **linep, struct Curl_str *out,
const size_t max, char delim)
const size_t max, char delim)
{
const char *s = *linep;
size_t len = 0;
@@ -64,7 +67,7 @@ int curlx_str_until(const char **linep, struct Curl_str *out,
/* Get a word until the first space or end of string. At least one byte long.
return non-zero on error */
int curlx_str_word(const char **linep, struct Curl_str *out,
const size_t max)
const size_t max)
{
return curlx_str_until(linep, out, max, ' ');
}
@@ -72,7 +75,7 @@ int curlx_str_word(const char **linep, struct Curl_str *out,
/* Get a word until a newline byte or end of string. At least one byte long.
return non-zero on error */
int curlx_str_untilnl(const char **linep, struct Curl_str *out,
const size_t max)
const size_t max)
{
const char *s = *linep;
size_t len = 0;
@@ -96,7 +99,7 @@ int curlx_str_untilnl(const char **linep, struct Curl_str *out,
/* Get a "quoted" word. No escaping possible.
return non-zero on error */
int curlx_str_quotedword(const char **linep, struct Curl_str *out,
const size_t max)
const size_t max)
{
const char *s = *linep;
size_t len = 0;
@@ -238,7 +241,7 @@ int curlx_str_newline(const char **linep)
int curlx_str_casecompare(struct Curl_str *str, const char *check)
{
size_t clen = check ? strlen(check) : 0;
return ((str->len == clen) && strncasecompare(str->str, check, clen));
return ((str->len == clen) && curl_strnequal(str->str, check, clen));
}
#endif
+3 -3
View File
@@ -55,17 +55,17 @@ int curlx_str_word(const char **linep, struct Curl_str *out, const size_t max);
/* Get a word until the first DELIM or end of string
return non-zero on error */
int curlx_str_until(const char **linep, struct Curl_str *out, const size_t max,
char delim);
char delim);
/* Get a word until a newline byte or end of string. At least one byte long.
return non-zero on error */
int curlx_str_untilnl(const char **linep, struct Curl_str *out,
const size_t max);
const size_t max);
/* Get a "quoted" word. No escaping possible.
return non-zero on error */
int curlx_str_quotedword(const char **linep, struct Curl_str *out,
const size_t max);
const size_t max);
/* Advance over a single character.
return non-zero on error */
+97
View File
@@ -0,0 +1,97 @@
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* SPDX-License-Identifier: curl
*
***************************************************************************/
#include "../curl_setup.h"
#ifndef HAVE_SELECT
#error "We cannot compile without select() support."
#endif
#include <limits.h>
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#elif defined(HAVE_UNISTD_H)
#include <unistd.h>
#endif
#ifdef MSDOS
#include <dos.h> /* delay() */
#endif
#include "timediff.h"
#include "wait.h"
/*
* Internal function used for waiting a specific amount of ms in
* Curl_socket_check() and Curl_poll() when no file descriptor is provided to
* wait on, just being used to delay execution. Winsock select() and poll()
* timeout mechanisms need a valid socket descriptor in a not null file
* descriptor set to work. Waiting indefinitely with this function is not
* allowed, a zero or negative timeout value will return immediately. Timeout
* resolution, accuracy, as well as maximum supported value is system
* dependent, neither factor is a critical issue for the intended use of this
* function in the library.
*
* Return values:
* -1 = system call error, or invalid timeout value
* 0 = specified timeout has elapsed, or interrupted
*/
int curlx_wait_ms(timediff_t timeout_ms)
{
int r = 0;
if(!timeout_ms)
return 0;
if(timeout_ms < 0) {
SET_SOCKERRNO(SOCKEINVAL);
return -1;
}
#if defined(MSDOS)
delay((unsigned int)timeout_ms);
#elif defined(_WIN32)
/* prevent overflow, timeout_ms is typecast to ULONG/DWORD. */
#if TIMEDIFF_T_MAX >= ULONG_MAX
if(timeout_ms >= ULONG_MAX)
timeout_ms = ULONG_MAX-1;
/* do not use ULONG_MAX, because that is equal to INFINITE */
#endif
Sleep((DWORD)timeout_ms);
#else
/* avoid using poll() for this since it behaves incorrectly with no sockets
on Apple operating systems */
{
struct timeval pending_tv;
r = select(0, NULL, NULL, NULL, curlx_mstotv(&pending_tv, timeout_ms));
}
#endif /* _WIN32 */
if(r) {
if((r == -1) && (SOCKERRNO == SOCKEINTR))
/* make EINTR from select or poll not a "lethal" error */
r = 0;
else
r = -1;
}
return r;
}
@@ -1,5 +1,5 @@
#ifndef HEADER_CURL_SECTRANSP_H
#define HEADER_CURL_SECTRANSP_H
#ifndef HEADER_CURL_WAIT_H
#define HEADER_CURL_WAIT_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
@@ -7,7 +7,6 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) Nick Zitzmann, <nickzman@gmail.com>.
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
@@ -24,11 +23,9 @@
* SPDX-License-Identifier: curl
*
***************************************************************************/
#include "../curl_setup.h"
#ifdef USE_SECTRANSP
int curlx_wait_ms(timediff_t timeout_ms);
extern const struct Curl_ssl Curl_ssl_sectransp;
#endif /* USE_SECTRANSP */
#endif /* HEADER_CURL_SECTRANSP_H */
#endif /* HEADER_CURL_WAIT_H */
-23
View File
@@ -35,11 +35,6 @@
#endif /* __INTEL_COMPILER && __unix__ */
#ifdef _WIN32
#undef read
#undef write
#endif
#include <limits.h>
#define CURL_MASK_UCHAR ((unsigned char)~0)
@@ -295,21 +290,3 @@ size_t curlx_sitouz(int sinum)
# pragma warning(pop)
#endif
}
#ifdef _WIN32
ssize_t curlx_read(int fd, void *buf, size_t count)
{
return (ssize_t)read(fd, buf, curlx_uztoui(count));
}
ssize_t curlx_write(int fd, const void *buf, size_t count)
{
return (ssize_t)write(fd, buf, curlx_uztoui(count));
}
#endif /* _WIN32 */
/* Ensure that warnless.h redefinitions continue to have an effect
in "unity" builds. */
#undef HEADER_CURL_WARNLESS_H_REDEFS
+3 -16
View File
@@ -57,24 +57,11 @@ unsigned short curlx_uitous(unsigned int uinum);
size_t curlx_sitouz(int sinum);
#ifdef _WIN32
ssize_t curlx_read(int fd, void *buf, size_t count);
ssize_t curlx_write(int fd, const void *buf, size_t count);
#endif /* _WIN32 */
#endif /* HEADER_CURL_WARNLESS_H */
#ifndef HEADER_CURL_WARNLESS_H_REDEFS
#define HEADER_CURL_WARNLESS_H_REDEFS
#ifdef _WIN32
#undef read
#define read(fd, buf, count) curlx_read(fd, buf, count)
#define read(fd, buf, count) (ssize_t)_read(fd, buf, curlx_uztoui(count))
#undef write
#define write(fd, buf, count) curlx_write(fd, buf, count)
#define write(fd, buf, count) (ssize_t)_write(fd, buf, curlx_uztoui(count))
#endif
#endif /* HEADER_CURL_WARNLESS_H_REDEFS */
#endif /* HEADER_CURL_WARNLESS_H */
+2 -3
View File
@@ -31,6 +31,7 @@
#include "headers.h"
#include "multiif.h"
#include "sendf.h"
#include "transfer.h"
#include "cw-out.h"
#include "cw-pause.h"
@@ -234,11 +235,9 @@ static CURLcode cw_out_ptr_flush(struct cw_out_ctx *ctx,
failf(data, "Write callback asked for PAUSE when not supported");
return CURLE_WRITE_ERROR;
}
/* mark the connection as RECV paused */
data->req.keepon |= KEEP_RECV_PAUSE;
ctx->paused = TRUE;
CURL_TRC_WRITE(data, "[OUT] PAUSE requested by client");
break;
return Curl_xfer_pause_recv(data, TRUE);
}
else if(CURL_WRITEFUNC_ERROR == nwritten) {
failf(data, "client returned ERROR on write of %zu bytes", wlen);
+6 -7
View File
@@ -60,7 +60,6 @@
#include "progress.h"
#include "dict.h"
#include "curl_printf.h"
#include "strcase.h"
#include "curl_memory.h"
/* The last #include file should be: */
#include "memdebug.h"
@@ -198,9 +197,9 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
if(result)
return result;
if(strncasecompare(path, DICT_MATCH, sizeof(DICT_MATCH)-1) ||
strncasecompare(path, DICT_MATCH2, sizeof(DICT_MATCH2)-1) ||
strncasecompare(path, DICT_MATCH3, sizeof(DICT_MATCH3)-1)) {
if(curl_strnequal(path, DICT_MATCH, sizeof(DICT_MATCH)-1) ||
curl_strnequal(path, DICT_MATCH2, sizeof(DICT_MATCH2)-1) ||
curl_strnequal(path, DICT_MATCH3, sizeof(DICT_MATCH3)-1)) {
word = strchr(path, ':');
if(word) {
@@ -245,9 +244,9 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
}
Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE); /* no upload */
}
else if(strncasecompare(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) ||
strncasecompare(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) ||
strncasecompare(path, DICT_DEFINE3, sizeof(DICT_DEFINE3)-1)) {
else if(curl_strnequal(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) ||
curl_strnequal(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) ||
curl_strnequal(path, DICT_DEFINE3, sizeof(DICT_DEFINE3)-1)) {
word = strchr(path, ':');
if(word) {
+2 -4
View File
@@ -257,7 +257,7 @@ static void doh_probe_done(struct Curl_easy *data,
if(!dohp->pending) {
/* DoH completed, run the transfer picking up the results */
Curl_expire(data, 0, EXPIRE_RUN_NOW);
Curl_multi_mark_dirty(data);
}
}
}
@@ -377,8 +377,6 @@ static CURLcode doh_probe_run(struct Curl_easy *data,
options should be added to check doh proxy insecure separately,
CURLOPT_DOH_PROXY_SSL_VERIFYHOST and CURLOPT_DOH_PROXY_SSL_VERIFYPEER.
*/
if(data->set.ssl.falsestart)
ERROR_CHECK_SETOPT(CURLOPT_SSL_FALSESTART, 1L);
if(data->set.str[STRING_SSL_CAFILE]) {
ERROR_CHECK_SETOPT(CURLOPT_CAINFO,
data->set.str[STRING_SSL_CAFILE]);
@@ -590,7 +588,7 @@ static void doh_store_a(const unsigned char *doh, int index,
}
static void doh_store_aaaa(const unsigned char *doh, int index,
struct dohentry *d)
struct dohentry *d)
{
/* silently ignore addresses over the limit */
if(d->numaddr < DOH_MAX_ADDR) {
+3 -3
View File
@@ -150,7 +150,7 @@ struct dynhds_entry *Curl_dynhds_get(struct dynhds *dynhds, const char *name,
size_t i;
for(i = 0; i < dynhds->hds_len; ++i) {
if(dynhds->hds[i]->namelen == namelen &&
strncasecompare(dynhds->hds[i]->name, name, namelen)) {
curl_strnequal(dynhds->hds[i]->name, name, namelen)) {
return dynhds->hds[i];
}
}
@@ -297,7 +297,7 @@ size_t Curl_dynhds_count_name(struct dynhds *dynhds,
size_t i;
for(i = 0; i < dynhds->hds_len; ++i) {
if((namelen == dynhds->hds[i]->namelen) &&
strncasecompare(name, dynhds->hds[i]->name, namelen))
curl_strnequal(name, dynhds->hds[i]->name, namelen))
++n;
}
}
@@ -325,7 +325,7 @@ size_t Curl_dynhds_remove(struct dynhds *dynhds,
size_t i, len;
for(i = 0; i < dynhds->hds_len; ++i) {
if((namelen == dynhds->hds[i]->namelen) &&
strncasecompare(name, dynhds->hds[i]->name, namelen)) {
curl_strnequal(name, dynhds->hds[i]->name, namelen)) {
++n;
--dynhds->hds_len;
dynhds->strs_len -= (dynhds->hds[i]->namelen +
+24 -62
View File
@@ -67,6 +67,7 @@
#include "amigaos.h"
#include "macos.h"
#include "curlx/warnless.h"
#include "curlx/wait.h"
#include "sigpipe.h"
#include "vssh/ssh.h"
#include "setopt.h"
@@ -128,9 +129,6 @@ curl_free_callback Curl_cfree = (curl_free_callback)free;
curl_realloc_callback Curl_crealloc = (curl_realloc_callback)realloc;
curl_strdup_callback Curl_cstrdup = (curl_strdup_callback)system_strdup;
curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc;
#if defined(_WIN32) && defined(UNICODE)
curl_wcsdup_callback Curl_cwcsdup = Curl_wcsdup;
#endif
#if defined(_MSC_VER) && defined(_DLL)
# pragma warning(pop)
@@ -156,9 +154,6 @@ static CURLcode global_init(long flags, bool memoryfuncs)
Curl_crealloc = (curl_realloc_callback)realloc;
Curl_cstrdup = (curl_strdup_callback)system_strdup;
Curl_ccalloc = (curl_calloc_callback)calloc;
#if defined(_WIN32) && defined(UNICODE)
Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup;
#endif
}
if(Curl_trc_init()) {
@@ -611,7 +606,7 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
#endif
pollrc = 0;
if(ev->ms > 0)
Curl_wait_ms(ev->ms);
curlx_wait_ms(ev->ms);
}
ev->msbump = FALSE; /* reset here */
@@ -733,7 +728,7 @@ static CURLcode easy_transfer(struct Curl_multi *multi)
/*
* easy_perform() is the external interface that performs a blocking
* easy_perform() is the internal interface that performs a blocking
* transfer as previously setup.
*
* CONCEPT: This function creates a multi handle, adds the easy handle to it,
@@ -1128,13 +1123,12 @@ void curl_easy_reset(CURL *d)
*/
CURLcode curl_easy_pause(CURL *d, int action)
{
struct SingleRequest *k;
CURLcode result = CURLE_OK;
int oldstate;
int newstate;
bool recursive = FALSE;
bool keep_changed, unpause_read, not_all_paused;
bool changed = FALSE;
struct Curl_easy *data = d;
bool recv_paused, recv_paused_new;
bool send_paused, send_paused_new;
if(!GOOD_EASY_HANDLE(data) || !data->conn)
/* crazy input, do not continue */
@@ -1142,62 +1136,37 @@ CURLcode curl_easy_pause(CURL *d, int action)
if(Curl_is_in_callback(data))
recursive = TRUE;
k = &data->req;
oldstate = k->keepon & (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE);
/* first switch off both pause bits then set the new pause bits */
newstate = (k->keepon &~ (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE)) |
((action & CURLPAUSE_RECV) ? KEEP_RECV_PAUSE : 0) |
((action & CURLPAUSE_SEND) ? KEEP_SEND_PAUSE : 0);
recv_paused = Curl_xfer_recv_is_paused(data);
recv_paused_new = (action & CURLPAUSE_RECV);
send_paused = Curl_xfer_send_is_paused(data);
send_paused_new = (action & CURLPAUSE_SEND);
keep_changed = ((newstate & (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE)) != oldstate);
not_all_paused = (newstate & (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) !=
(KEEP_RECV_PAUSE|KEEP_SEND_PAUSE);
unpause_read = ((k->keepon & ~newstate & KEEP_SEND_PAUSE) &&
(data->mstate == MSTATE_PERFORMING ||
data->mstate == MSTATE_RATELIMITING));
/* Unpausing writes is detected on the next run in
* transfer.c:Curl_sendrecv(). This is because this may result
* in a transfer error if the application's callbacks fail */
if(send_paused != send_paused_new) {
changed = TRUE;
result = Curl_1st_err(result, Curl_xfer_pause_send(data, send_paused_new));
}
/* Set the new keepon state, so it takes effect no matter what error
* may happen afterwards. */
k->keepon = newstate;
if(recv_paused != recv_paused_new) {
changed = TRUE;
result = Curl_1st_err(result, Curl_xfer_pause_recv(data, recv_paused_new));
}
/* If not completely pausing both directions now, run again in any case. */
if(not_all_paused) {
if(!Curl_xfer_is_blocked(data)) {
Curl_expire(data, 0, EXPIRE_RUN_NOW);
/* reset the too-slow time keeper */
data->state.keeps_speed.tv_sec = 0;
/* Simulate socket events on next run for unpaused directions */
if(!(newstate & KEEP_SEND_PAUSE))
data->state.select_bits |= CURL_CSELECT_OUT;
if(!(newstate & KEEP_RECV_PAUSE))
data->state.select_bits |= CURL_CSELECT_IN;
/* On changes, tell application to update its timers. */
if(keep_changed && data->multi) {
if(Curl_update_timer(data->multi)) {
if(changed && data->multi) {
if(Curl_update_timer(data->multi) && !result)
result = CURLE_ABORTED_BY_CALLBACK;
goto out;
}
}
}
if(unpause_read) {
result = Curl_creader_unpause(data);
if(result)
goto out;
}
if(!(k->keepon & KEEP_RECV_PAUSE) && Curl_cwriter_is_paused(data)) {
Curl_conn_ev_data_pause(data, FALSE);
result = Curl_cwriter_unpause(data);
}
out:
if(!result && !data->state.done && keep_changed && data->multi)
if(!result && changed && !data->state.done && data->multi)
/* pause/unpausing may result in multi event changes */
if(Curl_multi_ev_assess_xfer(data->multi, data))
if(Curl_multi_ev_assess_xfer(data->multi, data) && !result)
result = CURLE_ABORTED_BY_CALLBACK;
if(recursive)
@@ -1241,7 +1210,6 @@ static CURLcode easy_connection(struct Curl_easy *data,
CURLcode curl_easy_recv(CURL *d, void *buffer, size_t buflen, size_t *n)
{
CURLcode result;
ssize_t n1;
struct connectdata *c;
struct Curl_easy *data = d;
@@ -1258,13 +1226,7 @@ CURLcode curl_easy_recv(CURL *d, void *buffer, size_t buflen, size_t *n)
Curl_attach_connection(data, c);
*n = 0;
result = Curl_conn_recv(data, FIRSTSOCKET, buffer, buflen, &n1);
if(result)
return result;
*n = (size_t)n1;
return CURLE_OK;
return Curl_conn_recv(data, FIRSTSOCKET, buffer, buflen, n);
}
#ifndef CURL_DISABLE_WEBSOCKETS
+3 -4
View File
@@ -1,9 +1,9 @@
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ | |
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* ___|___/|_| ______|
* \___|\___/|_| \_\_____|
*
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
*
@@ -23,7 +23,6 @@
***************************************************************************/
#include "curl_setup.h"
#include "strcase.h"
#include "easyoptions.h"
#ifndef CURL_DISABLE_GETOPTIONS
@@ -37,7 +36,7 @@ static const struct curl_easyoption *lookup(const char *name, CURLoption id)
const struct curl_easyoption *o = &Curl_easyopts[0];
do {
if(name) {
if(strcasecompare(o->name, name))
if(curl_strequal(o->name, name))
return o;
}
else {
+7 -9
View File
@@ -85,7 +85,7 @@ char *curl_easy_escape(CURL *data, const char *string,
else {
/* encode it */
unsigned char out[3]={'%'};
Curl_hexbyte(&out[1], in, FALSE);
Curl_hexbyte(&out[1], in);
if(curlx_dyn_addn(&d, out, 3))
return NULL;
}
@@ -212,7 +212,8 @@ void Curl_hexencode(const unsigned char *src, size_t len, /* input length */
DEBUGASSERT(src && len && (olen >= 3));
if(src && len && (olen >= 3)) {
while(len-- && (olen >= 3)) {
Curl_hexbyte(out, *src, TRUE);
out[0] = Curl_ldigits[*src >> 4];
out[1] = Curl_ldigits[*src & 0x0F];
++src;
out += 2;
olen -= 2;
@@ -225,14 +226,11 @@ void Curl_hexencode(const unsigned char *src, size_t len, /* input length */
/* Curl_hexbyte
*
* Output a single unsigned char as a two-digit hex number, lowercase or
* uppercase
* Output a single unsigned char as a two-digit UPPERCASE hex number.
*/
void Curl_hexbyte(unsigned char *dest, /* must fit two bytes */
unsigned char val,
bool lowercase)
unsigned char val)
{
const unsigned char *t = lowercase ? Curl_ldigits : Curl_udigits;
dest[0] = t[val >> 4];
dest[1] = t[val & 0x0F];
dest[0] = Curl_udigits[val >> 4];
dest[1] = Curl_udigits[val & 0x0F];
}
+1 -2
View File
@@ -42,7 +42,6 @@ void Curl_hexencode(const unsigned char *src, size_t len, /* input length */
unsigned char *out, size_t olen); /* output buffer size */
void Curl_hexbyte(unsigned char *dest, /* must fit two bytes */
unsigned char val,
bool lowercase);
unsigned char val);
#endif /* HEADER_CURL_ESCAPE_H */
-1
View File
@@ -34,7 +34,6 @@ struct Curl_easy;
#include "urldata.h" /* for struct Curl_easy */
#include "mime.h"
#include "vtls/vtls.h"
#include "strcase.h"
#include "sendf.h"
#include "strdup.h"
#include "rand.h"
+53 -15
View File
@@ -60,7 +60,7 @@
#include "cf-socket.h"
#include "connect.h"
#include "strerror.h"
#include "inet_ntop.h"
#include "curlx/inet_ntop.h"
#include "curlx/inet_pton.h"
#include "select.h"
#include "parsedate.h" /* for the week day and month names */
@@ -114,12 +114,14 @@ static const char * const ftp_state_names[]={
"QUOTE",
"RETR_PREQUOTE",
"STOR_PREQUOTE",
"LIST_PREQUOTE",
"POSTQUOTE",
"CWD",
"MKD",
"MDTM",
"TYPE",
"LIST_TYPE",
"RETR_LIST_TYPE",
"RETR_TYPE",
"STOR_TYPE",
"SIZE",
@@ -765,7 +767,12 @@ static CURLcode ftp_state_user(struct Curl_easy *data,
static CURLcode ftp_state_pwd(struct Curl_easy *data,
struct ftp_conn *ftpc)
{
CURLcode result = Curl_pp_sendf(data, &ftpc->pp, "%s", "PWD");
CURLcode result;
#ifdef DEBUGBUILD
if(!data->id && getenv("CURL_FTP_PWD_STOP"))
return CURLE_OK;
#endif
result = Curl_pp_sendf(data, &ftpc->pp, "%s", "PWD");
if(!result)
ftp_state(data, ftpc, FTP_PWD);
@@ -978,6 +985,12 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
port_min = port_max = 0;
if(addrlen) {
const struct Curl_sockaddr_ex *remote_addr =
Curl_conn_get_remote_addr(data, FIRSTSOCKET);
DEBUGASSERT(remote_addr);
if(!remote_addr)
goto out;
DEBUGASSERT(addr);
if(addrlen >= sizeof(ipstr))
goto out;
@@ -985,9 +998,9 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
ipstr[addrlen] = 0;
/* attempt to get the address of the given interface name */
switch(Curl_if2ip(conn->remote_addr->family,
switch(Curl_if2ip(remote_addr->family,
#ifdef USE_IPV6
Curl_ipv6_scope(&conn->remote_addr->curl_sa_addr),
Curl_ipv6_scope(&remote_addr->curl_sa_addr),
conn->scope_id,
#endif
ipstr, hbuf, sizeof(hbuf))) {
@@ -1020,11 +1033,11 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
switch(sa->sa_family) {
#ifdef USE_IPV6
case AF_INET6:
r = Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
r = curlx_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
break;
#endif
default:
r = Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf));
r = curlx_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf));
break;
}
if(!r) {
@@ -1052,7 +1065,8 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
/* step 2, create a socket for the requested address */
error = 0;
for(ai = res; ai; ai = ai->ai_next) {
if(Curl_socket_open(data, ai, NULL, conn->transport, &portsock)) {
if(Curl_socket_open(data, ai, NULL,
Curl_conn_get_transport(data, conn), &portsock)) {
error = SOCKERRNO;
continue;
}
@@ -1245,7 +1259,7 @@ out:
}
data->conn->bits.do_more = FALSE;
Curl_pgrsTime(data, TIMER_STARTACCEPT);
Curl_expire(data, data->set.accepttimeout ?
Curl_expire(data, (data->set.accepttimeout > 0) ?
data->set.accepttimeout: DEFAULT_ACCEPT_TIMEOUT,
EXPIRE_FTP_ACCEPT);
}
@@ -1448,6 +1462,14 @@ static CURLcode ftp_state_list(struct Curl_easy *data,
return result;
}
static CURLcode ftp_state_list_prequote(struct Curl_easy *data,
struct ftp_conn *ftpc,
struct FTP *ftp)
{
/* We have sent the TYPE, now we must send the list of prequote strings */
return ftp_state_quote(data, ftpc, ftp, TRUE, FTP_LIST_PREQUOTE);
}
static CURLcode ftp_state_retr_prequote(struct Curl_easy *data,
struct ftp_conn *ftpc,
struct FTP *ftp)
@@ -1636,6 +1658,7 @@ static CURLcode ftp_state_quote(struct Curl_easy *data,
break;
case FTP_RETR_PREQUOTE:
case FTP_STOR_PREQUOTE:
case FTP_LIST_PREQUOTE:
item = data->set.prequote;
break;
case FTP_POSTQUOTE:
@@ -1725,6 +1748,10 @@ static CURLcode ftp_state_quote(struct Curl_easy *data,
break;
case FTP_POSTQUOTE:
break;
case FTP_LIST_PREQUOTE:
ftp_state(data, ftpc, FTP_LIST_TYPE);
result = ftp_state_list(data, ftpc, ftp);
break;
}
}
@@ -2198,6 +2225,8 @@ static CURLcode ftp_state_type_resp(struct Curl_easy *data,
result = ftp_state_retr_prequote(data, ftpc, ftp);
else if(instate == FTP_STOR_TYPE)
result = ftp_state_stor_prequote(data, ftpc, ftp);
else if(instate == FTP_RETR_LIST_TYPE)
result = ftp_state_list_prequote(data, ftpc, ftp);
return result;
}
@@ -2961,7 +2990,7 @@ static CURLcode ftp_pp_statemachine(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
/* Check for special servers here. */
if(strcasecompare(os, "OS/400")) {
if(curl_strequal(os, "OS/400")) {
/* Force OS400 name format 1. */
result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SITE NAMEFMT 1");
if(result) {
@@ -3002,6 +3031,7 @@ static CURLcode ftp_pp_statemachine(struct Curl_easy *data,
case FTP_POSTQUOTE:
case FTP_RETR_PREQUOTE:
case FTP_STOR_PREQUOTE:
case FTP_LIST_PREQUOTE:
if((ftpcode >= 400) && !ftpc->count2) {
/* failure response code, and not allowed to fail */
failf(data, "QUOT command failed with %03d", ftpcode);
@@ -3071,6 +3101,7 @@ static CURLcode ftp_pp_statemachine(struct Curl_easy *data,
case FTP_LIST_TYPE:
case FTP_RETR_TYPE:
case FTP_STOR_TYPE:
case FTP_RETR_LIST_TYPE:
result = ftp_state_type_resp(data, ftpc, ftp, ftpcode, ftpc->state);
break;
@@ -3125,8 +3156,8 @@ static CURLcode ftp_pp_statemachine(struct Curl_easy *data,
/* called repeatedly until done from multi.c */
static CURLcode ftp_statemach(struct Curl_easy *data,
struct ftp_conn *ftpc,
bool *done)
struct ftp_conn *ftpc,
bool *done)
{
CURLcode result = Curl_pp_statemach(data, &ftpc->pp, FALSE, FALSE);
@@ -3675,7 +3706,8 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
if(result)
;
else if(data->state.list_only || !ftpc->file) {
else if((data->state.list_only || !ftpc->file) &&
!(data->set.prequote)) {
/* The specified path ends with a slash, and therefore we think this
is a directory that is requested, use LIST. But before that we
need to set ASCII transfer mode. */
@@ -3689,8 +3721,14 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
/* otherwise just fall through */
}
else {
result = ftp_nb_type(data, ftpc, ftp, data->state.prefer_ascii,
FTP_RETR_TYPE);
if(data->set.prequote && !ftpc->file) {
result = ftp_nb_type(data, ftpc, ftp, TRUE,
FTP_RETR_LIST_TYPE);
}
else {
result = ftp_nb_type(data, ftpc, ftp, data->state.prefer_ascii,
FTP_RETR_TYPE);
}
if(result)
return result;
}
@@ -4118,7 +4156,7 @@ static CURLcode ftp_disconnect(struct Curl_easy *data,
will try to send the QUIT command, otherwise it will just return.
*/
ftpc->shutdown = TRUE;
if(dead_connection)
if(dead_connection || Curl_pp_needs_flush(data, &ftpc->pp))
ftpc->ctl_valid = FALSE;
/* The FTP session may or may not have been allocated/setup at this point! */
+2
View File
@@ -62,12 +62,14 @@ enum {
FTP_QUOTE, /* waiting for a response to a command sent in a quote list */
FTP_RETR_PREQUOTE,
FTP_STOR_PREQUOTE,
FTP_LIST_PREQUOTE,
FTP_POSTQUOTE,
FTP_CWD, /* change dir */
FTP_MKD, /* if the dir did not exist */
FTP_MDTM, /* to figure out the datestamp */
FTP_TYPE, /* to set type when doing a head-like request */
FTP_LIST_TYPE, /* set type when about to do a dir list */
FTP_RETR_LIST_TYPE,
FTP_RETR_TYPE, /* set type when about to RETR a file */
FTP_STOR_TYPE, /* set type when about to STOR a file */
FTP_SIZE, /* get the remote file's size for head-like request */
+460 -367
View File
@@ -396,407 +396,500 @@ static CURLcode unix_filetype(const char c, curlfiletype *t)
return CURLE_OK;
}
static CURLcode parse_unix_totalsize(struct ftp_parselist_data *parser,
struct fileinfo *infop,
const char c)
{
size_t len = curlx_dyn_len(&infop->buf);
char *mem = curlx_dyn_ptr(&infop->buf);
switch(parser->state.UNIX.sub.total_dirsize) {
case PL_UNIX_TOTALSIZE_INIT:
if(c == 't') {
parser->state.UNIX.sub.total_dirsize = PL_UNIX_TOTALSIZE_READING;
parser->item_length++;
}
else {
parser->state.UNIX.main = PL_UNIX_FILETYPE;
/* continue to fall through */
}
break;
case PL_UNIX_TOTALSIZE_READING:
parser->item_length++;
if(c == '\r') {
parser->item_length--;
if(len)
curlx_dyn_setlen(&infop->buf, --len);
}
else if(c == '\n') {
mem[parser->item_length - 1] = 0;
if(!strncmp("total ", mem, 6)) {
const char *endptr = mem + 6;
/* here we can deal with directory size, pass the leading
whitespace and then the digits */
curlx_str_passblanks(&endptr);
while(ISDIGIT(*endptr))
endptr++;
if(*endptr) {
return CURLE_FTP_BAD_FILE_LIST;
}
parser->state.UNIX.main = PL_UNIX_FILETYPE;
curlx_dyn_reset(&infop->buf);
}
else
return CURLE_FTP_BAD_FILE_LIST;
}
break;
}
return CURLE_OK;
}
static CURLcode parse_unix_permission(struct ftp_parselist_data *parser,
struct fileinfo *infop,
const char c)
{
char *mem = curlx_dyn_ptr(&infop->buf);
parser->item_length++;
if((parser->item_length <= 9) && !strchr("rwx-tTsS", c))
return CURLE_FTP_BAD_FILE_LIST;
else if(parser->item_length == 10) {
unsigned int perm;
if(c != ' ')
return CURLE_FTP_BAD_FILE_LIST;
mem[10] = 0; /* terminate permissions */
perm = ftp_pl_get_permission(mem + parser->item_offset);
if(perm & FTP_LP_MALFORMATED_PERM)
return CURLE_FTP_BAD_FILE_LIST;
parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_PERM;
parser->file_data->info.perm = perm;
parser->offsets.perm = parser->item_offset;
parser->item_length = 0;
parser->state.UNIX.main = PL_UNIX_HLINKS;
parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_PRESPACE;
}
return CURLE_OK;
}
static CURLcode parse_unix_hlinks(struct ftp_parselist_data *parser,
struct fileinfo *infop,
const char c)
{
size_t len = curlx_dyn_len(&infop->buf);
char *mem = curlx_dyn_ptr(&infop->buf);
switch(parser->state.UNIX.sub.hlinks) {
case PL_UNIX_HLINKS_PRESPACE:
if(c != ' ') {
if(ISDIGIT(c) && len) {
parser->item_offset = len - 1;
parser->item_length = 1;
parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_NUMBER;
}
else
return CURLE_FTP_BAD_FILE_LIST;
}
break;
case PL_UNIX_HLINKS_NUMBER:
parser->item_length ++;
if(c == ' ') {
const char *p = &mem[parser->item_offset];
curl_off_t hlinks;
mem[parser->item_offset + parser->item_length - 1] = 0;
if(!curlx_str_number(&p, &hlinks, LONG_MAX)) {
parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_HLINKCOUNT;
parser->file_data->info.hardlinks = (long)hlinks;
}
parser->item_length = 0;
parser->item_offset = 0;
parser->state.UNIX.main = PL_UNIX_USER;
parser->state.UNIX.sub.user = PL_UNIX_USER_PRESPACE;
}
else if(!ISDIGIT(c))
return CURLE_FTP_BAD_FILE_LIST;
break;
}
return CURLE_OK;
}
static CURLcode parse_unix_user(struct ftp_parselist_data *parser,
struct fileinfo *infop,
const char c)
{
size_t len = curlx_dyn_len(&infop->buf);
char *mem = curlx_dyn_ptr(&infop->buf);
switch(parser->state.UNIX.sub.user) {
case PL_UNIX_USER_PRESPACE:
if(c != ' ' && len) {
parser->item_offset = len - 1;
parser->item_length = 1;
parser->state.UNIX.sub.user = PL_UNIX_USER_PARSING;
}
break;
case PL_UNIX_USER_PARSING:
parser->item_length++;
if(c == ' ') {
mem[parser->item_offset + parser->item_length - 1] = 0;
parser->offsets.user = parser->item_offset;
parser->state.UNIX.main = PL_UNIX_GROUP;
parser->state.UNIX.sub.group = PL_UNIX_GROUP_PRESPACE;
parser->item_offset = 0;
parser->item_length = 0;
}
break;
}
return CURLE_OK;
}
static CURLcode parse_unix_group(struct ftp_parselist_data *parser,
struct fileinfo *infop,
const char c)
{
size_t len = curlx_dyn_len(&infop->buf);
char *mem = curlx_dyn_ptr(&infop->buf);
switch(parser->state.UNIX.sub.group) {
case PL_UNIX_GROUP_PRESPACE:
if(c != ' ' && len) {
parser->item_offset = len - 1;
parser->item_length = 1;
parser->state.UNIX.sub.group = PL_UNIX_GROUP_NAME;
}
break;
case PL_UNIX_GROUP_NAME:
parser->item_length++;
if(c == ' ') {
mem[parser->item_offset + parser->item_length - 1] = 0;
parser->offsets.group = parser->item_offset;
parser->state.UNIX.main = PL_UNIX_SIZE;
parser->state.UNIX.sub.size = PL_UNIX_SIZE_PRESPACE;
parser->item_offset = 0;
parser->item_length = 0;
}
break;
}
return CURLE_OK;
}
static CURLcode parse_unix_size(struct ftp_parselist_data *parser,
struct fileinfo *infop,
const char c)
{
size_t len = curlx_dyn_len(&infop->buf);
char *mem = curlx_dyn_ptr(&infop->buf);
switch(parser->state.UNIX.sub.size) {
case PL_UNIX_SIZE_PRESPACE:
if(c != ' ') {
if(ISDIGIT(c) && len) {
parser->item_offset = len - 1;
parser->item_length = 1;
parser->state.UNIX.sub.size = PL_UNIX_SIZE_NUMBER;
}
else
return CURLE_FTP_BAD_FILE_LIST;
}
break;
case PL_UNIX_SIZE_NUMBER:
parser->item_length++;
if(c == ' ') {
const char *p = mem + parser->item_offset;
curl_off_t fsize;
mem[parser->item_offset + parser->item_length - 1] = 0;
if(!curlx_str_numblanks(&p, &fsize)) {
if(p[0] == '\0' && fsize != CURL_OFF_T_MAX) {
parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE;
parser->file_data->info.size = fsize;
}
parser->item_length = 0;
parser->item_offset = 0;
parser->state.UNIX.main = PL_UNIX_TIME;
parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART1;
}
}
else if(!ISDIGIT(c))
return CURLE_FTP_BAD_FILE_LIST;
break;
}
return CURLE_OK;
}
static CURLcode parse_unix_time(struct ftp_parselist_data *parser,
struct fileinfo *infop,
const char c)
{
size_t len = curlx_dyn_len(&infop->buf);
char *mem = curlx_dyn_ptr(&infop->buf);
struct curl_fileinfo *finfo = &infop->info;
switch(parser->state.UNIX.sub.time) {
case PL_UNIX_TIME_PREPART1:
if(c != ' ') {
if(ISALNUM(c) && len) {
parser->item_offset = len -1;
parser->item_length = 1;
parser->state.UNIX.sub.time = PL_UNIX_TIME_PART1;
}
else
return CURLE_FTP_BAD_FILE_LIST;
}
break;
case PL_UNIX_TIME_PART1:
parser->item_length++;
if(c == ' ')
parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART2;
else if(!ISALNUM(c) && c != '.')
return CURLE_FTP_BAD_FILE_LIST;
break;
case PL_UNIX_TIME_PREPART2:
parser->item_length++;
if(c != ' ') {
if(ISALNUM(c))
parser->state.UNIX.sub.time = PL_UNIX_TIME_PART2;
else
return CURLE_FTP_BAD_FILE_LIST;
}
break;
case PL_UNIX_TIME_PART2:
parser->item_length++;
if(c == ' ')
parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART3;
else if(!ISALNUM(c) && c != '.')
return CURLE_FTP_BAD_FILE_LIST;
break;
case PL_UNIX_TIME_PREPART3:
parser->item_length++;
if(c != ' ') {
if(ISALNUM(c))
parser->state.UNIX.sub.time = PL_UNIX_TIME_PART3;
else
return CURLE_FTP_BAD_FILE_LIST;
}
break;
case PL_UNIX_TIME_PART3:
parser->item_length++;
if(c == ' ') {
mem[parser->item_offset + parser->item_length -1] = 0;
parser->offsets.time = parser->item_offset;
if(finfo->filetype == CURLFILETYPE_SYMLINK) {
parser->state.UNIX.main = PL_UNIX_SYMLINK;
parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRESPACE;
}
else {
parser->state.UNIX.main = PL_UNIX_FILENAME;
parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_PRESPACE;
}
}
else if(!ISALNUM(c) && c != '.' && c != ':')
return CURLE_FTP_BAD_FILE_LIST;
break;
}
return CURLE_OK;
}
static CURLcode parse_unix_filename(struct Curl_easy *data,
struct ftp_parselist_data *parser,
struct fileinfo *infop,
const char c)
{
size_t len = curlx_dyn_len(&infop->buf);
char *mem = curlx_dyn_ptr(&infop->buf);
CURLcode result = CURLE_OK;
switch(parser->state.UNIX.sub.filename) {
case PL_UNIX_FILENAME_PRESPACE:
if(c != ' ' && len) {
parser->item_offset = len - 1;
parser->item_length = 1;
parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_NAME;
}
break;
case PL_UNIX_FILENAME_NAME:
parser->item_length++;
if(c == '\r')
parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_WINDOWSEOL;
else if(c == '\n') {
mem[parser->item_offset + parser->item_length - 1] = 0;
parser->offsets.filename = parser->item_offset;
parser->state.UNIX.main = PL_UNIX_FILETYPE;
result = ftp_pl_insert_finfo(data, infop);
}
break;
case PL_UNIX_FILENAME_WINDOWSEOL:
if(c == '\n') {
mem[parser->item_offset + parser->item_length - 1] = 0;
parser->offsets.filename = parser->item_offset;
parser->state.UNIX.main = PL_UNIX_FILETYPE;
result = ftp_pl_insert_finfo(data, infop);
}
else
result = CURLE_FTP_BAD_FILE_LIST;
break;
}
return result;
}
static CURLcode parse_unix_symlink(struct Curl_easy *data,
struct ftp_parselist_data *parser,
struct fileinfo *infop,
const char c)
{
size_t len = curlx_dyn_len(&infop->buf);
char *mem = curlx_dyn_ptr(&infop->buf);
CURLcode result = CURLE_OK;
switch(parser->state.UNIX.sub.symlink) {
case PL_UNIX_SYMLINK_PRESPACE:
if(c != ' ' && len) {
parser->item_offset = len - 1;
parser->item_length = 1;
parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
}
break;
case PL_UNIX_SYMLINK_NAME:
parser->item_length++;
if(c == ' ')
parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET1;
else if(c == '\r' || c == '\n')
return CURLE_FTP_BAD_FILE_LIST;
break;
case PL_UNIX_SYMLINK_PRETARGET1:
parser->item_length++;
if(c == '-')
parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET2;
else if(c == '\r' || c == '\n')
return CURLE_FTP_BAD_FILE_LIST;
else
parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
break;
case PL_UNIX_SYMLINK_PRETARGET2:
parser->item_length++;
if(c == '>')
parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET3;
else if(c == '\r' || c == '\n')
return CURLE_FTP_BAD_FILE_LIST;
else
parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
break;
case PL_UNIX_SYMLINK_PRETARGET3:
parser->item_length++;
if(c == ' ') {
parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET4;
/* now place where is symlink following */
mem[parser->item_offset + parser->item_length - 4] = 0;
parser->offsets.filename = parser->item_offset;
parser->item_length = 0;
parser->item_offset = 0;
}
else if(c == '\r' || c == '\n')
return CURLE_FTP_BAD_FILE_LIST;
else
parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
break;
case PL_UNIX_SYMLINK_PRETARGET4:
if(c != '\r' && c != '\n' && len) {
parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_TARGET;
parser->item_offset = len - 1;
parser->item_length = 1;
}
else
return CURLE_FTP_BAD_FILE_LIST;
break;
case PL_UNIX_SYMLINK_TARGET:
parser->item_length++;
if(c == '\r')
parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_WINDOWSEOL;
else if(c == '\n') {
mem[parser->item_offset + parser->item_length - 1] = 0;
parser->offsets.symlink_target = parser->item_offset;
result = ftp_pl_insert_finfo(data, infop);
if(result)
break;
parser->state.UNIX.main = PL_UNIX_FILETYPE;
}
break;
case PL_UNIX_SYMLINK_WINDOWSEOL:
if(c == '\n') {
mem[parser->item_offset + parser->item_length - 1] = 0;
parser->offsets.symlink_target = parser->item_offset;
result = ftp_pl_insert_finfo(data, infop);
if(result)
break;
parser->state.UNIX.main = PL_UNIX_FILETYPE;
}
else
result = CURLE_FTP_BAD_FILE_LIST;
break;
}
return result;
}
static CURLcode parse_unix(struct Curl_easy *data,
struct ftp_parselist_data *parser,
struct fileinfo *infop,
const char c)
{
struct curl_fileinfo *finfo = &infop->info;
size_t len = curlx_dyn_len(&infop->buf);
char *mem = curlx_dyn_ptr(&infop->buf);
CURLcode result = CURLE_OK;
switch(parser->state.UNIX.main) {
case PL_UNIX_TOTALSIZE:
switch(parser->state.UNIX.sub.total_dirsize) {
case PL_UNIX_TOTALSIZE_INIT:
if(c == 't') {
parser->state.UNIX.sub.total_dirsize = PL_UNIX_TOTALSIZE_READING;
parser->item_length++;
}
else {
parser->state.UNIX.main = PL_UNIX_FILETYPE;
/* continue to fall through */
}
result = parse_unix_totalsize(parser, infop, c);
if(result)
break;
case PL_UNIX_TOTALSIZE_READING:
parser->item_length++;
if(c == '\r') {
parser->item_length--;
if(len)
curlx_dyn_setlen(&infop->buf, --len);
}
else if(c == '\n') {
mem[parser->item_length - 1] = 0;
if(!strncmp("total ", mem, 6)) {
const char *endptr = mem + 6;
/* here we can deal with directory size, pass the leading
whitespace and then the digits */
curlx_str_passblanks(&endptr);
while(ISDIGIT(*endptr))
endptr++;
if(*endptr) {
return CURLE_FTP_BAD_FILE_LIST;
}
parser->state.UNIX.main = PL_UNIX_FILETYPE;
curlx_dyn_reset(&infop->buf);
}
else
return CURLE_FTP_BAD_FILE_LIST;
}
break;
}
if(parser->state.UNIX.main != PL_UNIX_FILETYPE)
break;
FALLTHROUGH();
case PL_UNIX_FILETYPE:
result = unix_filetype(c, &finfo->filetype);
if(result)
return result;
parser->state.UNIX.main = PL_UNIX_PERMISSION;
parser->item_length = 0;
parser->item_offset = 1;
if(!result) {
parser->state.UNIX.main = PL_UNIX_PERMISSION;
parser->item_length = 0;
parser->item_offset = 1;
}
break;
case PL_UNIX_PERMISSION:
parser->item_length++;
if((parser->item_length <= 9) && !strchr("rwx-tTsS", c))
return CURLE_FTP_BAD_FILE_LIST;
else if(parser->item_length == 10) {
unsigned int perm;
if(c != ' ')
return CURLE_FTP_BAD_FILE_LIST;
mem[10] = 0; /* terminate permissions */
perm = ftp_pl_get_permission(mem + parser->item_offset);
if(perm & FTP_LP_MALFORMATED_PERM)
return CURLE_FTP_BAD_FILE_LIST;
parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_PERM;
parser->file_data->info.perm = perm;
parser->offsets.perm = parser->item_offset;
parser->item_length = 0;
parser->state.UNIX.main = PL_UNIX_HLINKS;
parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_PRESPACE;
}
result = parse_unix_permission(parser, infop, c);
break;
case PL_UNIX_HLINKS:
switch(parser->state.UNIX.sub.hlinks) {
case PL_UNIX_HLINKS_PRESPACE:
if(c != ' ') {
if(ISDIGIT(c) && len) {
parser->item_offset = len - 1;
parser->item_length = 1;
parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_NUMBER;
}
else
return CURLE_FTP_BAD_FILE_LIST;
}
break;
case PL_UNIX_HLINKS_NUMBER:
parser->item_length ++;
if(c == ' ') {
const char *p = &mem[parser->item_offset];
curl_off_t hlinks;
mem[parser->item_offset + parser->item_length - 1] = 0;
if(!curlx_str_number(&p, &hlinks, LONG_MAX)) {
parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_HLINKCOUNT;
parser->file_data->info.hardlinks = (long)hlinks;
}
parser->item_length = 0;
parser->item_offset = 0;
parser->state.UNIX.main = PL_UNIX_USER;
parser->state.UNIX.sub.user = PL_UNIX_USER_PRESPACE;
}
else if(!ISDIGIT(c))
return CURLE_FTP_BAD_FILE_LIST;
break;
}
result = parse_unix_hlinks(parser, infop, c);
break;
case PL_UNIX_USER:
switch(parser->state.UNIX.sub.user) {
case PL_UNIX_USER_PRESPACE:
if(c != ' ' && len) {
parser->item_offset = len - 1;
parser->item_length = 1;
parser->state.UNIX.sub.user = PL_UNIX_USER_PARSING;
}
break;
case PL_UNIX_USER_PARSING:
parser->item_length++;
if(c == ' ') {
mem[parser->item_offset + parser->item_length - 1] = 0;
parser->offsets.user = parser->item_offset;
parser->state.UNIX.main = PL_UNIX_GROUP;
parser->state.UNIX.sub.group = PL_UNIX_GROUP_PRESPACE;
parser->item_offset = 0;
parser->item_length = 0;
}
break;
}
result = parse_unix_user(parser, infop, c);
break;
case PL_UNIX_GROUP:
switch(parser->state.UNIX.sub.group) {
case PL_UNIX_GROUP_PRESPACE:
if(c != ' ' && len) {
parser->item_offset = len - 1;
parser->item_length = 1;
parser->state.UNIX.sub.group = PL_UNIX_GROUP_NAME;
}
break;
case PL_UNIX_GROUP_NAME:
parser->item_length++;
if(c == ' ') {
mem[parser->item_offset + parser->item_length - 1] = 0;
parser->offsets.group = parser->item_offset;
parser->state.UNIX.main = PL_UNIX_SIZE;
parser->state.UNIX.sub.size = PL_UNIX_SIZE_PRESPACE;
parser->item_offset = 0;
parser->item_length = 0;
}
break;
}
result = parse_unix_group(parser, infop, c);
break;
case PL_UNIX_SIZE:
switch(parser->state.UNIX.sub.size) {
case PL_UNIX_SIZE_PRESPACE:
if(c != ' ') {
if(ISDIGIT(c) && len) {
parser->item_offset = len - 1;
parser->item_length = 1;
parser->state.UNIX.sub.size = PL_UNIX_SIZE_NUMBER;
}
else
return CURLE_FTP_BAD_FILE_LIST;
}
break;
case PL_UNIX_SIZE_NUMBER:
parser->item_length++;
if(c == ' ') {
const char *p = mem + parser->item_offset;
curl_off_t fsize;
mem[parser->item_offset + parser->item_length - 1] = 0;
if(!curlx_str_numblanks(&p, &fsize)) {
if(p[0] == '\0' && fsize != CURL_OFF_T_MAX) {
parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE;
parser->file_data->info.size = fsize;
}
parser->item_length = 0;
parser->item_offset = 0;
parser->state.UNIX.main = PL_UNIX_TIME;
parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART1;
}
}
else if(!ISDIGIT(c))
return CURLE_FTP_BAD_FILE_LIST;
break;
}
result = parse_unix_size(parser, infop, c);
break;
case PL_UNIX_TIME:
switch(parser->state.UNIX.sub.time) {
case PL_UNIX_TIME_PREPART1:
if(c != ' ') {
if(ISALNUM(c) && len) {
parser->item_offset = len -1;
parser->item_length = 1;
parser->state.UNIX.sub.time = PL_UNIX_TIME_PART1;
}
else
return CURLE_FTP_BAD_FILE_LIST;
}
break;
case PL_UNIX_TIME_PART1:
parser->item_length++;
if(c == ' ')
parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART2;
else if(!ISALNUM(c) && c != '.')
return CURLE_FTP_BAD_FILE_LIST;
break;
case PL_UNIX_TIME_PREPART2:
parser->item_length++;
if(c != ' ') {
if(ISALNUM(c))
parser->state.UNIX.sub.time = PL_UNIX_TIME_PART2;
else
return CURLE_FTP_BAD_FILE_LIST;
}
break;
case PL_UNIX_TIME_PART2:
parser->item_length++;
if(c == ' ')
parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART3;
else if(!ISALNUM(c) && c != '.')
return CURLE_FTP_BAD_FILE_LIST;
break;
case PL_UNIX_TIME_PREPART3:
parser->item_length++;
if(c != ' ') {
if(ISALNUM(c))
parser->state.UNIX.sub.time = PL_UNIX_TIME_PART3;
else
return CURLE_FTP_BAD_FILE_LIST;
}
break;
case PL_UNIX_TIME_PART3:
parser->item_length++;
if(c == ' ') {
mem[parser->item_offset + parser->item_length -1] = 0;
parser->offsets.time = parser->item_offset;
if(finfo->filetype == CURLFILETYPE_SYMLINK) {
parser->state.UNIX.main = PL_UNIX_SYMLINK;
parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRESPACE;
}
else {
parser->state.UNIX.main = PL_UNIX_FILENAME;
parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_PRESPACE;
}
}
else if(!ISALNUM(c) && c != '.' && c != ':')
return CURLE_FTP_BAD_FILE_LIST;
break;
}
result = parse_unix_time(parser, infop, c);
break;
case PL_UNIX_FILENAME:
switch(parser->state.UNIX.sub.filename) {
case PL_UNIX_FILENAME_PRESPACE:
if(c != ' ' && len) {
parser->item_offset = len - 1;
parser->item_length = 1;
parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_NAME;
}
break;
case PL_UNIX_FILENAME_NAME:
parser->item_length++;
if(c == '\r')
parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_WINDOWSEOL;
else if(c == '\n') {
mem[parser->item_offset + parser->item_length - 1] = 0;
parser->offsets.filename = parser->item_offset;
parser->state.UNIX.main = PL_UNIX_FILETYPE;
result = ftp_pl_insert_finfo(data, infop);
if(result)
return result;
}
break;
case PL_UNIX_FILENAME_WINDOWSEOL:
if(c == '\n') {
mem[parser->item_offset + parser->item_length - 1] = 0;
parser->offsets.filename = parser->item_offset;
parser->state.UNIX.main = PL_UNIX_FILETYPE;
result = ftp_pl_insert_finfo(data, infop);
if(result)
return result;
}
else
return CURLE_FTP_BAD_FILE_LIST;
break;
}
result = parse_unix_filename(data, parser, infop, c);
break;
case PL_UNIX_SYMLINK:
switch(parser->state.UNIX.sub.symlink) {
case PL_UNIX_SYMLINK_PRESPACE:
if(c != ' ' && len) {
parser->item_offset = len - 1;
parser->item_length = 1;
parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
}
break;
case PL_UNIX_SYMLINK_NAME:
parser->item_length++;
if(c == ' ')
parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET1;
else if(c == '\r' || c == '\n')
return CURLE_FTP_BAD_FILE_LIST;
break;
case PL_UNIX_SYMLINK_PRETARGET1:
parser->item_length++;
if(c == '-')
parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET2;
else if(c == '\r' || c == '\n')
return CURLE_FTP_BAD_FILE_LIST;
else
parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
break;
case PL_UNIX_SYMLINK_PRETARGET2:
parser->item_length++;
if(c == '>')
parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET3;
else if(c == '\r' || c == '\n')
return CURLE_FTP_BAD_FILE_LIST;
else
parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
break;
case PL_UNIX_SYMLINK_PRETARGET3:
parser->item_length++;
if(c == ' ') {
parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET4;
/* now place where is symlink following */
mem[parser->item_offset + parser->item_length - 4] = 0;
parser->offsets.filename = parser->item_offset;
parser->item_length = 0;
parser->item_offset = 0;
}
else if(c == '\r' || c == '\n')
return CURLE_FTP_BAD_FILE_LIST;
else
parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
break;
case PL_UNIX_SYMLINK_PRETARGET4:
if(c != '\r' && c != '\n' && len) {
parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_TARGET;
parser->item_offset = len - 1;
parser->item_length = 1;
}
else
return CURLE_FTP_BAD_FILE_LIST;
break;
case PL_UNIX_SYMLINK_TARGET:
parser->item_length++;
if(c == '\r')
parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_WINDOWSEOL;
else if(c == '\n') {
mem[parser->item_offset + parser->item_length - 1] = 0;
parser->offsets.symlink_target = parser->item_offset;
result = ftp_pl_insert_finfo(data, infop);
if(result)
return result;
parser->state.UNIX.main = PL_UNIX_FILETYPE;
}
break;
case PL_UNIX_SYMLINK_WINDOWSEOL:
if(c == '\n') {
mem[parser->item_offset + parser->item_length - 1] = 0;
parser->offsets.symlink_target = parser->item_offset;
result = ftp_pl_insert_finfo(data, infop);
if(result)
return result;
parser->state.UNIX.main = PL_UNIX_FILETYPE;
}
else
return CURLE_FTP_BAD_FILE_LIST;
break;
}
result = parse_unix_symlink(data, parser, infop, c);
break;
}
return CURLE_OK;
return result;
}
static CURLcode parse_winnt(struct Curl_easy *data,
+6 -10
View File
@@ -28,6 +28,7 @@
#include "urldata.h"
#include "getinfo.h"
#include "cfilters.h"
#include "vtls/vtls.h"
#include "connect.h" /* Curl_getconnectinfo() */
#include "progress.h"
@@ -579,19 +580,14 @@ static CURLcode getinfo_slist(struct Curl_easy *data, CURLINFO info,
struct curl_tlssessioninfo **tsip = (struct curl_tlssessioninfo **)
param_slistp;
struct curl_tlssessioninfo *tsi = &data->tsi;
#ifdef USE_SSL
struct connectdata *conn = data->conn;
#endif
/* we are exposing a pointer to internal memory with unknown
* lifetime here. */
*tsip = tsi;
tsi->backend = Curl_ssl_backend();
tsi->internals = NULL;
#ifdef USE_SSL
if(conn && tsi->backend != CURLSSLBACKEND_NONE) {
tsi->internals = Curl_ssl_get_internals(data, FIRSTSOCKET, info, 0);
if(!Curl_conn_get_ssl_info(data, data->conn, FIRSTSOCKET, tsi)) {
tsi->backend = Curl_ssl_backend();
tsi->internals = NULL;
}
#endif
}
break;
default:
+1 -1
View File
@@ -353,7 +353,7 @@ size_t Curl_hash_str(void *key, size_t key_length, size_t slots_num)
}
size_t curlx_str_key_compare(void *k1, size_t key1_len,
void *k2, size_t key2_len)
void *k2, size_t key2_len)
{
if((key1_len == key2_len) && !memcmp(k1, k2, key1_len))
return 1;
+1 -1
View File
@@ -99,7 +99,7 @@ void Curl_hash_clean_with_criterium(struct Curl_hash *h, void *user,
int (*comp)(void *, void *));
size_t Curl_hash_str(void *key, size_t key_length, size_t slots_num);
size_t curlx_str_key_compare(void *k1, size_t key1_len, void *k2,
size_t key2_len);
size_t key2_len);
void Curl_hash_start_iterate(struct Curl_hash *hash,
struct Curl_hash_iterator *iter);
struct Curl_hash_element *
+3 -4
View File
@@ -26,7 +26,6 @@
#include "urldata.h"
#include "strdup.h"
#include "strcase.h"
#include "sendf.h"
#include "headers.h"
#include "curlx/strparse.h"
@@ -88,7 +87,7 @@ CURLHcode curl_easy_header(CURL *easy,
/* we need a first round to count amount of this header */
for(e = Curl_llist_head(&data->state.httphdrs); e; e = Curl_node_next(e)) {
hs = Curl_node_elem(e);
if(strcasecompare(hs->name, name) &&
if(curl_strequal(hs->name, name) &&
(hs->type & type) &&
(hs->request == request)) {
amount++;
@@ -107,7 +106,7 @@ CURLHcode curl_easy_header(CURL *easy,
else {
for(e = Curl_llist_head(&data->state.httphdrs); e; e = Curl_node_next(e)) {
hs = Curl_node_elem(e);
if(strcasecompare(hs->name, name) &&
if(curl_strequal(hs->name, name) &&
(hs->type & type) &&
(hs->request == request) &&
(match++ == nameindex)) {
@@ -173,7 +172,7 @@ struct curl_header *curl_easy_nextheader(CURL *easy,
the index for the currently selected entry */
for(e = Curl_llist_head(&data->state.httphdrs); e; e = Curl_node_next(e)) {
struct Curl_header_store *check = Curl_node_elem(e);
if(strcasecompare(hs->name, check->name) &&
if(curl_strequal(hs->name, check->name) &&
(check->request == request) &&
(check->type & type))
amount++;
+8 -6
View File
@@ -54,7 +54,7 @@
#include "rand.h"
#include "share.h"
#include "url.h"
#include "inet_ntop.h"
#include "curlx/inet_ntop.h"
#include "curlx/inet_pton.h"
#include "multiif.h"
#include "doh.h"
@@ -145,14 +145,14 @@ void Curl_printable_address(const struct Curl_addrinfo *ai, char *buf,
case AF_INET: {
const struct sockaddr_in *sa4 = (const void *)ai->ai_addr;
const struct in_addr *ipaddr4 = &sa4->sin_addr;
(void)Curl_inet_ntop(ai->ai_family, (const void *)ipaddr4, buf, bufsize);
(void)curlx_inet_ntop(ai->ai_family, (const void *)ipaddr4, buf, bufsize);
break;
}
#ifdef USE_IPV6
case AF_INET6: {
const struct sockaddr_in6 *sa6 = (const void *)ai->ai_addr;
const struct in6_addr *ipaddr6 = &sa6->sin6_addr;
(void)Curl_inet_ntop(ai->ai_family, (const void *)ipaddr6, buf, bufsize);
(void)curlx_inet_ntop(ai->ai_family, (const void *)ipaddr6, buf, bufsize);
break;
}
#endif
@@ -505,6 +505,8 @@ Curl_dnscache_mk_entry(struct Curl_easy *data,
return NULL;
}
}
#else
(void)data;
#endif
if(!hostlen)
hostlen = strlen(hostname);
@@ -730,7 +732,7 @@ static bool tailmatch(const char *full, size_t flen,
{
if(plen > flen)
return FALSE;
return strncasecompare(part, &full[flen - plen], plen);
return curl_strnequal(part, &full[flen - plen], plen);
}
static struct Curl_addrinfo *
@@ -872,8 +874,8 @@ CURLcode Curl_resolv(struct Curl_easy *data,
goto error;
if(!is_ipaddr &&
(strcasecompare(hostname, "localhost") ||
strcasecompare(hostname, "localhost.") ||
(curl_strequal(hostname, "localhost") ||
curl_strequal(hostname, "localhost.") ||
tailmatch(hostname, hostname_len, STRCONST(".localhost")) ||
tailmatch(hostname, hostname_len, STRCONST(".localhost.")))) {
addr = get_localhost(port, hostname);
+3 -1
View File
@@ -44,6 +44,7 @@
#endif
#include "urldata.h"
#include "cfilters.h"
#include "sendf.h"
#include "hostip.h"
#include "hash.h"
@@ -104,7 +105,8 @@ struct Curl_addrinfo *Curl_sync_getaddrinfo(struct Curl_easy *data,
memset(&hints, 0, sizeof(hints));
hints.ai_family = pf;
hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP) ?
hints.ai_socktype =
(Curl_conn_get_transport(data, data->conn) == TRNSPRT_TCP) ?
SOCK_STREAM : SOCK_DGRAM;
#ifndef USE_RESOLVE_ON_IPS
+9 -6
View File
@@ -33,7 +33,6 @@
#include "llist.h"
#include "hsts.h"
#include "curl_get_line.h"
#include "strcase.h"
#include "sendf.h"
#include "parsedate.h"
#include "fopen.h"
@@ -155,7 +154,7 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname,
do {
curlx_str_passblanks(&p);
if(strncasecompare("max-age", p, 7)) {
if(curl_strnequal("max-age", p, 7)) {
bool quoted = FALSE;
int rc;
@@ -185,7 +184,7 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname,
}
gotma = TRUE;
}
else if(strncasecompare("includesubdomains", p, 17)) {
else if(curl_strnequal("includesubdomains", p, 17)) {
if(gotinc)
return CURLE_BAD_FUNCTION_ARGUMENT;
subdomains = TRUE;
@@ -272,15 +271,15 @@ struct stsentry *Curl_hsts(struct hsts *h, const char *hostname,
if((subdomain && sts->includeSubDomains) && (ntail < hlen)) {
size_t offs = hlen - ntail;
if((hostname[offs-1] == '.') &&
strncasecompare(&hostname[offs], sts->host, ntail) &&
curl_strnequal(&hostname[offs], sts->host, ntail) &&
(ntail > blen)) {
/* save the tail match with the longest tail */
bestsub = sts;
blen = ntail;
}
}
/* avoid strcasecompare because the host name is not null-terminated */
if((hlen == ntail) && strncasecompare(hostname, sts->host, hlen))
/* avoid curl_strequal because the host name is not null-terminated */
if((hlen == ntail) && curl_strnequal(hostname, sts->host, hlen))
return sts;
}
}
@@ -581,4 +580,8 @@ void Curl_hsts_loadfiles(struct Curl_easy *data)
}
}
#if defined(DEBUGBUILD) || defined(UNITTESTS)
#undef time
#endif
#endif /* CURL_DISABLE_HTTP || CURL_DISABLE_HSTS */
+462 -351
View File
@@ -232,7 +232,7 @@ CURLcode Curl_http_setup_conn(struct Curl_easy *data,
connkeep(conn, "HTTP default");
if(data->state.http_neg.wanted == CURL_HTTP_V3x) {
/* only HTTP/3, needs to work */
CURLcode result = Curl_conn_may_http3(data, conn);
CURLcode result = Curl_conn_may_http3(data, conn, conn->transport_wanted);
if(result)
return result;
}
@@ -259,7 +259,7 @@ char *Curl_checkProxyheaders(struct Curl_easy *data,
for(head = (conn->bits.proxy && data->set.sep_headers) ?
data->set.proxyheaders : data->set.headers;
head; head = head->next) {
if(strncasecompare(head->data, thisheader, thislen) &&
if(curl_strnequal(head->data, thisheader, thislen) &&
Curl_headersep(head->data[thislen]))
return head->data;
}
@@ -862,7 +862,7 @@ static bool authcmp(const char *auth, const char *line)
{
/* the auth string must not have an alnum following */
size_t n = strlen(auth);
return strncasecompare(auth, line, n) && !ISALNUM(line[n]);
return curl_strnequal(auth, line, n) && !ISALNUM(line[n]);
}
#endif
@@ -1482,7 +1482,7 @@ Curl_compareheader(const char *headerline, /* line to check */
DEBUGASSERT(header);
DEBUGASSERT(content);
if(!strncasecompare(headerline, header, hlen))
if(!curl_strnequal(headerline, header, hlen))
return FALSE; /* does not start with header */
/* pass the header */
@@ -1497,7 +1497,7 @@ Curl_compareheader(const char *headerline, /* line to check */
size_t len;
p = curlx_str(&val);
for(len = curlx_strlen(&val); len >= curlx_strlen(&val); len--, p++) {
if(strncasecompare(p, content, clen))
if(curl_strnequal(p, content, clen))
return TRUE; /* match! */
}
}
@@ -1893,7 +1893,7 @@ static CURLcode http_host(struct Curl_easy *data, struct connectdata *conn)
ptr = Curl_checkheaders(data, STRCONST("Host"));
if(ptr && (!data->state.this_is_a_follow ||
strcasecompare(data->state.first_host, conn->host.name))) {
curl_strequal(data->state.first_host, conn->host.name))) {
#if !defined(CURL_DISABLE_COOKIES)
/* If we have a given custom Host: header, we extract the hostname in
order to possibly use it for cookie reasons later on. We only allow the
@@ -1929,7 +1929,7 @@ static CURLcode http_host(struct Curl_easy *data, struct connectdata *conn)
}
#endif
if(!strcasecompare("Host:", ptr)) {
if(!curl_strequal("Host:", ptr)) {
aptr->host = aprintf("Host:%s\r\n", &ptr[5]);
if(!aptr->host)
return CURLE_OUT_OF_MEMORY;
@@ -2005,7 +2005,7 @@ static CURLcode http_target(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
}
if(strcasecompare("http", data->state.up.scheme)) {
if(curl_strequal("http", data->state.up.scheme)) {
/* when getting HTTP, we do not want the userinfo the URL */
uc = curl_url_set(h, CURLUPART_USER, NULL, 0);
if(uc) {
@@ -2034,7 +2034,7 @@ static CURLcode http_target(struct Curl_easy *data,
if(result)
return result;
if(strcasecompare("ftp", data->state.up.scheme)) {
if(curl_strequal("ftp", data->state.up.scheme)) {
if(data->set.proxy_transfer_mode) {
/* when doing ftp, append ;type=<a|i> if not present */
char *type = strstr(path, ";type=");
@@ -2443,7 +2443,7 @@ static CURLcode http_cookies(struct Curl_easy *data,
data->state.aptr.cookiehost : conn->host.name;
const bool secure_context =
conn->handler->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS) ||
strcasecompare("localhost", host) ||
curl_strequal("localhost", host) ||
!strcmp(host, "127.0.0.1") ||
!strcmp(host, "::1");
Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
@@ -3000,377 +3000,489 @@ checkprotoprefix(struct Curl_easy *data, struct connectdata *conn,
((hdlen) > ((sizeof(n)-1) + (sizeof(v)-1))) && \
Curl_compareheader(hd, STRCONST(n), STRCONST(v)))
/*
* http_header_a() parses a single response header starting with A.
*/
static CURLcode http_header_a(struct Curl_easy *data,
const char *hd, size_t hdlen)
{
#ifndef CURL_DISABLE_ALTSVC
const char *v;
struct connectdata *conn = data->conn;
v = (data->asi &&
(Curl_conn_is_ssl(data->conn, FIRSTSOCKET) ||
#ifdef DEBUGBUILD
/* allow debug builds to circumvent the HTTPS restriction */
getenv("CURL_ALTSVC_HTTP")
#else
0
#endif
)) ? HD_VAL(hd, hdlen, "Alt-Svc:") : NULL;
if(v) {
/* the ALPN of the current request */
struct SingleRequest *k = &data->req;
enum alpnid id = (k->httpversion == 30) ? ALPN_h3 :
(k->httpversion == 20) ? ALPN_h2 : ALPN_h1;
return Curl_altsvc_parse(data, data->asi, v, id, conn->host.name,
curlx_uitous((unsigned int)conn->remote_port));
}
#else
(void)data;
(void)hd;
(void)hdlen;
#endif
return CURLE_OK;
}
/*
* http_header_c() parses a single response header starting with C.
*/
static CURLcode http_header_c(struct Curl_easy *data,
const char *hd, size_t hdlen)
{
struct connectdata *conn = data->conn;
struct SingleRequest *k = &data->req;
const char *v;
/* Check for Content-Length: header lines to get size */
v = (!k->http_bodyless && !data->set.ignorecl) ?
HD_VAL(hd, hdlen, "Content-Length:") : NULL;
if(v) {
curl_off_t contentlength;
int offt = curlx_str_numblanks(&v, &contentlength);
if(offt == STRE_OK) {
k->size = contentlength;
k->maxdownload = k->size;
}
else if(offt == STRE_OVERFLOW) {
/* out of range */
if(data->set.max_filesize) {
failf(data, "Maximum file size exceeded");
return CURLE_FILESIZE_EXCEEDED;
}
streamclose(conn, "overflow content-length");
infof(data, "Overflow Content-Length: value");
}
else {
/* negative or just rubbish - bad HTTP */
failf(data, "Invalid Content-Length: value");
return CURLE_WEIRD_SERVER_REPLY;
}
return CURLE_OK;
}
v = (!k->http_bodyless && data->set.str[STRING_ENCODING]) ?
HD_VAL(hd, hdlen, "Content-Encoding:") : NULL;
if(v) {
/*
* Process Content-Encoding. Look for the values: identity,
* gzip, deflate, compress, x-gzip and x-compress. x-gzip and
* x-compress are the same as gzip and compress. (Sec 3.5 RFC
* 2616). zlib cannot handle compress. However, errors are
* handled further down when the response body is processed
*/
return Curl_build_unencoding_stack(data, v, FALSE);
}
/* check for Content-Type: header lines to get the MIME-type */
v = HD_VAL(hd, hdlen, "Content-Type:");
if(v) {
char *contenttype = Curl_copy_header_value(hd);
if(!contenttype)
return CURLE_OUT_OF_MEMORY;
if(!*contenttype)
/* ignore empty data */
free(contenttype);
else {
free(data->info.contenttype);
data->info.contenttype = contenttype;
}
return CURLE_OK;
}
if(HD_IS_AND_SAYS(hd, hdlen, "Connection:", "close")) {
/*
* [RFC 2616, section 8.1.2.1]
* "Connection: close" is HTTP/1.1 language and means that
* the connection will close when this request has been
* served.
*/
streamclose(conn, "Connection: close used");
return CURLE_OK;
}
if((k->httpversion == 10) &&
HD_IS_AND_SAYS(hd, hdlen, "Connection:", "keep-alive")) {
/*
* An HTTP/1.0 reply with the 'Connection: keep-alive' line
* tells us the connection will be kept alive for our
* pleasure. Default action for 1.0 is to close.
*
* [RFC2068, section 19.7.1] */
connkeep(conn, "Connection keep-alive");
infof(data, "HTTP/1.0 connection set to keep alive");
return CURLE_OK;
}
v = !k->http_bodyless ? HD_VAL(hd, hdlen, "Content-Range:") : NULL;
if(v) {
/* Content-Range: bytes [num]-
Content-Range: bytes: [num]-
Content-Range: [num]-
Content-Range: [asterisk]/[total]
The second format was added since Sun's webserver
JavaWebServer/1.1.1 obviously sends the header this way!
The third added since some servers use that!
The fourth means the requested range was unsatisfied.
*/
const char *ptr = v;
/* Move forward until first digit or asterisk */
while(*ptr && !ISDIGIT(*ptr) && *ptr != '*')
ptr++;
/* if it truly stopped on a digit */
if(ISDIGIT(*ptr)) {
if(!curlx_str_number(&ptr, &k->offset, CURL_OFF_T_MAX) &&
(data->state.resume_from == k->offset))
/* we asked for a resume and we got it */
k->content_range = TRUE;
}
else if(k->httpcode < 300)
data->state.resume_from = 0; /* get everything */
}
return CURLE_OK;
}
/*
* http_header_l() parses a single response header starting with L.
*/
static CURLcode http_header_l(struct Curl_easy *data,
const char *hd, size_t hdlen)
{
struct connectdata *conn = data->conn;
struct SingleRequest *k = &data->req;
const char *v = (!k->http_bodyless &&
(data->set.timecondition || data->set.get_filetime)) ?
HD_VAL(hd, hdlen, "Last-Modified:") : NULL;
if(v) {
k->timeofdoc = Curl_getdate_capped(v);
if(data->set.get_filetime)
data->info.filetime = k->timeofdoc;
return CURLE_OK;
}
if((k->httpcode >= 300 && k->httpcode < 400) &&
HD_IS(hd, hdlen, "Location:") &&
!data->req.location) {
/* this is the URL that the server advises us to use instead */
char *location = Curl_copy_header_value(hd);
if(!location)
return CURLE_OUT_OF_MEMORY;
if(!*location)
/* ignore empty data */
free(location);
else {
data->req.location = location;
if(data->set.http_follow_mode) {
CURLcode result;
DEBUGASSERT(!data->req.newurl);
data->req.newurl = strdup(data->req.location); /* clone */
if(!data->req.newurl)
return CURLE_OUT_OF_MEMORY;
/* some cases of POST and PUT etc needs to rewind the data
stream at this point */
result = http_perhapsrewind(data, conn);
if(result)
return result;
/* mark the next request as a followed location: */
data->state.this_is_a_follow = TRUE;
}
}
}
return CURLE_OK;
}
/*
* http_header_p() parses a single response header starting with P.
*/
static CURLcode http_header_p(struct Curl_easy *data,
const char *hd, size_t hdlen)
{
struct SingleRequest *k = &data->req;
#ifndef CURL_DISABLE_PROXY
const char *v = HD_VAL(hd, hdlen, "Proxy-Connection:");
if(v) {
struct connectdata *conn = data->conn;
if((k->httpversion == 10) && conn->bits.httpproxy &&
HD_IS_AND_SAYS(hd, hdlen, "Proxy-Connection:", "keep-alive")) {
/*
* When an HTTP/1.0 reply comes when using a proxy, the
* 'Proxy-Connection: keep-alive' line tells us the
* connection will be kept alive for our pleasure.
* Default action for 1.0 is to close.
*/
connkeep(conn, "Proxy-Connection keep-alive"); /* do not close */
infof(data, "HTTP/1.0 proxy connection set to keep alive");
}
else if((k->httpversion == 11) && conn->bits.httpproxy &&
HD_IS_AND_SAYS(hd, hdlen, "Proxy-Connection:", "close")) {
/*
* We get an HTTP/1.1 response from a proxy and it says it will
* close down after this transfer.
*/
connclose(conn, "Proxy-Connection: asked to close after done");
infof(data, "HTTP/1.1 proxy connection set close");
}
return CURLE_OK;
}
#endif
if((407 == k->httpcode) && HD_IS(hd, hdlen, "Proxy-authenticate:")) {
char *auth = Curl_copy_header_value(hd);
CURLcode result;
if(!auth)
return CURLE_OUT_OF_MEMORY;
result = Curl_http_input_auth(data, TRUE, auth);
free(auth);
return result;
}
#ifdef USE_SPNEGO
if(HD_IS(hd, hdlen, "Persistent-Auth:")) {
struct connectdata *conn = data->conn;
struct negotiatedata *negdata = Curl_auth_nego_get(conn, FALSE);
struct auth *authp = &data->state.authhost;
if(!negdata)
return CURLE_OUT_OF_MEMORY;
if(authp->picked == CURLAUTH_NEGOTIATE) {
char *persistentauth = Curl_copy_header_value(hd);
if(!persistentauth)
return CURLE_OUT_OF_MEMORY;
negdata->noauthpersist = !!checkprefix("false", persistentauth);
negdata->havenoauthpersist = TRUE;
infof(data, "Negotiate: noauthpersist -> %d, header part: %s",
negdata->noauthpersist, persistentauth);
free(persistentauth);
}
}
#endif
return CURLE_OK;
}
/*
* http_header_r() parses a single response header starting with R.
*/
static CURLcode http_header_r(struct Curl_easy *data,
const char *hd, size_t hdlen)
{
const char *v = HD_VAL(hd, hdlen, "Retry-After:");
if(v) {
/* Retry-After = HTTP-date / delay-seconds */
curl_off_t retry_after = 0; /* zero for unknown or "now" */
time_t date;
curlx_str_passblanks(&v);
/* try it as a date first, because a date can otherwise start with and
get treated as a number */
date = Curl_getdate_capped(v);
if((time_t)-1 != date) {
time_t current = time(NULL);
if(date >= current)
/* convert date to number of seconds into the future */
retry_after = date - current;
}
else
/* Try it as a decimal number, ignore errors */
(void)curlx_str_number(&v, &retry_after, CURL_OFF_T_MAX);
/* limit to 6 hours max. this is not documented so that it can be changed
in the future if necessary. */
if(retry_after > 21600)
retry_after = 21600;
data->info.retry_after = retry_after;
}
return CURLE_OK;
}
/*
* http_header_s() parses a single response header starting with S.
*/
static CURLcode http_header_s(struct Curl_easy *data,
const char *hd, size_t hdlen)
{
#if !defined(CURL_DISABLE_COOKIES) || !defined(CURL_DISABLE_HSTS)
struct connectdata *conn = data->conn;
const char *v;
#else
(void)data;
(void)hd;
(void)hdlen;
#endif
#if !defined(CURL_DISABLE_COOKIES)
v = (data->cookies && data->state.cookie_engine) ?
HD_VAL(hd, hdlen, "Set-Cookie:") : NULL;
if(v) {
/* If there is a custom-set Host: name, use it here, or else use
* real peer hostname. */
const char *host = data->state.aptr.cookiehost ?
data->state.aptr.cookiehost : conn->host.name;
const bool secure_context =
conn->handler->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS) ||
curl_strequal("localhost", host) ||
!strcmp(host, "127.0.0.1") ||
!strcmp(host, "::1");
Curl_share_lock(data, CURL_LOCK_DATA_COOKIE,
CURL_LOCK_ACCESS_SINGLE);
Curl_cookie_add(data, data->cookies, TRUE, FALSE, v, host,
data->state.up.path, secure_context);
Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
return CURLE_OK;
}
#endif
#ifndef CURL_DISABLE_HSTS
/* If enabled, the header is incoming and this is over HTTPS */
v = (data->hsts &&
(Curl_conn_is_ssl(conn, FIRSTSOCKET) ||
#ifdef DEBUGBUILD
/* allow debug builds to circumvent the HTTPS restriction */
getenv("CURL_HSTS_HTTP")
#else
0
#endif
)
) ? HD_VAL(hd, hdlen, "Strict-Transport-Security:") : NULL;
if(v) {
CURLcode check =
Curl_hsts_parse(data->hsts, conn->host.name, v);
if(check)
infof(data, "Illegal STS header skipped");
#ifdef DEBUGBUILD
else
infof(data, "Parsed STS header fine (%zu entries)",
Curl_llist_count(&data->hsts->list));
#endif
}
#endif
return CURLE_OK;
}
/*
* http_header_t() parses a single response header starting with T.
*/
static CURLcode http_header_t(struct Curl_easy *data,
const char *hd, size_t hdlen)
{
struct connectdata *conn = data->conn;
struct SingleRequest *k = &data->req;
/* RFC 9112, ch. 6.1
* "Transfer-Encoding MAY be sent in a response to a HEAD request or
* in a 304 (Not Modified) response (Section 15.4.5 of [HTTP]) to a
* GET request, neither of which includes a message body, to indicate
* that the origin server would have applied a transfer coding to the
* message body if the request had been an unconditional GET."
*
* Read: in these cases the 'Transfer-Encoding' does not apply
* to any data following the response headers. Do not add any decoders.
*/
const char *v = (!k->http_bodyless &&
(data->state.httpreq != HTTPREQ_HEAD) &&
(k->httpcode != 304)) ?
HD_VAL(hd, hdlen, "Transfer-Encoding:") : NULL;
if(v) {
/* One or more encodings. We check for chunked and/or a compression
algorithm. */
CURLcode result = Curl_build_unencoding_stack(data, v, TRUE);
if(result)
return result;
if(!k->chunk && data->set.http_transfer_encoding) {
/* if this is not chunked, only close can signal the end of this
* transfer as Content-Length is said not to be trusted for
* transfer-encoding! */
connclose(conn, "HTTP/1.1 transfer-encoding without chunks");
k->ignore_cl = TRUE;
}
return CURLE_OK;
}
v = HD_VAL(hd, hdlen, "Trailer:");
if(v) {
data->req.resp_trailer = TRUE;
return CURLE_OK;
}
return CURLE_OK;
}
/*
* http_header_w() parses a single response header starting with W.
*/
static CURLcode http_header_w(struct Curl_easy *data,
const char *hd, size_t hdlen)
{
struct SingleRequest *k = &data->req;
CURLcode result = CURLE_OK;
if((401 == k->httpcode) && HD_IS(hd, hdlen, "WWW-Authenticate:")) {
char *auth = Curl_copy_header_value(hd);
if(!auth)
return CURLE_OUT_OF_MEMORY;
result = Curl_http_input_auth(data, FALSE, auth);
free(auth);
}
return result;
}
/*
* http_header() parses a single response header.
*/
static CURLcode http_header(struct Curl_easy *data,
const char *hd, size_t hdlen)
{
struct connectdata *conn = data->conn;
CURLcode result;
struct SingleRequest *k = &data->req;
const char *v;
CURLcode result = CURLE_OK;
switch(hd[0]) {
case 'a':
case 'A':
#ifndef CURL_DISABLE_ALTSVC
v = (data->asi &&
(Curl_conn_is_ssl(data->conn, FIRSTSOCKET) ||
#ifdef DEBUGBUILD
/* allow debug builds to circumvent the HTTPS restriction */
getenv("CURL_ALTSVC_HTTP")
#else
0
#endif
)) ? HD_VAL(hd, hdlen, "Alt-Svc:") : NULL;
if(v) {
/* the ALPN of the current request */
enum alpnid id = (k->httpversion == 30) ? ALPN_h3 :
(k->httpversion == 20) ? ALPN_h2 : ALPN_h1;
return Curl_altsvc_parse(data, data->asi, v, id, conn->host.name,
curlx_uitous((unsigned int)conn->remote_port));
}
#endif
result = http_header_a(data, hd, hdlen);
break;
case 'c':
case 'C':
/* Check for Content-Length: header lines to get size */
v = (!k->http_bodyless && !data->set.ignorecl) ?
HD_VAL(hd, hdlen, "Content-Length:") : NULL;
if(v) {
curl_off_t contentlength;
int offt = curlx_str_numblanks(&v, &contentlength);
if(offt == STRE_OK) {
k->size = contentlength;
k->maxdownload = k->size;
}
else if(offt == STRE_OVERFLOW) {
/* out of range */
if(data->set.max_filesize) {
failf(data, "Maximum file size exceeded");
return CURLE_FILESIZE_EXCEEDED;
}
streamclose(conn, "overflow content-length");
infof(data, "Overflow Content-Length: value");
}
else {
/* negative or just rubbish - bad HTTP */
failf(data, "Invalid Content-Length: value");
return CURLE_WEIRD_SERVER_REPLY;
}
return CURLE_OK;
}
v = (!k->http_bodyless && data->set.str[STRING_ENCODING]) ?
HD_VAL(hd, hdlen, "Content-Encoding:") : NULL;
if(v) {
/*
* Process Content-Encoding. Look for the values: identity,
* gzip, deflate, compress, x-gzip and x-compress. x-gzip and
* x-compress are the same as gzip and compress. (Sec 3.5 RFC
* 2616). zlib cannot handle compress. However, errors are
* handled further down when the response body is processed
*/
return Curl_build_unencoding_stack(data, v, FALSE);
}
/* check for Content-Type: header lines to get the MIME-type */
v = HD_VAL(hd, hdlen, "Content-Type:");
if(v) {
char *contenttype = Curl_copy_header_value(hd);
if(!contenttype)
return CURLE_OUT_OF_MEMORY;
if(!*contenttype)
/* ignore empty data */
free(contenttype);
else {
free(data->info.contenttype);
data->info.contenttype = contenttype;
}
return CURLE_OK;
}
if(HD_IS_AND_SAYS(hd, hdlen, "Connection:", "close")) {
/*
* [RFC 2616, section 8.1.2.1]
* "Connection: close" is HTTP/1.1 language and means that
* the connection will close when this request has been
* served.
*/
streamclose(conn, "Connection: close used");
return CURLE_OK;
}
if((k->httpversion == 10) &&
HD_IS_AND_SAYS(hd, hdlen, "Connection:", "keep-alive")) {
/*
* An HTTP/1.0 reply with the 'Connection: keep-alive' line
* tells us the connection will be kept alive for our
* pleasure. Default action for 1.0 is to close.
*
* [RFC2068, section 19.7.1] */
connkeep(conn, "Connection keep-alive");
infof(data, "HTTP/1.0 connection set to keep alive");
return CURLE_OK;
}
v = !k->http_bodyless ? HD_VAL(hd, hdlen, "Content-Range:") : NULL;
if(v) {
/* Content-Range: bytes [num]-
Content-Range: bytes: [num]-
Content-Range: [num]-
Content-Range: [asterisk]/[total]
The second format was added since Sun's webserver
JavaWebServer/1.1.1 obviously sends the header this way!
The third added since some servers use that!
The fourth means the requested range was unsatisfied.
*/
const char *ptr = v;
/* Move forward until first digit or asterisk */
while(*ptr && !ISDIGIT(*ptr) && *ptr != '*')
ptr++;
/* if it truly stopped on a digit */
if(ISDIGIT(*ptr)) {
if(!curlx_str_number(&ptr, &k->offset, CURL_OFF_T_MAX) &&
(data->state.resume_from == k->offset))
/* we asked for a resume and we got it */
k->content_range = TRUE;
}
else if(k->httpcode < 300)
data->state.resume_from = 0; /* get everything */
}
result = http_header_c(data, hd, hdlen);
break;
case 'l':
case 'L':
v = (!k->http_bodyless &&
(data->set.timecondition || data->set.get_filetime)) ?
HD_VAL(hd, hdlen, "Last-Modified:") : NULL;
if(v) {
k->timeofdoc = Curl_getdate_capped(v);
if(data->set.get_filetime)
data->info.filetime = k->timeofdoc;
return CURLE_OK;
}
if((k->httpcode >= 300 && k->httpcode < 400) &&
HD_IS(hd, hdlen, "Location:") &&
!data->req.location) {
/* this is the URL that the server advises us to use instead */
char *location = Curl_copy_header_value(hd);
if(!location)
return CURLE_OUT_OF_MEMORY;
if(!*location)
/* ignore empty data */
free(location);
else {
data->req.location = location;
if(data->set.http_follow_mode) {
DEBUGASSERT(!data->req.newurl);
data->req.newurl = strdup(data->req.location); /* clone */
if(!data->req.newurl)
return CURLE_OUT_OF_MEMORY;
/* some cases of POST and PUT etc needs to rewind the data
stream at this point */
result = http_perhapsrewind(data, conn);
if(result)
return result;
/* mark the next request as a followed location: */
data->state.this_is_a_follow = TRUE;
}
}
}
result = http_header_l(data, hd, hdlen);
break;
case 'p':
case 'P':
#ifndef CURL_DISABLE_PROXY
v = HD_VAL(hd, hdlen, "Proxy-Connection:");
if(v) {
if((k->httpversion == 10) && conn->bits.httpproxy &&
HD_IS_AND_SAYS(hd, hdlen, "Proxy-Connection:", "keep-alive")) {
/*
* When an HTTP/1.0 reply comes when using a proxy, the
* 'Proxy-Connection: keep-alive' line tells us the
* connection will be kept alive for our pleasure.
* Default action for 1.0 is to close.
*/
connkeep(conn, "Proxy-Connection keep-alive"); /* do not close */
infof(data, "HTTP/1.0 proxy connection set to keep alive");
}
else if((k->httpversion == 11) && conn->bits.httpproxy &&
HD_IS_AND_SAYS(hd, hdlen, "Proxy-Connection:", "close")) {
/*
* We get an HTTP/1.1 response from a proxy and it says it will
* close down after this transfer.
*/
connclose(conn, "Proxy-Connection: asked to close after done");
infof(data, "HTTP/1.1 proxy connection set close");
}
return CURLE_OK;
}
#endif
if((407 == k->httpcode) && HD_IS(hd, hdlen, "Proxy-authenticate:")) {
char *auth = Curl_copy_header_value(hd);
if(!auth)
return CURLE_OUT_OF_MEMORY;
result = Curl_http_input_auth(data, TRUE, auth);
free(auth);
return result;
}
#ifdef USE_SPNEGO
if(HD_IS(hd, hdlen, "Persistent-Auth:")) {
struct negotiatedata *negdata = &conn->negotiate;
struct auth *authp = &data->state.authhost;
if(authp->picked == CURLAUTH_NEGOTIATE) {
char *persistentauth = Curl_copy_header_value(hd);
if(!persistentauth)
return CURLE_OUT_OF_MEMORY;
negdata->noauthpersist = !!checkprefix("false", persistentauth);
negdata->havenoauthpersist = TRUE;
infof(data, "Negotiate: noauthpersist -> %d, header part: %s",
negdata->noauthpersist, persistentauth);
free(persistentauth);
}
}
#endif
result = http_header_p(data, hd, hdlen);
break;
case 'r':
case 'R':
v = HD_VAL(hd, hdlen, "Retry-After:");
if(v) {
/* Retry-After = HTTP-date / delay-seconds */
curl_off_t retry_after = 0; /* zero for unknown or "now" */
time_t date;
curlx_str_passblanks(&v);
/* try it as a date first, because a date can otherwise start with and
get treated as a number */
date = Curl_getdate_capped(v);
if((time_t)-1 != date) {
time_t current = time(NULL);
if(date >= current)
/* convert date to number of seconds into the future */
retry_after = date - current;
}
else
/* Try it as a decimal number */
curlx_str_number(&v, &retry_after, CURL_OFF_T_MAX);
/* limit to 6 hours max. this is not documented so that it can be changed
in the future if necessary. */
if(retry_after > 21600)
retry_after = 21600;
data->info.retry_after = retry_after;
return CURLE_OK;
}
result = http_header_r(data, hd, hdlen);
break;
case 's':
case 'S':
#if !defined(CURL_DISABLE_COOKIES)
v = (data->cookies && data->state.cookie_engine) ?
HD_VAL(hd, hdlen, "Set-Cookie:") : NULL;
if(v) {
/* If there is a custom-set Host: name, use it here, or else use
* real peer hostname. */
const char *host = data->state.aptr.cookiehost ?
data->state.aptr.cookiehost : conn->host.name;
const bool secure_context =
conn->handler->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS) ||
strcasecompare("localhost", host) ||
!strcmp(host, "127.0.0.1") ||
!strcmp(host, "::1");
Curl_share_lock(data, CURL_LOCK_DATA_COOKIE,
CURL_LOCK_ACCESS_SINGLE);
Curl_cookie_add(data, data->cookies, TRUE, FALSE, v, host,
data->state.up.path, secure_context);
Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
return CURLE_OK;
}
#endif
#ifndef CURL_DISABLE_HSTS
/* If enabled, the header is incoming and this is over HTTPS */
v = (data->hsts &&
(Curl_conn_is_ssl(conn, FIRSTSOCKET) ||
#ifdef DEBUGBUILD
/* allow debug builds to circumvent the HTTPS restriction */
getenv("CURL_HSTS_HTTP")
#else
0
#endif
)
) ? HD_VAL(hd, hdlen, "Strict-Transport-Security:") : NULL;
if(v) {
CURLcode check =
Curl_hsts_parse(data->hsts, conn->host.name, v);
if(check)
infof(data, "Illegal STS header skipped");
#ifdef DEBUGBUILD
else
infof(data, "Parsed STS header fine (%zu entries)",
Curl_llist_count(&data->hsts->list));
#endif
}
#endif
result = http_header_s(data, hd, hdlen);
break;
case 't':
case 'T':
/* RFC 9112, ch. 6.1
* "Transfer-Encoding MAY be sent in a response to a HEAD request or
* in a 304 (Not Modified) response (Section 15.4.5 of [HTTP]) to a
* GET request, neither of which includes a message body, to indicate
* that the origin server would have applied a transfer coding to the
* message body if the request had been an unconditional GET."
*
* Read: in these cases the 'Transfer-Encoding' does not apply
* to any data following the response headers. Do not add any decoders.
*/
v = (!k->http_bodyless &&
(data->state.httpreq != HTTPREQ_HEAD) &&
(k->httpcode != 304)) ?
HD_VAL(hd, hdlen, "Transfer-Encoding:") : NULL;
if(v) {
/* One or more encodings. We check for chunked and/or a compression
algorithm. */
result = Curl_build_unencoding_stack(data, v, TRUE);
if(result)
return result;
if(!k->chunk && data->set.http_transfer_encoding) {
/* if this is not chunked, only close can signal the end of this
* transfer as Content-Length is said not to be trusted for
* transfer-encoding! */
connclose(conn, "HTTP/1.1 transfer-encoding without chunks");
k->ignore_cl = TRUE;
}
return CURLE_OK;
}
v = HD_VAL(hd, hdlen, "Trailer:");
if(v) {
data->req.resp_trailer = TRUE;
return CURLE_OK;
}
result = http_header_t(data, hd, hdlen);
break;
case 'w':
case 'W':
if((401 == k->httpcode) && HD_IS(hd, hdlen, "WWW-Authenticate:")) {
char *auth = Curl_copy_header_value(hd);
if(!auth)
return CURLE_OUT_OF_MEMORY;
result = Curl_http_input_auth(data, FALSE, auth);
free(auth);
return result;
}
result = http_header_w(data, hd, hdlen);
break;
}
if(conn->handler->protocol & CURLPROTO_RTSP) {
result = Curl_rtsp_parseheader(data, hd);
if(result)
return result;
if(!result) {
struct connectdata *conn = data->conn;
if(conn->handler->protocol & CURLPROTO_RTSP)
result = Curl_rtsp_parseheader(data, hd);
}
return CURLE_OK;
return result;
}
/*
@@ -3850,9 +3962,8 @@ static CURLcode http_on_response(struct Curl_easy *data,
out:
if(last_hd) {
/* if not written yet, write it now */
CURLcode r2 = http_write_header(data, last_hd, last_hd_len);
if(!result)
result = r2;
result = Curl_1st_err(
result, http_write_header(data, last_hd, last_hd_len));
}
return result;
}
@@ -4474,7 +4585,7 @@ static bool h2_permissible_field(struct dynhds_entry *e)
if(e->namelen < H2_NON_FIELD[i].namelen)
return TRUE;
if(e->namelen == H2_NON_FIELD[i].namelen &&
strcasecompare(H2_NON_FIELD[i].name, e->name))
curl_strequal(H2_NON_FIELD[i].name, e->name))
return FALSE;
}
return TRUE;
@@ -4565,7 +4676,7 @@ CURLcode Curl_http_req_to_h2(struct dynhds *h2_headers,
e = Curl_dynhds_getn(&req->headers, i);
/* "TE" is special in that it is only permissible when it
* has only value "trailers". RFC 9113 ch. 8.2.2 */
if(e->namelen == 2 && strcasecompare("TE", e->name)) {
if(e->namelen == 2 && curl_strequal("TE", e->name)) {
if(http_TE_has_token(e->value, "trailers"))
result = Curl_dynhds_add(h2_headers, e->name, e->namelen,
"trailers", sizeof("trailers") - 1);
+171 -227
View File
@@ -36,7 +36,6 @@
#include "sendf.h"
#include "select.h"
#include "curlx/base64.h"
#include "strcase.h"
#include "multiif.h"
#include "url.h"
#include "urlapi-int.h"
@@ -205,6 +204,9 @@ static void cf_h2_ctx_close(struct cf_h2_ctx *ctx)
}
}
static CURLcode nw_out_flush(struct Curl_cfilter *cf,
struct Curl_easy *data);
static CURLcode h2_progress_egress(struct Curl_cfilter *cf,
struct Curl_easy *data);
@@ -374,27 +376,6 @@ static CURLcode cf_h2_update_local_win(struct Curl_cfilter *cf,
}
#endif /* !NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE */
/*
* Mark this transfer to get "drained".
*/
static void drain_stream(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct h2_stream_ctx *stream)
{
unsigned char bits;
(void)cf;
bits = CURL_CSELECT_IN;
if(!stream->closed &&
(!stream->body_eos || !Curl_bufq_is_empty(&stream->sendbuf)))
bits |= CURL_CSELECT_OUT;
if(stream->closed || (data->state.select_bits != bits)) {
CURL_TRC_CF(data, cf, "[%d] DRAIN select_bits=%x",
stream->id, bits);
data->state.select_bits = bits;
Curl_expire(data, 0, EXPIRE_RUN_NOW);
}
}
static CURLcode http2_data_setup(struct Curl_cfilter *cf,
struct Curl_easy *data,
@@ -449,8 +430,10 @@ static void http2_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
flush_egress = TRUE;
}
if(flush_egress)
nghttp2_session_send(ctx->h2);
if(flush_egress) {
(void)nghttp2_session_send(ctx->h2);
(void)nw_out_flush(cf, data);
}
}
Curl_uint_hash_remove(&ctx->streams, data->mid);
@@ -480,33 +463,6 @@ static int h2_client_new(struct Curl_cfilter *cf,
return rc;
}
static ssize_t nw_in_reader(void *reader_ctx,
unsigned char *buf, size_t buflen,
CURLcode *err)
{
struct Curl_cfilter *cf = reader_ctx;
struct Curl_easy *data = CF_DATA_CURRENT(cf);
return Curl_conn_cf_recv(cf->next, data, (char *)buf, buflen, err);
}
static ssize_t nw_out_writer(void *writer_ctx,
const unsigned char *buf, size_t buflen,
CURLcode *err)
{
struct Curl_cfilter *cf = writer_ctx;
struct Curl_easy *data = CF_DATA_CURRENT(cf);
if(data) {
ssize_t nwritten = Curl_conn_cf_send(cf->next, data, (const char *)buf,
buflen, FALSE, err);
if(nwritten > 0)
CURL_TRC_CF(data, cf, "[0] egress: wrote %zd bytes", nwritten);
return nwritten;
}
return 0;
}
static ssize_t send_callback(nghttp2_session *h2,
const uint8_t *mem, size_t length, int flags,
void *userp);
@@ -727,12 +683,12 @@ static bool http2_connisalive(struct Curl_cfilter *cf, struct Curl_easy *data,
not in use by any other transfer, there should not be any data here,
only "protocol frames" */
CURLcode result;
ssize_t nread = -1;
size_t nread;
*input_pending = FALSE;
nread = Curl_bufq_slurp(&ctx->inbufq, nw_in_reader, cf, &result);
if(nread != -1) {
CURL_TRC_CF(data, cf, "%zd bytes stray data read before trying "
result = Curl_cf_recv_bufq(cf->next, data, &ctx->inbufq, 0, &nread);
if(!result) {
CURL_TRC_CF(data, cf, "%zu bytes stray data read before trying "
"h2 connection", nread);
if(h2_process_pending_input(cf, data, &result) < 0)
/* immediate error, considered dead */
@@ -785,15 +741,16 @@ static CURLcode nw_out_flush(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_h2_ctx *ctx = cf->ctx;
ssize_t nwritten;
size_t nwritten;
CURLcode result;
(void)data;
if(Curl_bufq_is_empty(&ctx->outbufq))
return CURLE_OK;
nwritten = Curl_bufq_pass(&ctx->outbufq, nw_out_writer, cf, &result);
if(nwritten < 0) {
result = Curl_cf_send_bufq(cf->next, data, &ctx->outbufq, NULL, 0,
&nwritten);
if(result) {
if(result == CURLE_AGAIN) {
CURL_TRC_CF(data, cf, "flush nw send buffer(%zu) -> EAGAIN",
Curl_bufq_len(&ctx->outbufq));
@@ -816,7 +773,7 @@ static ssize_t send_callback(nghttp2_session *h2,
struct Curl_cfilter *cf = userp;
struct cf_h2_ctx *ctx = cf->ctx;
struct Curl_easy *data = CF_DATA_CURRENT(cf);
ssize_t nwritten;
size_t nwritten;
CURLcode result = CURLE_OK;
(void)h2;
@@ -824,11 +781,12 @@ static ssize_t send_callback(nghttp2_session *h2,
DEBUGASSERT(data);
if(!cf->connected)
nwritten = Curl_bufq_write(&ctx->outbufq, buf, blen, &result);
result = Curl_bufq_write(&ctx->outbufq, buf, blen, &nwritten);
else
nwritten = Curl_bufq_write_pass(&ctx->outbufq, buf, blen,
nw_out_writer, cf, &result);
if(nwritten < 0) {
result = Curl_cf_send_bufq(cf->next, data, &ctx->outbufq, buf, blen,
&nwritten);
if(result) {
if(result == CURLE_AGAIN) {
ctx->nw_out_blocked = 1;
return NGHTTP2_ERR_WOULDBLOCK;
@@ -841,7 +799,8 @@ static ssize_t send_callback(nghttp2_session *h2,
ctx->nw_out_blocked = 1;
return NGHTTP2_ERR_WOULDBLOCK;
}
return nwritten;
return (nwritten > SSIZE_T_MAX) ?
NGHTTP2_ERR_CALLBACK_FAILURE : (ssize_t)nwritten;
}
@@ -1191,7 +1150,7 @@ static CURLcode on_stream_frame(struct Curl_cfilter *cf,
if(stream->status_code / 100 != 1) {
stream->resp_hds_complete = TRUE;
}
drain_stream(cf, data, stream);
Curl_multi_mark_dirty(data);
break;
case NGHTTP2_PUSH_PROMISE:
rv = push_promise(cf, data, &frame->push_promise);
@@ -1214,12 +1173,12 @@ static CURLcode on_stream_frame(struct Curl_cfilter *cf,
if(frame->rst_stream.error_code) {
stream->reset = TRUE;
}
drain_stream(cf, data, stream);
Curl_multi_mark_dirty(data);
break;
case NGHTTP2_WINDOW_UPDATE:
if(CURL_WANT_SEND(data) && Curl_bufq_is_empty(&stream->sendbuf)) {
/* need more data, force processing of transfer */
drain_stream(cf, data, stream);
Curl_multi_mark_dirty(data);
}
else if(!Curl_bufq_is_empty(&stream->sendbuf)) {
/* resume the potentially suspended stream */
@@ -1245,7 +1204,7 @@ static CURLcode on_stream_frame(struct Curl_cfilter *cf,
stream->id, NGHTTP2_STREAM_CLOSED);
stream->closed = TRUE;
}
drain_stream(cf, data, stream);
Curl_multi_mark_dirty(data);
}
return CURLE_OK;
}
@@ -1394,11 +1353,8 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
* window and *assume* that we treat this like a WINDOW_UPDATE. Some
* servers send an explicit WINDOW_UPDATE, but not all seem to do that.
* To be safe, we UNHOLD a stream in order not to stall. */
if(CURL_WANT_SEND(data)) {
struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
if(stream)
drain_stream(cf, data, stream);
}
if(CURL_WANT_SEND(data))
Curl_multi_mark_dirty(data);
}
break;
}
@@ -1543,7 +1499,7 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id,
stream_id, nghttp2_http2_strerror(error_code), error_code);
else
CURL_TRC_CF(data_s, cf, "[%d] CLOSED", stream_id);
drain_stream(cf, data_s, stream);
Curl_multi_mark_dirty(data_s);
/* remove `data_s` from the nghttp2 stream */
rv = nghttp2_session_set_stream_user_data(session, stream_id, 0);
@@ -1641,9 +1597,9 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
if(!check)
/* no memory */
return NGHTTP2_ERR_CALLBACK_FAILURE;
if(!strcasecompare(check, (const char *)value) &&
if(!curl_strequal(check, (const char *)value) &&
((cf->conn->remote_port != cf->conn->given->defport) ||
!strcasecompare(cf->conn->host.name, (const char *)value))) {
!curl_strequal(cf->conn->host.name, (const char *)value))) {
/* This is push is not for the same authority that was asked for in
* the URL. RFC 7540 section 8.2 says: "A client MUST treat a
* PUSH_PROMISE for which the server is not authoritative as a stream
@@ -1737,7 +1693,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
}
/* if we receive data for another handle, wake that up */
if(CF_DATA_CURRENT(cf) != data_s)
Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
Curl_multi_mark_dirty(data_s);
CURL_TRC_CF(data_s, cf, "[%d] status: HTTP/2 %03d",
stream->id, stream->status_code);
@@ -1764,7 +1720,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
}
/* if we receive data for another handle, wake that up */
if(CF_DATA_CURRENT(cf) != data_s)
Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
Curl_multi_mark_dirty(data_s);
CURL_TRC_CF(data_s, cf, "[%d] header: %.*s: %.*s",
stream->id, (int)namelen, name, (int)valuelen, value);
@@ -1785,6 +1741,7 @@ static ssize_t req_body_read_callback(nghttp2_session *session,
struct h2_stream_ctx *stream = NULL;
CURLcode result;
ssize_t nread;
size_t n;
(void)source;
(void)cf;
@@ -1803,12 +1760,14 @@ static ssize_t req_body_read_callback(nghttp2_session *session,
if(!stream)
return NGHTTP2_ERR_CALLBACK_FAILURE;
nread = Curl_bufq_read(&stream->sendbuf, buf, length, &result);
if(nread < 0) {
result = Curl_bufq_read(&stream->sendbuf, buf, length, &n);
if(result) {
if(result != CURLE_AGAIN)
return NGHTTP2_ERR_CALLBACK_FAILURE;
nread = 0;
}
else
nread = (ssize_t)n;
CURL_TRC_CF(data_s, cf, "[%d] req_body_read(len=%zu) eos=%d -> %zd, %d",
stream_id, length, stream->body_eos, nread, result);
@@ -1874,20 +1833,20 @@ CURLcode Curl_http2_request_upgrade(struct dynbuf *req,
return result;
}
static ssize_t http2_handle_stream_close(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct h2_stream_ctx *stream,
CURLcode *err)
static CURLcode http2_handle_stream_close(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct h2_stream_ctx *stream,
size_t *pnlen)
{
ssize_t rv = 0;
CURLcode result;
*pnlen = 0;
if(stream->error == NGHTTP2_REFUSED_STREAM) {
CURL_TRC_CF(data, cf, "[%d] REFUSED_STREAM, try again on a new "
"connection", stream->id);
connclose(cf->conn, "REFUSED_STREAM"); /* do not use this anymore */
data->state.refused_stream = TRUE;
*err = CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */
return -1;
return CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */
}
else if(stream->error != NGHTTP2_NO_ERROR) {
if(stream->resp_hds_complete && data->req.no_body) {
@@ -1896,27 +1855,23 @@ static ssize_t http2_handle_stream_close(struct Curl_cfilter *cf,
stream->id, nghttp2_http2_strerror(stream->error),
stream->error);
stream->close_handled = TRUE;
*err = CURLE_OK;
goto out;
return CURLE_OK;
}
failf(data, "HTTP/2 stream %u was not closed cleanly: %s (err %u)",
stream->id, nghttp2_http2_strerror(stream->error),
stream->error);
*err = CURLE_HTTP2_STREAM;
return -1;
return CURLE_HTTP2_STREAM;
}
else if(stream->reset) {
failf(data, "HTTP/2 stream %u was reset", stream->id);
*err = data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP2;
return -1;
return data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP2;
}
if(!stream->bodystarted) {
failf(data, "HTTP/2 stream %u was closed cleanly, but before getting "
" all response header fields, treated as error",
stream->id);
*err = CURLE_HTTP2_STREAM;
return -1;
return CURLE_HTTP2_STREAM;
}
if(Curl_dynhds_count(&stream->resp_trailers)) {
@@ -1924,37 +1879,36 @@ static ssize_t http2_handle_stream_close(struct Curl_cfilter *cf,
struct dynbuf dbuf;
size_t i;
*err = CURLE_OK;
result = CURLE_OK;
curlx_dyn_init(&dbuf, DYN_TRAILERS);
for(i = 0; i < Curl_dynhds_count(&stream->resp_trailers); ++i) {
e = Curl_dynhds_getn(&stream->resp_trailers, i);
if(!e)
break;
curlx_dyn_reset(&dbuf);
*err = curlx_dyn_addf(&dbuf, "%.*s: %.*s\x0d\x0a",
result = curlx_dyn_addf(&dbuf, "%.*s: %.*s\x0d\x0a",
(int)e->namelen, e->name,
(int)e->valuelen, e->value);
if(*err)
if(result)
break;
Curl_debug(data, CURLINFO_HEADER_IN, curlx_dyn_ptr(&dbuf),
curlx_dyn_len(&dbuf));
*err = Curl_client_write(data, CLIENTWRITE_HEADER|CLIENTWRITE_TRAILER,
curlx_dyn_ptr(&dbuf), curlx_dyn_len(&dbuf));
if(*err)
result = Curl_client_write(data, CLIENTWRITE_HEADER|CLIENTWRITE_TRAILER,
curlx_dyn_ptr(&dbuf), curlx_dyn_len(&dbuf));
if(result)
break;
}
curlx_dyn_free(&dbuf);
if(*err)
if(result)
goto out;
}
stream->close_handled = TRUE;
*err = CURLE_OK;
rv = 0;
result = CURLE_OK;
out:
CURL_TRC_CF(data, cf, "handle_stream_close -> %zd, %d", rv, *err);
return rv;
CURL_TRC_CF(data, cf, "handle_stream_close -> %d, %zu", result, *pnlen);
return result;
}
static int sweight_wanted(const struct Curl_easy *data)
@@ -1997,7 +1951,7 @@ static void h2_pri_spec(struct cf_h2_ctx *ctx,
* Flush any out data pending in the network buffer.
*/
static CURLcode h2_progress_egress(struct Curl_cfilter *cf,
struct Curl_easy *data)
struct Curl_easy *data)
{
struct cf_h2_ctx *ctx = cf->ctx;
struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
@@ -2037,36 +1991,36 @@ out:
return nw_out_flush(cf, data);
}
static ssize_t stream_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
struct h2_stream_ctx *stream,
char *buf, size_t len, CURLcode *err)
static CURLcode stream_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
struct h2_stream_ctx *stream,
char *buf, size_t len, size_t *pnread)
{
struct cf_h2_ctx *ctx = cf->ctx;
ssize_t nread = -1;
CURLcode result = CURLE_AGAIN;
(void)buf;
*err = CURLE_AGAIN;
(void)len;
*pnread = 0;
if(stream->xfer_result) {
CURL_TRC_CF(data, cf, "[%d] xfer write failed", stream->id);
*err = stream->xfer_result;
nread = -1;
result = stream->xfer_result;
}
else if(stream->closed) {
CURL_TRC_CF(data, cf, "[%d] returning CLOSE", stream->id);
nread = http2_handle_stream_close(cf, data, stream, err);
result = http2_handle_stream_close(cf, data, stream, pnread);
}
else if(stream->reset ||
(ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) ||
(ctx->rcvd_goaway && ctx->remote_max_sid < stream->id)) {
CURL_TRC_CF(data, cf, "[%d] returning ERR", stream->id);
*err = data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP2;
nread = -1;
result = data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP2;
}
if(nread < 0 && *err != CURLE_AGAIN)
CURL_TRC_CF(data, cf, "[%d] stream_recv(len=%zu) -> %zd, %d",
stream->id, len, nread, *err);
return nread;
if(result && (result != CURLE_AGAIN))
CURL_TRC_CF(data, cf, "[%d] stream_recv(len=%zu) -> %d, %zu",
stream->id, len, result, *pnread);
return result;
}
static CURLcode h2_progress_ingress(struct Curl_cfilter *cf,
@@ -2076,7 +2030,7 @@ static CURLcode h2_progress_ingress(struct Curl_cfilter *cf,
struct cf_h2_ctx *ctx = cf->ctx;
struct h2_stream_ctx *stream;
CURLcode result = CURLE_OK;
ssize_t nread;
size_t nread;
if(should_close_session(ctx)) {
CURL_TRC_CF(data, cf, "progress ingress, session is closed");
@@ -2102,12 +2056,12 @@ static CURLcode h2_progress_ingress(struct Curl_cfilter *cf,
* this may leave data in underlying buffers that will not
* be consumed. */
if(!cf->next || !cf->next->cft->has_data_pending(cf->next, data))
drain_stream(cf, data, stream);
Curl_multi_mark_dirty(data);
break;
}
nread = Curl_bufq_sipn(&ctx->inbufq, 0, nw_in_reader, cf, &result);
if(nread < 0) {
result = Curl_cf_recv_bufq(cf->next, data, &ctx->inbufq, 0, &nread);
if(result) {
if(result != CURLE_AGAIN) {
failf(data, "Failed receiving HTTP2 data: %d(%s)", result,
curl_easy_strerror(result));
@@ -2121,9 +2075,8 @@ static CURLcode h2_progress_ingress(struct Curl_cfilter *cf,
break;
}
else {
CURL_TRC_CF(data, cf, "[0] ingress: read %zd bytes", nread);
data_max_bytes = (data_max_bytes > (size_t)nread) ?
(data_max_bytes - (size_t)nread) : 0;
CURL_TRC_CF(data, cf, "[0] ingress: read %zu bytes", nread);
data_max_bytes = (data_max_bytes > nread) ? (data_max_bytes - nread) : 0;
}
if(h2_process_pending_input(cf, data, &result))
@@ -2140,15 +2093,15 @@ static CURLcode h2_progress_ingress(struct Curl_cfilter *cf,
return CURLE_OK;
}
static ssize_t cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, CURLcode *err)
static CURLcode cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, size_t *pnread)
{
struct cf_h2_ctx *ctx = cf->ctx;
struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
ssize_t nread = -1;
CURLcode result;
CURLcode result, r2;
struct cf_call_data save;
*pnread = 0;
if(!stream) {
/* Abnormal call sequence: either this transfer has never opened a stream
* (unlikely) or the transfer has been done, cleaned up its resources, but
@@ -2156,51 +2109,49 @@ static ssize_t cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
* is for such a case. */
failf(data, "http/2 recv on a transfer never opened "
"or already cleared, mid=%u", data->mid);
*err = CURLE_HTTP2;
return -1;
return CURLE_HTTP2;
}
CF_DATA_SAVE(save, cf, data);
nread = stream_recv(cf, data, stream, buf, len, err);
if(nread < 0 && *err != CURLE_AGAIN)
result = stream_recv(cf, data, stream, buf, len, pnread);
if(result && (result != CURLE_AGAIN))
goto out;
if(nread < 0) {
*err = h2_progress_ingress(cf, data, len);
if(*err)
if(result) {
result = h2_progress_ingress(cf, data, len);
if(result)
goto out;
nread = stream_recv(cf, data, stream, buf, len, err);
result = stream_recv(cf, data, stream, buf, len, pnread);
}
if(nread > 0) {
if(*pnread > 0) {
/* Now that we transferred this to the upper layer, we report
* the actual amount of DATA consumed to the H2 session, so
* that it adjusts stream flow control */
nghttp2_session_consume(ctx->h2, stream->id, (size_t)nread);
nghttp2_session_consume(ctx->h2, stream->id, *pnread);
if(stream->closed) {
CURL_TRC_CF(data, cf, "[%d] DRAIN closed stream", stream->id);
drain_stream(cf, data, stream);
Curl_multi_mark_dirty(data);
}
}
out:
result = h2_progress_egress(cf, data);
if(result == CURLE_AGAIN) {
r2 = h2_progress_egress(cf, data);
if(r2 == CURLE_AGAIN) {
/* pending data to send, need to be called again. Ideally, we
* monitor the socket for POLLOUT, but when not SENDING
* any more, we force processing of the transfer. */
if(!CURL_WANT_SEND(data))
drain_stream(cf, data, stream);
Curl_multi_mark_dirty(data);
}
else if(result) {
*err = result;
nread = -1;
else if(r2) {
result = r2;
}
CURL_TRC_CF(data, cf, "[%d] cf_recv(len=%zu) -> %zd %d, "
CURL_TRC_CF(data, cf, "[%d] cf_recv(len=%zu) -> %d, %zu, "
"window=%d/%d, connection %d/%d",
stream->id, len, nread, *err,
stream->id, len, result, *pnread,
nghttp2_session_get_stream_effective_recv_data_length(
ctx->h2, stream->id),
nghttp2_session_get_stream_effective_local_window_size(
@@ -2209,7 +2160,7 @@ out:
HTTP2_HUGE_WINDOW_SIZE);
CF_DATA_RESTORE(cf, save);
return nread;
return result;
}
static ssize_t cf_h2_body_send(struct Curl_cfilter *cf,
@@ -2219,7 +2170,7 @@ static ssize_t cf_h2_body_send(struct Curl_cfilter *cf,
CURLcode *err)
{
struct cf_h2_ctx *ctx = cf->ctx;
ssize_t nwritten;
size_t nwritten;
if(stream->closed) {
if(stream->resp_hds_complete) {
@@ -2241,11 +2192,11 @@ static ssize_t cf_h2_body_send(struct Curl_cfilter *cf,
return -1;
}
nwritten = Curl_bufq_write(&stream->sendbuf, buf, blen, err);
if(nwritten < 0)
*err = Curl_bufq_write(&stream->sendbuf, buf, blen, &nwritten);
if(*err)
return -1;
if(eos && (blen == (size_t)nwritten))
if(eos && (blen == nwritten))
stream->body_eos = TRUE;
if(eos || !Curl_bufq_is_empty(&stream->sendbuf)) {
@@ -2256,13 +2207,13 @@ static ssize_t cf_h2_body_send(struct Curl_cfilter *cf,
return -1;
}
}
return nwritten;
return (ssize_t)nwritten;
}
static ssize_t h2_submit(struct h2_stream_ctx **pstream,
struct Curl_cfilter *cf, struct Curl_easy *data,
const void *buf, size_t len,
bool eos, CURLcode *err)
static CURLcode h2_submit(struct h2_stream_ctx **pstream,
struct Curl_cfilter *cf, struct Curl_easy *data,
const void *buf, size_t len,
bool eos, size_t *pnwritten)
{
struct cf_h2_ctx *ctx = cf->ctx;
struct h2_stream_ctx *stream = NULL;
@@ -2274,36 +2225,34 @@ static ssize_t h2_submit(struct h2_stream_ctx **pstream,
int32_t stream_id;
nghttp2_priority_spec pri_spec;
ssize_t nwritten;
CURLcode result = CURLE_OK;
*pnwritten = 0;
Curl_dynhds_init(&h2_headers, 0, DYN_HTTP_REQUEST);
*err = http2_data_setup(cf, data, &stream);
if(*err) {
nwritten = -1;
result = http2_data_setup(cf, data, &stream);
if(result)
goto out;
}
nwritten = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, err);
nwritten = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, &result);
if(nwritten < 0)
goto out;
*pnwritten = (size_t)nwritten;
if(!stream->h1.done) {
/* need more data */
goto out;
}
DEBUGASSERT(stream->h1.req);
*err = Curl_http_req_to_h2(&h2_headers, stream->h1.req, data);
if(*err) {
nwritten = -1;
result = Curl_http_req_to_h2(&h2_headers, stream->h1.req, data);
if(result)
goto out;
}
/* no longer needed */
Curl_h1_req_parse_free(&stream->h1);
nva = Curl_dynhds_to_nva(&h2_headers, &nheader);
if(!nva) {
*err = CURLE_OUT_OF_MEMORY;
nwritten = -1;
result = CURLE_OUT_OF_MEMORY;
goto out;
}
@@ -2329,8 +2278,7 @@ static ssize_t h2_submit(struct h2_stream_ctx **pstream,
if(stream_id < 0) {
CURL_TRC_CF(data, cf, "send: nghttp2_submit_request error (%s)%u",
nghttp2_strerror(stream_id), stream_id);
*err = CURLE_SEND_ERROR;
nwritten = -1;
result = CURLE_SEND_ERROR;
goto out;
}
@@ -2357,48 +2305,46 @@ static ssize_t h2_submit(struct h2_stream_ctx **pstream,
stream->id = stream_id;
body = (const char *)buf + nwritten;
bodylen = len - nwritten;
body = (const char *)buf + *pnwritten;
bodylen = len - *pnwritten;
if(bodylen || eos) {
ssize_t n = cf_h2_body_send(cf, data, stream, body, bodylen, eos, err);
ssize_t n = cf_h2_body_send(cf, data, stream, body, bodylen, eos, &result);
if(n >= 0)
nwritten += n;
else if(*err == CURLE_AGAIN)
*err = CURLE_OK;
else if(*err != CURLE_AGAIN) {
*err = CURLE_SEND_ERROR;
nwritten = -1;
goto out;
*pnwritten += n;
else if(result == CURLE_AGAIN)
result = CURLE_OK;
else {
result = CURLE_SEND_ERROR;
}
}
out:
CURL_TRC_CF(data, cf, "[%d] submit -> %zd, %d",
stream ? stream->id : -1, nwritten, *err);
CURL_TRC_CF(data, cf, "[%d] submit -> %d, %zu",
stream ? stream->id : -1, result, *pnwritten);
Curl_safefree(nva);
*pstream = stream;
Curl_dynhds_free(&h2_headers);
return nwritten;
return result;
}
static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const void *buf, size_t len, bool eos,
CURLcode *err)
static CURLcode cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const void *buf, size_t len, bool eos,
size_t *pnwritten)
{
struct cf_h2_ctx *ctx = cf->ctx;
struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
struct cf_call_data save;
ssize_t nwritten;
CURLcode result;
CURLcode result = CURLE_OK, r2;
CF_DATA_SAVE(save, cf, data);
*pnwritten = 0;
if(!stream || stream->id == -1) {
nwritten = h2_submit(&stream, cf, data, buf, len, eos, err);
if(nwritten < 0) {
result = h2_submit(&stream, cf, data, buf, len, eos, pnwritten);
if(result)
goto out;
}
DEBUGASSERT(stream);
}
else if(stream->body_eos) {
@@ -2407,35 +2353,35 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
* to trigger flushing again.
* If this works, we report to have written `len` bytes. */
DEBUGASSERT(eos);
nwritten = cf_h2_body_send(cf, data, stream, buf, 0, eos, err);
nwritten = cf_h2_body_send(cf, data, stream, buf, 0, eos, &result);
CURL_TRC_CF(data, cf, "[%d] cf_body_send last CHUNK -> %zd, %d, eos=%d",
stream->id, nwritten, *err, eos);
stream->id, nwritten, result, eos);
if(nwritten < 0) {
goto out;
}
nwritten = len;
*pnwritten = len;
}
else {
nwritten = cf_h2_body_send(cf, data, stream, buf, len, eos, err);
nwritten = cf_h2_body_send(cf, data, stream, buf, len, eos, &result);
CURL_TRC_CF(data, cf, "[%d] cf_body_send(len=%zu) -> %zd, %d, eos=%d",
stream->id, len, nwritten, *err, eos);
stream->id, len, nwritten, result, eos);
if(nwritten >= 0)
*pnwritten = (size_t)nwritten;
}
/* Call the nghttp2 send loop and flush to write ALL buffered data,
* headers and/or request body completely out to the network */
result = h2_progress_egress(cf, data);
r2 = h2_progress_egress(cf, data);
/* if the stream has been closed in egress handling (nghttp2 does that
* when it does not like the headers, for example */
if(stream && stream->closed) {
infof(data, "stream %u closed", stream->id);
*err = CURLE_SEND_ERROR;
nwritten = -1;
result = CURLE_SEND_ERROR;
goto out;
}
else if(result && (result != CURLE_AGAIN)) {
*err = result;
nwritten = -1;
else if(r2 && (r2 != CURLE_AGAIN)) {
result = r2;
goto out;
}
@@ -2443,21 +2389,20 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
/* nghttp2 thinks this session is done. If the stream has not been
* closed, this is an error state for out transfer */
if(stream && stream->closed) {
nwritten = http2_handle_stream_close(cf, data, stream, err);
result = http2_handle_stream_close(cf, data, stream, pnwritten);
}
else {
CURL_TRC_CF(data, cf, "send: nothing to do in this session");
*err = CURLE_HTTP2;
nwritten = -1;
result = CURLE_HTTP2;
}
}
out:
if(stream) {
CURL_TRC_CF(data, cf, "[%d] cf_send(len=%zu) -> %zd, %d, "
CURL_TRC_CF(data, cf, "[%d] cf_send(len=%zu) -> %d, %zu, "
"eos=%d, h2 windows %d-%d (stream-conn), "
"buffers %zu-%zu (stream-conn)",
stream->id, len, nwritten, *err,
stream->id, len, result, *pnwritten,
stream->body_eos,
nghttp2_session_get_stream_remote_window_size(
ctx->h2, stream->id),
@@ -2466,14 +2411,14 @@ out:
Curl_bufq_len(&ctx->outbufq));
}
else {
CURL_TRC_CF(data, cf, "cf_send(len=%zu) -> %zd, %d, "
CURL_TRC_CF(data, cf, "cf_send(len=%zu) -> %d, %zu, "
"connection-window=%d, nw_send_buffer(%zu)",
len, nwritten, *err,
len, result, *pnwritten,
nghttp2_session_get_remote_window_size(ctx->h2),
Curl_bufq_len(&ctx->outbufq));
}
CF_DATA_RESTORE(cf, save);
return nwritten;
return result;
}
static CURLcode cf_h2_flush(struct Curl_cfilter *cf,
@@ -2716,8 +2661,7 @@ static CURLcode http2_data_pause(struct Curl_cfilter *cf,
* not. We may have already buffered and exhausted the new window
* by operating on things in flight during the handling of other
* transfers. */
drain_stream(cf, data, stream);
Curl_expire(data, 0, EXPIRE_RUN_NOW);
Curl_multi_mark_dirty(data);
}
CURL_TRC_CF(data, cf, "[%d] stream now %spaused", stream->id,
pause ? "" : "un");
@@ -2769,15 +2713,16 @@ static bool cf_h2_is_alive(struct Curl_cfilter *cf,
bool *input_pending)
{
struct cf_h2_ctx *ctx = cf->ctx;
CURLcode result;
bool alive;
struct cf_call_data save;
*input_pending = FALSE;
CF_DATA_SAVE(save, cf, data);
result = (ctx && ctx->h2 && http2_connisalive(cf, data, input_pending));
alive = (ctx && ctx->h2 && http2_connisalive(cf, data, input_pending));
CURL_TRC_CF(data, cf, "conn alive -> %d, input_pending=%d",
result, *input_pending);
alive, *input_pending);
CF_DATA_RESTORE(cf, save);
return result;
return alive;
}
static CURLcode cf_h2_keep_alive(struct Curl_cfilter *cf,
@@ -2805,7 +2750,7 @@ static CURLcode cf_h2_query(struct Curl_cfilter *cf,
DEBUGASSERT(pres1);
CF_DATA_SAVE(save, cf, data);
if(nghttp2_session_check_request_allowed(ctx->h2) == 0) {
if(!ctx->h2 || !nghttp2_session_check_request_allowed(ctx->h2)) {
/* the limit is what we have in use right now */
effective_max = CONN_ATTACHED(cf->conn);
}
@@ -2848,7 +2793,6 @@ struct Curl_cftype Curl_cft_nghttp2 = {
cf_h2_connect,
cf_h2_close,
cf_h2_shutdown,
Curl_cf_def_get_host,
cf_h2_adjust_pollset,
cf_h2_data_pending,
cf_h2_send,
@@ -3001,17 +2945,17 @@ CURLcode Curl_http2_upgrade(struct Curl_easy *data,
/* Remaining data from the protocol switch reply is already using
* the switched protocol, ie. HTTP/2. We add that to the network
* inbufq. */
ssize_t copied;
size_t copied;
copied = Curl_bufq_write(&ctx->inbufq,
(const unsigned char *)mem, nread, &result);
if(copied < 0) {
result = Curl_bufq_write(&ctx->inbufq,
(const unsigned char *)mem, nread, &copied);
if(result) {
failf(data, "error on copying HTTP Upgrade response: %d", result);
return CURLE_RECV_ERROR;
}
if((size_t)copied < nread) {
if(copied < nread) {
failf(data, "connection buffer size could not take all data "
"from HTTP Upgrade response header: copied=%zd, datalen=%zu",
"from HTTP Upgrade response header: copied=%zu, datalen=%zu",
copied, nread);
return CURLE_HTTP2;
}
+2 -2
View File
@@ -537,8 +537,8 @@ static int compare_func(const void *a, const void *b)
}
UNITTEST CURLcode canon_path(const char *q, size_t len,
struct dynbuf *new_path,
bool do_uri_encode)
struct dynbuf *new_path,
bool do_uri_encode)
{
CURLcode result = CURLE_OK;
+26 -18
View File
@@ -39,6 +39,20 @@
#include "curl_memory.h"
#include "memdebug.h"
static void http_auth_nego_reset(struct connectdata *conn,
struct negotiatedata *neg_ctx,
bool proxy)
{
if(proxy)
conn->proxy_negotiate_state = GSS_AUTHNONE;
else
conn->http_negotiate_state = GSS_AUTHNONE;
if(neg_ctx)
Curl_auth_cleanup_spnego(neg_ctx);
}
CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
bool proxy, const char *header)
{
@@ -62,7 +76,6 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
service = data->set.str[STRING_PROXY_SERVICE_NAME] ?
data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP";
host = conn->http_proxy.host.name;
neg_ctx = &conn->proxyneg;
state = conn->proxy_negotiate_state;
#else
return CURLE_NOT_BUILT_IN;
@@ -74,10 +87,13 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
service = data->set.str[STRING_SERVICE_NAME] ?
data->set.str[STRING_SERVICE_NAME] : "HTTP";
host = conn->host.name;
neg_ctx = &conn->negotiate;
state = conn->http_negotiate_state;
}
neg_ctx = Curl_auth_nego_get(conn, proxy);
if(!neg_ctx)
return CURLE_OUT_OF_MEMORY;
/* Not set means empty */
if(!userp)
userp = "";
@@ -94,12 +110,12 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
if(!len) {
if(state == GSS_AUTHSUCC) {
infof(data, "Negotiate auth restarted");
Curl_http_auth_cleanup_negotiate(conn);
http_auth_nego_reset(conn, neg_ctx, proxy);
}
else if(state != GSS_AUTHNONE) {
/* The server rejected our authentication and has not supplied any more
negotiation mechanisms */
Curl_http_auth_cleanup_negotiate(conn);
http_auth_nego_reset(conn, neg_ctx, proxy);
return CURLE_LOGIN_DENIED;
}
}
@@ -116,7 +132,7 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
result = Curl_ssl_get_channel_binding(
data, FIRSTSOCKET, &neg_ctx->channel_binding_data);
if(result) {
Curl_http_auth_cleanup_negotiate(conn);
http_auth_nego_reset(conn, neg_ctx, proxy);
return result;
}
}
@@ -134,7 +150,7 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
#endif
if(result)
Curl_http_auth_cleanup_negotiate(conn);
http_auth_nego_reset(conn, neg_ctx, proxy);
return result;
}
@@ -152,7 +168,6 @@ CURLcode Curl_output_negotiate(struct Curl_easy *data,
if(proxy) {
#ifndef CURL_DISABLE_PROXY
neg_ctx = &conn->proxyneg;
authp = &data->state.authproxy;
state = &conn->proxy_negotiate_state;
#else
@@ -160,10 +175,12 @@ CURLcode Curl_output_negotiate(struct Curl_easy *data,
#endif
}
else {
neg_ctx = &conn->negotiate;
authp = &data->state.authhost;
state = &conn->http_negotiate_state;
}
neg_ctx = Curl_auth_nego_get(conn, proxy);
if(!neg_ctx)
return CURLE_OUT_OF_MEMORY;
authp->done = FALSE;
@@ -184,7 +201,7 @@ CURLcode Curl_output_negotiate(struct Curl_easy *data,
if(neg_ctx->noauthpersist && *state == GSS_AUTHSUCC) {
infof(data, "Curl_output_negotiate, "
"no persistent authentication: cleanup existing context");
Curl_http_auth_cleanup_negotiate(conn);
http_auth_nego_reset(conn, neg_ctx, proxy);
}
if(!neg_ctx->context) {
result = Curl_input_negotiate(data, conn, proxy, "Negotiate");
@@ -249,13 +266,4 @@ CURLcode Curl_output_negotiate(struct Curl_easy *data,
return CURLE_OK;
}
void Curl_http_auth_cleanup_negotiate(struct connectdata *conn)
{
conn->http_negotiate_state = GSS_AUTHNONE;
conn->proxy_negotiate_state = GSS_AUTHNONE;
Curl_auth_cleanup_spnego(&conn->negotiate);
Curl_auth_cleanup_spnego(&conn->proxyneg);
}
#endif /* !CURL_DISABLE_HTTP && USE_SPNEGO */
-4
View File
@@ -34,10 +34,6 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
CURLcode Curl_output_negotiate(struct Curl_easy *data,
struct connectdata *conn, bool proxy);
void Curl_http_auth_cleanup_negotiate(struct connectdata *conn);
#else /* !CURL_DISABLE_HTTP && USE_SPNEGO */
#define Curl_http_auth_cleanup_negotiate(x)
#endif
#endif /* HEADER_CURL_HTTP_NEGOTIATE_H */
+13 -18
View File
@@ -60,17 +60,18 @@ CURLcode Curl_input_ntlm(struct Curl_easy *data,
header */
{
/* point to the correct struct with this */
struct ntlmdata *ntlm;
curlntlm *state;
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
ntlm = proxy ? &conn->proxyntlm : &conn->ntlm;
state = proxy ? &conn->proxy_ntlm_state : &conn->http_ntlm_state;
if(checkprefix("NTLM", header)) {
header += strlen("NTLM");
struct ntlmdata *ntlm = Curl_auth_ntlm_get(conn, proxy);
if(!ntlm)
return CURLE_FAILED_INIT;
header += strlen("NTLM");
curlx_str_passblanks(&header);
if(*header) {
unsigned char *hdr;
@@ -93,11 +94,11 @@ CURLcode Curl_input_ntlm(struct Curl_easy *data,
else {
if(*state == NTLMSTATE_LAST) {
infof(data, "NTLM auth restarted");
Curl_http_auth_cleanup_ntlm(conn);
Curl_auth_ntlm_remove(conn, proxy);
}
else if(*state == NTLMSTATE_TYPE3) {
infof(data, "NTLM handshake rejected");
Curl_http_auth_cleanup_ntlm(conn);
Curl_auth_ntlm_remove(conn, proxy);
*state = NTLMSTATE_NONE;
return CURLE_REMOTE_ACCESS_DENIED;
}
@@ -150,7 +151,6 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
service = data->set.str[STRING_PROXY_SERVICE_NAME] ?
data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP";
hostname = conn->http_proxy.host.name;
ntlm = &conn->proxyntlm;
state = &conn->proxy_ntlm_state;
authp = &data->state.authproxy;
#else
@@ -164,10 +164,12 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
service = data->set.str[STRING_SERVICE_NAME] ?
data->set.str[STRING_SERVICE_NAME] : "HTTP";
hostname = conn->host.name;
ntlm = &conn->ntlm;
state = &conn->http_ntlm_state;
authp = &data->state.authhost;
}
ntlm = Curl_auth_ntlm_get(conn, proxy);
if(!ntlm)
return CURLE_OUT_OF_MEMORY;
authp->done = FALSE;
/* not set means empty */
@@ -178,10 +180,10 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
passwdp = "";
#ifdef USE_WINDOWS_SSPI
if(!Curl_hSecDll) {
if(!Curl_pSecFn) {
/* not thread safe and leaks - use curl_global_init() to avoid */
CURLcode err = Curl_sspi_global_init();
if(!Curl_hSecDll)
if(!Curl_pSecFn)
return err;
}
#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
@@ -200,9 +202,8 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
case NTLMSTATE_TYPE1:
default: /* for the weird cases we (re)start here */
/* Create a type-1 message */
result = Curl_auth_create_ntlm_type1_message(data, userp, passwdp,
service, hostname,
ntlm, &ntlmmsg);
result = Curl_auth_create_ntlm_type1_message(data, userp, passwdp, service,
hostname, ntlm, &ntlmmsg);
if(!result) {
DEBUGASSERT(Curl_bufref_len(&ntlmmsg) != 0);
result = curlx_base64_encode((const char *) Curl_bufref_ptr(&ntlmmsg),
@@ -258,10 +259,4 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
return result;
}
void Curl_http_auth_cleanup_ntlm(struct connectdata *conn)
{
Curl_auth_cleanup_ntlm(&conn->ntlm);
Curl_auth_cleanup_ntlm(&conn->proxyntlm);
}
#endif /* !CURL_DISABLE_HTTP && USE_NTLM */
-4
View File
@@ -35,10 +35,6 @@ CURLcode Curl_input_ntlm(struct Curl_easy *data, bool proxy,
/* this is for creating NTLM header output */
CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy);
void Curl_http_auth_cleanup_ntlm(struct connectdata *conn);
#else /* !CURL_DISABLE_HTTP && USE_NTLM */
#define Curl_http_auth_cleanup_ntlm(x)
#endif
#endif /* HEADER_CURL_HTTP_NTLM_H */
+15 -17
View File
@@ -38,7 +38,6 @@
#include "cf-h1-proxy.h"
#include "cf-h2-proxy.h"
#include "connect.h"
#include "strcase.h"
#include "vtls/vtls.h"
#include "transfer.h"
#include "multiif.h"
@@ -53,7 +52,7 @@
static bool hd_name_eq(const char *n1, size_t n1len,
const char *n2, size_t n2len)
{
return (n1len == n2len) ? strncasecompare(n1, n2, n1len) : FALSE;
return (n1len == n2len) ? curl_strnequal(n1, n2, n1len) : FALSE;
}
static CURLcode dynhds_add_custom(struct Curl_easy *data,
@@ -383,21 +382,21 @@ out:
return result;
}
void Curl_cf_http_proxy_get_host(struct Curl_cfilter *cf,
struct Curl_easy *data,
const char **phost,
const char **pdisplay_host,
int *pport)
CURLcode Curl_cf_http_proxy_query(struct Curl_cfilter *cf,
struct Curl_easy *data,
int query, int *pres1, void *pres2)
{
(void)data;
if(!cf->connected) {
*phost = cf->conn->http_proxy.host.name;
*pdisplay_host = cf->conn->http_proxy.host.dispname;
*pport = (int)cf->conn->http_proxy.port;
}
else {
cf->next->cft->get_host(cf->next, data, phost, pdisplay_host, pport);
switch(query) {
case CF_QUERY_HOST_PORT:
*pres1 = (int)cf->conn->http_proxy.port;
*((const char **)pres2) = cf->conn->http_proxy.host.name;
return CURLE_OK;
default:
break;
}
return cf->next ?
cf->next->cft->query(cf->next, data, query, pres1, pres2) :
CURLE_UNKNOWN_OPTION;
}
static void http_proxy_cf_destroy(struct Curl_cfilter *cf,
@@ -443,7 +442,6 @@ struct Curl_cftype Curl_cft_http_proxy = {
http_proxy_cf_connect,
http_proxy_cf_close,
Curl_cf_def_shutdown,
Curl_cf_http_proxy_get_host,
Curl_cf_def_adjust_pollset,
Curl_cf_def_data_pending,
Curl_cf_def_send,
@@ -451,7 +449,7 @@ struct Curl_cftype Curl_cft_http_proxy = {
Curl_cf_def_cntrl,
Curl_cf_def_conn_is_alive,
Curl_cf_def_conn_keep_alive,
Curl_cf_def_query,
Curl_cf_http_proxy_query,
};
CURLcode Curl_cf_http_proxy_insert_after(struct Curl_cfilter *cf_at,
+4 -6
View File
@@ -48,18 +48,16 @@ CURLcode Curl_http_proxy_create_CONNECT(struct httpreq **preq,
/* Default proxy timeout in milliseconds */
#define PROXY_TIMEOUT (3600*1000)
void Curl_cf_http_proxy_get_host(struct Curl_cfilter *cf,
struct Curl_easy *data,
const char **phost,
const char **pdisplay_host,
int *pport);
CURLcode Curl_cf_http_proxy_query(struct Curl_cfilter *cf,
struct Curl_easy *data,
int query, int *pres1, void *pres2);
CURLcode Curl_cf_http_proxy_insert_after(struct Curl_cfilter *cf_at,
struct Curl_easy *data);
extern struct Curl_cftype Curl_cft_http_proxy;
#endif /* !CURL_DISABLE_PROXY && !CURL_DISABLE_HTTP */
#endif /* !CURL_DISABLE_PROXY && !CURL_DISABLE_HTTP */
#define IS_HTTPS_PROXY(t) (((t) == CURLPROXY_HTTPS) || \
((t) == CURLPROXY_HTTPS2))
+5 -6
View File
@@ -52,8 +52,7 @@
# include <inet.h>
#endif
#include "inet_ntop.h"
#include "strcase.h"
#include "curlx/inet_ntop.h"
#include "if2ip.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -117,7 +116,7 @@ if2ip_result_t Curl_if2ip(int af,
for(iface = head; iface != NULL; iface = iface->ifa_next) {
if(iface->ifa_addr) {
if(iface->ifa_addr->sa_family == af) {
if(strcasecompare(iface->ifa_name, interf)) {
if(curl_strequal(iface->ifa_name, interf)) {
void *addr;
const char *ip;
char scope[12] = "";
@@ -162,13 +161,13 @@ if2ip_result_t Curl_if2ip(int af,
addr =
&((struct sockaddr_in *)(void *)iface->ifa_addr)->sin_addr;
res = IF2IP_FOUND;
ip = Curl_inet_ntop(af, addr, ipstr, sizeof(ipstr));
ip = curlx_inet_ntop(af, addr, ipstr, sizeof(ipstr));
msnprintf(buf, buf_size, "%s%s", ip, scope);
break;
}
}
else if((res == IF2IP_NOT_FOUND) &&
strcasecompare(iface->ifa_name, interf)) {
curl_strequal(iface->ifa_name, interf)) {
res = IF2IP_AF_NOT_SUPPORTED;
}
}
@@ -235,7 +234,7 @@ if2ip_result_t Curl_if2ip(int af,
s = (struct sockaddr_in *)(void *)&req.ifr_addr;
memcpy(&in, &s->sin_addr, sizeof(in));
r = Curl_inet_ntop(s->sin_family, &in, buf, buf_size);
r = curlx_inet_ntop(s->sin_family, &in, buf, buf_size);
sclose(dummy);
if(!r)
+24 -31
View File
@@ -302,7 +302,7 @@ static bool imap_matchresp(const char *line, size_t len, const char *cmd)
/* Does the command name match and is it followed by a space character or at
the end of line? */
if(line + cmd_len <= end && strncasecompare(line, cmd, cmd_len) &&
if(line + cmd_len <= end && curl_strnequal(line, cmd, cmd_len) &&
(line[cmd_len] == ' ' || line + cmd_len + 2 == end))
return TRUE;
@@ -358,16 +358,16 @@ static bool imap_endofresp(struct Curl_easy *data, struct connectdata *conn,
case IMAP_LIST:
if((!imap->custom && !imap_matchresp(line, len, "LIST")) ||
(imap->custom && !imap_matchresp(line, len, imap->custom) &&
(!strcasecompare(imap->custom, "STORE") ||
(!curl_strequal(imap->custom, "STORE") ||
!imap_matchresp(line, len, "FETCH")) &&
!strcasecompare(imap->custom, "SELECT") &&
!strcasecompare(imap->custom, "EXAMINE") &&
!strcasecompare(imap->custom, "SEARCH") &&
!strcasecompare(imap->custom, "EXPUNGE") &&
!strcasecompare(imap->custom, "LSUB") &&
!strcasecompare(imap->custom, "UID") &&
!strcasecompare(imap->custom, "GETQUOTAROOT") &&
!strcasecompare(imap->custom, "NOOP")))
!curl_strequal(imap->custom, "SELECT") &&
!curl_strequal(imap->custom, "EXAMINE") &&
!curl_strequal(imap->custom, "SEARCH") &&
!curl_strequal(imap->custom, "EXPUNGE") &&
!curl_strequal(imap->custom, "LSUB") &&
!curl_strequal(imap->custom, "UID") &&
!curl_strequal(imap->custom, "GETQUOTAROOT") &&
!curl_strequal(imap->custom, "NOOP")))
return FALSE;
break;
@@ -1239,7 +1239,7 @@ static CURLcode imap_state_select_resp(struct Curl_easy *data,
else if(imapcode == IMAP_RESP_OK) {
/* Check if the UIDVALIDITY has been specified and matches */
if(imap->uidvalidity && imapc->mailbox_uidvalidity &&
!strcasecompare(imap->uidvalidity, imapc->mailbox_uidvalidity)) {
!curl_strequal(imap->uidvalidity, imapc->mailbox_uidvalidity)) {
failf(data, "Mailbox UIDVALIDITY has changed");
result = CURLE_REMOTE_FILE_NOT_FOUND;
}
@@ -1347,9 +1347,6 @@ static CURLcode imap_state_fetch_resp(struct Curl_easy *data,
else {
/* IMAP download */
data->req.maxdownload = size;
/* force a recv/send check of this connection, as the data might've been
read off the socket already */
data->state.select_bits = CURL_CSELECT_IN;
Curl_xfer_setup1(data, CURL_XFER_RECV, size, FALSE);
}
}
@@ -1693,9 +1690,9 @@ static CURLcode imap_perform(struct Curl_easy *data, bool *connected,
/* Determine if the requested mailbox (with the same UIDVALIDITY if set)
has already been selected on this connection */
if(imap->mailbox && imapc->mailbox &&
strcasecompare(imap->mailbox, imapc->mailbox) &&
curl_strequal(imap->mailbox, imapc->mailbox) &&
(!imap->uidvalidity || !imapc->mailbox_uidvalidity ||
strcasecompare(imap->uidvalidity, imapc->mailbox_uidvalidity)))
curl_strequal(imap->uidvalidity, imapc->mailbox_uidvalidity)))
selected = TRUE;
/* Start the first command in the DO phase */
@@ -1780,18 +1777,14 @@ static CURLcode imap_disconnect(struct Curl_easy *data,
(void)data;
if(imapc) {
/* We cannot send quit unconditionally. If this connection is stale or
bad in any way, sending quit and waiting around here will make the
bad in any way (pingpong has pending data to send),
sending quit and waiting around here will make the
disconnect wait in vain and cause more problems than we need to. */
/* The IMAP session may or may not have been allocated/setup at this
point! */
if(!dead_connection && conn->bits.protoconnstart) {
if(!dead_connection && conn->bits.protoconnstart &&
!Curl_pp_needs_flush(data, &imapc->pp)) {
if(!imap_perform_logout(data, imapc))
(void)imap_block_statemach(data, imapc, TRUE); /* ignore errors */
}
/* Cleanup the SASL module */
Curl_sasl_cleanup(conn, imapc->sasl.authused);
}
return CURLE_OK;
}
@@ -2079,12 +2072,12 @@ static CURLcode imap_parse_url_options(struct connectdata *conn,
while(*ptr && *ptr != ';')
ptr++;
if(strncasecompare(key, "AUTH=+LOGIN", 11)) {
if(curl_strnequal(key, "AUTH=+LOGIN", 11)) {
/* User prefers plaintext LOGIN over any SASL, including SASL LOGIN */
prefer_login = TRUE;
imapc->sasl.prefmech = SASL_AUTH_NONE;
}
else if(strncasecompare(key, "AUTH=", 5)) {
else if(curl_strnequal(key, "AUTH=", 5)) {
prefer_login = FALSE;
result = Curl_sasl_parse_url_auth_option(&imapc->sasl,
value, ptr - value);
@@ -2189,35 +2182,35 @@ static CURLcode imap_parse_url_path(struct Curl_easy *data,
PARTIAL) stripping of the trailing slash character if it is present.
Note: Unknown parameters trigger a URL_MALFORMAT error. */
if(strcasecompare(name, "UIDVALIDITY") && !imap->uidvalidity) {
if(curl_strequal(name, "UIDVALIDITY") && !imap->uidvalidity) {
if(valuelen > 0 && value[valuelen - 1] == '/')
value[valuelen - 1] = '\0';
imap->uidvalidity = value;
value = NULL;
}
else if(strcasecompare(name, "UID") && !imap->uid) {
else if(curl_strequal(name, "UID") && !imap->uid) {
if(valuelen > 0 && value[valuelen - 1] == '/')
value[valuelen - 1] = '\0';
imap->uid = value;
value = NULL;
}
else if(strcasecompare(name, "MAILINDEX") && !imap->mindex) {
else if(curl_strequal(name, "MAILINDEX") && !imap->mindex) {
if(valuelen > 0 && value[valuelen - 1] == '/')
value[valuelen - 1] = '\0';
imap->mindex = value;
value = NULL;
}
else if(strcasecompare(name, "SECTION") && !imap->section) {
else if(curl_strequal(name, "SECTION") && !imap->section) {
if(valuelen > 0 && value[valuelen - 1] == '/')
value[valuelen - 1] = '\0';
imap->section = value;
value = NULL;
}
else if(strcasecompare(name, "PARTIAL") && !imap->partial) {
else if(curl_strequal(name, "PARTIAL") && !imap->partial) {
if(valuelen > 0 && value[valuelen - 1] == '/')
value[valuelen - 1] = '\0';
+54 -54
View File
@@ -56,7 +56,6 @@
#include "transfer.h"
#include "curl_krb5.h"
#include "curlx/warnless.h"
#include "strcase.h"
#include "strdup.h"
/* The last 3 #include files should be in this order */
@@ -215,12 +214,14 @@ krb5_auth(void *app_data, struct Curl_easy *data, struct connectdata *conn)
gss_ctx_id_t *context = app_data;
struct gss_channel_bindings_struct chan;
size_t base64_sz = 0;
struct sockaddr_in *remote_addr =
(struct sockaddr_in *)CURL_UNCONST(&conn->remote_addr->curl_sa_addr);
const struct Curl_sockaddr_ex *remote_addr =
Curl_conn_get_remote_addr(data, FIRSTSOCKET);
struct sockaddr_in *remote_in_addr = remote_addr ?
(struct sockaddr_in *)CURL_UNCONST(&remote_addr->curl_sa_addr) : NULL;
char *stringp;
struct ftp_conn *ftpc = Curl_conn_meta_get(conn, CURL_META_FTP_CONN);
if(!ftpc)
if(!ftpc || !remote_in_addr)
return -2;
if(getsockname(conn->sock[FIRSTSOCKET],
@@ -232,7 +233,7 @@ krb5_auth(void *app_data, struct Curl_easy *data, struct connectdata *conn)
chan.initiator_address.value = &conn->local_addr.sin_addr.s_addr;
chan.acceptor_addrtype = GSS_C_AF_INET;
chan.acceptor_address.length = l - 4;
chan.acceptor_address.value = &remote_addr->sin_addr.s_addr;
chan.acceptor_address.value = &remote_in_addr->sin_addr.s_addr;
chan.application_data.length = 0;
chan.application_data.value = NULL;
@@ -384,7 +385,8 @@ static void krb5_end(void *app_data)
OM_uint32 min;
gss_ctx_id_t *context = app_data;
if(*context != GSS_C_NO_CONTEXT) {
OM_uint32 maj = gss_delete_sec_context(&min, context, GSS_C_NO_BUFFER);
OM_uint32 maj = Curl_gss_delete_sec_context(&min, context,
GSS_C_NO_BUFFER);
(void)maj;
DEBUGASSERT(maj == GSS_S_COMPLETE);
}
@@ -479,19 +481,18 @@ socket_read(struct Curl_easy *data, int sockindex, void *to, size_t len)
{
char *to_p = to;
CURLcode result;
ssize_t nread = 0;
size_t nread = 0;
while(len > 0) {
result = Curl_conn_recv(data, sockindex, to_p, len, &nread);
if(nread > 0) {
len -= nread;
to_p += nread;
}
else {
if(result == CURLE_AGAIN)
continue;
if(result == CURLE_AGAIN)
continue;
if(result)
return result;
}
if(nread > len)
return CURLE_RECV_ERROR;
len -= nread;
to_p += nread;
}
return CURLE_OK;
}
@@ -523,8 +524,8 @@ socket_write(struct Curl_easy *data, int sockindex, const void *to,
return CURLE_OK;
}
static CURLcode read_data(struct Curl_easy *data, int sockindex,
struct krb5buffer *buf)
static CURLcode krb5_read_data(struct Curl_easy *data, int sockindex,
struct krb5buffer *buf)
{
struct connectdata *conn = data->conn;
int len;
@@ -579,52 +580,49 @@ buffer_read(struct krb5buffer *buf, void *data, size_t len)
}
/* Matches Curl_recv signature */
static ssize_t sec_recv(struct Curl_easy *data, int sockindex,
char *buffer, size_t len, CURLcode *err)
static CURLcode sec_recv(struct Curl_easy *data, int sockindex,
char *buffer, size_t len, size_t *pnread)
{
size_t bytes_read;
size_t total_read = 0;
struct connectdata *conn = data->conn;
*err = CURLE_OK;
CURLcode result = CURLE_OK;
size_t bytes_read;
/* Handle clear text response. */
if(conn->sec_complete == 0 || conn->data_prot == PROT_CLEAR) {
ssize_t nread;
*err = Curl_conn_recv(data, sockindex, buffer, len, &nread);
return nread;
}
if(conn->sec_complete == 0 || conn->data_prot == PROT_CLEAR)
return Curl_conn_recv(data, sockindex, buffer, len, pnread);
if(conn->in_buffer.eof_flag) {
conn->in_buffer.eof_flag = 0;
return 0;
*pnread = 0;
return CURLE_OK;
}
bytes_read = buffer_read(&conn->in_buffer, buffer, len);
len -= bytes_read;
total_read += bytes_read;
buffer += bytes_read;
len -= bytes_read;
*pnread += bytes_read;
while(len > 0) {
if(read_data(data, sockindex, &conn->in_buffer))
return -1;
result = krb5_read_data(data, sockindex, &conn->in_buffer);
if(result)
return result;
if(curlx_dyn_len(&conn->in_buffer.buf) == 0) {
if(bytes_read > 0)
if(*pnread > 0)
conn->in_buffer.eof_flag = 1;
return bytes_read;
return result;
}
bytes_read = buffer_read(&conn->in_buffer, buffer, len);
len -= bytes_read;
total_read += bytes_read;
buffer += bytes_read;
len -= bytes_read;
*pnread += bytes_read;
}
return total_read;
return result;
}
/* Send |length| bytes from |from| to the |sockindex| socket taking care of
encoding and negotiating with the server. |from| can be NULL. */
static void do_sec_send(struct Curl_easy *data, struct connectdata *conn,
int sockindex, const char *from, int length)
int sockindex, const char *from, size_t length)
{
int bytes, htonl_bytes; /* 32-bit integers for htonl */
char *buffer = NULL;
@@ -642,8 +640,8 @@ static void do_sec_send(struct Curl_easy *data, struct connectdata *conn,
else
prot_level = conn->command_prot;
}
bytes = conn->mech->encode(conn->app_data, from, length, (int)prot_level,
(void **)&buffer);
bytes = conn->mech->encode(conn->app_data, from, (int)length,
(int)prot_level, (void **)&buffer);
if(!buffer || bytes <= 0)
return; /* error */
@@ -677,34 +675,36 @@ static void do_sec_send(struct Curl_easy *data, struct connectdata *conn,
free(buffer);
}
static ssize_t sec_write(struct Curl_easy *data, struct connectdata *conn,
int sockindex, const char *buffer, size_t length)
static CURLcode sec_write(struct Curl_easy *data, int sockindex,
const char *buffer, size_t length,
size_t *pnwritten)
{
ssize_t tx = 0, len = conn->buffer_size;
struct connectdata *conn = data->conn;
size_t len = conn->buffer_size;
*pnwritten = 0;
if(len <= 0)
len = length;
while(length) {
if(length < (size_t)len)
if(length < len)
len = length;
do_sec_send(data, conn, sockindex, buffer, curlx_sztosi(len));
/* WTF: this ignores all errors writing to the socket */
do_sec_send(data, conn, sockindex, buffer, len);
length -= len;
buffer += len;
tx += len;
*pnwritten += len;
}
return tx;
return CURLE_OK;
}
/* Matches Curl_send signature */
static ssize_t sec_send(struct Curl_easy *data, int sockindex,
const void *buffer, size_t len, bool eos,
CURLcode *err)
static CURLcode sec_send(struct Curl_easy *data, int sockindex,
const void *buffer, size_t len, bool eos,
size_t *pnwritten)
{
struct connectdata *conn = data->conn;
(void)eos; /* unused */
*err = CURLE_OK;
return sec_write(data, conn, sockindex, buffer, len);
return sec_write(data, sockindex, buffer, len, pnwritten);
}
int Curl_sec_read_msg(struct Curl_easy *data, struct connectdata *conn,

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