Skip to content
Open
Show file tree
Hide file tree
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
5 changes: 3 additions & 2 deletions Sources/AHCHTTPClient/AHC+HTTPClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,16 @@ import Foundation
import HTTPTypes
import NIOCore
import NIOHTTP1
public import NetworkTypes
import Synchronization

@available(macOS 26.2, iOS 26.2, watchOS 26.2, tvOS 26.2, *)
extension AsyncHTTPClient.HTTPClient: HTTPAPIs.HTTPClient {
public typealias RequestWriter = RequestBodyWriter
public typealias ResponseConcludingReader = ResponseReader

public struct RequestOptions: HTTPClientCapability.RequestOptions {

public struct RequestOptions: HTTPClientCapability.ServerTransportHint {
public var serverSupportedTransportsHint: Set<NetworkTypes.HTTPTransportVersion> = []
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Should AHC conform or should we keep it to URLSession? Also let's make this .tcp by default as well

}

public struct RequestBodyWriter: AsyncWriter, ~Copyable {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift HTTP API Proposal open source project
//
// Copyright (c) 2026 Apple Inc. and the Swift HTTP API Proposal project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

public import NetworkTypes

@available(macOS 26.2, iOS 26.2, watchOS 26.2, tvOS 26.2, visionOS 26.2, *)
extension HTTPClientCapability {
/// A protocol for HTTP request options that hint at the transports a
/// server is known to support.
///
/// Providing server transport information allows the client to optimize
/// connection establishment. For example, if a server is known to support
/// QUIC, the client can attempt an HTTP/3 connection directly instead of
/// falling back to TCP-based negotiation.
public protocol ServerTransportHint: RequestOptions {
/// The transports that the target server is known to support.
///
/// An empty set indicates no prior knowledge of server capabilities,
/// and the client uses its default protocol negotiation behavior.
var serverSupportedTransportsHint: Set<HTTPTransportVersion> { get set }
}
}
6 changes: 3 additions & 3 deletions Sources/HTTPClient/DefaultHTTPClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -137,12 +137,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 translatedOptions = self.client.defaultRequestOptions
translatedOptions.serverSupportedTransportsHint = options.serverSupportedTransportsHint
let body = body.map {
HTTPClientRequestBody<ActualHTTPClient.RequestWriter>(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: translatedOptions) { response, body in
try await responseHandler(response, ResponseConcludingReader(actual: body))
}
}
Expand Down
5 changes: 4 additions & 1 deletion Sources/HTTPClient/HTTPRequestOptions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//
public import NetworkTypes

/// The options for the default HTTP client implementation.
@available(macOS 26.2, iOS 26.2, watchOS 26.2, tvOS 26.2, visionOS 26.2, *)
public struct HTTPRequestOptions: HTTPClientCapability.RequestOptions {
public struct HTTPRequestOptions: HTTPClientCapability.ServerTransportHint {
public var serverSupportedTransportsHint: Set<HTTPTransportVersion> = []

public init() {}
}
34 changes: 34 additions & 0 deletions Sources/NetworkTypes/HTTPTransportVersion.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift HTTP API Proposal open source project
//
// Copyright (c) 2026 Apple Inc. and the Swift HTTP API Proposal project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

/// An enumeration that represents a transport protocol used to carry HTTP
/// traffic.
///
/// ``HTTPTransportVersion`` provides type-safe access to supported transport
/// protocols, allowing clients and servers to communicate transport
/// capabilities. New transports may be added in future releases, so client
/// code must handle unknown cases.
@nonexhaustive
public enum HTTPTransportVersion: Sendable, Hashable {
/// TCP transport.
///
/// Whether TLS is layered on top is determined by the request's URL
/// scheme (`http` vs. `https`).
case tcp

/// QUIC transport.
///
/// QUIC is defined in RFC 9000 and is the transport used by HTTP/3
/// (RFC 9114).
case quic
}
2 changes: 1 addition & 1 deletion Sources/URLSessionHTTPClient/URLSessionHTTPClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ public final class URLSessionHTTPClient: HTTPClient, IdleTimerEntryProvider {
}
request.allowsExpensiveNetworkAccess = options.allowsExpensiveNetworkAccess
request.allowsConstrainedNetworkAccess = options.allowsConstrainedNetworkAccess
request.assumesHTTP3Capable = options.assumesHTTP3Capable
request.assumesHTTP3Capable = options.serverSupportedTransportsHint.contains(.quic)
if let stallTimeout = options.stallTimeout {
request.timeoutInterval = stallTimeout / .seconds(1)
} else {
Expand Down
5 changes: 3 additions & 2 deletions Sources/URLSessionHTTPClient/URLSessionRequestOptions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ public import NetworkTypes
public struct URLSessionRequestOptions:
HTTPClientCapability.RedirectionHandler,
HTTPClientCapability.TLSSecurityHandler,
HTTPClientCapability.TLSVersionSelection
HTTPClientCapability.TLSVersionSelection,
HTTPClientCapability.ServerTransportHint
{
public var redirectionHandler: (any HTTPClientRedirectionHandler)? = nil

Expand All @@ -30,7 +31,7 @@ public struct URLSessionRequestOptions:
public var maximumTLSVersion: TLSVersion = .v1_3
public var allowsExpensiveNetworkAccess: Bool = true
public var allowsConstrainedNetworkAccess: Bool = true
public var assumesHTTP3Capable: Bool = false
public var serverSupportedTransportsHint: Set<HTTPTransportVersion> = [.tcp]
public var stallTimeout: Duration? = nil

public init() {}
Expand Down
Loading