Skip to content

Commit

Permalink
Make update checker use libcurl and https
Browse files Browse the repository at this point in the history
The 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 <[email protected]>
  • Loading branch information
2 people authored and CoffeeFlux committed Dec 3, 2023
1 parent 0e2a14c commit c88f918
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 42 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ tools/repack-thes-dict.dSYM
build*/
subprojects/boost*/
subprojects/cairo*
subprojects/curl-*
subprojects/ffmpeg
subprojects/ffms2*
subprojects/fontconfig*
Expand Down
39 changes: 39 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ if get_option('official_release')
conf.set('AEGI_OFFICIAL_RELEASE', 1)
endif
conf.set('WITH_UPDATE_CHECKER', get_option('enable_update_checker'))
if 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'))
endif

deps = []
deps_inc = []
Expand Down Expand Up @@ -277,6 +281,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')

# Horrible meson hack to work around the cmake subproject creating broken include directories
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 <lauxlib.h>
Expand Down
4 changes: 2 additions & 2 deletions meson_options.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,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('official_release', type: 'boolean', value: false, description: 'Set on official builds')

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')
79 changes: 39 additions & 40 deletions src/dialog_version_check.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,6 @@

#ifdef WITH_UPDATE_CHECKER

#ifdef _MSC_VER
#pragma warning(disable : 4250) // 'boost::asio::basic_socket_iostream<Protocol>' : 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"
Expand All @@ -46,9 +42,10 @@
#include <libaegisub/split.h>

#include <ctime>
#include <boost/asio/ip/tcp.hpp>
#include <curl/curl.h>
#include <functional>
#include <mutex>
#include <sstream>
#include <vector>
#include <wx/button.h>
#include <wx/checkbox.h>
Expand Down Expand Up @@ -280,44 +277,46 @@ 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<std::streamsize>::max(), '\n');

// Skip the headers since we don't care about them
for (auto const& header : agi::line_iterator<std::string>(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);
curl_easy_cleanup(curl);
if (res_code != CURLE_OK) {
std::string err_msg = agi::format(_("Checking for updates failed: %s."), curl_easy_strerror(res_code));
throw VersionCheckError(err_msg);
}

std::stringstream ss(result);
std::vector<AegisubUpdateDescription> results;
for (auto const& line : agi::line_iterator<std::string>(stream)) {
for (auto const& line : agi::line_iterator<std::string>(ss)) {
if (line.empty()) continue;

std::vector<std::string> parsed;
Expand Down
9 changes: 9 additions & 0 deletions subprojects/curl.wrap
Original file line number Diff line number Diff line change
@@ -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
6 changes: 6 additions & 0 deletions subprojects/curl_meson.wrap
Original file line number Diff line number Diff line change
@@ -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
3 changes: 3 additions & 0 deletions subprojects/packagefiles/curl/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
project('curl_meson', 'cpp')

libcurl_fixed_inc = include_directories('include/')

0 comments on commit c88f918

Please sign in to comment.