// // EndpointValidator.swift // readeck // // Created by Ilyas Hallak on 05.12.25. // import Foundation /// Validates and normalizes server endpoint URLs for consistent API usage struct EndpointValidator { /// Normalizes an endpoint URL by: /// - Trimming whitespace /// - Ensuring proper scheme (http/https, defaults to https if missing) /// - Preserving custom ports /// - Removing trailing slashes from path /// - Removing query parameters and fragments /// /// - Parameter endpoint: Raw endpoint string from user input /// - Returns: Normalized endpoint URL string /// /// Examples: /// - "example.com" → "https://example.com" /// - "http://100.80.0.1:8080" → "http://100.80.0.1:8080" /// - "https://server:3000/path/" → "https://server:3000/path" /// - "192.168.1.100:9090?query=test" → "https://192.168.1.100:9090" static func normalize(_ endpoint: String) -> String { var normalized = endpoint.trimmingCharacters(in: .whitespacesAndNewlines) // Handle empty input guard !normalized.isEmpty else { return normalized } // Remove query parameters first if let queryIndex = normalized.firstIndex(of: "?") { normalized = String(normalized[.. Bool { let normalized = normalize(endpoint) guard let url = URL(string: normalized) else { return false } // Check that we have at minimum a scheme and host return url.scheme != nil && url.host != nil } // MARK: - Private Helpers private static func buildNormalizedURL(from components: URLComponents) -> String { var urlComponents = components // Ensure scheme is http or https, default to https if urlComponents.scheme == nil { urlComponents.scheme = "https" } else if urlComponents.scheme != "http" && urlComponents.scheme != "https" { urlComponents.scheme = "https" } // Remove trailing slash from path if present if urlComponents.path.hasSuffix("/") { urlComponents.path = String(urlComponents.path.dropLast()) } // Remove query parameters and fragments urlComponents.query = nil urlComponents.fragment = nil return urlComponents.string ?? components.string ?? "" } }