]> git.ipfire.org Git - thirdparty/FORT-validator.git/commitdiff
Implement HTTP redirects
authorAlberto Leiva Popper <ydahhrk@gmail.com>
Fri, 17 Nov 2023 19:14:46 +0000 (13:14 -0600)
committerAlberto Leiva Popper <ydahhrk@gmail.com>
Fri, 17 Nov 2023 19:14:46 +0000 (13:14 -0600)
Fixes #71.

docs/usage.md
man/fort.8
src/config.c
src/config.h
src/http/http.c

index e4e3bdd0a1a979897faba437d6b2dfc670965def..00254e4e498652d7f47139ef002bf7741d2be991 100644 (file)
@@ -49,6 +49,7 @@ description: Guide to use arguments of FORT Validator.
        36. [`--http.retry.count`](#--httpretrycount)
        37. [`--http.retry.interval`](#--httpretryinterval)
        38. [`--http.user-agent`](#--httpuser-agent)
+       38. [`--http.max-redirs`](#--httpmax-redirs)
        39. [`--http.connect-timeout`](#--httpconnect-timeout)
        40. [`--http.transfer-timeout`](#--httptransfer-timeout)
        41. [`--http.low-speed-limit`](#--httplow-speed-limit)
@@ -673,6 +674,17 @@ User-Agent to use at HTTP requests.
 
 The value specified (either by the argument or the default value) is utilized in libcurl's option [CURLOPT_USERAGENT](https://curl.haxx.se/libcurl/c/CURLOPT_USERAGENT.html).
 
+### `--http.max-redirs`
+
+- **Type:** Integer
+- **Availability:** `argv` and JSON
+- **Default:** 10
+- **Range:** [0, [`UINT_MAX`](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html)]
+
+Maximum allowed number of redirections to follow per HTTP request. (The total number of requests is `--http.max-redirs + 1`.)
+
+Unlike [`curl`'s `--max-redirs`](https://curl.se/docs/manpage.html#--max-redirs), Fort does not provide a means to allow for infinite redirects.
+
 ### `--http.connect-timeout`
 
 - **Type:** Integer
index f9f161d5f8d6dd394ae305955517903e987f7a7e..0e6d24eba1084342e3ba9650c26f419e87086ec3 100644 (file)
@@ -758,6 +758,14 @@ By default, the value is \fIfort/<current-version>\fR.
 .RE
 .P
 
+.BR \-\-http.max\-redirs=\fIUNSIGNED_INTEGER\fR
+.RS 4
+Maximum number of redirections to follow, per HTTP request.
+.P
+Defaults to 10.
+.RE
+.P
+
 .B \-\-http.connect\-timeout=\fIUNSIGNED_INTEGER\fR
 .RS 4
 Timeout (in seconds) for the connect phase.
index 0ba56ff45534d72b399ab39e2eec8c10ab73cd30..0ce330ad01935f11c967c8a070a95fc3307c672b 100644 (file)
@@ -76,9 +76,9 @@ struct rpki_config {
        struct {
                /* Enables the protocol */
                bool enabled;
-               /* Deprecated; does nothing. */
+               /* Protocol preference; compared to http.priority */
                unsigned int priority;
-               /* Synchronization download strategy. */
+               /* Deprecated; does nothing. */
                char *strategy;
                /* Retry conf, utilized on errors */
                struct {
@@ -89,7 +89,7 @@ struct rpki_config {
                } retry;
                char *program;
                struct {
-                       struct string_array flat;
+                       struct string_array flat; /* Deprecated */
                        struct string_array recursive;
                } args;
        } rsync;
@@ -97,7 +97,7 @@ struct rpki_config {
        struct {
                /* Enables the protocol */
                bool enabled;
-               /* Deprecated; does nothing. */
+               /* Protocol preference; compared to rsync.priority */
                unsigned int priority;
                /* Retry conf, utilized on errors */
                struct {
@@ -106,8 +106,10 @@ struct rpki_config {
                        /* Interval (in seconds) between each retry */
                        unsigned int interval;
                } retry;
-               /* User-Agent header set at requests */
+               /* HTTP User-Agent request header */
                char *user_agent;
+               /* Allowed redirects per request */
+               unsigned int max_redirs;
                /* CURLOPT_CONNECTTIMEOUT for our HTTP transfers. */
                unsigned int connect_timeout;
                /* CURLOPT_TIMEOUT for our HTTP transfers. */
@@ -515,6 +517,14 @@ static const struct option_field options[] = {
                .type = &gt_string,
                .offset = offsetof(struct rpki_config, http.user_agent),
                .doc = "User-Agent to use at HTTP requests, eg. Fort Validator Local/1.0",
+       }, {
+               .id = 9012,
+               .name = "http.max-redirs",
+               .type = &gt_uint,
+               .offset = offsetof(struct rpki_config, http.max_redirs),
+               .doc = "Maximum number of redirections to follow, per request.",
+               .min = 0,
+               .max = UINT_MAX,
        }, {
                .id = 9005,
                .name = "http.connect-timeout",
@@ -920,6 +930,7 @@ set_default_values(void)
        rpki_config.http.retry.count = 1;
        rpki_config.http.retry.interval = 4;
        rpki_config.http.user_agent = pstrdup(PACKAGE_NAME "/" PACKAGE_VERSION);
+       rpki_config.http.max_redirs = 10;
        rpki_config.http.connect_timeout = 30;
        rpki_config.http.transfer_timeout = 0;
        rpki_config.http.low_speed_limit = 100000;
@@ -1358,6 +1369,12 @@ config_get_http_user_agent(void)
        return rpki_config.http.user_agent;
 }
 
+unsigned int
+config_get_max_redirs(void)
+{
+       return rpki_config.http.max_redirs;
+}
+
 long
 config_get_http_connect_timeout(void)
 {
index 0ef1c65d5bcee6ab2cd07e143c4c70a3a13d1619..8f9738145f6a99ecbfb3e0a763c27355b604bd43 100644 (file)
@@ -33,6 +33,7 @@ char const *config_get_local_repository(void);
 unsigned int config_get_max_cert_depth(void);
 enum mode config_get_mode(void);
 char const *config_get_http_user_agent(void);
+unsigned int config_get_max_redirs(void);
 long config_get_http_connect_timeout(void);
 long config_get_http_transfer_timeout(void);
 long config_get_http_low_speed_limit(void);
index 724185a4647bd324ccd06631d251c8c5ac9f9776..f7427b854d678e3addec81736ee980f8f05ce79a 100644 (file)
@@ -147,6 +147,9 @@ http_easy_init(struct http_handler *handler, curl_off_t ims)
 
        setopt_str(result, CURLOPT_USERAGENT, config_get_http_user_agent());
 
+       setopt_long(result, CURLOPT_FOLLOWLOCATION, 1);
+       setopt_long(result, CURLOPT_MAXREDIRS, config_get_max_redirs());
+
        setopt_long(result, CURLOPT_CONNECTTIMEOUT,
            config_get_http_connect_timeout());
        setopt_long(result, CURLOPT_TIMEOUT,
@@ -311,6 +314,9 @@ http_fetch(char const *src, char const *dst, curl_off_t ims, bool *changed)
                case CURLE_FTP_ACCEPT_TIMEOUT:
                        error = EAGAIN; /* Retry */
                        goto end;
+               case CURLE_TOO_MANY_REDIRECTS:
+                       error = -EINVAL;
+                       goto end;
                default:
                        error = handle_http_response_code(http_code);
                        goto end;
@@ -328,17 +334,6 @@ http_fetch(char const *src, char const *dst, curl_off_t ims, bool *changed)
                error = 0;
                goto end;
        }
-       if (http_code >= 300) {
-               /*
-                * If you're ever forced to implement this, please remember that
-                * a malicious server can send us on a wild chase with infinite
-                * redirects, so there needs to be a limit.
-                */
-               pr_val_err("HTTP result code: %ld. I don't follow redirects; discarding file.",
-                   http_code);
-               error = -EINVAL; /* Do not retry. */
-               goto end;
-       }
 
        pr_val_debug("HTTP result code: %ld", http_code);
        error = 0;
@@ -363,7 +358,7 @@ do_retries(char const *src, char const *dst, curl_off_t ims, bool *changed)
 
        r = 0;
        do {
-               pr_val_debug("Download attempt #%u...", r);
+               pr_val_debug("Download attempt #%u...", r + 1);
 
                error = http_fetch(src, dst, ims, changed);
                switch (error) {
@@ -375,7 +370,7 @@ do_retries(char const *src, char const *dst, curl_off_t ims, bool *changed)
                        break;
 
                default:
-                       pr_val_debug("Download failed: %s", strerror(error));
+                       pr_val_debug("Download failed.");
                        return error;
                }