/******************************************************************************* * Copyright 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. * ***************************************************************************** * __ _ _ ___ * ( )( \/\/ )/ __) * /__\ \ / \__ \ * (_)(_) \/\/ (___/ * * AWS SDK for .NET * API Version: 2006-03-01 * */ using Amazon.Runtime.Internal; using Amazon.S3.Model; using Amazon.Util; using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Net; using System.Text; using System.Threading; namespace Amazon.S3.Util { public static partial class AmazonS3Util { /// /// Determines whether an S3 bucket exists or not. /// /// The name of the bucket to check. /// The Amazon S3 Client to use for S3 specific operations. /// False is returned in case S3 responds with a NoSuchBucket error. /// True is returned in case of success, AccessDenied error or PermanentRedirect error. /// An exception is thrown in case of any other error. /// This method calls GetACL for the bucket. public static bool DoesS3BucketExistV2(IAmazonS3 s3Client, string bucketName) { try { s3Client.GetACL(bucketName); } catch (AmazonS3Exception e) { switch (e.ErrorCode) { // A redirect error or a forbidden error means the bucket exists. case "AccessDenied": case "PermanentRedirect": return true; case "NoSuchBucket": return false; default: throw; } } return true; } /// /// Determines whether an S3 bucket exists or not. /// This is done by: /// 1. Creating a PreSigned Url for the bucket. To work with Signature V4 only regions, as /// well as Signature V4-optional regions, we keep the expiry to within the maximum for V4 /// (which is one week). /// 2. Making a HEAD request to the Url /// /// The name of the bucket to check. /// The Amazon S3 Client to use for S3 specific operations. /// [Obsolete("This method is deprecated: its behavior is inconsistent and always uses HTTP. Please use DoesS3BucketExistV2 instead.")] public static bool DoesS3BucketExist(IAmazonS3 s3Client, string bucketName) { if (s3Client == null) { throw new ArgumentNullException("s3Client", "The s3Client cannot be null!"); } if (String.IsNullOrEmpty(bucketName)) { throw new ArgumentNullException("bucketName", "The bucketName cannot be null or the empty string!"); } var config = s3Client.Config; var request = new GetPreSignedUrlRequest { BucketName = bucketName, Expires = config.CorrectedUtcNow.ToLocalTime().AddDays(1), Verb = HttpVerb.HEAD, Protocol = Protocol.HTTP }; var url = s3Client.GetPreSignedURL(request); var uri = new Uri(url); var response = AmazonS3HttpUtil.GetHead(s3Client, config, url, HeaderKeys.XAmzBucketRegion); if (response.StatusCode == null) { // there was a problem with the request and we weren't able // conclusively determine if the bucket exists return false; } else { AmazonS3Uri s3Uri; var mismatchDetected = AmazonS3Uri.TryParseAmazonS3Uri(uri, out s3Uri) && BucketRegionDetector.GetCorrectRegion(s3Uri, response.StatusCode.Value, response.HeaderValue) != null; var statusCodeAcceptable = response.StatusCode != HttpStatusCode.NotFound && response.StatusCode != HttpStatusCode.BadRequest; return statusCodeAcceptable || mismatchDetected; } } ///// ///// Sets the storage class for the S3 Object to the value ///// specified. ///// ///// The S3 Object whose storage class needs changing ///// The new Storage Class for the object ///// The Amazon S3 Client to use for S3 specific operations. ///// //public static void SetObjectStorageClass(S3Object s3Object, S3StorageClass sClass, IAmazonS3 s3Client) //{ // SetObjectStorageClass(s3Object.BucketName, s3Object.Key, sClass, s3Client); //} /// /// Sets the storage class for the S3 Object to the value /// specified. /// /// The name of the bucket in which the key is stored /// The key of the S3 Object whose storage class needs changing /// The new Storage Class for the object /// The Amazon S3 Client to use for S3 specific operations. /// public static void SetObjectStorageClass(IAmazonS3 s3Client, string bucketName, string key, S3StorageClass sClass) { SetObjectStorageClass(s3Client, bucketName, key, null, sClass); } /// /// Sets the storage class for the S3 Object's Version to the value /// specified. /// /// The name of the bucket in which the key is stored /// The key of the S3 Object whose storage class needs changing /// The version of the S3 Object whose storage class needs changing /// The new Storage Class for the object /// The Amazon S3 Client to use for S3 specific operations. /// public static void SetObjectStorageClass(IAmazonS3 s3Client, string bucketName, string key, string version, S3StorageClass sClass) { CopyObjectRequest copyRequest; PutACLRequest putACLRequest; SetupForObjectModification(s3Client, bucketName, key, version, out copyRequest, out putACLRequest); copyRequest.StorageClass = sClass; CopyObjectResponse copyResponse = s3Client.CopyObject(copyRequest); if (!string.IsNullOrEmpty(copyResponse.SourceVersionId)) putACLRequest.VersionId = copyResponse.SourceVersionId; s3Client.PutACL(putACLRequest); } ///// ///// Sets the server side encryption method for the S3 Object to the value ///// specified. ///// ///// The S3 Object ///// The server side encryption method ///// The Amazon S3 Client to use for S3 specific operations. //public static void SetServerSideEncryption(S3Object s3Object, ServerSideEncryptionMethod method, IAmazonS3 s3Client) //{ // SetServerSideEncryption(s3Object.BucketName, s3Object.Key, method, s3Client); //} /// /// Sets the server side encryption method for the S3 Object to the value /// specified. /// /// The name of the bucket in which the key is stored /// The key of the S3 Object /// The server side encryption method /// The Amazon S3 Client to use for S3 specific operations. public static void SetServerSideEncryption(IAmazonS3 s3Client, string bucketName, string key, ServerSideEncryptionMethod method) { SetServerSideEncryption(s3Client, bucketName, key, null, method); } ///// ///// Sets the server side encryption method for the S3 Object Version to the value ///// specified. ///// ///// The S3 Object Version ///// The server side encryption method ///// The Amazon S3 Client to use for S3 specific operations. //public static void SetServerSideEncryption(S3ObjectVersion s3ObjectVer, ServerSideEncryptionMethod method, IAmazonS3 s3Client) //{ // SetServerSideEncryption(s3ObjectVer.BucketName, s3ObjectVer.Key, s3ObjectVer.VersionId, method, s3Client); //} /// /// Sets the server side encryption method for the S3 Object's Version to the value /// specified. /// /// The name of the bucket in which the key is stored /// The key of the S3 Object /// The version of the S3 Object /// The server side encryption method /// The Amazon S3 Client to use for S3 specific operations. public static void SetServerSideEncryption(IAmazonS3 s3Client, string bucketName, string key, string version, ServerSideEncryptionMethod method) { CopyObjectRequest copyRequest; PutACLRequest putACLRequest; SetupForObjectModification(s3Client, bucketName, key, version, out copyRequest, out putACLRequest); copyRequest.ServerSideEncryptionMethod = method; CopyObjectResponse copyResponse = s3Client.CopyObject(copyRequest); if (!string.IsNullOrEmpty(copyResponse.SourceVersionId)) putACLRequest.VersionId = copyResponse.SourceVersionId; s3Client.PutACL(putACLRequest); } ///// ///// Sets the redirect location for the S3 Object's when being accessed through the S3 website endpoint. ///// ///// The S3 Object ///// The redirect location ///// The Amazon S3 Client to use for S3 specific operations. //public static void SetWebsiteRedirectLocation(S3Object s3Object, string websiteRedirectLocation, IAmazonS3 s3Client) //{ // SetWebsiteRedirectLocation(s3Object.BucketName, s3Object.Key, websiteRedirectLocation, s3Client); //} /// /// Sets the redirect location for the S3 Object's when being accessed through the S3 website endpoint. /// /// The name of the bucket in which the key is stored /// The key of the S3 Object /// The redirect location /// The Amazon S3 Client to use for S3 specific operations. public static void SetWebsiteRedirectLocation(IAmazonS3 s3Client, string bucketName, string key, string websiteRedirectLocation) { CopyObjectRequest copyRequest; PutACLRequest putACLRequest; SetupForObjectModification(s3Client, bucketName, key, null, out copyRequest, out putACLRequest); copyRequest.WebsiteRedirectLocation = websiteRedirectLocation; CopyObjectResponse copyResponse = s3Client.CopyObject(copyRequest); if (!string.IsNullOrEmpty(copyResponse.SourceVersionId)) putACLRequest.VersionId = copyResponse.SourceVersionId; s3Client.PutACL(putACLRequest); } /// /// Sets up the request needed to make an exact copy of the object leaving the parent method /// the ability to change just the attribute being requested to change. /// /// /// /// /// /// /// static void SetupForObjectModification(IAmazonS3 s3Client, string bucketName, string key, string version, out CopyObjectRequest copyRequest, out PutACLRequest putACLRequest) { // Get the existing ACL of the object GetACLRequest getACLRequest = new GetACLRequest(); getACLRequest.BucketName = bucketName; getACLRequest.Key = key; if (version != null) getACLRequest.VersionId = version; GetACLResponse getACLResponse = s3Client.GetACL(getACLRequest); // Set the object's original ACL back onto it because a COPY // operation resets the ACL on the destination object. putACLRequest = new PutACLRequest(); putACLRequest.BucketName = bucketName; putACLRequest.Key = key; putACLRequest.AccessControlList = getACLResponse.AccessControlList; ListObjectsResponse listObjectResponse = s3Client.ListObjects(new ListObjectsRequest { BucketName = bucketName, Prefix = key, MaxKeys = 1 }); if (listObjectResponse.S3Objects.Count != 1) { throw new InvalidOperationException("No object exists with this bucket name and key."); } GetObjectMetadataRequest getMetaRequest = new GetObjectMetadataRequest() { BucketName = bucketName, Key = key }; GetObjectMetadataResponse getMetaResponse = s3Client.GetObjectMetadata(getMetaRequest); // Set the storage class on the object copyRequest = new CopyObjectRequest(); copyRequest.SourceBucket = copyRequest.DestinationBucket = bucketName; copyRequest.SourceKey = copyRequest.DestinationKey = key; copyRequest.StorageClass = listObjectResponse.S3Objects[0].StorageClass == "STANDARD" ? S3StorageClass.Standard : S3StorageClass.ReducedRedundancy; if (version != null) copyRequest.SourceVersionId = version; copyRequest.WebsiteRedirectLocation = getMetaResponse.WebsiteRedirectLocation; copyRequest.ServerSideEncryptionMethod = getMetaResponse.ServerSideEncryptionMethod; } /// /// Converts the string representing a storage class that would come back from a ListObjects request /// to the S3StorageClass enumeration. /// /// Amazon S3 string values for storage class /// The converted S3StorageClass enumeration public static S3StorageClass ConvertToS3StorageClass(string value) { switch (value) { case "REDUCED_REDUNDANCY": return S3StorageClass.ReducedRedundancy; case "GLACIER": return S3StorageClass.Glacier; default: return S3StorageClass.Standard; } } /// /// Upload data to Amazon S3 using HTTP POST. /// /// /// For more information, /// /// Request object which describes the data to POST /// Thrown if the service returns an error public static S3PostUploadResponse PostUpload(S3PostUploadRequest request) { string url; string subdomain = (request.Region.Equals(RegionEndpoint.USEast1) || request.Region?.SystemName == RegionEndpoint.USEast1.SystemName) ? "s3" : "s3-" + request.Region.SystemName; if (request.Bucket.IndexOf('.') > -1) url = string.Format(CultureInfo.InvariantCulture, "https://{0}.amazonaws.com/{1}/", subdomain, request.Bucket); else url = string.Format(CultureInfo.InvariantCulture, "https://{0}.{1}.amazonaws.com", request.Bucket, subdomain); Uri uri = new Uri(url); HttpWebRequest webRequest = WebRequest.Create(uri) as HttpWebRequest; var boundary = Convert.ToBase64String(Guid.NewGuid().ToByteArray()).Replace('=', 'z'); webRequest.ContentType = string.Format(CultureInfo.InvariantCulture, "multipart/form-data; boundary={0}", boundary); webRequest.Method = "POST"; using (var reqStream = webRequest.GetRequestStream()) { request.WriteFormData(boundary, reqStream); byte[] boundaryBytes = Encoding.UTF8.GetBytes(string.Format(CultureInfo.InvariantCulture, "--{0}\r\nContent-Disposition: form-data; name=\"file\"\r\n\r\n", boundary)); reqStream.Write(boundaryBytes, 0, boundaryBytes.Length); using (var inputStream = null == request.Path ? request.InputStream : File.OpenRead(request.Path)) { byte[] buf = new byte[1024]; int bytesRead; while ((bytesRead = inputStream.Read(buf, 0, 1024)) > 0) { reqStream.Write(buf, 0, bytesRead); } } byte[] endBoundaryBytes = Encoding.UTF8.GetBytes(string.Format(CultureInfo.InvariantCulture, "\r\n--{0}--", boundary)); reqStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length); } HttpWebResponse response = null; try { response = webRequest.GetResponse() as HttpWebResponse; return S3PostUploadResponse.FromWebResponse(response); } catch (WebException ex) { throw S3PostUploadException.FromResponse((HttpWebResponse)ex.Response); } finally { if (response != null) { response.Close(); } } } } }