import Foundation final class NoRedirect: NSObject, URLSessionTaskDelegate { func urlSession( _ session: URLSession, task: URLSessionTask, willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest, completionHandler: @escaping (URLRequest?) -> Void ) { completionHandler(nil) } } enum ServerProbe { static func check(_ server: ServerAddress) async throws { let configuration = URLSessionConfiguration.ephemeral configuration.httpCookieStorage = nil configuration.urlCache = nil configuration.timeoutIntervalForRequest = 10 configuration.timeoutIntervalForResource = 20 let session = URLSession(configuration: configuration, delegate: NoRedirect(), delegateQueue: nil) defer { session.invalidateAndCancel() } let version = try await json(session, server.url.appendingPathComponent("api/v1/version")) let auth = try await json(session, server.url.appendingPathComponent("api/v1/auth/oidc/config")) try ServerMetadata.validate(bootstrap: version, authentication: auth) } private static func json(_ session: URLSession, _ url: URL) async throws -> Data { var request = URLRequest(url: url) request.setValue("application/json", forHTTPHeaderField: "Accept") let (stream, response) = try await session.bytes(for: request) guard (response as? HTTPURLResponse)?.statusCode == 200 else { throw ConnectionError.unavailable } var data = Data() for try await byte in stream { guard data.count < 65_536 else { throw ConnectionError.incompatible } data.append(byte) } return data } }