Add an "excessively large object" safeguard.
This commit is contained in:
parent
fbaf4a09e2
commit
28e3b23e8c
|
@ -25,6 +25,9 @@ public class TorExitNodeConfiguration {
|
||||||
@NotBlank
|
@NotBlank
|
||||||
private String objectKey;
|
private String objectKey;
|
||||||
|
|
||||||
|
@JsonProperty
|
||||||
|
private long maxSize = 16 * 1024 * 1024;
|
||||||
|
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private Duration refreshInterval = Duration.ofMinutes(5);
|
private Duration refreshInterval = Duration.ofMinutes(5);
|
||||||
|
|
||||||
|
@ -45,6 +48,15 @@ public class TorExitNodeConfiguration {
|
||||||
return objectKey;
|
return objectKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getMaxSize() {
|
||||||
|
return maxSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public void setMaxSize(final long maxSize) {
|
||||||
|
this.maxSize = maxSize;
|
||||||
|
}
|
||||||
|
|
||||||
public Duration getRefreshInterval() {
|
public Duration getRefreshInterval() {
|
||||||
return refreshInterval;
|
return refreshInterval;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ public class S3ObjectMonitor implements Managed {
|
||||||
|
|
||||||
private final String s3Bucket;
|
private final String s3Bucket;
|
||||||
private final String objectKey;
|
private final String objectKey;
|
||||||
|
private final long maxObjectSize;
|
||||||
|
|
||||||
private final ScheduledExecutorService refreshExecutorService;
|
private final ScheduledExecutorService refreshExecutorService;
|
||||||
private final Duration refreshInterval;
|
private final Duration refreshInterval;
|
||||||
|
@ -46,6 +47,7 @@ public class S3ObjectMonitor implements Managed {
|
||||||
final String s3Region,
|
final String s3Region,
|
||||||
final String s3Bucket,
|
final String s3Bucket,
|
||||||
final String objectKey,
|
final String objectKey,
|
||||||
|
final long maxObjectSize,
|
||||||
final ScheduledExecutorService refreshExecutorService,
|
final ScheduledExecutorService refreshExecutorService,
|
||||||
final Duration refreshInterval,
|
final Duration refreshInterval,
|
||||||
final Consumer<S3Object> changeListener) {
|
final Consumer<S3Object> changeListener) {
|
||||||
|
@ -56,6 +58,7 @@ public class S3ObjectMonitor implements Managed {
|
||||||
.build(),
|
.build(),
|
||||||
s3Bucket,
|
s3Bucket,
|
||||||
objectKey,
|
objectKey,
|
||||||
|
maxObjectSize,
|
||||||
refreshExecutorService,
|
refreshExecutorService,
|
||||||
refreshInterval,
|
refreshInterval,
|
||||||
changeListener);
|
changeListener);
|
||||||
|
@ -66,6 +69,7 @@ public class S3ObjectMonitor implements Managed {
|
||||||
final AmazonS3 s3Client,
|
final AmazonS3 s3Client,
|
||||||
final String s3Bucket,
|
final String s3Bucket,
|
||||||
final String objectKey,
|
final String objectKey,
|
||||||
|
final long maxObjectSize,
|
||||||
final ScheduledExecutorService refreshExecutorService,
|
final ScheduledExecutorService refreshExecutorService,
|
||||||
final Duration refreshInterval,
|
final Duration refreshInterval,
|
||||||
final Consumer<S3Object> changeListener) {
|
final Consumer<S3Object> changeListener) {
|
||||||
|
@ -73,6 +77,7 @@ public class S3ObjectMonitor implements Managed {
|
||||||
this.s3Client = s3Client;
|
this.s3Client = s3Client;
|
||||||
this.s3Bucket = s3Bucket;
|
this.s3Bucket = s3Bucket;
|
||||||
this.objectKey = objectKey;
|
this.objectKey = objectKey;
|
||||||
|
this.maxObjectSize = maxObjectSize;
|
||||||
|
|
||||||
this.refreshExecutorService = refreshExecutorService;
|
this.refreshExecutorService = refreshExecutorService;
|
||||||
this.refreshInterval = refreshInterval;
|
this.refreshInterval = refreshInterval;
|
||||||
|
@ -111,7 +116,17 @@ public class S3ObjectMonitor implements Managed {
|
||||||
final String refreshedETag = objectMetadata.getETag();
|
final String refreshedETag = objectMetadata.getETag();
|
||||||
|
|
||||||
if (!StringUtils.equals(initialETag, refreshedETag) && lastETag.compareAndSet(initialETag, refreshedETag)) {
|
if (!StringUtils.equals(initialETag, refreshedETag) && lastETag.compareAndSet(initialETag, refreshedETag)) {
|
||||||
changeListener.accept(s3Client.getObject(s3Bucket, objectKey));
|
final S3Object s3Object = s3Client.getObject(s3Bucket, objectKey);
|
||||||
|
|
||||||
|
log.info("Object at s3://{}/{} has changed; new eTag is {} and object size is {} bytes",
|
||||||
|
s3Bucket, objectKey, s3Object.getObjectMetadata().getETag(), s3Object.getObjectMetadata().getContentLength());
|
||||||
|
|
||||||
|
if (s3Object.getObjectMetadata().getContentLength() <= maxObjectSize) {
|
||||||
|
changeListener.accept(s3Object);
|
||||||
|
} else {
|
||||||
|
log.warn("Object at s3://{}/{} has a size of {} bytes, which exceeds the maximum allowed size of {} bytes",
|
||||||
|
s3Bucket, objectKey, s3Object.getObjectMetadata().getContentLength(), maxObjectSize);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
log.warn("Failed to refresh monitored object", e);
|
log.warn("Failed to refresh monitored object", e);
|
||||||
|
|
|
@ -49,6 +49,7 @@ public class TorExitNodeManager implements Managed {
|
||||||
configuration.getS3Region(),
|
configuration.getS3Region(),
|
||||||
configuration.getS3Bucket(),
|
configuration.getS3Bucket(),
|
||||||
configuration.getObjectKey(),
|
configuration.getObjectKey(),
|
||||||
|
configuration.getMaxSize(),
|
||||||
scheduledExecutorService,
|
scheduledExecutorService,
|
||||||
configuration.getRefreshInterval(),
|
configuration.getRefreshInterval(),
|
||||||
this::handleExitListChanged);
|
this::handleExitListChanged);
|
||||||
|
|
|
@ -10,8 +10,9 @@ import java.util.UUID;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
@ -32,7 +33,9 @@ class S3ObjectMonitorTest {
|
||||||
final S3ObjectMonitor objectMonitor = new S3ObjectMonitor(
|
final S3ObjectMonitor objectMonitor = new S3ObjectMonitor(
|
||||||
s3Client,
|
s3Client,
|
||||||
bucket,
|
bucket,
|
||||||
objectKey, mock(ScheduledExecutorService.class),
|
objectKey,
|
||||||
|
16 * 1024 * 1024,
|
||||||
|
mock(ScheduledExecutorService.class),
|
||||||
Duration.ofMinutes(1),
|
Duration.ofMinutes(1),
|
||||||
listener);
|
listener);
|
||||||
|
|
||||||
|
@ -46,4 +49,37 @@ class S3ObjectMonitorTest {
|
||||||
|
|
||||||
verify(listener).accept(s3Object);
|
verify(listener).accept(s3Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void refreshOversizedObject() {
|
||||||
|
final AmazonS3 s3Client = mock(AmazonS3.class);
|
||||||
|
final ObjectMetadata metadata = mock(ObjectMetadata.class);
|
||||||
|
final S3Object s3Object = mock(S3Object.class);
|
||||||
|
|
||||||
|
final String bucket = "s3bucket";
|
||||||
|
final String objectKey = "greatest-smooth-jazz-hits-of-all-time.zip";
|
||||||
|
final long maxObjectSize = 16 * 1024 * 1024;
|
||||||
|
|
||||||
|
//noinspection unchecked
|
||||||
|
final Consumer<S3Object> listener = mock(Consumer.class);
|
||||||
|
|
||||||
|
final S3ObjectMonitor objectMonitor = new S3ObjectMonitor(
|
||||||
|
s3Client,
|
||||||
|
bucket,
|
||||||
|
objectKey,
|
||||||
|
maxObjectSize,
|
||||||
|
mock(ScheduledExecutorService.class),
|
||||||
|
Duration.ofMinutes(1),
|
||||||
|
listener);
|
||||||
|
|
||||||
|
when(metadata.getETag()).thenReturn(UUID.randomUUID().toString());
|
||||||
|
when(metadata.getContentLength()).thenReturn(maxObjectSize + 1);
|
||||||
|
when(s3Object.getObjectMetadata()).thenReturn(metadata);
|
||||||
|
when(s3Client.getObjectMetadata(bucket, objectKey)).thenReturn(metadata);
|
||||||
|
when(s3Client.getObject(bucket, objectKey)).thenReturn(s3Object);
|
||||||
|
|
||||||
|
objectMonitor.refresh();
|
||||||
|
|
||||||
|
verify(listener, never()).accept(any());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue