/* * Copyright 2010-2019 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.util.LengthCheckInputStream.EXCLUDE_SKIPPED_BYTES; import static com.amazonaws.util.LengthCheckInputStream.INCLUDE_SKIPPED_BYTES; import static com.amazonaws.util.ValidationUtils.assertNotNull; import static com.amazonaws.util.ValidationUtils.assertParameterNotNull; import static com.amazonaws.util.ValidationUtils.assertStringNotEmpty; import com.amazonaws.AbortedException; 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.Request; import com.amazonaws.Response; import com.amazonaws.auth.AWSCredentials; import com.amazonaws.auth.AWSCredentialsProvider; import com.amazonaws.auth.DefaultAWSCredentialsProviderChain; import com.amazonaws.auth.Presigner; import com.amazonaws.auth.Signer; import com.amazonaws.auth.SignerFactory; import com.amazonaws.event.ProgressEvent; import com.amazonaws.event.ProgressListener; import com.amazonaws.event.ProgressListenerCallbackExecutor; import com.amazonaws.event.ProgressReportingInputStream; import com.amazonaws.handlers.HandlerChainFactory; import com.amazonaws.handlers.RequestHandler2; import com.amazonaws.http.ExecutionContext; import com.amazonaws.http.HttpClient; import com.amazonaws.http.HttpMethodName; import com.amazonaws.http.HttpResponseHandler; import com.amazonaws.http.UrlHttpClient; import com.amazonaws.internal.StaticCredentialsProvider; import com.amazonaws.metrics.AwsSdkMetrics; import com.amazonaws.metrics.RequestMetricCollector; import com.amazonaws.regions.RegionUtils; import com.amazonaws.retry.PredefinedRetryPolicies; import com.amazonaws.retry.RetryPolicy; import com.amazonaws.services.s3.internal.AWSS3V4Signer; 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.GetObjectTaggingResponseHeaderHandler; import com.amazonaws.services.s3.internal.InputSubstream; import com.amazonaws.services.s3.internal.ObjectExpirationHeaderHandler; import com.amazonaws.services.s3.internal.RepeatableFileInputStream; import com.amazonaws.services.s3.internal.ResponseHeaderHandlerChain; import com.amazonaws.services.s3.internal.S3ErrorResponseHandler; import com.amazonaws.services.s3.internal.S3ExecutionContext; import com.amazonaws.services.s3.internal.S3HttpUtils; import com.amazonaws.services.s3.internal.S3MetadataResponseHandler; import com.amazonaws.services.s3.internal.S3ObjectResponseHandler; import com.amazonaws.services.s3.internal.S3QueryStringSigner; import com.amazonaws.services.s3.internal.S3RequesterChargedHeaderHandler; import com.amazonaws.services.s3.internal.S3Signer; import com.amazonaws.services.s3.internal.S3StringResponseHandler; 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.XmlWriter; import com.amazonaws.services.s3.metrics.S3ServiceMetric; import com.amazonaws.services.s3.model.*; import com.amazonaws.services.s3.model.RequestPaymentConfiguration.Payer; import com.amazonaws.services.s3.model.analytics.AnalyticsConfiguration; import com.amazonaws.services.s3.model.inventory.InventoryConfiguration; import com.amazonaws.services.s3.model.metrics.MetricsConfiguration; 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.HeadBucketResultHandler; import com.amazonaws.services.s3.model.transform.MultiObjectDeleteXmlFactory; 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.util.Mimetypes; 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.Base64; import com.amazonaws.util.BinaryUtils; import com.amazonaws.util.DateUtils; import com.amazonaws.util.IOUtils; import com.amazonaws.util.LengthCheckInputStream; import com.amazonaws.util.Md5Utils; import com.amazonaws.util.RuntimeHttpUtils; import com.amazonaws.util.ServiceClientHolderInputStream; import com.amazonaws.util.StringUtils; import com.amazonaws.logging.Log; import com.amazonaws.logging.LogFactory; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; 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.Set; import java.util.regex.Matcher; /** *
* 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 Android 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 *
*/ @SuppressWarnings("deprecation") public class AmazonS3Client extends AmazonWebServiceClient implements AmazonS3 { public static final String S3_SERVICE_NAME = "s3"; private static final String S3_V4_SIGNER = "AWSS3V4SignerType"; /** 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_V4_SIGNER, AWSS3V4Signer.class); } /** Responsible for handling error responses from all S3 service calls. */ private final S3ErrorResponseHandler errorResponseHandler = new S3ErrorResponseHandler(); /** Shared response handler for operations with no response. */ private final S3XmlResponseHandler* 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: *
* You can force the client to operate in an anonymous mode, and skip the
* credentials provider chain, by passing in null
for the
* credentials.
*
* 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: *
* You can force the client to operate in an anonymous mode, and skip the
* credentials provider chain, by passing in null
for the
* credentials.
*
* 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: *
* You can force the client to operate in an anonymous mode, and skip the
* credentials provider chain, by passing in null
for the
* credentials.
*
* 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 void setS3ClientOptions(S3ClientOptions clientOptions) { this.clientOptions = new S3ClientOptions(clientOptions); } /* * (non-Javadoc) * @see * com.amazonaws.services.s3.AmazonS3#listNextBatchOfVersions(com.amazonaws * .services.s3.model.S3VersionListing) */ @Override public VersionListing listNextBatchOfVersions(VersionListing previousVersionListing) throws AmazonClientException, AmazonServiceException { return listNextBatchOfVersions(new ListNextBatchOfVersionsRequest(previousVersionListing)); } @Override public VersionListing listNextBatchOfVersions( ListNextBatchOfVersionsRequest listNextBatchOfVersionsRequest) throws AmazonClientException, AmazonServiceException { assertParameterNotNull( listNextBatchOfVersionsRequest, "The request object parameter must be specified when listing the next batch of versions in a bucket"); final VersionListing previousVersionListing = listNextBatchOfVersionsRequest .getPreviousVersionListing(); if (!previousVersionListing.isTruncated()) { final 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()); } /* * (non-Javadoc) * @see com.amazonaws.services.s3.AmazonS3#listVersions(java.lang.String, * java.lang.String) */ @Override public VersionListing listVersions(String bucketName, String prefix) throws AmazonClientException, AmazonServiceException { return listVersions(new ListVersionsRequest(bucketName, prefix, null, null, null, null)); } /* * (non-Javadoc) * @see com.amazonaws.services.s3.AmazonS3#listVersions(java.lang.String, * java.lang.String, java.lang.String, java.lang.String, java.lang.String, * java.lang.Integer) */ @Override public VersionListing listVersions(String bucketName, String prefix, String keyMarker, String versionIdMarker, String delimiter, Integer maxKeys) throws AmazonClientException, AmazonServiceException { final ListVersionsRequest request = new ListVersionsRequest() .withBucketName(bucketName) .withPrefix(prefix) .withDelimiter(delimiter) .withKeyMarker(keyMarker) .withVersionIdMarker(versionIdMarker) .withMaxResults(maxKeys); return listVersions(request); } /* * (non-Javadoc) * @see * com.amazonaws.services.s3.AmazonS3#listVersions(com.amazonaws.services * .s3.model.ListVersionsRequest) */ @Override public VersionListing listVersions(ListVersionsRequest listVersionsRequest) throws AmazonClientException, AmazonServiceException { assertParameterNotNull(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 call * {@link listVersionsRequest#setEncodingType(url)}. */ final boolean shouldSDKDecodeResponse = Constants.URL_ENCODING .equals(listVersionsRequest.getEncodingType()); final Request
* 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.
*
null
if constraints were specified that weren't met
* when Amazon S3 attempted to copy the object.
* @throws AmazonClientException 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) {
assertParameterNotNull(copyPartRequest.getSourceBucketName(),
"The source bucket name must be specified when copying a part");
assertParameterNotNull(copyPartRequest.getSourceKey(),
"The source object key must be specified when copying a part");
assertParameterNotNull(copyPartRequest.getDestinationBucketName(),
"The destination bucket name must be specified when copying a part");
assertParameterNotNull(copyPartRequest.getUploadId(),
"The upload id must be specified when copying a part");
assertParameterNotNull(copyPartRequest.getDestinationKey(),
"The destination object key must be specified when copying a part");
assertParameterNotNull(copyPartRequest.getPartNumber(),
"The part number must be specified when copying a part");
final String destinationKey = copyPartRequest.getDestinationKey();
final String destinationBucketName = copyPartRequest.getDestinationBucketName();
final Request* 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); } final Request* 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; } /** * 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; } private boolean isStandardEndpoint(URI endpoint) { return endpoint.getHost().endsWith(Constants.S3_HOSTNAME); } @Deprecated private S3Signer createSigV2Signer(final Request> request, final String bucketName, final String key) { final String resourcePath = "/" + ((bucketName != null) ? bucketName + "/" : "") + ((key != null) ? key : ""); return new S3Signer(request.getHttpMethod().toString(), resourcePath); } /** * 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* 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) { final Map* 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; } final String endpoint = request.getEndpoint().toString(); if (endpoint.startsWith("http://")) { final 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
.
*
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 = "/" + copyObjectRequest.getSourceBucketName()
+ "/" + copyObjectRequest.getSourceKey();
if (copyObjectRequest.getSourceVersionId() != null) {
copySourceHeader += "?versionId=" + 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());
final ObjectMetadata newObjectMetadata = copyObjectRequest.getNewObjectMetadata();
if (newObjectMetadata != null) {
request.addHeader(Headers.METADATA_DIRECTIVE, "REPLACE");
populateRequestMetadata(request, newObjectMetadata);
}
// 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
.
*
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 = "/" + copyPartRequest.getSourceBucketName()
+ "/" + copyPartRequest.getSourceKey();
if (copyPartRequest.getSourceVersionId() != null) {
copySourceHeader += "?versionId=" + 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) {
final 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 with the numerous attributes available in
* SSEWithCustomerKeyRequest
.
*
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) {
final String encryptionKey_b64 = sseKey.getKey();
final 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-CPK 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) {
final String encryptionKey_b64 = sseKey.getKey();
final 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_KMS_KEY_ID,
sseParams.getAwsKmsKeyId());
}
}
/**
* 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);
}
}
/**
* 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
.
*
* 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.
*
* 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 (final Exception e) { return null; } } /** * Returns an URL for the object stored in the specified bucket and key. ** If the object identified by the given bucket and key has public read * permissions (ex: {@link CannedAccessControlList#PublicRead}), then this * URL can be directly accessed to retrieve the object's data. * * @param bucketName The name of the bucket containing the object whose URL * is being requested. * @param key The key under which the object whose URL is being requested is * stored. * @return A unique URL for the object stored in the specified bucket and * key. */ @Override public URL getUrl(String bucketName, String key) { final Request> request = new DefaultRequest