diff --git a/Makefile.am b/Makefile.am index 9b2f75c6..c554f11c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -93,8 +93,6 @@ unittest_sources = \ src/tools/clipboard.c src/tools/clipboard.h \ src/tools/bookmark_ignore.c \ src/tools/bookmark_ignore.h \ - src/tools/http_download.c \ - src/tools/http_download.h \ src/config/accounts.h \ src/config/account.c src/config/account.h \ src/config/files.c src/config/files.h \ @@ -153,7 +151,6 @@ unittest_sources = \ tests/unittests/test_cmd_disconnect.c tests/unittests/test_cmd_disconnect.h \ tests/unittests/test_callbacks.c tests/unittests/test_callbacks.h \ tests/unittests/test_plugins_disco.c tests/unittests/test_plugins_disco.h \ - tests/unittests/test_http_common.c tests/unittests/test_http_common.h \ tests/unittests/unittests.c functionaltest_sources = \ diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index 88461f1d..147eca4d 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -9110,67 +9110,6 @@ _url_external_method(const char* cmd_template, const char* url, const char* file g_strfreev(argv); } -char* -_unique_filename(const char* filename) -{ - char* unique = strdup(filename); - - unsigned int i = 0; - while (g_file_test(unique, G_FILE_TEST_EXISTS)) { - free(unique); - - if (i > 1000) { // Give up after 1000 attempts. - return NULL; - } - - if (asprintf(&unique, "%s.%u", filename, i) < 0) { - return NULL; - } - - i++; - } - - return unique; -} - -char* -_unique_filename_from_url(char* url, char* path) -{ - gchar* directory = NULL; - gchar* basename = NULL; - if (path != NULL) { - directory = g_path_get_dirname(path); - basename = g_path_get_basename(path); - } - - if (directory == NULL) { - // Explicitly use "./" as directory if no directory has been passed. - directory = "./"; - } - - if (!g_file_test(directory, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) { - cons_show_error("Directory '%s' does not exist or is not a directory.", directory); - return NULL; - } - - if (!basename) { - basename = http_basename_from_url(url); - } - - char* filename = NULL; - filename = g_build_filename(directory, basename, NULL); - - char* unique_filename = _unique_filename(filename); - if (!unique_filename) { - cons_show_error("Failed to generate an unique filename from '%s'.", filename); - free(filename); - return NULL; - } - - free(filename); - return unique_filename; -} - gboolean cmd_url_open(ProfWin* window, const char* const command, gchar** args) { @@ -9200,7 +9139,7 @@ cmd_url_open(ProfWin* window, const char* const command, gchar** args) #ifdef HAVE_OMEMO // OMEMO URLs (aesgcm://) must be saved and decrypted before being opened. if (0 == g_strcmp0(scheme, "aesgcm")) { - char* filename = _unique_filename_from_url(url, files_get_data_path(DIR_DOWNLOADS)); + char* filename = unique_filename_from_url(url, files_get_data_path(DIR_DOWNLOADS)); _url_aesgcm_method(window, cmd_template, url, filename); free(filename); @@ -9241,7 +9180,7 @@ cmd_url_save(ProfWin* window, const char* const command, gchar** args) return TRUE; } - char* filename = _unique_filename_from_url(url, path); + char* filename = unique_filename_from_url(url, path); char* cmd_template = prefs_get_string_with_option(PREF_URL_SAVE_CMD, scheme); if (cmd_template == NULL) { diff --git a/src/common.c b/src/common.c index 079c3af5..66e344c5 100644 --- a/src/common.c +++ b/src/common.c @@ -33,6 +33,9 @@ * source files in the program, then also delete it here. * */ + +#define _GNU_SOURCE 1 + #include "config.h" #include @@ -575,3 +578,80 @@ format_call_external_argv(const char* template, const char* url, const char* fil return argv; } + +gchar* +_unique_filename(const char* filename) +{ + gchar* unique = g_strdup(filename); + + unsigned int i = 0; + while (g_file_test(unique, G_FILE_TEST_EXISTS)) { + free(unique); + + if (i > 1000) { // Give up after 1000 attempts. + return NULL; + } + + if (asprintf(&unique, "%s.%u", filename, i) < 0) { + return NULL; + } + + i++; + } + + return unique; +} + +gchar* +_basename_from_url(const char* url) +{ + const char* default_name = "index.html"; + + GFile* file = g_file_new_for_uri(url); + gchar* filename = g_file_get_basename(file); + g_object_unref(file); + + if (g_strcmp0(filename, ".") == 0 + || g_strcmp0(filename, "..") == 0 + || g_strcmp0(filename, G_DIR_SEPARATOR_S) == 0) { + g_free(filename); + return strdup(default_name); + } + + return filename; +} + +gchar* +unique_filename_from_url(const char* url, const char* path) +{ + gchar* directory = NULL; + gchar* basename = NULL; + if (path != NULL) { + directory = g_path_get_dirname(path); + basename = g_path_get_basename(path); + } + + if (!directory) { + // Explicitly use "./" as directory if no directory has been passed. + directory = "./"; + } + + if (!g_file_test(directory, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) { + return NULL; + } + + if (g_file_test(path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) { + basename = _basename_from_url(url); + } + + gchar* filename = g_build_filename(directory, basename, NULL); + + gchar* unique_filename = _unique_filename(filename); + if (!unique_filename) { + g_free(filename); + return NULL; + } + + g_free(filename); + return unique_filename; +} diff --git a/src/common.h b/src/common.h index b56d31d4..088ba953 100644 --- a/src/common.h +++ b/src/common.h @@ -107,4 +107,6 @@ char* get_random_string(int length); gboolean call_external(gchar** argv, gchar*** const output_ptr, gchar*** const error_ptr); gchar** format_call_external_argv(const char* template, const char* url, const char* filename); +gchar* unique_filename_from_url(const char* url, const char* path); + #endif diff --git a/src/config/preferences.c b/src/config/preferences.c index 4b524fcf..7a9b842b 100644 --- a/src/config/preferences.c +++ b/src/config/preferences.c @@ -1865,7 +1865,6 @@ _get_group(preference_t pref) return PREF_GROUP_LOGGING; case PREF_AVATAR_CMD: case PREF_URL_OPEN_CMD: - return PREF_GROUP_EXECUTABLES; case PREF_URL_SAVE_CMD: return PREF_GROUP_EXECUTABLES; case PREF_AUTOAWAY_CHECK: diff --git a/src/tools/http_common.c b/src/tools/http_common.c index dfd0aa87..e066a6f6 100644 --- a/src/tools/http_common.c +++ b/src/tools/http_common.c @@ -44,25 +44,6 @@ #define FALLBACK_MSG "" -char* -http_basename_from_url(const char* url) -{ - const char* default_name = "index.html"; - - GFile* file = g_file_new_for_uri(url); - char* filename = g_file_get_basename(file); - g_object_unref(file); - - if (g_strcmp0(filename, ".") == 0 - || g_strcmp0(filename, "..") == 0 - || g_strcmp0(filename, G_DIR_SEPARATOR_S) == 0) { - g_free(filename); - return strdup(default_name); - } - - return filename; -} - void http_print_transfer_update(ProfWin* window, char* url, const char* fmt, ...) { diff --git a/src/tools/http_common.h b/src/tools/http_common.h index c0a553de..ac51b5a8 100644 --- a/src/tools/http_common.h +++ b/src/tools/http_common.h @@ -38,9 +38,7 @@ #include "ui/window.h" -char* http_basename_from_url(const char* url); void http_print_transfer(ProfWin* window, char* url, const char* fmt, ...); void http_print_transfer_update(ProfWin* window, char* url, const char* fmt, ...); -gchar** http_format_external_argv(const char* cmd, const char* url, const char* filename); #endif diff --git a/tests/unittests/test_common.c b/tests/unittests/test_common.c index b8958dda..462676cc 100644 --- a/tests/unittests/test_common.c +++ b/tests/unittests/test_common.c @@ -330,6 +330,83 @@ strip_quotes_strips_both(void** state) free(result); } +typedef struct +{ + char* url; + char* path; + char* filename; +} unique_filename_from_url_t; + +void +unique_filename_from_url_td(void** state) +{ + enum table { num_tests = 11 }; + + unique_filename_from_url_t tests[num_tests] = { + (unique_filename_from_url_t){ + .url = "https://host.test/image.jpeg", + .path = "./", + .filename = "./image.jpeg", + }, + (unique_filename_from_url_t){ + .url = "https://host.test/image.jpeg#somefragment", + .path = "./", + .filename = "./image.jpeg", + }, + (unique_filename_from_url_t){ + .url = "https://host.test/image.jpeg?query=param", + .path = "./", + .filename = "./image.jpeg", + }, + (unique_filename_from_url_t){ + .url = "https://host.test/image.jpeg?query=param&another=one", + .path = "./", + .filename = "./image.jpeg", + }, + (unique_filename_from_url_t){ + .url = "https://host.test/images/", + .path = "./", + .filename = "./images", + }, + (unique_filename_from_url_t){ + .url = "https://host.test/images/../../file", + .path = "./", + .filename = "./file", + }, + (unique_filename_from_url_t){ + .url = "https://host.test/images/../../file/..", + .path = "./", + .filename = "./index.html", + }, + (unique_filename_from_url_t){ + .url = "https://host.test/images/..//", + .path = "./", + .filename = "./index.html", + }, + (unique_filename_from_url_t){ + .url = "https://host.test/", + .path = "./", + .filename = "./index.html", + }, + (unique_filename_from_url_t){ + .url = "https://host.test", + .path = "./", + .filename = "./index.html", + }, + (unique_filename_from_url_t){ + .url = "aesgcm://host.test", + .path = "./", + .filename = "./index.html", + }, + }; + + char* filename; + for (int i = 0; i < num_tests; i++) { + filename = unique_filename_from_url(tests[i].url, tests[i].path); + assert_string_equal(filename, tests[i].filename); + } +} + gboolean _lists_equal(GSList* a, GSList* b) { diff --git a/tests/unittests/test_common.h b/tests/unittests/test_common.h index b9e7291e..a1ef7c6e 100644 --- a/tests/unittests/test_common.h +++ b/tests/unittests/test_common.h @@ -31,3 +31,4 @@ void strip_quotes_strips_last(void** state); void strip_quotes_strips_both(void** state); void prof_partial_occurrences_tests(void** state); void prof_whole_occurrences_tests(void** state); +void unique_filename_from_url_td(void** state); diff --git a/tests/unittests/test_http_common.c b/tests/unittests/test_http_common.c deleted file mode 100644 index 195f370b..00000000 --- a/tests/unittests/test_http_common.c +++ /dev/null @@ -1,75 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" - -#include "tools/http_common.c" - -typedef struct -{ - char* url; - char* basename; -} url_test_t; - -void -http_basename_from_url_td(void** state) -{ - int num_tests = 11; - url_test_t tests[] = { - (url_test_t){ - .url = "https://host.test/image.jpeg", - .basename = "image.jpeg", - }, - (url_test_t){ - .url = "https://host.test/image.jpeg#somefragment", - .basename = "image.jpeg", - }, - (url_test_t){ - .url = "https://host.test/image.jpeg?query=param", - .basename = "image.jpeg", - }, - (url_test_t){ - .url = "https://host.test/image.jpeg?query=param&another=one", - .basename = "image.jpeg", - }, - (url_test_t){ - .url = "https://host.test/images/", - .basename = "images", - }, - (url_test_t){ - .url = "https://host.test/images/../../file", - .basename = "file", - }, - (url_test_t){ - .url = "https://host.test/images/../../file/..", - .basename = "index.html", - }, - (url_test_t){ - .url = "https://host.test/images/..//", - .basename = "index.html", - }, - (url_test_t){ - .url = "https://host.test/", - .basename = "index.html", - }, - (url_test_t){ - .url = "https://host.test", - .basename = "index.html", - }, - (url_test_t){ - .url = "aesgcm://host.test", - .basename = "index.html", - }, - }; - - char* basename; - for (int i = 0; i < num_tests; i++) { - basename = http_basename_from_url(tests[i].url); - assert_string_equal(basename, tests[i].basename); - } -} diff --git a/tests/unittests/test_http_common.h b/tests/unittests/test_http_common.h deleted file mode 100644 index a1c62a7f..00000000 --- a/tests/unittests/test_http_common.h +++ /dev/null @@ -1 +0,0 @@ -void http_basename_from_url_td(void** state); diff --git a/tests/unittests/tools/stub_http_download.c b/tests/unittests/tools/stub_http_download.c index 5fa1c46e..cc7bddc5 100644 --- a/tests/unittests/tools/stub_http_download.c +++ b/tests/unittests/tools/stub_http_download.c @@ -18,4 +18,13 @@ typedef struct http_download_t int cancel; } HTTPDownload; +void* +http_file_get(void* userdata) +{ + return NULL; +} + +void http_download_cancel_processes(){}; +void http_download_add_download(){}; + #endif diff --git a/tests/unittests/unittests.c b/tests/unittests/unittests.c index cab99bf5..c63a3783 100644 --- a/tests/unittests/unittests.c +++ b/tests/unittests/unittests.c @@ -38,7 +38,6 @@ #include "test_form.h" #include "test_callbacks.h" #include "test_plugins_disco.h" -#include "test_http_common.h" int main(int argc, char* argv[]) @@ -91,6 +90,7 @@ main(int argc, char* argv[]) unit_test(strip_quotes_strips_first), unit_test(strip_quotes_strips_last), unit_test(strip_quotes_strips_both), + unit_test(unique_filename_from_url_td), unit_test(clear_empty), unit_test(reset_after_create), @@ -627,8 +627,6 @@ main(int argc, char* argv[]) unit_test(does_not_add_duplicate_feature), unit_test(removes_plugin_features), unit_test(does_not_remove_feature_when_more_than_one_reference), - - unit_test(http_basename_from_url_td), }; return run_tests(all_tests);