From 64a3cde52f4b42366ea02c9f0eea5fc63feb940a Mon Sep 17 00:00:00 2001 From: Jeremy Long Date: Fri, 24 Nov 2023 11:16:26 -0500 Subject: [PATCH] fix: honor retry after header (#94) --- .../client/nvd/NvdApiRetryStrategy.java | 32 ++++++++++++++++--- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/open-vulnerability-clients/src/main/java/io/github/jeremylong/openvulnerability/client/nvd/NvdApiRetryStrategy.java b/open-vulnerability-clients/src/main/java/io/github/jeremylong/openvulnerability/client/nvd/NvdApiRetryStrategy.java index 4a7bb97f..29d18400 100644 --- a/open-vulnerability-clients/src/main/java/io/github/jeremylong/openvulnerability/client/nvd/NvdApiRetryStrategy.java +++ b/open-vulnerability-clients/src/main/java/io/github/jeremylong/openvulnerability/client/nvd/NvdApiRetryStrategy.java @@ -17,6 +17,9 @@ package io.github.jeremylong.openvulnerability.client.nvd; import org.apache.hc.client5.http.impl.DefaultHttpRequestRetryStrategy; +import org.apache.hc.client5.http.utils.DateUtils; +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpHeaders; import org.apache.hc.core5.http.HttpRequest; import org.apache.hc.core5.http.HttpResponse; import org.apache.hc.core5.http.protocol.HttpContext; @@ -25,12 +28,13 @@ import org.slf4j.LoggerFactory; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; import java.util.concurrent.TimeUnit; /** - * Implements a back-off delay retry strategy. + * Implements a back-off delay retry strategy that honors the retry-after header. */ public class NvdApiRetryStrategy extends DefaultHttpRequestRetryStrategy { @@ -70,11 +74,29 @@ public boolean retryRequest(HttpResponse response, int execCount, HttpContext co @Override public TimeValue getRetryInterval(final HttpResponse response, final int execCount, final HttpContext context) { - + TimeValue value; if (execCount < maxRetries / 2) { - return TimeValue.of(delay * execCount, TimeUnit.MILLISECONDS); + value = TimeValue.of(delay * execCount, TimeUnit.MILLISECONDS); + } else { + value = TimeValue.of(delay * execCount / 2, TimeUnit.MILLISECONDS); } - - return TimeValue.of(delay * execCount / 2, TimeUnit.MILLISECONDS); + //check retry after header + final Header header = response.getFirstHeader(HttpHeaders.RETRY_AFTER); + if (header != null) { + TimeValue retryAfter = null; + final String headerValue = header.getValue(); + try { + retryAfter = TimeValue.ofSeconds(Long.parseLong(headerValue)); + } catch (final NumberFormatException ignore) { + final Instant retryAfterDate = DateUtils.parseStandardDate(headerValue); + if (retryAfterDate != null) { + retryAfter = TimeValue.ofMilliseconds(retryAfterDate.toEpochMilli() - System.currentTimeMillis()); + } + } + if (TimeValue.isPositive(retryAfter) && retryAfter.compareTo(value) < 0) { + return retryAfter; + } + } + return value; } }