From 740890e402705c7aec8d9655f25118082f43e315 Mon Sep 17 00:00:00 2001 From: tastytea Date: Wed, 14 Aug 2019 00:15:04 +0200 Subject: [PATCH 01/25] Modernized CMake recipes. --- CMakeLists.txt | 149 +++++++++++------------------- cmake/CMakeLists.txt | 19 ++++ cmake/mastodon-cppConfig.cmake.in | 8 ++ cmake/packages.cmake | 40 ++++++++ examples/CMakeLists.txt | 11 +++ packages.CMakeLists.txt | 54 ----------- src/CMakeLists.txt | 53 +++++++++++ tests/CMakeLists.txt | 13 ++- 8 files changed, 194 insertions(+), 153 deletions(-) create mode 100644 cmake/CMakeLists.txt create mode 100644 cmake/mastodon-cppConfig.cmake.in create mode 100644 cmake/packages.cmake create mode 100644 examples/CMakeLists.txt delete mode 100644 packages.CMakeLists.txt create mode 100644 src/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index bf7f5d9..126d66d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,124 +1,85 @@ -cmake_minimum_required (VERSION 3.6) -project (mastodon-cpp - VERSION 0.106.0 - LANGUAGES CXX - ) - -set(WITH_EASY "YES" CACHE STRING "WITH_EASY defaults to \"YES\"") -set(WITH_EXAMPLES "NO" CACHE STRING "WITH_EXAMPLES defaults to \"NO\"") -set(WITH_TESTS "NO" CACHE STRING "WITH_TESTS defaults to \"NO\"") -set(WITH_DOC "YES" CACHE STRING "WITH_DOC defaults to \"YES\"") -set(WITH_DEB "NO" CACHE STRING "WITH_DEB defaults to \"NO\"") -set(WITH_RPM "NO" CACHE STRING "WITH_RPM defaults to \"NO\"") +# Support version 3.6 and above, but use policy settings up to 3.14. +# 3.6 is needed because of IMPORTED_TARGET in pkg_check_modules(). +cmake_minimum_required(VERSION 3.6...3.14) +# Ranges are supported from 3.12, set policy to current for < 3.12. +if(${CMAKE_VERSION} VERSION_LESS 3.12) + cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) +endif() include(GNUInstallDirs) -find_package(PkgConfig REQUIRED) -find_package(PkgConfig REQUIRED) -pkg_check_modules(CURLPP REQUIRED curlpp) -if(WITH_EASY) - pkg_check_modules(JSONCPP REQUIRED jsoncpp) + +project (mastodon-cpp + VERSION 0.106.0 + LANGUAGES CXX) + +# DESCRIPTION was introduced in version 3.9. +if(NOT (${CMAKE_VERSION} VERSION_LESS 3.9)) + set(PROJECT_DESCRIPTION + "C++ wrapper for the Mastodon API.") endif() +option(WITH_EASY "Compile Easy interface." YES) +option(WITH_EXAMPLES "Compile examples." NO) +option(WITH_TESTS "Compile tests." NO) +option(WITH_DOC "Generate HTML documentation." YES) +option(WITH_DEB "Prepare for the building of .deb packages." NO) +option(WITH_RPM "Prepare for the building of .rpm packages." NO) +option(BUILD_SHARED_LIBS "Build shared libraries." YES) +set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type, Release or Debug.") + set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) -set(CMAKE_CXX_FLAGS_DEBUG - "${CMAKE_CXX_FLAGS_DEBUG} -Wall -Wextra -Wpedantic -ftrapv -fsanitize=undefined -g -Og -fno-omit-frame-pointer") - -# Do not complain about compatibility-wrapper -if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations") +set(DEBUG_CXXFLAGS + "-Wall" + "-Wextra" + "-Wpedantic" + "-ftrapv" + "-fsanitize=undefined" + "-g" + "-Og" + "-fno-omit-frame-pointer" + "-Wno-deprecated-declarations") +set(DEBUG_LDFLAGS + "-fsanitize=undefined") +add_compile_options("$<$:${DEBUG_CXXFLAGS}>") +# add_link_options was introduced in version 3.13. +if(${CMAKE_VERSION} VERSION_LESS 3.13) + set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${DEBUG_LDFLAGS}") +else() + add_link_options("$<$:${DEBUG_LDFLAGS}>") endif() -include_directories(${PROJECT_SOURCE_DIR}/src) -include_directories(${PROJECT_BINARY_DIR}) - -include_directories(${CURL_INCLUDE_DIRS}) -include_directories(${CURLPP_INCLUDE_DIRS}) -include_directories(${JSONCPP_INCLUDE_DIRS}) - -link_directories(${CURL_LIBRARY_DIRS}) -link_directories(${CURLPP_LIBRARY_DIRS}) -link_directories(${JSONCPP_LIBRARY_DIRS}) - -# Write version in header -configure_file ( - "${PROJECT_SOURCE_DIR}/src/version.hpp.in" - "${PROJECT_BINARY_DIR}/version.hpp" -) - +# Turn on debug output. if(CMAKE_BUILD_TYPE STREQUAL "Debug") - add_definitions(-DDEBUG=1) + add_definitions("-DDEBUG=1") endif() if(NOT WITH_EASY) - add_definitions(-DWITHOUT_EASY=1) + add_definitions("-DWITHOUT_EASY=1") endif() -# Compile library -if(WITH_EASY) - file(GLOB sources src/*.cpp src/api/*.cpp - src/easy/*.cpp src/easy/entities/*.cpp) -else() - file(GLOB sources src/*.cpp src/api/*.cpp) -endif() -add_library(${PROJECT_NAME} SHARED ${sources}) -set_target_properties(${PROJECT_NAME} PROPERTIES - VERSION ${PROJECT_VERSION} - SOVERSION ${${PROJECT_NAME}_VERSION_MAJOR} - ) +add_subdirectory("src") -if(WITH_EASY) - target_link_libraries(${PROJECT_NAME} - ${CURLPP_LIBRARIES} pthread ${JSONCPP_LIBRARIES}) -else() - target_link_libraries(${PROJECT_NAME} - ${CURLPP_LIBRARIES} pthread) -endif() - -# Compile examples if(WITH_EXAMPLES) - file(GLOB sources_examples examples/*.cpp) - foreach(src ${sources_examples}) - get_filename_component(bin ${src} NAME_WE) - add_executable(${bin} ${src}) - target_link_libraries(${bin} pthread ${JSONCPP_LIBRARIES} ${PROJECT_NAME}) - endforeach() + add_subdirectory("examples") endif() -# Compile tests if(WITH_TESTS) - configure_file("tests/test.gif" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY) - add_subdirectory(tests) + add_subdirectory("tests") endif() -# Install library and header files -install(TARGETS ${PROJECT_NAME} LIBRARY - DESTINATION ${CMAKE_INSTALL_LIBDIR}) -install(FILES src/mastodon-cpp.hpp src/return_types.hpp src/types.hpp - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}) -if(WITH_EASY) - file(GLOB easy_header src/easy/*.hpp) - install(FILES ${easy_header} - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}/easy) - file(GLOB easy_entities_header src/easy/entities/*.hpp) - install(FILES ${easy_entities_header} - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}/easy/entities) -endif() - -# Compile & install documentation if(WITH_DOC) add_custom_command(OUTPUT ${PROJECT_SOURCE_DIR}/doc/html - COMMAND ./build_doc.sh WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) + COMMAND "./build_doc.sh" WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) add_custom_target(doc DEPENDS doc/html) add_dependencies(${PROJECT_NAME} doc) + install(DIRECTORY ${PROJECT_SOURCE_DIR}/doc/html - DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/doc/${PROJECT_NAME}-${PROJECT_VERSION}) - file(GLOB examples examples/example*.cpp) - install(FILES ${examples} - DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/doc/${PROJECT_NAME}-${PROJECT_VERSION}/examples) + DESTINATION "${CMAKE_INSTALL_DOCDIR}") endif() -# Packages -include(packages.CMakeLists.txt) +add_subdirectory("cmake") + +include("cmake/packages.cmake") diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt new file mode 100644 index 0000000..33a0740 --- /dev/null +++ b/cmake/CMakeLists.txt @@ -0,0 +1,19 @@ +include(CMakePackageConfigHelpers) +include(GNUInstallDirs) + +write_basic_package_version_file("${PROJECT_NAME}ConfigVersion.cmake" + VERSION ${PACKAGE_VERSION} + COMPATIBILITY ExactVersion) # TODO: Set to SameMajorVersion when stable. + +install(EXPORT ${PROJECT_NAME}Targets + FILE "${PROJECT_NAME}Targets.cmake" + NAMESPACE "${PROJECT_NAME}::" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") + +configure_file("${PROJECT_NAME}Config.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" @ONLY) + +install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") diff --git a/cmake/mastodon-cppConfig.cmake.in b/cmake/mastodon-cppConfig.cmake.in new file mode 100644 index 0000000..c3cffe3 --- /dev/null +++ b/cmake/mastodon-cppConfig.cmake.in @@ -0,0 +1,8 @@ +include(CMakeFindDependencyMacro) +include(GNUInstallDirs) + +find_depencency(jsoncpp REQUIRED CONFIG) +find_dependency(PkgConfig REQUIRED) +pkg_check_modules(curlpp REQUIRED IMPORTED_TARGET curlpp) + +include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") diff --git a/cmake/packages.cmake b/cmake/packages.cmake new file mode 100644 index 0000000..743b52b --- /dev/null +++ b/cmake/packages.cmake @@ -0,0 +1,40 @@ +set(CPACK_PACKAGE_NAME ${PROJECT_NAME}) +set(CPACK_PACKAGE_VERSION_MAJOR ${${PROJECT_NAME}_VERSION_MAJOR}) +set(CPACK_PACKAGE_VERSION_MINOR ${${PROJECT_NAME}_VERSION_MINOR}) +set(CPACK_PACKAGE_VERSION_PATCH ${${PROJECT_NAME}_VERSION_PATCH}) +set(CPACK_PACKAGE_VERSION ${mastodon-cpp_VERSION}) +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PROJECT_DESCRIPTION}") +set(CPACK_PACKAGE_CONTACT "tastytea ") +set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE") +set(CPACK_RESOURCE_FILE_README "${PROJECT_SOURCE_DIR}/README.adoc") + +execute_process(COMMAND uname -m + OUTPUT_VARIABLE CPACK_PACKAGE_ARCHITECTURE OUTPUT_STRIP_TRAILING_WHITESPACE) +set(CPACK_PACKAGE_FILE_NAME + "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}_${CPACK_PACKAGE_ARCHITECTURE}") +set(CPACK_GENERATOR "TGZ") + +if (WITH_DEB) + set(CPACK_PACKAGE_NAME "lib${PROJECT_NAME}") + set(CPACK_GENERATOR "DEB") + set(CPACK_DEBIAN_PACKAGE_HOMEPAGE + "https://schlomp.space/tastytea/${PROJECT_NAME}") + set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) + execute_process(COMMAND dpkg --print-architecture + OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE + OUTPUT_STRIP_TRAILING_WHITESPACE) + set(CPACK_PACKAGE_FILE_NAME + "${CPACK_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}-0_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}") +endif() + +if (WITH_RPM) + set(CPACK_PACKAGE_NAME "lib${PROJECT_NAME}") + set(CPACK_GENERATOR "RPM") + set(CPACK_RPM_PACKAGE_LICENSE "GPL-3") + set(CPACK_RPM_PACKAGE_URL "https://schlomp.space/tastytea/${PROJECT_NAME}") + set(CPACK_RPM_PACKAGE_REQUIRES "curlpp >= 0.8.1 jsoncpp, >= 1.7.4") + set(CPACK_PACKAGE_FILE_NAME + "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-0.${CPACK_PACKAGE_ARCHITECTURE}") +endif() + +include(CPack) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000..23cc73a --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,11 @@ +file(GLOB sources_examples *.cpp) +foreach(src ${sources_examples}) + get_filename_component(bin ${src} NAME_WE) + add_executable(${bin} ${src}) + target_link_libraries(${bin} PRIVATE ${PROJECT_NAME}) +endforeach() + +if(WITH_DOC) + install(FILES ${sources_examples} + DESTINATION "${CMAKE_INSTALL_DOCDIR}/examples") +endif() diff --git a/packages.CMakeLists.txt b/packages.CMakeLists.txt deleted file mode 100644 index 505f667..0000000 --- a/packages.CMakeLists.txt +++ /dev/null @@ -1,54 +0,0 @@ -set(CPACK_PACKAGE_NAME ${PROJECT_NAME}) -set(CPACK_PACKAGE_VERSION_MAJOR ${${PROJECT_NAME}_VERSION_MAJOR}) -set(CPACK_PACKAGE_VERSION_MINOR ${${PROJECT_NAME}_VERSION_MINOR}) -set(CPACK_PACKAGE_VERSION_PATCH ${${PROJECT_NAME}_VERSION_PATCH}) -set(CPACK_PACKAGE_VERSION ${mastodon-cpp_VERSION}) -set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "C++ wrapper for the Mastodon API") -set(CPACK_PACKAGE_CONTACT "tastytea ") -set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE") -set(CPACK_RESOURCE_FILE_README "${PROJECT_SOURCE_DIR}/README.adoc") -list(APPEND CPACK_SOURCE_IGNORE_FILES "/\\\\.git" - "/.gitignore" - "/build/" - "/doc/" - "\\\\.sublime-" - "/update_doc.sh" - "/.drone.yml" - "/ISSUE_TEMPLATE.md$") -execute_process(COMMAND uname -m - OUTPUT_VARIABLE CPACK_PACKAGE_ARCHITECTURE - OUTPUT_STRIP_TRAILING_WHITESPACE) -set(CPACK_PACKAGE_FILE_NAME - "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}_${CPACK_PACKAGE_ARCHITECTURE}") -set(CPACK_GENERATOR "TGZ") -set(CPACK_SOURCE_GENERATOR "TGZ") - -if (WITH_DEB) - set(CPACK_PACKAGE_NAME "lib${PROJECT_NAME}") - set(CPACK_GENERATOR "DEB") - set(CPACK_SOURCE_GENERATOR "DEB") - set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "https://schlomp.space/tastytea/mastodon-cpp") - set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) - execute_process(COMMAND dpkg --print-architecture - OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE - OUTPUT_STRIP_TRAILING_WHITESPACE) - set(CPACK_PACKAGE_FILE_NAME - "${CPACK_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}-0_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}") - set(CPACK_SOURCE_PACKAGE_FILE_NAME - "${CPACK_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}-0_src") -endif() - -if (WITH_RPM) - set(CPACK_PACKAGE_NAME "lib${PROJECT_NAME}") - set(CPACK_GENERATOR "RPM") - set(CPACK_SOURCE_GENERATOR "RPM") - set(CPACK_RPM_PACKAGE_LICENSE "GPL-3") - set(CPACK_RPM_PACKAGE_URL "https://schlomp.space/tastytea/mastodon-cpp") - set(CPACK_RPM_PACKAGE_REQUIRES "curlpp >= 0.8.1 jsoncpp, >= 1.7.4") - set(CPACK_PACKAGE_FILE_NAME - "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-0.${CPACK_PACKAGE_ARCHITECTURE}") - set(CPACK_SOURCE_PACKAGE_FILE_NAME - "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-0.src") -endif() - -include(CPack) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..cf39f14 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,53 @@ +include(GNUInstallDirs) + +find_package(PkgConfig REQUIRED) +pkg_check_modules(curlpp REQUIRED IMPORTED_TARGET curlpp) +if(WITH_EASY) + find_package(jsoncpp REQUIRED CONFIG) +endif() + +if(WITH_EASY) + file(GLOB_RECURSE sources *.cpp *.hpp) +else() + file(GLOB sources *.cpp api/*.cpp *.hpp api/*.hpp) +endif() + +# Write version in header +configure_file ("version.hpp.in" + "${CMAKE_CURRENT_BINARY_DIR}/version.hpp") + +add_library(${PROJECT_NAME} ${sources}) +set_target_properties(${PROJECT_NAME} PROPERTIES + VERSION ${PROJECT_VERSION} + SOVERSION ${${PROJECT_NAME}_VERSION_MAJOR}) + +target_include_directories(${PROJECT_NAME} + PRIVATE + "$" + PUBLIC + "$" + "$") + +if(WITH_EASY) + target_link_libraries(${PROJECT_NAME} + PUBLIC pthread PkgConfig::curlpp jsoncpp_lib) +else() + target_link_libraries(${PROJECT_NAME} + PUBLIC pthread PkgConfig::curlpp) +endif() + +install(TARGETS ${PROJECT_NAME} + EXPORT "${PROJECT_NAME}Targets" + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}") + +install(FILES mastodon-cpp.hpp return_types.hpp types.hpp + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}) +if(WITH_EASY) + file(GLOB easy_header easy/*.hpp) + install(FILES ${easy_header} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}/easy) + file(GLOB easy_entities_header easy/entities/*.hpp) + install(FILES ${easy_entities_header} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}/easy/entities) +endif() diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index bc5ab0c..8cd0771 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,20 +1,23 @@ include(CTest) -file(GLOB sources_tests test_*.cpp */test_*.cpp) + +file(GLOB_RECURSE sources_tests test_*.cpp) + +configure_file("test.gif" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY) find_package(Catch2) -if(Catch2_FOUND) # Catch 2.x +if(Catch2_FOUND) # Catch 2.x include(Catch) add_executable(all_tests main.cpp ${sources_tests}) - target_link_libraries(all_tests ${PROJECT_NAME} Catch2::Catch2) + target_link_libraries(all_tests PRIVATE ${PROJECT_NAME} Catch2::Catch2) target_include_directories(all_tests PRIVATE "/usr/include/catch2") catch_discover_tests(all_tests EXTRA_ARGS "${EXTRA_TEST_ARGS}") -else() # Catch 1.x +else() # Catch 1.x if(EXISTS "/usr/include/catch.hpp") message(STATUS "Catch 1.x found.") foreach(src ${sources_tests}) get_filename_component(bin ${src} NAME_WE) add_executable(${bin} main.cpp ${src}) - target_link_libraries(${bin} ${PROJECT_NAME}) + target_link_libraries(${bin} PRIVATE ${PROJECT_NAME}) add_test(${bin} ${bin} "${EXTRA_TEST_ARGS}") endforeach() else() From 72efbb515dbc8c201b7762a7e6f658d81107436b Mon Sep 17 00:00:00 2001 From: tastytea Date: Wed, 14 Aug 2019 00:19:12 +0200 Subject: [PATCH 02/25] Add pkg-config recipe. --- CMakeLists.txt | 1 + pkg-config/CMakeLists.txt | 7 +++++++ pkg-config/mastodon-cpp.pc.in | 11 +++++++++++ 3 files changed, 19 insertions(+) create mode 100644 pkg-config/CMakeLists.txt create mode 100644 pkg-config/mastodon-cpp.pc.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 126d66d..8fcf9b3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -81,5 +81,6 @@ if(WITH_DOC) endif() add_subdirectory("cmake") +add_subdirectory("pkg-config") include("cmake/packages.cmake") diff --git a/pkg-config/CMakeLists.txt b/pkg-config/CMakeLists.txt new file mode 100644 index 0000000..4640f17 --- /dev/null +++ b/pkg-config/CMakeLists.txt @@ -0,0 +1,7 @@ +include(GNUInstallDirs) + +configure_file("${PROJECT_NAME}.pc.in" + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc" @ONLY) + +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") diff --git a/pkg-config/mastodon-cpp.pc.in b/pkg-config/mastodon-cpp.pc.in new file mode 100644 index 0000000..40f0ccd --- /dev/null +++ b/pkg-config/mastodon-cpp.pc.in @@ -0,0 +1,11 @@ +name=@PROJECT_NAME@ +prefix=@CMAKE_INSTALL_PREFIX@ +libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ +includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ + +Name: ${name} +Description: @PROJECT_DESCRIPTION@ +Version: @PROJECT_VERSION@ +Cflags: -I${includedir} +Libs: -L${libdir} -l${name} -lpthread +Requires: jsoncpp curlpp From 5f730200567ef1cd0761adc08aaf77e72b425dcf Mon Sep 17 00:00:00 2001 From: tastytea Date: Wed, 14 Aug 2019 00:15:04 +0200 Subject: [PATCH 03/25] Modernized CMake recipes. --- CMakeLists.txt | 149 +++++++++++------------------- cmake/CMakeLists.txt | 19 ++++ cmake/mastodon-cppConfig.cmake.in | 8 ++ cmake/packages.cmake | 40 ++++++++ examples/CMakeLists.txt | 11 +++ packages.CMakeLists.txt | 54 ----------- src/CMakeLists.txt | 53 +++++++++++ tests/CMakeLists.txt | 13 ++- 8 files changed, 194 insertions(+), 153 deletions(-) create mode 100644 cmake/CMakeLists.txt create mode 100644 cmake/mastodon-cppConfig.cmake.in create mode 100644 cmake/packages.cmake create mode 100644 examples/CMakeLists.txt delete mode 100644 packages.CMakeLists.txt create mode 100644 src/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index bf7f5d9..126d66d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,124 +1,85 @@ -cmake_minimum_required (VERSION 3.6) -project (mastodon-cpp - VERSION 0.106.0 - LANGUAGES CXX - ) - -set(WITH_EASY "YES" CACHE STRING "WITH_EASY defaults to \"YES\"") -set(WITH_EXAMPLES "NO" CACHE STRING "WITH_EXAMPLES defaults to \"NO\"") -set(WITH_TESTS "NO" CACHE STRING "WITH_TESTS defaults to \"NO\"") -set(WITH_DOC "YES" CACHE STRING "WITH_DOC defaults to \"YES\"") -set(WITH_DEB "NO" CACHE STRING "WITH_DEB defaults to \"NO\"") -set(WITH_RPM "NO" CACHE STRING "WITH_RPM defaults to \"NO\"") +# Support version 3.6 and above, but use policy settings up to 3.14. +# 3.6 is needed because of IMPORTED_TARGET in pkg_check_modules(). +cmake_minimum_required(VERSION 3.6...3.14) +# Ranges are supported from 3.12, set policy to current for < 3.12. +if(${CMAKE_VERSION} VERSION_LESS 3.12) + cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) +endif() include(GNUInstallDirs) -find_package(PkgConfig REQUIRED) -find_package(PkgConfig REQUIRED) -pkg_check_modules(CURLPP REQUIRED curlpp) -if(WITH_EASY) - pkg_check_modules(JSONCPP REQUIRED jsoncpp) + +project (mastodon-cpp + VERSION 0.106.0 + LANGUAGES CXX) + +# DESCRIPTION was introduced in version 3.9. +if(NOT (${CMAKE_VERSION} VERSION_LESS 3.9)) + set(PROJECT_DESCRIPTION + "C++ wrapper for the Mastodon API.") endif() +option(WITH_EASY "Compile Easy interface." YES) +option(WITH_EXAMPLES "Compile examples." NO) +option(WITH_TESTS "Compile tests." NO) +option(WITH_DOC "Generate HTML documentation." YES) +option(WITH_DEB "Prepare for the building of .deb packages." NO) +option(WITH_RPM "Prepare for the building of .rpm packages." NO) +option(BUILD_SHARED_LIBS "Build shared libraries." YES) +set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type, Release or Debug.") + set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) -set(CMAKE_CXX_FLAGS_DEBUG - "${CMAKE_CXX_FLAGS_DEBUG} -Wall -Wextra -Wpedantic -ftrapv -fsanitize=undefined -g -Og -fno-omit-frame-pointer") - -# Do not complain about compatibility-wrapper -if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations") +set(DEBUG_CXXFLAGS + "-Wall" + "-Wextra" + "-Wpedantic" + "-ftrapv" + "-fsanitize=undefined" + "-g" + "-Og" + "-fno-omit-frame-pointer" + "-Wno-deprecated-declarations") +set(DEBUG_LDFLAGS + "-fsanitize=undefined") +add_compile_options("$<$:${DEBUG_CXXFLAGS}>") +# add_link_options was introduced in version 3.13. +if(${CMAKE_VERSION} VERSION_LESS 3.13) + set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${DEBUG_LDFLAGS}") +else() + add_link_options("$<$:${DEBUG_LDFLAGS}>") endif() -include_directories(${PROJECT_SOURCE_DIR}/src) -include_directories(${PROJECT_BINARY_DIR}) - -include_directories(${CURL_INCLUDE_DIRS}) -include_directories(${CURLPP_INCLUDE_DIRS}) -include_directories(${JSONCPP_INCLUDE_DIRS}) - -link_directories(${CURL_LIBRARY_DIRS}) -link_directories(${CURLPP_LIBRARY_DIRS}) -link_directories(${JSONCPP_LIBRARY_DIRS}) - -# Write version in header -configure_file ( - "${PROJECT_SOURCE_DIR}/src/version.hpp.in" - "${PROJECT_BINARY_DIR}/version.hpp" -) - +# Turn on debug output. if(CMAKE_BUILD_TYPE STREQUAL "Debug") - add_definitions(-DDEBUG=1) + add_definitions("-DDEBUG=1") endif() if(NOT WITH_EASY) - add_definitions(-DWITHOUT_EASY=1) + add_definitions("-DWITHOUT_EASY=1") endif() -# Compile library -if(WITH_EASY) - file(GLOB sources src/*.cpp src/api/*.cpp - src/easy/*.cpp src/easy/entities/*.cpp) -else() - file(GLOB sources src/*.cpp src/api/*.cpp) -endif() -add_library(${PROJECT_NAME} SHARED ${sources}) -set_target_properties(${PROJECT_NAME} PROPERTIES - VERSION ${PROJECT_VERSION} - SOVERSION ${${PROJECT_NAME}_VERSION_MAJOR} - ) +add_subdirectory("src") -if(WITH_EASY) - target_link_libraries(${PROJECT_NAME} - ${CURLPP_LIBRARIES} pthread ${JSONCPP_LIBRARIES}) -else() - target_link_libraries(${PROJECT_NAME} - ${CURLPP_LIBRARIES} pthread) -endif() - -# Compile examples if(WITH_EXAMPLES) - file(GLOB sources_examples examples/*.cpp) - foreach(src ${sources_examples}) - get_filename_component(bin ${src} NAME_WE) - add_executable(${bin} ${src}) - target_link_libraries(${bin} pthread ${JSONCPP_LIBRARIES} ${PROJECT_NAME}) - endforeach() + add_subdirectory("examples") endif() -# Compile tests if(WITH_TESTS) - configure_file("tests/test.gif" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY) - add_subdirectory(tests) + add_subdirectory("tests") endif() -# Install library and header files -install(TARGETS ${PROJECT_NAME} LIBRARY - DESTINATION ${CMAKE_INSTALL_LIBDIR}) -install(FILES src/mastodon-cpp.hpp src/return_types.hpp src/types.hpp - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}) -if(WITH_EASY) - file(GLOB easy_header src/easy/*.hpp) - install(FILES ${easy_header} - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}/easy) - file(GLOB easy_entities_header src/easy/entities/*.hpp) - install(FILES ${easy_entities_header} - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}/easy/entities) -endif() - -# Compile & install documentation if(WITH_DOC) add_custom_command(OUTPUT ${PROJECT_SOURCE_DIR}/doc/html - COMMAND ./build_doc.sh WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) + COMMAND "./build_doc.sh" WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) add_custom_target(doc DEPENDS doc/html) add_dependencies(${PROJECT_NAME} doc) + install(DIRECTORY ${PROJECT_SOURCE_DIR}/doc/html - DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/doc/${PROJECT_NAME}-${PROJECT_VERSION}) - file(GLOB examples examples/example*.cpp) - install(FILES ${examples} - DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/doc/${PROJECT_NAME}-${PROJECT_VERSION}/examples) + DESTINATION "${CMAKE_INSTALL_DOCDIR}") endif() -# Packages -include(packages.CMakeLists.txt) +add_subdirectory("cmake") + +include("cmake/packages.cmake") diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt new file mode 100644 index 0000000..33a0740 --- /dev/null +++ b/cmake/CMakeLists.txt @@ -0,0 +1,19 @@ +include(CMakePackageConfigHelpers) +include(GNUInstallDirs) + +write_basic_package_version_file("${PROJECT_NAME}ConfigVersion.cmake" + VERSION ${PACKAGE_VERSION} + COMPATIBILITY ExactVersion) # TODO: Set to SameMajorVersion when stable. + +install(EXPORT ${PROJECT_NAME}Targets + FILE "${PROJECT_NAME}Targets.cmake" + NAMESPACE "${PROJECT_NAME}::" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") + +configure_file("${PROJECT_NAME}Config.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" @ONLY) + +install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") diff --git a/cmake/mastodon-cppConfig.cmake.in b/cmake/mastodon-cppConfig.cmake.in new file mode 100644 index 0000000..c3cffe3 --- /dev/null +++ b/cmake/mastodon-cppConfig.cmake.in @@ -0,0 +1,8 @@ +include(CMakeFindDependencyMacro) +include(GNUInstallDirs) + +find_depencency(jsoncpp REQUIRED CONFIG) +find_dependency(PkgConfig REQUIRED) +pkg_check_modules(curlpp REQUIRED IMPORTED_TARGET curlpp) + +include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") diff --git a/cmake/packages.cmake b/cmake/packages.cmake new file mode 100644 index 0000000..743b52b --- /dev/null +++ b/cmake/packages.cmake @@ -0,0 +1,40 @@ +set(CPACK_PACKAGE_NAME ${PROJECT_NAME}) +set(CPACK_PACKAGE_VERSION_MAJOR ${${PROJECT_NAME}_VERSION_MAJOR}) +set(CPACK_PACKAGE_VERSION_MINOR ${${PROJECT_NAME}_VERSION_MINOR}) +set(CPACK_PACKAGE_VERSION_PATCH ${${PROJECT_NAME}_VERSION_PATCH}) +set(CPACK_PACKAGE_VERSION ${mastodon-cpp_VERSION}) +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PROJECT_DESCRIPTION}") +set(CPACK_PACKAGE_CONTACT "tastytea ") +set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE") +set(CPACK_RESOURCE_FILE_README "${PROJECT_SOURCE_DIR}/README.adoc") + +execute_process(COMMAND uname -m + OUTPUT_VARIABLE CPACK_PACKAGE_ARCHITECTURE OUTPUT_STRIP_TRAILING_WHITESPACE) +set(CPACK_PACKAGE_FILE_NAME + "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}_${CPACK_PACKAGE_ARCHITECTURE}") +set(CPACK_GENERATOR "TGZ") + +if (WITH_DEB) + set(CPACK_PACKAGE_NAME "lib${PROJECT_NAME}") + set(CPACK_GENERATOR "DEB") + set(CPACK_DEBIAN_PACKAGE_HOMEPAGE + "https://schlomp.space/tastytea/${PROJECT_NAME}") + set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) + execute_process(COMMAND dpkg --print-architecture + OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE + OUTPUT_STRIP_TRAILING_WHITESPACE) + set(CPACK_PACKAGE_FILE_NAME + "${CPACK_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}-0_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}") +endif() + +if (WITH_RPM) + set(CPACK_PACKAGE_NAME "lib${PROJECT_NAME}") + set(CPACK_GENERATOR "RPM") + set(CPACK_RPM_PACKAGE_LICENSE "GPL-3") + set(CPACK_RPM_PACKAGE_URL "https://schlomp.space/tastytea/${PROJECT_NAME}") + set(CPACK_RPM_PACKAGE_REQUIRES "curlpp >= 0.8.1 jsoncpp, >= 1.7.4") + set(CPACK_PACKAGE_FILE_NAME + "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-0.${CPACK_PACKAGE_ARCHITECTURE}") +endif() + +include(CPack) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000..23cc73a --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,11 @@ +file(GLOB sources_examples *.cpp) +foreach(src ${sources_examples}) + get_filename_component(bin ${src} NAME_WE) + add_executable(${bin} ${src}) + target_link_libraries(${bin} PRIVATE ${PROJECT_NAME}) +endforeach() + +if(WITH_DOC) + install(FILES ${sources_examples} + DESTINATION "${CMAKE_INSTALL_DOCDIR}/examples") +endif() diff --git a/packages.CMakeLists.txt b/packages.CMakeLists.txt deleted file mode 100644 index 505f667..0000000 --- a/packages.CMakeLists.txt +++ /dev/null @@ -1,54 +0,0 @@ -set(CPACK_PACKAGE_NAME ${PROJECT_NAME}) -set(CPACK_PACKAGE_VERSION_MAJOR ${${PROJECT_NAME}_VERSION_MAJOR}) -set(CPACK_PACKAGE_VERSION_MINOR ${${PROJECT_NAME}_VERSION_MINOR}) -set(CPACK_PACKAGE_VERSION_PATCH ${${PROJECT_NAME}_VERSION_PATCH}) -set(CPACK_PACKAGE_VERSION ${mastodon-cpp_VERSION}) -set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "C++ wrapper for the Mastodon API") -set(CPACK_PACKAGE_CONTACT "tastytea ") -set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE") -set(CPACK_RESOURCE_FILE_README "${PROJECT_SOURCE_DIR}/README.adoc") -list(APPEND CPACK_SOURCE_IGNORE_FILES "/\\\\.git" - "/.gitignore" - "/build/" - "/doc/" - "\\\\.sublime-" - "/update_doc.sh" - "/.drone.yml" - "/ISSUE_TEMPLATE.md$") -execute_process(COMMAND uname -m - OUTPUT_VARIABLE CPACK_PACKAGE_ARCHITECTURE - OUTPUT_STRIP_TRAILING_WHITESPACE) -set(CPACK_PACKAGE_FILE_NAME - "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}_${CPACK_PACKAGE_ARCHITECTURE}") -set(CPACK_GENERATOR "TGZ") -set(CPACK_SOURCE_GENERATOR "TGZ") - -if (WITH_DEB) - set(CPACK_PACKAGE_NAME "lib${PROJECT_NAME}") - set(CPACK_GENERATOR "DEB") - set(CPACK_SOURCE_GENERATOR "DEB") - set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "https://schlomp.space/tastytea/mastodon-cpp") - set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) - execute_process(COMMAND dpkg --print-architecture - OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE - OUTPUT_STRIP_TRAILING_WHITESPACE) - set(CPACK_PACKAGE_FILE_NAME - "${CPACK_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}-0_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}") - set(CPACK_SOURCE_PACKAGE_FILE_NAME - "${CPACK_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}-0_src") -endif() - -if (WITH_RPM) - set(CPACK_PACKAGE_NAME "lib${PROJECT_NAME}") - set(CPACK_GENERATOR "RPM") - set(CPACK_SOURCE_GENERATOR "RPM") - set(CPACK_RPM_PACKAGE_LICENSE "GPL-3") - set(CPACK_RPM_PACKAGE_URL "https://schlomp.space/tastytea/mastodon-cpp") - set(CPACK_RPM_PACKAGE_REQUIRES "curlpp >= 0.8.1 jsoncpp, >= 1.7.4") - set(CPACK_PACKAGE_FILE_NAME - "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-0.${CPACK_PACKAGE_ARCHITECTURE}") - set(CPACK_SOURCE_PACKAGE_FILE_NAME - "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-0.src") -endif() - -include(CPack) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..cf39f14 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,53 @@ +include(GNUInstallDirs) + +find_package(PkgConfig REQUIRED) +pkg_check_modules(curlpp REQUIRED IMPORTED_TARGET curlpp) +if(WITH_EASY) + find_package(jsoncpp REQUIRED CONFIG) +endif() + +if(WITH_EASY) + file(GLOB_RECURSE sources *.cpp *.hpp) +else() + file(GLOB sources *.cpp api/*.cpp *.hpp api/*.hpp) +endif() + +# Write version in header +configure_file ("version.hpp.in" + "${CMAKE_CURRENT_BINARY_DIR}/version.hpp") + +add_library(${PROJECT_NAME} ${sources}) +set_target_properties(${PROJECT_NAME} PROPERTIES + VERSION ${PROJECT_VERSION} + SOVERSION ${${PROJECT_NAME}_VERSION_MAJOR}) + +target_include_directories(${PROJECT_NAME} + PRIVATE + "$" + PUBLIC + "$" + "$") + +if(WITH_EASY) + target_link_libraries(${PROJECT_NAME} + PUBLIC pthread PkgConfig::curlpp jsoncpp_lib) +else() + target_link_libraries(${PROJECT_NAME} + PUBLIC pthread PkgConfig::curlpp) +endif() + +install(TARGETS ${PROJECT_NAME} + EXPORT "${PROJECT_NAME}Targets" + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}") + +install(FILES mastodon-cpp.hpp return_types.hpp types.hpp + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}) +if(WITH_EASY) + file(GLOB easy_header easy/*.hpp) + install(FILES ${easy_header} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}/easy) + file(GLOB easy_entities_header easy/entities/*.hpp) + install(FILES ${easy_entities_header} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}/easy/entities) +endif() diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index bc5ab0c..8cd0771 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,20 +1,23 @@ include(CTest) -file(GLOB sources_tests test_*.cpp */test_*.cpp) + +file(GLOB_RECURSE sources_tests test_*.cpp) + +configure_file("test.gif" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY) find_package(Catch2) -if(Catch2_FOUND) # Catch 2.x +if(Catch2_FOUND) # Catch 2.x include(Catch) add_executable(all_tests main.cpp ${sources_tests}) - target_link_libraries(all_tests ${PROJECT_NAME} Catch2::Catch2) + target_link_libraries(all_tests PRIVATE ${PROJECT_NAME} Catch2::Catch2) target_include_directories(all_tests PRIVATE "/usr/include/catch2") catch_discover_tests(all_tests EXTRA_ARGS "${EXTRA_TEST_ARGS}") -else() # Catch 1.x +else() # Catch 1.x if(EXISTS "/usr/include/catch.hpp") message(STATUS "Catch 1.x found.") foreach(src ${sources_tests}) get_filename_component(bin ${src} NAME_WE) add_executable(${bin} main.cpp ${src}) - target_link_libraries(${bin} ${PROJECT_NAME}) + target_link_libraries(${bin} PRIVATE ${PROJECT_NAME}) add_test(${bin} ${bin} "${EXTRA_TEST_ARGS}") endforeach() else() From 1273518a5c4686e93154848ea5553f94bb3e7bc8 Mon Sep 17 00:00:00 2001 From: tastytea Date: Wed, 14 Aug 2019 00:19:12 +0200 Subject: [PATCH 04/25] Add pkg-config recipe. --- CMakeLists.txt | 1 + pkg-config/CMakeLists.txt | 7 +++++++ pkg-config/mastodon-cpp.pc.in | 11 +++++++++++ 3 files changed, 19 insertions(+) create mode 100644 pkg-config/CMakeLists.txt create mode 100644 pkg-config/mastodon-cpp.pc.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 126d66d..8fcf9b3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -81,5 +81,6 @@ if(WITH_DOC) endif() add_subdirectory("cmake") +add_subdirectory("pkg-config") include("cmake/packages.cmake") diff --git a/pkg-config/CMakeLists.txt b/pkg-config/CMakeLists.txt new file mode 100644 index 0000000..4640f17 --- /dev/null +++ b/pkg-config/CMakeLists.txt @@ -0,0 +1,7 @@ +include(GNUInstallDirs) + +configure_file("${PROJECT_NAME}.pc.in" + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc" @ONLY) + +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") diff --git a/pkg-config/mastodon-cpp.pc.in b/pkg-config/mastodon-cpp.pc.in new file mode 100644 index 0000000..40f0ccd --- /dev/null +++ b/pkg-config/mastodon-cpp.pc.in @@ -0,0 +1,11 @@ +name=@PROJECT_NAME@ +prefix=@CMAKE_INSTALL_PREFIX@ +libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ +includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ + +Name: ${name} +Description: @PROJECT_DESCRIPTION@ +Version: @PROJECT_VERSION@ +Cflags: -I${includedir} +Libs: -L${libdir} -l${name} -lpthread +Requires: jsoncpp curlpp From bd07dc6f9cf84b78b23968c083b197750704f55e Mon Sep 17 00:00:00 2001 From: tastytea Date: Fri, 16 Aug 2019 02:09:12 +0200 Subject: [PATCH 05/25] Change license in package generation recipe. --- cmake/packages.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/packages.cmake b/cmake/packages.cmake index 743b52b..7ebe85d 100644 --- a/cmake/packages.cmake +++ b/cmake/packages.cmake @@ -30,7 +30,7 @@ endif() if (WITH_RPM) set(CPACK_PACKAGE_NAME "lib${PROJECT_NAME}") set(CPACK_GENERATOR "RPM") - set(CPACK_RPM_PACKAGE_LICENSE "GPL-3") + set(CPACK_RPM_PACKAGE_LICENSE "AGPL-3") set(CPACK_RPM_PACKAGE_URL "https://schlomp.space/tastytea/${PROJECT_NAME}") set(CPACK_RPM_PACKAGE_REQUIRES "curlpp >= 0.8.1 jsoncpp, >= 1.7.4") set(CPACK_PACKAGE_FILE_NAME From f97608ecfaae308b93e83ba9ae23eadc8fbb131c Mon Sep 17 00:00:00 2001 From: tastytea Date: Tue, 20 Aug 2019 18:02:45 +0200 Subject: [PATCH 06/25] [WIP] Switch from curlpp to POCO. Compilable, but untested and unfinished. --- README.adoc | 3 +- src/CMakeLists.txt | 23 ++++ src/http.cpp | 307 +++++++++++++++++++++++++++---------------- src/mastodon-cpp.cpp | 79 ++++++----- src/mastodon-cpp.hpp | 24 ++-- 5 files changed, 274 insertions(+), 162 deletions(-) diff --git a/README.adoc b/README.adoc index d70fcbc..c6af591 100644 --- a/README.adoc +++ b/README.adoc @@ -110,8 +110,7 @@ Not included in this list are entities. | 110 | Connection timed out | 111 | Connection refused (check http_error_code) | 113 | No route to host / Could not resolve host -| 192 | curlpp runtime error -| 193 | curlpp logic error +| 150 | Encryption error (TODO: CHANGEME!) | 255 | Unknown error |=================================================== diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cf39f14..f602aff 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,6 +5,8 @@ pkg_check_modules(curlpp REQUIRED IMPORTED_TARGET curlpp) if(WITH_EASY) find_package(jsoncpp REQUIRED CONFIG) endif() +# Some distributions do not contain Poco*Config.cmake recipes. +find_package(Poco COMPONENTS Foundation Net NetSSL CONFIG) if(WITH_EASY) file(GLOB_RECURSE sources *.cpp *.hpp) @@ -24,6 +26,7 @@ set_target_properties(${PROJECT_NAME} PROPERTIES target_include_directories(${PROJECT_NAME} PRIVATE "$" + "$" PUBLIC "$" "$") @@ -36,6 +39,26 @@ else() PUBLIC pthread PkgConfig::curlpp) endif() +# If no Poco*Config.cmake recipes are found, look for headers in standard dirs. +if(PocoNetSSL_FOUND) + target_link_libraries(${PROJECT_NAME} + PRIVATE Poco::Foundation Poco::Net Poco::NetSSL) +else() + find_file(Poco_h NAMES "Poco/Poco.h" + PATHS "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}") + + if("${Poco_h}" STREQUAL "Poco_h-NOTFOUND") + message(FATAL_ERROR "Could not find POCO.") + else() + message(WARNING + "Your distribution of POCO doesn't contain the *Config.cmake recipes, " + "but the files seem to be in the standard directories. " + "Let's hope this works.") + target_link_libraries(${PROJECT_NAME} + PRIVATE PocoFoundation PocoNet PocoNetSSL) + endif() +endif() + install(TARGETS ${PROJECT_NAME} EXPORT "${PROJECT_NAME}Targets" LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} diff --git a/src/http.cpp b/src/http.cpp index 81080d2..b0c8dca 100644 --- a/src/http.cpp +++ b/src/http.cpp @@ -16,19 +16,36 @@ #include #include // std::bind -#include -#include // std::strncmp #include #include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "debug.hpp" #include "mastodon-cpp.hpp" +#include using namespace Mastodon; namespace curlopts = curlpp::options; using std::cerr; +using std::istream; +using std::make_unique; +using std::move; +using Poco::Net::HTTPSClientSession; +using Poco::Net::HTTPRequest; +using Poco::Net::HTTPResponse; +using Poco::Net::HTTPMessage; +using Poco::StreamCopier; +using Poco::Environment; API::http::http(const API &api, const string &instance, const string &access_token) @@ -38,23 +55,65 @@ API::http::http(const API &api, const string &instance, , _cancel_stream(false) { curlpp::initialize(); + + Poco::Net::initializeSSL(); + + // FIXME: rewrite set_proxy() and set proxy here. + // string proxy_host, proxy_userpw; + // parent.get_proxy(proxy_host, proxy_userpw); + + try + { + HTTPSClientSession::ProxyConfig proxy; + string proxy_env = Environment::get("http_proxy"); + size_t pos; + + // Only keep text between // and /. + if ((pos = proxy_env.find("//")) != string::npos) + { + proxy_env = proxy_env.substr(pos + 2); + } + if ((pos = proxy_env.find('/')) != string::npos) + { + proxy_env = proxy_env.substr(0, pos); + } + + if ((pos = proxy_env.find(':')) != string::npos) + { + proxy.host = proxy_env.substr(0, pos); + proxy.port = std::stoi(proxy_env.substr(pos + 1)); + } + else + { + proxy.host = proxy_env; + } + + HTTPSClientSession::setGlobalProxyConfig(proxy); + } + catch (const std::exception &) + { + // No proxy found, no problem. + } + } API::http::~http() { curlpp::terminate(); + + Poco::Net::uninitializeSSL(); } return_call API::http::request(const http_method &meth, const string &path) { - return request(meth, path, curlpp::Forms()); + return request(meth, path, make_unique()); } return_call API::http::request(const http_method &meth, const string &path, - const curlpp::Forms &formdata) + unique_ptr formdata) { string answer; - return request_common(meth, path, formdata, answer); + return request_common(meth, path, move(formdata), answer); } void API::http::request_stream(const string &path, string &stream) @@ -64,7 +123,7 @@ void API::http::request_stream(const string &path, string &stream) [&, path] // path is captured by value because it may be { // deleted before we access it. ret = request_common(http_method::GET_STREAM, path, - curlpp::Forms(), stream); + make_unique(), stream); ttdebug << "Remaining content of the stream: " << stream << '\n'; if (!ret) { @@ -78,149 +137,171 @@ void API::http::request_stream(const string &path, string &stream) return_call API::http::request_common(const http_method &meth, const string &path, - const curlpp::Forms &formdata, + unique_ptr formdata, string &answer) { - using namespace std::placeholders; // _1, _2, _3 - ttdebug << "Path is: " << path << '\n'; try { - curlpp::Easy request; - std::list headers; - - request.setOpt("https://" + _instance + path); - ttdebug << "User-Agent: " << parent.get_useragent() << "\n"; - request.setOpt(parent.get_useragent()); - - { - string proxy; - string userpw; - parent.get_proxy(proxy, userpw); - if (!proxy.empty()) - { - request.setOpt(proxy); - if (!userpw.empty()) - { - request.setOpt(userpw); - } - } - } - - if (!_access_token.empty()) - { - headers.push_back("Authorization: Bearer " + _access_token); - } - if (meth != http_method::GET_STREAM) - { - headers.push_back("Connection: close"); - // Get headers from server - request.setOpt(true); - } - - request.setOpt(headers); - request.setOpt(true); - request.setOpt - (std::bind(&http::callback_write, this, _1, _2, _3, &answer)); - request.setOpt - (std::bind(&http::callback_progress, this, _1, _2, _3, _4)); - request.setOpt(0); - if (!formdata.empty()) - { - request.setOpt(formdata); - } + string method; + // TODO: operator string on http_method? switch (meth) { case http_method::GET: case http_method::GET_STREAM: - break; - case http_method::PATCH: - request.setOpt("PATCH"); - break; - case http_method::POST: - request.setOpt("POST"); - break; - case http_method::PUT: - request.setOpt("PUT"); - break; - case http_method::DELETE: - request.setOpt("DELETE"); + { + method = HTTPRequest::HTTP_GET; break; } + case http_method::PUT: + { + method = HTTPRequest::HTTP_PUT; + break; + } + case http_method::POST: + { + method = HTTPRequest::HTTP_POST; + break; + } + case http_method::PATCH: + { + method = HTTPRequest::HTTP_PATCH; + break; + } + case http_method::DELETE: + { + method = HTTPRequest::HTTP_DELETE; + break; + } + default: + { + break; + } + } - //request.setOpt(true); + HTTPSClientSession session(_instance); + HTTPRequest request(method, path, HTTPMessage::HTTP_1_1); + request.set("User-Agent", parent.get_useragent()); + + if (!_access_token.empty()) + { + request.set("Authorization", " Bearer " + _access_token); + } + + if (!formdata->empty()) + { + // TODO: Test form submit. + // TODO: Change maptoformdata() and so on. + formdata->prepareSubmit(request); + } + + HTTPResponse response; + + session.sendRequest(request); + istream &rs = session.receiveResponse(response); + + const uint16_t http_code = response.getStatus(); + ttdebug << "Response code: " << http_code << '\n'; answer.clear(); - request.perform(); - uint16_t http_code = curlpp::infos::ResponseCode::get(request); - ttdebug << "Response code: " << http_code << '\n'; - // Work around "HTTP/1.1 100 Continue\r\n\r\nHTTP/1.1 200 OK" - size_t pos = answer.find("\r\n\r\n", 25); - _headers = answer.substr(0, pos); - // Only return body - answer = answer.substr(pos + 4); + StreamCopier::copyToString(rs, answer); - if (http_code == 200 || http_code == 302 || http_code == 307) - { // OK or Found or Temporary Redirect + switch (http_code) + { + case HTTPResponse::HTTP_OK: + { return { 0, "", http_code, answer }; } - else if (http_code == 301 || http_code == 308) - { // Moved Permanently or Permanent Redirect - // return new URL - answer = curlpp::infos::EffectiveUrl::get(request); - return { 78, "Remote address changed", http_code, answer }; - } - else if (http_code == 0) + // Not using the constants because some are too new for Debian stretch. + case 301: // HTTPResponse::HTTP_MOVED_PERMANENTLY + case 308: // HTTPResponse::HTTP_PERMANENT_REDIRECT + case 302: // HTTPResponse::HTTP_FOUND + case 303: // HTTPResponse::HTTP_SEE_OTHER + case 307: // HTTPResponse::HTTP_TEMPORARY_REDIRECT { - return { 255, "Unknown error", http_code, answer }; + string location = response.get("Location"); + + // TODO: Test this. + if (location.substr(0, 4) == "http") + { // Remove protocol and instance from path. + size_t pos1 = location.find("//") + 2; + size_t pos2 = location.find('/', pos1); + + if (location.substr(pos1, pos2) != _instance) + { // Return new location if the domain changed. + return { 78, "Remote address changed", http_code, + location }; + } + + location = location.substr(pos2); + } + + if (http_code == 301 || http_code == 308) + { // Return new location for permanent redirects. + return { 78, "Remote address changed", http_code, location }; + } + else + { + return request_common(meth, location, move(formdata), answer); + } } - else + default: { return { 111, "Connection refused", http_code, answer }; } + } } - catch (curlpp::RuntimeError &e) + catch (const Poco::Net::DNSException &e) { - const string what = e.what(); - // This error is thrown if http.cancel_stream() is used. - if ((what.compare(0, 16, "Callback aborted") == 0) || - (what.compare(0, 19, "Failed writing body") == 0)) - { - ttdebug << "Request was cancelled by user\n"; - return { 0, "Request was cancelled by user", 0, "" }; - } - else if (what.compare(what.size() - 20, 20, "Connection timed out") == 0) - { - ttdebug << what << "\n"; - return { 110, "Connection timed out", 0, "" }; - } - else if (what.compare(0, 23, "Could not resolve host:") == 0) - { - ttdebug << what << "\n"; - return { 113, "Could not resolve host", 0, "" }; - } - if (parent.exceptions()) { - std::rethrow_exception(std::current_exception()); - } - else - { - ttdebug << "curlpp::RuntimeError: " << e.what() << std::endl; - return { 192, e.what(), 0, "" }; + e.rethrow(); } + + ttdebug << e.displayText() << "\n"; + return { 113, e.displayText(), 0, "" }; } - catch (curlpp::LogicError &e) + catch (const Poco::Net::ConnectionRefusedException &e) + { + if (parent.exceptions()) + { + e.rethrow(); + } + + ttdebug << e.displayText() << "\n"; + return { 111, e.displayText(), 0, "" }; + } + catch (const Poco::Net::SSLException &e) + { + if (parent.exceptions()) + { + e.rethrow(); + } + + ttdebug << e.displayText() << "\n"; + return { 150, e.displayText(), 0, "" }; + } + catch (const Poco::Net::NetException &e) + { + if (parent.exceptions()) + { + e.rethrow(); + } + + ttdebug << "Unknown network error: " << e.displayText() << std::endl; + return { 255, e.displayText(), 0, "" }; + } + catch (const std::exception &e) { if (parent.exceptions()) { std::rethrow_exception(std::current_exception()); } - ttdebug << "curlpp::LogicError: " << e.what() << std::endl; - return { 193, e.what(), 0, "" }; + ttdebug << "Unknown error: " << e.what() << std::endl; + return { 255, e.what(), 0, "" }; } } diff --git a/src/mastodon-cpp.cpp b/src/mastodon-cpp.cpp index f5ee783..a43b1c0 100644 --- a/src/mastodon-cpp.cpp +++ b/src/mastodon-cpp.cpp @@ -14,20 +14,20 @@ * along with this program. If not, see . */ -#include #include #include #include #include #include -#include -#include #include +#include #include "version.hpp" #include "debug.hpp" #include "mastodon-cpp.hpp" using namespace Mastodon; +using std::make_unique; +using Poco::Net::FilePartSource; API::API(const string &instance, const string &access_token) : _instance(instance) @@ -111,9 +111,10 @@ const string API::maptostr(const parameters &map, const bool &firstparam) return result; } -const curlpp::Forms API::maptoformdata(const parameters &map) +unique_ptr API::maptoformdata(const parameters &map) { - curlpp::Forms formdata; + unique_ptr formdata = + make_unique(HTMLForm::ENCODING_MULTIPART); if (map.size() == 0) { @@ -122,51 +123,57 @@ const curlpp::Forms API::maptoformdata(const parameters &map) for (const auto &it : map) { + string key = it.key; + + // TODO: Test nested parameters. + if (const size_t pos = key.find('.') != string::npos) + { // Nested parameters. + key.replace(pos, 1, "["); + key += ']'; + } + if (it.values.size() == 1) { // If the file is not base64-encoded, treat as filename. - if ((it.key == "avatar" || - it.key == "header" || - it.key == "file") && + if ((key == "avatar" || + key == "header" || + key == "file") && it.values.front().substr(0, 5) != "data:") - { - ttdebug << it.key << ": Filename detected.\n"; - std::ifstream testfile(it.values.front()); - if (testfile.good()) + { + ttdebug << key << ": Filename detected.\n"; + + try { - testfile.close(); - formdata.push_back( - new curlpp::FormParts::File(it.key, it.values.front())); + formdata->addPart(key, + new FilePartSource(it.values.front())); } - else + catch (const std::exception &e) { - std::cerr << "Error: File not found: " << it.values.front() - << std::endl; + if (exceptions()) + { + std::rethrow_exception(std::current_exception()); + } + + // TODO: Proper error handling without exceptions. + std::cerr << "Error: Could not open file: " + << it.values.front() << std::endl; } - } - else - { - string key = it.key; - // Append [] to array keys. - if (key == "account_ids" + } + else if (key == "account_ids" || key == "exclude_types" || key == "media_ids" || key == "context") - { - key += "[]"; - } - formdata.push_back( - new curlpp::FormParts::Content(key, it.values.front())); + { + key += "[]"; } + + formdata->add(key, it.values.front()); } else { - std::transform(it.values.begin(), it.values.end(), - std::back_inserter(formdata), - [&it](const string &s) - { - return new curlpp::FormParts::Content - (it.key + "[]", s); - }); + for (const string &value : it.values) + { + formdata->add(key + "[]", value); + } } } diff --git a/src/mastodon-cpp.hpp b/src/mastodon-cpp.hpp index 9790aa6..46a0706 100644 --- a/src/mastodon-cpp.hpp +++ b/src/mastodon-cpp.hpp @@ -27,12 +27,15 @@ #include #include #include +#include #include "return_types.hpp" #include "types.hpp" using std::string; using std::uint8_t; +using std::unique_ptr; +using Poco::Net::HTMLForm; /*! * @example example01_get_public_timeline.cpp @@ -45,6 +48,7 @@ using std::uint8_t; */ namespace Mastodon { + // TODO: error enum, different error codes. /*! * @brief Interface to the Mastodon API. * @@ -60,8 +64,7 @@ namespace Mastodon * | 110 | Connection timed out | * | 111 | Connection refused (check http_error_code) | * | 113 | No route to host / Could not resolve host | - * | 192 | curlpp runtime error | - * | 193 | curlpp logic error | + * | 150 | Encryption error | * | 255 | Unknown error | * * @since before 0.11.0 @@ -102,7 +105,7 @@ namespace Mastodon */ return_call request(const http_method &meth, const string &path, - const curlpp::Forms &formdata); + unique_ptr formdata); /*! * @brief HTTP Request for streams. @@ -153,7 +156,7 @@ namespace Mastodon return_call request_common(const http_method &meth, const string &path, - const curlpp::Forms &formdata, + unique_ptr formdata, string &answer); size_t callback_write(char* data, size_t size, size_t nmemb, string *oss); @@ -412,8 +415,7 @@ namespace Mastodon /*! * @brief Turn exceptions on or off. Defaults to off. * - * This applies to exceptions from curlpp. curlpp::RuntimeError - * and curlpp::LogicError. + * Most exceptions will be thrown at you to handle if on. * * @param value true for on, false for off * @@ -514,7 +516,7 @@ namespace Mastodon */ void get_stream(const Mastodon::API::v1 &call, const parameters ¶meters, - std::unique_ptr &ptr, + unique_ptr &ptr, string &stream); /*! @@ -527,7 +529,7 @@ namespace Mastodon * @since 0.100.0 */ void get_stream(const Mastodon::API::v1 &call, - std::unique_ptr &ptr, + unique_ptr &ptr, string &stream); /*! @@ -540,7 +542,7 @@ namespace Mastodon * @since 0.100.0 */ void get_stream(const string &call, - std::unique_ptr &ptr, + unique_ptr &ptr, string &stream); /*! @@ -665,9 +667,9 @@ namespace Mastodon * * @param map Map of parameters * - * @return Form data as curlpp::Forms + * @return Form data as Poco::Net::HTMLForm. */ - const curlpp::Forms maptoformdata(const parameters &map); + unique_ptr maptoformdata(const parameters &map); /*! * @brief Delete Mastodon::param from Mastodon::parameters. From bc58a977f0984f2c9f6f0d1841f2c810f467713e Mon Sep 17 00:00:00 2001 From: tastytea Date: Wed, 21 Aug 2019 03:35:44 +0200 Subject: [PATCH 07/25] Add more debug statements around forms. --- src/http.cpp | 1 + src/mastodon-cpp.cpp | 3 +++ 2 files changed, 4 insertions(+) diff --git a/src/http.cpp b/src/http.cpp index b0c8dca..1105ec3 100644 --- a/src/http.cpp +++ b/src/http.cpp @@ -194,6 +194,7 @@ return_call API::http::request_common(const http_method &meth, { // TODO: Test form submit. // TODO: Change maptoformdata() and so on. + ttdebug << "Size of HTMLForm is " << formdata->size() << '\n'; formdata->prepareSubmit(request); } diff --git a/src/mastodon-cpp.cpp b/src/mastodon-cpp.cpp index a43b1c0..0d66b86 100644 --- a/src/mastodon-cpp.cpp +++ b/src/mastodon-cpp.cpp @@ -113,6 +113,8 @@ const string API::maptostr(const parameters &map, const bool &firstparam) unique_ptr API::maptoformdata(const parameters &map) { + ttdebug << "Transforming Mastodon::parameters to Poco::Net::HTMLForm.\n"; + unique_ptr formdata = make_unique(HTMLForm::ENCODING_MULTIPART); @@ -124,6 +126,7 @@ unique_ptr API::maptoformdata(const parameters &map) for (const auto &it : map) { string key = it.key; + ttdebug << "Processing \"" + key + "\".\n"; // TODO: Test nested parameters. if (const size_t pos = key.find('.') != string::npos) From ecb49c7e0023a444ad7bcc23691b77feeb044ab2 Mon Sep 17 00:00:00 2001 From: tastytea Date: Wed, 21 Aug 2019 03:36:25 +0200 Subject: [PATCH 08/25] Actually send forms. --- src/http.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/http.cpp b/src/http.cpp index 1105ec3..3a7412e 100644 --- a/src/http.cpp +++ b/src/http.cpp @@ -192,15 +192,16 @@ return_call API::http::request_common(const http_method &meth, if (!formdata->empty()) { - // TODO: Test form submit. - // TODO: Change maptoformdata() and so on. ttdebug << "Size of HTMLForm is " << formdata->size() << '\n'; formdata->prepareSubmit(request); + formdata->write(session.sendRequest(request)); + } + else + { + session.sendRequest(request); } HTTPResponse response; - - session.sendRequest(request); istream &rs = session.receiveResponse(response); const uint16_t http_code = response.getStatus(); From 12c0b896db625693fbba0c365dae4b354e67c463 Mon Sep 17 00:00:00 2001 From: tastytea Date: Wed, 21 Aug 2019 03:53:51 +0200 Subject: [PATCH 09/25] Use references for HTMLForm, where possible. HTMLForm can't be copied, so I'm returning using unique_ptr in maptoformdata() and references everywhere else. --- src/api/delete.cpp | 2 +- src/api/patch.cpp | 3 +-- src/api/post.cpp | 2 +- src/api/put.cpp | 2 +- src/http.cpp | 22 ++++++++++++---------- src/mastodon-cpp.hpp | 4 ++-- 6 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/api/delete.cpp b/src/api/delete.cpp index 709e637..59429a6 100644 --- a/src/api/delete.cpp +++ b/src/api/delete.cpp @@ -88,5 +88,5 @@ return_call API::del(const Mastodon::API::v1 &call, return_call API::del(const std::string &call, const parameters ¶ms) { - return _http.request(http_method::DELETE, call, maptoformdata(params)); + return _http.request(http_method::DELETE, call, *maptoformdata(params)); } diff --git a/src/api/patch.cpp b/src/api/patch.cpp index 1dd0a30..82f6801 100644 --- a/src/api/patch.cpp +++ b/src/api/patch.cpp @@ -36,6 +36,5 @@ return_call API::patch(const Mastodon::API::v1 &call, break; } - return _http.request(http_method::PATCH, - strcall, maptoformdata(params)); + return _http.request(http_method::PATCH, strcall, *maptoformdata(params)); } diff --git a/src/api/post.cpp b/src/api/post.cpp index 486a07c..b4a1332 100644 --- a/src/api/post.cpp +++ b/src/api/post.cpp @@ -214,5 +214,5 @@ return_call API::post(const Mastodon::API::v1 &call) return_call API::post(const string &call, const parameters ¶ms) { - return _http.request(http_method::POST, call, maptoformdata(params)); + return _http.request(http_method::POST, call, *maptoformdata(params)); } diff --git a/src/api/put.cpp b/src/api/put.cpp index 1a6bcc6..7a3c430 100644 --- a/src/api/put.cpp +++ b/src/api/put.cpp @@ -68,5 +68,5 @@ return_call API::put(const Mastodon::API::v1 &call, return_call API::put(const string &call, const parameters ¶ms) { - return _http.request(http_method::PUT, call, maptoformdata(params)); + return _http.request(http_method::PUT, call, *maptoformdata(params)); } diff --git a/src/http.cpp b/src/http.cpp index 3a7412e..d345b86 100644 --- a/src/http.cpp +++ b/src/http.cpp @@ -106,14 +106,15 @@ API::http::~http() return_call API::http::request(const http_method &meth, const string &path) { - return request(meth, path, make_unique()); + HTMLForm form; + return request(meth, path, form); } return_call API::http::request(const http_method &meth, const string &path, - unique_ptr formdata) + HTMLForm &formdata) { string answer; - return request_common(meth, path, move(formdata), answer); + return request_common(meth, path, formdata, answer); } void API::http::request_stream(const string &path, string &stream) @@ -122,8 +123,9 @@ void API::http::request_stream(const string &path, string &stream) _streamthread = std::thread( [&, path] // path is captured by value because it may be { // deleted before we access it. + HTMLForm form; ret = request_common(http_method::GET_STREAM, path, - make_unique(), stream); + form, stream); ttdebug << "Remaining content of the stream: " << stream << '\n'; if (!ret) { @@ -137,7 +139,7 @@ void API::http::request_stream(const string &path, string &stream) return_call API::http::request_common(const http_method &meth, const string &path, - unique_ptr formdata, + HTMLForm &formdata, string &answer) { ttdebug << "Path is: " << path << '\n'; @@ -190,11 +192,11 @@ return_call API::http::request_common(const http_method &meth, request.set("Authorization", " Bearer " + _access_token); } - if (!formdata->empty()) + if (!formdata.empty()) { - ttdebug << "Size of HTMLForm is " << formdata->size() << '\n'; - formdata->prepareSubmit(request); - formdata->write(session.sendRequest(request)); + ttdebug << "Size of HTMLForm is " << formdata.size() << '\n'; + formdata.prepareSubmit(request); + formdata.write(session.sendRequest(request)); } else { @@ -246,7 +248,7 @@ return_call API::http::request_common(const http_method &meth, } else { - return request_common(meth, location, move(formdata), answer); + return request_common(meth, location, formdata, answer); } } default: diff --git a/src/mastodon-cpp.hpp b/src/mastodon-cpp.hpp index 46a0706..9ef785c 100644 --- a/src/mastodon-cpp.hpp +++ b/src/mastodon-cpp.hpp @@ -105,7 +105,7 @@ namespace Mastodon */ return_call request(const http_method &meth, const string &path, - unique_ptr formdata); + HTMLForm &formdata); /*! * @brief HTTP Request for streams. @@ -156,7 +156,7 @@ namespace Mastodon return_call request_common(const http_method &meth, const string &path, - unique_ptr formdata, + HTMLForm &formdata, string &answer); size_t callback_write(char* data, size_t size, size_t nmemb, string *oss); From 62d28c523a51e93cf17a6d82cb8cacd8303a75a8 Mon Sep 17 00:00:00 2001 From: tastytea Date: Wed, 21 Aug 2019 04:20:11 +0200 Subject: [PATCH 10/25] Updated TODOs and FIXMEs. --- src/http.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/http.cpp b/src/http.cpp index d345b86..6388781 100644 --- a/src/http.cpp +++ b/src/http.cpp @@ -58,9 +58,8 @@ API::http::http(const API &api, const string &instance, Poco::Net::initializeSSL(); - // FIXME: rewrite set_proxy() and set proxy here. - // string proxy_host, proxy_userpw; - // parent.get_proxy(proxy_host, proxy_userpw); + // FIXME: rewrite set_proxy() that it calls set_proxy() here. + // FIXME: Username and password for proxy. try { @@ -227,7 +226,7 @@ return_call API::http::request_common(const http_method &meth, { string location = response.get("Location"); - // TODO: Test this. + // TODO: Test HTTP redirects. if (location.substr(0, 4) == "http") { // Remove protocol and instance from path. size_t pos1 = location.find("//") + 2; From 9da01c0398cc8b0ee5c46847c95436ccdb51fb54 Mon Sep 17 00:00:00 2001 From: tastytea Date: Wed, 21 Aug 2019 04:25:20 +0200 Subject: [PATCH 11/25] Add POCO to drone recipe. --- .drone.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.drone.yml b/.drone.yml index 07793fc..1427b3c 100644 --- a/.drone.yml +++ b/.drone.yml @@ -31,7 +31,7 @@ steps: - echo "deb http://deb.debian.org/debian sid main" >> /etc/apt/sources.list.d/sid.list - apt-get update -q - apt-get install -qy build-essential cmake pkg-config - - apt-get install -qy libcurl4-openssl-dev libjsoncpp-dev doxygen catch + - apt-get install -qy libcurl4-openssl-dev libpoco-dev libjsoncpp-dev doxygen catch - apt-get install -qy -t sid libcurlpp-dev - rm -rf build && mkdir -p build && cd build - cmake -DWITH_EXAMPLES=YES -DWITH_TESTS=YES -DEXTRA_TEST_ARGS="~[api]" .. @@ -63,7 +63,7 @@ steps: - apt-get update -q - apt-get install -qy build-essential cmake pkg-config - apt-get install -qy -t xenial g++-9 - - apt-get install -qy libcurl4-openssl-dev libjsoncpp-dev doxygen catch + - apt-get install -qy libcurl4-openssl-dev libpoco-dev libjsoncpp-dev doxygen catch - apt-get install -qy -t sid libcurlpp-dev - rm -rf build && mkdir -p build && cd build - cmake -DWITH_EXAMPLES=YES .. @@ -91,7 +91,7 @@ steps: - apt-get update -q - apt-get install -qy build-essential cmake pkg-config - apt-get install -qy -t stretch-backports clang-5.0 - - apt-get install -qy libcurl4-openssl-dev libjsoncpp-dev doxygen catch + - apt-get install -qy libcurl4-openssl-dev libpoco-dev libjsoncpp-dev doxygen catch - apt-get install -qy -t sid libcurlpp-dev - rm -rf build && mkdir -p build && cd build - cmake -DWITH_EXAMPLES=YES .. @@ -120,7 +120,7 @@ steps: - apt-get update -q - apt-get install -qy build-essential cmake pkg-config - apt-get install -qy -t stretch-backports clang-6.0 - - apt-get install -qy libcurl4-openssl-dev libjsoncpp-dev doxygen catch + - apt-get install -qy libcurl4-openssl-dev libpoco-dev libjsoncpp-dev doxygen catch - apt-get install -qy -t sid libcurlpp-dev - rm -rf build && mkdir -p build && cd build - cmake -DWITH_EXAMPLES=YES .. @@ -177,7 +177,7 @@ steps: - echo "deb http://deb.debian.org/debian sid main" >> /etc/apt/sources.list.d/sid.list - apt-get update -q - apt-get install -qy build-essential cmake pkg-config - - apt-get install -qy libcurl4-openssl-dev libjsoncpp-dev doxygen + - apt-get install -qy libcurl4-openssl-dev libpoco-dev libjsoncpp-dev doxygen - apt-get install -qy -t sid libcurlpp-dev - apt-get install -qy file - rm -rf build && mkdir -p build && cd build @@ -204,7 +204,7 @@ steps: - yum install -qy centos-release-scl - yum install -qy devtoolset-6 - scl enable devtoolset-6 bash - - yum install -qy libcurl-devel doxygen rpm-build + - yum install -qy libcurl-devel poco-devel doxygen rpm-build - yum --enablerepo=epel install -qy cmake3 jsoncpp-devel - curl -s -o /var/cache/yum/curlpp-devel-0.7.3-5.el6.x86_64.rpm https://download.fedoraproject.org/pub/epel/6/x86_64/Packages/c/curlpp-devel-0.7.3-5.el6.x86_64.rpm - curl -s -o /var/cache/yum/curlpp-0.7.3-5.el6.x86_64.rpm https://download.fedoraproject.org/pub/epel/6/x86_64/Packages/c/curlpp-0.7.3-5.el6.x86_64.rpm From 565317115c32d99a7200c1b5044ec7f0c115b56c Mon Sep 17 00:00:00 2001 From: tastytea Date: Wed, 21 Aug 2019 04:27:24 +0200 Subject: [PATCH 12/25] Replace curlpp with POCO in RPM dependencies. --- cmake/packages.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/packages.cmake b/cmake/packages.cmake index 7ebe85d..26bb563 100644 --- a/cmake/packages.cmake +++ b/cmake/packages.cmake @@ -32,7 +32,7 @@ if (WITH_RPM) set(CPACK_GENERATOR "RPM") set(CPACK_RPM_PACKAGE_LICENSE "AGPL-3") set(CPACK_RPM_PACKAGE_URL "https://schlomp.space/tastytea/${PROJECT_NAME}") - set(CPACK_RPM_PACKAGE_REQUIRES "curlpp >= 0.8.1 jsoncpp, >= 1.7.4") + set(CPACK_RPM_PACKAGE_REQUIRES "poco-netssl >= 1.6, jsoncpp >= 1.7.4") set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-0.${CPACK_PACKAGE_ARCHITECTURE}") endif() From d0bac6779f79f7f5a42a3dc4b5e93f9da905ebd2 Mon Sep 17 00:00:00 2001 From: tastytea Date: Wed, 21 Aug 2019 04:31:18 +0200 Subject: [PATCH 13/25] Replace curlpp with POCO in README. --- README.adoc | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/README.adoc b/README.adoc index c6af591..d006e7a 100644 --- a/README.adoc +++ b/README.adoc @@ -156,13 +156,6 @@ Prebuilt DEB and RPM packages for x86_64(amd64) are provided with each release. `.deb` packages are built on Debian stretch and `.rpm` packages are built on CentOS 7. These packages are automatically built and not tested. -To use the `.deb` package on Debian stretch, you will need -https://packages.debian.org/libcurlpp0[libcurlpp0] from sid. - -To use the `.rpm` package on CentOS 7, you will need -https://download.fedoraproject.org/pub/epel/6/x86_64/Packages/c/[curlpp] -from EPEL 6. - === From source ==== Dependencies @@ -171,8 +164,7 @@ from EPEL 6. * C++ compiler (tested: https://gcc.gnu.org/[gcc] 6/8/9, https://llvm.org/[clang] 5/6) * https://cmake.org/[cmake] (at least: 3.6) -* https://pkgconfig.freedesktop.org/wiki/[pkgconfig] (tested: 0.29 / 0.27) -* http://www.curlpp.org/[curlpp] (tested: 0.8) +* https://pocoproject.org/[POCO] (tested: 1.9 / 1.7) * Optional ** Easy interface & Examples: https://github.com/open-source-parsers/jsoncpp[jsoncpp] (tested: 1.8 / 1.7) @@ -185,11 +177,7 @@ from EPEL 6. ==== [source,shell] ---- -echo "APT::Default-Release \"stretch\";" >> /etc/apt/apt.conf.d/00default_release -echo "deb http://deb.debian.org/debian sid main" >> /etc/apt/sources.list.d/sid.list -apt-get update -apt-get install build-essential cmake pkg-config libcurl4-openssl-dev libjsoncpp-dev doxygen file -apt-get install -t sid libcurlpp-dev +apt-get install build-essential cmake libpoco-dev libjsoncpp-dev doxygen ---- ==== From a6f70263b872382f7ea77b89414cc1337b5719e4 Mon Sep 17 00:00:00 2001 From: tastytea Date: Wed, 21 Aug 2019 04:36:04 +0200 Subject: [PATCH 14/25] Remove curlpp from drone recipe. --- .drone.yml | 36 ++++++++++-------------------------- 1 file changed, 10 insertions(+), 26 deletions(-) diff --git a/.drone.yml b/.drone.yml index 1427b3c..4088fa6 100644 --- a/.drone.yml +++ b/.drone.yml @@ -27,12 +27,9 @@ steps: commands: - rm /etc/apt/apt.conf.d/docker-clean - rm /var/cache/apt/archives/lock - - echo "APT::Default-Release \"stretch\";" >> /etc/apt/apt.conf.d/00default_release - - echo "deb http://deb.debian.org/debian sid main" >> /etc/apt/sources.list.d/sid.list - apt-get update -q - - apt-get install -qy build-essential cmake pkg-config - - apt-get install -qy libcurl4-openssl-dev libpoco-dev libjsoncpp-dev doxygen catch - - apt-get install -qy -t sid libcurlpp-dev + - apt-get install -qy build-essential cmake + - apt-get install -qy libpoco-dev libjsoncpp-dev doxygen catch - rm -rf build && mkdir -p build && cd build - cmake -DWITH_EXAMPLES=YES -DWITH_TESTS=YES -DEXTRA_TEST_ARGS="~[api]" .. - make VERBOSE=1 @@ -55,16 +52,14 @@ steps: - rm /var/cache/apt/archives/lock - apt-get update -q - echo "APT::Default-Release \"stretch\";" >> /etc/apt/apt.conf.d/00default_release - - echo "deb http://deb.debian.org/debian sid main" >> /etc/apt/sources.list.d/sid.list - echo "deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu xenial main" >> /etc/apt/sources.list.d/ubuntu-toolchain-r.list - apt-get install -qy gnupg - gpg --keyserver hkp://keyserver.ubuntu.com --recv-keys 0x60c317803a41ba51845e371a1e9377a2ba9ef27f - gpg --armor --export 0x60c317803a41ba51845e371a1e9377a2ba9ef27f | apt-key add - - apt-get update -q - - apt-get install -qy build-essential cmake pkg-config + - apt-get install -qy build-essential cmake - apt-get install -qy -t xenial g++-9 - - apt-get install -qy libcurl4-openssl-dev libpoco-dev libjsoncpp-dev doxygen catch - - apt-get install -qy -t sid libcurlpp-dev + - apt-get install -qy libpoco-dev libjsoncpp-dev doxygen catch - rm -rf build && mkdir -p build && cd build - cmake -DWITH_EXAMPLES=YES .. - make VERBOSE=1 @@ -87,12 +82,10 @@ steps: - apt-get update -q - echo "APT::Default-Release \"stretch\";" >> /etc/apt/apt.conf.d/00default_release - echo "deb http://deb.debian.org/debian stretch-backports main" >> /etc/apt/sources.list.d/stretch.list - - echo "deb http://deb.debian.org/debian sid main" >> /etc/apt/sources.list.d/sid.list - apt-get update -q - - apt-get install -qy build-essential cmake pkg-config + - apt-get install -qy build-essential cmake - apt-get install -qy -t stretch-backports clang-5.0 - - apt-get install -qy libcurl4-openssl-dev libpoco-dev libjsoncpp-dev doxygen catch - - apt-get install -qy -t sid libcurlpp-dev + - apt-get install -qy libpoco-dev libjsoncpp-dev doxygen catch - rm -rf build && mkdir -p build && cd build - cmake -DWITH_EXAMPLES=YES .. - make VERBOSE=1 @@ -116,12 +109,10 @@ steps: - apt-get update -q - echo "APT::Default-Release \"stretch\";" >> /etc/apt/apt.conf.d/00default_release - echo "deb http://deb.debian.org/debian stretch-backports main" >> /etc/apt/sources.list.d/stretch.list - - echo "deb http://deb.debian.org/debian sid main" >> /etc/apt/sources.list.d/sid.list - apt-get update -q - - apt-get install -qy build-essential cmake pkg-config + - apt-get install -qy build-essential cmake - apt-get install -qy -t stretch-backports clang-6.0 - - apt-get install -qy libcurl4-openssl-dev libpoco-dev libjsoncpp-dev doxygen catch - - apt-get install -qy -t sid libcurlpp-dev + - apt-get install -qy libpoco-dev libjsoncpp-dev doxygen catch - rm -rf build && mkdir -p build && cd build - cmake -DWITH_EXAMPLES=YES .. - make VERBOSE=1 @@ -173,13 +164,9 @@ steps: commands: - rm /etc/apt/apt.conf.d/docker-clean - rm /var/cache/apt/archives/lock - - echo "APT::Default-Release \"stretch\";" >> /etc/apt/apt.conf.d/00default_release - - echo "deb http://deb.debian.org/debian sid main" >> /etc/apt/sources.list.d/sid.list - apt-get update -q - - apt-get install -qy build-essential cmake pkg-config - - apt-get install -qy libcurl4-openssl-dev libpoco-dev libjsoncpp-dev doxygen - - apt-get install -qy -t sid libcurlpp-dev - - apt-get install -qy file + - apt-get install -qy build-essential cmake + - apt-get install -qy libpoco-dev libjsoncpp-dev doxygen file - rm -rf build && mkdir -p build && cd build - cmake -DWITH_EXAMPLES=NO -DWITH_TESTS=NO .. - make package @@ -206,9 +193,6 @@ steps: - scl enable devtoolset-6 bash - yum install -qy libcurl-devel poco-devel doxygen rpm-build - yum --enablerepo=epel install -qy cmake3 jsoncpp-devel - - curl -s -o /var/cache/yum/curlpp-devel-0.7.3-5.el6.x86_64.rpm https://download.fedoraproject.org/pub/epel/6/x86_64/Packages/c/curlpp-devel-0.7.3-5.el6.x86_64.rpm - - curl -s -o /var/cache/yum/curlpp-0.7.3-5.el6.x86_64.rpm https://download.fedoraproject.org/pub/epel/6/x86_64/Packages/c/curlpp-0.7.3-5.el6.x86_64.rpm - - yum localinstall -qy /var/cache/yum/curlpp-* - rm -rf build && mkdir -p build && cd build - cmake3 -DWITH_EXAMPLES=NO -DWITH_TESTS=NO .. - make package From ed989935ac3175b9848993e198423b9af39bfdc6 Mon Sep 17 00:00:00 2001 From: tastytea Date: Wed, 21 Aug 2019 04:37:13 +0200 Subject: [PATCH 15/25] Test with clang7. --- .drone.yml | 11 ++++------- README.adoc | 2 +- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/.drone.yml b/.drone.yml index 4088fa6..80f77c6 100644 --- a/.drone.yml +++ b/.drone.yml @@ -94,12 +94,12 @@ steps: - name: debian-package-cache path: /var/cache/apt/archives -- name: clang6 - image: debian:stretch-slim +- name: clang7 + image: debian:buster-slim pull: true environment: LANG: C.utf8 - CXX: clang++-6.0 + CXX: clang++ CXXFLAGS: -pipe -O2 MASTODON_CPP_ACCESS_TOKEN: from_secret: mastodon_cpp_access_token @@ -107,11 +107,8 @@ steps: - rm /etc/apt/apt.conf.d/docker-clean - rm /var/cache/apt/archives/lock - apt-get update -q - - echo "APT::Default-Release \"stretch\";" >> /etc/apt/apt.conf.d/00default_release - - echo "deb http://deb.debian.org/debian stretch-backports main" >> /etc/apt/sources.list.d/stretch.list - apt-get update -q - - apt-get install -qy build-essential cmake - - apt-get install -qy -t stretch-backports clang-6.0 + - apt-get install -qy build-essential cmake clang - apt-get install -qy libpoco-dev libjsoncpp-dev doxygen catch - rm -rf build && mkdir -p build && cd build - cmake -DWITH_EXAMPLES=YES .. diff --git a/README.adoc b/README.adoc index d006e7a..66a14e7 100644 --- a/README.adoc +++ b/README.adoc @@ -162,7 +162,7 @@ CentOS 7. These packages are automatically built and not tested. * Tested OS: Linux * C++ compiler (tested: https://gcc.gnu.org/[gcc] 6/8/9, - https://llvm.org/[clang] 5/6) + https://llvm.org/[clang] 5/7) * https://cmake.org/[cmake] (at least: 3.6) * https://pocoproject.org/[POCO] (tested: 1.9 / 1.7) * Optional From c48c1a66f2cc61739849573d82844c7141090ab8 Mon Sep 17 00:00:00 2001 From: tastytea Date: Wed, 21 Aug 2019 04:54:17 +0200 Subject: [PATCH 16/25] Removed and replaced last bits of curlpp. --- cmake/mastodon-cppConfig.cmake.in | 5 ++--- pkg-config/mastodon-cpp.pc.in | 5 +++-- src/CMakeLists.txt | 9 ++------- src/http.cpp | 8 -------- src/mastodon-cpp.cpp | 10 ++++++++-- src/mastodon-cpp.hpp | 13 ++++--------- 6 files changed, 19 insertions(+), 31 deletions(-) diff --git a/cmake/mastodon-cppConfig.cmake.in b/cmake/mastodon-cppConfig.cmake.in index c3cffe3..7d572b4 100644 --- a/cmake/mastodon-cppConfig.cmake.in +++ b/cmake/mastodon-cppConfig.cmake.in @@ -1,8 +1,7 @@ include(CMakeFindDependencyMacro) include(GNUInstallDirs) -find_depencency(jsoncpp REQUIRED CONFIG) -find_dependency(PkgConfig REQUIRED) -pkg_check_modules(curlpp REQUIRED IMPORTED_TARGET curlpp) +find_depencency(jsoncpp CONFIG REQUIRED) +find_package(Poco COMPONENTS Foundation Net NetSSL CONFIG REQUIRED) include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") diff --git a/pkg-config/mastodon-cpp.pc.in b/pkg-config/mastodon-cpp.pc.in index 40f0ccd..9daa607 100644 --- a/pkg-config/mastodon-cpp.pc.in +++ b/pkg-config/mastodon-cpp.pc.in @@ -7,5 +7,6 @@ Name: ${name} Description: @PROJECT_DESCRIPTION@ Version: @PROJECT_VERSION@ Cflags: -I${includedir} -Libs: -L${libdir} -l${name} -lpthread -Requires: jsoncpp curlpp +Libs: -L${libdir} -l${name} -lpthread -lPocoNet +Requires: jsoncpp +Libs.private: -lPocoFoundation -lPocoNetSSL diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f602aff..a9af23e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,9 +1,7 @@ include(GNUInstallDirs) -find_package(PkgConfig REQUIRED) -pkg_check_modules(curlpp REQUIRED IMPORTED_TARGET curlpp) if(WITH_EASY) - find_package(jsoncpp REQUIRED CONFIG) + find_package(jsoncpp CONFIG REQUIRED) endif() # Some distributions do not contain Poco*Config.cmake recipes. find_package(Poco COMPONENTS Foundation Net NetSSL CONFIG) @@ -33,10 +31,7 @@ target_include_directories(${PROJECT_NAME} if(WITH_EASY) target_link_libraries(${PROJECT_NAME} - PUBLIC pthread PkgConfig::curlpp jsoncpp_lib) -else() - target_link_libraries(${PROJECT_NAME} - PUBLIC pthread PkgConfig::curlpp) + PUBLIC pthread jsoncpp_lib) endif() # If no Poco*Config.cmake recipes are found, look for headers in standard dirs. diff --git a/src/http.cpp b/src/http.cpp index 6388781..f6a150f 100644 --- a/src/http.cpp +++ b/src/http.cpp @@ -18,9 +18,6 @@ #include // std::bind #include #include -#include -#include -#include #include #include #include @@ -35,7 +32,6 @@ #include using namespace Mastodon; -namespace curlopts = curlpp::options; using std::cerr; using std::istream; using std::make_unique; @@ -54,8 +50,6 @@ API::http::http(const API &api, const string &instance, , _access_token(access_token) , _cancel_stream(false) { - curlpp::initialize(); - Poco::Net::initializeSSL(); // FIXME: rewrite set_proxy() that it calls set_proxy() here. @@ -98,8 +92,6 @@ API::http::http(const API &api, const string &instance, API::http::~http() { - curlpp::terminate(); - Poco::Net::uninitializeSSL(); } diff --git a/src/mastodon-cpp.cpp b/src/mastodon-cpp.cpp index 0d66b86..cca5d95 100644 --- a/src/mastodon-cpp.cpp +++ b/src/mastodon-cpp.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include "version.hpp" #include "debug.hpp" #include "mastodon-cpp.hpp" @@ -333,11 +334,16 @@ const parameters API::delete_params(const parameters ¶ms, const string Mastodon::urlencode(const std::string &str) { - return curlpp::escape(str); + string out; + Poco::URI::encode(str, "", out); + return out; } + const string Mastodon::urldecode(const std::string &str) { - return curlpp::unescape(str); + string out; + Poco::URI::decode(str, out); + return out; } const string Mastodon::unescape_html(const string &html) diff --git a/src/mastodon-cpp.hpp b/src/mastodon-cpp.hpp index 9ef785c..7f30d43 100644 --- a/src/mastodon-cpp.hpp +++ b/src/mastodon-cpp.hpp @@ -25,8 +25,6 @@ #include #include #include -#include -#include #include #include "return_types.hpp" @@ -686,13 +684,12 @@ namespace Mastodon }; /*! - * @brief Percent-encodes a string. This is done automatically, unless - * you make a custom request. + * @brief Percent-encodes a string. * - * Calls curlpp::escape(str). * - * The only time you should use this, is if you use - * get(const string &call, string &answer). + * This is done automatically where necessary. The only time you + * should use this, is if you use get(const string &call, string + * &answer). * * See RFC 3986 section 2.1 for more info. * @@ -707,8 +704,6 @@ namespace Mastodon /*! * @brief Decodes a percent-encoded string. * - * Calls curlpp::unescape(str). - * * See RFC 3986 section 2.1 for more info. * * @param str The string to decode. From 5ddea0992458f10b98d3bd552a28eab4073e6d51 Mon Sep 17 00:00:00 2001 From: tastytea Date: Wed, 21 Aug 2019 07:28:28 +0200 Subject: [PATCH 17/25] Repair domain-change detection on HTTP redirect. Also added debug statements. --- src/http.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/http.cpp b/src/http.cpp index f6a150f..3180f58 100644 --- a/src/http.cpp +++ b/src/http.cpp @@ -139,7 +139,6 @@ return_call API::http::request_common(const http_method &meth, { string method; - // TODO: operator string on http_method? switch (meth) { case http_method::GET: @@ -216,16 +215,17 @@ return_call API::http::request_common(const http_method &meth, case 303: // HTTPResponse::HTTP_SEE_OTHER case 307: // HTTPResponse::HTTP_TEMPORARY_REDIRECT { + ttdebug << "HTTP redirect.\n"; string location = response.get("Location"); - // TODO: Test HTTP redirects. if (location.substr(0, 4) == "http") { // Remove protocol and instance from path. size_t pos1 = location.find("//") + 2; size_t pos2 = location.find('/', pos1); - if (location.substr(pos1, pos2) != _instance) + if (location.substr(pos1, pos2 - pos1) != _instance) { // Return new location if the domain changed. + ttdebug << "New location is on another domain.\n"; return { 78, "Remote address changed", http_code, location }; } @@ -239,6 +239,7 @@ return_call API::http::request_common(const http_method &meth, } else { + ttdebug << "Following temporary redirect: " << location << '\n'; return request_common(meth, location, formdata, answer); } } From 915c85e9e9188dd9060da60737ac1dd08de8d9a1 Mon Sep 17 00:00:00 2001 From: tastytea Date: Wed, 21 Aug 2019 08:00:46 +0200 Subject: [PATCH 18/25] Changed error codes and introduced error constants. --- CMakeLists.txt | 2 +- README.adoc | 14 +++++------ src/api/delete.cpp | 2 +- src/api/get.cpp | 6 ++--- src/api/get_stream.cpp | 5 +++- src/api/patch.cpp | 2 +- src/api/post.cpp | 2 +- src/api/put.cpp | 2 +- src/easy/return_types_easy.cpp | 10 ++++++++ src/easy/return_types_easy.hpp | 13 ++++++++++ src/easy/simple_calls.cpp | 8 ++++--- src/http.cpp | 43 ++++++++++------------------------ src/mastodon-cpp.hpp | 15 ++++++------ src/return_types.cpp | 9 +++++++ src/return_types.hpp | 14 +++++++++++ src/types.hpp | 12 ++++++++++ 16 files changed, 102 insertions(+), 57 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8fcf9b3..dc6efea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,7 @@ endif() include(GNUInstallDirs) project (mastodon-cpp - VERSION 0.106.0 + VERSION 0.110.0 LANGUAGES CXX) # DESCRIPTION was introduced in version 3.9. diff --git a/README.adoc b/README.adoc index 66a14e7..fbc5408 100644 --- a/README.adoc +++ b/README.adoc @@ -105,13 +105,13 @@ Not included in this list are entities. |=================================================== | Code | Explanation | 0 | No error -| 22 | Invalid argument -| 78 | URL changed (HTTP 301 or 308) -| 110 | Connection timed out -| 111 | Connection refused (check http_error_code) -| 113 | No route to host / Could not resolve host -| 150 | Encryption error (TODO: CHANGEME!) -| 255 | Unknown error +| 1 | Invalid argument +| 10 | URL changed (HTTP 301 or 308) +| 11 | Connection timed out +| 12 | Connection refused (check http_error_code) +| 13 | No route to host / Could not resolve host +| 14 | Encryption error +| 127 | Unknown error |=================================================== If you use a debug build, you get more verbose error messages. diff --git a/src/api/delete.cpp b/src/api/delete.cpp index 59429a6..a56f212 100644 --- a/src/api/delete.cpp +++ b/src/api/delete.cpp @@ -78,7 +78,7 @@ return_call API::del(const Mastodon::API::v1 &call, default: { ttdebug << "ERROR: Invalid argument.\n"; - return { 22, "Invalid argument", 0, "" }; + return { error::INVALID_ARGUMENT, "Invalid argument", 0, "" }; } } diff --git a/src/api/get.cpp b/src/api/get.cpp index 5c2e5bc..5ce5fed 100644 --- a/src/api/get.cpp +++ b/src/api/get.cpp @@ -192,7 +192,7 @@ const return_call API::get(const Mastodon::API::v1 &call, else { ttdebug << "ERROR: Invalid argument.\n"; - return { 22, "Invalid argument", 0, "" }; + return { error::INVALID_ARGUMENT, "Invalid argument", 0, "" }; } break; } @@ -239,7 +239,7 @@ const return_call API::get(const Mastodon::API::v1 &call, default: { ttdebug << "ERROR: Invalid argument.\n"; - return { 22, "Invalid argument", 0, "" }; + return { error::INVALID_ARGUMENT, "Invalid argument", 0, "" }; } } @@ -276,7 +276,7 @@ const return_call API::get(const Mastodon::API::v2 &call, default: { ttdebug << "ERROR: Invalid argument.\n"; - return { 22, "Invalid argument", 0, "" }; + return { error::INVALID_ARGUMENT, "Invalid argument", 0, "" }; } } diff --git a/src/api/get_stream.cpp b/src/api/get_stream.cpp index c5af438..29e6b3e 100644 --- a/src/api/get_stream.cpp +++ b/src/api/get_stream.cpp @@ -20,6 +20,7 @@ using namespace Mastodon; using std::cerr; +using std::to_string; void API::get_stream(const Mastodon::API::v1 &call, const parameters ¶ms, @@ -57,8 +58,10 @@ void API::get_stream(const Mastodon::API::v1 &call, } default: { + const uint8_t err = static_cast(error::INVALID_ARGUMENT); ttdebug << "ERROR: Invalid call.\n"; - stream = "event: ERROR\ndata: {\"error_code\":22}\n"; + stream = "event: ERROR\ndata: " + "{\"error_code\":" + to_string(err) + "}\n"; return; } } diff --git a/src/api/patch.cpp b/src/api/patch.cpp index 82f6801..576f3ea 100644 --- a/src/api/patch.cpp +++ b/src/api/patch.cpp @@ -32,7 +32,7 @@ return_call API::patch(const Mastodon::API::v1 &call, break; default: ttdebug << "ERROR: Invalid argument.\n"; - return { 22, "Invalid argument", 0, "" }; + return { error::INVALID_ARGUMENT, "Invalid argument", 0, "" }; break; } diff --git a/src/api/post.cpp b/src/api/post.cpp index b4a1332..fed3d55 100644 --- a/src/api/post.cpp +++ b/src/api/post.cpp @@ -198,7 +198,7 @@ return_call API::post(const Mastodon::API::v1 &call, default: { ttdebug << "ERROR: Invalid argument.\n"; - return { 22, "Invalid argument", 0, ""}; + return { error::INVALID_ARGUMENT, "Invalid argument", 0, ""}; } } diff --git a/src/api/put.cpp b/src/api/put.cpp index 7a3c430..7dc3794 100644 --- a/src/api/put.cpp +++ b/src/api/put.cpp @@ -58,7 +58,7 @@ return_call API::put(const Mastodon::API::v1 &call, default: { ttdebug << "ERROR: Invalid argument.\n"; - return { 22, "Invalid argument", 0, "" }; + return { error::INVALID_ARGUMENT, "Invalid argument", 0, "" }; } } diff --git a/src/easy/return_types_easy.cpp b/src/easy/return_types_easy.cpp index 656b289..8204e36 100644 --- a/src/easy/return_types_easy.cpp +++ b/src/easy/return_types_easy.cpp @@ -51,6 +51,16 @@ Easy::return_entity::return_entity(const uint8_t ec, const string &em, http_error_code = hec; } +template +Easy::return_entity::return_entity(const error ec, const string &em, + const uint16_t hec, const T &ent) + : entity(ent) +{ + error_code = static_cast(ec); + error_message = em; + http_error_code = hec; +} + template Easy::return_entity::return_entity::operator const T() const { diff --git a/src/easy/return_types_easy.hpp b/src/easy/return_types_easy.hpp index 5cc06c8..915a89f 100644 --- a/src/easy/return_types_easy.hpp +++ b/src/easy/return_types_easy.hpp @@ -61,6 +61,19 @@ namespace Easy return_entity(const uint8_t ec, const string &em, const uint16_t hec, const T &ent); + /*! + * @brief Return type for easy Mastodon::Easy::API. + * + * @param ec Error code + * @param em Error message + * @param hec HTTP error code + * @param ent Answer + * + * @since 0.110.0 + */ + return_entity(const error ec, const string &em, + const uint16_t hec, const T &ent); + /*! * @brief Same as return_entity::entity. * diff --git a/src/easy/simple_calls.cpp b/src/easy/simple_calls.cpp index 74dac23..9b1d7e3 100644 --- a/src/easy/simple_calls.cpp +++ b/src/easy/simple_calls.cpp @@ -39,7 +39,8 @@ const return_entity API::send_post(const Status &status) else { ttdebug << "ERROR: Easy::Status::content can not be empty.\n"; - return { 22, "Easy::Status::content can not be empty", 0, Status() }; + return { error::INVALID_ARGUMENT, + "Easy::Status::content can not be empty", 0, Status() }; } if (!status.in_reply_to_id().empty()) @@ -94,8 +95,9 @@ const return_entity API::send_post(const Status &status) else { ttdebug << "ERROR: Easy::Attachment::file can not be empty.\n"; - return { 22, "Easy::Attachment::file can not be empty", - 0, Status() }; + return { error::INVALID_ARGUMENT, + "Easy::Attachment::file can not be empty", 0, + Status() }; } if (!att.description().empty()) { diff --git a/src/http.cpp b/src/http.cpp index 3180f58..4dd2136 100644 --- a/src/http.cpp +++ b/src/http.cpp @@ -206,7 +206,7 @@ return_call API::http::request_common(const http_method &meth, { case HTTPResponse::HTTP_OK: { - return { 0, "", http_code, answer }; + return { error::OK, "", http_code, answer }; } // Not using the constants because some are too new for Debian stretch. case 301: // HTTPResponse::HTTP_MOVED_PERMANENTLY @@ -226,8 +226,8 @@ return_call API::http::request_common(const http_method &meth, if (location.substr(pos1, pos2 - pos1) != _instance) { // Return new location if the domain changed. ttdebug << "New location is on another domain.\n"; - return { 78, "Remote address changed", http_code, - location }; + return { error::URL_CHANGED, "Remote address changed", + http_code, location }; } location = location.substr(pos2); @@ -235,7 +235,8 @@ return_call API::http::request_common(const http_method &meth, if (http_code == 301 || http_code == 308) { // Return new location for permanent redirects. - return { 78, "Remote address changed", http_code, location }; + return { error::URL_CHANGED, "Remote address changed", + http_code, location }; } else { @@ -245,7 +246,8 @@ return_call API::http::request_common(const http_method &meth, } default: { - return { 111, "Connection refused", http_code, answer }; + return { error::CONNECTION_REFUSED, "Connection refused", + http_code, answer }; } } } @@ -257,7 +259,7 @@ return_call API::http::request_common(const http_method &meth, } ttdebug << e.displayText() << "\n"; - return { 113, e.displayText(), 0, "" }; + return { error::DNS, e.displayText(), 0, "" }; } catch (const Poco::Net::ConnectionRefusedException &e) { @@ -267,7 +269,7 @@ return_call API::http::request_common(const http_method &meth, } ttdebug << e.displayText() << "\n"; - return { 111, e.displayText(), 0, "" }; + return { error::CONNECTION_REFUSED, e.displayText(), 0, "" }; } catch (const Poco::Net::SSLException &e) { @@ -277,7 +279,7 @@ return_call API::http::request_common(const http_method &meth, } ttdebug << e.displayText() << "\n"; - return { 150, e.displayText(), 0, "" }; + return { error::ENCRYPTION, e.displayText(), 0, "" }; } catch (const Poco::Net::NetException &e) { @@ -287,7 +289,7 @@ return_call API::http::request_common(const http_method &meth, } ttdebug << "Unknown network error: " << e.displayText() << std::endl; - return { 255, e.displayText(), 0, "" }; + return { error::UNKNOWN, e.displayText(), 0, "" }; } catch (const std::exception &e) { @@ -297,35 +299,16 @@ return_call API::http::request_common(const http_method &meth, } ttdebug << "Unknown error: " << e.what() << std::endl; - return { 255, e.what(), 0, "" }; + return { error::UNKNOWN, e.what(), 0, "" }; } } +// FIXME: get_headers() doesn't work anymore. void API::http::get_headers(string &headers) const { headers = _headers; } -size_t API::http::callback_write(char* data, size_t size, size_t nmemb, - string *str) -{ - std::lock_guard lock(_mutex); - str->append(data, size * nmemb); - // ttdebug << "Received " << size * nmemb << " Bytes\n"; - return size * nmemb; -} - -double API::http::callback_progress(double /* dltotal */, double /* dlnow */, - double /* ultotal */, double /* ulnow */) -{ - if (_cancel_stream) - { - // This throws the runtime error: Callback aborted - return 1; - } - return 0; -} - void API::http::cancel_stream() { _cancel_stream = true; diff --git a/src/mastodon-cpp.hpp b/src/mastodon-cpp.hpp index 7f30d43..dc506c3 100644 --- a/src/mastodon-cpp.hpp +++ b/src/mastodon-cpp.hpp @@ -46,7 +46,6 @@ using Poco::Net::HTMLForm; */ namespace Mastodon { - // TODO: error enum, different error codes. /*! * @brief Interface to the Mastodon API. * @@ -57,13 +56,13 @@ namespace Mastodon * | Code | Explanation | * | --------: |:-------------------------------------------| * | 0 | No error | - * | 22 | Invalid argument | - * | 78 | URL changed (HTTP 301 or 308) | - * | 110 | Connection timed out | - * | 111 | Connection refused (check http_error_code) | - * | 113 | No route to host / Could not resolve host | - * | 150 | Encryption error | - * | 255 | Unknown error | + * | 1 | Invalid argument | + * | 10 | URL changed (HTTP 301 or 308) | + * | 11 | Connection timed out | + * | 12 | Connection refused (check http_error_code) | + * | 13 | No route to host / Could not resolve host | + * | 14 | Encryption error | + * | 127 | Unknown error | * * @since before 0.11.0 */ diff --git a/src/return_types.cpp b/src/return_types.cpp index 90c70dc..06411c6 100644 --- a/src/return_types.cpp +++ b/src/return_types.cpp @@ -57,4 +57,13 @@ namespace Mastodon error_message = em; http_error_code = hec; } + + return_call::return_call(const error ec, const string &em, + const uint16_t hec, const string &a) + : answer(a) + { + error_code = static_cast(ec); + error_message = em; + http_error_code = hec; + } } diff --git a/src/return_types.hpp b/src/return_types.hpp index d5827c0..d86ce54 100644 --- a/src/return_types.hpp +++ b/src/return_types.hpp @@ -19,6 +19,7 @@ #include #include +#include "types.hpp" using std::uint8_t; using std::uint16_t; @@ -113,6 +114,19 @@ namespace Mastodon return_call(const uint8_t ec, const string &em, const uint16_t hec, const string &a); + /*! + * @brief Return type for Mastodon::API. + * + * @param ec Error code + * @param em Error message + * @param hec HTTP error code + * @param a Answer + * + * @since 0.110.0 + */ + return_call(const error ec, const string &em, + const uint16_t hec, const string &a); + /*! * @brief Same es return_call::answer. * diff --git a/src/types.hpp b/src/types.hpp index b523553..1916e7b 100644 --- a/src/types.hpp +++ b/src/types.hpp @@ -93,6 +93,18 @@ namespace Mastodon DELETE, GET_STREAM }; + + enum class error + { + OK = 0, + INVALID_ARGUMENT = 1, + URL_CHANGED = 10, + CONNECTION_TIMEOUT = 11, + CONNECTION_REFUSED = 12, + DNS = 13, + ENCRYPTION = 14, + UNKNOWN = 127 + }; } #endif // MASTODON_CPP_TYPES_HPP From 41a580b32bc5063d11060d23fd98446f9a2957dc Mon Sep 17 00:00:00 2001 From: tastytea Date: Wed, 21 Aug 2019 10:39:14 +0200 Subject: [PATCH 19/25] Rewrite parsing of http_proxy environment variable. The regex matches host, port, username and password. --- src/http.cpp | 36 +++++++++++++----------------------- 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/src/http.cpp b/src/http.cpp index 4dd2136..e375447 100644 --- a/src/http.cpp +++ b/src/http.cpp @@ -18,6 +18,7 @@ #include // std::bind #include #include +#include #include #include #include @@ -29,13 +30,15 @@ #include #include "debug.hpp" #include "mastodon-cpp.hpp" -#include using namespace Mastodon; using std::cerr; using std::istream; using std::make_unique; using std::move; +using std::regex; +using std::regex_search; +using std::smatch; using Poco::Net::HTTPSClientSession; using Poco::Net::HTTPRequest; using Poco::Net::HTTPResponse; @@ -53,33 +56,20 @@ API::http::http(const API &api, const string &instance, Poco::Net::initializeSSL(); // FIXME: rewrite set_proxy() that it calls set_proxy() here. - // FIXME: Username and password for proxy. try { HTTPSClientSession::ProxyConfig proxy; - string proxy_env = Environment::get("http_proxy"); - size_t pos; + string env_proxy = Environment::get("http_proxy"); + regex re_proxy("^(?:https?://)?(?:([^:]+):?([^@]*)@)?" // user:password + "([^:]+):([[:digit:]]+/?)"); // host:port + smatch match; - // Only keep text between // and /. - if ((pos = proxy_env.find("//")) != string::npos) - { - proxy_env = proxy_env.substr(pos + 2); - } - if ((pos = proxy_env.find('/')) != string::npos) - { - proxy_env = proxy_env.substr(0, pos); - } - - if ((pos = proxy_env.find(':')) != string::npos) - { - proxy.host = proxy_env.substr(0, pos); - proxy.port = std::stoi(proxy_env.substr(pos + 1)); - } - else - { - proxy.host = proxy_env; - } + regex_search(env_proxy, match, re_proxy); + proxy.host = match[3].str(); + proxy.port = std::stoi(match[4].str()); + proxy.username = match[1].str(); + proxy.password = match[2].str(); HTTPSClientSession::setGlobalProxyConfig(proxy); } From 188033a0c10a7a9b4ec0517f7ae1ba55236909c0 Mon Sep 17 00:00:00 2001 From: tastytea Date: Wed, 21 Aug 2019 10:51:52 +0200 Subject: [PATCH 20/25] Simplify get_proxy(). --- src/mastodon-cpp.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/mastodon-cpp.cpp b/src/mastodon-cpp.cpp index cca5d95..d3fd927 100644 --- a/src/mastodon-cpp.cpp +++ b/src/mastodon-cpp.cpp @@ -301,14 +301,8 @@ void API::set_proxy(const string &proxy, const string &userpw) void API::get_proxy(string &proxy, string &userpw) const { - if (!_proxy.empty()) - { - proxy = _proxy; - if (!_proxy_userpw.empty()) - { - userpw = _proxy_userpw; - } - } + proxy = _proxy; + userpw = _proxy_userpw; } const parameters API::delete_params(const parameters ¶ms, From acbcb6224ec1cf91b5e76398e6a2ec2a4f9acf5c Mon Sep 17 00:00:00 2001 From: tastytea Date: Wed, 21 Aug 2019 11:06:41 +0200 Subject: [PATCH 21/25] Mastodon::http inherits proxy config from parent. Ff set_proxy() is called, _http.inherit_proxy() is called. --- src/http.cpp | 55 +++++++++++++++++++++++++++++++++++++++----- src/mastodon-cpp.cpp | 2 ++ src/mastodon-cpp.hpp | 11 +++++++-- 3 files changed, 60 insertions(+), 8 deletions(-) diff --git a/src/http.cpp b/src/http.cpp index e375447..e4e58f3 100644 --- a/src/http.cpp +++ b/src/http.cpp @@ -59,19 +59,19 @@ API::http::http(const API &api, const string &instance, try { - HTTPSClientSession::ProxyConfig proxy; + HTTPSClientSession::ProxyConfig proxyconfig; string env_proxy = Environment::get("http_proxy"); regex re_proxy("^(?:https?://)?(?:([^:]+):?([^@]*)@)?" // user:password "([^:]+):([[:digit:]]+/?)"); // host:port smatch match; regex_search(env_proxy, match, re_proxy); - proxy.host = match[3].str(); - proxy.port = std::stoi(match[4].str()); - proxy.username = match[1].str(); - proxy.password = match[2].str(); + proxyconfig.host = match[3].str(); + proxyconfig.port = std::stoi(match[4].str()); + proxyconfig.username = match[1].str(); + proxyconfig.password = match[2].str(); - HTTPSClientSession::setGlobalProxyConfig(proxy); + HTTPSClientSession::setGlobalProxyConfig(proxyconfig); } catch (const std::exception &) { @@ -85,6 +85,49 @@ API::http::~http() Poco::Net::uninitializeSSL(); } +void API::http::inherit_proxy() +{ + // TODO: Test proxy. + string proxy, userpw; + parent.get_proxy(proxy, userpw); + + size_t pos = proxy.find(':'); + if (pos == string::npos) + { + return; + } + + try + { + HTTPSClientSession::ProxyConfig proxyconfig; + proxyconfig.host = proxy.substr(0, pos); + proxyconfig.port = std::stoi(proxy.substr(pos + 1)); + + if (!userpw.empty()) + { + pos = userpw.find(':'); + if (pos == string::npos) + { + proxyconfig.username = userpw; + } + else + { + proxyconfig.username = userpw.substr(0, pos); + proxyconfig.password = std::stoi(userpw.substr(pos + 1)); + } + } + + HTTPSClientSession::setGlobalProxyConfig(proxyconfig); + } + catch (const std::exception &e) + { + if (parent.exceptions()) + { + std::rethrow_exception(std::current_exception()); + } + } +} + return_call API::http::request(const http_method &meth, const string &path) { HTMLForm form; diff --git a/src/mastodon-cpp.cpp b/src/mastodon-cpp.cpp index d3fd927..1b0e4c3 100644 --- a/src/mastodon-cpp.cpp +++ b/src/mastodon-cpp.cpp @@ -297,6 +297,8 @@ void API::set_proxy(const string &proxy, const string &userpw) { _proxy = proxy; _proxy_userpw = userpw; + + _http.inherit_proxy(); } void API::get_proxy(string &proxy, string &userpw) const diff --git a/src/mastodon-cpp.hpp b/src/mastodon-cpp.hpp index dc506c3..c051a11 100644 --- a/src/mastodon-cpp.hpp +++ b/src/mastodon-cpp.hpp @@ -142,6 +142,13 @@ namespace Mastodon */ std::mutex &get_mutex(); + /*! + * @brief Inherit proxy from parent. Do not call this. + * + * @since 0.110.0 + */ + void inherit_proxy(); + private: const API &parent; const string _instance; @@ -441,8 +448,8 @@ namespace Mastodon * Since mastodon-cpp is built on libcurl, it respects the same * proxy environment variables. See `man curl`. * - * @param proxy See `man 3 CURLOPT_PROXY` - * @param userpw See `man 3 CURLOPT_PROXYUSERPWD` (optional) + * @param proxy host:port + * @param userpw username[:password] (optional) * * @since 0.15.0 */ From d2a4d835de74760ea53ae36adeac21b2c07ebffa Mon Sep 17 00:00:00 2001 From: tastytea Date: Sun, 25 Aug 2019 04:50:08 +0200 Subject: [PATCH 22/25] Moved set_proxy() to API::http(). API::set_proxy() calls API::http::set_proxy(). Deleted API::get_proxy(). --- src/http.cpp | 59 +++++++++++++++++++++++--------------------- src/mastodon-cpp.cpp | 15 ++--------- src/mastodon-cpp.hpp | 29 ++++++++-------------- 3 files changed, 43 insertions(+), 60 deletions(-) diff --git a/src/http.cpp b/src/http.cpp index e4e58f3..50bc4eb 100644 --- a/src/http.cpp +++ b/src/http.cpp @@ -59,19 +59,29 @@ API::http::http(const API &api, const string &instance, try { - HTTPSClientSession::ProxyConfig proxyconfig; string env_proxy = Environment::get("http_proxy"); - regex re_proxy("^(?:https?://)?(?:([^:]+):?([^@]*)@)?" // user:password - "([^:]+):([[:digit:]]+/?)"); // host:port - smatch match; + size_t pos; - regex_search(env_proxy, match, re_proxy); - proxyconfig.host = match[3].str(); - proxyconfig.port = std::stoi(match[4].str()); - proxyconfig.username = match[1].str(); - proxyconfig.password = match[2].str(); + // Only keep text between // and /. + if ((pos = env_proxy.find("//")) != string::npos) + { + env_proxy = env_proxy.substr(pos + 2); + } + if ((pos = env_proxy.find('/')) != string::npos) + { + env_proxy = env_proxy.substr(0, pos); + } - HTTPSClientSession::setGlobalProxyConfig(proxyconfig); + if ((pos = env_proxy.find('@')) != string::npos) + { + string hostport = env_proxy.substr(pos + 1); + string userpw = env_proxy.substr(0, pos); + parent.set_proxy(hostport, userpw); + } + else + { + parent.set_proxy(env_proxy); + } } catch (const std::exception &) { @@ -85,35 +95,28 @@ API::http::~http() Poco::Net::uninitializeSSL(); } -void API::http::inherit_proxy() +void API::http::set_proxy(const string &hostport, const string &userpw) { // TODO: Test proxy. - string proxy, userpw; - parent.get_proxy(proxy, userpw); - - size_t pos = proxy.find(':'); - if (pos == string::npos) - { - return; - } try { HTTPSClientSession::ProxyConfig proxyconfig; - proxyconfig.host = proxy.substr(0, pos); - proxyconfig.port = std::stoi(proxy.substr(pos + 1)); + size_t pos = hostport.find(':'); + + proxyconfig.host = hostport.substr(0, pos); + if (pos != string::npos) + { + proxyconfig.port = std::stoi(hostport.substr(pos + 1)); + } if (!userpw.empty()) { pos = userpw.find(':'); - if (pos == string::npos) + proxyconfig.username = userpw.substr(0, pos); + if (pos != string::npos) { - proxyconfig.username = userpw; - } - else - { - proxyconfig.username = userpw.substr(0, pos); - proxyconfig.password = std::stoi(userpw.substr(pos + 1)); + proxyconfig.password = userpw.substr(pos + 1); } } diff --git a/src/mastodon-cpp.cpp b/src/mastodon-cpp.cpp index 1b0e4c3..332603c 100644 --- a/src/mastodon-cpp.cpp +++ b/src/mastodon-cpp.cpp @@ -36,8 +36,6 @@ API::API(const string &instance, const string &access_token) , _useragent(string("mastodon-cpp/") + global::version) , _http(*this, instance, access_token) , _exceptions(false) -, _proxy("") -, _proxy_userpw("") { bool fash = false; const std::regex re_gab("(?:\\.|^)gab\\.[^\\.]+$"); @@ -293,18 +291,9 @@ bool API::exceptions() const return _exceptions; } -void API::set_proxy(const string &proxy, const string &userpw) +void API::set_proxy(const string &hostport, const string &userpw) { - _proxy = proxy; - _proxy_userpw = userpw; - - _http.inherit_proxy(); -} - -void API::get_proxy(string &proxy, string &userpw) const -{ - proxy = _proxy; - userpw = _proxy_userpw; + _http.set_proxy(hostport, userpw); } const parameters API::delete_params(const parameters ¶ms, diff --git a/src/mastodon-cpp.hpp b/src/mastodon-cpp.hpp index c051a11..58c7b8a 100644 --- a/src/mastodon-cpp.hpp +++ b/src/mastodon-cpp.hpp @@ -143,11 +143,14 @@ namespace Mastodon std::mutex &get_mutex(); /*! - * @brief Inherit proxy from parent. Do not call this. + * @brief Set proxy. Do not call this directly. + * + * @param hostport host[:port] + * @param userpw user[:password] * * @since 0.110.0 */ - void inherit_proxy(); + void set_proxy(const string &hostport, const string &userpw); private: const API &parent; @@ -445,25 +448,15 @@ namespace Mastodon /*! * @brief Sets the proxy. * - * Since mastodon-cpp is built on libcurl, it respects the same - * proxy environment variables. See `man curl`. + * Both the username and the password will be URL decoded + * before use. * - * @param proxy host:port - * @param userpw username[:password] (optional) + * @param hostport host[:port] + * @param userpw username[:password] (optional) * * @since 0.15.0 */ - void set_proxy(const string &proxy, const string &userpw = ""); - - /*! - * @brief For internal use - * - * @param proxy URL - * @param userpw username:password - * - * @since 0.15.1 - */ - void get_proxy(string &proxy, string &userpw) const; + void set_proxy(const string &hostport, const string &userpw = ""); /*! * @brief Make a GET request that doesn't require parameters. @@ -652,8 +645,6 @@ namespace Mastodon string _useragent; http _http; bool _exceptions; - string _proxy; - string _proxy_userpw; /*! * @brief Converts map of parameters into a string. From 6b070dec9857b2811b4dddf02d73a5f47803b4f0 Mon Sep 17 00:00:00 2001 From: tastytea Date: Sun, 25 Aug 2019 05:08:37 +0200 Subject: [PATCH 23/25] Percent-decode proxy username and password. --- src/http.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/http.cpp b/src/http.cpp index 50bc4eb..7e006dc 100644 --- a/src/http.cpp +++ b/src/http.cpp @@ -112,11 +112,17 @@ void API::http::set_proxy(const string &hostport, const string &userpw) if (!userpw.empty()) { + string username; + pos = userpw.find(':'); - proxyconfig.username = userpw.substr(0, pos); + Poco::URI::decode(userpw.substr(0, pos), username); + proxyconfig.username = username; + if (pos != string::npos) { - proxyconfig.password = userpw.substr(pos + 1); + string password; + Poco::URI::decode(userpw.substr(pos + 1), password); + proxyconfig.password = password; } } From 707771c7bf20ccfce2e8d900ea4acdf385b9ab62 Mon Sep 17 00:00:00 2001 From: tastytea Date: Sun, 25 Aug 2019 05:27:00 +0200 Subject: [PATCH 24/25] Bugfix: Do not try to set proxy in parent class. --- src/http.cpp | 4 ++-- src/mastodon-cpp.hpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/http.cpp b/src/http.cpp index 7e006dc..9648e0a 100644 --- a/src/http.cpp +++ b/src/http.cpp @@ -76,11 +76,11 @@ API::http::http(const API &api, const string &instance, { string hostport = env_proxy.substr(pos + 1); string userpw = env_proxy.substr(0, pos); - parent.set_proxy(hostport, userpw); + set_proxy(hostport, userpw); } else { - parent.set_proxy(env_proxy); + set_proxy(env_proxy); } } catch (const std::exception &) diff --git a/src/mastodon-cpp.hpp b/src/mastodon-cpp.hpp index 58c7b8a..6e06235 100644 --- a/src/mastodon-cpp.hpp +++ b/src/mastodon-cpp.hpp @@ -146,11 +146,11 @@ namespace Mastodon * @brief Set proxy. Do not call this directly. * * @param hostport host[:port] - * @param userpw user[:password] + * @param userpw user[:password] (optional) * * @since 0.110.0 */ - void set_proxy(const string &hostport, const string &userpw); + void set_proxy(const string &hostport, const string &userpw = ""); private: const API &parent; From 08ae30835cfd2673a6fa5f564a2673283cec6f85 Mon Sep 17 00:00:00 2001 From: tastytea Date: Fri, 30 Aug 2019 08:06:48 +0200 Subject: [PATCH 25/25] Confirmed that proxies work, added debug message with proxy info. --- src/http.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/http.cpp b/src/http.cpp index 9648e0a..064b134 100644 --- a/src/http.cpp +++ b/src/http.cpp @@ -55,8 +55,6 @@ API::http::http(const API &api, const string &instance, { Poco::Net::initializeSSL(); - // FIXME: rewrite set_proxy() that it calls set_proxy() here. - try { string env_proxy = Environment::get("http_proxy"); @@ -97,8 +95,6 @@ API::http::~http() void API::http::set_proxy(const string &hostport, const string &userpw) { - // TODO: Test proxy. - try { HTTPSClientSession::ProxyConfig proxyconfig; @@ -127,6 +123,7 @@ void API::http::set_proxy(const string &hostport, const string &userpw) } HTTPSClientSession::setGlobalProxyConfig(proxyconfig); + ttdebug << "Set proxy to " << hostport << ".\n"; } catch (const std::exception &e) {