Skip to content

Commit 5535841

Browse files
narahavisbiscigl
authored andcommitted
S3 transfer manager: single-file upload and download
Implements single-file Upload and Download for the SEP-compliant S3 Transfer Manager (aws-cpp-sdk-s3-transfer), backed by aws-c-s3 meta requests via the aws-crt-cpp S3 bindings. Covers file and stream sources/sinks, progress and finish callbacks, checksum config, cancellation, and CRT-to-SEP error mapping.
1 parent 467ffba commit 5535841

44 files changed

Lines changed: 5246 additions & 347 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

cmake/sdksCommon.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ list(APPEND SDK_TEST_PROJECT_LIST "redshift:tests/aws-cpp-sdk-redshift-integrati
108108
list(APPEND SDK_TEST_PROJECT_LIST "s3:tests/aws-cpp-sdk-s3-integration-tests")
109109
list(APPEND SDK_TEST_PROJECT_LIST "s3:tests/aws-cpp-sdk-s3-unit-tests")
110110
list(APPEND SDK_TEST_PROJECT_LIST "s3-crt:tests/aws-cpp-sdk-s3-crt-integration-tests")
111+
list(APPEND SDK_TEST_PROJECT_LIST "s3-transfer:tests/aws-cpp-sdk-s3-transfer-integration-tests")
111112
list(APPEND SDK_TEST_PROJECT_LIST "s3-encryption:tests/aws-cpp-sdk-s3-encryption-tests,tests/aws-cpp-sdk-s3-encryption-integration-tests")
112113
list(APPEND SDK_TEST_PROJECT_LIST "s3control:tests/aws-cpp-sdk-s3control-integration-tests")
113114
list(APPEND SDK_TEST_PROJECT_LIST "sns:tests/aws-cpp-sdk-sns-integration-tests")

prefetch_crt_dependency.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# SPDX-License-Identifier: Apache-2.0.
44

55
CRT_URI_PREFIX=https://codeload.github.com/awslabs
6-
CRT_URI=${CRT_URI_PREFIX}/aws-crt-cpp/zip/0463563f9f656a493ec22ca962c2464bc8b831ab # v0.43.2
6+
CRT_URI=${CRT_URI_PREFIX}/aws-crt-cpp/zip/851d8d003c9d5150edab56807e2393013f3771de # v0.43.4
77

88
AWS_C_AUTH_URI=${CRT_URI_PREFIX}/aws-c-auth/zip/4b5d524bf1a511b05e0fffe5bdc51800770b9427 # v0.10.4
99
AWS_C_CAL_URI=${CRT_URI_PREFIX}/aws-c-cal/zip/8aa2a48a09f93c65d4cf06388e143a6584de6321 # v0.9.15
@@ -14,7 +14,7 @@ AWS_C_HTTP_URI=${CRT_URI_PREFIX}/aws-c-http/zip/8aefd899fc3210bfd0e3fd414011a3cb
1414
AWS_C_IO_URI=${CRT_URI_PREFIX}/aws-c-io/zip/e2946c99521fa12d285c9a0829c92b1bf713922b # v0.27.5
1515
AWS_C_MQTT_URI=${CRT_URI_PREFIX}/aws-c-mqtt/zip/2ef9605ec9c50bea3f921e08022ddd57eed70901 # v0.16.0
1616
AWS_C_S3_URI=${CRT_URI_PREFIX}/aws-c-s3/zip/a852faa2df3ab2b31fb4cfd64fd3379a2f4ae22e # v0.13.2
17-
AWS_C_SDKUTILS_URI=${CRT_URI_PREFIX}/aws-c-sdkutils/zip/528b9dfff4a804b334875ecf8a0471f7d1366f24 # v0.2.8
17+
AWS_C_SDKUTILS_URI=${CRT_URI_PREFIX}/aws-c-sdkutils/zip/a1cc19f53b63658f1b1400b36f199eafeeb895a6 # v0.2.9
1818
AWS_CHECKSUMS_URI=${CRT_URI_PREFIX}/aws-checksums/zip/1d5f2f1f3e5d013aae8810878ceb5b3f6f258c4e # v0.2.10
1919
AWS_LC_URI=${CRT_URI_PREFIX}/aws-lc/zip/f6acf748df0ea6157d55e640730b38d21a7751cd # v5.4.0
2020
S2N_URI=${CRT_URI_PREFIX}/s2n/zip/66b1c94d1dfc99b237427cbde230eca63bb8b89c # v1.7.6
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/**
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0.
4+
*/
5+
#pragma once
6+
#include <aws/s3-transfer/S3Transfer_EXPORTS.h>
7+
#include <aws/s3-transfer/S3DownloadBuffer.h>
8+
9+
namespace Aws {
10+
namespace S3 {
11+
namespace Transfer {
12+
13+
/**
14+
* Callback interface for zero-copy downloads. The transfer manager delivers each part of the
15+
* object to OnDataReceived as it arrives, in object order. The buffer is move-only; move it out
16+
* (e.g. auto held = std::move(buffer)) to retain the bytes past this call.
17+
*/
18+
class AWS_S3_TRANSFER_API DownloadDataReceiver {
19+
public:
20+
virtual ~DownloadDataReceiver() = default;
21+
virtual void OnDataReceived(S3DownloadBuffer buffer) = 0;
22+
};
23+
24+
} // namespace Transfer
25+
} // namespace S3
26+
} // namespace Aws
Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,41 @@
11
/**
2-
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
33
* SPDX-License-Identifier: Apache-2.0.
44
*/
55
#pragma once
66
#include <aws/s3-transfer/S3Transfer_EXPORTS.h>
77
#include <future>
88
#include <memory>
99
#include <aws/s3-transfer/DownloadResponse.h>
10+
#include <aws/core/utils/memory/AWSMemory.h>
1011

1112

1213
namespace Aws {
1314
namespace S3 {
1415
namespace Transfer {
1516

16-
/**
17-
* Returned from S3TransferManager::Download to represent a single in-flight download. The
18-
* handle is move-only and owns the underlying transfer state.
19-
*/
17+
class DownloadHandleImpl;
18+
19+
// Move-only handle for a single in-flight download.
2020
class AWS_S3_TRANSFER_API DownloadHandle final {
2121
public:
22-
DownloadHandle();
22+
explicit DownloadHandle(Aws::UniquePtr<DownloadHandleImpl> impl);
2323
~DownloadHandle();
24+
DownloadHandle(const DownloadHandle&) = delete;
25+
DownloadHandle& operator=(const DownloadHandle&) = delete;
2426
DownloadHandle(DownloadHandle&&) noexcept;
2527
DownloadHandle& operator=(DownloadHandle&&) noexcept;
2628

27-
/**
28-
* Returns a future that resolves once the transfer finishes, succeeds, or fails.
29-
*/
29+
// Resolves once the transfer finishes, succeeds, or fails.
3030
std::future<DownloadOutcome> CompletionFuture();
3131

32-
/**
33-
* Requests cancellation of the in-flight download. Returns immediately; the future
34-
* returned by CompletionFuture will resolve with a failure once the cancel takes effect.
35-
*/
32+
// Returns immediately; the completion future resolves with a failure once the cancel takes effect.
3633
void Cancel();
37-
};
3834

35+
private:
36+
Aws::UniquePtr<DownloadHandleImpl> m_impl;
37+
};
3938

40-
}
41-
}
42-
}
39+
} // namespace Transfer
40+
} // namespace S3
41+
} // namespace Aws

