Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 98 additions & 3 deletions Sources/ClientRuntime/Networking/Http/NIO/NIOHTTPClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,39 @@
import NIOCore
import NIOPosix
import NIOSSL
import SmithyHTTPAPI
import struct Smithy.Attributes
import struct Smithy.SwiftLogger
import protocol Smithy.LogAgent
import struct SmithyHTTPAPI.Headers
import protocol SmithyHTTPAPI.HTTPClient
import class SmithyHTTPAPI.HTTPResponse
import class SmithyHTTPAPI.HTTPRequest
import enum SmithyHTTPAPI.HTTPStatusCode
import protocol Smithy.ReadableStream
import enum Smithy.ByteStream
import class SmithyStreams.BufferedStream
import struct Foundation.Date
import AwsCommonRuntimeKit

/// AsyncHTTPClient-based HTTP client implementation that conforms to SmithyHTTPAPI.HTTPClient
/// This implementation is thread-safe and supports concurrent request execution.
public final class NIOHTTPClient: SmithyHTTPAPI.HTTPClient {
public static let noOpNIOHTTPClientTelemetry = HttpTelemetry(
httpScope: "NIOHTTPClient",
telemetryProvider: DefaultTelemetry.provider
)

private let client: AsyncHTTPClient.HTTPClient
private let config: HttpClientConfiguration
private let tlsConfiguration: NIOHTTPClientTLSOptions?
private let allocator: ByteBufferAllocator

/// HTTP Client Telemetry
private let telemetry: HttpTelemetry

/// Logger for HTTP-related events.
private var logger: LogAgent

/// Creates a new `NIOHTTPClient`.
///
/// The client is created with its own internal `AsyncHTTPClient`, which is configured with system defaults.
Expand All @@ -28,6 +51,8 @@
httpClientConfiguration: HttpClientConfiguration
) throws {
self.config = httpClientConfiguration
self.telemetry = httpClientConfiguration.telemetry ?? NIOHTTPClient.noOpNIOHTTPClientTelemetry
self.logger = self.telemetry.loggerProvider.getLogger(name: "NIOHTTPClient")
self.tlsConfiguration = httpClientConfiguration.tlsConfiguration as? NIOHTTPClientTLSOptions
self.allocator = ByteBufferAllocator()

Expand All @@ -42,7 +67,77 @@
}

