From c456862f87237831ce2bbaeb53a37d1b3d669285 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 19 Aug 2021 18:15:37 +0200 Subject: [PATCH] import: allow file:// in addition to HTTP(S) Previously we only allows http/https urls, let's open this up a bit. Why? Because it makes testing *so* *much* *easier* as we don't need to run a HTTP server all the time. CURL mostly abstracts the differences of http/https away from us, hence we can get away with very little extra work. --- src/import/importd.c | 2 +- src/import/pull-job.c | 76 +++++++++++++++++++++++----------------- src/import/pull-raw.c | 2 +- src/import/pull-tar.c | 2 +- src/import/pull.c | 4 +-- src/machine/machinectl.c | 4 +-- src/shared/web-util.c | 17 +++++++-- src/shared/web-util.h | 1 + 8 files changed, 67 insertions(+), 41 deletions(-) diff --git a/src/import/importd.c b/src/import/importd.c index 0a870568194..86181628d9d 100644 --- a/src/import/importd.c +++ b/src/import/importd.c @@ -928,7 +928,7 @@ static int method_pull_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_er if (r < 0) return r; - if (!http_url_is_valid(remote)) + if (!http_url_is_valid(remote) && !file_url_is_valid(remote)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "URL %s is invalid", remote); diff --git a/src/import/pull-job.c b/src/import/pull-job.c index 8764207960b..826da953785 100644 --- a/src/import/pull-job.c +++ b/src/import/pull-job.c @@ -117,7 +117,7 @@ static int pull_job_restart(PullJob *j, const char *new_url) { void pull_job_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result) { PullJob *j = NULL; CURLcode code; - long status; + long protocol; int r; if (curl_easy_getinfo(curl, CURLINFO_PRIVATE, (char **)&j) != CURLE_OK) @@ -131,50 +131,62 @@ void pull_job_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result) { goto finish; } - code = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status); + code = curl_easy_getinfo(curl, CURLINFO_PROTOCOL, &protocol); if (code != CURLE_OK) { r = log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to retrieve response code: %s", curl_easy_strerror(code)); goto finish; - } else if (status == 304) { - log_info("Image already downloaded. Skipping download."); - j->etag_exists = true; - r = 0; - goto finish; - } else if (status >= 300) { + } - if (status == 404 && j->on_not_found) { - _cleanup_free_ char *new_url = NULL; + if (IN_SET(protocol, CURLPROTO_HTTP, CURLPROTO_HTTPS)) { + long status; - /* This resource wasn't found, but the implementor wants to maybe let us know a new URL, query for it. */ - r = j->on_not_found(j, &new_url); - if (r < 0) - goto finish; + code = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status); + if (code != CURLE_OK) { + r = log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to retrieve response code: %s", curl_easy_strerror(code)); + goto finish; + } - if (r > 0) { /* A new url to use */ - assert(new_url); + if (status == 304) { + log_info("Image already downloaded. Skipping download."); + j->etag_exists = true; + r = 0; + goto finish; + } else if (status >= 300) { - r = pull_job_restart(j, new_url); + if (status == 404 && j->on_not_found) { + _cleanup_free_ char *new_url = NULL; + + /* This resource wasn't found, but the implementor wants to maybe let us know a new URL, query for it. */ + r = j->on_not_found(j, &new_url); if (r < 0) goto finish; - code = curl_easy_getinfo(j->curl, CURLINFO_RESPONSE_CODE, &status); - if (code != CURLE_OK) { - r = log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to retrieve response code: %s", curl_easy_strerror(code)); - goto finish; + if (r > 0) { /* A new url to use */ + assert(new_url); + + r = pull_job_restart(j, new_url); + if (r < 0) + goto finish; + + code = curl_easy_getinfo(j->curl, CURLINFO_RESPONSE_CODE, &status); + if (code != CURLE_OK) { + r = log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to retrieve response code: %s", curl_easy_strerror(code)); + goto finish; + } + + if (status == 0) + return; } - - if (status == 0) - return; } - } - r = log_error_errno( - status == 404 ? SYNTHETIC_ERRNO(ENOMEDIUM) : SYNTHETIC_ERRNO(EIO), /* Make the most common error recognizable */ - "HTTP request to %s failed with code %li.", j->url, status); - goto finish; - } else if (status < 200) { - r = log_error_errno(SYNTHETIC_ERRNO(EIO), "HTTP request to %s finished with unexpected code %li.", j->url, status); - goto finish; + r = log_error_errno( + status == 404 ? SYNTHETIC_ERRNO(ENOMEDIUM) : SYNTHETIC_ERRNO(EIO), /* Make the most common error recognizable */ + "HTTP request to %s failed with code %li.", j->url, status); + goto finish; + } else if (status < 200) { + r = log_error_errno(SYNTHETIC_ERRNO(EIO), "HTTP request to %s finished with unexpected code %li.", j->url, status); + goto finish; + } } if (j->state != PULL_JOB_RUNNING) { diff --git a/src/import/pull-raw.c b/src/import/pull-raw.c index c071e134f29..6a0c2c8b177 100644 --- a/src/import/pull-raw.c +++ b/src/import/pull-raw.c @@ -835,7 +835,7 @@ int raw_pull_start( assert(!(flags & (PULL_SETTINGS|PULL_ROOTHASH|PULL_ROOTHASH_SIGNATURE|PULL_VERITY)) || !(flags & PULL_DIRECT)); assert(!(flags & (PULL_SETTINGS|PULL_ROOTHASH|PULL_ROOTHASH_SIGNATURE|PULL_VERITY)) || !checksum); - if (!http_url_is_valid(url)) + if (!http_url_is_valid(url) && !file_url_is_valid(url)) return -EINVAL; if (local && !pull_validate_local(local, flags)) diff --git a/src/import/pull-tar.c b/src/import/pull-tar.c index 6aca3c9979b..06d336bca91 100644 --- a/src/import/pull-tar.c +++ b/src/import/pull-tar.c @@ -597,7 +597,7 @@ int tar_pull_start( assert(!(flags & PULL_SETTINGS) || !(flags & PULL_DIRECT)); assert(!(flags & PULL_SETTINGS) || !checksum); - if (!http_url_is_valid(url)) + if (!http_url_is_valid(url) && !file_url_is_valid(url)) return -EINVAL; if (local && !pull_validate_local(local, flags)) diff --git a/src/import/pull.c b/src/import/pull.c index a903c35aa77..2cf0cca14ff 100644 --- a/src/import/pull.c +++ b/src/import/pull.c @@ -110,7 +110,7 @@ static int pull_tar(int argc, char *argv[], void *userdata) { int r; url = argv[1]; - if (!http_url_is_valid(url)) + if (!http_url_is_valid(url) && !file_url_is_valid(url)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "URL '%s' is not valid.", url); if (argc >= 3) @@ -183,7 +183,7 @@ static int pull_raw(int argc, char *argv[], void *userdata) { int r; url = argv[1]; - if (!http_url_is_valid(url)) + if (!http_url_is_valid(url) && !file_url_is_valid(url)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "URL '%s' is not valid.", url); if (argc >= 3) diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 3f4ad878972..c3a2384f150 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -2125,7 +2125,7 @@ static int pull_tar(int argc, char *argv[], void *userdata) { assert(bus); remote = argv[1]; - if (!http_url_is_valid(remote)) + if (!http_url_is_valid(remote) && !file_url_is_valid(remote)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "URL '%s' is not valid.", remote); @@ -2181,7 +2181,7 @@ static int pull_raw(int argc, char *argv[], void *userdata) { assert(bus); remote = argv[1]; - if (!http_url_is_valid(remote)) + if (!http_url_is_valid(remote) && !file_url_is_valid(remote)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "URL '%s' is not valid.", remote); diff --git a/src/shared/web-util.c b/src/shared/web-util.c index 82cd5fbd6bb..39a300f5c96 100644 --- a/src/shared/web-util.c +++ b/src/shared/web-util.c @@ -36,16 +36,29 @@ bool http_url_is_valid(const char *url) { return ascii_is_valid(p); } +bool file_url_is_valid(const char *url) { + const char *p; + + if (isempty(url)) + return false; + + p = startswith(url, "file:/"); + if (isempty(p)) + return false; + + return ascii_is_valid(p); +} + bool documentation_url_is_valid(const char *url) { const char *p; if (isempty(url)) return false; - if (http_url_is_valid(url)) + if (http_url_is_valid(url) || file_url_is_valid(url)) return true; - p = STARTSWITH_SET(url, "file:/", "info:", "man:"); + p = STARTSWITH_SET(url, "info:", "man:"); if (isempty(p)) return false; diff --git a/src/shared/web-util.h b/src/shared/web-util.h index ec54669f501..88b4897be05 100644 --- a/src/shared/web-util.h +++ b/src/shared/web-util.h @@ -6,6 +6,7 @@ #include "macro.h" bool http_url_is_valid(const char *url) _pure_; +bool file_url_is_valid(const char *url) _pure_; bool documentation_url_is_valid(const char *url) _pure_;