Skip to content

Commit

Permalink
feat!: Use closures for processing HTTP response (#1242)
Browse files Browse the repository at this point in the history
  • Loading branch information
jbelkins authored Nov 30, 2023
1 parent d0db2f3 commit 7624f1e
Show file tree
Hide file tree
Showing 19 changed files with 186 additions and 190 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import AwsCommonRuntimeKit
import ClientRuntime
import AwsCCal

public struct Sha256TreeHashMiddleware<OperationStackOutput: HttpResponseBinding,
OperationStackError: HttpResponseErrorBinding>: Middleware {
public struct Sha256TreeHashMiddleware<OperationStackOutput>: Middleware {
public let id: String = "Sha256TreeHash"

private let X_AMZ_SHA256_TREE_HASH_HEADER_NAME = "X-Amz-Sha256-Tree-Hash"
Expand Down Expand Up @@ -104,5 +103,4 @@ public struct Sha256TreeHashMiddleware<OperationStackOutput: HttpResponseBinding
public typealias MInput = SdkHttpRequestBuilder
public typealias MOutput = OperationOutput<OperationStackOutput>
public typealias Context = HttpContext
public typealias MError = OperationStackError
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
import ClientRuntime
import AwsCommonRuntimeKit

public struct SigV4Middleware<OperationStackOutput: HttpResponseBinding,
OperationStackError: HttpResponseErrorBinding>: Middleware {
public struct SigV4Middleware<OperationStackOutput>: Middleware {
public let id: String = "Sigv4Signer"

let config: SigV4Config
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import ClientRuntime

public struct UserAgentMiddleware<OperationStackOutput: HttpResponseBinding>: Middleware {
public struct UserAgentMiddleware<OperationStackOutput>: Middleware {
public let id: String = "UserAgentHeader"

private let X_AMZ_USER_AGENT: String = "x-amz-user-agent"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
// SPDX-License-Identifier: Apache-2.0.
import ClientRuntime

public struct XAmzTargetMiddleware<OperationStackInput,
OperationStackOutput: HttpResponseBinding>: Middleware {
public struct XAmzTargetMiddleware<OperationStackInput, OperationStackOutput>: Middleware {
public let id: String = "XAmzTargetHeader"

let xAmzTarget: String
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ class Sha256TreeHashMiddlewareTests: XCTestCase {
let byteArray: [UInt8] = Array(repeating: 0, count: bytesIn5_5MB)
let byteStream = ByteStream.stream(BufferedStream(data: .init(byteArray), isClosed: true))
let streamInput = MockStreamInput(body: byteStream)
var stack = OperationStack<MockStreamInput, MockOutput, MockMiddlewareError>(id: "TreeHashMiddlewareTestStack")
var stack = OperationStack<MockStreamInput, MockOutput>(id: "TreeHashMiddlewareTestStack")
stack.serializeStep.intercept(position: .before, middleware: MockSerializeStreamMiddleware())
let mockHttpResponse = HttpResponse(body: HttpBody.none, statusCode: .accepted)
let mockOutput = try MockOutput(httpResponse: mockHttpResponse, decoder: nil)
let output = OperationOutput<MockOutput>(httpResponse: mockHttpResponse, output: mockOutput)
stack.finalizeStep.intercept(position: .after, middleware: Sha256TreeHashMiddleware<MockOutput, MockMiddlewareError>())
stack.finalizeStep.intercept(position: .after, middleware: Sha256TreeHashMiddleware<MockOutput>())
_ = try await stack.handleMiddleware(context: context, input: streamInput, next: MockHandler(handleCallback: { context, input in
let linear = input.headers.value(for: "X-Amz-Content-Sha256")
XCTAssertEqual(linear, "733cf513448ce6b20ad1bc5e50eb27c06aefae0c320713a5dd99f4e51bc1ca60")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,10 @@ class PresignerGenerator : SwiftIntegration {
presignOperations.forEach { presignableOperation ->
val op = ctx.model.expectShape<OperationShape>(presignableOperation.operationId)
val inputType = op.input.get().getName()
val outputType = op.output.get().getName()
delegator.useFileWriter("${ctx.settings.moduleName}/models/$inputType+Presigner.swift") { writer ->
var serviceConfig = AWSServiceConfig(writer, protoCtx)
renderPresigner(writer, ctx, delegator, op, inputType, serviceConfig)
renderPresigner(writer, ctx, delegator, op, inputType, outputType, serviceConfig)
}
// Expose presign-request as a method for service client object
val symbol = protoCtx.symbolProvider.toSymbol(protoCtx.service)
Expand All @@ -71,6 +72,7 @@ class PresignerGenerator : SwiftIntegration {
delegator: SwiftDelegator,
op: OperationShape,
inputType: String,
outputType: String,
serviceConfig: AWSServiceConfig
) {
val serviceShape = ctx.model.expectShape<ServiceShape>(ctx.settings.service)
Expand Down Expand Up @@ -108,7 +110,11 @@ class PresignerGenerator : SwiftIntegration {
}
val requestBuilderName = "presignedRequestBuilder"
val builtRequestName = "builtRequest"
writer.write("let $requestBuilderName = try await $operationStackName.presignedRequest(context: context, input: input, next: \$N())", NoopHandler)
writer.write(
"let $requestBuilderName = try await $operationStackName.presignedRequest(context: context, input: input, output: \$L(), next: \$N())",
outputType,
NoopHandler
)
writer.openBlock("guard let $builtRequestName = $requestBuilderName?.build() else {", "}") {
writer.write("return nil")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,10 @@ class PresignableUrlIntegration(private val presignedOperations: Map<String, Set
presignOperations.forEach { presignableOperation ->
val op = ctx.model.expectShape<OperationShape>(presignableOperation.operationId)
val inputType = op.input.get().getName()
val outputType = op.output.get().getName()
delegator.useFileWriter("${ctx.settings.moduleName}/models/$inputType+Presigner.swift") { writer ->
val serviceConfig = AWSServiceConfig(writer, protocolGenerationContext)
renderPresigner(writer, ctx, delegator, op, inputType, serviceConfig)
renderPresigner(writer, ctx, delegator, op, inputType, outputType, serviceConfig)
}
// Expose presign-URL as a method for service client object
val symbol = protocolGenerationContext.symbolProvider.toSymbol(protocolGenerationContext.service)
Expand All @@ -93,6 +94,7 @@ class PresignableUrlIntegration(private val presignedOperations: Map<String, Set
delegator: SwiftDelegator,
op: OperationShape,
inputType: String,
outputType: String,
serviceConfig: AWSServiceConfig
) {
val serviceShape = ctx.model.expectShape<ServiceShape>(ctx.settings.service)
Expand Down Expand Up @@ -139,7 +141,8 @@ class PresignableUrlIntegration(private val presignedOperations: Map<String, Set
val builtRequestName = "builtRequest"
val presignedURL = "presignedURL"
writer.write(
"let $requestBuilderName = try await $operationStackName.presignedRequest(context: context, input: input, next: \$N())",
"let $requestBuilderName = try await $operationStackName.presignedRequest(context: context, input: input, output: \$L(), next: \$N())",
outputType,
ClientRuntimeTypes.Middleware.NoopHandler
)
writer.openBlock("guard let $builtRequestName = $requestBuilderName?.build(), let $presignedURL = $builtRequestName.endpoint.url else {", "}") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,9 @@ open class AWSSigningMiddleware(
val output = MiddlewareShapeUtils.outputSymbol(symbolProvider, model, op)
val outputError = MiddlewareShapeUtils.outputErrorSymbol(op)
writer.write(
"$operationStackName.${middlewareStep.stringValue()}.intercept(position: ${position.stringValue()}, middleware: \$N<\$N, \$N>(config: sigv4Config))",
AWSClientRuntimeTypes.Signing.SigV4Middleware, output, outputError
"$operationStackName.${middlewareStep.stringValue()}.intercept(position: ${position.stringValue()}, middleware: \$N<\$N>(config: sigv4Config))",
AWSClientRuntimeTypes.Signing.SigV4Middleware,
output
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import software.amazon.smithy.aws.swift.codegen.AWSSwiftDependency
import software.amazon.smithy.aws.swift.codegen.ENDPOINT_PARAMS
import software.amazon.smithy.aws.swift.codegen.ENDPOINT_RESOLVER
import software.amazon.smithy.codegen.core.Symbol
import software.amazon.smithy.swift.codegen.ClientRuntimeTypes
import software.amazon.smithy.swift.codegen.Middleware
import software.amazon.smithy.swift.codegen.SwiftDependency
import software.amazon.smithy.swift.codegen.SwiftWriter
Expand All @@ -30,8 +29,7 @@ class EndpointResolverMiddleware(

override val id: String = "EndpointResolverMiddleware"

override val typeName =
"EndpointResolverMiddleware<$outputSymbol: ${ClientRuntimeTypes.Http.HttpResponseBinding}, $outputErrorSymbol: ${ClientRuntimeTypes.Http.HttpResponseErrorBinding}>"
override val typeName = "EndpointResolverMiddleware<$outputSymbol>"

override val properties: MutableMap<String, Symbol> = mutableMapOf(
ENDPOINT_RESOLVER to AWSServiceTypes.EndpointResolver,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ class GlacierAccountIdMiddleware(private val model: Model, private val symbolPro

override fun render(ctx: ProtocolGenerator.GenerationContext, writer: SwiftWriter, op: OperationShape, operationStackName: String) {
val outputShapeName = MiddlewareShapeUtils.outputSymbol(symbolProvider, model, op).name
val outputErrorShapeName = MiddlewareShapeUtils.outputErrorSymbolName(op)
val accountId = model.expectShape<StructureShape>(op.input.get()).members().first { it.memberName.lowercase() == "accountid" }
writer.openBlock(
"$operationStackName.${middlewareStep.stringValue()}.intercept(position: ${position.stringValue()}, id: \"${name}\") { (context, input, next) -> \$N<$outputShapeName> in", "}",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ class OperationEndpointResolverMiddleware(
}
writer.write("let endpointParams = EndpointParams(${params.joinToString(separator = ", ")})")
val middlewareParamsString = "endpointResolver: config.serviceSpecific.endpointResolver, endpointParams: endpointParams"
writer.write("$operationStackName.${middlewareStep.stringValue()}.intercept(position: ${position.stringValue()}, middleware: \$N<\$N, \$N>($middlewareParamsString))", AWSServiceTypes.EndpointResolverMiddleware, output, outputError)
writer.write("$operationStackName.${middlewareStep.stringValue()}.intercept(position: ${position.stringValue()}, middleware: \$N<\$N>($middlewareParamsString))", AWSServiceTypes.EndpointResolverMiddleware, output)
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ class Sha256TreeHashMiddleware(private val symbolProvider: SymbolProvider, priva

override fun render(ctx: ProtocolGenerator.GenerationContext, writer: SwiftWriter, op: OperationShape, operationStackName: String) {
val outputShape = MiddlewareShapeUtils.outputSymbol(symbolProvider, model, op)
val outputErrorShapeName = MiddlewareShapeUtils.outputErrorSymbolName(op)
writer.write("$operationStackName.${middlewareStep.stringValue()}.intercept(position: ${position.stringValue()}, middleware: \$N<\$N, $outputErrorShapeName>())", AWSClientRuntimeTypes.Core.Sha256TreeHashMiddleware, outputShape)
writer.write("$operationStackName.${middlewareStep.stringValue()}.intercept(position: ${position.stringValue()}, middleware: \$N<\$N>())", AWSClientRuntimeTypes.Core.Sha256TreeHashMiddleware, outputShape)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,9 @@ class AWSSigningMiddlewareTests {
@Test
fun `render unsignedBody true`() {
val expectedContents = """
let sigv4Config = AWSClientRuntime.SigV4Config(unsignedBody: true, signingAlgorithm: .sigv4)
stack.finalizeStep.intercept(position: .before, middleware: AWSClientRuntime.SigV4Middleware<ExampleOutput, ExampleOperationOutputError>(config: sigv4Config))
""".trimIndent()
let sigv4Config = AWSClientRuntime.SigV4Config(unsignedBody: true, signingAlgorithm: .sigv4)
stack.finalizeStep.intercept(position: .before, middleware: AWSClientRuntime.SigV4Middleware<ExampleOutput>(config: sigv4Config))
"""
val writer = SwiftWriter("testName")
val context = contextForSDK("ExampleService")
val operation = context.model.operationShapes.first()
Expand All @@ -102,9 +102,9 @@ class AWSSigningMiddlewareTests {
@Test
fun `render unsignedBody false`() {
val expectedContents = """
let sigv4Config = AWSClientRuntime.SigV4Config(unsignedBody: false, signingAlgorithm: .sigv4)
stack.finalizeStep.intercept(position: .before, middleware: AWSClientRuntime.SigV4Middleware<ExampleOutput, ExampleOperationOutputError>(config: sigv4Config))
""".trimIndent()
let sigv4Config = AWSClientRuntime.SigV4Config(unsignedBody: false, signingAlgorithm: .sigv4)
stack.finalizeStep.intercept(position: .before, middleware: AWSClientRuntime.SigV4Middleware<ExampleOutput>(config: sigv4Config))
"""
val writer = SwiftWriter("testName")
val context = contextForSDK("ExampleService")
val operation = context.model.operationShapes.first()
Expand All @@ -127,9 +127,9 @@ class AWSSigningMiddlewareTests {
@Test
fun `render unsignedBody true, presigner`() {
val expectedContents = """
let sigv4Config = AWSClientRuntime.SigV4Config(expiration: expiration, unsignedBody: true, signingAlgorithm: .sigv4)
stack.finalizeStep.intercept(position: .before, middleware: AWSClientRuntime.SigV4Middleware<ExampleOutput, ExampleOperationOutputError>(config: sigv4Config))
""".trimIndent()
let sigv4Config = AWSClientRuntime.SigV4Config(expiration: expiration, unsignedBody: true, signingAlgorithm: .sigv4)
stack.finalizeStep.intercept(position: .before, middleware: AWSClientRuntime.SigV4Middleware<ExampleOutput>(config: sigv4Config))
"""
val writer = SwiftWriter("testName")
val context = contextForSDK("ExampleService")
val operation = context.model.operationShapes.first()
Expand All @@ -152,9 +152,9 @@ class AWSSigningMiddlewareTests {
@Test
fun `render unsignedBody false, presigner`() {
val expectedContents = """
let sigv4Config = AWSClientRuntime.SigV4Config(expiration: expiration, unsignedBody: false, signingAlgorithm: .sigv4)
stack.finalizeStep.intercept(position: .before, middleware: AWSClientRuntime.SigV4Middleware<ExampleOutput, ExampleOperationOutputError>(config: sigv4Config))
""".trimIndent()
let sigv4Config = AWSClientRuntime.SigV4Config(expiration: expiration, unsignedBody: false, signingAlgorithm: .sigv4)
stack.finalizeStep.intercept(position: .before, middleware: AWSClientRuntime.SigV4Middleware<ExampleOutput>(config: sigv4Config))
"""
val writer = SwiftWriter("testName")
val context = contextForSDK("ExampleService")
val operation = context.model.operationShapes.first()
Expand All @@ -177,9 +177,9 @@ class AWSSigningMiddlewareTests {
@Test
fun `render s3 with query string sig`() {
val expectedContents = """
let sigv4Config = AWSClientRuntime.SigV4Config(signatureType: .requestQueryParams, useDoubleURIEncode: false, shouldNormalizeURIPath: false, expiration: expiration, unsignedBody: true, signingAlgorithm: .sigv4)
stack.finalizeStep.intercept(position: .before, middleware: AWSClientRuntime.SigV4Middleware<ExampleOutput, ExampleOperationOutputError>(config: sigv4Config))
""".trimIndent()
let sigv4Config = AWSClientRuntime.SigV4Config(signatureType: .requestQueryParams, useDoubleURIEncode: false, shouldNormalizeURIPath: false, expiration: expiration, unsignedBody: true, signingAlgorithm: .sigv4)
stack.finalizeStep.intercept(position: .before, middleware: AWSClientRuntime.SigV4Middleware<ExampleOutput>(config: sigv4Config))
"""
val writer = SwiftWriter("testName")
val context = contextForSDK("S3")
val operation = context.model.operationShapes.first()
Expand All @@ -202,8 +202,8 @@ class AWSSigningMiddlewareTests {
@Test
fun `render s3 with signed body & normal sig`() {
val expectedContents = """
let sigv4Config = AWSClientRuntime.SigV4Config(useDoubleURIEncode: false, shouldNormalizeURIPath: false, expiration: expiration, signedBodyHeader: .contentSha256, unsignedBody: false, signingAlgorithm: .sigv4)
stack.finalizeStep.intercept(position: .before, middleware: AWSClientRuntime.SigV4Middleware<ExampleOutput, ExampleOperationOutputError>(config: sigv4Config))
let sigv4Config = AWSClientRuntime.SigV4Config(useDoubleURIEncode: false, shouldNormalizeURIPath: false, expiration: expiration, signedBodyHeader: .contentSha256, unsignedBody: false, signingAlgorithm: .sigv4)
stack.finalizeStep.intercept(position: .before, middleware: AWSClientRuntime.SigV4Middleware<ExampleOutput>(config: sigv4Config))
""".trimIndent()
val writer = SwiftWriter("testName")
val context = contextForSDK("S3")
Expand All @@ -227,9 +227,9 @@ class AWSSigningMiddlewareTests {
@Test
fun `render glacier with signed body & normal sig`() {
val expectedContents = """
let sigv4Config = AWSClientRuntime.SigV4Config(signedBodyHeader: .contentSha256, unsignedBody: false, signingAlgorithm: .sigv4)
stack.finalizeStep.intercept(position: .before, middleware: AWSClientRuntime.SigV4Middleware<ExampleOutput, ExampleOperationOutputError>(config: sigv4Config))
""".trimIndent()
let sigv4Config = AWSClientRuntime.SigV4Config(signedBodyHeader: .contentSha256, unsignedBody: false, signingAlgorithm: .sigv4)
stack.finalizeStep.intercept(position: .before, middleware: AWSClientRuntime.SigV4Middleware<ExampleOutput>(config: sigv4Config))
"""
val writer = SwiftWriter("testName")
val context = contextForSDK("Glacier")
val operation = context.model.operationShapes.first()
Expand Down
Loading

0 comments on commit 7624f1e

Please sign in to comment.