From c117bd830435eac35bec7f13230c646325c5a4b8 Mon Sep 17 00:00:00 2001 From: Nakul Bajaj Date: Thu, 21 May 2026 10:26:59 -0700 Subject: [PATCH 1/2] Abstract API: add declarative TLS request option to AHC and DefaultHTTPClient --- Package.swift | 2 ++ Sources/AHCHTTPClient/AHC+HTTPClient.swift | 22 +++++++++++++++++-- ...HTTPClientCapability+DeclarativeTLS.swift} | 2 ++ Sources/HTTPAPIs/HTTP.swift | 1 + Sources/HTTPClient/DefaultHTTPClient.swift | 6 ++--- Sources/HTTPClient/HTTPRequestOptions.swift | 7 +++++- .../TrustEvaluationPolicy.swift | 0 ...PClientCapability+TLSSecurityHandler.swift | 1 + 8 files changed, 35 insertions(+), 6 deletions(-) rename Sources/{URLSessionHTTPClient/HTTPClientCapability+DeclarativeTLSHandler.swift => HTTPAPIs/Client/HTTPClientCapability+DeclarativeTLS.swift} (96%) rename Sources/{URLSessionHTTPClient => NetworkTypes}/TrustEvaluationPolicy.swift (100%) diff --git a/Package.swift b/Package.swift index de42a4c..3547ac2 100644 --- a/Package.swift +++ b/Package.swift @@ -73,6 +73,7 @@ let package = Package( dependencies: [ "AHCHTTPClient", "URLSessionHTTPClient", + "NetworkTypes", .product(name: "AsyncHTTPClient", package: "async-http-client"), ], swiftSettings: extraSettings @@ -96,6 +97,7 @@ let package = Package( .product(name: "AsyncHTTPClient", package: "async-http-client"), .product(name: "NIOHTTP1", package: "swift-nio"), + .product(name: "NIOSSL", package: "swift-nio-ssl"), ], swiftSettings: extraSettings ), diff --git a/Sources/AHCHTTPClient/AHC+HTTPClient.swift b/Sources/AHCHTTPClient/AHC+HTTPClient.swift index 5500e63..5c3e5c6 100644 --- a/Sources/AHCHTTPClient/AHC+HTTPClient.swift +++ b/Sources/AHCHTTPClient/AHC+HTTPClient.swift @@ -18,6 +18,8 @@ import Foundation import HTTPTypes import NIOCore import NIOHTTP1 +import NIOSSL +public import NetworkTypes import Synchronization @available(anyAppleOS 26.0, *) @@ -25,8 +27,8 @@ extension AsyncHTTPClient.HTTPClient: HTTPAPIs.HTTPClient { public typealias RequestWriter = RequestBodyWriter public typealias ResponseConcludingReader = ResponseReader - public struct RequestOptions: HTTPClientCapability.RequestOptions { - + public struct RequestOptions: HTTPClientCapability.DeclarativeTLS { + public var serverTrustPolicy: TrustEvaluationPolicy = .default } public struct RequestBodyWriter: AsyncWriter, ~Copyable { @@ -163,6 +165,7 @@ extension AsyncHTTPClient.HTTPClient: HTTPAPIs.HTTPClient { let sequence = request.headerFields.lazy.map({ ($0.name.rawName, $0.value) }) ahcRequest.headers.add(contentsOf: sequence) } + ahcRequest.tlsConfiguration = Self.tlsConfiguration(for: options.serverTrustPolicy) if let body, body.knownLength != 0 { let (asyncStream, startUploadContinuation) = AsyncStream.makeStream(of: HTTPClientRequest.Body.RequestWriter.self) @@ -217,4 +220,19 @@ extension AsyncHTTPClient.HTTPClient: HTTPAPIs.HTTPClient { return try result!.get() } + + private static func tlsConfiguration(for policy: TrustEvaluationPolicy) -> TLSConfiguration? { + switch policy { + case .default: + return nil + case .allowNameMismatch: + var config = TLSConfiguration.makeClientConfiguration() + config.certificateVerification = .noHostnameVerification + return config + case .allowAny: + var config = TLSConfiguration.makeClientConfiguration() + config.certificateVerification = .none + return config + } + } } diff --git a/Sources/URLSessionHTTPClient/HTTPClientCapability+DeclarativeTLSHandler.swift b/Sources/HTTPAPIs/Client/HTTPClientCapability+DeclarativeTLS.swift similarity index 96% rename from Sources/URLSessionHTTPClient/HTTPClientCapability+DeclarativeTLSHandler.swift rename to Sources/HTTPAPIs/Client/HTTPClientCapability+DeclarativeTLS.swift index 894c295..8c07b28 100644 --- a/Sources/URLSessionHTTPClient/HTTPClientCapability+DeclarativeTLSHandler.swift +++ b/Sources/HTTPAPIs/Client/HTTPClientCapability+DeclarativeTLS.swift @@ -11,6 +11,8 @@ // //===----------------------------------------------------------------------===// +public import NetworkTypes + @available(anyAppleOS 26.0, *) extension HTTPClientCapability { /// A protocol for HTTP request options that support TLS policies. diff --git a/Sources/HTTPAPIs/HTTP.swift b/Sources/HTTPAPIs/HTTP.swift index 9ceab1c..e98e2f3 100644 --- a/Sources/HTTPAPIs/HTTP.swift +++ b/Sources/HTTPAPIs/HTTP.swift @@ -14,6 +14,7 @@ @_exported public import AsyncStreaming @_exported public import ContainersPreview @_exported public import HTTPTypes +@_exported public import NetworkTypes /// The namespace for HTTP. public enum HTTP {} diff --git a/Sources/HTTPClient/DefaultHTTPClient.swift b/Sources/HTTPClient/DefaultHTTPClient.swift index 3d1d5d5..05bee49 100644 --- a/Sources/HTTPClient/DefaultHTTPClient.swift +++ b/Sources/HTTPClient/DefaultHTTPClient.swift @@ -139,12 +139,12 @@ public final class DefaultHTTPClient: HTTPAPIs.HTTPClient { options: HTTPRequestOptions, responseHandler: (HTTPResponse, consuming ResponseConcludingReader) async throws -> Return ) async throws -> Return { - // TODO: translate request options - let options = self.client.defaultRequestOptions + var actualOptions = self.client.defaultRequestOptions + actualOptions.serverTrustPolicy = options.serverTrustPolicy let body = body.map { HTTPClientRequestBody(other: $0) { RequestWriter(actual: $0) } } - return try await self.client.perform(request: request, body: body, options: options) { response, body in + return try await self.client.perform(request: request, body: body, options: actualOptions) { response, body in try await responseHandler(response, ResponseConcludingReader(actual: body)) } } diff --git a/Sources/HTTPClient/HTTPRequestOptions.swift b/Sources/HTTPClient/HTTPRequestOptions.swift index 9dd8c73..fd5472c 100644 --- a/Sources/HTTPClient/HTTPRequestOptions.swift +++ b/Sources/HTTPClient/HTTPRequestOptions.swift @@ -11,8 +11,13 @@ // //===----------------------------------------------------------------------===// +public import HTTPAPIs +public import NetworkTypes + /// The options for the default HTTP client implementation. @available(anyAppleOS 26.0, *) -public struct HTTPRequestOptions: HTTPClientCapability.RequestOptions { +public struct HTTPRequestOptions: HTTPClientCapability.DeclarativeTLS { + public var serverTrustPolicy: TrustEvaluationPolicy = .default + public init() {} } diff --git a/Sources/URLSessionHTTPClient/TrustEvaluationPolicy.swift b/Sources/NetworkTypes/TrustEvaluationPolicy.swift similarity index 100% rename from Sources/URLSessionHTTPClient/TrustEvaluationPolicy.swift rename to Sources/NetworkTypes/TrustEvaluationPolicy.swift diff --git a/Sources/URLSessionHTTPClient/HTTPClientCapability+TLSSecurityHandler.swift b/Sources/URLSessionHTTPClient/HTTPClientCapability+TLSSecurityHandler.swift index b4230f0..74bddde 100644 --- a/Sources/URLSessionHTTPClient/HTTPClientCapability+TLSSecurityHandler.swift +++ b/Sources/URLSessionHTTPClient/HTTPClientCapability+TLSSecurityHandler.swift @@ -13,6 +13,7 @@ #if canImport(Darwin) import Security +public import NetworkTypes @available(anyAppleOS 26.0, *) extension HTTPClientCapability { From d0127ddfc7d2c7a84c65b5f0763a765249a11a79 Mon Sep 17 00:00:00 2001 From: Nakul Bajaj Date: Thu, 21 May 2026 13:00:07 -0700 Subject: [PATCH 2/2] Remove extra public imports --- Package.swift | 1 - Sources/AHCHTTPClient/AHC+HTTPClient.swift | 1 - Sources/HTTPClient/HTTPRequestOptions.swift | 3 --- .../HTTPClientCapability+TLSSecurityHandler.swift | 1 - 4 files changed, 6 deletions(-) diff --git a/Package.swift b/Package.swift index 3547ac2..dace077 100644 --- a/Package.swift +++ b/Package.swift @@ -73,7 +73,6 @@ let package = Package( dependencies: [ "AHCHTTPClient", "URLSessionHTTPClient", - "NetworkTypes", .product(name: "AsyncHTTPClient", package: "async-http-client"), ], swiftSettings: extraSettings diff --git a/Sources/AHCHTTPClient/AHC+HTTPClient.swift b/Sources/AHCHTTPClient/AHC+HTTPClient.swift index 5c3e5c6..fa231db 100644 --- a/Sources/AHCHTTPClient/AHC+HTTPClient.swift +++ b/Sources/AHCHTTPClient/AHC+HTTPClient.swift @@ -19,7 +19,6 @@ import HTTPTypes import NIOCore import NIOHTTP1 import NIOSSL -public import NetworkTypes import Synchronization @available(anyAppleOS 26.0, *) diff --git a/Sources/HTTPClient/HTTPRequestOptions.swift b/Sources/HTTPClient/HTTPRequestOptions.swift index fd5472c..b651a46 100644 --- a/Sources/HTTPClient/HTTPRequestOptions.swift +++ b/Sources/HTTPClient/HTTPRequestOptions.swift @@ -11,9 +11,6 @@ // //===----------------------------------------------------------------------===// -public import HTTPAPIs -public import NetworkTypes - /// The options for the default HTTP client implementation. @available(anyAppleOS 26.0, *) public struct HTTPRequestOptions: HTTPClientCapability.DeclarativeTLS { diff --git a/Sources/URLSessionHTTPClient/HTTPClientCapability+TLSSecurityHandler.swift b/Sources/URLSessionHTTPClient/HTTPClientCapability+TLSSecurityHandler.swift index 74bddde..b4230f0 100644 --- a/Sources/URLSessionHTTPClient/HTTPClientCapability+TLSSecurityHandler.swift +++ b/Sources/URLSessionHTTPClient/HTTPClientCapability+TLSSecurityHandler.swift @@ -13,7 +13,6 @@ #if canImport(Darwin) import Security -public import NetworkTypes @available(anyAppleOS 26.0, *) extension HTTPClientCapability {