Skip to content

Commit

Permalink
chore: Merge updates from main into project epic branch (#658)
Browse files Browse the repository at this point in the history
* chore: Require Swift 5.7, fix deprecation warnings (#600)

* feat: support initial-response in RPC based event streams (#597)

* chore: Updates version to 0.32.0

* chore: Add newline to README.md (#602)

* feat: add limited support in smithy-swift for visionOS (#606)

* feat: add support for requiresLength trait and Transfer-Encoding: Chunked (#604)

* chore: Update to aws-crt-swift 0.15.0 (#607)

* fix: content-length middleware should not error on event streams (#608)

* chore: Updates version to 0.33.0

* chore: Improved downstream task (#568)

* chore: Convert idempotency token middleware from closure to reusable type (#610)

* fix: Update aws-crt-swift dependency to 0.17.0 (#612)

* chore: Updates version to 0.34.0

* fix: Endpoint url should be nil if host or scheme is missing (#614)

* fix: Pool HTTP connections based on scheme, host, and port (#615)

* add default log level to initialize method (#616)

* feat: add utility method for converting SdkHttpRequest to URLRequest. (#613)

* Add extension constructor to URLRequest to convert SDKHttpRequest

* Add preprocessor conditional import functionality to SwiftWriter.

---------

Co-authored-by: Sichan Yoo <chanyoo@amazon.com>

* chore: Updates version to 0.35.0

* fix: Add a header to operation doc comments (#621)

* remove unnecessary TODOs (#622)

* fix: Codegen issues re: recursion, Swift keywords in unions (#623)

* feat!: Replace the XML encoder with a custom Smithy implementation (#619)

* feat!: Use closures for processing HTTP response (#624)

* feat: add custom trait PaginationTruncationMember (#625)

* allow isTruncated to be optional bool (#626)

* chore: Updates version to 0.36.0

* chore: Run tvOS old & new in CI (#628)

* fix: Fix Package.swift warning on Mac (#629)

* chore: refactor HttpBody and ByteStream to be a single class ByteStream (#627)

* chore: remove sync read in unused data extension (#630)

* update smithy to 1.42.0 (#631)

* chore: Updates version to 0.37.0

* chore: Update to aws-crt-swift 0.20.0 (#633)

* fix: add back from method with fileHandle (#635)

* fix!: Add no-op behavior for initialize methods of logging system. (#637)

* Add no-op behavior for initialize methods if it isn't the first time being called.

* Make LockingSystem threadsafe.

* Make initialize methods async.

---------

Co-authored-by: Sichan Yoo <chanyoo@amazon.com>

* feat!: URLSession-based HTTP Client (#636)

* bump up CRT version to 0.22.0 (#639)

* chore: Update version to 0.38.0 (#641)

* chore: Empty commit (#643)

* feat: add wrapper for checksums + unit tests (#642)

* feat: Use the Foundation HTTP client by default on Mac (#646)

* chore: Updates version to 0.39.0

* chore: Change MyURLQueryItem to SDKURLQueryItem (#652)

* feat!: Provide HTTP request components by closure instead of protocol (#654)

* fix: Don't retry modeled errors by default (#653)

* Missed merge conflict marker - deleted.

---------

Co-authored-by: Josh Elkins <jbelkins@users.noreply.github.com>
Co-authored-by: David Yaffe <dayaffe@amazon.com>
Co-authored-by: AWS SDK Swift Automation <github-aws-sdk-swift-automation@amazon.com>
Co-authored-by: Cyprien Ricque <48893621+CyprienRicque@users.noreply.github.com>
Co-authored-by: Sichan Yoo <chanyoo@amazon.com>
  • Loading branch information
6 people authored Feb 6, 2024
1 parent 6b51513 commit c695be9
Show file tree
Hide file tree
Showing 43 changed files with 764 additions and 436 deletions.
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ let package = Package(
.library(name: "SmithyTestUtil", targets: ["SmithyTestUtil"]),
],
dependencies: [
.package(url: "https://github.com/awslabs/aws-crt-swift.git", exact: "0.20.0"),
.package(url: "https://github.com/awslabs/aws-crt-swift.git", exact: "0.22.0"),
.package(url: "https://github.com/apple/swift-log.git", from: "1.0.0"),
.package(url: "https://github.com/MaxDesiatov/XMLCoder.git", exact: "0.17.0")
],
Expand Down
2 changes: 1 addition & 1 deletion Package.version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.37.0
0.39.0
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public extension DefaultSDKRuntimeConfiguration {
/// - Parameter httpClientConfiguration: The configuration for the HTTP client.
/// - Returns: The `CRTClientEngine` client on Mac & Linux platforms, returns `URLSessionHttpClient` on non-Mac Apple platforms.
static func makeClient(httpClientConfiguration: HttpClientConfiguration) -> HTTPClient {
#if os(iOS) || os(tvOS) || os(watchOS) || os(visionOS)
#if os(iOS) || os(tvOS) || os(watchOS) || os(visionOS) || os(macOS)
return URLSessionHTTPClient(httpClientConfiguration: httpClientConfiguration)
#else
let connectTimeoutMs = httpClientConfiguration.connectTimeout.map { UInt32($0 * 1_000_000) }
Expand Down
4 changes: 2 additions & 2 deletions Sources/ClientRuntime/Networking/Endpoint.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import Foundation

public struct Endpoint: Hashable {
public let path: String
public let queryItems: [URLQueryItem]?
public let queryItems: [SDKURLQueryItem]?
public let protocolType: ProtocolType?
public let host: String
public let port: Int16
Expand Down Expand Up @@ -43,7 +43,7 @@ public struct Endpoint: Hashable {
public init(host: String,
path: String = "/",
port: Int16 = 443,
queryItems: [URLQueryItem]? = nil,
queryItems: [SDKURLQueryItem]? = nil,
protocolType: ProtocolType? = .https,
headers: Headers? = nil,
properties: [String: AnyHashable] = [:]) {
Expand Down
83 changes: 83 additions & 0 deletions Sources/ClientRuntime/Networking/HashFunction.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/

import AwsCommonRuntimeKit

enum HashResult {
case data(Data)
case integer(UInt32)
}

enum HashError: Error {
case invalidInput
case hashingFailed(reason: String)
}

enum HashFunction {
case crc32, crc32c, sha1, sha256, md5

static func from(string: String) -> HashFunction? {
switch string.lowercased() {
case "crc32": return .crc32
case "crc32c": return .crc32c
case "sha1": return .sha1
case "sha256": return .sha256
case "md5": return .md5 // md5 is not a valid flexible checksum algorithm
default: return nil
}
}

var isSupported: Bool {
switch self {
case .crc32, .crc32c, .sha256, .sha1:
return true
default:
return false
}
}

func computeHash(of data: Data) throws -> HashResult {
switch self {
case .crc32:
return .integer(data.computeCRC32())
case .crc32c:
return .integer(data.computeCRC32C())
case .sha1:
do {
let hashed = try data.computeSHA1()
return .data(hashed)
} catch {
throw HashError.hashingFailed(reason: "Error computing SHA1: \(error)")
}
case .sha256:
do {
let hashed = try data.computeSHA256()
return .data(hashed)
} catch {
throw HashError.hashingFailed(reason: "Error computing SHA256: \(error)")
}
case .md5:
do {
let hashed = try data.computeMD5()
return .data(hashed)
} catch {
throw HashError.hashingFailed(reason: "Error computing MD5: \(error)")
}
}
}
}

extension HashResult {

// Convert a HashResult to a hexadecimal String
func toHexString() -> String {
switch self {
case .data(let data):
return data.map { String(format: "%02x", $0) }.joined()
case .integer(let integer):
return String(format: "%08x", integer)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ public class CRTClientEngine: HTTPClient {
clientBootstrap: sharedDefaultIO.clientBootstrap,
hostName: endpoint.host,
initialWindowSize: windowSize,
port: UInt16(endpoint.port),
port: UInt32(endpoint.port),
proxyOptions: nil,
socketOptions: socketOptions,
tlsOptions: tlsConnectionOptions,
Expand Down Expand Up @@ -118,7 +118,7 @@ public class CRTClientEngine: HTTPClient {
let options = HTTP2StreamManagerOptions(
clientBootstrap: sharedDefaultIO.clientBootstrap,
hostName: endpoint.host,
port: UInt16(endpoint.port),
port: UInt32(endpoint.port),
maxConnections: maxConnectionsPerEndpoint,
socketOptions: socketOptions,
tlsOptions: tlsConnectionOptions,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ extension HTTP2Stream {
func write(body: ByteStream) async throws {
switch body {
case .data(let data):
try await writeData(data: data ?? .init(), endOfStream: true)
try await writeChunk(chunk: data ?? .init(), endOfStream: true)
case .stream(let stream):
while let data = try await stream.readAsync(upToCount: manualWriteBufferSize) {
try await writeData(data: data, endOfStream: false)
try await writeChunk(chunk: data, endOfStream: false)
}
try await writeData(data: .init(), endOfStream: true)
try await writeChunk(chunk: .init(), endOfStream: true)
case .noStream:
try await writeData(data: .init(), endOfStream: true)
try await writeChunk(chunk: .init(), endOfStream: true)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,11 @@ public struct ContentMD5Middleware<OperationStackOutput>: Middleware {

switch input.body {
case .data(let data):
guard
let data = data,
let bodyString = String(data: data, encoding: .utf8)
else {
guard let data = data else {
return try await next.handle(context: context, input: input)
}
let base64Encoded = try bodyString.base64EncodedMD5()
let md5Hash = try data.computeMD5()
let base64Encoded = md5Hash.base64EncodedString()
input.headers.update(name: "Content-MD5", value: base64Encoded)
case .stream:
guard let logger = context.getLogger() else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@
// SPDX-License-Identifier: Apache-2.0
//

public struct HeaderMiddleware<OperationStackInput: HeaderProvider, OperationStackOutput>: Middleware {
public struct HeaderMiddleware<OperationStackInput, OperationStackOutput>: Middleware {
public let id: String = "\(String(describing: OperationStackInput.self))HeadersMiddleware"

public init() {}
let headerProvider: HeaderProvider<OperationStackInput>

public init(_ headerProvider: @escaping HeaderProvider<OperationStackInput>) {
self.headerProvider = headerProvider
}

public func handle<H>(context: Context,
input: MInput,
Expand All @@ -17,8 +21,7 @@ public struct HeaderMiddleware<OperationStackInput: HeaderProvider, OperationSta
Self.MInput == H.Input,
Self.MOutput == H.Output,
Self.Context == H.Context {
input.builder.withHeaders(input.operationInput.headers)

input.builder.withHeaders(headerProvider(input.operationInput))
return try await next.handle(context: context, input: input)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,4 @@
// SPDX-License-Identifier: Apache-2.0
//

public protocol HeaderProvider {
var headers: Headers { get }
}
public typealias HeaderProvider<T> = (T) -> Headers
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,4 @@
// SPDX-License-Identifier: Apache-2.0
//

public protocol QueryItemProvider {
var queryItems: [URLQueryItem] { get throws }
}
public typealias QueryItemProvider<T> = (T) throws -> [SDKURLQueryItem]
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,4 @@
// SPDX-License-Identifier: Apache-2.0
//

public protocol URLPathProvider {
var urlPath: String? { get }
}
public typealias URLPathProvider<T> = (T) -> String?
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@
// SPDX-License-Identifier: Apache-2.0
//

public struct QueryItemMiddleware<OperationStackInput: QueryItemProvider, OperationStackOutput>: Middleware {
public struct QueryItemMiddleware<OperationStackInput, OperationStackOutput>: Middleware {
public let id: String = "\(String(describing: OperationStackInput.self))QueryItemMiddleware"

public init() {}
let queryItemProvider: QueryItemProvider<OperationStackInput>

public init(_ queryItemProvider: @escaping QueryItemProvider<OperationStackInput>) {
self.queryItemProvider = queryItemProvider
}

public func handle<H>(context: Context,
input: MInput,
Expand All @@ -17,7 +21,7 @@ public struct QueryItemMiddleware<OperationStackInput: QueryItemProvider, Operat
Self.MInput == H.Input,
Self.MOutput == H.Output,
Self.Context == H.Context {
for queryItem in try input.operationInput.queryItems {
for queryItem in try queryItemProvider(input.operationInput) {
input.builder.withQueryItem(queryItem)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
// SPDX-License-Identifier: Apache-2.0
//

public struct URLPathMiddleware<OperationStackInput: URLPathProvider, OperationStackOutput>: Middleware {
public struct URLPathMiddleware<OperationStackInput, OperationStackOutput>: Middleware {
public let id: Swift.String = "\(String(describing: OperationStackInput.self))URLPathMiddleware"

let urlPrefix: Swift.String?
let urlPathProvider: URLPathProvider<OperationStackInput>

public init(urlPrefix: Swift.String? = nil) {
public init(urlPrefix: Swift.String? = nil, _ urlPathProvider: @escaping URLPathProvider<OperationStackInput>) {
self.urlPrefix = urlPrefix
self.urlPathProvider = urlPathProvider
}

public func handle<H>(context: Context,
Expand All @@ -21,7 +23,7 @@ public struct URLPathMiddleware<OperationStackInput: URLPathProvider, OperationS
Self.MInput == H.Input,
Self.MOutput == H.Output,
Self.Context == H.Context {
guard var urlPath = input.urlPath else {
guard var urlPath = urlPathProvider(input) else {
let message = "Creating the url path failed, a required property in the path was nil"
throw ClientError.pathCreationFailed(message)
}
Expand Down
14 changes: 7 additions & 7 deletions Sources/ClientRuntime/Networking/Http/SdkHttpRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public class SdkHttpRequest {
}
public var path: String { endpoint.path }
public var host: String { endpoint.host }
public var queryItems: [URLQueryItem]? { endpoint.queryItems }
public var queryItems: [SDKURLQueryItem]? { endpoint.queryItems }

public init(method: HttpMethodType,
endpoint: Endpoint,
Expand Down Expand Up @@ -146,8 +146,8 @@ extension SdkHttpRequestBuilder {
host = originalRequest.host
if let crtRequest = crtRequest as? HTTPRequest, let components = URLComponents(string: crtRequest.path) {
path = components.percentEncodedPath
queryItems = components.percentEncodedQueryItems?.map { URLQueryItem(name: $0.name, value: $0.value) }
?? [URLQueryItem]()
queryItems = components.percentEncodedQueryItems?.map { SDKURLQueryItem(name: $0.name, value: $0.value) }
?? [SDKURLQueryItem]()
} else if crtRequest as? HTTP2Request != nil {
assertionFailure("HTTP2Request not supported")
} else {
Expand All @@ -170,11 +170,11 @@ public class SdkHttpRequestBuilder {
var host: String = ""
var path: String = "/"
var body: ByteStream = .noStream
var queryItems: [URLQueryItem]?
var queryItems: [SDKURLQueryItem]?
var port: Int16 = 443
var protocolType: ProtocolType = .https

public var currentQueryItems: [URLQueryItem]? {
public var currentQueryItems: [SDKURLQueryItem]? {
return queryItems
}

Expand Down Expand Up @@ -225,14 +225,14 @@ public class SdkHttpRequestBuilder {
}

@discardableResult
public func withQueryItems(_ value: [URLQueryItem]) -> SdkHttpRequestBuilder {
public func withQueryItems(_ value: [SDKURLQueryItem]) -> SdkHttpRequestBuilder {
self.queryItems = self.queryItems ?? []
self.queryItems?.append(contentsOf: value)
return self
}

@discardableResult
public func withQueryItem(_ value: URLQueryItem) -> SdkHttpRequestBuilder {
public func withQueryItem(_ value: SDKURLQueryItem) -> SdkHttpRequestBuilder {
withQueryItems([value])
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ public typealias URL = Foundation.URL

extension URL {

func toQueryItems() -> [URLQueryItem]? {
func toQueryItems() -> [SDKURLQueryItem]? {
URLComponents(url: self, resolvingAgainstBaseURL: false)?
.queryItems?
.map { URLQueryItem(name: $0.name, value: $0.value) }
.map { SDKURLQueryItem(name: $0.name, value: $0.value) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
* SPDX-License-Identifier: Apache-2.0.
*/

public typealias URLQueryItem = MyURLQueryItem

public struct MyURLQueryItem: Hashable {
public struct SDKURLQueryItem: Hashable {
public var name: String
public var value: String?

Expand Down
17 changes: 6 additions & 11 deletions Sources/ClientRuntime/Retries/DefaultRetryErrorInfoProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,12 @@ public enum DefaultRetryErrorInfoProvider: RetryErrorInfoProvider {
hint = TimeInterval(retryAfterString)
}
if let modeledError = error as? ModeledError {
switch type(of: modeledError).isThrottling {
case true:
return .init(errorType: .throttling, retryAfterHint: hint, isTimeout: false)
case false:
let errorType = type(of: modeledError).fault.retryErrorType
return .init(errorType: errorType, retryAfterHint: hint, isTimeout: false)
}
} else if let httpError = error as? HTTPError {
if retryableStatusCodes.contains(httpError.httpResponse.statusCode) {
return .init(errorType: .serverError, retryAfterHint: hint, isTimeout: false)
}
let type = type(of: modeledError)
guard type.isRetryable else { return nil }
let errorType: RetryErrorType = type.isThrottling ? .throttling : type.fault.retryErrorType
return .init(errorType: errorType, retryAfterHint: hint, isTimeout: false)
} else if let code = (error as? HTTPError)?.httpResponse.statusCode, retryableStatusCodes.contains(code) {
return .init(errorType: .serverError, retryAfterHint: hint, isTimeout: false)
}
return nil
}
Expand Down
Loading

0 comments on commit c695be9

Please sign in to comment.