com.amazonaws.services.s3.internal.S3V4AuthErrorRetryStrategy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aws-java-sdk-s3 Show documentation
Show all versions of aws-java-sdk-s3 Show documentation
The AWS Java SDK for Amazon S3 module holds the client classes that are used for communicating with Amazon Simple Storage Service
/*
* Copyright 2010-2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file 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 com.amazonaws.services.s3.internal;
import java.net.URI;
import java.net.URISyntaxException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.amazonaws.annotation.Immutable;
import com.amazonaws.SdkClientException;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.Request;
import com.amazonaws.http.HttpResponse;
import com.amazonaws.internal.SdkPredicate;
import com.amazonaws.regions.Regions;
import com.amazonaws.retry.internal.AuthErrorRetryStrategy;
import com.amazonaws.retry.internal.AuthRetryParameters;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.Headers;
import com.amazonaws.util.StringUtils;
/**
* The internal implementation of AuthErrorRetryStrategy which automatically switches to V4 signer
* when the S3 returns auth error asking for v4 authentication.
*/
@Immutable
public class S3V4AuthErrorRetryStrategy implements AuthErrorRetryStrategy {
private static Log log = LogFactory.getLog(S3V4AuthErrorRetryStrategy.class);
private static final String V4_REGION_WARNING = "please use region-specific endpoint to access "
+ "buckets located in regions that require V4 signing.";
private final S3RequestEndpointResolver endpointResolver;
private final SdkPredicate sigV4RetryPredicate;
public S3V4AuthErrorRetryStrategy(S3RequestEndpointResolver endpointResolver) {
this(endpointResolver, new IsSigV4RetryablePredicate());
}
/**
* Currently only used for testing
*/
S3V4AuthErrorRetryStrategy(S3RequestEndpointResolver endpointResolver,
SdkPredicate isSigV4Retryable) {
this.endpointResolver = endpointResolver;
this.sigV4RetryPredicate = isSigV4Retryable;
}
@Override
public AuthRetryParameters shouldRetryWithAuthParam(Request> request,
HttpResponse response,
AmazonServiceException ase) {
if (!sigV4RetryPredicate.test(ase)) {
return null;
}
if (hasServingRegionHeader(response)) {
return redirectToRegionInHeader(request, response);
} else if (canUseVirtualAddressing()) {
return redirectToS3External();
} else {
throw new SdkClientException(V4_REGION_WARNING, ase);
}
}
private boolean canUseVirtualAddressing() {
return BucketNameUtils.isDNSBucketName(endpointResolver.getBucketName());
}
private AuthRetryParameters redirectToRegionInHeader(Request> request, HttpResponse response) {
final String region = getServingRegionHeader(response);
AWSS3V4Signer v4Signer = buildSigV4Signer(region);
endpointResolver.resolveRequestEndpoint(request, region);
return buildRetryParams(v4Signer, request.getEndpoint());
}
/**
* If the response doesn't have the x-amz-region header we have to resort to sending a request
* to s3-external-1
*
* @return
*/
private AuthRetryParameters redirectToS3External() {
AWSS3V4Signer v4Signer = buildSigV4Signer(Regions.US_EAST_1.getName());
try {
URI bucketEndpoint = new URI(
String.format("https://%s.s3-external-1.amazonaws.com", endpointResolver.getBucketName()));
return buildRetryParams(v4Signer, bucketEndpoint);
} catch (URISyntaxException e) {
throw new SdkClientException(
"Failed to re-send the request to \"s3-external-1.amazonaws.com\". " + V4_REGION_WARNING, e);
}
}
private AWSS3V4Signer buildSigV4Signer(final String region) {
AWSS3V4Signer v4Signer = new AWSS3V4Signer();
v4Signer.setRegionName(region);
v4Signer.setServiceName(AmazonS3Client.S3_SERVICE_NAME);
return v4Signer;
}
private AuthRetryParameters buildRetryParams(AWSS3V4Signer signer, URI endpoint) {
log.warn("Attempting to re-send the request to " + endpoint.getHost() + " with AWS V4 authentication. "
+ "To avoid this warning in the future, " + V4_REGION_WARNING);
return new AuthRetryParameters(signer, endpoint);
}
private static boolean hasServingRegionHeader(HttpResponse response) {
return !StringUtils.isNullOrEmpty(getServingRegionHeader(response));
}
private static String getServingRegionHeader(HttpResponse response) {
return response.getHeaders().get(Headers.S3_SERVING_REGION);
}
}