diff --git a/src/link.c b/src/link.c index 0119f7a..9b6d1b2 100644 --- a/src/link.c +++ b/src/link.c @@ -77,10 +77,15 @@ static CURL *Link_to_curl(Link *link) if (ret) { lprintf(error, "%s", curl_easy_strerror(ret)); } - ret = curl_easy_setopt(curl, CURLOPT_URL, link->f_url); + + char *escaped_spaces = escape_spaces(link->f_url); + ret = curl_easy_setopt(curl, CURLOPT_URL, + escaped_spaces ? escaped_spaces : link->f_url); if (ret) { lprintf(error, "%s", curl_easy_strerror(ret)); } + free(escaped_spaces); + ret = curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1); if (ret) { lprintf(error, "%s", curl_easy_strerror(ret)); diff --git a/src/util.c b/src/util.c index 1e868f6..800c9c2 100644 --- a/src/util.c +++ b/src/util.c @@ -49,6 +49,47 @@ char *path_append(const char *path, const char *filename) return str; } +char *escape_spaces(const char *path) +{ + char space = ' '; + + if (!strchr(path, space)) { + return NULL; + } + + int len = strnlen(path, MAX_PATH_LEN); + /* Best case scenario of only one character to escape and + * [MAX_PATH_LEN - 1] is '\0' + */ + if (len + 3 >= MAX_PATH_LEN - 1) { + lprintf(fatal, "path too long: %s\n", path); + } + + int replacement_len = 3; + const char* replacement = "%20"; + + char *escaped = CALLOC(MAX_PATH_LEN, sizeof(char)); + + int j = 0; + for (int i = 0; i < len; i++) { + /* Precaution against writing beyond the buffer, since we do not count + * all spaces beforehand to know the exact amount of memory to calloc + * for the escaped path. + */ + if (j >= MAX_PATH_LEN - 1) { + lprintf(fatal, "path too long: %s\n", path); + } + if (path[i] == space) { + mempcpy(escaped + j, replacement, replacement_len); + j += replacement_len; + } else { + escaped[j++] = path[i]; + } + } + return escaped; +} + + int64_t round_div(int64_t a, int64_t b) { return (a + (b / 2)) / b; diff --git a/src/util.h b/src/util.h index 5010de4..892f9aa 100644 --- a/src/util.h +++ b/src/util.h @@ -17,6 +17,14 @@ */ char *path_append(const char *path, const char *filename); +/** + * \brief escapes the space character in a path/URL + * \details This function escapes the space character in a path, and + * returns a pointer to the escaped path. + * \note You need to free the char * after use. + */ +char *escape_spaces(const char *path); + /** * \brief division, but rounded to the nearest integer rather than truncating */