From 371f5726462b00f8df9096d4c72e4f6ba145a7c5 Mon Sep 17 00:00:00 2001 From: Sebastian Messmer Date: Wed, 12 Jul 2023 21:33:51 -0700 Subject: [PATCH] Use libcurl dependency from conan instead of requiring it to be preinstalled --- .github/workflows/main.yaml | 11 + ChangeLog.txt | 1 + README.md | 8 +- cmake-utils/DependenciesFromConan.cmake | 3 + cmake-utils/DependenciesFromLocalSystem.cmake | 7 + conanfile.py | 1 + src/cpp-utils/CMakeLists.txt | 11 +- src/cpp-utils/network/CurlHttpClient.cpp | 4 - src/cpp-utils/network/CurlHttpClient.h | 4 - src/cpp-utils/network/WinHttpClient.cpp | 260 ------------------ src/cpp-utils/network/WinHttpClient.h | 31 --- src/cryfs-cli/main.cpp | 8 +- 12 files changed, 28 insertions(+), 321 deletions(-) delete mode 100644 src/cpp-utils/network/WinHttpClient.cpp delete mode 100644 src/cpp-utils/network/WinHttpClient.h diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index a0402662..234a75cb 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -183,6 +183,17 @@ jobs: - os: ubuntu-22.04 compiler: {cxx: clang++-11, cc: clang-11, macos_cxx: /usr/local/opt/llvm@11/bin/clang++, macos_cc: /usr/local/opt/llvm@11/bin/clang, apt_package: "clang-11 libomp5-11 libomp-11-dev", homebrew_package: llvm@11} build_type: Debug + # GCC on MacOS 11 doesn't work, see https://github.com/curl/curl/issues/11441 + - os: macos-11 + compiler: {cxx: g++-9, cc: gcc-9, macos_cxx: g++-9, macos_cc: gcc-9, homebrew_package: gcc@9, apt_package: g++-9} + - os: macos-11 + compiler: {cxx: g++-10, cc: gcc-10, macos_cxx: g++-10, macos_cc: gcc-10, homebrew_package: gcc@10, apt_package: g++-10} + - os: macos-11 + compiler: {cxx: g++-11, cc: gcc-11, macos_cxx: g++-11, macos_cc: gcc-11, homebrew_package: gcc@11, apt_package: g++-11} + - os: macos-11 + compiler: {cxx: g++-12, cc: gcc-12, macos_cxx: g++-12, macos_cc: gcc-12, homebrew_package: gcc@12, apt_package: g++-12} + - os: macos-11 + compiler: {cxx: g++-13, cc: gcc-13, macos_cxx: g++-13, macos_cc: gcc-13, homebrew_package: gcc@13, apt_package: g++-13} include: - name: Local dependencies os: ubuntu-22.04 diff --git a/ChangeLog.txt b/ChangeLog.txt index eef57a6f..45f92117 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -2,6 +2,7 @@ Version 0.12.0 (unreleased) --------------- * Added a man page for `cryfs-unmount` * Fixed small inaccuracy in calculation of free space in statvfs +* Use libcurl dependency from conan instead of requiring it to be preinstalled * Updated dependencies to * DokanY 2.0.6.1000 * range-v3/0.12.0 diff --git a/README.md b/README.md index e889f851..7259e340 100644 --- a/README.md +++ b/README.md @@ -89,8 +89,6 @@ Requirements - CMake version >= 3.10 - pkg-config (on Unix) - Conan package manager (version 1.x) - - libcurl4 (including development headers) - - SSL development libraries (including development headers, e.g. libssl-dev) - libFUSE version >= 2.8.6 (including development headers), on Mac OS X instead install macFUSE from https://osxfuse.github.io/ - Python >= 3.5 - OpenMP @@ -98,15 +96,15 @@ Requirements You can use the following commands to install these requirements # Ubuntu - $ sudo apt install git g++ cmake make pkg-config libcurl4-openssl-dev libssl-dev libfuse-dev python3 python3-pip + $ sudo apt install git g++ cmake make pkg-config libfuse-dev python3 python3-pip $ sudo pip3 install conan==1.60.1 # Fedora - $ sudo dnf install git gcc-c++ cmake make pkgconf libcurl-devel openssl-devel fuse-devel python3 python3-pip + $ sudo dnf install git gcc-c++ cmake make pkgconf fuse-devel python3 python3-pip $ sudo pip3 install conan==1.60.1 # Macintosh - $ brew install cmake pkg-config openssl libomp macfuse + $ brew install cmake pkg-config libomp macfuse $ sudo pip3 install conan==1.60.1 Build & Install diff --git a/cmake-utils/DependenciesFromConan.cmake b/cmake-utils/DependenciesFromConan.cmake index b0258aaf..00de525e 100644 --- a/cmake-utils/DependenciesFromConan.cmake +++ b/cmake-utils/DependenciesFromConan.cmake @@ -17,3 +17,6 @@ target_link_libraries(CryfsDependencies_spdlog INTERFACE CONAN_PKG::spdlog) add_library(CryfsDependencies_boost INTERFACE) target_link_libraries(CryfsDependencies_boost INTERFACE CONAN_PKG::boost) + +add_library(CryfsDependencies_libcurl INTERFACE) +target_link_libraries(CryfsDependencies_libcurl INTERFACE CONAN_PKG::libcurl) diff --git a/cmake-utils/DependenciesFromLocalSystem.cmake b/cmake-utils/DependenciesFromLocalSystem.cmake index 54064532..f9d949fd 100644 --- a/cmake-utils/DependenciesFromLocalSystem.cmake +++ b/cmake-utils/DependenciesFromLocalSystem.cmake @@ -59,3 +59,10 @@ find_package(spdlog REQUIRED) check_target_is_not_from_conan(spdlog::spdlog) add_library(CryfsDependencies_spdlog INTERFACE) target_link_libraries(CryfsDependencies_spdlog INTERFACE spdlog::spdlog) + + + +# Setup libcurl dependency +find_package(CURL REQUIRED) +add_library(CryfsDependencies_libcurl INTERFACE) +target_link_libraries(CryfsDependencies_libcurl INTERFACE CURL::libcurl) diff --git a/conanfile.py b/conanfile.py index 0b91e80f..0265601d 100644 --- a/conanfile.py +++ b/conanfile.py @@ -6,6 +6,7 @@ class CryFSConan(ConanFile): "range-v3/0.12.0", "spdlog/1.11.0", "boost/1.79.0", + "libcurl/8.1.2", ] generators = "cmake" default_options = { diff --git a/src/cpp-utils/CMakeLists.txt b/src/cpp-utils/CMakeLists.txt index bac6d4ff..b0f69d32 100644 --- a/src/cpp-utils/CMakeLists.txt +++ b/src/cpp-utils/CMakeLists.txt @@ -17,7 +17,6 @@ set(SOURCES tempfile/TempDir.cpp network/HttpClient.cpp network/CurlHttpClient.cpp - network/WinHttpClient.cpp network/FakeHttpClient.cpp io/Console.cpp io/DontEchoStdinToStdoutRAII.cpp @@ -67,20 +66,12 @@ elseif (APPLE) target_compile_definitions(${PROJECT_NAME} PRIVATE BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED) endif() -if (NOT MSVC) - find_package(CURL REQUIRED) - target_include_directories(${PROJECT_NAME} PUBLIC ${CURL_INCLUDE_DIRS}) - target_link_libraries(${PROJECT_NAME} PUBLIC ${CURL_LIBRARIES}) -else() - target_link_libraries(${PROJECT_NAME} PUBLIC WinHttp) -endif() - find_package(Threads REQUIRED) target_link_libraries(${PROJECT_NAME} PUBLIC ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries(${PROJECT_NAME} PUBLIC ${CMAKE_DL_LIBS}) -target_link_libraries(${PROJECT_NAME} PUBLIC CryfsDependencies_spdlog cryptopp CryfsDependencies_range-v3) +target_link_libraries(${PROJECT_NAME} PUBLIC CryfsDependencies_spdlog cryptopp CryfsDependencies_range-v3 CryfsDependencies_libcurl) target_add_boost(${PROJECT_NAME}) target_enable_style_warnings(${PROJECT_NAME}) diff --git a/src/cpp-utils/network/CurlHttpClient.cpp b/src/cpp-utils/network/CurlHttpClient.cpp index ed404892..62bff88e 100644 --- a/src/cpp-utils/network/CurlHttpClient.cpp +++ b/src/cpp-utils/network/CurlHttpClient.cpp @@ -1,7 +1,5 @@ // Base version taken from https://techoverflow.net/blog/2013/03/15/c-simple-http-download-using-libcurl-easy-api/ -#if !defined(_MSC_VER) - #include "CurlHttpClient.h" #include #include @@ -69,5 +67,3 @@ namespace cpputils { } } - -#endif diff --git a/src/cpp-utils/network/CurlHttpClient.h b/src/cpp-utils/network/CurlHttpClient.h index 16b2e23f..da784381 100644 --- a/src/cpp-utils/network/CurlHttpClient.h +++ b/src/cpp-utils/network/CurlHttpClient.h @@ -2,8 +2,6 @@ #ifndef MESSMER_CPPUTILS_NETWORK_CURLHTTPCLIENT_HPP #define MESSMER_CPPUTILS_NETWORK_CURLHTTPCLIENT_HPP -#if !defined(_MSC_VER) - #include "HttpClient.h" #include "../macros.h" #include @@ -44,5 +42,3 @@ namespace cpputils { } #endif - -#endif diff --git a/src/cpp-utils/network/WinHttpClient.cpp b/src/cpp-utils/network/WinHttpClient.cpp deleted file mode 100644 index 14458e5c..00000000 --- a/src/cpp-utils/network/WinHttpClient.cpp +++ /dev/null @@ -1,260 +0,0 @@ -#if defined(_MSC_VER) - -#include "WinHttpClient.h" -#include -#include -#include -#include -#include -#include -#include -#include - -using boost::none; -using boost::optional; -using std::string; -using std::wstring; -using std::wstring_convert; -using std::ostringstream; - -namespace cpputils { - - namespace { - struct HttpHandleRAII final { - HINTERNET handle; - - HttpHandleRAII(HINTERNET handle_) : handle(handle_) {} - - HttpHandleRAII(HttpHandleRAII&& rhs) : handle(rhs.handle) { - rhs.handle = nullptr; - } - - ~HttpHandleRAII() { - if (nullptr != handle) { - BOOL success = WinHttpCloseHandle(handle); - if (!success) { - throw std::runtime_error("Error calling WinHttpCloseHandle. Error code: " + std::to_string(GetLastError())); - } - } - } - - DISALLOW_COPY_AND_ASSIGN(HttpHandleRAII); - }; - - URL_COMPONENTS parse_url(const wstring &url) { - URL_COMPONENTS result; - result.dwStructSize = sizeof(result); - // Declare fields we want. Setting a field to nullptr and the length to non-zero means the field will be returned. - result.lpszScheme = nullptr; - result.dwSchemeLength = 1; - result.lpszHostName = nullptr; - result.dwHostNameLength = 1; - result.lpszUserName = nullptr; - result.dwUserNameLength = 1; - result.lpszPassword = nullptr; - result.dwPasswordLength = 1; - result.lpszUrlPath = nullptr; - result.dwUrlPathLength = 1; - result.lpszExtraInfo = nullptr; - result.dwExtraInfoLength = 1; - - BOOL success = WinHttpCrackUrl(url.c_str(), url.size(), ICU_REJECT_USERPWD, &result); - if (!success) { - throw std::runtime_error("Error parsing url '" + wstring_convert>().to_bytes(url) + "'. Error code: " + std::to_string(GetLastError())); - } - - return result; - } - - INTERNET_PORT get_port_from_url(const URL_COMPONENTS& parsedUrl) { - wstring scheme_str(parsedUrl.lpszScheme, parsedUrl.dwSchemeLength); - string s_(wstring_convert < std::codecvt_utf8_utf16>().to_bytes(scheme_str)); - if (parsedUrl.nScheme == INTERNET_SCHEME_HTTP) { - ASSERT(scheme_str == L"http", "Scheme mismatch"); - if (parsedUrl.nPort != 80) { - throw std::runtime_error("We don't support non-default ports"); - } - return INTERNET_DEFAULT_HTTP_PORT; - } - else if (parsedUrl.nScheme == INTERNET_SCHEME_HTTPS) { - ASSERT(scheme_str == L"https", "Scheme mismatch"); - if (parsedUrl.nPort != 443) { - throw std::runtime_error("We don't support non-default ports"); - } - return INTERNET_DEFAULT_HTTPS_PORT; - } - else { - throw std::runtime_error("Unsupported scheme: " + wstring_convert>().to_bytes(scheme_str)); - } - } - - class Request final { - public: - Request(HttpHandleRAII request) : request_(std::move(request)) {} - - void set_redirect_policy(DWORD redirectPolicy) { - BOOL success = WinHttpSetOption(request_.handle, WINHTTP_OPTION_REDIRECT_POLICY, &redirectPolicy, sizeof(redirectPolicy)); - if (!success) { - throw std::runtime_error("Error calling WinHttpSetOption. Error code: " + std::to_string(GetLastError())); - } - } - - void set_timeouts(long timeoutMsec) { - // TODO Timeout should be a total timeout, not per step as we're doing it here. - BOOL success = WinHttpSetTimeouts(request_.handle, timeoutMsec, timeoutMsec, timeoutMsec, timeoutMsec); - if (!success) { - throw std::runtime_error("Error calling WinHttpSetTimeouts. Error code: " + std::to_string(GetLastError())); - } - } - - void send() { - BOOL success = WinHttpSendRequest(request_.handle, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0); - if (!success) { - throw std::runtime_error("Error calling WinHttpSendRequest. Error code: " + std::to_string(GetLastError())); - } - } - - void wait_for_response() { - BOOL success = WinHttpReceiveResponse(request_.handle, nullptr); - if (!success) { - throw std::runtime_error("Error calling WinHttpReceiveResponse. Error code: " + std::to_string(GetLastError())); - } - } - - DWORD get_status_code() { - DWORD statusCode; - DWORD statusCodeSize = sizeof(statusCode); - BOOL success = WinHttpQueryHeaders(request_.handle, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &statusCode, &statusCodeSize, WINHTTP_NO_HEADER_INDEX); - if (!success) { - throw std::runtime_error("Eror calling WinHttpQueryHeaders. Error code: " + std::to_string(GetLastError())); - } - return statusCode; - } - - string read_response() { - ostringstream result; - - while (true) { - DWORD size = num_bytes_readable(); - if (size == 0) { - break; - } - - cpputils::Data buffer(size + 1); - buffer.FillWithZeroes(); - - DWORD num_read; - BOOL success = WinHttpReadData(request_.handle, buffer.data(), buffer.size(), &num_read); - if (!success) { - throw std::runtime_error("Error calling WinHttpReadData. Error code: " + std::to_string(GetLastError())); - } - ASSERT(0 != num_read, "Weird behavior of WinHttpReadData.It should never read zero bytes since WinHttpQueryDataAvailable said there are bytes readable."); - - result.write(reinterpret_cast(buffer.data()), num_read); - ASSERT(result.good(), "Error writing to ostringstream"); - } - - return result.str(); - } - - private: - DWORD num_bytes_readable() { - DWORD result; - BOOL success = WinHttpQueryDataAvailable(request_.handle, &result); - if (!success) { - throw std::runtime_error("Error calling WinHttpQueryDataAvailable. Error code: " + std::to_string(GetLastError())); - } - return result; - } - - HttpHandleRAII request_; - }; - - struct Connection final { - public: - Connection(HttpHandleRAII connection) : connection_(std::move(connection)) {} - - Request create_request(const URL_COMPONENTS& parsedUrl) { - const INTERNET_PORT port = get_port_from_url(parsedUrl); - const wstring path = wstring(parsedUrl.lpszUrlPath, parsedUrl.dwUrlPathLength) + wstring(parsedUrl.lpszExtraInfo, parsedUrl.dwExtraInfoLength); - const DWORD flags = (port == INTERNET_DEFAULT_HTTPS_PORT) ? WINHTTP_FLAG_SECURE : 0; - - HttpHandleRAII request_handle(WinHttpOpenRequest(connection_.handle, L"GET", path.c_str(), nullptr, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, flags)); - if (nullptr == request_handle.handle) { - throw std::runtime_error("Error calling WinHttpOpenRequest. Error code: " + std::to_string(GetLastError())); - } - return Request(std::move(request_handle)); - } - - private: - HttpHandleRAII connection_; - }; - } - - struct WinHttpSession final { - public: - WinHttpSession(HttpHandleRAII session) : session_(std::move(session)) {} - - Connection create_connection(const URL_COMPONENTS& parsedUrl) { - const INTERNET_PORT port = get_port_from_url(parsedUrl); - const wstring host(parsedUrl.lpszHostName, parsedUrl.dwHostNameLength); - - HttpHandleRAII connection_handle = WinHttpConnect(session_.handle, host.c_str(), port, 0); - if (nullptr == connection_handle.handle) { - throw std::runtime_error("Error calling WinHttpConnect. Error code: " + std::to_string(GetLastError())); - } - - return Connection(std::move(connection_handle)); - } - - private: - HttpHandleRAII session_; - }; - - namespace { - cpputils::unique_ref create_session() { - const DWORD dwAccessType = IsWindows8Point1OrGreater() ? WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY : WINHTTP_ACCESS_TYPE_DEFAULT_PROXY; - HttpHandleRAII session_handle = WinHttpOpen(L"cpputils::HttpClient", dwAccessType, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); - if(nullptr == session_handle.handle) { - throw std::runtime_error("Error calling WinHttpOpen. Error code: " + std::to_string(GetLastError())); - } - - return cpputils::make_unique_ref(std::move(session_handle)); - } - } - - WinHttpClient::WinHttpClient() : session_(create_session()) {} - - WinHttpClient::~WinHttpClient() {} - - string WinHttpClient::get(const string &url, optional timeoutMsec) { - wstring wurl = wstring_convert>().from_bytes(url); - const URL_COMPONENTS parsedUrl = parse_url(wurl); - - ASSERT(parsedUrl.dwUserNameLength == 0, "Authentication not supported"); - ASSERT(parsedUrl.dwPasswordLength == 0, "Authentication not supported"); - - Connection connection = session_->create_connection(parsedUrl); - Request request = connection.create_request(parsedUrl); - - // allow redirects but not from https to http - request.set_redirect_policy(WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP); - - if (timeoutMsec != none) { - request.set_timeouts(*timeoutMsec); - } - - request.send(); - request.wait_for_response(); - - DWORD statusCode = request.get_status_code(); - if (statusCode != HTTP_STATUS_OK) { - throw std::runtime_error("HTTP Server returned unsupported status code: " + std::to_string(statusCode)); - } - - return request.read_response(); - } - -} - -#endif diff --git a/src/cpp-utils/network/WinHttpClient.h b/src/cpp-utils/network/WinHttpClient.h deleted file mode 100644 index 8ef55b2e..00000000 --- a/src/cpp-utils/network/WinHttpClient.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once -#ifndef MESSMER_CPPUTILS_NETWORK_WINHTTPCLIENT_HPP -#define MESSMER_CPPUTILS_NETWORK_WINHTTPCLIENT_HPP - -#if defined(_MSC_VER) - -#include "HttpClient.h" -#include "../macros.h" -#include "../pointer/unique_ref.h" - -namespace cpputils { - - class WinHttpSession; - - class WinHttpClient final : public HttpClient { - public: - WinHttpClient(); - ~WinHttpClient(); - - std::string get(const std::string &url, boost::optional timeoutMsec = boost::none) override; - - private: - unique_ref session_; - - DISALLOW_COPY_AND_ASSIGN(WinHttpClient); - }; - -} - -#endif -#endif diff --git a/src/cryfs-cli/main.cpp b/src/cryfs-cli/main.cpp index cb78e950..4e6ee3fa 100644 --- a/src/cryfs-cli/main.cpp +++ b/src/cryfs-cli/main.cpp @@ -1,13 +1,11 @@ #include "Cli.h" #include #include +#include #include #if defined(_MSC_VER) -#include #include -#else -#include #endif using namespace cryfs_cli; @@ -28,11 +26,7 @@ int main(int argc, const char *argv[]) { try { auto &keyGenerator = Random::OSRandom(); -#if defined(_MSC_VER) - auto httpClient = make_unique_ref(); -#else auto httpClient = make_unique_ref(); -#endif return Cli(keyGenerator, SCrypt::DefaultSettings, make_shared()) .main(argc, argv, std::move(httpClient), []{}); } catch (const cryfs::CryfsException &e) {