From c83df44eed9228d7ed88f6a553ad085d5585aac2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Richard=20K=C3=B6rber?= Date: Sat, 9 Jan 2016 17:23:05 +0100 Subject: [PATCH] Expire resource directory cache. A long term AcmeClient instance could miss changes to the directory, so the cache is invalidated after 1 hour. --- .../shredzone/acme4j/impl/GenericAcmeClient.java | 13 +++++++++++-- .../acme4j/impl/GenericAcmeClientTest.java | 11 +++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/impl/GenericAcmeClient.java b/acme4j-client/src/main/java/org/shredzone/acme4j/impl/GenericAcmeClient.java index 122d0329..9245608c 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/impl/GenericAcmeClient.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/impl/GenericAcmeClient.java @@ -15,6 +15,7 @@ package org.shredzone.acme4j.impl; import java.net.HttpURLConnection; import java.net.URI; +import java.util.Date; import java.util.EnumMap; import java.util.Map; @@ -38,6 +39,7 @@ public class GenericAcmeClient extends AbstractAcmeClient { private final AcmeClientProvider provider; private final URI directoryUri; private final Map directoryMap = new EnumMap<>(Resource.class); + /* package protected */ Date directoryCacheExpiry; /** * Creates a new {@link GenericAcmeClient}. @@ -86,7 +88,9 @@ public class GenericAcmeClient extends AbstractAcmeClient { throw new NullPointerException("resource must not be null"); } - if (directoryMap.isEmpty()) { + Date now = new Date(); + + if (directoryMap.isEmpty() || !directoryCacheExpiry.after(now)) { if (directoryUri == null) { throw new IllegalStateException("directoryUri was null on construction time"); } @@ -100,7 +104,12 @@ public class GenericAcmeClient extends AbstractAcmeClient { // use nonce header if there is one, saves a HEAD request... conn.updateSession(getSession()); - directoryMap.putAll(conn.readDirectory()); + Map newMap = conn.readDirectory(); + + // only reached when readDirectory did not throw an exception + directoryMap.clear(); + directoryMap.putAll(newMap); + directoryCacheExpiry = new Date(now.getTime() + 60 * 60 * 1000L); } } return directoryMap.get(resource); diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/impl/GenericAcmeClientTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/impl/GenericAcmeClientTest.java index 509e3bec..dd397a52 100644 --- a/acme4j-client/src/test/java/org/shredzone/acme4j/impl/GenericAcmeClientTest.java +++ b/acme4j-client/src/test/java/org/shredzone/acme4j/impl/GenericAcmeClientTest.java @@ -19,6 +19,7 @@ import static org.mockito.Mockito.*; import java.net.URI; import java.net.URISyntaxException; +import java.util.Date; import java.util.HashMap; import java.util.Map; @@ -107,6 +108,16 @@ public class GenericAcmeClientTest { verify(mockConnection, times(1)).readDirectory(); verify(mockProvider).createConnection(); + + // Simulate a cache expiry + client.directoryCacheExpiry = new Date(); + + // Make sure directory is read once again + assertThat(client.resourceUri(Resource.NEW_AUTHZ), is(new URI("http://example.com/acme/new-authz"))); + assertThat(client.resourceUri(Resource.NEW_CERT), is(new URI("http://example.com/acme/new-cert"))); + assertThat(client.resourceUri(Resource.NEW_REG), is(nullValue())); + verify(mockConnection, times(2)).sendRequest(directoryUri); + verify(mockConnection, times(2)).readDirectory(); } }