fix(storage): disable chunked encoding for Aliyun OSS compatibility

Adds skillhub.storage.s3.disable-chunked-encoding (env:
SKILLHUB_STORAGE_S3_DISABLE_CHUNKED_ENCODING, default false) so
operators can turn off aws-chunked encoding when the S3 backend is
Aliyun OSS, which rejects it with 'InvalidArgument: aws-chunked
encoding is not supported'.

Closes #365
This commit is contained in:
dongmucat 2026-05-06 13:56:55 +08:00
parent ebe7db36be
commit e3a0dcb139
4 changed files with 19 additions and 1 deletions

View file

@ -120,6 +120,7 @@ skillhub:
secret-key: ${SKILLHUB_STORAGE_S3_SECRET_KEY:}
region: ${SKILLHUB_STORAGE_S3_REGION:us-east-1}
force-path-style: ${SKILLHUB_STORAGE_S3_FORCE_PATH_STYLE:true}
disable-chunked-encoding: ${SKILLHUB_STORAGE_S3_DISABLE_CHUNKED_ENCODING:false}
auto-create-bucket: ${SKILLHUB_STORAGE_S3_AUTO_CREATE_BUCKET:false}
presign-expiry: ${SKILLHUB_STORAGE_S3_PRESIGN_EXPIRY:PT10M}
max-connections: ${SKILLHUB_STORAGE_S3_MAX_CONNECTIONS:100}

View file

@ -15,6 +15,7 @@ public class S3StorageProperties {
private String secretKey;
private String region = "us-east-1";
private boolean forcePathStyle = true;
private boolean disableChunkedEncoding = false;
private boolean autoCreateBucket = false;
private Duration presignExpiry = Duration.ofMinutes(10);
private Integer maxConnections = 100;
@ -36,6 +37,8 @@ public class S3StorageProperties {
public void setRegion(String region) { this.region = region; }
public boolean isForcePathStyle() { return forcePathStyle; }
public void setForcePathStyle(boolean forcePathStyle) { this.forcePathStyle = forcePathStyle; }
public boolean isDisableChunkedEncoding() { return disableChunkedEncoding; }
public void setDisableChunkedEncoding(boolean disableChunkedEncoding) { this.disableChunkedEncoding = disableChunkedEncoding; }
public boolean isAutoCreateBucket() { return autoCreateBucket; }
public void setAutoCreateBucket(boolean autoCreateBucket) { this.autoCreateBucket = autoCreateBucket; }
public Duration getPresignExpiry() { return presignExpiry; }

View file

@ -78,7 +78,10 @@ public class S3StorageService implements ObjectStorageService {
var builder = S3Client.builder()
.region(Region.of(properties.getRegion()))
.credentialsProvider(buildCredentialsProvider())
.forcePathStyle(properties.isForcePathStyle())
.serviceConfiguration(S3Configuration.builder()
.pathStyleAccessEnabled(properties.isForcePathStyle())
.chunkedEncodingEnabled(!properties.isDisableChunkedEncoding())
.build())
.httpClientBuilder(httpClientBuilder)
.overrideConfiguration(config -> config
.apiCallAttemptTimeout(properties.getApiCallAttemptTimeout())

View file

@ -39,6 +39,17 @@ import static org.mockito.Mockito.when;
class S3StorageServiceTest {
@Test
void buildS3ClientShouldDisableChunkedEncodingWhenConfigured() {
S3StorageProperties props = createProperties(true);
props.setDisableChunkedEncoding(true);
S3StorageService service = new S3StorageService(props);
ApacheHttpClient.Builder httpClientBuilder = ApacheHttpClient.builder();
S3Client client = service.buildS3Client(httpClientBuilder);
assertThat(client).isNotNull();
client.close();
}
@Test
void shouldUsePathStylePresignedUrlWhenForcePathStyleEnabled() {
URI presignedUrl = presignGetObjectUrl(true);