From 74e4995e39d69bfa76d63be7c47fbc077a09909f Mon Sep 17 00:00:00 2001 From: Guoye Zhang Date: Mon, 28 Oct 2024 17:16:02 -0700 Subject: [PATCH] Support building without CoreFoundation on Windows --- .../HTTPTypesFoundation/HTTPRequest+URL.swift | 62 ++++++++++++++++++- .../HTTPTypesFoundationTests.swift | 30 +++++++++ 2 files changed, 89 insertions(+), 3 deletions(-) diff --git a/Sources/HTTPTypesFoundation/HTTPRequest+URL.swift b/Sources/HTTPTypesFoundation/HTTPRequest+URL.swift index 66562f5..dec2bc2 100644 --- a/Sources/HTTPTypesFoundation/HTTPRequest+URL.swift +++ b/Sources/HTTPTypesFoundation/HTTPRequest+URL.swift @@ -12,10 +12,13 @@ // //===----------------------------------------------------------------------===// -import CoreFoundation import Foundation import HTTPTypes +#if canImport(CoreFoundation) +import CoreFoundation +#endif // canImport(CoreFoundation) + extension HTTPRequest { /// The URL of the request synthesized from the scheme, authority, and path pseudo header /// fields. @@ -80,6 +83,7 @@ extension URL { buffer.append(contentsOf: authority) buffer.append(contentsOf: path) + #if canImport(CoreFoundation) if let url = buffer.withUnsafeBytes({ buffer in CFURLCreateAbsoluteURLWithBytes( kCFAllocatorDefault, @@ -94,9 +98,14 @@ extension URL { } else { return nil } + #else // canImport(CoreFoundation) + // This initializer does not preserve WHATWG URLs + self.init(string: String(decoding: buffer, as: UTF8.self)) + #endif // canImport(CoreFoundation) } fileprivate var httpRequestComponents: (scheme: [UInt8], authority: [UInt8]?, path: [UInt8]) { + #if canImport(CoreFoundation) // CFURL parser based on byte ranges does not unnecessarily percent-encode WHATWG URL let url = unsafeBitCast(self.absoluteURL as NSURL, to: CFURL.self) let length = CFURLGetBytes(url, nil, 0) @@ -133,11 +142,11 @@ extension URL { let requestPathRange = unionRange(pathRange, queryRange) if pathRange.length == 0 { if requestPathRange.length == 0 { - path = Array("/".utf8) + path = [UInt8(ascii: "/")] } else { let pathBuffer = bufferSlice(requestPathRange) path = [UInt8](unsafeUninitializedCapacity: pathBuffer.count + 1) { buffer, initializedCount in - buffer[0] = 0x2F + buffer[0] = UInt8(ascii: "/") UnsafeMutableRawBufferPointer(UnsafeMutableBufferPointer(rebasing: buffer[1...])).copyMemory( from: UnsafeRawBufferPointer(pathBuffer) ) @@ -149,5 +158,52 @@ extension URL { } return (scheme, authority, path) } + #else // canImport(CoreFoundation) + guard let components = URLComponents(url: self, resolvingAgainstBaseURL: true), + let urlString = components.string + else { + fatalError("Invalid URL") + } + + guard let schemeRange = components.rangeOfScheme else { + fatalError("Schemeless URL is not supported") + } + let scheme = Array(urlString[schemeRange].utf8) + + let authority: [UInt8]? + if let hostRange = components.rangeOfHost { + let authorityRange = + if let portRange = components.rangeOfPort { + hostRange.lowerBound..? + if let lowerBound = pathRange?.lowerBound ?? queryRange?.lowerBound, + let upperBound = queryRange?.upperBound ?? pathRange?.upperBound + { + requestPathRange = lowerBound..