From 58447cf61d1028f663a263582ffa711e97778c59 Mon Sep 17 00:00:00 2001 From: Guoye Zhang Date: Tue, 4 Mar 2025 13:21:37 -0800 Subject: [PATCH 1/2] Convert WebSocket URLRequest to RFC8441 HTTPRequest --- .../URLRequest+HTTPTypes.swift | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/Sources/HTTPTypesFoundation/URLRequest+HTTPTypes.swift b/Sources/HTTPTypesFoundation/URLRequest+HTTPTypes.swift index 624f8a3..05829ac 100644 --- a/Sources/HTTPTypesFoundation/URLRequest+HTTPTypes.swift +++ b/Sources/HTTPTypesFoundation/URLRequest+HTTPTypes.swift @@ -25,6 +25,23 @@ extension URLRequest { /// Create a `URLRequest` from an `HTTPRequest`. /// - Parameter httpRequest: The HTTP request to convert from. public init?(httpRequest: HTTPRequest) { + // Translate an extended-CONNECT WebSocket request to the legacy form + if httpRequest.method == .connect && httpRequest.extendedConnectProtocol == "websocket" { + var legacyRequest = httpRequest + legacyRequest.method = .get + switch httpRequest.scheme?.lowercased() { + case "https": + legacyRequest.scheme = "wss" + case "http": + legacyRequest.scheme = "ws" + default: + break + } + legacyRequest.extendedConnectProtocol = nil + self.init(httpRequest: legacyRequest) + return + } + guard let url = httpRequest.url else { return nil } @@ -63,6 +80,27 @@ extension URLRequest { } } } + + // Translate a legacy WebSocket request to the extended-CONNECT form + if method == .get, let scheme = request.scheme { + switch scheme.utf8.count { + case 3: + if scheme.lowercased() == "wss" { + request.method = .connect + request.scheme = "https" + request.extendedConnectProtocol = "websocket" + } + case 2: + if scheme.lowercased() == "ws" { + request.method = .connect + request.scheme = "http" + request.extendedConnectProtocol = "websocket" + } + default: + break + } + } + return request } } From 43d6a454735b3e48bef53a899d1960c959df28f5 Mon Sep 17 00:00:00 2001 From: Guoye Zhang Date: Tue, 4 Mar 2025 15:27:29 -0800 Subject: [PATCH 2/2] Add test --- .../HTTPTypesFoundationTests.swift | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Tests/HTTPTypesFoundationTests/HTTPTypesFoundationTests.swift b/Tests/HTTPTypesFoundationTests/HTTPTypesFoundationTests.swift index 6302bc7..657b245 100644 --- a/Tests/HTTPTypesFoundationTests/HTTPTypesFoundationTests.swift +++ b/Tests/HTTPTypesFoundationTests/HTTPTypesFoundationTests.swift @@ -143,6 +143,22 @@ final class HTTPTypesFoundationTests: XCTestCase { XCTAssertEqual(request.headerFields[.init("x-foo")!], "Bar") } + func testWebSocketRequest() throws { + let urlRequest = URLRequest(url: URL(string: "wss://www.example.com/")!) + + let request = try XCTUnwrap(urlRequest.httpRequest) + XCTAssertEqual(request.method, .connect) + XCTAssertEqual(request.scheme, "https") + XCTAssertEqual(request.authority, "www.example.com") + XCTAssertEqual(request.path, "/") + XCTAssertEqual(request.extendedConnectProtocol, "websocket") + + let urlRequestConverted = try XCTUnwrap(URLRequest(httpRequest: request)) + XCTAssertEqual(urlRequestConverted.httpMethod, "GET") + XCTAssertEqual(urlRequestConverted.url, URL(string: "wss://www.example.com/")) + XCTAssertEqual(urlRequest, urlRequestConverted) + } + func testResponseToFoundation() throws { let response = HTTPResponse( status: .ok,