Skip to content

Commit ed1f50b

Browse files
committed
Remodel NotModified from throwable to value type
1 parent 983674d commit ed1f50b

1 file changed

Lines changed: 62 additions & 38 deletions

File tree

webauthn-server-attestation/src/main/java/com/yubico/fido/metadata/FidoMetadataDownloader.java

Lines changed: 62 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -876,48 +876,50 @@ private Optional<MetadataBLOB> refreshBlobInternal(
876876

877877
try {
878878
log.debug("Attempting to download new BLOB...");
879-
final ByteArray downloadedBytes =
879+
final DownloadResult downloadResult =
880880
download(
881881
blobUrl,
882882
// This should ideally use the value of the ETag response header from when the cached
883883
// BLOB was downloaded, but we don't have anywhere to store that without changing the
884884
// format of the cache serialization. This is good enough as the MDS explicitly
885885
// specifies that the ETag is set to the "no" of the BLOB.
886886
cached.map(cachedBlob -> String.format("%d", cachedBlob.getPayload().getNo())));
887-
final MetadataBLOB downloadedBlob = parseAndVerifyBlob(downloadedBytes, trustRoot);
888-
log.debug("New BLOB downloaded.");
887+
if (downloadResult.isNotModified()) {
888+
log.debug("Remote BLOB not modified - using cached BLOB.");
889+
return cached;
889890

890-
if (cached.isPresent()) {
891-
log.debug("Cached BLOB exists - checking if new BLOB has a higher \"no\"...");
892-
if (downloadedBlob.getPayload().getNo() <= cached.get().getPayload().getNo()) {
893-
log.debug("New BLOB does not have a higher \"no\" - using cached BLOB instead.");
894-
return cached;
891+
} else {
892+
ByteArray downloadedBytes = downloadResult.getContent();
893+
final MetadataBLOB downloadedBlob = parseAndVerifyBlob(downloadedBytes, trustRoot);
894+
log.debug("New BLOB downloaded.");
895+
896+
if (cached.isPresent()) {
897+
log.debug("Cached BLOB exists - checking if new BLOB has a higher \"no\"...");
898+
if (downloadedBlob.getPayload().getNo() <= cached.get().getPayload().getNo()) {
899+
log.debug("New BLOB does not have a higher \"no\" - using cached BLOB instead.");
900+
return cached;
901+
}
902+
log.debug("New BLOB has a higher \"no\" - proceeding with new BLOB.");
895903
}
896-
log.debug("New BLOB has a higher \"no\" - proceeding with new BLOB.");
897-
}
898-
899-
log.debug("Checking legalHeader in new BLOB...");
900-
if (!expectedLegalHeaders.contains(downloadedBlob.getPayload().getLegalHeader())) {
901-
throw new UnexpectedLegalHeader(cached.orElse(null), downloadedBlob);
902-
}
903904

904-
log.debug("Writing new BLOB to cache...");
905-
if (blobCacheFile != null) {
906-
try (FileOutputStream f = new FileOutputStream(blobCacheFile)) {
907-
f.write(downloadedBytes.getBytes());
905+
log.debug("Checking legalHeader in new BLOB...");
906+
if (!expectedLegalHeaders.contains(downloadedBlob.getPayload().getLegalHeader())) {
907+
throw new UnexpectedLegalHeader(cached.orElse(null), downloadedBlob);
908908
}
909-
}
910-
911-
if (blobCacheConsumer != null) {
912-
blobCacheConsumer.accept(downloadedBytes);
913-
}
914909

915-
return Optional.of(downloadedBlob);
910+
log.debug("Writing new BLOB to cache...");
911+
if (blobCacheFile != null) {
912+
try (FileOutputStream f = new FileOutputStream(blobCacheFile)) {
913+
f.write(downloadedBytes.getBytes());
914+
}
915+
}
916916

917-
} catch (NotModified e) {
918-
log.debug("Remote BLOB not modified - using cached BLOB.");
919-
return cached;
917+
if (blobCacheConsumer != null) {
918+
blobCacheConsumer.accept(downloadedBytes);
919+
}
920920

921+
return Optional.of(downloadedBlob);
922+
}
921923
} catch (FidoMetadataDownloaderException e) {
922924
if (e.getReason() == Reason.BAD_SIGNATURE && cached.isPresent()) {
923925
log.warn("New BLOB has bad signature - falling back to cached BLOB.");
@@ -1074,17 +1076,18 @@ Optional<ByteArray> readCacheFile(File cacheFile) throws IOException {
10741076
}
10751077

10761078
private ByteArray download(URL url) throws IOException {
1077-
try {
1078-
return download(url, Optional.empty());
1079-
} catch (NotModified e) {
1079+
final DownloadResult downloadResult = download(url, Optional.empty());
1080+
if (downloadResult.isOk()) {
1081+
return downloadResult.getContent();
1082+
} else {
10801083
final String msg =
1081-
"NotModified thrown by download(URL, Optional.empty()). This should be impossible, please file a bug report.";
1084+
"download(URL, Optional.empty()) returned non-OK success response. This should be impossible, please file a bug report.";
10821085
log.error(msg);
1083-
throw new RuntimeException(msg, e);
1086+
throw new RuntimeException(msg);
10841087
}
10851088
}
10861089

1087-
private ByteArray download(URL url, Optional<String> etag) throws IOException, NotModified {
1090+
private DownloadResult download(URL url, Optional<String> etag) throws IOException {
10881091
URLConnection conn = url.openConnection();
10891092

10901093
if (conn instanceof HttpsURLConnection) {
@@ -1114,7 +1117,7 @@ private ByteArray download(URL url, Optional<String> etag) throws IOException, N
11141117
switch (httpsConn.getResponseCode()) {
11151118
case 304: // Not Modified
11161119
log.debug("Received 304 Not Modified response to download request: {}", url);
1117-
throw new NotModified();
1120+
return DownloadResult.notModified();
11181121
}
11191122

11201123
log.warn(
@@ -1135,13 +1138,13 @@ private ByteArray download(URL url, Optional<String> etag) throws IOException, N
11351138
et.equals(responseEtag) || String.format("\"%s\"", et).equals(responseEtag))
11361139
.orElse(false)) {
11371140
log.debug("Response ETag matches local ETag - interpreting as not modified.");
1138-
throw new NotModified();
1141+
return DownloadResult.notModified();
11391142
}
11401143
}
11411144
}
11421145
}
11431146

1144-
return readAll(conn.getInputStream());
1147+
return DownloadResult.ok(readAll(conn.getInputStream()));
11451148
}
11461149

11471150
private MetadataBLOB parseAndVerifyBlob(ByteArray jwt, X509Certificate trustRootCertificate)
@@ -1379,5 +1382,26 @@ private Optional<CertStore> fetchCrlDistributionPoints(
13791382
}
13801383
}
13811384

1382-
private static class NotModified extends Throwable {}
1385+
@Value
1386+
@AllArgsConstructor(access = AccessLevel.PRIVATE)
1387+
private static class DownloadResult {
1388+
private boolean notModified;
1389+
private Optional<ByteArray> content;
1390+
1391+
static DownloadResult notModified() {
1392+
return new DownloadResult(true, Optional.empty());
1393+
}
1394+
1395+
static DownloadResult ok(@NonNull ByteArray content) {
1396+
return new DownloadResult(false, Optional.of(content));
1397+
}
1398+
1399+
ByteArray getContent() {
1400+
return content.get();
1401+
}
1402+
1403+
boolean isOk() {
1404+
return content.isPresent();
1405+
}
1406+
}
13831407
}

0 commit comments

Comments
 (0)