diff --git a/Sources/SotoCore/AWSServiceConfig.swift b/Sources/SotoCore/AWSServiceConfig.swift index 8e0470435..0b71b9404 100644 --- a/Sources/SotoCore/AWSServiceConfig.swift +++ b/Sources/SotoCore/AWSServiceConfig.swift @@ -205,6 +205,9 @@ public final class AWSServiceConfig { /// Disable S3 signed chunked uploads public static let s3DisableChunkedUploads = Options(rawValue: 1 << 4) + + /// calculate MD5 for requests with content-md5 header + public static let calculateMD5 = Options(rawValue: 1 << 5) } private init( diff --git a/Sources/SotoCore/Doc/AWSShape.swift b/Sources/SotoCore/Doc/AWSShape.swift index 322a1a15a..132f58639 100644 --- a/Sources/SotoCore/Doc/AWSShape.swift +++ b/Sources/SotoCore/Doc/AWSShape.swift @@ -218,6 +218,8 @@ public struct AWSShapeOptions: OptionSet { public static let rawPayload = AWSShapeOptions(rawValue: 1 << 2) /// Calculate MD5 of body is required public static let md5ChecksumRequired = AWSShapeOptions(rawValue: 1 << 3) + /// Request includes a MD5 checksum + public static let md5ChecksumHeader = AWSShapeOptions(rawValue: 1 << 4) } /// Root AWSShape which include a payload diff --git a/Sources/SotoCore/Message/AWSRequest.swift b/Sources/SotoCore/Message/AWSRequest.swift index 58e71b8bc..421d38bfb 100644 --- a/Sources/SotoCore/Message/AWSRequest.swift +++ b/Sources/SotoCore/Message/AWSRequest.swift @@ -289,7 +289,9 @@ extension AWSRequest { } /// MD5 checksum - if Input._options.contains(.md5ChecksumRequired), + let checksumRequired = Input._options.contains(.md5ChecksumRequired) || + (Input._options.contains(.md5ChecksumHeader) && configuration.options.contains(.calculateMD5)) + if checksumRequired, let buffer = body.asByteBuffer(byteBufferAllocator: configuration.byteBufferAllocator), headers["content-md5"].first == nil, let md5 = Self.calculateMD5(buffer) diff --git a/Tests/SotoCoreTests/AWSRequestTests.swift b/Tests/SotoCoreTests/AWSRequestTests.swift index b0d872d14..505b33bca 100644 --- a/Tests/SotoCoreTests/AWSRequestTests.swift +++ b/Tests/SotoCoreTests/AWSRequestTests.swift @@ -459,7 +459,7 @@ class AWSRequestTests: XCTestCase { XCTAssertFalse(body.isEmpty) } - func testMD5Checksum() { + func testRequiredMD5Checksum() { struct Input: AWSEncodableShape { static let _options: AWSShapeOptions = .md5ChecksumRequired let q: [String] @@ -471,6 +471,23 @@ class AWSRequestTests: XCTestCase { XCTAssertEqual(request?.httpHeaders["Content-MD5"].first, "3W1MVcXgkODdv+m6VeZqdQ==") } + func testMD5ChecksumHeader() { + struct Input: AWSEncodableShape { + static let _options: AWSShapeOptions = .md5ChecksumHeader + let q: [String] + } + let input = Input(q: ["one", "two", "three", "four"]) + let config = createServiceConfig(region: .useast2, service: "myservice", options: .calculateMD5) + var request: AWSRequest? + XCTAssertNoThrow(request = try AWSRequest(operation: "Test", path: "/", httpMethod: .GET, input: input, configuration: config)) + XCTAssertEqual(request?.httpHeaders["Content-MD5"].first, "3W1MVcXgkODdv+m6VeZqdQ==") + + let config2 = createServiceConfig(region: .useast2, service: "myservice") + var request2: AWSRequest? + XCTAssertNoThrow(request2 = try AWSRequest(operation: "Test", path: "/", httpMethod: .GET, input: input, configuration: config2)) + XCTAssertNil(request2?.httpHeaders["Content-MD5"].first) + } + func testMD5ChecksumSetAlready() { struct Input: AWSEncodableShape { static let _options: AWSShapeOptions = .md5ChecksumRequired