Use libcurl dependency from conan instead of requiring it to be preinstalled
This commit is contained in:
parent
fc21f1c520
commit
371f572646
11
.github/workflows/main.yaml
vendored
11
.github/workflows/main.yaml
vendored
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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 = {
|
||||
|
@ -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})
|
||||
|
@ -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 <sstream>
|
||||
#include <iostream>
|
||||
@ -69,5 +67,3 @@ namespace cpputils {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -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 <mutex>
|
||||
@ -44,5 +42,3 @@ namespace cpputils {
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -1,260 +0,0 @@
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
#include "WinHttpClient.h"
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <cpp-utils/assert/assert.h>
|
||||
#include <cpp-utils/data/Data.h>
|
||||
#include <codecvt>
|
||||
#include <Windows.h>
|
||||
#include <Winhttp.h>
|
||||
#include <VersionHelpers.h>
|
||||
|
||||
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<std::codecvt_utf8_utf16<wchar_t>>().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<wchar_t>>().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<std::codecvt_utf8_utf16<wchar_t>>().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<char*>(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<WinHttpSession> 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<WinHttpSession>(std::move(session_handle));
|
||||
}
|
||||
}
|
||||
|
||||
WinHttpClient::WinHttpClient() : session_(create_session()) {}
|
||||
|
||||
WinHttpClient::~WinHttpClient() {}
|
||||
|
||||
string WinHttpClient::get(const string &url, optional<long> timeoutMsec) {
|
||||
wstring wurl = wstring_convert<std::codecvt_utf8_utf16<wchar_t>>().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
|
@ -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<long> timeoutMsec = boost::none) override;
|
||||
|
||||
private:
|
||||
unique_ref<WinHttpSession> session_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(WinHttpClient);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
@ -1,13 +1,11 @@
|
||||
#include "Cli.h"
|
||||
#include <cpp-utils/random/Random.h>
|
||||
#include <cpp-utils/io/IOStreamConsole.h>
|
||||
#include <cpp-utils/network/CurlHttpClient.h>
|
||||
#include <cryfs/impl/CryfsException.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <cpp-utils/network/WinHttpClient.h>
|
||||
#include <VersionHelpers.h>
|
||||
#else
|
||||
#include <cpp-utils/network/CurlHttpClient.h>
|
||||
#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<cpputils::WinHttpClient>();
|
||||
#else
|
||||
auto httpClient = make_unique_ref<cpputils::CurlHttpClient>();
|
||||
#endif
|
||||
return Cli(keyGenerator, SCrypt::DefaultSettings, make_shared<IOStreamConsole>())
|
||||
.main(argc, argv, std::move(httpClient), []{});
|
||||
} catch (const cryfs::CryfsException &e) {
|
||||
|
Loading…
Reference in New Issue
Block a user