Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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.ServerTransportCapabilityHint {
public var serverSupportedTransports: Set<NetworkTypes.TransportVersion> = []
}

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 ServerTransportCapabilityHint: 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 serverSupportedTransports: Set<TransportVersion> { 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.serverSupportedTransports = options.serverSupportedTransports
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.ServerTransportCapabilityHint {
public var serverSupportedTransports: Set<TransportVersion> = []

public init() {}
}
34 changes: 34 additions & 0 deletions Sources/NetworkTypes/TransportVersion.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.
///
/// ``TransportVersion`` 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 TransportVersion: Sendable, Hashable {

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.

Let's name it HTTPTransportProtocol since this is specific to HTTP

/// Plaintext TCP transport.
case tcp

/// TCP with TLS transport.
case tcpWithTLS

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.

I think we don't need this case since whether the server supports TLS is already known to the user when they put http or https in the URL.


/// 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.serverSupportedTransports.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.ServerTransportCapabilityHint
{
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 serverSupportedTransports: Set<TransportVersion> = []

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.

We should default it to [.tcp], maybe call it a hint in the property name as well?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Updated to serverSupportedTransportsHint and the protocol name to just ServerTransportHint, I realized it doesn't need Capability in the name

public var stallTimeout: Duration? = nil

public init() {}
Expand Down
Loading