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
24 changes: 24 additions & 0 deletions Sources/HTTPAPIs/Server/HTTPServerCapability+HTTPVersionInfo.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//===----------------------------------------------------------------------===//
//
// 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(anyAppleOS 26.0, *)
extension HTTPServerCapability {
/// A capability for request contexts that expose the HTTP version used for the
/// connection a request arrived on.
public protocol HTTPVersionInfo: RequestContext, ~Copyable, ~Escapable {
/// The HTTP version used for this request
var httpVersion: HTTPVersion { get }
}
}
59 changes: 59 additions & 0 deletions Sources/NetworkTypes/HTTPVersion.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

/// Representation of an HTTP version.
public struct HTTPVersion: Sendable, Hashable {
private enum Representation: UInt8, Sendable, Hashable {
case http1_0
case http1_1
case http2
case http3
}

private let representation: Representation

private init(_ representation: Representation) {
self.representation = representation
}

/// HTTP/1.0, as defined in RFC 1945.
public static var http1_0: HTTPVersion {
.init(.http1_0)
}

/// HTTP/1.1, as defined in RFC 9112.
public static var http1_1: HTTPVersion {
.init(.http1_1)
}

/// HTTP/2, as defined in RFC 9113.
public static var http2: HTTPVersion {
.init(.http2)
}

/// HTTP/3, as defined in RFC 9114.
public static var http3: HTTPVersion {
.init(.http3)
}
}

extension HTTPVersion: CustomStringConvertible {
public var description: String {
switch self.representation {
case .http1_0: "HTTP/1.0"
case .http1_1: "HTTP/1.1"
case .http2: "HTTP/2"
case .http3: "HTTP/3"
}
}
}
12 changes: 10 additions & 2 deletions Tests/HTTPAPIsTests/Helpers/HTTPClientAndServerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import ContainersPreview
import DequeModule
import HTTPAPIs
import HTTPTypes
import NetworkTypes
import Synchronization
import Testing

Expand All @@ -30,10 +31,16 @@ final class TestClientAndServer: HTTPClient, HTTPServer {
struct HTTPRequestContext: HTTPServerCapability.RequestContext {
var remoteAddress: String?
var localAddress: String?
var httpVersion: HTTPVersion

init(remoteAddress: String? = nil, localAddress: String? = nil) {
init(
remoteAddress: String? = nil,
localAddress: String? = nil,
httpVersion: HTTPVersion = .http1_1
) {
self.remoteAddress = remoteAddress
self.localAddress = localAddress
self.httpVersion = httpVersion
}
}

Expand Down Expand Up @@ -333,7 +340,8 @@ final class TestClientAndServer: HTTPClient, HTTPServer {
request: httpRequest,
requestContext: HTTPRequestContext(
remoteAddress: "127.0.0.1:54321",
localAddress: "0.0.0.0:8080"
localAddress: "0.0.0.0:8080",
httpVersion: .http2
),
reader: requestReader,
responseSender: responseSender
Expand Down
5 changes: 5 additions & 0 deletions Tests/HTTPAPIsTests/ServerCapabilityTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import BasicContainers
import Foundation
import HTTPAPIs
import NetworkTypes
import Testing

@available(anyAppleOS 26.0, *)
Expand All @@ -27,12 +28,16 @@ extension HTTPServerCapability {
@available(anyAppleOS 26.0, *)
extension TestClientAndServer.HTTPRequestContext: HTTPServerCapability.ConnectionInfo {}

@available(anyAppleOS 26.0, *)
extension TestClientAndServer.HTTPRequestContext: HTTPServerCapability.HTTPVersionInfo {}

@available(anyAppleOS 26.0, *)
extension TestClientAndServer {
func serveWithContextAssertions() async throws {
try await self.serve { request, requestContext, reader, responseSender in
#expect(requestContext.remoteAddress == "127.0.0.1:54321")
#expect(requestContext.localAddress == "0.0.0.0:8080")
#expect(requestContext.httpVersion == .http2)

try await responseSender.sendAndFinish(.init(status: .ok))
}
Expand Down
Loading