mirror of
https://github.com/Kitware/CMake.git
synced 2026-05-05 05:39:57 -05:00
Merge topic 'update-curl'
82ac700f78ci: Drop nightly job that builds CMake with vendored curl on macOS8d8283642acurl: Set build options the way we need for CMakec8f51c1d21Merge branch 'upstream-curl' into update-curl71e5adbcc9curl 2025-07-16 (cfbfb650)bf8360ddadcurl: 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:
@@ -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")
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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/*
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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 */
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -42,7 +42,6 @@
|
||||
#include "sigpipe.h"
|
||||
#include "connect.h"
|
||||
#include "select.h"
|
||||
#include "strcase.h"
|
||||
#include "curlx/strparse.h"
|
||||
#include "uint-table.h"
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
|
||||
#if defined(USE_CURL_NTLM_CORE) && \
|
||||
(defined(USE_GNUTLS) || \
|
||||
defined(USE_SECTRANSP) || \
|
||||
defined(USE_OS400CRYPTO) || \
|
||||
defined(USE_WIN32_CRYPTO))
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
|
||||
#if defined(USE_CURL_NTLM_CORE) && \
|
||||
(defined(USE_GNUTLS) || \
|
||||
defined(USE_SECTRANSP) || \
|
||||
defined(USE_OS400CRYPTO) || \
|
||||
defined(USE_WIN32_CRYPTO))
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)), \
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
*/
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
@@ -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! */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 *
|
||||
|
||||
@@ -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++;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
@@ -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
@@ -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
Reference in New Issue
Block a user