Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support orchestrator #1435

Merged
merged 1 commit into from
May 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@

import ClientRuntime

public struct AWSS3ErrorWith200StatusXMLMiddleware<OperationStackOutput>: Middleware {
public struct AWSS3ErrorWith200StatusXMLMiddleware<OperationStackInput, OperationStackOutput>: Middleware {
public let id: String = "AWSS3ErrorWith200StatusXMLMiddleware"
private let errorStatusCode: HttpStatusCode = .internalServerError

public init() {}

Expand All @@ -23,30 +24,48 @@ public struct AWSS3ErrorWith200StatusXMLMiddleware<OperationStackOutput>: Middle
// Let the next handler in the chain process the input
let response = try await next.handle(context: context, input: input)

if try await isErrorWith200Status(response: response.httpResponse) {
// Handle the error as a 500 Internal Server Error
let modifiedResponse = response
modifiedResponse.httpResponse.statusCode = errorStatusCode
return modifiedResponse
}

return response
}

private func isErrorWith200Status(response: HttpResponse) async throws -> Bool {
// Check if the status code is OK (200)
guard response.httpResponse.statusCode == .ok else {
return response
guard response.statusCode == .ok else {
return false
}

// Check if the response body contains an XML Error
guard let data = try await response.httpResponse.body.readData() else {
return response
guard let data = try await response.body.readData() else {
return false
}

response.httpResponse.body = .data(data)

response.body = .data(data)
let xmlString = String(data: data, encoding: .utf8) ?? ""
if xmlString.contains("<Error>") {
// Handle the error as a 500 Internal Server Error
let modifiedResponse = response
modifiedResponse.httpResponse.statusCode = .internalServerError
return modifiedResponse
}

return response
return xmlString.contains("<Error>")
}

public typealias MInput = SdkHttpRequest
public typealias MOutput = OperationOutput<OperationStackOutput>
public typealias Context = HttpContext
}

extension AWSS3ErrorWith200StatusXMLMiddleware: HttpInterceptor {
public typealias InputType = OperationStackInput
public typealias OutputType = OperationStackOutput

public func modifyBeforeDeserialization(
context: some MutableResponse<Self.InputType, Self.RequestType, Self.ResponseType, Self.AttributesType>
) async throws {
let response = context.getResponse()
if try await isErrorWith200Status(response: response) {
response.statusCode = errorStatusCode
context.updateResponse(updated: response)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,32 @@ public struct Route53TrimHostedZoneMiddleware<Input, Output>: ClientRuntime.Midd
Self.MInput == H.Input,
Self.MOutput == H.Output,
Self.Context == H.Context {
let updatedInput = getUpdatedInput(input: input)
return try await next.handle(context: context, input: updatedInput)
}

private func getUpdatedInput(input: Input) -> Input {
guard let hostedZoneId = input[keyPath: hostedZoneIDKeyPath] else {
return try await next.handle(context: context, input: input)
return input
}
var copiedInput = input
let stripped = hostedZoneId.stripFirstMatching(prefixes: prefixes)
copiedInput[keyPath: hostedZoneIDKeyPath] = stripped
return try await next.handle(context: context, input: copiedInput)
return copiedInput
}

public typealias MInput = Input
public typealias MOutput = ClientRuntime.OperationOutput<Output>
public typealias Context = ClientRuntime.HttpContext
}

extension Route53TrimHostedZoneMiddleware: HttpInterceptor {
public typealias InputType = Input
public typealias OutputType = Output

public func modifyBeforeSerialization(
context: some MutableInput<Self.InputType, Self.AttributesType>
) async throws {
context.updateInput(updated: getUpdatedInput(input: context.getInput()))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import AwsCommonRuntimeKit
import ClientRuntime
import AwsCCal

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

private let X_AMZ_SHA256_TREE_HASH_HEADER_NAME = "X-Amz-Sha256-Tree-Hash"
Expand All @@ -22,44 +22,46 @@ public struct Sha256TreeHashMiddleware<OperationStackOutput>: Middleware {
Self.MOutput == H.Output,
Self.Context == H.Context {
let request = input.build()

switch request.body {
case .data(let data):
guard let data = data else {
return try await next.handle(context: context, input: input)
}
if !request.headers.exists(name: X_AMZ_CONTENT_SHA256_HEADER_NAME) {
let sha256 = try data.computeSHA256().encodeToHexString()
input.withHeader(name: X_AMZ_CONTENT_SHA256_HEADER_NAME, value: sha256)
}
case .stream(let stream):
let streamBytes: Data?
let currentPosition = stream.position
if stream.isSeekable {
streamBytes = try await stream.readToEndAsync()
try stream.seek(toOffset: currentPosition)
} else {
// If the stream is not seekable, we need to cache the stream in memory
// so we can compute the hash and still be able to send the stream to the service.
// This is not ideal, but it is the best we can do.
streamBytes = try await stream.readToEndAsync()
input.withBody(.data(streamBytes))
}
guard let streamBytes = streamBytes, !streamBytes.isEmpty else {
return try await next.handle(context: context, input: input)
}
let (linearHash, treeHash) = try computeHashes(data: streamBytes)
if let treeHash = treeHash, let linearHash = linearHash {
input.withHeader(name: X_AMZ_SHA256_TREE_HASH_HEADER_NAME, value: treeHash)
input.withHeader(name: X_AMZ_CONTENT_SHA256_HEADER_NAME, value: linearHash)
}
case .noStream:
break
}

try await addHashes(request: request, builder: input)
return try await next.handle(context: context, input: input)
}

private func addHashes(request: SdkHttpRequest, builder: SdkHttpRequestBuilder) async throws {
switch request.body {
case .data(let data):
guard let data = data else {
return
}
if !request.headers.exists(name: X_AMZ_CONTENT_SHA256_HEADER_NAME) {
let sha256 = try data.computeSHA256().encodeToHexString()
builder.withHeader(name: X_AMZ_CONTENT_SHA256_HEADER_NAME, value: sha256)
}
case .stream(let stream):
let streamBytes: Data?
let currentPosition = stream.position
if stream.isSeekable {
streamBytes = try await stream.readToEndAsync()
try stream.seek(toOffset: currentPosition)
} else {
// If the stream is not seekable, we need to cache the stream in memory
// so we can compute the hash and still be able to send the stream to the service.
// This is not ideal, but it is the best we can do.
streamBytes = try await stream.readToEndAsync()
builder.withBody(.data(streamBytes))
}
guard let streamBytes = streamBytes, !streamBytes.isEmpty else {
return
}
let (linearHash, treeHash) = try computeHashes(data: streamBytes)
if let treeHash = treeHash, let linearHash = linearHash {
builder.withHeader(name: X_AMZ_SHA256_TREE_HASH_HEADER_NAME, value: treeHash)
builder.withHeader(name: X_AMZ_CONTENT_SHA256_HEADER_NAME, value: linearHash)
}
case .noStream:
break
}
}

/// Computes the tree-hash and linear hash of Data.
/// See http://docs.aws.amazon.com/amazonglacier/latest/dev/checksum-calculations.html for more information.
private func computeHashes(data: Data) throws -> (String?, String?) {
Expand Down Expand Up @@ -102,3 +104,17 @@ public struct Sha256TreeHashMiddleware<OperationStackOutput>: Middleware {
public typealias MOutput = OperationOutput<OperationStackOutput>
public typealias Context = HttpContext
}

extension Sha256TreeHashMiddleware: HttpInterceptor {
public typealias InputType = OperationStackInput
public typealias OutputType = OperationStackOutput

public func modifyBeforeTransmit(
context: some MutableRequest<Self.InputType, Self.RequestType, Self.AttributesType>
) async throws {
let request = context.getRequest()
let builder = request.toBuilder()
try await addHashes(request: request, builder: builder)
context.updateRequest(updated: builder.build())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import ClientRuntime

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

private let X_AMZ_USER_AGENT: String = "x-amz-user-agent"
Expand All @@ -26,12 +26,28 @@ public struct UserAgentMiddleware<OperationStackOutput>: Middleware {
Self.MInput == H.Input,
Self.MOutput == H.Output,
Self.Context == H.Context {
input.withHeader(name: USER_AGENT, value: metadata.userAgent)

addHeader(builder: input)
return try await next.handle(context: context, input: input)
}

private func addHeader(builder: SdkHttpRequestBuilder) {
builder.withHeader(name: USER_AGENT, value: metadata.userAgent)
}

public typealias MInput = SdkHttpRequestBuilder
public typealias MOutput = OperationOutput<OperationStackOutput>
public typealias Context = HttpContext
}

extension UserAgentMiddleware: HttpInterceptor {
public typealias InputType = OperationStackInput
public typealias OutputType = OperationStackOutput

public func modifyBeforeRetryLoop(
context: some MutableRequest<Self.InputType, SdkHttpRequest, HttpContext>
) async throws {
let builder = context.getRequest().toBuilder()
addHeader(builder: builder)
context.updateRequest(updated: builder.build())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,28 @@ public struct XAmzTargetMiddleware<OperationStackInput, OperationStackOutput>: M
Self.MOutput == H.Output,
Self.Context == H.Context {

input.builder.withHeader(name: "X-Amz-Target", value: xAmzTarget)

addHeader(builder: input.builder)
return try await next.handle(context: context, input: input)
}

private func addHeader(builder: SdkHttpRequestBuilder) {
builder.withHeader(name: "X-Amz-Target", value: xAmzTarget)
}

public typealias MInput = SerializeStepInput<OperationStackInput>
public typealias MOutput = OperationOutput<OperationStackOutput>
public typealias Context = HttpContext
}

extension XAmzTargetMiddleware: HttpInterceptor {
public typealias InputType = OperationStackInput
public typealias OutputType = OperationStackOutput

public func modifyBeforeRetryLoop(
context: some MutableRequest<Self.InputType, Self.RequestType, Self.AttributesType>
) async throws {
let builder = context.getRequest().toBuilder()
addHeader(builder: builder)
context.updateRequest(updated: builder.build())
}
}
Loading
Loading