public func send(request: SmithyHTTPAPI.HTTPRequest) async throws -> SmithyHTTPAPI.HTTPResponse {
// TODO
return HTTPResponse()
let telemetryContext = telemetry.contextManager.current()
let tracer = telemetry.tracerProvider.getTracer(
scope: telemetry.tracerScope
)
do {
// START - smithy.client.http.requests.queued_duration
let queuedStart = Date().timeIntervalSinceReferenceDate
let span = tracer.createSpan(
name: telemetry.spanName,
initialAttributes: telemetry.spanAttributes,
spanKind: SpanKind.internal,
parentContext: telemetryContext)
defer {
span.end()
}

// START - smithy.client.http.connections.acquire_duration
let acquireConnectionStart = Date().timeIntervalSinceReferenceDate

// TODO: Convert Smithy HTTPRequest to AsyncHTTPClient HTTPClientRequest

let acquireConnectionEnd = Date().timeIntervalSinceReferenceDate
telemetry.connectionsAcquireDuration.record(
value: acquireConnectionEnd - acquireConnectionStart,
attributes: Attributes(),
context: telemetryContext)
// END - smithy.client.http.connections.acquire_duration

let queuedEnd = acquireConnectionEnd
telemetry.requestsQueuedDuration.record(
value: queuedEnd - queuedStart,
attributes: Attributes(),
context: telemetryContext)
// END - smithy.client.http.requests.queued_duration

// TODO: Update connection and request usage metrics based on AsyncHTTPClient configuration
telemetry.updateHTTPMetricsUsage { httpMetricsUsage in
// TICK - smithy.client.http.connections.limit
httpMetricsUsage.connectionsLimit = 0 // TODO: Get from AsyncHTTPClient configuration

// TICK - smithy.client.http.connections.usage
httpMetricsUsage.acquiredConnections = 0 // TODO: Get from AsyncHTTPClient
httpMetricsUsage.idleConnections = 0 // TODO: Get from AsyncHTTPClient

// TICK - smithy.client.http.requests.usage
httpMetricsUsage.inflightRequests = httpMetricsUsage.acquiredConnections
httpMetricsUsage.queuedRequests = httpMetricsUsage.idleConnections
}

// DURATION - smithy.client.http.connections.uptime
let connectionUptimeStart = acquireConnectionEnd
defer {
telemetry.connectionsUptime.record(
value: Date().timeIntervalSinceReferenceDate - connectionUptimeStart,
attributes: Attributes(),
context: telemetryContext)
}

// TODO: Execute the HTTP request using AsyncHTTPClient

// TODO: Log body description

// TODO: Handle response
// TODO: Record bytes sent during request body streaming with server address attributes
// TODO: Record bytes received during response streaming with server address attributes

// TODO: Convert NIO response to Smithy HTTPResponse

return HTTPResponse() // TODO: Return actual response
} catch {

Check warning on line 139 in Sources/ClientRuntime/Networking/Http/NIO/NIOHTTPClient.swift

View workflow job for this annotation

GitHub Actions / apple-ci (macos-14, Xcode_15.2, platform=iOS Simulator,OS=17.2,name=iPhone 15)

'catch' block is unreachable because no errors are thrown in 'do' block

Check warning on line 139 in Sources/ClientRuntime/Networking/Http/NIO/NIOHTTPClient.swift

View workflow job for this annotation

GitHub Actions / apple-ci (macos-14, Xcode_15.2, platform=tvOS Simulator,OS=17.2,name=Apple TV 4K (3rd generation)...

'catch' block is unreachable because no errors are thrown in 'do' block

Check warning on line 139 in Sources/ClientRuntime/Networking/Http/NIO/NIOHTTPClient.swift

View workflow job for this annotation

GitHub Actions / apple-ci (macos-15, Xcode_26.0, platform=macOS)

'catch' block is unreachable because no errors are thrown in 'do' block

Check warning on line 139 in Sources/ClientRuntime/Networking/Http/NIO/NIOHTTPClient.swift

View workflow job for this annotation

GitHub Actions / apple-ci (macos-14, Xcode_15.2, platform=macOS)

'catch' block is unreachable because no errors are thrown in 'do' block

Check warning on line 139 in Sources/ClientRuntime/Networking/Http/NIO/NIOHTTPClient.swift

View workflow job for this annotation

GitHub Actions / apple-ci (macos-15, Xcode_26.0, platform=tvOS Simulator,OS=26.0,name=Apple TV 4K (3rd generation)...

'catch' block is unreachable because no errors are thrown in 'do' block

Check warning on line 139 in Sources/ClientRuntime/Networking/Http/NIO/NIOHTTPClient.swift

View workflow job for this annotation

GitHub Actions / apple-ci (macos-15, Xcode_26.0, platform=visionOS Simulator,OS=26.0,name=Apple Vision Pro)

'catch' block is unreachable because no errors are thrown in 'do' block

Check warning on line 139 in Sources/ClientRuntime/Networking/Http/NIO/NIOHTTPClient.swift

View workflow job for this annotation

GitHub Actions / apple-ci (macos-14, Xcode_15.2, platform=visionOS Simulator,OS=1.0,name=Apple Vision Pro)

'catch' block is unreachable because no errors are thrown in 'do' block

Check warning on line 139 in Sources/ClientRuntime/Networking/Http/NIO/NIOHTTPClient.swift

View workflow job for this annotation

GitHub Actions / apple-ci (macos-15, Xcode_26.0, platform=iOS Simulator,OS=26.0,name=iPhone 17)

'catch' block is unreachable because no errors are thrown in 'do' block
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ignore this warning it will be reachable once send is implemented

// TODO: Handle catch
}
}
}
Loading