/******************************************************************************* * Copyright 2008-2013 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 * */ using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Text; using Amazon.S3.Model; using System.Globalization; using Amazon.Util; namespace Amazon.S3.Util { /// /// Parameters for uploading to Amazon S3 a file using HTTP POS /// /// /// /// If a S3PostUploadSignedPolicy is assigned, then values set (other than InputStream or Path) on this object must adhere to the policy. /// This includes metadata. If metadata is specified in the policy, then it must be included in the request. Adding metadata not in the /// policy will cause the POST to fail. /// /// For more information, /// /// public class S3PostUploadRequest { private S3StorageClass _storageClass; private HttpStatusCode _actionStatus; private RegionEndpoint _region = RegionEndpoint.USEast1; private bool _isSetStorageClass = false, _isSetActionStatus = false; /// /// Default constructor. /// public S3PostUploadRequest() { this.Metadata = new Dictionary(); this.CannedACL = S3CannedACL.Private; this._actionStatus = HttpStatusCode.NoContent; this._storageClass = S3StorageClass.Standard; } /// /// S3 Bucket to upload the object to /// public string Bucket { get; set; } /// /// The name of the uploaded key. /// public string Key { get; set; } /// /// Stream to read the upload data for /// /// /// If you use InputStream, then you also need to set ContentLength /// public Stream InputStream { get; set; } /// /// File path to read the upload data from /// public string Path { get; set; } /// /// Content type for the uploaded data /// /// /// If this is not set, an attempt will be made to infer it from the extension on Key or Path (in that order), /// otherwise 'application/octet-stream' will be assumed. /// public string ContentType { get; set; } /// /// Specifies an Amazon S3 access control list /// public S3CannedACL CannedACL { get; set; } /// /// Signed policy from bucket owner. /// public S3PostUploadSignedPolicy SignedPolicy { get; set; } /// /// Where to redirect browsers on a successful upload /// public string SuccessActionRedirect { get; set; } /// /// The status code returned to the client upon successful upload if success_action_redirect is not specified /// /// /// /// Accepts the values OK (200) , Created (201), or NoContent (204, default). /// /// If the value is set to OK or NoContent, Amazon S3 returns an empty document with a 200 or 204 status code. /// /// If the value is set to Created, Amazon S3 returns an XML document with a 201 status code. /// /// If the value is not set or if it is set to an invalid value, Amazon S3 returns an empty document with a 204 status code. /// /// public HttpStatusCode SuccessActionStatus { get { return this._actionStatus; } set { this._actionStatus = value; this._isSetActionStatus = true; } } /// /// Storage class to use for storing the object /// /// /// Default: STANDARD /// public S3StorageClass StorageClass { get { return this._storageClass; } set { this._storageClass = value; this._isSetStorageClass = true; } } /// /// The AWS region where the bucket is located. /// /// /// Depending upon the bucket name, POST uploads will be /// successfully redirected, but for buckets with non-DNS-compliant /// characters, redirects will fail. Setting this to the appropriate /// region will avoid the redirect. /// public RegionEndpoint Region { get { return this._region; } set { this._region = value; } } /// /// Metadata to set on the uploaded object /// /// /// If keys do not begin with 'x-amz-meta-' it will be added at POST time. /// public IDictionary Metadata { get; set; } /// /// Write the multipart/form-data for this request for all fields except the file data to a stream /// internal void WriteFormData(string boundary, Stream outputStream) { if (!String.IsNullOrEmpty(this.Key)) WriteFormDatum(outputStream, S3Constants.PostFormDataObjectKey, this.Key, boundary); WriteFormDatum(outputStream, S3Constants.PostFormDataAcl, this.CannedACL, boundary); if (this._isSetStorageClass) WriteFormDatum(outputStream, HeaderKeys.XAmzStorageClassHeader, this.StorageClass, boundary); if (this._isSetActionStatus) WriteFormDatum(outputStream, S3Constants.PostFormDataStatus, ((Int32)this.SuccessActionStatus).ToString(CultureInfo.InvariantCulture), boundary); if (!String.IsNullOrEmpty(this.SuccessActionRedirect)) WriteFormDatum(outputStream, S3Constants.PostFormDataRedirect, this.SuccessActionRedirect, boundary); if (String.IsNullOrEmpty(this.ContentType)) { if (this.Key.IndexOf('.') > -1) this.ContentType = AmazonS3Util.MimeTypeFromExtension(this.Key.Substring(this.Key.LastIndexOf('.'))); else if (!String.IsNullOrEmpty(this.Path) && this.Path.IndexOf('.') > -1) this.ContentType = AmazonS3Util.MimeTypeFromExtension(this.Key.Substring(this.Path.LastIndexOf('.'))); } WriteFormDatum(outputStream, S3Constants.PostFormDataContentType, this.ContentType, boundary); if (this.SignedPolicy != null && !string.IsNullOrEmpty(this.SignedPolicy.SecurityToken)) { this.Metadata[S3Constants.PostFormDataSecurityToken] = this.SignedPolicy.SecurityToken; } foreach (var kvp in this.Metadata) { var metakey = kvp.Key.StartsWith(S3Constants.PostFormDataXAmzPrefix, StringComparison.Ordinal) ? kvp.Key : S3Constants.PostFormDataMetaPrefix + kvp.Key; WriteFormDatum(outputStream, metakey, kvp.Value, boundary); } if (this.SignedPolicy != null) { WriteFormDatum(outputStream, S3Constants.PostFormDataAccessKeyId, this.SignedPolicy.AccessKeyId, boundary); WriteFormDatum(outputStream, S3Constants.PostFormDataPolicy, this.SignedPolicy.Policy, boundary); WriteFormDatum(outputStream, S3Constants.PostFormDataSignature, this.SignedPolicy.Signature, boundary); } } private static void WriteFormDatum(Stream stream, string name, string value, string boundary) { byte[] bytes = Encoding.UTF8.GetBytes(string.Format(CultureInfo.InvariantCulture, "--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}\r\n", boundary, name, value)); stream.Write(bytes, 0, bytes.Length); } } }