src/aws-cpp-sdk-s3-transfer/include/aws/s3-transfer/DownloadProgressListener.h

Lines changed: 0 additions & 26 deletions
This file was deleted.

src/aws-cpp-sdk-s3-transfer/include/aws/s3-transfer/DownloadProgressSnapshot.h

Lines changed: 0 additions & 26 deletions
This file was deleted.

src/aws-cpp-sdk-s3-transfer/include/aws/s3-transfer/DownloadRequest.h

Lines changed: 67 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,50 +4,88 @@
44
*/
55
#pragma once
66
#include <aws/s3-transfer/S3Transfer_EXPORTS.h>
7-
#include <aws/s3-transfer/DownloadProgressListener.h>
7+
#include <aws/s3-transfer/ProgressListener.h>
8+
#include <aws/s3-transfer/DownloadDataReceiver.h>
9+
#include <aws/core/client/AWSError.h>
10+
#include <aws/crt/Optional.h>
11+
#include <aws/core/utils/DateTime.h>
12+
#include <aws/core/utils/memory/AWSMemory.h>
813
#include <aws/core/utils/memory/stl/AWSString.h>
914
#include <aws/core/utils/memory/stl/AWSVector.h>
10-
#include <aws/core/utils/stream/ResponseStream.h>
15+
#include <aws/s3/S3Errors.h>
16+
#include <aws/s3/model/ChecksumMode.h>
1117
#include <aws/s3/model/GetObjectRequest.h>
18+
#include <aws/s3/model/RequestPayer.h>
1219
#include <memory>
13-
#include <utility>
1420

