]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: acme: use Retry-After value for retries
authorWilliam Lallemand <wlallemand@haproxy.com>
Thu, 24 Apr 2025 15:31:51 +0000 (17:31 +0200)
committerWilliam Lallemand <wlallemand@haproxy.com>
Thu, 24 Apr 2025 18:14:47 +0000 (20:14 +0200)
Parse the Retry-After header in response and store it in order to use
the value as the next delay for the next retry, fallback to 3s if the
value couldn't be parse or does not exist.

include/haproxy/acme-t.h
src/acme.c

index 585728ef0798698fabed4e5e6817b47f2c736fd3..4689624178631bb52018161ff98a8d4a660d5ba6 100644 (file)
@@ -61,6 +61,7 @@ struct acme_ctx {
        enum acme_st state;
        enum http_st http_state;
        int retries;
+       int retryafter;
        struct httpclient *hc;
        struct acme_cfg *cfg;
        struct ckch_store *store;
index 3a838320d491f90fe14e5807997aff5c0aa7b774..2debfdb4ec8932ff98626e47ac866c23e52fcfea 100644 (file)
@@ -720,6 +720,10 @@ int acme_res_certificate(struct task *task, struct acme_ctx *ctx, char **errmsg)
                        istfree(&ctx->nonce);
                        ctx->nonce = istdup(hdr->v);
                }
+               /* get the next retry timing */
+               if (isteqi(hdr->n, ist("Retry-After"))) {
+                       ctx->retryafter = atol(hdr->v.ptr);
+               }
        }
 
        if (hc->res.status < 200 || hc->res.status >= 300) {
@@ -787,6 +791,10 @@ int acme_res_chkorder(struct task *task, struct acme_ctx *ctx, char **errmsg)
                        istfree(&ctx->nonce);
                        ctx->nonce = istdup(hdr->v);
                }
+               /* get the next retry timing */
+               if (isteqi(hdr->n, ist("Retry-After"))) {
+                       ctx->retryafter = atol(hdr->v.ptr);
+               }
        }
 
        if (hc->res.status < 200 || hc->res.status >= 300) {
@@ -912,6 +920,10 @@ int acme_res_finalize(struct task *task, struct acme_ctx *ctx, char **errmsg)
                        istfree(&ctx->nonce);
                        ctx->nonce = istdup(hdr->v);
                }
+               /* get the next retry timing */
+               if (isteqi(hdr->n, ist("Retry-After"))) {
+                       ctx->retryafter = atol(hdr->v.ptr);
+               }
        }
 
        if (hc->res.status < 200 || hc->res.status >= 300) {
@@ -999,6 +1011,10 @@ int acme_res_challenge(struct task *task, struct acme_ctx *ctx, struct acme_auth
                        istfree(&ctx->nonce);
                        ctx->nonce = istdup(hdr->v);
                }
+               /* get the next retry timing */
+               if (isteqi(hdr->n, ist("Retry-After"))) {
+                       ctx->retryafter = atol(hdr->v.ptr);
+               }
        }
 
        if (hc->res.status < 200 || hc->res.status >= 300 || mjson_find(hc->res.buf.area, hc->res.buf.data, "$.error", NULL, NULL) == MJSON_TOK_OBJECT) {
@@ -1087,6 +1103,11 @@ int acme_res_auth(struct task *task, struct acme_ctx *ctx, struct acme_auth *aut
                        istfree(&ctx->nonce);
                        ctx->nonce = istdup(hdr->v);
                }
+               /* get the next retry timing */
+               if (isteqi(hdr->n, ist("Retry-After"))) {
+                       ctx->retryafter = atol(hdr->v.ptr);
+               }
+
        }
 
        if (hc->res.status < 200 || hc->res.status >= 300) {
@@ -1238,6 +1259,10 @@ int acme_res_neworder(struct task *task, struct acme_ctx *ctx, char **errmsg)
                        istfree(&ctx->nonce);
                        ctx->nonce = istdup(hdr->v);
                }
+               /* get the next retry timing */
+               if (isteqi(hdr->n, ist("Retry-After"))) {
+                       ctx->retryafter = atol(hdr->v.ptr);
+               }
                /* get the order URL */
                if (isteqi(hdr->n, ist("Location"))) {
                        istfree(&ctx->order);
@@ -1386,6 +1411,10 @@ int acme_res_account(struct task *task, struct acme_ctx *ctx, int newaccount, ch
                        istfree(&ctx->kid);
                        ctx->kid = istdup(hdr->v);
                }
+               /* get the next retry timing */
+               if (isteqi(hdr->n, ist("Retry-After"))) {
+                       ctx->retryafter = atol(hdr->v.ptr);
+               }
                if (isteqi(hdr->n, ist("Replay-Nonce"))) {
                        istfree(&ctx->nonce);
                        ctx->nonce = istdup(hdr->v);
@@ -1742,9 +1771,16 @@ retry:
                int delay = 1;
                int i;
 
-               for (i = 0; i < ACME_RETRY - ctx->retries; i++)
-                       delay *= 3;
-               send_log(NULL, LOG_NOTICE, "acme: %s: %s, retrying in %ds (%d/%d)...\n", ctx->store->path, errmsg ? errmsg : "", delay, ACME_RETRY - ctx->retries, ACME_RETRY);
+               if (ctx->retryafter > 0) {
+                       /* Use the Retry-After value from the header */
+                       delay = ctx->retryafter;
+                       ctx->retryafter = 0;
+               } else {
+                       /* else does an exponential backoff * 3 */
+                       for (i = 0; i < ACME_RETRY - ctx->retries; i++)
+                               delay *= 3;
+               }
+               send_log(NULL, LOG_NOTICE, "acme: %s: %s, retrying in %ds (%d/%d retries)...\n", ctx->store->path, errmsg ? errmsg : "", delay, ACME_RETRY - ctx->retries, ACME_RETRY);
                task->expire = tick_add(now_ms, delay * 1000);
 
        } else {