diff --git a/aws-cpp-sdk-transfer-tests/TransferTests.cpp b/aws-cpp-sdk-transfer-tests/TransferTests.cpp index 7c5b7102787..e3e228a07d9 100644 --- a/aws-cpp-sdk-transfer-tests/TransferTests.cpp +++ b/aws-cpp-sdk-transfer-tests/TransferTests.cpp @@ -1188,5 +1188,101 @@ TEST_F(TransferTests, ScopeTests) } } +// Single part upload with metadata specified +TEST_F(TransferTests, SinglePartUploadWithMetadataTest) +{ + if (EmptyBucket(GetTestBucketName())) + { + WaitForBucketToEmpty(GetTestBucketName()); + } + GetObjectRequest getObjectRequest; + getObjectRequest.SetBucket(GetTestBucketName()); + getObjectRequest.SetKey(TEST_FILE_NAME); + + GetObjectOutcome getObjectOutcome = m_s3Client->GetObject(getObjectRequest); + EXPECT_FALSE(getObjectOutcome.IsSuccess()); + + Aws::Map metadata; + metadata["key1"] = "val1"; + metadata["key2"] = "val2"; + const bool cCreateBucket = false; + const bool cConsistencyChecks = false; + std::shared_ptr requestPtr = m_transferClient->UploadFile(TEST_FILE_NAME, GetTestBucketName(), "", "", metadata, cCreateBucket, cConsistencyChecks); + + ASSERT_FALSE(requestPtr->IsDone()); + + WaitForUploadAndUpdate(requestPtr, 100.0f); + + ASSERT_TRUE(requestPtr->IsDone()); + + ASSERT_TRUE(requestPtr->CompletedSuccessfully()); + + WaitForObjectToPropagate(GetTestBucketName(), TEST_FILE_NAME); + + // Check the metadata matches + HeadObjectRequest headObjectRequest; + headObjectRequest.SetBucket(GetTestBucketName()); + headObjectRequest.SetKey(TEST_FILE_NAME); + + HeadObjectOutcome headObjectOutcome = m_s3Client->HeadObject(headObjectRequest); + ASSERT_TRUE(headObjectOutcome.IsSuccess()); + + Aws::Map headObjectMetadata = headObjectOutcome.GetResult().GetMetadata(); + ASSERT_EQ(2u, headObjectMetadata.size()); + ASSERT_EQ("val1", headObjectMetadata["key1"]); + ASSERT_EQ("val2", headObjectMetadata["key2"]); + +} + +// Multipart upload with metadata specified +TEST_F(TransferTests, MultipartUploadWithMetadataTest) +{ + if (EmptyBucket(GetTestBucketName())) + { + WaitForBucketToEmpty(GetTestBucketName()); + } + + GetObjectRequest getObjectRequest; + getObjectRequest.SetBucket(GetTestBucketName()); + getObjectRequest.SetKey(MEDIUM_FILE_KEY); + + GetObjectOutcome getObjectOutcome = m_s3Client->GetObject(getObjectRequest); + EXPECT_FALSE(getObjectOutcome.IsSuccess()); + + ListMultipartUploadsRequest listMultipartRequest; + + listMultipartRequest.SetBucket(GetTestBucketName()); + + Aws::Map metadata; + metadata["key1"] = "val1"; + metadata["key2"] = "val2"; + const bool cCreateBucket = false; + const bool cConsistencyChecks = false; + std::shared_ptr requestPtr = m_transferClient->UploadFile(MEDIUM_TEST_FILE_NAME, GetTestBucketName(), MEDIUM_FILE_KEY, "", metadata, cCreateBucket, cConsistencyChecks); + + ASSERT_FALSE(requestPtr->IsDone()); + + WaitForUploadAndUpdate(requestPtr, 100.0f); + + ASSERT_TRUE(requestPtr->IsDone()); + ASSERT_TRUE(requestPtr->CompletedSuccessfully()); + + WaitForObjectToPropagate(GetTestBucketName(), MEDIUM_FILE_KEY); + + // Check the metadata matches + HeadObjectRequest headObjectRequest; + headObjectRequest.SetBucket(GetTestBucketName()); + headObjectRequest.SetKey(MEDIUM_FILE_KEY); + + HeadObjectOutcome headObjectOutcome = m_s3Client->HeadObject(headObjectRequest); + ASSERT_TRUE(headObjectOutcome.IsSuccess()); + + Aws::Map headObjectMetadata = headObjectOutcome.GetResult().GetMetadata(); + ASSERT_EQ(2u, headObjectMetadata.size()); + ASSERT_EQ("val1", headObjectMetadata["key1"]); + ASSERT_EQ("val2", headObjectMetadata["key2"]); + +} + } diff --git a/aws-cpp-sdk-transfer/include/aws/transfer/TransferClient.h b/aws-cpp-sdk-transfer/include/aws/transfer/TransferClient.h index 7a55ffaa140..8eb457937ee 100644 --- a/aws-cpp-sdk-transfer/include/aws/transfer/TransferClient.h +++ b/aws-cpp-sdk-transfer/include/aws/transfer/TransferClient.h @@ -61,10 +61,13 @@ class AWS_TRANSFER_API TransferClient TransferClient(const std::shared_ptr& s3Client, const TransferClientConfiguration& config); ~TransferClient(); - // Single entry point for attempting an upload - attempting to create an existing bucket won't hurt anything but will affect performance + // Entry point for attempting an upload - attempting to create an existing bucket won't hurt anything but will affect performance // unnecessarily as the request waits for S3 to propagate the bucket // All queries about the upload after this point can be found in UploadFileRequest's interface std::shared_ptr UploadFile(const Aws::String& fileName, const Aws::String& bucketName, const Aws::String& keyName, const Aws::String& contentType, bool createBucket = false, bool doConsistencyChecks = false); + // Entry point similar to above but with metadata specified + std::shared_ptr UploadFile(const Aws::String& fileName, const Aws::String& bucketName, const Aws::String& keyName, const Aws::String& contentType, const Aws::Map& metadata, bool createBucket = false, bool doConsistencyChecks = false); + std::shared_ptr UploadFile(const Aws::String& fileName, const Aws::String& bucketName, const Aws::String& keyName, const Aws::String& contentType, Aws::Map&& metadata, bool createBucket = false, bool doConsistencyChecks = false); // User requested upload cancels should go through here void CancelUpload(std::shared_ptr& fileRequest) const; @@ -84,7 +87,7 @@ class AWS_TRANSFER_API TransferClient private: void UploadFileInternal(std::shared_ptr& fileRequest); - + void ProcessSingleBuffer(std::shared_ptr& request, const std::shared_ptr& buffer); void CancelUploadInternal(std::shared_ptr& fileRequest) const; @@ -168,4 +171,4 @@ class AWS_TRANSFER_API TransferClient } // namespace Transfer } // namespace Aws -#endif \ No newline at end of file +#endif diff --git a/aws-cpp-sdk-transfer/include/aws/transfer/UploadFileRequest.h b/aws-cpp-sdk-transfer/include/aws/transfer/UploadFileRequest.h index 97b6277d0a4..5a560e9b782 100644 --- a/aws-cpp-sdk-transfer/include/aws/transfer/UploadFileRequest.h +++ b/aws-cpp-sdk-transfer/include/aws/transfer/UploadFileRequest.h @@ -83,6 +83,22 @@ class AWS_TRANSFER_API UploadFileRequest : public S3FileRequest, public std::ena const std::shared_ptr& s3Client, bool createBucket, bool doConsistencyChecks); + UploadFileRequest(const Aws::String& fileName, + const Aws::String& bucketName, + const Aws::String& keyName, + const Aws::String& contentType, + const Aws::Map& metadata, + const std::shared_ptr& s3Client, + bool createBucket, + bool doConsistencyChecks); + UploadFileRequest(const Aws::String& fileName, + const Aws::String& bucketName, + const Aws::String& keyName, + const Aws::String& contentType, + Aws::Map&& metadata, + const std::shared_ptr& s3Client, + bool createBucket, + bool doConsistencyChecks); ~UploadFileRequest(); // How many parts have we at least begun to upload @@ -255,6 +271,8 @@ class AWS_TRANSFER_API UploadFileRequest : public S3FileRequest, public std::ena Aws::List > m_buffersReady; Aws::String m_contentType; + Aws::Map m_metadata; + bool m_metadataHasBeenSet; Aws::String m_uploadId; uint32_t m_createMultipartRetries; uint32_t m_createBucketRetries; diff --git a/aws-cpp-sdk-transfer/source/transfer/TransferClient.cpp b/aws-cpp-sdk-transfer/source/transfer/TransferClient.cpp index 7fa0c4ad6ec..2143cafa266 100644 --- a/aws-cpp-sdk-transfer/source/transfer/TransferClient.cpp +++ b/aws-cpp-sdk-transfer/source/transfer/TransferClient.cpp @@ -74,6 +74,24 @@ std::shared_ptr TransferClient::UploadFile(const Aws::String& return request; } +std::shared_ptr TransferClient::UploadFile(const Aws::String& fileName, const Aws::String& bucketName, const Aws::String& keyName, const Aws::String& contentType, const Aws::Map& metadata, bool createBucket, bool doConsistencyChecks) +{ + auto request = Aws::MakeShared(ALLOCATION_TAG, fileName, bucketName, keyName, contentType, metadata, m_s3Client, createBucket, doConsistencyChecks); + + UploadFileInternal(request); + + return request; +} + +std::shared_ptr TransferClient::UploadFile(const Aws::String& fileName, const Aws::String& bucketName, const Aws::String& keyName, const Aws::String& contentType, Aws::Map&& metadata, bool createBucket, bool doConsistencyChecks) +{ + auto request = Aws::MakeShared(ALLOCATION_TAG, fileName, bucketName, keyName, contentType, metadata, m_s3Client, createBucket, doConsistencyChecks); + + UploadFileInternal(request); + + return request; +} + void TransferClient::UploadFileInternal(std::shared_ptr& request) { diff --git a/aws-cpp-sdk-transfer/source/transfer/UploadFileRequest.cpp b/aws-cpp-sdk-transfer/source/transfer/UploadFileRequest.cpp index 8f7d2873e0f..bd47a316ba5 100644 --- a/aws-cpp-sdk-transfer/source/transfer/UploadFileRequest.cpp +++ b/aws-cpp-sdk-transfer/source/transfer/UploadFileRequest.cpp @@ -73,6 +73,7 @@ m_bucketPropagated(false), m_totalParts(0), m_fileStream(fileName.c_str(), std::ios::binary | std::ios::ate), m_contentType(contentType), +m_metadataHasBeenSet(false), m_createMultipartRetries(0), m_createBucketRetries(0), m_completeRetries(0), @@ -105,6 +106,34 @@ m_headBucketRetries(0) } } +UploadFileRequest::UploadFileRequest(const Aws::String& fileName, + const Aws::String& bucketName, + const Aws::String& keyName, + const Aws::String& contentType, + const Aws::Map& metadata, + const std::shared_ptr& s3Client, + bool createBucket, + bool doConsistencyChecks) : +UploadFileRequest(fileName, bucketName, keyName, contentType, s3Client, createBucket, doConsistencyChecks) +{ + m_metadataHasBeenSet = true; + m_metadata = metadata; +} + +UploadFileRequest::UploadFileRequest(const Aws::String& fileName, + const Aws::String& bucketName, + const Aws::String& keyName, + const Aws::String& contentType, + Aws::Map&& metadata, + const std::shared_ptr& s3Client, + bool createBucket, + bool doConsistencyChecks) : +UploadFileRequest(fileName, bucketName, keyName, contentType, s3Client, createBucket, doConsistencyChecks) +{ + m_metadataHasBeenSet = true; + m_metadata = metadata; +} + UploadFileRequest::~UploadFileRequest() { m_fileStream.close(); @@ -202,6 +231,10 @@ bool UploadFileRequest::CreateMultipartUpload() { createMultipartUploadRequest.SetContentType(m_contentType); } + if (m_metadataHasBeenSet) + { + createMultipartUploadRequest.SetMetadata(m_metadata); + } std::shared_ptr context = Aws::MakeShared(ALLOCATION_TAG, shared_from_this()); @@ -507,7 +540,7 @@ bool UploadFileRequest::ProcessBuffer(const std::shared_ptr& buffe return false; } - if (GetTotalParts() == 1) + if (IsSinglePartUpload()) { // Don't need more than one part, do everything now return DoSingleObjectUpload(streamBuf, bytesRead); @@ -774,6 +807,10 @@ bool UploadFileRequest::DoSingleObjectUpload(std::shared_ptr& str { putObjectRequest.SetContentType(m_contentType); } + if (m_metadataHasBeenSet) + { + putObjectRequest.SetMetadata(m_metadata); + } putObjectRequest.SetKey(GetKeyName()); putObjectRequest.SetDataSentEventHandler(std::bind(&UploadFileRequest::OnDataSent, this, std::placeholders::_1, std::placeholders::_2));