/* * Copyright 2010-2014 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. */ using Amazon.Runtime; using Amazon.S3.Util; using Amazon.Util; using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Net; using System.Text; namespace Amazon.S3.Model { /// /// Parameters for uploading to Amazon S3 a file using HTTP POST /// /// /// /// 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 PostObjectRequest : AmazonWebServiceRequest { private S3StorageClass _storageClass; private HttpStatusCode _actionStatus; private RegionEndpoint _region = RegionEndpoint.USEast1; private bool _isSetStorageClass = false, _isSetActionStatus = false; /// /// Upload data to Amazon S3 using HTTP POST. /// /// /// For more information, /// public PostObjectRequest() { 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 /// /// /// This API is deprecated. We recommend that you use Headers.ContentType instead. /// [Obsolete("This API is deprecated. We recommend that you use Headers.ContentType instead.")] public string ContentType { get { return Headers.ContentType; } set { Headers.ContentType = value; } } /// /// 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; } private HeadersCollectionPost headersCollection = new HeadersCollectionPost(); /// /// The collection of headers for the request. /// public HeadersCollectionPost Headers { get { if (this.headersCollection == null) this.headersCollection = new HeadersCollectionPost(); return this.headersCollection; } internal set { this.headersCollection = value; } } /// /// Attach a callback that will be called as data is being sent to the AWS Service. /// public EventHandler StreamTransferProgress { get { return ((Amazon.Runtime.Internal.IAmazonWebServiceRequest)this).StreamUploadProgressCallback; } set { ((Amazon.Runtime.Internal.IAmazonWebServiceRequest)this).StreamUploadProgressCallback = value; } } /// /// 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 (this.SignedPolicy != null && !string.IsNullOrEmpty(this.SignedPolicy.SecurityToken)) { this.Metadata[S3Constants.PostFormDataSecurityToken] = this.SignedPolicy.SecurityToken; } foreach (var key in this.Headers.Keys) { if (!String.IsNullOrEmpty(this.Headers[key])) WriteFormDatum(outputStream, key, this.Headers[key], boundary); } 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) { if (this.SignedPolicy.SignatureVersion == "2") { WriteFormDatum(outputStream, S3Constants.PostFormDataPolicy, this.SignedPolicy.Policy, boundary); WriteFormDatum(outputStream, S3Constants.PostFormDataSignature, this.SignedPolicy.Signature, boundary); WriteFormDatum(outputStream, S3Constants.PostFormDataAccessKeyId, this.SignedPolicy.AccessKeyId, boundary); } else { WriteFormDatum(outputStream, S3Constants.PostFormDataPolicy, this.SignedPolicy.Policy, boundary); WriteFormDatum(outputStream, S3Constants.PostFormDataXAmzSignature, this.SignedPolicy.Signature, boundary); WriteFormDatum(outputStream, S3Constants.PostFormDataXAmzAlgorithm, this.SignedPolicy.Algorithm, boundary); WriteFormDatum(outputStream, S3Constants.PostFormDataXAmzCredential, this.SignedPolicy.Credential, boundary); WriteFormDatum(outputStream, S3Constants.PostFormDataXAmzDate, this.SignedPolicy.Date, 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); } } }