From 2f56d112767d738bf8540cc25d471a9cfd738cb7 Mon Sep 17 00:00:00 2001 From: arch1t3cht Date: Tue, 27 Jun 2023 04:04:50 +0200 Subject: [PATCH] [TEST] Make update checker use libcurl and https That horrible hack with the curl_meson subproject is needed since the libcurl dependency generated by libcurl's cmake build system (via meson's cmake module) includes its internal files its include_directories, which shadows certain other includes. So instead we manually replace the include_directories with the correct ones, taken from a separate meson subproject. This needs an additional wrap file, but it points to the same subproject directory in order to prevent there being multiple downloads of the same libcurl source that could go out of sync at some point. Co-authored-by: sepro <4618135+seproDev@users.noreply.github.com> --- .gitignore | 1 + meson.build | 37 +++++++++++ meson_options.txt | 4 +- src/dialog_version_check.cpp | 81 ++++++++++++----------- subprojects/curl.wrap | 9 +++ subprojects/curl_meson.wrap | 6 ++ subprojects/packagefiles/curl/meson.build | 3 + 7 files changed, 99 insertions(+), 42 deletions(-) create mode 100644 subprojects/curl.wrap create mode 100644 subprojects/curl_meson.wrap create mode 100644 subprojects/packagefiles/curl/meson.build diff --git a/.gitignore b/.gitignore index c9cdd97cbd..b049c5bbe6 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,7 @@ subprojects/avisynth subprojects/bestsource/ subprojects/boost*/ subprojects/cairo* +subprojects/curl-* subprojects/dav1d subprojects/ffmpeg subprojects/ffms2 diff --git a/meson.build b/meson.build index f8a0e877f8..e751cdddee 100644 --- a/meson.build +++ b/meson.build @@ -68,6 +68,8 @@ if get_option('build_appimage') conf.set('APPIMAGE_BUILD', 1) endif conf.set('WITH_UPDATE_CHECKER', get_option('enable_update_checker')) +conf.set_quoted('UPDATE_CHECKER_SERVER', get_option('update_server')) +conf.set_quoted('UPDATE_CHECKER_BASE_URL', get_option('update_url')) deps = [] deps_inc = [] @@ -348,6 +350,41 @@ endif conf_platform = configuration_data() conf_platform.set('DEFAULT_PLAYER_AUDIO', def_audio) +if get_option('enable_update_checker') + libcurl_dep = dependency('libcurl', required: false) + + if (not libcurl_dep.found()) + libcurl_opt = cmake.subproject_options() + options_dict = { + 'HTTP_ONLY': true, + 'BUILD_CURL_EXE': false, + 'CMAKE_BUILD_TYPE': get_option('buildtype') == 'release' ? 'Release' : 'Debug', + } + if host_machine.system() == 'windows' + options_dict += {'CURL_USE_SCHANNEL': true} + deps += cc.find_library('crypt32') + elif host_machine.system() == 'darwin' + options_dict += {'CURL_USE_SECTRANSP': true} + else + options_dict += {'CURL_USE_OPENSSL': true} + endif + if get_option('default_library') == 'static' and (host_machine.system() == 'windows' or host_machine.system() == 'darwin') + options_dict += {'BUILD_SHARED_LIBS': false} + add_project_arguments('-DCURL_STATICLIB', language: ['cpp']) + endif + libcurl_opt.add_cmake_defines(options_dict) + libcurl = cmake.subproject('curl', options: libcurl_opt) + + libcurl_dep = libcurl.dependency('libcurl') + + # I hate this I hate this I hate this I hate this I hate this I hate this I hate this I hate this I hate this I hate this + libcurl_dep = libcurl_dep.partial_dependency(compile_args: true, link_args: true, links: true, sources: true) + libcurl_fixed_inc = declare_dependency(include_directories: subproject('curl_meson').get_variable('libcurl_fixed_inc')) + deps += [libcurl_fixed_inc] + endif + deps += [libcurl_dep] +endif + luajit = dependency('luajit', version: '>=2.0.0', required: get_option('system_luajit')) if luajit.found() and luajit.type_name() != 'internal' luajit_test = cc.run('''#include diff --git a/meson_options.txt b/meson_options.txt index ec182fe08f..f76db02501 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -23,8 +23,8 @@ option('wx_version', type: 'string', value: '3.0.0', description: 'The minimum w option('credit', type: 'string', value: '', description: 'Build credit shown in program title') -option('enable_update_checker', type: 'boolean', value: false, description: 'Enable the update checker') -option('update_server', type: 'string', value: 'updates.aegisub.org', description: 'Server to use for the update checker') +option('enable_update_checker', type: 'boolean', value: true, description: 'Enable the update checker') +option('update_server', type: 'string', value: 'https://updates.aegisub.org', description: 'Server to use for the update checker') option('update_url', type: 'string', value: '/trunk', description: 'Base path to use for the update checker') option('build_osx_bundle', type: 'boolean', value: 'false', description: 'Package Aegisub.app on OSX') diff --git a/src/dialog_version_check.cpp b/src/dialog_version_check.cpp index 6dea7e3b6a..31becd020c 100644 --- a/src/dialog_version_check.cpp +++ b/src/dialog_version_check.cpp @@ -29,10 +29,6 @@ #ifdef WITH_UPDATE_CHECKER -#ifdef _MSC_VER -#pragma warning(disable : 4250) // 'boost::asio::basic_socket_iostream' : inherits 'std::basic_ostream<_Elem,_Traits>::std::basic_ostream<_Elem,_Traits>::_Add_vtordisp2' via dominance -#endif - #include "compat.h" #include "format.h" #include "options.h" @@ -46,9 +42,10 @@ #include #include -#include +#include #include #include +#include #include #include #include @@ -280,44 +277,48 @@ static wxString GetAegisubLanguage() { return to_wx(OPT_GET("App/Language")->GetString()); } +size_t writeToStringCb(char *contents, size_t size, size_t nmemb, std::string *s) { + s->append(contents, size * nmemb); + return size * nmemb; +} + void DoCheck(bool interactive) { - boost::asio::ip::tcp::iostream stream; - stream.connect(UPDATE_CHECKER_SERVER, "http"); - if (!stream) - throw VersionCheckError(from_wx(_("Could not connect to updates server."))); - - agi::format(stream, - "GET %s?rev=%d&rel=%d&os=%s&lang=%s&aegilang=%s HTTP/1.0\r\n" - "User-Agent: Aegisub %s\r\n" - "Host: %s\r\n" - "Accept: */*\r\n" - "Connection: close\r\n\r\n" - , UPDATE_CHECKER_BASE_URL - , GetSVNRevision() - , (GetIsOfficialRelease() ? 1 : 0) - , GetOSShortName() - , GetSystemLanguage() - , GetAegisubLanguage() - , GetAegisubLongVersionString() - , UPDATE_CHECKER_SERVER); - - std::string http_version; - stream >> http_version; - int status_code; - stream >> status_code; - if (!stream || http_version.substr(0, 5) != "HTTP/") - throw VersionCheckError(from_wx(_("Could not download from updates server."))); - if (status_code != 200) - throw VersionCheckError(agi::format(_("HTTP request failed, got HTTP response %d."), status_code)); - - stream.ignore(std::numeric_limits::max(), '\n'); - - // Skip the headers since we don't care about them - for (auto const& header : agi::line_iterator(stream)) - if (header.empty()) break; + CURL *curl; + CURLcode res_code; + + curl = curl_easy_init(); + if(!curl) + throw VersionCheckError(from_wx(_("Curl could not be initialized."))); + + curl_easy_setopt(curl, CURLOPT_URL, + agi::format("%s%s?rev=%d&rel=%d&os=%s&lang=%s&aegilang=%s" + , UPDATE_CHECKER_SERVER + , UPDATE_CHECKER_BASE_URL + , GetSVNRevision() + , (GetIsOfficialRelease() ? 1 : 0) + , GetOSShortName() + , GetSystemLanguage() + , GetAegisubLanguage() + ).c_str()); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(curl, CURLOPT_USERAGENT, agi::format("Aegisub %s", GetAegisubLongVersionString()).c_str()); + + std::string result; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeToStringCb); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &result); + + res_code = curl_easy_perform(curl); + if(res_code != CURLE_OK) { + std::string err_msg = agi::format(_("Checking for updates failed: %s."), curl_easy_strerror(res_code)); + curl_easy_cleanup(curl); + throw VersionCheckError(err_msg); + } + + curl_easy_cleanup(curl); + std::stringstream ss(result); std::vector results; - for (auto const& line : agi::line_iterator(stream)) { + for (auto const& line : agi::line_iterator(ss)) { if (line.empty()) continue; std::vector parsed; diff --git a/subprojects/curl.wrap b/subprojects/curl.wrap new file mode 100644 index 0000000000..e79b6bd03d --- /dev/null +++ b/subprojects/curl.wrap @@ -0,0 +1,9 @@ +[wrap-file] +directory = curl-7.82.0 +source_url = https://github.com/curl/curl/releases/download/curl-7_82_0/curl-7.82.0.tar.gz +source_filename = curl-7.82.0.tar.xz +source_hash = 910cc5fe279dc36e2cca534172c94364cf3fcf7d6494ba56e6c61a390881ddce +patch_directory = curl + +[provide] +dependency_names = libcurl \ No newline at end of file diff --git a/subprojects/curl_meson.wrap b/subprojects/curl_meson.wrap new file mode 100644 index 0000000000..067cf2d6f2 --- /dev/null +++ b/subprojects/curl_meson.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = curl-7.82.0 +source_url = https://github.com/curl/curl/releases/download/curl-7_82_0/curl-7.82.0.tar.gz +source_filename = curl-7.82.0.tar.xz +source_hash = 910cc5fe279dc36e2cca534172c94364cf3fcf7d6494ba56e6c61a390881ddce +patch_directory = curl \ No newline at end of file diff --git a/subprojects/packagefiles/curl/meson.build b/subprojects/packagefiles/curl/meson.build new file mode 100644 index 0000000000..612c78ec3b --- /dev/null +++ b/subprojects/packagefiles/curl/meson.build @@ -0,0 +1,3 @@ +project('curl_meson', 'cpp') + +libcurl_fixed_inc = include_directories('include/') \ No newline at end of file