Skip to content

Commit

Permalink
feat: handle errors in 200 response from S3 (#1266)
Browse files Browse the repository at this point in the history
  • Loading branch information
dayaffe authored Jan 4, 2024
1 parent a383887 commit a6b7f12
Show file tree
Hide file tree
Showing 7 changed files with 279 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import Foundation
import XCTest
import AWSS3
import AWSClientRuntime
import AwsCommonRuntimeKit
import ClientRuntime

public class MockHttpClientEngine: HttpClientEngine {

// Public initializer
public init() {}

func successHttpResponse(request: SdkHttpRequest) -> HttpResponse {
let errorResponsePayload = """
<Error>
<Code>SlowDown</Code>
<Message>Please reduce your request rate.</Message>
<RequestId>K2H6N7ZGQT6WHCEG</RequestId>
<HostId>WWoZlnK4pTjKCYn6eNV7GgOurabfqLkjbSyqTvDMGBaI9uwzyNhSaDhOCPs8paFGye7S6b/AB3A=</HostId>
</Error>
"""
return HttpResponse(
headers: request.headers,
body: ByteStream.data(errorResponsePayload.data(using: .utf8)),
statusCode: HttpStatusCode.ok
)
}

public func execute(request: SdkHttpRequest) async throws -> HttpResponse {
return successHttpResponse(request: request)
}
}

class S3ErrorIn200Test: XCTestCase {

override class func setUp() {
AwsCommonRuntimeKit.CommonRuntimeKit.initialize()
}

/// S3Client throws expected error in response (200) with <Error> tag
func test_foundExpectedError() async throws {
let config = try await S3Client.S3ClientConfiguration(region: "us-west-2")
config.httpClientEngine = MockHttpClientEngine()
let client = S3Client(config: config)

do {
// any method on S3Client where the output shape doesnt have a stream
_ = try await client.listBuckets(input: .init())
XCTFail("Expected an error to be thrown, but it was not.")
} catch let error as UnknownAWSHTTPServiceError {
// check for the error we added in our mock client
XCTAssertEqual("Please reduce your request rate.", error.message)
} catch {
XCTFail("Unexpected error: \(error)")
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import ClientRuntime

public struct AWSS3ErrorWith200StatusXMLMiddleware<OperationStackOutput>: Middleware {
public let id: String = "AWSS3ErrorWith200StatusXMLMiddleware"

public init() {}

public func handle<H>(context: Context,
input: SdkHttpRequest,
next: H) async throws -> OperationOutput<OperationStackOutput>
where H: Handler,
Self.MInput == H.Input,
Self.MOutput == H.Output,
Self.Context == H.Context {

// Let the next handler in the chain process the input
let response = try await next.handle(context: context, input: input)

// Check if the status code is OK (200)
guard response.httpResponse.statusCode == .ok else {
return response
}

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

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

return response
}

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

0 comments on commit a6b7f12

Please sign in to comment.