com.amazonaws.services.s3.AmazonS3Client Maven / Gradle / Ivy
Show all versions of aws-java-sdk-s3 Show documentation
/*
* 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;
import static com.amazonaws.event.SDKProgressPublisher.publishProgress;
import static com.amazonaws.internal.ResettableInputStream.newResettableInputStream;
import static com.amazonaws.services.s3.Headers.TRANSITION_DEFAULT_MINIMUM_OBJECT_SIZE;
import static com.amazonaws.services.s3.model.S3DataSource.Utils.cleanupDataSource;
import static com.amazonaws.util.LengthCheckInputStream.EXCLUDE_SKIPPED_BYTES;
import static com.amazonaws.util.LengthCheckInputStream.INCLUDE_SKIPPED_BYTES;
import static com.amazonaws.util.Throwables.failure;
import static com.amazonaws.util.ValidationUtils.assertNotNull;
import static com.amazonaws.util.ValidationUtils.assertStringNotEmpty;
import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.AmazonServiceException.ErrorType;
import com.amazonaws.AmazonWebServiceClient;
import com.amazonaws.AmazonWebServiceRequest;
import com.amazonaws.AmazonWebServiceResponse;
import com.amazonaws.ClientConfiguration;
import com.amazonaws.DefaultRequest;
import com.amazonaws.HttpMethod;
import com.amazonaws.Protocol;
import com.amazonaws.Request;
import com.amazonaws.RequestConfig;
import com.amazonaws.ResetException;
import com.amazonaws.Response;
import com.amazonaws.SDKGlobalConfiguration;
import com.amazonaws.SdkClientException;
import com.amazonaws.annotation.SdkInternalApi;
import com.amazonaws.annotation.SdkTestInternalApi;
import com.amazonaws.annotation.ThreadSafe;
import com.amazonaws.arn.Arn;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.Presigner;
import com.amazonaws.auth.ServiceAwareSigner;
import com.amazonaws.auth.Signer;
import com.amazonaws.auth.SignerFactory;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.event.ProgressEventType;
import com.amazonaws.event.ProgressInputStream;
import com.amazonaws.event.ProgressListener;
import com.amazonaws.handlers.HandlerChainFactory;
import com.amazonaws.handlers.HandlerContextKey;
import com.amazonaws.handlers.RequestHandler2;
import com.amazonaws.http.ExecutionContext;
import com.amazonaws.http.HttpMethodName;
import com.amazonaws.http.HttpResponseHandler;
import com.amazonaws.internal.AmazonWebServiceRequestAdapter;
import com.amazonaws.internal.DefaultServiceEndpointBuilder;
import com.amazonaws.internal.IdentityEndpointBuilder;
import com.amazonaws.internal.ReleasableInputStream;
import com.amazonaws.internal.ResettableInputStream;
import com.amazonaws.internal.SdkFilterInputStream;
import com.amazonaws.internal.ServiceEndpointBuilder;
import com.amazonaws.internal.StaticCredentialsProvider;
import com.amazonaws.internal.auth.NoOpSignerProvider;
import com.amazonaws.internal.auth.SignerProvider;
import com.amazonaws.metrics.AwsSdkMetrics;
import com.amazonaws.metrics.RequestMetricCollector;
import com.amazonaws.regions.RegionUtils;
import com.amazonaws.regions.Regions;
import com.amazonaws.retry.PredefinedRetryPolicies;
import com.amazonaws.retry.RetryPolicy;
import com.amazonaws.services.s3.internal.AWSS3V4Signer;
import com.amazonaws.services.s3.internal.BucketLifecycleConfigurationHeaderHandler;
import com.amazonaws.services.s3.internal.BucketNameUtils;
import com.amazonaws.services.s3.internal.CompleteMultipartUploadRetryCondition;
import com.amazonaws.services.s3.internal.Constants;
import com.amazonaws.services.s3.internal.DeleteObjectTaggingHeaderHandler;
import com.amazonaws.services.s3.internal.DeleteObjectsResponse;
import com.amazonaws.services.s3.internal.DigestValidationInputStream;
import com.amazonaws.services.s3.internal.DualstackEndpointBuilder;
import com.amazonaws.services.s3.internal.GetObjectTaggingResponseHeaderHandler;
import com.amazonaws.services.s3.internal.InitiateMultipartUploadHeaderHandler;
import com.amazonaws.services.s3.internal.InputSubstream;
import com.amazonaws.services.s3.internal.ListPartsHeaderHandler;
import com.amazonaws.services.s3.internal.MD5DigestCalculatingInputStream;
import com.amazonaws.services.s3.internal.Mimetypes;
import com.amazonaws.services.s3.internal.MultiFileOutputStream;
import com.amazonaws.services.s3.internal.ObjectExpirationHeaderHandler;
import com.amazonaws.services.s3.internal.RegionalEndpointsOptionResolver;
import com.amazonaws.services.s3.internal.ResponseHeaderHandlerChain;
import com.amazonaws.services.s3.internal.S3AbortableInputStream;
import com.amazonaws.services.s3.internal.S3AccessPointBuilder;
import com.amazonaws.services.s3.internal.S3ObjectLambdaOperationEndpointBuilder;
import com.amazonaws.services.s3.internal.S3ObjectLambdaEndpointBuilder;
import com.amazonaws.services.s3.internal.S3ErrorResponseHandler;
import com.amazonaws.services.s3.internal.S3MetadataResponseHandler;
import com.amazonaws.services.s3.internal.S3ObjectResponseHandler;
import com.amazonaws.services.s3.internal.S3OutpostAccessPointBuilder;
import com.amazonaws.services.s3.internal.S3OutpostResource;
import com.amazonaws.services.s3.internal.S3QueryStringSigner;
import com.amazonaws.services.s3.internal.S3RequestEndpointResolver;
import com.amazonaws.services.s3.internal.S3RequesterChargedHeaderHandler;
import com.amazonaws.services.s3.internal.S3RestoreOutputPathHeaderHandler;
import com.amazonaws.services.s3.internal.S3Signer;
import com.amazonaws.services.s3.internal.S3StringResponseHandler;
import com.amazonaws.services.s3.internal.S3V4AuthErrorRetryStrategy;
import com.amazonaws.services.s3.internal.S3VersionHeaderHandler;
import com.amazonaws.services.s3.internal.S3XmlResponseHandler;
import com.amazonaws.services.s3.internal.ServerSideEncryptionHeaderHandler;
import com.amazonaws.services.s3.internal.ServiceUtils;
import com.amazonaws.services.s3.internal.SetObjectTaggingResponseHeaderHandler;
import com.amazonaws.services.s3.internal.SkipMd5CheckStrategy;
import com.amazonaws.services.s3.internal.UploadObjectStrategy;
import com.amazonaws.services.s3.internal.UseArnRegionResolver;
import com.amazonaws.services.s3.internal.XmlWriter;
import com.amazonaws.services.s3.internal.auth.S3SignerProvider;
import com.amazonaws.services.s3.metrics.S3ServiceMetric;
import com.amazonaws.services.s3.model.AbortMultipartUploadRequest;
import com.amazonaws.services.s3.model.AccessControlList;
import com.amazonaws.services.s3.model.AmazonS3Exception;
import com.amazonaws.services.s3.model.Bucket;
import com.amazonaws.services.s3.model.BucketAccelerateConfiguration;
import com.amazonaws.services.s3.model.BucketCrossOriginConfiguration;
import com.amazonaws.services.s3.model.BucketLifecycleConfiguration;
import com.amazonaws.services.s3.model.BucketLoggingConfiguration;
import com.amazonaws.services.s3.model.BucketNotificationConfiguration;
import com.amazonaws.services.s3.model.BucketPolicy;
import com.amazonaws.services.s3.model.BucketReplicationConfiguration;
import com.amazonaws.services.s3.model.BucketTaggingConfiguration;
import com.amazonaws.services.s3.model.BucketVersioningConfiguration;
import com.amazonaws.services.s3.model.BucketWebsiteConfiguration;
import com.amazonaws.services.s3.model.CannedAccessControlList;
import com.amazonaws.services.s3.model.CompleteMultipartUploadRequest;
import com.amazonaws.services.s3.model.CompleteMultipartUploadResult;
import com.amazonaws.services.s3.model.CopyObjectRequest;
import com.amazonaws.services.s3.model.CopyObjectResult;
import com.amazonaws.services.s3.model.CopyPartRequest;
import com.amazonaws.services.s3.model.CopyPartResult;
import com.amazonaws.services.s3.model.CreateBucketRequest;
import com.amazonaws.services.s3.model.DeleteBucketAnalyticsConfigurationRequest;
import com.amazonaws.services.s3.model.DeleteBucketAnalyticsConfigurationResult;
import com.amazonaws.services.s3.model.DeleteBucketCrossOriginConfigurationRequest;
import com.amazonaws.services.s3.model.DeleteBucketEncryptionRequest;
import com.amazonaws.services.s3.model.DeleteBucketEncryptionResult;
import com.amazonaws.services.s3.model.DeleteBucketIntelligentTieringConfigurationRequest;
import com.amazonaws.services.s3.model.DeleteBucketIntelligentTieringConfigurationResult;
import com.amazonaws.services.s3.model.DeleteBucketInventoryConfigurationRequest;
import com.amazonaws.services.s3.model.DeleteBucketInventoryConfigurationResult;
import com.amazonaws.services.s3.model.DeleteBucketLifecycleConfigurationRequest;
import com.amazonaws.services.s3.model.DeleteBucketMetricsConfigurationRequest;
import com.amazonaws.services.s3.model.DeleteBucketMetricsConfigurationResult;
import com.amazonaws.services.s3.model.DeleteBucketOwnershipControlsRequest;
import com.amazonaws.services.s3.model.DeleteBucketOwnershipControlsResult;
import com.amazonaws.services.s3.model.DeleteBucketPolicyRequest;
import com.amazonaws.services.s3.model.DeleteBucketReplicationConfigurationRequest;
import com.amazonaws.services.s3.model.DeleteBucketRequest;
import com.amazonaws.services.s3.model.DeleteBucketTaggingConfigurationRequest;
import com.amazonaws.services.s3.model.DeleteBucketWebsiteConfigurationRequest;
import com.amazonaws.services.s3.model.DeleteObjectRequest;
import com.amazonaws.services.s3.model.DeleteObjectTaggingRequest;
import com.amazonaws.services.s3.model.DeleteObjectTaggingResult;
import com.amazonaws.services.s3.model.DeleteObjectsRequest;
import com.amazonaws.services.s3.model.DeleteObjectsResult;
import com.amazonaws.services.s3.model.DeletePublicAccessBlockRequest;
import com.amazonaws.services.s3.model.DeletePublicAccessBlockResult;
import com.amazonaws.services.s3.model.DeleteVersionRequest;
import com.amazonaws.services.s3.model.ExpectedBucketOwnerRequest;
import com.amazonaws.services.s3.model.ExpectedSourceBucketOwnerRequest;
import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest;
import com.amazonaws.services.s3.model.GenericBucketRequest;
import com.amazonaws.services.s3.model.GetBucketAccelerateConfigurationRequest;
import com.amazonaws.services.s3.model.GetBucketAclRequest;
import com.amazonaws.services.s3.model.GetBucketAnalyticsConfigurationRequest;
import com.amazonaws.services.s3.model.GetBucketAnalyticsConfigurationResult;
import com.amazonaws.services.s3.model.GetBucketCrossOriginConfigurationRequest;
import com.amazonaws.services.s3.model.GetBucketEncryptionRequest;
import com.amazonaws.services.s3.model.GetBucketEncryptionResult;
import com.amazonaws.services.s3.model.GetBucketIntelligentTieringConfigurationRequest;
import com.amazonaws.services.s3.model.GetBucketIntelligentTieringConfigurationResult;
import com.amazonaws.services.s3.model.GetBucketInventoryConfigurationRequest;
import com.amazonaws.services.s3.model.GetBucketInventoryConfigurationResult;
import com.amazonaws.services.s3.model.GetBucketLifecycleConfigurationRequest;
import com.amazonaws.services.s3.model.GetBucketLocationRequest;
import com.amazonaws.services.s3.model.GetBucketLoggingConfigurationRequest;
import com.amazonaws.services.s3.model.GetBucketMetricsConfigurationRequest;
import com.amazonaws.services.s3.model.GetBucketMetricsConfigurationResult;
import com.amazonaws.services.s3.model.GetBucketNotificationConfigurationRequest;
import com.amazonaws.services.s3.model.GetBucketOwnershipControlsRequest;
import com.amazonaws.services.s3.model.GetBucketOwnershipControlsResult;
import com.amazonaws.services.s3.model.GetBucketPolicyRequest;
import com.amazonaws.services.s3.model.GetBucketPolicyStatusRequest;
import com.amazonaws.services.s3.model.GetBucketPolicyStatusResult;
import com.amazonaws.services.s3.model.GetBucketReplicationConfigurationRequest;
import com.amazonaws.services.s3.model.GetBucketTaggingConfigurationRequest;
import com.amazonaws.services.s3.model.GetBucketVersioningConfigurationRequest;
import com.amazonaws.services.s3.model.GetBucketWebsiteConfigurationRequest;
import com.amazonaws.services.s3.model.GetObjectAclRequest;
import com.amazonaws.services.s3.model.GetObjectLegalHoldRequest;
import com.amazonaws.services.s3.model.GetObjectLegalHoldResult;
import com.amazonaws.services.s3.model.GetObjectLockConfigurationRequest;
import com.amazonaws.services.s3.model.GetObjectLockConfigurationResult;
import com.amazonaws.services.s3.model.GetObjectMetadataRequest;
import com.amazonaws.services.s3.model.GetObjectRequest;
import com.amazonaws.services.s3.model.GetObjectRetentionRequest;
import com.amazonaws.services.s3.model.GetObjectRetentionResult;
import com.amazonaws.services.s3.model.GetObjectTaggingRequest;
import com.amazonaws.services.s3.model.GetObjectTaggingResult;
import com.amazonaws.services.s3.model.GetPublicAccessBlockRequest;
import com.amazonaws.services.s3.model.GetPublicAccessBlockResult;
import com.amazonaws.services.s3.model.GetRequestPaymentConfigurationRequest;
import com.amazonaws.services.s3.model.GetS3AccountOwnerRequest;
import com.amazonaws.services.s3.model.Grant;
import com.amazonaws.services.s3.model.Grantee;
import com.amazonaws.services.s3.model.GroupGrantee;
import com.amazonaws.services.s3.model.HeadBucketRequest;
import com.amazonaws.services.s3.model.HeadBucketResult;
import com.amazonaws.services.s3.model.InitiateMultipartUploadRequest;
import com.amazonaws.services.s3.model.InitiateMultipartUploadResult;
import com.amazonaws.services.s3.model.ListBucketAnalyticsConfigurationsRequest;
import com.amazonaws.services.s3.model.ListBucketAnalyticsConfigurationsResult;
import com.amazonaws.services.s3.model.ListBucketIntelligentTieringConfigurationsRequest;
import com.amazonaws.services.s3.model.ListBucketIntelligentTieringConfigurationsResult;
import com.amazonaws.services.s3.model.ListBucketInventoryConfigurationsRequest;
import com.amazonaws.services.s3.model.ListBucketInventoryConfigurationsResult;
import com.amazonaws.services.s3.model.ListBucketMetricsConfigurationsRequest;
import com.amazonaws.services.s3.model.ListBucketMetricsConfigurationsResult;
import com.amazonaws.services.s3.model.ListBucketsPaginatedRequest;
import com.amazonaws.services.s3.model.ListBucketsPaginatedResult;
import com.amazonaws.services.s3.model.ListBucketsRequest;
import com.amazonaws.services.s3.model.ListMultipartUploadsRequest;
import com.amazonaws.services.s3.model.ListNextBatchOfObjectsRequest;
import com.amazonaws.services.s3.model.ListNextBatchOfVersionsRequest;
import com.amazonaws.services.s3.model.ListObjectsRequest;
import com.amazonaws.services.s3.model.ListObjectsV2Request;
import com.amazonaws.services.s3.model.ListObjectsV2Result;
import com.amazonaws.services.s3.model.ListPartsRequest;
import com.amazonaws.services.s3.model.ListVersionsRequest;
import com.amazonaws.services.s3.model.MultiFactorAuthentication;
import com.amazonaws.services.s3.model.MultiObjectDeleteException;
import com.amazonaws.services.s3.model.MultiObjectDeleteSlowdownException;
import com.amazonaws.services.s3.model.MultipartUploadListing;
import com.amazonaws.services.s3.model.ObjectListing;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.ObjectTagging;
import com.amazonaws.services.s3.model.Owner;
import com.amazonaws.services.s3.model.PartETag;
import com.amazonaws.services.s3.model.PartListing;
import com.amazonaws.services.s3.model.Permission;
import com.amazonaws.services.s3.model.PresignedUrlDownloadRequest;
import com.amazonaws.services.s3.model.PresignedUrlDownloadResult;
import com.amazonaws.services.s3.model.PresignedUrlUploadRequest;
import com.amazonaws.services.s3.model.PresignedUrlUploadResult;
import com.amazonaws.services.s3.model.PublicAccessBlockConfiguration;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.amazonaws.services.s3.model.PutObjectResult;
import com.amazonaws.services.s3.model.Region;
import com.amazonaws.services.s3.model.RequestPaymentConfiguration;
import com.amazonaws.services.s3.model.RequestPaymentConfiguration.Payer;
import com.amazonaws.services.s3.model.ResponseHeaderOverrides;
import com.amazonaws.services.s3.model.RestoreObjectRequest;
import com.amazonaws.services.s3.model.RestoreObjectResult;
import com.amazonaws.services.s3.model.RestoreRequestType;
import com.amazonaws.services.s3.model.S3AccelerateUnsupported;
import com.amazonaws.services.s3.model.S3DataSource;
import com.amazonaws.services.s3.model.S3Object;
import com.amazonaws.services.s3.model.S3ObjectInputStream;
import com.amazonaws.services.s3.model.SSEAwsKeyManagementParams;
import com.amazonaws.services.s3.model.SSEAwsKeyManagementParamsProvider;
import com.amazonaws.services.s3.model.SSECustomerKey;
import com.amazonaws.services.s3.model.SSECustomerKeyProvider;
import com.amazonaws.services.s3.model.SelectObjectContentEventStream;
import com.amazonaws.services.s3.model.SelectObjectContentRequest;
import com.amazonaws.services.s3.model.SelectObjectContentResult;
import com.amazonaws.services.s3.model.ServerSideEncryptionConfiguration;
import com.amazonaws.services.s3.model.SetBucketAccelerateConfigurationRequest;
import com.amazonaws.services.s3.model.SetBucketAclRequest;
import com.amazonaws.services.s3.model.SetBucketAnalyticsConfigurationRequest;
import com.amazonaws.services.s3.model.SetBucketAnalyticsConfigurationResult;
import com.amazonaws.services.s3.model.SetBucketCrossOriginConfigurationRequest;
import com.amazonaws.services.s3.model.SetBucketEncryptionRequest;
import com.amazonaws.services.s3.model.SetBucketEncryptionResult;
import com.amazonaws.services.s3.model.SetBucketIntelligentTieringConfigurationRequest;
import com.amazonaws.services.s3.model.SetBucketIntelligentTieringConfigurationResult;
import com.amazonaws.services.s3.model.SetBucketInventoryConfigurationRequest;
import com.amazonaws.services.s3.model.SetBucketInventoryConfigurationResult;
import com.amazonaws.services.s3.model.SetBucketLifecycleConfigurationRequest;
import com.amazonaws.services.s3.model.SetBucketLoggingConfigurationRequest;
import com.amazonaws.services.s3.model.SetBucketMetricsConfigurationRequest;
import com.amazonaws.services.s3.model.SetBucketMetricsConfigurationResult;
import com.amazonaws.services.s3.model.SetBucketNotificationConfigurationRequest;
import com.amazonaws.services.s3.model.SetBucketOwnershipControlsRequest;
import com.amazonaws.services.s3.model.SetBucketOwnershipControlsResult;
import com.amazonaws.services.s3.model.SetBucketPolicyRequest;
import com.amazonaws.services.s3.model.SetBucketReplicationConfigurationRequest;
import com.amazonaws.services.s3.model.SetBucketTaggingConfigurationRequest;
import com.amazonaws.services.s3.model.SetBucketVersioningConfigurationRequest;
import com.amazonaws.services.s3.model.SetBucketWebsiteConfigurationRequest;
import com.amazonaws.services.s3.model.SetObjectAclRequest;
import com.amazonaws.services.s3.model.SetObjectLegalHoldRequest;
import com.amazonaws.services.s3.model.SetObjectLegalHoldResult;
import com.amazonaws.services.s3.model.SetObjectLockConfigurationRequest;
import com.amazonaws.services.s3.model.SetObjectLockConfigurationResult;
import com.amazonaws.services.s3.model.SetObjectRetentionRequest;
import com.amazonaws.services.s3.model.SetObjectRetentionResult;
import com.amazonaws.services.s3.model.SetObjectTaggingRequest;
import com.amazonaws.services.s3.model.SetObjectTaggingResult;
import com.amazonaws.services.s3.model.SetPublicAccessBlockRequest;
import com.amazonaws.services.s3.model.SetPublicAccessBlockResult;
import com.amazonaws.services.s3.model.SetRequestPaymentConfigurationRequest;
import com.amazonaws.services.s3.model.StorageClass;
import com.amazonaws.services.s3.model.Tag;
import com.amazonaws.services.s3.model.TransitionDefaultMinimumObjectSize;
import com.amazonaws.services.s3.model.UploadObjectRequest;
import com.amazonaws.services.s3.model.UploadPartRequest;
import com.amazonaws.services.s3.model.UploadPartResult;
import com.amazonaws.services.s3.model.VersionListing;
import com.amazonaws.services.s3.model.WriteGetObjectResponseRequest;
import com.amazonaws.services.s3.model.WriteGetObjectResponseResult;
import com.amazonaws.services.s3.model.analytics.AnalyticsConfiguration;
import com.amazonaws.services.s3.model.intelligenttiering.IntelligentTieringConfiguration;
import com.amazonaws.services.s3.model.inventory.InventoryConfiguration;
import com.amazonaws.services.s3.model.metrics.MetricsConfiguration;
import com.amazonaws.services.s3.model.ownership.OwnershipControls;
import com.amazonaws.services.s3.model.transform.AclXmlFactory;
import com.amazonaws.services.s3.model.transform.BucketConfigurationXmlFactory;
import com.amazonaws.services.s3.model.transform.BucketNotificationConfigurationStaxUnmarshaller;
import com.amazonaws.services.s3.model.transform.GetBucketEncryptionStaxUnmarshaller;
import com.amazonaws.services.s3.model.transform.GetBucketPolicyStatusStaxUnmarshaller;
import com.amazonaws.services.s3.model.transform.GetPublicAccessBlockStaxUnmarshaller;
import com.amazonaws.services.s3.model.transform.HeadBucketResultHandler;
import com.amazonaws.services.s3.model.transform.MultiObjectDeleteXmlFactory;
import com.amazonaws.services.s3.model.transform.ObjectLockConfigurationXmlFactory;
import com.amazonaws.services.s3.model.transform.ObjectLockLegalHoldXmlFactory;
import com.amazonaws.services.s3.model.transform.ObjectLockRetentionXmlFactory;
import com.amazonaws.services.s3.model.transform.ObjectTaggingXmlFactory;
import com.amazonaws.services.s3.model.transform.RequestPaymentConfigurationXmlFactory;
import com.amazonaws.services.s3.model.transform.RequestXmlFactory;
import com.amazonaws.services.s3.model.transform.Unmarshallers;
import com.amazonaws.services.s3.model.transform.XmlResponsesSaxParser.CompleteMultipartUploadHandler;
import com.amazonaws.services.s3.model.transform.XmlResponsesSaxParser.CopyObjectResultHandler;
import com.amazonaws.services.s3.request.S3HandlerContextKeys;
import com.amazonaws.services.s3.waiters.AmazonS3Waiters;
import com.amazonaws.transform.Unmarshaller;
import com.amazonaws.util.AWSRequestMetrics;
import com.amazonaws.util.AWSRequestMetrics.Field;
import com.amazonaws.util.AwsHostNameUtils;
import com.amazonaws.util.Base16;
import com.amazonaws.util.Base64;
import com.amazonaws.util.BinaryUtils;
import com.amazonaws.util.CredentialUtils;
import com.amazonaws.util.DateUtils;
import com.amazonaws.util.HostnameValidator;
import com.amazonaws.util.IOUtils;
import com.amazonaws.util.LengthCheckInputStream;
import com.amazonaws.util.Md5Utils;
import com.amazonaws.util.RuntimeHttpUtils;
import com.amazonaws.util.SdkHttpUtils;
import com.amazonaws.util.ServiceClientHolderInputStream;
import com.amazonaws.util.StringUtils;
import com.amazonaws.util.UriResourcePathUtils;
import com.amazonaws.util.ValidationUtils;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.regex.Matcher;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.ContentType;
/**
*
* Provides the client for accessing the Amazon S3 web service.
*
*
* Amazon S3 provides storage for the Internet,
* and is designed to make web-scale computing easier for developers.
*
*
* The Amazon S3 Java Client provides a simple interface that can be
* used to store and retrieve any amount of data, at any time,
* from anywhere on the web. It gives any developer access to the same
* highly scalable, reliable, secure, fast, inexpensive infrastructure
* that Amazon uses to run its own global network of web sites.
* The service aims to maximize benefits of scale and to pass those
* benefits on to developers.
*
*
* For more information about Amazon S3, please see
*
* http://aws.amazon.com/s3
*
*/
@ThreadSafe
public class AmazonS3Client extends AmazonWebServiceClient implements AmazonS3 {
public static final String S3_SERVICE_NAME = "s3";
private static final String S3_SIGNER = "S3SignerType";
private static final String S3_V4_SIGNER = "AWSS3V4SignerType";
private static final String SERVICE_ID = "S3";
private static final String AWS_PARTITION_KEY = "aws";
private static final String S3_OUTPOSTS_NAME = "s3-outposts";
private static final String S3_OBJECT_LAMBDAS_NAME = "s3-object-lambda";
protected static final AmazonS3ClientConfigurationFactory configFactory
= new AmazonS3ClientConfigurationFactory();
/** Shared logger for client events */
private static Log log = LogFactory.getLog(AmazonS3Client.class);
static {
// Enable S3 specific predefined request metrics.
AwsSdkMetrics.addAll(Arrays.asList(S3ServiceMetric.values()));
// Register S3-specific signers.
SignerFactory.registerSigner(S3_SIGNER, S3Signer.class);
SignerFactory.registerSigner(S3_V4_SIGNER, AWSS3V4Signer.class);
}
private volatile AmazonS3Waiters waiters;
/** Provider for Amazon Web Services credentials. */
protected final AWSCredentialsProvider awsCredentialsProvider;
/** Responsible for handling error responses from all S3 service calls. */
protected final S3ErrorResponseHandler errorResponseHandler;
/** Shared response handler for operations with no response. */
private final S3XmlResponseHandler voidResponseHandler = new S3XmlResponseHandler(null);
/** Shared factory for converting configuration objects to XML */
private static final BucketConfigurationXmlFactory bucketConfigurationXmlFactory = new BucketConfigurationXmlFactory();
/** Shared factory for converting request payment configuration objects to XML */
private static final RequestPaymentConfigurationXmlFactory requestPaymentConfigurationXmlFactory = new RequestPaymentConfigurationXmlFactory();
private static final UseArnRegionResolver USE_ARN_REGION_RESOLVER = new UseArnRegionResolver();
/** S3 specific client configuration options */
private volatile S3ClientOptions clientOptions = S3ClientOptions.builder().build();
/**
* The S3 client region that is set by either (a) calling
* setRegion/configureRegion OR (b) calling setEndpoint with a
* region-specific S3 endpoint. This region string will be used for signing
* requests sent by this client.
*/
private volatile String clientRegion;
private static RegionalEndpointsOptionResolver REGIONAL_ENDPOINTS_OPTION_RESOLVER = new RegionalEndpointsOptionResolver();
private static final int BUCKET_REGION_CACHE_SIZE = 300;
private static final Map bucketRegionCache =
Collections.synchronizedMap(new LinkedHashMap(BUCKET_REGION_CACHE_SIZE, 1.1f, true) {
private static final long serialVersionUID = 23453L;
@Override
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > BUCKET_REGION_CACHE_SIZE;
}
});
static Map getBucketRegionCache() {
return bucketRegionCache;
}
private final SkipMd5CheckStrategy skipMd5CheckStrategy;
private final CompleteMultipartUploadRetryCondition
completeMultipartUploadRetryCondition = new CompleteMultipartUploadRetryCondition();
/**
* Constructs a new client to invoke service methods on Amazon S3. A
* credentials provider chain will be used that searches for credentials in
* this order:
*
* - Environment Variables - AWS_ACCESS_KEY_ID and AWS_SECRET_KEY
* - Java System Properties - aws.accessKeyId and aws.secretKey
* - Credential profiles file at the default location (~/.aws/credentials) shared by all Amazon Web Services SDKs
* and the Amazon Web Services CLI
* - Instance Profile Credentials - delivered through the Amazon EC2
* metadata service
*
*
*
* If no credentials are found in the chain, this client will attempt to
* work in an anonymous mode where requests aren't signed. Only a subset of
* the Amazon S3 API will work with anonymous (i.e. unsigned) requests,
* but this can prove useful in some situations. For example:
*
* - If an Amazon S3 bucket has {@link Permission#Read} permission for the
* {@link GroupGrantee#AllUsers} group, anonymous clients can call
* {@link #listObjects(String)} to see what objects are stored in a bucket.
* - If an object has {@link Permission#Read} permission for the
* {@link GroupGrantee#AllUsers} group, anonymous clients can call
* {@link #String, String)} and
* {@link #getObjectMetadata(String, String)} to pull object content and
* metadata.
* - If a bucket has {@link Permission#Write} permission for the
* {@link GroupGrantee#AllUsers} group, anonymous clients can upload objects
* to the bucket.
*
*
*
* You can force the client to operate in an anonymous mode, and skip the credentials
* provider chain, by passing in null
for the credentials.
*
*
* @see AmazonS3Client#AmazonS3Client(AWSCredentials)
* @see AmazonS3Client#AmazonS3Client(AWSCredentials, ClientConfiguration)
* @sample AmazonS3.CreateClient
* @deprecated use {@link AmazonS3ClientBuilder#defaultClient()}
*/
@Deprecated
public AmazonS3Client() {
this(new S3CredentialsProviderChain());
}
/**
* Constructs a new Amazon S3 client using the specified Amazon Web Services credentials to
* access Amazon S3.
*
* @param awsCredentials
* The Amazon Web Services credentials to use when making requests to Amazon S3
* with this client.
*
* @see AmazonS3Client#AmazonS3Client()
* @see AmazonS3Client#AmazonS3Client(AWSCredentials, ClientConfiguration)
* @deprecated use {@link AmazonS3ClientBuilder#withCredentials(AWSCredentialsProvider)}
*/
@Deprecated
public AmazonS3Client(AWSCredentials awsCredentials) {
this(awsCredentials, configFactory.getConfig());
}
/**
* Constructs a new Amazon S3 client using the specified Amazon Web Services credentials and
* client configuration to access Amazon S3.
*
* @param awsCredentials
* The Amazon Web Services credentials to use when making requests to Amazon S3
* with this client.
* @param clientConfiguration
* The client configuration options controlling how this client
* connects to Amazon S3 (e.g. proxy settings, retry counts, etc).
*
* @see AmazonS3Client#AmazonS3Client()
* @see AmazonS3Client#AmazonS3Client(AWSCredentials)
* @deprecated use {@link AmazonS3ClientBuilder#withCredentials(AWSCredentialsProvider)} and
* {@link AmazonS3ClientBuilder#withClientConfiguration(ClientConfiguration)}
*/
@Deprecated
public AmazonS3Client(AWSCredentials awsCredentials, ClientConfiguration clientConfiguration) {
this(new StaticCredentialsProvider(awsCredentials), clientConfiguration);
}
/**
* Constructs a new Amazon S3 client using the specified Amazon Web Services credentials
* provider to access Amazon S3.
*
* @param credentialsProvider
* The Amazon Web Services credentials provider which will provide credentials
* to authenticate requests with Amazon Web Services services.
* @deprecated use {@link AmazonS3ClientBuilder#withCredentials(AWSCredentialsProvider)}
*/
@Deprecated
public AmazonS3Client(AWSCredentialsProvider credentialsProvider) {
this(credentialsProvider, configFactory.getConfig());
}
/**
* Constructs a new Amazon S3 client using the specified Amazon Web Services credentials and
* client configuration to access Amazon S3.
*
* @param credentialsProvider
* The Amazon Web Services credentials provider which will provide credentials
* to authenticate requests with Amazon Web Services services.
* @param clientConfiguration
* The client configuration options controlling how this client
* connects to Amazon S3 (e.g. proxy settings, retry counts, etc).
* @deprecated use {@link AmazonS3ClientBuilder#withCredentials(AWSCredentialsProvider)} and
* {@link AmazonS3ClientBuilder#withClientConfiguration(ClientConfiguration)}
*/
@Deprecated
public AmazonS3Client(AWSCredentialsProvider credentialsProvider,
ClientConfiguration clientConfiguration) {
this(credentialsProvider, clientConfiguration, null);
}
/**
* Constructs a new Amazon S3 client using the specified Amazon Web Services credentials,
* client configuration and request metric collector to access Amazon S3.
*
* @param credentialsProvider
* The Amazon Web Services credentials provider which will provide credentials
* to authenticate requests with Amazon Web Services services.
* @param clientConfiguration
* The client configuration options controlling how this client
* connects to Amazon S3 (e.g. proxy settings, retry counts, etc).
* @param requestMetricCollector request metric collector
* @deprecated use {@link AmazonS3ClientBuilder#withCredentials(AWSCredentialsProvider)} and
* {@link AmazonS3ClientBuilder#withClientConfiguration(ClientConfiguration)} and
* {@link AmazonS3ClientBuilder#withMetricsCollector(RequestMetricCollector)}
*/
@Deprecated
public AmazonS3Client(AWSCredentialsProvider credentialsProvider,
ClientConfiguration clientConfiguration,
RequestMetricCollector requestMetricCollector) {
this(credentialsProvider, clientConfiguration, requestMetricCollector, SkipMd5CheckStrategy.INSTANCE);
}
/**
* Constructs a new Amazon S3 client using the specified Amazon Web Services credentials,
* client configuration and request metric collector to access Amazon S3.
*
* @param credentialsProvider
* The Amazon Web Services credentials provider which will provide credentials
* to authenticate requests with Amazon Web Services services.
* @param clientConfiguration
* The client configuration options controlling how this client
* connects to Amazon S3 (e.g. proxy settings, retry counts, etc).
* @param requestMetricCollector request metric collector
*/
@SdkTestInternalApi
AmazonS3Client(AWSCredentialsProvider credentialsProvider,
ClientConfiguration clientConfiguration,
RequestMetricCollector requestMetricCollector,
SkipMd5CheckStrategy skipMd5CheckStrategy) {
super(clientConfiguration, requestMetricCollector, true);
this.awsCredentialsProvider = credentialsProvider;
this.skipMd5CheckStrategy = skipMd5CheckStrategy;
this.errorResponseHandler = new S3ErrorResponseHandler(clientConfiguration);
init();
}
/**
* Constructs a new client using the specified client configuration to
* access Amazon S3. A credentials provider chain will be used that searches
* for credentials in this order:
*
* - Environment Variables - AWS_ACCESS_KEY_ID and AWS_SECRET_KEY
* - Java System Properties - aws.accessKeyId and aws.secretKey
* - Instance Profile Credentials - delivered through the Amazon EC2
* metadata service
*
*
*
* If no credentials are found in the chain, this client will attempt to
* work in an anonymous mode where requests aren't signed. Only a subset of
* the Amazon S3 API will work with anonymous (i.e. unsigned)
* requests, but this can prove useful in some situations. For example:
*
* - If an Amazon S3 bucket has {@link Permission#Read} permission for the
* {@link GroupGrantee#AllUsers} group, anonymous clients can call
* {@link #listObjects(String)} to see what objects are stored in a bucket.
* - If an object has {@link Permission#Read} permission for the
* {@link GroupGrantee#AllUsers} group, anonymous clients can call
* {@link #getObject(String, String)} and
* {@link #getObjectMetadata(String, String)} to pull object content and
* metadata.
* - If a bucket has {@link Permission#Write} permission for the
* {@link GroupGrantee#AllUsers} group, anonymous clients can upload objects
* to the bucket.
*
*
*
* You can force the client to operate in an anonymous mode, and skip the
* credentials provider chain, by passing in null
for the
* credentials.
*
*
* @param clientConfiguration
* The client configuration options controlling how this client
* connects to Amazon S3 (e.g. proxy settings, retry counts, etc).
*
* @see AmazonS3Client#AmazonS3Client(AWSCredentials)
* @see AmazonS3Client#AmazonS3Client(AWSCredentials, ClientConfiguration)
* @deprecated use {@link AmazonS3ClientBuilder#withClientConfiguration(ClientConfiguration)}
*/
@Deprecated
public AmazonS3Client(ClientConfiguration clientConfiguration) {
this(new S3CredentialsProviderChain(), clientConfiguration);
}
/**
* Constructs a new client to invoke service methods on S3 using the specified parameters. All
* service calls made using this new client object are blocking, and will not return until the
* service call completes.
*
* @param s3ClientParams Object providing S3 client parameters.
* @see AmazonS3ClientBuilder For a fluent way to construct a client.
*/
@SdkInternalApi
AmazonS3Client(AmazonS3ClientParams s3ClientParams) {
super(s3ClientParams.getClientParams());
this.awsCredentialsProvider = s3ClientParams.getClientParams().getCredentialsProvider();
this.skipMd5CheckStrategy = SkipMd5CheckStrategy.INSTANCE;
setS3ClientOptions(s3ClientParams.getS3ClientOptions());
this.errorResponseHandler = new S3ErrorResponseHandler(
s3ClientParams.getClientParams().getClientConfiguration());
init();
}
public static AmazonS3ClientBuilder builder() {
return AmazonS3ClientBuilder.standard();
}
private void init() {
// calling this.setEndpoint(...) will also modify the signer accordingly
setEndpoint(Constants.S3_HOSTNAME);
HandlerChainFactory chainFactory = new HandlerChainFactory();
requestHandler2s.addAll(chainFactory.newRequestHandlerChain(
"/com/amazonaws/services/s3/request.handlers"));
requestHandler2s.addAll(chainFactory.newRequestHandler2Chain(
"/com/amazonaws/services/s3/request.handler2s"));
requestHandler2s.addAll(chainFactory.getGlobalHandlers());
}
/**
* @deprecated use {@link AmazonS3ClientBuilder#setEndpointConfiguration(AwsClientBuilder.EndpointConfiguration)}
*/
@Override
@Deprecated
public synchronized void setEndpoint(String endpoint) {
if (ServiceUtils.isS3AccelerateEndpoint(endpoint)) {
throw new IllegalStateException("To enable accelerate mode, please use AmazonS3ClientBuilder.withAccelerateModeEnabled(true)");
} else {
super.setEndpoint(endpoint);
/*
* Extract the region string from the endpoint if it's not known to be a
* global S3 endpoint.
*/
if (!ServiceUtils.isS3USStandardEndpoint(endpoint)) {
clientRegion = AwsHostNameUtils.parseRegionName(this.endpoint.getHost(), S3_SERVICE_NAME);
}
}
}
/**
* @deprecated use {@link AmazonS3ClientBuilder#setRegion(String)}
*/
@Override
@Deprecated
public synchronized void setRegion(com.amazonaws.regions.Region region) {
if (region.getName().equalsIgnoreCase("us-east-1")) {
if (clientOptions.isRegionalUsEast1EndpointEnabled() || REGIONAL_ENDPOINTS_OPTION_RESOLVER.useRegionalMode()) {
region = RegionUtils.getRegion("us-east-1-regional");
}
}
super.setRegion(region);
/*
* We need to preserve the user provided region. This is because the
* region might be mapped to a global s3 endpoint (e.g. when the client
* is in accelerate mode), in which case we won't be able to extract the
* region back from the endpoint during request signing phase.
*/
clientRegion = region.getName();
}
/**
*
* Override the default S3 client options for this client. Also set the
* endpoint to s3-accelerate if such is specified in the S3 client options.
*
*
* @param clientOptions
* The S3 client options to use.
*/
@Override
public synchronized void setS3ClientOptions(S3ClientOptions clientOptions) {
checkMutability();
this.clientOptions = new S3ClientOptions(clientOptions);
}
/**
* S3 uses wildcard certificates so we have to disable strict hostname verification when using
* SSL.
*/
@Override
protected boolean useStrictHostNameVerification() {
return false;
}
@Override
public VersionListing listNextBatchOfVersions(VersionListing previousVersionListing)
throws SdkClientException, AmazonServiceException {
return listNextBatchOfVersions(new ListNextBatchOfVersionsRequest(previousVersionListing));
}
@Override
public VersionListing listNextBatchOfVersions(ListNextBatchOfVersionsRequest listNextBatchOfVersionsRequest) {
listNextBatchOfVersionsRequest = beforeClientExecution(listNextBatchOfVersionsRequest);
rejectNull(listNextBatchOfVersionsRequest,
"The request object parameter must be specified when listing the next batch of versions in a bucket");
VersionListing previousVersionListing = listNextBatchOfVersionsRequest.getPreviousVersionListing();
if (!previousVersionListing.isTruncated()) {
VersionListing emptyListing = new VersionListing();
emptyListing.setBucketName(previousVersionListing.getBucketName());
emptyListing.setDelimiter(previousVersionListing.getDelimiter());
emptyListing.setKeyMarker(previousVersionListing.getNextKeyMarker());
emptyListing.setVersionIdMarker(previousVersionListing.getNextVersionIdMarker());
emptyListing.setMaxKeys(previousVersionListing.getMaxKeys());
emptyListing.setPrefix(previousVersionListing.getPrefix());
emptyListing.setEncodingType(previousVersionListing.getEncodingType());
emptyListing.setTruncated(false);
return emptyListing;
}
return listVersions(listNextBatchOfVersionsRequest.toListVersionsRequest());
}
@Override
public VersionListing listVersions(String bucketName, String prefix)
throws SdkClientException, AmazonServiceException {
return listVersions(new ListVersionsRequest(bucketName, prefix, null, null, null, null));
}
@Override
public VersionListing listVersions(String bucketName, String prefix, String keyMarker, String versionIdMarker, String delimiter, Integer maxKeys)
throws SdkClientException, AmazonServiceException {
ListVersionsRequest request = new ListVersionsRequest()
.withBucketName(bucketName)
.withPrefix(prefix)
.withDelimiter(delimiter)
.withKeyMarker(keyMarker)
.withVersionIdMarker(versionIdMarker)
.withMaxResults(maxKeys);
return listVersions(request);
}
@Override
public VersionListing listVersions(ListVersionsRequest listVersionsRequest)
throws SdkClientException, AmazonServiceException {
listVersionsRequest = beforeClientExecution(listVersionsRequest);
rejectNull(listVersionsRequest.getBucketName(), "The bucket name parameter must be specified when listing versions in a bucket");
/**
* This flag shows whether we need to url decode S3 key names. This flag is enabled
* only when the customers don't explicitly call {@link listVersionsRequest#setEncodingType(String)},
* otherwise, it will be disabled for maintaining backwards compatibility.
*/
final boolean shouldSDKDecodeResponse = listVersionsRequest.getEncodingType() == null;
Request request = createRequest(listVersionsRequest.getBucketName(), null, listVersionsRequest, HttpMethodName.GET);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "ListObjectVersions");
request.addParameter("versions", null);
addParameterIfNotNull(request, "prefix", listVersionsRequest.getPrefix());
addParameterIfNotNull(request, "key-marker", listVersionsRequest.getKeyMarker());
addParameterIfNotNull(request, "version-id-marker", listVersionsRequest.getVersionIdMarker());
addParameterIfNotNull(request, "delimiter", listVersionsRequest.getDelimiter());
addStringListHeader(request, Headers.OPTIONAL_OBJECT_ATTRIBUTE, listVersionsRequest.getOptionalObjectAttributes());
if (listVersionsRequest.getMaxResults() != null && listVersionsRequest.getMaxResults() >= 0) request.addParameter("max-keys", listVersionsRequest.getMaxResults().toString());
request.addParameter("encoding-type", shouldSDKDecodeResponse ? Constants.URL_ENCODING : listVersionsRequest.getEncodingType());
populateRequesterPaysHeader(request, listVersionsRequest.isRequesterPays());
@SuppressWarnings("unchecked")
ResponseHeaderHandlerChain responseHandler =
new ResponseHeaderHandlerChain(
// xml payload unmarshaller
new Unmarshallers.VersionListUnmarshaller(shouldSDKDecodeResponse),
// header handler
new S3RequesterChargedHeaderHandler());
return invoke(request, responseHandler, listVersionsRequest.getBucketName(), null);
}
@Override
public ObjectListing listObjects(String bucketName)
throws SdkClientException, AmazonServiceException {
return listObjects(new ListObjectsRequest(bucketName, null, null, null, null));
}
@Override
public ObjectListing listObjects(String bucketName, String prefix)
throws SdkClientException, AmazonServiceException {
return listObjects(new ListObjectsRequest(bucketName, prefix, null, null, null));
}
@Override
public ObjectListing listObjects(ListObjectsRequest listObjectsRequest)
throws SdkClientException, AmazonServiceException {
listObjectsRequest = beforeClientExecution(listObjectsRequest);
rejectNull(listObjectsRequest.getBucketName(), "The bucket name parameter must be specified when listing objects in a bucket");
/**
* This flag shows whether we need to url decode S3 key names. This flag is enabled
* only when the customers don't explicitly call {@link ListObjectsRequest#setEncodingType(String)},
* otherwise, it will be disabled for maintaining backwards compatibility.
*/
final boolean shouldSDKDecodeResponse = listObjectsRequest.getEncodingType() == null;
Request request = createRequest(listObjectsRequest.getBucketName(), null, listObjectsRequest, HttpMethodName.GET);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "ListObjects");
addParameterIfNotNull(request, "prefix", listObjectsRequest.getPrefix());
addParameterIfNotNull(request, "marker", listObjectsRequest.getMarker());
addParameterIfNotNull(request, "delimiter", listObjectsRequest.getDelimiter());
addStringListHeader(request, Headers.OPTIONAL_OBJECT_ATTRIBUTE, listObjectsRequest.getOptionalObjectAttributes());
if (listObjectsRequest.getMaxKeys() != null && listObjectsRequest.getMaxKeys().intValue() >= 0) request.addParameter("max-keys", listObjectsRequest.getMaxKeys().toString());
request.addParameter("encoding-type", shouldSDKDecodeResponse ? Constants.URL_ENCODING : listObjectsRequest.getEncodingType());
populateRequesterPaysHeader(request, listObjectsRequest.isRequesterPays());
@SuppressWarnings("unchecked")
ResponseHeaderHandlerChain responseHandler =
new ResponseHeaderHandlerChain(
// xml payload unmarshaller
new Unmarshallers.ListObjectsUnmarshaller(shouldSDKDecodeResponse),
// header handler
new S3RequesterChargedHeaderHandler());
return invoke(request, responseHandler, listObjectsRequest.getBucketName(), null);
}
@Override
public ListObjectsV2Result listObjectsV2(String bucketName)
throws SdkClientException, AmazonServiceException {
return listObjectsV2(new ListObjectsV2Request().withBucketName(bucketName));
}
@Override
public ListObjectsV2Result listObjectsV2(String bucketName, String prefix)
throws SdkClientException, AmazonServiceException {
return listObjectsV2(new ListObjectsV2Request().withBucketName(bucketName).withPrefix(prefix));
}
@Override
public ListObjectsV2Result listObjectsV2(ListObjectsV2Request listObjectsV2Request)
throws SdkClientException, AmazonServiceException {
listObjectsV2Request = beforeClientExecution(listObjectsV2Request);
rejectNull(listObjectsV2Request.getBucketName(), "The bucket name parameter must be specified when listing objects in a bucket");
Request request = createRequest(listObjectsV2Request.getBucketName(), null, listObjectsV2Request, HttpMethodName.GET);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "ListObjectsV2");
/**
* List type '2' is required to opt-in to listObjectsV2.
*/
request.addParameter("list-type", "2");
addParameterIfNotNull(request, "start-after", listObjectsV2Request.getStartAfter());
addParameterIfNotNull(request, "continuation-token", listObjectsV2Request.getContinuationToken());
addParameterIfNotNull(request, "delimiter", listObjectsV2Request.getDelimiter());
addParameterIfNotNull(request, "max-keys", listObjectsV2Request.getMaxKeys());
addParameterIfNotNull(request, "prefix", listObjectsV2Request.getPrefix());
addParameterIfNotNull(request, "encoding-type", listObjectsV2Request.getEncodingType());
addStringListHeader(request, Headers.OPTIONAL_OBJECT_ATTRIBUTE, listObjectsV2Request.getOptionalObjectAttributes());
request.addParameter("fetch-owner", Boolean.toString(listObjectsV2Request.isFetchOwner()));
populateRequesterPaysHeader(request, listObjectsV2Request.isRequesterPays());
/**
* If URL encoding has been requested from S3 we'll automatically decode the response.
*/
final boolean shouldSDKDecodeResponse = Constants.URL_ENCODING.equals(listObjectsV2Request.getEncodingType());
@SuppressWarnings("unchecked")
ResponseHeaderHandlerChain responseHandler =
new ResponseHeaderHandlerChain(
// xml payload unmarshaller
new Unmarshallers.ListObjectsV2Unmarshaller(shouldSDKDecodeResponse),
// header handler
new S3RequesterChargedHeaderHandler());
return invoke(request, responseHandler, listObjectsV2Request.getBucketName(), null);
}
@Override
public ObjectListing listNextBatchOfObjects(ObjectListing previousObjectListing)
throws SdkClientException, AmazonServiceException {
return listNextBatchOfObjects(new ListNextBatchOfObjectsRequest(previousObjectListing));
}
@Override
public ObjectListing listNextBatchOfObjects(ListNextBatchOfObjectsRequest listNextBatchOfObjectsRequest)
throws SdkClientException, AmazonServiceException {
listNextBatchOfObjectsRequest = beforeClientExecution(listNextBatchOfObjectsRequest);
rejectNull(listNextBatchOfObjectsRequest,
"The request object parameter must be specified when listing the next batch of objects in a bucket");
ObjectListing previousObjectListing = listNextBatchOfObjectsRequest.getPreviousObjectListing();
if (!previousObjectListing.isTruncated()) {
ObjectListing emptyListing = new ObjectListing();
emptyListing.setBucketName(previousObjectListing.getBucketName());
emptyListing.setDelimiter(previousObjectListing.getDelimiter());
emptyListing.setMarker(previousObjectListing.getNextMarker());
emptyListing.setMaxKeys(previousObjectListing.getMaxKeys());
emptyListing.setPrefix(previousObjectListing.getPrefix());
emptyListing.setEncodingType(previousObjectListing.getEncodingType());
emptyListing.setTruncated(false);
return emptyListing;
}
return listObjects(listNextBatchOfObjectsRequest.toListObjectsRequest());
}
@Override
public Owner getS3AccountOwner()
throws SdkClientException, AmazonServiceException {
return getS3AccountOwner(new GetS3AccountOwnerRequest());
}
@Override
public Owner getS3AccountOwner(GetS3AccountOwnerRequest getS3AccountOwnerRequest)
throws SdkClientException, AmazonServiceException {
getS3AccountOwnerRequest = beforeClientExecution(getS3AccountOwnerRequest);
rejectNull(getS3AccountOwnerRequest, "The request object parameter getS3AccountOwnerRequest must be specified.");
Request request = createRequest(null, null, getS3AccountOwnerRequest, HttpMethodName.GET);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "ListBuckets");
return invoke(request, new Unmarshallers.ListBucketsOwnerUnmarshaller(), null, null);
}
@Override
public List listBuckets(ListBucketsRequest listBucketsRequest)
throws SdkClientException, AmazonServiceException {
listBucketsRequest = beforeClientExecution(listBucketsRequest);
rejectNull(listBucketsRequest, "The request object parameter listBucketsRequest must be specified.");
Request request = createRequest(null, null, listBucketsRequest, HttpMethodName.GET);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "ListBuckets");
return invoke(request, new Unmarshallers.ListBucketsUnmarshaller(), null, null);
}
@Override
public ListBucketsPaginatedResult listBuckets(ListBucketsPaginatedRequest listBucketsRequest)
throws SdkClientException, AmazonServiceException {
listBucketsRequest = beforeClientExecution(listBucketsRequest);
rejectNull(listBucketsRequest, "The request object parameter listBucketsRequest must be specified.");
Request request = createRequest(null, null, listBucketsRequest, HttpMethodName.GET);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "ListBuckets");
addParameterIfNotNull(request, "continuation-token", listBucketsRequest.getContinuationToken());
addParameterIfNotNull(request, "max-buckets", listBucketsRequest.getMaxBuckets());
return invoke(request, new Unmarshallers.ListBucketsPaginatedUnmarshaller(), null, null);
}
@Override
public List listBuckets()
throws SdkClientException, AmazonServiceException {
return listBuckets(new ListBucketsRequest());
}
@Override
public String getBucketLocation(GetBucketLocationRequest getBucketLocationRequest)
throws SdkClientException, AmazonServiceException {
getBucketLocationRequest = beforeClientExecution(getBucketLocationRequest);
rejectNull(getBucketLocationRequest, "The request parameter must be specified when requesting a bucket's location");
String bucketName = getBucketLocationRequest.getBucketName();
rejectNull(bucketName, "The bucket name parameter must be specified when requesting a bucket's location");
Request request = createRequest(bucketName, null, getBucketLocationRequest, HttpMethodName.GET);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "GetBucketLocation");
request.addParameter("location", null);
return invoke(request, new Unmarshallers.BucketLocationUnmarshaller(), bucketName, null);
}
@Override
public String getBucketLocation(String bucketName)
throws SdkClientException, AmazonServiceException {
return getBucketLocation(new GetBucketLocationRequest(bucketName));
}
@Override
public Bucket createBucket(String bucketName)
throws SdkClientException, AmazonServiceException {
return createBucket(new CreateBucketRequest(bucketName));
}
@Override
@Deprecated
public Bucket createBucket(String bucketName, Region region)
throws SdkClientException, AmazonServiceException {
return createBucket(new CreateBucketRequest(bucketName, region));
}
@Override
@Deprecated
public Bucket createBucket(String bucketName, String region)
throws SdkClientException, AmazonServiceException {
return createBucket(new CreateBucketRequest(bucketName, region));
}
@Override
public Bucket createBucket(CreateBucketRequest createBucketRequest)
throws SdkClientException, AmazonServiceException {
createBucketRequest = beforeClientExecution(createBucketRequest);
rejectNull(createBucketRequest,
"The CreateBucketRequest parameter must be specified when creating a bucket");
String bucketName = createBucketRequest.getBucketName();
rejectNull(bucketName, "The bucket name parameter must be specified when creating a bucket");
bucketName = bucketName.trim();
String requestRegion = createBucketRequest.getRegion();
URI requestEndpoint = getCreateBucketEndpoint(requestRegion);
BucketNameUtils.validateBucketName(bucketName);
Request request = createRequest(bucketName, null, createBucketRequest, HttpMethodName.PUT, requestEndpoint);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "CreateBucket");
if (createBucketRequest.getAccessControlList() != null) {
addAclHeaders(request, createBucketRequest.getAccessControlList());
} else if (createBucketRequest.getCannedAcl() != null) {
request.addHeader(Headers.S3_CANNED_ACL, createBucketRequest.getCannedAcl().toString());
}
/*
* If we're talking to a region-specific endpoint other than the US, we
* *must* specify a location constraint. Try to derive the region from
* the endpoint.
*/
if (getSignerRegion() != null && !getSignerRegion().equals("us-east-1") && StringUtils.isNullOrEmpty(requestRegion)) {
requestRegion = AwsHostNameUtils.parseRegion(requestEndpoint.getHost(), S3_SERVICE_NAME);
}
/*
* We can only send the CreateBucketConfiguration if we're *not*
* creating a bucket in the US region.
*/
if (requestRegion != null && !StringUtils.upperCase(requestRegion).equals(Region.US_Standard.toString())) {
XmlWriter xml = new XmlWriter();
xml.start("CreateBucketConfiguration", "xmlns", Constants.XML_NAMESPACE);
xml.start("LocationConstraint").value(requestRegion).end();
xml.end();
request.setContent(new ByteArrayInputStream(xml.getBytes()));
}
if (createBucketRequest.getObjectLockEnabledForBucket()) {
request.addHeader(Headers.OBJECT_LOCK_ENABLED_FOR_BUCKET, "true");
}
if (createBucketRequest.getObjectOwnership() != null) {
request.addHeader(Headers.OBJECT_OWNERSHIP, createBucketRequest.getObjectOwnership());
}
invoke(request, voidResponseHandler, bucketName, null);
return new Bucket(bucketName);
}
private URI getCreateBucketEndpoint(String requestRegion) {
// Route to the default endpoint if they're not trying to specify a different one in the request.
if(requestRegion == null || requestRegion.equals(clientRegion) || !clientOptions.isForceGlobalBucketAccessEnabled()) {
return endpoint;
}
// If they enabled global bucket access and they're trying to create a bucket in a region different than the default
// one specified when they created the client, it will probably fail because only us-east-1 (actually the global
// endpoint) is capable of creating buckets outside of its region. Override the endpoint to which the request
// is routed so that it will succeed.
com.amazonaws.regions.Region targetRegion = com.amazonaws.regions.Region.getRegion(Regions.fromName(requestRegion));
return new DefaultServiceEndpointBuilder(getEndpointPrefix(),
clientConfiguration.getProtocol().toString()).withRegion(targetRegion)
.getServiceEndpoint();
}
@Override
public AccessControlList getObjectAcl(String bucketName, String key)
throws SdkClientException, AmazonServiceException {
return getObjectAcl(new GetObjectAclRequest(bucketName, key));
}
@Override
public AccessControlList getObjectAcl(String bucketName, String key, String versionId)
throws SdkClientException, AmazonServiceException {
return getObjectAcl(new GetObjectAclRequest(bucketName, key, versionId));
}
@Override
public AccessControlList getObjectAcl(GetObjectAclRequest getObjectAclRequest) {
getObjectAclRequest = beforeClientExecution(getObjectAclRequest);
rejectNull(getObjectAclRequest, "The request parameter must be specified when requesting an object's ACL");
rejectNull(getObjectAclRequest.getBucketName(), "The bucket name parameter must be specified when requesting an object's ACL");
rejectNull(getObjectAclRequest.getKey(), "The key parameter must be specified when requesting an object's ACL");
return getAcl(getObjectAclRequest.getBucketName(), getObjectAclRequest.getKey(),
getObjectAclRequest.getVersionId(), getObjectAclRequest.isRequesterPays(),
getObjectAclRequest);
}
@Override
public void setObjectAcl(String bucketName, String key, AccessControlList acl)
throws SdkClientException, AmazonServiceException {
setObjectAcl(bucketName, key, null, acl);
}
@Override
public void setObjectAcl(String bucketName, String key, CannedAccessControlList acl)
throws SdkClientException, AmazonServiceException {
setObjectAcl(bucketName, key, null, acl);
}
@Override
public void setObjectAcl(String bucketName, String key, String versionId, AccessControlList acl)
throws SdkClientException, AmazonServiceException {
setObjectAcl(new SetObjectAclRequest(bucketName, key, versionId, acl));
}
/**
* Same as {@link #setObjectAcl(String, String, String, AccessControlList)}
* but allows specifying a request metric collector.
*/
public void setObjectAcl(String bucketName, String key, String versionId,
AccessControlList acl, RequestMetricCollector requestMetricCollector)
throws SdkClientException, AmazonServiceException {
setObjectAcl(new SetObjectAclRequest(bucketName, key, versionId, acl)
. withRequestMetricCollector(requestMetricCollector));
}
@Override
public void setObjectAcl(String bucketName, String key, String versionId, CannedAccessControlList acl)
throws SdkClientException, AmazonServiceException {
setObjectAcl(new SetObjectAclRequest(bucketName, key, versionId, acl));
}
/**
* Same as {@link #setObjectAcl(String, String, String, CannedAccessControlList)}
* but allows specifying a request metric collector.
*/
public void setObjectAcl(String bucketName, String key, String versionId,
CannedAccessControlList acl,
RequestMetricCollector requestMetricCollector) {
setObjectAcl(new SetObjectAclRequest(bucketName, key, versionId, acl)
. withRequestMetricCollector(requestMetricCollector));
}
@Override
public void setObjectAcl(SetObjectAclRequest setObjectAclRequest)
throws SdkClientException, AmazonServiceException {
setObjectAclRequest = beforeClientExecution(setObjectAclRequest);
rejectNull(setObjectAclRequest,
"The request must not be null.");
rejectNull(setObjectAclRequest.getBucketName(),
"The bucket name parameter must be specified when setting an object's ACL");
rejectNull(setObjectAclRequest.getKey(),
"The key parameter must be specified when setting an object's ACL");
if (setObjectAclRequest.getAcl() != null && setObjectAclRequest.getCannedAcl() != null) {
throw new IllegalArgumentException(
"Only one of the ACL and CannedACL parameters can be specified, not both.");
}
if (setObjectAclRequest.getAcl() != null) {
setAcl(setObjectAclRequest.getBucketName(),
setObjectAclRequest.getKey(),
setObjectAclRequest.getVersionId(),
setObjectAclRequest.getAcl(),
setObjectAclRequest.isRequesterPays(),
setObjectAclRequest);
} else if (setObjectAclRequest.getCannedAcl() != null) {
setAcl(setObjectAclRequest.getBucketName(),
setObjectAclRequest.getKey(),
setObjectAclRequest.getVersionId(),
setObjectAclRequest.getCannedAcl(),
setObjectAclRequest.isRequesterPays(),
setObjectAclRequest);
} else {
throw new IllegalArgumentException(
"At least one of the ACL and CannedACL parameters should be specified");
}
}
/**
* {@inheritDoc}
* @see #getBucketAcl(String)
*/
@Override
public AccessControlList getBucketAcl(String bucketName)
throws SdkClientException, AmazonServiceException {
return getBucketAcl(new GetBucketAclRequest(bucketName));
}
@Override
public AccessControlList getBucketAcl(GetBucketAclRequest getBucketAclRequest)
throws SdkClientException, AmazonServiceException {
getBucketAclRequest = beforeClientExecution(getBucketAclRequest);
String bucketName = getBucketAclRequest.getBucketName();
rejectNull(bucketName, "The bucket name parameter must be specified when requesting a bucket's ACL");
return getAcl(bucketName, null, null, false, getBucketAclRequest);
}
@Override
public void setBucketAcl(String bucketName, AccessControlList acl)
throws SdkClientException, AmazonServiceException {
setBucketAcl(new SetBucketAclRequest(bucketName, acl));
}
/**
* Same as {@link #setBucketAcl(String, AccessControlList)}
* but allows specifying a request metric collector.
*/
public void setBucketAcl(String bucketName, AccessControlList acl,
RequestMetricCollector requestMetricCollector) {
SetBucketAclRequest request = new SetBucketAclRequest(bucketName, acl)
.withRequestMetricCollector(requestMetricCollector);
setBucketAcl(request);
}
@Override
public void setBucketAcl(String bucketName, CannedAccessControlList cannedAcl)
throws SdkClientException, AmazonServiceException {
setBucketAcl(new SetBucketAclRequest(bucketName, cannedAcl));
}
/**
* Same as {@link #setBucketAcl(String, CannedAccessControlList)}
* but allows specifying a request metric collector.
*/
public void setBucketAcl(String bucketName, CannedAccessControlList cannedAcl,
RequestMetricCollector requestMetricCollector) throws SdkClientException,
AmazonServiceException {
SetBucketAclRequest request = new SetBucketAclRequest(bucketName, cannedAcl)
.withRequestMetricCollector(requestMetricCollector);
setBucketAcl(request);
}
@Override
public void setBucketAcl(SetBucketAclRequest setBucketAclRequest)
throws SdkClientException, AmazonServiceException {
setBucketAclRequest = beforeClientExecution(setBucketAclRequest);
String bucketName = setBucketAclRequest.getBucketName();
rejectNull(bucketName, "The bucket name parameter must be specified when setting a bucket's ACL");
AccessControlList acl = setBucketAclRequest.getAcl();
CannedAccessControlList cannedAcl = setBucketAclRequest.getCannedAcl();
if (acl == null && cannedAcl == null) {
throw new IllegalArgumentException(
"The ACL parameter must be specified when setting a bucket's ACL");
}
if (acl != null && cannedAcl != null) {
throw new IllegalArgumentException(
"Only one of the acl and cannedAcl parameter can be specified, not both.");
}
if (acl != null) {
setAcl(bucketName, null, null, acl, false, setBucketAclRequest);
} else {
setAcl(bucketName, null, null, cannedAcl, false, setBucketAclRequest);
}
}
@Override
public ObjectMetadata getObjectMetadata(String bucketName, String key)
throws SdkClientException, AmazonServiceException {
return getObjectMetadata(new GetObjectMetadataRequest(bucketName, key));
}
@Override
public ObjectMetadata getObjectMetadata(GetObjectMetadataRequest getObjectMetadataRequest)
throws SdkClientException, AmazonServiceException {
getObjectMetadataRequest = beforeClientExecution(getObjectMetadataRequest);
rejectNull(getObjectMetadataRequest, "The GetObjectMetadataRequest parameter must be specified when requesting an object's metadata");
String bucketName = getObjectMetadataRequest.getBucketName();
String key = getObjectMetadataRequest.getKey();
String versionId = getObjectMetadataRequest.getVersionId();
rejectNull(bucketName, "The bucket name parameter must be specified when requesting an object's metadata");
rejectNull(key, "The key parameter must be specified when requesting an object's metadata");
Request request = createRequest(bucketName, key, getObjectMetadataRequest, HttpMethodName.HEAD);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "HeadObject");
if (versionId != null) request.addParameter("versionId", versionId);
populateRequesterPaysHeader(request, getObjectMetadataRequest.isRequesterPays());
addPartNumberIfNotNull(request, getObjectMetadataRequest.getPartNumber());
populateSSE_C(request, getObjectMetadataRequest.getSSECustomerKey());
return invoke(request, new S3MetadataResponseHandler(), bucketName, key);
}
@Override
public S3Object getObject(String bucketName, String key)
throws SdkClientException, AmazonServiceException {
return getObject(new GetObjectRequest(bucketName, key));
}
@Override
public boolean doesBucketExist(String bucketName)
throws SdkClientException, AmazonServiceException {
try {
ValidationUtils.assertStringNotEmpty(bucketName, "bucketName");
headBucket(new HeadBucketRequest(bucketName));
return true;
} catch (AmazonServiceException ase) {
// A redirect error or a forbidden error means the bucket exists. So
// returning true.
if ((ase.getStatusCode() == Constants.BUCKET_REDIRECT_STATUS_CODE)
|| (ase.getStatusCode() == Constants.BUCKET_ACCESS_FORBIDDEN_STATUS_CODE)) {
return true;
}
if (ase.getStatusCode() == Constants.NO_SUCH_BUCKET_STATUS_CODE) {
return false;
}
throw ase;
}
}
@Override
public boolean doesBucketExistV2(String bucketName) throws SdkClientException {
try {
ValidationUtils.assertStringNotEmpty(bucketName, "bucketName");
getBucketAcl(bucketName);
return true;
} catch (AmazonServiceException ase) {
// A redirect error or an AccessDenied exception means the bucket exists but it's not in this region
// or we don't have permissions to it.
if ((ase.getStatusCode() == Constants.BUCKET_REDIRECT_STATUS_CODE) || "AccessDenied".equals(ase.getErrorCode())) {
return true;
}
if (ase.getStatusCode() == Constants.NO_SUCH_BUCKET_STATUS_CODE) {
return false;
}
throw ase;
}
}
@Override
public boolean doesObjectExist(String bucketName, String objectName)
throws AmazonServiceException, SdkClientException {
try {
ValidationUtils.assertStringNotEmpty(bucketName, "bucketName");
ValidationUtils.assertStringNotEmpty(objectName, "objectName");
getObjectMetadata(bucketName, objectName);
return true;
} catch (AmazonS3Exception e) {
if (e.getStatusCode() == 404) {
return false;
}
throw e;
}
}
@Override
public HeadBucketResult headBucket(HeadBucketRequest headBucketRequest)
throws SdkClientException, AmazonServiceException {
headBucketRequest = beforeClientExecution(headBucketRequest);
String bucketName = headBucketRequest.getBucketName();
rejectNull(bucketName,
"The bucketName parameter must be specified.");
Request request = createRequest(bucketName, null,
headBucketRequest, HttpMethodName.HEAD);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "HeadBucket");
return invoke(request, new HeadBucketResultHandler(), bucketName, null);
}
@Override
public void changeObjectStorageClass(String bucketName, String key, StorageClass newStorageClass)
throws SdkClientException, AmazonServiceException {
rejectNull(bucketName,
"The bucketName parameter must be specified when changing an object's storage class");
rejectNull(key,
"The key parameter must be specified when changing an object's storage class");
rejectNull(newStorageClass,
"The newStorageClass parameter must be specified when changing an object's storage class");
copyObject(new CopyObjectRequest(bucketName, key, bucketName, key)
.withStorageClass(newStorageClass.toString()));
}
@Override
public void setObjectRedirectLocation(String bucketName, String key, String newRedirectLocation)
throws SdkClientException, AmazonServiceException {
rejectNull(bucketName,
"The bucketName parameter must be specified when changing an object's storage class");
rejectNull(key,
"The key parameter must be specified when changing an object's storage class");
rejectNull(newRedirectLocation,
"The newStorageClass parameter must be specified when changing an object's storage class");
copyObject(new CopyObjectRequest(bucketName, key, bucketName, key)
.withRedirectLocation(newRedirectLocation));
}
@Override
public S3Object getObject(GetObjectRequest getObjectRequest)
throws SdkClientException, AmazonServiceException {
getObjectRequest = beforeClientExecution(getObjectRequest);
assertNotNull(getObjectRequest, "GetObjectRequest");
assertStringNotEmpty(getObjectRequest.getBucketName(), "BucketName");
assertStringNotEmpty(getObjectRequest.getKey(), "Key");
Request request = createRequest(getObjectRequest.getBucketName(), getObjectRequest.getKey(), getObjectRequest, HttpMethodName.GET);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "GetObject");
request.addHandlerContext(HandlerContextKey.HAS_STREAMING_OUTPUT, Boolean.TRUE);
if (getObjectRequest.getVersionId() != null) {
request.addParameter("versionId", getObjectRequest.getVersionId());
}
addPartNumberIfNotNull(request, getObjectRequest.getPartNumber());
// Range
long[] range = getObjectRequest.getRange();
if (range != null) {
request.addHeader(Headers.RANGE, "bytes=" + Long.toString(range[0]) + "-" + Long.toString(range[1]));
}
populateRequesterPaysHeader(request, getObjectRequest.isRequesterPays());
addResponseHeaderParameters(request, getObjectRequest.getResponseHeaders());
addDateHeader(request, Headers.GET_OBJECT_IF_MODIFIED_SINCE,
getObjectRequest.getModifiedSinceConstraint());
addDateHeader(request, Headers.GET_OBJECT_IF_UNMODIFIED_SINCE,
getObjectRequest.getUnmodifiedSinceConstraint());
addStringListHeader(request, Headers.GET_OBJECT_IF_MATCH,
getObjectRequest.getMatchingETagConstraints());
addStringListHeader(request, Headers.GET_OBJECT_IF_NONE_MATCH,
getObjectRequest.getNonmatchingETagConstraints());
// Populate the SSE-C parameters to the request header
populateSSE_C(request, getObjectRequest.getSSECustomerKey());
final ProgressListener listener = getObjectRequest.getGeneralProgressListener();
publishProgress(listener, ProgressEventType.TRANSFER_STARTED_EVENT);
try {
S3Object s3Object = invoke(request, new S3ObjectResponseHandler(),
getObjectRequest.getBucketName(), getObjectRequest.getKey());
/*
* TODO: For now, it's easiest to set there here in the client, but
* we could push this back into the response handler with a
* little more work.
*/
s3Object.setBucketName(getObjectRequest.getBucketName());
s3Object.setKey(getObjectRequest.getKey());
boolean skipClientSideValidation = skipMd5CheckStrategy.skipClientSideValidation(getObjectRequest,
s3Object.getObjectMetadata());
postProcessS3Object(s3Object, skipClientSideValidation, listener);
return s3Object;
} catch (AmazonS3Exception ase) {
/*
* If the request failed because one of the specified constraints
* was not met (ex: matching ETag, modified since date, etc.), then
* return null, so that users don't have to wrap their code in
* try/catch blocks and check for this status code if they want to
* use constraints.
*/
if (ase.getStatusCode() == 412 || ase.getStatusCode() == 304) {
publishProgress(listener, ProgressEventType.TRANSFER_CANCELED_EVENT);
return null;
}
publishProgress(listener, ProgressEventType.TRANSFER_FAILED_EVENT);
throw ase;
}
}
/**
* Post processing the {@link S3Object} downloaded from S3. It includes wrapping the data with wrapper input streams,
* doing client side validation if possible etc.
*/
private void postProcessS3Object(final S3Object s3Object, final boolean skipClientSideValidation,
final ProgressListener listener) {
InputStream is = s3Object.getObjectContent();
HttpRequestBase httpRequest = s3Object.getObjectContent().getHttpRequest();
// Hold a reference to this client while the InputStream is still
// around - otherwise a finalizer in the HttpClient may reset the
// underlying TCP connection out from under us.
is = new ServiceClientHolderInputStream(is, this);
// used trigger a tranfer complete event when the stream is entirely consumed
ProgressInputStream progressInputStream =
new ProgressInputStream(is, listener) {
@Override protected void onEOF() {
publishProgress(getListener(), ProgressEventType.TRANSFER_COMPLETED_EVENT);
}
};
is = progressInputStream;
// The Etag header contains a server-side MD5 of the object. If
// we're downloading the whole object, by default we wrap the
// stream in a validator that calculates an MD5 of the downloaded
// bytes and complains if what we received doesn't match the Etag.
if (!skipClientSideValidation) {
byte[] serverSideHash = BinaryUtils.fromHex(s3Object.getObjectMetadata().getETag());
try {
// No content length check is performed when the
// MD5 check is enabled, since a correct MD5 check would
// imply a correct content length.
MessageDigest digest = MessageDigest.getInstance("MD5");
is = new DigestValidationInputStream(is, digest, serverSideHash);
} catch (NoSuchAlgorithmException e) {
log.warn("No MD5 digest algorithm available. Unable to calculate "
+ "checksum and verify data integrity.", e);
}
} else {
// Ensures the data received from S3 has the same length as the
// expected content-length
// Note: The GetObject response many not have a content-length if
// it was uploaded using chunked encoding, e.g.
// using WriteGetObjectResponse
Object contentLength = s3Object.getObjectMetadata().getRawMetadataValue(Headers.CONTENT_LENGTH);
if (contentLength != null) {
is = new LengthCheckInputStream(is,
s3Object.getObjectMetadata().getContentLength(), // expected length
INCLUDE_SKIPPED_BYTES); // bytes received from S3 are all included even if skipped
}
}
S3AbortableInputStream abortableInputStream =
new S3AbortableInputStream(is, httpRequest, s3Object.getObjectMetadata().getContentLength());
s3Object.setObjectContent(new S3ObjectInputStream(abortableInputStream, httpRequest, false));
}
@Override
public ObjectMetadata getObject(final GetObjectRequest getObjectRequest, File destinationFile)
throws SdkClientException, AmazonServiceException {
rejectNull(destinationFile,
"The destination file parameter must be specified when downloading an object directly to a file");
S3Object s3Object = ServiceUtils.retryableDownloadS3ObjectToFile(destinationFile, new ServiceUtils.RetryableS3DownloadTask() {
@Override
public S3Object getS3ObjectStream() {
return getObject(getObjectRequest);
}
@Override
public boolean needIntegrityCheck() {
return !skipMd5CheckStrategy.skipClientSideValidationPerRequest(getObjectRequest);
}
}, ServiceUtils.OVERWRITE_MODE);
// getObject can return null if constraints were specified but not met
if (s3Object == null) return null;
return s3Object.getObjectMetadata();
}
@Override
public String getObjectAsString(String bucketName, String key)
throws AmazonServiceException, SdkClientException {
rejectNull(bucketName, "Bucket name must be provided");
rejectNull(key, "Object key must be provided");
S3Object object = getObject(bucketName, key);
try {
return IOUtils.toString(object.getObjectContent());
} catch (IOException e) {
throw new SdkClientException("Error streaming content from S3 during download", e);
} finally {
IOUtils.closeQuietly(object, log);
}
}
@Override
public GetObjectTaggingResult getObjectTagging(GetObjectTaggingRequest getObjectTaggingRequest) {
getObjectTaggingRequest = beforeClientExecution(getObjectTaggingRequest);
rejectNull(getObjectTaggingRequest,
"The request parameter must be specified when getting the object tags");
String bucketName = assertStringNotEmpty(getObjectTaggingRequest.getBucketName(), "BucketName");
String key = assertNotNull(getObjectTaggingRequest.getKey(), "Key");
Request request = createRequest(bucketName, key, getObjectTaggingRequest, HttpMethodName.GET);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "GetObjectTagging");
request.addParameter("tagging", null);
addParameterIfNotNull(request, "versionId", getObjectTaggingRequest.getVersionId());
populateRequesterPaysHeader(request, getObjectTaggingRequest.isRequesterPays());
ResponseHeaderHandlerChain handlerChain = new ResponseHeaderHandlerChain(
new Unmarshallers.GetObjectTaggingResponseUnmarshaller(),
new GetObjectTaggingResponseHeaderHandler()
);
return invoke(request, handlerChain, bucketName, key);
}
@Override
public SetObjectTaggingResult setObjectTagging(SetObjectTaggingRequest setObjectTaggingRequest) {
setObjectTaggingRequest = beforeClientExecution(setObjectTaggingRequest);
rejectNull(setObjectTaggingRequest,
"The request parameter must be specified setting the object tags");
String bucketName = assertStringNotEmpty(setObjectTaggingRequest.getBucketName(), "BucketName");
String key = assertNotNull(setObjectTaggingRequest.getKey(), "Key");
ObjectTagging tagging = assertNotNull(setObjectTaggingRequest.getTagging(), "ObjectTagging");
Request request = createRequest(bucketName, key, setObjectTaggingRequest, HttpMethodName.PUT);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "PutObjectTagging");
request.addParameter("tagging", null);
addParameterIfNotNull(request, "versionId", setObjectTaggingRequest.getVersionId());
byte[] content = new ObjectTaggingXmlFactory().convertToXmlByteArray(tagging);
setContent(request, content, "application/xml", true);
populateRequesterPaysHeader(request, setObjectTaggingRequest.isRequesterPays());
ResponseHeaderHandlerChain handlerChain = new ResponseHeaderHandlerChain(
new Unmarshallers.SetObjectTaggingResponseUnmarshaller(),
new SetObjectTaggingResponseHeaderHandler()
);
return invoke(request, handlerChain, bucketName, key);
}
@Override
public DeleteObjectTaggingResult deleteObjectTagging(DeleteObjectTaggingRequest deleteObjectTaggingRequest) {
deleteObjectTaggingRequest = beforeClientExecution(deleteObjectTaggingRequest);
rejectNull(deleteObjectTaggingRequest, "The request parameter must be specified when delete the object tags");
String bucketName = assertStringNotEmpty(deleteObjectTaggingRequest.getBucketName(), "BucketName");
String key = assertStringNotEmpty(deleteObjectTaggingRequest.getKey(), "Key");
Request request = createRequest(bucketName, key, deleteObjectTaggingRequest, HttpMethodName.DELETE);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "DeleteObjectTagging");
request.addParameter("tagging", null);
addParameterIfNotNull(request, "versionId", deleteObjectTaggingRequest.getVersionId());
ResponseHeaderHandlerChain handlerChain = new ResponseHeaderHandlerChain(
new Unmarshallers.DeleteObjectTaggingResponseUnmarshaller(),
new DeleteObjectTaggingHeaderHandler()
);
return invoke(request, handlerChain, bucketName, key);
}
@Override
public void deleteBucket(String bucketName)
throws SdkClientException, AmazonServiceException {
deleteBucket(new DeleteBucketRequest(bucketName));
}
@Override
public void deleteBucket(DeleteBucketRequest deleteBucketRequest)
throws SdkClientException, AmazonServiceException {
deleteBucketRequest = beforeClientExecution(deleteBucketRequest);
rejectNull(deleteBucketRequest,
"The DeleteBucketRequest parameter must be specified when deleting a bucket");
String bucketName = deleteBucketRequest.getBucketName();
rejectNull(bucketName,
"The bucket name parameter must be specified when deleting a bucket");
Request request = createRequest(bucketName, null, deleteBucketRequest, HttpMethodName.DELETE);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "DeleteBucket");
invoke(request, voidResponseHandler, bucketName, null);
bucketRegionCache.remove(bucketName);
}
@Override
public PutObjectResult putObject(String bucketName, String key, File file)
throws SdkClientException, AmazonServiceException {
return putObject(new PutObjectRequest(bucketName, key, file)
.withMetadata(new ObjectMetadata()));
}
@Override
public PutObjectResult putObject(String bucketName, String key, InputStream input, ObjectMetadata metadata)
throws SdkClientException, AmazonServiceException {
return putObject(new PutObjectRequest(bucketName, key, input, metadata));
}
@Override
public PutObjectResult putObject(PutObjectRequest putObjectRequest) throws SdkClientException, AmazonServiceException {
putObjectRequest = beforeClientExecution(putObjectRequest);
rejectNull(putObjectRequest, "The PutObjectRequest parameter must be specified when uploading an object");
final File file = putObjectRequest.getFile();
final InputStream isOrig = putObjectRequest.getInputStream();
final String bucketName = putObjectRequest.getBucketName();
final String key = putObjectRequest.getKey();
final ProgressListener listener = putObjectRequest.getGeneralProgressListener();
rejectNull(bucketName, "The bucket name parameter must be specified when uploading an object");
rejectNull(key, "The key parameter must be specified when uploading an object");
ObjectMetadata metadata = putObjectRequest.getMetadata();
if (metadata == null)
metadata = new ObjectMetadata();
Request request = createRequest(bucketName, key, putObjectRequest, HttpMethodName.PUT);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "PutObject");
request.addHandlerContext(HandlerContextKey.REQUIRES_LENGTH, Boolean.TRUE);
request.addHandlerContext(HandlerContextKey.HAS_STREAMING_INPUT, Boolean.TRUE);
// Make backward compatible with buffer size via system property
final Integer bufsize = Constants.getS3StreamBufferSize();
if (bufsize != null) {
AmazonWebServiceRequest awsreq = request.getOriginalRequest();
// Note awsreq is never null at this point even if the original
// request was
awsreq.getRequestClientOptions()
.setReadLimit(bufsize.intValue());
}
if ( putObjectRequest.getAccessControlList() != null) {
addAclHeaders(request, putObjectRequest.getAccessControlList());
} else if ( putObjectRequest.getCannedAcl() != null ) {
request.addHeader(Headers.S3_CANNED_ACL, putObjectRequest.getCannedAcl().toString());
}
if (putObjectRequest.getStorageClass() != null) {
request.addHeader(Headers.STORAGE_CLASS, putObjectRequest.getStorageClass());
}
if (putObjectRequest.getRedirectLocation() != null) {
request.addHeader(Headers.REDIRECT_LOCATION, putObjectRequest.getRedirectLocation());
}
Boolean bucketKeyEnabled = putObjectRequest.getBucketKeyEnabled();
if (bucketKeyEnabled != null) {
addHeaderIfNotNull(request, Headers.SERVER_SIDE_ENCRYPTION_BUCKET_KEY_ENABLED,
String.valueOf(bucketKeyEnabled));
}
addHeaderIfNotNull(request, Headers.S3_TAGGING, urlEncodeTags(putObjectRequest.getTagging()));
addHeaderIfNotNull(request, Headers.PUT_OBJECT_IF_NONE_MATCH, putObjectRequest.getIfNoneMatch());
populateRequesterPaysHeader(request, putObjectRequest.isRequesterPays());
// Populate the SSE-C parameters to the request header
populateSSE_C(request, putObjectRequest.getSSECustomerKey());
// Populate the SSE Amazon Web Services KMS parameters to the request header
populateSSE_KMS(request,
putObjectRequest.getSSEAwsKeyManagementParams());
populateObjectLockHeaders(request, putObjectRequest.getObjectLockMode(), putObjectRequest.getObjectLockRetainUntilDate(),
putObjectRequest.getObjectLockLegalHoldStatus());
return uploadObject(isOrig, file, metadata, listener, request, putObjectRequest,
skipMd5CheckStrategy.skipServerSideValidation(putObjectRequest),
skipMd5CheckStrategy.skipClientSideValidationPerRequest(putObjectRequest),
new PutObjectStrategy(bucketName, key),
true);
}
/**
* Helper method used by {@link #putObject(PutObjectRequest)} and {@link #upload(PresignedUrlUploadRequest)}.
*/
private ResponseT uploadObject(final InputStream originalStream,
final File file,
final ObjectMetadata metadata,
final ProgressListener listener,
final Request request,
final S3DataSource originalRequest,
final boolean skipServerSideValidation,
final boolean skipClientSideValidationPerRequest,
final UploadObjectStrategy uploadStrategy,
final boolean setContentTypeIfNotProvided) {
InputStream input = getInputStream(originalStream, file, metadata, request,
skipServerSideValidation, setContentTypeIfNotProvided);
final ObjectMetadata returnedMetadata;
MD5DigestCalculatingInputStream md5DigestStream = null;
try {
if (metadata.getContentMD5() == null && !skipClientSideValidationPerRequest) {
/*
* If the user hasn't set the content MD5, then we don't want to buffer the whole
* stream in memory just to calculate it. Instead, we can calculate it on the fly
* and validate it with the returned ETag from the object upload.
*/
input = md5DigestStream = new MD5DigestCalculatingInputStream(input);
}
populateRequestMetadata(request, metadata);
request.setContent(input);
publishProgress(listener, ProgressEventType.TRANSFER_STARTED_EVENT);
try {
returnedMetadata = uploadStrategy.invokeServiceCall(request);
} catch (Throwable t) {
publishProgress(listener, ProgressEventType.TRANSFER_FAILED_EVENT);
throw failure(t);
}
} finally {
cleanupDataSource(originalRequest, file, originalStream, input, log);
}
String contentMd5 = metadata.getContentMD5();
if (md5DigestStream != null) {
contentMd5 = Base64.encodeAsString(md5DigestStream.getMd5Digest());
}
final String etag = returnedMetadata.getETag();
if (contentMd5 != null && !skipMd5CheckStrategy.skipClientSideValidationPerPutResponse(returnedMetadata)) {
byte[] clientSideHash = BinaryUtils.fromBase64(contentMd5);
byte[] serverSideHash = BinaryUtils.fromHex(etag);
if (!Arrays.equals(clientSideHash, serverSideHash)) {
publishProgress(listener, ProgressEventType.TRANSFER_FAILED_EVENT);
throw new SdkClientException(
"Unable to verify integrity of data upload. Client calculated content hash (contentMD5: " + contentMd5
+ " in base 64) didn't match hash (etag: " + etag + " in hex) calculated by Amazon S3. "
+ "You may need to delete the data stored in Amazon S3. (metadata.contentMD5: " + metadata.getContentMD5()
+ ", md5DigestStream: " + md5DigestStream
+ uploadStrategy.md5ValidationErrorSuffix()
+ ")");
}
}
publishProgress(listener, ProgressEventType.TRANSFER_COMPLETED_EVENT);
return uploadStrategy.createResult(returnedMetadata, contentMd5);
}
private InputStream getInputStream(final InputStream origStream, final File file, final ObjectMetadata metadata,
final Request> request, final boolean skipServerSideValidation,
final boolean setContentTypeIfNotProvided) {
InputStream input = origStream;
// If a file is specified for upload, we need to pull some additional
// information from it to auto-configure a few options
if (file == null) {
// When input is a FileInputStream, this wrapping enables
// unlimited mark-and-reset
if (input != null)
input = ReleasableInputStream.wrap(input);
} else {
// Always set the content length, even if it's already set
metadata.setContentLength(file.length());
final boolean calculateMD5 = metadata.getContentMD5() == null;
// Only set the content type if it hasn't already been set
if (metadata.getContentType() == null && setContentTypeIfNotProvided) {
metadata.setContentType(Mimetypes.getInstance().getMimetype(file));
}
if (calculateMD5 && !skipServerSideValidation) {
try {
String contentMd5_b64 = Md5Utils.md5AsBase64(file);
metadata.setContentMD5(contentMd5_b64);
} catch (Exception e) {
throw new SdkClientException(
"Unable to calculate MD5 hash: " + e.getMessage(), e);
}
}
input = newResettableInputStream(file, "Unable to find file to upload");
}
if (metadata.getContentType() == null && setContentTypeIfNotProvided) {
/*
* Default to the "application/octet-stream" if the user hasn't
* specified a content type.
*/
metadata.setContentType(Mimetypes.MIMETYPE_OCTET_STREAM);
}
if (request.getHeaders().get(Headers.REDIRECT_LOCATION) != null && input == null) {
input = new ByteArrayInputStream(new byte[0]);
}
// Use internal interface to differentiate 0 from unset.
final Long contentLength = (Long)metadata.getRawMetadataValue(Headers.CONTENT_LENGTH);
if (contentLength == null) {
/*
* There's nothing we can do except for let the HTTP client buffer
* the input stream contents if the caller doesn't tell us how much
* data to expect in a stream since we have to explicitly tell
* Amazon S3 how much we're sending before we start sending any of
* it.
*/
log.warn("No content length specified for stream data. " +
"Stream contents will be buffered in memory and could result in " +
"out of memory errors.");
} else {
final long expectedLength = contentLength.longValue();
if (expectedLength >= 0) {
// Performs length check on the underlying data stream.
// For S3 encryption client, the underlying data stream here
// refers to the cipher-text data stream (ie not the underlying
// plain-text data stream which in turn may have been wrapped
// with it's own length check input stream.)
LengthCheckInputStream lcis = new LengthCheckInputStream(
input,
expectedLength, // expected data length to be uploaded
EXCLUDE_SKIPPED_BYTES);
input = lcis;
}
}
return input;
}
private static PutObjectResult createPutObjectResult(ObjectMetadata metadata) {
final PutObjectResult result = new PutObjectResult();
result.setVersionId(metadata.getVersionId());
result.setSSEAlgorithm(metadata.getSSEAlgorithm());
result.setSSECustomerAlgorithm(metadata.getSSECustomerAlgorithm());
result.setSSECustomerKeyMd5(metadata.getSSECustomerKeyMd5());
result.setExpirationTime(metadata.getExpirationTime());
result.setExpirationTimeRuleId(metadata.getExpirationTimeRuleId());
result.setETag(metadata.getETag());
result.setMetadata(metadata);
result.setRequesterCharged(metadata.isRequesterCharged());
result.setBucketKeyEnabled(metadata.getBucketKeyEnabled());
return result;
}
/**
* Sets the access control headers for the request given.
*/
private static void addAclHeaders(Request extends AmazonWebServiceRequest> request, AccessControlList acl) {
List grants = acl.getGrantsAsList();
Map> grantsByPermission = new HashMap>();
for ( Grant grant : grants ) {
if ( !grantsByPermission.containsKey(grant.getPermission()) ) {
grantsByPermission.put(grant.getPermission(), new LinkedList());
}
grantsByPermission.get(grant.getPermission()).add(grant.getGrantee());
}
for ( Permission permission : Permission.values() ) {
if ( grantsByPermission.containsKey(permission) ) {
Collection grantees = grantsByPermission.get(permission);
boolean seenOne = false;
StringBuilder granteeString = new StringBuilder();
for ( Grantee grantee : grantees ) {
if ( !seenOne )
seenOne = true;
else
granteeString.append(", ");
granteeString.append(grantee.getTypeIdentifier()).append("=").append("\"")
.append(grantee.getIdentifier()).append("\"");
}
request.addHeader(permission.getHeaderName(), granteeString.toString());
}
}
}
@Override
public CopyObjectResult copyObject(String sourceBucketName, String sourceKey,
String destinationBucketName, String destinationKey)
throws SdkClientException, AmazonServiceException {
return copyObject(new CopyObjectRequest(sourceBucketName, sourceKey,
destinationBucketName, destinationKey));
}
@Override
public CopyObjectResult copyObject(CopyObjectRequest copyObjectRequest)
throws SdkClientException, AmazonServiceException {
copyObjectRequest = beforeClientExecution(copyObjectRequest);
rejectNull(copyObjectRequest.getSourceBucketName(),
"The source bucket name must be specified when copying an object");
rejectNull(copyObjectRequest.getSourceKey(),
"The source object key must be specified when copying an object");
rejectNull(copyObjectRequest.getDestinationBucketName(),
"The destination bucket name must be specified when copying an object");
rejectNull(copyObjectRequest.getDestinationKey(),
"The destination object key must be specified when copying an object");
String destinationKey = copyObjectRequest.getDestinationKey();
String destinationBucketName = copyObjectRequest.getDestinationBucketName();
Request request = createRequest(destinationBucketName, destinationKey, copyObjectRequest, HttpMethodName.PUT);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "CopyObject");
Boolean bucketKeyEnabled = copyObjectRequest.getBucketKeyEnabled();
if (bucketKeyEnabled != null) {
addHeaderIfNotNull(request, Headers.SERVER_SIDE_ENCRYPTION_BUCKET_KEY_ENABLED,
String.valueOf(bucketKeyEnabled));
}
populateRequestWithCopyObjectParameters(request, copyObjectRequest);
// Populate the SSE Amazon Web Services KMS parameters to the request header
populateSSE_KMS(request,
copyObjectRequest.getSSEAwsKeyManagementParams());
populateObjectLockHeaders(request, copyObjectRequest.getObjectLockMode(), copyObjectRequest.getObjectLockRetainUntilDate(),
copyObjectRequest.getObjectLockLegalHoldStatus());
/*
* We can't send a non-zero length Content-Length header if the user
* specified it, otherwise it messes up the HTTP connection when the
* remote server thinks there's more data to pull.
*/
setZeroContentLength(request);
CopyObjectResultHandler copyObjectResultHandler = null;
try {
@SuppressWarnings("unchecked")
ResponseHeaderHandlerChain handler = new ResponseHeaderHandlerChain(
// xml payload unmarshaller
new Unmarshallers.CopyObjectUnmarshaller(),
// header handlers
new ServerSideEncryptionHeaderHandler(),
new S3VersionHeaderHandler(),
new ObjectExpirationHeaderHandler(),
new S3RequesterChargedHeaderHandler());
copyObjectResultHandler = invoke(request, handler, destinationBucketName, destinationKey);
} catch (AmazonS3Exception ase) {
/*
* If the request failed because one of the specified constraints
* was not met (ex: matching ETag, modified since date, etc.), then
* return null, so that users don't have to wrap their code in
* try/catch blocks and check for this status code if they want to
* use constraints.
*/
if (ase.getStatusCode() == Constants.FAILED_PRECONDITION_STATUS_CODE) {
return null;
}
throw ase;
}
/*
* CopyObject has two failure modes:
* 1 - An HTTP error code is returned and the error is processed like any
* other error response.
* 2 - An HTTP 200 OK code is returned, but the response content contains
* an XML error response.
*
* This makes it very difficult for the client runtime to cleanly detect
* this case and handle it like any other error response. We could
* extend the runtime to have a more flexible/customizable definition of
* success/error (per request), but it's probably overkill for this
* one special case.
*/
if (copyObjectResultHandler.getErrorCode() != null) {
String errorCode = copyObjectResultHandler.getErrorCode();
String errorMessage = copyObjectResultHandler.getErrorMessage();
String requestId = copyObjectResultHandler.getErrorRequestId();
String hostId = copyObjectResultHandler.getErrorHostId();
AmazonS3Exception ase = new AmazonS3Exception(errorMessage);
ase.setErrorCode(errorCode);
ase.setErrorType(ErrorType.Service);
ase.setRequestId(requestId);
ase.setExtendedRequestId(hostId);
ase.setServiceName(request.getServiceName());
ase.setStatusCode(200);
ase.setProxyHost(clientConfiguration.getProxyHost());
throw ase;
}
// TODO: Might be nice to create this in our custom S3VersionHeaderHandler
CopyObjectResult copyObjectResult = new CopyObjectResult();
copyObjectResult.setETag(copyObjectResultHandler.getETag());
copyObjectResult.setLastModifiedDate(copyObjectResultHandler.getLastModified());
copyObjectResult.setVersionId(copyObjectResultHandler.getVersionId());
copyObjectResult.setSSEAlgorithm(copyObjectResultHandler.getSSEAlgorithm());
copyObjectResult.setSSECustomerAlgorithm(copyObjectResultHandler.getSSECustomerAlgorithm());
copyObjectResult.setSSECustomerKeyMd5(copyObjectResultHandler.getSSECustomerKeyMd5());
copyObjectResult.setBucketKeyEnabled(copyObjectResultHandler.getBucketKeyEnabled());
copyObjectResult.setExpirationTime(copyObjectResultHandler.getExpirationTime());
copyObjectResult.setExpirationTimeRuleId(copyObjectResultHandler.getExpirationTimeRuleId());
copyObjectResult.setRequesterCharged(copyObjectResultHandler.isRequesterCharged());
return copyObjectResult;
}
/**
* Copies a source object to a part of a multipart upload.
*
* To copy an object, the caller's account must have read access to the source object and
* write access to the destination bucket.
*
* For information about maximum and minimum part sizes and other multipart upload specifications,
* see Multipart upload limits
* in the Amazon S3 User Guide.
*
* If constraints are specified in the CopyPartRequest
* (e.g.
* {@link CopyPartRequest#setMatchingETagConstraints(List)})
* and are not satisfied when Amazon S3 receives the
* request, this method returns null
.
* This method returns a non-null result under all other
* circumstances.
*
*
* @param copyPartRequest
* The request object containing all the options for copying an
* Amazon S3 object.
*
* @return A {@link CopyPartResult} object containing the information
* returned by Amazon S3 about the newly created object, or null
if
* constraints were specified that weren't met when Amazon S3 attempted
* to copy the object.
*
* @throws SdkClientException
* If any errors are encountered in the client while making the
* request or handling the response.
* @throws AmazonServiceException
* If any errors occurred in Amazon S3 while processing the
* request.
*
* @see AmazonS3#copyObject(CopyObjectRequest)
* @see AmazonS3#initiateMultipartUpload(InitiateMultipartUploadRequest)
*/
@Override
public CopyPartResult copyPart(CopyPartRequest copyPartRequest) {
copyPartRequest = beforeClientExecution(copyPartRequest);
rejectNull(copyPartRequest.getSourceBucketName(),
"The source bucket name must be specified when copying a part");
rejectNull(copyPartRequest.getSourceKey(),
"The source object key must be specified when copying a part");
rejectNull(copyPartRequest.getDestinationBucketName(),
"The destination bucket name must be specified when copying a part");
rejectNull(copyPartRequest.getUploadId(),
"The upload id must be specified when copying a part");
rejectNull(copyPartRequest.getDestinationKey(),
"The destination object key must be specified when copying a part");
rejectNull(copyPartRequest.getPartNumber(),
"The part number must be specified when copying a part");
String destinationKey = copyPartRequest.getDestinationKey();
String destinationBucketName = copyPartRequest.getDestinationBucketName();
Request request = createRequest(destinationBucketName, destinationKey, copyPartRequest,
HttpMethodName.PUT);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "UploadPartCopy");
populateRequestWithCopyPartParameters(request, copyPartRequest);
request.addParameter("uploadId", copyPartRequest.getUploadId());
request.addParameter("partNumber", Integer.toString(copyPartRequest.getPartNumber()));
populateRequesterPaysHeader(request, copyPartRequest.isRequesterPays());
/*
* We can't send a non-zero length Content-Length header if the user
* specified it, otherwise it messes up the HTTP connection when the
* remote server thinks there's more data to pull.
*/
setZeroContentLength(request);
CopyObjectResultHandler copyObjectResultHandler = null;
try {
@SuppressWarnings("unchecked")
ResponseHeaderHandlerChain handler = new ResponseHeaderHandlerChain(
// xml payload unmarshaller
new Unmarshallers.CopyObjectUnmarshaller(),
// header handlers
new ServerSideEncryptionHeaderHandler(),
new S3VersionHeaderHandler());
copyObjectResultHandler = invoke(request, handler, destinationBucketName, destinationKey);
} catch ( AmazonS3Exception ase ) {
/*
* If the request failed because one of the specified constraints
* was not met (ex: matching ETag, modified since date, etc.), then
* return null, so that users don't have to wrap their code in
* try/catch blocks and check for this status code if they want to
* use constraints.
*/
if ( ase.getStatusCode() == Constants.FAILED_PRECONDITION_STATUS_CODE ) {
return null;
}
throw ase;
}
/*
* CopyPart has two failure modes: 1 - An HTTP error code is returned
* and the error is processed like any other error response. 2 - An HTTP
* 200 OK code is returned, but the response content contains an XML
* error response.
*
* This makes it very difficult for the client runtime to cleanly detect
* this case and handle it like any other error response. We could
* extend the runtime to have a more flexible/customizable definition of
* success/error (per request), but it's probably overkill for this one
* special case.
*/
if ( copyObjectResultHandler.getErrorCode() != null ) {
String errorCode = copyObjectResultHandler.getErrorCode();
String errorMessage = copyObjectResultHandler.getErrorMessage();
String requestId = copyObjectResultHandler.getErrorRequestId();
String hostId = copyObjectResultHandler.getErrorHostId();
AmazonS3Exception ase = new AmazonS3Exception(errorMessage);
ase.setErrorCode(errorCode);
ase.setErrorType(ErrorType.Service);
ase.setRequestId(requestId);
ase.setExtendedRequestId(hostId);
ase.setServiceName(request.getServiceName());
ase.setStatusCode(200);
ase.setProxyHost(clientConfiguration.getProxyHost());
throw ase;
}
CopyPartResult copyPartResult = new CopyPartResult();
copyPartResult.setETag(copyObjectResultHandler.getETag());
copyPartResult.setPartNumber(copyPartRequest.getPartNumber());
copyPartResult.setLastModifiedDate(copyObjectResultHandler.getLastModified());
copyPartResult.setVersionId(copyObjectResultHandler.getVersionId());
copyPartResult.setSSEAlgorithm(copyObjectResultHandler.getSSEAlgorithm());
copyPartResult.setSSECustomerAlgorithm(copyObjectResultHandler.getSSECustomerAlgorithm());
copyPartResult.setSSECustomerKeyMd5(copyObjectResultHandler.getSSECustomerKeyMd5());
copyPartResult.setBucketKeyEnabled(copyObjectResultHandler.getBucketKeyEnabled());
return copyPartResult;
}
@Override
public void deleteObject(String bucketName, String key)
throws SdkClientException, AmazonServiceException {
deleteObject(new DeleteObjectRequest(bucketName, key));
}
@Override
public void deleteObject(DeleteObjectRequest deleteObjectRequest)
throws SdkClientException, AmazonServiceException {
deleteObjectRequest = beforeClientExecution(deleteObjectRequest);
rejectNull(deleteObjectRequest,
"The delete object request must be specified when deleting an object");
rejectNull(deleteObjectRequest.getBucketName(), "The bucket name must be specified when deleting an object");
rejectNull(deleteObjectRequest.getKey(), "The key must be specified when deleting an object");
Request request = createRequest(deleteObjectRequest.getBucketName(), deleteObjectRequest.getKey(), deleteObjectRequest, HttpMethodName.DELETE);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "DeleteObject");
invoke(request, voidResponseHandler, deleteObjectRequest.getBucketName(), deleteObjectRequest.getKey());
}
@Override
public DeleteObjectsResult deleteObjects(DeleteObjectsRequest deleteObjectsRequest) {
deleteObjectsRequest = beforeClientExecution(deleteObjectsRequest);
Request request = createRequest(deleteObjectsRequest.getBucketName(), null, deleteObjectsRequest, HttpMethodName.POST);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "DeleteObjects");
request.addParameter("delete", null);
if (deleteObjectsRequest.getBypassGovernanceRetention()) {
request.addHeader(Headers.BYPASS_GOVERNANCE_RETENTION, "true");
}
if ( deleteObjectsRequest.getMfa() != null ) {
populateRequestWithMfaDetails(request, deleteObjectsRequest.getMfa());
}
populateRequesterPaysHeader(request, deleteObjectsRequest.isRequesterPays());
byte[] content = new MultiObjectDeleteXmlFactory().convertToXmlByteArray(deleteObjectsRequest);
request.addHeader("Content-Length", String.valueOf(content.length));
request.addHeader("Content-Type", "application/xml");
request.setContent(new ByteArrayInputStream(content));
populateRequestHeaderWithMd5(request, content);
@SuppressWarnings("unchecked")
ResponseHeaderHandlerChain responseHandler = new ResponseHeaderHandlerChain(
new Unmarshallers.DeleteObjectsResultUnmarshaller(),
new S3RequesterChargedHeaderHandler());
DeleteObjectsResponse response = null;
try {
response = invoke(request, responseHandler, deleteObjectsRequest.getBucketName(), null);
} catch (SdkClientException e) {
/*
* If there was a SlowDown error, the returned S3 response will not contain the progress made. We'll throw
* an {@code MultiObjectDeleteSlowdownException} in this case.
*/
if (e.getCause() instanceof MultiObjectDeleteSlowdownException) {
MultiObjectDeleteSlowdownException ex = (MultiObjectDeleteSlowdownException) e.getCause();
handleSlowDownException(ex, responseHandler.getResponseHeaders());
}
throw e;
}
/*
* If the result was only partially successful, throw an exception
*/
if ( !response.getErrors().isEmpty() ) {
Map headers = responseHandler.getResponseHeaders();
MultiObjectDeleteException ex = new MultiObjectDeleteException(
response.getErrors(),
response.getDeletedObjects());
ex.setStatusCode(200);
ex.setRequestId(headers.get(Headers.REQUEST_ID));
ex.setExtendedRequestId(headers.get(Headers.EXTENDED_REQUEST_ID));
ex.setCloudFrontId(headers.get(Headers.CLOUD_FRONT_ID));
ex.setProxyHost(clientConfiguration.getProxyHost());
throw ex;
}
DeleteObjectsResult result = new DeleteObjectsResult(response.getDeletedObjects(), response.isRequesterCharged());
return result;
}
private void handleSlowDownException(MultiObjectDeleteSlowdownException e, Map headers) {
e.setRequestId(headers.get(Headers.REQUEST_ID));
e.setExtendedRequestId(headers.get(Headers.EXTENDED_REQUEST_ID));
e.setCloudFrontId(headers.get(Headers.CLOUD_FRONT_ID));
e.setProxyHost(clientConfiguration.getProxyHost());
throw e;
}
@Override
public void deleteVersion(String bucketName, String key, String versionId)
throws SdkClientException, AmazonServiceException {
deleteVersion(new DeleteVersionRequest(bucketName, key, versionId));
}
@Override
public void deleteVersion(DeleteVersionRequest deleteVersionRequest)
throws SdkClientException, AmazonServiceException {
deleteVersionRequest = beforeClientExecution(deleteVersionRequest);
rejectNull(deleteVersionRequest,
"The delete version request object must be specified when deleting a version");
String bucketName = deleteVersionRequest.getBucketName();
String key = deleteVersionRequest.getKey();
String versionId = deleteVersionRequest.getVersionId();
rejectNull(bucketName, "The bucket name must be specified when deleting a version");
rejectNull(key, "The key must be specified when deleting a version");
rejectNull(versionId, "The version ID must be specified when deleting a version");
Request request = createRequest(bucketName, key, deleteVersionRequest, HttpMethodName.DELETE);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "DeleteObject");
if (versionId != null) request.addParameter("versionId", versionId);
if (deleteVersionRequest.getMfa() != null) {
populateRequestWithMfaDetails(request, deleteVersionRequest.getMfa());
}
if (deleteVersionRequest.getBypassGovernanceRetention()) {
request.addHeader(Headers.BYPASS_GOVERNANCE_RETENTION, "true");
}
invoke(request, voidResponseHandler, bucketName, key);
}
@Override
public void setBucketVersioningConfiguration(SetBucketVersioningConfigurationRequest setBucketVersioningConfigurationRequest)
throws SdkClientException, AmazonServiceException {
setBucketVersioningConfigurationRequest = beforeClientExecution(setBucketVersioningConfigurationRequest);
rejectNull(setBucketVersioningConfigurationRequest,
"The SetBucketVersioningConfigurationRequest object must be specified when setting versioning configuration");
String bucketName = setBucketVersioningConfigurationRequest.getBucketName();
BucketVersioningConfiguration versioningConfiguration = setBucketVersioningConfigurationRequest.getVersioningConfiguration();
rejectNull(bucketName,
"The bucket name parameter must be specified when setting versioning configuration");
rejectNull(versioningConfiguration,
"The bucket versioning parameter must be specified when setting versioning configuration");
if (versioningConfiguration.isMfaDeleteEnabled() != null) {
rejectNull(setBucketVersioningConfigurationRequest.getMfa(),
"The MFA parameter must be specified when changing MFA Delete status in the versioning configuration");
}
Request request = createRequest(bucketName, null, setBucketVersioningConfigurationRequest, HttpMethodName.PUT);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "PutBucketVersioning");
request.addParameter("versioning", null);
if (versioningConfiguration.isMfaDeleteEnabled() != null) {
if (setBucketVersioningConfigurationRequest.getMfa() != null) {
populateRequestWithMfaDetails(request, setBucketVersioningConfigurationRequest.getMfa());
}
}
byte[] bytes = bucketConfigurationXmlFactory.convertToXmlByteArray(versioningConfiguration);
request.setContent(new ByteArrayInputStream(bytes));
populateRequestHeaderWithMd5(request, bytes);
invoke(request, voidResponseHandler, bucketName, null);
}
@Override
public BucketVersioningConfiguration getBucketVersioningConfiguration(String bucketName)
throws SdkClientException, AmazonServiceException {
return getBucketVersioningConfiguration(new GetBucketVersioningConfigurationRequest(bucketName));
}
@Override
public BucketVersioningConfiguration getBucketVersioningConfiguration(GetBucketVersioningConfigurationRequest getBucketVersioningConfigurationRequest)
throws SdkClientException, AmazonServiceException {
getBucketVersioningConfigurationRequest = beforeClientExecution(getBucketVersioningConfigurationRequest);
rejectNull(getBucketVersioningConfigurationRequest, "The request object parameter getBucketVersioningConfigurationRequest must be specified.");
String bucketName = getBucketVersioningConfigurationRequest.getBucketName();
rejectNull(bucketName,
"The bucket name parameter must be specified when querying versioning configuration");
Request request = createRequest(bucketName, null, getBucketVersioningConfigurationRequest, HttpMethodName.GET);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "GetBucketVersioning");
request.addParameter("versioning", null);
return invoke(request, new Unmarshallers.BucketVersioningConfigurationUnmarshaller(), bucketName, null);
}
@Override
public BucketWebsiteConfiguration getBucketWebsiteConfiguration(String bucketName)
throws SdkClientException, AmazonServiceException {
return getBucketWebsiteConfiguration(new GetBucketWebsiteConfigurationRequest(bucketName));
}
@Override
public BucketWebsiteConfiguration getBucketWebsiteConfiguration(GetBucketWebsiteConfigurationRequest getBucketWebsiteConfigurationRequest)
throws SdkClientException, AmazonServiceException {
getBucketWebsiteConfigurationRequest = beforeClientExecution(getBucketWebsiteConfigurationRequest);
rejectNull(getBucketWebsiteConfigurationRequest, "The request object parameter getBucketWebsiteConfigurationRequest must be specified.");
String bucketName = getBucketWebsiteConfigurationRequest.getBucketName();
rejectNull(bucketName,
"The bucket name parameter must be specified when requesting a bucket's website configuration");
Request request = createRequest(bucketName, null, getBucketWebsiteConfigurationRequest, HttpMethodName.GET);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "GetBucketWebsite");
request.addParameter("website", null);
request.addHeader("Content-Type", "application/xml");
try {
return invoke(request, new Unmarshallers.BucketWebsiteConfigurationUnmarshaller(), bucketName, null);
} catch (AmazonServiceException ase) {
if (ase.getStatusCode() == 404) return null;
throw ase;
}
}
@Override
public BucketLifecycleConfiguration getBucketLifecycleConfiguration(String bucketName) {
return getBucketLifecycleConfiguration(new GetBucketLifecycleConfigurationRequest(bucketName));
}
@Override
public BucketLifecycleConfiguration getBucketLifecycleConfiguration(GetBucketLifecycleConfigurationRequest getBucketLifecycleConfigurationRequest) {
getBucketLifecycleConfigurationRequest = beforeClientExecution(getBucketLifecycleConfigurationRequest);
rejectNull(getBucketLifecycleConfigurationRequest, "The request object pamameter getBucketLifecycleConfigurationRequest must be specified.");
String bucketName = getBucketLifecycleConfigurationRequest.getBucketName();
rejectNull(bucketName, "The bucket name must be specifed when retrieving the bucket lifecycle configuration.");
Request request = createRequest(bucketName, null, getBucketLifecycleConfigurationRequest, HttpMethodName.GET);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "GetBucketLifecycleConfiguration");
request.addParameter("lifecycle", null);
try {
ResponseHeaderHandlerChain handlerChain = new ResponseHeaderHandlerChain(
new Unmarshallers.BucketLifecycleConfigurationUnmarshaller(),
new BucketLifecycleConfigurationHeaderHandler()
);
return invoke(request, handlerChain, bucketName, null);
} catch (AmazonServiceException ase) {
switch (ase.getStatusCode()) {
case 404:
return null;
default:
throw ase;
}
}
}
@Override
public void setBucketLifecycleConfiguration(String bucketName, BucketLifecycleConfiguration bucketLifecycleConfiguration) {
setBucketLifecycleConfiguration(new SetBucketLifecycleConfigurationRequest(bucketName, bucketLifecycleConfiguration));
}
@Override
public void setBucketLifecycleConfiguration(
SetBucketLifecycleConfigurationRequest setBucketLifecycleConfigurationRequest) {
setBucketLifecycleConfigurationRequest = beforeClientExecution(setBucketLifecycleConfigurationRequest);
rejectNull(setBucketLifecycleConfigurationRequest,
"The set bucket lifecycle configuration request object must be specified.");
String bucketName = setBucketLifecycleConfigurationRequest.getBucketName();
BucketLifecycleConfiguration bucketLifecycleConfiguration = setBucketLifecycleConfigurationRequest.getLifecycleConfiguration();
rejectNull(bucketName,
"The bucket name parameter must be specified when setting bucket lifecycle configuration.");
rejectNull(bucketLifecycleConfiguration,
"The lifecycle configuration parameter must be specified when setting bucket lifecycle configuration.");
TransitionDefaultMinimumObjectSize transitionDefaultMinimumObjectSize = bucketLifecycleConfiguration.getTransitionDefaultMinimumObjectSize();
Request request = createRequest(bucketName, null, setBucketLifecycleConfigurationRequest, HttpMethodName.PUT);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "PutBucketLifecycleConfiguration");
request.addParameter("lifecycle", null);
byte[] content = new BucketConfigurationXmlFactory().convertToXmlByteArray(bucketLifecycleConfiguration);
request.addHeader("Content-Length", String.valueOf(content.length));
request.addHeader("Content-Type", "application/xml");
if (transitionDefaultMinimumObjectSize != null) {
request.addHeader(TRANSITION_DEFAULT_MINIMUM_OBJECT_SIZE, transitionDefaultMinimumObjectSize.toString());
}
request.setContent(new ByteArrayInputStream(content));
populateRequestHeaderWithMd5(request, content);
invoke(request, voidResponseHandler, bucketName, null);
}
@Override
public void deleteBucketLifecycleConfiguration(String bucketName) {
deleteBucketLifecycleConfiguration(new DeleteBucketLifecycleConfigurationRequest(bucketName));
}
@Override
public void deleteBucketLifecycleConfiguration(
DeleteBucketLifecycleConfigurationRequest deleteBucketLifecycleConfigurationRequest) {
deleteBucketLifecycleConfigurationRequest = beforeClientExecution(deleteBucketLifecycleConfigurationRequest);
rejectNull(deleteBucketLifecycleConfigurationRequest,
"The delete bucket lifecycle configuration request object must be specified.");
String bucketName = deleteBucketLifecycleConfigurationRequest.getBucketName();
rejectNull(bucketName,
"The bucket name parameter must be specified when deleting bucket lifecycle configuration.");
Request request = createRequest(bucketName, null, deleteBucketLifecycleConfigurationRequest, HttpMethodName.DELETE);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "DeleteBucketLifecycle");
request.addParameter("lifecycle", null);
invoke(request, voidResponseHandler, bucketName, null);
}
@Override
public BucketCrossOriginConfiguration getBucketCrossOriginConfiguration(String bucketName) {
return getBucketCrossOriginConfiguration(new GetBucketCrossOriginConfigurationRequest(bucketName));
}
@Override
public BucketCrossOriginConfiguration getBucketCrossOriginConfiguration(GetBucketCrossOriginConfigurationRequest getBucketCrossOriginConfigurationRequest) {
getBucketCrossOriginConfigurationRequest = beforeClientExecution(getBucketCrossOriginConfigurationRequest);
rejectNull(getBucketCrossOriginConfigurationRequest, "The request object parameter getBucketCrossOriginConfigurationRequest must be specified.");
String bucketName = getBucketCrossOriginConfigurationRequest.getBucketName();
rejectNull(bucketName, "The bucket name must be specified when retrieving the bucket cross origin configuration.");
Request request = createRequest(bucketName, null, getBucketCrossOriginConfigurationRequest, HttpMethodName.GET);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "GetBucketCors");
request.addParameter("cors", null);
try {
return invoke(request, new Unmarshallers.BucketCrossOriginConfigurationUnmarshaller(), bucketName, null);
} catch (AmazonServiceException ase) {
switch (ase.getStatusCode()) {
case 404:
return null;
default:
throw ase;
}
}
}
@Override
public void setBucketCrossOriginConfiguration(String bucketName, BucketCrossOriginConfiguration bucketCrossOriginConfiguration) {
setBucketCrossOriginConfiguration(new SetBucketCrossOriginConfigurationRequest(bucketName, bucketCrossOriginConfiguration));
}
@Override
public void setBucketCrossOriginConfiguration(
SetBucketCrossOriginConfigurationRequest setBucketCrossOriginConfigurationRequest) {
setBucketCrossOriginConfigurationRequest = beforeClientExecution(setBucketCrossOriginConfigurationRequest);
rejectNull(setBucketCrossOriginConfigurationRequest,
"The set bucket cross origin configuration request object must be specified.");
String bucketName = setBucketCrossOriginConfigurationRequest.getBucketName();
BucketCrossOriginConfiguration bucketCrossOriginConfiguration = setBucketCrossOriginConfigurationRequest.getCrossOriginConfiguration();
rejectNull(bucketName,
"The bucket name parameter must be specified when setting bucket cross origin configuration.");
rejectNull(bucketCrossOriginConfiguration,
"The cross origin configuration parameter must be specified when setting bucket cross origin configuration.");
Request request = createRequest(bucketName, null, setBucketCrossOriginConfigurationRequest, HttpMethodName.PUT);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "PutBucketCors");
request.addParameter("cors", null);
byte[] content = new BucketConfigurationXmlFactory().convertToXmlByteArray(bucketCrossOriginConfiguration);
request.addHeader("Content-Length", String.valueOf(content.length));
request.addHeader("Content-Type", "application/xml");
request.setContent(new ByteArrayInputStream(content));
populateRequestHeaderWithMd5(request, content);
invoke(request, voidResponseHandler, bucketName, null);
}
@Override
public void deleteBucketCrossOriginConfiguration(String bucketName) {
deleteBucketCrossOriginConfiguration(new DeleteBucketCrossOriginConfigurationRequest(bucketName));
}
@Override
public void deleteBucketCrossOriginConfiguration(
DeleteBucketCrossOriginConfigurationRequest deleteBucketCrossOriginConfigurationRequest) {
deleteBucketCrossOriginConfigurationRequest = beforeClientExecution(deleteBucketCrossOriginConfigurationRequest);
rejectNull(deleteBucketCrossOriginConfigurationRequest,
"The delete bucket cross origin configuration request object must be specified.");
String bucketName = deleteBucketCrossOriginConfigurationRequest.getBucketName();
rejectNull(bucketName,
"The bucket name parameter must be specified when deleting bucket cross origin configuration.");
Request request = createRequest(bucketName, null, deleteBucketCrossOriginConfigurationRequest, HttpMethodName.DELETE);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "DeleteBucketCors");
request.addParameter("cors", null);
invoke(request, voidResponseHandler, bucketName, null);
}
@Override
public BucketTaggingConfiguration getBucketTaggingConfiguration(String bucketName) {
return getBucketTaggingConfiguration(new GetBucketTaggingConfigurationRequest(bucketName));
}
@Override
public BucketTaggingConfiguration getBucketTaggingConfiguration(GetBucketTaggingConfigurationRequest getBucketTaggingConfigurationRequest) {
getBucketTaggingConfigurationRequest = beforeClientExecution(getBucketTaggingConfigurationRequest);
rejectNull(getBucketTaggingConfigurationRequest, "The request object parameter getBucketTaggingConfigurationRequest must be specifed.");
String bucketName = getBucketTaggingConfigurationRequest.getBucketName();
rejectNull(bucketName, "The bucket name must be specified when retrieving the bucket tagging configuration.");
Request request = createRequest(bucketName, null, getBucketTaggingConfigurationRequest, HttpMethodName.GET);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "GetBucketTagging");
request.addParameter("tagging", null);
try {
return invoke(request, new Unmarshallers.BucketTaggingConfigurationUnmarshaller(), bucketName, null);
} catch (AmazonServiceException ase) {
switch (ase.getStatusCode()) {
case 404:
return null;
default:
throw ase;
}
}
}
@Override
public void setBucketTaggingConfiguration(String bucketName, BucketTaggingConfiguration bucketTaggingConfiguration) {
setBucketTaggingConfiguration(new SetBucketTaggingConfigurationRequest(bucketName, bucketTaggingConfiguration));
}
@Override
public void setBucketTaggingConfiguration(
SetBucketTaggingConfigurationRequest setBucketTaggingConfigurationRequest) {
setBucketTaggingConfigurationRequest = beforeClientExecution(setBucketTaggingConfigurationRequest);
rejectNull(setBucketTaggingConfigurationRequest,
"The set bucket tagging configuration request object must be specified.");
String bucketName = setBucketTaggingConfigurationRequest.getBucketName();
BucketTaggingConfiguration bucketTaggingConfiguration = setBucketTaggingConfigurationRequest.getTaggingConfiguration();
rejectNull(bucketName,
"The bucket name parameter must be specified when setting bucket tagging configuration.");
rejectNull(bucketTaggingConfiguration,
"The tagging configuration parameter must be specified when setting bucket tagging configuration.");
Request request = createRequest(bucketName, null, setBucketTaggingConfigurationRequest, HttpMethodName.PUT);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "PutBucketTagging");
request.addParameter("tagging", null);
byte[] content = new BucketConfigurationXmlFactory().convertToXmlByteArray(bucketTaggingConfiguration);
request.addHeader("Content-Length", String.valueOf(content.length));
request.addHeader("Content-Type", "application/xml");
request.setContent(new ByteArrayInputStream(content));
populateRequestHeaderWithMd5(request, content);
invoke(request, voidResponseHandler, bucketName, null);
}
@Override
public void deleteBucketTaggingConfiguration(String bucketName) {
deleteBucketTaggingConfiguration(new DeleteBucketTaggingConfigurationRequest(bucketName));
}
@Override
public void deleteBucketTaggingConfiguration(
DeleteBucketTaggingConfigurationRequest deleteBucketTaggingConfigurationRequest) {
deleteBucketTaggingConfigurationRequest = beforeClientExecution(deleteBucketTaggingConfigurationRequest);
rejectNull(deleteBucketTaggingConfigurationRequest,
"The delete bucket tagging configuration request object must be specified.");
String bucketName = deleteBucketTaggingConfigurationRequest.getBucketName();
rejectNull(bucketName,
"The bucket name parameter must be specified when deleting bucket tagging configuration.");
Request request = createRequest(bucketName, null, deleteBucketTaggingConfigurationRequest, HttpMethodName.DELETE);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "DeleteBucketTagging");
request.addParameter("tagging", null);
invoke(request, voidResponseHandler, bucketName, null);
}
@Override
public void setBucketWebsiteConfiguration(String bucketName, BucketWebsiteConfiguration configuration)
throws SdkClientException, AmazonServiceException {
setBucketWebsiteConfiguration(new SetBucketWebsiteConfigurationRequest(bucketName, configuration));
}
@Override
public void setBucketWebsiteConfiguration(SetBucketWebsiteConfigurationRequest setBucketWebsiteConfigurationRequest)
throws SdkClientException, AmazonServiceException {
setBucketWebsiteConfigurationRequest = beforeClientExecution(setBucketWebsiteConfigurationRequest);
String bucketName = setBucketWebsiteConfigurationRequest.getBucketName();
BucketWebsiteConfiguration configuration = setBucketWebsiteConfigurationRequest.getConfiguration();
rejectNull(bucketName,
"The bucket name parameter must be specified when setting a bucket's website configuration");
rejectNull(configuration,
"The bucket website configuration parameter must be specified when setting a bucket's website configuration");
if (configuration.getRedirectAllRequestsTo() == null) {
rejectNull(configuration.getIndexDocumentSuffix(),
"The bucket website configuration parameter must specify the index document suffix when setting a bucket's website configuration");
}
Request request = createRequest(bucketName, null, setBucketWebsiteConfigurationRequest, HttpMethodName.PUT);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "PutBucketWebsite");
request.addParameter("website", null);
request.addHeader("Content-Type", "application/xml");
byte[] bytes = bucketConfigurationXmlFactory.convertToXmlByteArray(configuration);
request.setContent(new ByteArrayInputStream(bytes));
populateRequestHeaderWithMd5(request, bytes);
invoke(request, voidResponseHandler, bucketName, null);
}
@Override
public void deleteBucketWebsiteConfiguration(String bucketName)
throws SdkClientException, AmazonServiceException {
deleteBucketWebsiteConfiguration(new DeleteBucketWebsiteConfigurationRequest(bucketName));
}
@Override
public void deleteBucketWebsiteConfiguration(DeleteBucketWebsiteConfigurationRequest deleteBucketWebsiteConfigurationRequest)
throws SdkClientException, AmazonServiceException {
deleteBucketWebsiteConfigurationRequest = beforeClientExecution(deleteBucketWebsiteConfigurationRequest);
String bucketName = deleteBucketWebsiteConfigurationRequest.getBucketName();
rejectNull(bucketName,
"The bucket name parameter must be specified when deleting a bucket's website configuration");
Request request = createRequest(bucketName, null, deleteBucketWebsiteConfigurationRequest, HttpMethodName.DELETE);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "DeleteBucketWebsite");
request.addParameter("website", null);
request.addHeader("Content-Type", "application/xml");
invoke(request, voidResponseHandler, bucketName, null);
}
@Override
public void setBucketNotificationConfiguration(String bucketName, BucketNotificationConfiguration bucketNotificationConfiguration)
throws SdkClientException, AmazonServiceException {
setBucketNotificationConfiguration(new SetBucketNotificationConfigurationRequest(bucketName, bucketNotificationConfiguration));
}
@Override
public void setBucketNotificationConfiguration(
SetBucketNotificationConfigurationRequest setBucketNotificationConfigurationRequest)
throws SdkClientException, AmazonServiceException {
setBucketNotificationConfigurationRequest = beforeClientExecution(setBucketNotificationConfigurationRequest);
rejectNull(setBucketNotificationConfigurationRequest,
"The set bucket notification configuration request object must be specified.");
String bucketName = setBucketNotificationConfigurationRequest.getBucketName();
BucketNotificationConfiguration bucketNotificationConfiguration = setBucketNotificationConfigurationRequest.getNotificationConfiguration();
Boolean skipDestinationValidation = setBucketNotificationConfigurationRequest.getSkipDestinationValidation();
rejectNull(bucketName,
"The bucket name parameter must be specified when setting bucket notification configuration.");
rejectNull(bucketNotificationConfiguration,
"The notification configuration parameter must be specified when setting bucket notification configuration.");
Request request = createRequest(bucketName, null, setBucketNotificationConfigurationRequest, HttpMethodName.PUT);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "PutBucketNotificationConfiguration");
request.addParameter("notification", null);
if (skipDestinationValidation != null) {
request.addHeader("x-amz-skip-destination-validation", Boolean.toString(skipDestinationValidation));
}
byte[] bytes = bucketConfigurationXmlFactory.convertToXmlByteArray(bucketNotificationConfiguration);
request.setContent(new ByteArrayInputStream(bytes));
invoke(request, voidResponseHandler, bucketName, null);
}
@Override
public BucketNotificationConfiguration getBucketNotificationConfiguration(String bucketName)
throws SdkClientException, AmazonServiceException {
return getBucketNotificationConfiguration(new GetBucketNotificationConfigurationRequest(bucketName));
}
@Override
public BucketNotificationConfiguration getBucketNotificationConfiguration(GetBucketNotificationConfigurationRequest getBucketNotificationConfigurationRequest)
throws SdkClientException, AmazonServiceException {
getBucketNotificationConfigurationRequest = beforeClientExecution(getBucketNotificationConfigurationRequest);
rejectNull(getBucketNotificationConfigurationRequest,
"The bucket request parameter must be specified when querying notification configuration");
String bucketName = getBucketNotificationConfigurationRequest.getBucketName();
rejectNull(bucketName,
"The bucket request must specify a bucket name when querying notification configuration");
Request request = createRequest(bucketName, null, getBucketNotificationConfigurationRequest, HttpMethodName.GET);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "GetBucketNotificationConfiguration");
request.addParameter("notification", null);
return invoke(request, BucketNotificationConfigurationStaxUnmarshaller.getInstance(), bucketName, null);
}
@Override
public BucketLoggingConfiguration getBucketLoggingConfiguration(String bucketName)
throws SdkClientException, AmazonServiceException {
return getBucketLoggingConfiguration(new GetBucketLoggingConfigurationRequest(bucketName));
}
@Override
public BucketLoggingConfiguration getBucketLoggingConfiguration(GetBucketLoggingConfigurationRequest getBucketLoggingConfigurationRequest)
throws SdkClientException, AmazonServiceException {
getBucketLoggingConfigurationRequest = beforeClientExecution(getBucketLoggingConfigurationRequest);
rejectNull(getBucketLoggingConfigurationRequest, "The request object parameter getBucketLoggingConfigurationRequest must be specifed.");
String bucketName = getBucketLoggingConfigurationRequest.getBucketName();
rejectNull(bucketName,
"The bucket name parameter must be specified when requesting a bucket's logging status");
Request request = createRequest(bucketName, null, getBucketLoggingConfigurationRequest, HttpMethodName.GET);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "GetBucketLogging");
request.addParameter("logging", null);
return invoke(request, new Unmarshallers.BucketLoggingConfigurationnmarshaller(), bucketName, null);
}
@Override
public void setBucketLoggingConfiguration(SetBucketLoggingConfigurationRequest setBucketLoggingConfigurationRequest)
throws SdkClientException, AmazonServiceException {
setBucketLoggingConfigurationRequest = beforeClientExecution(setBucketLoggingConfigurationRequest);
rejectNull(setBucketLoggingConfigurationRequest,
"The set bucket logging configuration request object must be specified when enabling server access logging");
String bucketName = setBucketLoggingConfigurationRequest.getBucketName();
BucketLoggingConfiguration loggingConfiguration = setBucketLoggingConfigurationRequest.getLoggingConfiguration();
rejectNull(bucketName,
"The bucket name parameter must be specified when enabling server access logging");
rejectNull(loggingConfiguration,
"The logging configuration parameter must be specified when enabling server access logging");
Request request = createRequest(bucketName, null, setBucketLoggingConfigurationRequest, HttpMethodName.PUT);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "PutBucketLogging");
request.addParameter("logging", null);
byte[] bytes = bucketConfigurationXmlFactory.convertToXmlByteArray(loggingConfiguration);
request.setContent(new ByteArrayInputStream(bytes));
populateRequestHeaderWithMd5(request, bytes);
invoke(request, voidResponseHandler, bucketName, null);
}
@Override
public BucketAccelerateConfiguration getBucketAccelerateConfiguration(
String bucketName) throws AmazonServiceException,
SdkClientException {
return getBucketAccelerateConfiguration(new GetBucketAccelerateConfigurationRequest(
bucketName));
}
@Override
public BucketAccelerateConfiguration getBucketAccelerateConfiguration(
GetBucketAccelerateConfigurationRequest getBucketAccelerateConfigurationRequest)
throws AmazonServiceException, SdkClientException {
getBucketAccelerateConfigurationRequest = beforeClientExecution(getBucketAccelerateConfigurationRequest);
rejectNull(getBucketAccelerateConfigurationRequest, "getBucketAccelerateConfigurationRequest must be specified.");
String bucketName = getBucketAccelerateConfigurationRequest.getBucketName();
rejectNull(bucketName,
"The bucket name parameter must be specified when querying accelerate configuration");
Request request = createRequest(bucketName, null, getBucketAccelerateConfigurationRequest, HttpMethodName.GET);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "GetBucketAccelerateConfiguration");
request.addParameter("accelerate", null);
populateRequesterPaysHeader(request, getBucketAccelerateConfigurationRequest.isRequesterPays());
@SuppressWarnings("unchecked")
ResponseHeaderHandlerChain responseHandler =
new ResponseHeaderHandlerChain(
// xml payload unmarshaller
new Unmarshallers.BucketAccelerateConfigurationUnmarshaller(),
// header handler
new S3RequesterChargedHeaderHandler());
return invoke(request, responseHandler, bucketName, null);
}
@Override
public void setBucketAccelerateConfiguration(String bucketName,
BucketAccelerateConfiguration accelerateConfiguration)
throws AmazonServiceException, SdkClientException {
setBucketAccelerateConfiguration(new SetBucketAccelerateConfigurationRequest(
bucketName, accelerateConfiguration));
}
@Override
public void setBucketAccelerateConfiguration(
SetBucketAccelerateConfigurationRequest setBucketAccelerateConfigurationRequest)
throws AmazonServiceException, SdkClientException {
setBucketAccelerateConfigurationRequest = beforeClientExecution(setBucketAccelerateConfigurationRequest);
rejectNull(setBucketAccelerateConfigurationRequest,
"setBucketAccelerateConfigurationRequest must be specified");
String bucketName = setBucketAccelerateConfigurationRequest.getBucketName();
BucketAccelerateConfiguration accelerateConfiguration = setBucketAccelerateConfigurationRequest.getAccelerateConfiguration();
rejectNull(bucketName,
"The bucket name parameter must be specified when setting accelerate configuration.");
rejectNull(accelerateConfiguration,
"The bucket accelerate configuration parameter must be specified.");
rejectNull(accelerateConfiguration.getStatus(),
"The status parameter must be specified when updating bucket accelerate configuration.");
Request request = createRequest(
bucketName, null, setBucketAccelerateConfigurationRequest,
HttpMethodName.PUT);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "PutBucketAccelerateConfiguration");
request.addParameter("accelerate", null);
byte[] bytes = bucketConfigurationXmlFactory.convertToXmlByteArray(accelerateConfiguration);
request.setContent(new ByteArrayInputStream(bytes));
invoke(request, voidResponseHandler, bucketName, null);
}
@Override
public BucketPolicy getBucketPolicy(String bucketName)
throws SdkClientException, AmazonServiceException {
return getBucketPolicy(new GetBucketPolicyRequest(bucketName));
}
@Override
public void deleteBucketPolicy(String bucketName)
throws SdkClientException, AmazonServiceException {
deleteBucketPolicy(new DeleteBucketPolicyRequest(bucketName));
}
@Override
public BucketPolicy getBucketPolicy(
GetBucketPolicyRequest getBucketPolicyRequest)
throws SdkClientException, AmazonServiceException {
getBucketPolicyRequest = beforeClientExecution(getBucketPolicyRequest);
rejectNull(getBucketPolicyRequest,
"The request object must be specified when getting a bucket policy");
String bucketName = getBucketPolicyRequest.getBucketName();
rejectNull(bucketName,
"The bucket name must be specified when getting a bucket policy");
Request request = createRequest(bucketName, null, getBucketPolicyRequest, HttpMethodName.GET);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "GetBucketPolicy");
request.addParameter("policy", null);
BucketPolicy result = new BucketPolicy();
try {
String policyText = invoke(request, new S3StringResponseHandler(), bucketName, null);
result.setPolicyText(policyText);
return result;
} catch (AmazonServiceException ase) {
/*
* If we receive an error response telling us that no policy has
* been set for this bucket, then instead of forcing the user to
* deal with the exception, we'll just return an empty result. Any
* other exceptions will be rethrown for the user to handle.
*/
if (ase.getErrorCode().equals("NoSuchBucketPolicy")) return result;
throw ase;
}
}
@Override
public void setBucketPolicy(String bucketName, String policyText)
throws SdkClientException, AmazonServiceException {
setBucketPolicy(new SetBucketPolicyRequest(bucketName, policyText));
}
@Override
public void setBucketPolicy(SetBucketPolicyRequest setBucketPolicyRequest)
throws SdkClientException, AmazonServiceException {
setBucketPolicyRequest = beforeClientExecution(setBucketPolicyRequest);
rejectNull(setBucketPolicyRequest,
"The request object must be specified when setting a bucket policy");
String bucketName = setBucketPolicyRequest.getBucketName();
String policyText = setBucketPolicyRequest.getPolicyText();
rejectNull(bucketName,
"The bucket name must be specified when setting a bucket policy");
rejectNull(policyText,
"The policy text must be specified when setting a bucket policy");
Request request = createRequest(bucketName, null, setBucketPolicyRequest, HttpMethodName.PUT);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "PutBucketPolicy");
request.addParameter("policy", null);
byte[] content = ServiceUtils.toByteArray(policyText);
request.setContent(new ByteArrayInputStream(content));
populateRequestHeaderWithMd5(request, content);
if (setBucketPolicyRequest.getConfirmRemoveSelfBucketAccess() != null &&
setBucketPolicyRequest.getConfirmRemoveSelfBucketAccess()) {
request.addHeader(Headers.REMOVE_SELF_BUCKET_ACCESS, "true");
}
invoke(request, voidResponseHandler, bucketName, null);
}
@Override
public void deleteBucketPolicy(
DeleteBucketPolicyRequest deleteBucketPolicyRequest)
throws SdkClientException, AmazonServiceException {
deleteBucketPolicyRequest = beforeClientExecution(deleteBucketPolicyRequest);
rejectNull(deleteBucketPolicyRequest,
"The request object must be specified when deleting a bucket policy");
String bucketName = deleteBucketPolicyRequest.getBucketName();
rejectNull(bucketName,
"The bucket name must be specified when deleting a bucket policy");
Request request = createRequest(bucketName, null, deleteBucketPolicyRequest, HttpMethodName.DELETE);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "DeleteBucketPolicy");
request.addParameter("policy", null);
invoke(request, voidResponseHandler, bucketName, null);
}
@Override
public DeleteBucketEncryptionResult deleteBucketEncryption(String bucketName) throws SdkClientException {
return deleteBucketEncryption(new DeleteBucketEncryptionRequest().withBucketName(bucketName));
}
@Override
public DeleteBucketEncryptionResult deleteBucketEncryption(DeleteBucketEncryptionRequest deleteBucketEncryptionRequest)
throws SdkClientException {
deleteBucketEncryptionRequest = beforeClientExecution(deleteBucketEncryptionRequest);
rejectNull(deleteBucketEncryptionRequest,
"The request object must be specified when deleting a bucket encryption configuration");
String bucketName = deleteBucketEncryptionRequest.getBucketName();
rejectNull(bucketName,
"The bucket name must be specified when deleting a bucket encryption configuration");
Request request =
createRequest(bucketName, null, deleteBucketEncryptionRequest, HttpMethodName.DELETE);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "DeleteBucketEncryption");
request.addParameter("encryption", null);
return invoke(request, new Unmarshallers.DeleteBucketEncryptionUnmarshaller(), bucketName, null);
}
@Override
public GetBucketEncryptionResult getBucketEncryption(String bucketName) throws SdkClientException {
return getBucketEncryption(new GetBucketEncryptionRequest().withBucketName(bucketName));
}
@Override
public GetBucketEncryptionResult getBucketEncryption(GetBucketEncryptionRequest getBucketEncryptionRequest) throws SdkClientException {
getBucketEncryptionRequest = beforeClientExecution(getBucketEncryptionRequest);
rejectNull(getBucketEncryptionRequest,
"The bucket request parameter must be specified when querying encryption configuration");
String bucketName = getBucketEncryptionRequest.getBucketName();
rejectNull(bucketName,
"The bucket request must specify a bucket name when querying encryption configuration");
Request request = createRequest(bucketName, null, getBucketEncryptionRequest, HttpMethodName.GET);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "GetBucketEncryption");
request.addParameter("encryption", null);
return invoke(request, GetBucketEncryptionStaxUnmarshaller.getInstance(), bucketName, null);
}
@Override
public SetBucketEncryptionResult setBucketEncryption(SetBucketEncryptionRequest setBucketEncryptionRequest)
throws AmazonServiceException, SdkClientException {
setBucketEncryptionRequest = beforeClientExecution(setBucketEncryptionRequest);
rejectNull(setBucketEncryptionRequest,
"The request object must be specified.");
String bucketName = setBucketEncryptionRequest.getBucketName();
ServerSideEncryptionConfiguration sseConfig = setBucketEncryptionRequest.getServerSideEncryptionConfiguration();
rejectNull(bucketName,
"The bucket name parameter must be specified when setting bucket encryption configuration.");
rejectNull(sseConfig,
"The SSE configuration parameter must be specified when setting bucket encryption configuration.");
Request request = createRequest(bucketName, null, setBucketEncryptionRequest, HttpMethodName.PUT);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "PutBucketEncryption");
request.addParameter("encryption", null);
byte[] bytes = bucketConfigurationXmlFactory.convertToXmlByteArray(sseConfig);
request.setContent(new ByteArrayInputStream(bytes));
populateRequestHeaderWithMd5(request, bytes);
return invoke(request, new Unmarshallers.SetBucketEncryptionUnmarshaller(), bucketName, null);
}
@Override
public SetPublicAccessBlockResult setPublicAccessBlock(SetPublicAccessBlockRequest setPublicAccessBlockRequest) {
setPublicAccessBlockRequest = beforeClientExecution(setPublicAccessBlockRequest);
rejectNull(setPublicAccessBlockRequest, "The request object must be specified.");
String bucketName = setPublicAccessBlockRequest.getBucketName();
PublicAccessBlockConfiguration config = setPublicAccessBlockRequest.getPublicAccessBlockConfiguration();
rejectNull(bucketName,
"The bucket name parameter must be specified when setting public block configuration.");
rejectNull(config,
"The PublicAccessBlockConfiguration parameter must be specified when setting public block");
Request request = createRequest(bucketName, null, setPublicAccessBlockRequest, HttpMethodName.PUT);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "PutPublicAccessBlock");
request.addParameter("publicAccessBlock", null);
byte[] bytes = bucketConfigurationXmlFactory.convertToXmlByteArray(config);
request.setContent(new ByteArrayInputStream(bytes));
populateRequestHeaderWithMd5(request, bytes);
return invoke(request, new Unmarshallers.SetPublicAccessBlockUnmarshaller(), bucketName, null);
}
@Override
public GetPublicAccessBlockResult getPublicAccessBlock(GetPublicAccessBlockRequest getPublicAccessBlockRequest) {
getPublicAccessBlockRequest = beforeClientExecution(getPublicAccessBlockRequest);
rejectNull(getPublicAccessBlockRequest, "The request object must be specified.");
String bucketName = getPublicAccessBlockRequest.getBucketName();
rejectNull(bucketName,
"The bucket name parameter must be specified when getting public block configuration.");
Request request = createRequest(bucketName, null, getPublicAccessBlockRequest, HttpMethodName.GET);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "GetPublicAccessBlock");
request.addParameter("publicAccessBlock", null);
return invoke(request, GetPublicAccessBlockStaxUnmarshaller.getInstance(), bucketName, null);
}
@Override
public DeletePublicAccessBlockResult deletePublicAccessBlock(DeletePublicAccessBlockRequest deletePublicAccessBlockRequest) {
deletePublicAccessBlockRequest = beforeClientExecution(deletePublicAccessBlockRequest);
rejectNull(deletePublicAccessBlockRequest, "The request object must be specified.");
String bucketName = deletePublicAccessBlockRequest.getBucketName();
rejectNull(bucketName,
"The bucket name parameter must be specified when deleting public block configuration.");
Request request = createRequest(bucketName, null, deletePublicAccessBlockRequest, HttpMethodName.DELETE);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "DeletePublicAccessBlock");
request.addParameter("publicAccessBlock", null);
return invoke(request, new Unmarshallers.DeletePublicAccessBlockUnmarshaller(), bucketName, null);
}
@Override
public GetBucketPolicyStatusResult getBucketPolicyStatus(GetBucketPolicyStatusRequest getBucketPolicyStatusRequest) {
getBucketPolicyStatusRequest = beforeClientExecution(getBucketPolicyStatusRequest);
rejectNull(getBucketPolicyStatusRequest, "The request object must be specified.");
String bucketName = getBucketPolicyStatusRequest.getBucketName();
rejectNull(bucketName,
"The bucket name parameter must be specified when getting bucket policy status");
Request request = createRequest(bucketName, null, getBucketPolicyStatusRequest, HttpMethodName.GET);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "GetBucketPolicyStatus");
request.addParameter("policyStatus", null);
return invoke(request, GetBucketPolicyStatusStaxUnmarshaller.getInstance(), bucketName, null);
}
@Override
public SelectObjectContentResult selectObjectContent(SelectObjectContentRequest selectRequest) throws AmazonServiceException, SdkClientException {
selectRequest = beforeClientExecution(selectRequest);
rejectNull(selectRequest, "The request parameter must be specified");
rejectNull(selectRequest.getBucketName(), "The bucket name parameter must be specified when selecting object content.");
rejectNull(selectRequest.getKey(), "The key parameter must be specified when selecting object content.");
Request request = createRequest(selectRequest.getBucketName(), selectRequest.getKey(), selectRequest, HttpMethodName.POST);
request.addParameter("select", null);
request.addParameter("select-type", "2");
populateSSE_C(request, selectRequest.getSSECustomerKey());
setContent(request, RequestXmlFactory.convertToXmlByteArray(selectRequest), ContentType.APPLICATION_XML.toString(), true);
S3Object result = invoke(request, new S3ObjectResponseHandler(), selectRequest.getBucketName(), selectRequest.getKey());
// Hold a reference to this client while the InputStream is still
// around - otherwise a finalizer in the HttpClient may reset the
// underlying TCP connection out from under us.
SdkFilterInputStream resultStream = new ServiceClientHolderInputStream(result.getObjectContent(), this);
return new SelectObjectContentResult().withPayload(new SelectObjectContentEventStream(resultStream));
}
@Override
public SetObjectLegalHoldResult setObjectLegalHold(SetObjectLegalHoldRequest setObjectLegalHoldRequest) {
setObjectLegalHoldRequest = beforeClientExecution(setObjectLegalHoldRequest);
rejectNull(setObjectLegalHoldRequest, "The request parameter must be specified");
String bucketName = setObjectLegalHoldRequest.getBucketName();
String key = setObjectLegalHoldRequest.getKey();
rejectNull(bucketName, "The bucket name parameter must be specified when setting the object legal hold.");
rejectNull(key, "The key parameter must be specified when setting the object legal hold.");
Request request = createRequest(bucketName, key, setObjectLegalHoldRequest, HttpMethodName.PUT);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "PutObjectLegalHold");
setContent(request, new ObjectLockLegalHoldXmlFactory().convertToXmlByteArray(setObjectLegalHoldRequest.getLegalHold()),
ContentType.APPLICATION_XML.toString(), true);
request.addParameter("legal-hold", null);
addParameterIfNotNull(request, "versionId", setObjectLegalHoldRequest.getVersionId());
populateRequesterPaysHeader(request, setObjectLegalHoldRequest.isRequesterPays());
ResponseHeaderHandlerChain responseHandler = new ResponseHeaderHandlerChain(
new Unmarshallers.SetObjectLegalHoldResultUnmarshaller(),
new S3RequesterChargedHeaderHandler());
return invoke(request, responseHandler, bucketName, key);
}
@Override
public GetObjectLegalHoldResult getObjectLegalHold(GetObjectLegalHoldRequest getObjectLegalHoldRequest) {
getObjectLegalHoldRequest = beforeClientExecution(getObjectLegalHoldRequest);
rejectNull(getObjectLegalHoldRequest, "The request parameter must be specified");
String bucketName = getObjectLegalHoldRequest.getBucketName();
String key = getObjectLegalHoldRequest.getKey();
rejectNull(bucketName, "The bucket name parameter must be specified when getting the object legal hold.");
rejectNull(key, "The key parameter must be specified when getting the object legal hold.");
Request request = createRequest(bucketName, key, getObjectLegalHoldRequest, HttpMethodName.GET);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "GetObjectLegalHold");
request.addParameter("legal-hold", null);
addParameterIfNotNull(request, "versionId", getObjectLegalHoldRequest.getVersionId());
populateRequesterPaysHeader(request, getObjectLegalHoldRequest.isRequesterPays());
return invoke(request, new Unmarshallers.GetObjectLegalHoldResultUnmarshaller(), bucketName, key);
}
@Override
public SetObjectLockConfigurationResult setObjectLockConfiguration(SetObjectLockConfigurationRequest setObjectLockConfigurationRequest) {
setObjectLockConfigurationRequest = beforeClientExecution(setObjectLockConfigurationRequest);
rejectNull(setObjectLockConfigurationRequest, "The request parameter must be specified");
String bucketName = setObjectLockConfigurationRequest.getBucketName();
rejectNull(bucketName, "The bucket name parameter must be specified when setting the object lock configuration");
Request request = createRequest(bucketName, null, setObjectLockConfigurationRequest, HttpMethodName.PUT);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "PutObjectLockConfiguration");
request.addParameter("object-lock", null);
addHeaderIfNotNull(request, Headers.OBJECT_LOCK_TOKEN, setObjectLockConfigurationRequest.getToken());
populateRequesterPaysHeader(request, setObjectLockConfigurationRequest.isRequesterPays());
setContent(request, new ObjectLockConfigurationXmlFactory().convertToXmlByteArray(setObjectLockConfigurationRequest.getObjectLockConfiguration()),
ContentType.APPLICATION_XML.toString(), true);
ResponseHeaderHandlerChain responseHandler = new ResponseHeaderHandlerChain(
new Unmarshallers.SetObjectLockConfigurationResultUnmarshaller(),
new S3RequesterChargedHeaderHandler());
return invoke(request, responseHandler, bucketName, null);
}
@Override
public GetObjectLockConfigurationResult getObjectLockConfiguration(GetObjectLockConfigurationRequest getObjectLockConfigurationRequest) {
getObjectLockConfigurationRequest = beforeClientExecution(getObjectLockConfigurationRequest);
rejectNull(getObjectLockConfigurationRequest, "The request parameter must be specified");
String bucketName = getObjectLockConfigurationRequest.getBucketName();
rejectNull(bucketName, "The bucket name parameter must be specified when getting the object lock configuration");
Request request = createRequest(bucketName, null, getObjectLockConfigurationRequest, HttpMethodName.GET);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "GetObjectLockConfiguration");
request.addParameter("object-lock", null);
return invoke(request, new Unmarshallers.GetObjectLockConfigurationResultUnmarshaller(), bucketName, null);
}
@Override
public SetObjectRetentionResult setObjectRetention(SetObjectRetentionRequest setObjectRetentionRequest) {
setObjectRetentionRequest = beforeClientExecution(setObjectRetentionRequest);
rejectNull(setObjectRetentionRequest, "The request parameter must be specified");
String bucketName = setObjectRetentionRequest.getBucketName();
String key = setObjectRetentionRequest.getKey();
rejectNull(bucketName, "The bucket name parameter must be specified when setting the object retention.");
rejectNull(key, "The key parameter must be specified when setting the object retention.");
Request request = createRequest(bucketName, key, setObjectRetentionRequest, HttpMethodName.PUT);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "PutObjectRetention");
request.addParameter("retention", null);
if (setObjectRetentionRequest.getBypassGovernanceRetention()) {
request.addHeader(Headers.BYPASS_GOVERNANCE_RETENTION, "true");
}
addParameterIfNotNull(request, "versionId", setObjectRetentionRequest.getVersionId());
populateRequesterPaysHeader(request, setObjectRetentionRequest.isRequesterPays());
setContent(request, new ObjectLockRetentionXmlFactory().convertToXmlByteArray(setObjectRetentionRequest.getRetention()),
ContentType.APPLICATION_XML.toString(), true);
ResponseHeaderHandlerChain responseHandler = new ResponseHeaderHandlerChain(
new Unmarshallers.SetObjectRetentionResultUnmarshaller(),
new S3RequesterChargedHeaderHandler());
return invoke(request, responseHandler, bucketName, key);
}
@Override
public GetObjectRetentionResult getObjectRetention(GetObjectRetentionRequest getObjectRetentionRequest) {
getObjectRetentionRequest = beforeClientExecution(getObjectRetentionRequest);
rejectNull(getObjectRetentionRequest, "The request parameter must be specified");
String bucketName = getObjectRetentionRequest.getBucketName();
String key = getObjectRetentionRequest.getKey();
rejectNull(bucketName, "The bucket name parameter must be specified when getting the object retention.");
rejectNull(key, "The key parameter must be specified when getting the object retention.");
Request request = createRequest(bucketName, key, getObjectRetentionRequest, HttpMethodName.GET);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "GetObjectRetention");
request.addParameter("retention", null);
addParameterIfNotNull(request, "versionId", getObjectRetentionRequest.getVersionId());
// Note: the model has a requester pays member on the request but no requester charged on the result...
populateRequesterPaysHeader(request, getObjectRetentionRequest.isRequesterPays());
return invoke(request, new Unmarshallers.GetObjectRetentionResultUnmarshaller(), bucketName, key);
}
@Override
public WriteGetObjectResponseResult writeGetObjectResponse(WriteGetObjectResponseRequest writeGetObjectResponseRequest) {
writeGetObjectResponseRequest = beforeClientExecution(writeGetObjectResponseRequest);
rejectNull(writeGetObjectResponseRequest, "The request parameter must be specified");
Request request = createRequest(null, null, writeGetObjectResponseRequest, HttpMethodName.POST);
request.setResourcePath("/WriteGetObjectResponse");
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "WriteGetObjectResponse");
request.addHandlerContext(HandlerContextKey.REQUIRES_LENGTH, false);
request.addHandlerContext(HandlerContextKey.HAS_STREAMING_INPUT, true);
// Never sign the body. This operation is v4-unsigned-body
request.addHandlerContext(S3HandlerContextKeys.IS_CHUNKED_ENCODING_DISABLED, true);
request.addHandlerContext(S3HandlerContextKeys.IS_PAYLOAD_SIGNING_ENABLED, false);
addHeaderIfNotNull(request, Headers.REQUEST_ROUTE, writeGetObjectResponseRequest.getRequestRoute());
addHeaderIfNotNull(request, Headers.REQUEST_TOKEN, writeGetObjectResponseRequest.getRequestToken());
addIntegerHeaderIfNotNull(request, Headers.FWD_STATUS_CODE, writeGetObjectResponseRequest.getStatusCode());
addHeaderIfNotNull(request, Headers.FWD_ERROR_CODE, writeGetObjectResponseRequest.getErrorCode());
addHeaderIfNotNull(request, Headers.FWD_ERROR_MESSAGE, writeGetObjectResponseRequest.getErrorMessage());
addHeaderIfNotNull(request, Headers.FWD_ACCEPT_RANGES, writeGetObjectResponseRequest.getAcceptRanges());
addHeaderIfNotNull(request, Headers.FWD_CACHE_CONTROL, writeGetObjectResponseRequest.getCacheControl());
addHeaderIfNotNull(request, Headers.FWD_CONTENT_DISPOSITION, writeGetObjectResponseRequest.getContentDisposition());
addHeaderIfNotNull(request, Headers.FWD_CONTENT_ENCODING, writeGetObjectResponseRequest.getContentEncoding());
addHeaderIfNotNull(request, Headers.FWD_CONTENT_LANGUAGE, writeGetObjectResponseRequest.getContentLanguage());
addHeaderIfNotNull(request, Headers.FWD_CONTENT_RANGE, writeGetObjectResponseRequest.getContentRange());
addHeaderIfNotNull(request, Headers.FWD_CONTENT_TYPE, writeGetObjectResponseRequest.getContentType());
addHeaderIfNotNull(request, Headers.FWD_DELETE_MARKER, writeGetObjectResponseRequest.getDeleteMarker());
addHeaderIfNotNull(request, Headers.FWD_ETAG, writeGetObjectResponseRequest.getETag());
addDateHeader(request, Headers.FWD_EXPIRES, writeGetObjectResponseRequest.getExpires());
addHeaderIfNotNull(request, Headers.FWD_EXPIRATION, writeGetObjectResponseRequest.getExpiration());
addDateHeader(request, Headers.FWD_LAST_MODIFIED, writeGetObjectResponseRequest.getLastModified());
addIntegerHeaderIfNotNull(request, Headers.FWD_MISSING_META, writeGetObjectResponseRequest.getMissingMeta());
addHeaderIfNotNull(request, Headers.FWD_OBJECT_LOCK_MODE, writeGetObjectResponseRequest.getObjectLockMode());
addHeaderIfNotNull(request, Headers.FWD_OBJECT_LOCK_LEGAL_HOLD, writeGetObjectResponseRequest.getObjectLockLegalHoldStatus());
addDateHeader(request, Headers.FWD_OBJECT_LOCK_RETAIN_UNTIL_DATE, writeGetObjectResponseRequest.getObjectLockRetainUntilDate());
addIntegerHeaderIfNotNull(request, Headers.FWD_PARTS_COUNT, writeGetObjectResponseRequest.getPartsCount());
addHeaderIfNotNull(request, Headers.FWD_REPLICATION_STATUS, writeGetObjectResponseRequest.getReplicationStatus());
addHeaderIfNotNull(request, Headers.FWD_REQUEST_CHARGED, writeGetObjectResponseRequest.getRequestCharged());
addHeaderIfNotNull(request, Headers.FWD_RESTORE, writeGetObjectResponseRequest.getRestore());
addHeaderIfNotNull(request, Headers.FWD_SERVER_SIDE_ENCRYPTION, writeGetObjectResponseRequest.getServerSideEncryption());
addHeaderIfNotNull(request, Headers.FWD_SSE_CUSTOMER_ALGORITHM, writeGetObjectResponseRequest.getSSECustomerAlgorithm());
addHeaderIfNotNull(request, Headers.FWD_SSE_KMS_KEY_ID, writeGetObjectResponseRequest.getSSEKMSKeyId());
addHeaderIfNotNull(request, Headers.FWD_SSE_CUSTOMER_KEY_MD5, writeGetObjectResponseRequest.getSSECustomerKeyMD5());
addHeaderIfNotNull(request, Headers.FWD_STORAGE_CLASS, writeGetObjectResponseRequest.getStorageClass());
addIntegerHeaderIfNotNull(request, Headers.FWD_TAG_COUNT, writeGetObjectResponseRequest.getTagCount());
addHeaderIfNotNull(request, Headers.FWD_VERSION_ID, writeGetObjectResponseRequest.getVersionId());
if (writeGetObjectResponseRequest.getBucketKeyEnabled() != null) {
request.addHeader(Headers.FWD_SSE_BUCKET_KEY_ENABLED, writeGetObjectResponseRequest.getBucketKeyEnabled().toString());
}
ObjectMetadata metadata = writeGetObjectResponseRequest.getMetadata();
if (metadata == null) {
metadata = new ObjectMetadata();
}
if (writeGetObjectResponseRequest.getContentLength() != null) {
metadata.setContentLength(writeGetObjectResponseRequest.getContentLength());
}
InputStream originalIs = writeGetObjectResponseRequest.getInputStream();
File originalFile = writeGetObjectResponseRequest.getFile();
InputStream requestInputStream = null;
try {
requestInputStream = getInputStream(
writeGetObjectResponseRequest.getInputStream(),
writeGetObjectResponseRequest.getFile(),
metadata,
request,
false,
true
);
request.setContent(requestInputStream);
populateRequestMetadata(request, metadata);
return invoke(request, new Unmarshallers.WriteGetObjectResponseResultUnmarshaller(), null, null);
} finally {
cleanupDataSource(writeGetObjectResponseRequest, originalFile, originalIs, requestInputStream, log);
}
}
@Override
public URL generatePresignedUrl(String bucketName, String key, Date expiration)
throws SdkClientException {
return generatePresignedUrl(bucketName, key, expiration, HttpMethod.GET);
}
@Override
public URL generatePresignedUrl(String bucketName, String key, Date expiration, HttpMethod method)
throws SdkClientException {
GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, key, method);
request.setExpiration(expiration);
return generatePresignedUrl(request);
}
@Override
public URL generatePresignedUrl(GeneratePresignedUrlRequest req) {
rejectNull(req,
"The request parameter must be specified when generating a pre-signed URL");
req.rejectIllegalArguments();
final String bucketName = req.getBucketName();
final String key = req.getKey();
if (req.getExpiration() == null) {
req.setExpiration(
new Date(System.currentTimeMillis() + 1000 * 60 * 15));
}
HttpMethodName httpMethod = HttpMethodName.valueOf(req.getMethod().toString());
// If the key starts with a slash character itself, the following method
// will actually add another slash before the resource path to prevent
// the HttpClient mistakenly treating the slash as a path delimiter.
// For presigned request, we need to remember to remove this extra slash
// before generating the URL.
Request request = createRequest(
bucketName, key, req, httpMethod);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "GeneratePresignedUrl");
addParameterIfNotNull(request, "versionId", req.getVersionId());
if (req.isZeroByteContent())
request.setContent(new ByteArrayInputStream(new byte[0]));
for (Entry entry : req.getRequestParameters().entrySet()) {
request.addParameter(entry.getKey(), entry.getValue());
}
addHeaderIfNotNull(request, Headers.CONTENT_TYPE, req.getContentType());
addHeaderIfNotNull(request, Headers.CONTENT_MD5, req.getContentMd5());
// SSE-C
populateSSE_C(request, req.getSSECustomerKey());
// SSE
addHeaderIfNotNull(request, Headers.SERVER_SIDE_ENCRYPTION,
req.getSSEAlgorithm());
// SSE-KMS
addHeaderIfNotNull(request,
Headers.SERVER_SIDE_ENCRYPTION_AWS_KMS_KEYID, req.getKmsCmkId());
// Custom headers that open up the possibility of supporting unexpected
// cases.
Map customHeaders = req.getCustomRequestHeaders();
if (customHeaders != null) {
for (Map.Entry e: customHeaders.entrySet()) {
request.addHeader(e.getKey(), e.getValue());
}
}
addResponseHeaderParameters(request, req.getResponseHeaders());
Signer signer = createSigner(request, bucketName, key);
if (request.getHandlerContext(HandlerContextKey.SIGNING_NAME) != null && !isSignerOverridden()) {
String signingName = request.getHandlerContext(HandlerContextKey.SIGNING_NAME);
if (signer instanceof ServiceAwareSigner) {
((ServiceAwareSigner) signer).setServiceName(signingName);
}
}
if (signer instanceof Presigner) {
// If we have a signer which knows how to presign requests,
// delegate directly to it.
((Presigner) signer).presignRequest(
request,
CredentialUtils.getCredentialsProvider(request.getOriginalRequest(), awsCredentialsProvider).getCredentials(),
req.getExpiration()
);
} else {
// Otherwise use the default presigning method, which is hardcoded
// to use QueryStringSigner.
presignRequest(
request,
req.getMethod(),
bucketName,
key,
req.getExpiration(),
null
);
}
// Remove the leading slash (if any) in the resource-path
return ServiceUtils.convertRequestToUrl(request, true, false);
}
@Override
public void abortMultipartUpload(AbortMultipartUploadRequest abortMultipartUploadRequest)
throws SdkClientException, AmazonServiceException {
abortMultipartUploadRequest = beforeClientExecution(abortMultipartUploadRequest);
rejectNull(abortMultipartUploadRequest,
"The request parameter must be specified when aborting a multipart upload");
rejectNull(abortMultipartUploadRequest.getBucketName(),
"The bucket name parameter must be specified when aborting a multipart upload");
rejectNull(abortMultipartUploadRequest.getKey(),
"The key parameter must be specified when aborting a multipart upload");
rejectNull(abortMultipartUploadRequest.getUploadId(),
"The upload ID parameter must be specified when aborting a multipart upload");
String bucketName = abortMultipartUploadRequest.getBucketName();
String key = abortMultipartUploadRequest.getKey();
Request request = createRequest(bucketName, key, abortMultipartUploadRequest, HttpMethodName.DELETE);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "AbortMultipartUpload");
request.addParameter("uploadId", abortMultipartUploadRequest.getUploadId());
populateRequesterPaysHeader(request, abortMultipartUploadRequest.isRequesterPays());
invoke(request, voidResponseHandler, bucketName, key);
}
@Override
public CompleteMultipartUploadResult completeMultipartUpload(
CompleteMultipartUploadRequest completeMultipartUploadRequest)
throws SdkClientException, AmazonServiceException {
completeMultipartUploadRequest = beforeClientExecution(completeMultipartUploadRequest);
rejectNull(completeMultipartUploadRequest,
"The request parameter must be specified when completing a multipart upload");
String bucketName = completeMultipartUploadRequest.getBucketName();
String key = completeMultipartUploadRequest.getKey();
String uploadId = completeMultipartUploadRequest.getUploadId();
rejectNull(bucketName,
"The bucket name parameter must be specified when completing a multipart upload");
rejectNull(key,
"The key parameter must be specified when completing a multipart upload");
rejectNull(uploadId,
"The upload ID parameter must be specified when completing a multipart upload");
rejectNull(completeMultipartUploadRequest.getPartETags(),
"The part ETags parameter must be specified when completing a multipart upload");
int retries = 0;
CompleteMultipartUploadHandler handler;
do {
Request request = createRequest(bucketName, key, completeMultipartUploadRequest, HttpMethodName.POST);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "CompleteMultipartUpload");
request.addParameter("uploadId", uploadId);
populateRequesterPaysHeader(request, completeMultipartUploadRequest.isRequesterPays());
populateSSE_C(request, completeMultipartUploadRequest.getSSECustomerKey());
byte[] xml = RequestXmlFactory.convertToXmlByteArray(completeMultipartUploadRequest.getPartETags());
request.addHeader("Content-Type", "application/xml");
request.addHeader("Content-Length", String.valueOf(xml.length));
addHeaderIfNotNull(request, Headers.PUT_OBJECT_IF_NONE_MATCH, completeMultipartUploadRequest.getIfNoneMatch());
request.setContent(new ByteArrayInputStream(xml));
@SuppressWarnings("unchecked")
ResponseHeaderHandlerChain responseHandler = new ResponseHeaderHandlerChain(
// xml payload unmarshaller
new Unmarshallers.CompleteMultipartUploadResultUnmarshaller(),
// header handlers
new ServerSideEncryptionHeaderHandler(),
new ObjectExpirationHeaderHandler(),
new S3VersionHeaderHandler(),
new S3RequesterChargedHeaderHandler());
handler = invoke(request, responseHandler, bucketName, key);
/**
* When the number of parts is greater than 1000, CompleteMultipartUpload will return an HTTP 200 OK code
* even when there is an error, e.g., Slowdown, EntityTooSmall. We need to manually set the status code and
* service name in this case of a 200 error response, similar to CopyObject.
*/
AmazonS3Exception ase = handler.getAmazonS3Exception();
if (ase != null) {
ase.setStatusCode(200);
ase.setServiceName(request.getServiceName());
throw ase;
}
if (handler.getCompleteMultipartUploadResult() != null) {
return handler.getCompleteMultipartUploadResult();
}
} while (shouldRetryCompleteMultipartUpload(completeMultipartUploadRequest,
handler.getAmazonS3Exception(), retries++));
throw handler.getAmazonS3Exception();
}
private boolean shouldRetryCompleteMultipartUpload(AmazonWebServiceRequest originalRequest,
AmazonS3Exception exception,
int retriesAttempted) {
final RetryPolicy retryPolicy = clientConfiguration.getRetryPolicy();
if (retryPolicy == null || retryPolicy.getRetryCondition() == null) {
return false;
}
if (retryPolicy == PredefinedRetryPolicies.NO_RETRY_POLICY) {
return false;
}
return completeMultipartUploadRetryCondition.shouldRetry
(originalRequest, exception, retriesAttempted);
}
@Override
public InitiateMultipartUploadResult initiateMultipartUpload(
InitiateMultipartUploadRequest initiateMultipartUploadRequest)
throws SdkClientException, AmazonServiceException {
initiateMultipartUploadRequest = beforeClientExecution(initiateMultipartUploadRequest);
rejectNull(initiateMultipartUploadRequest,
"The request parameter must be specified when initiating a multipart upload");
rejectNull(initiateMultipartUploadRequest.getBucketName(),
"The bucket name parameter must be specified when initiating a multipart upload");
rejectNull(initiateMultipartUploadRequest.getKey(),
"The key parameter must be specified when initiating a multipart upload");
Request request = createRequest(initiateMultipartUploadRequest.getBucketName(), initiateMultipartUploadRequest.getKey(), initiateMultipartUploadRequest, HttpMethodName.POST);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "CreateMultipartUpload");
request.addParameter("uploads", null);
if (initiateMultipartUploadRequest.getStorageClass() != null)
request.addHeader(Headers.STORAGE_CLASS, initiateMultipartUploadRequest.getStorageClass().toString());
if (initiateMultipartUploadRequest.getRedirectLocation() != null) {
request.addHeader(Headers.REDIRECT_LOCATION, initiateMultipartUploadRequest.getRedirectLocation());
}
if ( initiateMultipartUploadRequest.getAccessControlList() != null ) {
addAclHeaders(request, initiateMultipartUploadRequest.getAccessControlList());
} else if ( initiateMultipartUploadRequest.getCannedACL() != null ) {
request.addHeader(Headers.S3_CANNED_ACL, initiateMultipartUploadRequest.getCannedACL().toString());
}
if (initiateMultipartUploadRequest.objectMetadata != null) {
populateRequestMetadata(request, initiateMultipartUploadRequest.objectMetadata);
}
Boolean bucketKeyEnabled = initiateMultipartUploadRequest.getBucketKeyEnabled();
if (bucketKeyEnabled != null) {
addHeaderIfNotNull(request, Headers.SERVER_SIDE_ENCRYPTION_BUCKET_KEY_ENABLED,
String.valueOf(bucketKeyEnabled));
}
populateRequesterPaysHeader(request, initiateMultipartUploadRequest.isRequesterPays());
// Populate the SSE-C parameters to the request header
populateSSE_C(request, initiateMultipartUploadRequest.getSSECustomerKey());
// Populate the SSE Amazon Web Services KMS parameters to the request header
populateSSE_KMS(request,
initiateMultipartUploadRequest.getSSEAwsKeyManagementParams());
addHeaderIfNotNull(request, Headers.S3_TAGGING, urlEncodeTags(initiateMultipartUploadRequest.getTagging()));
populateObjectLockHeaders(request, initiateMultipartUploadRequest.getObjectLockMode(), initiateMultipartUploadRequest.getObjectLockRetainUntilDate(),
initiateMultipartUploadRequest.getObjectLockLegalHoldStatus());
// Be careful that we don't send the object's total size as the content
// length for the InitiateMultipartUpload request.
setZeroContentLength(request);
// Set the request content to be empty (but not null) to force the runtime to pass
// any query params in the query string and not the request body, to keep S3 happy.
request.setContent(new ByteArrayInputStream(new byte[0]));
@SuppressWarnings("unchecked")
ResponseHeaderHandlerChain responseHandler = new ResponseHeaderHandlerChain(
// xml payload unmarshaller
new Unmarshallers.InitiateMultipartUploadResultUnmarshaller(),
// header handlers
new ServerSideEncryptionHeaderHandler(),
new S3RequesterChargedHeaderHandler(),
new InitiateMultipartUploadHeaderHandler());
return invoke(request, responseHandler,
initiateMultipartUploadRequest.getBucketName(), initiateMultipartUploadRequest.getKey());
}
@Override
public MultipartUploadListing listMultipartUploads(ListMultipartUploadsRequest listMultipartUploadsRequest)
throws SdkClientException, AmazonServiceException {
listMultipartUploadsRequest = beforeClientExecution(listMultipartUploadsRequest);
rejectNull(listMultipartUploadsRequest,
"The request parameter must be specified when listing multipart uploads");
rejectNull(listMultipartUploadsRequest.getBucketName(),
"The bucket name parameter must be specified when listing multipart uploads");
Request request = createRequest(listMultipartUploadsRequest.getBucketName(), null, listMultipartUploadsRequest, HttpMethodName.GET);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "ListMultipartUploads");
request.addParameter("uploads", null);
if (listMultipartUploadsRequest.getKeyMarker() != null) request.addParameter("key-marker", listMultipartUploadsRequest.getKeyMarker());
if (listMultipartUploadsRequest.getMaxUploads() != null) request.addParameter("max-uploads", listMultipartUploadsRequest.getMaxUploads().toString());
if (listMultipartUploadsRequest.getUploadIdMarker() != null) request.addParameter("upload-id-marker", listMultipartUploadsRequest.getUploadIdMarker());
if (listMultipartUploadsRequest.getDelimiter() != null) request.addParameter("delimiter", listMultipartUploadsRequest.getDelimiter());
if (listMultipartUploadsRequest.getPrefix() != null) request.addParameter("prefix", listMultipartUploadsRequest.getPrefix());
if (listMultipartUploadsRequest.getEncodingType() != null) request.addParameter("encoding-type", listMultipartUploadsRequest.getEncodingType());
populateRequesterPaysHeader(request, listMultipartUploadsRequest.isRequesterPays());
@SuppressWarnings("unchecked")
ResponseHeaderHandlerChain responseHandler =
new ResponseHeaderHandlerChain(
// xml payload unmarshaller
new Unmarshallers.ListMultipartUploadsResultUnmarshaller(),
// header handler
new S3RequesterChargedHeaderHandler());
return invoke(request, responseHandler, listMultipartUploadsRequest.getBucketName(), null);
}
@Override
public PartListing listParts(ListPartsRequest listPartsRequest)
throws SdkClientException, AmazonServiceException {
listPartsRequest = beforeClientExecution(listPartsRequest);
rejectNull(listPartsRequest,
"The request parameter must be specified when listing parts");
rejectNull(listPartsRequest.getBucketName(),
"The bucket name parameter must be specified when listing parts");
rejectNull(listPartsRequest.getKey(),
"The key parameter must be specified when listing parts");
rejectNull(listPartsRequest.getUploadId(),
"The upload ID parameter must be specified when listing parts");
Request request = createRequest(listPartsRequest.getBucketName(), listPartsRequest.getKey(), listPartsRequest, HttpMethodName.GET);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "ListParts");
request.addParameter("uploadId", listPartsRequest.getUploadId());
if (listPartsRequest.getMaxParts() != null) request.addParameter("max-parts", listPartsRequest.getMaxParts().toString());
if (listPartsRequest.getPartNumberMarker() != null) request.addParameter("part-number-marker", listPartsRequest.getPartNumberMarker().toString());
if (listPartsRequest.getEncodingType() != null) request.addParameter("encoding-type", listPartsRequest.getEncodingType());
populateRequesterPaysHeader(request, listPartsRequest.isRequesterPays());
@SuppressWarnings("unchecked")
ResponseHeaderHandlerChain responseHandler = new ResponseHeaderHandlerChain(
// xml payload unmarshaller
new Unmarshallers.ListPartsResultUnmarshaller(),
// header handler
new S3RequesterChargedHeaderHandler(),
new ListPartsHeaderHandler());
return invoke(request, responseHandler, listPartsRequest.getBucketName(), listPartsRequest.getKey());
}
@Override
public UploadPartResult uploadPart(UploadPartRequest uploadPartRequest)
throws SdkClientException, AmazonServiceException {
uploadPartRequest = beforeClientExecution(uploadPartRequest);
rejectNull(uploadPartRequest,
"The request parameter must be specified when uploading a part");
final File fileOrig = uploadPartRequest.getFile();
final InputStream isOrig = uploadPartRequest.getInputStream();
final String bucketName = uploadPartRequest.getBucketName();
final String key = uploadPartRequest.getKey();
final String uploadId = uploadPartRequest.getUploadId();
final int partNumber = uploadPartRequest.getPartNumber();
final long partSize = uploadPartRequest.getPartSize();
rejectNull(bucketName,
"The bucket name parameter must be specified when uploading a part");
rejectNull(key,
"The key parameter must be specified when uploading a part");
rejectNull(uploadId,
"The upload ID parameter must be specified when uploading a part");
Request request = createRequest(bucketName, key, uploadPartRequest, HttpMethodName.PUT);
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "UploadPart");
request.addHandlerContext(HandlerContextKey.REQUIRES_LENGTH, Boolean.TRUE);
request.addHandlerContext(HandlerContextKey.HAS_STREAMING_INPUT, Boolean.TRUE);
request.addParameter("uploadId", uploadId);
request.addParameter("partNumber", Integer.toString(partNumber));
final ObjectMetadata objectMetadata = uploadPartRequest.getObjectMetadata();
if (objectMetadata != null)
populateRequestMetadata(request, objectMetadata);
addHeaderIfNotNull(request, Headers.CONTENT_MD5, uploadPartRequest.getMd5Digest());
request.addHeader(Headers.CONTENT_LENGTH, Long.toString(partSize));
populateRequesterPaysHeader(request, uploadPartRequest.isRequesterPays());
// Populate the SSE-C parameters to the request header
populateSSE_C(request, uploadPartRequest.getSSECustomerKey());
InputStream isCurr = isOrig;
try {
if (fileOrig == null) {
if (isOrig == null) {
throw new IllegalArgumentException(
"A File or InputStream must be specified when uploading part");
} else {
// When isCurr is a FileInputStream, this wrapping enables
// unlimited mark-and-reset
isCurr = ReleasableInputStream.wrap(isCurr);
}
// Make backward compatible with buffer size via system property
final Integer bufsize = Constants.getS3StreamBufferSize();
if (bufsize != null) {
AmazonWebServiceRequest awsreq = request.getOriginalRequest();
// Note awsreq is never null at this point even if the original
// request was
awsreq.getRequestClientOptions()
.setReadLimit(bufsize.intValue());
}
} else {
try {
isCurr = new ResettableInputStream(fileOrig);
} catch(IOException e) {
throw new IllegalArgumentException("Failed to open file "
+ fileOrig, e);
}
}
isCurr = new InputSubstream(
isCurr,
uploadPartRequest.getFileOffset(),
partSize,
uploadPartRequest.isLastPart());
MD5DigestCalculatingInputStream md5DigestStream = null;
if (uploadPartRequest.getMd5Digest() == null
&& !skipMd5CheckStrategy.skipClientSideValidationPerRequest(uploadPartRequest)) {
/*
* If the user hasn't set the content MD5, then we don't want to buffer the whole
* stream in memory just to calculate it. Instead, we can calculate it on the fly
* and validate it with the returned ETag from the object upload.
*/
isCurr = md5DigestStream = new MD5DigestCalculatingInputStream(isCurr);
}
final ProgressListener listener = uploadPartRequest.getGeneralProgressListener();
publishProgress(listener, ProgressEventType.TRANSFER_PART_STARTED_EVENT);
return doUploadPart(bucketName, key, uploadId, partNumber,
partSize, request, isCurr, md5DigestStream, listener);
} finally {
cleanupDataSource(uploadPartRequest, fileOrig, isOrig, isCurr, log);
}
}
private UploadPartResult doUploadPart(final String bucketName,
final String key, final String uploadId, final int partNumber,
final long partSize, Request request,
InputStream inputStream,
MD5DigestCalculatingInputStream md5DigestStream,
final ProgressListener listener) {
try {
request.setContent(inputStream);
ObjectMetadata metadata = invoke(request, new S3MetadataResponseHandler(), bucketName, key);
final String etag = metadata.getETag();
if (md5DigestStream != null
&& !skipMd5CheckStrategy.skipClientSideValidationPerUploadPartResponse(metadata)) {
byte[] clientSideHash = md5DigestStream.getMd5Digest();
byte[] serverSideHash = BinaryUtils.fromHex(etag);
if (!Arrays.equals(clientSideHash, serverSideHash)) {
final String info = "bucketName: " + bucketName + ", key: "
+ key + ", uploadId: " + uploadId
+ ", partNumber: " + partNumber + ", partSize: "
+ partSize;
throw new SdkClientException(
"Unable to verify integrity of data upload. "
+ "Client calculated content hash (contentMD5: "
+ Base16.encodeAsString(clientSideHash)
+ " in hex) didn't match hash (etag: "
+ etag
+ " in hex) calculated by Amazon S3. "
+ "You may need to delete the data stored in Amazon S3. "
+ "(" + info + ")");
}
}
publishProgress(listener, ProgressEventType.TRANSFER_PART_COMPLETED_EVENT);
UploadPartResult result = new UploadPartResult();
result.setETag(etag);
result.setPartNumber(partNumber);
result.setSSEAlgorithm(metadata.getSSEAlgorithm());
result.setSSECustomerAlgorithm(metadata.getSSECustomerAlgorithm());
result.setSSECustomerKeyMd5(metadata.getSSECustomerKeyMd5());
result.setRequesterCharged(metadata.isRequesterCharged());
result.setBucketKeyEnabled(metadata.getBucketKeyEnabled());
return result;
} catch (Throwable t) {
publishProgress(listener, ProgressEventType.TRANSFER_PART_FAILED_EVENT);
// Leaving this here in case anyone is depending on it, but it's
// inconsistent with other methods which only generate one of
// COMPLETED_EVENT_CODE or FAILED_EVENT_CODE.
publishProgress(listener, ProgressEventType.TRANSFER_PART_COMPLETED_EVENT);
throw failure(t);
}
}
@Override
public S3ResponseMetadata getCachedResponseMetadata(AmazonWebServiceRequest request) {
return (S3ResponseMetadata)client.getResponseMetadataForRequest(request);
}
@Override
public void restoreObject(RestoreObjectRequest restoreObjectRequest)
throws AmazonServiceException {
restoreObjectV2(restoreObjectRequest);
}
@Override
public RestoreObjectResult restoreObjectV2(RestoreObjectRequest restoreObjectRequest)
throws AmazonServiceException {
restoreObjectRequest = beforeClientExecution(restoreObjectRequest);
String bucketName = restoreObjectRequest.getBucketName();
String key = restoreObjectRequest.getKey();
rejectNull(bucketName, "The bucket name parameter must be specified when restoring a glacier object");
rejectNull(key, "The key parameter must be specified when restoring a glacier object");
if (restoreObjectRequest.getOutputLocation() != null) {
rejectNull(restoreObjectRequest.getType(), "The restore request type must be specified with restores that specify OutputLocation");
if (RestoreRequestType.SELECT.toString().equals(restoreObjectRequest.getType())) {
rejectNull(restoreObjectRequest.getSelectParameters(),
"The select parameters must be specified when restoring a glacier object with SELECT restore request type");
}
}
Request request = createRestoreObjectRequest(restoreObjectRequest);
@SuppressWarnings("unchecked")
ResponseHeaderHandlerChain responseHandler = new ResponseHeaderHandlerChain(
new Unmarshallers.RestoreObjectResultUnmarshaller(),
new S3RequesterChargedHeaderHandler(),
new S3RestoreOutputPathHeaderHandler());
return invoke(request, responseHandler, bucketName, key);
}
@Override
public void restoreObject(String bucketName, String key, int expirationInDays)
throws AmazonServiceException {
restoreObject(new RestoreObjectRequest(bucketName, key, expirationInDays));
}
@Override
public PutObjectResult putObject(String bucketName, String key, String content)
throws AmazonServiceException, SdkClientException {
rejectNull(bucketName, "Bucket name must be provided");
rejectNull(key, "Object key must be provided");
rejectNull(content, "String content must be provided");
byte[] contentBytes = content.getBytes(StringUtils.UTF8);
InputStream is = new ByteArrayInputStream(contentBytes);
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentType("text/plain");
metadata.setContentLength(contentBytes.length);
return putObject(new PutObjectRequest(bucketName, key, is, metadata));
}
/*
* Private Interface
*/
/**
*
* Asserts that the specified parameter value is not null
and if it is,
* throws an IllegalArgumentException
with the specified error message.
*
*
* @param parameterValue
* The parameter value being checked.
* @param errorMessage
* The error message to include in the IllegalArgumentException
* if the specified parameter is null.
*/
private void rejectNull(Object parameterValue, String errorMessage) {
if (parameterValue == null) throw new IllegalArgumentException(errorMessage);
}
/**
*
* Gets the Amazon S3 {@link AccessControlList} (ACL) for the specified resource.
* (bucket if only the bucketName parameter is specified, otherwise the object with the
* specified key in the bucket).
*
*
* @param bucketName
* The name of the bucket whose ACL should be returned if the key
* parameter is not specified, otherwise the bucket containing
* the specified key.
* @param key
* The object key whose ACL should be retrieve. If not specified,
* the bucket's ACL is returned.
* @param versionId
* The version ID of the object version whose ACL is being
* retrieved.
* @param originalRequest
* The original, user facing request object.
*
* @return The S3 ACL for the specified resource.
*/
private AccessControlList getAcl(String bucketName, String key, String versionId,
boolean isRequesterPays, AmazonWebServiceRequest originalRequest) {
if (originalRequest == null) originalRequest = new GenericBucketRequest(bucketName);
Request request = createRequest(bucketName, key, originalRequest, HttpMethodName.GET);
if (bucketName != null && key != null) {
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "GetObjectAcl");
} else if (bucketName != null) {
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "GetBucketAcl");
}
request.addParameter("acl", null);
if (versionId != null) {
request.addParameter("versionId", versionId);
}
populateRequesterPaysHeader(request, isRequesterPays);
@SuppressWarnings("unchecked")
ResponseHeaderHandlerChain responseHandler = new ResponseHeaderHandlerChain(
new Unmarshallers.AccessControlListUnmarshaller(),
new S3RequesterChargedHeaderHandler());
return invoke(request, responseHandler, bucketName, key);
}
/**
* Sets the Canned ACL for the specified resource in S3. If only bucketName
* is specified, the canned ACL will be applied to the bucket, otherwise if
* bucketName and key are specified, the canned ACL will be applied to the
* object.
*
* @param bucketName
* The name of the bucket containing the specified key, or if no
* key is listed, the bucket whose ACL will be set.
* @param key
* The optional object key within the specified bucket whose ACL
* will be set. If not specified, the bucket ACL will be set.
* @param versionId
* The version ID of the object version whose ACL is being set.
* @param cannedAcl
* The canned ACL to apply to the resource.
* @param originalRequest
* The original, user facing request object.
*/
private void setAcl(String bucketName, String key, String versionId, CannedAccessControlList cannedAcl, boolean isRequesterPays,
AmazonWebServiceRequest originalRequest) {
if (originalRequest == null) originalRequest = new GenericBucketRequest(bucketName);
Request request = createRequest(bucketName, key, originalRequest, HttpMethodName.PUT);
if (bucketName != null && key != null) {
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "PutObjectAcl");
} else if (bucketName != null) {
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "PutBucketAcl");
}
request.addParameter("acl", null);
request.addHeader(Headers.S3_CANNED_ACL, cannedAcl.toString());
if (versionId != null) request.addParameter("versionId", versionId);
populateRequesterPaysHeader(request, isRequesterPays);
invoke(request, voidResponseHandler, bucketName, key);
}
/**
* Sets the ACL for the specified resource in S3. If only bucketName is
* specified, the ACL will be applied to the bucket, otherwise if bucketName
* and key are specified, the ACL will be applied to the object.
*
* @param bucketName
* The name of the bucket containing the specified key, or if no
* key is listed, the bucket whose ACL will be set.
* @param key
* The optional object key within the specified bucket whose ACL
* will be set. If not specified, the bucket ACL will be set.
* @param versionId
* The version ID of the object version whose ACL is being set.
* @param acl
* The ACL to apply to the resource.
* @param originalRequest
* The original, user facing request object.
*/
private void setAcl(String bucketName, String key, String versionId, AccessControlList acl, boolean isRequesterPays,
AmazonWebServiceRequest originalRequest) {
if (originalRequest == null) originalRequest = new GenericBucketRequest(bucketName);
Request request = createRequest(bucketName, key, originalRequest, HttpMethodName.PUT);
if (bucketName != null && key != null) {
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "PutObjectAcl");
} else if (bucketName != null) {
request.addHandlerContext(HandlerContextKey.OPERATION_NAME, "PutBucketAcl");
}
request.addParameter("acl", null);
if (versionId != null) request.addParameter("versionId", versionId);
populateRequesterPaysHeader(request, isRequesterPays);
byte[] aclAsXml = new AclXmlFactory().convertToXmlByteArray(acl);
request.addHeader("Content-Type", "application/xml");
request.addHeader("Content-Length", String.valueOf(aclAsXml.length));
request.setContent(new ByteArrayInputStream(aclAsXml));
populateRequestHeaderWithMd5(request, aclAsXml);
invoke(request, voidResponseHandler, bucketName, key);
}
/**
* Returns a "complete" S3 specific signer, taking into the S3 bucket, key,
* and the current S3 client configuration into account.
*/
protected Signer createSigner(final Request> request,
final String bucketName,
final String key) {
return createSigner(request, bucketName, key, false);
}
/**
* Returns a "complete" S3 specific signer, taking into the S3 bucket, key,
* and the current S3 client configuration into account.
*/
protected Signer createSigner(final Request> request,
final String bucketName,
final String key,
final boolean isAdditionalHeadRequestToFindRegion) {
// Instead of using request.getEndpoint() for this parameter, we use endpoint which is because
// in accelerate mode, the endpoint in request is regionless. We need the client-wide endpoint
// to fetch the region information and pick the correct signer.
URI uri = clientOptions.isAccelerateModeEnabled() ? endpoint : request.getEndpoint();
Signer signer;
if (isAccessPointArn(bucketName)) {
Arn resourceArn = Arn.fromString(bucketName);
S3Resource s3Resource = S3ArnConverter.getInstance().convertArn(resourceArn);
String region = s3Resource.getRegion();
String regionalEndpoint = RegionUtils.getRegion(region).getServiceEndpoint("s3");
signer = getSignerByURI(URI.create(uri.getScheme() + "://" + regionalEndpoint));
} else {
signer = getSignerByURI(uri);
}
if (!isSignerOverridden()) {
if ((signer instanceof AWSS3V4Signer) && bucketRegionShouldBeCached(request)) {
String region = bucketRegionCache.get(bucketName);
if (region != null) {
// If cache contains the region for the bucket, create an endpoint for the region and
// update the request with that endpoint if accelerate mode is not enabled
request.addHandlerContext(HandlerContextKey.SIGNING_REGION, region);
if (!clientOptions.isAccelerateModeEnabled()) {
String serviceEndpoint = RegionUtils.getRegion(region).getServiceEndpoint(S3_SERVICE_NAME);
resolveRequestEndpoint(request,
bucketName,
key,
RuntimeHttpUtils.toUri(serviceEndpoint, clientConfiguration),
region);
}
return updateSigV4SignerWithServiceAndRegion((AWSS3V4Signer) signer, request, region);
} else if (request.getOriginalRequest() instanceof GeneratePresignedUrlRequest) {
String signerRegion = getSignerRegion();
if (signerRegion == null) {
return createSigV2Signer(request, bucketName, key);
}
return updateSigV4SignerWithServiceAndRegion((AWSS3V4Signer) signer, request, signerRegion);
} else if (isAdditionalHeadRequestToFindRegion) {
return updateSigV4SignerWithServiceAndRegion((AWSS3V4Signer) signer, request, "us-east-1");
}
}
String regionOverride = getSignerRegionOverride();
if (regionOverride != null) {
return updateSigV4SignerWithServiceAndRegion(new AWSS3V4Signer(), request, regionOverride);
}
}
if (signer instanceof S3Signer) {
// The old S3Signer needs a method and path passed to its
// constructor; if that's what we should use, getSigner()
// will return a dummy instance and we need to create a
// new one with the appropriate values for this request.
return createSigV2Signer(request, bucketName, key);
}
return signer;
}
private S3Signer createSigV2Signer(final Request> request,
final String bucketName,
final String key) {
String resourcePath = "/" +
((bucketName != null) ? bucketName + "/" : "") +
((key != null) ? key : "");
return new S3Signer(request.getHttpMethod().toString(), resourcePath);
}
private AWSS3V4Signer updateSigV4SignerWithServiceAndRegion(final AWSS3V4Signer v4Signer, Request> request, String region) {
String signingNameOverride = request.getHandlerContext(HandlerContextKey.SIGNING_NAME);
if (signingNameOverride != null) {
v4Signer.setServiceName(signingNameOverride);
} else {
v4Signer.setServiceName(getServiceNameIntern());
}
String signingRegionOverride = request.getHandlerContext(HandlerContextKey.SIGNING_REGION);
if (signingRegionOverride != null) {
v4Signer.setRegionName(signingRegionOverride);
} else {
v4Signer.setRegionName(region);
}
return v4Signer;
}
/**
* Return the region string that should be used for signing requests sent by
* this client. This method can only return null if both of the following
* are true:
* (a) the user has never specified a region via setRegion/configureRegion/setSignerRegionOverride
* (b) the user has specified a client endpoint that is known to be a global S3 endpoint
*/
private String getSignerRegion() {
String region = getSignerRegionOverride();
if (region == null) {
region = clientRegion;
}
return region;
}
/**
* Has signer been explicitly overriden in the configuration?
*/
private boolean isSignerOverridden() {
return clientConfiguration != null
&& clientConfiguration.getSignerOverride() != null;
}
/**
* Returns true if the region required for signing could not be computed from the client or the request.
*
* This is the case when the standard endpoint is in use and neither an explicit region nor a signer override
* have been provided by the user.
*
*/
private boolean noExplicitRegionProvided(final Request> request) {
return isStandardEndpoint(request.getEndpoint()) &&
getSignerRegion() == null;
}
private boolean isStandardEndpoint(URI endpoint) {
return endpoint.getHost().endsWith(Constants.S3_HOSTNAME);
}
/**
* Pre-signs the specified request, using a signature query-string
* parameter.
*
* @param request
* The request to sign.
* @param methodName
* The HTTP method (GET, PUT, DELETE, HEAD) for the specified
* request.
* @param bucketName
* The name of the bucket involved in the request. If the request
* is not an operation on a bucket this parameter should be null.
* @param key
* The object key involved in the request. If the request is not
* an operation on an object, this parameter should be null.
* @param expiration
* The time at which the signed request is no longer valid, and
* will stop working.
* @param subResource
* The optional sub-resource being requested as part of the
* request (e.g. "location", "acl", "logging", or "torrent").
*/
protected void presignRequest(Request request, HttpMethod methodName,
String bucketName, String key, Date expiration, String subResource) {
// Run any additional request handlers if present
beforeRequest(request);
String resourcePath = "/" +
((bucketName != null) ? bucketName + "/" : "") +
((key != null) ? SdkHttpUtils.urlEncode(key, true) : "") +
((subResource != null) ? "?" + subResource : "");
// Make sure the resource-path for signing does not contain
// any consecutive "/"s.
// Note that we should also follow the same rule to escape
// consecutive "/"s when generating the presigned URL.
// See ServiceUtils#convertRequestToUrl(...)
resourcePath = resourcePath.replaceAll("(?<=/)/", "%2F");
new S3QueryStringSigner(methodName.toString(), resourcePath, expiration)
.sign(request, CredentialUtils.getCredentialsProvider(request.getOriginalRequest(), awsCredentialsProvider).getCredentials());
// The Amazon S3 DevPay token header is a special exception and can be safely moved
// from the request's headers into the query string to ensure that it travels along
// with the pre-signed URL when it's sent back to Amazon S3.
if (request.getHeaders().containsKey(Headers.SECURITY_TOKEN)) {
String value = request.getHeaders().get(Headers.SECURITY_TOKEN);
request.addParameter(Headers.SECURITY_TOKEN, value);
request.getHeaders().remove(Headers.SECURITY_TOKEN);
}
}
private void beforeRequest(Request request) {
if (requestHandler2s != null) {
for (RequestHandler2 requestHandler2 : requestHandler2s) {
requestHandler2.beforeRequest(request);
}
}
}
/**
*
* Populates the specified request object with the appropriate headers from
* the {@link ObjectMetadata} object.
*
*
* @param request
* The request to populate with headers.
* @param metadata
* The metadata containing the header information to include in
* the request.
*/
protected static void populateRequestMetadata(Request> request, ObjectMetadata metadata) {
Map rawMetadata = metadata.getRawMetadata();
if (rawMetadata != null) {
for (Entry entry : rawMetadata.entrySet()) {
request.addHeader(entry.getKey(), entry.getValue().toString());
}
}
Date httpExpiresDate = metadata.getHttpExpiresDate();
if (httpExpiresDate != null) {
request.addHeader(Headers.EXPIRES, DateUtils.formatRFC822Date(httpExpiresDate));
}
Map userMetadata = metadata.getUserMetadata();
if (userMetadata != null) {
for (Entry entry : userMetadata.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
if (key != null) key = key.trim();
if (value != null) value = value.trim();
request.addHeader(Headers.S3_USER_METADATA_PREFIX + key, value);
}
}
}
/**
*
* Populate the specified request with {@link Constants#REQUESTER_PAYS} to header {@link Headers#REQUESTER_PAYS_HEADER},
* if isRequesterPays is true.
*
*
* @param request
* The specified request to populate.
* @param isRequesterPays
* The flag whether to populate the header or not.
*/
protected static void populateRequesterPaysHeader(Request> request, boolean isRequesterPays) {
if (isRequesterPays) {
request.addHeader(Headers.REQUESTER_PAYS_HEADER, Constants.REQUESTER_PAYS);
}
}
/**
*
* Populates the specified request with the specified Multi-Factor
* Authentication (MFA) details. This includes the MFA header with device serial
* number and generated token. Since all requests which include the MFA
* header must be sent over HTTPS, this operation also configures the request object to
* use HTTPS instead of HTTP.
*
*
* @param request
* The request to populate.
* @param mfa
* The Multi-Factor Authentication information.
*/
private void populateRequestWithMfaDetails(Request> request, MultiFactorAuthentication mfa) {
if (mfa == null) return;
String endpoint = request.getEndpoint().toString();
if (endpoint.startsWith("http://")) {
String httpsEndpoint = endpoint.replace("http://", "https://");
request.setEndpoint(URI.create(httpsEndpoint));
log.info("Overriding current endpoint to use HTTPS " +
"as required by S3 for requests containing an MFA header");
}
request.addHeader(Headers.S3_MFA,
mfa.getDeviceSerialNumber() + " " + mfa.getToken());
}
/**
*
* Populates the specified request with the numerous options available in
* CopyObjectRequest
.
*
*
* @param request
* The request to populate with headers to represent all the
* options expressed in the CopyObjectRequest
object.
* @param copyObjectRequest
* The object containing all the options for copying an object in
* Amazon S3.
*/
private void populateRequestWithCopyObjectParameters(Request extends AmazonWebServiceRequest> request, CopyObjectRequest copyObjectRequest) {
String copySourceHeader = assembleCopySourceHeader(copyObjectRequest.getSourceBucketName(),
copyObjectRequest.getSourceKey(),
copyObjectRequest.getSourceVersionId());
request.addHeader("x-amz-copy-source", copySourceHeader);
addDateHeader(request, Headers.COPY_SOURCE_IF_MODIFIED_SINCE,
copyObjectRequest.getModifiedSinceConstraint());
addDateHeader(request, Headers.COPY_SOURCE_IF_UNMODIFIED_SINCE,
copyObjectRequest.getUnmodifiedSinceConstraint());
addStringListHeader(request, Headers.COPY_SOURCE_IF_MATCH,
copyObjectRequest.getMatchingETagConstraints());
addStringListHeader(request, Headers.COPY_SOURCE_IF_NO_MATCH,
copyObjectRequest.getNonmatchingETagConstraints());
if (copyObjectRequest.getAccessControlList() != null) {
addAclHeaders(request, copyObjectRequest.getAccessControlList());
} else if (copyObjectRequest.getCannedAccessControlList() != null) {
request.addHeader(Headers.S3_CANNED_ACL,
copyObjectRequest.getCannedAccessControlList().toString());
}
if (copyObjectRequest.getStorageClass() != null) {
request.addHeader(Headers.STORAGE_CLASS, copyObjectRequest.getStorageClass());
}
if (copyObjectRequest.getRedirectLocation() != null) {
request.addHeader(Headers.REDIRECT_LOCATION, copyObjectRequest.getRedirectLocation());
}
populateRequesterPaysHeader(request, copyObjectRequest.isRequesterPays());
ObjectMetadata newObjectMetadata = copyObjectRequest.getNewObjectMetadata();
if (copyObjectRequest.getMetadataDirective() != null) {
request.addHeader(Headers.METADATA_DIRECTIVE, copyObjectRequest.getMetadataDirective());
} else if (newObjectMetadata != null) {
request.addHeader(Headers.METADATA_DIRECTIVE, "REPLACE");
}
if (newObjectMetadata != null) {
populateRequestMetadata(request, newObjectMetadata);
}
ObjectTagging newObjectTagging = copyObjectRequest.getNewObjectTagging();
if (newObjectTagging != null) {
request.addHeader(Headers.TAGGING_DIRECTIVE, "REPLACE");
request.addHeader(Headers.S3_TAGGING, urlEncodeTags(newObjectTagging));
}
// Populate the SSE-C parameters for the destination object
populateSourceSSE_C(request, copyObjectRequest.getSourceSSECustomerKey());
populateSSE_C(request, copyObjectRequest.getDestinationSSECustomerKey());
}
/**
*
* Populates the specified request with the numerous options available in
* CopyObjectRequest
.
*
*
* @param request
* The request to populate with headers to represent all the
* options expressed in the CopyPartRequest
object.
* @param copyPartRequest
* The object containing all the options for copying an object in
* Amazon S3.
*/
private void populateRequestWithCopyPartParameters(Request> request, CopyPartRequest copyPartRequest) {
String copySourceHeader = assembleCopySourceHeader(copyPartRequest.getSourceBucketName(),
copyPartRequest.getSourceKey(),
copyPartRequest.getSourceVersionId());
request.addHeader("x-amz-copy-source", copySourceHeader);
addDateHeader(request, Headers.COPY_SOURCE_IF_MODIFIED_SINCE,
copyPartRequest.getModifiedSinceConstraint());
addDateHeader(request, Headers.COPY_SOURCE_IF_UNMODIFIED_SINCE,
copyPartRequest.getUnmodifiedSinceConstraint());
addStringListHeader(request, Headers.COPY_SOURCE_IF_MATCH,
copyPartRequest.getMatchingETagConstraints());
addStringListHeader(request, Headers.COPY_SOURCE_IF_NO_MATCH,
copyPartRequest.getNonmatchingETagConstraints());
if ( copyPartRequest.getFirstByte() != null && copyPartRequest.getLastByte() != null ) {
String range = "bytes=" + copyPartRequest.getFirstByte() + "-" + copyPartRequest.getLastByte();
request.addHeader(Headers.COPY_PART_RANGE, range);
}
// Populate the SSE-C parameters for the destination object
populateSourceSSE_C(request, copyPartRequest.getSourceSSECustomerKey());
populateSSE_C(request, copyPartRequest.getDestinationSSECustomerKey());
}
/**
* Populates the specified request header with Content-MD5.
* @param request The request to populate with Content-MD5 header.
* @param content Content for which MD5Hash is calculated.
*/
private void populateRequestHeaderWithMd5(Request> request, byte[] content) {
try {
byte[] md5 = Md5Utils.computeMD5Hash(content);
String md5Base64 = BinaryUtils.toBase64(md5);
request.addHeader("Content-MD5", md5Base64);
} catch ( Exception e ) {
throw new SdkClientException("Couldn't compute md5 sum", e);
}
}
/**
* Assemble copy source header (x-amz-copy-source) from copy source bucket name, object key, and version ID.
*
* @param sourceBucketName copy source bucket name, can either be source bucket name or source access point ARN
* @param sourceObjectKey copy source object key
* @param sourceVersionId copy source version ID, optional.
* @return copy source header (x-amz-copy-source)
*/
private String assembleCopySourceHeader(String sourceBucketName, String sourceObjectKey, String sourceVersionId) {
if (sourceBucketName == null) {
throw new IllegalArgumentException("Copy source bucket name should not be null");
}
if (sourceObjectKey == null) {
throw new IllegalArgumentException("Copy source object key should not be null");
}
String copySourceHeader;
if (isArn(sourceBucketName)) {
// The source bucket name appears to be ARN. Parse it as S3 access point ARN and form
// object-via-access-point copy source header.
Arn resourceArn = Arn.fromString(sourceBucketName);
S3Resource s3Resource;
try {
s3Resource = S3ArnConverter.getInstance().convertArn(resourceArn);
} catch (RuntimeException e) {
throw new IllegalArgumentException("An ARN was passed as a bucket parameter to an S3 operation, "
+ "however it does not appear to be a valid S3 access point ARN.", e);
}
if (!S3ResourceType.ACCESS_POINT.toString().equals(s3Resource.getType())) {
throw new IllegalArgumentException("An ARN was passed as a bucket parameter to an S3 operation, "
+ "however it does not appear to be a valid S3 access point ARN.");
}
copySourceHeader = SdkHttpUtils.urlEncode(sourceBucketName + "/object/" + sourceObjectKey, false);
} else {
copySourceHeader = "/" + SdkHttpUtils.urlEncode(sourceBucketName, true)
+ "/" + SdkHttpUtils.urlEncode(sourceObjectKey, true);
}
if (sourceVersionId != null) {
copySourceHeader += "?versionId=" + sourceVersionId;
}
return copySourceHeader;
}
/**
*
* Populates the specified request with the numerous attributes available in
* SSEWithCustomerKeyRequest
.
*
*
* @param request
* The request to populate with headers to represent all the
* options expressed in the
* ServerSideEncryptionWithCustomerKeyRequest
* object.
* @param sseKey
* The request object for an S3 operation that allows server-side
* encryption using customer-provided keys.
*/
private static void populateSSE_C(Request> request, SSECustomerKey sseKey) {
if (sseKey == null) return;
addHeaderIfNotNull(request, Headers.SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM,
sseKey.getAlgorithm());
addHeaderIfNotNull(request, Headers.SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY,
sseKey.getKey());
addHeaderIfNotNull(request, Headers.SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5,
sseKey.getMd5());
// Calculate the MD5 hash of the encryption key and fill it in the
// header, if the user didn't specify it in the metadata
if (sseKey.getKey() != null
&& sseKey.getMd5() == null) {
String encryptionKey_b64 = sseKey.getKey();
byte[] encryptionKey = Base64.decode(encryptionKey_b64);
request.addHeader(Headers.SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5,
Md5Utils.md5AsBase64(encryptionKey));
}
}
private static void populateSourceSSE_C(Request> request, SSECustomerKey sseKey) {
if (sseKey == null) return;
// Populate the SSE-C parameters for the source object
addHeaderIfNotNull(request, Headers.COPY_SOURCE_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM,
sseKey.getAlgorithm());
addHeaderIfNotNull(request, Headers.COPY_SOURCE_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY,
sseKey.getKey());
addHeaderIfNotNull(request, Headers.COPY_SOURCE_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5,
sseKey.getMd5());
// Calculate the MD5 hash of the encryption key and fill it in the
// header, if the user didn't specify it in the metadata
if (sseKey.getKey() != null
&& sseKey.getMd5() == null) {
String encryptionKey_b64 = sseKey.getKey();
byte[] encryptionKey = Base64.decode(encryptionKey_b64);
request.addHeader(Headers.COPY_SOURCE_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5,
Md5Utils.md5AsBase64(encryptionKey));
}
}
private static void populateSSE_KMS(Request> request,
SSEAwsKeyManagementParams sseParams) {
if (sseParams != null) {
addHeaderIfNotNull(request, Headers.SERVER_SIDE_ENCRYPTION,
sseParams.getEncryption());
addHeaderIfNotNull(request,
Headers.SERVER_SIDE_ENCRYPTION_AWS_KMS_KEYID,
sseParams.getAwsKmsKeyId());
addHeaderIfNotNull(request, Headers.SERVER_SIDE_ENCRYPTION_AWS_KMS_CONTEXT, sseParams.getAwsKmsEncryptionContext());
}
}
/**
* Adds the part number to the specified request, if partNumber is not null.
*
* @param request
* The request to add the partNumber to.
* @param partNumber
* The part number to be added.
*/
private void addPartNumberIfNotNull(Request> request, Integer partNumber) {
if (partNumber != null) {
request.addParameter("partNumber", partNumber.toString());
}
}
/**
* Adds the specified header to the specified request, if the header value
* is not null.
*
* @param request
* The request to add the header to.
* @param header
* The header name.
* @param value
* The header value.
*/
private static void addHeaderIfNotNull(Request> request, String header, String value) {
if (value != null) {
request.addHeader(header, value);
}
}
private static void addIntegerHeaderIfNotNull(Request> request, String header, Integer value) {
if (value != null) {
request.addHeader(header, Integer.toString(value));
}
}
/**
* Adds the specified parameter to the specified request, if the parameter
* value is not null.
*
* @param request
* The request to add the parameter to.
* @param paramName
* The parameter name.
* @param paramValue
* The parameter value.
*/
private static void addParameterIfNotNull(Request> request, String paramName, Integer paramValue) {
if (paramValue != null) {
addParameterIfNotNull(request, paramName, paramValue.toString());
}
}
/**
* Adds the specified parameter to the specified request, if the parameter
* value is not null.
*
* @param request
* The request to add the parameter to.
* @param paramName
* The parameter name.
* @param paramValue
* The parameter value.
*/
private static void addParameterIfNotNull(Request> request, String paramName, String paramValue) {
if (paramValue != null) {
request.addParameter(paramName, paramValue);
}
}
/**
*
* Adds the specified date header in RFC 822 date format to the specified
* request.
* This method will not add a date header if the specified date value is null
.
*
*
* @param request
* The request to add the header to.
* @param header
* The header name.
* @param value
* The header value.
*/
private static void addDateHeader(Request> request, String header, Date value) {
if (value != null) {
request.addHeader(header, ServiceUtils.formatRfc822Date(value));
}
}
/**
*
* Adds the specified string list header, joined together separated with
* commas, to the specified request.
* This method will not add a string list header if the specified values
* are null
or empty.
*
*
* @param request
* The request to add the header to.
* @param header
* The header name.
* @param values
* The list of strings to join together for the header value.
*/
private static void addStringListHeader(Request> request, String header, List values) {
if (values != null && !values.isEmpty()) {
request.addHeader(header, ServiceUtils.join(values));
}
}
/**
*
* Adds response headers parameters to the request given, if non-null.
*
*
* @param request
* The request to add the response header parameters to.
* @param responseHeaders
* The full set of response headers to add, or null for none.
*/
private static void addResponseHeaderParameters(Request> request, ResponseHeaderOverrides responseHeaders) {
if ( responseHeaders != null ) {
if ( responseHeaders.getCacheControl() != null ) {
request.addParameter(ResponseHeaderOverrides.RESPONSE_HEADER_CACHE_CONTROL, responseHeaders.getCacheControl());
}
if ( responseHeaders.getContentDisposition() != null ) {
request.addParameter(ResponseHeaderOverrides.RESPONSE_HEADER_CONTENT_DISPOSITION,
responseHeaders.getContentDisposition());
}
if ( responseHeaders.getContentEncoding() != null ) {
request.addParameter(ResponseHeaderOverrides.RESPONSE_HEADER_CONTENT_ENCODING,
responseHeaders.getContentEncoding());
}
if ( responseHeaders.getContentLanguage() != null ) {
request.addParameter(ResponseHeaderOverrides.RESPONSE_HEADER_CONTENT_LANGUAGE,
responseHeaders.getContentLanguage());
}
if ( responseHeaders.getContentType() != null ) {
request.addParameter(ResponseHeaderOverrides.RESPONSE_HEADER_CONTENT_TYPE, responseHeaders.getContentType());
}
if ( responseHeaders.getExpires() != null ) {
request.addParameter(ResponseHeaderOverrides.RESPONSE_HEADER_EXPIRES, responseHeaders.getExpires());
}
}
}
/**
* Returns the URL to the key in the bucket given, using the client's scheme
* and endpoint. Returns null if the given bucket and key cannot be
* converted to a URL.
*/
public String getResourceUrl(String bucketName, String key) {
try {
return getUrl(bucketName, key).toString();
} catch ( Exception e ) {
return null;
}
}
@Override
public URL getUrl(String bucketName, String key) {
if (isArn(bucketName)) {
throw new IllegalArgumentException("ARNs are not supported for getUrl in this SDK version. Please use S3Utilities "
+ "in the AWS SDK for Java 2.x.");
}
Request> request = new DefaultRequest