From a64435cc91fd71ddebdfbd4251bc2527f11f12cd Mon Sep 17 00:00:00 2001 From: Ian Saultz <52051793+atierian@users.noreply.github.com> Date: Tue, 19 Sep 2023 16:55:17 -0400 Subject: [PATCH 01/16] add initial foundationhttpclient --- .../FoundationHTTPClientEngine.swift | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine.swift diff --git a/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine.swift b/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine.swift new file mode 100644 index 0000000000..610766e771 --- /dev/null +++ b/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine.swift @@ -0,0 +1,80 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import Foundation +import ClientRuntime + +struct PlaceholderError: Error {} + +extension Foundation.URLRequest { + init(sdkRequest: ClientRuntime.SdkHttpRequest) throws { + guard let url = sdkRequest.endpoint.url else { throw PlaceholderError() } + self.init(url: url) + httpMethod = sdkRequest.method.rawValue + + for header in sdkRequest.headers.headers { + for value in header.value { + addValue(value, forHTTPHeaderField: header.name) + } + } + + httpBody = switch sdkRequest.body { + case .data(let data): data + case .stream(let stream): stream.toBytes().getData() + case .none: nil + } + } +} + +extension ClientRuntime.HttpResponse { + private static func headers( + from allHeaderFields: [AnyHashable: Any] + ) -> ClientRuntime.Headers { + var headers = Headers() + for header in allHeaderFields { + switch (header.key, header.value) { + case let (key, value) as (String, String): + headers.add(name: key, value: value) + case let (key, values) as (String, [String]): + headers.add(name: key, values: values) + default: continue + } + } + return headers + } + + convenience init(httpURLResponse: HTTPURLResponse, data: Data) { + let headers = Self.headers(from: httpURLResponse.allHeaderFields) + let body = HttpBody.data(data) + // fix force unwrap + let statusCode = HttpStatusCode(rawValue: httpURLResponse.statusCode)! + self.init(headers: headers, body: body, statusCode: statusCode) + } +} + +@_spi(FoundationHTTPClientEngine) +public struct FoundationHTTPClient: HttpClientEngine { + public func execute(request: ClientRuntime.SdkHttpRequest) async throws -> ClientRuntime.HttpResponse { + let urlRequest = try URLRequest(sdkRequest: request) + + let (data, response) = try await URLSession.shared.data(for: urlRequest) + // Quinn says it's ok to do this. + // Safely Force Downcasting a URLResponse to an HTTPURLResponse - + // https://developer.apple.com/forums/thread/120099?answerId=372749022#372749022 + let httpURLResponse = response as! HTTPURLResponse + + let httpResponse = HttpResponse( + httpURLResponse: httpURLResponse, + data: data + ) + + return httpResponse + } + + /// no-op + func close() async {} +} From ef88a47f4a6a049ce98f50c139ff68ad3e7b8067 Mon Sep 17 00:00:00 2001 From: Ian Saultz <52051793+atierian@users.noreply.github.com> Date: Tue, 19 Sep 2023 16:55:40 -0400 Subject: [PATCH 02/16] use foundationhttpclient in auth when applicable --- .../AWSCognitoAuthPlugin+Configure.swift | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/AWSCognitoAuthPlugin+Configure.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/AWSCognitoAuthPlugin+Configure.swift index 99895a0d3b..0824e8f51f 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/AWSCognitoAuthPlugin+Configure.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/AWSCognitoAuthPlugin+Configure.swift @@ -12,6 +12,7 @@ import AWSCognitoIdentity import AWSCognitoIdentityProvider import AWSPluginsCore import ClientRuntime +@_spi(FoundationHTTPClientEngine) import AWSPluginsCore extension AWSCognitoAuthPlugin { @@ -92,9 +93,18 @@ extension AWSCognitoAuthPlugin { ) if var httpClientEngineProxy = httpClientEngineProxy { - let sdkEngine = configuration.httpClientEngine - httpClientEngineProxy.target = sdkEngine + let httpClientEngine: HttpClientEngine + #if os(watchOS) || os(tvOS) + httpClientEngine = FoundationHTTPClient() + #else + httpClientEngine = configuration.httpClientEngine + #endif + httpClientEngineProxy.target = httpClientEngine configuration.httpClientEngine = httpClientEngineProxy + } else { + #if os(watchOS) || os(tvOS) + configuration.httpClientEngine = FoundationHTTPClient() + #endif } return CognitoIdentityProviderClient(config: configuration) @@ -110,6 +120,11 @@ extension AWSCognitoAuthPlugin { frameworkMetadata: AmplifyAWSServiceConfiguration.frameworkMetaData(), region: identityPoolConfig.region ) + + #if os(watchOS) || os(tvOS) + configuration.httpClientEngine = FoundationHTTPClient() + #endif + return CognitoIdentityClient(config: configuration) default: fatalError() From 01411c22556ad8e99d6f99cd614bb65b090f2c21 Mon Sep 17 00:00:00 2001 From: Ian Saultz <52051793+atierian@users.noreply.github.com> Date: Wed, 20 Sep 2023 13:10:03 -0400 Subject: [PATCH 03/16] add public init / fix http body response --- .../CustomHttpClientEngine/FoundationHTTPClientEngine.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine.swift b/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine.swift index 610766e771..b93936f2d1 100644 --- a/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine.swift +++ b/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine.swift @@ -49,7 +49,7 @@ extension ClientRuntime.HttpResponse { convenience init(httpURLResponse: HTTPURLResponse, data: Data) { let headers = Self.headers(from: httpURLResponse.allHeaderFields) - let body = HttpBody.data(data) + let body = HttpBody.stream(ByteStream.from(data: data)) // fix force unwrap let statusCode = HttpStatusCode(rawValue: httpURLResponse.statusCode)! self.init(headers: headers, body: body, statusCode: statusCode) @@ -75,6 +75,8 @@ public struct FoundationHTTPClient: HttpClientEngine { return httpResponse } + public init() {} + /// no-op func close() async {} } From 645bef010cd996e415bd60a340fa4dbab47d6db7 Mon Sep 17 00:00:00 2001 From: Ian Saultz <52051793+atierian@users.noreply.github.com> Date: Wed, 20 Sep 2023 13:41:09 -0400 Subject: [PATCH 04/16] add foundationclient to Geo --- .../AWSLocationGeoPlugin+Configure.swift | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/AmplifyPlugins/Geo/Sources/AWSLocationGeoPlugin/AWSLocationGeoPlugin+Configure.swift b/AmplifyPlugins/Geo/Sources/AWSLocationGeoPlugin/AWSLocationGeoPlugin+Configure.swift index be53fc1f45..fbc1f69593 100644 --- a/AmplifyPlugins/Geo/Sources/AWSLocationGeoPlugin/AWSLocationGeoPlugin+Configure.swift +++ b/AmplifyPlugins/Geo/Sources/AWSLocationGeoPlugin/AWSLocationGeoPlugin+Configure.swift @@ -5,10 +5,10 @@ // SPDX-License-Identifier: Apache-2.0 // +import Foundation import Amplify import AWSPluginsCore -import Foundation - +@_spi(FoundationHTTPClientEngine) import AWSPluginsCore import AWSLocation import AWSClientRuntime @@ -35,6 +35,11 @@ extension AWSLocationGeoPlugin { frameworkMetadata: AmplifyAWSServiceConfiguration.frameworkMetaData(), region: region) + #if os(watchOS) || os(tvOS) + // Use Foundation instead of CRT for networking on watchOS and tvOS + serviceConfiguration.httpClientEngine = FoundationHTTPClient() + #endif + let location = LocationClient(config: serviceConfiguration) let locationService = AWSLocationAdapter(location: location) From 89b1f008e8b30679b95bda9fcd6c90f6147acf18 Mon Sep 17 00:00:00 2001 From: Ian Saultz <52051793+atierian@users.noreply.github.com> Date: Wed, 20 Sep 2023 13:41:51 -0400 Subject: [PATCH 05/16] add foundationclient to cloudwatch logging --- .../AWSCloudWatchLoggingSessionController.swift | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/AWSCloudWatchLoggingSessionController.swift b/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/AWSCloudWatchLoggingSessionController.swift index 18d2483ffb..49e3cf3051 100644 --- a/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/AWSCloudWatchLoggingSessionController.swift +++ b/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/AWSCloudWatchLoggingSessionController.swift @@ -6,6 +6,7 @@ // import AWSPluginsCore +@_spi(FoundationHTTPClientEngine) import AWSPluginsCore import Amplify import Combine import Foundation @@ -107,6 +108,12 @@ final class AWSCloudWatchLoggingSessionController { frameworkMetadata: AmplifyAWSServiceConfiguration.frameworkMetaData(), region: region ) + + #if os(watchOS) || os(tvOS) + // Use Foundation instead of CRT for networking on watchOS and tvOS + configuration.httpClientEngine = FoundationHTTPClient() + #endif + self.client = CloudWatchLogsClient(config: configuration) } From db7765ce250db70ce4206333de8c3ea5c1eee96c Mon Sep 17 00:00:00 2001 From: Ian Saultz <52051793+atierian@users.noreply.github.com> Date: Wed, 20 Sep 2023 13:43:08 -0400 Subject: [PATCH 06/16] add foundationclient to predictions --- .../Predictions/AWSPredictionsService.swift | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/AmplifyPlugins/Predictions/AWSPredictionsPlugin/Service/Predictions/AWSPredictionsService.swift b/AmplifyPlugins/Predictions/AWSPredictionsPlugin/Service/Predictions/AWSPredictionsService.swift index ad7341fede..d2181b6387 100644 --- a/AmplifyPlugins/Predictions/AWSPredictionsPlugin/Service/Predictions/AWSPredictionsService.swift +++ b/AmplifyPlugins/Predictions/AWSPredictionsPlugin/Service/Predictions/AWSPredictionsService.swift @@ -12,6 +12,7 @@ import AWSTextract import AWSComprehend import AWSPolly import AWSPluginsCore +@_spi(FoundationHTTPClientEngine) import AWSPluginsCore import Foundation import ClientRuntime import AWSClientRuntime @@ -37,30 +38,50 @@ class AWSPredictionsService { credentialsProvider: credentialsProvider, region: configuration.convert.region ) + #if os(watchOS) || os(tvOS) + // Use Foundation instead of CRT for networking on watchOS and tvOS + translateClientConfiguration.httpClientEngine = FoundationHTTPClient() + #endif let awsTranslateClient = TranslateClient(config: translateClientConfiguration) let pollyClientConfiguration = try PollyClient.PollyClientConfiguration( credentialsProvider: credentialsProvider, region: configuration.convert.region ) + #if os(watchOS) || os(tvOS) + // Use Foundation instead of CRT for networking on watchOS and tvOS + pollyClientConfiguration.httpClientEngine = FoundationHTTPClient() + #endif let awsPollyClient = PollyClient(config: pollyClientConfiguration) let comprehendClientConfiguration = try ComprehendClient.ComprehendClientConfiguration( credentialsProvider: credentialsProvider, region: configuration.convert.region ) + #if os(watchOS) || os(tvOS) + // Use Foundation instead of CRT for networking on watchOS and tvOS + comprehendClientConfiguration.httpClientEngine = FoundationHTTPClient() + #endif let awsComprehendClient = ComprehendClient(config: comprehendClientConfiguration) let rekognitionClientConfiguration = try RekognitionClient.RekognitionClientConfiguration( credentialsProvider: credentialsProvider, region: configuration.identify.region ) + #if os(watchOS) || os(tvOS) + // Use Foundation instead of CRT for networking on watchOS and tvOS + rekognitionClientConfiguration.httpClientEngine = FoundationHTTPClient() + #endif let awsRekognitionClient = RekognitionClient(config: rekognitionClientConfiguration) let textractClientConfiguration = try TextractClient.TextractClientConfiguration( credentialsProvider: credentialsProvider, region: configuration.identify.region ) + #if os(watchOS) || os(tvOS) + // Use Foundation instead of CRT for networking on watchOS and tvOS + textractClientConfiguration.httpClientEngine = FoundationHTTPClient() + #endif let awsTextractClient = TextractClient(config: textractClientConfiguration) let awsTranscribeStreamingAdapter = AWSTranscribeStreamingAdapter( From 2c3cf6dd5b4883a3a439fbc67f9ec6568bfe906a Mon Sep 17 00:00:00 2001 From: Ian Saultz <52051793+atierian@users.noreply.github.com> Date: Wed, 20 Sep 2023 13:43:42 -0400 Subject: [PATCH 07/16] add foundationclient to storage --- .../Service/Storage/AWSS3StorageService.swift | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService.swift b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService.swift index 415417bb5a..689076d3af 100644 --- a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService.swift +++ b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService.swift @@ -10,6 +10,8 @@ import Foundation import AWSS3 import Amplify import AWSPluginsCore +@_spi(FoundationHTTPClientEngine) import AWSPluginsCore +import ClientRuntime /// - Tag: AWSS3StorageService class AWSS3StorageService: AWSS3StorageServiceBehavior, StorageServiceProxy { @@ -61,9 +63,20 @@ class AWSS3StorageService: AWSS3StorageServiceBehavior, StorageServiceProxy { credentialsProvider: credentialsProvider, region: region, signingRegion: region) + if var proxy = httpClientEngineProxy { - proxy.target = clientConfig.httpClientEngine + let httpClientEngine: HttpClientEngine + #if os(watchOS) || os(tvOS) + httpClientEngine = FoundationHTTPClient() + #else + httpClientEngine = clientConfig.httpClientEngine + #endif + proxy.target = httpClientEngine clientConfig.httpClientEngine = proxy + } else { + #if os(watchOS) || os(tvOS) + clientConfig.httpClientEngine = FoundationHTTPClient() + #endif } let s3Client = S3Client(config: clientConfig) From a9e7ad8d4b044dfab54b4a7c5e0a47a302d795eb Mon Sep 17 00:00:00 2001 From: Ian Saultz <52051793+atierian@users.noreply.github.com> Date: Wed, 20 Sep 2023 13:44:23 -0400 Subject: [PATCH 08/16] add foundationclient to internalpinpoint --- .../Support/Utils/PinpointRequestsRegistry.swift | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Support/Utils/PinpointRequestsRegistry.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Support/Utils/PinpointRequestsRegistry.swift index 8c0aeba4a3..4a07bdaf36 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Support/Utils/PinpointRequestsRegistry.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Support/Utils/PinpointRequestsRegistry.swift @@ -8,6 +8,7 @@ import Foundation import AWSPinpoint import ClientRuntime +@_spi(FoundationHTTPClientEngine) import AWSPluginsCore @globalActor actor PinpointRequestsRegistry { static let shared = PinpointRequestsRegistry() @@ -20,9 +21,16 @@ import ClientRuntime } nonisolated func setCustomHttpEngine(on configuration: PinpointClient.PinpointClientConfiguration) { - let oldHttpClientEngine = configuration.httpClientEngine + let baseHTTPClientEngine: HttpClientEngine + #if os(watchOS) || os(tvOS) + // Use Foundation instead of CRT for networking on watchOS and tvOS + baseHTTPClientEngine = FoundationHTTPClient() + #else + baseHTTPClientEngine = configuration.httpClientEngine + #endif + configuration.httpClientEngine = CustomPinpointHttpClientEngine( - httpClientEngine: oldHttpClientEngine + httpClientEngine: baseHTTPClientEngine ) } From 7cb4832ab5f555bf43847caa5e4fcc7d61f9c51a Mon Sep 17 00:00:00 2001 From: Ian Saultz <52051793+atierian@users.noreply.github.com> Date: Wed, 20 Sep 2023 15:04:30 -0400 Subject: [PATCH 09/16] switch expressions are 5.9 :( --- .../FoundationHTTPClientEngine.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine.swift b/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine.swift index b93936f2d1..6ccac4f3b8 100644 --- a/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine.swift +++ b/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine.swift @@ -22,10 +22,10 @@ extension Foundation.URLRequest { } } - httpBody = switch sdkRequest.body { - case .data(let data): data - case .stream(let stream): stream.toBytes().getData() - case .none: nil + switch sdkRequest.body { + case .data(let data): httpBody = data + case .stream(let stream): httpBody = stream.toBytes().getData() + case .none: break } } } From be5700cc0b0e68fb6fe09bfc9bd3ec26776ac261 Mon Sep 17 00:00:00 2001 From: Ian Saultz <52051793+atierian@users.noreply.github.com> Date: Wed, 20 Sep 2023 16:20:13 -0400 Subject: [PATCH 10/16] update pinpointclient --- .../Extensions/PinpointClient+CredentialsProvider.swift | 5 +++++ .../Support/Utils/PinpointRequestsRegistry.swift | 9 +-------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Extensions/PinpointClient+CredentialsProvider.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Extensions/PinpointClient+CredentialsProvider.swift index f3ff0b4f70..c9f03937bd 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Extensions/PinpointClient+CredentialsProvider.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Extensions/PinpointClient+CredentialsProvider.swift @@ -8,6 +8,7 @@ import AWSClientRuntime import AWSPluginsCore import AWSPinpoint +@_spi(FoundationHTTPClientEngine) import AWSPluginsCore extension PinpointClient { convenience init(region: String, credentialsProvider: CredentialsProvider) throws { @@ -16,6 +17,10 @@ extension PinpointClient { frameworkMetadata: AmplifyAWSServiceConfiguration.frameworkMetaData(), region: region ) + #if os(watchOS) || os(tvOS) + // Use Foundation instead of CRT for networking on watchOS and tvOS + configuration.httpClientEngine = FoundationHTTPClient() + #endif PinpointRequestsRegistry.shared.setCustomHttpEngine(on: configuration) self.init(config: configuration) } diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Support/Utils/PinpointRequestsRegistry.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Support/Utils/PinpointRequestsRegistry.swift index 4a07bdaf36..7bcd61a0a5 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Support/Utils/PinpointRequestsRegistry.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Support/Utils/PinpointRequestsRegistry.swift @@ -8,7 +8,6 @@ import Foundation import AWSPinpoint import ClientRuntime -@_spi(FoundationHTTPClientEngine) import AWSPluginsCore @globalActor actor PinpointRequestsRegistry { static let shared = PinpointRequestsRegistry() @@ -21,13 +20,7 @@ import ClientRuntime } nonisolated func setCustomHttpEngine(on configuration: PinpointClient.PinpointClientConfiguration) { - let baseHTTPClientEngine: HttpClientEngine - #if os(watchOS) || os(tvOS) - // Use Foundation instead of CRT for networking on watchOS and tvOS - baseHTTPClientEngine = FoundationHTTPClient() - #else - baseHTTPClientEngine = configuration.httpClientEngine - #endif + let baseHTTPClientEngine = configuration.httpClientEngine configuration.httpClientEngine = CustomPinpointHttpClientEngine( httpClientEngine: baseHTTPClientEngine From 6802f8c6cac06b3d44709eb972b1d94ea9094247 Mon Sep 17 00:00:00 2001 From: Ian Saultz <52051793+atierian@users.noreply.github.com> Date: Wed, 20 Sep 2023 17:34:54 -0400 Subject: [PATCH 11/16] use an applicable error / remove placeholder --- .../FoundationHTTPClientEngine.swift | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine.swift b/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine.swift index 6ccac4f3b8..5e5bc6835a 100644 --- a/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine.swift +++ b/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine.swift @@ -7,12 +7,42 @@ import Foundation import ClientRuntime +import Amplify -struct PlaceholderError: Error {} +struct InvalidRequestURL: AmplifyError { + let errorDescription: ErrorDescription + let recoverySuggestion: RecoverySuggestion + let underlyingError: Error? + + init(sdkRequest: ClientRuntime.SdkHttpRequest) { + self.errorDescription = """ + The SdkHttpRequest generated by ClientRuntime doesn't include a valid URL + - \(sdkRequest) + """ + self.recoverySuggestion = """ + Please open an issue at https://github.com/aws-amplify/amplify-swift + with the contents of this error message. + """ + self.underlyingError = nil + } + + // Protocol requirement + init( + errorDescription: ErrorDescription, + recoverySuggestion: RecoverySuggestion, + error: Error + ) { + self.errorDescription = errorDescription + self.recoverySuggestion = recoverySuggestion + self.underlyingError = error + } +} extension Foundation.URLRequest { init(sdkRequest: ClientRuntime.SdkHttpRequest) throws { - guard let url = sdkRequest.endpoint.url else { throw PlaceholderError() } + guard let url = sdkRequest.endpoint.url else { + throw InvalidRequestURL(sdkRequest: sdkRequest) + } self.init(url: url) httpMethod = sdkRequest.method.rawValue From a2b0b6392ab4be09ad3e5049de236c0c2002d9f7 Mon Sep 17 00:00:00 2001 From: Ian Saultz <52051793+atierian@users.noreply.github.com> Date: Wed, 20 Sep 2023 18:09:18 -0400 Subject: [PATCH 12/16] split out some files and clean up error handling in foundation client --- .../ClientRuntimeFoundationBridge.swift | 64 ++++++++++++++ .../FoundationHTTPClientEngine+Error.swift | 81 +++++++++++++++++ .../FoundationHTTPClientEngine.swift | 87 ++----------------- 3 files changed, 151 insertions(+), 81 deletions(-) create mode 100644 AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/ClientRuntimeFoundationBridge.swift create mode 100644 AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine+Error.swift diff --git a/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/ClientRuntimeFoundationBridge.swift b/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/ClientRuntimeFoundationBridge.swift new file mode 100644 index 0000000000..113acb5e16 --- /dev/null +++ b/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/ClientRuntimeFoundationBridge.swift @@ -0,0 +1,64 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import Foundation +import ClientRuntime + +extension Foundation.URLRequest { + init(sdkRequest: ClientRuntime.SdkHttpRequest) throws { + guard let url = sdkRequest.endpoint.url else { + throw FoundationHTTPClientError.invalidRequestURL(sdkRequest: sdkRequest) + } + self.init(url: url) + httpMethod = sdkRequest.method.rawValue + + for header in sdkRequest.headers.headers { + for value in header.value { + addValue(value, forHTTPHeaderField: header.name) + } + } + + switch sdkRequest.body { + case .data(let data): httpBody = data + case .stream(let stream): httpBody = stream.toBytes().getData() + case .none: break + } + } +} + +extension ClientRuntime.HttpResponse { + private static func headers( + from allHeaderFields: [AnyHashable: Any] + ) -> ClientRuntime.Headers { + var headers = Headers() + for header in allHeaderFields { + switch (header.key, header.value) { + case let (key, value) as (String, String): + headers.add(name: key, value: value) + case let (key, values) as (String, [String]): + headers.add(name: key, values: values) + default: continue + } + } + return headers + } + + convenience init(httpURLResponse: HTTPURLResponse, data: Data) throws { + let headers = Self.headers(from: httpURLResponse.allHeaderFields) + let body = HttpBody.stream(ByteStream.from(data: data)) + + guard let statusCode = HttpStatusCode(rawValue: httpURLResponse.statusCode) else { + // This shouldn't happen, but `HttpStatusCode` only exposes a failable + // `init`. The alternative here is force unwrapping, but we can't + // make the decision to crash here on behalf on consuming applications. + throw FoundationHTTPClientError.unexpectedStatusCode( + statusCode: httpURLResponse.statusCode + ) + } + self.init(headers: headers, body: body, statusCode: statusCode) + } +} diff --git a/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine+Error.swift b/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine+Error.swift new file mode 100644 index 0000000000..362bcf803c --- /dev/null +++ b/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine+Error.swift @@ -0,0 +1,81 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import Foundation +import Amplify +import ClientRuntime + +struct FoundationHTTPClientError: AmplifyError { + let errorDescription: ErrorDescription + let recoverySuggestion: RecoverySuggestion + let underlyingError: Error? + + // protocol requirement + init( + errorDescription: ErrorDescription, + recoverySuggestion: RecoverySuggestion, + error: Error + ) { + self.errorDescription = errorDescription + self.recoverySuggestion = recoverySuggestion + self.underlyingError = error + } +} + +extension FoundationHTTPClientError { + init( + errorDescription: ErrorDescription, + recoverySuggestion: RecoverySuggestion, + error: Error? + ) { + self.errorDescription = errorDescription + self.recoverySuggestion = recoverySuggestion + self.underlyingError = error + } + + static func invalidRequestURL(sdkRequest: ClientRuntime.SdkHttpRequest) -> Self { + .init( + errorDescription: """ + The SdkHttpRequest generated by ClientRuntime doesn't include a valid URL + - \(sdkRequest) + """, + recoverySuggestion: """ + Please open an issue at https://github.com/aws-amplify/amplify-swift + with the contents of this error message. + """, + error: nil + ) + } + + static func invalidURLResponse(urlRequest: URLResponse) -> Self { + .init( + errorDescription: """ + The URLResponse received is not an HTTPURLResponse + - \(urlRequest) + """, + recoverySuggestion: """ + Please open an issue at https://github.com/aws-amplify/amplify-swift + with the contents of this error message. + """, + error: nil + ) + } + + static func unexpectedStatusCode(statusCode: Int) -> Self { + .init( + errorDescription: """ + The status code received isn't a valid `HttpStatusCode` value. + - status code: \(statusCode) + """, + recoverySuggestion: """ + Please open an issue at https://github.com/aws-amplify/amplify-swift + with the contents of this error message. + """, + error: nil + ) + } +} diff --git a/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine.swift b/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine.swift index 5e5bc6835a..03dfc5abb1 100644 --- a/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine.swift +++ b/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine.swift @@ -9,93 +9,18 @@ import Foundation import ClientRuntime import Amplify -struct InvalidRequestURL: AmplifyError { - let errorDescription: ErrorDescription - let recoverySuggestion: RecoverySuggestion - let underlyingError: Error? - - init(sdkRequest: ClientRuntime.SdkHttpRequest) { - self.errorDescription = """ - The SdkHttpRequest generated by ClientRuntime doesn't include a valid URL - - \(sdkRequest) - """ - self.recoverySuggestion = """ - Please open an issue at https://github.com/aws-amplify/amplify-swift - with the contents of this error message. - """ - self.underlyingError = nil - } - - // Protocol requirement - init( - errorDescription: ErrorDescription, - recoverySuggestion: RecoverySuggestion, - error: Error - ) { - self.errorDescription = errorDescription - self.recoverySuggestion = recoverySuggestion - self.underlyingError = error - } -} - -extension Foundation.URLRequest { - init(sdkRequest: ClientRuntime.SdkHttpRequest) throws { - guard let url = sdkRequest.endpoint.url else { - throw InvalidRequestURL(sdkRequest: sdkRequest) - } - self.init(url: url) - httpMethod = sdkRequest.method.rawValue - - for header in sdkRequest.headers.headers { - for value in header.value { - addValue(value, forHTTPHeaderField: header.name) - } - } - - switch sdkRequest.body { - case .data(let data): httpBody = data - case .stream(let stream): httpBody = stream.toBytes().getData() - case .none: break - } - } -} - -extension ClientRuntime.HttpResponse { - private static func headers( - from allHeaderFields: [AnyHashable: Any] - ) -> ClientRuntime.Headers { - var headers = Headers() - for header in allHeaderFields { - switch (header.key, header.value) { - case let (key, value) as (String, String): - headers.add(name: key, value: value) - case let (key, values) as (String, [String]): - headers.add(name: key, values: values) - default: continue - } - } - return headers - } - - convenience init(httpURLResponse: HTTPURLResponse, data: Data) { - let headers = Self.headers(from: httpURLResponse.allHeaderFields) - let body = HttpBody.stream(ByteStream.from(data: data)) - // fix force unwrap - let statusCode = HttpStatusCode(rawValue: httpURLResponse.statusCode)! - self.init(headers: headers, body: body, statusCode: statusCode) - } -} - @_spi(FoundationHTTPClientEngine) public struct FoundationHTTPClient: HttpClientEngine { public func execute(request: ClientRuntime.SdkHttpRequest) async throws -> ClientRuntime.HttpResponse { let urlRequest = try URLRequest(sdkRequest: request) let (data, response) = try await URLSession.shared.data(for: urlRequest) - // Quinn says it's ok to do this. - // Safely Force Downcasting a URLResponse to an HTTPURLResponse - - // https://developer.apple.com/forums/thread/120099?answerId=372749022#372749022 - let httpURLResponse = response as! HTTPURLResponse + guard let httpURLResponse = response as? HTTPURLResponse else { + // This shouldn't be necessary because we're only making HTTP requests. + // `URLResponse` should always be a `HTTPURLResponse`. + // But to refrain from crashing consuming applications, we're throwing here. + throw FoundationHTTPClientError.invalidURLResponse(urlRequest: response) + } let httpResponse = HttpResponse( httpURLResponse: httpURLResponse, From 2d0711fb82fbdca182b45cdb637ea82ccb00fae1 Mon Sep 17 00:00:00 2001 From: Ian Saultz <52051793+atierian@users.noreply.github.com> Date: Wed, 20 Sep 2023 18:12:21 -0400 Subject: [PATCH 13/16] rename FoundationHTTPClient to FoundationClientEngine for parity with prior art --- .../AWSCognitoAuthPlugin+Configure.swift | 8 ++++---- .../ClientRuntimeFoundationBridge.swift | 4 ++-- .../FoundationHTTPClientEngine+Error.swift | 4 ++-- .../FoundationHTTPClientEngine.swift | 6 +++--- .../AWSLocationGeoPlugin+Configure.swift | 4 ++-- .../PinpointClient+CredentialsProvider.swift | 4 ++-- .../AWSCloudWatchLoggingSessionController.swift | 4 ++-- .../Service/Predictions/AWSPredictionsService.swift | 12 ++++++------ .../Service/Storage/AWSS3StorageService.swift | 6 +++--- 9 files changed, 26 insertions(+), 26 deletions(-) diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/AWSCognitoAuthPlugin+Configure.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/AWSCognitoAuthPlugin+Configure.swift index 0824e8f51f..a6d8d678de 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/AWSCognitoAuthPlugin+Configure.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/AWSCognitoAuthPlugin+Configure.swift @@ -12,7 +12,7 @@ import AWSCognitoIdentity import AWSCognitoIdentityProvider import AWSPluginsCore import ClientRuntime -@_spi(FoundationHTTPClientEngine) import AWSPluginsCore +@_spi(FoundationClientEngine) import AWSPluginsCore extension AWSCognitoAuthPlugin { @@ -95,7 +95,7 @@ extension AWSCognitoAuthPlugin { if var httpClientEngineProxy = httpClientEngineProxy { let httpClientEngine: HttpClientEngine #if os(watchOS) || os(tvOS) - httpClientEngine = FoundationHTTPClient() + httpClientEngine = FoundationClientEngine() #else httpClientEngine = configuration.httpClientEngine #endif @@ -103,7 +103,7 @@ extension AWSCognitoAuthPlugin { configuration.httpClientEngine = httpClientEngineProxy } else { #if os(watchOS) || os(tvOS) - configuration.httpClientEngine = FoundationHTTPClient() + configuration.httpClientEngine = FoundationClientEngine() #endif } @@ -122,7 +122,7 @@ extension AWSCognitoAuthPlugin { ) #if os(watchOS) || os(tvOS) - configuration.httpClientEngine = FoundationHTTPClient() + configuration.httpClientEngine = FoundationClientEngine() #endif return CognitoIdentityClient(config: configuration) diff --git a/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/ClientRuntimeFoundationBridge.swift b/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/ClientRuntimeFoundationBridge.swift index 113acb5e16..b503ed5f3d 100644 --- a/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/ClientRuntimeFoundationBridge.swift +++ b/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/ClientRuntimeFoundationBridge.swift @@ -11,7 +11,7 @@ import ClientRuntime extension Foundation.URLRequest { init(sdkRequest: ClientRuntime.SdkHttpRequest) throws { guard let url = sdkRequest.endpoint.url else { - throw FoundationHTTPClientError.invalidRequestURL(sdkRequest: sdkRequest) + throw FoundationClientEngineError.invalidRequestURL(sdkRequest: sdkRequest) } self.init(url: url) httpMethod = sdkRequest.method.rawValue @@ -55,7 +55,7 @@ extension ClientRuntime.HttpResponse { // This shouldn't happen, but `HttpStatusCode` only exposes a failable // `init`. The alternative here is force unwrapping, but we can't // make the decision to crash here on behalf on consuming applications. - throw FoundationHTTPClientError.unexpectedStatusCode( + throw FoundationClientEngineError.unexpectedStatusCode( statusCode: httpURLResponse.statusCode ) } diff --git a/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine+Error.swift b/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine+Error.swift index 362bcf803c..09e6df49ef 100644 --- a/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine+Error.swift +++ b/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine+Error.swift @@ -9,7 +9,7 @@ import Foundation import Amplify import ClientRuntime -struct FoundationHTTPClientError: AmplifyError { +struct FoundationClientEngineError: AmplifyError { let errorDescription: ErrorDescription let recoverySuggestion: RecoverySuggestion let underlyingError: Error? @@ -26,7 +26,7 @@ struct FoundationHTTPClientError: AmplifyError { } } -extension FoundationHTTPClientError { +extension FoundationClientEngineError { init( errorDescription: ErrorDescription, recoverySuggestion: RecoverySuggestion, diff --git a/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine.swift b/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine.swift index 03dfc5abb1..c7554a2025 100644 --- a/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine.swift +++ b/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine.swift @@ -9,8 +9,8 @@ import Foundation import ClientRuntime import Amplify -@_spi(FoundationHTTPClientEngine) -public struct FoundationHTTPClient: HttpClientEngine { +@_spi(FoundationClientEngine) +public struct FoundationClientEngine: HttpClientEngine { public func execute(request: ClientRuntime.SdkHttpRequest) async throws -> ClientRuntime.HttpResponse { let urlRequest = try URLRequest(sdkRequest: request) @@ -19,7 +19,7 @@ public struct FoundationHTTPClient: HttpClientEngine { // This shouldn't be necessary because we're only making HTTP requests. // `URLResponse` should always be a `HTTPURLResponse`. // But to refrain from crashing consuming applications, we're throwing here. - throw FoundationHTTPClientError.invalidURLResponse(urlRequest: response) + throw FoundationClientEngineError.invalidURLResponse(urlRequest: response) } let httpResponse = HttpResponse( diff --git a/AmplifyPlugins/Geo/Sources/AWSLocationGeoPlugin/AWSLocationGeoPlugin+Configure.swift b/AmplifyPlugins/Geo/Sources/AWSLocationGeoPlugin/AWSLocationGeoPlugin+Configure.swift index fbc1f69593..d2dddeffc5 100644 --- a/AmplifyPlugins/Geo/Sources/AWSLocationGeoPlugin/AWSLocationGeoPlugin+Configure.swift +++ b/AmplifyPlugins/Geo/Sources/AWSLocationGeoPlugin/AWSLocationGeoPlugin+Configure.swift @@ -8,7 +8,7 @@ import Foundation import Amplify import AWSPluginsCore -@_spi(FoundationHTTPClientEngine) import AWSPluginsCore +@_spi(FoundationClientEngine) import AWSPluginsCore import AWSLocation import AWSClientRuntime @@ -37,7 +37,7 @@ extension AWSLocationGeoPlugin { #if os(watchOS) || os(tvOS) // Use Foundation instead of CRT for networking on watchOS and tvOS - serviceConfiguration.httpClientEngine = FoundationHTTPClient() + serviceConfiguration.httpClientEngine = FoundationClientEngine() #endif let location = LocationClient(config: serviceConfiguration) diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Extensions/PinpointClient+CredentialsProvider.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Extensions/PinpointClient+CredentialsProvider.swift index c9f03937bd..e911db23a3 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Extensions/PinpointClient+CredentialsProvider.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Extensions/PinpointClient+CredentialsProvider.swift @@ -8,7 +8,7 @@ import AWSClientRuntime import AWSPluginsCore import AWSPinpoint -@_spi(FoundationHTTPClientEngine) import AWSPluginsCore +@_spi(FoundationClientEngine) import AWSPluginsCore extension PinpointClient { convenience init(region: String, credentialsProvider: CredentialsProvider) throws { @@ -19,7 +19,7 @@ extension PinpointClient { ) #if os(watchOS) || os(tvOS) // Use Foundation instead of CRT for networking on watchOS and tvOS - configuration.httpClientEngine = FoundationHTTPClient() + configuration.httpClientEngine = FoundationClientEngine() #endif PinpointRequestsRegistry.shared.setCustomHttpEngine(on: configuration) self.init(config: configuration) diff --git a/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/AWSCloudWatchLoggingSessionController.swift b/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/AWSCloudWatchLoggingSessionController.swift index 49e3cf3051..07fcfc20b6 100644 --- a/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/AWSCloudWatchLoggingSessionController.swift +++ b/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/AWSCloudWatchLoggingSessionController.swift @@ -6,7 +6,7 @@ // import AWSPluginsCore -@_spi(FoundationHTTPClientEngine) import AWSPluginsCore +@_spi(FoundationClientEngine) import AWSPluginsCore import Amplify import Combine import Foundation @@ -111,7 +111,7 @@ final class AWSCloudWatchLoggingSessionController { #if os(watchOS) || os(tvOS) // Use Foundation instead of CRT for networking on watchOS and tvOS - configuration.httpClientEngine = FoundationHTTPClient() + configuration.httpClientEngine = FoundationClientEngine() #endif self.client = CloudWatchLogsClient(config: configuration) diff --git a/AmplifyPlugins/Predictions/AWSPredictionsPlugin/Service/Predictions/AWSPredictionsService.swift b/AmplifyPlugins/Predictions/AWSPredictionsPlugin/Service/Predictions/AWSPredictionsService.swift index d2181b6387..5fd33ad9f9 100644 --- a/AmplifyPlugins/Predictions/AWSPredictionsPlugin/Service/Predictions/AWSPredictionsService.swift +++ b/AmplifyPlugins/Predictions/AWSPredictionsPlugin/Service/Predictions/AWSPredictionsService.swift @@ -12,7 +12,7 @@ import AWSTextract import AWSComprehend import AWSPolly import AWSPluginsCore -@_spi(FoundationHTTPClientEngine) import AWSPluginsCore +@_spi(FoundationClientEngine) import AWSPluginsCore import Foundation import ClientRuntime import AWSClientRuntime @@ -40,7 +40,7 @@ class AWSPredictionsService { ) #if os(watchOS) || os(tvOS) // Use Foundation instead of CRT for networking on watchOS and tvOS - translateClientConfiguration.httpClientEngine = FoundationHTTPClient() + translateClientConfiguration.httpClientEngine = FoundationClientEngine() #endif let awsTranslateClient = TranslateClient(config: translateClientConfiguration) @@ -50,7 +50,7 @@ class AWSPredictionsService { ) #if os(watchOS) || os(tvOS) // Use Foundation instead of CRT for networking on watchOS and tvOS - pollyClientConfiguration.httpClientEngine = FoundationHTTPClient() + pollyClientConfiguration.httpClientEngine = FoundationClientEngine() #endif let awsPollyClient = PollyClient(config: pollyClientConfiguration) @@ -60,7 +60,7 @@ class AWSPredictionsService { ) #if os(watchOS) || os(tvOS) // Use Foundation instead of CRT for networking on watchOS and tvOS - comprehendClientConfiguration.httpClientEngine = FoundationHTTPClient() + comprehendClientConfiguration.httpClientEngine = FoundationClientEngine() #endif let awsComprehendClient = ComprehendClient(config: comprehendClientConfiguration) @@ -70,7 +70,7 @@ class AWSPredictionsService { ) #if os(watchOS) || os(tvOS) // Use Foundation instead of CRT for networking on watchOS and tvOS - rekognitionClientConfiguration.httpClientEngine = FoundationHTTPClient() + rekognitionClientConfiguration.httpClientEngine = FoundationClientEngine() #endif let awsRekognitionClient = RekognitionClient(config: rekognitionClientConfiguration) @@ -80,7 +80,7 @@ class AWSPredictionsService { ) #if os(watchOS) || os(tvOS) // Use Foundation instead of CRT for networking on watchOS and tvOS - textractClientConfiguration.httpClientEngine = FoundationHTTPClient() + textractClientConfiguration.httpClientEngine = FoundationClientEngine() #endif let awsTextractClient = TextractClient(config: textractClientConfiguration) diff --git a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService.swift b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService.swift index 689076d3af..c21f951c43 100644 --- a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService.swift +++ b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService.swift @@ -10,7 +10,7 @@ import Foundation import AWSS3 import Amplify import AWSPluginsCore -@_spi(FoundationHTTPClientEngine) import AWSPluginsCore +@_spi(FoundationClientEngine) import AWSPluginsCore import ClientRuntime /// - Tag: AWSS3StorageService @@ -67,7 +67,7 @@ class AWSS3StorageService: AWSS3StorageServiceBehavior, StorageServiceProxy { if var proxy = httpClientEngineProxy { let httpClientEngine: HttpClientEngine #if os(watchOS) || os(tvOS) - httpClientEngine = FoundationHTTPClient() + httpClientEngine = FoundationClientEngine() #else httpClientEngine = clientConfig.httpClientEngine #endif @@ -75,7 +75,7 @@ class AWSS3StorageService: AWSS3StorageServiceBehavior, StorageServiceProxy { clientConfig.httpClientEngine = proxy } else { #if os(watchOS) || os(tvOS) - clientConfig.httpClientEngine = FoundationHTTPClient() + clientConfig.httpClientEngine = FoundationClientEngine() #endif } From fc38b44dd39dad03567b45f4ee3dbb0930009d0f Mon Sep 17 00:00:00 2001 From: Ian Saultz <52051793+atierian@users.noreply.github.com> Date: Wed, 20 Sep 2023 18:13:05 -0400 Subject: [PATCH 14/16] httpResponse convenience init now throws --- .../CustomHttpClientEngine/FoundationHTTPClientEngine.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine.swift b/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine.swift index c7554a2025..3bda16f9c1 100644 --- a/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine.swift +++ b/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine.swift @@ -22,7 +22,7 @@ public struct FoundationClientEngine: HttpClientEngine { throw FoundationClientEngineError.invalidURLResponse(urlRequest: response) } - let httpResponse = HttpResponse( + let httpResponse = try HttpResponse( httpURLResponse: httpURLResponse, data: data ) From fe2dd9d387ee104cd6fdf83666bea8d6ada04872 Mon Sep 17 00:00:00 2001 From: Ian Saultz <52051793+atierian@users.noreply.github.com> Date: Wed, 20 Sep 2023 18:17:08 -0400 Subject: [PATCH 15/16] rename files --- ...ndationHTTPClientEngine.swift => FoundationClientEngine.swift} | 0 ...ClientEngine+Error.swift => FoundationClientEngineError.swift} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/{FoundationHTTPClientEngine.swift => FoundationClientEngine.swift} (100%) rename AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/{FoundationHTTPClientEngine+Error.swift => FoundationClientEngineError.swift} (100%) diff --git a/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine.swift b/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationClientEngine.swift similarity index 100% rename from AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine.swift rename to AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationClientEngine.swift diff --git a/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine+Error.swift b/AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationClientEngineError.swift similarity index 100% rename from AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationHTTPClientEngine+Error.swift rename to AmplifyPlugins/Core/AWSPluginsCore/Utils/CustomHttpClientEngine/FoundationClientEngineError.swift From c9b6f3bbff5e2b97cc815f86b10105f75e76dad2 Mon Sep 17 00:00:00 2001 From: Ian Saultz <52051793+atierian@users.noreply.github.com> Date: Thu, 21 Sep 2023 12:06:25 -0400 Subject: [PATCH 16/16] inverse #if os checks --- .../AWSCognitoAuthPlugin+Configure.swift | 18 +++++++---- .../AWSLocationGeoPlugin+Configure.swift | 6 ++-- .../PinpointClient+CredentialsProvider.swift | 6 ++-- ...WSCloudWatchLoggingSessionController.swift | 6 ++-- .../Predictions/AWSPredictionsService.swift | 30 ++++++++++++------- .../Service/Storage/AWSS3StorageService.swift | 13 +++++--- 6 files changed, 54 insertions(+), 25 deletions(-) diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/AWSCognitoAuthPlugin+Configure.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/AWSCognitoAuthPlugin+Configure.swift index a6d8d678de..ae80ff67f2 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/AWSCognitoAuthPlugin+Configure.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/AWSCognitoAuthPlugin+Configure.swift @@ -94,15 +94,20 @@ extension AWSCognitoAuthPlugin { if var httpClientEngineProxy = httpClientEngineProxy { let httpClientEngine: HttpClientEngine - #if os(watchOS) || os(tvOS) - httpClientEngine = FoundationClientEngine() - #else + #if os(iOS) || os(macOS) + // networking goes through CRT httpClientEngine = configuration.httpClientEngine + #else + // networking goes through Foundation + httpClientEngine = FoundationClientEngine() #endif httpClientEngineProxy.target = httpClientEngine configuration.httpClientEngine = httpClientEngineProxy } else { - #if os(watchOS) || os(tvOS) + #if os(iOS) || os(macOS) // no-op + #else + // For any platform except iOS or macOS + // Use Foundation instead of CRT for networking. configuration.httpClientEngine = FoundationClientEngine() #endif } @@ -121,7 +126,10 @@ extension AWSCognitoAuthPlugin { region: identityPoolConfig.region ) - #if os(watchOS) || os(tvOS) + #if os(iOS) || os(macOS) // no-op + #else + // For any platform except iOS or macOS + // Use Foundation instead of CRT for networking. configuration.httpClientEngine = FoundationClientEngine() #endif diff --git a/AmplifyPlugins/Geo/Sources/AWSLocationGeoPlugin/AWSLocationGeoPlugin+Configure.swift b/AmplifyPlugins/Geo/Sources/AWSLocationGeoPlugin/AWSLocationGeoPlugin+Configure.swift index d2dddeffc5..c210cdd23f 100644 --- a/AmplifyPlugins/Geo/Sources/AWSLocationGeoPlugin/AWSLocationGeoPlugin+Configure.swift +++ b/AmplifyPlugins/Geo/Sources/AWSLocationGeoPlugin/AWSLocationGeoPlugin+Configure.swift @@ -35,8 +35,10 @@ extension AWSLocationGeoPlugin { frameworkMetadata: AmplifyAWSServiceConfiguration.frameworkMetaData(), region: region) - #if os(watchOS) || os(tvOS) - // Use Foundation instead of CRT for networking on watchOS and tvOS + #if os(iOS) || os(macOS) // no-op + #else + // For any platform except iOS or macOS + // Use Foundation instead of CRT for networking. serviceConfiguration.httpClientEngine = FoundationClientEngine() #endif diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Extensions/PinpointClient+CredentialsProvider.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Extensions/PinpointClient+CredentialsProvider.swift index e911db23a3..447d092b61 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Extensions/PinpointClient+CredentialsProvider.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Extensions/PinpointClient+CredentialsProvider.swift @@ -17,8 +17,10 @@ extension PinpointClient { frameworkMetadata: AmplifyAWSServiceConfiguration.frameworkMetaData(), region: region ) - #if os(watchOS) || os(tvOS) - // Use Foundation instead of CRT for networking on watchOS and tvOS + #if os(iOS) || os(macOS) // no-op + #else + // For any platform except iOS or macOS + // Use Foundation instead of CRT for networking. configuration.httpClientEngine = FoundationClientEngine() #endif PinpointRequestsRegistry.shared.setCustomHttpEngine(on: configuration) diff --git a/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/AWSCloudWatchLoggingSessionController.swift b/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/AWSCloudWatchLoggingSessionController.swift index 07fcfc20b6..b12e9c134e 100644 --- a/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/AWSCloudWatchLoggingSessionController.swift +++ b/AmplifyPlugins/Logging/Sources/AWSCloudWatchLoggingPlugin/AWSCloudWatchLoggingSessionController.swift @@ -109,8 +109,10 @@ final class AWSCloudWatchLoggingSessionController { region: region ) - #if os(watchOS) || os(tvOS) - // Use Foundation instead of CRT for networking on watchOS and tvOS + #if os(iOS) || os(macOS) // no-op + #else + // For any platform except iOS or macOS + // Use Foundation instead of CRT for networking. configuration.httpClientEngine = FoundationClientEngine() #endif diff --git a/AmplifyPlugins/Predictions/AWSPredictionsPlugin/Service/Predictions/AWSPredictionsService.swift b/AmplifyPlugins/Predictions/AWSPredictionsPlugin/Service/Predictions/AWSPredictionsService.swift index 5fd33ad9f9..08a3336789 100644 --- a/AmplifyPlugins/Predictions/AWSPredictionsPlugin/Service/Predictions/AWSPredictionsService.swift +++ b/AmplifyPlugins/Predictions/AWSPredictionsPlugin/Service/Predictions/AWSPredictionsService.swift @@ -38,8 +38,10 @@ class AWSPredictionsService { credentialsProvider: credentialsProvider, region: configuration.convert.region ) - #if os(watchOS) || os(tvOS) - // Use Foundation instead of CRT for networking on watchOS and tvOS + #if os(iOS) || os(macOS) // no-op + #else + // For any platform except iOS or macOS + // Use Foundation instead of CRT for networking. translateClientConfiguration.httpClientEngine = FoundationClientEngine() #endif let awsTranslateClient = TranslateClient(config: translateClientConfiguration) @@ -48,8 +50,10 @@ class AWSPredictionsService { credentialsProvider: credentialsProvider, region: configuration.convert.region ) - #if os(watchOS) || os(tvOS) - // Use Foundation instead of CRT for networking on watchOS and tvOS + #if os(iOS) || os(macOS) // no-op + #else + // For any platform except iOS or macOS + // Use Foundation instead of CRT for networking. pollyClientConfiguration.httpClientEngine = FoundationClientEngine() #endif let awsPollyClient = PollyClient(config: pollyClientConfiguration) @@ -58,8 +62,10 @@ class AWSPredictionsService { credentialsProvider: credentialsProvider, region: configuration.convert.region ) - #if os(watchOS) || os(tvOS) - // Use Foundation instead of CRT for networking on watchOS and tvOS + #if os(iOS) || os(macOS) // no-op + #else + // For any platform except iOS or macOS + // Use Foundation instead of CRT for networking. comprehendClientConfiguration.httpClientEngine = FoundationClientEngine() #endif let awsComprehendClient = ComprehendClient(config: comprehendClientConfiguration) @@ -68,8 +74,10 @@ class AWSPredictionsService { credentialsProvider: credentialsProvider, region: configuration.identify.region ) - #if os(watchOS) || os(tvOS) - // Use Foundation instead of CRT for networking on watchOS and tvOS + #if os(iOS) || os(macOS) // no-op + #else + // For any platform except iOS or macOS + // Use Foundation instead of CRT for networking. rekognitionClientConfiguration.httpClientEngine = FoundationClientEngine() #endif let awsRekognitionClient = RekognitionClient(config: rekognitionClientConfiguration) @@ -78,8 +86,10 @@ class AWSPredictionsService { credentialsProvider: credentialsProvider, region: configuration.identify.region ) - #if os(watchOS) || os(tvOS) - // Use Foundation instead of CRT for networking on watchOS and tvOS + #if os(iOS) || os(macOS) // no-op + #else + // For any platform except iOS or macOS + // Use Foundation instead of CRT for networking. textractClientConfiguration.httpClientEngine = FoundationClientEngine() #endif let awsTextractClient = TextractClient(config: textractClientConfiguration) diff --git a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService.swift b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService.swift index c21f951c43..58329ddb84 100644 --- a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService.swift +++ b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Service/Storage/AWSS3StorageService.swift @@ -66,15 +66,20 @@ class AWSS3StorageService: AWSS3StorageServiceBehavior, StorageServiceProxy { if var proxy = httpClientEngineProxy { let httpClientEngine: HttpClientEngine - #if os(watchOS) || os(tvOS) - httpClientEngine = FoundationClientEngine() - #else + #if os(iOS) || os(macOS) httpClientEngine = clientConfig.httpClientEngine + #else + // For any platform except iOS or macOS + // Use Foundation instead of CRT for networking. + httpClientEngine = FoundationClientEngine() #endif proxy.target = httpClientEngine clientConfig.httpClientEngine = proxy } else { - #if os(watchOS) || os(tvOS) + #if os(iOS) || os(macOS) // no-op + #else + // For any platform except iOS or macOS + // Use Foundation instead of CRT for networking. clientConfig.httpClientEngine = FoundationClientEngine() #endif }