diff options
220 files changed, 3997 insertions, 2400 deletions
diff --git a/Help/command/try_compile.rst b/Help/command/try_compile.rst index 7830deb..cde3776 100644 --- a/Help/command/try_compile.rst +++ b/Help/command/try_compile.rst @@ -35,7 +35,11 @@ Try Compiling Source Files [COMPILE_DEFINITIONS <defs>...] [LINK_LIBRARIES <libs>...] [OUTPUT_VARIABLE <var>] - [COPY_FILE <fileName> [COPY_FILE_ERROR <var>]]) + [COPY_FILE <fileName> [COPY_FILE_ERROR <var>]] + [<LANG>_STANDARD <std>] + [<LANG>_STANDARD_REQUIRED <bool>] + [<LANG>_EXTENSIONS <bool>] + ) Try building an executable from one or more source files. The success or failure of the ``try_compile``, i.e. ``TRUE`` or ``FALSE`` respectively, is @@ -82,6 +86,18 @@ The options are: ``OUTPUT_VARIABLE <var>`` Store the output from the build process the given variable. +``<LANG>_STANDARD <std>`` + Specify the :prop_tgt:`C_STANDARD` or :prop_tgt:`CXX_STANDARD` + target property of the generated project. + +``<LANG>_STANDARD_REQUIRED <bool>`` + Specify the :prop_tgt:`C_STANDARD_REQUIRED` or + :prop_tgt:`CXX_STANDARD_REQUIRED` target property of the generated project. + +``<LANG>_EXTENSIONS <bool>`` + Specify the :prop_tgt:`C_EXTENSIONS` or :prop_tgt:`CXX_EXTENSIONS` + target property of the generated project. + In this version all files in ``<bindir>/CMakeFiles/CMakeTmp`` will be cleaned automatically. For debugging, ``--debug-trycompile`` can be passed to ``cmake`` to avoid this clean. However, multiple sequential @@ -119,3 +135,17 @@ the type of target used for the source file signature. Set the :variable:`CMAKE_TRY_COMPILE_PLATFORM_VARIABLES` variable to specify variables that must be propagated into the test project. This variable is meant for use only in toolchain files. + +If :policy:`CMP0067` is set to ``NEW``, or any of the ``<LANG>_STANDARD``, +``<LANG>_STANDARD_REQUIRED``, or ``<LANG>_EXTENSIONS`` options are used, +then the language standard variables are honored: + +* :variable:`CMAKE_C_STANDARD` +* :variable:`CMAKE_C_STANDARD_REQUIRED` +* :variable:`CMAKE_C_EXTENSIONS` +* :variable:`CMAKE_CXX_STANDARD` +* :variable:`CMAKE_CXX_STANDARD_REQUIRED` +* :variable:`CMAKE_CXX_EXTENSIONS` + +Their values are used to set the corresponding target properties in +the generated project (unless overridden by an explicit option). diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst index 0cfe983..3266958 100644 --- a/Help/manual/cmake-policies.7.rst +++ b/Help/manual/cmake-policies.7.rst @@ -51,6 +51,14 @@ The :variable:`CMAKE_MINIMUM_REQUIRED_VERSION` variable may also be used to determine whether to report an error on use of deprecated macros or functions. +Policies Introduced by CMake 3.8 +================================ + +.. toctree:: + :maxdepth: 1 + + CMP0067: Honor language standard in try_compile() source-file signature. </policy/CMP0067> + Policies Introduced by CMake 3.7 ================================ diff --git a/Help/manual/cmake-qt.7.rst b/Help/manual/cmake-qt.7.rst index 7827065..80b0f49 100644 --- a/Help/manual/cmake-qt.7.rst +++ b/Help/manual/cmake-qt.7.rst @@ -22,12 +22,11 @@ Qt 4 and Qt 5 may be used together in the same .. code-block:: cmake - cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR) + cmake_minimum_required(VERSION 3.8.0 FATAL_ERROR) project(Qt4And5) set(CMAKE_AUTOMOC ON) - set(CMAKE_INCLUDE_CURRENT_DIR ON) find_package(Qt5 COMPONENTS Widgets DBus REQUIRED) add_executable(publisher publisher.cpp) @@ -73,9 +72,12 @@ The ``moc`` command line will consume the :prop_tgt:`COMPILE_DEFINITIONS` and :prop_tgt:`INCLUDE_DIRECTORIES` target properties from the target it is being invoked for, and for the appropriate build configuration. -Generated ``moc_*.cpp`` and ``*.moc`` files are placed in the build directory -so it is convenient to set the :variable:`CMAKE_INCLUDE_CURRENT_DIR` -variable. The :prop_tgt:`AUTOMOC` target property may be pre-set for all +The generated ``moc_*.cpp`` and ``*.moc`` files are placed in the +``<CMAKE_CURRENT_BINARY_DIR>/<TARGETNAME>_autogen/include`` directory which is +automatically added to the target's :prop_tgt:`INCLUDE_DIRECTORIES`. +(This differs from CMake 3.7 and below; see their documentation for details.) + +The :prop_tgt:`AUTOMOC` target property may be pre-set for all following targets by setting the :variable:`CMAKE_AUTOMOC` variable. The :prop_tgt:`AUTOMOC_MOC_OPTIONS` target property may be populated to set options to pass to ``moc``. The :variable:`CMAKE_AUTOMOC_MOC_OPTIONS` @@ -94,10 +96,13 @@ If a preprocessor ``#include`` directive is found which matches ``ui_<basename>.h``, and a ``<basename>.ui`` file exists, then ``uic`` will be executed to generate the appropriate file. -Generated ``ui_*.h`` files are placed in the build directory so it is -convenient to set the :variable:`CMAKE_INCLUDE_CURRENT_DIR` variable. The -:prop_tgt:`AUTOUIC` target property may be pre-set for all following targets -by setting the :variable:`CMAKE_AUTOUIC` variable. The +The generated generated ``ui_*.h`` files are placed in the +``<CMAKE_CURRENT_BINARY_DIR>/<TARGETNAME>_autogen/include`` directory which is +automatically added to the target's :prop_tgt:`INCLUDE_DIRECTORIES`. +(This differs from CMake 3.7 and below; see their documentation for details.) + +The :prop_tgt:`AUTOUIC` target property may be pre-set for all following +targets by setting the :variable:`CMAKE_AUTOUIC` variable. The :prop_tgt:`AUTOUIC_OPTIONS` target property may be populated to set options to pass to ``uic``. The :variable:`CMAKE_AUTOUIC_OPTIONS` variable may be populated to pre-set the options for all following targets. The diff --git a/Help/policy/CMP0067.rst b/Help/policy/CMP0067.rst new file mode 100644 index 0000000..d52ba7f --- /dev/null +++ b/Help/policy/CMP0067.rst @@ -0,0 +1,34 @@ +CMP0067 +------- + +Honor language standard in :command:`try_compile` source-file signature. + +The :command:`try_compile` source file signature is intended to allow +callers to check whether they will be able to compile a given source file +with the current toolchain. In order to match compiler behavior, any +language standard mode should match. However, CMake 3.7 and below did not +do this. CMake 3.8 and above prefer to honor the language standard settings +for ``C`` and ``CXX`` (C++) using the values of the variables: + +* :variable:`CMAKE_C_STANDARD` +* :variable:`CMAKE_C_STANDARD_REQUIRED` +* :variable:`CMAKE_C_EXTENSIONS` +* :variable:`CMAKE_CXX_STANDARD` +* :variable:`CMAKE_CXX_STANDARD_REQUIRED` +* :variable:`CMAKE_CXX_EXTENSIONS` + +This policy provides compatibility for projects that do not expect +the language standard settings to be used automatically. + +The ``OLD`` behavior of this policy is to ignore language standard +setting variables when generating the ``try_compile`` test project. +The ``NEW`` behavior of this policy is to honor language standard +setting variables. + +This policy was introduced in CMake version 3.8. Unlike most policies, +CMake version |release| does *not* warn by default when this policy +is not set and simply uses OLD behavior. See documentation of the +:variable:`CMAKE_POLICY_WARNING_CMP0067 <CMAKE_POLICY_WARNING_CMP<NNNN>>` +variable to control the warning. + +.. include:: DEPRECATED.txt diff --git a/Help/prop_gbl/AUTOGEN_TARGETS_FOLDER.rst b/Help/prop_gbl/AUTOGEN_TARGETS_FOLDER.rst index 5a69ef3..fae5626 100644 --- a/Help/prop_gbl/AUTOGEN_TARGETS_FOLDER.rst +++ b/Help/prop_gbl/AUTOGEN_TARGETS_FOLDER.rst @@ -1,7 +1,7 @@ AUTOGEN_TARGETS_FOLDER ---------------------- -Name of :prop_tgt:`FOLDER` for ``*_automoc`` targets that are added automatically by +Name of :prop_tgt:`FOLDER` for ``*_autogen`` targets that are added automatically by CMake for targets for which :prop_tgt:`AUTOMOC` is enabled. If not set, CMake uses the :prop_tgt:`FOLDER` property of the parent target as a diff --git a/Help/prop_gbl/AUTOMOC_TARGETS_FOLDER.rst b/Help/prop_gbl/AUTOMOC_TARGETS_FOLDER.rst index 671f86a..17666e4 100644 --- a/Help/prop_gbl/AUTOMOC_TARGETS_FOLDER.rst +++ b/Help/prop_gbl/AUTOMOC_TARGETS_FOLDER.rst @@ -1,7 +1,7 @@ AUTOMOC_TARGETS_FOLDER ---------------------- -Name of :prop_tgt:`FOLDER` for ``*_automoc`` targets that are added automatically by +Name of :prop_tgt:`FOLDER` for ``*_autogen`` targets that are added automatically by CMake for targets for which :prop_tgt:`AUTOMOC` is enabled. This property is obsolete. Use :prop_gbl:`AUTOGEN_TARGETS_FOLDER` instead. diff --git a/Help/prop_gbl/CMAKE_CXX_KNOWN_FEATURES.rst b/Help/prop_gbl/CMAKE_CXX_KNOWN_FEATURES.rst index 00a5104..2ad8157 100644 --- a/Help/prop_gbl/CMAKE_CXX_KNOWN_FEATURES.rst +++ b/Help/prop_gbl/CMAKE_CXX_KNOWN_FEATURES.rst @@ -23,6 +23,9 @@ The features known to this version of CMake are: ``cxx_std_14`` Compiler mode is aware of C++ 14. +``cxx_std_17`` + Compiler mode is aware of C++ 17. + ``cxx_aggregate_default_initializers`` Aggregate default initializers, as defined in N3605_. diff --git a/Help/prop_tgt/AUTOGEN_TARGET_DEPENDS.rst b/Help/prop_tgt/AUTOGEN_TARGET_DEPENDS.rst index 5063244..f522c6b 100644 --- a/Help/prop_tgt/AUTOGEN_TARGET_DEPENDS.rst +++ b/Help/prop_tgt/AUTOGEN_TARGET_DEPENDS.rst @@ -1,16 +1,16 @@ AUTOGEN_TARGET_DEPENDS ---------------------- -Target dependencies of the corresponding ``_automoc`` target. +Target dependencies of the corresponding ``_autogen`` target. Targets which have their :prop_tgt:`AUTOMOC` target ``ON`` have a -corresponding ``_automoc`` target which is used to autogenerate generate moc -files. As this ``_automoc`` target is created at generate-time, it is not +corresponding ``_autogen`` target which is used to autogenerate generate moc +files. As this ``_autogen`` target is created at generate-time, it is not possible to define dependencies of it, such as to create inputs for the ``moc`` executable. The ``AUTOGEN_TARGET_DEPENDS`` target property can be set instead to a list of -dependencies for the ``_automoc`` target. The buildsystem will be generated to +dependencies for the ``_autogen`` target. The buildsystem will be generated to depend on its contents. See the :manual:`cmake-qt(7)` manual for more information on using CMake diff --git a/Help/prop_tgt/AUTOMOC.rst b/Help/prop_tgt/AUTOMOC.rst index 8143ba9..30a39b1 100644 --- a/Help/prop_tgt/AUTOMOC.rst +++ b/Help/prop_tgt/AUTOMOC.rst @@ -15,11 +15,12 @@ source files at build time and invoke moc accordingly. the ``Q_OBJECT`` class declaration is expected in the header, and ``moc`` is run on the header file. A ``moc_foo.cpp`` file will be generated from the source's header into the - :variable:`CMAKE_CURRENT_BINARY_DIR` directory. This allows the - compiler to find the included ``moc_foo.cpp`` file regardless of the - location the original source. However, if multiple source files - in different directories do this then their generated moc files would - collide. In this case a diagnostic will be issued. + ``<CMAKE_CURRENT_BINARY_DIR>/<TARGETNAME>_autogen/include`` + directory which is automatically added to the target's + :prop_tgt:`INCLUDE_DIRECTORIES`. This allows the compiler to find the + included ``moc_foo.cpp`` file regardless of the location the original source. + However, if multiple source files in different directories do this then their + generated moc files would collide. In this case a diagnostic will be issued. * If an ``#include`` statement like ``#include "foo.moc"`` is found, then a ``Q_OBJECT`` is expected in the current source file and ``moc`` @@ -30,7 +31,7 @@ source files at build time and invoke moc accordingly. alternative extensions, such as ``hpp``, ``hxx`` etc when searching for headers. The resulting moc files, which are not included as shown above in any of the source files are included in a generated - ``<targetname>_automoc.cpp`` file, which is compiled as part of the + ``moc_compilation.cpp`` file, which is compiled as part of the target. This property is initialized by the value of the :variable:`CMAKE_AUTOMOC` diff --git a/Help/prop_tgt/CXX_STANDARD.rst b/Help/prop_tgt/CXX_STANDARD.rst index 5b186c1..30a612d 100644 --- a/Help/prop_tgt/CXX_STANDARD.rst +++ b/Help/prop_tgt/CXX_STANDARD.rst @@ -8,7 +8,7 @@ to build this target. For some compilers, this results in adding a flag such as ``-std=gnu++11`` to the compile line. For compilers that have no notion of a standard level, such as MSVC, this has no effect. -Supported values are ``98``, ``11`` and ``14``. +Supported values are ``98``, ``11``, ``14``, and ``17``. If the value requested does not result in a compile flag being added for the compiler in use, a previous standard flag will be added instead. This diff --git a/Help/release/dev/FindOpenGL-imported-targets.rst b/Help/release/dev/FindOpenGL-imported-targets.rst new file mode 100644 index 0000000..79e3cb0 --- /dev/null +++ b/Help/release/dev/FindOpenGL-imported-targets.rst @@ -0,0 +1,5 @@ +FindOpenGL-imported-targets +--------------------------- + +* The :module:`FindOpenGL` module now provides imported targets + ``OpenGL::GL`` and ``OpenGL::GLU`` when the libraries are found. diff --git a/Help/release/dev/QtAutogen_Contain.rst b/Help/release/dev/QtAutogen_Contain.rst new file mode 100644 index 0000000..182233b --- /dev/null +++ b/Help/release/dev/QtAutogen_Contain.rst @@ -0,0 +1,10 @@ +QtAutogen_Contain +----------------- + +* When using AUTOMOC or AUTOUIC, generated + ``moc_*``, ``*.moc`` and ``ui_*`` are placed in the + ``<CMAKE_CURRENT_BINARY_DIR>/<TARGETNAME>_autogen/include`` directory which + is automatically added to the target's :prop_tgt:`INCLUDE_DIRECTORIES`. + It is therefore not necessary anymore to have + :variable:`CMAKE_CURRENT_BINARY_DIR` in the target's + :prop_tgt:`INCLUDE_DIRECTORIES`. diff --git a/Help/release/dev/cpack-rpm-user-file-list-with-multiple-directives.rst b/Help/release/dev/cpack-rpm-user-file-list-with-multiple-directives.rst new file mode 100644 index 0000000..ad0154d --- /dev/null +++ b/Help/release/dev/cpack-rpm-user-file-list-with-multiple-directives.rst @@ -0,0 +1,6 @@ +cpack-rpm-user-file-list-with-multiple-directives +------------------------------------------------- + +* The :module:`CPackRPM` module learned to support + multiple directives per file when using + :variable:`CPACK_RPM_USER_FILELIST` variable. diff --git a/Help/release/dev/features-c++17.rst b/Help/release/dev/features-c++17.rst new file mode 100644 index 0000000..9c28ddf --- /dev/null +++ b/Help/release/dev/features-c++17.rst @@ -0,0 +1,6 @@ +features-c++17 +-------------- + +* The :manual:`Compile Features <cmake-compile-features(7)>` functionality + is now aware of C++ 17. No specific features are yet enumerated besides + the ``cxx_std_17`` meta-feature. diff --git a/Help/release/dev/try_compile-lang-std.rst b/Help/release/dev/try_compile-lang-std.rst new file mode 100644 index 0000000..849cecc --- /dev/null +++ b/Help/release/dev/try_compile-lang-std.rst @@ -0,0 +1,9 @@ +try_compile-lang-std +-------------------- + +* The :command:`try_compile` command source file signature gained new options + to specify the language standard to use in the generated test project. + +* The :command:`try_compile` command source file signature now honors + language standard variables like :variable:`CMAKE_CXX_STANDARD`. + See policy :policy:`CMP0067`. diff --git a/Help/release/dev/wix-reg-install-dir.rst b/Help/release/dev/wix-reg-install-dir.rst new file mode 100644 index 0000000..961fad2 --- /dev/null +++ b/Help/release/dev/wix-reg-install-dir.rst @@ -0,0 +1,6 @@ +wix-reg-install-dir +------------------- + +* The precompiled Windows binary MSI package provided on ``cmake.org`` now + records the installation directory in the Windows Registry under the key + ``HKLM\Software\Kitware\CMake`` with a value named ``InstallDir``. diff --git a/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst b/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst index 36cf75f..aa23b65 100644 --- a/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst +++ b/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst @@ -17,6 +17,8 @@ warn by default: policy :policy:`CMP0065`. * ``CMAKE_POLICY_WARNING_CMP0066`` controls the warning for policy :policy:`CMP0066`. +* ``CMAKE_POLICY_WARNING_CMP0067`` controls the warning for + policy :policy:`CMP0067`. This variable should not be set by a project in CMake code. Project developers running CMake may set this variable in their cache to diff --git a/Modules/AutogenInfo.cmake.in b/Modules/AutogenInfo.cmake.in index 7d89420..84b0f4d 100644 --- a/Modules/AutogenInfo.cmake.in +++ b/Modules/AutogenInfo.cmake.in @@ -1,12 +1,11 @@ set(AM_SOURCES @_cpp_files@ ) -set(AM_RCC_SOURCES @_rcc_files@ ) -set(AM_RCC_INPUTS @_qt_rcc_inputs@) set(AM_SKIP_MOC @_skip_moc@ ) set(AM_SKIP_UIC @_skip_uic@ ) set(AM_HEADERS @_moc_headers@ ) set(AM_MOC_COMPILE_DEFINITIONS @_moc_compile_defs@) set(AM_MOC_INCLUDES @_moc_incs@) set(AM_MOC_OPTIONS @_moc_options@) +set(AM_MOC_RELAXED_MODE "@_moc_relaxed_mode@") set(AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE "@CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE@") set(AM_CMAKE_BINARY_DIR "@CMAKE_BINARY_DIR@/") set(AM_CMAKE_SOURCE_DIR "@CMAKE_SOURCE_DIR@/") @@ -18,9 +17,10 @@ set(AM_CMAKE_CURRENT_BINARY_DIR "@CMAKE_CURRENT_BINARY_DIR@/") set(AM_QT_VERSION_MAJOR "@_target_qt_version@") set(AM_TARGET_NAME @_moc_target_name@) set(AM_ORIGIN_TARGET_NAME @_origin_target_name@) -set(AM_RELAXED_MODE "@_moc_relaxed_mode@") set(AM_UIC_TARGET_OPTIONS @_uic_target_options@) set(AM_UIC_OPTIONS_FILES @_qt_uic_options_files@) set(AM_UIC_OPTIONS_OPTIONS @_qt_uic_options_options@) -set(AM_RCC_OPTIONS_FILES @_qt_rcc_options_files@) -set(AM_RCC_OPTIONS_OPTIONS @_qt_rcc_options_options@) +set(AM_RCC_SOURCES @_rcc_files@ ) +set(AM_RCC_INPUTS @_rcc_inputs@) +set(AM_RCC_OPTIONS_FILES @_rcc_options_files@) +set(AM_RCC_OPTIONS_OPTIONS @_rcc_options_options@) diff --git a/Modules/CMakeCUDACompilerId.cu.in b/Modules/CMakeCUDACompilerId.cu.in index 5fa85da..a20f1b1 100644 --- a/Modules/CMakeCUDACompilerId.cu.in +++ b/Modules/CMakeCUDACompilerId.cu.in @@ -14,7 +14,9 @@ char const* info_compiler = "INFO" ":" "compiler[" COMPILER_ID "]"; @CMAKE_CUDA_COMPILER_ID_ERROR_FOR_TEST@ const char* info_language_dialect_default = "INFO" ":" "dialect_default[" -#if __cplusplus >= 201402L +#if __cplusplus > 201402L + "17" +#elif __cplusplus >= 201402L "14" #elif __cplusplus >= 201103L "11" diff --git a/Modules/CMakeCXXCompiler.cmake.in b/Modules/CMakeCXXCompiler.cmake.in index c295b74..6d56488 100644 --- a/Modules/CMakeCXXCompiler.cmake.in +++ b/Modules/CMakeCXXCompiler.cmake.in @@ -8,6 +8,7 @@ set(CMAKE_CXX_COMPILE_FEATURES "@CMAKE_CXX_COMPILE_FEATURES@") set(CMAKE_CXX98_COMPILE_FEATURES "@CMAKE_CXX98_COMPILE_FEATURES@") set(CMAKE_CXX11_COMPILE_FEATURES "@CMAKE_CXX11_COMPILE_FEATURES@") set(CMAKE_CXX14_COMPILE_FEATURES "@CMAKE_CXX14_COMPILE_FEATURES@") +set(CMAKE_CXX17_COMPILE_FEATURES "@CMAKE_CXX17_COMPILE_FEATURES@") set(CMAKE_CXX_PLATFORM_ID "@CMAKE_CXX_PLATFORM_ID@") set(CMAKE_CXX_SIMULATE_ID "@CMAKE_CXX_SIMULATE_ID@") diff --git a/Modules/CMakeCXXCompilerId.cpp.in b/Modules/CMakeCXXCompilerId.cpp.in index 3e5c0fc..9aa096d 100644 --- a/Modules/CMakeCXXCompilerId.cpp.in +++ b/Modules/CMakeCXXCompilerId.cpp.in @@ -28,7 +28,9 @@ char const *info_cray = "INFO" ":" "compiler_wrapper[CrayPrgEnv]"; @CMAKE_CXX_COMPILER_ID_ERROR_FOR_TEST@ const char* info_language_dialect_default = "INFO" ":" "dialect_default[" -#if __cplusplus >= 201402L +#if __cplusplus > 201402L + "17" +#elif __cplusplus >= 201402L "14" #elif __cplusplus >= 201103L "11" diff --git a/Modules/CMakeDetermineASMCompiler.cmake b/Modules/CMakeDetermineASMCompiler.cmake index deb10fb..4162726 100644 --- a/Modules/CMakeDetermineASMCompiler.cmake +++ b/Modules/CMakeDetermineASMCompiler.cmake @@ -9,7 +9,13 @@ include(${CMAKE_ROOT}/Modules/CMakeDetermineCompiler.cmake) if(NOT CMAKE_ASM${ASM_DIALECT}_COMPILER) # prefer the environment variable ASM if(NOT $ENV{ASM${ASM_DIALECT}} STREQUAL "") - set(CMAKE_ASM${ASM_DIALECT}_COMPILER_INIT "$ENV{ASM${ASM_DIALECT}}") + get_filename_component(CMAKE_ASM${ASM_DIALECT}_COMPILER_INIT $ENV{ASM${ASM_DIALECT}} PROGRAM PROGRAM_ARGS CMAKE_ASM${ASM_DIALECT}_FLAGS_ENV_INIT) + if(CMAKE_ASM${ASM_DIALECT}_FLAGS_ENV_INIT) + set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ARG1 "${CMAKE_ASM${ASM_DIALECT}_FLAGS_ENV_INIT}" CACHE STRING "First argument to ASM${ASM_DIALECT} compiler") + endif() + if(NOT EXISTS ${CMAKE_ASM${ASM_DIALECT}_COMPILER_INIT}) + message(FATAL_ERROR "Could not find compiler set in environment variable ASM${ASM_DIALECT}:\n$ENV{ASM${ASM_DIALECT}}.") + endif() endif() # finally list compilers to try diff --git a/Modules/CMakeDetermineCompileFeatures.cmake b/Modules/CMakeDetermineCompileFeatures.cmake index 5ca72cc..3ed92be 100644 --- a/Modules/CMakeDetermineCompileFeatures.cmake +++ b/Modules/CMakeDetermineCompileFeatures.cmake @@ -48,6 +48,7 @@ function(cmake_determine_compile_features lang) set(CMAKE_CXX98_COMPILE_FEATURES) set(CMAKE_CXX11_COMPILE_FEATURES) set(CMAKE_CXX14_COMPILE_FEATURES) + set(CMAKE_CXX17_COMPILE_FEATURES) include("${CMAKE_ROOT}/Modules/Internal/FeatureTesting.cmake") @@ -58,6 +59,9 @@ function(cmake_determine_compile_features lang) return() endif() + if (CMAKE_CXX14_COMPILE_FEATURES AND CMAKE_CXX17_COMPILE_FEATURES) + list(REMOVE_ITEM CMAKE_CXX17_COMPILE_FEATURES ${CMAKE_CXX14_COMPILE_FEATURES}) + endif() if (CMAKE_CXX11_COMPILE_FEATURES AND CMAKE_CXX14_COMPILE_FEATURES) list(REMOVE_ITEM CMAKE_CXX14_COMPILE_FEATURES ${CMAKE_CXX11_COMPILE_FEATURES}) endif() @@ -70,6 +74,7 @@ function(cmake_determine_compile_features lang) ${CMAKE_CXX98_COMPILE_FEATURES} ${CMAKE_CXX11_COMPILE_FEATURES} ${CMAKE_CXX14_COMPILE_FEATURES} + ${CMAKE_CXX17_COMPILE_FEATURES} ) endif() @@ -77,6 +82,7 @@ function(cmake_determine_compile_features lang) set(CMAKE_CXX98_COMPILE_FEATURES ${CMAKE_CXX98_COMPILE_FEATURES} PARENT_SCOPE) set(CMAKE_CXX11_COMPILE_FEATURES ${CMAKE_CXX11_COMPILE_FEATURES} PARENT_SCOPE) set(CMAKE_CXX14_COMPILE_FEATURES ${CMAKE_CXX14_COMPILE_FEATURES} PARENT_SCOPE) + set(CMAKE_CXX17_COMPILE_FEATURES ${CMAKE_CXX17_COMPILE_FEATURES} PARENT_SCOPE) message(STATUS "Detecting ${lang} compile features - done") endif() diff --git a/Modules/CPackDeb.cmake b/Modules/CPackDeb.cmake index 909a12b..bee69d9 100644 --- a/Modules/CPackDeb.cmake +++ b/Modules/CPackDeb.cmake @@ -587,12 +587,21 @@ function(cpack_deb_prepare_package_vars) file(GLOB_RECURSE FILE_PATHS_ LIST_DIRECTORIES false RELATIVE "${WDIR}" "${WDIR}/*") cmake_policy(POP) + find_program(FILE_EXECUTABLE file) + if(NOT FILE_EXECUTABLE) + message(FATAL_ERROR "CPackDeb: file utility is not available. CPACK_DEBIAN_PACKAGE_SHLIBDEPS and CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS options are not available.") + endif() + # get file info so that we can determine if file is executable or not unset(CPACK_DEB_INSTALL_FILES) foreach(FILE_ IN LISTS FILE_PATHS_) - execute_process(COMMAND file "./${FILE_}" + execute_process(COMMAND env LC_ALL=C ${FILE_EXECUTABLE} "./${FILE_}" WORKING_DIRECTORY "${WDIR}" + RESULT_VARIABLE FILE_RESULT_ OUTPUT_VARIABLE INSTALL_FILE_) + if(NOT FILE_RESULT_ EQUAL 0) + message (FATAL_ERROR "CPackDeb: execution of command: '${FILE_EXECUTABLE} ./${FILE_}' failed with exit code: ${FILE_RESULT_}") + endif() list(APPEND CPACK_DEB_INSTALL_FILES "${INSTALL_FILE_}") endforeach() diff --git a/Modules/CPackRPM.cmake b/Modules/CPackRPM.cmake index 39697f0..5021c41 100644 --- a/Modules/CPackRPM.cmake +++ b/Modules/CPackRPM.cmake @@ -507,10 +507,12 @@ # # May be used to explicitly specify ``%(<directive>)`` file line # in the spec file. Like ``%config(noreplace)`` or any other directive -# that be found in the ``%files`` section. Since CPackRPM is generating -# the list of files (and directories) the user specified files of -# the ``CPACK_RPM_<COMPONENT>_USER_FILELIST`` list will be removed from -# the generated list. +# that be found in the ``%files`` section. You can have multiple directives +# per line, as in ``%attr(600,root,root) %config(noreplace)``. Since +# CPackRPM is generating the list of files (and directories) the user +# specified files of the ``CPACK_RPM_<COMPONENT>_USER_FILELIST`` list will +# be removed from the generated list. If referring to directories do +# not add a trailing slash. # # .. variable:: CPACK_RPM_CHANGELOG_FILE # @@ -2055,7 +2057,8 @@ function(cpack_rpm_generate_package) set(CPACK_RPM_USER_INSTALL_FILES "") foreach(F IN LISTS CPACK_RPM_USER_FILELIST_INTERNAL) string(REGEX REPLACE "%[A-Za-z]+(\\([^()]*\\))? " "" F_PATH ${F}) - string(REGEX MATCH "%[A-Za-z]+(\\([^()]*\\))?" F_PREFIX ${F}) + string(REGEX MATCH "(%[A-Za-z]+(\\([^()]*\\))? )*" F_PREFIX ${F}) + string(STRIP ${F_PREFIX} F_PREFIX) if(CPACK_RPM_PACKAGE_DEBUG) message("CPackRPM:Debug: F_PREFIX=<${F_PREFIX}>, F_PATH=<${F_PATH}>") diff --git a/Modules/Compiler/AppleClang-C.cmake b/Modules/Compiler/AppleClang-C.cmake index fe39b3b..f874e74 100644 --- a/Modules/Compiler/AppleClang-C.cmake +++ b/Modules/Compiler/AppleClang-C.cmake @@ -27,7 +27,9 @@ endif() macro(cmake_record_c_compile_features) set(_result 0) if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.0) - _record_compiler_features_c(11) + if (_result EQUAL 0) + _record_compiler_features_c(11) + endif() if (_result EQUAL 0) _record_compiler_features_c(99) endif() diff --git a/Modules/Compiler/AppleClang-CXX.cmake b/Modules/Compiler/AppleClang-CXX.cmake index 8dd6278..ee900ae 100644 --- a/Modules/Compiler/AppleClang-CXX.cmake +++ b/Modules/Compiler/AppleClang-CXX.cmake @@ -22,6 +22,11 @@ elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.1) set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std=gnu++1y") endif() +if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.1) + set(CMAKE_CXX17_STANDARD_COMPILE_OPTION "-std=c++1z") + set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION "-std=gnu++1z") +endif() + if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.0) if (NOT CMAKE_CXX_COMPILER_FORCED) if (NOT CMAKE_CXX_STANDARD_COMPUTED_DEFAULT) @@ -38,8 +43,10 @@ endif() macro(cmake_record_cxx_compile_features) set(_result 0) if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.0) - set(_result 0) - if(CMAKE_CXX14_STANDARD_COMPILE_OPTION) + if(_result EQUAL 0 AND CMAKE_CXX17_STANDARD_COMPILE_OPTION) + _record_compiler_features_cxx(17) + endif() + if(_result EQUAL 0 AND CMAKE_CXX14_STANDARD_COMPILE_OPTION) _record_compiler_features_cxx(14) endif() if (_result EQUAL 0) diff --git a/Modules/Compiler/Clang-C.cmake b/Modules/Compiler/Clang-C.cmake index b3f3805..bcd9218 100644 --- a/Modules/Compiler/Clang-C.cmake +++ b/Modules/Compiler/Clang-C.cmake @@ -36,7 +36,9 @@ endif() macro(cmake_record_c_compile_features) set(_result 0) if (UNIX AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.4) - _record_compiler_features_c(11) + if (_result EQUAL 0) + _record_compiler_features_c(11) + endif() if (_result EQUAL 0) _record_compiler_features_c(99) endif() diff --git a/Modules/Compiler/Clang-CXX.cmake b/Modules/Compiler/Clang-CXX.cmake index dfe0628..d0e2521 100644 --- a/Modules/Compiler/Clang-CXX.cmake +++ b/Modules/Compiler/Clang-CXX.cmake @@ -31,6 +31,11 @@ elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.4) set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std=gnu++1y") endif() +if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.5) + set(CMAKE_CXX17_STANDARD_COMPILE_OPTION "-std=c++1z") + set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION "-std=gnu++1z") +endif() + if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.4) if (NOT CMAKE_CXX_COMPILER_FORCED) if (NOT CMAKE_CXX_STANDARD_COMPUTED_DEFAULT) @@ -46,7 +51,12 @@ endif() macro(cmake_record_cxx_compile_features) set(_result 0) if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.4) - _record_compiler_features_cxx(14) + if(_result EQUAL 0 AND CMAKE_CXX17_STANDARD_COMPILE_OPTION) + _record_compiler_features_cxx(17) + endif() + if(_result EQUAL 0 AND CMAKE_CXX14_STANDARD_COMPILE_OPTION) + _record_compiler_features_cxx(14) + endif() if (_result EQUAL 0) _record_compiler_features_cxx(11) endif() diff --git a/Modules/Compiler/GNU-C.cmake b/Modules/Compiler/GNU-C.cmake index 4dbf6ef..05c3bb2 100644 --- a/Modules/Compiler/GNU-C.cmake +++ b/Modules/Compiler/GNU-C.cmake @@ -41,10 +41,10 @@ endif() macro(cmake_record_c_compile_features) set(_result 0) - if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.6) - _record_compiler_features_c(11) - endif() if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.4) + if(_result EQUAL 0 AND CMAKE_C11_STANDARD_COMPILE_OPTION) + _record_compiler_features_c(11) + endif() if (_result EQUAL 0) _record_compiler_features_c(99) endif() diff --git a/Modules/Compiler/GNU-CXX.cmake b/Modules/Compiler/GNU-CXX.cmake index 936f62b..b04ea11 100644 --- a/Modules/Compiler/GNU-CXX.cmake +++ b/Modules/Compiler/GNU-CXX.cmake @@ -34,6 +34,11 @@ elseif (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8) set(CMAKE_CXX14_EXTENSION_COMPILE_OPTION "-std=gnu++1y") endif() +if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.1) + set(CMAKE_CXX17_STANDARD_COMPILE_OPTION "-std=c++1z") + set(CMAKE_CXX17_EXTENSION_COMPILE_OPTION "-std=gnu++1z") +endif() + if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.4) if (NOT CMAKE_CXX_COMPILER_FORCED) if (NOT CMAKE_CXX_STANDARD_COMPUTED_DEFAULT) @@ -48,10 +53,13 @@ endif() macro(cmake_record_cxx_compile_features) set(_result 0) - if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8) - _record_compiler_features_cxx(14) - endif() if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.4) + if(_result EQUAL 0 AND CMAKE_CXX17_STANDARD_COMPILE_OPTION) + _record_compiler_features_cxx(17) + endif() + if(_result EQUAL 0 AND CMAKE_CXX14_STANDARD_COMPILE_OPTION) + _record_compiler_features_cxx(14) + endif() if (_result EQUAL 0) _record_compiler_features_cxx(11) endif() diff --git a/Modules/Compiler/Intel-C.cmake b/Modules/Compiler/Intel-C.cmake index 5a79452..6408392 100644 --- a/Modules/Compiler/Intel-C.cmake +++ b/Modules/Compiler/Intel-C.cmake @@ -49,7 +49,7 @@ unset(_ext) macro(cmake_record_c_compile_features) set(_result 0) if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 12.1) - if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 15.0.0) + if (_result EQUAL 0 AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 15.0.0) _record_compiler_features_C(11) endif() if (_result EQUAL 0) diff --git a/Modules/Compiler/Intel-CXX.cmake b/Modules/Compiler/Intel-CXX.cmake index d01d38d..9c39236 100644 --- a/Modules/Compiler/Intel-CXX.cmake +++ b/Modules/Compiler/Intel-CXX.cmake @@ -66,9 +66,10 @@ unset(_ext) macro(cmake_record_cxx_compile_features) set(_result 0) if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 12.1) - if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 16.0 - OR (NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC" AND - NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15.0)) + if (_result EQUAL 0 AND + (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 16.0 + OR (NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC" AND + NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15.0))) _record_compiler_features_cxx(14) endif() if (_result EQUAL 0) diff --git a/Modules/Compiler/MSVC-CXX.cmake b/Modules/Compiler/MSVC-CXX.cmake index f103832..8fcfa0f 100644 --- a/Modules/Compiler/MSVC-CXX.cmake +++ b/Modules/Compiler/MSVC-CXX.cmake @@ -10,6 +10,7 @@ macro(cmake_record_cxx_compile_features) cxx_std_98 cxx_std_11 cxx_std_14 + cxx_std_17 ) _record_compiler_features(CXX "" CMAKE_CXX_COMPILE_FEATURES) endif() diff --git a/Modules/Compiler/SunPro-CXX.cmake b/Modules/Compiler/SunPro-CXX.cmake index e83c896..f4345b8 100644 --- a/Modules/Compiler/SunPro-CXX.cmake +++ b/Modules/Compiler/SunPro-CXX.cmake @@ -53,7 +53,9 @@ endif() macro(cmake_record_cxx_compile_features) set(_result 0) if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.13) - _record_compiler_features_cxx(11) + if (_result EQUAL 0) + _record_compiler_features_cxx(11) + endif() if (_result EQUAL 0) _record_compiler_features_cxx(98) endif() diff --git a/Modules/FindBoost.cmake b/Modules/FindBoost.cmake index 9bd7a30..e6bf3dc 100644 --- a/Modules/FindBoost.cmake +++ b/Modules/FindBoost.cmake @@ -427,7 +427,9 @@ function(_Boost_GUESS_COMPILER_PREFIX _ret) elseif (GHSMULTI) set(_boost_COMPILER "-ghs") elseif("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC") - if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19) + if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.10) + set(_boost_COMPILER "-vc150") + elseif (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19) set(_boost_COMPILER "-vc140") elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 18) set(_boost_COMPILER "-vc120") @@ -882,7 +884,9 @@ macro(_Boost_UPDATE_LIBRARY_SEARCH_DIRS_WITH_PREBUILT_PATHS componentlibvar base else() set(_arch_suffix 32) endif() - if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19) + if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.10) + list(APPEND ${componentlibvar} ${${basedir}}/lib${_arch_suffix}-msvc-15.0) + elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19) list(APPEND ${componentlibvar} ${${basedir}}/lib${_arch_suffix}-msvc-14.0) elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 18) list(APPEND ${componentlibvar} ${${basedir}}/lib${_arch_suffix}-msvc-12.0) diff --git a/Modules/FindOpenGL.cmake b/Modules/FindOpenGL.cmake index 295de65..503d955 100644 --- a/Modules/FindOpenGL.cmake +++ b/Modules/FindOpenGL.cmake @@ -7,6 +7,16 @@ # # FindModule for OpenGL and GLU. # +# IMPORTED Targets +# ^^^^^^^^^^^^^^^^ +# +# This module defines the :prop_tgt:`IMPORTED` targets: +# +# ``OpenGL::GL`` +# Defined if the system has OpenGL. +# ``OpenGL::GLU`` +# Defined if the system has GLU. +# # Result Variables # ^^^^^^^^^^^^^^^^ # @@ -160,6 +170,55 @@ include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) FIND_PACKAGE_HANDLE_STANDARD_ARGS(OpenGL REQUIRED_VARS ${_OpenGL_REQUIRED_VARS}) unset(_OpenGL_REQUIRED_VARS) +# OpenGL:: targets +if(OPENGL_FOUND) + if(NOT TARGET OpenGL::GL) + if(IS_ABSOLUTE "${OPENGL_gl_LIBRARY}") + add_library(OpenGL::GL UNKNOWN IMPORTED) + if(OPENGL_gl_LIBRARY MATCHES "/([^/]+)\\.framework$") + set(_gl_fw "${OPENGL_gl_LIBRARY}/${CMAKE_MATCH_1}") + if(EXISTS "${_gl_fw}.tbd") + set(_gl_fw "${_gl_fw}.tbd") + endif() + set_target_properties(OpenGL::GL PROPERTIES + IMPORTED_LOCATION "${_gl_fw}") + else() + set_target_properties(OpenGL::GL PROPERTIES + IMPORTED_LOCATION "${OPENGL_gl_LIBRARY}") + endif() + else() + add_library(OpenGL::GL INTERFACE IMPORTED) + set_target_properties(OpenGL::GL PROPERTIES + IMPORTED_LIBNAME "${OPENGL_gl_LIBRARY}") + endif() + set_target_properties(OpenGL::GL PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${OPENGL_INCLUDE_DIR}") + endif() + + if(OPENGL_GLU_FOUND AND NOT TARGET OpenGL::GLU) + if(IS_ABSOLUTE "${OPENGL_glu_LIBRARY}") + add_library(OpenGL::GLU UNKNOWN IMPORTED) + if(OPENGL_glu_LIBRARY MATCHES "/([^/]+)\\.framework$") + set(_glu_fw "${OPENGL_glu_LIBRARY}/${CMAKE_MATCH_1}") + if(EXISTS "${_glu_fw}.tbd") + set(_glu_fw "${_glu_fw}.tbd") + endif() + set_target_properties(OpenGL::GLU PROPERTIES + IMPORTED_LOCATION "${_glu_fw}") + else() + set_target_properties(OpenGL::GLU PROPERTIES + IMPORTED_LOCATION "${OPENGL_glu_LIBRARY}") + endif() + else() + add_library(OpenGL::GLU INTERFACE IMPORTED) + set_target_properties(OpenGL::GLU PROPERTIES + IMPORTED_LIBNAME "${OPENGL_glu_LIBRARY}") + endif() + set_target_properties(OpenGL::GLU PROPERTIES + INTERFACE_LINK_LIBRARIES OpenGL::GL) + endif() +endif() + mark_as_advanced( OPENGL_INCLUDE_DIR OPENGL_xmesa_INCLUDE_DIR diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 5b381b4..d15fdbe 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -243,8 +243,8 @@ set(SRCS cmFileLockPool.h cmFileLockResult.cxx cmFileLockResult.h - cmFilePathUuid.cxx - cmFilePathUuid.h + cmFilePathChecksum.cxx + cmFilePathChecksum.h cmFileTimeComparison.cxx cmFileTimeComparison.h cmFortranLexer.cxx diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 124aa29..d484bee 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 7) -set(CMake_VERSION_PATCH 20161203) +set(CMake_VERSION_PATCH 20161212) #set(CMake_VERSION_RC 1) diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx index ab43dbc..68f9a54 100644 --- a/Source/CTest/cmCTestTestHandler.cxx +++ b/Source/CTest/cmCTestTestHandler.cxx @@ -797,8 +797,9 @@ void cmCTestTestHandler::UpdateForFixtures(ListOfTests& tests) const // Prepare some maps to help us find setup and cleanup tests for // any given fixture - typedef std::set<ListOfTests::const_iterator> TestIteratorSet; - typedef std::map<std::string, TestIteratorSet> FixtureDependencies; + typedef ListOfTests::const_iterator TestIterator; + typedef std::multimap<std::string, TestIterator> FixtureDependencies; + typedef FixtureDependencies::const_iterator FixtureDepsIterator; FixtureDependencies fixtureSetups; FixtureDependencies fixtureDeps; @@ -809,14 +810,14 @@ void cmCTestTestHandler::UpdateForFixtures(ListOfTests& tests) const const std::set<std::string>& setups = p.FixturesSetup; for (std::set<std::string>::const_iterator depsIt = setups.begin(); depsIt != setups.end(); ++depsIt) { - fixtureSetups[*depsIt].insert(it); - fixtureDeps[*depsIt].insert(it); + fixtureSetups.insert(std::make_pair(*depsIt, it)); + fixtureDeps.insert(std::make_pair(*depsIt, it)); } const std::set<std::string>& cleanups = p.FixturesCleanup; for (std::set<std::string>::const_iterator depsIt = cleanups.begin(); depsIt != cleanups.end(); ++depsIt) { - fixtureDeps[*depsIt].insert(it); + fixtureDeps.insert(std::make_pair(*depsIt, it)); } } @@ -859,17 +860,15 @@ void cmCTestTestHandler::UpdateForFixtures(ListOfTests& tests) const // associated with the required fixture. If any of those setup // tests fail, this test should not run. We make the fixture's // cleanup tests depend on this test case later. - FixtureDependencies::const_iterator setupIt = - fixtureSetups.find(requiredFixtureName); - if (setupIt != fixtureSetups.end()) { - for (TestIteratorSet::const_iterator sIt = setupIt->second.begin(); - sIt != setupIt->second.end(); ++sIt) { - const std::string& setupTestName = (**sIt).Name; - tests[i].RequireSuccessDepends.insert(setupTestName); - if (std::find(tests[i].Depends.begin(), tests[i].Depends.end(), - setupTestName) == tests[i].Depends.end()) { - tests[i].Depends.push_back(setupTestName); - } + std::pair<FixtureDepsIterator, FixtureDepsIterator> setupRange = + fixtureSetups.equal_range(requiredFixtureName); + for (FixtureDepsIterator sIt = setupRange.first; + sIt != setupRange.second; ++sIt) { + const std::string& setupTestName = sIt->second->Name; + tests[i].RequireSuccessDepends.insert(setupTestName); + if (std::find(tests[i].Depends.begin(), tests[i].Depends.end(), + setupTestName) == tests[i].Depends.end()) { + tests[i].Depends.push_back(setupTestName); } } @@ -882,17 +881,11 @@ void cmCTestTestHandler::UpdateForFixtures(ListOfTests& tests) const // Already added this fixture continue; } - FixtureDependencies::const_iterator fixtureIt = - fixtureDeps.find(requiredFixtureName); - if (fixtureIt == fixtureDeps.end()) { - // No setup or cleanup tests for this fixture - continue; - } - - const TestIteratorSet& testIters = fixtureIt->second; - for (TestIteratorSet::const_iterator depsIt = testIters.begin(); - depsIt != testIters.end(); ++depsIt) { - ListOfTests::const_iterator lotIt = *depsIt; + std::pair<FixtureDepsIterator, FixtureDepsIterator> fixtureRange = + fixtureDeps.equal_range(requiredFixtureName); + for (FixtureDepsIterator it = fixtureRange.first; + it != fixtureRange.second; ++it) { + ListOfTests::const_iterator lotIt = it->second; const cmCTestTestProperties& p = *lotIt; if (!addedTests.insert(p.Name).second) { diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx index fbad778..1b7180c 100644 --- a/Source/cmCoreTryCompile.cxx +++ b/Source/cmCoreTryCompile.cxx @@ -46,6 +46,25 @@ static std::string const kCMAKE_TRY_COMPILE_PLATFORM_VARIABLES = "CMAKE_TRY_COMPILE_PLATFORM_VARIABLES"; static std::string const kCMAKE_WARN_DEPRECATED = "CMAKE_WARN_DEPRECATED"; +static void writeProperty(FILE* fout, std::string const& targetName, + std::string const& prop, std::string const& value) +{ + fprintf(fout, "set_property(TARGET %s PROPERTY %s %s)\n", targetName.c_str(), + cmOutputConverter::EscapeForCMake(prop).c_str(), + cmOutputConverter::EscapeForCMake(value).c_str()); +} + +std::string cmCoreTryCompile::LookupStdVar(std::string const& var, + bool warnCMP0067) +{ + std::string value = this->Makefile->GetSafeDefinition(var); + if (warnCMP0067 && !value.empty()) { + value.clear(); + this->WarnCMP0067.push_back(var); + } + return value; +} + int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, bool isTryRun) { @@ -87,6 +106,12 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, std::string outputVariable; std::string copyFile; std::string copyFileError; + std::string cStandard; + std::string cxxStandard; + std::string cStandardRequired; + std::string cxxStandardRequired; + std::string cExtensions; + std::string cxxExtensions; std::vector<std::string> targets; std::string libsToLink = " "; bool useOldLinkLibs = true; @@ -94,6 +119,12 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, bool didOutputVariable = false; bool didCopyFile = false; bool didCopyFileError = false; + bool didCStandard = false; + bool didCxxStandard = false; + bool didCStandardRequired = false; + bool didCxxStandardRequired = false; + bool didCExtensions = false; + bool didCxxExtensions = false; bool useSources = argv[2] == "SOURCES"; std::vector<std::string> sources; @@ -106,6 +137,12 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, DoingOutputVariable, DoingCopyFile, DoingCopyFileError, + DoingCStandard, + DoingCxxStandard, + DoingCStandardRequired, + DoingCxxStandardRequired, + DoingCExtensions, + DoingCxxExtensions, DoingSources }; Doing doing = useSources ? DoingSources : DoingNone; @@ -126,6 +163,24 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, } else if (argv[i] == "COPY_FILE_ERROR") { doing = DoingCopyFileError; didCopyFileError = true; + } else if (argv[i] == "C_STANDARD") { + doing = DoingCStandard; + didCStandard = true; + } else if (argv[i] == "CXX_STANDARD") { + doing = DoingCxxStandard; + didCxxStandard = true; + } else if (argv[i] == "C_STANDARD_REQUIRED") { + doing = DoingCStandardRequired; + didCStandardRequired = true; + } else if (argv[i] == "CXX_STANDARD_REQUIRED") { + doing = DoingCxxStandardRequired; + didCxxStandardRequired = true; + } else if (argv[i] == "C_EXTENSIONS") { + doing = DoingCExtensions; + didCExtensions = true; + } else if (argv[i] == "CXX_EXTENSIONS") { + doing = DoingCxxExtensions; + didCxxExtensions = true; } else if (doing == DoingCMakeFlags) { cmakeFlags.push_back(argv[i]); } else if (doing == DoingCompileDefinitions) { @@ -166,6 +221,24 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, } else if (doing == DoingCopyFileError) { copyFileError = argv[i]; doing = DoingNone; + } else if (doing == DoingCStandard) { + cStandard = argv[i]; + doing = DoingNone; + } else if (doing == DoingCxxStandard) { + cxxStandard = argv[i]; + doing = DoingNone; + } else if (doing == DoingCStandardRequired) { + cStandardRequired = argv[i]; + doing = DoingNone; + } else if (doing == DoingCxxStandardRequired) { + cxxStandardRequired = argv[i]; + doing = DoingNone; + } else if (doing == DoingCExtensions) { + cExtensions = argv[i]; + doing = DoingNone; + } else if (doing == DoingCxxExtensions) { + cxxExtensions = argv[i]; + doing = DoingNone; } else if (doing == DoingSources) { sources.push_back(argv[i]); } else if (i == 3) { @@ -213,6 +286,42 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, return -1; } + if (didCStandard && !this->SrcFileSignature) { + this->Makefile->IssueMessage( + cmake::FATAL_ERROR, "C_STANDARD allowed only in source file signature."); + return -1; + } + if (didCxxStandard && !this->SrcFileSignature) { + this->Makefile->IssueMessage( + cmake::FATAL_ERROR, + "CXX_STANDARD allowed only in source file signature."); + return -1; + } + if (didCStandardRequired && !this->SrcFileSignature) { + this->Makefile->IssueMessage( + cmake::FATAL_ERROR, + "C_STANDARD_REQUIRED allowed only in source file signature."); + return -1; + } + if (didCxxStandardRequired && !this->SrcFileSignature) { + this->Makefile->IssueMessage( + cmake::FATAL_ERROR, + "CXX_STANDARD_REQUIRED allowed only in source file signature."); + return -1; + } + if (didCExtensions && !this->SrcFileSignature) { + this->Makefile->IssueMessage( + cmake::FATAL_ERROR, + "C_EXTENSIONS allowed only in source file signature."); + return -1; + } + if (didCxxExtensions && !this->SrcFileSignature) { + this->Makefile->IssueMessage( + cmake::FATAL_ERROR, + "CXX_EXTENSIONS allowed only in source file signature."); + return -1; + } + // compute the binary dir when TRY_COMPILE is called with a src file // signature if (this->SrcFileSignature) { @@ -518,6 +627,104 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, } } fprintf(fout, ")\n"); + + bool const testC = testLangs.find("C") != testLangs.end(); + bool const testCxx = testLangs.find("CXX") != testLangs.end(); + + bool warnCMP0067 = false; + bool honorStandard = true; + + if (!didCStandard && !didCxxStandard && !didCStandardRequired && + !didCxxStandardRequired && !didCExtensions && !didCxxExtensions) { + switch (this->Makefile->GetPolicyStatus(cmPolicies::CMP0067)) { + case cmPolicies::WARN: + warnCMP0067 = this->Makefile->PolicyOptionalWarningEnabled( + "CMAKE_POLICY_WARNING_CMP0067"); + case cmPolicies::OLD: + // OLD behavior is to not honor the language standard variables. + honorStandard = false; + break; + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + this->Makefile->IssueMessage( + cmake::FATAL_ERROR, + cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0067)); + case cmPolicies::NEW: + // NEW behavior is to honor the language standard variables. + // We already initialized honorStandard to true. + break; + } + } + + if (honorStandard || warnCMP0067) { + if (testC) { + if (!didCStandard) { + cStandard = this->LookupStdVar("CMAKE_C_STANDARD", warnCMP0067); + } + if (!didCStandardRequired) { + cStandardRequired = + this->LookupStdVar("CMAKE_C_STANDARD_REQUIRED", warnCMP0067); + } + if (!didCExtensions) { + cExtensions = this->LookupStdVar("CMAKE_C_EXTENSIONS", warnCMP0067); + } + } + if (testCxx) { + if (!didCxxStandard) { + cxxStandard = this->LookupStdVar("CMAKE_CXX_STANDARD", warnCMP0067); + } + if (!didCxxStandardRequired) { + cxxStandardRequired = + this->LookupStdVar("CMAKE_CXX_STANDARD_REQUIRED", warnCMP0067); + } + if (!didCxxExtensions) { + cxxExtensions = + this->LookupStdVar("CMAKE_CXX_EXTENSIONS", warnCMP0067); + } + } + } + + if (!this->WarnCMP0067.empty()) { + std::ostringstream w; + /* clang-format off */ + w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0067) << "\n" + "For compatibility with older versions of CMake, try_compile " + "is not honoring language standard variables in the test project:\n" + ; + /* clang-format on */ + for (std::vector<std::string>::iterator vi = this->WarnCMP0067.begin(); + vi != this->WarnCMP0067.end(); ++vi) { + w << " " << *vi << "\n"; + } + this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, w.str()); + } + + if (testC) { + if (!cStandard.empty()) { + writeProperty(fout, targetName, "C_STANDARD", cStandard); + } + if (!cStandardRequired.empty()) { + writeProperty(fout, targetName, "C_STANDARD_REQUIRED", + cStandardRequired); + } + if (!cExtensions.empty()) { + writeProperty(fout, targetName, "C_EXTENSIONS", cExtensions); + } + } + + if (testCxx) { + if (!cxxStandard.empty()) { + writeProperty(fout, targetName, "CXX_STANDARD", cxxStandard); + } + if (!cxxStandardRequired.empty()) { + writeProperty(fout, targetName, "CXX_STANDARD_REQUIRED", + cxxStandardRequired); + } + if (!cxxExtensions.empty()) { + writeProperty(fout, targetName, "CXX_EXTENSIONS", cxxExtensions); + } + } + if (useOldLinkLibs) { fprintf(fout, "target_link_libraries(%s ${LINK_LIBRARIES})\n", targetName.c_str()); diff --git a/Source/cmCoreTryCompile.h b/Source/cmCoreTryCompile.h index 1c94f09..4b96aed 100644 --- a/Source/cmCoreTryCompile.h +++ b/Source/cmCoreTryCompile.h @@ -47,6 +47,10 @@ protected: std::string OutputFile; std::string FindErrorMessage; bool SrcFileSignature; + +private: + std::vector<std::string> WarnCMP0067; + std::string LookupStdVar(std::string const& var, bool warnCMP0067); }; #endif diff --git a/Source/cmFilePathChecksum.cxx b/Source/cmFilePathChecksum.cxx new file mode 100644 index 0000000..3d8b695 --- /dev/null +++ b/Source/cmFilePathChecksum.cxx @@ -0,0 +1,88 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmFilePathChecksum.h" + +#include "cmBase32.h" +#include "cmCryptoHash.h" +#include "cmMakefile.h" +#include "cmSystemTools.h" + +#include <vector> + +cmFilePathChecksum::cmFilePathChecksum() +{ +} + +cmFilePathChecksum::cmFilePathChecksum(const std::string& currentSrcDir, + const std::string& currentBinDir, + const std::string& projectSrcDir, + const std::string& projectBinDir) +{ + setupParentDirs(currentSrcDir, currentBinDir, projectSrcDir, projectBinDir); +} + +cmFilePathChecksum::cmFilePathChecksum(cmMakefile* makefile) +{ + setupParentDirs(makefile->GetCurrentSourceDirectory(), + makefile->GetCurrentBinaryDirectory(), + makefile->GetHomeDirectory(), + makefile->GetHomeOutputDirectory()); +} + +void cmFilePathChecksum::setupParentDirs(const std::string& currentSrcDir, + const std::string& currentBinDir, + const std::string& projectSrcDir, + const std::string& projectBinDir) +{ + parentDirs[0].first = cmsys::SystemTools::GetRealPath(currentSrcDir); + parentDirs[1].first = cmsys::SystemTools::GetRealPath(currentBinDir); + parentDirs[2].first = cmsys::SystemTools::GetRealPath(projectSrcDir); + parentDirs[3].first = cmsys::SystemTools::GetRealPath(projectBinDir); + + parentDirs[0].second = "CurrentSource"; + parentDirs[1].second = "CurrentBinary"; + parentDirs[2].second = "ProjectSource"; + parentDirs[3].second = "ProjectBinary"; +} + +std::string cmFilePathChecksum::get(const std::string& filePath) +{ + std::string relPath; + std::string relSeed; + { + const std::string fileReal = cmsys::SystemTools::GetRealPath(filePath); + std::string parentDir; + // Find closest project parent directory + for (size_t ii = 0; ii != numParentDirs; ++ii) { + const std::string& pDir = parentDirs[ii].first; + if (!pDir.empty() && + cmsys::SystemTools::IsSubDirectory(fileReal, pDir)) { + relSeed = parentDirs[ii].second; + parentDir = pDir; + break; + } + } + // Use file system root as fallback parent directory + if (parentDir.empty()) { + relSeed = "FileSystemRoot"; + cmsys::SystemTools::SplitPathRootComponent(fileReal, &parentDir); + } + // Calculate relative path from project parent directory + relPath = cmsys::SystemTools::RelativePath( + parentDir, cmsys::SystemTools::GetParentDirectory(fileReal)); + } + + // Calculate the file ( seed + relative path ) binary checksum + std::vector<unsigned char> hashBytes = + cmCryptoHash(cmCryptoHash::AlgoSHA256).ByteHashString(relSeed + relPath); + + // Convert binary checksum to string + return cmBase32Encoder().encodeString(&hashBytes[0], hashBytes.size(), + false); +} + +std::string cmFilePathChecksum::getPart(const std::string& filePath, + size_t length) +{ + return get(filePath).substr(0, length); +} diff --git a/Source/cmFilePathChecksum.h b/Source/cmFilePathChecksum.h new file mode 100644 index 0000000..df19053 --- /dev/null +++ b/Source/cmFilePathChecksum.h @@ -0,0 +1,65 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmFilePathChecksum_h +#define cmFilePathChecksum_h + +#include <cmConfigure.h> // IWYU pragma: keep + +#include <stddef.h> +#include <string> +#include <utility> + +class cmMakefile; + +/** \class cmFilePathChecksum + * @brief Generates a checksum for the parent directory of a file + * + * The checksum is calculated from the relative file path to the + * closest known project directory. This guarantees reproducibility + * when source and build directory differ e.g. for different project + * build directories. + */ +class cmFilePathChecksum +{ +public: + /// Maximum number of characters to use from the path checksum + static const size_t partLengthDefault = 10; + + /// @brief Parent directories are empty + cmFilePathChecksum(); + + /// @brief Initilizes the parent directories manually + cmFilePathChecksum(const std::string& currentSrcDir, + const std::string& currentBinDir, + const std::string& projectSrcDir, + const std::string& projectBinDir); + + /// @brief Initilizes the parent directories from a makefile + cmFilePathChecksum(cmMakefile* makefile); + + /// @brief Allows parent directories setup after construction + /// + void setupParentDirs(const std::string& currentSrcDir, + const std::string& currentBinDir, + const std::string& projectSrcDir, + const std::string& projectBinDir); + + /* @brief Calculates the path checksum for the parent directory of a file + * + */ + std::string get(const std::string& filePath); + + /* @brief Same as get() but returns only the first length characters + * + */ + std::string getPart(const std::string& filePath, + size_t length = partLengthDefault); + +private: + /// Size of the parent directory list + static const size_t numParentDirs = 4; + /// List of (directory name, seed name) pairs + std::pair<std::string, std::string> parentDirs[numParentDirs]; +}; + +#endif diff --git a/Source/cmFilePathUuid.cxx b/Source/cmFilePathUuid.cxx deleted file mode 100644 index 03d2524..0000000 --- a/Source/cmFilePathUuid.cxx +++ /dev/null @@ -1,118 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#include "cmFilePathUuid.h" - -#include "cmBase32.h" -#include "cmCryptoHash.h" -#include "cmMakefile.h" -#include "cmSystemTools.h" - -#include <vector> - -cmFilePathUuid::cmFilePathUuid(cmMakefile* makefile) -{ - initParentDirs(makefile->GetCurrentSourceDirectory(), - makefile->GetCurrentBinaryDirectory(), - makefile->GetHomeDirectory(), - makefile->GetHomeOutputDirectory()); -} - -cmFilePathUuid::cmFilePathUuid(const std::string& currentSrcDir, - const std::string& currentBinDir, - const std::string& projectSrcDir, - const std::string& projectBinDir) -{ - initParentDirs(currentSrcDir, currentBinDir, projectSrcDir, projectBinDir); -} - -void cmFilePathUuid::initParentDirs(const std::string& currentSrcDir, - const std::string& currentBinDir, - const std::string& projectSrcDir, - const std::string& projectBinDir) -{ - parentDirs[0].first = cmsys::SystemTools::GetRealPath(currentSrcDir); - parentDirs[1].first = cmsys::SystemTools::GetRealPath(currentBinDir); - parentDirs[2].first = cmsys::SystemTools::GetRealPath(projectSrcDir); - parentDirs[3].first = cmsys::SystemTools::GetRealPath(projectBinDir); - - parentDirs[0].second = "CurrentSource"; - parentDirs[1].second = "CurrentBinary"; - parentDirs[2].second = "ProjectSource"; - parentDirs[3].second = "ProjectBinary"; -} - -std::string cmFilePathUuid::get(const std::string& filePath, - const char* outputPrefix, - const char* outputSuffix) -{ - std::string sourceFilename = cmsys::SystemTools::GetFilenameName(filePath); - std::string sourceBasename = - cmsys::SystemTools::GetFilenameWithoutLastExtension(sourceFilename); - - // Acquire checksum string - std::string checksum; - { - std::string sourceRelPath; - std::string sourceRelSeed; - GetRelPathSeed(filePath, sourceRelPath, sourceRelSeed); - checksum = GetChecksumString(sourceFilename, sourceRelPath, sourceRelSeed); - } - - // Compose the file name - std::string uuid; - if (outputPrefix) { - uuid += outputPrefix; - } - uuid += sourceBasename.substr(0, partLengthName); - uuid += "_"; - uuid += checksum.substr(0, partLengthCheckSum); - if (outputSuffix) { - uuid += outputSuffix; - } - return uuid; -} - -void cmFilePathUuid::GetRelPathSeed(const std::string& filePath, - std::string& sourceRelPath, - std::string& sourceRelSeed) -{ - const std::string sourceNameReal = cmsys::SystemTools::GetRealPath(filePath); - std::string parentDirectory; - // Find closest project parent directory - for (size_t ii = 0; ii != numParentDirs; ++ii) { - const std::string& pDir = parentDirs[ii].first; - if (!pDir.empty() && - cmsys::SystemTools::IsSubDirectory(sourceNameReal, pDir)) { - sourceRelSeed = parentDirs[ii].second; - parentDirectory = pDir; - break; - } - } - // Check if the file path is below a known project directory - if (parentDirectory.empty()) { - // Use file syste root as fallback parent directory - sourceRelSeed = "FileSystemRoot"; - cmsys::SystemTools::SplitPathRootComponent(sourceNameReal, - &parentDirectory); - } - sourceRelPath = cmsys::SystemTools::RelativePath( - parentDirectory, cmsys::SystemTools::GetParentDirectory(sourceNameReal)); -} - -std::string cmFilePathUuid::GetChecksumString( - const std::string& sourceFilename, const std::string& sourceRelPath, - const std::string& sourceRelSeed) -{ - std::string checksumBase32; - { - // Calculate the file ( seed + relative path + name ) checksum - std::vector<unsigned char> hashBytes = - cmCryptoHash(cmCryptoHash::AlgoSHA256) - .ByteHashString(sourceRelSeed + sourceRelPath + sourceFilename); - - checksumBase32 = - cmBase32Encoder().encodeString(&hashBytes[0], hashBytes.size(), false); - } - - return checksumBase32; -} diff --git a/Source/cmFilePathUuid.h b/Source/cmFilePathUuid.h deleted file mode 100644 index a450526..0000000 --- a/Source/cmFilePathUuid.h +++ /dev/null @@ -1,69 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#ifndef cmFilePathUuid_h -#define cmFilePathUuid_h - -#include <cmConfigure.h> // IWYU pragma: keep - -#include <stddef.h> -#include <string> -#include <utility> - -class cmMakefile; - -/** \class cmFilePathUuid - * @brief Generates a unique pathless file name with a checksum component - * calculated from the file path. - * - * The checksum is calculated from the relative file path to the - * closest known project directory. This guarantees reproducibility - * when source and build directory differ e.g. for different project - * build directories. - */ -class cmFilePathUuid -{ -public: - /// Maximum number of characters to use from the file name - static const size_t partLengthName = 14; - /// Maximum number of characters to use from the path checksum - static const size_t partLengthCheckSum = 14; - - /// @brief Initilizes the parent directories from a makefile - cmFilePathUuid(cmMakefile* makefile); - - /// @brief Initilizes the parent directories manually - cmFilePathUuid(const std::string& currentSrcDir, - const std::string& currentBinDir, - const std::string& projectSrcDir, - const std::string& projectBinDir); - - /* @brief Calculates and returns the uuid for a file path - * - * @arg outputPrefix optional string to prepend to the result - * @arg outputSuffix optional string to append to the result - */ - std::string get(const std::string& filePath, - const char* outputPrefix = CM_NULLPTR, - const char* outputSuffix = CM_NULLPTR); - -private: - void initParentDirs(const std::string& currentSrcDir, - const std::string& currentBinDir, - const std::string& projectSrcDir, - const std::string& projectBinDir); - - /// Returns the relative path and the parent directory key string (seed) - void GetRelPathSeed(const std::string& filePath, std::string& sourceRelPath, - std::string& sourceRelSeed); - - std::string GetChecksumString(const std::string& sourceFilename, - const std::string& sourceRelPath, - const std::string& sourceRelSeed); - - /// Size of the parent directory list - static const size_t numParentDirs = 4; - /// List of (directory name, seed name) pairs - std::pair<std::string, std::string> parentDirs[numParentDirs]; -}; - -#endif diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 903bcec..6ee2c14 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -533,6 +533,21 @@ void cmGeneratorTarget::AddTracedSources(std::vector<std::string> const& srcs) } } +void cmGeneratorTarget::AddIncludeDirectory(const std::string& src, + bool before) +{ + this->Target->InsertInclude(src, this->Makefile->GetBacktrace(), before); + cmListFileBacktrace lfbt = this->Makefile->GetBacktrace(); + cmGeneratorExpression ge(lfbt); + CM_AUTO_PTR<cmCompiledGeneratorExpression> cge = ge.Parse(src); + cge->SetEvaluateForBuildsystem(true); + // Insert before begin/end + std::vector<TargetPropertyEntry*>::iterator pos = before + ? this->IncludeDirectoriesEntries.begin() + : this->IncludeDirectoriesEntries.end(); + this->IncludeDirectoriesEntries.insert(pos, new TargetPropertyEntry(cge)); +} + std::vector<cmSourceFile*> const* cmGeneratorTarget::GetSourceDepends( cmSourceFile const* sf) const { diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 4c3c14b..f568699 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -396,6 +396,12 @@ public: void AddTracedSources(std::vector<std::string> const& srcs); /** + * Adds an entry to the INCLUDE_DIRECTORIES list. + * If before is true the entry is pushed at the front. + */ + void AddIncludeDirectory(const std::string& src, bool before = false); + + /** * Flags for a given source file as used in this target. Typically assigned * via SET_TARGET_PROPERTIES when the property is a list of source files. */ diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx index d992aef..dde6e82 100644 --- a/Source/cmGlobalVisualStudio10Generator.cxx +++ b/Source/cmGlobalVisualStudio10Generator.cxx @@ -98,7 +98,16 @@ cmGlobalVisualStudio10Generator::cmGlobalVisualStudio10Generator( this->SystemIsWindowsPhone = false; this->SystemIsWindowsStore = false; this->MSBuildCommandInitialized = false; - this->DefaultPlatformToolset = "v100"; + { + std::string envPlatformToolset; + if (cmSystemTools::GetEnv("PlatformToolset", envPlatformToolset) && + envPlatformToolset == "Windows7.1SDK") { + // We are running from a Windows7.1SDK command prompt. + this->DefaultPlatformToolset = "Windows7.1SDK"; + } else { + this->DefaultPlatformToolset = "v100"; + } + } this->DefaultClFlagTable = cmVS10CLFlagTable; this->DefaultCSharpFlagTable = cmVS10CSharpFlagTable; this->DefaultLibFlagTable = cmVS10LibFlagTable; diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 46e49dc..ead1e72 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -1470,6 +1470,7 @@ void cmLocalGenerator::AddCompilerRequirementFlag( static std::map<std::string, std::vector<std::string> > langStdMap; if (langStdMap.empty()) { // Maintain sorted order, most recent first. + langStdMap["CXX"].push_back("17"); langStdMap["CXX"].push_back("14"); langStdMap["CXX"].push_back("11"); langStdMap["CXX"].push_back("98"); diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index fecc983..f52fe26 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -3158,8 +3158,10 @@ int cmMakefile::TryCompile(const std::string& srcdir, cmGlobalGenerator* gg = cm.CreateGlobalGenerator(this->GetGlobalGenerator()->GetName()); if (!gg) { - cmSystemTools::Error( - "Internal CMake error, TryCompile bad GlobalGenerator"); + this->IssueMessage(cmake::INTERNAL_ERROR, "Global generator '" + + this->GetGlobalGenerator()->GetName() + + "' could not be created."); + cmSystemTools::SetFatalErrorOccured(); // return to the original directory cmSystemTools::ChangeDirectory(cwd); this->IsSourceFileTryCompile = false; @@ -3222,8 +3224,9 @@ int cmMakefile::TryCompile(const std::string& srcdir, cmStateEnums::INTERNAL); } if (cm.Configure() != 0) { - cmSystemTools::Error( - "Internal CMake error, TryCompile configure of cmake failed"); + this->IssueMessage(cmake::FATAL_ERROR, + "Failed to configure test project build system."); + cmSystemTools::SetFatalErrorOccured(); // return to the original directory cmSystemTools::ChangeDirectory(cwd); this->IsSourceFileTryCompile = false; @@ -3231,8 +3234,9 @@ int cmMakefile::TryCompile(const std::string& srcdir, } if (cm.Generate() != 0) { - cmSystemTools::Error( - "Internal CMake error, TryCompile generation of cmake failed"); + this->IssueMessage(cmake::FATAL_ERROR, + "Failed to generate test project build system."); + cmSystemTools::SetFatalErrorOccured(); // return to the original directory cmSystemTools::ChangeDirectory(cwd); this->IsSourceFileTryCompile = false; @@ -4064,7 +4068,7 @@ static const char* const CXX_FEATURES[] = { CM_NULLPTR FOR_EACH_CXX_FEATURE( #undef FEATURE_STRING static const char* const C_STANDARDS[] = { "90", "99", "11" }; -static const char* const CXX_STANDARDS[] = { "98", "11", "14" }; +static const char* const CXX_STANDARDS[] = { "98", "11", "14", "17" }; bool cmMakefile::AddRequiredTargetFeature(cmTarget* target, const std::string& feature, @@ -4297,7 +4301,9 @@ bool cmMakefile::HaveCxxStandardAvailable(cmTarget const* target, bool needCxx98 = false; bool needCxx11 = false; bool needCxx14 = false; - this->CheckNeededCxxLanguage(feature, needCxx98, needCxx11, needCxx14); + bool needCxx17 = false; + this->CheckNeededCxxLanguage(feature, needCxx98, needCxx11, needCxx14, + needCxx17); const char* existingCxxStandard = target->GetProperty("CXX_STANDARD"); if (!existingCxxStandard) { @@ -4336,7 +4342,7 @@ bool cmMakefile::HaveCxxStandardAvailable(cmTarget const* target, void cmMakefile::CheckNeededCxxLanguage(const std::string& feature, bool& needCxx98, bool& needCxx11, - bool& needCxx14) const + bool& needCxx14, bool& needCxx17) const { if (const char* propCxx98 = this->GetDefinition("CMAKE_CXX98_COMPILE_FEATURES")) { @@ -4356,6 +4362,12 @@ void cmMakefile::CheckNeededCxxLanguage(const std::string& feature, cmSystemTools::ExpandListArgument(propCxx14, props); needCxx14 = std::find(props.begin(), props.end(), feature) != props.end(); } + if (const char* propCxx17 = + this->GetDefinition("CMAKE_CXX17_COMPILE_FEATURES")) { + std::vector<std::string> props; + cmSystemTools::ExpandListArgument(propCxx17, props); + needCxx17 = std::find(props.begin(), props.end(), feature) != props.end(); + } } bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target, @@ -4365,8 +4377,10 @@ bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target, bool needCxx98 = false; bool needCxx11 = false; bool needCxx14 = false; + bool needCxx17 = false; - this->CheckNeededCxxLanguage(feature, needCxx98, needCxx11, needCxx14); + this->CheckNeededCxxLanguage(feature, needCxx98, needCxx11, needCxx14, + needCxx17); const char* existingCxxStandard = target->GetProperty("CXX_STANDARD"); if (existingCxxStandard) { @@ -4393,11 +4407,17 @@ bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target, bool setCxx98 = needCxx98 && !existingCxxStandard; bool setCxx11 = needCxx11 && !existingCxxStandard; bool setCxx14 = needCxx14 && !existingCxxStandard; + bool setCxx17 = needCxx17 && !existingCxxStandard; - if (needCxx14 && existingCxxStandard && + if (needCxx17 && existingCxxStandard && existingCxxIt < std::find_if(cmArrayBegin(CXX_STANDARDS), cmArrayEnd(CXX_STANDARDS), - cmStrCmp("14"))) { + cmStrCmp("17"))) { + setCxx17 = true; + } else if (needCxx14 && existingCxxStandard && + existingCxxIt < std::find_if(cmArrayBegin(CXX_STANDARDS), + cmArrayEnd(CXX_STANDARDS), + cmStrCmp("14"))) { setCxx14 = true; } else if (needCxx11 && existingCxxStandard && existingCxxIt < std::find_if(cmArrayBegin(CXX_STANDARDS), @@ -4411,7 +4431,10 @@ bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target, setCxx98 = true; } - if (setCxx14) { + if (setCxx17) { + target->SetProperty("CXX_STANDARD", "17"); + target->SetProperty("CUDA_STANDARD", "17"); + } else if (setCxx14) { target->SetProperty("CXX_STANDARD", "14"); target->SetProperty("CUDA_STANDARD", "14"); } else if (setCxx11) { diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 859b3c8..3484e5a 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -905,7 +905,8 @@ private: void CheckNeededCLanguage(const std::string& feature, bool& needC90, bool& needC99, bool& needC11) const; void CheckNeededCxxLanguage(const std::string& feature, bool& needCxx98, - bool& needCxx11, bool& needCxx14) const; + bool& needCxx11, bool& needCxx14, + bool& needCxx17) const; bool HaveCStandardAvailable(cmTarget const* target, const std::string& feature) const; diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 6906a90..4218930 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -553,7 +553,6 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( } } cmRulePlaceholderExpander::RuleVariables vars; - vars.RuleLauncher = "RULE_LAUNCH_COMPILE"; vars.CMTargetName = this->GeneratorTarget->GetName().c_str(); vars.CMTargetType = cmState::GetTargetTypeName(this->GeneratorTarget->GetType()); @@ -624,6 +623,7 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( lang_can_export_cmds && compileCommands.size() == 1) { std::string compileCommand = compileCommands[0]; + // no launcher for CMAKE_EXPORT_COMPILE_COMMANDS rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator, compileCommand, vars); std::string workingDirectory = cmSystemTools::CollapseFullPath( @@ -681,9 +681,20 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( } } + std::string launcher; + { + const char* val = this->LocalGenerator->GetRuleLauncher( + this->GeneratorTarget, "RULE_LAUNCH_COMPILE"); + if (val && *val) { + launcher = val; + launcher += " "; + } + } + // Expand placeholders in the commands. for (std::vector<std::string>::iterator i = compileCommands.begin(); i != compileCommands.end(); ++i) { + *i = launcher + *i; rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator, *i, vars); } @@ -748,6 +759,7 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( // Expand placeholders in the commands. for (std::vector<std::string>::iterator i = preprocessCommands.begin(); i != preprocessCommands.end(); ++i) { + // no launcher for preprocessor commands rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator, *i, vars); } @@ -796,6 +808,7 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( // Expand placeholders in the commands. for (std::vector<std::string>::iterator i = assemblyCommands.begin(); i != assemblyCommands.end(); ++i) { + // no launcher for assembly commands rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator, *i, vars); } diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 8090542..b5aeb54 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -1046,6 +1046,7 @@ void cmNinjaTargetGenerator::ExportObjectCompileCommand( for (std::vector<std::string>::iterator i = compileCmds.begin(); i != compileCmds.end(); ++i) { + // no launcher for CMAKE_EXPORT_COMPILE_COMMANDS rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(), *i, compileObjectVars); } diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index 9b86435..62e67c7 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -197,7 +197,10 @@ class cmMakefile; 3, 4, 0, cmPolicies::WARN) \ SELECT(POLICY, CMP0066, \ "Honor per-config flags in try_compile() source-file signature.", 3, \ - 7, 0, cmPolicies::WARN) + 7, 0, cmPolicies::WARN) \ + SELECT(POLICY, CMP0067, \ + "Honor language standard in try_compile() source-file signature.", \ + 3, 8, 0, cmPolicies::WARN) #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1) #define CM_FOR_EACH_POLICY_ID(POLICY) \ diff --git a/Source/cmQtAutoGeneratorInitializer.cxx b/Source/cmQtAutoGeneratorInitializer.cxx index 8afd532..f0847b1 100644 --- a/Source/cmQtAutoGeneratorInitializer.cxx +++ b/Source/cmQtAutoGeneratorInitializer.cxx @@ -4,7 +4,7 @@ #include "cmAlgorithms.h" #include "cmCustomCommandLines.h" -#include "cmFilePathUuid.h" +#include "cmFilePathChecksum.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmLocalGenerator.h" @@ -35,14 +35,34 @@ #include <utility> #include <vector> +static void utilCopyTargetProperty(cmTarget* destinationTarget, + cmTarget* sourceTarget, + const std::string& propertyName) +{ + const char* propertyValue = sourceTarget->GetProperty(propertyName); + if (propertyValue) { + destinationTarget->SetProperty(propertyName, propertyValue); + } +} + +static std::string utilStripCR(std::string const& line) +{ + // Strip CR characters rcc may have printed (possibly more than one!). + std::string::size_type cr = line.find('\r'); + if (cr != line.npos) { + return line.substr(0, cr); + } + return line; +} + static std::string GetAutogenTargetName(cmGeneratorTarget const* target) { std::string autogenTargetName = target->GetName(); - autogenTargetName += "_automoc"; + autogenTargetName += "_autogen"; return autogenTargetName; } -static std::string GetAutogenTargetDir(cmGeneratorTarget const* target) +static std::string GetAutogenTargetFilesDir(cmGeneratorTarget const* target) { cmMakefile* makefile = target->Target->GetMakefile(); std::string targetDir = makefile->GetCurrentBinaryDirectory(); @@ -59,10 +79,25 @@ static std::string GetAutogenTargetBuildDir(cmGeneratorTarget const* target) std::string targetDir = makefile->GetCurrentBinaryDirectory(); targetDir += "/"; targetDir += GetAutogenTargetName(target); - targetDir += ".dir/"; + targetDir += "/"; return targetDir; } +static std::string GetQtMajorVersion(cmGeneratorTarget const* target) +{ + cmMakefile* makefile = target->Target->GetMakefile(); + std::string qtMajorVersion = makefile->GetSafeDefinition("QT_VERSION_MAJOR"); + if (qtMajorVersion.empty()) { + qtMajorVersion = makefile->GetSafeDefinition("Qt5Core_VERSION_MAJOR"); + } + const char* targetQtVersion = + target->GetLinkInterfaceDependentStringProperty("QT_MAJOR_VERSION", ""); + if (targetQtVersion != CM_NULLPTR) { + qtMajorVersion = targetQtVersion; + } + return qtMajorVersion; +} + static void SetupSourceFiles(cmGeneratorTarget const* target, std::vector<std::string>& skipMoc, std::vector<std::string>& mocSources, @@ -74,41 +109,20 @@ static void SetupSourceFiles(cmGeneratorTarget const* target, std::vector<cmSourceFile*> srcFiles; target->GetConfigCommonSourceFiles(srcFiles); - std::vector<std::string> newRccFiles; - - cmFilePathUuid fpathUuid(makefile); + cmFilePathChecksum fpathCheckSum(makefile); for (std::vector<cmSourceFile*>::const_iterator fileIt = srcFiles.begin(); fileIt != srcFiles.end(); ++fileIt) { cmSourceFile* sf = *fileIt; - std::string absFile = cmsys::SystemTools::GetRealPath(sf->GetFullPath()); - bool skipFileForMoc = - cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTOMOC")); - bool generated = cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED")); + const std::string absFile = + cmsys::SystemTools::GetRealPath(sf->GetFullPath()); + const std::string ext = sf->GetExtension(); if (cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTOUIC"))) { skipUic.push_back(absFile); } - std::string ext = sf->GetExtension(); - - if (target->GetPropertyAsBool("AUTORCC")) { - if (ext == "qrc" && - !cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC"))) { - - std::string rcc_output_file = GetAutogenTargetBuildDir(target); - // Create output directory - cmSystemTools::MakeDirectory(rcc_output_file.c_str()); - rcc_output_file += fpathUuid.get(absFile, "qrc_", ".cpp"); - - makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", - rcc_output_file.c_str(), false); - makefile->GetOrCreateSource(rcc_output_file, true); - newRccFiles.push_back(rcc_output_file); - } - } - - if (!generated) { - if (skipFileForMoc) { + if (!cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"))) { + if (cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTOMOC"))) { skipMoc.push_back(absFile); } else { cmSystemTools::FileFormat fileType = @@ -121,11 +135,6 @@ static void SetupSourceFiles(cmGeneratorTarget const* target, } } } - - for (std::vector<std::string>::const_iterator fileIt = newRccFiles.begin(); - fileIt != newRccFiles.end(); ++fileIt) { - const_cast<cmGeneratorTarget*>(target)->AddSource(*fileIt); - } } static void GetCompileDefinitionsAndDirectories( @@ -146,7 +155,7 @@ static void GetCompileDefinitionsAndDirectories( defs += cmJoin(defines, ";"); } -static void SetupAutoMocTarget( +static void MocSetupAutoTarget( cmGeneratorTarget const* target, const std::string& autogenTargetName, std::vector<std::string> const& skipMoc, std::vector<std::string> const& mocHeaders, @@ -229,7 +238,7 @@ static void SetupAutoMocTarget( } } -static void GetUicOpts(cmGeneratorTarget const* target, +static void UicGetOpts(cmGeneratorTarget const* target, const std::string& config, std::string& optString) { std::vector<std::string> opts; @@ -237,7 +246,7 @@ static void GetUicOpts(cmGeneratorTarget const* target, optString = cmJoin(opts, ";"); } -static void SetupAutoUicTarget( +static void UicSetupAutoTarget( cmGeneratorTarget const* target, std::vector<std::string> const& skipUic, std::map<std::string, std::string>& configUicOptions) { @@ -259,7 +268,7 @@ static void SetupAutoUicTarget( std::string _uic_opts; std::vector<std::string> configs; const std::string& config = makefile->GetConfigurations(configs); - GetUicOpts(target, config, _uic_opts); + UicGetOpts(target, config, _uic_opts); if (!_uic_opts.empty()) { _uic_opts = cmOutputConverter::EscapeForCMake(_uic_opts); @@ -268,7 +277,7 @@ static void SetupAutoUicTarget( for (std::vector<std::string>::const_iterator li = configs.begin(); li != configs.end(); ++li) { std::string config_uic_opts; - GetUicOpts(target, *li, config_uic_opts); + UicGetOpts(target, *li, config_uic_opts); if (config_uic_opts != _uic_opts) { configUicOptions[*li] = cmOutputConverter::EscapeForCMake(config_uic_opts); @@ -331,25 +340,13 @@ static void SetupAutoUicTarget( } } -static std::string GetRccExecutable(cmGeneratorTarget const* target) +static std::string RccGetExecutable(cmGeneratorTarget const* target, + const std::string& qtMajorVersion) { cmLocalGenerator* lg = target->GetLocalGenerator(); - cmMakefile* makefile = target->Target->GetMakefile(); - const char* qtVersion = makefile->GetDefinition("_target_qt_version"); - if (!qtVersion) { - qtVersion = makefile->GetDefinition("Qt5Core_VERSION_MAJOR"); - if (!qtVersion) { - qtVersion = makefile->GetDefinition("QT_VERSION_MAJOR"); - } - if (const char* targetQtVersion = - target->GetLinkInterfaceDependentStringProperty("QT_MAJOR_VERSION", - "")) { - qtVersion = targetQtVersion; - } - } - std::string targetName = target->GetName(); - if (strcmp(qtVersion, "5") == 0) { + std::string const& targetName = target->GetName(); + if (qtMajorVersion == "5") { cmGeneratorTarget* qt5Rcc = lg->FindGeneratorTargetToUse("Qt5::rcc"); if (!qt5Rcc) { cmSystemTools::Error("Qt5::rcc target not found ", targetName.c_str()); @@ -357,7 +354,7 @@ static std::string GetRccExecutable(cmGeneratorTarget const* target) } return qt5Rcc->ImportedGetLocation(""); } - if (strcmp(qtVersion, "4") == 0) { + if (qtMajorVersion == "4") { cmGeneratorTarget* qt4Rcc = lg->FindGeneratorTargetToUse("Qt4::rcc"); if (!qt4Rcc) { cmSystemTools::Error("Qt4::rcc target not found ", targetName.c_str()); @@ -372,7 +369,7 @@ static std::string GetRccExecutable(cmGeneratorTarget const* target) return std::string(); } -static void MergeRccOptions(std::vector<std::string>& opts, +static void RccMergeOptions(std::vector<std::string>& opts, const std::vector<std::string>& fileOpts, bool isQt5) { @@ -404,41 +401,16 @@ static void MergeRccOptions(std::vector<std::string>& opts, opts.insert(opts.end(), extraOpts.begin(), extraOpts.end()); } -static void copyTargetProperty(cmTarget* destinationTarget, - cmTarget* sourceTarget, - const std::string& propertyName) -{ - const char* propertyValue = sourceTarget->GetProperty(propertyName); - if (propertyValue) { - destinationTarget->SetProperty(propertyName, propertyValue); - } -} - -static std::string cmQtAutoGeneratorsStripCR(std::string const& line) -{ - // Strip CR characters rcc may have printed (possibly more than one!). - std::string::size_type cr = line.find('\r'); - if (cr != line.npos) { - return line.substr(0, cr); - } - return line; -} - -static std::string ReadAll(const std::string& filename) -{ - cmsys::ifstream file(filename.c_str()); - std::ostringstream stream; - stream << file.rdbuf(); - file.close(); - return stream.str(); -} - /// @brief Reads the resource files list from from a .qrc file - Qt5 version /// @return True if the .qrc file was successfully parsed -static bool ListQt5RccInputs(cmSourceFile* sf, cmGeneratorTarget const* target, +static bool RccListInputsQt5(cmSourceFile* sf, cmGeneratorTarget const* target, std::vector<std::string>& depends) { - std::string rccCommand = GetRccExecutable(target); + const std::string rccCommand = RccGetExecutable(target, "5"); + if (rccCommand.empty()) { + cmSystemTools::Error("AUTOGEN: error: rcc executable not available\n"); + return false; + } bool hasDashDashList = false; // Read rcc features @@ -486,7 +458,7 @@ static bool ListQt5RccInputs(cmSourceFile* sf, cmGeneratorTarget const* target, std::istringstream ostr(rccStdOut); std::string oline; while (std::getline(ostr, oline)) { - oline = cmQtAutoGeneratorsStripCR(oline); + oline = utilStripCR(oline); if (!oline.empty()) { depends.push_back(oline); } @@ -497,7 +469,7 @@ static bool ListQt5RccInputs(cmSourceFile* sf, cmGeneratorTarget const* target, std::istringstream estr(rccStdErr); std::string eline; while (std::getline(estr, eline)) { - eline = cmQtAutoGeneratorsStripCR(eline); + eline = utilStripCR(eline); if (cmHasLiteralPrefix(eline, "RCC: Error in")) { static std::string searchString = "Cannot find file '"; @@ -521,10 +493,16 @@ static bool ListQt5RccInputs(cmSourceFile* sf, cmGeneratorTarget const* target, /// @brief Reads the resource files list from from a .qrc file - Qt4 version /// @return True if the .qrc file was successfully parsed -static bool ListQt4RccInputs(cmSourceFile* sf, +static bool RccListInputsQt4(cmSourceFile* sf, std::vector<std::string>& depends) { - const std::string qrcContents = ReadAll(sf->GetFullPath()); + // Read file into string + std::string qrcContents; + { + std::ostringstream stream; + stream << cmsys::ifstream(sf->GetFullPath().c_str()).rdbuf(); + qrcContents = stream.str(); + } cmsys::RegularExpression fileMatchRegex("(<file[^<]+)"); @@ -551,17 +529,18 @@ static bool ListQt4RccInputs(cmSourceFile* sf, /// @brief Reads the resource files list from from a .qrc file /// @return True if the rcc file was successfully parsed -static bool ListQtRccInputs(const std::string& qtMajorVersion, - cmSourceFile* sf, cmGeneratorTarget const* target, - std::vector<std::string>& depends) +static bool RccListInputs(const std::string& qtMajorVersion, cmSourceFile* sf, + cmGeneratorTarget const* target, + std::vector<std::string>& depends) { if (qtMajorVersion == "5") { - return ListQt5RccInputs(sf, target, depends); + return RccListInputsQt5(sf, target, depends); } - return ListQt4RccInputs(sf, depends); + return RccListInputsQt4(sf, depends); } -static void SetupAutoRccTarget(cmGeneratorTarget const* target) +static void RccSetupAutoTarget(cmGeneratorTarget const* target, + const std::string& qtMajorVersion) { std::string _rcc_files; const char* sepRccFiles = ""; @@ -577,16 +556,12 @@ static void SetupAutoRccTarget(cmGeneratorTarget const* target) std::string rccFileOptions; const char* optionSep = ""; - const char* qtVersion = makefile->GetDefinition("_target_qt_version"); + const bool qtMajorVersion5 = (qtMajorVersion == "5"); std::vector<std::string> rccOptions; if (const char* opts = target->GetProperty("AUTORCC_OPTIONS")) { cmSystemTools::ExpandListArgument(opts, rccOptions); } - std::string qtMajorVersion = makefile->GetSafeDefinition("QT_VERSION_MAJOR"); - if (qtMajorVersion == "") { - qtMajorVersion = makefile->GetSafeDefinition("Qt5Core_VERSION_MAJOR"); - } for (std::vector<cmSourceFile*>::const_iterator fileIt = srcFiles.begin(); fileIt != srcFiles.end(); ++fileIt) { @@ -604,7 +579,7 @@ static void SetupAutoRccTarget(cmGeneratorTarget const* target) if (const char* prop = sf->GetProperty("AUTORCC_OPTIONS")) { std::vector<std::string> optsVec; cmSystemTools::ExpandListArgument(prop, optsVec); - MergeRccOptions(rccOptions, optsVec, strcmp(qtVersion, "5") == 0); + RccMergeOptions(rccOptions, optsVec, qtMajorVersion5); } if (!rccOptions.empty()) { @@ -624,7 +599,7 @@ static void SetupAutoRccTarget(cmGeneratorTarget const* target) std::string entriesList; if (!cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"))) { std::vector<std::string> depends; - if (ListQtRccInputs(qtMajorVersion, sf, target, depends)) { + if (RccListInputs(qtMajorVersion, sf, target, depends)) { entriesList = cmJoin(depends, "@list_sep@"); } else { return; @@ -637,38 +612,27 @@ static void SetupAutoRccTarget(cmGeneratorTarget const* target) } } makefile->AddDefinition( - "_qt_rcc_inputs_" + target->GetName(), - cmOutputConverter::EscapeForCMake(qrcInputs).c_str()); - + "_rcc_inputs", cmOutputConverter::EscapeForCMake(qrcInputs).c_str()); makefile->AddDefinition( "_rcc_files", cmOutputConverter::EscapeForCMake(_rcc_files).c_str()); - makefile->AddDefinition( - "_qt_rcc_options_files", + "_rcc_options_files", cmOutputConverter::EscapeForCMake(rccFileFiles).c_str()); makefile->AddDefinition( - "_qt_rcc_options_options", + "_rcc_options_options", cmOutputConverter::EscapeForCMake(rccFileOptions).c_str()); - makefile->AddDefinition("_qt_rcc_executable", - GetRccExecutable(target).c_str()); + RccGetExecutable(target, qtMajorVersion).c_str()); } void cmQtAutoGeneratorInitializer::InitializeAutogenSources( cmGeneratorTarget* target) { - cmMakefile* makefile = target->Target->GetMakefile(); - if (target->GetPropertyAsBool("AUTOMOC")) { - std::string automocTargetName = GetAutogenTargetName(target); - std::string mocCppFile = makefile->GetCurrentBinaryDirectory(); - mocCppFile += "/"; - mocCppFile += automocTargetName; - mocCppFile += ".cpp"; + cmMakefile* makefile = target->Target->GetMakefile(); + const std::string mocCppFile = + GetAutogenTargetBuildDir(target) + "moc_compilation.cpp"; makefile->GetOrCreateSource(mocCppFile, true); - makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", mocCppFile.c_str(), - false); - target->AddSource(mocCppFile); } } @@ -678,56 +642,77 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( { cmMakefile* makefile = target->Target->GetMakefile(); - std::string qtMajorVersion = makefile->GetSafeDefinition("QT_VERSION_MAJOR"); - if (qtMajorVersion == "") { - qtMajorVersion = makefile->GetSafeDefinition("Qt5Core_VERSION_MAJOR"); - } - - // create a custom target for running generators at buildtime: - std::string autogenTargetName = GetAutogenTargetName(target); - - std::string targetDir = GetAutogenTargetDir(target); + // Create a custom target for running generators at buildtime + const std::string autogenTargetName = GetAutogenTargetName(target); + const std::string autogenBuildDir = GetAutogenTargetBuildDir(target); + const std::string workingDirectory = + cmSystemTools::CollapseFullPath("", makefile->GetCurrentBinaryDirectory()); + const std::string qtMajorVersion = GetQtMajorVersion(target); + std::vector<std::string> autogenOutputFiles; - cmCustomCommandLine currentLine; - currentLine.push_back(cmSystemTools::GetCMakeCommand()); - currentLine.push_back("-E"); - currentLine.push_back("cmake_autogen"); - currentLine.push_back(targetDir); - currentLine.push_back("$<CONFIGURATION>"); + // Create autogen target build directory and add it to the clean files + cmSystemTools::MakeDirectory(autogenBuildDir); + makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", + autogenBuildDir.c_str(), false); - cmCustomCommandLines commandLines; - commandLines.push_back(currentLine); + if (target->GetPropertyAsBool("AUTOMOC") || + target->GetPropertyAsBool("AUTOUIC")) { + // Create autogen target includes directory and + // add it to the origin target INCLUDE_DIRECTORIES + const std::string incsDir = autogenBuildDir + "include"; + cmSystemTools::MakeDirectory(incsDir); + target->AddIncludeDirectory(incsDir, true); + } - std::string workingDirectory = - cmSystemTools::CollapseFullPath("", makefile->GetCurrentBinaryDirectory()); + if (target->GetPropertyAsBool("AUTOMOC")) { + // Register moc compilation file as generated + autogenOutputFiles.push_back(autogenBuildDir + "moc_compilation.cpp"); + } + // Initialize autogen target dependencies std::vector<std::string> depends; if (const char* autogenDepends = target->GetProperty("AUTOGEN_TARGET_DEPENDS")) { cmSystemTools::ExpandListArgument(autogenDepends, depends); } - std::vector<std::string> toolNames; - if (target->GetPropertyAsBool("AUTOMOC")) { - toolNames.push_back("moc"); - } - if (target->GetPropertyAsBool("AUTOUIC")) { - toolNames.push_back("uic"); - } - if (target->GetPropertyAsBool("AUTORCC")) { - toolNames.push_back("rcc"); + + // Compose command lines + cmCustomCommandLines commandLines; + { + cmCustomCommandLine currentLine; + currentLine.push_back(cmSystemTools::GetCMakeCommand()); + currentLine.push_back("-E"); + currentLine.push_back("cmake_autogen"); + currentLine.push_back(GetAutogenTargetFilesDir(target)); + currentLine.push_back("$<CONFIGURATION>"); + commandLines.push_back(currentLine); } - std::string tools = toolNames[0]; - toolNames.erase(toolNames.begin()); - while (toolNames.size() > 1) { - tools += ", " + toolNames[0]; + // Compose target comment + std::string autogenComment; + { + std::vector<std::string> toolNames; + if (target->GetPropertyAsBool("AUTOMOC")) { + toolNames.push_back("MOC"); + } + if (target->GetPropertyAsBool("AUTOUIC")) { + toolNames.push_back("UIC"); + } + if (target->GetPropertyAsBool("AUTORCC")) { + toolNames.push_back("RCC"); + } + + std::string tools = toolNames[0]; toolNames.erase(toolNames.begin()); + while (toolNames.size() > 1) { + tools += ", " + toolNames[0]; + toolNames.erase(toolNames.begin()); + } + if (toolNames.size() == 1) { + tools += " and " + toolNames[0]; + } + autogenComment = "Automatic " + tools + " for target " + target->GetName(); } - if (toolNames.size() == 1) { - tools += " and " + toolNames[0]; - } - std::string autogenComment = "Automatic " + tools + " for target "; - autogenComment += target->GetName(); #if defined(_WIN32) && !defined(__CYGWIN__) bool usePRE_BUILD = false; @@ -741,6 +726,8 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( // https://connect.microsoft.com/VisualStudio/feedback/details/769495 usePRE_BUILD = vsgg->GetVersion() >= cmGlobalVisualStudioGenerator::VS7; if (usePRE_BUILD) { + // If the autogen target depends on an other target + // don't use PRE_BUILD for (std::vector<std::string>::iterator it = depends.begin(); it != depends.end(); ++it) { if (!makefile->FindTargetToUse(it->c_str())) { @@ -752,35 +739,42 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( } #endif - std::vector<std::string> rcc_output; - bool const isNinja = lg->GetGlobalGenerator()->GetName() == "Ninja"; - if (isNinja -#if defined(_WIN32) && !defined(__CYGWIN__) - || usePRE_BUILD -#endif - ) { + if (target->GetPropertyAsBool("AUTORCC")) { + cmFilePathChecksum fpathCheckSum(makefile); std::vector<cmSourceFile*> srcFiles; target->GetConfigCommonSourceFiles(srcFiles); - cmFilePathUuid fpathUuid(makefile); for (std::vector<cmSourceFile*>::const_iterator fileIt = srcFiles.begin(); fileIt != srcFiles.end(); ++fileIt) { cmSourceFile* sf = *fileIt; - std::string absFile = cmsys::SystemTools::GetRealPath(sf->GetFullPath()); - - std::string ext = sf->GetExtension(); - - if (target->GetPropertyAsBool("AUTORCC")) { - if (ext == "qrc" && - !cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC"))) { - { - std::string rcc_output_file = GetAutogenTargetBuildDir(target); - // Create output directory - cmSystemTools::MakeDirectory(rcc_output_file.c_str()); - rcc_output_file += fpathUuid.get(absFile, "qrc_", ".cpp"); - rcc_output.push_back(rcc_output_file); - } + if (sf->GetExtension() == "qrc" && + !cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC"))) { + { + const std::string absFile = + cmsys::SystemTools::GetRealPath(sf->GetFullPath()); + + // Run cmake again when .qrc file changes + makefile->AddCMakeDependFile(absFile); + + std::string rccOutputFile = autogenBuildDir; + rccOutputFile += fpathCheckSum.getPart(absFile); + rccOutputFile += "/qrc_"; + rccOutputFile += + cmsys::SystemTools::GetFilenameWithoutLastExtension(absFile); + rccOutputFile += ".cpp"; + + // Add rcc output file to origin target sources + makefile->GetOrCreateSource(rccOutputFile, true); + target->AddSource(rccOutputFile); + // Register rcc output file as generated + autogenOutputFiles.push_back(rccOutputFile); + } + if (lg->GetGlobalGenerator()->GetName() == "Ninja" +#if defined(_WIN32) && !defined(__CYGWIN__) + || usePRE_BUILD +#endif + ) { if (!cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"))) { - ListQtRccInputs(qtMajorVersion, sf, target, depends); + RccListInputs(qtMajorVersion, sf, target, depends); #if defined(_WIN32) && !defined(__CYGWIN__) // Cannot use PRE_BUILD because the resource files themselves // may not be sources within the target so VS may not know the @@ -811,7 +805,7 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( { cmTarget* autogenTarget = makefile->AddUtilityCommand( autogenTargetName, true, workingDirectory.c_str(), - /*byproducts=*/rcc_output, depends, commandLines, false, + /*byproducts=*/autogenOutputFiles, depends, commandLines, false, autogenComment.c_str()); cmGeneratorTarget* gt = new cmGeneratorTarget(autogenTarget, lg); @@ -828,7 +822,7 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( autogenTarget->SetProperty("FOLDER", autogenFolder); } else { // inherit FOLDER property from target (#13688) - copyTargetProperty(gt->Target, target->Target, "FOLDER"); + utilCopyTargetProperty(gt->Target, target->Target, "FOLDER"); } target->Target->AddUtility(autogenTargetName); @@ -845,7 +839,8 @@ void cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget( static_cast<void>(varScope); // create a custom target for running generators at buildtime: - std::string autogenTargetName = GetAutogenTargetName(target); + const std::string autogenTargetName = GetAutogenTargetName(target); + const std::string qtMajorVersion = GetQtMajorVersion(target); makefile->AddDefinition( "_moc_target_name", @@ -853,28 +848,14 @@ void cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget( makefile->AddDefinition( "_origin_target_name", cmOutputConverter::EscapeForCMake(target->GetName()).c_str()); - - std::string targetDir = GetAutogenTargetDir(target); - - const char* qtVersion = makefile->GetDefinition("Qt5Core_VERSION_MAJOR"); - if (!qtVersion) { - qtVersion = makefile->GetDefinition("QT_VERSION_MAJOR"); - } - if (const char* targetQtVersion = - target->GetLinkInterfaceDependentStringProperty("QT_MAJOR_VERSION", - "")) { - qtVersion = targetQtVersion; - } - if (qtVersion) { - makefile->AddDefinition("_target_qt_version", qtVersion); - } + makefile->AddDefinition("_target_qt_version", qtMajorVersion.c_str()); std::vector<std::string> skipUic; std::vector<std::string> skipMoc; std::vector<std::string> mocSources; std::vector<std::string> mocHeaders; - std::map<std::string, std::string> configIncludes; - std::map<std::string, std::string> configDefines; + std::map<std::string, std::string> configMocIncludes; + std::map<std::string, std::string> configMocDefines; std::map<std::string, std::string> configUicOptions; if (target->GetPropertyAsBool("AUTOMOC") || @@ -886,39 +867,41 @@ void cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget( "_cpp_files", cmOutputConverter::EscapeForCMake(cmJoin(mocSources, ";")).c_str()); if (target->GetPropertyAsBool("AUTOMOC")) { - SetupAutoMocTarget(target, autogenTargetName, skipMoc, mocHeaders, - configIncludes, configDefines); + MocSetupAutoTarget(target, autogenTargetName, skipMoc, mocHeaders, + configMocIncludes, configMocDefines); } if (target->GetPropertyAsBool("AUTOUIC")) { - SetupAutoUicTarget(target, skipUic, configUicOptions); + UicSetupAutoTarget(target, skipUic, configUicOptions); } if (target->GetPropertyAsBool("AUTORCC")) { - SetupAutoRccTarget(target); + RccSetupAutoTarget(target, qtMajorVersion); } + // Generate config file std::string inputFile = cmSystemTools::GetCMakeRoot(); inputFile += "/Modules/AutogenInfo.cmake.in"; - std::string outputFile = targetDir; + std::string outputFile = GetAutogenTargetFilesDir(target); outputFile += "/AutogenInfo.cmake"; - makefile->AddDefinition( - "_qt_rcc_inputs", - makefile->GetDefinition("_qt_rcc_inputs_" + target->GetName())); + makefile->ConfigureFile(inputFile.c_str(), outputFile.c_str(), false, true, false); - // Ensure we have write permission in case .in was read-only. - mode_t perm = 0; + // Append custom definitions to config file + if (!configMocDefines.empty() || !configMocIncludes.empty() || + !configUicOptions.empty()) { + + // Ensure we have write permission in case .in was read-only. + mode_t perm = 0; #if defined(_WIN32) && !defined(__CYGWIN__) - mode_t mode_write = S_IWRITE; + mode_t mode_write = S_IWRITE; #else - mode_t mode_write = S_IWUSR; + mode_t mode_write = S_IWUSR; #endif - cmSystemTools::GetPermissions(outputFile, perm); - if (!(perm & mode_write)) { - cmSystemTools::SetPermissions(outputFile, perm | mode_write); - } - if (!configDefines.empty() || !configIncludes.empty() || - !configUicOptions.empty()) { + cmSystemTools::GetPermissions(outputFile, perm); + if (!(perm & mode_write)) { + cmSystemTools::SetPermissions(outputFile, perm | mode_write); + } + cmsys::ofstream infoFile(outputFile.c_str(), std::ios::app); if (!infoFile) { std::string error = "Internal CMake error when trying to open file: "; @@ -927,19 +910,19 @@ void cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget( cmSystemTools::Error(error.c_str()); return; } - if (!configDefines.empty()) { + if (!configMocDefines.empty()) { for (std::map<std::string, std::string>::iterator - it = configDefines.begin(), - end = configDefines.end(); + it = configMocDefines.begin(), + end = configMocDefines.end(); it != end; ++it) { infoFile << "set(AM_MOC_COMPILE_DEFINITIONS_" << it->first << " " << it->second << ")\n"; } } - if (!configIncludes.empty()) { + if (!configMocIncludes.empty()) { for (std::map<std::string, std::string>::iterator - it = configIncludes.begin(), - end = configIncludes.end(); + it = configMocIncludes.begin(), + end = configMocIncludes.end(); it != end; ++it) { infoFile << "set(AM_MOC_INCLUDES_" << it->first << " " << it->second << ")\n"; diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx index fa33cf2..eb513e5 100644 --- a/Source/cmQtAutoGenerators.cxx +++ b/Source/cmQtAutoGenerators.cxx @@ -15,7 +15,6 @@ #include <utility> #include "cmAlgorithms.h" -#include "cmFilePathUuid.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" #include "cmOutputConverter.h" @@ -159,7 +158,6 @@ void cmQtAutoGenerators::MergeUicOptions( bool cmQtAutoGenerators::Run(const std::string& targetDirectory, const std::string& config) { - bool success = true; cmake cm; cm.SetHomeOutputDirectory(targetDirectory); cm.SetHomeDirectory(targetDirectory); @@ -173,18 +171,18 @@ bool cmQtAutoGenerators::Run(const std::string& targetDirectory, CM_AUTO_PTR<cmMakefile> mf(new cmMakefile(&gg, snapshot)); gg.SetCurrentMakefile(mf.get()); - this->ReadAutogenInfoFile(mf.get(), targetDirectory, config); + if (!this->ReadAutogenInfoFile(mf.get(), targetDirectory, config)) { + return false; + } this->ReadOldMocDefinitionsFile(mf.get(), targetDirectory); - this->Init(); if (this->QtMajorVersion == "4" || this->QtMajorVersion == "5") { - success = this->RunAutogen(mf.get()); + if (!this->RunAutogen(mf.get())) { + return false; + } } - - this->WriteOldMocDefinitionsFile(targetDirectory); - - return success; + return this->WriteOldMocDefinitionsFile(targetDirectory); } bool cmQtAutoGenerators::ReadAutogenInfoFile( @@ -196,30 +194,41 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( filename += "/AutogenInfo.cmake"; if (!makefile->ReadListFile(filename.c_str())) { - cmSystemTools::Error("Error processing file: ", filename.c_str()); + std::ostringstream err; + err << "AUTOGEN: error processing file: " << filename << std::endl; + this->LogError(err.str()); return false; } + // - Target names + this->OriginTargetName = + makefile->GetSafeDefinition("AM_ORIGIN_TARGET_NAME"); + this->AutogenTargetName = makefile->GetSafeDefinition("AM_TARGET_NAME"); + + // - Directories + this->ProjectSourceDir = makefile->GetSafeDefinition("AM_CMAKE_SOURCE_DIR"); + this->ProjectBinaryDir = makefile->GetSafeDefinition("AM_CMAKE_BINARY_DIR"); + this->CurrentSourceDir = + makefile->GetSafeDefinition("AM_CMAKE_CURRENT_SOURCE_DIR"); + this->CurrentBinaryDir = + makefile->GetSafeDefinition("AM_CMAKE_CURRENT_BINARY_DIR"); + + // - Qt environment this->QtMajorVersion = makefile->GetSafeDefinition("AM_QT_VERSION_MAJOR"); if (this->QtMajorVersion == "") { this->QtMajorVersion = makefile->GetSafeDefinition("AM_Qt5Core_VERSION_MAJOR"); } - this->Sources = makefile->GetSafeDefinition("AM_SOURCES"); - { - std::string rccSources = makefile->GetSafeDefinition("AM_RCC_SOURCES"); - cmSystemTools::ExpandListArgument(rccSources, this->RccSources); - } - this->SkipMoc = makefile->GetSafeDefinition("AM_SKIP_MOC"); - this->SkipUic = makefile->GetSafeDefinition("AM_SKIP_UIC"); - this->Headers = makefile->GetSafeDefinition("AM_HEADERS"); - this->IncludeProjectDirsBefore = - makefile->IsOn("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE"); - this->Srcdir = makefile->GetSafeDefinition("AM_CMAKE_CURRENT_SOURCE_DIR"); - this->Builddir = makefile->GetSafeDefinition("AM_CMAKE_CURRENT_BINARY_DIR"); this->MocExecutable = makefile->GetSafeDefinition("AM_QT_MOC_EXECUTABLE"); this->UicExecutable = makefile->GetSafeDefinition("AM_QT_UIC_EXECUTABLE"); this->RccExecutable = makefile->GetSafeDefinition("AM_QT_RCC_EXECUTABLE"); + + // - File Lists + this->Sources = makefile->GetSafeDefinition("AM_SOURCES"); + this->Headers = makefile->GetSafeDefinition("AM_HEADERS"); + + // - Moc + this->SkipMoc = makefile->GetSafeDefinition("AM_SKIP_MOC"); { std::string compileDefsPropOrig = "AM_MOC_COMPILE_DEFINITIONS"; std::string compileDefsProp = compileDefsPropOrig; @@ -244,12 +253,9 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( includes ? includes : makefile->GetSafeDefinition(includesPropOrig); } this->MocOptionsStr = makefile->GetSafeDefinition("AM_MOC_OPTIONS"); - this->ProjectBinaryDir = makefile->GetSafeDefinition("AM_CMAKE_BINARY_DIR"); - this->ProjectSourceDir = makefile->GetSafeDefinition("AM_CMAKE_SOURCE_DIR"); - this->TargetName = makefile->GetSafeDefinition("AM_TARGET_NAME"); - this->OriginTargetName = - makefile->GetSafeDefinition("AM_ORIGIN_TARGET_NAME"); + // - Uic + this->SkipUic = makefile->GetSafeDefinition("AM_SKIP_UIC"); { const char* uicOptionsFiles = makefile->GetSafeDefinition("AM_UIC_OPTIONS_FILES"); @@ -280,6 +286,12 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( this->UicOptions[*fileIt] = *optionIt; } } + + // - Rcc + { + std::string rccSources = makefile->GetSafeDefinition("AM_RCC_SOURCES"); + cmSystemTools::ExpandListArgument(rccSources, this->RccSources); + } { const char* rccOptionsFiles = makefile->GetSafeDefinition("AM_RCC_OPTIONS_FILES"); @@ -303,8 +315,15 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( std::vector<std::string> rccInputLists; cmSystemTools::ExpandListArgument(rccInputs, rccInputLists); + // qrc files in the end of the list may have been empty + if (rccInputLists.size() < this->RccSources.size()) { + rccInputLists.resize(this->RccSources.size()); + } if (this->RccSources.size() != rccInputLists.size()) { - cmSystemTools::Error("Error processing file: ", filename.c_str()); + std::ostringstream err; + err << "AUTOGEN: RCC sources lists size missmatch in: " << filename; + err << std::endl; + this->LogError(err.str()); return false; } @@ -318,9 +337,14 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( this->RccInputs[*fileIt] = rccInputFiles; } } + + // - Settings this->CurrentCompileSettingsStr = this->MakeCompileSettingsString(makefile); - this->RelaxedMode = makefile->IsOn("AM_RELAXED_MODE"); + // - Flags + this->IncludeProjectDirsBefore = + makefile->IsOn("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE"); + this->MocRelaxedMode = makefile->IsOn("AM_MOC_RELAXED_MODE"); return true; } @@ -341,7 +365,7 @@ std::string cmQtAutoGenerators::MakeCompileSettingsString(cmMakefile* makefile) return s; } -bool cmQtAutoGenerators::ReadOldMocDefinitionsFile( +void cmQtAutoGenerators::ReadOldMocDefinitionsFile( cmMakefile* makefile, const std::string& targetDirectory) { std::string filename(cmSystemTools::CollapseFullPath(targetDirectory)); @@ -352,34 +376,49 @@ bool cmQtAutoGenerators::ReadOldMocDefinitionsFile( this->OldCompileSettingsStr = makefile->GetSafeDefinition("AM_OLD_COMPILE_SETTINGS"); } - return true; } -void cmQtAutoGenerators::WriteOldMocDefinitionsFile( +bool cmQtAutoGenerators::WriteOldMocDefinitionsFile( const std::string& targetDirectory) { + bool success = true; + std::string filename(cmSystemTools::CollapseFullPath(targetDirectory)); cmSystemTools::ConvertToUnixSlashes(filename); filename += "/AutomocOldMocDefinitions.cmake"; - cmsys::ofstream outfile; - outfile.open(filename.c_str(), std::ios::trunc); - outfile << "set(AM_OLD_COMPILE_SETTINGS " - << cmOutputConverter::EscapeForCMake(this->CurrentCompileSettingsStr) - << ")\n"; + { + cmsys::ofstream outfile; + outfile.open(filename.c_str(), std::ios::trunc); + if (outfile) { + outfile << "set(AM_OLD_COMPILE_SETTINGS " + << cmOutputConverter::EscapeForCMake( + this->CurrentCompileSettingsStr) + << ")\n"; + success = outfile.good(); + } else { + success = false; + } + } - outfile.close(); + return success; } void cmQtAutoGenerators::Init() { - this->TargetBuildSubDir = this->TargetName; - this->TargetBuildSubDir += ".dir/"; + this->AutogenBuildSubDir = this->AutogenTargetName; + this->AutogenBuildSubDir += "/"; - this->OutMocCppFilenameRel = this->TargetName; - this->OutMocCppFilenameRel += ".cpp"; + this->OutMocCppFilenameRel = this->AutogenBuildSubDir; + this->OutMocCppFilenameRel += "moc_compilation.cpp"; - this->OutMocCppFilenameAbs = this->Builddir + this->OutMocCppFilenameRel; + this->OutMocCppFilenameAbs = + this->CurrentBinaryDir + this->OutMocCppFilenameRel; + + // Init file path checksum generator + fpathCheckSum.setupParentDirs(this->CurrentSourceDir, this->CurrentBinaryDir, + this->ProjectSourceDir, + this->ProjectBinaryDir); std::vector<std::string> cdefList; cmSystemTools::ExpandListArgument(this->MocCompileDefinitionsStr, cdefList); @@ -464,10 +503,10 @@ bool cmQtAutoGenerators::RunAutogen(cmMakefile* makefile) // the program goes through all .cpp files to see which moc files are // included. It is not really interesting how the moc file is named, but // what file the moc is created from. Once a moc is included the same moc - // may not be included in the _automoc.cpp file anymore. OTOH if there's a - // header containing Q_OBJECT where no corresponding moc file is included - // anywhere a moc_<filename>.cpp file is created and included in - // the _automoc.cpp file. + // may not be included in the moc_compilation.cpp file anymore. OTOH if + // there's a header containing Q_OBJECT where no corresponding moc file + // is included anywhere a moc_<filename>.cpp file is created and included in + // the moc_compilation.cpp file. // key = moc source filepath, value = moc output filepath std::map<std::string, std::string> includedMocs; @@ -497,11 +536,16 @@ bool cmQtAutoGenerators::RunAutogen(cmMakefile* makefile) err << "AUTOGEN: Checking " << absFilename << std::endl; this->LogInfo(err.str()); } - if (this->RelaxedMode) { - this->ParseCppFile(absFilename, headerExtensions, includedMocs, uiFiles); + if (this->MocRelaxedMode) { + if (!this->ParseCppFile(absFilename, headerExtensions, includedMocs, + uiFiles)) { + return false; + } } else { - this->StrictParseCppFile(absFilename, headerExtensions, includedMocs, - uiFiles); + if (!this->StrictParseCppFile(absFilename, headerExtensions, + includedMocs, uiFiles)) { + return false; + } } this->SearchHeadersForCppFile(absFilename, headerExtensions, headerFiles); } @@ -533,38 +577,28 @@ bool cmQtAutoGenerators::RunAutogen(cmMakefile* makefile) this->ParseHeaders(headerFiles, includedMocs, notIncludedMocs, includedUis); if (!this->MocExecutable.empty()) { - this->GenerateMocFiles(includedMocs, notIncludedMocs); + if (!this->GenerateMocFiles(includedMocs, notIncludedMocs)) { + return false; + } } if (!this->UicExecutable.empty()) { - this->GenerateUiFiles(includedUis); + if (!this->GenerateUiFiles(includedUis)) { + return false; + } } if (!this->RccExecutable.empty()) { - this->GenerateQrcFiles(); - } - - if (this->RunMocFailed) { - std::ostringstream err; - err << "moc failed..." << std::endl; - this->LogError(err.str()); - return false; - } - if (this->RunUicFailed) { - std::ostringstream err; - err << "uic failed..." << std::endl; - this->LogError(err.str()); - return false; - } - if (this->RunRccFailed) { - std::ostringstream err; - err << "rcc failed..." << std::endl; - this->LogError(err.str()); - return false; + if (!this->GenerateQrcFiles()) { + return false; + } } return true; } -void cmQtAutoGenerators::ParseCppFile( +/** + * @return True on success + */ +bool cmQtAutoGenerators::ParseCppFile( const std::string& absFilename, const std::vector<std::string>& headerExtensions, std::map<std::string, std::string>& includedMocs, @@ -579,12 +613,12 @@ void cmQtAutoGenerators::ParseCppFile( std::ostringstream err; err << "AUTOGEN: warning: " << absFilename << ": file is empty\n" << std::endl; - this->LogError(err.str()); - return; + this->LogWarning(err.str()); + return true; } this->ParseForUic(absFilename, contentsString, includedUis); if (this->MocExecutable.empty()) { - return; + return true; } const std::string absPath = cmsys::SystemTools::GetFilenamePath( @@ -648,7 +682,7 @@ void cmQtAutoGenerators::ParseCppFile( << std::endl; } this->LogError(err.str()); - ::exit(EXIT_FAILURE); + return false; } } else { std::string fileToMoc = absFilename; @@ -670,7 +704,7 @@ void cmQtAutoGenerators::ParseCppFile( << ".cpp\" for a compatibility with " "strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n" << std::endl; - this->LogError(err.str()); + this->LogWarning(err.str()); } else { std::ostringstream err; err << "AUTOGEN: warning: " << absFilename @@ -683,7 +717,7 @@ void cmQtAutoGenerators::ParseCppFile( << ".cpp\" for compatibility with " "strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n" << std::endl; - this->LogError(err.str()); + this->LogWarning(err.str()); } } else { std::ostringstream err; @@ -696,7 +730,7 @@ void cmQtAutoGenerators::ParseCppFile( "header.\n" << std::endl; this->LogError(err.str()); - ::exit(EXIT_FAILURE); + return false; } } else { dotMocIncluded = true; @@ -727,7 +761,7 @@ void cmQtAutoGenerators::ParseCppFile( << ".moc\" for compatibility with " "strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n" << std::endl; - this->LogError(err.str()); + this->LogWarning(err.str()); includedMocs[absFilename] = ownMocUnderscoreFile; includedMocs.erase(ownMocHeaderFile); @@ -740,13 +774,17 @@ void cmQtAutoGenerators::ParseCppFile( << "\"" << scannedFileBasename << ".moc\" !\n" << std::endl; this->LogError(err.str()); - - ::exit(EXIT_FAILURE); + return false; } } + + return true; } -void cmQtAutoGenerators::StrictParseCppFile( +/** + * @return True on success + */ +bool cmQtAutoGenerators::StrictParseCppFile( const std::string& absFilename, const std::vector<std::string>& headerExtensions, std::map<std::string, std::string>& includedMocs, @@ -761,12 +799,12 @@ void cmQtAutoGenerators::StrictParseCppFile( std::ostringstream err; err << "AUTOGEN: warning: " << absFilename << ": file is empty\n" << std::endl; - this->LogError(err.str()); - return; + this->LogWarning(err.str()); + return true; } this->ParseForUic(absFilename, contentsString, includedUis); if (this->MocExecutable.empty()) { - return; + return true; } const std::string absPath = cmsys::SystemTools::GetFilenamePath( @@ -819,7 +857,7 @@ void cmQtAutoGenerators::StrictParseCppFile( << std::endl; } this->LogError(err.str()); - ::exit(EXIT_FAILURE); + return false; } } else { if (basename != scannedFileBasename) { @@ -835,7 +873,7 @@ void cmQtAutoGenerators::StrictParseCppFile( "moc on this source file.\n" << std::endl; this->LogError(err.str()); - ::exit(EXIT_FAILURE); + return false; } dotMocIncluded = true; includedMocs[absFilename] = currentMoc; @@ -857,8 +895,10 @@ void cmQtAutoGenerators::StrictParseCppFile( << "\"" << scannedFileBasename << ".moc\" !\n" << std::endl; this->LogError(err.str()); - ::exit(EXIT_FAILURE); + return false; } + + return true; } void cmQtAutoGenerators::ParseForUic( @@ -873,7 +913,7 @@ void cmQtAutoGenerators::ParseForUic( std::ostringstream err; err << "AUTOGEN: warning: " << absFilename << ": file is empty\n" << std::endl; - this->LogError(err.str()); + this->LogWarning(err.str()); return; } this->ParseForUic(absFilename, contentsString, includedUis); @@ -950,8 +990,6 @@ void cmQtAutoGenerators::ParseHeaders( std::map<std::string, std::string>& notIncludedMocs, std::map<std::string, std::vector<std::string> >& includedUis) { - cmFilePathUuid fpathUuid(this->Srcdir, this->Builddir, - this->ProjectSourceDir, this->ProjectBinaryDir); for (std::set<std::string>::const_iterator hIt = absHeaders.begin(); hIt != absHeaders.end(); ++hIt) { const std::string& headerName = *hIt; @@ -967,8 +1005,10 @@ void cmQtAutoGenerators::ParseHeaders( std::string macroName; if (requiresMocing(contents, macroName)) { - notIncludedMocs[headerName] = - this->TargetBuildSubDir + fpathUuid.get(headerName, "moc_", ".cpp"); + notIncludedMocs[headerName] = fpathCheckSum.getPart(headerName) + + "/moc_" + + cmsys::SystemTools::GetFilenameWithoutLastExtension(headerName) + + ".cpp"; } } this->ParseForUic(headerName, contents, includedUis); @@ -994,44 +1034,52 @@ bool cmQtAutoGenerators::GenerateMocFiles( << "To avoid this error either" << std::endl << "- rename the source files or" << std::endl << "- do not include the (moc_NAME.cpp|NAME.moc) file" << std::endl; - this->NameCollisionLog(err.str(), collisions); - ::exit(EXIT_FAILURE); + this->LogErrorNameCollision(err.str(), collisions); + return false; } } // generate moc files that are included by source files. - for (std::map<std::string, std::string>::const_iterator it = - includedMocs.begin(); - it != includedMocs.end(); ++it) { - if (!this->GenerateMoc(it->first, it->second)) { - if (this->RunMocFailed) { - return false; + { + const std::string subDirPrefix = "include/"; + for (std::map<std::string, std::string>::const_iterator it = + includedMocs.begin(); + it != includedMocs.end(); ++it) { + if (!this->GenerateMoc(it->first, it->second, subDirPrefix)) { + if (this->RunMocFailed) { + return false; + } } } } // generate moc files that are _not_ included by source files. bool automocCppChanged = false; - for (std::map<std::string, std::string>::const_iterator it = - notIncludedMocs.begin(); - it != notIncludedMocs.end(); ++it) { - if (this->GenerateMoc(it->first, it->second)) { - automocCppChanged = true; - } else { - if (this->RunMocFailed) { - return false; + { + const std::string subDirPrefix; + for (std::map<std::string, std::string>::const_iterator it = + notIncludedMocs.begin(); + it != notIncludedMocs.end(); ++it) { + if (this->GenerateMoc(it->first, it->second, subDirPrefix)) { + automocCppChanged = true; + } else { + if (this->RunMocFailed) { + return false; + } } } } - // compose _automoc.cpp content + // Compose moc_compilation.cpp content std::string automocSource; { std::ostringstream outStream; outStream << "/* This file is autogenerated, do not edit*/\n"; if (notIncludedMocs.empty()) { + // Dummy content outStream << "enum some_compilers { need_more_than_nothing };\n"; } else { + // Valid content for (std::map<std::string, std::string>::const_iterator it = notIncludedMocs.begin(); it != notIncludedMocs.end(); ++it) { @@ -1042,12 +1090,12 @@ bool cmQtAutoGenerators::GenerateMocFiles( automocSource = outStream.str(); } - // check if we even need to update _automoc.cpp + // Check if we even need to update moc_compilation.cpp if (!automocCppChanged) { - // compare contents of the _automoc.cpp file + // compare contents of the moc_compilation.cpp file const std::string oldContents = ReadAll(this->OutMocCppFilenameAbs); if (oldContents == automocSource) { - // nothing changed: don't touch the _automoc.cpp file + // nothing changed: don't touch the moc_compilation.cpp file if (this->Verbose) { std::ostringstream err; err << "AUTOGEN: " << this->OutMocCppFilenameRel << " still up to date" @@ -1058,43 +1106,58 @@ bool cmQtAutoGenerators::GenerateMocFiles( } } - // actually write _automoc.cpp + // Actually write moc_compilation.cpp { - std::string msg = "Generating moc compilation "; + std::string msg = "Generating MOC compilation "; msg += this->OutMocCppFilenameRel; - cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundBlue | - cmsysTerminal_Color_ForegroundBold, - msg.c_str(), true, this->ColorOutput); + this->LogBold(msg); } - { + // Make sure the parent directory exists + bool success = this->makeParentDirectory(this->OutMocCppFilenameAbs); + if (success) { cmsys::ofstream outfile; outfile.open(this->OutMocCppFilenameAbs.c_str(), std::ios::trunc); - outfile << automocSource; - outfile.close(); + if (!outfile) { + success = false; + std::ostringstream err; + err << "AUTOGEN: error opening " << this->OutMocCppFilenameAbs << "\n"; + this->LogError(err.str()); + } else { + outfile << automocSource; + // Check for write errors + if (!outfile.good()) { + success = false; + std::ostringstream err; + err << "AUTOGEN: error writing " << this->OutMocCppFilenameAbs << "\n"; + this->LogError(err.str()); + } + } } - - return true; + return success; } +/** + * @return True if a moc file was created. False may indicate an error. + */ bool cmQtAutoGenerators::GenerateMoc(const std::string& sourceFile, - const std::string& mocFileName) + const std::string& mocFileName, + const std::string& subDirPrefix) { - const std::string mocFilePath = this->Builddir + mocFileName; + const std::string mocFileRel = + this->AutogenBuildSubDir + subDirPrefix + mocFileName; + const std::string mocFileAbs = this->CurrentBinaryDir + mocFileRel; int sourceNewerThanMoc = 0; - bool success = cmsys::SystemTools::FileTimeCompare(sourceFile, mocFilePath, + bool success = cmsys::SystemTools::FileTimeCompare(sourceFile, mocFileAbs, &sourceNewerThanMoc); if (this->GenerateAll || !success || sourceNewerThanMoc >= 0) { - // make sure the directory for the resulting moc file exists - std::string mocDir = mocFilePath.substr(0, mocFilePath.rfind('/')); - if (!cmsys::SystemTools::FileExists(mocDir.c_str(), false)) { - cmsys::SystemTools::MakeDirectory(mocDir.c_str()); - } + // Log + this->LogBold("Generating MOC source " + mocFileRel); - std::string msg = "Generating moc source "; - msg += mocFileName; - cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundBlue | - cmsysTerminal_Color_ForegroundBold, - msg.c_str(), true, this->ColorOutput); + // Make sure the parent directory exists + if (!this->makeParentDirectory(mocFileAbs)) { + this->RunMocFailed = true; + return false; + } std::vector<std::string> command; command.push_back(this->MocExecutable); @@ -1108,7 +1171,7 @@ bool cmQtAutoGenerators::GenerateMoc(const std::string& sourceFile, command.push_back("-DWIN32"); #endif command.push_back("-o"); - command.push_back(mocFilePath); + command.push_back(mocFileAbs); command.push_back(sourceFile); if (this->Verbose) { @@ -1120,12 +1183,15 @@ bool cmQtAutoGenerators::GenerateMoc(const std::string& sourceFile, bool result = cmSystemTools::RunSingleCommand(command, &output, &output, &retVal); if (!result || retVal) { - std::ostringstream err; - err << "AUTOGEN: error: process for " << mocFilePath << " failed:\n" - << output << std::endl; - this->LogError(err.str()); + { + std::ostringstream err; + err << "AUTOGEN: error: moc process for " << mocFileRel << " failed:\n" + << output << std::endl; + this->LogError(err.str()); + } + cmSystemTools::RemoveFile(mocFileAbs); this->RunMocFailed = true; - cmSystemTools::RemoveFile(mocFilePath); + return false; } return true; } @@ -1166,8 +1232,8 @@ bool cmQtAutoGenerators::GenerateUiFiles( "from different sources." << std::endl << "To avoid this error rename the source files." << std::endl; - this->NameCollisionLog(err.str(), collisions); - ::exit(EXIT_FAILURE); + this->LogErrorNameCollision(err.str(), collisions); + return false; } } testMap.clear(); @@ -1191,25 +1257,29 @@ bool cmQtAutoGenerators::GenerateUiFiles( return true; } +/** + * @return True if a uic file was created. False may indicate an error. + */ bool cmQtAutoGenerators::GenerateUi(const std::string& realName, const std::string& uiInputFile, const std::string& uiOutputFile) { - if (!cmsys::SystemTools::FileExists(this->Builddir.c_str(), false)) { - cmsys::SystemTools::MakeDirectory(this->Builddir.c_str()); - } - - const std::string uiBuildFile = this->Builddir + uiOutputFile; + const std::string uicFileRel = + this->AutogenBuildSubDir + "include/" + uiOutputFile; + const std::string uicFileAbs = this->CurrentBinaryDir + uicFileRel; int sourceNewerThanUi = 0; - bool success = cmsys::SystemTools::FileTimeCompare(uiInputFile, uiBuildFile, + bool success = cmsys::SystemTools::FileTimeCompare(uiInputFile, uicFileAbs, &sourceNewerThanUi); if (this->GenerateAll || !success || sourceNewerThanUi >= 0) { - std::string msg = "Generating ui header "; - msg += uiOutputFile; - cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundBlue | - cmsysTerminal_Color_ForegroundBold, - msg.c_str(), true, this->ColorOutput); + // Log + this->LogBold("Generating UIC header " + uicFileRel); + + // Make sure the parent directory exists + if (!this->makeParentDirectory(uicFileAbs)) { + this->RunUicFailed = true; + return false; + } std::vector<std::string> command; command.push_back(this->UicExecutable); @@ -1226,7 +1296,7 @@ bool cmQtAutoGenerators::GenerateUi(const std::string& realName, command.insert(command.end(), opts.begin(), opts.end()); command.push_back("-o"); - command.push_back(uiBuildFile); + command.push_back(uicFileAbs); command.push_back(uiInputFile); if (this->Verbose) { @@ -1237,13 +1307,15 @@ bool cmQtAutoGenerators::GenerateUi(const std::string& realName, bool result = cmSystemTools::RunSingleCommand(command, &output, &output, &retVal); if (!result || retVal) { - std::ostringstream err; - err << "AUTOUIC: error: process for " << uiOutputFile - << " needed by\n \"" << realName << "\"\nfailed:\n" - << output << std::endl; - this->LogError(err.str()); + { + std::ostringstream err; + err << "AUTOUIC: error: uic process for " << uicFileRel + << " needed by\n \"" << realName << "\"\nfailed:\n" + << output << std::endl; + this->LogError(err.str()); + } + cmSystemTools::RemoveFile(uicFileAbs); this->RunUicFailed = true; - cmSystemTools::RemoveFile(uiOutputFile); return false; } return true; @@ -1271,18 +1343,13 @@ bool cmQtAutoGenerators::GenerateQrcFiles() { // generate single map with input / output names std::map<std::string, std::string> qrcGenMap; - { - cmFilePathUuid fpathUuid(this->Srcdir, this->Builddir, - this->ProjectSourceDir, this->ProjectBinaryDir); - for (std::vector<std::string>::const_iterator si = - this->RccSources.begin(); - si != this->RccSources.end(); ++si) { - const std::string ext = - cmsys::SystemTools::GetFilenameLastExtension(*si); - if (ext == ".qrc") { - qrcGenMap[*si] = - (this->TargetBuildSubDir + fpathUuid.get(*si, "qrc_", ".cpp")); - } + for (std::vector<std::string>::const_iterator si = this->RccSources.begin(); + si != this->RccSources.end(); ++si) { + const std::string ext = cmsys::SystemTools::GetFilenameLastExtension(*si); + if (ext == ".qrc") { + qrcGenMap[*si] = this->AutogenBuildSubDir + fpathCheckSum.getPart(*si) + + "/qrc_" + cmsys::SystemTools::GetFilenameWithoutLastExtension(*si) + + ".cpp"; } } @@ -1295,8 +1362,8 @@ bool cmQtAutoGenerators::GenerateQrcFiles() " will be generated from different sources." << std::endl << "To avoid this error rename the source .qrc files." << std::endl; - this->NameCollisionLog(err.str(), collisions); - ::exit(EXIT_FAILURE); + this->LogErrorNameCollision(err.str(), collisions); + return false; } } @@ -1314,25 +1381,24 @@ bool cmQtAutoGenerators::GenerateQrcFiles() return true; } +/** + * @return True if a rcc file was created. False may indicate an error. + */ bool cmQtAutoGenerators::GenerateQrc(const std::string& qrcInputFile, const std::string& qrcOutputFile, bool unique_n) { - std::string symbolName; - if (unique_n) { - symbolName = - cmsys::SystemTools::GetFilenameWithoutLastExtension(qrcInputFile); - } else { - symbolName = - cmsys::SystemTools::GetFilenameWithoutLastExtension(qrcOutputFile); - // Remove "qrc_" at string begin - symbolName.erase(0, 4); + std::string symbolName = + cmsys::SystemTools::GetFilenameWithoutLastExtension(qrcInputFile); + if (!unique_n) { + symbolName += "_"; + symbolName += fpathCheckSum.getPart(qrcInputFile); } // Replace '-' with '_'. The former is valid for // file names but not for symbol names. std::replace(symbolName.begin(), symbolName.end(), '-', '_'); - const std::string qrcBuildFile = this->Builddir + qrcOutputFile; + const std::string qrcBuildFile = this->CurrentBinaryDir + qrcOutputFile; int sourceNewerThanQrc = 0; bool generateQrc = !cmsys::SystemTools::FileTimeCompare( @@ -1342,21 +1408,27 @@ bool cmQtAutoGenerators::GenerateQrc(const std::string& qrcInputFile, generateQrc || this->InputFilesNewerThanQrc(qrcInputFile, qrcBuildFile); if (this->GenerateAll || generateQrc) { - std::string msg = "Generating qrc source "; - msg += qrcOutputFile; - cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundBlue | - cmsysTerminal_Color_ForegroundBold, - msg.c_str(), true, this->ColorOutput); + { + std::string msg = "Generating RCC source "; + msg += qrcOutputFile; + this->LogBold(msg); + } + + // Make sure the parent directory exists + if (!this->makeParentDirectory(qrcOutputFile)) { + this->RunRccFailed = true; + return false; + } std::vector<std::string> command; command.push_back(this->RccExecutable); - - std::map<std::string, std::string>::const_iterator optionIt = - this->RccOptions.find(qrcInputFile); - if (optionIt != this->RccOptions.end()) { - cmSystemTools::ExpandListArgument(optionIt->second, command); + { + std::map<std::string, std::string>::const_iterator optionIt = + this->RccOptions.find(qrcInputFile); + if (optionIt != this->RccOptions.end()) { + cmSystemTools::ExpandListArgument(optionIt->second, command); + } } - command.push_back("-name"); command.push_back(symbolName); command.push_back("-o"); @@ -1371,16 +1443,20 @@ bool cmQtAutoGenerators::GenerateQrc(const std::string& qrcInputFile, bool result = cmSystemTools::RunSingleCommand(command, &output, &output, &retVal); if (!result || retVal) { - std::ostringstream err; - err << "AUTORCC: error: process for " << qrcOutputFile << " failed:\n" - << output << std::endl; - this->LogError(err.str()); - this->RunRccFailed = true; + { + std::ostringstream err; + err << "AUTORCC: error: rcc process for " << qrcOutputFile + << " failed:\n" + << output << std::endl; + this->LogError(err.str()); + } cmSystemTools::RemoveFile(qrcBuildFile); + this->RunRccFailed = true; return false; } + return true; } - return true; + return false; } /** @@ -1413,7 +1489,7 @@ bool cmQtAutoGenerators::NameCollisionTest( return !collisions.empty(); } -void cmQtAutoGenerators::NameCollisionLog( +void cmQtAutoGenerators::LogErrorNameCollision( const std::string& message, const std::multimap<std::string, std::string>& collisions) { @@ -1429,14 +1505,30 @@ void cmQtAutoGenerators::NameCollisionLog( this->LogError(err.str()); } +void cmQtAutoGenerators::LogBold(const std::string& message) +{ + cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundBlue | + cmsysTerminal_Color_ForegroundBold, + message.c_str(), true, this->ColorOutput); +} + void cmQtAutoGenerators::LogInfo(const std::string& message) { - std::cout << message; + std::cout << message.c_str(); +} + +void cmQtAutoGenerators::LogWarning(const std::string& message) +{ + std::ostringstream ostr; + ostr << message << "\n"; + std::cout << message.c_str(); } void cmQtAutoGenerators::LogError(const std::string& message) { - std::cerr << message; + std::ostringstream ostr; + ostr << message << "\n\n"; + std::cerr << ostr.str(); } void cmQtAutoGenerators::LogCommand(const std::vector<std::string>& command) @@ -1455,6 +1547,25 @@ void cmQtAutoGenerators::LogCommand(const std::vector<std::string>& command) } } +/** + * @brief Generates the parent directory of the given file on demand + * @return True on success + */ +bool cmQtAutoGenerators::makeParentDirectory(const std::string& filename) +{ + bool success = true; + const std::string dirName = cmSystemTools::GetFilenamePath(filename); + if (!dirName.empty()) { + success = cmsys::SystemTools::MakeDirectory(dirName); + if (!success) { + std::ostringstream err; + err << "AUTOGEN: Directory creation failed: " << dirName << std::endl; + this->LogError(err.str()); + } + } + return success; +} + std::string cmQtAutoGenerators::JoinExts(const std::vector<std::string>& lst) { if (lst.empty()) { diff --git a/Source/cmQtAutoGenerators.h b/Source/cmQtAutoGenerators.h index 08d7e03..c241579 100644 --- a/Source/cmQtAutoGenerators.h +++ b/Source/cmQtAutoGenerators.h @@ -4,6 +4,7 @@ #define cmQtAutoGenerators_h #include <cmConfigure.h> // IWYU pragma: keep +#include <cmFilePathChecksum.h> #include <list> #include <map> @@ -23,32 +24,36 @@ private: bool ReadAutogenInfoFile(cmMakefile* makefile, const std::string& targetDirectory, const std::string& config); - bool ReadOldMocDefinitionsFile(cmMakefile* makefile, + void ReadOldMocDefinitionsFile(cmMakefile* makefile, const std::string& targetDirectory); - void WriteOldMocDefinitionsFile(const std::string& targetDirectory); + bool WriteOldMocDefinitionsFile(const std::string& targetDirectory); std::string MakeCompileSettingsString(cmMakefile* makefile); bool RunAutogen(cmMakefile* makefile); + bool GenerateMocFiles( const std::map<std::string, std::string>& includedMocs, const std::map<std::string, std::string>& notIncludedMocs); bool GenerateMoc(const std::string& sourceFile, - const std::string& mocFileName); + const std::string& mocFileName, + const std::string& subDirPrefix); + bool GenerateUiFiles( const std::map<std::string, std::vector<std::string> >& includedUis); bool GenerateUi(const std::string& realName, const std::string& uiInputFile, const std::string& uiOutputFile); + bool GenerateQrcFiles(); bool GenerateQrc(const std::string& qrcInputFile, const std::string& qrcOutputFile, bool unique_n); - void ParseCppFile( + bool ParseCppFile( const std::string& absFilename, const std::vector<std::string>& headerExtensions, std::map<std::string, std::string>& includedMocs, std::map<std::string, std::vector<std::string> >& includedUis); - void StrictParseCppFile( + bool StrictParseCppFile( const std::string& absFilename, const std::vector<std::string>& headerExtensions, std::map<std::string, std::string>& includedMocs, @@ -76,13 +81,18 @@ private: bool NameCollisionTest(const std::map<std::string, std::string>& genFiles, std::multimap<std::string, std::string>& collisions); - void NameCollisionLog( + + void LogErrorNameCollision( const std::string& message, const std::multimap<std::string, std::string>& collisions); - + void LogBold(const std::string& message); void LogInfo(const std::string& message); + void LogWarning(const std::string& message); void LogError(const std::string& message); void LogCommand(const std::vector<std::string>& command); + + bool makeParentDirectory(const std::string& filename); + std::string JoinExts(const std::vector<std::string>& lst); static void MergeUicOptions(std::vector<std::string>& opts, @@ -92,39 +102,47 @@ private: bool InputFilesNewerThanQrc(const std::string& qrcFile, const std::string& rccOutput); + // - Target names + std::string OriginTargetName; + std::string AutogenTargetName; + // - Directories + std::string ProjectSourceDir; + std::string ProjectBinaryDir; + std::string CurrentSourceDir; + std::string CurrentBinaryDir; + std::string AutogenBuildSubDir; + // - Qt environment std::string QtMajorVersion; - std::string Sources; - std::vector<std::string> RccSources; - std::string SkipMoc; - std::string SkipUic; - std::string Headers; - std::string Srcdir; - std::string Builddir; std::string MocExecutable; std::string UicExecutable; std::string RccExecutable; + // - File lists + std::string Sources; + std::string Headers; + // - Moc + std::string SkipMoc; std::string MocCompileDefinitionsStr; std::string MocIncludesStr; std::string MocOptionsStr; - std::string ProjectBinaryDir; - std::string ProjectSourceDir; - std::string TargetName; - std::string OriginTargetName; - - std::string CurrentCompileSettingsStr; - std::string OldCompileSettingsStr; - - std::string TargetBuildSubDir; std::string OutMocCppFilenameRel; std::string OutMocCppFilenameAbs; std::list<std::string> MocIncludes; std::list<std::string> MocDefinitions; std::vector<std::string> MocOptions; + // - Uic + std::string SkipUic; std::vector<std::string> UicTargetOptions; std::map<std::string, std::string> UicOptions; + // - Rcc + std::vector<std::string> RccSources; std::map<std::string, std::string> RccOptions; std::map<std::string, std::vector<std::string> > RccInputs; - + // - Settings + std::string CurrentCompileSettingsStr; + std::string OldCompileSettingsStr; + // - Utility + cmFilePathChecksum fpathCheckSum; + // - Flags bool IncludeProjectDirsBefore; bool Verbose; bool ColorOutput; @@ -132,7 +150,7 @@ private: bool RunUicFailed; bool RunRccFailed; bool GenerateAll; - bool RelaxedMode; + bool MocRelaxedMode; }; #endif diff --git a/Source/cmRulePlaceholderExpander.h b/Source/cmRulePlaceholderExpander.h index 5223ae9..8329166 100644 --- a/Source/cmRulePlaceholderExpander.h +++ b/Source/cmRulePlaceholderExpander.h @@ -56,7 +56,6 @@ public: const char* LanguageCompileFlags; const char* Defines; const char* Includes; - const char* RuleLauncher; const char* DependencyFile; const char* FilterPrefix; }; diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx index 3776538..c08a36b 100644 --- a/Source/cmServerProtocol.cxx +++ b/Source/cmServerProtocol.cxx @@ -672,8 +672,9 @@ static Json::Value DumpSourceFilesList( std::string compileFlags = ld.Flags; if (const char* cflags = file->GetProperty("COMPILE_FLAGS")) { cmGeneratorExpression ge; + auto cge = ge.Parse(cflags); const char* processed = - ge.Parse(cflags)->Evaluate(target->GetLocalGenerator(), config); + cge->Evaluate(target->GetLocalGenerator(), config); lg->AppendFlags(compileFlags, processed); } fileData.Flags = compileFlags; diff --git a/Source/cmVisualStudioGeneratorOptions.cxx b/Source/cmVisualStudioGeneratorOptions.cxx index 62200ce..c0913e6 100644 --- a/Source/cmVisualStudioGeneratorOptions.cxx +++ b/Source/cmVisualStudioGeneratorOptions.cxx @@ -130,7 +130,17 @@ void cmVisualStudioGeneratorOptions::SetVerboseMakefile(bool verbose) bool cmVisualStudioGeneratorOptions::IsDebug() const { - return this->FlagMap.find("DebugInformationFormat") != this->FlagMap.end(); + if (this->CurrentTool != CSharpCompiler) { + return this->FlagMap.find("DebugInformationFormat") != this->FlagMap.end(); + } + std::map<std::string, FlagValue>::const_iterator i = + this->FlagMap.find("DebugType"); + if (i != this->FlagMap.end()) { + if (i->second.size() == 1) { + return i->second[0] != "none"; + } + } + return false; } bool cmVisualStudioGeneratorOptions::IsWinRt() const diff --git a/Source/cmVisualStudioGeneratorOptions.h b/Source/cmVisualStudioGeneratorOptions.h index e27c5d3..ab6b8cc 100644 --- a/Source/cmVisualStudioGeneratorOptions.h +++ b/Source/cmVisualStudioGeneratorOptions.h @@ -28,7 +28,8 @@ public: ResourceCompiler, MasmCompiler, Linker, - FortranCompiler + FortranCompiler, + CSharpCompiler }; cmVisualStudioGeneratorOptions(cmLocalVisualStudioGenerator* lg, Tool tool, cmVS7FlagTable const* table, diff --git a/Source/cmake.h b/Source/cmake.h index 0f1891d..5347745 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -549,6 +549,7 @@ private: F(cxx_std_98) \ F(cxx_std_11) \ F(cxx_std_14) \ + F(cxx_std_17) \ F(cxx_aggregate_default_initializers) \ F(cxx_alias_templates) \ F(cxx_alignas) \ diff --git a/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt index b8a9a6b..9eb3b2d 100644 --- a/Source/kwsys/CMakeLists.txt +++ b/Source/kwsys/CMakeLists.txt @@ -429,6 +429,17 @@ SET_SOURCE_FILES_PROPERTIES(ProcessUNIX.c System.c PROPERTIES COMPILE_FLAGS "-DKWSYS_C_HAS_PTRDIFF_T=${KWSYS_C_HAS_PTRDIFF_T} -DKWSYS_C_HAS_SSIZE_T=${KWSYS_C_HAS_SSIZE_T}" ) +IF(KWSYS_USE_DynamicLoader) + GET_PROPERTY(KWSYS_SUPPORTS_SHARED_LIBS GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS) + IF(KWSYS_SUPPORTS_SHARED_LIBS) + SET(KWSYS_SUPPORTS_SHARED_LIBS 1) + ELSE() + SET(KWSYS_SUPPORTS_SHARED_LIBS 0) + ENDIF() + SET_PROPERTY(SOURCE DynamicLoader.cxx APPEND PROPERTY COMPILE_DEFINITIONS + KWSYS_SUPPORTS_SHARED_LIBS=${KWSYS_SUPPORTS_SHARED_LIBS}) +ENDIF() + IF(KWSYS_USE_SystemTools) KWSYS_PLATFORM_CXX_TEST(KWSYS_CXX_HAS_SETENV "Checking whether CXX compiler has setenv" DIRECT) @@ -868,7 +879,7 @@ ENDIF() IF(KWSYS_USE_Encoding) # Set default 8 bit encoding in "EndcodingC.c". - SET_PROPERTY(SOURCE EncodingC.c APPEND PROPERTY COMPILE_DEFINITIONS + SET_PROPERTY(SOURCE EncodingC.c EncodingCXX.cxx APPEND PROPERTY COMPILE_DEFINITIONS KWSYS_ENCODING_DEFAULT_CODEPAGE=${KWSYS_ENCODING_DEFAULT_CODEPAGE}) ENDIF() diff --git a/Source/kwsys/ConsoleBuf.hxx.in b/Source/kwsys/ConsoleBuf.hxx.in index c45a351..cb58865 100644 --- a/Source/kwsys/ConsoleBuf.hxx.in +++ b/Source/kwsys/ConsoleBuf.hxx.in @@ -327,14 +327,13 @@ private: const int length = WideCharToMultiByte(m_activeOutputCodepage, 0, wbuffer.c_str(), (int)wbuffer.size(), NULL, 0, NULL, NULL); - char* buf = new char[length + 1]; + char* buf = new char[length]; const bool success = WideCharToMultiByte(m_activeOutputCodepage, 0, wbuffer.c_str(), (int)wbuffer.size(), buf, length, NULL, NULL) > 0 ? true : false; - buf[length] = '\0'; - buffer = buf; + buffer = std::string(buf, length); delete[] buf; return success; } diff --git a/Source/kwsys/DynamicLoader.cxx b/Source/kwsys/DynamicLoader.cxx index e0268c0..e494db6 100644 --- a/Source/kwsys/DynamicLoader.cxx +++ b/Source/kwsys/DynamicLoader.cxx @@ -12,20 +12,63 @@ #include "DynamicLoader.hxx.in" #endif -// This file is actually 3 different implementations. -// 1. HP machines which uses shl_load -// 2. Mac OS X 10.2.x and earlier which uses NSLinkModule -// 3. Windows which uses LoadLibrary -// 4. Most unix systems (including Mac OS X 10.3 and later) which use dlopen -// (default) Each part of the ifdef contains a complete implementation for +// This file actually contains several different implementations: +// * NOOP for environments without dynamic libs +// * HP machines which uses shl_load +// * Mac OS X 10.2.x and earlier which uses NSLinkModule +// * Windows which uses LoadLibrary +// * BeOS / Haiku +// * FreeMiNT for Atari +// * Default implementation for *NIX systems (including Mac OS X 10.3 and +// later) which use dlopen +// +// Each part of the ifdef contains a complete implementation for // the static methods of DynamicLoader. -// --------------------------------------------------------------- -// 1. Implementation for HPUX machines -#ifdef __hpux +#if !KWSYS_SUPPORTS_SHARED_LIBS +//---------------------------------------------------------------------------- +// Implementation for environments without dynamic libs +#include <string.h> // for strerror() + +namespace KWSYS_NAMESPACE { + +//---------------------------------------------------------------------------- +DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( + const std::string& libname) +{ + return 0; +} + +//---------------------------------------------------------------------------- +int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib) +{ + if (!lib) { + return 0; + } + + return 1; +} + +//---------------------------------------------------------------------------- +DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( + DynamicLoader::LibraryHandle lib, const std::string& sym) +{ + return 0; +} + +//---------------------------------------------------------------------------- +const char* DynamicLoader::LastError() +{ + return "General error"; +} + +} // namespace KWSYS_NAMESPACE + +#elif defined(__hpux) +//---------------------------------------------------------------------------- +// Implementation for HPUX machines #include <dl.h> #include <errno.h> -#define DYNAMICLOADER_DEFINED 1 namespace KWSYS_NAMESPACE { @@ -88,15 +131,11 @@ const char* DynamicLoader::LastError() } // namespace KWSYS_NAMESPACE -#endif //__hpux - -// --------------------------------------------------------------- -// 2. Implementation for Mac OS X 10.2.x and earlier -#ifdef __APPLE__ -#if MAC_OS_X_VERSION_MAX_ALLOWED < 1030 +#elif defined(__APPLE__) && (MAC_OS_X_VERSION_MAX_ALLOWED < 1030) +//---------------------------------------------------------------------------- +// Implementation for Mac OS X 10.2.x and earlier #include <mach-o/dyld.h> #include <string.h> // for strlen -#define DYNAMICLOADER_DEFINED 1 namespace KWSYS_NAMESPACE { @@ -160,14 +199,10 @@ const char* DynamicLoader::LastError() } // namespace KWSYS_NAMESPACE -#endif // MAC_OS_X_VERSION_MAX_ALLOWED < 1030 -#endif // __APPLE__ - -// --------------------------------------------------------------- -// 3. Implementation for Windows win32 code but not cygwin -#if defined(_WIN32) && !defined(__CYGWIN__) +#elif defined(_WIN32) && !defined(__CYGWIN__) +//---------------------------------------------------------------------------- +// Implementation for Windows win32 code but not cygwin #include <windows.h> -#define DYNAMICLOADER_DEFINED 1 namespace KWSYS_NAMESPACE { @@ -263,19 +298,14 @@ const char* DynamicLoader::LastError() } // namespace KWSYS_NAMESPACE -#endif //_WIN32 - -// --------------------------------------------------------------- -// 4. Implementation for BeOS -#if defined __BEOS__ - +#elif defined(__BEOS__) +//---------------------------------------------------------------------------- +// Implementation for BeOS / Haiku #include <string.h> // for strerror() #include <be/kernel/image.h> #include <be/support/Errors.h> -#define DYNAMICLOADER_DEFINED 1 - namespace KWSYS_NAMESPACE { static image_id last_dynamic_err = B_OK; @@ -351,54 +381,10 @@ const char* DynamicLoader::LastError() } } // namespace KWSYS_NAMESPACE -#endif - -// --------------------------------------------------------------- -// 5. Implementation for systems without dynamic libs -// __gnu_blrts__ is IBM BlueGene/L -// __LIBCATAMOUNT__ is defined on Catamount on Cray compute nodes -#if defined(__gnu_blrts__) || defined(__LIBCATAMOUNT__) || \ - defined(__CRAYXT_COMPUTE_LINUX_TARGET) -#include <string.h> // for strerror() -#define DYNAMICLOADER_DEFINED 1 - -namespace KWSYS_NAMESPACE { - -//---------------------------------------------------------------------------- -DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary( - const std::string& libname) -{ - return 0; -} +#elif defined(__MINT__) //---------------------------------------------------------------------------- -int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib) -{ - if (!lib) { - return 0; - } - - return 1; -} - -//---------------------------------------------------------------------------- -DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress( - DynamicLoader::LibraryHandle lib, const std::string& sym) -{ - return 0; -} - -//---------------------------------------------------------------------------- -const char* DynamicLoader::LastError() -{ - return "General error"; -} - -} // namespace KWSYS_NAMESPACE -#endif - -#ifdef __MINT__ -#define DYNAMICLOADER_DEFINED 1 +// Implementation for FreeMiNT on Atari #define _GNU_SOURCE /* for program_invocation_name */ #include <dld.h> #include <errno.h> @@ -447,14 +433,11 @@ const char* DynamicLoader::LastError() } } // namespace KWSYS_NAMESPACE -#endif -// --------------------------------------------------------------- -// 6. Implementation for default UNIX machines. -// if nothing has been defined then use this -#ifndef DYNAMICLOADER_DEFINED -#define DYNAMICLOADER_DEFINED 1 -// Setup for most unix machines +#else +//---------------------------------------------------------------------------- +// Default implementation for *NIX systems (including Mac OS X 10.3 and +// later) which use dlopen #include <dlfcn.h> namespace KWSYS_NAMESPACE { @@ -498,5 +481,4 @@ const char* DynamicLoader::LastError() } } // namespace KWSYS_NAMESPACE - #endif diff --git a/Source/kwsys/EncodingCXX.cxx b/Source/kwsys/EncodingCXX.cxx index 5c58bcb..e904c1a 100644 --- a/Source/kwsys/EncodingCXX.cxx +++ b/Source/kwsys/EncodingCXX.cxx @@ -125,12 +125,68 @@ char const* const* Encoding::CommandLineArguments::argv() const std::wstring Encoding::ToWide(const std::string& str) { - return ToWide(str.c_str()); + std::wstring wstr; +#if defined(_WIN32) + const int wlength = MultiByteToWideChar( + KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.data(), int(str.size()), NULL, 0); + if (wlength > 0) { + wchar_t* wdata = new wchar_t[wlength]; + int r = MultiByteToWideChar(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.data(), + int(str.size()), wdata, wlength); + if (r > 0) { + wstr = std::wstring(wdata, wlength); + } + delete[] wdata; + } +#else + size_t pos = 0; + size_t nullPos = 0; + do { + if (pos < str.size() && str.at(pos) != '\0') { + wstr += ToWide(str.c_str() + pos); + } + nullPos = str.find('\0', pos); + if (nullPos != str.npos) { + pos = nullPos + 1; + wstr += wchar_t('\0'); + } + } while (nullPos != str.npos); +#endif + return wstr; } std::string Encoding::ToNarrow(const std::wstring& str) { - return ToNarrow(str.c_str()); + std::string nstr; +#if defined(_WIN32) + int length = + WideCharToMultiByte(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.c_str(), + int(str.size()), NULL, 0, NULL, NULL); + if (length > 0) { + char* data = new char[length]; + int r = + WideCharToMultiByte(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, str.c_str(), + int(str.size()), data, length, NULL, NULL); + if (r > 0) { + nstr = std::string(data, length); + } + delete[] data; + } +#else + size_t pos = 0; + size_t nullPos = 0; + do { + if (pos < str.size() && str.at(pos) != '\0') { + nstr += ToNarrow(str.c_str() + pos); + } + nullPos = str.find(wchar_t('\0'), pos); + if (nullPos != str.npos) { + pos = nullPos + 1; + nstr += '\0'; + } + } while (nullPos != str.npos); +#endif + return nstr; } std::wstring Encoding::ToWide(const char* cstr) diff --git a/Source/kwsys/testConsoleBuf.cxx b/Source/kwsys/testConsoleBuf.cxx index bd58fb6..3b8cdab 100644 --- a/Source/kwsys/testConsoleBuf.cxx +++ b/Source/kwsys/testConsoleBuf.cxx @@ -18,6 +18,7 @@ #if defined(_WIN32) +#include <algorithm> #include <iomanip> #include <iostream> #include <stdexcept> @@ -318,6 +319,7 @@ static int testPipe() bytesRead == 0) { throw std::runtime_error("ReadFile#1 failed!"); } + buffer[bytesRead] = 0; if ((bytesRead < encodedTestString.size() + 1 + encodedInputTestString.size() && !ReadFile(outPipeRead, buffer + bytesRead, @@ -336,8 +338,12 @@ static int testPipe() bytesRead == 0) { throw std::runtime_error("ReadFile#3 failed!"); } - buffer2[bytesRead - 1] = 0; - didFail = encodedTestString.compare(buffer2) == 0 ? 0 : 1; + buffer2[bytesRead] = 0; + didFail = + encodedTestString.compare(0, encodedTestString.npos, buffer2, + encodedTestString.size()) == 0 + ? 0 + : 1; } if (didFail != 0) { std::cerr << "Pipe's output didn't match expected output!" @@ -423,23 +429,28 @@ static int testFile() bytesRead == 0) { throw std::runtime_error("ReadFile#1 failed!"); } - buffer[bytesRead - 1] = 0; + buffer[bytesRead] = 0; if (memcmp(buffer, encodedTestString.c_str(), encodedTestString.size()) == 0 && memcmp(buffer + encodedTestString.size() + 1, encodedInputTestString.c_str(), - encodedInputTestString.size() - 1) == 0) { + encodedInputTestString.size()) == 0) { bytesRead = 0; if (SetFilePointer(errFile, 0, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) { throw std::runtime_error("SetFilePointer#2 failed!"); } + if (!ReadFile(errFile, buffer2, sizeof(buffer2), &bytesRead, NULL) || bytesRead == 0) { throw std::runtime_error("ReadFile#2 failed!"); } - buffer2[bytesRead - 1] = 0; - didFail = encodedTestString.compare(buffer2) == 0 ? 0 : 1; + buffer2[bytesRead] = 0; + didFail = + encodedTestString.compare(0, encodedTestString.npos, buffer2, + encodedTestString.size()) == 0 + ? 0 + : 1; } if (didFail != 0) { std::cerr << "File's output didn't match expected output!" @@ -448,7 +459,7 @@ static int testFile() encodedTestString.size()); dumpBuffers<char>(encodedInputTestString.c_str(), buffer + encodedTestString.size() + 1, - encodedInputTestString.size() - 1); + encodedInputTestString.size()); dumpBuffers<char>(encodedTestString.c_str(), buffer2, encodedTestString.size()); } @@ -685,6 +696,7 @@ static int testConsole() throw std::runtime_error("ReadConsoleOutputCharacter failed!"); } std::wstring wideTestString = kwsys::Encoding::ToWide(encodedTestString); + std::replace(wideTestString.begin(), wideTestString.end(), '\0', ' '); std::wstring wideInputTestString = kwsys::Encoding::ToWide(encodedInputTestString); if (memcmp(outputBuffer, wideTestString.c_str(), @@ -757,8 +769,11 @@ int testConsoleBuf(int, char* []) return 1; } - encodedTestString = kwsys::Encoding::ToNarrow(UnicodeTestString); - encodedInputTestString = kwsys::Encoding::ToNarrow(UnicodeInputTestString); + encodedTestString = kwsys::Encoding::ToNarrow(std::wstring( + UnicodeTestString, sizeof(UnicodeTestString) / sizeof(wchar_t) - 1)); + encodedInputTestString = kwsys::Encoding::ToNarrow( + std::wstring(UnicodeInputTestString, + sizeof(UnicodeInputTestString) / sizeof(wchar_t) - 1)); encodedInputTestString += "\n"; ret |= testPipe(); diff --git a/Source/kwsys/testConsoleBuf.hxx b/Source/kwsys/testConsoleBuf.hxx index 8891960..e93cb4f 100644 --- a/Source/kwsys/testConsoleBuf.hxx +++ b/Source/kwsys/testConsoleBuf.hxx @@ -11,7 +11,7 @@ static const wchar_t AfterOutputEventName[] = L"AfterOutputEvent"; // यूनिकोड είναι здорово! static const wchar_t UnicodeTestString[] = L"\u092F\u0942\u0928\u093F\u0915\u094B\u0921 " - L"\u03B5\u03AF\u03BD\u03B1\u03B9 " + L"\u03B5\u03AF\u03BD\0\u03B1\u03B9 " L"\u0437\u0434\u043E\u0440\u043E\u0432\u043E!"; #endif diff --git a/Source/kwsys/testConsoleBufChild.cxx b/Source/kwsys/testConsoleBufChild.cxx index 313323e..83bf545 100644 --- a/Source/kwsys/testConsoleBufChild.cxx +++ b/Source/kwsys/testConsoleBufChild.cxx @@ -28,7 +28,8 @@ int main(int argc, const char* argv[]) std::cout << argv[1] << std::endl; std::cerr << argv[1] << std::endl; } else { - std::string str = kwsys::Encoding::ToNarrow(UnicodeTestString); + std::string str = kwsys::Encoding::ToNarrow(std::wstring( + UnicodeTestString, sizeof(UnicodeTestString) / sizeof(wchar_t) - 1)); std::cout << str << std::endl; std::cerr << str << std::endl; } diff --git a/Source/kwsys/testEncoding.cxx b/Source/kwsys/testEncoding.cxx index 996976f..03f2ec9 100644 --- a/Source/kwsys/testEncoding.cxx +++ b/Source/kwsys/testEncoding.cxx @@ -9,6 +9,7 @@ #include KWSYS_HEADER(Encoding.hxx) #include KWSYS_HEADER(Encoding.h) +#include <algorithm> #include <iostream> #include <locale.h> #include <stdlib.h> @@ -124,6 +125,35 @@ static int testRobustEncoding() return ret; } +static int testWithNulls() +{ + int ret = 0; + std::vector<std::string> strings; + strings.push_back(std::string("ab") + '\0' + 'c'); + strings.push_back(std::string("d") + '\0' + '\0' + 'e'); + strings.push_back(std::string() + '\0' + 'f'); + strings.push_back(std::string() + '\0' + '\0' + "gh"); + strings.push_back(std::string("ij") + '\0'); + strings.push_back(std::string("k") + '\0' + '\0'); + strings.push_back(std::string("\0\0\0\0", 4) + "lmn" + + std::string("\0\0\0\0", 4)); + for (std::vector<std::string>::iterator it = strings.begin(); + it != strings.end(); ++it) { + std::wstring wstr = kwsys::Encoding::ToWide(*it); + std::string str = kwsys::Encoding::ToNarrow(wstr); + std::string s(*it); + std::replace(s.begin(), s.end(), '\0', ' '); + std::cout << "'" << s << "' (" << it->size() << ")" << std::endl; + if (str != *it) { + std::replace(str.begin(), str.end(), '\0', ' '); + std::cout << "string with null was different: '" << str << "' (" + << str.size() << ")" << std::endl; + ret++; + } + } + return ret; +} + static int testCommandLineArguments() { int status = 0; @@ -165,6 +195,7 @@ int testEncoding(int, char* []) ret |= testHelloWorldEncoding(); ret |= testRobustEncoding(); ret |= testCommandLineArguments(); + ret |= testWithNulls(); return ret; } diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index fa5f3e8..73eef9a 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -1400,6 +1400,10 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release add_subdirectory(FindOpenCL) endif() + if(CMake_TEST_FindOpenGL) + add_subdirectory(FindOpenGL) + endif() + if(CMake_TEST_FindOpenSSL) add_subdirectory(FindOpenSSL) endif() diff --git a/Tests/CompileFeatures/CMakeLists.txt b/Tests/CompileFeatures/CMakeLists.txt index 8acdd93..0405def 100644 --- a/Tests/CompileFeatures/CMakeLists.txt +++ b/Tests/CompileFeatures/CMakeLists.txt @@ -28,7 +28,7 @@ foreach(feature ${c_features}) run_test(${feature} C) endforeach() get_property(cxx_features GLOBAL PROPERTY CMAKE_CXX_KNOWN_FEATURES) -list(REMOVE_ITEM cxx_features cxx_std_98 cxx_std_11 cxx_std_14) +list(REMOVE_ITEM cxx_features cxx_std_98 cxx_std_11 cxx_std_14 cxx_std_17) foreach(feature ${cxx_features}) run_test(${feature} CXX) endforeach() @@ -268,6 +268,7 @@ if (CMAKE_CXX_COMPILE_FEATURES) if (std_flag_idx EQUAL -1) add_executable(default_dialect default_dialect.cpp) target_compile_definitions(default_dialect PRIVATE + DEFAULT_CXX17=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},17> DEFAULT_CXX14=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},14> DEFAULT_CXX11=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},11> DEFAULT_CXX98=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},98> diff --git a/Tests/CompileFeatures/default_dialect.cpp b/Tests/CompileFeatures/default_dialect.cpp index 0efaefa..9b65b42 100644 --- a/Tests/CompileFeatures/default_dialect.cpp +++ b/Tests/CompileFeatures/default_dialect.cpp @@ -2,7 +2,11 @@ template <long l> struct Outputter; -#if DEFAULT_CXX14 +#if DEFAULT_CXX17 +#if __cplusplus <= 201402L +Outputter<__cplusplus> o; +#endif +#elif DEFAULT_CXX14 #if __cplusplus != 201402L Outputter<__cplusplus> o; #endif diff --git a/Tests/FindOpenGL/CMakeLists.txt b/Tests/FindOpenGL/CMakeLists.txt new file mode 100644 index 0000000..9aa3aba --- /dev/null +++ b/Tests/FindOpenGL/CMakeLists.txt @@ -0,0 +1,10 @@ +add_test(NAME FindOpenGL.Test COMMAND + ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION> + --build-and-test + "${CMake_SOURCE_DIR}/Tests/FindOpenGL/Test" + "${CMake_BINARY_DIR}/Tests/FindOpenGL/Test" + ${build_generator_args} + --build-project TestFindOpenGL + --build-options ${build_options} + --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION> + ) diff --git a/Tests/FindOpenGL/Test/CMakeLists.txt b/Tests/FindOpenGL/Test/CMakeLists.txt new file mode 100644 index 0000000..cac3424 --- /dev/null +++ b/Tests/FindOpenGL/Test/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.7) +project(TestFindOpenGL C) +include(CTest) + +find_package(OpenGL REQUIRED) + +add_executable(test_tgt main.c) +target_link_libraries(test_tgt OpenGL::GLU) +add_test(NAME test_tgt COMMAND test_tgt) + +add_executable(test_var main.c) +target_include_directories(test_var PRIVATE ${OPENGL_INGLUDE_DIRS}) +target_link_libraries(test_var PRIVATE ${OPENGL_LIBRARIES}) +add_test(NAME test_var COMMAND test_var) diff --git a/Tests/FindOpenGL/Test/main.c b/Tests/FindOpenGL/Test/main.c new file mode 100644 index 0000000..bca3d7e --- /dev/null +++ b/Tests/FindOpenGL/Test/main.c @@ -0,0 +1,17 @@ +#ifdef _WIN32 +#include <windows.h> +#endif +#ifdef __APPLE__ +#include <OpenGL/gl.h> +#else +#include <GL/gl.h> +#endif + +#include <stdio.h> + +int main() +{ + /* Reference a GL symbol without requiring a context at runtime. */ + printf("&glGetString = %p\n", &glGetString); + return 0; +} diff --git a/Tests/QtAutoUicInterface/CMakeLists.txt b/Tests/QtAutoUicInterface/CMakeLists.txt index 555f016..70175fb 100644 --- a/Tests/QtAutoUicInterface/CMakeLists.txt +++ b/Tests/QtAutoUicInterface/CMakeLists.txt @@ -1,5 +1,5 @@ -cmake_minimum_required(VERSION 2.8.12) +cmake_minimum_required(VERSION 3.7) project(QtAutoUicInterface) @@ -21,7 +21,6 @@ else() endif() set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON) -set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOUIC ON) @@ -65,6 +64,6 @@ target_link_libraries(MyWidget KI18n ${QT_GUI_TARGET}) add_executable(QtAutoUicInterface main.cpp) target_compile_definitions(QtAutoUicInterface PRIVATE - UI_LIBWIDGET_H="${CMAKE_CURRENT_BINARY_DIR}/ui_libwidget.h" - UI_MYWIDGET_H="${CMAKE_CURRENT_BINARY_DIR}/ui_mywidget.h" + UI_LIBWIDGET_H="${CMAKE_CURRENT_BINARY_DIR}/LibWidget_autogen/include/ui_libwidget.h" + UI_MYWIDGET_H="${CMAKE_CURRENT_BINARY_DIR}/MyWidget_autogen/include/ui_mywidget.h" ) diff --git a/Tests/QtAutoUicInterface/libwidget.cpp b/Tests/QtAutoUicInterface/libwidget.cpp index b25f3d7..008c22a 100644 --- a/Tests/QtAutoUicInterface/libwidget.cpp +++ b/Tests/QtAutoUicInterface/libwidget.cpp @@ -7,3 +7,8 @@ LibWidget::LibWidget(QWidget* parent) { ui->setupUi(this); } + +LibWidget::~LibWidget() +{ + delete ui; +} diff --git a/Tests/QtAutoUicInterface/libwidget.h b/Tests/QtAutoUicInterface/libwidget.h index a4400d2..b6f3e82 100644 --- a/Tests/QtAutoUicInterface/libwidget.h +++ b/Tests/QtAutoUicInterface/libwidget.h @@ -16,9 +16,10 @@ class LibWidget : public QWidget Q_OBJECT public: explicit LibWidget(QWidget* parent = 0); + ~LibWidget(); private: - const std::auto_ptr<Ui::LibWidget> ui; + Ui::LibWidget* ui; }; #endif diff --git a/Tests/QtAutoUicInterface/mywidget.cpp b/Tests/QtAutoUicInterface/mywidget.cpp index 885165b..7cf1a13 100644 --- a/Tests/QtAutoUicInterface/mywidget.cpp +++ b/Tests/QtAutoUicInterface/mywidget.cpp @@ -7,3 +7,8 @@ MyWidget::MyWidget(QWidget* parent) { ui->setupUi(this); } + +MyWidget::~MyWidget() +{ + delete ui; +} diff --git a/Tests/QtAutoUicInterface/mywidget.h b/Tests/QtAutoUicInterface/mywidget.h index fc49e80..c23e55d 100644 --- a/Tests/QtAutoUicInterface/mywidget.h +++ b/Tests/QtAutoUicInterface/mywidget.h @@ -16,9 +16,10 @@ class MyWidget : public QWidget Q_OBJECT public: explicit MyWidget(QWidget* parent = 0); + ~MyWidget(); private: - const std::auto_ptr<Ui::MyWidget> ui; + Ui::MyWidget* ui; }; #endif diff --git a/Tests/QtAutogen/CMakeLists.txt b/Tests/QtAutogen/CMakeLists.txt index c4d0567..6d4e2c4 100644 --- a/Tests/QtAutogen/CMakeLists.txt +++ b/Tests/QtAutogen/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.7) project(QtAutogen) @@ -45,7 +45,6 @@ else() endif() get_property(QT_COMPILE_FEATURES TARGET ${QT_QTCORE_TARGET} PROPERTY INTERFACE_COMPILE_FEATURES) -include_directories(${CMAKE_CURRENT_BINARY_DIR}) # -- Test: AUTORCC # RCC only diff --git a/Tests/QtAutogen/automoc_rerun/CMakeLists.txt b/Tests/QtAutogen/automoc_rerun/CMakeLists.txt index 17bc332..92a682b 100644 --- a/Tests/QtAutogen/automoc_rerun/CMakeLists.txt +++ b/Tests/QtAutogen/automoc_rerun/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.7) project(automoc_rerun CXX) if (QT_TEST_VERSION STREQUAL 4) diff --git a/Tests/QtAutogen/autorcc_depends/CMakeLists.txt b/Tests/QtAutogen/autorcc_depends/CMakeLists.txt index fbe71ad..7b51e11 100644 --- a/Tests/QtAutogen/autorcc_depends/CMakeLists.txt +++ b/Tests/QtAutogen/autorcc_depends/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.7) project(autorcc_depends) set(CMAKE_AUTORCC ON) diff --git a/Tests/QtAutogen/complex/Bdir/CMakeLists.txt b/Tests/QtAutogen/complex/Bdir/CMakeLists.txt index d9d4aa7..d338763 100644 --- a/Tests/QtAutogen/complex/Bdir/CMakeLists.txt +++ b/Tests/QtAutogen/complex/Bdir/CMakeLists.txt @@ -6,5 +6,4 @@ set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON) add_library(libB SHARED libB.cpp) generate_export_header(libB) -# set_property(TARGET libB APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) target_link_libraries(libB LINK_PUBLIC libA) diff --git a/Tests/QtAutogen/complex/CMakeLists.txt b/Tests/QtAutogen/complex/CMakeLists.txt index 0d44f50..d48f6cc 100644 --- a/Tests/QtAutogen/complex/CMakeLists.txt +++ b/Tests/QtAutogen/complex/CMakeLists.txt @@ -1,7 +1,6 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.7) # -- Test: AUTOMOC AUTORCC AUTOUIC -include_directories(${CMAKE_CURRENT_BINARY_DIR}) add_definitions(-DFOO -DSomeDefine="Barx") # enable relaxed mode so automoc can handle all the special cases: @@ -77,5 +76,7 @@ add_library(libC SHARED libC.cpp) set_target_properties(libC PROPERTIES AUTOMOC TRUE) generate_export_header(libC) target_link_libraries(libC LINK_PUBLIC libB) +target_include_directories(libC PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) +set_property(TARGET libC APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_BINARY_DIR} ) target_link_libraries(QtAutogen codeeditorLib ${QT_LIBRARIES} libC) diff --git a/Tests/QtAutogen/defines_test/CMakeLists.txt b/Tests/QtAutogen/defines_test/CMakeLists.txt index ad4e684..9ee9a22 100644 --- a/Tests/QtAutogen/defines_test/CMakeLists.txt +++ b/Tests/QtAutogen/defines_test/CMakeLists.txt @@ -1,6 +1,4 @@ -include_directories(${CMAKE_CURRENT_BINARY_DIR}) - add_executable(defines_test defines_test.cpp) set_target_properties(defines_test PROPERTIES AUTOMOC TRUE) target_link_libraries(defines_test Qt4::QtGui) diff --git a/Tests/QtAutogen/sameName/CMakeLists.txt b/Tests/QtAutogen/sameName/CMakeLists.txt index ed045fb..9e47a3e 100644 --- a/Tests/QtAutogen/sameName/CMakeLists.txt +++ b/Tests/QtAutogen/sameName/CMakeLists.txt @@ -16,6 +16,5 @@ add_executable(sameName data.qrc main.cpp ) -target_include_directories(sameName PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) target_link_libraries(sameName ${QT_LIBRARIES}) -set_target_properties( sameName PROPERTIES AUTOMOC TRUE AUTORCC TRUE ) +set_target_properties(sameName PROPERTIES AUTOMOC TRUE AUTORCC TRUE) diff --git a/Tests/QtAutogen/uicOnlySource/uiconly.cpp b/Tests/QtAutogen/uicOnlySource/uiconly.cpp index ac22789..7b91b25 100644 --- a/Tests/QtAutogen/uicOnlySource/uiconly.cpp +++ b/Tests/QtAutogen/uicOnlySource/uiconly.cpp @@ -7,6 +7,11 @@ UicOnly::UicOnly(QWidget* parent) { } +UicOnly::~UicOnly() +{ + delete ui; +} + int main() { return 0; diff --git a/Tests/QtAutogen/uicOnlySource/uiconly.h b/Tests/QtAutogen/uicOnlySource/uiconly.h index 9b0b1b4..8f4eebe 100644 --- a/Tests/QtAutogen/uicOnlySource/uiconly.h +++ b/Tests/QtAutogen/uicOnlySource/uiconly.h @@ -3,7 +3,6 @@ #define UIC_ONLY_H #include <QWidget> -#include <memory> #include "ui_uiconly.h" @@ -12,9 +11,10 @@ class UicOnly : public QWidget Q_OBJECT public: explicit UicOnly(QWidget* parent = 0); + ~UicOnly(); private: - const std::auto_ptr<Ui::UicOnly> ui; + Ui::UicOnly* ui; }; #endif diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index c02b917..1b88d46 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -215,6 +215,18 @@ add_RunCMake_test(project -DCMake_TEST_RESOURCES=${CMake_TEST_RESOURCES}) add_RunCMake_test(return) add_RunCMake_test(set_property) add_RunCMake_test(string) +foreach(var + CMAKE_C_COMPILER_ID + CMAKE_C_COMPILER_VERSION + CMAKE_C_STANDARD_DEFAULT + CMAKE_CXX_COMPILER_ID + CMAKE_CXX_COMPILER_VERSION + CMAKE_CXX_STANDARD_DEFAULT + ) + if(DEFINED ${var}) + list(APPEND try_compile_ARGS -D${var}=${${var}}) + endif() +endforeach() add_RunCMake_test(try_compile) add_RunCMake_test(try_run) add_RunCMake_test(set) diff --git a/Tests/RunCMake/CPack/RunCMakeTest.cmake b/Tests/RunCMake/CPack/RunCMakeTest.cmake index 092fb47..3077340 100644 --- a/Tests/RunCMake/CPack/RunCMakeTest.cmake +++ b/Tests/RunCMake/CPack/RunCMakeTest.cmake @@ -22,3 +22,4 @@ run_cpack_test(PER_COMPONENT_FIELDS "RPM;DEB" false "COMPONENT") run_cpack_test_subtests(SINGLE_DEBUGINFO "no_main_component;one_component;one_component_main;no_debuginfo;one_component_no_debuginfo;no_components;valid" "RPM" true "CUSTOM") run_cpack_source_test(SOURCE_PACKAGE "RPM") run_cpack_test(SUGGESTS "RPM" false "MONOLITHIC") +run_cpack_test(USER_FILELIST "RPM" false "MONOLITHIC") diff --git a/Tests/RunCMake/CPack/tests/USER_FILELIST/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/USER_FILELIST/ExpectedFiles.cmake new file mode 100644 index 0000000..aabe537 --- /dev/null +++ b/Tests/RunCMake/CPack/tests/USER_FILELIST/ExpectedFiles.cmake @@ -0,0 +1,2 @@ +set(EXPECTED_FILES_COUNT "1") +set(EXPECTED_FILE_CONTENT_1_LIST "/usr/one;/usr/one/foo.txt;/usr/one/two;/usr/one/two/bar.txt;/usr/three;/usr/three/baz.txt;/usr/three/qux.txt") diff --git a/Tests/RunCMake/CPack/tests/USER_FILELIST/VerifyResult.cmake b/Tests/RunCMake/CPack/tests/USER_FILELIST/VerifyResult.cmake new file mode 100644 index 0000000..57444ed --- /dev/null +++ b/Tests/RunCMake/CPack/tests/USER_FILELIST/VerifyResult.cmake @@ -0,0 +1,12 @@ +execute_process(COMMAND ${RPM_EXECUTABLE} -qpd ${FOUND_FILE_1} + WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}" + OUTPUT_VARIABLE DOC_FILES_ + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + +string(REPLACE "\n" ";" DOC_FILES_ "${DOC_FILES_}") + +set(DOC_FILES_WANTED_ "/usr/one/foo.txt;/usr/one/two/bar.txt;/usr/three/baz.txt") +if (NOT "${DOC_FILES_}" STREQUAL "${DOC_FILES_WANTED_}") + message(FATAL_ERROR "USER_FILELIST handling error: Check filelist in spec file. Doc files were: ${DOC_FILES_}. Should have been ${DOC_FILES_WANTED_}") +endif() diff --git a/Tests/RunCMake/CPack/tests/USER_FILELIST/test.cmake b/Tests/RunCMake/CPack/tests/USER_FILELIST/test.cmake new file mode 100644 index 0000000..acfee42 --- /dev/null +++ b/Tests/RunCMake/CPack/tests/USER_FILELIST/test.cmake @@ -0,0 +1,13 @@ +install(FILES CMakeLists.txt DESTINATION one RENAME foo.txt) +install(FILES CMakeLists.txt DESTINATION one/two RENAME bar.txt) +install(FILES CMakeLists.txt DESTINATION three RENAME baz.txt) +install(FILES CMakeLists.txt DESTINATION three RENAME qux.txt) + +# We are verifying the USER_FILELIST works by comparing what +# ends up with a %doc tag in the final rpm with what we expect +# from this USER_FILELIST. +set(CPACK_RPM_USER_FILELIST + "%doc /usr/one/foo.txt" + "%doc %attr(640,root,root) /usr/one/two/bar.txt" + "%attr(600, -, root) %doc /usr/three/baz.txt" +) diff --git a/Tests/RunCMake/try_compile/CMP0067-stderr.txt b/Tests/RunCMake/try_compile/CMP0067-stderr.txt new file mode 100644 index 0000000..e2677ed --- /dev/null +++ b/Tests/RunCMake/try_compile/CMP0067-stderr.txt @@ -0,0 +1,25 @@ +before try_compile with CMP0067 WARN-enabled but no variables +after try_compile with CMP0067 WARN-enabled but no variables +before try_compile with CMP0067 WARN-default +after try_compile with CMP0067 WARN-default +before try_compile with CMP0067 WARN-enabled +CMake Warning \(dev\) at CMP0067.cmake:[0-9]+ \(try_compile\): + Policy CMP0067 is not set: Honor language standard in try_compile\(\) + source-file signature. Run "cmake --help-policy CMP0067" for policy + details. Use the cmake_policy command to set the policy and suppress this + warning. + + For compatibility with older versions of CMake, try_compile is not honoring + language standard variables in the test project: + + CMAKE_C_STANDARD + +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) +This warning is for project developers. Use -Wno-dev to suppress it. + +after try_compile with CMP0067 WARN-enabled +before try_compile with CMP0067 OLD +after try_compile with CMP0067 OLD +before try_compile with CMP0067 NEW +after try_compile with CMP0067 NEW diff --git a/Tests/RunCMake/try_compile/CMP0067.cmake b/Tests/RunCMake/try_compile/CMP0067.cmake new file mode 100644 index 0000000..dd05d96 --- /dev/null +++ b/Tests/RunCMake/try_compile/CMP0067.cmake @@ -0,0 +1,40 @@ +enable_language(C) + +set(CMAKE_POLICY_WARNING_CMP0067 ON) +message("before try_compile with CMP0067 WARN-enabled but no variables") +try_compile(RESULT ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/src.c + ) +message("after try_compile with CMP0067 WARN-enabled but no variables") +set(CMAKE_POLICY_WARNING_CMP0067 OFF) + +#----------------------------------------------------------------------------- + +set(CMAKE_C_STANDARD 90) + +message("before try_compile with CMP0067 WARN-default") +try_compile(RESULT ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/src.c + ) +message("after try_compile with CMP0067 WARN-default") + +set(CMAKE_POLICY_WARNING_CMP0067 ON) +message("before try_compile with CMP0067 WARN-enabled") +try_compile(RESULT ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/src.c + ) +message("after try_compile with CMP0067 WARN-enabled") + +cmake_policy(SET CMP0067 OLD) +message("before try_compile with CMP0067 OLD") +try_compile(RESULT ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/src.c + ) +message("after try_compile with CMP0067 OLD") + +cmake_policy(SET CMP0066 NEW) +message("before try_compile with CMP0067 NEW") +try_compile(RESULT ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/src.c + ) +message("after try_compile with CMP0067 NEW") diff --git a/Tests/RunCMake/try_compile/CStandard-result.txt b/Tests/RunCMake/try_compile/CStandard-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/try_compile/CStandard-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/try_compile/CStandard-stderr.txt b/Tests/RunCMake/try_compile/CStandard-stderr.txt new file mode 100644 index 0000000..209afcc --- /dev/null +++ b/Tests/RunCMake/try_compile/CStandard-stderr.txt @@ -0,0 +1,7 @@ +^CMake Error at .*/Tests/RunCMake/try_compile/CStandard-build/CMakeFiles/CMakeTmp/CMakeLists.txt:[0-9]+ \(add_executable\): + C_STANDARD is set to invalid value '3' ++ +CMake Error at CStandard.cmake:[0-9]+ \(try_compile\): + Failed to generate test project build system. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/try_compile/CStandard.cmake b/Tests/RunCMake/try_compile/CStandard.cmake new file mode 100644 index 0000000..2849ed4 --- /dev/null +++ b/Tests/RunCMake/try_compile/CStandard.cmake @@ -0,0 +1,7 @@ +enable_language(C) +try_compile(result ${CMAKE_CURRENT_BINARY_DIR} + SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src.c + C_STANDARD 3 + OUTPUT_VARIABLE out + ) +message("try_compile output:\n${out}") diff --git a/Tests/RunCMake/try_compile/CStandardGNU.c b/Tests/RunCMake/try_compile/CStandardGNU.c new file mode 100644 index 0000000..ac26c15 --- /dev/null +++ b/Tests/RunCMake/try_compile/CStandardGNU.c @@ -0,0 +1,10 @@ +#if __STDC_VERSION__ != 199901L +#error "Not GNU C 99 mode!" +#endif +#ifndef __STRICT_ANSI__ +#error "Not GNU C strict ANSI!" +#endif +int main(void) +{ + return 0; +} diff --git a/Tests/RunCMake/try_compile/CStandardGNU.cmake b/Tests/RunCMake/try_compile/CStandardGNU.cmake new file mode 100644 index 0000000..79ae874 --- /dev/null +++ b/Tests/RunCMake/try_compile/CStandardGNU.cmake @@ -0,0 +1,23 @@ +enable_language(C) +try_compile(result ${CMAKE_CURRENT_BINARY_DIR} + SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/CStandardGNU.c + C_STANDARD 99 + C_STANDARD_REQUIRED 1 + C_EXTENSIONS 0 + OUTPUT_VARIABLE out + ) +if(NOT result) + message(FATAL_ERROR "try_compile failed:\n${out}") +endif() + +cmake_policy(SET CMP0067 NEW) +set(CMAKE_C_STANDARD 99) +set(CMAKE_C_STANDARD_REQUIRED 1) +set(CMAKE_C_EXTENSIONS 0) +try_compile(result ${CMAKE_CURRENT_BINARY_DIR} + SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/CStandardGNU.c + OUTPUT_VARIABLE out + ) +if(NOT result) + message(FATAL_ERROR "try_compile failed:\n${out}") +endif() diff --git a/Tests/RunCMake/try_compile/CStandardNoDefault.cmake b/Tests/RunCMake/try_compile/CStandardNoDefault.cmake new file mode 100644 index 0000000..97e72ea --- /dev/null +++ b/Tests/RunCMake/try_compile/CStandardNoDefault.cmake @@ -0,0 +1,9 @@ +enable_language(C) +try_compile(result ${CMAKE_CURRENT_BINARY_DIR} + SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src.c + C_STANDARD 3 # bogus, but not used + OUTPUT_VARIABLE out + ) +if(NOT result) + message(FATAL_ERROR "try_compile failed:\n${out}") +endif() diff --git a/Tests/RunCMake/try_compile/CxxStandard-result.txt b/Tests/RunCMake/try_compile/CxxStandard-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/try_compile/CxxStandard-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/try_compile/CxxStandard-stderr.txt b/Tests/RunCMake/try_compile/CxxStandard-stderr.txt new file mode 100644 index 0000000..ec7245f --- /dev/null +++ b/Tests/RunCMake/try_compile/CxxStandard-stderr.txt @@ -0,0 +1,7 @@ +^CMake Error at .*/Tests/RunCMake/try_compile/CxxStandard-build/CMakeFiles/CMakeTmp/CMakeLists.txt:[0-9]+ \(add_executable\): + CXX_STANDARD is set to invalid value '3' ++ +CMake Error at CxxStandard.cmake:[0-9]+ \(try_compile\): + Failed to generate test project build system. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/try_compile/CxxStandard.cmake b/Tests/RunCMake/try_compile/CxxStandard.cmake new file mode 100644 index 0000000..bcb49b9 --- /dev/null +++ b/Tests/RunCMake/try_compile/CxxStandard.cmake @@ -0,0 +1,7 @@ +enable_language(CXX) +try_compile(result ${CMAKE_CURRENT_BINARY_DIR} + SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src.cxx + CXX_STANDARD 3 + OUTPUT_VARIABLE out + ) +message("try_compile output:\n${out}") diff --git a/Tests/RunCMake/try_compile/CxxStandardGNU.cmake b/Tests/RunCMake/try_compile/CxxStandardGNU.cmake new file mode 100644 index 0000000..e714fe4 --- /dev/null +++ b/Tests/RunCMake/try_compile/CxxStandardGNU.cmake @@ -0,0 +1,23 @@ +enable_language(CXX) +try_compile(result ${CMAKE_CURRENT_BINARY_DIR} + SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/CxxStandardGNU.cxx + CXX_STANDARD 11 + CXX_STANDARD_REQUIRED 1 + CXX_EXTENSIONS 0 + OUTPUT_VARIABLE out + ) +if(NOT result) + message(FATAL_ERROR "try_compile failed:\n${out}") +endif() + +cmake_policy(SET CMP0067 NEW) +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED 1) +set(CMAKE_CXX_EXTENSIONS 0) +try_compile(result ${CMAKE_CURRENT_BINARY_DIR} + SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/CxxStandardGNU.cxx + OUTPUT_VARIABLE out + ) +if(NOT result) + message(FATAL_ERROR "try_compile failed:\n${out}") +endif() diff --git a/Tests/RunCMake/try_compile/CxxStandardGNU.cxx b/Tests/RunCMake/try_compile/CxxStandardGNU.cxx new file mode 100644 index 0000000..7990a78 --- /dev/null +++ b/Tests/RunCMake/try_compile/CxxStandardGNU.cxx @@ -0,0 +1,11 @@ +#if __cplusplus != 201103L && \ + !(__cplusplus < 201103L && defined(__GXX_EXPERIMENTAL_CXX0X__)) +#error "Not GNU C++ 11 mode!" +#endif +#ifndef __STRICT_ANSI__ +#error "Not GNU C++ strict ANSI!" +#endif +int main() +{ + return 0; +} diff --git a/Tests/RunCMake/try_compile/CxxStandardNoDefault.cmake b/Tests/RunCMake/try_compile/CxxStandardNoDefault.cmake new file mode 100644 index 0000000..35caa9d --- /dev/null +++ b/Tests/RunCMake/try_compile/CxxStandardNoDefault.cmake @@ -0,0 +1,9 @@ +enable_language(CXX) +try_compile(result ${CMAKE_CURRENT_BINARY_DIR} + SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src.cxx + CXX_STANDARD 3 # bogus, but not used + OUTPUT_VARIABLE out + ) +if(NOT result) + message(FATAL_ERROR "try_compile failed:\n${out}") +endif() diff --git a/Tests/RunCMake/try_compile/RunCMakeTest.cmake b/Tests/RunCMake/try_compile/RunCMakeTest.cmake index 4934bcd..d1b0217 100644 --- a/Tests/RunCMake/try_compile/RunCMakeTest.cmake +++ b/Tests/RunCMake/try_compile/RunCMakeTest.cmake @@ -25,8 +25,26 @@ run_cmake(TargetTypeExe) run_cmake(TargetTypeInvalid) run_cmake(TargetTypeStatic) +if(CMAKE_C_STANDARD_DEFAULT) + run_cmake(CStandard) +elseif(DEFINED CMAKE_C_STANDARD_DEFAULT) + run_cmake(CStandardNoDefault) +endif() +if(CMAKE_CXX_STANDARD_DEFAULT) + run_cmake(CxxStandard) +elseif(DEFINED CMAKE_CXX_STANDARD_DEFAULT) + run_cmake(CxxStandardNoDefault) +endif() +if(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.4) + run_cmake(CStandardGNU) +endif() +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.4) + run_cmake(CxxStandardGNU) +endif() + run_cmake(CMP0056) run_cmake(CMP0066) +run_cmake(CMP0067) if(RunCMake_GENERATOR MATCHES "Make|Ninja") # Use a single build tree for a few tests without cleaning. diff --git a/Tests/RunCMake/try_compile/src.cxx b/Tests/RunCMake/try_compile/src.cxx new file mode 100644 index 0000000..f8b643a --- /dev/null +++ b/Tests/RunCMake/try_compile/src.cxx @@ -0,0 +1,4 @@ +int main() +{ + return 0; +} diff --git a/Utilities/Release/WiX/WIX.template.in b/Utilities/Release/WiX/WIX.template.in index 094999f..fe176ca 100644 --- a/Utilities/Release/WiX/WIX.template.in +++ b/Utilities/Release/WiX/WIX.template.in @@ -36,7 +36,18 @@ <WixVariable Id="WixUIDialogBmp" Value="$(var.CPACK_WIX_UI_DIALOG)"/> <?endif?> - <FeatureRef Id="ProductFeature"/> + <DirectoryRef Id="TARGETDIR"> + <Component Id="CMakeRegistry"> + <RegistryKey Root="HKLM" Key="Software\Kitware\CMake"> + <RegistryValue Type="string" Name="InstallDir" + Value="[INSTALL_ROOT]" KeyPath="yes"/> + </RegistryKey> + </Component> + </DirectoryRef> + + <FeatureRef Id="ProductFeature"> + <ComponentRef Id="CMakeRegistry"/> + </FeatureRef> <UIRef Id="$(var.CPACK_WIX_UI_REF)" /> diff --git a/Utilities/Scripts/update-curl.bash b/Utilities/Scripts/update-curl.bash index 590bd44..22d1d8a 100755 --- a/Utilities/Scripts/update-curl.bash +++ b/Utilities/Scripts/update-curl.bash @@ -8,7 +8,7 @@ readonly name="curl" readonly ownership="Curl Upstream <curl-library@cool.haxx.se>" readonly subtree="Utilities/cmcurl" readonly repo="https://github.com/curl/curl.git" -readonly tag="curl-7_50_1" +readonly tag="curl-7_51_0" readonly shortlog=false readonly paths=" CMake/* diff --git a/Utilities/cmcurl/CMake/CurlSymbolHiding.cmake b/Utilities/cmcurl/CMake/CurlSymbolHiding.cmake new file mode 100644 index 0000000..9f7d296 --- /dev/null +++ b/Utilities/cmcurl/CMake/CurlSymbolHiding.cmake @@ -0,0 +1,61 @@ +include(CheckCSourceCompiles) + +option(CURL_HIDDEN_SYMBOLS "Set to ON to hide libcurl internal symbols (=hide all symbols that aren't officially external)." ON) +mark_as_advanced(CURL_HIDDEN_SYMBOLS) + +if(CURL_HIDDEN_SYMBOLS) + set(SUPPORTS_SYMBOL_HIDING FALSE) + + if(CMAKE_C_COMPILER_ID MATCHES "Clang") + set(SUPPORTS_SYMBOL_HIDING TRUE) + set(_SYMBOL_EXTERN "__attribute__ ((__visibility__ (\"default\")))") + set(_CFLAG_SYMBOLS_HIDE "-fvisibility=hidden") + elseif(CMAKE_COMPILER_IS_GNUCC) + if(NOT CMAKE_VERSION VERSION_LESS 2.8.10) + set(GCC_VERSION ${CMAKE_C_COMPILER_VERSION}) + else() + execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion + OUTPUT_VARIABLE GCC_VERSION) + endif() + if(NOT GCC_VERSION VERSION_LESS 3.4) + # note: this is considered buggy prior to 4.0 but the autotools don't care, so let's ignore that fact + set(SUPPORTS_SYMBOL_HIDING TRUE) + set(_SYMBOL_EXTERN "__attribute__ ((__visibility__ (\"default\")))") + set(_CFLAG_SYMBOLS_HIDE "-fvisibility=hidden") + endif() + elseif(CMAKE_C_COMPILER_ID MATCHES "SunPro" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 8.0) + set(SUPPORTS_SYMBOL_HIDING TRUE) + set(_SYMBOL_EXTERN "__global") + set(_CFLAG_SYMBOLS_HIDE "-xldscope=hidden") + elseif(CMAKE_C_COMPILER_ID MATCHES "Intel" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 9.0) + # note: this should probably just check for version 9.1.045 but I'm not 100% sure + # so let's to it the same way autotools do. + set(SUPPORTS_SYMBOL_HIDING TRUE) + set(_SYMBOL_EXTERN "__attribute__ ((__visibility__ (\"default\")))") + set(_CFLAG_SYMBOLS_HIDE "-fvisibility=hidden") + check_c_source_compiles("#include <stdio.h> + int main (void) { printf(\"icc fvisibility bug test\"); return 0; }" _no_bug) + if(NOT _no_bug) + set(SUPPORTS_SYMBOL_HIDING FALSE) + set(_SYMBOL_EXTERN "") + set(_CFLAG_SYMBOLS_HIDE "") + endif() + elseif(MSVC) + set(SUPPORTS_SYMBOL_HIDING TRUE) + endif() + + set(HIDES_CURL_PRIVATE_SYMBOLS ${SUPPORTS_SYMBOL_HIDING}) +elseif(MSVC) + if(NOT CMAKE_VERSION VERSION_LESS 3.7) + set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE) #present since 3.4.3 but broken + set(HIDES_CURL_PRIVATE_SYMBOLS FALSE) + else() + message(WARNING "Hiding private symbols regardless CURL_HIDDEN_SYMBOLS being disabled.") + set(HIDES_CURL_PRIVATE_SYMBOLS TRUE) + endif() +elseif() + set(HIDES_CURL_PRIVATE_SYMBOLS FALSE) +endif() + +set(CURL_CFLAG_SYMBOLS_HIDE ${_CFLAG_SYMBOLS_HIDE}) +set(CURL_EXTERN_SYMBOL ${_SYMBOL_EXTERN}) diff --git a/Utilities/cmcurl/CMake/FindNGHTTP2.cmake b/Utilities/cmcurl/CMake/FindNGHTTP2.cmake new file mode 100644 index 0000000..4e566cf --- /dev/null +++ b/Utilities/cmcurl/CMake/FindNGHTTP2.cmake @@ -0,0 +1,18 @@ +include(FindPackageHandleStandardArgs) + +find_path(NGHTTP2_INCLUDE_DIR "nghttp2/nghttp2.h") + +find_library(NGHTTP2_LIBRARY NAMES nghttp2) + +find_package_handle_standard_args(NGHTTP2 + FOUND_VAR + NGHTTP2_FOUND + REQUIRED_VARS + NGHTTP2_LIBRARY + NGHTTP2_INCLUDE_DIR + FAIL_MESSAGE + "Could NOT find NGHTTP2" +) + +set(NGHTTP2_INCLUDE_DIRS ${NGHTTP2_INCLUDE_DIR} ) +set(NGHTTP2_LIBRARIES ${NGHTTP2_LIBRARY}) diff --git a/Utilities/cmcurl/CMakeLists.txt b/Utilities/cmcurl/CMakeLists.txt index 9031181..262554d 100644 --- a/Utilities/cmcurl/CMakeLists.txt +++ b/Utilities/cmcurl/CMakeLists.txt @@ -65,7 +65,7 @@ endif() # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # -# Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. +# Copyright (C) 1998 - 2016, 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 @@ -79,7 +79,7 @@ endif() # KIND, either express or implied. # ########################################################################### -# cURL/libcurl CMake script +# curl/libcurl CMake script # by Tetetest and Sukender (Benoit Neil) # TODO: @@ -102,6 +102,7 @@ cmake_minimum_required(VERSION 2.8 FATAL_ERROR) set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake;${CMAKE_MODULE_PATH}") include(Utilities) include(Macros) +include(CMakeDependentOption) project( CURL C ) @@ -135,11 +136,17 @@ set(OS "\"${CMAKE_SYSTEM_NAME}\"") include_directories(${PROJECT_BINARY_DIR}/include/curl) include_directories( ${CURL_SOURCE_DIR}/include ) -option(BUILD_CURL_EXE "Set to ON to build cURL executable." ON) +option(BUILD_CURL_EXE "Set to ON to build curl executable." ON) option(CURL_STATICLIB "Set to ON to build libcurl with static linking." OFF) option(ENABLE_ARES "Set to ON to enable c-ares support" OFF) -option(ENABLE_THREADED_RESOLVER "Set to ON to enable POSIX threaded DNS lookup" OFF) - +if(WIN32) + CMAKE_DEPENDENT_OPTION(ENABLE_THREADED_RESOLVER + "Set to ON to enable threaded DNS lookup" + ON "NOT ENABLE_ARES" + OFF) +else() + option(ENABLE_THREADED_RESOLVER "Set to ON to enable POSIX threaded DNS lookup" OFF) +endif() option(ENABLE_DEBUG "Set to ON to enable curl debug features" OFF) option(ENABLE_CURLDEBUG "Set to ON to build with TrackMemory feature enabled" OFF) @@ -176,8 +183,9 @@ if(MSVC) mark_as_advanced(BUILD_RELEASE_DEBUG_DIRS) endif() -option(CURL_HIDDEN_SYMBOLS "Set to ON to hide libcurl internal symbols (=hide all symbols that aren't officially external)." ON) -mark_as_advanced(CURL_HIDDEN_SYMBOLS) +if(0) # This code not needed for building within CMake. +include(CurlSymbolHiding) +endif() option(HTTP_ONLY "disables all protocols except HTTP (This overrides all CURL_DISABLE_* options)" OFF) mark_as_advanced(HTTP_ONLY) @@ -313,13 +321,17 @@ if(WIN32) endif(WIN32) if(ENABLE_THREADED_RESOLVER) - check_include_file_concat("pthread.h" HAVE_PTHREAD_H) - if(HAVE_PTHREAD_H) - set(CMAKE_THREAD_PREFER_PTHREAD 1) - find_package(Threads) - if(CMAKE_USE_PTHREADS_INIT) - set(CURL_LIBS ${CURL_LIBS} ${CMAKE_THREAD_LIBS_INIT}) - set(USE_THREADS_POSIX 1) + if(WIN32) + set(USE_THREADS_WIN32 ON) + else() + check_include_file_concat("pthread.h" HAVE_PTHREAD_H) + if(HAVE_PTHREAD_H) + set(CMAKE_THREAD_PREFER_PTHREAD 1) + find_package(Threads) + if(CMAKE_USE_PTHREADS_INIT) + set(CURL_LIBS ${CURL_LIBS} ${CMAKE_THREAD_LIBS_INIT}) + set(USE_THREADS_POSIX 1) + endif() endif() endif() endif() @@ -411,6 +423,13 @@ elseif(APPLE) endif() endif() +option(USE_NGHTTP2 "Use Nghttp2 library" OFF) +if(USE_NGHTTP2) + find_package(NGHTTP2 REQUIRED) + include_directories(${NGHTTP2_INCLUDE_DIRS}) + list(APPEND CURL_LIBS ${NGHTTP2_LIBRARIES}) +endif() + if(NOT CURL_DISABLE_LDAP) if(WIN32) option(USE_WIN32_LDAP "Use Windows LDAP implementation" ON) @@ -521,13 +540,13 @@ if(NOT CURL_DISABLE_LDAPS) endif() # Check for idn -check_library_exists_concat("idn" idna_to_ascii_lz HAVE_LIBIDN) +check_library_exists_concat("idn2" idn2_lookup_ul HAVE_LIBIDN2) # Check for symbol dlopen (same as HAVE_LIBDL) check_library_exists("${CURL_LIBS}" dlopen "" HAVE_DLOPEN) if(0) # This code not needed for building within CMake. -option(CURL_ZLIB "Set to ON to enable building cURL with zlib support." ON) +option(CURL_ZLIB "Set to ON to enable building curl with zlib support." ON) set(HAVE_LIBZ OFF) set(HAVE_ZLIB_H OFF) set(HAVE_ZLIB OFF) @@ -707,7 +726,7 @@ check_include_file_concat("des.h" HAVE_DES_H) check_include_file_concat("err.h" HAVE_ERR_H) check_include_file_concat("errno.h" HAVE_ERRNO_H) check_include_file_concat("fcntl.h" HAVE_FCNTL_H) -check_include_file_concat("idn-free.h" HAVE_IDN_FREE_H) +check_include_file_concat("idn2.h" HAVE_IDN2_H) check_include_file_concat("ifaddrs.h" HAVE_IFADDRS_H) check_include_file_concat("io.h" HAVE_IO_H) check_include_file_concat("krb.h" HAVE_KRB_H) @@ -737,7 +756,6 @@ check_include_file_concat("stropts.h" HAVE_STROPTS_H) check_include_file_concat("termio.h" HAVE_TERMIO_H) check_include_file_concat("termios.h" HAVE_TERMIOS_H) check_include_file_concat("time.h" HAVE_TIME_H) -check_include_file_concat("tld.h" HAVE_TLD_H) check_include_file_concat("unistd.h" HAVE_UNISTD_H) check_include_file_concat("utime.h" HAVE_UTIME_H) check_include_file_concat("x509.h" HAVE_X509_H) @@ -751,9 +769,6 @@ check_include_file_concat("netinet/if_ether.h" HAVE_NETINET_IF_ETHER_H) check_include_file_concat("stdint.h" HAVE_STDINT_H) check_include_file_concat("sockio.h" HAVE_SOCKIO_H) check_include_file_concat("sys/utsname.h" HAVE_SYS_UTSNAME_H) -check_include_file_concat("idna.h" HAVE_IDNA_H) - - check_type_size(size_t SIZEOF_SIZE_T) check_type_size(ssize_t SIZEOF_SSIZE_T) @@ -763,7 +778,6 @@ check_type_size("short" SIZEOF_SHORT) check_type_size("int" SIZEOF_INT) check_type_size("__int64" SIZEOF___INT64) check_type_size("time_t" SIZEOF_TIME_T) -check_type_size("off_t" SIZEOF_OFF_T) # Make public versions of some type sizes for curlbuild.h. foreach(t INT LONG LONG_LONG SSIZE_T) @@ -823,8 +837,6 @@ if(CMAKE_USE_OPENSSL) check_symbol_exists(RAND_status "${CURL_INCLUDES}" HAVE_RAND_STATUS) check_symbol_exists(RAND_screen "${CURL_INCLUDES}" HAVE_RAND_SCREEN) check_symbol_exists(RAND_egd "${CURL_INCLUDES}" HAVE_RAND_EGD) - check_symbol_exists(CRYPTO_cleanup_all_ex_data "${CURL_INCLUDES}" - HAVE_CRYPTO_CLEANUP_ALL_EX_DATA) if(HAVE_LIBCRYPTO AND HAVE_LIBSSL) set(USE_OPENSSL 1) endif(HAVE_LIBCRYPTO AND HAVE_LIBSSL) @@ -854,9 +866,6 @@ check_symbol_exists(pipe "${CURL_INCLUDES}" HAVE_PIPE) check_symbol_exists(ftruncate "${CURL_INCLUDES}" HAVE_FTRUNCATE) check_symbol_exists(getprotobyname "${CURL_INCLUDES}" HAVE_GETPROTOBYNAME) check_symbol_exists(getrlimit "${CURL_INCLUDES}" HAVE_GETRLIMIT) -check_symbol_exists(idn_free "${CURL_INCLUDES}" HAVE_IDN_FREE) -check_symbol_exists(idna_strerror "${CURL_INCLUDES}" HAVE_IDNA_STRERROR) -check_symbol_exists(tld_strerror "${CURL_INCLUDES}" HAVE_TLD_STRERROR) check_symbol_exists(setlocale "${CURL_INCLUDES}" HAVE_SETLOCALE) check_symbol_exists(setrlimit "${CURL_INCLUDES}" HAVE_SETRLIMIT) check_symbol_exists(fcntl "${CURL_INCLUDES}" HAVE_FCNTL) @@ -923,9 +932,14 @@ foreach(CURL_TEST ) curl_internal_test(${CURL_TEST}) endforeach(CURL_TEST) + if(HAVE_FILE_OFFSET_BITS) set(_FILE_OFFSET_BITS 64) + set(CMAKE_REQUIRED_FLAGS "-D_FILE_OFFSET_BITS=64") endif(HAVE_FILE_OFFSET_BITS) +check_type_size("off_t" SIZEOF_OFF_T) +set(CMAKE_REQUIRED_FLAGS) + foreach(CURL_TEST HAVE_GLIBC_STRERROR_R HAVE_POSIX_STRERROR_R @@ -987,16 +1001,6 @@ if(NOT CURL_SPECIAL_LIBZ) endif(NOT HAVE_ZLIB_H) endif(NOT CURL_SPECIAL_LIBZ) -if(_FILE_OFFSET_BITS) - set(_FILE_OFFSET_BITS 64) -endif(_FILE_OFFSET_BITS) -set(CMAKE_REQUIRED_FLAGS "-D_FILE_OFFSET_BITS=64") -set(CMAKE_EXTRA_INCLUDE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/curl/curl.h") -check_type_size("curl_off_t" SIZEOF_CURL_OFF_T) -set(CMAKE_EXTRA_INCLUDE_FILES) -set(CMAKE_REQUIRED_FLAGS) - - # Check for nonblocking set(HAVE_DISABLED_NONBLOCKING 1) if(HAVE_FIONBIO OR @@ -1069,6 +1073,11 @@ if(WIN32) add_definitions(-D_WIN32_WINNT=0x0501) endif(WIN32) +# For windows, all compilers used by cmake should support large files +if(WIN32) + set(USE_WIN32_LARGE_FILES ON) +endif(WIN32) + if(MSVC) add_definitions(-D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE) endif(MSVC) @@ -1133,8 +1142,10 @@ _add_if("OpenSSL" SSL_ENABLED AND USE_OPENSSL) _add_if("IPv6" ENABLE_IPV6) _add_if("unix-sockets" USE_UNIX_SOCKETS) _add_if("libz" HAVE_LIBZ) -_add_if("AsynchDNS" USE_ARES OR USE_THREADS_POSIX) -_add_if("IDN" HAVE_LIBIDN) +_add_if("AsynchDNS" USE_ARES OR USE_THREADS_POSIX OR USE_THREADS_WIN32) +_add_if("IDN" HAVE_LIBIDN2) +_add_if("Largefile" (CURL_SIZEOF_CURL_OFF_T GREATER 4) AND + ((SIZEOF_OFF_T GREATER 4) OR USE_WIN32_LARGE_FILES)) # TODO SSP1 (WinSSL) check is missing _add_if("SSPI" USE_WINDOWS_SSPI) _add_if("GSS-API" HAVE_GSSAPI) @@ -1200,9 +1211,7 @@ set(CURL_CA_BUNDLE "") set(CURLVERSION "${CURL_VERSION}") set(ENABLE_SHARED "yes") if(CURL_STATICLIB) - # Broken: LIBCURL_LIBS below; .a lib is not built - message(WARNING "Static linking is broken!") - set(ENABLE_STATIC "no") + set(ENABLE_STATIC "yes") else() set(ENABLE_STATIC "no") endif() @@ -1211,9 +1220,12 @@ set(includedir "\${prefix}/include") set(LDFLAGS "${CMAKE_SHARED_LINKER_FLAGS}") set(LIBCURL_LIBS "") set(libdir "${CMAKE_INSTALL_PREFIX}/lib") -# TODO CURL_LIBS also contains absolute paths which don't work with static -l... foreach(_lib ${CMAKE_C_IMPLICIT_LINK_LIBRARIES} ${CURL_LIBS}) - set(LIBCURL_LIBS "${LIBCURL_LIBS} -l${_lib}") + if(_lib MATCHES ".*/.*") + set(LIBCURL_LIBS "${LIBCURL_LIBS} ${_lib}") + else() + set(LIBCURL_LIBS "${LIBCURL_LIBS} -l${_lib}") + endif() endforeach() # "a" (Linux) or "lib" (Windows) string(REPLACE "." "" libext "${CMAKE_STATIC_LIBRARY_SUFFIX}") diff --git a/Utilities/cmcurl/include/curl/curl.h b/Utilities/cmcurl/include/curl/curl.h index dfaea5d..aa1034b 100644 --- a/Utilities/cmcurl/include/curl/curl.h +++ b/Utilities/cmcurl/include/curl/curl.h @@ -30,6 +30,10 @@ * https://cool.haxx.se/mailman/listinfo/curl-library/ */ +#ifdef CURL_NO_OLDIES +#define CURL_STRICTER +#endif + #include "curlver.h" /* libcurl version defines */ #include "cmcurl/include/curl/curlbuild.h" /* libcurl build definitions */ #include "curlrules.h" /* libcurl rules enforcement */ @@ -431,7 +435,7 @@ typedef enum { CURLE_COULDNT_RESOLVE_PROXY, /* 5 */ CURLE_COULDNT_RESOLVE_HOST, /* 6 */ CURLE_COULDNT_CONNECT, /* 7 */ - CURLE_FTP_WEIRD_SERVER_REPLY, /* 8 */ + CURLE_WEIRD_SERVER_REPLY, /* 8 */ CURLE_REMOTE_ACCESS_DENIED, /* 9 a service was denied by the server due to lack of access - when login fails this is not returned. */ @@ -562,6 +566,7 @@ typedef enum { /* compatibility with older names */ #define CURLOPT_ENCODING CURLOPT_ACCEPT_ENCODING +#define CURLE_FTP_WEIRD_SERVER_REPLY CURLE_WEIRD_SERVER_REPLY /* The following were added in 7.21.5, April 2011 */ #define CURLE_UNKNOWN_TELNET_OPTION CURLE_UNKNOWN_OPTION @@ -1695,6 +1700,10 @@ typedef enum { /* Set TCP Fast Open */ CINIT(TCP_FASTOPEN, LONG, 244), + /* Continue to send data if the server responds early with an + * HTTP status code >= 300 */ + CINIT(KEEP_SENDING_ON_ERROR, LONG, 245), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; diff --git a/Utilities/cmcurl/include/curl/curlver.h b/Utilities/cmcurl/include/curl/curlver.h index 09f612a..2415d1a 100644 --- a/Utilities/cmcurl/include/curl/curlver.h +++ b/Utilities/cmcurl/include/curl/curlver.h @@ -30,13 +30,13 @@ /* This is the version number of the libcurl package from which this header file origins: */ -#define LIBCURL_VERSION "7.50.1" +#define LIBCURL_VERSION "7.51.0" /* The numeric version number is also available "in parts" by using these defines: */ #define LIBCURL_VERSION_MAJOR 7 -#define LIBCURL_VERSION_MINOR 50 -#define LIBCURL_VERSION_PATCH 1 +#define LIBCURL_VERSION_MINOR 51 +#define LIBCURL_VERSION_PATCH 0 /* This is the numeric version of the libcurl version number, meant for easier parsing and comparions by programs. The LIBCURL_VERSION_NUM define will @@ -57,7 +57,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 0x073201 +#define LIBCURL_VERSION_NUM 0x073300 /* * This is the date and time when the full source package was created. The diff --git a/Utilities/cmcurl/lib/CMakeLists.txt b/Utilities/cmcurl/lib/CMakeLists.txt index 0d7b717..76dd6c6 100644 --- a/Utilities/cmcurl/lib/CMakeLists.txt +++ b/Utilities/cmcurl/lib/CMakeLists.txt @@ -111,6 +111,11 @@ endif() set_target_properties(${LIB_NAME} PROPERTIES COMPILE_DEFINITIONS BUILDING_LIBCURL) if(0) # This code not needed for building within CMake. +if(HIDES_CURL_PRIVATE_SYMBOLS) + set_property(TARGET ${LIB_NAME} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS") + set_property(TARGET ${LIB_NAME} APPEND PROPERTY COMPILE_FLAGS ${CURL_CFLAG_SYMBOLS_HIDE}) +endif() + # Remove the "lib" prefix since the library is already named "libcurl". set_target_properties(${LIB_NAME} PROPERTIES PREFIX "") set_target_properties(${LIB_NAME} PROPERTIES IMPORT_PREFIX "") diff --git a/Utilities/cmcurl/lib/Makefile.inc b/Utilities/cmcurl/lib/Makefile.inc index 0ed998c..1328cad 100644 --- a/Utilities/cmcurl/lib/Makefile.inc +++ b/Utilities/cmcurl/lib/Makefile.inc @@ -40,13 +40,13 @@ LIB_VTLS_HFILES = vtls/openssl.h vtls/vtls.h vtls/gtls.h \ LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \ cookie.c http.c sendf.c ftp.c url.c dict.c if2ip.c speedcheck.c \ ldap.c version.c getenv.c escape.c mprintf.c telnet.c netrc.c \ - getinfo.c transfer.c strequal.c easy.c security.c curl_fnmatch.c \ + getinfo.c transfer.c strcase.c easy.c security.c curl_fnmatch.c \ fileinfo.c ftplistparser.c wildcard.c krb5.c memdebug.c http_chunks.c \ strtok.c connect.c llist.c hash.c multi.c content_encoding.c share.c \ http_digest.c md4.c md5.c http_negotiate.c inet_pton.c strtoofft.c \ strerror.c amigaos.c hostasyn.c hostip4.c hostip6.c hostsyn.c \ inet_ntop.c parsedate.c select.c tftp.c splay.c strdup.c socks.c \ - ssh.c rawstr.c curl_addrinfo.c socks_gssapi.c socks_sspi.c \ + ssh.c curl_addrinfo.c socks_gssapi.c socks_sspi.c \ curl_sspi.c slist.c nonblock.c curl_memrchr.c imap.c pop3.c smtp.c \ pingpong.c rtsp.c curl_threads.c warnless.c hmac.c curl_rtmp.c \ openldap.c curl_gethostname.c gopher.c idn_win32.c \ @@ -58,13 +58,13 @@ LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \ LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \ formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h if2ip.h \ speedcheck.h urldata.h curl_ldap.h escape.h telnet.h getinfo.h \ - strequal.h curl_sec.h memdebug.h http_chunks.h curl_fnmatch.h \ + strcase.h curl_sec.h memdebug.h http_chunks.h curl_fnmatch.h \ wildcard.h fileinfo.h ftplistparser.h strtok.h connect.h llist.h \ hash.h content_encoding.h share.h curl_md4.h curl_md5.h http_digest.h \ http_negotiate.h inet_pton.h amigaos.h strtoofft.h strerror.h \ inet_ntop.h curlx.h curl_memory.h curl_setup.h transfer.h select.h \ easyif.h multiif.h parsedate.h tftp.h sockaddr.h splay.h strdup.h \ - socks.h ssh.h curl_base64.h rawstr.h curl_addrinfo.h curl_sspi.h \ + socks.h ssh.h curl_base64.h curl_addrinfo.h curl_sspi.h \ slist.h nonblock.h curl_memrchr.h imap.h pop3.h smtp.h pingpong.h \ rtsp.h curl_threads.h warnless.h curl_hmac.h curl_rtmp.h \ curl_gethostname.h gopher.h http_proxy.h non-ascii.h asyn.h \ diff --git a/Utilities/cmcurl/lib/amigaos.c b/Utilities/cmcurl/lib/amigaos.c index 5591d22..4f55b30 100644 --- a/Utilities/cmcurl/lib/amigaos.c +++ b/Utilities/cmcurl/lib/amigaos.c @@ -57,7 +57,7 @@ bool Curl_amiga_init() } if(SocketBaseTags(SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno))), (ULONG) &errno, - SBTM_SETVAL(SBTC_LOGTAGPTR), (ULONG) "cURL", + SBTM_SETVAL(SBTC_LOGTAGPTR), (ULONG) "curl", TAG_DONE)) { __request("SocketBaseTags ERROR"); return FALSE; diff --git a/Utilities/cmcurl/lib/base64.c b/Utilities/cmcurl/lib/base64.c index ad25459..204a227 100644 --- a/Utilities/cmcurl/lib/base64.c +++ b/Utilities/cmcurl/lib/base64.c @@ -190,6 +190,11 @@ static CURLcode base64_encode(const char *table64, if(!insize) insize = strlen(indata); +#if SIZEOF_SIZE_T == 4 + if(insize > UINT_MAX/4) + return CURLE_OUT_OF_MEMORY; +#endif + base64data = output = malloc(insize * 4 / 3 + 4); if(!output) return CURLE_OUT_OF_MEMORY; diff --git a/Utilities/cmcurl/lib/conncache.c b/Utilities/cmcurl/lib/conncache.c index 32a7030..01b1b44 100644 --- a/Utilities/cmcurl/lib/conncache.c +++ b/Utilities/cmcurl/lib/conncache.c @@ -30,7 +30,6 @@ #include "progress.h" #include "multiif.h" #include "sendf.h" -#include "rawstr.h" #include "conncache.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" diff --git a/Utilities/cmcurl/lib/connect.c b/Utilities/cmcurl/lib/connect.c index 0047f9a..3df34d9 100644 --- a/Utilities/cmcurl/lib/connect.c +++ b/Utilities/cmcurl/lib/connect.c @@ -762,7 +762,7 @@ CURLcode Curl_is_connected(struct connectdata *conn, #endif /* check socket for connect */ - rc = Curl_socket_ready(CURL_SOCKET_BAD, conn->tempsock[i], 0); + rc = SOCKET_WRITABLE(conn->tempsock[i], 0); if(rc == 0) { /* no connection yet */ error = 0; @@ -1368,25 +1368,26 @@ CURLcode Curl_socket(struct connectdata *conn, } -#ifdef CURLDEBUG /* - * Curl_conncontrol() is used to set the conn->bits.close bit on or off. It - * MUST be called with the connclose() or connkeep() macros with a stated - * reason. The reason is only shown in debug builds but helps to figure out - * decision paths when connections are or aren't re-used as expected. + * Curl_conncontrol() marks streams or connection for closure. */ -void Curl_conncontrol(struct connectdata *conn, bool closeit, - const char *reason) -{ -#if defined(CURL_DISABLE_VERBOSE_STRINGS) - (void) reason; +void Curl_conncontrol(struct connectdata *conn, + int ctrl /* see defines in header */ +#ifdef DEBUGBUILD + , const char *reason #endif - if(closeit != conn->bits.close) { - infof(conn->data, "Marked for [%s]: %s\n", closeit?"closure":"keep alive", - reason); - + ) +{ + /* close if a connection, or a stream that isn't multiplexed */ + bool closeit = (ctrl == CONNCTRL_CONNECTION) || + ((ctrl == CONNCTRL_STREAM) && !(conn->handler->flags & PROTOPT_STREAM)); + if((ctrl == CONNCTRL_STREAM) && + (conn->handler->flags & PROTOPT_STREAM)) + DEBUGF(infof(conn->data, "Kill stream: %s\n", reason)); + else if(closeit != conn->bits.close) { + DEBUGF(infof(conn->data, "Marked for [%s]: %s\n", + closeit?"closure":"keep alive", reason)); conn->bits.close = closeit; /* the only place in the source code that should assign this bit */ } } -#endif diff --git a/Utilities/cmcurl/lib/connect.h b/Utilities/cmcurl/lib/connect.h index 6d60e0d..a7cbc9b 100644 --- a/Utilities/cmcurl/lib/connect.h +++ b/Utilities/cmcurl/lib/connect.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2016, 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 @@ -104,21 +104,37 @@ CURLcode Curl_socket(struct connectdata *conn, void Curl_tcpnodelay(struct connectdata *conn, curl_socket_t sockfd); -#ifdef CURLDEBUG /* - * Curl_connclose() sets the bit.close bit to TRUE with an explanation. - * Nothing else. + * Curl_conncontrol() marks the end of a connection/stream. The 'closeit' + * argument specifies if it is the end of a connection or a stream. + * + * For stream-based protocols (such as HTTP/2), a stream close will not cause + * a connection close. Other protocols will close the connection for both + * cases. + * + * It sets the bit.close bit to TRUE (with an explanation for debug builds), + * when the connection will close. */ -void Curl_conncontrol(struct connectdata *conn, - bool closeit, - const char *reason); -#define connclose(x,y) Curl_conncontrol(x,TRUE, y) -#define connkeep(x,y) Curl_conncontrol(x, FALSE, y) -#else /* if !CURLDEBUG */ -#define connclose(x,y) (x)->bits.close = TRUE -#define connkeep(x,y) (x)->bits.close = FALSE +#define CONNCTRL_KEEP 0 /* undo a marked closure */ +#define CONNCTRL_CONNECTION 1 +#define CONNCTRL_STREAM 2 +void Curl_conncontrol(struct connectdata *conn, + int closeit +#ifdef DEBUGBUILD + , const char *reason +#endif + ); + +#ifdef DEBUGBUILD +#define streamclose(x,y) Curl_conncontrol(x, CONNCTRL_STREAM, y) +#define connclose(x,y) Curl_conncontrol(x, CONNCTRL_CONNECTION, y) +#define connkeep(x,y) Curl_conncontrol(x, CONNCTRL_KEEP, y) +#else /* if !CURLDEBUG */ +#define streamclose(x,y) Curl_conncontrol(x, CONNCTRL_STREAM) +#define connclose(x,y) Curl_conncontrol(x, CONNCTRL_CONNECTION) +#define connkeep(x,y) Curl_conncontrol(x, CONNCTRL_KEEP) #endif #endif /* HEADER_CURL_CONNECT_H */ diff --git a/Utilities/cmcurl/lib/cookie.c b/Utilities/cmcurl/lib/cookie.c index d5a83fd..1b3e645 100644 --- a/Utilities/cmcurl/lib/cookie.c +++ b/Utilities/cmcurl/lib/cookie.c @@ -90,13 +90,12 @@ Example set of cookies: #include "urldata.h" #include "cookie.h" -#include "strequal.h" #include "strtok.h" #include "sendf.h" #include "slist.h" #include "share.h" #include "strtoofft.h" -#include "rawstr.h" +#include "strcase.h" #include "curl_memrchr.h" #include "inet_pton.h" @@ -126,7 +125,7 @@ static bool tailmatch(const char *cooke_domain, const char *hostname) if(hostname_len < cookie_domain_len) return FALSE; - if(!Curl_raw_equal(cooke_domain, hostname+hostname_len-cookie_domain_len)) + if(!strcasecompare(cooke_domain, hostname+hostname_len-cookie_domain_len)) return FALSE; /* A lead char of cookie_domain is not '.'. @@ -469,9 +468,9 @@ Curl_cookie_add(struct Curl_easy *data, /* this was a "<name>=" with no content, and we must allow 'secure' and 'httponly' specified this weirdly */ done = TRUE; - if(Curl_raw_equal("secure", name)) + if(strcasecompare("secure", name)) co->secure = TRUE; - else if(Curl_raw_equal("httponly", name)) + else if(strcasecompare("httponly", name)) co->httponly = TRUE; else if(sep) /* there was a '=' so we're not done parsing this field */ @@ -479,7 +478,7 @@ Curl_cookie_add(struct Curl_easy *data, } if(done) ; - else if(Curl_raw_equal("path", name)) { + else if(strcasecompare("path", name)) { strstore(&co->path, whatptr); if(!co->path) { badcookie = TRUE; /* out of memory bad */ @@ -491,7 +490,7 @@ Curl_cookie_add(struct Curl_easy *data, break; } } - else if(Curl_raw_equal("domain", name)) { + else if(strcasecompare("domain", name)) { bool is_ip; const char *dotp; @@ -529,14 +528,14 @@ Curl_cookie_add(struct Curl_easy *data, whatptr); } } - else if(Curl_raw_equal("version", name)) { + else if(strcasecompare("version", name)) { strstore(&co->version, whatptr); if(!co->version) { badcookie = TRUE; break; } } - else if(Curl_raw_equal("max-age", name)) { + else if(strcasecompare("max-age", name)) { /* Defined in RFC2109: Optional. The Max-Age attribute defines the lifetime of the @@ -552,7 +551,7 @@ Curl_cookie_add(struct Curl_easy *data, break; } } - else if(Curl_raw_equal("expires", name)) { + else if(strcasecompare("expires", name)) { strstore(&co->expirestr, whatptr); if(!co->expirestr) { badcookie = TRUE; @@ -713,7 +712,7 @@ Curl_cookie_add(struct Curl_easy *data, As far as I can see, it is set to true when the cookie says .domain.com and to false when the domain is complete www.domain.com */ - co->tailmatch = Curl_raw_equal(ptr, "TRUE")?TRUE:FALSE; + co->tailmatch = strcasecompare(ptr, "TRUE")?TRUE:FALSE; break; case 2: /* It turns out, that sometimes the file format allows the path @@ -742,7 +741,7 @@ Curl_cookie_add(struct Curl_easy *data, fields++; /* add a field and fall down to secure */ /* FALLTHROUGH */ case 3: - co->secure = Curl_raw_equal(ptr, "TRUE")?TRUE:FALSE; + co->secure = strcasecompare(ptr, "TRUE")?TRUE:FALSE; break; case 4: co->expires = curlx_strtoofft(ptr, NULL, 10); @@ -813,11 +812,12 @@ Curl_cookie_add(struct Curl_easy *data, clist = c->cookies; replace_old = FALSE; while(clist) { - if(Curl_raw_equal(clist->name, co->name)) { + if(strcasecompare(clist->name, co->name)) { /* the names are identical */ if(clist->domain && co->domain) { - if(Curl_raw_equal(clist->domain, co->domain)) + if(strcasecompare(clist->domain, co->domain) && + (clist->tailmatch == co->tailmatch)) /* The domains are identical */ replace_old=TRUE; } @@ -828,7 +828,7 @@ Curl_cookie_add(struct Curl_easy *data, /* the domains were identical */ if(clist->spath && co->spath) { - if(Curl_raw_equal(clist->spath, co->spath)) { + if(strcasecompare(clist->spath, co->spath)) { replace_old = TRUE; } else @@ -902,6 +902,35 @@ Curl_cookie_add(struct Curl_easy *data, return co; } +/* + * get_line() makes sure to only return complete whole lines that fit in 'len' + * bytes and end with a newline. + */ +static char *get_line(char *buf, int len, FILE *input) +{ + bool partial = FALSE; + while(1) { + char *b = fgets(buf, len, input); + if(b) { + size_t rlen = strlen(b); + if(rlen && (b[rlen-1] == '\n')) { + if(partial) { + partial = FALSE; + continue; + } + return b; + } + else + /* read a partial, discard the next piece that ends with newline */ + partial = TRUE; + } + else + break; + } + return NULL; +} + + /***************************************************************************** * * Curl_cookie_init() @@ -938,7 +967,7 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data, } c->running = FALSE; /* this is not running, this is init */ - if(file && strequal(file, "-")) { + if(file && !strcmp(file, "-")) { fp = stdin; fromfile=FALSE; } @@ -958,7 +987,7 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data, line = malloc(MAX_COOKIE_LINE); if(!line) goto fail; - while(fgets(line, MAX_COOKIE_LINE, fp)) { + while(get_line(line, MAX_COOKIE_LINE, fp)) { if(checkprefix("Set-Cookie:", line)) { /* This is a cookie line, get it! */ lineptr=&line[11]; @@ -1023,6 +1052,40 @@ static int cookie_sort(const void *p1, const void *p2) return 0; } +#define CLONE(field) \ + do { \ + if(src->field) { \ + dup->field = strdup(src->field); \ + if(!dup->field) \ + goto fail; \ + } \ + } while(0) + +static struct Cookie *dup_cookie(struct Cookie *src) +{ + struct Cookie *dup = calloc(sizeof(struct Cookie), 1); + if(dup) { + CLONE(expirestr); + CLONE(domain); + CLONE(path); + CLONE(spath); + CLONE(name); + CLONE(value); + CLONE(maxage); + CLONE(version); + dup->expires = src->expires; + dup->tailmatch = src->tailmatch; + dup->secure = src->secure; + dup->livecookie = src->livecookie; + dup->httponly = src->httponly; + } + return dup; + + fail: + freecookie(dup); + return NULL; +} + /***************************************************************************** * * Curl_cookie_getlist() @@ -1067,7 +1130,7 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, /* now check if the domain is correct */ if(!co->domain || (co->tailmatch && !is_ip && tailmatch(co->domain, host)) || - ((!co->tailmatch || is_ip) && Curl_raw_equal(host, co->domain)) ) { + ((!co->tailmatch || is_ip) && strcasecompare(host, co->domain)) ) { /* the right part of the host matches the domain stuff in the cookie data */ @@ -1078,11 +1141,8 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, /* and now, we know this is a match and we should create an entry for the return-linked-list */ - newco = malloc(sizeof(struct Cookie)); + newco = dup_cookie(co); if(newco) { - /* first, copy the whole source cookie: */ - memcpy(newco, co, sizeof(struct Cookie)); - /* then modify our next */ newco->next = mainco; @@ -1094,12 +1154,7 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, else { fail: /* failure, clear up the allocated chain and return NULL */ - while(mainco) { - co = mainco->next; - free(mainco); - mainco = co; - } - + Curl_cookie_freelist(mainco); return NULL; } } @@ -1151,7 +1206,7 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, void Curl_cookie_clearall(struct CookieInfo *cookies) { if(cookies) { - Curl_cookie_freelist(cookies->cookies, TRUE); + Curl_cookie_freelist(cookies->cookies); cookies->cookies = NULL; cookies->numcookies = 0; } @@ -1163,21 +1218,14 @@ void Curl_cookie_clearall(struct CookieInfo *cookies) * * Free a list of cookies previously returned by Curl_cookie_getlist(); * - * The 'cookiestoo' argument tells this function whether to just free the - * list or actually also free all cookies within the list as well. - * ****************************************************************************/ -void Curl_cookie_freelist(struct Cookie *co, bool cookiestoo) +void Curl_cookie_freelist(struct Cookie *co) { struct Cookie *next; while(co) { next = co->next; - if(cookiestoo) - freecookie(co); - else - free(co); /* we only free the struct since the "members" are all just - pointed out in the main cookie list! */ + freecookie(co); co = next; } } @@ -1232,7 +1280,7 @@ void Curl_cookie_cleanup(struct CookieInfo *c) { if(c) { free(c->filename); - Curl_cookie_freelist(c->cookies, TRUE); + Curl_cookie_freelist(c->cookies); free(c); /* free the base struct as well */ } } @@ -1290,7 +1338,7 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere) /* at first, remove expired cookies */ remove_expired(c); - if(strequal("-", dumphere)) { + if(!strcmp("-", dumphere)) { /* use stdout */ out = stdout; use_stdout=TRUE; diff --git a/Utilities/cmcurl/lib/cookie.h b/Utilities/cmcurl/lib/cookie.h index cd7c54a..a9a4578 100644 --- a/Utilities/cmcurl/lib/cookie.h +++ b/Utilities/cmcurl/lib/cookie.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2016, 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 @@ -82,7 +82,7 @@ struct Cookie *Curl_cookie_add(struct Curl_easy *data, struct Cookie *Curl_cookie_getlist(struct CookieInfo *, const char *, const char *, bool); -void Curl_cookie_freelist(struct Cookie *cookies, bool cookiestoo); +void Curl_cookie_freelist(struct Cookie *cookies); void Curl_cookie_clearall(struct CookieInfo *cookies); void Curl_cookie_clearsess(struct CookieInfo *cookies); diff --git a/Utilities/cmcurl/lib/curl_config.h.cmake b/Utilities/cmcurl/lib/curl_config.h.cmake index 20f212b..13f69b2 100644 --- a/Utilities/cmcurl/lib/curl_config.h.cmake +++ b/Utilities/cmcurl/lib/curl_config.h.cmake @@ -61,7 +61,7 @@ #cmakedefine CURL_DISABLE_VERBOSE_STRINGS 1 /* to make a symbol visible */ -#cmakedefine CURL_EXTERN_SYMBOL 1 +#cmakedefine CURL_EXTERN_SYMBOL ${CURL_EXTERN_SYMBOL} /* Ensure using CURL_EXTERN_SYMBOL is possible */ #ifndef CURL_EXTERN_SYMBOL #define CURL_EXTERN_SYMBOL @@ -900,6 +900,9 @@ /* Define if you want to enable POSIX threaded DNS lookup */ #cmakedefine USE_THREADS_POSIX 1 +/* Define if you want to enable WIN32 threaded DNS lookup */ +#cmakedefine USE_THREADS_WIN32 1 + /* Define to disable non-blocking sockets. */ #cmakedefine USE_BLOCKING_SOCKETS 1 @@ -927,6 +930,9 @@ /* if OpenSSL is in use */ #cmakedefine USE_OPENSSL 1 +/* to enable NGHTTP2 */ +#cmakedefine USE_NGHTTP2 1 + /* if Unix domain sockets are enabled */ #cmakedefine USE_UNIX_SOCKETS diff --git a/Utilities/cmcurl/lib/curl_ntlm_core.c b/Utilities/cmcurl/lib/curl_ntlm_core.c index f3fb013..812a073 100644 --- a/Utilities/cmcurl/lib/curl_ntlm_core.c +++ b/Utilities/cmcurl/lib/curl_ntlm_core.c @@ -76,6 +76,11 @@ # define MD5_DIGEST_LENGTH 16 # define MD4_DIGEST_LENGTH 16 +#elif defined(USE_MBEDTLS) + +# include <mbedtls/des.h> +# include <mbedtls/md4.h> + #elif defined(USE_NSS) # include <nss.h> @@ -100,7 +105,7 @@ #include "urldata.h" #include "non-ascii.h" -#include "rawstr.h" +#include "strcase.h" #include "curl_ntlm_core.h" #include "curl_md5.h" #include "curl_hmac.h" @@ -188,6 +193,26 @@ static void setup_des_key(const unsigned char *key_56, gcry_cipher_setkey(*des, key, sizeof(key)); } +#elif defined(USE_MBEDTLS) + +static bool encrypt_des(const unsigned char *in, unsigned char *out, + const unsigned char *key_56) +{ + mbedtls_des_context ctx; + char key[8]; + + /* Expand the 56-bit key to 64-bits */ + extend_key_56_to_64(key_56, key); + + /* Set the key parity to odd */ + mbedtls_des_key_set_parity((unsigned char *) key); + + /* Perform the encryption */ + mbedtls_des_init(&ctx); + mbedtls_des_setkey_enc(&ctx, (unsigned char *) key); + return mbedtls_des_crypt_ecb(&ctx, in, out) == 0; +} + #elif defined(USE_NSS) /* @@ -400,8 +425,8 @@ void Curl_ntlm_core_lm_resp(const unsigned char *keys, setup_des_key(keys + 14, &des); gcry_cipher_encrypt(des, results + 16, 8, plaintext, 8); gcry_cipher_close(des); -#elif defined(USE_NSS) || defined(USE_DARWINSSL) || defined(USE_OS400CRYPTO) \ - || defined(USE_WIN32_CRYPTO) +#elif defined(USE_MBEDTLS) || defined(USE_NSS) || defined(USE_DARWINSSL) \ + || 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); @@ -464,8 +489,8 @@ CURLcode Curl_ntlm_core_mk_lm_hash(struct Curl_easy *data, setup_des_key(pw + 7, &des); gcry_cipher_encrypt(des, lmbuffer + 8, 8, magic, 8); gcry_cipher_close(des); -#elif defined(USE_NSS) || defined(USE_DARWINSSL) || defined(USE_OS400CRYPTO) \ - || defined(USE_WIN32_CRYPTO) +#elif defined(USE_MBEDTLS) || defined(USE_NSS) || defined(USE_DARWINSSL) \ + || defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) encrypt_des(magic, lmbuffer, pw); encrypt_des(magic, lmbuffer + 8, pw + 7); #endif @@ -543,6 +568,8 @@ CURLcode Curl_ntlm_core_mk_nt_hash(struct Curl_easy *data, gcry_md_write(MD4pw, pw, 2 * len); memcpy (ntbuffer, gcry_md_read (MD4pw, 0), MD4_DIGEST_LENGTH); gcry_md_close(MD4pw); +#elif defined(USE_MBEDTLS) + mbedtls_md4(pw, 2 * len, ntbuffer); #elif defined(USE_NSS) || defined(USE_OS400CRYPTO) Curl_md4it(ntbuffer, pw, 2 * len); #elif defined(USE_DARWINSSL) diff --git a/Utilities/cmcurl/lib/curl_sasl.c b/Utilities/cmcurl/lib/curl_sasl.c index 35e9fea..6b86962 100644 --- a/Utilities/cmcurl/lib/curl_sasl.c +++ b/Utilities/cmcurl/lib/curl_sasl.c @@ -42,8 +42,6 @@ #include "curl_sasl.h" #include "warnless.h" #include "strtok.h" -#include "strequal.h" -#include "rawstr.h" #include "sendf.h" #include "non-ascii.h" /* included for Curl_convert_... prototypes */ /* The last 3 #include files should be in this order */ @@ -159,7 +157,7 @@ CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl, sasl->prefmech = SASL_AUTH_NONE; } - if(strnequal(value, "*", len)) + if(!strncmp(value, "*", len)) sasl->prefmech = SASL_AUTH_DEFAULT; else { mechbit = Curl_sasl_decode_mech(value, len, &mechlen); @@ -288,7 +286,8 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, } else if(conn->bits.user_passwd) { #if defined(USE_KERBEROS5) - if(enabledmechs & SASL_MECH_GSSAPI) { + if((enabledmechs & SASL_MECH_GSSAPI) && Curl_auth_is_gssapi_supported() && + Curl_auth_user_contains_domain(conn->user)) { sasl->mutual_auth = FALSE; /* TODO: Calculate mutual authentication */ mech = SASL_MECH_STRING_GSSAPI; state1 = SASL_GSSAPI; @@ -308,7 +307,8 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, else #endif #ifndef CURL_DISABLE_CRYPTO_AUTH - if(enabledmechs & SASL_MECH_DIGEST_MD5) { + 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; @@ -321,7 +321,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, else #endif #ifdef USE_NTLM - if(enabledmechs & SASL_MECH_NTLM) { + if((enabledmechs & SASL_MECH_NTLM) && Curl_auth_is_ntlm_supported()) { mech = SASL_MECH_STRING_NTLM; state1 = SASL_NTLM; state2 = SASL_NTLM_TYPE2MSG; diff --git a/Utilities/cmcurl/lib/curl_setup.h b/Utilities/cmcurl/lib/curl_setup.h index 2122220..4eb17a1 100644 --- a/Utilities/cmcurl/lib/curl_setup.h +++ b/Utilities/cmcurl/lib/curl_setup.h @@ -614,10 +614,9 @@ int netware_init(void); #endif #endif -#if defined(HAVE_LIBIDN) && defined(HAVE_TLD_H) -/* The lib was present and the tld.h header (which is missing in libidn 0.3.X - but we only work with libidn 0.4.1 or later) */ -#define USE_LIBIDN +#if defined(HAVE_LIBIDN2) && defined(HAVE_IDN2_H) +/* The lib and header are present */ +#define USE_LIBIDN2 #endif #ifndef SIZEOF_TIME_T @@ -653,6 +652,13 @@ int netware_init(void); defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) #define USE_NTLM + +#elif defined(USE_MBEDTLS) +# include <mbedtls/md4.h> +# if defined(MBEDTLS_MD4_C) +#define USE_NTLM +# endif + #endif #endif @@ -761,4 +767,14 @@ endings either CRLF or LF so 't' is appropriate. # endif #endif /* DONT_USE_RECV_BEFORE_SEND_WORKAROUNDS */ +/* Detect Windows App environment which has a restricted access + * to the Win32 APIs. */ +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0602) +# include <winapifamily.h> +# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \ + !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# define CURL_WINDOWS_APP +# endif +# endif + #endif /* HEADER_CURL_SETUP_H */ diff --git a/Utilities/cmcurl/lib/curl_sspi.c b/Utilities/cmcurl/lib/curl_sspi.c index ee3f1b1..11a7120 100644 --- a/Utilities/cmcurl/lib/curl_sspi.c +++ b/Utilities/cmcurl/lib/curl_sspi.c @@ -64,6 +64,12 @@ PSecurityFunctionTable s_pSecFn = NULL; * * Once this function has been executed, Windows SSPI functions can be * called through the Security Service Provider Interface dispatch table. + * + * Parameters: + * + * None. + * + * Returns CURLE_OK on success. */ CURLcode Curl_sspi_global_init(void) { @@ -102,8 +108,11 @@ CURLcode Curl_sspi_global_init(void) * Curl_sspi_global_cleanup() * * This deinitializes the Security Service Provider Interface from libcurl. + * + * Parameters: + * + * None. */ - void Curl_sspi_global_cleanup(void) { if(s_hSecDll) { @@ -205,6 +214,15 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp, return CURLE_OK; } +/* + * Curl_sspi_free_identity() + * + * This is used to free the contents of a SSPI identifier structure. + * + * Parameters: + * + * identity [in/out] - The identity structure. + */ void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY *identity) { if(identity) { diff --git a/Utilities/cmcurl/lib/curlx.h b/Utilities/cmcurl/lib/curlx.h index 448a34f..6168dc1 100644 --- a/Utilities/cmcurl/lib/curlx.h +++ b/Utilities/cmcurl/lib/curlx.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2016, 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 @@ -34,8 +34,8 @@ functions while they still are offered publicly. They will be made library- private one day */ -#include "strequal.h" -/* "strequal.h" provides the strequal protos */ +#include "strcase.h" +/* "strcase.h" provides the strcasecompare protos */ #include "strtoofft.h" /* "strtoofft.h" provides this function: curlx_strtoofft(), returns a @@ -67,15 +67,12 @@ be removed from a future libcurl official API: curlx_getenv curlx_mprintf (and its variations) - curlx_strequal - curlx_strnequal + curlx_strcasecompare + curlx_strncasecompare */ #define curlx_getenv curl_getenv -#define curlx_strequal curl_strequal -#define curlx_strnequal curl_strnequal -#define curlx_raw_equal Curl_raw_equal #define curlx_mvsnprintf curl_mvsnprintf #define curlx_msnprintf curl_msnprintf #define curlx_maprintf curl_maprintf diff --git a/Utilities/cmcurl/lib/dict.c b/Utilities/cmcurl/lib/dict.c index a7b5965..69defc4 100644 --- a/Utilities/cmcurl/lib/dict.c +++ b/Utilities/cmcurl/lib/dict.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2016, 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 @@ -52,11 +52,10 @@ #include <curl/curl.h> #include "transfer.h" #include "sendf.h" - +#include "escape.h" #include "progress.h" -#include "strequal.h" #include "dict.h" -#include "rawstr.h" +#include "strcase.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -96,12 +95,12 @@ static char *unescape_word(struct Curl_easy *data, const char *inputbuff) char *newp; char *dictp; char *ptr; - int len; + size_t len; char ch; int olen=0; - newp = curl_easy_unescape(data, inputbuff, 0, &len); - if(!newp) + CURLcode result = Curl_urldecode(data, inputbuff, 0, &newp, &len, FALSE); + if(!newp || result) return NULL; dictp = malloc(((size_t)len)*2 + 1); /* add one for terminating zero */ @@ -145,9 +144,9 @@ static CURLcode dict_do(struct connectdata *conn, bool *done) /* AUTH is missing */ } - if(Curl_raw_nequal(path, DICT_MATCH, sizeof(DICT_MATCH)-1) || - Curl_raw_nequal(path, DICT_MATCH2, sizeof(DICT_MATCH2)-1) || - Curl_raw_nequal(path, DICT_MATCH3, sizeof(DICT_MATCH3)-1)) { + 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)) { word = strchr(path, ':'); if(word) { @@ -203,9 +202,9 @@ static CURLcode dict_do(struct connectdata *conn, bool *done) Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount, -1, NULL); /* no upload */ } - else if(Curl_raw_nequal(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) || - Curl_raw_nequal(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) || - Curl_raw_nequal(path, DICT_DEFINE3, sizeof(DICT_DEFINE3)-1)) { + 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)) { word = strchr(path, ':'); if(word) { diff --git a/Utilities/cmcurl/lib/easy.c b/Utilities/cmcurl/lib/easy.c index dc7139f..eee1061 100644 --- a/Utilities/cmcurl/lib/easy.c +++ b/Utilities/cmcurl/lib/easy.c @@ -50,7 +50,6 @@ #include <sys/param.h> #endif -#include "strequal.h" #include "urldata.h" #include <curl/curl.h> #include "transfer.h" @@ -144,28 +143,6 @@ static CURLcode win32_init(void) return CURLE_OK; } -#ifdef USE_LIBIDN -/* - * Initialise use of IDNA library. - * It falls back to ASCII if $CHARSET isn't defined. This doesn't work for - * idna_to_ascii_lz(). - */ -static void idna_init (void) -{ -#ifdef WIN32 - char buf[60]; - UINT cp = GetACP(); - - if(!getenv("CHARSET") && cp > 0) { - snprintf(buf, sizeof(buf), "CHARSET=cp%u", cp); - putenv(buf); - } -#else - /* to do? */ -#endif -} -#endif /* USE_LIBIDN */ - /* true globals -- for curl_global_init() and curl_global_cleanup() */ static unsigned int initialized; static long init_flags; @@ -217,7 +194,7 @@ curl_calloc_callback Curl_ccalloc; #endif /** - * curl_global_init() globally initializes cURL given a bitwise set of the + * curl_global_init() globally initializes curl given a bitwise set of the * different features of what to initialize. */ static CURLcode global_init(long flags, bool memoryfuncs) @@ -262,10 +239,6 @@ static CURLcode global_init(long flags, bool memoryfuncs) } #endif -#ifdef USE_LIBIDN - idna_init(); -#endif - if(Curl_resolver_global_init()) { DEBUGF(fprintf(stderr, "Error: resolver_global_init failed\n")); return CURLE_FAILED_INIT; @@ -292,7 +265,7 @@ static CURLcode global_init(long flags, bool memoryfuncs) /** - * curl_global_init() globally initializes cURL given a bitwise set of the + * curl_global_init() globally initializes curl given a bitwise set of the * different features of what to initialize. */ CURLcode curl_global_init(long flags) @@ -301,7 +274,7 @@ CURLcode curl_global_init(long flags) } /* - * curl_global_init_mem() globally initializes cURL and also registers the + * curl_global_init_mem() globally initializes curl and also registers the * user provided callback routines. */ CURLcode curl_global_init_mem(long flags, curl_malloc_callback m, @@ -333,7 +306,7 @@ CURLcode curl_global_init_mem(long flags, curl_malloc_callback m, } /** - * curl_global_cleanup() globally cleanups cURL, uses the value of + * curl_global_cleanup() globally cleanups curl, uses the value of * "init_flags" to determine what needs to be cleaned up and what doesn't. */ void curl_global_cleanup(void) @@ -995,6 +968,9 @@ void curl_easy_reset(struct Curl_easy *data) /* zero out Progress data: */ memset(&data->progress, 0, sizeof(struct Progress)); + /* zero out PureInfo data: */ + Curl_initinfo(data); + data->progress.flags |= PGRS_HIDE; data->state.current_speed = -1; /* init to negative == impossible */ } @@ -1044,7 +1020,7 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action) if(!result && ((newstate&(KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) != (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) ) - Curl_expire(data, 1); /* get this handle going again */ + Curl_expire(data, 0); /* get this handle going again */ return result; } diff --git a/Utilities/cmcurl/lib/escape.c b/Utilities/cmcurl/lib/escape.c index 04230b4..6657007 100644 --- a/Utilities/cmcurl/lib/escape.c +++ b/Utilities/cmcurl/lib/escape.c @@ -78,15 +78,21 @@ char *curl_unescape(const char *string, int length) char *curl_easy_escape(struct Curl_easy *data, const char *string, int inlength) { - size_t alloc = (inlength?(size_t)inlength:strlen(string))+1; + size_t alloc; char *ns; char *testing_ptr = NULL; unsigned char in; /* we need to treat the characters unsigned */ - size_t newlen = alloc; + size_t newlen; size_t strindex=0; size_t length; CURLcode result; + if(inlength < 0) + return NULL; + + alloc = (inlength?(size_t)inlength:strlen(string))+1; + newlen = alloc; + ns = malloc(alloc); if(!ns) return NULL; @@ -211,14 +217,22 @@ char *curl_easy_unescape(struct Curl_easy *data, const char *string, int length, int *olen) { char *str = NULL; - size_t inputlen = length; - size_t outputlen; - CURLcode res = Curl_urldecode(data, string, inputlen, &str, &outputlen, - FALSE); - if(res) - return NULL; - if(olen) - *olen = curlx_uztosi(outputlen); + if(length >= 0) { + size_t inputlen = length; + size_t outputlen; + CURLcode res = Curl_urldecode(data, string, inputlen, &str, &outputlen, + FALSE); + if(res) + return NULL; + + if(olen) { + if(outputlen <= (size_t) INT_MAX) + *olen = curlx_uztosi(outputlen); + else + /* too large to return in an int, fail! */ + Curl_safefree(str); + } + } return str; } diff --git a/Utilities/cmcurl/lib/file.c b/Utilities/cmcurl/lib/file.c index b534ec1..272289e 100644 --- a/Utilities/cmcurl/lib/file.c +++ b/Utilities/cmcurl/lib/file.c @@ -190,14 +190,15 @@ static CURLcode file_connect(struct connectdata *conn, bool *done) struct FILEPROTO *file = data->req.protop; int fd; #ifdef DOS_FILESYSTEM - int i; + size_t i; char *actual_path; #endif - int real_path_len; + size_t real_path_len; - real_path = curl_easy_unescape(data, data->state.path, 0, &real_path_len); - if(!real_path) - return CURLE_OUT_OF_MEMORY; + CURLcode result = Curl_urldecode(data, data->state.path, 0, &real_path, + &real_path_len, FALSE); + if(result) + return result; #ifdef DOS_FILESYSTEM /* If the first character is a slash, and there's diff --git a/Utilities/cmcurl/lib/formdata.c b/Utilities/cmcurl/lib/formdata.c index 673759d..785f1a6 100644 --- a/Utilities/cmcurl/lib/formdata.c +++ b/Utilities/cmcurl/lib/formdata.c @@ -33,7 +33,7 @@ #include "urldata.h" /* for struct Curl_easy */ #include "formdata.h" #include "vtls/vtls.h" -#include "strequal.h" +#include "strcase.h" #include "sendf.h" #include "strdup.h" /* The last 3 #include files should be in this order */ @@ -201,9 +201,9 @@ static const char *ContentTypeForFilename(const char *filename, if(filename) { /* in case a NULL was passed in */ for(i=0; i<sizeof(ctts)/sizeof(ctts[0]); i++) { if(strlen(filename) >= strlen(ctts[i].extension)) { - if(strequal(filename + - strlen(filename) - strlen(ctts[i].extension), - ctts[i].extension)) { + if(strcasecompare(filename + + strlen(filename) - strlen(ctts[i].extension), + ctts[i].extension)) { contenttype = ctts[i].type; break; } @@ -845,16 +845,23 @@ static CURLcode AddFormData(struct FormData **formp, goto error; } #endif + if(type != FORM_DATAMEM) { + newform->line = malloc((size_t)length+1); + if(!newform->line) { + result = CURLE_OUT_OF_MEMORY; + goto error; + } + alloc2 = newform->line; + memcpy(newform->line, line, (size_t)length); - newform->line = malloc((size_t)length+1); - if(!newform->line) { - result = CURLE_OUT_OF_MEMORY; - goto error; + /* zero terminate for easier debugging */ + newform->line[(size_t)length]=0; + } + else { + newform->line = (char *)line; + type = FORM_DATA; /* in all other aspects this is just FORM_DATA */ } - alloc2 = newform->line; - memcpy(newform->line, line, (size_t)length); newform->length = (size_t)length; - newform->line[(size_t)length]=0; /* zero terminate for easier debugging */ } else /* For callbacks and files we don't have any actual data so we just keep a @@ -863,13 +870,6 @@ static CURLcode AddFormData(struct FormData **formp, newform->type = type; - if(*formp) { - (*formp)->next = newform; - *formp = newform; - } - else - *formp = newform; - if(size) { if(type != FORM_FILE) /* for static content as well as callback data we add the size given @@ -878,7 +878,7 @@ static CURLcode AddFormData(struct FormData **formp, else { /* Since this is a file to be uploaded here, add the size of the actual file */ - if(!strequal("-", newform->line)) { + if(strcmp("-", newform->line)) { struct_stat file; if(!stat(newform->line, &file) && !S_ISDIR(file.st_mode)) *size += filesize(newform->line, file); @@ -889,6 +889,14 @@ static CURLcode AddFormData(struct FormData **formp, } } } + + if(*formp) { + (*formp)->next = newform; + *formp = newform; + } + else + *formp = newform; + return CURLE_OK; error: if(newform) @@ -906,13 +914,21 @@ static CURLcode AddFormDataf(struct FormData **formp, curl_off_t *size, const char *fmt, ...) { - char s[4096]; + char *s; + CURLcode result; va_list ap; va_start(ap, fmt); - vsnprintf(s, sizeof(s), fmt, ap); + s = curl_mvaprintf(fmt, ap); va_end(ap); - return AddFormData(formp, FORM_DATA, s, 0, size); + if(!s) + return CURLE_OUT_OF_MEMORY; + + result = AddFormData(formp, FORM_DATAMEM, s, 0, size); + if(result) + free(s); + + return result; } /* @@ -1289,7 +1305,7 @@ CURLcode Curl_getformdata(struct Curl_easy *data, /* we should include the contents from the specified file */ FILE *fileread; - fileread = strequal("-", file->contents)? + fileread = !strcmp("-", file->contents)? stdin:fopen(file->contents, "rb"); /* binary read for win32 */ /* diff --git a/Utilities/cmcurl/lib/formdata.h b/Utilities/cmcurl/lib/formdata.h index 6eb7c6c..200470b 100644 --- a/Utilities/cmcurl/lib/formdata.h +++ b/Utilities/cmcurl/lib/formdata.h @@ -23,6 +23,7 @@ ***************************************************************************/ enum formtype { + FORM_DATAMEM, /* already allocated FORM_DATA memory */ FORM_DATA, /* form metadata (convert to network encoding if necessary) */ FORM_CONTENT, /* form content (never convert) */ FORM_CALLBACK, /* 'line' points to the custom pointer we pass to the callback diff --git a/Utilities/cmcurl/lib/ftp.c b/Utilities/cmcurl/lib/ftp.c index b0165bc..9d0a03c 100644 --- a/Utilities/cmcurl/lib/ftp.c +++ b/Utilities/cmcurl/lib/ftp.c @@ -61,7 +61,7 @@ #include "ftplistparser.h" #include "curl_sec.h" #include "strtoofft.h" -#include "strequal.h" +#include "strcase.h" #include "vtls/vtls.h" #include "connect.h" #include "strerror.h" @@ -72,7 +72,7 @@ #include "sockaddr.h" /* required for Curl_sockaddr_storage */ #include "multiif.h" #include "url.h" -#include "rawstr.h" +#include "strcase.h" #include "speedcheck.h" #include "warnless.h" #include "http_proxy.h" @@ -475,7 +475,7 @@ static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received) if(ftpcode/100 > 3) return CURLE_FTP_ACCEPT_FAILED; - return CURLE_FTP_WEIRD_SERVER_REPLY; + return CURLE_WEIRD_SERVER_REPLY; } break; @@ -741,7 +741,7 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */ */ } else { - switch (Curl_socket_ready(sockfd, CURL_SOCKET_BAD, interval_ms)) { + switch (SOCKET_READABLE(sockfd, interval_ms)) { case -1: /* select() error, stop reading */ failf(data, "FTP response aborted due to select/poll error: %d", SOCKERRNO); @@ -911,7 +911,7 @@ static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks, } else { socks[1] = conn->sock[SECONDARYSOCKET]; - bits |= GETSOCK_WRITESOCK(1); + bits |= GETSOCK_WRITESOCK(1) | GETSOCK_READSOCK(1); } return bits; @@ -1835,7 +1835,7 @@ static CURLcode ftp_epsv_disable(struct connectdata *conn) if(conn->bits.ipv6) { /* We can't disable EPSV when doing IPv6, so this is instead a fail */ failf(conn->data, "Failed EPSV attempt, exiting\n"); - return CURLE_FTP_WEIRD_SERVER_REPLY; + return CURLE_WEIRD_SERVER_REPLY; } infof(conn->data, "Failed EPSV attempt. Disabling EPSV\n"); @@ -2742,7 +2742,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) else if(ftpcode != 220) { failf(data, "Got a %03d ftp-server response when 220 was expected", ftpcode); - return CURLE_FTP_WEIRD_SERVER_REPLY; + return CURLE_WEIRD_SERVER_REPLY; } /* We have received a 220 response fine, now we proceed. */ @@ -2999,7 +2999,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) /* Check for special servers here. */ - if(strequal(os, "OS/400")) { + if(strcasecompare(os, "OS/400")) { /* Force OS400 name format 1. */ result = Curl_pp_sendf(&ftpc->pp, "%s", "SITE NAMEFMT 1"); if(result) { @@ -3165,7 +3165,7 @@ static CURLcode ftp_multi_statemach(struct connectdata *conn, struct ftp_conn *ftpc = &conn->proto.ftpc; CURLcode result = Curl_pp_statemach(&ftpc->pp, FALSE); - /* Check for the state outside of the Curl_socket_ready() return code checks + /* Check for the state outside of the Curl_socket_check() return code checks since at times we are in fact already in this state when this function gets called. */ *done = (ftpc->state == FTP_STOP) ? TRUE : FALSE; @@ -3250,7 +3250,6 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status, ssize_t nread; int ftpcode; CURLcode result = CURLE_OK; - bool was_ctl_valid = ftpc->ctl_valid; char *path; const char *path_to_use = data->state.path; @@ -3274,10 +3273,9 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status, /* the connection stays alive fine even though this happened */ /* fall-through */ case CURLE_OK: /* doesn't affect the control connection's status */ - if(!premature) { - ftpc->ctl_valid = was_ctl_valid; + if(!premature) break; - } + /* until we cope better with prematurely ended requests, let them * fallback as if in complete failure */ default: /* by default, an error means the control connection is @@ -3300,13 +3298,12 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status, ftpc->known_filesize = -1; } - /* get the "raw" path */ - path = curl_easy_unescape(data, path_to_use, 0, NULL); - if(!path) { - /* out of memory, but we can limp along anyway (and should try to - * since we may already be in the out of memory cleanup path) */ - if(!result) - result = CURLE_OUT_OF_MEMORY; + if(!result) + /* get the "raw" path */ + result = Curl_urldecode(data, path_to_use, 0, &path, NULL, FALSE); + if(result) { + /* We can limp along anyway (and should try to since we may already be in + * the error path) */ ftpc->ctl_valid = FALSE; /* mark control connection as bad */ connclose(conn, "FTP: out of memory!"); /* mark for connection closure */ ftpc->prevpath = NULL; /* no path remembering */ @@ -4094,8 +4091,7 @@ static CURLcode ftp_do(struct connectdata *conn, bool *done) } -CURLcode Curl_ftpsendf(struct connectdata *conn, - const char *fmt, ...) +CURLcode Curl_ftpsend(struct connectdata *conn, const char *cmd) { ssize_t bytes_written; #define SBUF_SIZE 1024 @@ -4107,10 +4103,9 @@ CURLcode Curl_ftpsendf(struct connectdata *conn, enum protection_level data_sec = conn->data_prot; #endif - va_list ap; - va_start(ap, fmt); - write_len = vsnprintf(s, SBUF_SIZE-3, fmt, ap); - va_end(ap); + write_len = strlen(cmd); + if(write_len > (sizeof(s) -3)) + return CURLE_BAD_FUNCTION_ARGUMENT; strcpy(&s[write_len], "\r\n"); /* append a trailing CRLF */ write_len +=2; @@ -4292,6 +4287,7 @@ CURLcode ftp_parse_url_path(struct connectdata *conn) slash_pos=strrchr(cur_pos, '/'); if(slash_pos || !*cur_pos) { size_t dirlen = slash_pos-cur_pos; + CURLcode result; ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0])); if(!ftpc->dirs) @@ -4300,12 +4296,13 @@ CURLcode ftp_parse_url_path(struct connectdata *conn) if(!dirlen) dirlen++; - ftpc->dirs[0] = curl_easy_unescape(conn->data, slash_pos ? cur_pos : "/", - slash_pos ? curlx_uztosi(dirlen) : 1, - NULL); - if(!ftpc->dirs[0]) { + result = Curl_urldecode(conn->data, slash_pos ? cur_pos : "/", + slash_pos ? dirlen : 1, + &ftpc->dirs[0], NULL, + FALSE); + if(result) { freedirs(ftpc); - return CURLE_OUT_OF_MEMORY; + return result; } ftpc->dirdepth = 1; /* we consider it to be a single dir */ filename = slash_pos ? slash_pos+1 : cur_pos; /* rest is file name */ @@ -4323,7 +4320,7 @@ CURLcode ftp_parse_url_path(struct connectdata *conn) return CURLE_OUT_OF_MEMORY; /* we have a special case for listing the root dir only */ - if(strequal(path_to_use, "/")) { + if(!strcmp(path_to_use, "/")) { cur_pos++; /* make it point to the zero byte */ ftpc->dirs[0] = strdup("/"); ftpc->dirdepth++; @@ -4340,18 +4337,15 @@ CURLcode ftp_parse_url_path(struct connectdata *conn) /* we skip empty path components, like "x//y" since the FTP command CWD requires a parameter and a non-existent parameter a) doesn't work on many servers and b) has no effect on the others. */ - int len = curlx_sztosi(slash_pos - cur_pos + absolute_dir); - ftpc->dirs[ftpc->dirdepth] = - curl_easy_unescape(conn->data, cur_pos - absolute_dir, len, NULL); - if(!ftpc->dirs[ftpc->dirdepth]) { /* run out of memory ... */ - failf(data, "no memory"); - freedirs(ftpc); - return CURLE_OUT_OF_MEMORY; - } - if(isBadFtpString(ftpc->dirs[ftpc->dirdepth])) { + size_t len = slash_pos - cur_pos + absolute_dir; + CURLcode result = + Curl_urldecode(conn->data, cur_pos - absolute_dir, len, + &ftpc->dirs[ftpc->dirdepth], NULL, + TRUE); + if(result) { free(ftpc->dirs[ftpc->dirdepth]); freedirs(ftpc); - return CURLE_URL_MALFORMAT; + return result; } } else { @@ -4387,15 +4381,12 @@ CURLcode ftp_parse_url_path(struct connectdata *conn) } /* switch */ if(filename && *filename) { - ftpc->file = curl_easy_unescape(conn->data, filename, 0, NULL); - if(NULL == ftpc->file) { - freedirs(ftpc); - failf(data, "no memory"); - return CURLE_OUT_OF_MEMORY; - } - if(isBadFtpString(ftpc->file)) { + CURLcode result = + Curl_urldecode(conn->data, filename, 0, &ftpc->file, NULL, TRUE); + + if(result) { freedirs(ftpc); - return CURLE_URL_MALFORMAT; + return result; } } else @@ -4413,16 +4404,18 @@ CURLcode ftp_parse_url_path(struct connectdata *conn) if(ftpc->prevpath) { /* prevpath is "raw" so we convert the input path before we compare the strings */ - int dlen; - char *path = curl_easy_unescape(conn->data, data->state.path, 0, &dlen); - if(!path) { + size_t dlen; + char *path; + CURLcode result = + Curl_urldecode(conn->data, data->state.path, 0, &path, &dlen, FALSE); + if(result) { freedirs(ftpc); - return CURLE_OUT_OF_MEMORY; + return result; } - dlen -= ftpc->file?curlx_uztosi(strlen(ftpc->file)):0; - if((dlen == curlx_uztosi(strlen(ftpc->prevpath))) && - strnequal(path, ftpc->prevpath, dlen)) { + dlen -= ftpc->file?strlen(ftpc->file):0; + if((dlen == strlen(ftpc->prevpath)) && + !strncmp(path, ftpc->prevpath, dlen)) { infof(data, "Request has same path as previous transfer\n"); ftpc->cwddone = TRUE; } diff --git a/Utilities/cmcurl/lib/ftp.h b/Utilities/cmcurl/lib/ftp.h index 2ed5b43..dbd8567 100644 --- a/Utilities/cmcurl/lib/ftp.h +++ b/Utilities/cmcurl/lib/ftp.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2016, 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 @@ -31,7 +31,7 @@ extern const struct Curl_handler Curl_handler_ftp; extern const struct Curl_handler Curl_handler_ftps; #endif -CURLcode Curl_ftpsendf(struct connectdata *, const char *fmt, ...); +CURLcode Curl_ftpsend(struct connectdata *, const char *cmd); CURLcode Curl_GetFTPResponse(ssize_t *nread, struct connectdata *conn, int *ftpcode); #endif /* CURL_DISABLE_FTP */ diff --git a/Utilities/cmcurl/lib/ftplistparser.c b/Utilities/cmcurl/lib/ftplistparser.c index abbf76e..747dbba 100644 --- a/Utilities/cmcurl/lib/ftplistparser.c +++ b/Utilities/cmcurl/lib/ftplistparser.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2016, 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 @@ -45,7 +45,6 @@ #include "fileinfo.h" #include "llist.h" #include "strtoofft.h" -#include "rawstr.h" #include "ftp.h" #include "ftplistparser.h" #include "curl_fnmatch.h" diff --git a/Utilities/cmcurl/lib/getenv.c b/Utilities/cmcurl/lib/getenv.c index 50bb79f..89d181d 100644 --- a/Utilities/cmcurl/lib/getenv.c +++ b/Utilities/cmcurl/lib/getenv.c @@ -30,7 +30,8 @@ static char *GetEnv(const char *variable) { -#ifdef _WIN32_WCE +#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP) + (void)variable; return NULL; #else #ifdef WIN32 diff --git a/Utilities/cmcurl/lib/getinfo.c b/Utilities/cmcurl/lib/getinfo.c index 262cd93..9641d79 100644 --- a/Utilities/cmcurl/lib/getinfo.c +++ b/Utilities/cmcurl/lib/getinfo.c @@ -36,8 +36,8 @@ #include "memdebug.h" /* - * This is supposed to be called in the beginning of a perform() session - * and should reset all session-info variables + * This is supposed to be called in the beginning of a perform() session and + * in curl_easy_reset() and should reset all session-info variables. */ CURLcode Curl_initinfo(struct Curl_easy *data) { @@ -58,18 +58,27 @@ CURLcode Curl_initinfo(struct Curl_easy *data) info->filetime = -1; /* -1 is an illegal time and thus means unknown */ info->timecond = FALSE; - free(info->contenttype); - info->contenttype = NULL; - info->header_size = 0; info->request_size = 0; + info->proxyauthavail = 0; + info->httpauthavail = 0; info->numconnects = 0; + free(info->contenttype); + info->contenttype = NULL; + + free(info->wouldredirect); + info->wouldredirect = NULL; + info->conn_primary_ip[0] = '\0'; info->conn_local_ip[0] = '\0'; info->conn_primary_port = 0; info->conn_local_port = 0; +#ifdef USE_SSL + Curl_ssl_free_certinfo(data); +#endif + return CURLE_OK; } diff --git a/Utilities/cmcurl/lib/gopher.c b/Utilities/cmcurl/lib/gopher.c index f1efb60..a073d0b 100644 --- a/Utilities/cmcurl/lib/gopher.c +++ b/Utilities/cmcurl/lib/gopher.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2016, 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 @@ -28,13 +28,11 @@ #include <curl/curl.h> #include "transfer.h" #include "sendf.h" - #include "progress.h" -#include "strequal.h" #include "gopher.h" -#include "rawstr.h" #include "select.h" #include "url.h" +#include "escape.h" #include "warnless.h" #include "curl_memory.h" /* The last #include file should be: */ @@ -83,7 +81,7 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done) char *sel; char *sel_org = NULL; ssize_t amount, k; - int len; + size_t len; *done = TRUE; /* unconditionally */ @@ -107,7 +105,7 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done) newp[i] = '\x09'; /* ... and finally unescape */ - sel = curl_easy_unescape(data, newp, 0, &len); + result = Curl_urldecode(data, newp, 0, &sel, &len, FALSE); if(!sel) return CURLE_OUT_OF_MEMORY; sel_org = sel; @@ -121,20 +119,17 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done) result = Curl_write(conn, sockfd, sel, k, &amount); if(!result) { /* Which may not have written it all! */ result = Curl_client_write(conn, CLIENTWRITE_HEADER, sel, amount); - if(result) { - free(sel_org); - return result; - } + if(result) + break; + k -= amount; sel += amount; if(k < 1) break; /* but it did write it all */ } - else { - failf(data, "Failed sending Gopher request"); - free(sel_org); - return result; - } + else + break; + /* Don't busyloop. The entire loop thing is a work-around as it causes a BLOCKING behavior which is a NO-NO. This function should rather be split up in a do and a doing piece where the pieces that aren't @@ -144,14 +139,18 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done) Wait a while for the socket to be writable. Note that this doesn't acknowledge the timeout. */ - Curl_socket_ready(CURL_SOCKET_BAD, sockfd, 100); + if(SOCKET_WRITABLE(sockfd, 100) < 0) { + result = CURLE_SEND_ERROR; + break; + } } free(sel_org); - /* We can use Curl_sendf to send the terminal \r\n relatively safely and - save allocing another string/doing another _write loop. */ - result = Curl_sendf(sockfd, conn, "\r\n"); + if(!result) + /* We can use Curl_sendf to send the terminal \r\n relatively safely and + save allocing another string/doing another _write loop. */ + result = Curl_sendf(sockfd, conn, "\r\n"); if(result) { failf(data, "Failed sending Gopher request"); return result; diff --git a/Utilities/cmcurl/lib/hostcheck.c b/Utilities/cmcurl/lib/hostcheck.c index 4db9e6b..f545254 100644 --- a/Utilities/cmcurl/lib/hostcheck.c +++ b/Utilities/cmcurl/lib/hostcheck.c @@ -30,7 +30,7 @@ #endif #include "hostcheck.h" -#include "rawstr.h" +#include "strcase.h" #include "inet_pton.h" #include "curl_memory.h" @@ -77,7 +77,7 @@ static int hostmatch(char *hostname, char *pattern) pattern_wildcard = strchr(pattern, '*'); if(pattern_wildcard == NULL) - return Curl_raw_equal(pattern, hostname) ? + return strcasecompare(pattern, hostname) ? CURL_HOST_MATCH : CURL_HOST_NOMATCH; /* detect IP address as hostname and fail the match if so */ @@ -94,16 +94,16 @@ static int hostmatch(char *hostname, char *pattern) pattern_label_end = strchr(pattern, '.'); if(pattern_label_end == NULL || strchr(pattern_label_end+1, '.') == NULL || pattern_wildcard > pattern_label_end || - Curl_raw_nequal(pattern, "xn--", 4)) { + strncasecompare(pattern, "xn--", 4)) { wildcard_enabled = 0; } if(!wildcard_enabled) - return Curl_raw_equal(pattern, hostname) ? + return strcasecompare(pattern, hostname) ? CURL_HOST_MATCH : CURL_HOST_NOMATCH; hostname_label_end = strchr(hostname, '.'); if(hostname_label_end == NULL || - !Curl_raw_equal(pattern_label_end, hostname_label_end)) + !strcasecompare(pattern_label_end, hostname_label_end)) return CURL_HOST_NOMATCH; /* The wildcard must match at least one character, so the left-most @@ -114,8 +114,8 @@ static int hostmatch(char *hostname, char *pattern) prefixlen = pattern_wildcard - pattern; suffixlen = pattern_label_end - (pattern_wildcard+1); - return Curl_raw_nequal(pattern, hostname, prefixlen) && - Curl_raw_nequal(pattern_wildcard+1, hostname_label_end - suffixlen, + return strncasecompare(pattern, hostname, prefixlen) && + strncasecompare(pattern_wildcard+1, hostname_label_end - suffixlen, suffixlen) ? CURL_HOST_MATCH : CURL_HOST_NOMATCH; } diff --git a/Utilities/cmcurl/lib/hostip.c b/Utilities/cmcurl/lib/hostip.c index f2d9841..24a922e 100644 --- a/Utilities/cmcurl/lib/hostip.c +++ b/Utilities/cmcurl/lib/hostip.c @@ -603,11 +603,14 @@ int Curl_resolv_timeout(struct connectdata *conn, /* USE_ALARM_TIMEOUT defined, but no timeout actually requested */ return Curl_resolv(conn, hostname, port, entry); - if(timeout < 1000) + if(timeout < 1000) { /* The alarm() function only provides integer second resolution, so if we want to wait less than one second we must bail out already now. */ + failf(data, + "remaining timeout of %ld too small to resolve via SIGALRM method", + timeout); return CURLRESOLV_TIMEDOUT; - + } /* This allows us to time-out from the name resolver, as the timeout will generate a signal and we will siglongjmp() from that here. This technique has problems (see alarmfunc). diff --git a/Utilities/cmcurl/lib/http.c b/Utilities/cmcurl/lib/http.c index 378d8f7..e7788e7 100644 --- a/Utilities/cmcurl/lib/http.c +++ b/Utilities/cmcurl/lib/http.c @@ -53,7 +53,6 @@ #include "progress.h" #include "curl_base64.h" #include "cookie.h" -#include "strequal.h" #include "vauth/vauth.h" #include "vtls/vtls.h" #include "http_digest.h" @@ -68,7 +67,7 @@ #include "parsedate.h" /* for the week day and month names */ #include "strtoofft.h" #include "multiif.h" -#include "rawstr.h" +#include "strcase.h" #include "content_encoding.h" #include "http_proxy.h" #include "warnless.h" @@ -182,7 +181,7 @@ char *Curl_checkheaders(const struct connectdata *conn, struct Curl_easy *data = conn->data; for(head = data->set.headers;head; head=head->next) { - if(Curl_raw_nequal(head->data, thisheader, thislen)) + if(strncasecompare(head->data, thisheader, thislen)) return head->data; } @@ -208,7 +207,7 @@ char *Curl_checkProxyheaders(const struct connectdata *conn, for(head = (conn->bits.proxy && data->set.sep_headers) ? data->set.proxyheaders : data->set.headers; head; head=head->next) { - if(Curl_raw_nequal(head->data, thisheader, thislen)) + if(strncasecompare(head->data, thisheader, thislen)) return head->data; } @@ -462,7 +461,7 @@ static CURLcode http_perhapsrewind(struct connectdata *conn) #endif /* This is not NTLM or many bytes left to send: close */ - connclose(conn, "Mid-auth HTTP and much data left to send"); + streamclose(conn, "Mid-auth HTTP and much data left to send"); data->req.size = 0; /* don't download any more than 0 bytes */ /* There still is data left to send, but this connection is marked for @@ -726,7 +725,7 @@ Curl_http_output_auth(struct connectdata *conn, conn->bits.netrc || !data->state.first_host || data->set.http_disable_hostname_check_before_authentication || - Curl_raw_equal(data->state.first_host, conn->host.name)) { + strcasecompare(data->state.first_host, conn->host.name)) { result = output_auth_headers(conn, authhost, request, path, FALSE); } else @@ -784,23 +783,27 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy, while(*auth) { #ifdef USE_SPNEGO if(checkprefix("Negotiate", auth)) { - *availp |= CURLAUTH_NEGOTIATE; - authp->avail |= CURLAUTH_NEGOTIATE; - - if(authp->picked == CURLAUTH_NEGOTIATE) { - if(negdata->state == GSS_AUTHSENT || negdata->state == GSS_AUTHNONE) { - CURLcode result = Curl_input_negotiate(conn, proxy, auth); - if(!result) { - DEBUGASSERT(!data->req.newurl); - data->req.newurl = strdup(data->change.url); - if(!data->req.newurl) - return CURLE_OUT_OF_MEMORY; - data->state.authproblem = FALSE; - /* we received a GSS auth token and we dealt with it fine */ - negdata->state = GSS_AUTHRECV; + if((authp->avail & CURLAUTH_NEGOTIATE) || + Curl_auth_is_spnego_supported()) { + *availp |= CURLAUTH_NEGOTIATE; + authp->avail |= CURLAUTH_NEGOTIATE; + + if(authp->picked == CURLAUTH_NEGOTIATE) { + if(negdata->state == GSS_AUTHSENT || + negdata->state == GSS_AUTHNONE) { + CURLcode result = Curl_input_negotiate(conn, proxy, auth); + if(!result) { + DEBUGASSERT(!data->req.newurl); + data->req.newurl = strdup(data->change.url); + if(!data->req.newurl) + return CURLE_OUT_OF_MEMORY; + data->state.authproblem = FALSE; + /* we received a GSS auth token and we dealt with it fine */ + negdata->state = GSS_AUTHRECV; + } + else + data->state.authproblem = TRUE; } - else - data->state.authproblem = TRUE; } } } @@ -809,39 +812,44 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy, #ifdef USE_NTLM /* NTLM support requires the SSL crypto libs */ if(checkprefix("NTLM", auth)) { - *availp |= CURLAUTH_NTLM; - authp->avail |= CURLAUTH_NTLM; - if(authp->picked == CURLAUTH_NTLM || - authp->picked == CURLAUTH_NTLM_WB) { - /* NTLM authentication is picked and activated */ - CURLcode result = Curl_input_ntlm(conn, proxy, auth); - if(!result) { - data->state.authproblem = FALSE; + if((authp->avail & CURLAUTH_NTLM) || + (authp->avail & CURLAUTH_NTLM_WB) || + Curl_auth_is_ntlm_supported()) { + *availp |= CURLAUTH_NTLM; + authp->avail |= CURLAUTH_NTLM; + + if(authp->picked == CURLAUTH_NTLM || + authp->picked == CURLAUTH_NTLM_WB) { + /* NTLM authentication is picked and activated */ + CURLcode result = Curl_input_ntlm(conn, proxy, auth); + if(!result) { + data->state.authproblem = FALSE; #ifdef NTLM_WB_ENABLED - if(authp->picked == CURLAUTH_NTLM_WB) { - *availp &= ~CURLAUTH_NTLM; - authp->avail &= ~CURLAUTH_NTLM; - *availp |= CURLAUTH_NTLM_WB; - authp->avail |= CURLAUTH_NTLM_WB; - - /* Get the challenge-message which will be passed to - * ntlm_auth for generating the type 3 message later */ - while(*auth && ISSPACE(*auth)) - auth++; - if(checkprefix("NTLM", auth)) { - auth += strlen("NTLM"); + if(authp->picked == CURLAUTH_NTLM_WB) { + *availp &= ~CURLAUTH_NTLM; + authp->avail &= ~CURLAUTH_NTLM; + *availp |= CURLAUTH_NTLM_WB; + authp->avail |= CURLAUTH_NTLM_WB; + + /* Get the challenge-message which will be passed to + * ntlm_auth for generating the type 3 message later */ while(*auth && ISSPACE(*auth)) auth++; - if(*auth) - if((conn->challenge_header = strdup(auth)) == NULL) - return CURLE_OUT_OF_MEMORY; + if(checkprefix("NTLM", auth)) { + auth += strlen("NTLM"); + while(*auth && ISSPACE(*auth)) + auth++; + if(*auth) + if((conn->challenge_header = strdup(auth)) == NULL) + return CURLE_OUT_OF_MEMORY; + } } - } #endif - } - else { - infof(data, "Authentication problem. Ignoring this.\n"); - data->state.authproblem = TRUE; + } + else { + infof(data, "Authentication problem. Ignoring this.\n"); + data->state.authproblem = TRUE; + } } } } @@ -849,18 +857,18 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy, #endif #ifndef CURL_DISABLE_CRYPTO_AUTH if(checkprefix("Digest", auth)) { - if((authp->avail & CURLAUTH_DIGEST) != 0) { + if((authp->avail & CURLAUTH_DIGEST) != 0) infof(data, "Ignoring duplicate digest auth header.\n"); - } - else { + else if(Curl_auth_is_digest_supported()) { CURLcode result; + *availp |= CURLAUTH_DIGEST; authp->avail |= CURLAUTH_DIGEST; /* We call this function on input Digest headers even if Digest * authentication isn't activated yet, as we need to store the - * incoming data from this header in case we are gonna use - * Digest. */ + * incoming data from this header in case we are going to use + * Digest */ result = Curl_input_digest(conn, proxy, auth); if(result) { infof(data, "Authentication problem. Ignoring this.\n"); @@ -1296,7 +1304,7 @@ Curl_compareheader(const char *headerline, /* line to check */ const char *start; const char *end; - if(!Curl_raw_nequal(headerline, header, hlen)) + if(!strncasecompare(headerline, header, hlen)) return FALSE; /* doesn't start with header */ /* pass the header */ @@ -1322,7 +1330,7 @@ Curl_compareheader(const char *headerline, /* line to check */ /* find the content string in the rest of the line */ for(;len>=clen;len--, start++) { - if(Curl_raw_nequal(start, content, clen)) + if(strncasecompare(start, content, clen)) return TRUE; /* match! */ } @@ -1443,9 +1451,8 @@ CURLcode Curl_http_done(struct connectdata *conn, { struct Curl_easy *data = conn->data; struct HTTP *http = data->req.protop; -#ifdef USE_NGHTTP2 - struct http_conn *httpc = &conn->proto.httpc; -#endif + + infof(data, "Curl_http_done: called premature == %d\n", premature); Curl_unencode_cleanup(conn); @@ -1458,7 +1465,7 @@ CURLcode Curl_http_done(struct connectdata *conn, * Do not close CONNECT_ONLY connections. */ if((data->req.httpcode != 401) && (data->req.httpcode != 407) && !data->set.connect_only) - connclose(conn, "Negotiate transfer completed"); + streamclose(conn, "Negotiate transfer completed"); Curl_cleanup_negotiate(data); } #endif @@ -1475,27 +1482,7 @@ CURLcode Curl_http_done(struct connectdata *conn, http->send_buffer = NULL; /* clear the pointer */ } -#ifdef USE_NGHTTP2 - if(http->header_recvbuf) { - DEBUGF(infof(data, "free header_recvbuf!!\n")); - Curl_add_buffer_free(http->header_recvbuf); - http->header_recvbuf = NULL; /* clear the pointer */ - Curl_add_buffer_free(http->trailer_recvbuf); - http->trailer_recvbuf = NULL; /* clear the pointer */ - if(http->push_headers) { - /* if they weren't used and then freed before */ - for(; http->push_headers_used > 0; --http->push_headers_used) { - free(http->push_headers[http->push_headers_used - 1]); - } - free(http->push_headers); - http->push_headers = NULL; - } - } - if(http->stream_id) { - nghttp2_session_set_stream_user_data(httpc->h2, http->stream_id, 0); - http->stream_id = 0; - } -#endif + Curl_http2_done(conn, premature); if(HTTPREQ_POST_FORM == data->set.httpreq) { data->req.bytecount = http->readbytecount + http->writebytecount; @@ -1660,6 +1647,10 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, Connection: */ checkprefix("Connection", headers->data)) ; + else if((conn->httpversion == 20) && + checkprefix("Transfer-Encoding:", headers->data)) + /* HTTP/2 doesn't support chunked requests */ + ; else { CURLcode result = Curl_add_bufferf(req_buffer, "%s\r\n", headers->data); @@ -1946,47 +1937,42 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } #endif - if(conn->httpversion == 20) - /* In HTTP2 forbids Transfer-Encoding: chunked */ - ptr = NULL; + ptr = Curl_checkheaders(conn, "Transfer-Encoding:"); + if(ptr) { + /* Some kind of TE is requested, check if 'chunked' is chosen */ + data->req.upload_chunky = + Curl_compareheader(ptr, "Transfer-Encoding:", "chunked"); + } else { - ptr = Curl_checkheaders(conn, "Transfer-Encoding:"); - if(ptr) { - /* Some kind of TE is requested, check if 'chunked' is chosen */ - data->req.upload_chunky = - Curl_compareheader(ptr, "Transfer-Encoding:", "chunked"); - } - else { - if((conn->handler->protocol&PROTO_FAMILY_HTTP) && - data->set.upload && - (data->state.infilesize == -1)) { - if(conn->bits.authneg) - /* don't enable chunked during auth neg */ - ; - else if(use_http_1_1plus(data, conn)) { - /* HTTP, upload, unknown file size and not HTTP 1.0 */ - data->req.upload_chunky = TRUE; - } - else { - failf(data, "Chunky upload is not supported by HTTP 1.0"); - return CURLE_UPLOAD_FAILED; - } + if((conn->handler->protocol&PROTO_FAMILY_HTTP) && + data->set.upload && + (data->state.infilesize == -1)) { + if(conn->bits.authneg) + /* don't enable chunked during auth neg */ + ; + else if(use_http_1_1plus(data, conn)) { + /* HTTP, upload, unknown file size and not HTTP 1.0 */ + data->req.upload_chunky = TRUE; } else { - /* else, no chunky upload */ - data->req.upload_chunky = FALSE; + failf(data, "Chunky upload is not supported by HTTP 1.0"); + return CURLE_UPLOAD_FAILED; } - - if(data->req.upload_chunky) - te = "Transfer-Encoding: chunked\r\n"; } + else { + /* else, no chunky upload */ + data->req.upload_chunky = FALSE; + } + + if(data->req.upload_chunky) + te = "Transfer-Encoding: chunked\r\n"; } Curl_safefree(conn->allocptr.host); ptr = Curl_checkheaders(conn, "Host:"); if(ptr && (!data->state.this_is_a_follow || - Curl_raw_equal(data->state.first_host, conn->host.name))) { + strcasecompare(data->state.first_host, conn->host.name))) { #if !defined(CURL_DISABLE_COOKIES) /* If we have a given custom Host: header, we extract the host name in order to possibly use it for cookie reasons later on. We only allow the @@ -2305,6 +2291,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) "%s" /* TE: */ "%s" /* accept-encoding */ "%s" /* referer */ + "%s" /* Proxy-Connection */ "%s",/* transfer-encoding */ ftp_typecode, @@ -2327,6 +2314,10 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) conn->allocptr.accept_encoding:"", (data->change.referer && conn->allocptr.ref)? conn->allocptr.ref:"" /* Referer: <data> */, + (conn->bits.httpproxy && + !conn->bits.tunnel_proxy && + !Curl_checkProxyheaders(conn, "Proxy-Connection:"))? + "Proxy-Connection: Keep-Alive\r\n":"", te ); @@ -2392,7 +2383,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } co = co->next; /* next cookie please */ } - Curl_cookie_freelist(store, FALSE); /* free the cookie list */ + Curl_cookie_freelist(store); } if(addcookies && !result) { if(!count) @@ -2768,6 +2759,11 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } } + if((conn->httpversion == 20) && data->req.upload_chunky) + /* upload_chunky was set above to set up the request in a chunky fashion, + but is disabled here again to avoid that the chunked encoded version is + actually used when sending the request body over h2 */ + data->req.upload_chunky = FALSE; return result; } @@ -3040,19 +3036,19 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, #endif /* CURL_DOES_CONVERSIONS */ if(100 <= k->httpcode && 199 >= k->httpcode) { - /* - * We have made a HTTP PUT or POST and this is 1.1-lingo - * that tells us that the server is OK with this and ready - * to receive the data. - * However, we'll get more headers now so we must get - * back into the header-parsing state! - */ - k->header = TRUE; - k->headerline = 0; /* restart the header line counter */ - /* "A user agent MAY ignore unexpected 1xx status responses." */ switch(k->httpcode) { case 100: + /* + * We have made a HTTP PUT or POST and this is 1.1-lingo + * that tells us that the server is OK with this and ready + * to receive the data. + * However, we'll get more headers now so we must get + * back into the header-parsing state! + */ + k->header = TRUE; + k->headerline = 0; /* restart the header line counter */ + /* if we did wait for this do enable write now! */ if(k->exp100 > EXP100_SEND_DATA) { k->exp100 = EXP100_SEND_DATA; @@ -3062,9 +3058,14 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, case 101: /* Switching Protocols */ if(k->upgr101 == UPGR101_REQUESTED) { + /* Switching to HTTP/2 */ infof(data, "Received 101\n"); k->upgr101 = UPGR101_RECEIVED; + /* we'll get more headers (HTTP/2 response) */ + k->header = TRUE; + k->headerline = 0; /* restart the header line counter */ + /* switch to http2 now. The bytes after response headers are also processed here, otherwise they are lost. */ result = Curl_http2_switched(conn, k->str, *nread); @@ -3072,8 +3073,16 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, return result; *nread = 0; } + else { + /* Switching to another protocol (e.g. WebSocket) */ + k->header = FALSE; /* no more header to parse! */ + } break; default: + /* the status code 1xx indicates a provisional response, so + we'll get another set of headers */ + k->header = TRUE; + k->headerline = 0; /* restart the header line counter */ break; } } @@ -3091,7 +3100,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, signal the end of the document. */ infof(data, "no chunk, no close, no size. Assume close to " "signal end\n"); - connclose(conn, "HTTP: No end-of-message indicator"); + streamclose(conn, "HTTP: No end-of-message indicator"); } } @@ -3171,12 +3180,21 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, * connection for closure after we've read the entire response. */ if(!k->upload_done) { - infof(data, "HTTP error before end of send, stop sending\n"); - connclose(conn, "Stop sending data before everything sent"); - k->upload_done = TRUE; - k->keepon &= ~KEEP_SEND; /* don't send */ - if(data->state.expect100header) - k->exp100 = EXP100_FAILED; + if(data->set.http_keep_sending_on_error) { + infof(data, "HTTP error before end of send, keep sending\n"); + if(k->exp100 > EXP100_SEND_DATA) { + k->exp100 = EXP100_SEND_DATA; + k->keepon |= KEEP_SEND; + } + } + else { + infof(data, "HTTP error before end of send, stop sending\n"); + streamclose(conn, "Stop sending data before everything sent"); + k->upload_done = TRUE; + k->keepon &= ~KEEP_SEND; /* don't send */ + if(data->state.expect100header) + k->exp100 = EXP100_FAILED; + } } break; @@ -3476,7 +3494,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, /* Negative Content-Length is really odd, and we know it happens for example when older Apache servers send large files */ - connclose(conn, "negative content-length"); + streamclose(conn, "negative content-length"); infof(data, "Negative content-length: %" CURL_FORMAT_CURL_OFF_T ", closing after transfer\n", contentlength); } @@ -3549,7 +3567,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, * the connection will close when this request has been * served. */ - connclose(conn, "Connection: close used"); + streamclose(conn, "Connection: close used"); } else if(checkprefix("Transfer-Encoding:", k->p)) { /* One or more encodings. We check for chunked and/or a compression diff --git a/Utilities/cmcurl/lib/http.h b/Utilities/cmcurl/lib/http.h index 6529005..9fb669c 100644 --- a/Utilities/cmcurl/lib/http.h +++ b/Utilities/cmcurl/lib/http.h @@ -168,6 +168,7 @@ struct HTTP { const uint8_t *pausedata; /* pointer to data received in on_data_chunk */ size_t pauselen; /* the number of bytes left in data */ bool closed; /* TRUE on HTTP2 stream close */ + bool close_handled; /* TRUE if stream closure is handled by libcurl */ uint32_t error_code; /* HTTP/2 error code */ char *mem; /* points to a buffer in memory to store received data */ diff --git a/Utilities/cmcurl/lib/http2.c b/Utilities/cmcurl/lib/http2.c index efc082d..cfdb327 100644 --- a/Utilities/cmcurl/lib/http2.c +++ b/Utilities/cmcurl/lib/http2.c @@ -29,7 +29,7 @@ #include "http.h" #include "sendf.h" #include "curl_base64.h" -#include "rawstr.h" +#include "strcase.h" #include "multiif.h" #include "conncache.h" #include "url.h" @@ -92,8 +92,9 @@ static int http2_perform_getsock(const struct connectdata *conn, because of renegotiation. */ sock[0] = conn->sock[FIRSTSOCKET]; - if(nghttp2_session_want_read(c->h2)) - bitmap |= GETSOCK_READSOCK(FIRSTSOCKET); + /* in a HTTP/2 connection we can basically always get a frame so we should + always be ready for one */ + bitmap |= GETSOCK_READSOCK(FIRSTSOCKET); if(nghttp2_session_want_write(c->h2)) bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET); @@ -150,6 +151,7 @@ void Curl_http2_setup_req(struct Curl_easy *data) http->pauselen = 0; http->error_code = NGHTTP2_NO_ERROR; http->closed = FALSE; + http->close_handled = FALSE; http->mem = data->state.buffer; http->len = BUFSIZE; http->memlen = 0; @@ -184,7 +186,7 @@ const struct Curl_handler Curl_handler_http2 = { ZERO_NULL, /* readwrite */ PORT_HTTP, /* defport */ CURLPROTO_HTTP, /* protocol */ - PROTOPT_NONE /* flags */ + PROTOPT_STREAM /* flags */ }; const struct Curl_handler Curl_handler_http2_ssl = { @@ -204,7 +206,7 @@ const struct Curl_handler Curl_handler_http2_ssl = { ZERO_NULL, /* readwrite */ PORT_HTTP, /* defport */ CURLPROTO_HTTPS, /* protocol */ - PROTOPT_SSL /* flags */ + PROTOPT_SSL | PROTOPT_STREAM /* flags */ }; /* @@ -317,7 +319,7 @@ char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header) the middle of header, it could be matched in middle of the value, this is because we do prefix match.*/ if(!h || !GOOD_EASY_HANDLE(h->data) || !header || !header[0] || - Curl_raw_equal(header, ":") || strchr(header + 1, ':')) + !strcmp(header, ":") || strchr(header + 1, ':')) return NULL; else { struct HTTP *stream = h->data->req.protop; @@ -488,8 +490,11 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, } stream = data_s->req.protop; - if(!stream) + if(!stream) { + DEBUGF(infof(conn->data, "No proto pointer for stream: %x\n", + stream_id)); return NGHTTP2_ERR_CALLBACK_FAILURE; + } DEBUGF(infof(data_s, "on_frame_recv() header %x stream %x\n", frame->hd.type, stream_id)); @@ -547,7 +552,7 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, /* if we receive data for another handle, wake that up */ if(conn_s->data != data_s) - Curl_expire(data_s, 1); + Curl_expire(data_s, 0); } break; case NGHTTP2_PUSH_PROMISE: @@ -621,8 +626,7 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags, /* if we receive data for another handle, wake that up */ if(conn->data != data_s) - Curl_expire(data_s, 1); /* TODO: fix so that this can be set to 0 for - immediately? */ + Curl_expire(data_s, 0); DEBUGF(infof(data_s, "%zu data received for stream %u " "(%zu left in buffer %p, total %zu)\n", @@ -883,7 +887,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, Curl_add_buffer(stream->header_recvbuf, " \r\n", 3); /* if we receive data for another handle, wake that up */ if(conn->data != data_s) - Curl_expire(data_s, 1); + Curl_expire(data_s, 0); DEBUGF(infof(data_s, "h2 status: HTTP/2 %03d (easy %p)\n", stream->status_code, data_s)); @@ -899,7 +903,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, Curl_add_buffer(stream->header_recvbuf, "\r\n", 2); /* if we receive data for another handle, wake that up */ if(conn->data != data_s) - Curl_expire(data_s, 1); + Curl_expire(data_s, 0); DEBUGF(infof(data_s, "h2 header: %.*s: %.*s\n", namelen, name, valuelen, value)); @@ -941,11 +945,12 @@ static ssize_t data_source_read_callback(nghttp2_session *session, memcpy(buf, stream->upload_mem, nread); stream->upload_mem += nread; stream->upload_len -= nread; - stream->upload_left -= nread; + if(data_s->state.infilesize != -1) + stream->upload_left -= nread; } if(stream->upload_left == 0) - *data_flags = 1; + *data_flags = NGHTTP2_DATA_FLAG_EOF; else if(nread == 0) return NGHTTP2_ERR_DEFERRED; @@ -979,6 +984,43 @@ static int error_callback(nghttp2_session *session, } #endif +void Curl_http2_done(struct connectdata *conn, bool premature) +{ + struct Curl_easy *data = conn->data; + struct HTTP *http = data->req.protop; + struct http_conn *httpc = &conn->proto.httpc; + + if(http->header_recvbuf) { + DEBUGF(infof(data, "free header_recvbuf!!\n")); + Curl_add_buffer_free(http->header_recvbuf); + http->header_recvbuf = NULL; /* clear the pointer */ + Curl_add_buffer_free(http->trailer_recvbuf); + http->trailer_recvbuf = NULL; /* clear the pointer */ + if(http->push_headers) { + /* if they weren't used and then freed before */ + for(; http->push_headers_used > 0; --http->push_headers_used) { + free(http->push_headers[http->push_headers_used - 1]); + } + free(http->push_headers); + http->push_headers = NULL; + } + } + + if(premature) { + /* RST_STREAM */ + nghttp2_submit_rst_stream(httpc->h2, NGHTTP2_FLAG_NONE, http->stream_id, + NGHTTP2_STREAM_CLOSED); + if(http->stream_id == httpc->pause_stream_id) { + infof(data, "stopped the pause stream!\n"); + httpc->pause_stream_id = 0; + } + } + if(http->stream_id) { + nghttp2_session_set_stream_user_data(httpc->h2, http->stream_id, 0); + http->stream_id = 0; + } +} + /* * Initialize nghttp2 for a Curl connection */ @@ -1091,9 +1133,10 @@ CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req, /* * Returns nonzero if current HTTP/2 session should be closed. */ -static int should_close_session(struct http_conn *httpc) { +static int should_close_session(struct http_conn *httpc) +{ return httpc->drain_total == 0 && !nghttp2_session_want_read(httpc->h2) && - !nghttp2_session_want_write(httpc->h2); + !nghttp2_session_want_write(httpc->h2); } static int h2_session_send(struct Curl_easy *data, @@ -1107,7 +1150,8 @@ static int h2_session_send(struct Curl_easy *data, */ static int h2_process_pending_input(struct Curl_easy *data, struct http_conn *httpc, - CURLcode *err) { + CURLcode *err) +{ ssize_t nread; char *inbuf; ssize_t rv; @@ -1155,9 +1199,41 @@ static int h2_process_pending_input(struct Curl_easy *data, return 0; } +/* + * Called from transfer.c:done_sending when we stop uploading. + */ +CURLcode Curl_http2_done_sending(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + + if((conn->handler == &Curl_handler_http2_ssl) || + (conn->handler == &Curl_handler_http2)) { + /* make sure this is only attempted for HTTP/2 transfers */ + + struct HTTP *stream = conn->data->req.protop; + + if(stream->upload_left) { + /* If the stream still thinks there's data left to upload. */ + struct http_conn *httpc = &conn->proto.httpc; + nghttp2_session *h2 = httpc->h2; + + stream->upload_left = 0; /* DONE! */ + + /* resume sending here to trigger the callback to get called again so + that it can signal EOF to nghttp2 */ + (void)nghttp2_session_resume_data(h2, stream->stream_id); + + (void)h2_process_pending_input(conn->data, httpc, &result); + } + } + return result; +} + + static ssize_t http2_handle_stream_close(struct connectdata *conn, struct Curl_easy *data, - struct HTTP *stream, CURLcode *err) { + struct HTTP *stream, CURLcode *err) +{ char *trailer_pos, *trailer_end; CURLcode result; struct http_conn *httpc = &conn->proto.httpc; @@ -1178,8 +1254,7 @@ static ssize_t http2_handle_stream_close(struct connectdata *conn, DEBUGASSERT(data->state.drain == 0); - /* Reset to FALSE to prevent infinite loop in readwrite_data - function. */ + /* Reset to FALSE to prevent infinite loop in readwrite_data function. */ stream->closed = FALSE; if(stream->error_code != NGHTTP2_NO_ERROR) { failf(data, "HTTP/2 stream %u was not closed cleanly: %s (err %d)", @@ -1216,6 +1291,8 @@ static ssize_t http2_handle_stream_close(struct connectdata *conn, } } + stream->close_handled = TRUE; + DEBUGF(infof(data, "http2_recv returns 0, http2_handle_stream_close\n")); return 0; } @@ -1268,10 +1345,6 @@ static int h2_session_send(struct Curl_easy *data, return nghttp2_session_send(h2); } -/* - * If the read would block (EWOULDBLOCK) we return -1. Otherwise we return - * a regular CURLcode value. - */ static ssize_t http2_recv(struct connectdata *conn, int sockindex, char *mem, size_t len, CURLcode *err) { @@ -1382,6 +1455,8 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex, socket is not read. But it seems that usually streams are notified with its drain property, and socket is read again quickly. */ + DEBUGF(infof(data, "stream %x is paused, pause id: %x\n", + stream->stream_id, httpc->pause_stream_id)); *err = CURLE_AGAIN; return -1; } @@ -1497,7 +1572,6 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex, #define HEADER_OVERFLOW(x) \ (x.namelen > (uint16_t)-1 || x.valuelen > (uint16_t)-1 - x.namelen) -/* return number of received (decrypted) bytes */ static ssize_t http2_send(struct connectdata *conn, int sockindex, const void *mem, size_t len, CURLcode *err) { @@ -1525,6 +1599,14 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, DEBUGF(infof(conn->data, "http2_send len=%zu\n", len)); if(stream->stream_id != -1) { + if(stream->close_handled) { + infof(conn->data, "stream %d closed\n", stream->stream_id); + *err = CURLE_HTTP2_STREAM; + return -1; + } + else if(stream->closed) { + return http2_handle_stream_close(conn, conn->data, stream, err); + } /* If stream_id != -1, we have dispatched request HEADERS, and now are going to send or sending request body in DATA frame */ stream->upload_mem = mem; @@ -1661,12 +1743,12 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, goto fail; hlen = end - hdbuf; - if(hlen == 10 && Curl_raw_nequal("connection", hdbuf, 10)) { + if(hlen == 10 && strncasecompare("connection", hdbuf, 10)) { /* skip Connection: headers! */ skip = 1; --nheader; } - else if(hlen == 4 && Curl_raw_nequal("host", hdbuf, 4)) { + else if(hlen == 4 && strncasecompare("host", hdbuf, 4)) { authority_idx = i; nva[i].name = (unsigned char *)":authority"; nva[i].namelen = strlen((char *)nva[i].name); @@ -1687,28 +1769,6 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, failf(conn->data, "Failed sending HTTP request: Header overflow"); goto fail; } - /* Inspect Content-Length header field and retrieve the request - entity length so that we can set END_STREAM to the last DATA - frame. */ - if(nva[i].namelen == 14 && - Curl_raw_nequal("content-length", (char*)nva[i].name, 14)) { - size_t j; - stream->upload_left = 0; - if(!nva[i].valuelen) - goto fail; - for(j = 0; j < nva[i].valuelen; ++j) { - if(nva[i].value[j] < '0' || nva[i].value[j] > '9') - goto fail; - if(stream->upload_left >= CURL_OFF_T_MAX / 10) - goto fail; - stream->upload_left *= 10; - stream->upload_left += nva[i].value[j] - '0'; - } - DEBUGF(infof(conn->data, - "request content-length=%" - CURL_FORMAT_CURL_OFF_T - "\n", stream->upload_left)); - } ++i; } } @@ -1736,6 +1796,10 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, if(nva[i].valuelen > max_acc - acc) break; acc += nva[i].valuelen; + + DEBUGF(infof(conn->data, "h2 header: %.*s:%.*s\n", + nva[i].namelen, nva[i].name, + nva[i].valuelen, nva[i].value)); } if(i != nheader) { @@ -1751,6 +1815,12 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, case HTTPREQ_POST: case HTTPREQ_POST_FORM: case HTTPREQ_PUT: + if(conn->data->state.infilesize != -1) + stream->upload_left = conn->data->state.infilesize; + else + /* data sending without specifying the data amount up front */ + stream->upload_left = -1; /* unknown, but not zero */ + data_prd.read_callback = data_source_read_callback; data_prd.source.ptr = NULL; stream_id = nghttp2_submit_request(h2, &pri_spec, nva, nheader, @@ -1850,10 +1920,6 @@ CURLcode Curl_http2_setup(struct connectdata *conn) infof(conn->data, "Connection state changed (HTTP/2 confirmed)\n"); Curl_multi_connchanged(conn->data->multi); - /* switch on TCP_NODELAY as we need to send off packets without delay for - maximum throughput */ - Curl_tcpnodelay(conn, conn->sock[FIRSTSOCKET]); - return CURLE_OK; } diff --git a/Utilities/cmcurl/lib/http2.h b/Utilities/cmcurl/lib/http2.h index bedbebf..8917535 100644 --- a/Utilities/cmcurl/lib/http2.h +++ b/Utilities/cmcurl/lib/http2.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2016, 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 @@ -51,6 +51,8 @@ CURLcode Curl_http2_switched(struct connectdata *conn, /* called from Curl_http_setup_conn */ void Curl_http2_setup_conn(struct connectdata *conn); void Curl_http2_setup_req(struct Curl_easy *data); +void Curl_http2_done(struct connectdata *conn, bool premature); +CURLcode Curl_http2_done_sending(struct connectdata *conn); #else /* USE_NGHTTP2 */ #define Curl_http2_init(x) CURLE_UNSUPPORTED_PROTOCOL #define Curl_http2_send_request(x) CURLE_UNSUPPORTED_PROTOCOL @@ -61,6 +63,8 @@ void Curl_http2_setup_req(struct Curl_easy *data); #define Curl_http2_setup_req(x) #define Curl_http2_init_state(x) #define Curl_http2_init_userset(x) +#define Curl_http2_done(x,y) +#define Curl_http2_done_sending(x) #endif #endif /* HEADER_CURL_HTTP2_H */ diff --git a/Utilities/cmcurl/lib/http_digest.c b/Utilities/cmcurl/lib/http_digest.c index 97230e7..184d00b 100644 --- a/Utilities/cmcurl/lib/http_digest.c +++ b/Utilities/cmcurl/lib/http_digest.c @@ -25,7 +25,7 @@ #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH) #include "urldata.h" -#include "rawstr.h" +#include "strcase.h" #include "vauth/vauth.h" #include "http_digest.h" /* The last 3 #include files should be in this order */ diff --git a/Utilities/cmcurl/lib/http_negotiate.c b/Utilities/cmcurl/lib/http_negotiate.c index c39d6f3..eb17ed4 100644 --- a/Utilities/cmcurl/lib/http_negotiate.c +++ b/Utilities/cmcurl/lib/http_negotiate.c @@ -26,7 +26,6 @@ #include "urldata.h" #include "sendf.h" -#include "rawstr.h" #include "http_negotiate.h" #include "vauth/vauth.h" diff --git a/Utilities/cmcurl/lib/http_ntlm.c b/Utilities/cmcurl/lib/http_ntlm.c index 935df25..e424040 100644 --- a/Utilities/cmcurl/lib/http_ntlm.c +++ b/Utilities/cmcurl/lib/http_ntlm.c @@ -35,7 +35,7 @@ #include "urldata.h" #include "sendf.h" -#include "rawstr.h" +#include "strcase.h" #include "http_ntlm.h" #include "curl_ntlm_wb.h" #include "vauth/vauth.h" diff --git a/Utilities/cmcurl/lib/http_proxy.c b/Utilities/cmcurl/lib/http_proxy.c index c6b05e3..8f5e9b4 100644 --- a/Utilities/cmcurl/lib/http_proxy.c +++ b/Utilities/cmcurl/lib/http_proxy.c @@ -31,7 +31,6 @@ #include "http.h" #include "url.h" #include "select.h" -#include "rawstr.h" #include "progress.h" #include "non-ascii.h" #include "connect.h" @@ -160,6 +159,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, if(!result) { char *host=(char *)""; + const char *proxyconn=""; const char *useragent=""; const char *http = (conn->proxytype == CURLPROXY_HTTP_1_0) ? "1.0" : "1.1"; @@ -185,6 +185,9 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, return CURLE_OUT_OF_MEMORY; } } + if(!Curl_checkProxyheaders(conn, "Proxy-Connection:")) + proxyconn = "Proxy-Connection: Keep-Alive\r\n"; + if(!Curl_checkProxyheaders(conn, "User-Agent:") && data->set.str[STRING_USERAGENT]) useragent = conn->allocptr.uagent; @@ -194,13 +197,15 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, "CONNECT %s HTTP/%s\r\n" "%s" /* Host: */ "%s" /* Proxy-Authorization */ - "%s", /* User-Agent */ + "%s" /* User-Agent */ + "%s", /* Proxy-Connection */ hostheader, http, host, conn->allocptr.proxyuserpwd? conn->allocptr.proxyuserpwd:"", - useragent); + useragent, + proxyconn); if(host && *host) free(host); @@ -239,7 +244,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, } if(!blocking) { - if(0 == Curl_socket_ready(tunnelsocket, CURL_SOCKET_BAD, 0)) + if(0 == SOCKET_READABLE(tunnelsocket, 0)) /* return so we'll be called again polling-style */ return CURLE_OK; else { @@ -274,8 +279,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, } /* loop every second at least, less if the timeout is near */ - switch (Curl_socket_ready(tunnelsocket, CURL_SOCKET_BAD, - check<1000L?check:1000)) { + switch (SOCKET_READABLE(tunnelsocket, check<1000L?check:1000)) { case -1: /* select() error, stop reading */ error = SELECT_ERROR; failf(data, "Proxy CONNECT aborted due to select/poll error"); @@ -568,7 +572,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, free(data->req.newurl); data->req.newurl = NULL; /* failure, close this connection to avoid re-use */ - connclose(conn, "proxy CONNECT failure"); + streamclose(conn, "proxy CONNECT failure"); Curl_closesocket(conn, conn->sock[sockindex]); conn->sock[sockindex] = CURL_SOCKET_BAD; } diff --git a/Utilities/cmcurl/lib/if2ip.c b/Utilities/cmcurl/lib/if2ip.c index 2f92b2d..e6faa4b 100644 --- a/Utilities/cmcurl/lib/if2ip.c +++ b/Utilities/cmcurl/lib/if2ip.c @@ -51,7 +51,7 @@ #endif #include "inet_ntop.h" -#include "strequal.h" +#include "strcase.h" #include "if2ip.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -102,7 +102,7 @@ bool Curl_if_is_interface_name(const char *interf) if(getifaddrs(&head) >= 0) { for(iface=head; iface != NULL; iface=iface->ifa_next) { - if(curl_strequal(iface->ifa_name, interf)) { + if(strcasecompare(iface->ifa_name, interf)) { result = TRUE; break; } @@ -132,7 +132,7 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, for(iface = head; iface != NULL; iface=iface->ifa_next) { if(iface->ifa_addr != NULL) { if(iface->ifa_addr->sa_family == af) { - if(curl_strequal(iface->ifa_name, interf)) { + if(strcasecompare(iface->ifa_name, interf)) { void *addr; char *ip; char scope[12] = ""; @@ -180,7 +180,7 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, } } else if((res == IF2IP_NOT_FOUND) && - curl_strequal(iface->ifa_name, interf)) { + strcasecompare(iface->ifa_name, interf)) { res = IF2IP_AF_NOT_SUPPORTED; } } diff --git a/Utilities/cmcurl/lib/imap.c b/Utilities/cmcurl/lib/imap.c index 123ea3b..4aa7dcc 100644 --- a/Utilities/cmcurl/lib/imap.c +++ b/Utilities/cmcurl/lib/imap.c @@ -68,16 +68,15 @@ #include "http.h" /* for HTTP proxy tunnel stuff */ #include "socks.h" #include "imap.h" - #include "strtoofft.h" -#include "strequal.h" +#include "strcase.h" #include "vtls/vtls.h" #include "connect.h" #include "strerror.h" #include "select.h" #include "multiif.h" #include "url.h" -#include "rawstr.h" +#include "strcase.h" #include "curl_sasl.h" #include "warnless.h" @@ -271,7 +270,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 && Curl_raw_nequal(line, cmd, cmd_len) && + if(line + cmd_len <= end && strncasecompare(line, cmd, cmd_len) && (line[cmd_len] == ' ' || line + cmd_len + 2 == end)) return TRUE; @@ -846,7 +845,7 @@ static CURLcode imap_state_servergreet_resp(struct connectdata *conn, if(imapcode != 'O') { failf(data, "Got unexpected imap-server response"); - result = CURLE_FTP_WEIRD_SERVER_REPLY; /* TODO: fix this code */ + result = CURLE_WEIRD_SERVER_REPLY; } else result = imap_perform_capability(conn); @@ -1179,7 +1178,7 @@ static CURLcode imap_state_fetch_resp(struct connectdata *conn, int imapcode, else { /* We don't know how to parse this line */ failf(pp->conn->data, "Failed to parse FETCH response."); - result = CURLE_FTP_WEIRD_SERVER_REPLY; /* TODO: fix this code */ + result = CURLE_WEIRD_SERVER_REPLY; } /* End of DO phase */ @@ -1198,7 +1197,7 @@ static CURLcode imap_state_fetch_final_resp(struct connectdata *conn, (void)instate; /* No use for this yet */ if(imapcode != 'O') - result = CURLE_FTP_WEIRD_SERVER_REPLY; /* TODO: Fix error code */ + result = CURLE_WEIRD_SERVER_REPLY; else /* End of DONE phase */ state(conn, IMAP_STOP); @@ -1275,7 +1274,7 @@ static CURLcode imap_statemach_act(struct connectdata *conn) /* Was there an error parsing the response line? */ if(imapcode == -1) - return CURLE_FTP_WEIRD_SERVER_REPLY; + return CURLE_WEIRD_SERVER_REPLY; if(!imapcode) break; @@ -1935,7 +1934,7 @@ static CURLcode imap_parse_url_options(struct connectdata *conn) while(*ptr && *ptr != ';') ptr++; - if(strnequal(key, "AUTH=", 5)) + if(strncasecompare(key, "AUTH=", 5)) result = Curl_sasl_parse_url_auth_option(&imapc->sasl, value, ptr - value); else @@ -2031,28 +2030,28 @@ static CURLcode imap_parse_url_path(struct connectdata *conn) PARTIAL) stripping of the trailing slash character if it is present. Note: Unknown parameters trigger a URL_MALFORMAT error. */ - if(Curl_raw_equal(name, "UIDVALIDITY") && !imap->uidvalidity) { + if(strcasecompare(name, "UIDVALIDITY") && !imap->uidvalidity) { if(valuelen > 0 && value[valuelen - 1] == '/') value[valuelen - 1] = '\0'; imap->uidvalidity = value; value = NULL; } - else if(Curl_raw_equal(name, "UID") && !imap->uid) { + else if(strcasecompare(name, "UID") && !imap->uid) { if(valuelen > 0 && value[valuelen - 1] == '/') value[valuelen - 1] = '\0'; imap->uid = value; value = NULL; } - else if(Curl_raw_equal(name, "SECTION") && !imap->section) { + else if(strcasecompare(name, "SECTION") && !imap->section) { if(valuelen > 0 && value[valuelen - 1] == '/') value[valuelen - 1] = '\0'; imap->section = value; value = NULL; } - else if(Curl_raw_equal(name, "PARTIAL") && !imap->partial) { + else if(strcasecompare(name, "PARTIAL") && !imap->partial) { if(valuelen > 0 && value[valuelen - 1] == '/') value[valuelen - 1] = '\0'; diff --git a/Utilities/cmcurl/lib/krb5.c b/Utilities/cmcurl/lib/krb5.c index 87ce8ee..5d5c003 100644 --- a/Utilities/cmcurl/lib/krb5.c +++ b/Utilities/cmcurl/lib/krb5.c @@ -182,7 +182,7 @@ krb5_auth(void *app_data, struct connectdata *conn) for(;;) { /* this really shouldn't be repeated here, but can't help it */ if(service == srv_host) { - result = Curl_ftpsendf(conn, "AUTH GSSAPI"); + result = Curl_ftpsend(conn, "AUTH GSSAPI"); if(result) return -2; @@ -243,16 +243,22 @@ krb5_auth(void *app_data, struct connectdata *conn) } if(output_buffer.length != 0) { + char *cmd; + result = Curl_base64_encode(data, (char *)output_buffer.value, output_buffer.length, &p, &base64_sz); if(result) { Curl_infof(data, "base64-encoding: %s\n", curl_easy_strerror(result)); - ret = AUTH_CONTINUE; + ret = AUTH_ERROR; break; } - result = Curl_ftpsendf(conn, "ADAT %s", p); + cmd = aprintf("ADAT %s", p); + if(cmd) + result = Curl_ftpsend(conn, cmd); + else + result = CURLE_OUT_OF_MEMORY; free(p); diff --git a/Utilities/cmcurl/lib/ldap.c b/Utilities/cmcurl/lib/ldap.c index a164627..7dbc1b0 100644 --- a/Utilities/cmcurl/lib/ldap.c +++ b/Utilities/cmcurl/lib/ldap.c @@ -69,12 +69,11 @@ #include "escape.h" #include "progress.h" #include "transfer.h" -#include "strequal.h" +#include "strcase.h" #include "strtok.h" #include "curl_ldap.h" #include "curl_multibyte.h" #include "curl_base64.h" -#include "rawstr.h" #include "connect.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -284,7 +283,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) /* Novell SDK supports DER or BASE64 files. */ int cert_type = LDAPSSL_CERT_FILETYPE_B64; if((data->set.str[STRING_CERT_TYPE]) && - (Curl_raw_equal(data->set.str[STRING_CERT_TYPE], "DER"))) + (strcasecompare(data->set.str[STRING_CERT_TYPE], "DER"))) cert_type = LDAPSSL_CERT_FILETYPE_DER; if(!ldap_ca) { failf(data, "LDAP local: ERROR %s CA cert not set!", @@ -325,7 +324,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) if(data->set.ssl.verifypeer) { /* OpenLDAP SDK supports BASE64 files. */ if((data->set.str[STRING_CERT_TYPE]) && - (!Curl_raw_equal(data->set.str[STRING_CERT_TYPE], "PEM"))) { + (!strcasecompare(data->set.str[STRING_CERT_TYPE], "PEM"))) { failf(data, "LDAP local: ERROR OpenLDAP only supports PEM cert-type!"); result = CURLE_SSL_CERTPROBLEM; goto quit; @@ -708,16 +707,16 @@ static void _ldap_trace (const char *fmt, ...) */ static int str2scope (const char *p) { - if(strequal(p, "one")) - return LDAP_SCOPE_ONELEVEL; - if(strequal(p, "onetree")) - return LDAP_SCOPE_ONELEVEL; - if(strequal(p, "base")) - return LDAP_SCOPE_BASE; - if(strequal(p, "sub")) - return LDAP_SCOPE_SUBTREE; - if(strequal(p, "subtree")) - return LDAP_SCOPE_SUBTREE; + if(strcasecompare(p, "one")) + return LDAP_SCOPE_ONELEVEL; + if(strcasecompare(p, "onetree")) + return LDAP_SCOPE_ONELEVEL; + if(strcasecompare(p, "base")) + return LDAP_SCOPE_BASE; + if(strcasecompare(p, "sub")) + return LDAP_SCOPE_SUBTREE; + if(strcasecompare(p, "subtree")) + return LDAP_SCOPE_SUBTREE; return (-1); } @@ -767,7 +766,7 @@ static bool split_str(char *str, char ***out, size_t *count) * * Defined in RFC4516 section 2. */ -static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp) +static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp) { int rc = LDAP_SUCCESS; char *path; @@ -776,9 +775,9 @@ static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp) size_t i; if(!conn->data || - !conn->data->state.path || - conn->data->state.path[0] != '/' || - !checkprefix("LDAP", conn->data->change.url)) + !conn->data->state.path || + conn->data->state.path[0] != '/' || + !checkprefix("LDAP", conn->data->change.url)) return LDAP_INVALID_SYNTAX; ludp->lud_scope = LDAP_SCOPE_BASE; @@ -798,12 +797,13 @@ static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp) if(*p) { char *dn = p; char *unescaped; + CURLcode result; LDAP_TRACE (("DN '%s'\n", dn)); /* Unescape the DN */ - unescaped = curl_easy_unescape(conn->data, dn, 0, NULL); - if(!unescaped) { + result = Curl_urldecode(conn->data, dn, 0, &unescaped, NULL, FALSE); + if(result) { rc = LDAP_NO_MEMORY; goto quit; @@ -862,12 +862,14 @@ static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp) for(i = 0; i < count; i++) { char *unescaped; + CURLcode result; LDAP_TRACE (("attr[%d] '%s'\n", i, attributes[i])); /* Unescape the attribute */ - unescaped = curl_easy_unescape(conn->data, attributes[i], 0, NULL); - if(!unescaped) { + result = Curl_urldecode(conn->data, attributes[i], 0, &unescaped, NULL, + FALSE); + if(result) { free(attributes); rc = LDAP_NO_MEMORY; @@ -930,12 +932,13 @@ static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp) if(*p) { char *filter = p; char *unescaped; + CURLcode result; LDAP_TRACE (("filter '%s'\n", filter)); /* Unescape the filter */ - unescaped = curl_easy_unescape(conn->data, filter, 0, NULL); - if(!unescaped) { + result = Curl_urldecode(conn->data, filter, 0, &unescaped, NULL, FALSE); + if(result) { rc = LDAP_NO_MEMORY; goto quit; @@ -971,8 +974,8 @@ quit: return rc; } -static int _ldap_url_parse (const struct connectdata *conn, - LDAPURLDesc **ludpp) +static int _ldap_url_parse(const struct connectdata *conn, + LDAPURLDesc **ludpp) { LDAPURLDesc *ludp = calloc(1, sizeof(*ludp)); int rc; @@ -981,7 +984,7 @@ static int _ldap_url_parse (const struct connectdata *conn, if(!ludp) return LDAP_NO_MEMORY; - rc = _ldap_url_parse2 (conn, ludp); + rc = _ldap_url_parse2(conn, ludp); if(rc != LDAP_SUCCESS) { _ldap_free_urldesc(ludp); ludp = NULL; @@ -990,7 +993,7 @@ static int _ldap_url_parse (const struct connectdata *conn, return (rc); } -static void _ldap_free_urldesc (LDAPURLDesc *ludp) +static void _ldap_free_urldesc(LDAPURLDesc *ludp) { size_t i; diff --git a/Utilities/cmcurl/lib/libcurl.rc b/Utilities/cmcurl/lib/libcurl.rc index 50b365d..c1efbad 100644 --- a/Utilities/cmcurl/lib/libcurl.rc +++ b/Utilities/cmcurl/lib/libcurl.rc @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2016, 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 @@ -44,12 +44,12 @@ BEGIN BEGIN BLOCK "040904b0" BEGIN - VALUE "CompanyName", "The cURL library, https://curl.haxx.se/\0" + VALUE "CompanyName", "The curl library, https://curl.haxx.se/\0" VALUE "FileDescription", "libcurl Shared Library\0" VALUE "FileVersion", LIBCURL_VERSION "\0" VALUE "InternalName", "libcurl\0" VALUE "OriginalFilename", "libcurl.dll\0" - VALUE "ProductName", "The cURL library\0" + VALUE "ProductName", "The curl library\0" VALUE "ProductVersion", LIBCURL_VERSION "\0" VALUE "LegalCopyright", "© " LIBCURL_COPYRIGHT "\0" VALUE "License", "https://curl.haxx.se/docs/copyright.html\0" diff --git a/Utilities/cmcurl/lib/md5.c b/Utilities/cmcurl/lib/md5.c index 84adb99..f818d32 100644 --- a/Utilities/cmcurl/lib/md5.c +++ b/Utilities/cmcurl/lib/md5.c @@ -124,7 +124,7 @@ static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) CC_MD5_Final(digest, ctx); } -#elif defined(_WIN32) +#elif defined(_WIN32) && !defined(CURL_WINDOWS_APP) #include <wincrypt.h> #include "curl_memory.h" diff --git a/Utilities/cmcurl/lib/mprintf.c b/Utilities/cmcurl/lib/mprintf.c index 380c3d6..3cdd41a 100644 --- a/Utilities/cmcurl/lib/mprintf.c +++ b/Utilities/cmcurl/lib/mprintf.c @@ -223,10 +223,12 @@ static bool dprintf_IsQualifierNoDollar(const char *fmt) * Create an index with the type of each parameter entry and its * value (may vary in size) * + * Returns zero on success. + * ******************************************************************/ -static long dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos, - va_list arglist) +static int dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos, + va_list arglist) { char *fmt = (char *)format; int param_num = 0; @@ -389,6 +391,10 @@ static long dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos, i = this_param - 1; + if((i < 0) || (i >= MAX_PARAMETERS)) + /* out of allowed range */ + return 1; + switch (*fmt) { case 'S': flags |= FLAGS_ALT; @@ -545,7 +551,7 @@ static long dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos, } } - return max_param; + return 0; } @@ -583,7 +589,8 @@ static int dprintf_formatf( char *workend = &work[sizeof(work) - 2]; /* Do the actual %-code parsing */ - dprintf_Pass1(format, vto, endpos, ap_save); + if(dprintf_Pass1(format, vto, endpos, ap_save)) + return -1; end = &endpos[0]; /* the initial end-position from the list dprintf_Pass1() created for us */ @@ -988,7 +995,7 @@ int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format, info.max = maxlength; retcode = dprintf_formatf(&info, addbyter, format, ap_save); - if(info.max) { + if((retcode != -1) && info.max) { /* we terminate this with a zero byte */ if(info.max == info.length) /* we're at maximum, scrap the last letter */ @@ -1025,16 +1032,19 @@ static int alloc_addbyter(int output, FILE *data) infop->len =0; } else if(infop->len+1 >= infop->alloc) { - char *newptr; + char *newptr = NULL; + size_t newsize = infop->alloc*2; - newptr = realloc(infop->buffer, infop->alloc*2); + /* detect wrap-around or other overflow problems */ + if(newsize > infop->alloc) + newptr = realloc(infop->buffer, newsize); if(!newptr) { infop->fail = 1; return -1; /* fail */ } infop->buffer = newptr; - infop->alloc *= 2; + infop->alloc = newsize; } infop->buffer[ infop->len ] = outc; diff --git a/Utilities/cmcurl/lib/multi.c b/Utilities/cmcurl/lib/multi.c index 8bb9366..2432b15 100644 --- a/Utilities/cmcurl/lib/multi.c +++ b/Utilities/cmcurl/lib/multi.c @@ -42,6 +42,7 @@ #include "multihandle.h" #include "pipeline.h" #include "sigpipe.h" +#include "connect.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" @@ -442,7 +443,7 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi, sockets that time-out or have actions will be dealt with. Since this handle has no action yet, we make sure it times out to get things to happen. */ - Curl_expire(data, 1); + Curl_expire(data, 0); /* increase the node-counter */ multi->num_easy++; @@ -462,6 +463,14 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi, handle is added */ memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall)); + /* The closure handle only ever has default timeouts set. To improve the + state somewhat we clone the timeouts from each added handle so that the + closure handle always has the same timeouts as the most recently added + easy handle. */ + multi->closure_handle->set.timeout = data->set.timeout; + multi->closure_handle->set.server_response_timeout = + data->set.server_response_timeout; + update_timer(multi); return CURLM_OK; } @@ -569,12 +578,12 @@ static CURLcode multi_done(struct connectdata **connp, result = CURLE_ABORTED_BY_CALLBACK; } - if((!premature && - conn->send_pipe->size + conn->recv_pipe->size != 0 && - !data->set.reuse_forbid && - !conn->bits.close)) { + if(conn->send_pipe->size + conn->recv_pipe->size != 0 && + !data->set.reuse_forbid && + !conn->bits.close) { /* Stop if pipeline is not empty and we do not have to close connection. */ + data->easy_conn = NULL; DEBUGF(infof(data, "Connection still in use, no more multi_done now!\n")); return CURLE_OK; } @@ -685,7 +694,7 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi, /* If the handle is in a pipeline and has started sending off its request but not received its response yet, we need to close connection. */ - connclose(data->easy_conn, "Removed with partial response"); + streamclose(data->easy_conn, "Removed with partial response"); /* Set connection owner so that the DONE function closes it. We can safely do this here since connection is killed. */ data->easy_conn->data = easy; @@ -695,7 +704,7 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi, /* The timer must be shut down before data->multi is set to NULL, else the timenode will remain in the splay tree after curl_easy_cleanup is called. */ - Curl_expire(data, 0); + Curl_expire_clear(data); if(data->dns.hostcachetype == HCACHE_MULTI) { /* stop using the multi handle's DNS cache */ @@ -1298,7 +1307,9 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, return CURLM_BAD_EASY_HANDLE; do { - bool disconnect_conn = FALSE; + /* A "stream" here is a logical stream if the protocol can handle that + (HTTP/2), or the full connection for older protocols */ + bool stream_error = FALSE; rc = CURLM_OK; /* Handle the case when the pipe breaks, i.e., the connection @@ -1376,8 +1387,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* Force connection closed if the connection has indeed been used */ if(data->mstate > CURLM_STATE_DO) { - connclose(data->easy_conn, "Disconnected with pending data"); - disconnect_conn = TRUE; + streamclose(data->easy_conn, "Disconnected with pending data"); + stream_error = TRUE; } result = CURLE_OPERATION_TIMEDOUT; (void)multi_done(&data->easy_conn, result, TRUE); @@ -1426,7 +1437,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* Add this handle to the send or pend pipeline */ result = Curl_add_handle_to_pipeline(data, data->easy_conn); if(result) - disconnect_conn = TRUE; + stream_error = TRUE; else { if(async) /* We're now waiting for an asynchronous name lookup */ @@ -1518,7 +1529,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, if(result) { /* failure detected */ - disconnect_conn = TRUE; + stream_error = TRUE; break; } } @@ -1558,7 +1569,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, else if(result) { /* failure detected */ /* Just break, the cleaning up is handled all in one place */ - disconnect_conn = TRUE; + stream_error = TRUE; break; } break; @@ -1578,7 +1589,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* failure detected */ Curl_posttransfer(data); multi_done(&data->easy_conn, result, TRUE); - disconnect_conn = TRUE; + stream_error = TRUE; } break; @@ -1595,7 +1606,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* failure detected */ Curl_posttransfer(data); multi_done(&data->easy_conn, result, TRUE); - disconnect_conn = TRUE; + stream_error = TRUE; } break; @@ -1670,7 +1681,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, if(drc) { /* a failure here pretty much implies an out of memory */ result = drc; - disconnect_conn = TRUE; + stream_error = TRUE; } else retry = (newurl)?TRUE:FALSE; @@ -1703,7 +1714,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, } else { /* Have error handler disconnect conn if we can't retry */ - disconnect_conn = TRUE; + stream_error = TRUE; free(newurl); } } @@ -1712,7 +1723,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, Curl_posttransfer(data); if(data->easy_conn) multi_done(&data->easy_conn, result, FALSE); - disconnect_conn = TRUE; + stream_error = TRUE; } } break; @@ -1734,7 +1745,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* failure detected */ Curl_posttransfer(data); multi_done(&data->easy_conn, result, FALSE); - disconnect_conn = TRUE; + stream_error = TRUE; } break; @@ -1763,7 +1774,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* failure detected */ Curl_posttransfer(data); multi_done(&data->easy_conn, result, FALSE); - disconnect_conn = TRUE; + stream_error = TRUE; } break; @@ -1800,9 +1811,17 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, result = Curl_speedcheck(data, now); if(( (data->set.max_send_speed == 0) || - (data->progress.ulspeed < data->set.max_send_speed)) && + (Curl_pgrsLimitWaitTime(data->progress.uploaded, + data->progress.ul_limit_size, + data->set.max_send_speed, + data->progress.ul_limit_start, + now) <= 0)) && ( (data->set.max_recv_speed == 0) || - (data->progress.dlspeed < data->set.max_recv_speed))) + (Curl_pgrsLimitWaitTime(data->progress.downloaded, + data->progress.dl_limit_size, + data->set.max_recv_speed, + data->progress.dl_limit_start, + now) <= 0))) multistate(data, CURLM_STATE_PERFORM); break; @@ -1810,41 +1829,38 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, { char *newurl = NULL; bool retry = FALSE; + bool comeback = FALSE; /* check if over send speed */ - if((data->set.max_send_speed > 0) && - (data->progress.ulspeed > data->set.max_send_speed)) { - int buffersize; - - multistate(data, CURLM_STATE_TOOFAST); - - /* calculate upload rate-limitation timeout. */ - buffersize = (int)(data->set.buffer_size ? - data->set.buffer_size : BUFSIZE); - timeout_ms = Curl_sleep_time(data->set.max_send_speed, - data->progress.ulspeed, buffersize); - Curl_expire_latest(data, timeout_ms); - break; + if(data->set.max_send_speed > 0) { + timeout_ms = Curl_pgrsLimitWaitTime(data->progress.uploaded, + data->progress.ul_limit_size, + data->set.max_send_speed, + data->progress.ul_limit_start, + now); + if(timeout_ms > 0) { + multistate(data, CURLM_STATE_TOOFAST); + Curl_expire_latest(data, timeout_ms); + break; + } } /* check if over recv speed */ - if((data->set.max_recv_speed > 0) && - (data->progress.dlspeed > data->set.max_recv_speed)) { - int buffersize; - - multistate(data, CURLM_STATE_TOOFAST); - - /* Calculate download rate-limitation timeout. */ - buffersize = (int)(data->set.buffer_size ? - data->set.buffer_size : BUFSIZE); - timeout_ms = Curl_sleep_time(data->set.max_recv_speed, - data->progress.dlspeed, buffersize); - Curl_expire_latest(data, timeout_ms); - break; + if(data->set.max_recv_speed > 0) { + timeout_ms = Curl_pgrsLimitWaitTime(data->progress.downloaded, + data->progress.dl_limit_size, + data->set.max_recv_speed, + data->progress.dl_limit_start, + now); + if(timeout_ms > 0) { + multistate(data, CURLM_STATE_TOOFAST); + Curl_expire_latest(data, timeout_ms); + break; + } } /* read/write data if it is ready to do so */ - result = Curl_readwrite(data->easy_conn, data, &done); + result = Curl_readwrite(data->easy_conn, data, &done, &comeback); k = &data->req; @@ -1884,10 +1900,10 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, if(!(data->easy_conn->handler->flags & PROTOPT_DUAL) && result != CURLE_HTTP2_STREAM) - connclose(data->easy_conn, "Transfer returned error"); + streamclose(data->easy_conn, "Transfer returned error"); Curl_posttransfer(data); - multi_done(&data->easy_conn, result, FALSE); + multi_done(&data->easy_conn, result, TRUE); } else if(done) { followtype follow=FOLLOW_NONE; @@ -1900,7 +1916,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* expire the new receiving pipeline head */ if(data->easy_conn->recv_pipe->head) - Curl_expire_latest(data->easy_conn->recv_pipe->head->ptr, 1); + Curl_expire_latest(data->easy_conn->recv_pipe->head->ptr, 0); /* Check if we can move pending requests to send pipe */ Curl_multi_process_pending_handles(multi); @@ -1943,13 +1959,15 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, if(!result) newurl = NULL; /* allocation was handed over Curl_follow() */ else - disconnect_conn = TRUE; + stream_error = TRUE; } multistate(data, CURLM_STATE_DONE); rc = CURLM_CALL_MULTI_PERFORM; } } + else if(comeback) + rc = CURLM_CALL_MULTI_PERFORM; free(newurl); break; @@ -2008,7 +2026,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, that could be freed anytime */ data->easy_conn = NULL; - Curl_expire(data, 0); /* stop all timers */ + Curl_expire_clear(data); /* stop all timers */ break; case CURLM_STATE_MSGSENT: @@ -2042,7 +2060,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, Curl_removeHandleFromPipeline(data, data->easy_conn->send_pipe); Curl_removeHandleFromPipeline(data, data->easy_conn->recv_pipe); - if(disconnect_conn) { + if(stream_error) { /* Don't attempt to send data over a connection that timed out */ bool dead_connection = result == CURLE_OPERATION_TIMEDOUT; /* disconnect properly */ @@ -2066,7 +2084,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* aborted due to progress callback return code must close the connection */ result = CURLE_ABORTED_BY_CALLBACK; - connclose(data->easy_conn, "Aborted by callback"); + streamclose(data->easy_conn, "Aborted by callback"); /* if not yet in DONE state, go there, otherwise COMPLETED */ multistate(data, (data->mstate < CURLM_STATE_DONE)? @@ -2160,6 +2178,7 @@ static void close_all_connections(struct Curl_multi *multi) conn->data->easy_conn = NULL; /* clear the easy handle's connection pointer */ /* This will remove the connection from the cache */ + connclose(conn, "kill all"); (void)Curl_disconnect(conn, FALSE); sigpipe_restore(&pipe_st); @@ -2876,92 +2895,59 @@ multi_addtimeout(struct curl_llist *timeoutlist, * given a number of milliseconds from now to use to set the 'act before * this'-time for the transfer, to be extracted by curl_multi_timeout() * - * Note that the timeout will be added to a queue of timeouts if it defines a - * moment in time that is later than the current head of queue. - * - * Pass zero to clear all timeout values for this handle. -*/ + * The timeout will be added to a queue of timeouts if it defines a moment in + * time that is later than the current head of queue. + */ void Curl_expire(struct Curl_easy *data, long milli) { struct Curl_multi *multi = data->multi; struct timeval *nowp = &data->state.expiretime; int rc; + struct timeval set; /* this is only interesting while there is still an associated multi struct remaining! */ if(!multi) return; - if(!milli) { - /* No timeout, clear the time data. */ - if(nowp->tv_sec || nowp->tv_usec) { - /* Since this is an cleared time, we must remove the previous entry from - the splay tree */ - struct curl_llist *list = data->state.timeoutlist; - - rc = Curl_splayremovebyaddr(multi->timetree, - &data->state.timenode, - &multi->timetree); - if(rc) - infof(data, "Internal error clearing splay node = %d\n", rc); - - /* flush the timeout list too */ - while(list->size > 0) - Curl_llist_remove(list, list->tail, NULL); + set = Curl_tvnow(); + set.tv_sec += milli/1000; + set.tv_usec += (milli%1000)*1000; -#ifdef DEBUGBUILD - infof(data, "Expire cleared\n"); -#endif - nowp->tv_sec = 0; - nowp->tv_usec = 0; - } + if(set.tv_usec >= 1000000) { + set.tv_sec++; + set.tv_usec -= 1000000; } - else { - struct timeval set; - - set = Curl_tvnow(); - set.tv_sec += milli/1000; - set.tv_usec += (milli%1000)*1000; - - if(set.tv_usec >= 1000000) { - set.tv_sec++; - set.tv_usec -= 1000000; - } - - if(nowp->tv_sec || nowp->tv_usec) { - /* This means that the struct is added as a node in the splay tree. - Compare if the new time is earlier, and only remove-old/add-new if it - is. */ - long diff = curlx_tvdiff(set, *nowp); - if(diff > 0) { - /* the new expire time was later so just add it to the queue - and get out */ - multi_addtimeout(data->state.timeoutlist, &set); - return; - } - /* the new time is newer than the presently set one, so add the current - to the queue and update the head */ - multi_addtimeout(data->state.timeoutlist, nowp); - - /* Since this is an updated time, we must remove the previous entry from - the splay tree first and then re-add the new value */ - rc = Curl_splayremovebyaddr(multi->timetree, - &data->state.timenode, - &multi->timetree); - if(rc) - infof(data, "Internal error removing splay node = %d\n", rc); + if(nowp->tv_sec || nowp->tv_usec) { + /* This means that the struct is added as a node in the splay tree. + Compare if the new time is earlier, and only remove-old/add-new if it + is. */ + long diff = curlx_tvdiff(set, *nowp); + if(diff > 0) { + /* the new expire time was later so just add it to the queue + and get out */ + multi_addtimeout(data->state.timeoutlist, &set); + return; } - *nowp = set; - data->state.timenode.payload = data; - multi->timetree = Curl_splayinsert(*nowp, - multi->timetree, - &data->state.timenode); + /* the new time is newer than the presently set one, so add the current + to the queue and update the head */ + multi_addtimeout(data->state.timeoutlist, nowp); + + /* Since this is an updated time, we must remove the previous entry from + the splay tree first and then re-add the new value */ + rc = Curl_splayremovebyaddr(multi->timetree, + &data->state.timenode, + &multi->timetree); + if(rc) + infof(data, "Internal error removing splay node = %d\n", rc); } -#if 0 - Curl_splayprint(multi->timetree, 0, TRUE); -#endif + + *nowp = set; + data->state.timenode.payload = data; + multi->timetree = Curl_splayinsert(*nowp, multi->timetree, + &data->state.timenode); } /* @@ -3004,6 +2990,49 @@ void Curl_expire_latest(struct Curl_easy *data, long milli) Curl_expire(data, milli); } + +/* + * Curl_expire_clear() + * + * Clear ALL timeout values for this handle. + */ +void Curl_expire_clear(struct Curl_easy *data) +{ + struct Curl_multi *multi = data->multi; + struct timeval *nowp = &data->state.expiretime; + int rc; + + /* this is only interesting while there is still an associated multi struct + remaining! */ + if(!multi) + return; + + if(nowp->tv_sec || nowp->tv_usec) { + /* Since this is an cleared time, we must remove the previous entry from + the splay tree */ + struct curl_llist *list = data->state.timeoutlist; + + rc = Curl_splayremovebyaddr(multi->timetree, + &data->state.timenode, + &multi->timetree); + if(rc) + infof(data, "Internal error clearing splay node = %d\n", rc); + + /* flush the timeout list too */ + while(list->size > 0) + Curl_llist_remove(list, list->tail, NULL); + +#ifdef DEBUGBUILD + infof(data, "Expire cleared\n"); +#endif + nowp->tv_sec = 0; + nowp->tv_usec = 0; + } +} + + + + CURLMcode curl_multi_assign(struct Curl_multi *multi, curl_socket_t s, void *hashp) { @@ -3064,7 +3093,7 @@ void Curl_multi_process_pending_handles(struct Curl_multi *multi) Curl_llist_remove(multi->pending, e, NULL); /* Make sure that the handle will be processed soonish. */ - Curl_expire_latest(data, 1); + Curl_expire_latest(data, 0); } e = next; /* operate on next handle */ diff --git a/Utilities/cmcurl/lib/multiif.h b/Utilities/cmcurl/lib/multiif.h index fd2df55..eaff496 100644 --- a/Utilities/cmcurl/lib/multiif.h +++ b/Utilities/cmcurl/lib/multiif.h @@ -26,6 +26,7 @@ * Prototypes for library-wide functions provided by multi.c */ void Curl_expire(struct Curl_easy *data, long milli); +void Curl_expire_clear(struct Curl_easy *data); void Curl_expire_latest(struct Curl_easy *data, long milli); bool Curl_pipeline_wanted(const struct Curl_multi* multi, int bits); void Curl_multi_handlePipeBreak(struct Curl_easy *data); diff --git a/Utilities/cmcurl/lib/netrc.c b/Utilities/cmcurl/lib/netrc.c index 46f427a..996711d 100644 --- a/Utilities/cmcurl/lib/netrc.c +++ b/Utilities/cmcurl/lib/netrc.c @@ -28,10 +28,8 @@ #include <curl/curl.h> #include "netrc.h" - -#include "strequal.h" #include "strtok.h" -#include "rawstr.h" +#include "strcase.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -130,20 +128,20 @@ int Curl_parsenetrc(const char *host, switch(state) { case NOTHING: - if(Curl_raw_equal("machine", tok)) { + if(strcasecompare("machine", tok)) { /* the next tok is the machine name, this is in itself the delimiter that starts the stuff entered for this machine, after this we need to search for 'login' and 'password'. */ state=HOSTFOUND; } - else if(Curl_raw_equal("default", tok)) { + else if(strcasecompare("default", tok)) { state=HOSTVALID; retcode=0; /* we did find our host */ } break; case HOSTFOUND: - if(Curl_raw_equal(host, tok)) { + if(strcasecompare(host, tok)) { /* and yes, this is our host! */ state=HOSTVALID; retcode=0; /* we did find our host */ @@ -156,7 +154,7 @@ int Curl_parsenetrc(const char *host, /* we are now parsing sub-keywords concerning "our" host */ if(state_login) { if(specific_login) { - state_our_login = Curl_raw_equal(*loginp, tok); + state_our_login = strcasecompare(*loginp, tok); } else { free(*loginp); @@ -179,11 +177,11 @@ int Curl_parsenetrc(const char *host, } state_password=0; } - else if(Curl_raw_equal("login", tok)) + else if(strcasecompare("login", tok)) state_login=1; - else if(Curl_raw_equal("password", tok)) + else if(strcasecompare("password", tok)) state_password=1; - else if(Curl_raw_equal("machine", tok)) { + else if(strcasecompare("machine", tok)) { /* ok, there's machine here go => */ state = HOSTFOUND; state_our_login = FALSE; diff --git a/Utilities/cmcurl/lib/parsedate.c b/Utilities/cmcurl/lib/parsedate.c index dfcf855..3c783be 100644 --- a/Utilities/cmcurl/lib/parsedate.c +++ b/Utilities/cmcurl/lib/parsedate.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2016, 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 @@ -80,7 +80,7 @@ #endif #include <curl/curl.h> -#include "rawstr.h" +#include "strcase.h" #include "warnless.h" #include "parsedate.h" @@ -211,7 +211,7 @@ static int checkday(const char *check, size_t len) else what = &Curl_wkday[0]; for(i=0; i<7; i++) { - if(Curl_raw_equal(check, what[0])) { + if(strcasecompare(check, what[0])) { found=TRUE; break; } @@ -228,7 +228,7 @@ static int checkmonth(const char *check) what = &Curl_month[0]; for(i=0; i<12; i++) { - if(Curl_raw_equal(check, what[0])) { + if(strcasecompare(check, what[0])) { found=TRUE; break; } @@ -248,7 +248,7 @@ static int checktz(const char *check) what = tz; for(i=0; i< sizeof(tz)/sizeof(tz[0]); i++) { - if(Curl_raw_equal(check, what->name)) { + if(strcasecompare(check, what->name)) { found=TRUE; break; } @@ -386,15 +386,17 @@ static int parsedate(const char *date, time_t *output) /* a digit */ int val; char *end; + int len=0; if((secnum == -1) && - (3 == sscanf(date, "%02d:%02d:%02d", &hournum, &minnum, &secnum))) { + (3 == sscanf(date, "%02d:%02d:%02d%n", + &hournum, &minnum, &secnum, &len))) { /* time stamp! */ - date += 8; + date += len; } else if((secnum == -1) && - (2 == sscanf(date, "%02d:%02d", &hournum, &minnum))) { + (2 == sscanf(date, "%02d:%02d%n", &hournum, &minnum, &len))) { /* time stamp without seconds */ - date += 5; + date += len; secnum = 0; } else { diff --git a/Utilities/cmcurl/lib/pingpong.c b/Utilities/cmcurl/lib/pingpong.c index 92ff84b..bf2c8fd 100644 --- a/Utilities/cmcurl/lib/pingpong.c +++ b/Utilities/cmcurl/lib/pingpong.c @@ -108,7 +108,8 @@ CURLcode Curl_pp_statemach(struct pingpong *pp, bool block) /* We are receiving and there is data ready in the SSL library */ rc = 1; else - rc = Curl_socket_ready(pp->sendleft?CURL_SOCKET_BAD:sock, /* reading */ + rc = Curl_socket_check(pp->sendleft?CURL_SOCKET_BAD:sock, /* reading */ + CURL_SOCKET_BAD, pp->sendleft?sock:CURL_SOCKET_BAD, /* writing */ interval_ms); diff --git a/Utilities/cmcurl/lib/pipeline.c b/Utilities/cmcurl/lib/pipeline.c index 0ff82f0..40a5e82 100644 --- a/Utilities/cmcurl/lib/pipeline.c +++ b/Utilities/cmcurl/lib/pipeline.c @@ -6,7 +6,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2013, Linus Nielsen Feltzing, <linus@haxx.se> - * Copyright (C) 2013-2015, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2013-2016, 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 @@ -31,7 +31,7 @@ #include "multiif.h" #include "pipeline.h" #include "sendf.h" -#include "rawstr.h" +#include "strcase.h" #include "curl_memory.h" /* The last #include file should be: */ @@ -114,7 +114,7 @@ CURLcode Curl_add_handle_to_pipeline(struct Curl_easy *handle, if(pipeline == conn->send_pipe && sendhead != conn->send_pipe->head) { /* this is a new one as head, expire it */ Curl_pipeline_leave_write(conn); /* not in use yet */ - Curl_expire(conn->send_pipe->head->ptr, 1); + Curl_expire(conn->send_pipe->head->ptr, 0); } #if 0 /* enable for pipeline debugging */ @@ -149,7 +149,7 @@ void Curl_move_handle_from_send_to_recv_pipe(struct Curl_easy *handle, infof(conn->data, "%p is at send pipe head B!\n", (void *)conn->send_pipe->head->ptr); #endif - Curl_expire(conn->send_pipe->head->ptr, 1); + Curl_expire(conn->send_pipe->head->ptr, 0); } /* The receiver's list is not really interesting here since either this @@ -177,7 +177,7 @@ bool Curl_pipeline_site_blacklisted(struct Curl_easy *handle, struct site_blacklist_entry *site; site = curr->ptr; - if(Curl_raw_equal(site->hostname, conn->host.name) && + if(strcasecompare(site->hostname, conn->host.name) && site->port == conn->remote_port) { infof(handle, "Site %s:%d is pipeline blacklisted\n", conn->host.name, conn->remote_port); @@ -269,7 +269,7 @@ bool Curl_pipeline_server_blacklisted(struct Curl_easy *handle, char *bl_server_name; bl_server_name = curr->ptr; - if(Curl_raw_nequal(bl_server_name, server_name, + if(strncasecompare(bl_server_name, server_name, strlen(bl_server_name))) { infof(handle, "Server %s is blacklisted\n", server_name); return TRUE; diff --git a/Utilities/cmcurl/lib/pop3.c b/Utilities/cmcurl/lib/pop3.c index 591e877..8486519 100644 --- a/Utilities/cmcurl/lib/pop3.c +++ b/Utilities/cmcurl/lib/pop3.c @@ -70,16 +70,14 @@ #include "http.h" /* for HTTP proxy tunnel stuff */ #include "socks.h" #include "pop3.h" - #include "strtoofft.h" -#include "strequal.h" +#include "strcase.h" #include "vtls/vtls.h" #include "connect.h" #include "strerror.h" #include "select.h" #include "multiif.h" #include "url.h" -#include "rawstr.h" #include "curl_sasl.h" #include "curl_md5.h" #include "warnless.h" @@ -663,7 +661,7 @@ static CURLcode pop3_state_servergreet_resp(struct connectdata *conn, if(pop3code != '+') { failf(data, "Got unexpected pop3-server response"); - result = CURLE_FTP_WEIRD_SERVER_REPLY; + result = CURLE_WEIRD_SERVER_REPLY; } else { /* Does the server support APOP authentication? */ @@ -1412,11 +1410,11 @@ static CURLcode pop3_parse_url_options(struct connectdata *conn) while(*ptr && *ptr != ';') ptr++; - if(strnequal(key, "AUTH=", 5)) { + if(strncasecompare(key, "AUTH=", 5)) { result = Curl_sasl_parse_url_auth_option(&pop3c->sasl, value, ptr - value); - if(result && strnequal(value, "+APOP", ptr - value)) { + if(result && strncasecompare(value, "+APOP", ptr - value)) { pop3c->preftype = POP3_TYPE_APOP; pop3c->sasl.prefmech = SASL_AUTH_NONE; result = CURLE_OK; diff --git a/Utilities/cmcurl/lib/progress.c b/Utilities/cmcurl/lib/progress.c index 760ca1c..0f67ef2 100644 --- a/Utilities/cmcurl/lib/progress.c +++ b/Utilities/cmcurl/lib/progress.c @@ -216,18 +216,93 @@ void Curl_pgrsStartNow(struct Curl_easy *data) { data->progress.speeder_c = 0; /* reset the progress meter display */ data->progress.start = Curl_tvnow(); + data->progress.ul_limit_start.tv_sec = 0; + data->progress.ul_limit_start.tv_usec = 0; + data->progress.dl_limit_start.tv_sec = 0; + data->progress.dl_limit_start.tv_usec = 0; /* clear all bits except HIDE and HEADERS_OUT */ data->progress.flags &= PGRS_HIDE|PGRS_HEADERS_OUT; } +/* + * This is used to handle speed limits, calculating how much milliseconds we + * need to wait until we're back under the speed limit, if needed. + * + * The way it works is by having a "starting point" (time & amount of data + * transfered by then) used in the speed computation, to be used instead of the + * start of the transfer. + * This starting point is regularly moved as transfer goes on, to keep getting + * accurate values (instead of average over the entire tranfer). + * + * This function takes the current amount of data transfered, the amount at the + * starting point, the limit (in bytes/s), the time of the starting point and + * the current time. + * + * Returns -1 if no waiting is needed (not enough data transfered since + * starting point yet), 0 when no waiting is needed but the starting point + * should be reset (to current), or the number of milliseconds to wait to get + * back under the speed limit. + */ +long Curl_pgrsLimitWaitTime(curl_off_t cursize, + curl_off_t startsize, + curl_off_t limit, + struct timeval start, + struct timeval now) +{ + curl_off_t size = cursize - startsize; + long minimum, actual; + + /* we don't have a starting point yet -- return 0 so it gets (re)set */ + if(start.tv_sec == 0 && start.tv_usec == 0) + return 0; + + /* not enough data yet */ + if(size < limit) + return -1; + + minimum = (long) (CURL_OFF_T_C(1000) * size / limit); + actual = Curl_tvdiff(now, start); + + if(actual < minimum) + return minimum - actual; + else + return 0; +} + void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size) { + struct timeval now = Curl_tvnow(); + data->progress.downloaded = size; + + /* download speed limit */ + if((data->set.max_recv_speed > 0) && + (Curl_pgrsLimitWaitTime(data->progress.downloaded, + data->progress.dl_limit_size, + data->set.max_recv_speed, + data->progress.dl_limit_start, + now) == 0)) { + data->progress.dl_limit_start = now; + data->progress.dl_limit_size = size; + } } void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size) { + struct timeval now = Curl_tvnow(); + data->progress.uploaded = size; + + /* upload speed limit */ + if((data->set.max_send_speed > 0) && + (Curl_pgrsLimitWaitTime(data->progress.uploaded, + data->progress.ul_limit_size, + data->set.max_send_speed, + data->progress.ul_limit_start, + now) == 0)) { + data->progress.ul_limit_start = now; + data->progress.ul_limit_size = size; + } } void Curl_pgrsSetDownloadSize(struct Curl_easy *data, curl_off_t size) diff --git a/Utilities/cmcurl/lib/progress.h b/Utilities/cmcurl/lib/progress.h index a77b7ce..155ff04 100644 --- a/Utilities/cmcurl/lib/progress.h +++ b/Utilities/cmcurl/lib/progress.h @@ -49,7 +49,11 @@ void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size); int Curl_pgrsUpdate(struct connectdata *); void Curl_pgrsResetTimesSizes(struct Curl_easy *data); void Curl_pgrsTime(struct Curl_easy *data, timerid timer); - +long Curl_pgrsLimitWaitTime(curl_off_t cursize, + curl_off_t startsize, + curl_off_t limit, + struct timeval start, + struct timeval now); /* Don't show progress for sizes smaller than: */ #define LEAST_SIZE_PROGRESS BUFSIZE diff --git a/Utilities/cmcurl/lib/rtsp.c b/Utilities/cmcurl/lib/rtsp.c index 27955bc..d1bad19 100644 --- a/Utilities/cmcurl/lib/rtsp.c +++ b/Utilities/cmcurl/lib/rtsp.c @@ -33,7 +33,7 @@ #include "url.h" #include "progress.h" #include "rtsp.h" -#include "rawstr.h" +#include "strcase.h" #include "select.h" #include "connect.h" /* The last 3 #include files should be in this order */ @@ -147,7 +147,7 @@ bool Curl_rtsp_connisdead(struct connectdata *check) int sval; bool ret_val = TRUE; - sval = Curl_socket_ready(check->sock[FIRSTSOCKET], CURL_SOCKET_BAD, 0); + sval = SOCKET_READABLE(check->sock[FIRSTSOCKET], 0); if(sval == 0) { /* timeout */ ret_val = FALSE; @@ -796,19 +796,15 @@ CURLcode Curl_rtsp_parseheader(struct connectdata *conn, } } else { - /* If the Session ID is not set, and we find it in a response, then - set it */ - - /* The session ID can be an alphanumeric or a 'safe' character + /* If the Session ID is not set, and we find it in a response, then set + * it. * - * RFC 2326 15.1 Base Syntax: - * safe = "\$" | "-" | "_" | "." | "+" - * */ + * Allow any non whitespace content, up to the field seperator or end of + * line. RFC 2326 isn't 100% clear on the session ID and for example + * gstreamer does url-encoded session ID's not covered by the standard. + */ char *end = start; - while(*end && - (ISALNUM(*end) || *end == '-' || *end == '_' || *end == '.' || - *end == '+' || - (*end == '\\' && *(end + 1) && *(end + 1) == '$' && (++end, 1)))) + while(*end && *end != ';' && !ISSPACE(*end)) end++; /* Copy the id substring into a new buffer */ diff --git a/Utilities/cmcurl/lib/security.c b/Utilities/cmcurl/lib/security.c index a0bcaea..ff26066 100644 --- a/Utilities/cmcurl/lib/security.c +++ b/Utilities/cmcurl/lib/security.c @@ -60,7 +60,7 @@ #include "curl_sec.h" #include "ftp.h" #include "sendf.h" -#include "rawstr.h" +#include "strcase.h" #include "warnless.h" /* The last #include file should be: */ @@ -122,7 +122,7 @@ static int ftp_send_command(struct connectdata *conn, const char *message, ...) vsnprintf(print_buffer, sizeof(print_buffer), message, args); va_end(args); - if(Curl_ftpsendf(conn, print_buffer)) { + if(Curl_ftpsend(conn, print_buffer)) { ftp_code = -1; } else { @@ -192,15 +192,18 @@ static CURLcode read_data(struct connectdata *conn, struct krb5buffer *buf) { int len; - void* tmp; + void *tmp = NULL; CURLcode result; result = socket_read(fd, &len, sizeof(len)); if(result) return result; - len = ntohl(len); - tmp = realloc(buf->data, len); + if(len) { + /* only realloc if there was a length */ + len = ntohl(len); + tmp = realloc(buf->data, len); + } if(tmp == NULL) return CURLE_OUT_OF_MEMORY; diff --git a/Utilities/cmcurl/lib/select.c b/Utilities/cmcurl/lib/select.c index 2002349..d5caa70 100644 --- a/Utilities/cmcurl/lib/select.c +++ b/Utilities/cmcurl/lib/select.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2016, 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 @@ -51,15 +51,14 @@ #include "warnless.h" /* Convenience local macros */ - -#define elapsed_ms (int)curlx_tvdiff(curlx_tvnow(), initial_tv) +#define ELAPSED_MS() (int)curlx_tvdiff(curlx_tvnow(), initial_tv) int Curl_ack_eintr = 0; -#define error_not_EINTR (Curl_ack_eintr || error != EINTR) +#define ERROR_NOT_EINTR(error) (Curl_ack_eintr || error != EINTR) /* * Internal function used for waiting a specific amount of ms - * in Curl_socket_ready() and Curl_poll() when no file descriptor + * 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. @@ -109,9 +108,9 @@ int Curl_wait_ms(int timeout_ms) if(r != -1) break; error = SOCKERRNO; - if(error && error_not_EINTR) + if(error && ERROR_NOT_EINTR(error)) break; - pending_ms = timeout_ms - elapsed_ms; + pending_ms = timeout_ms - ELAPSED_MS(); if(pending_ms <= 0) { r = 0; /* Simulate a "call timed out" case */ break; @@ -165,6 +164,12 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ int r; int ret; +#if SIZEOF_LONG != SIZEOF_INT + /* wrap-around precaution */ + if(timeout_ms >= INT_MAX) + timeout_ms = INT_MAX; +#endif + if((readfd0 == CURL_SOCKET_BAD) && (readfd1 == CURL_SOCKET_BAD) && (writefd == CURL_SOCKET_BAD)) { /* no sockets, just wait */ @@ -213,10 +218,10 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ if(r != -1) break; error = SOCKERRNO; - if(error && error_not_EINTR) + if(error && ERROR_NOT_EINTR(error)) break; if(timeout_ms > 0) { - pending_ms = (int)(timeout_ms - elapsed_ms); + pending_ms = (int)(timeout_ms - ELAPSED_MS()); if(pending_ms <= 0) { r = 0; /* Simulate a "call timed out" case */ break; @@ -328,10 +333,10 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ if(r != -1) break; error = SOCKERRNO; - if(error && error_not_EINTR) + if(error && ERROR_NOT_EINTR(error)) break; if(timeout_ms > 0) { - pending_ms = timeout_ms - elapsed_ms; + pending_ms = (int)(timeout_ms - ELAPSED_MS()); if(pending_ms <= 0) { r = 0; /* Simulate a "call timed out" case */ break; @@ -434,10 +439,10 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) if(r != -1) break; error = SOCKERRNO; - if(error && error_not_EINTR) + if(error && ERROR_NOT_EINTR(error)) break; if(timeout_ms > 0) { - pending_ms = timeout_ms - elapsed_ms; + pending_ms = (int)(timeout_ms - ELAPSED_MS()); if(pending_ms <= 0) { r = 0; /* Simulate a "call timed out" case */ break; @@ -521,10 +526,10 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) if(r != -1) break; error = SOCKERRNO; - if(error && error_not_EINTR) + if(error && ERROR_NOT_EINTR(error)) break; if(timeout_ms > 0) { - pending_ms = timeout_ms - elapsed_ms; + pending_ms = timeout_ms - ELAPSED_MS(); if(pending_ms <= 0) { r = 0; /* Simulate a "call timed out" case */ break; diff --git a/Utilities/cmcurl/lib/select.h b/Utilities/cmcurl/lib/select.h index 695bb69..1d26f49 100644 --- a/Utilities/cmcurl/lib/select.h +++ b/Utilities/cmcurl/lib/select.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2016, 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 @@ -75,9 +75,10 @@ int Curl_socket_check(curl_socket_t readfd, curl_socket_t readfd2, curl_socket_t writefd, long timeout_ms); -/* provide the former API internally */ -#define Curl_socket_ready(x,y,z) \ - Curl_socket_check(x, CURL_SOCKET_BAD, y, z) +#define SOCKET_READABLE(x,z) \ + Curl_socket_check(x, CURL_SOCKET_BAD, CURL_SOCKET_BAD, z) +#define SOCKET_WRITABLE(x,z) \ + Curl_socket_check(CURL_SOCKET_BAD, CURL_SOCKET_BAD, x, z) int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms); diff --git a/Utilities/cmcurl/lib/smb.c b/Utilities/cmcurl/lib/smb.c index 56a38c2..7cb0c96 100644 --- a/Utilities/cmcurl/lib/smb.c +++ b/Utilities/cmcurl/lib/smb.c @@ -673,7 +673,7 @@ static CURLcode smb_connection_state(struct connectdata *conn, bool *done) switch(smbc->state) { case SMB_NEGOTIATE: - if(h->status) { + if(h->status || smbc->got < sizeof(*nrsp) + sizeof(smbc->challenge) - 1) { connclose(conn, "SMB: negotiation failed"); return CURLE_COULDNT_CONNECT; } @@ -712,6 +712,7 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done) { struct smb_request *req = conn->data->req.protop; struct smb_header *h; + struct smb_conn *smbc = &conn->proto.smbc; enum smb_req_state next_state = SMB_DONE; unsigned short len; unsigned short off; @@ -754,7 +755,7 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done) break; case SMB_OPEN: - if(h->status) { + if(h->status || smbc->got < sizeof(struct smb_nt_create_response)) { req->result = CURLE_REMOTE_FILE_NOT_FOUND; next_state = SMB_TREE_DISCONNECT; break; @@ -775,7 +776,7 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done) break; case SMB_DOWNLOAD: - if(h->status) { + if(h->status || smbc->got < sizeof(struct smb_header) + 14) { req->result = CURLE_RECV_ERROR; next_state = SMB_CLOSE; break; @@ -785,7 +786,6 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done) off = Curl_read16_le(((unsigned char *) msg) + sizeof(struct smb_header) + 13); if(len > 0) { - struct smb_conn *smbc = &conn->proto.smbc; if(off + sizeof(unsigned int) + len > smbc->got) { failf(conn->data, "Invalid input packet"); result = CURLE_RECV_ERROR; @@ -807,7 +807,7 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done) break; case SMB_UPLOAD: - if(h->status) { + if(h->status || smbc->got < sizeof(struct smb_header) + 6) { req->result = CURLE_UPLOAD_FAILED; next_state = SMB_CLOSE; break; diff --git a/Utilities/cmcurl/lib/smtp.c b/Utilities/cmcurl/lib/smtp.c index d203b53..a4fc2c2 100644 --- a/Utilities/cmcurl/lib/smtp.c +++ b/Utilities/cmcurl/lib/smtp.c @@ -69,16 +69,14 @@ #include "http.h" /* for HTTP proxy tunnel stuff */ #include "socks.h" #include "smtp.h" - #include "strtoofft.h" -#include "strequal.h" +#include "strcase.h" #include "vtls/vtls.h" #include "connect.h" #include "strerror.h" #include "select.h" #include "multiif.h" #include "url.h" -#include "rawstr.h" #include "curl_gethostname.h" #include "curl_sasl.h" #include "warnless.h" @@ -674,7 +672,7 @@ static CURLcode smtp_state_servergreet_resp(struct connectdata *conn, if(smtpcode/100 != 2) { failf(data, "Got unexpected smtp-server response: %d", smtpcode); - result = CURLE_FTP_WEIRD_SERVER_REPLY; + result = CURLE_WEIRD_SERVER_REPLY; } else result = smtp_perform_ehlo(conn); @@ -1512,7 +1510,7 @@ static CURLcode smtp_parse_url_options(struct connectdata *conn) while(*ptr && *ptr != ';') ptr++; - if(strnequal(key, "AUTH=", 5)) + if(strncasecompare(key, "AUTH=", 5)) result = Curl_sasl_parse_url_auth_option(&smtpc->sasl, value, ptr - value); else diff --git a/Utilities/cmcurl/lib/socks.c b/Utilities/cmcurl/lib/socks.c index fccb16d..742d411 100644 --- a/Utilities/cmcurl/lib/socks.c +++ b/Utilities/cmcurl/lib/socks.c @@ -33,7 +33,6 @@ #include "urldata.h" #include "sendf.h" -#include "strequal.h" #include "select.h" #include "connect.h" #include "timeval.h" @@ -67,7 +66,7 @@ int Curl_blockread_all(struct connectdata *conn, /* connection data */ result = CURLE_OPERATION_TIMEDOUT; break; } - if(Curl_socket_ready(sockfd, CURL_SOCKET_BAD, timeleft) <= 0) { + if(SOCKET_READABLE(sockfd, timeleft) <= 0) { result = ~CURLE_OK; break; } @@ -170,24 +169,26 @@ CURLcode Curl_SOCKS4(const char *proxy_name, hp=dns->addr; if(hp) { char buf[64]; - unsigned short ip[4]; Curl_printable_address(hp, buf, sizeof(buf)); - if(4 == sscanf(buf, "%hu.%hu.%hu.%hu", - &ip[0], &ip[1], &ip[2], &ip[3])) { - /* Set DSTIP */ - socksreq[4] = (unsigned char)ip[0]; - socksreq[5] = (unsigned char)ip[1]; - socksreq[6] = (unsigned char)ip[2]; - socksreq[7] = (unsigned char)ip[3]; + if(hp->ai_family == AF_INET) { + struct sockaddr_in *saddr_in; + + saddr_in = (struct sockaddr_in*)(void*)hp->ai_addr; + socksreq[4] = ((unsigned char*)&saddr_in->sin_addr.s_addr)[0]; + socksreq[5] = ((unsigned char*)&saddr_in->sin_addr.s_addr)[1]; + socksreq[6] = ((unsigned char*)&saddr_in->sin_addr.s_addr)[2]; + socksreq[7] = ((unsigned char*)&saddr_in->sin_addr.s_addr)[3]; + + infof(data, "SOCKS4 connect to IPv4 %s (locally resolved)\n", buf); } - else + else { hp = NULL; /* fail! */ - infof(data, "SOCKS4 connect to %s (locally resolved)\n", buf); + failf(data, "SOCKS4 connection to %s not supported\n", buf); + } Curl_resolv_unlock(data, dns); /* not used anymore from now on */ - } if(!hp) { failf(data, "Failed to resolve \"%s\" for SOCKS4 connect.", @@ -399,7 +400,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, (void)curlx_nonblock(sock, TRUE); /* wait until socket gets connected */ - result = Curl_socket_ready(CURL_SOCKET_BAD, sock, timeout); + result = SOCKET_WRITABLE(sock, timeout); if(-1 == result) { failf(conn->data, "SOCKS5: no connection here"); @@ -429,6 +430,8 @@ CURLcode Curl_SOCKS5(const char *proxy_name, (void)curlx_nonblock(sock, FALSE); + infof(data, "SOCKS5 communication to %s:%d\n", hostname, remote_port); + code = Curl_write_plain(conn, sock, (char *)socksreq, (2 + (int)socksreq[1]), &written); if(code || (written != (2 + (int)socksreq[1]))) { @@ -438,7 +441,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, (void)curlx_nonblock(sock, TRUE); - result = Curl_socket_ready(sock, CURL_SOCKET_BAD, timeout); + result = SOCKET_READABLE(sock, timeout); if(-1 == result) { failf(conn->data, "SOCKS5 nothing to read"); @@ -594,34 +597,40 @@ CURLcode Curl_SOCKS5(const char *proxy_name, if(dns) hp=dns->addr; if(hp) { - struct sockaddr_in *saddr_in; -#ifdef ENABLE_IPV6 - struct sockaddr_in6 *saddr_in6; -#endif int i; + char buf[64]; + Curl_printable_address(hp, buf, sizeof(buf)); if(hp->ai_family == AF_INET) { + struct sockaddr_in *saddr_in; socksreq[len++] = 1; /* ATYP: IPv4 = 1 */ saddr_in = (struct sockaddr_in*)(void*)hp->ai_addr; for(i = 0; i < 4; i++) { socksreq[len++] = ((unsigned char*)&saddr_in->sin_addr.s_addr)[i]; - infof(data, "%d\n", socksreq[len-1]); } + + infof(data, "SOCKS5 connect to IPv4 %s (locally resolved)\n", buf); } #ifdef ENABLE_IPV6 else if(hp->ai_family == AF_INET6) { + struct sockaddr_in6 *saddr_in6; socksreq[len++] = 4; /* ATYP: IPv6 = 4 */ saddr_in6 = (struct sockaddr_in6*)(void*)hp->ai_addr; for(i = 0; i < 16; i++) { socksreq[len++] = ((unsigned char*)&saddr_in6->sin6_addr.s6_addr)[i]; } + + infof(data, "SOCKS5 connect to IPv6 %s (locally resolved)\n", buf); } #endif - else + else { hp = NULL; /* fail! */ + failf(data, "SOCKS5 connection to %s not supported\n", buf); + } + Curl_resolv_unlock(data, dns); /* not used anymore from now on */ } if(!hp) { @@ -668,39 +677,6 @@ CURLcode Curl_SOCKS5(const char *proxy_name, "SOCKS5 reply has wrong version, version should be 5."); return CURLE_COULDNT_CONNECT; } - if(socksreq[1] != 0) { /* Anything besides 0 is an error */ - if(socksreq[3] == 1) { - failf(data, - "Can't complete SOCKS5 connection to %d.%d.%d.%d:%d. (%d)", - (unsigned char)socksreq[4], (unsigned char)socksreq[5], - (unsigned char)socksreq[6], (unsigned char)socksreq[7], - (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]), - (unsigned char)socksreq[1]); - } - else if(socksreq[3] == 3) { - failf(data, - "Can't complete SOCKS5 connection to %s:%d. (%d)", - hostname, - (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]), - (unsigned char)socksreq[1]); - } - else if(socksreq[3] == 4) { - failf(data, - "Can't complete SOCKS5 connection to %02x%02x:%02x%02x:" - "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%d. (%d)", - (unsigned char)socksreq[4], (unsigned char)socksreq[5], - (unsigned char)socksreq[6], (unsigned char)socksreq[7], - (unsigned char)socksreq[8], (unsigned char)socksreq[9], - (unsigned char)socksreq[10], (unsigned char)socksreq[11], - (unsigned char)socksreq[12], (unsigned char)socksreq[13], - (unsigned char)socksreq[14], (unsigned char)socksreq[15], - (unsigned char)socksreq[16], (unsigned char)socksreq[17], - (unsigned char)socksreq[18], (unsigned char)socksreq[19], - (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]), - (unsigned char)socksreq[1]); - } - return CURLE_COULDNT_CONNECT; - } /* Fix: in general, returned BND.ADDR is variable length parameter by RFC 1928, so the reply packet should be read until the end to avoid errors at @@ -735,10 +711,9 @@ CURLcode Curl_SOCKS5(const char *proxy_name, /* decrypt_gssapi_blockread already read the whole packet */ #endif if(len > 10) { - len -= 10; result = Curl_blockread_all(conn, sock, (char *)&socksreq[10], - len, &actualread); - if(result || (len != actualread)) { + len - 10, &actualread); + if(result || ((len - 10) != actualread)) { failf(data, "Failed to receive SOCKS5 connect request ack."); return CURLE_COULDNT_CONNECT; } @@ -747,6 +722,49 @@ CURLcode Curl_SOCKS5(const char *proxy_name, } #endif + if(socksreq[1] != 0) { /* Anything besides 0 is an error */ + if(socksreq[3] == 1) { + failf(data, + "Can't complete SOCKS5 connection to %d.%d.%d.%d:%d. (%d)", + (unsigned char)socksreq[4], (unsigned char)socksreq[5], + (unsigned char)socksreq[6], (unsigned char)socksreq[7], + (((unsigned char)socksreq[8] << 8) | + (unsigned char)socksreq[9]), + (unsigned char)socksreq[1]); + } + else if(socksreq[3] == 3) { + unsigned char port_upper = (unsigned char)socksreq[len - 2]; + socksreq[len - 2] = 0; + failf(data, + "Can't complete SOCKS5 connection to %s:%d. (%d)", + (char *)&socksreq[5], + ((port_upper << 8) | + (unsigned char)socksreq[len - 1]), + (unsigned char)socksreq[1]); + socksreq[len - 2] = port_upper; + } + else if(socksreq[3] == 4) { + failf(data, + "Can't complete SOCKS5 connection to %02x%02x:%02x%02x:" + "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%d. (%d)", + (unsigned char)socksreq[4], (unsigned char)socksreq[5], + (unsigned char)socksreq[6], (unsigned char)socksreq[7], + (unsigned char)socksreq[8], (unsigned char)socksreq[9], + (unsigned char)socksreq[10], (unsigned char)socksreq[11], + (unsigned char)socksreq[12], (unsigned char)socksreq[13], + (unsigned char)socksreq[14], (unsigned char)socksreq[15], + (unsigned char)socksreq[16], (unsigned char)socksreq[17], + (unsigned char)socksreq[18], (unsigned char)socksreq[19], + (((unsigned char)socksreq[20] << 8) | + (unsigned char)socksreq[21]), + (unsigned char)socksreq[1]); + } + return CURLE_COULDNT_CONNECT; + } + else { + infof(data, "SOCKS5 request granted.\n"); + } + (void)curlx_nonblock(sock, TRUE); return CURLE_OK; /* Proxy was successful! */ } diff --git a/Utilities/cmcurl/lib/ssh.c b/Utilities/cmcurl/lib/ssh.c index 7bc3136..43c8283 100644 --- a/Utilities/cmcurl/lib/ssh.c +++ b/Utilities/cmcurl/lib/ssh.c @@ -72,7 +72,7 @@ #include "speedcheck.h" #include "getinfo.h" -#include "strequal.h" +#include "strcase.h" #include "vtls/vtls.h" #include "connect.h" #include "strerror.h" @@ -416,12 +416,12 @@ static CURLcode ssh_getworkingpath(struct connectdata *conn, struct Curl_easy *data = conn->data; char *real_path = NULL; char *working_path; - int working_path_len; - - working_path = curl_easy_unescape(data, data->state.path, 0, - &working_path_len); - if(!working_path) - return CURLE_OUT_OF_MEMORY; + size_t working_path_len; + CURLcode result = + Curl_urldecode(data, data->state.path, 0, &working_path, + &working_path_len, FALSE); + if(result) + return result; /* Check for /~/, indicating relative to the user's home directory */ if(conn->handler->protocol & CURLPROTO_SCP) { @@ -676,7 +676,7 @@ static CURLcode ssh_check_fingerprint(struct connectdata *conn) * against a known fingerprint, if available. */ if(pubkey_md5 && strlen(pubkey_md5) == 32) { - if(!fingerprint || !strequal(md5buffer, pubkey_md5)) { + if(!fingerprint || strcmp(md5buffer, pubkey_md5)) { if(fingerprint) failf(data, "Denied establishing ssh session: mismatch md5 fingerprint. " @@ -1233,7 +1233,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) sshc->acceptfail = TRUE; } - if(curl_strequal("pwd", cmd)) { + if(strcasecompare("pwd", cmd)) { /* output debug output if that is requested */ char *tmp = aprintf("257 \"%s\" is current directory.\n", sftp_scp->path); @@ -1297,9 +1297,9 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) * OpenSSH's sftp program and call the appropriate libssh2 * functions. */ - if(curl_strnequal(cmd, "chgrp ", 6) || - curl_strnequal(cmd, "chmod ", 6) || - curl_strnequal(cmd, "chown ", 6) ) { + if(strncasecompare(cmd, "chgrp ", 6) || + strncasecompare(cmd, "chmod ", 6) || + strncasecompare(cmd, "chown ", 6) ) { /* attribute change */ /* sshc->quote_path1 contains the mode to set */ @@ -1321,8 +1321,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) state(conn, SSH_SFTP_QUOTE_STAT); break; } - else if(curl_strnequal(cmd, "ln ", 3) || - curl_strnequal(cmd, "symlink ", 8)) { + else if(strncasecompare(cmd, "ln ", 3) || + strncasecompare(cmd, "symlink ", 8)) { /* symbolic linking */ /* sshc->quote_path1 is the source */ /* get the destination */ @@ -1342,12 +1342,12 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) state(conn, SSH_SFTP_QUOTE_SYMLINK); break; } - else if(curl_strnequal(cmd, "mkdir ", 6)) { + else if(strncasecompare(cmd, "mkdir ", 6)) { /* create dir */ state(conn, SSH_SFTP_QUOTE_MKDIR); break; } - else if(curl_strnequal(cmd, "rename ", 7)) { + else if(strncasecompare(cmd, "rename ", 7)) { /* rename file */ /* first param is the source path */ /* second param is the dest. path */ @@ -1366,17 +1366,17 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) state(conn, SSH_SFTP_QUOTE_RENAME); break; } - else if(curl_strnequal(cmd, "rmdir ", 6)) { + else if(strncasecompare(cmd, "rmdir ", 6)) { /* delete dir */ state(conn, SSH_SFTP_QUOTE_RMDIR); break; } - else if(curl_strnequal(cmd, "rm ", 3)) { + else if(strncasecompare(cmd, "rm ", 3)) { state(conn, SSH_SFTP_QUOTE_UNLINK); break; } #ifdef HAS_STATVFS_SUPPORT - else if(curl_strnequal(cmd, "statvfs ", 8)) { + else if(strncasecompare(cmd, "statvfs ", 8)) { state(conn, SSH_SFTP_QUOTE_STATVFS); break; } @@ -1431,7 +1431,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) sshc->acceptfail = TRUE; } - if(!curl_strnequal(cmd, "chmod", 5)) { + if(!strncasecompare(cmd, "chmod", 5)) { /* Since chown and chgrp only set owner OR group but libssh2 wants to * set them both at once, we need to obtain the current ownership * first. This takes an extra protocol round trip. @@ -1457,7 +1457,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) } /* Now set the new attributes... */ - if(curl_strnequal(cmd, "chgrp", 5)) { + if(strncasecompare(cmd, "chgrp", 5)) { sshc->quote_attrs.gid = strtoul(sshc->quote_path1, NULL, 10); sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID; if(sshc->quote_attrs.gid == 0 && !ISDIGIT(sshc->quote_path1[0]) && @@ -1471,7 +1471,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) break; } } - else if(curl_strnequal(cmd, "chmod", 5)) { + else if(strncasecompare(cmd, "chmod", 5)) { sshc->quote_attrs.permissions = strtoul(sshc->quote_path1, NULL, 8); sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS; /* permissions are octal */ @@ -1486,7 +1486,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) break; } } - else if(curl_strnequal(cmd, "chown", 5)) { + else if(strncasecompare(cmd, "chown", 5)) { sshc->quote_attrs.uid = strtoul(sshc->quote_path1, NULL, 10); sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID; if(sshc->quote_attrs.uid == 0 && !ISDIGIT(sshc->quote_path1[0]) && @@ -1895,7 +1895,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) /* since we don't really wait for anything at this point, we want the state machine to move on as soon as possible so we set a very short timeout here */ - Curl_expire(data, 1); + Curl_expire(data, 0); state(conn, SSH_STOP); } @@ -2860,7 +2860,7 @@ static CURLcode ssh_block_statemach(struct connectdata *conn, if(LIBSSH2_SESSION_BLOCK_OUTBOUND & dir) fd_write = sock; /* wait for the socket to become ready */ - Curl_socket_ready(fd_read, fd_write, + Curl_socket_check(fd_read, CURL_SOCKET_BAD, fd_write, left>1000?1000:left); /* ignore result */ } #endif @@ -3109,7 +3109,6 @@ static CURLcode scp_done(struct connectdata *conn, CURLcode status, } -/* return number of received (decrypted) bytes */ static ssize_t scp_send(struct connectdata *conn, int sockindex, const void *mem, size_t len, CURLcode *err) { @@ -3134,10 +3133,6 @@ static ssize_t scp_send(struct connectdata *conn, int sockindex, return nwrite; } -/* - * If the read would block (EWOULDBLOCK) we return -1. Otherwise we return - * a regular CURLcode value. - */ static ssize_t scp_recv(struct connectdata *conn, int sockindex, char *mem, size_t len, CURLcode *err) { diff --git a/Utilities/cmcurl/lib/rawstr.c b/Utilities/cmcurl/lib/strcase.c index 5665ebd..807689e 100644 --- a/Utilities/cmcurl/lib/rawstr.c +++ b/Utilities/cmcurl/lib/strcase.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2016, 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 @@ -22,7 +22,9 @@ #include "curl_setup.h" -#include "rawstr.h" +#include <curl/curl.h> + +#include "strcase.h" /* Portable, consistent toupper (remember EBCDIC). Do not use toupper() because its behavior is altered by the current locale. */ @@ -99,9 +101,11 @@ char Curl_raw_toupper(char in) * * The function is capable of comparing a-z case insensitively even for * non-ascii. + * + * @unittest: 1301 */ -int Curl_raw_equal(const char *first, const char *second) +int Curl_strcasecompare(const char *first, const char *second) { while(*first && *second) { if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second)) @@ -116,7 +120,10 @@ int Curl_raw_equal(const char *first, const char *second) return (Curl_raw_toupper(*first) == Curl_raw_toupper(*second)); } -int Curl_raw_nequal(const char *first, const char *second, size_t max) +/* + * @unittest: 1301 + */ +int Curl_strncasecompare(const char *first, const char *second, size_t max) { while(*first && *second && max) { if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second)) { @@ -146,3 +153,14 @@ void Curl_strntoupper(char *dest, const char *src, size_t n) *dest++ = Curl_raw_toupper(*src); } while(*src++ && --n); } + +/* --- public functions --- */ + +int curl_strequal(const char *first, const char *second) +{ + return Curl_strcasecompare(first, second); +} +int curl_strnequal(const char *first, const char *second, size_t max) +{ + return Curl_strncasecompare(first, second, max); +} diff --git a/Utilities/cmcurl/lib/rawstr.h b/Utilities/cmcurl/lib/strcase.h index 4af00f1..bf057b1 100644 --- a/Utilities/cmcurl/lib/rawstr.h +++ b/Utilities/cmcurl/lib/strcase.h @@ -1,5 +1,5 @@ -#ifndef HEADER_CURL_RAWSTR_H -#define HEADER_CURL_RAWSTR_H +#ifndef HEADER_CURL_STRCASE_H +#define HEADER_CURL_STRCASE_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2016, 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 @@ -25,23 +25,26 @@ #include <curl/curl.h> /* - * Curl_raw_equal() is for doing "raw" case insensitive strings. This is meant - * to be locale independent and only compare strings we know are safe for - * this. + * Only "raw" case insensitive strings. This is meant to be locale independent + * and only compare strings we know are safe for this. * * The function is capable of comparing a-z case insensitively even for * non-ascii. */ -int Curl_raw_equal(const char *first, const char *second); -int Curl_raw_nequal(const char *first, const char *second, size_t max); + +#define strcasecompare(a,b) Curl_strcasecompare(a,b) +#define strncasecompare(a,b,c) Curl_strncasecompare(a,b,c) + +int Curl_strcasecompare(const char *first, const char *second); +int Curl_strncasecompare(const char *first, const char *second, size_t max); char Curl_raw_toupper(char in); /* checkprefix() is a shorter version of the above, used when the first argument is zero-byte terminated */ -#define checkprefix(a,b) Curl_raw_nequal(a,b,strlen(a)) +#define checkprefix(a,b) curl_strnequal(a,b,strlen(a)) void Curl_strntoupper(char *dest, const char *src, size_t n); +char Curl_raw_toupper(char in); -#endif /* HEADER_CURL_RAWSTR_H */ - +#endif /* HEADER_CURL_STRCASE_H */ diff --git a/Utilities/cmcurl/lib/strdup.c b/Utilities/cmcurl/lib/strdup.c index 23f554e..5a15c2b 100644 --- a/Utilities/cmcurl/lib/strdup.c +++ b/Utilities/cmcurl/lib/strdup.c @@ -65,9 +65,9 @@ char *curlx_strdup(const char *str) * Returns the new pointer or NULL on failure. * ***************************************************************************/ -char *Curl_memdup(const char *src, size_t length) +void *Curl_memdup(const void *src, size_t length) { - char *buffer = malloc(length); + void *buffer = malloc(length); if(!buffer) return NULL; /* fail */ diff --git a/Utilities/cmcurl/lib/strdup.h b/Utilities/cmcurl/lib/strdup.h index 4c48ca4..c74a3b7 100644 --- a/Utilities/cmcurl/lib/strdup.h +++ b/Utilities/cmcurl/lib/strdup.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2016, 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 @@ -26,6 +26,6 @@ #ifndef HAVE_STRDUP extern char *curlx_strdup(const char *str); #endif -char *Curl_memdup(const char *src, size_t buffer_length); +void *Curl_memdup(const void *src, size_t buffer_length); #endif /* HEADER_CURL_STRDUP_H */ diff --git a/Utilities/cmcurl/lib/strequal.c b/Utilities/cmcurl/lib/strequal.c deleted file mode 100644 index 01c3784..0000000 --- a/Utilities/cmcurl/lib/strequal.c +++ /dev/null @@ -1,79 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2013, 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.haxx.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. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef HAVE_STRINGS_H -#include <strings.h> -#endif - -#include "strequal.h" - -/* - * @unittest: 1301 - */ -int curl_strequal(const char *first, const char *second) -{ -#if defined(HAVE_STRCASECMP) - return !(strcasecmp)(first, second); -#elif defined(HAVE_STRCMPI) - return !(strcmpi)(first, second); -#elif defined(HAVE_STRICMP) - return !(stricmp)(first, second); -#else - while(*first && *second) { - if(toupper(*first) != toupper(*second)) { - break; - } - first++; - second++; - } - return toupper(*first) == toupper(*second); -#endif -} - -/* - * @unittest: 1301 - */ -int curl_strnequal(const char *first, const char *second, size_t max) -{ -#if defined(HAVE_STRNCASECMP) - return !strncasecmp(first, second, max); -#elif defined(HAVE_STRNCMPI) - return !strncmpi(first, second, max); -#elif defined(HAVE_STRNICMP) - return !strnicmp(first, second, max); -#else - while(*first && *second && max) { - if(toupper(*first) != toupper(*second)) { - break; - } - max--; - first++; - second++; - } - if(0 == max) - return 1; /* they are equal this far */ - - return toupper(*first) == toupper(*second); -#endif -} diff --git a/Utilities/cmcurl/lib/strequal.h b/Utilities/cmcurl/lib/strequal.h deleted file mode 100644 index ff56df5..0000000 --- a/Utilities/cmcurl/lib/strequal.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef HEADER_CURL_STREQUAL_H -#define HEADER_CURL_STREQUAL_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2013, 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.haxx.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. - * - ***************************************************************************/ - -#include <curl/curl.h> - -#define strequal(a,b) curl_strequal(a,b) -#define strnequal(a,b,c) curl_strnequal(a,b,c) - -#endif /* HEADER_CURL_STREQUAL_H */ - diff --git a/Utilities/cmcurl/lib/strerror.c b/Utilities/cmcurl/lib/strerror.c index 0e268d5..db50c7d 100644 --- a/Utilities/cmcurl/lib/strerror.c +++ b/Utilities/cmcurl/lib/strerror.c @@ -35,8 +35,8 @@ #include <curl/curl.h> -#ifdef USE_LIBIDN -#include <idna.h> +#ifdef USE_LIBIDN2 +#include <idn2.h> #endif #ifdef USE_WINDOWS_SSPI @@ -79,8 +79,8 @@ curl_easy_strerror(CURLcode error) case CURLE_COULDNT_CONNECT: return "Couldn't connect to server"; - case CURLE_FTP_WEIRD_SERVER_REPLY: - return "FTP: weird server reply"; + case CURLE_WEIRD_SERVER_REPLY: + return "Weird server reply"; case CURLE_REMOTE_ACCESS_DENIED: return "Access denied to remote resource"; @@ -427,7 +427,7 @@ curl_share_strerror(CURLSHcode error) #ifdef USE_WINSOCK -/* This function handles most / all (?) Winsock errors cURL is able to produce. +/* This function handles most / all (?) Winsock errors curl is able to produce. */ static const char * get_winsock_error (int err, char *buf, size_t len) @@ -726,83 +726,6 @@ const char *Curl_strerror(struct connectdata *conn, int err) return buf; } -#ifdef USE_LIBIDN -/* - * Return error-string for libidn status as returned from idna_to_ascii_lz(). - */ -const char *Curl_idn_strerror (struct connectdata *conn, int err) -{ -#ifdef HAVE_IDNA_STRERROR - (void)conn; - return idna_strerror((Idna_rc) err); -#else - const char *str; - char *buf; - size_t max; - - DEBUGASSERT(conn); - - buf = conn->syserr_buf; - max = sizeof(conn->syserr_buf)-1; - *buf = '\0'; - -#ifndef CURL_DISABLE_VERBOSE_STRINGS - switch ((Idna_rc)err) { - case IDNA_SUCCESS: - str = "No error"; - break; - case IDNA_STRINGPREP_ERROR: - str = "Error in string preparation"; - break; - case IDNA_PUNYCODE_ERROR: - str = "Error in Punycode operation"; - break; - case IDNA_CONTAINS_NON_LDH: - str = "Illegal ASCII characters"; - break; - case IDNA_CONTAINS_MINUS: - str = "Contains minus"; - break; - case IDNA_INVALID_LENGTH: - str = "Invalid output length"; - break; - case IDNA_NO_ACE_PREFIX: - str = "No ACE prefix (\"xn--\")"; - break; - case IDNA_ROUNDTRIP_VERIFY_ERROR: - str = "Round trip verify error"; - break; - case IDNA_CONTAINS_ACE_PREFIX: - str = "Already have ACE prefix (\"xn--\")"; - break; - case IDNA_ICONV_ERROR: - str = "Locale conversion failed"; - break; - case IDNA_MALLOC_ERROR: - str = "Allocation failed"; - break; - case IDNA_DLOPEN_ERROR: - str = "dlopen() error"; - break; - default: - snprintf(buf, max, "error %d", err); - str = NULL; - break; - } -#else - if((Idna_rc)err == IDNA_SUCCESS) - str = "No error"; - else - str = "Error"; -#endif - if(str) - strncpy(buf, str, max); - buf[max] = '\0'; - return (buf); -#endif -} -#endif /* USE_LIBIDN */ - #ifdef USE_WINDOWS_SSPI const char *Curl_sspi_strerror (struct connectdata *conn, int err) { diff --git a/Utilities/cmcurl/lib/strerror.h b/Utilities/cmcurl/lib/strerror.h index ae8c96b..627273e 100644 --- a/Utilities/cmcurl/lib/strerror.h +++ b/Utilities/cmcurl/lib/strerror.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2016, 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 @@ -26,7 +26,7 @@ const char *Curl_strerror (struct connectdata *conn, int err); -#ifdef USE_LIBIDN +#ifdef USE_LIBIDN2 const char *Curl_idn_strerror (struct connectdata *conn, int err); #endif diff --git a/Utilities/cmcurl/lib/system_win32.c b/Utilities/cmcurl/lib/system_win32.c index d6a998b..7873759 100644 --- a/Utilities/cmcurl/lib/system_win32.c +++ b/Utilities/cmcurl/lib/system_win32.c @@ -83,7 +83,39 @@ bool Curl_verify_windows_version(const unsigned int majorVersion, { bool matched = FALSE; -#if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_WIN2K) || \ +#if defined(CURL_WINDOWS_APP) + /* We have no way to determine the Windows version from Windows apps, + so let's assume we're running on the target Windows version. */ + const WORD fullVersion = MAKEWORD(minorVersion, majorVersion); + const WORD targetVersion = (WORD)_WIN32_WINNT; + + switch(condition) { + case VERSION_LESS_THAN: + matched = targetVersion < fullVersion; + break; + + case VERSION_LESS_THAN_EQUAL: + matched = targetVersion <= fullVersion; + break; + + case VERSION_EQUAL: + matched = targetVersion == fullVersion; + break; + + case VERSION_GREATER_THAN_EQUAL: + matched = targetVersion >= fullVersion; + break; + + case VERSION_GREATER_THAN: + matched = targetVersion > fullVersion; + break; + } + + if(matched && (platform == PLATFORM_WINDOWS)) { + /* we're always running on PLATFORM_WINNT */ + matched = FALSE; + } +#elif !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_WIN2K) || \ (_WIN32_WINNT < _WIN32_WINNT_WIN2K) OSVERSIONINFO osver; @@ -128,7 +160,7 @@ bool Curl_verify_windows_version(const unsigned int majorVersion, } /* Verify the platform identifier (if necessary) */ - if(matched && platform != PLATFORM_DONT_CARE) { + if(matched) { switch(platform) { case PLATFORM_WINDOWS: if(osver.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS) @@ -138,6 +170,9 @@ bool Curl_verify_windows_version(const unsigned int majorVersion, case PLATFORM_WINNT: if(osver.dwPlatformId != VER_PLATFORM_WIN32_NT) matched = FALSE; + + default: /* like platform == PLATFORM_DONT_CARE */ + break; } } } diff --git a/Utilities/cmcurl/lib/telnet.c b/Utilities/cmcurl/lib/telnet.c index cc705cf..c37242d 100644 --- a/Utilities/cmcurl/lib/telnet.c +++ b/Utilities/cmcurl/lib/telnet.c @@ -58,8 +58,7 @@ #include "arpa_telnet.h" #include "select.h" -#include "strequal.h" -#include "rawstr.h" +#include "strcase.h" #include "warnless.h" /* The last 3 #include files should be in this order */ @@ -846,7 +845,7 @@ static CURLcode check_telnet_options(struct connectdata *conn) option_keyword, option_arg) == 2) { /* Terminal type */ - if(Curl_raw_equal(option_keyword, "TTYPE")) { + if(strcasecompare(option_keyword, "TTYPE")) { strncpy(tn->subopt_ttype, option_arg, 31); tn->subopt_ttype[31] = 0; /* String termination */ tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES; @@ -854,7 +853,7 @@ static CURLcode check_telnet_options(struct connectdata *conn) } /* Display variable */ - if(Curl_raw_equal(option_keyword, "XDISPLOC")) { + if(strcasecompare(option_keyword, "XDISPLOC")) { strncpy(tn->subopt_xdisploc, option_arg, 127); tn->subopt_xdisploc[127] = 0; /* String termination */ tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES; @@ -862,7 +861,7 @@ static CURLcode check_telnet_options(struct connectdata *conn) } /* Environment variable */ - if(Curl_raw_equal(option_keyword, "NEW_ENV")) { + if(strcasecompare(option_keyword, "NEW_ENV")) { beg = curl_slist_append(tn->telnet_vars, option_arg); if(!beg) { result = CURLE_OUT_OF_MEMORY; @@ -874,7 +873,7 @@ static CURLcode check_telnet_options(struct connectdata *conn) } /* Window Size */ - if(Curl_raw_equal(option_keyword, "WS")) { + if(strcasecompare(option_keyword, "WS")) { if(sscanf(option_arg, "%hu%*[xX]%hu", &tn->subopt_wsx, &tn->subopt_wsy) == 2) tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES; @@ -887,7 +886,7 @@ static CURLcode check_telnet_options(struct connectdata *conn) } /* To take care or not of the 8th bit in data exchange */ - if(Curl_raw_equal(option_keyword, "BINARY")) { + if(strcasecompare(option_keyword, "BINARY")) { binary_option=atoi(option_arg); if(binary_option!=1) { tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO; diff --git a/Utilities/cmcurl/lib/tftp.c b/Utilities/cmcurl/lib/tftp.c index d7ff94f..deee394 100644 --- a/Utilities/cmcurl/lib/tftp.c +++ b/Utilities/cmcurl/lib/tftp.c @@ -55,9 +55,10 @@ #include "sockaddr.h" /* required for Curl_sockaddr_storage */ #include "multiif.h" #include "url.h" -#include "rawstr.h" +#include "strcase.h" #include "speedcheck.h" #include "select.h" +#include "escape.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -484,10 +485,10 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) /* As RFC3617 describes the separator slash is not actually part of the file name so we skip the always-present first letter of the path string. */ - filename = curl_easy_unescape(data, &state->conn->data->state.path[1], 0, - NULL); - if(!filename) - return CURLE_OUT_OF_MEMORY; + result = Curl_urldecode(data, &state->conn->data->state.path[1], 0, + &filename, NULL, FALSE); + if(result) + return result; snprintf((char *)state->spacket.data+2, state->blksize, @@ -705,6 +706,7 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) int rblock; CURLcode result = CURLE_OK; struct SingleRequest *k = &data->req; + int cb; /* Bytes currently read */ switch(event) { @@ -762,9 +764,20 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) return CURLE_OK; } - result = Curl_fillreadbuffer(state->conn, state->blksize, &state->sbytes); - if(result) - return result; + /* TFTP considers data block size < 512 bytes as an end of session. So + * in some cases we must wait for additional data to build full (512 bytes) + * data block. + * */ + state->sbytes = 0; + state->conn->data->req.upload_fromhere = (char *)state->spacket.data+4; + do { + result = Curl_fillreadbuffer(state->conn, state->blksize - state->sbytes, + &cb); + if(result) + return result; + state->sbytes += cb; + state->conn->data->req.upload_fromhere += cb; + } while(state->sbytes < state->blksize && cb != 0); sbytes = sendto(state->sockfd, (void *) state->spacket.data, 4 + state->sbytes, SEND_4TH_ARG, @@ -1221,7 +1234,7 @@ static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done) } else { /* no timeouts to handle, check our socket */ - rc = Curl_socket_ready(state->sockfd, CURL_SOCKET_BAD, 0); + rc = SOCKET_READABLE(state->sockfd, 0); if(rc == -1) { /* bail out */ diff --git a/Utilities/cmcurl/lib/transfer.c b/Utilities/cmcurl/lib/transfer.c index f5987fe..6245ee4 100644 --- a/Utilities/cmcurl/lib/transfer.c +++ b/Utilities/cmcurl/lib/transfer.c @@ -21,10 +21,7 @@ ***************************************************************************/ #include "curl_setup.h" - #include "strtoofft.h" -#include "strequal.h" -#include "rawstr.h" #ifdef HAVE_NETINET_IN_H #include <netinet/in.h> @@ -75,6 +72,7 @@ #include "multiif.h" #include "connect.h" #include "non-ascii.h" +#include "http2.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -384,11 +382,15 @@ bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc) * Go ahead and do a read if we have a readable socket or if * the stream was rewound (in which case we have data in a * buffer) + * + * return '*comeback' TRUE if we didn't properly drain the socket so this + * function should get called again without select() or similar in between! */ static CURLcode readwrite_data(struct Curl_easy *data, struct connectdata *conn, struct SingleRequest *k, - int *didwhat, bool *done) + int *didwhat, bool *done, + bool *comeback) { CURLcode result = CURLE_OK; ssize_t nread; /* number of bytes read */ @@ -398,6 +400,7 @@ static CURLcode readwrite_data(struct Curl_easy *data, int maxloops = 100; *done = FALSE; + *comeback = FALSE; /* This is where we loop until we have read everything there is to read or we get a CURLE_AGAIN */ @@ -529,6 +532,13 @@ static CURLcode readwrite_data(struct Curl_easy *data, is non-headers. */ if(k->str && !k->header && (nread > 0 || is_empty_data)) { + if(data->set.opt_no_body) { + /* data arrives although we want none, bail out */ + streamclose(conn, "ignoring body"); + *done = TRUE; + return CURLE_WEIRD_SERVER_REPLY; + } + #ifndef CURL_DISABLE_HTTP if(0 == k->bodywrites && !is_empty_data) { /* These checks are only made the first time we are about to @@ -804,6 +814,12 @@ static CURLcode readwrite_data(struct Curl_easy *data, } while(data_pending(conn) && maxloops--); + if(maxloops <= 0) { + /* we mark it as read-again-please */ + conn->cselect_bits = CURL_CSELECT_IN; + *comeback = TRUE; + } + if(((k->keepon & (KEEP_RECV|KEEP_SEND)) == KEEP_SEND) && conn->bits.close) { /* When we've read the entire thing and the close bit is set, the server @@ -821,6 +837,8 @@ static CURLcode done_sending(struct connectdata *conn, { k->keepon &= ~KEEP_SEND; /* we're done writing */ + Curl_http2_done_sending(conn); + if(conn->bits.rewindaftersend) { CURLcode result = Curl_readrewind(conn); if(result) @@ -1029,10 +1047,14 @@ static CURLcode readwrite_upload(struct Curl_easy *data, /* * Curl_readwrite() is the low-level function to be called when data is to * be read and written to/from the connection. + * + * return '*comeback' TRUE if we didn't properly drain the socket so this + * function should get called again without select() or similar in between! */ CURLcode Curl_readwrite(struct connectdata *conn, struct Curl_easy *data, - bool *done) + bool *done, + bool *comeback) { struct SingleRequest *k = &data->req; CURLcode result; @@ -1064,7 +1086,7 @@ CURLcode Curl_readwrite(struct connectdata *conn, if(!select_res) /* Call for select()/poll() only, if read/write/error status is not known. */ - select_res = Curl_socket_ready(fd_read, fd_write, 0); + select_res = Curl_socket_check(fd_read, CURL_SOCKET_BAD, fd_write, 0); if(select_res == CURL_CSELECT_ERR) { failf(data, "select/poll returned error"); @@ -1077,7 +1099,7 @@ CURLcode Curl_readwrite(struct connectdata *conn, if((k->keepon & KEEP_RECV) && ((select_res & CURL_CSELECT_IN) || conn->bits.stream_was_rewound)) { - result = readwrite_data(data, conn, k, &didwhat, done); + result = readwrite_data(data, conn, k, &didwhat, done, comeback); if(result || *done) return result; } @@ -1249,60 +1271,6 @@ int Curl_single_getsock(const struct connectdata *conn, return bitmap; } -/* - * Determine optimum sleep time based on configured rate, current rate, - * and packet size. - * Returns value in milliseconds. - * - * The basic idea is to adjust the desired rate up/down in this method - * based on whether we are running too slow or too fast. Then, calculate - * how many milliseconds to wait for the next packet to achieve this new - * rate. - */ -long Curl_sleep_time(curl_off_t rate_bps, curl_off_t cur_rate_bps, - int pkt_size) -{ - curl_off_t min_sleep = 0; - curl_off_t rv = 0; - - if(rate_bps == 0) - return 0; - - /* If running faster than about .1% of the desired speed, slow - * us down a bit. Use shift instead of division as the 0.1% - * cutoff is arbitrary anyway. - */ - if(cur_rate_bps > (rate_bps + (rate_bps >> 10))) { - /* running too fast, decrease target rate by 1/64th of rate */ - rate_bps -= rate_bps >> 6; - min_sleep = 1; - } - else if(cur_rate_bps < (rate_bps - (rate_bps >> 10))) { - /* running too slow, increase target rate by 1/64th of rate */ - rate_bps += rate_bps >> 6; - } - - /* Determine number of milliseconds to wait until we do - * the next packet at the adjusted rate. We should wait - * longer when using larger packets, for instance. - */ - rv = ((curl_off_t)(pkt_size * 1000) / rate_bps); - - /* Catch rounding errors and always slow down at least 1ms if - * we are running too fast. - */ - if(rv < min_sleep) - rv = min_sleep; - - /* Bound value to fit in 'long' on 32-bit platform. That's - * plenty long enough anyway! - */ - if(rv > 0x7fffffff) - rv = 0x7fffffff; - - return (long)rv; -} - /* Curl_init_CONNECT() gets called each time the handle switches to CONNECT which means this gets called once for each subsequent redirect etc */ void Curl_init_CONNECT(struct Curl_easy *data) @@ -1875,13 +1843,12 @@ CURLcode Curl_retry_request(struct connectdata *conn, return CURLE_OK; if((data->req.bytecount + data->req.headerbytecount == 0) && - conn->bits.reuse && - !data->set.opt_no_body && - (data->set.rtspreq != RTSPREQ_RECEIVE)) { - /* We got no data, we attempted to re-use a connection and yet we want a - "body". This might happen if the connection was left alive when we were - done using it before, but that was closed when we wanted to read from - it again. Bad luck. Retry the same request on a fresh connect! */ + conn->bits.reuse && + (data->set.rtspreq != RTSPREQ_RECEIVE)) { + /* We didn't get a single byte when we attempted to re-use a + connection. This might happen if the connection was left alive when we + were done using it before, but that was closed when we wanted to use it + again. Bad luck. Retry the same request on a fresh connect! */ infof(conn->data, "Connection died, retrying a fresh connect\n"); *url = strdup(conn->data->change.url); if(!*url) diff --git a/Utilities/cmcurl/lib/transfer.h b/Utilities/cmcurl/lib/transfer.h index 0e253e3..5189672 100644 --- a/Utilities/cmcurl/lib/transfer.h +++ b/Utilities/cmcurl/lib/transfer.h @@ -40,10 +40,9 @@ typedef enum { CURLcode Curl_follow(struct Curl_easy *data, char *newurl, followtype type); - - CURLcode Curl_readwrite(struct connectdata *conn, - struct Curl_easy *data, bool *done); + struct Curl_easy *data, bool *done, + bool *comeback); int Curl_single_getsock(const struct connectdata *conn, curl_socket_t *socks, int numsocks); @@ -65,8 +64,5 @@ Curl_setup_transfer (struct connectdata *data, curl_off_t *writecountp /* return number of bytes written */ ); -long Curl_sleep_time(curl_off_t rate_bps, curl_off_t cur_rate_bps, - int pkt_size); - #endif /* HEADER_CURL_TRANSFER_H */ diff --git a/Utilities/cmcurl/lib/url.c b/Utilities/cmcurl/lib/url.c index e547e5c..b997f41 100644 --- a/Utilities/cmcurl/lib/url.c +++ b/Utilities/cmcurl/lib/url.c @@ -59,24 +59,13 @@ #include <limits.h> #endif -#ifdef USE_LIBIDN -#include <idna.h> -#include <tld.h> -#include <stringprep.h> -#ifdef HAVE_IDN_FREE_H -#include <idn-free.h> -#else -/* prototype from idn-free.h, not provided by libidn 0.4.5's make install! */ -void idn_free (void *ptr); -#endif -#ifndef HAVE_IDN_FREE -/* if idn_free() was not found in this version of libidn use free() instead */ -#define idn_free(x) (free)(x) -#endif +#ifdef USE_LIBIDN2 +#include <idn2.h> + #elif defined(USE_WIN32_IDN) /* prototype for curl_win32_idn_to_ascii() */ bool curl_win32_idn_to_ascii(const char *in, char **out); -#endif /* USE_LIBIDN */ +#endif /* USE_LIBIDN2 */ #include "urldata.h" #include "netrc.h" @@ -88,7 +77,7 @@ bool curl_win32_idn_to_ascii(const char *in, char **out); #include "sendf.h" #include "progress.h" #include "cookie.h" -#include "strequal.h" +#include "strcase.h" #include "strerror.h" #include "escape.h" #include "strtok.h" @@ -100,7 +89,6 @@ bool curl_win32_idn_to_ascii(const char *in, char **out); #include "multiif.h" #include "easyif.h" #include "speedcheck.h" -#include "rawstr.h" #include "warnless.h" #include "non-ascii.h" #include "inet_pton.h" @@ -405,7 +393,7 @@ CURLcode Curl_close(struct Curl_easy *data) if(!data) return CURLE_OK; - Curl_expire(data, 0); /* shut off timers */ + Curl_expire_clear(data); /* shut off timers */ m = data->multi; @@ -602,6 +590,7 @@ CURLcode Curl_init_userdefined(struct UserDefined *set) set->tcp_keepintvl = 60; set->tcp_keepidle = 60; set->tcp_fastopen = FALSE; + set->tcp_nodelay = TRUE; set->ssl_enable_npn = TRUE; set->ssl_enable_alpn = TRUE; @@ -781,6 +770,10 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, */ data->set.http_fail_on_error = (0 != va_arg(param, long)) ? TRUE : FALSE; break; + case CURLOPT_KEEP_SENDING_ON_ERROR: + data->set.http_keep_sending_on_error = (0 != va_arg(param, long)) ? + TRUE : FALSE; + break; case CURLOPT_UPLOAD: case CURLOPT_PUT: /* @@ -1225,23 +1218,23 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, if(argptr == NULL) break; - if(Curl_raw_equal(argptr, "ALL")) { + if(strcasecompare(argptr, "ALL")) { /* clear all cookies */ Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); Curl_cookie_clearall(data->cookies); Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); } - else if(Curl_raw_equal(argptr, "SESS")) { + else if(strcasecompare(argptr, "SESS")) { /* clear session cookies */ Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); Curl_cookie_clearsess(data->cookies); Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); } - else if(Curl_raw_equal(argptr, "FLUSH")) { + else if(strcasecompare(argptr, "FLUSH")) { /* flush cookies to file, takes care of the locking */ Curl_flush_cookies(data, 0); } - else if(Curl_raw_equal(argptr, "RELOAD")) { + else if(strcasecompare(argptr, "RELOAD")) { /* reload cookies from file */ Curl_cookie_loadfiles(data); break; @@ -2614,7 +2607,7 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ break; case CURLOPT_TLSAUTH_TYPE: - if(strnequal((char *)va_arg(param, char *), "SRP", strlen("SRP"))) + if(strncasecompare((char *)va_arg(param, char *), "SRP", strlen("SRP"))) data->set.ssl.authtype = CURL_TLSAUTH_SRP; else data->set.ssl.authtype = CURL_TLSAUTH_NONE; @@ -2829,6 +2822,17 @@ CURLcode Curl_disconnect(struct connectdata *conn, bool dead_connection) return CURLE_OK; } + /* + * If this connection isn't marked to force-close, leave it open if there + * are other users of it + */ + if(!conn->bits.close && + (conn->send_pipe->size + conn->recv_pipe->size)) { + DEBUGF(infof(data, "Curl_disconnect, usecounter: %d\n", + conn->send_pipe->size + conn->recv_pipe->size)); + return CURLE_OK; + } + if(conn->dns_entry != NULL) { Curl_resolv_unlock(data, conn->dns_entry); conn->dns_entry = NULL; @@ -2876,7 +2880,7 @@ static bool SocketIsDead(curl_socket_t sock) int sval; bool ret_val = TRUE; - sval = Curl_socket_ready(sock, CURL_SOCKET_BAD, 0); + sval = SOCKET_READABLE(sock, 0); if(sval == 0) /* timeout */ ret_val = FALSE; @@ -2892,7 +2896,8 @@ static bool IsPipeliningPossible(const struct Curl_easy *handle, const struct connectdata *conn) { /* If a HTTP protocol and pipelining is enabled */ - if(conn->handler->protocol & PROTO_FAMILY_HTTP) { + if((conn->handler->protocol & PROTO_FAMILY_HTTP) && + (!conn->bits.protoconnstart || !conn->bits.close)) { if(Curl_pipeline_wanted(handle->multi, CURLPIPE_HTTP1) && (handle->set.httpversion != CURL_HTTP_VERSION_1_0) && @@ -3267,6 +3272,8 @@ ConnectionExists(struct Curl_easy *data, pipeLen = check->send_pipe->size + check->recv_pipe->size; if(canPipeline) { + if(check->bits.protoconnstart && check->bits.close) + continue; if(!check->bits.multiplex) { /* If not multiplexing, make sure the pipe has only GET requests */ @@ -3341,7 +3348,7 @@ ConnectionExists(struct Curl_easy *data, (needle->proxytype != check->proxytype || needle->bits.httpproxy != check->bits.httpproxy || needle->bits.tunnel_proxy != check->bits.tunnel_proxy || - !Curl_raw_equal(needle->proxy.name, check->proxy.name) || + !strcasecompare(needle->proxy.name, check->proxy.name) || needle->port != check->port)) /* don't mix connections that use different proxies */ continue; @@ -3384,8 +3391,8 @@ ConnectionExists(struct Curl_easy *data, if(!(needle->handler->flags & PROTOPT_CREDSPERREQUEST)) { /* This protocol requires credentials per connection, so verify that we're using the same name and password as well */ - if(!strequal(needle->user, check->user) || - !strequal(needle->passwd, check->passwd)) { + if(strcmp(needle->user, check->user) || + strcmp(needle->passwd, check->passwd)) { /* one of them was different */ continue; } @@ -3396,14 +3403,14 @@ ConnectionExists(struct Curl_easy *data, /* The requested connection does not use a HTTP proxy or it uses SSL or it is a non-SSL protocol tunneled over the same HTTP proxy name and port number */ - if((Curl_raw_equal(needle->handler->scheme, check->handler->scheme) || + if((strcasecompare(needle->handler->scheme, check->handler->scheme) || (get_protocol_family(check->handler->protocol) == needle->handler->protocol && check->tls_upgraded)) && - (!needle->bits.conn_to_host || Curl_raw_equal( + (!needle->bits.conn_to_host || strcasecompare( needle->conn_to_host.name, check->conn_to_host.name)) && (!needle->bits.conn_to_port || needle->conn_to_port == check->conn_to_port) && - Curl_raw_equal(needle->host.name, check->host.name) && + strcasecompare(needle->host.name, check->host.name) && needle->remote_port == check->remote_port) { /* The schemes match or the the protocol family is the same and the previous connection was TLS upgraded, and the hostname and host @@ -3445,8 +3452,8 @@ ConnectionExists(struct Curl_easy *data, possible. (Especially we must not reuse the same connection if partway through a handshake!) */ if(wantNTLMhttp) { - if(!strequal(needle->user, check->user) || - !strequal(needle->passwd, check->passwd)) + if(strcmp(needle->user, check->user) || + strcmp(needle->passwd, check->passwd)) continue; } else if(check->ntlm.state != NTLMSTATE_NONE) { @@ -3460,8 +3467,8 @@ ConnectionExists(struct Curl_easy *data, if(!check->proxyuser || !check->proxypasswd) continue; - if(!strequal(needle->proxyuser, check->proxyuser) || - !strequal(needle->proxypasswd, check->proxypasswd)) + if(strcmp(needle->proxyuser, check->proxyuser) || + strcmp(needle->proxypasswd, check->proxypasswd)) continue; } else if(check->proxyntlm.state != NTLMSTATE_NONE) { @@ -3752,58 +3759,15 @@ static bool is_ASCII_name(const char *hostname) return TRUE; } -#ifdef USE_LIBIDN -/* - * Check if characters in hostname is allowed in Top Level Domain. - */ -static bool tld_check_name(struct Curl_easy *data, - const char *ace_hostname) -{ - size_t err_pos; - char *uc_name = NULL; - int rc; -#ifndef CURL_DISABLE_VERBOSE_STRINGS - const char *tld_errmsg = "<no msg>"; -#else - (void)data; -#endif - - /* Convert (and downcase) ACE-name back into locale's character set */ - rc = idna_to_unicode_lzlz(ace_hostname, &uc_name, 0); - if(rc != IDNA_SUCCESS) - return FALSE; - - /* Warning: err_pos receives "the decoded character offset rather than the - byte position in the string." And as of libidn 1.32 that character offset - is for UTF-8, even if the passed in string is another locale. */ - rc = tld_check_lz(uc_name, &err_pos, NULL); -#ifndef CURL_DISABLE_VERBOSE_STRINGS -#ifdef HAVE_TLD_STRERROR - if(rc != TLD_SUCCESS) - tld_errmsg = tld_strerror((Tld_rc)rc); -#endif - if(rc != TLD_SUCCESS) - infof(data, "WARNING: TLD check for %s failed; %s\n", - uc_name, tld_errmsg); -#endif /* CURL_DISABLE_VERBOSE_STRINGS */ - if(uc_name) - idn_free(uc_name); - if(rc != TLD_SUCCESS) - return FALSE; - - return TRUE; -} -#endif - /* * Perform any necessary IDN conversion of hostname */ -static void fix_hostname(struct Curl_easy *data, - struct connectdata *conn, struct hostname *host) +static void fix_hostname(struct connectdata *conn, struct hostname *host) { size_t len; + struct Curl_easy *data = conn->data; -#ifndef USE_LIBIDN +#ifndef USE_LIBIDN2 (void)data; (void)conn; #elif defined(CURL_DISABLE_VERBOSE_STRINGS) @@ -3821,25 +3785,18 @@ static void fix_hostname(struct Curl_easy *data, /* Check name for non-ASCII and convert hostname to ACE form if we can */ if(!is_ASCII_name(host->name)) { -#ifdef USE_LIBIDN - if(stringprep_check_version(LIBIDN_REQUIRED_VERSION)) { +#ifdef USE_LIBIDN2 + if(idn2_check_version(IDN2_VERSION)) { char *ace_hostname = NULL; - - int rc = idna_to_ascii_lz(host->name, &ace_hostname, 0); - infof(data, "Input domain encoded as `%s'\n", - stringprep_locale_charset()); - if(rc == IDNA_SUCCESS) { - /* tld_check_name() displays a warning if the host name contains - "illegal" characters for this TLD */ - (void)tld_check_name(data, ace_hostname); - - host->encalloc = ace_hostname; + int rc = idn2_lookup_ul((const char *)host->name, &ace_hostname, 0); + if(rc == IDN2_OK) { + host->encalloc = (char *)ace_hostname; /* change the name pointer to point to the encoded hostname */ host->name = host->encalloc; } else infof(data, "Failed to convert %s to ACE; %s\n", host->name, - Curl_idn_strerror(conn, rc)); + idn2_strerror(rc)); } #elif defined(USE_WIN32_IDN) char *ace_hostname = NULL; @@ -3862,9 +3819,9 @@ static void fix_hostname(struct Curl_easy *data, */ static void free_fixed_hostname(struct hostname *host) { -#if defined(USE_LIBIDN) +#if defined(USE_LIBIDN2) if(host->encalloc) { - idn_free(host->encalloc); /* must be freed with idn_free() since this was + idn2_free(host->encalloc); /* must be freed with idn2_free() since this was allocated by libidn */ host->encalloc = NULL; } @@ -4022,7 +3979,7 @@ static CURLcode findprotocol(struct Curl_easy *data, variables based on the URL. Now that the handler may be changed later when the protocol specific setup function is called. */ for(pp = protocols; (p = *pp) != NULL; pp++) { - if(Curl_raw_equal(p->scheme, protostr)) { + if(strcasecompare(p->scheme, protostr)) { /* Protocol found in table. Check if allowed */ if(!(data->set.allowed_protocols & p->protocol)) /* nope, get out */ @@ -4091,7 +4048,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, ************************************************************/ if((2 == sscanf(data->change.url, "%15[^:]:%[^\n]", protobuf, path)) && - Curl_raw_equal(protobuf, "file")) { + strcasecompare(protobuf, "file")) { if(path[0] == '/' && path[1] == '/') { /* Allow omitted hostname (e.g. file:/<path>). This is not strictly * speaking a valid file: URL by RFC 1738, but treating file:/<path> as @@ -4145,7 +4102,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, path[0]=0; rc = sscanf(data->change.url, - "%15[^\n:]:%3[/]%[^\n/?]%[^\n]", + "%15[^\n:]:%3[/]%[^\n/?#]%[^\n]", protobuf, slashbuf, conn->host.name, path); if(2 == rc) { failf(data, "Bad URL"); @@ -4157,7 +4114,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, * The URL was badly formatted, let's try the browser-style _without_ * protocol specified like 'http://'. */ - rc = sscanf(data->change.url, "%[^\n/?]%[^\n]", conn->host.name, path); + rc = sscanf(data->change.url, "%[^\n/?#]%[^\n]", conn->host.name, path); if(1 > rc) { /* * We couldn't even get this format. @@ -4262,10 +4219,10 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, } /* If the URL is malformatted (missing a '/' after hostname before path) we - * insert a slash here. The only letter except '/' we accept to start a path - * is '?'. + * insert a slash here. The only letters except '/' that can start a path is + * '?' and '#' - as controlled by the two sscanf() patterns above. */ - if(path[0] == '?') { + if(path[0] != '/') { /* We need this function to deal with overlapping memory areas. We know that the memory area 'path' points to is 'urllen' bytes big and that is bigger than the path. Use +1 to move the zero byte too. */ @@ -4531,7 +4488,7 @@ static bool check_noproxy(const char* name, const char* no_proxy) char *endptr; if(no_proxy && no_proxy[0]) { - if(Curl_raw_equal("*", no_proxy)) { + if(strcasecompare("*", no_proxy)) { return TRUE; } @@ -4569,7 +4526,7 @@ static bool check_noproxy(const char* name, const char* no_proxy) if((tok_end - tok_start) <= namelen) { /* Match the last part of the name to the domain we are checking. */ const char *checkn = name + namelen - (tok_end - tok_start); - if(Curl_raw_nequal(no_proxy + tok_start, checkn, + if(strncasecompare(no_proxy + tok_start, checkn, tok_end - tok_start)) { if((tok_end - tok_start) == namelen || *(checkn - 1) == '.') { /* We either have an exact match, or the previous character is a . @@ -4648,7 +4605,7 @@ static char *detect_proxy(struct connectdata *conn) * This can cause 'internal' http/ftp requests to be * arbitrarily redirected by any external attacker. */ - if(!prox && !Curl_raw_equal("http_proxy", proxy_env)) { + if(!prox && !strcasecompare("http_proxy", proxy_env)) { /* There was no lowercase variable, try the uppercase version: */ Curl_strntoupper(proxy_env, proxy_env, sizeof(proxy_env)); prox=curl_getenv(proxy_env); @@ -4705,7 +4662,13 @@ static CURLcode parse_proxy(struct Curl_easy *data, conn->proxytype = CURLPROXY_SOCKS4A; else if(checkprefix("socks4", proxy) || checkprefix("socks", proxy)) conn->proxytype = CURLPROXY_SOCKS4; - /* Any other xxx:// : change to http proxy */ + else if(checkprefix("http:", proxy)) + ; /* leave it as HTTP or HTTP/1.0 */ + else { + /* Any other xxx:// reject! */ + failf(data, "Unsupported proxy scheme for \'%s\'", proxy); + return CURLE_COULDNT_CONNECT; + } } else proxyptr = proxy; /* No xxx:// head: It's a HTTP proxy */ @@ -4725,21 +4688,24 @@ static CURLcode parse_proxy(struct Curl_easy *data, them. */ Curl_safefree(conn->proxyuser); if(proxyuser && strlen(proxyuser) < MAX_CURL_USER_LENGTH) - conn->proxyuser = curl_easy_unescape(data, proxyuser, 0, NULL); - else + result = Curl_urldecode(data, proxyuser, 0, &conn->proxyuser, NULL, + FALSE); + else { conn->proxyuser = strdup(""); + if(!conn->proxyuser) + result = CURLE_OUT_OF_MEMORY; + } - if(!conn->proxyuser) - result = CURLE_OUT_OF_MEMORY; - else { + if(!result) { Curl_safefree(conn->proxypasswd); if(proxypasswd && strlen(proxypasswd) < MAX_CURL_PASSWORD_LENGTH) - conn->proxypasswd = curl_easy_unescape(data, proxypasswd, 0, NULL); - else + result = Curl_urldecode(data, proxypasswd, 0, + &conn->proxypasswd, NULL, FALSE); + else { conn->proxypasswd = strdup(""); - - if(!conn->proxypasswd) - result = CURLE_OUT_OF_MEMORY; + if(!conn->proxypasswd) + result = CURLE_OUT_OF_MEMORY; + } } if(!result) { @@ -4846,6 +4812,7 @@ static CURLcode parse_proxy_auth(struct Curl_easy *data, { char proxyuser[MAX_CURL_USER_LENGTH]=""; char proxypasswd[MAX_CURL_PASSWORD_LENGTH]=""; + CURLcode result; if(data->set.str[STRING_PROXYUSERNAME] != NULL) { strncpy(proxyuser, data->set.str[STRING_PROXYUSERNAME], @@ -4858,15 +4825,11 @@ static CURLcode parse_proxy_auth(struct Curl_easy *data, proxypasswd[MAX_CURL_PASSWORD_LENGTH-1] = '\0'; /*To be on safe side*/ } - conn->proxyuser = curl_easy_unescape(data, proxyuser, 0, NULL); - if(!conn->proxyuser) - return CURLE_OUT_OF_MEMORY; - - conn->proxypasswd = curl_easy_unescape(data, proxypasswd, 0, NULL); - if(!conn->proxypasswd) - return CURLE_OUT_OF_MEMORY; - - return CURLE_OK; + result = Curl_urldecode(data, proxyuser, 0, &conn->proxyuser, NULL, FALSE); + if(!result) + result = Curl_urldecode(data, proxypasswd, 0, &conn->proxypasswd, NULL, + FALSE); + return result; } #endif /* CURL_DISABLE_PROXY */ @@ -4940,9 +4903,8 @@ static CURLcode parse_url_login(struct Curl_easy *data, conn->bits.user_passwd = TRUE; /* enable user+password */ /* Decode the user */ - newname = curl_easy_unescape(data, userp, 0, NULL); - if(!newname) { - result = CURLE_OUT_OF_MEMORY; + result = Curl_urldecode(data, userp, 0, &newname, NULL, FALSE); + if(result) { goto out; } @@ -4952,9 +4914,9 @@ static CURLcode parse_url_login(struct Curl_easy *data, if(passwdp) { /* We have a password in the URL so decode it */ - char *newpasswd = curl_easy_unescape(data, passwdp, 0, NULL); - if(!newpasswd) { - result = CURLE_OUT_OF_MEMORY; + char *newpasswd; + result = Curl_urldecode(data, passwdp, 0, &newpasswd, NULL, FALSE); + if(result) { goto out; } @@ -4964,9 +4926,9 @@ static CURLcode parse_url_login(struct Curl_easy *data, if(optionsp) { /* We have an options list in the URL so decode it */ - char *newoptions = curl_easy_unescape(data, optionsp, 0, NULL); - if(!newoptions) { - result = CURLE_OUT_OF_MEMORY; + char *newoptions; + result = Curl_urldecode(data, optionsp, 0, &newoptions, NULL, FALSE); + if(result) { goto out; } @@ -5457,7 +5419,8 @@ static CURLcode parse_connect_to_string(struct Curl_easy *data, if(!hostname_to_match) return CURLE_OUT_OF_MEMORY; hostname_to_match_len = strlen(hostname_to_match); - host_match = curl_strnequal(ptr, hostname_to_match, hostname_to_match_len); + host_match = strncasecompare(ptr, hostname_to_match, + hostname_to_match_len); free(hostname_to_match); ptr += hostname_to_match_len; @@ -6021,18 +5984,18 @@ static CURLcode create_conn(struct Curl_easy *data, /************************************************************* * IDN-fix the hostnames *************************************************************/ - fix_hostname(data, conn, &conn->host); + fix_hostname(conn, &conn->host); if(conn->bits.conn_to_host) - fix_hostname(data, conn, &conn->conn_to_host); + fix_hostname(conn, &conn->conn_to_host); if(conn->proxy.name && *conn->proxy.name) - fix_hostname(data, conn, &conn->proxy); + fix_hostname(conn, &conn->proxy); /************************************************************* * Check whether the host and the "connect to host" are equal. * Do this after the hostnames have been IDN-fixed . *************************************************************/ if(conn->bits.conn_to_host && - Curl_raw_equal(conn->conn_to_host.name, conn->host.name)) { + strcasecompare(conn->conn_to_host.name, conn->host.name)) { conn->bits.conn_to_host = FALSE; } diff --git a/Utilities/cmcurl/lib/urldata.h b/Utilities/cmcurl/lib/urldata.h index 3cf7ed9..7c7bf1b 100644 --- a/Utilities/cmcurl/lib/urldata.h +++ b/Utilities/cmcurl/lib/urldata.h @@ -330,6 +330,7 @@ struct ssl_connect_data { CURLcode recv_unrecoverable_err; /* schannel_recv had an unrecoverable err */ bool recv_sspi_close_notify; /* true if connection closed by close_notify */ bool recv_connection_closed; /* true if connection closed, regardless how */ + bool use_alpn; /* true if ALPN is used for this connection */ #elif defined(USE_DARWINSSL) SSLContextRef ssl_ctx; curl_socket_t ssl_sockfd; @@ -373,6 +374,7 @@ struct ssl_config_data { struct curl_ssl_session { char *name; /* host name for which this ID was used */ char *conn_to_host; /* host name for the connection (may be NULL) */ + const char *scheme; /* protocol scheme used */ void *sessionid; /* as returned from the SSL layer */ size_t idsize; /* if known, otherwise 0 */ long age; /* just a number, the higher the more recent */ @@ -817,6 +819,7 @@ struct Curl_handler { #define PROTOPT_CREDSPERREQUEST (1<<7) /* requires login credentials per request instead of per connection */ #define PROTOPT_ALPN_NPN (1<<8) /* set ALPN and/or NPN for this */ +#define PROTOPT_STREAM (1<<9) /* a protocol with individual logical streams */ /* return the count of bytes sent, or -1 on error */ typedef ssize_t (Curl_send)(struct connectdata *conn, /* connection data */ @@ -1102,9 +1105,10 @@ struct connectdata { /* * Struct to keep statistical and informational data. + * All variables in this struct must be reset in Curl_initinfo(). */ struct PureInfo { - int httpcode; /* Recent HTTP, FTP, or RTSP response code */ + int httpcode; /* Recent HTTP, FTP, RTSP or SMTP response code */ int httpproxycode; /* response code from proxy when received separate */ int httpversion; /* the http version number X.Y = X*10+Y */ long filetime; /* If requested, this is might get set. Set to -1 if the time @@ -1171,6 +1175,14 @@ struct Progress { struct timeval t_startsingle; struct timeval t_startop; struct timeval t_acceptdata; + + /* upload speed limit */ + struct timeval ul_limit_start; + curl_off_t ul_limit_size; + /* download speed limit */ + struct timeval dl_limit_start; + curl_off_t dl_limit_size; + #define CURR_TIME (5+1) /* 6 entries for 5 seconds */ curl_off_t speeder[ CURR_TIME ]; @@ -1600,6 +1612,7 @@ struct UserDefined { bool ftp_use_port; /* use the FTP PORT command */ bool hide_progress; /* don't use the progress meter */ bool http_fail_on_error; /* fail on HTTP error codes >= 400 */ + bool http_keep_sending_on_error; /* for HTTP status codes >= 300 */ bool http_follow_location; /* follow HTTP redirects */ bool http_transfer_encoding; /* request compressed HTTP transfer-encoding */ bool http_disable_hostname_check_before_authentication; diff --git a/Utilities/cmcurl/lib/vauth/cleartext.c b/Utilities/cmcurl/lib/vauth/cleartext.c index 4e906bc..6df419a 100644 --- a/Utilities/cmcurl/lib/vauth/cleartext.c +++ b/Utilities/cmcurl/lib/vauth/cleartext.c @@ -33,8 +33,6 @@ #include "curl_md5.h" #include "warnless.h" #include "strtok.h" -#include "strequal.h" -#include "rawstr.h" #include "sendf.h" #include "curl_printf.h" diff --git a/Utilities/cmcurl/lib/vauth/digest.c b/Utilities/cmcurl/lib/vauth/digest.c index 26ea7b5..0a11a30 100644 --- a/Utilities/cmcurl/lib/vauth/digest.c +++ b/Utilities/cmcurl/lib/vauth/digest.c @@ -37,7 +37,7 @@ #include "vtls/vtls.h" #include "warnless.h" #include "strtok.h" -#include "rawstr.h" +#include "strcase.h" #include "non-ascii.h" /* included for Curl_convert_... prototypes */ #include "curl_printf.h" @@ -217,11 +217,11 @@ static CURLcode auth_digest_get_qop_values(const char *options, int *value) token = strtok_r(tmp, ",", &tok_buf); while(token != NULL) { - if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH)) + if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH)) *value |= DIGEST_QOP_VALUE_AUTH; - else if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) + else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) *value |= DIGEST_QOP_VALUE_AUTH_INT; - else if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH_CONF)) + else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_CONF)) *value |= DIGEST_QOP_VALUE_AUTH_CONF; token = strtok_r(NULL, ",", &tok_buf); @@ -306,6 +306,20 @@ static CURLcode auth_decode_digest_md5_message(const char *chlg64, } /* + * Curl_auth_is_digest_supported() + * + * This is used to evaluate if DIGEST is supported. + * + * Parameters: None + * + * Returns TRUE as DIGEST as handled by libcurl. + */ +bool Curl_auth_is_digest_supported(void) +{ + return TRUE; +} + +/* * Curl_auth_create_digest_md5_message() * * This is used to generate an already encoded DIGEST-MD5 response message @@ -524,31 +538,31 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, /* Extract a value=content pair */ if(Curl_auth_digest_get_pair(chlg, value, content, &chlg)) { - if(Curl_raw_equal(value, "nonce")) { + if(strcasecompare(value, "nonce")) { free(digest->nonce); digest->nonce = strdup(content); if(!digest->nonce) return CURLE_OUT_OF_MEMORY; } - else if(Curl_raw_equal(value, "stale")) { - if(Curl_raw_equal(content, "true")) { + else if(strcasecompare(value, "stale")) { + if(strcasecompare(content, "true")) { digest->stale = TRUE; digest->nc = 1; /* we make a new nonce now */ } } - else if(Curl_raw_equal(value, "realm")) { + else if(strcasecompare(value, "realm")) { free(digest->realm); digest->realm = strdup(content); if(!digest->realm) return CURLE_OUT_OF_MEMORY; } - else if(Curl_raw_equal(value, "opaque")) { + else if(strcasecompare(value, "opaque")) { free(digest->opaque); digest->opaque = strdup(content); if(!digest->opaque) return CURLE_OUT_OF_MEMORY; } - else if(Curl_raw_equal(value, "qop")) { + else if(strcasecompare(value, "qop")) { char *tok_buf; /* Tokenize the list and choose auth if possible, use a temporary clone of the buffer since strtok_r() ruins it */ @@ -558,10 +572,10 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, token = strtok_r(tmp, ",", &tok_buf); while(token != NULL) { - if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH)) { + if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH)) { foundAuth = TRUE; } - else if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) { + else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) { foundAuthInt = TRUE; } token = strtok_r(NULL, ",", &tok_buf); @@ -583,15 +597,15 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, return CURLE_OUT_OF_MEMORY; } } - else if(Curl_raw_equal(value, "algorithm")) { + else if(strcasecompare(value, "algorithm")) { free(digest->algorithm); digest->algorithm = strdup(content); if(!digest->algorithm) return CURLE_OUT_OF_MEMORY; - if(Curl_raw_equal(content, "MD5-sess")) + if(strcasecompare(content, "MD5-sess")) digest->algo = CURLDIGESTALGO_MD5SESS; - else if(Curl_raw_equal(content, "MD5")) + else if(strcasecompare(content, "MD5")) digest->algo = CURLDIGESTALGO_MD5; else return CURLE_BAD_CONTENT_ENCODING; @@ -730,7 +744,7 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, md5this = (unsigned char *) aprintf("%s:%s", request, uripath); - if(digest->qop && Curl_raw_equal(digest->qop, "auth-int")) { + if(digest->qop && strcasecompare(digest->qop, "auth-int")) { /* We don't support auth-int for PUT or POST at the moment. TODO: replace md5 of empty string with entity-body for PUT/POST */ unsigned char *md5this2 = (unsigned char *) @@ -806,7 +820,7 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, digest->qop, request_digest); - if(Curl_raw_equal(digest->qop, "auth")) + if(strcasecompare(digest->qop, "auth")) digest->nc++; /* The nc (from RFC) has to be a 8 hex digit number 0 padded which tells to the server how many times you are using the same nonce in the qop=auth mode */ diff --git a/Utilities/cmcurl/lib/vauth/digest_sspi.c b/Utilities/cmcurl/lib/vauth/digest_sspi.c index 6a7315e..29526fc 100644 --- a/Utilities/cmcurl/lib/vauth/digest_sspi.c +++ b/Utilities/cmcurl/lib/vauth/digest_sspi.c @@ -37,13 +37,34 @@ #include "curl_multibyte.h" #include "sendf.h" #include "strdup.h" -#include "rawstr.h" +#include "strcase.h" /* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" /* +* Curl_auth_is_digest_supported() +* +* This is used to evaluate if DIGEST is supported. +* +* Parameters: None +* +* Returns TRUE if DIGEST is supported by Windows SSPI. +*/ +bool Curl_auth_is_digest_supported(void) +{ + PSecPkgInfo SecurityPackage; + SECURITY_STATUS status; + + /* Query the security package for Digest */ + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST), + &SecurityPackage); + + return (status == SEC_E_OK ? TRUE : FALSE); +} + +/* * Curl_auth_create_digest_md5_message() * * This is used to generate an already encoded DIGEST-MD5 response message @@ -256,7 +277,7 @@ CURLcode Curl_override_sspi_http_realm(const char *chlg, /* Extract a value=content pair */ if(Curl_auth_digest_get_pair(chlg, value, content, &chlg)) { - if(Curl_raw_equal(value, "realm")) { + if(strcasecompare(value, "realm")) { /* Setup identity's domain and length */ domain.tchar_ptr = Curl_convert_UTF8_to_tchar((char *) content); diff --git a/Utilities/cmcurl/lib/vauth/krb5_gssapi.c b/Utilities/cmcurl/lib/vauth/krb5_gssapi.c index 31c8c7d..c754fae 100644 --- a/Utilities/cmcurl/lib/vauth/krb5_gssapi.c +++ b/Utilities/cmcurl/lib/vauth/krb5_gssapi.c @@ -42,6 +42,20 @@ #include "memdebug.h" /* + * Curl_auth_is_gssapi_supported() + * + * This is used to evaluate if GSSAPI (Kerberos V5) is supported. + * + * Parameters: None + * + * Returns TRUE if Kerberos V5 is supported by the GSS-API library. + */ +bool Curl_auth_is_gssapi_supported(void) +{ + return TRUE; +} + +/* * Curl_auth_create_gssapi_user_message() * * This is used to generate an already encoded GSSAPI (Kerberos V5) user token diff --git a/Utilities/cmcurl/lib/vauth/krb5_sspi.c b/Utilities/cmcurl/lib/vauth/krb5_sspi.c index 08774f6..151794e 100644 --- a/Utilities/cmcurl/lib/vauth/krb5_sspi.c +++ b/Utilities/cmcurl/lib/vauth/krb5_sspi.c @@ -40,6 +40,28 @@ #include "memdebug.h" /* + * Curl_auth_is_gssapi_supported() + * + * This is used to evaluate if GSSAPI (Kerberos V5) is supported. + * + * Parameters: None + * + * Returns TRUE if Kerberos V5 is supported by Windows SSPI. + */ +bool Curl_auth_is_gssapi_supported(void) +{ + PSecPkgInfo SecurityPackage; + SECURITY_STATUS status; + + /* Query the security package for Kerberos */ + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) + TEXT(SP_NAME_KERBEROS), + &SecurityPackage); + + return (status == SEC_E_OK ? TRUE : FALSE); +} + +/* * Curl_auth_create_gssapi_user_message() * * This is used to generate an already encoded GSSAPI (Kerberos V5) user token diff --git a/Utilities/cmcurl/lib/vauth/ntlm.c b/Utilities/cmcurl/lib/vauth/ntlm.c index c85fe42..b484a01 100644 --- a/Utilities/cmcurl/lib/vauth/ntlm.c +++ b/Utilities/cmcurl/lib/vauth/ntlm.c @@ -217,6 +217,20 @@ static CURLcode ntlm_decode_type2_target(struct Curl_easy *data, */ /* + * Curl_auth_is_ntlm_supported() + * + * This is used to evaluate if NTLM is supported. + * + * Parameters: None + * + * Returns TRUE as NTLM as handled by libcurl. + */ +bool Curl_auth_is_ntlm_supported(void) +{ + return TRUE; +} + +/* * Curl_auth_decode_ntlm_type2_message() * * This is used to decode an already encoded NTLM type-2 message. The message diff --git a/Utilities/cmcurl/lib/vauth/ntlm_sspi.c b/Utilities/cmcurl/lib/vauth/ntlm_sspi.c index 982a9d3..c330517 100644 --- a/Utilities/cmcurl/lib/vauth/ntlm_sspi.c +++ b/Utilities/cmcurl/lib/vauth/ntlm_sspi.c @@ -38,6 +38,27 @@ #include "memdebug.h" /* + * Curl_auth_is_ntlm_supported() + * + * This is used to evaluate if NTLM is supported. + * + * Parameters: None + * + * Returns TRUE if NTLM is supported by Windows SSPI. + */ +bool Curl_auth_is_ntlm_supported(void) +{ + PSecPkgInfo SecurityPackage; + SECURITY_STATUS status; + + /* Query the security package for NTLM */ + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM), + &SecurityPackage); + + return (status == SEC_E_OK ? TRUE : FALSE); +} + +/* * Curl_auth_create_ntlm_type1_message() * * This is used to generate an already encoded NTLM type-1 message ready for diff --git a/Utilities/cmcurl/lib/vauth/spnego_gssapi.c b/Utilities/cmcurl/lib/vauth/spnego_gssapi.c index b256ee6..8840db8 100644 --- a/Utilities/cmcurl/lib/vauth/spnego_gssapi.c +++ b/Utilities/cmcurl/lib/vauth/spnego_gssapi.c @@ -41,6 +41,20 @@ #include "memdebug.h" /* + * Curl_auth_is_spnego_supported() + * + * This is used to evaluate if SPNEGO (Negotiate) is supported. + * + * Parameters: None + * + * Returns TRUE if Negotiate supported by the GSS-API library. + */ +bool Curl_auth_is_spnego_supported(void) +{ + return TRUE; +} + +/* * Curl_auth_decode_spnego_message() * * This is used to decode an already encoded SPNEGO (Negotiate) challenge diff --git a/Utilities/cmcurl/lib/vauth/spnego_sspi.c b/Utilities/cmcurl/lib/vauth/spnego_sspi.c index b6176ec..672b43f 100644 --- a/Utilities/cmcurl/lib/vauth/spnego_sspi.c +++ b/Utilities/cmcurl/lib/vauth/spnego_sspi.c @@ -40,6 +40,28 @@ #include "memdebug.h" /* + * Curl_auth_is_spnego_supported() + * + * This is used to evaluate if SPNEGO (Negotiate) is supported. + * + * Parameters: None + * + * Returns TRUE if Negotiate is supported by Windows SSPI. + */ +bool Curl_auth_is_spnego_supported(void) +{ + PSecPkgInfo SecurityPackage; + SECURITY_STATUS status; + + /* Query the security package for Negotiate */ + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) + TEXT(SP_NAME_NEGOTIATE), + &SecurityPackage); + + return (status == SEC_E_OK ? TRUE : FALSE); +} + +/* * Curl_auth_decode_spnego_message() * * This is used to decode an already encoded SPNEGO (Negotiate) challenge @@ -249,8 +271,10 @@ CURLcode Curl_auth_create_spnego_message(struct Curl_easy *data, if(result) return result; - if(!*outptr || !*outlen) + if(!*outptr || !*outlen) { + free(*outptr); return CURLE_REMOTE_ACCESS_DENIED; + } return CURLE_OK; } diff --git a/Utilities/cmcurl/lib/vauth/vauth.c b/Utilities/cmcurl/lib/vauth/vauth.c index 702e2d4..b995f34 100644 --- a/Utilities/cmcurl/lib/vauth/vauth.c +++ b/Utilities/cmcurl/lib/vauth/vauth.c @@ -104,3 +104,44 @@ TCHAR *Curl_auth_build_spn(const char *service, const char *host, } #endif /* USE_WINDOWS_SSPI */ +/* +* Curl_auth_user_contains_domain() +* +* This is used to test if the specified user contains a Windows domain name as +* follows: +* +* User\Domain (Down-level Logon Name) +* User/Domain (curl Down-level format - for compatibility with existing code) +* User@Domain (User Principal Name) +* +* Note: The user name may be empty when using a GSS-API library or Windows SSPI +* as the user and domain are either obtained from the credientals cache when +* using GSS-API or via the currently logged in user's credientals when using +* Windows SSPI. +* +* Parameters: +* +* user [in] - The user name. +* +* Returns TRUE on success; otherwise FALSE. +*/ +bool Curl_auth_user_contains_domain(const char *user) +{ + bool valid = FALSE; + + if(user && *user) { + /* Check we have a domain name or UPN present */ + char *p = strpbrk(user, "\\/@"); + + valid = (p != NULL && p > user && p < user + strlen(user) - 1 ? TRUE : + FALSE); + } +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + else + /* User and domain are obtained from the GSS-API credientials cache or the + currently logged in user from Windows */ + valid = TRUE; +#endif + + return valid; +} diff --git a/Utilities/cmcurl/lib/vauth/vauth.h b/Utilities/cmcurl/lib/vauth/vauth.h index 38806ee..9d61228 100644 --- a/Utilities/cmcurl/lib/vauth/vauth.h +++ b/Utilities/cmcurl/lib/vauth/vauth.h @@ -55,6 +55,9 @@ TCHAR *Curl_auth_build_spn(const char *service, const char *host, const char *realm); #endif +/* This is used to test if the user contains a Windows domain name */ +bool Curl_auth_user_contains_domain(const char *user); + /* This is used to generate a base64 encoded PLAIN cleartext message */ CURLcode Curl_auth_create_plain_message(struct Curl_easy *data, const char *userp, @@ -83,6 +86,9 @@ CURLcode Curl_auth_create_cram_md5_message(struct Curl_easy *data, const char *passwdp, char **outptr, size_t *outlen); +/* This is used to evaluate if DIGEST is supported */ +bool Curl_auth_is_digest_supported(void); + /* This is used to generate a base64 encoded DIGEST-MD5 response message */ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, const char *chlg64, @@ -109,6 +115,9 @@ void Curl_auth_digest_cleanup(struct digestdata *digest); #endif /* !CURL_DISABLE_CRYPTO_AUTH */ #if defined(USE_NTLM) +/* This is used to evaluate if NTLM is supported */ +bool Curl_auth_is_ntlm_supported(void); + /* This is used to generate a base64 encoded NTLM type-1 message */ CURLcode Curl_auth_create_ntlm_type1_message(const char *userp, const char *passwdp, @@ -140,6 +149,9 @@ CURLcode Curl_auth_create_oauth_bearer_message(struct Curl_easy *data, const char *bearer, char **outptr, size_t *outlen); #if defined(USE_KERBEROS5) +/* This is used to evaluate if GSSAPI (Kerberos V5) is supported */ +bool Curl_auth_is_gssapi_supported(void); + /* This is used to generate a base64 encoded GSSAPI (Kerberos V5) user token message */ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data, @@ -165,6 +177,9 @@ void Curl_auth_gssapi_cleanup(struct kerberos5data *krb5); #endif /* USE_KERBEROS5 */ #if defined(USE_SPNEGO) +/* This is used to evaluate if SPNEGO (Negotiate) is supported */ +bool Curl_auth_is_spnego_supported(void); + /* This is used to decode a base64 encoded SPNEGO (Negotiate) challenge message */ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, diff --git a/Utilities/cmcurl/lib/version.c b/Utilities/cmcurl/lib/version.c index 1292445..a434a62 100644 --- a/Utilities/cmcurl/lib/version.c +++ b/Utilities/cmcurl/lib/version.c @@ -36,8 +36,8 @@ # include <ares.h> #endif -#ifdef USE_LIBIDN -#include <stringprep.h> +#ifdef USE_LIBIDN2 +#include <idn2.h> #endif #ifdef USE_LIBPSL @@ -111,9 +111,9 @@ char *curl_version(void) left -= len; ptr += len; #endif -#ifdef USE_LIBIDN - if(stringprep_check_version(LIBIDN_REQUIRED_VERSION)) { - len = snprintf(ptr, left, " libidn/%s", stringprep_check_version(NULL)); +#ifdef USE_LIBIDN2 + if(idn2_check_version(IDN2_VERSION)) { + len = snprintf(ptr, left, " libidn2/%s", idn2_check_version(NULL)); left -= len; ptr += len; } @@ -365,10 +365,10 @@ curl_version_info_data *curl_version_info(CURLversion stamp) version_info.ares_num = aresnum; } #endif -#ifdef USE_LIBIDN +#ifdef USE_LIBIDN2 /* This returns a version string if we use the given version or later, otherwise it returns NULL */ - version_info.libidn = stringprep_check_version(LIBIDN_REQUIRED_VERSION); + version_info.libidn = idn2_check_version(IDN2_VERSION); if(version_info.libidn) version_info.features |= CURL_VERSION_IDN; #elif defined(USE_WIN32_IDN) diff --git a/Utilities/cmcurl/lib/vtls/axtls.c b/Utilities/cmcurl/lib/vtls/axtls.c index b6c69ad..85b8bc4 100644 --- a/Utilities/cmcurl/lib/vtls/axtls.c +++ b/Utilities/cmcurl/lib/vtls/axtls.c @@ -579,8 +579,7 @@ int Curl_axtls_shutdown(struct connectdata *conn, int sockindex) */ if(connssl->ssl) { - int what = Curl_socket_ready(conn->sock[sockindex], - CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); + int what = SOCKET_READABLE(conn->sock[sockindex], SSL_SHUTDOWN_TIMEOUT); if(what > 0) { /* Something to read, let's do it and hope that it is the close notify alert from the server. buf is managed internally by diff --git a/Utilities/cmcurl/lib/vtls/cyassl.c b/Utilities/cmcurl/lib/vtls/cyassl.c index 7994b3e..5d6dbfb 100644 --- a/Utilities/cmcurl/lib/vtls/cyassl.c +++ b/Utilities/cmcurl/lib/vtls/cyassl.c @@ -55,7 +55,7 @@ and that's a problem since options.h hasn't been included yet. */ #include "parsedate.h" #include "connect.h" /* for the connect timeout */ #include "select.h" -#include "rawstr.h" +#include "strcase.h" #include "x509asn1.h" #include "curl_printf.h" @@ -118,9 +118,9 @@ static int do_file_type(const char *type) { if(!type || !type[0]) return SSL_FILETYPE_PEM; - if(Curl_raw_equal(type, "PEM")) + if(strcasecompare(type, "PEM")) return SSL_FILETYPE_PEM; - if(Curl_raw_equal(type, "DER")) + if(strcasecompare(type, "DER")) return SSL_FILETYPE_ASN1; return -1; } @@ -803,7 +803,8 @@ cyassl_connect_common(struct connectdata *conn, curl_socket_t readfd = ssl_connect_2_reading== connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - what = Curl_socket_ready(readfd, writefd, nonblocking?0:timeout_ms); + what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, + nonblocking?0:timeout_ms); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); diff --git a/Utilities/cmcurl/lib/vtls/darwinssl.c b/Utilities/cmcurl/lib/vtls/darwinssl.c index ebb9e30..66e74f1 100644 --- a/Utilities/cmcurl/lib/vtls/darwinssl.c +++ b/Utilities/cmcurl/lib/vtls/darwinssl.c @@ -6,7 +6,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2012 - 2014, Nick Zitzmann, <nickzman@gmail.com>. - * Copyright (C) 2012 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2012 - 2016, 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 @@ -920,7 +920,7 @@ static OSStatus CopyIdentityWithLabel(char *label, #if CURL_SUPPORT_MAC_10_6 /* On Leopard and Snow Leopard, fall back to SecKeychainSearch. */ status = CopyIdentityWithLabelOldSchool(label, out_cert_and_key); -#endif /* CURL_SUPPORT_MAC_10_7 */ +#endif /* CURL_SUPPORT_MAC_10_6 */ } #elif CURL_SUPPORT_MAC_10_6 /* For developers building on older cats, we have no choice but to fall back @@ -955,7 +955,7 @@ static OSStatus CopyIdentityFromPKCS12File(const char *cPath, /* Here we go: */ status = SecPKCS12Import(pkcs_data, options, &items); - if(status == noErr && items && CFArrayGetCount(items)) { + if(status == errSecSuccess && items && CFArrayGetCount(items)) { CFDictionaryRef identity_and_trust = CFArrayGetValueAtIndex(items, 0L); const void *temp_identity = CFDictionaryGetValue(identity_and_trust, kSecImportItemIdentity); @@ -1438,6 +1438,16 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, /* Disable IDEA: */ case SSL_RSA_WITH_IDEA_CBC_SHA: case SSL_RSA_WITH_IDEA_CBC_MD5: + /* Disable RC4: */ + case SSL_RSA_WITH_RC4_128_MD5: + case SSL_RSA_WITH_RC4_128_SHA: + case 0xC002: /* TLS_ECDH_ECDSA_WITH_RC4_128_SHA */ + case 0xC007: /* TLS_ECDHE_ECDSA_WITH_RC4_128_SHA*/ + case 0xC00C: /* TLS_ECDH_RSA_WITH_RC4_128_SHA */ + case 0xC011: /* TLS_ECDHE_RSA_WITH_RC4_128_SHA */ + case 0x008A: /* TLS_PSK_WITH_RC4_128_SHA */ + case 0x008E: /* TLS_DHE_PSK_WITH_RC4_128_SHA */ + case 0x0092: /* TLS_RSA_PSK_WITH_RC4_128_SHA */ break; default: /* enable everything else */ allowed_ciphers[allowed_ciphers_count++] = all_ciphers[i]; @@ -2140,7 +2150,8 @@ darwinssl_connect_common(struct connectdata *conn, curl_socket_t readfd = ssl_connect_2_reading == connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - what = Curl_socket_ready(readfd, writefd, nonblocking?0:timeout_ms); + what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, + nonblocking?0:timeout_ms); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); @@ -2262,8 +2273,7 @@ int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex) rc = 0; - what = Curl_socket_ready(conn->sock[sockindex], - CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); + what = SOCKET_READABLE(conn->sock[sockindex], SSL_SHUTDOWN_TIMEOUT); for(;;) { if(what < 0) { @@ -2291,7 +2301,7 @@ int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex) if(nread <= 0) break; - what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, 0); + what = SOCKET_READABLE(conn->sock[sockindex], 0); } return rc; diff --git a/Utilities/cmcurl/lib/vtls/gskit.c b/Utilities/cmcurl/lib/vtls/gskit.c index 55a55ef..3b0cfd5 100644 --- a/Utilities/cmcurl/lib/vtls/gskit.c +++ b/Utilities/cmcurl/lib/vtls/gskit.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2016, 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 @@ -72,7 +72,7 @@ #include "vtls.h" #include "connect.h" /* for the connect timeout */ #include "select.h" -#include "strequal.h" +#include "strcase.h" #include "x509asn1.h" #include "curl_printf.h" @@ -1001,8 +1001,8 @@ int Curl_gskit_shutdown(struct connectdata *conn, int sockindex) close_one(connssl, data); rc = 0; - what = Curl_socket_ready(conn->sock[sockindex], - CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); + what = SOCKET_READABLE(conn->sock[sockindex], + SSL_SHUTDOWN_TIMEOUT); for(;;) { if(what < 0) { @@ -1031,7 +1031,7 @@ int Curl_gskit_shutdown(struct connectdata *conn, int sockindex) if(nread <= 0) break; - what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, 0); + what = SOCKET_READABLE(conn->sock[sockindex], 0); } return rc; diff --git a/Utilities/cmcurl/lib/vtls/gtls.c b/Utilities/cmcurl/lib/vtls/gtls.c index 1c3e6b1..5c87c7f 100644 --- a/Utilities/cmcurl/lib/vtls/gtls.c +++ b/Utilities/cmcurl/lib/vtls/gtls.c @@ -52,7 +52,7 @@ #include "parsedate.h" #include "connect.h" /* for the connect timeout */ #include "select.h" -#include "rawstr.h" +#include "strcase.h" #include "warnless.h" #include "x509asn1.h" #include "curl_printf.h" @@ -289,7 +289,7 @@ static CURLcode handshake(struct connectdata *conn, curl_socket_t readfd = ssl_connect_2_reading== connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - what = Curl_socket_ready(readfd, writefd, + what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, nonblocking?0: timeout_ms?timeout_ms:1000); if(what < 0) { @@ -356,9 +356,9 @@ static gnutls_x509_crt_fmt_t do_file_type(const char *type) { if(!type || !type[0]) return GNUTLS_X509_FMT_PEM; - if(Curl_raw_equal(type, "PEM")) + if(strcasecompare(type, "PEM")) return GNUTLS_X509_FMT_PEM; - if(Curl_raw_equal(type, "DER")) + if(strcasecompare(type, "DER")) return GNUTLS_X509_FMT_DER; return -1; } @@ -1445,8 +1445,8 @@ int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) if(conn->ssl[sockindex].session) { while(!done) { - int what = Curl_socket_ready(conn->sock[sockindex], - CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); + int what = SOCKET_READABLE(conn->sock[sockindex], + SSL_SHUTDOWN_TIMEOUT); if(what > 0) { /* Something to read, let's do it and hope that it is the close notify alert from the server */ diff --git a/Utilities/cmcurl/lib/vtls/mbedtls.c b/Utilities/cmcurl/lib/vtls/mbedtls.c index a1e7d23..24249dd 100644 --- a/Utilities/cmcurl/lib/vtls/mbedtls.c +++ b/Utilities/cmcurl/lib/vtls/mbedtls.c @@ -31,7 +31,7 @@ #ifdef USE_MBEDTLS -#include <mbedtls/net.h> +#include <mbedtls/net_sockets.h> #include <mbedtls/ssl.h> #include <mbedtls/certs.h> #include <mbedtls/x509.h> @@ -50,7 +50,6 @@ #include "parsedate.h" #include "connect.h" /* for the connect timeout */ #include "select.h" -#include "rawstr.h" #include "polarssl_threadlock.h" /* The last 3 #include files should be in this order */ @@ -420,7 +419,15 @@ mbed_connect_step1(struct connectdata *conn, #endif #ifdef MBEDTLS_DEBUG + /* In order to make that work in mbedtls MBEDTLS_DEBUG_C must be defined. */ mbedtls_ssl_conf_dbg(&connssl->config, mbed_debug, data); + /* - 0 No debug + * - 1 Error + * - 2 State change + * - 3 Informational + * - 4 Verbose + */ + mbedtls_debug_set_threshold(4); #endif connssl->connecting_state = ssl_connect_2; @@ -765,7 +772,8 @@ mbed_connect_common(struct connectdata *conn, curl_socket_t readfd = ssl_connect_2_reading== connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - what = Curl_socket_ready(readfd, writefd, nonblocking ? 0 : timeout_ms); + what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, + nonblocking ? 0 : timeout_ms); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); diff --git a/Utilities/cmcurl/lib/vtls/nss.c b/Utilities/cmcurl/lib/vtls/nss.c index e467360..dff1575 100644 --- a/Utilities/cmcurl/lib/vtls/nss.c +++ b/Utilities/cmcurl/lib/vtls/nss.c @@ -34,7 +34,7 @@ #include "formdata.h" /* for the boundary function */ #include "url.h" /* for the ssl config check function */ #include "connect.h" -#include "strequal.h" +#include "strcase.h" #include "select.h" #include "vtls.h" #include "llist.h" @@ -64,7 +64,7 @@ #include <ocsp.h> #endif -#include "rawstr.h" +#include "strcase.h" #include "warnless.h" #include "x509asn1.h" @@ -78,13 +78,12 @@ #define SLOTSIZE 13 PRFileDesc *PR_ImportTCPSocket(PRInt32 osfd); - -PRLock * nss_initlock = NULL; -PRLock * nss_crllock = NULL; -struct curl_llist *nss_crl_list = NULL; -NSSInitContext * nss_context = NULL; - -volatile int initialized = 0; +static PRLock *nss_initlock = NULL; +static PRLock *nss_crllock = NULL; +static PRLock *nss_findslot_lock = NULL; +static struct curl_llist *nss_crl_list = NULL; +static NSSInitContext *nss_context = NULL; +static volatile int initialized = 0; typedef struct { const char *name; @@ -150,7 +149,7 @@ static const cipher_s cipherlist[] = { {"ecdh_rsa_3des_sha", TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA}, {"ecdh_rsa_aes_128_sha", TLS_ECDH_RSA_WITH_AES_128_CBC_SHA}, {"ecdh_rsa_aes_256_sha", TLS_ECDH_RSA_WITH_AES_256_CBC_SHA}, - {"echde_rsa_null", TLS_ECDHE_RSA_WITH_NULL_SHA}, + {"ecdhe_rsa_null", TLS_ECDHE_RSA_WITH_NULL_SHA}, {"ecdhe_rsa_rc4_128_sha", TLS_ECDHE_RSA_WITH_RC4_128_SHA}, {"ecdhe_rsa_3des_sha", TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA}, {"ecdhe_rsa_aes_128_sha", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}, @@ -180,10 +179,29 @@ static const cipher_s cipherlist[] = { {"ecdhe_rsa_aes_128_gcm_sha_256", TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, {"ecdh_rsa_aes_128_gcm_sha_256", TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256}, #endif +#ifdef TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + /* cipher suites using SHA384 */ + {"rsa_aes_256_gcm_sha_384", TLS_RSA_WITH_AES_256_GCM_SHA384}, + {"dhe_rsa_aes_256_gcm_sha_384", TLS_DHE_RSA_WITH_AES_256_GCM_SHA384}, + {"dhe_dss_aes_256_gcm_sha_384", TLS_DHE_DSS_WITH_AES_256_GCM_SHA384}, + {"ecdhe_ecdsa_aes_256_sha_384", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384}, + {"ecdhe_rsa_aes_256_sha_384", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384}, + {"ecdhe_ecdsa_aes_256_gcm_sha_384", TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384}, + {"ecdhe_rsa_aes_256_gcm_sha_384", TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384}, +#endif +#ifdef TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + /* chacha20-poly1305 cipher suites */ + {"ecdhe_rsa_chacha20_poly1305_sha_256", + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256}, + {"ecdhe_ecdsa_chacha20_poly1305_sha_256", + TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256}, + {"dhe_rsa_chacha20_poly1305_sha_256", + TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256}, +#endif }; static const char* pem_library = "libnsspem.so"; -SECMODModule* mod = NULL; +static SECMODModule* mod = NULL; /* NSPR I/O layer we use to detect blocking direction during SSL handshake */ static PRDescIdentity nspr_io_identity = PR_INVALID_IO_LAYER; @@ -243,7 +261,7 @@ static SECStatus set_ciphers(struct Curl_easy *data, PRFileDesc * model, found = PR_FALSE; for(i=0; i<NUM_OF_CIPHERS; i++) { - if(Curl_raw_equal(cipher, cipherlist[i].name)) { + if(strcasecompare(cipher, cipherlist[i].name)) { cipher_state[i] = PR_TRUE; found = PR_TRUE; break; @@ -340,6 +358,19 @@ static char* dup_nickname(struct Curl_easy *data, enum dupstring cert_kind) return NULL; } +/* Lock/unlock wrapper for PK11_FindSlotByName() to work around race condition + * in nssSlot_IsTokenPresent() causing spurious SEC_ERROR_NO_TOKEN. For more + * details, go to <https://bugzilla.mozilla.org/1297397>. + */ +static PK11SlotInfo* nss_find_slot_by_name(const char *slot_name) +{ + PK11SlotInfo *slot; + PR_Lock(nss_initlock); + slot = PK11_FindSlotByName(slot_name); + PR_Unlock(nss_initlock); + return slot; +} + /* Call PK11_CreateGenericObject() with the given obj_class and filename. If * the call succeeds, append the object handle to the list of objects so that * the object can be destroyed in Curl_nss_close(). */ @@ -362,7 +393,7 @@ static CURLcode nss_create_object(struct ssl_connect_data *ssl, if(!slot_name) return CURLE_OUT_OF_MEMORY; - slot = PK11_FindSlotByName(slot_name); + slot = nss_find_slot_by_name(slot_name); free(slot_name); if(!slot) return result; @@ -563,7 +594,7 @@ static CURLcode nss_load_key(struct connectdata *conn, int sockindex, return result; } - slot = PK11_FindSlotByName("PEM Token #1"); + slot = nss_find_slot_by_name("PEM Token #1"); if(!slot) return CURLE_SSL_CERTPROBLEM; @@ -1013,7 +1044,7 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, struct CERTCertificateStr *cert; struct SECKEYPrivateKeyStr *key; - PK11SlotInfo *slot = PK11_FindSlotByName(pem_slotname); + PK11SlotInfo *slot = nss_find_slot_by_name(pem_slotname); if(NULL == slot) { failf(data, "NSS: PK11 slot not found: %s", pem_slotname); return SECFailure; @@ -1249,6 +1280,7 @@ int Curl_nss_init(void) PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 256); nss_initlock = PR_NewLock(); nss_crllock = PR_NewLock(); + nss_findslot_lock = PR_NewLock(); } /* We will actually initialize NSS later */ @@ -1303,6 +1335,7 @@ void Curl_nss_cleanup(void) PR_DestroyLock(nss_initlock); PR_DestroyLock(nss_crllock); + PR_DestroyLock(nss_findslot_lock); nss_initlock = NULL; initialized = 0; @@ -1888,8 +1921,11 @@ static CURLcode nss_connect_common(struct connectdata *conn, int sockindex, const bool blocking = (done == NULL); CURLcode result; - if(connssl->state == ssl_connection_complete) + if(connssl->state == ssl_connection_complete) { + if(!blocking) + *done = TRUE; return CURLE_OK; + } if(connssl->connecting_state == ssl_connect_1) { result = nss_setup_connect(conn, sockindex); diff --git a/Utilities/cmcurl/lib/vtls/openssl.c b/Utilities/cmcurl/lib/vtls/openssl.c index 3027ca3..c040928 100644 --- a/Utilities/cmcurl/lib/vtls/openssl.c +++ b/Utilities/cmcurl/lib/vtls/openssl.c @@ -46,10 +46,9 @@ #include "openssl.h" #include "connect.h" #include "slist.h" -#include "strequal.h" #include "select.h" #include "vtls.h" -#include "rawstr.h" +#include "strcase.h" #include "hostcheck.h" #include "curl_printf.h" @@ -95,11 +94,6 @@ #if (OPENSSL_VERSION_NUMBER >= 0x10000000L) #define HAVE_ERR_REMOVE_THREAD_STATE 1 -#if (OPENSSL_VERSION_NUMBER >= 0x10100004L) && \ - !defined(LIBRESSL_VERSION_NUMBER) -/* OpenSSL 1.1.0 deprecates the function */ -#define HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED 1 -#endif #endif #if !defined(HAVE_SSLV2_CLIENT_METHOD) || \ @@ -110,11 +104,28 @@ #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && /* OpenSSL 1.1.0+ */ \ !defined(LIBRESSL_VERSION_NUMBER) -#define SSLeay_add_ssl_algorithms() SSL_library_init() #define SSLEAY_VERSION_NUMBER OPENSSL_VERSION_NUMBER #define HAVE_X509_GET0_EXTENSIONS 1 /* added in 1.1.0 -pre1 */ #define HAVE_OPAQUE_EVP_PKEY 1 /* since 1.1.0 -pre3 */ #define HAVE_OPAQUE_RSA_DSA_DH 1 /* since 1.1.0 -pre5 */ +#define CONST_EXTS const +#define CONST_ASN1_BIT_STRING const +#define HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED 1 +#else +/* For OpenSSL before 1.1.0 */ +#define ASN1_STRING_get0_data(x) ASN1_STRING_data(x) +#define X509_get0_notBefore(x) X509_get_notBefore(x) +#define X509_get0_notAfter(x) X509_get_notAfter(x) +#define CONST_EXTS /* nope */ +#define CONST_ASN1_BIT_STRING /* nope */ +#ifdef LIBRESSL_VERSION_NUMBER +static unsigned long OpenSSL_version_num(void) +{ + return LIBRESSL_VERSION_NUMBER; +} +#else +#define OpenSSL_version_num() SSLeay() +#endif #endif #if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) && /* 1.0.2 or later */ \ @@ -278,13 +289,13 @@ static int do_file_type(const char *type) { if(!type || !type[0]) return SSL_FILETYPE_PEM; - if(Curl_raw_equal(type, "PEM")) + if(strcasecompare(type, "PEM")) return SSL_FILETYPE_PEM; - if(Curl_raw_equal(type, "DER")) + if(strcasecompare(type, "DER")) return SSL_FILETYPE_ASN1; - if(Curl_raw_equal(type, "ENG")) + if(strcasecompare(type, "ENG")) return SSL_FILETYPE_ENGINE; - if(Curl_raw_equal(type, "P12")) + if(strcasecompare(type, "P12")) return SSL_FILETYPE_PKCS12; return -1; } @@ -711,6 +722,10 @@ int Curl_ossl_init(void) CONF_MFLAGS_DEFAULT_SECTION| CONF_MFLAGS_IGNORE_MISSING_FILE); +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \ + !defined(LIBRESSL_VERSION_NUMBER) + /* OpenSSL 1.1.0+ takes care of initialization itself */ +#else /* Lets get nice error messages */ SSL_load_error_strings(); @@ -719,6 +734,7 @@ int Curl_ossl_init(void) return 0; OpenSSL_add_all_algorithms(); +#endif return 1; } @@ -726,6 +742,11 @@ int Curl_ossl_init(void) /* Global cleanup */ void Curl_ossl_cleanup(void) { +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \ + !defined(LIBRESSL_VERSION_NUMBER) + /* OpenSSL 1.1 deprecates all these cleanup functions and + turns them into no-ops in OpenSSL 1.0 compatibility mode */ +#else /* Free ciphers and digests lists */ EVP_cleanup(); @@ -734,18 +755,11 @@ void Curl_ossl_cleanup(void) ENGINE_cleanup(); #endif -#ifdef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA - /* Free OpenSSL ex_data table */ - CRYPTO_cleanup_all_ex_data(); -#endif - /* Free OpenSSL error strings */ ERR_free_strings(); /* Free thread local error state, destroying hash upon zero refcount */ -#ifdef HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED - -#elif defined(HAVE_ERR_REMOVE_THREAD_STATE) +#ifdef HAVE_ERR_REMOVE_THREAD_STATE ERR_remove_thread_state(NULL); #else ERR_remove_state(0); @@ -757,6 +771,7 @@ void Curl_ossl_cleanup(void) #ifdef HAVE_SSL_COMP_FREE_COMPRESSION_METHODS SSL_COMP_free_compression_methods(); #endif +#endif } /* @@ -949,8 +964,8 @@ int Curl_ossl_shutdown(struct connectdata *conn, int sockindex) if(connssl->handle) { buffsize = (int)sizeof(buf); while(!done) { - int what = Curl_socket_ready(conn->sock[sockindex], - CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); + int what = SOCKET_READABLE(conn->sock[sockindex], + SSL_SHUTDOWN_TIMEOUT); if(what > 0) { ERR_clear_error(); @@ -1043,6 +1058,14 @@ void Curl_ossl_close_all(struct Curl_easy *data) #else (void)data; #endif +#if !defined(HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED) && \ + defined(HAVE_ERR_REMOVE_THREAD_STATE) + /* OpenSSL 1.0.1 and 1.0.2 build an error queue that is stored per-thread + so we need to clean it here in case the thread will be killed. All OpenSSL + code should extract the error in association with the error so clearing + this queue here should be harmless at worst. */ + ERR_remove_thread_state(NULL); +#endif } /* ====================================================== */ @@ -1083,6 +1106,7 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) #endif CURLcode result = CURLE_OK; bool dNSName = FALSE; /* if a dNSName field exists in the cert */ + bool iPAddress = FALSE; /* if a iPAddress field exists in the cert */ #ifdef ENABLE_IPV6 if(conn->bits.ipv6_ip && @@ -1115,15 +1139,15 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) /* get a handle to alternative name number i */ const GENERAL_NAME *check = sk_GENERAL_NAME_value(altnames, i); - /* If a subjectAltName extension of type dNSName is present, that MUST - be used as the identity. / RFC2818 section 3.1 */ if(check->type == GEN_DNS) dNSName = TRUE; + else if(check->type == GEN_IPADD) + iPAddress = TRUE; /* only check alternatives of the same type the target is */ if(check->type == target) { /* get data and length */ - const char *altptr = (char *)ASN1_STRING_data(check->d.ia5); + const char *altptr = (char *)ASN1_STRING_get0_data(check->d.ia5); size_t altlen = (size_t) ASN1_STRING_length(check->d.ia5); switch(target) { @@ -1164,18 +1188,14 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) } GENERAL_NAMES_free(altnames); - if(dnsmatched || (!dNSName && ipmatched)) { - /* count as a match if the dnsname matched or if there was no dnsname - fields at all AND there was an IP field match */ + if(dnsmatched || ipmatched) matched = TRUE; - } } if(matched) /* an alternative name matched */ ; - else if(dNSName) { - /* an dNSName field existed, but didn't match and then we MUST fail */ + else if(dNSName || iPAddress) { infof(data, " subjectAltName does not match %s\n", conn->host.dispname); failf(data, "SSL: no alternative certificate subject name matches " "target host name '%s'", conn->host.dispname); @@ -1215,7 +1235,7 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) if(j >= 0) { peer_CN = OPENSSL_malloc(j+1); if(peer_CN) { - memcpy(peer_CN, ASN1_STRING_data(tmp), j); + memcpy(peer_CN, ASN1_STRING_get0_data(tmp), j); peer_CN[j] = '\0'; } } @@ -2178,6 +2198,7 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) lerr = SSL_get_verify_result(connssl->handle); if(lerr != X509_V_OK) { + data->set.ssl.certverifyresult = lerr; snprintf(error_buffer, sizeof(error_buffer), "SSL certificate problem: %s", X509_verify_cert_error_string(lerr)); @@ -2309,7 +2330,7 @@ do { \ static int X509V3_ext(struct Curl_easy *data, int certnum, - STACK_OF(X509_EXTENSION) *exts) + CONST_EXTS STACK_OF(X509_EXTENSION) *exts) { int i; size_t j; @@ -2391,7 +2412,7 @@ static CURLcode get_cert_chain(struct connectdata *conn, EVP_PKEY *pubkey=NULL; int j; char *ptr; - ASN1_BIT_STRING *psig = NULL; + CONST_ASN1_BIT_STRING ASN1_BIT_STRING *psig = NULL; X509_NAME_print_ex(mem, X509_get_subject_name(x), 0, XN_FLAG_ONELINE); push_certinfo("Subject", i); @@ -2411,7 +2432,7 @@ static CURLcode get_cert_chain(struct connectdata *conn, #if defined(HAVE_X509_GET0_SIGNATURE) && defined(HAVE_X509_GET0_EXTENSIONS) { - X509_ALGOR *palg = NULL; + const X509_ALGOR *palg = NULL; ASN1_STRING *a = ASN1_STRING_new(); if(a) { X509_get0_signature(&psig, &palg, x); @@ -2442,10 +2463,10 @@ static CURLcode get_cert_chain(struct connectdata *conn, } #endif - ASN1_TIME_print(mem, X509_get_notBefore(x)); + ASN1_TIME_print(mem, X509_get0_notBefore(x)); push_certinfo("Start date", i); - ASN1_TIME_print(mem, X509_get_notAfter(x)); + ASN1_TIME_print(mem, X509_get0_notAfter(x)); push_certinfo("Expire date", i); pubkey = X509_get_pubkey(x); @@ -2629,7 +2650,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, X509* cert, break; /* failed */ /* https://www.openssl.org/docs/crypto/buffer.html */ - buff1 = temp = OPENSSL_malloc(len1); + buff1 = temp = malloc(len1); if(!buff1) break; /* failed */ @@ -2652,7 +2673,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, X509* cert, /* https://www.openssl.org/docs/crypto/buffer.html */ if(buff1) - OPENSSL_free(buff1); + free(buff1); return result; } @@ -2698,12 +2719,12 @@ static CURLcode servercert(struct connectdata *conn, buffer, BUFSIZE); infof(data, " subject: %s\n", rc?"[NONE]":buffer); - ASN1_TIME_print(mem, X509_get_notBefore(connssl->server_cert)); + ASN1_TIME_print(mem, X509_get0_notBefore(connssl->server_cert)); len = BIO_get_mem_data(mem, (char **) &ptr); infof(data, " start date: %.*s\n", len, ptr); rc = BIO_reset(mem); - ASN1_TIME_print(mem, X509_get_notAfter(connssl->server_cert)); + ASN1_TIME_print(mem, X509_get0_notAfter(connssl->server_cert)); len = BIO_get_mem_data(mem, (char **) &ptr); infof(data, " expire date: %.*s\n", len, ptr); rc = BIO_reset(mem); @@ -2945,7 +2966,8 @@ static CURLcode ossl_connect_common(struct connectdata *conn, curl_socket_t readfd = ssl_connect_2_reading== connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - what = Curl_socket_ready(readfd, writefd, nonblocking?0:timeout_ms); + what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, + nonblocking?0:timeout_ms); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); @@ -3142,7 +3164,7 @@ size_t Curl_ossl_version(char *buffer, size_t size) unsigned long ssleay_value; sub[2]='\0'; sub[1]='\0'; - ssleay_value=SSLeay(); + ssleay_value=OpenSSL_version_num(); if(ssleay_value < 0x906000) { ssleay_value=SSLEAY_VERSION_NUMBER; sub[0]='\0'; diff --git a/Utilities/cmcurl/lib/vtls/polarssl.c b/Utilities/cmcurl/lib/vtls/polarssl.c index d33f548..18b564e 100644 --- a/Utilities/cmcurl/lib/vtls/polarssl.c +++ b/Utilities/cmcurl/lib/vtls/polarssl.c @@ -54,7 +54,7 @@ #include "parsedate.h" #include "connect.h" /* for the connect timeout */ #include "select.h" -#include "rawstr.h" +#include "strcase.h" #include "polarssl_threadlock.h" #include "curl_printf.h" #include "curl_memory.h" @@ -75,6 +75,11 @@ #define THREADING_SUPPORT #endif +#ifndef POLARSSL_ERROR_C +#define error_strerror(x,y,z) +#endif /* POLARSSL_ERROR_C */ + + #if defined(THREADING_SUPPORT) static entropy_context entropy; @@ -96,13 +101,13 @@ static void entropy_init_mutex(entropy_context *ctx) /* start of entropy_func_mutex() */ static int entropy_func_mutex(void *data, unsigned char *output, size_t len) { - int ret; - /* lock 1 = entropy_func_mutex() */ - Curl_polarsslthreadlock_lock_function(1); - ret = entropy_func(data, output, len); - Curl_polarsslthreadlock_unlock_function(1); + int ret; + /* lock 1 = entropy_func_mutex() */ + Curl_polarsslthreadlock_lock_function(1); + ret = entropy_func(data, output, len); + Curl_polarsslthreadlock_unlock_function(1); - return ret; + return ret; } /* end of entropy_func_mutex() */ @@ -138,18 +143,11 @@ static Curl_send polarssl_send; static CURLcode polarssl_connect_step1(struct connectdata *conn, - int sockindex) + int sockindex) { struct Curl_easy *data = conn->data; struct ssl_connect_data* connssl = &conn->ssl[sockindex]; - - bool sni = TRUE; /* default is SNI enabled */ int ret = -1; -#ifdef ENABLE_IPV6 - struct in6_addr addr; -#else - struct in_addr addr; -#endif char errorbuf[128]; errorbuf[0]=0; @@ -158,30 +156,24 @@ polarssl_connect_step1(struct connectdata *conn, failf(data, "PolarSSL does not support SSLv2"); return CURLE_SSL_CONNECT_ERROR; } - else if(data->set.ssl.version == CURL_SSLVERSION_SSLv3) - sni = FALSE; /* SSLv3 has no SNI */ #ifdef THREADING_SUPPORT entropy_init_mutex(&entropy); if((ret = ctr_drbg_init(&connssl->ctr_drbg, entropy_func_mutex, &entropy, NULL, 0)) != 0) { -#ifdef POLARSSL_ERROR_C - error_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* POLARSSL_ERROR_C */ - failf(data, "Failed - PolarSSL: ctr_drbg_init returned (-0x%04X) %s\n", - -ret, errorbuf); + error_strerror(ret, errorbuf, sizeof(errorbuf)); + failf(data, "Failed - PolarSSL: ctr_drbg_init returned (-0x%04X) %s\n", + -ret, errorbuf); } #else entropy_init(&connssl->entropy); if((ret = ctr_drbg_init(&connssl->ctr_drbg, entropy_func, &connssl->entropy, NULL, 0)) != 0) { -#ifdef POLARSSL_ERROR_C - error_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* POLARSSL_ERROR_C */ - failf(data, "Failed - PolarSSL: ctr_drbg_init returned (-0x%04X) %s\n", - -ret, errorbuf); + error_strerror(ret, errorbuf, sizeof(errorbuf)); + failf(data, "Failed - PolarSSL: ctr_drbg_init returned (-0x%04X) %s\n", + -ret, errorbuf); } #endif /* THREADING_SUPPORT */ @@ -193,9 +185,7 @@ polarssl_connect_step1(struct connectdata *conn, data->set.str[STRING_SSL_CAFILE]); if(ret<0) { -#ifdef POLARSSL_ERROR_C error_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* POLARSSL_ERROR_C */ failf(data, "Error reading ca cert file %s - PolarSSL: (-0x%04X) %s", data->set.str[STRING_SSL_CAFILE], -ret, errorbuf); @@ -209,9 +199,7 @@ polarssl_connect_step1(struct connectdata *conn, data->set.str[STRING_SSL_CAPATH]); if(ret<0) { -#ifdef POLARSSL_ERROR_C error_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* POLARSSL_ERROR_C */ failf(data, "Error reading ca cert path %s - PolarSSL: (-0x%04X) %s", data->set.str[STRING_SSL_CAPATH], -ret, errorbuf); @@ -228,9 +216,7 @@ polarssl_connect_step1(struct connectdata *conn, data->set.str[STRING_CERT]); if(ret) { -#ifdef POLARSSL_ERROR_C error_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* POLARSSL_ERROR_C */ failf(data, "Error reading client cert file %s - PolarSSL: (-0x%04X) %s", data->set.str[STRING_CERT], -ret, errorbuf); @@ -253,9 +239,7 @@ polarssl_connect_step1(struct connectdata *conn, pk_free(&pk); if(ret) { -#ifdef POLARSSL_ERROR_C error_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* POLARSSL_ERROR_C */ failf(data, "Error reading private key %s - PolarSSL: (-0x%04X) %s", data->set.str[STRING_KEY], -ret, errorbuf); @@ -271,9 +255,7 @@ polarssl_connect_step1(struct connectdata *conn, data->set.str[STRING_SSL_CRLFILE]); if(ret) { -#ifdef POLARSSL_ERROR_C error_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* POLARSSL_ERROR_C */ failf(data, "Error reading CRL file %s - PolarSSL: (-0x%04X) %s", data->set.str[STRING_SSL_CRLFILE], -ret, errorbuf); @@ -344,13 +326,14 @@ polarssl_connect_step1(struct connectdata *conn, Curl_ssl_sessionid_lock(conn); if(!Curl_ssl_getsessionid(conn, &old_session, NULL)) { ret = ssl_set_session(&connssl->ssl, old_session); - Curl_ssl_sessionid_unlock(conn); if(ret) { + Curl_ssl_sessionid_unlock(conn); failf(data, "ssl_set_session returned -0x%x", -ret); return CURLE_SSL_CONNECT_ERROR; } infof(data, "PolarSSL re-using session\n"); } + Curl_ssl_sessionid_unlock(conn); } ssl_set_ca_chain(&connssl->ssl, @@ -401,7 +384,7 @@ polarssl_connect_step1(struct connectdata *conn, static CURLcode polarssl_connect_step2(struct connectdata *conn, - int sockindex) + int sockindex) { int ret; struct Curl_easy *data = conn->data; @@ -429,9 +412,7 @@ polarssl_connect_step2(struct connectdata *conn, return CURLE_OK; default: -#ifdef POLARSSL_ERROR_C error_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* POLARSSL_ERROR_C */ failf(data, "ssl_handshake returned - PolarSSL: (-0x%04X) %s", -ret, errorbuf); return CURLE_SSL_CONNECT_ERROR; @@ -538,9 +519,9 @@ polarssl_connect_step2(struct connectdata *conn, } else #endif - if(!strncmp(next_protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH)) { - conn->negnpn = CURL_HTTP_VERSION_1_1; - } + if(!strncmp(next_protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH)) { + conn->negnpn = CURL_HTTP_VERSION_1_1; + } } else infof(data, "ALPN, server did not agree to a protocol\n"); @@ -555,7 +536,7 @@ polarssl_connect_step2(struct connectdata *conn, static CURLcode polarssl_connect_step3(struct connectdata *conn, - int sockindex) + int sockindex) { CURLcode retcode = CURLE_OK; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; @@ -727,7 +708,8 @@ polarssl_connect_common(struct connectdata *conn, curl_socket_t readfd = ssl_connect_2_reading== connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - what = Curl_socket_ready(readfd, writefd, nonblocking?0:timeout_ms); + what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, + nonblocking?0:timeout_ms); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); @@ -786,8 +768,8 @@ polarssl_connect_common(struct connectdata *conn, CURLcode Curl_polarssl_connect_nonblocking(struct connectdata *conn, - int sockindex, - bool *done) + int sockindex, + bool *done) { return polarssl_connect_common(conn, sockindex, TRUE, done); } @@ -795,7 +777,7 @@ Curl_polarssl_connect_nonblocking(struct connectdata *conn, CURLcode Curl_polarssl_connect(struct connectdata *conn, - int sockindex) + int sockindex) { CURLcode result; bool done = FALSE; diff --git a/Utilities/cmcurl/lib/vtls/polarssl_threadlock.c b/Utilities/cmcurl/lib/vtls/polarssl_threadlock.c index 3b0ebf8..b1eb7b7 100644 --- a/Utilities/cmcurl/lib/vtls/polarssl_threadlock.c +++ b/Utilities/cmcurl/lib/vtls/polarssl_threadlock.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2013-2015, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2013-2016, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 2010, 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com> * * This software is licensed as described in the file COPYING, which @@ -52,7 +52,7 @@ int Curl_polarsslthreadlock_thread_setup(void) int i; int ret; - mutex_buf = malloc(NUMT * sizeof(POLARSSL_MUTEX_T)); + mutex_buf = calloc(NUMT * sizeof(POLARSSL_MUTEX_T), 1); if(!mutex_buf) return 0; /* error, no number of threads defined */ diff --git a/Utilities/cmcurl/lib/vtls/schannel.c b/Utilities/cmcurl/lib/vtls/schannel.c index f991ec9..f731eeb 100644 --- a/Utilities/cmcurl/lib/vtls/schannel.c +++ b/Utilities/cmcurl/lib/vtls/schannel.c @@ -127,6 +127,18 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) infof(data, "schannel: SSL/TLS connection with %s port %hu (step 1/3)\n", conn->host.name, conn->remote_port); +#ifdef HAS_ALPN + /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above. + Also it doesn't seem to be supported for Wine, see curl bug #983. */ + connssl->use_alpn = conn->bits.tls_enable_alpn && + !GetProcAddress(GetModuleHandleA("ntdll"), + "wine_get_version") && + Curl_verify_windows_version(6, 3, PLATFORM_WINNT, + VERSION_GREATER_THAN_EQUAL); +#else + connssl->use_alpn = false; +#endif + connssl->cred = NULL; /* check for an existing re-usable credential handle */ @@ -250,10 +262,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) } #ifdef HAS_ALPN - /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above */ - if(conn->bits.tls_enable_alpn && - Curl_verify_windows_version(6, 3, PLATFORM_WINNT, - VERSION_GREATER_THAN_EQUAL)) { + if(connssl->use_alpn) { int cur = 0; int list_start_index = 0; unsigned int* extension_len = NULL; @@ -328,11 +337,17 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) if(!host_name) return CURLE_OUT_OF_MEMORY; - /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx */ + /* Schannel InitializeSecurityContext: + https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx + At the moment we don't pass inbuf unless we're using ALPN since we only + use it for that, and Wine (for which we currently disable ALPN) is giving + us problems with inbuf regardless. https://github.com/curl/curl/issues/983 + */ sspi_status = s_pSecFn->InitializeSecurityContext( - &connssl->cred->cred_handle, NULL, host_name, - connssl->req_flags, 0, 0, &inbuf_desc, 0, &connssl->ctxt->ctxt_handle, + &connssl->cred->cred_handle, NULL, host_name, connssl->req_flags, 0, 0, + (connssl->use_alpn ? &inbuf_desc : NULL), + 0, &connssl->ctxt->ctxt_handle, &outbuf_desc, &connssl->ret_flags, &connssl->ctxt->time_stamp); Curl_unicodefree(host_name); @@ -651,10 +666,7 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) } #ifdef HAS_ALPN - /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above */ - if(conn->bits.tls_enable_alpn && - Curl_verify_windows_version(6, 3, PLATFORM_WINNT, - VERSION_GREATER_THAN_EQUAL)) { + if(connssl->use_alpn) { sspi_status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle, SECPKG_ATTR_APPLICATION_PROTOCOL, &alpn_result); @@ -803,7 +815,8 @@ schannel_connect_common(struct connectdata *conn, int sockindex, curl_socket_t readfd = ssl_connect_2_reading == connssl->connecting_state ? sockfd : CURL_SOCKET_BAD; - what = Curl_socket_ready(readfd, writefd, nonblocking ? 0 : timeout_ms); + what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, + nonblocking ? 0 : timeout_ms); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL/TLS socket, errno: %d", SOCKERRNO); @@ -959,8 +972,7 @@ schannel_send(struct connectdata *conn, int sockindex, break; } - what = Curl_socket_ready(CURL_SOCKET_BAD, conn->sock[sockindex], - timeleft); + what = SOCKET_WRITABLE(conn->sock[sockindex], timeleft); if(what < 0) { /* fatal error */ failf(conn->data, "select/poll on SSL socket, errno: %d", SOCKERRNO); diff --git a/Utilities/cmcurl/lib/vtls/vtls.c b/Utilities/cmcurl/lib/vtls/vtls.c index 3863777..56a8823 100644 --- a/Utilities/cmcurl/lib/vtls/vtls.c +++ b/Utilities/cmcurl/lib/vtls/vtls.c @@ -61,7 +61,7 @@ #include "vtls.h" /* generic SSL protos etc */ #include "slist.h" #include "sendf.h" -#include "rawstr.h" +#include "strcase.h" #include "url.h" #include "progress.h" #include "share.h" @@ -84,7 +84,7 @@ static bool safe_strequal(char* str1, char* str2) { if(str1 && str2) /* both pointers point to something then compare them */ - return (0 != Curl_raw_equal(str1, str2)) ? TRUE : FALSE; + return (0 != strcasecompare(str1, str2)) ? TRUE : FALSE; else /* if both pointers are NULL then treat them as equal */ return (!str1 && !str2) ? TRUE : FALSE; @@ -100,8 +100,6 @@ Curl_ssl_config_matches(struct ssl_config_data* data, safe_strequal(data->CApath, needle->CApath) && safe_strequal(data->CAfile, needle->CAfile) && safe_strequal(data->clientcert, needle->clientcert) && - safe_strequal(data->random_file, needle->random_file) && - safe_strequal(data->egdsocket, needle->egdsocket) && safe_strequal(data->cipher_list, needle->cipher_list)) return TRUE; @@ -392,14 +390,15 @@ bool Curl_ssl_getsessionid(struct connectdata *conn, if(!check->sessionid) /* not session ID means blank entry */ continue; - if(Curl_raw_equal(conn->host.name, check->name) && + if(strcasecompare(conn->host.name, check->name) && ((!conn->bits.conn_to_host && !check->conn_to_host) || - (conn->bits.conn_to_host && check->conn_to_host && - Curl_raw_equal(conn->conn_to_host.name, check->conn_to_host))) && + (conn->bits.conn_to_host && check->conn_to_host && + strcasecompare(conn->conn_to_host.name, check->conn_to_host))) && ((!conn->bits.conn_to_port && check->conn_to_port == -1) || - (conn->bits.conn_to_port && check->conn_to_port != -1 && - conn->conn_to_port == check->conn_to_port)) && + (conn->bits.conn_to_port && check->conn_to_port != -1 && + conn->conn_to_port == check->conn_to_port)) && (conn->remote_port == check->remote_port) && + strcasecompare(conn->handler->scheme, check->scheme) && Curl_ssl_config_matches(&conn->ssl_config, &check->ssl_config)) { /* yes, we have a session ID! */ (*general_age)++; /* increase general age */ @@ -530,6 +529,7 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, store->conn_to_host = clone_conn_to_host; /* clone connect to host name */ store->conn_to_port = conn_to_port; /* connect to port number */ store->remote_port = conn->remote_port; /* port number */ + store->scheme = conn->handler->scheme; if(!Curl_clone_ssl_config(&conn->ssl_config, &store->ssl_config)) { store->sessionid = NULL; /* let caller free sessionid */ diff --git a/Utilities/cmcurl/lib/x509asn1.c b/Utilities/cmcurl/lib/x509asn1.c index e17bcd9..74a511b 100644 --- a/Utilities/cmcurl/lib/x509asn1.c +++ b/Utilities/cmcurl/lib/x509asn1.c @@ -27,7 +27,7 @@ #include <curl/curl.h> #include "urldata.h" -#include "strequal.h" +#include "strcase.h" #include "hostcheck.h" #include "vtls/vtls.h" #include "sendf.h" @@ -178,7 +178,7 @@ static const curl_OID * searchOID(const char * oid) Return the table entry pointer or NULL if not found. */ for(op = OIDtable; op->numoid; op++) - if(!strcmp(op->numoid, oid) || curl_strequal(op->textoid, oid)) + if(!strcmp(op->numoid, oid) || strcasecompare(op->textoid, oid)) return op; return (const curl_OID *) NULL; @@ -817,7 +817,7 @@ static void do_pubkey(struct Curl_easy * data, int certnum, /* Get the public key (single element). */ Curl_getASN1Element(&pk, pubkey->beg + 1, pubkey->end); - if(curl_strequal(algo, "rsaEncryption")) { + if(strcasecompare(algo, "rsaEncryption")) { p = Curl_getASN1Element(&elem, pk.beg, pk.end); /* Compute key length. */ for(q = elem.beg; !*q && q < elem.end; q++) @@ -842,7 +842,7 @@ static void do_pubkey(struct Curl_easy * data, int certnum, Curl_getASN1Element(&elem, p, pk.end); do_pubkey_field(data, certnum, "rsa(e)", &elem); } - else if(curl_strequal(algo, "dsa")) { + else if(strcasecompare(algo, "dsa")) { p = Curl_getASN1Element(&elem, param->beg, param->end); do_pubkey_field(data, certnum, "dsa(p)", &elem); p = Curl_getASN1Element(&elem, p, param->end); @@ -851,7 +851,7 @@ static void do_pubkey(struct Curl_easy * data, int certnum, do_pubkey_field(data, certnum, "dsa(g)", &elem); do_pubkey_field(data, certnum, "dsa(pub_key)", &pk); } - else if(curl_strequal(algo, "dhpublicnumber")) { + else if(strcasecompare(algo, "dhpublicnumber")) { p = Curl_getASN1Element(&elem, param->beg, param->end); do_pubkey_field(data, certnum, "dh(p)", &elem); Curl_getASN1Element(&elem, param->beg, param->end); @@ -859,7 +859,7 @@ static void do_pubkey(struct Curl_easy * data, int certnum, do_pubkey_field(data, certnum, "dh(pub_key)", &pk); } #if 0 /* Patent-encumbered. */ - else if(curl_strequal(algo, "ecPublicKey")) { + else if(strcasecompare(algo, "ecPublicKey")) { /* Left TODO. */ } #endif |