mirror of https://github.com/shred/acme4j
Handle HTTP errors when fetching a nonce
The nonce is fetched via HEAD request. Before this fix, if there was a HTTP error, acme4j expected a Problem JSON body, which was not send because of the HEAD request, and lead to an AcmeProtocolException. Now either an AcmeException or AcmeRetryAfterException is thrown.pull/168/head
parent
aeff12088f
commit
6d5da63b8e
|
@ -152,6 +152,10 @@ public abstract class AcmeJsonResource extends AcmeResource {
|
|||
retryAfterOpt.ifPresent(instant -> LOG.debug("Retry-After: {}", instant));
|
||||
setRetryAfter(retryAfterOpt.orElse(null));
|
||||
return retryAfterOpt;
|
||||
} catch (AcmeRetryAfterException ex) {
|
||||
LOG.debug("Retry-After while attempting to read the resource", ex);
|
||||
setRetryAfter(ex.getRetryAfter());
|
||||
return Optional.of(ex.getRetryAfter());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -51,6 +51,7 @@ import org.shredzone.acme4j.exception.AcmeException;
|
|||
import org.shredzone.acme4j.exception.AcmeNetworkException;
|
||||
import org.shredzone.acme4j.exception.AcmeProtocolException;
|
||||
import org.shredzone.acme4j.exception.AcmeRateLimitedException;
|
||||
import org.shredzone.acme4j.exception.AcmeRetryAfterException;
|
||||
import org.shredzone.acme4j.exception.AcmeServerException;
|
||||
import org.shredzone.acme4j.exception.AcmeUnauthorizedException;
|
||||
import org.shredzone.acme4j.exception.AcmeUserActionRequiredException;
|
||||
|
@ -132,7 +133,12 @@ public class DefaultConnection implements Connection {
|
|||
|
||||
var rc = getResponse().statusCode();
|
||||
if (rc != HTTP_OK && rc != HTTP_NO_CONTENT) {
|
||||
throwAcmeException();
|
||||
var message = "Server responded with HTTP " + rc + " while trying to retrieve a nonce";
|
||||
var retryAfterInstant = getRetryAfter();
|
||||
if (retryAfterInstant.isPresent()) {
|
||||
throw new AcmeRetryAfterException(message, retryAfterInstant.get());
|
||||
};
|
||||
throw new AcmeException(message);
|
||||
}
|
||||
|
||||
session.setNonce(getNonce()
|
||||
|
|
|
@ -52,6 +52,7 @@ import org.shredzone.acme4j.Session;
|
|||
import org.shredzone.acme4j.exception.AcmeException;
|
||||
import org.shredzone.acme4j.exception.AcmeProtocolException;
|
||||
import org.shredzone.acme4j.exception.AcmeRateLimitedException;
|
||||
import org.shredzone.acme4j.exception.AcmeRetryAfterException;
|
||||
import org.shredzone.acme4j.exception.AcmeServerException;
|
||||
import org.shredzone.acme4j.exception.AcmeUnauthorizedException;
|
||||
import org.shredzone.acme4j.exception.AcmeUserActionRequiredException;
|
||||
|
@ -142,6 +143,57 @@ public class DefaultConnectionTest {
|
|||
verify(getRequestedFor(urlEqualTo(REQUEST_PATH)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that {@link DefaultConnection#getNonce()} handles a retry-after header
|
||||
* correctly.
|
||||
*/
|
||||
@Test
|
||||
public void testGetNonceFromHeaderRetryAfter() {
|
||||
var retryAfter = Instant.now().plusSeconds(30L).truncatedTo(SECONDS);
|
||||
|
||||
stubFor(head(urlEqualTo(NEW_NONCE_PATH)).willReturn(aResponse()
|
||||
.withStatus(HttpURLConnection.HTTP_UNAVAILABLE)
|
||||
.withHeader("Content-Type", "application/problem+json")
|
||||
.withHeader("Retry-After", DATE_FORMATTER.format(retryAfter))
|
||||
// do not send a body here because it is a HEAD request!
|
||||
));
|
||||
|
||||
assertThat(session.getNonce()).isNull();
|
||||
|
||||
var ex = assertThrows(AcmeRetryAfterException.class, () -> {
|
||||
try (var conn = session.connect()) {
|
||||
conn.resetNonce(session);
|
||||
}
|
||||
});
|
||||
assertThat(ex.getMessage()).isEqualTo("Server responded with HTTP 503 while trying to retrieve a nonce");
|
||||
assertThat(ex.getRetryAfter()).isEqualTo(retryAfter);
|
||||
|
||||
verify(headRequestedFor(urlEqualTo(NEW_NONCE_PATH)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that {@link DefaultConnection#getNonce()} handles a general HTTP error
|
||||
* correctly.
|
||||
*/
|
||||
@Test
|
||||
public void testGetNonceFromHeaderHttpError() {
|
||||
stubFor(head(urlEqualTo(NEW_NONCE_PATH)).willReturn(aResponse()
|
||||
.withStatus(HttpURLConnection.HTTP_INTERNAL_ERROR)
|
||||
// do not send a body here because it is a HEAD request!
|
||||
));
|
||||
|
||||
assertThat(session.getNonce()).isNull();
|
||||
|
||||
var ex = assertThrows(AcmeException.class, () -> {
|
||||
try (var conn = session.connect()) {
|
||||
conn.resetNonce(session);
|
||||
}
|
||||
});
|
||||
assertThat(ex.getMessage()).isEqualTo("Server responded with HTTP 500 while trying to retrieve a nonce");
|
||||
|
||||
verify(headRequestedFor(urlEqualTo(NEW_NONCE_PATH)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that {@link DefaultConnection#getNonce()} fails on an invalid
|
||||
* {@code Replay-Nonce} header.
|
||||
|
|
Loading…
Reference in New Issue