Skip to content

Commit

Permalink
Fix incorrect validity checks in getInfo() and newDerivativeImageInpu…
Browse files Browse the repository at this point in the history
…tStream()
  • Loading branch information
Alex Dolski committed May 3, 2021
1 parent 000c28c commit 59897e3
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
* Fixed a floating-point rounding bug that could cause an excessively large
TIFF pyramid level to be selected, resulting in unnecessary scaling.
* Fixed a bug in TurboJpegProcessor that could cause incorrect cropping.
* Fixed a bug in S3Cache that could cause hits against expired content.
* Fixed a bug that could cause S3 credentials from the configuration file to be
erroneously used even when not set.
* Fixed a bug that could cause corrupt image to be written to a derivative
Expand Down
30 changes: 28 additions & 2 deletions src/main/java/edu/illinois/library/cantaloupe/cache/S3Cache.java
Original file line number Diff line number Diff line change
Expand Up @@ -279,13 +279,15 @@ public Optional<Info> getInfo(Identifier identifier) throws IOException {
.build();
final Stopwatch watch = new Stopwatch();
try (ResponseInputStream<GetObjectResponse> is = client.getObject(request)) {
if (is != null) {
// This extra validity check may be needed with minio server
if (is != null && is.response().lastModified().isAfter(earliestValidInstant())) {
final Info info = Info.fromJSON(is);
LOGGER.debug("getInfo(): read {} from bucket {} in {}",
objectKey, bucketName, watch);
touchAsync(objectKey);
return Optional.of(info);
} else {
consumeStreamAsync(is);
LOGGER.debug("{} in bucket {} is invalid; purging asynchronously",
objectKey, bucketName);
purgeAsync(bucketName, objectKey);
Expand Down Expand Up @@ -315,10 +317,12 @@ public InputStream newDerivativeImageInputStream(OperationList opList)
.build();
try {
ResponseInputStream<GetObjectResponse> is = client.getObject(request);
if (is != null) {
// This extra validity check may be needed with minio server
if (is != null && is.response().lastModified().isAfter(earliestValidInstant())) {
touchAsync(objectKey);
return is;
} else {
consumeStreamAsync(is);
LOGGER.debug("{} in bucket {} is invalid; purging asynchronously",
objectKey, bucketName);
purgeAsync(bucketName, objectKey);
Expand Down Expand Up @@ -501,6 +505,28 @@ public void put(Identifier identifier, Info info) throws IOException {
}
}

/**
* The AWS client logs a warning when we close an InputStream without fully
* reading it. This method does that and then closes the stream.
*/
private void consumeStreamAsync(InputStream inputStream) {
ThreadPool.getInstance().submit(() -> {
try {
inputStream.readAllBytes();
} catch (IOException e) {
LOGGER.warn("consumeStreamAsync(): failed to consume the stream: {}",
e.getMessage());
} finally {
try {
inputStream.close();
} catch (IOException e) {
LOGGER.warn("consumeStreamAsync(): failed to close the stream: {}",
e.getMessage());
}
}
});
}

/**
* Updates an object's "last-accessed time." Since S3 doesn't support a
* last-accessed time and S3 objects are immutable, this method copies the
Expand Down

0 comments on commit 59897e3

Please sign in to comment.