1521
namespace Aws {
1622
namespace S3 {
1723
namespace Transfer {
1824

25+
struct DownloadTransferState;
26+
27+
namespace Internal {
28+
class DownloadRequestImpl;
29+
30+
using OptionalError = Aws::Crt::Optional<Aws::Client::AWSError<Aws::S3::S3Errors>>;
31+
}
32+
1933
/**
20-
* Request type for S3TransferManager::Download. Carries the inner S3 GetObjectRequest along
21-
* with the local destination (file path or stream factory) and any request-level progress
22-
* listeners. The transfer manager parallelizes large objects via ranged GETs internally.
34+
* Request type for S3TransferManager::Download. All state lives behind m_impl, whose concrete type
35+
* is chosen by the constructor: a destination file path selects the file strategy, a data receiver
36+
* the stream strategy. Move-only, because that impl is uniquely owned; pass with std::move.
2337
*/
2438
class AWS_S3_TRANSFER_API DownloadRequest final {
2539
public:
26-
explicit DownloadRequest(
27-
Aws::S3::Model::GetObjectRequest s3Request,
28-
Aws::String destinationFilePath,
29-
Aws::IOStreamFactory responseStreamFactory,
30-
Aws::Vector<std::shared_ptr<DownloadProgressListener>> transferListeners = {})
31-
: m_s3Request(std::move(s3Request)),
32-
m_destinationFilePath(std::move(destinationFilePath)),
33-
m_responseStreamFactory(std::move(responseStreamFactory)),
34-
m_transferListeners(std::move(transferListeners)) {}
35-
36-
inline const Aws::S3::Model::GetObjectRequest& GetS3Request() const { return m_s3Request; }
37-
inline const Aws::String& GetDestinationFilePath() const { return m_destinationFilePath; }
38-
inline const Aws::IOStreamFactory& GetResponseStreamFactory() const { return m_responseStreamFactory; }
39-
inline const Aws::Vector<std::shared_ptr<DownloadProgressListener>>& GetTransferListeners() const {
40-
return m_transferListeners;
41-
}
40+
DownloadRequest(Aws::String bucket,
41+
Aws::String key,
42+
Aws::String destinationFilePath,
43+
Aws::Vector<std::shared_ptr<DownloadProgressListener>> transferListeners = {});
44+
45+
DownloadRequest(Aws::String bucket,
46+
Aws::String key,
47+
std::shared_ptr<DownloadDataReceiver> dataReceiver,
48+
Aws::Vector<std::shared_ptr<DownloadProgressListener>> transferListeners = {});
49+
50+
~DownloadRequest();
4251

52+
const Aws::Vector<std::shared_ptr<DownloadProgressListener>>& GetTransferListeners() const;
53+
// Empty for a receiver-backed download; otherwise where the object lands once it completes.
54+
const Aws::String& GetDestinationFilePath() const;
55+
const Aws::String& GetTempFilePath() const;
56+
// Null for a file-backed download; otherwise the sink the CRT delivers body chunks to.
57+
const std::shared_ptr<DownloadDataReceiver>& GetDataReceiver() const;
58+
59+
DownloadRequest& SetChecksumMode(Aws::S3::Model::ChecksumMode v);
60+
DownloadRequest& SetExpectedBucketOwner(Aws::String v);
61+
DownloadRequest& SetIfMatch(Aws::String v);
62+
DownloadRequest& SetIfModifiedSince(Aws::Utils::DateTime v);
63+
DownloadRequest& SetIfNoneMatch(Aws::String v);
64+
DownloadRequest& SetIfUnmodifiedSince(Aws::Utils::DateTime v);
65+
DownloadRequest& SetRange(Aws::String v);
66+
DownloadRequest& SetRequestPayer(Aws::S3::Model::RequestPayer v);
67+
DownloadRequest& SetResponseCacheControl(Aws::String v);
68+
DownloadRequest& SetResponseContentDisposition(Aws::String v);
69+
DownloadRequest& SetResponseContentEncoding(Aws::String v);
70+
DownloadRequest& SetResponseContentLanguage(Aws::String v);
71+
DownloadRequest& SetResponseContentType(Aws::String v);
72+
DownloadRequest& SetResponseExpires(Aws::Utils::DateTime v);
73+
DownloadRequest& SetSSECustomerAlgorithm(Aws::String v);
74+
DownloadRequest& SetSSECustomerKey(Aws::String v);
75+
DownloadRequest& SetSSECustomerKeyMD5(Aws::String v);
76+
DownloadRequest& SetVersionId(Aws::String v);
77+
78+
const Aws::S3::Model::GetObjectRequest& GetS3Request() const;
79+
80+
Internal::OptionalError Validate() const;
81+
Internal::OptionalError FinalizeOnSuccess(
82+
const std::shared_ptr<DownloadTransferState>& state) const;
83+
Internal::OptionalError CleanupOnFailure(const std::shared_ptr<DownloadTransferState>& state) const;
4384

4485
private:
45-
Aws::S3::Model::GetObjectRequest m_s3Request;
46-
Aws::String m_destinationFilePath;
47-
Aws::IOStreamFactory m_responseStreamFactory;
48-
Aws::Vector<std::shared_ptr<DownloadProgressListener>> m_transferListeners;
86+
std::shared_ptr<Internal::DownloadRequestImpl> m_impl;
4987
};
5088

51-
}
52-
}
53-
}
89+
} // namespace Transfer
90+
} // namespace S3
91+
} // namespace Aws

