diff --git a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/AWSS3StoragePlugin+AsyncClientBehavior.swift b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/AWSS3StoragePlugin+AsyncClientBehavior.swift index 033af1a2e5..0bd830c3d9 100644 --- a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/AWSS3StoragePlugin+AsyncClientBehavior.swift +++ b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/AWSS3StoragePlugin+AsyncClientBehavior.swift @@ -35,6 +35,7 @@ extension AWSS3StoragePlugin { let result = try await storageService.getPreSignedURL( serviceKey: serviceKey, signingOperation: .getObject, + metadata: nil, accelerate: accelerate, expires: options.expires) diff --git a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Dependency/AWSS3PreSignedURLBuilderAdapter.swift b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Dependency/AWSS3PreSignedURLBuilderAdapter.swift index 5153e90c89..b935df2dd0 100644 --- a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Dependency/AWSS3PreSignedURLBuilderAdapter.swift +++ b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Dependency/AWSS3PreSignedURLBuilderAdapter.swift @@ -34,6 +34,7 @@ class AWSS3PreSignedURLBuilderAdapter: AWSS3PreSignedURLBuilderBehavior { /// - Returns: Pre-Signed URL func getPreSignedURL(key: String, signingOperation: AWSS3SigningOperation, + metadata: [String: String]? = nil, accelerate: Bool? = nil, expires: Int64? = nil) async throws -> URL { let expiresDate = Date(timeIntervalSinceNow: Double(expires ?? defaultExpiration)) @@ -47,7 +48,7 @@ class AWSS3PreSignedURLBuilderAdapter: AWSS3PreSignedURLBuilderBehavior { config: config, expiration: expiration) case .putObject: - let input = PutObjectInput(bucket: bucket, key: key) + let input = PutObjectInput(bucket: bucket, key: key, metadata: metadata) preSignedUrl = try await input.presignURL( config: config, expiration: expiration) diff --git a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Dependency/AWSS3PreSignedURLBuilderBehavior.swift b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Dependency/AWSS3PreSignedURLBuilderBehavior.swift index dddc19ed44..7ca3f989cb 100644 --- a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Dependency/AWSS3PreSignedURLBuilderBehavior.swift +++ b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Dependency/AWSS3PreSignedURLBuilderBehavior.swift @@ -41,6 +41,7 @@ protocol AWSS3PreSignedURLBuilderBehavior { /// - Tag: AWSS3PreSignedURLBuilderBehavior.getPreSignedURL func getPreSignedURL(key: String, signingOperation: AWSS3SigningOperation, + metadata: [String: String]?, accelerate: Bool?, expires: Int64?) async throws -> URL diff --git a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService+DownloadBehavior.swift b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService+DownloadBehavior.swift index c4893c86c9..ab7c5849de 100644 --- a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService+DownloadBehavior.swift +++ b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService+DownloadBehavior.swift @@ -30,6 +30,7 @@ extension AWSS3StorageService { do { let preSignedURL = try await preSignedURLBuilder.getPreSignedURL(key: serviceKey, signingOperation: .getObject, + metadata: nil, accelerate: accelerate, expires: nil) startDownload(preSignedURL: preSignedURL, transferTask: transferTask) diff --git a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService+GetPreSignedURLBehavior.swift b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService+GetPreSignedURLBehavior.swift index b13c4a25f6..fc3eb40699 100644 --- a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService+GetPreSignedURLBehavior.swift +++ b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService+GetPreSignedURLBehavior.swift @@ -14,11 +14,13 @@ extension AWSS3StorageService { func getPreSignedURL(serviceKey: String, signingOperation: AWSS3SigningOperation, + metadata: [String: String]?, accelerate: Bool?, expires: Int) async throws -> URL { return try await preSignedURLBuilder.getPreSignedURL( key: serviceKey, signingOperation: signingOperation, + metadata: metadata, accelerate: nil, expires: Int64(expires) ) diff --git a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService+MultiPartUploadBehavior.swift b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService+MultiPartUploadBehavior.swift index 77d7e4efb7..41ee946407 100644 --- a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService+MultiPartUploadBehavior.swift +++ b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService+MultiPartUploadBehavior.swift @@ -32,7 +32,8 @@ extension AWSS3StorageService { let client = DefaultStorageMultipartUploadClient(serviceProxy: self, bucket: bucket, key: serviceKey, - uploadFile: uploadFile) + uploadFile: uploadFile, + metadata: metadata) let multipartUploadSession = StorageMultipartUploadSession(client: client, bucket: bucket, key: serviceKey, diff --git a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService+UploadBehavior.swift b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService+UploadBehavior.swift index 7bff9e94ba..5349e4a6be 100644 --- a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService+UploadBehavior.swift +++ b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService+UploadBehavior.swift @@ -36,6 +36,7 @@ extension AWSS3StorageService { do { let preSignedURL = try await preSignedURLBuilder.getPreSignedURL(key: serviceKey, signingOperation: .putObject, + metadata: metadata, accelerate: accelerate, expires: nil) startUpload(preSignedURL: preSignedURL, diff --git a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageServiceBehavior.swift b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageServiceBehavior.swift index 8226df07ff..21ae5df171 100644 --- a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageServiceBehavior.swift +++ b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageServiceBehavior.swift @@ -44,6 +44,7 @@ protocol AWSS3StorageServiceBehavior { func getPreSignedURL(serviceKey: String, signingOperation: AWSS3SigningOperation, + metadata: [String: String]?, accelerate: Bool?, expires: Int) async throws -> URL diff --git a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Support/Internal/StorageMultipartUploadClient.swift b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Support/Internal/StorageMultipartUploadClient.swift index 7bedf97def..e25f486266 100644 --- a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Support/Internal/StorageMultipartUploadClient.swift +++ b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Support/Internal/StorageMultipartUploadClient.swift @@ -42,14 +42,17 @@ class DefaultStorageMultipartUploadClient: StorageMultipartUploadClient { let contentType: String? let requestHeaders: RequestHeaders? weak var session: StorageMultipartUploadSession? - + let metadata: [String: String]? + init(serviceProxy: StorageServiceProxy, fileSystem: FileSystem = .default, bucket: String, key: String, uploadFile: UploadFile, contentType: String? = nil, - requestHeaders: RequestHeaders? = nil) { + requestHeaders: RequestHeaders? = nil, + metadata: [String: String]? = nil + ) { self.serviceProxy = serviceProxy self.fileSystem = fileSystem self.bucket = bucket @@ -57,6 +60,7 @@ class DefaultStorageMultipartUploadClient: StorageMultipartUploadClient { self.uploadFile = uploadFile self.contentType = contentType self.requestHeaders = requestHeaders + self.metadata = metadata } func integrate(session: StorageMultipartUploadSession) { @@ -135,6 +139,7 @@ class DefaultStorageMultipartUploadClient: StorageMultipartUploadClient { let preSignedURL = try await serviceProxy.preSignedURLBuilder.getPreSignedURL( key: self.key, signingOperation: operation, + metadata: self.metadata, accelerate: nil, expires: nil ) diff --git a/AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/AWSS3StoragePluginGetPresignedUrlTests.swift b/AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/AWSS3StoragePluginGetPresignedUrlTests.swift index 49a5734754..4dcf9c0108 100644 --- a/AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/AWSS3StoragePluginGetPresignedUrlTests.swift +++ b/AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/AWSS3StoragePluginGetPresignedUrlTests.swift @@ -65,7 +65,7 @@ final class AWSS3StoragePluginGetPresignedUrlTests: XCTestCase { ]) let expectedServiceKey = "public/" + testKey XCTAssertEqual(storageService.interactions, [ - "getPreSignedURL(serviceKey:signingOperation:accelerate:expires:) \(expectedServiceKey) getObject 18000" + "getPreSignedURL(serviceKey:signingOperation:metadata:accelerate:expires:) \(expectedServiceKey) getObject nil 18000" ]) } @@ -120,7 +120,7 @@ final class AWSS3StoragePluginGetPresignedUrlTests: XCTestCase { let expectedServiceKey = StorageAccessLevel.protected.rawValue + "/" + testIdentityId + "/" + testKey XCTAssertEqual(storageService.interactions, [ - "getPreSignedURL(serviceKey:signingOperation:accelerate:expires:) \(expectedServiceKey) getObject \(expectedExpires)" + "getPreSignedURL(serviceKey:signingOperation:metadata:accelerate:expires:) \(expectedServiceKey) getObject nil \(expectedExpires)" ]) } @@ -152,7 +152,7 @@ final class AWSS3StoragePluginGetPresignedUrlTests: XCTestCase { let expectedServiceKey = StorageAccessLevel.protected.rawValue + "/" + testIdentityId + "/" + testKey XCTAssertEqual(storageService.interactions, [ - "getPreSignedURL(serviceKey:signingOperation:accelerate:expires:) \(expectedServiceKey) getObject \(expectedExpires)" + "getPreSignedURL(serviceKey:signingOperation:metadata:accelerate:expires:) \(expectedServiceKey) getObject nil \(expectedExpires)" ]) } @@ -173,7 +173,7 @@ final class AWSS3StoragePluginGetPresignedUrlTests: XCTestCase { let expectedExpires = 18000 let expectedServiceKey = StorageAccessLevel.protected.rawValue + "/" + testIdentityId + "/" + testKey XCTAssertEqual(storageService.interactions, [ - "getPreSignedURL(serviceKey:signingOperation:accelerate:expires:) \(expectedServiceKey) getObject \(expectedExpires)" + "getPreSignedURL(serviceKey:signingOperation:metadata:accelerate:expires:) \(expectedServiceKey) getObject nil \(expectedExpires)" ]) } diff --git a/AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Mocks/MockAWSS3PreSignedURLBuilder.swift b/AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Mocks/MockAWSS3PreSignedURLBuilder.swift index 0664ef453b..510e77bae0 100644 --- a/AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Mocks/MockAWSS3PreSignedURLBuilder.swift +++ b/AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Mocks/MockAWSS3PreSignedURLBuilder.swift @@ -22,9 +22,10 @@ extension MockAWSS3PreSignedURLBuilder: AWSS3PreSignedURLBuilderBehavior { func getPreSignedURL( key: String, signingOperation: AWSS3SigningOperation, + metadata: [String : String]?, accelerate: Bool?, expires: Int64?) async throws -> URL { - interactions.append("\(#function) \(key) \(signingOperation) \(String(describing: expires))") + interactions.append("\(#function) \(key) \(signingOperation) \(String(describing: metadata)) \(String(describing: expires))") return try await getPreSignedURLHandler(key, signingOperation, expires) } } diff --git a/AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Mocks/MockAWSS3StorageService.swift b/AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Mocks/MockAWSS3StorageService.swift index d11d5bd499..2b70e3bc90 100644 --- a/AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Mocks/MockAWSS3StorageService.swift +++ b/AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Mocks/MockAWSS3StorageService.swift @@ -80,9 +80,10 @@ public class MockAWSS3StorageService: AWSS3StorageServiceBehavior { public func getPreSignedURL( serviceKey: String, signingOperation: AWSS3SigningOperation, + metadata: [String: String]?, accelerate: Bool?, expires: Int) async throws -> URL { - interactions.append("\(#function) \(serviceKey) \(signingOperation) \(expires)") + interactions.append("\(#function) \(serviceKey) \(signingOperation) \(String(describing: metadata)) \(expires)") return try await getPreSignedURLHandler(serviceKey, signingOperation, expires) } diff --git a/AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Service/Storage/AWSS3StorageServiceGetPreSignedURLBehaviorTests.swift b/AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Service/Storage/AWSS3StorageServiceGetPreSignedURLBehaviorTests.swift index 787cd2ad3d..5e438e735f 100644 --- a/AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Service/Storage/AWSS3StorageServiceGetPreSignedURLBehaviorTests.swift +++ b/AmplifyPlugins/Storage/Tests/AWSS3StoragePluginTests/Service/Storage/AWSS3StorageServiceGetPreSignedURLBehaviorTests.swift @@ -68,11 +68,12 @@ class AWSS3StorageServiceGetPreSignedURLBehaviorTests: XCTestCase { func testForGetObject() async throws { let url = try await systemUnderTest.getPreSignedURL(serviceKey: serviceKey, signingOperation: .getObject, + metadata: nil, accelerate: nil, expires: expires) XCTAssertEqual(url, presignedURL) XCTAssertEqual(builder.interactions, [ - "getPreSignedURL(key:signingOperation:accelerate:expires:) \(serviceKey ?? "") \(AWSS3SigningOperation.getObject) \(String(describing: expires))" + "getPreSignedURL(key:signingOperation:metadata:accelerate:expires:) \(serviceKey ?? "") \(AWSS3SigningOperation.getObject) nil \(String(describing: expires))" ]) } @@ -82,11 +83,28 @@ class AWSS3StorageServiceGetPreSignedURLBehaviorTests: XCTestCase { func testForPutObject() async throws { let url = try await systemUnderTest.getPreSignedURL(serviceKey: serviceKey, signingOperation: .putObject, + metadata: nil, accelerate: nil, expires: expires) XCTAssertEqual(url, presignedURL) XCTAssertEqual(builder.interactions, [ - "getPreSignedURL(key:signingOperation:accelerate:expires:) \(serviceKey ?? "") \(AWSS3SigningOperation.putObject) \(String(describing: expires))" + "getPreSignedURL(key:signingOperation:metadata:accelerate:expires:) \(serviceKey ?? "") \(AWSS3SigningOperation.putObject) nil \(String(describing: expires))" + ]) + } + + /// - Given: A storage service configured to use a AWSS3PreSignedURLBuilder + /// - When: A presigned URL is requested for a **AWSS3SigningOperation.putObject** operation with metadata + /// - Then: A valid URL is returned + func testForPutObjectWithMetadata() async throws { + let metadata: [String: String]? = ["test": "value"] + let url = try await systemUnderTest.getPreSignedURL(serviceKey: serviceKey, + signingOperation: .putObject, + metadata: metadata, + accelerate: nil, + expires: expires) + XCTAssertEqual(url, presignedURL) + XCTAssertEqual(builder.interactions, [ + "getPreSignedURL(key:signingOperation:metadata:accelerate:expires:) \(serviceKey ?? "") \(AWSS3SigningOperation.putObject) \(String(describing: metadata)) \(String(describing: expires))" ]) } @@ -97,11 +115,12 @@ class AWSS3StorageServiceGetPreSignedURLBehaviorTests: XCTestCase { let operation = AWSS3SigningOperation.uploadPart(partNumber: 0, uploadId: UUID().uuidString) let url = try await systemUnderTest.getPreSignedURL(serviceKey: serviceKey, signingOperation: operation, + metadata: nil, accelerate: nil, expires: expires) XCTAssertEqual(url, presignedURL) XCTAssertEqual(builder.interactions, [ - "getPreSignedURL(key:signingOperation:accelerate:expires:) \(serviceKey ?? "") \(operation) \(String(describing: expires))" + "getPreSignedURL(key:signingOperation:metadata:accelerate:expires:) \(serviceKey ?? "") \(operation) nil \(String(describing: expires))" ]) }