Add NoCacheBlobStore

pull/849/head
polarctos 2025-08-26 17:56:09 +02:00
rodzic 664a94dbd5
commit b0ffdd47f3
6 zmienionych plików z 147 dodań i 0 usunięć

Wyświetl plik

@ -115,6 +115,7 @@ S3Proxy can modify its behavior based on middlewares:
* [sharded backend containers](https://github.com/gaul/s3proxy/wiki/Middleware-sharded-backend)
* [storage class override](https://github.com/gaul/s3proxy/wiki/Middleware-storage-class-override)
* [user metadata replacer](https://github.com/gaul/s3proxy/wiki/Middleware-user-metadata-replacer)
* [no cache override](https://github.com/gaul/s3proxy/wiki/Middleware-no-cache)
## SSL Support

Wyświetl plik

@ -314,6 +314,14 @@ public final class Main {
blobStore = LatencyBlobStore.newLatencyBlobStore(blobStore, latencies, speeds);
}
String noCacheBlobStore = properties.getProperty(
S3ProxyConstants.PROPERTY_NO_CACHE_BLOBSTORE);
if ("true".equalsIgnoreCase(noCacheBlobStore)) {
System.err.println("Using no-cache storage backend middleware");
blobStore = NoCacheBlobStore
.newNoCacheBlobStore(blobStore);
}
return blobStore;
}

Wyświetl plik

@ -0,0 +1,68 @@
/*
* Copyright 2014-2025 Andrew Gaul <andrew@gaul.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.gaul.s3proxy;
import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.options.GetOptions;
import org.jclouds.blobstore.util.ForwardingBlobStore;
/**
* BlobStore which drops eTag or date based cache options from object requests.
* This is useful as the JClouds library does not fully support the proxying of HTTP 304 responses.
*/
final class NoCacheBlobStore extends ForwardingBlobStore {
private NoCacheBlobStore(BlobStore blobStore) {
super(blobStore);
}
public static BlobStore newNoCacheBlobStore(BlobStore blobStore) {
return new NoCacheBlobStore(blobStore);
}
@Override
public Blob getBlob(String containerName, String name) {
return getBlob(containerName, name, new GetOptions());
}
@Override
public Blob getBlob(String containerName, String name, GetOptions getOptions) {
return super.getBlob(containerName, name, resetCacheHeaders(getOptions));
}
static GetOptions resetCacheHeaders(GetOptions options) {
if (options.getIfMatch() != null || options.getIfNoneMatch() != null ||
options.getIfModifiedSince() != null || options.getIfUnmodifiedSince() != null) {
// as there is no exposed method to reset just the cache headers, a copy is used
GetOptions optionsNoCache = new GetOptions();
for (String range : options.getRanges()) {
String[] ranges = range.split("-", 2);
if (ranges[0].isEmpty()) {
optionsNoCache.tail(Long.parseLong(ranges[1]));
} else if (ranges[1].isEmpty()) {
optionsNoCache.startAt(Long.parseLong(ranges[0]));
} else {
optionsNoCache.range(Long.parseLong(ranges[0]), Long.parseLong(ranges[1]));
}
}
return optionsNoCache;
}
return options;
}
}

Wyświetl plik

@ -138,6 +138,9 @@ public final class S3ProxyConstants {
public static final String PROPERTY_LATENCY =
"s3proxy.latency-blobstore";
public static final String PROPERTY_NO_CACHE_BLOBSTORE =
"s3proxy.no-cache-blobstore";
static final String PROPERTY_ALT_JCLOUDS_PREFIX = "alt.";
private S3ProxyConstants() {

Wyświetl plik

@ -25,6 +25,7 @@ exec java \
-Ds3proxy.encrypted-blobstore-salt="${S3PROXY_ENCRYPTED_BLOBSTORE_SALT}" \
-Ds3proxy.v4-max-non-chunked-request-size="${S3PROXY_V4_MAX_NON_CHUNKED_REQ_SIZE:-134217728}" \
-Ds3proxy.read-only-blobstore="${S3PROXY_READ_ONLY_BLOBSTORE:-false}" \
-Ds3proxy.no-cache-blobstore="${S3PROXY_NO_CACHE_BLOBSTORE:-false}" \
-Ds3proxy.maximum-timeskew="${S3PROXY_MAXIMUM_TIMESKEW}" \
-Ds3proxy.service-path="${S3PROXY_SERVICE_PATH}" \
-Djclouds.provider="${JCLOUDS_PROVIDER}" \

Wyświetl plik

@ -0,0 +1,66 @@
/*
* Copyright 2014-2025 Andrew Gaul <andrew@gaul.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.gaul.s3proxy;
import static org.assertj.core.api.Assertions.assertThat;
import java.time.Instant;
import java.util.Date;
import org.jclouds.blobstore.options.GetOptions;
import org.junit.jupiter.api.Test;
public final class NoCacheBlobStoreTest {
@Test
public void testResetCacheHeadersKeepRange() {
var options = GetOptions.Builder.range(1, 5);
var optionsResult = NoCacheBlobStore.resetCacheHeaders(options);
assertThat(optionsResult.getRanges()).isEqualTo(options.getRanges());
}
@Test
public void testResetCacheHeadersKeepTail() {
var options = GetOptions.Builder.range(1, 5).tail(3).startAt(10);
var optionsResult = NoCacheBlobStore.resetCacheHeaders(options);
assertThat(optionsResult.getRanges()).isEqualTo(options.getRanges());
}
@Test
public void testResetCacheHeadersRangeDropCache() {
var options = GetOptions.Builder
.range(1, 5)
.tail(3)
.startAt(10)
.ifETagDoesntMatch("abc")
.ifModifiedSince(Date.from(Instant.EPOCH));
var optionsResult = NoCacheBlobStore.resetCacheHeaders(options);
assertThat(optionsResult.getRanges()).isEqualTo(options.getRanges());
assertThat(optionsResult.getIfNoneMatch()).isEqualTo(null);
assertThat(optionsResult.getIfModifiedSince()).isEqualTo((Date) null);
}
@Test
public void testResetCacheHeadersNoRange() {
var options = GetOptions.Builder
.ifETagMatches("abc")
.ifUnmodifiedSince(Date.from(Instant.EPOCH));
var optionsResult = NoCacheBlobStore.resetCacheHeaders(options);
assertThat(optionsResult.getRanges()).isEqualTo(options.getRanges());
assertThat(optionsResult.getIfMatch()).isEqualTo(null);
assertThat(optionsResult.getIfUnmodifiedSince()).isEqualTo((Date) null);
}
}