src/aws-cpp-sdk-s3-transfer/include/aws/s3-transfer/DownloadResponse.h

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,32 +15,30 @@ namespace S3 {
1515
namespace Transfer {
1616

1717
/**
18-
* Response type returned via the DownloadHandle's future once the transfer completes. Wraps
19-
* the underlying S3 GetObjectResult with whole-object content length and range, regardless
20-
* of how many ranged GETs were issued internally.
18+
* Response type returned via the DownloadHandle's future once the transfer completes. Wraps the
19+
* underlying S3 GetObjectResult with whole-object content length and range. The S3 result is set
20+
* at construction time so a DownloadResponse is never in a half-populated state; access it via
21+
* GetS3Result().
2122
*/
2223
class AWS_S3_TRANSFER_API DownloadResponse final {
2324
public:
25+
// Default constructor exists to satisfy Aws::Utils::Outcome<R, E>, which default-constructs
26+
// its R on the error path. On the success path the S3 result is always provided via the
27+
// constructor below; a default-constructed instance is unreachable through DownloadOutcome
28+
// because Outcome::GetResult() is only meaningful when IsSuccess() is true.
29+
DownloadResponse() = default;
30+
31+
explicit DownloadResponse(Aws::S3::Model::GetObjectResult s3Result)
32+
: m_s3Result(std::move(s3Result)) {}
33+
2434
inline const Aws::S3::Model::GetObjectResult& GetS3Result() const { return m_s3Result; }
25-
inline bool S3ResultHasBeenSet() const { return m_s3ResultHasBeenSet; }
26-
template <typename GetObjectResultT = Aws::S3::Model::GetObjectResult>
27-
void SetS3Result(GetObjectResultT&& getS3Result) {
28-
m_s3ResultHasBeenSet = true;
29-
m_s3Result = std::forward<GetObjectResultT>(getS3Result);
30-
}
31-
template <typename GetObjectResultT = Aws::S3::Model::GetObjectResult>
32-
DownloadResponse& WithS3Result(GetObjectResultT&& getS3Result) {
33-
SetS3Result(std::forward<GetObjectResultT>(getS3Result));
34-
return *this;
35-
}
3635

3736
private:
3837
Aws::S3::Model::GetObjectResult m_s3Result;
39-
bool m_s3ResultHasBeenSet = false;
4038
};
4139

4240
using DownloadOutcome = Aws::Utils::Outcome<DownloadResponse, Aws::Client::AWSError<Aws::S3::S3Errors>>;
4341

44-
}
45-
}
46-
}
42+
} // namespace Transfer
43+
} // namespace S3
44+
} // namespace Aws

src/aws-cpp-sdk-s3-transfer/include/aws/s3-transfer/ProgressListener.h

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,20 @@
44
*/
55
#pragma once
66
#include <aws/s3-transfer/S3Transfer_EXPORTS.h>
7+
#include <aws/s3-transfer/ProgressSnapshot.h>
78

89
namespace Aws {
910
namespace S3 {
1011
namespace Transfer {
1112

13+
class UploadRequest;
14+
class DownloadRequest;
15+
1216
/**
1317
* Callback interface for receiving event-driven updates throughout the lifecycle of a transfer.
1418
* Subclass and override the events of interest; default implementations are empty so unused
1519
* callbacks can be ignored. Listeners may be registered on the request or on the manager.
16-
* Specialized via the UploadProgressListener and DownloadProgressListener type aliases.
20+
* Specialized via the UploadProgressListener and DownloadProgressListener subclasses below.
1721
*/
1822
template <typename RequestT, typename SnapshotT>
1923
class ProgressListener {
@@ -42,6 +46,22 @@ class ProgressListener {
4246
virtual void OnTransferFailed(const RequestT& /*request*/, const SnapshotT& /*snapshot*/) {}
4347
};
4448

45-
}
46-
}
47-
}
49+
/**
50+
* Callback interface for receiving event-driven updates throughout the lifecycle of an upload.
51+
* Subclass and override the events of interest; default implementations are empty so unused
52+
* callbacks can be ignored. Listeners may be registered on the request or on the manager.
53+
*/
54+
class AWS_S3_TRANSFER_API UploadProgressListener
55+
: public ProgressListener<UploadRequest, UploadProgressSnapshot> {};
56+
57+
/**
58+
* Callback interface for receiving event-driven updates throughout the lifecycle of a download.
59+
* Subclass and override the events of interest; default implementations are empty so unused
60+
* callbacks can be ignored. Listeners may be registered on the request or on the manager.
61+
*/
62+
class AWS_S3_TRANSFER_API DownloadProgressListener
63+
: public ProgressListener<DownloadRequest, DownloadProgressSnapshot> {};
64+
65+
} // namespace Transfer
66+
} // namespace S3
67+
} // namespace Aws

0 commit comments

Comments
 (0)