From b9c9fcfcd9ce9841d52b8c4343f7cbde0557b0a9 Mon Sep 17 00:00:00 2001 From: weixi Date: Mon, 20 Oct 2025 23:45:52 +0800 Subject: [PATCH 1/4] Fix WebSocket proxy URL construction order(#147) --- Sources/WebSocketKit/WebSocketClient.swift | 2 +- Tests/WebSocketKitTests/WebSocketKitTests.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/WebSocketKit/WebSocketClient.swift b/Sources/WebSocketKit/WebSocketClient.swift index e952190..9d9302c 100644 --- a/Sources/WebSocketKit/WebSocketClient.swift +++ b/Sources/WebSocketKit/WebSocketClient.swift @@ -117,7 +117,7 @@ public final class WebSocketClient: Sendable { } else { let relativePath = path.hasPrefix("/") ? path : "/" + path let port = proxyPort.map { ":\($0)" } ?? "" - uri = "\(scheme)://\(host)\(relativePath)\(port)" + uri = "\(scheme)://\(host)\(port)\(relativePath)" if scheme == "ws" { upgradeRequestHeaders.add(contentsOf: proxyHeaders) diff --git a/Tests/WebSocketKitTests/WebSocketKitTests.swift b/Tests/WebSocketKitTests/WebSocketKitTests.swift index 4be932e..0ebe426 100644 --- a/Tests/WebSocketKitTests/WebSocketKitTests.swift +++ b/Tests/WebSocketKitTests/WebSocketKitTests.swift @@ -348,7 +348,7 @@ final class WebSocketKitTests: XCTestCase { let localWebsocketBin: WebsocketBin let verifyProxyHead = { @Sendable (ctx: ChannelHandlerContext, requestHead: HTTPRequestHead) in - XCTAssertEqual(requestHead.uri, "ws://apple.com/:\(ctx.localAddress!.port!)") + XCTAssertEqual(requestHead.uri, "ws://apple.com:\(ctx.localAddress!.port!)/") XCTAssertEqual(requestHead.headers.first(name: "Host"), "apple.com") } localWebsocketBin = WebsocketBin( From a889231c2fc755ac9bbcb53ba774e7686a17fdaa Mon Sep 17 00:00:00 2001 From: weixi Date: Mon, 20 Oct 2025 23:48:18 +0800 Subject: [PATCH 2/4] Add missing configuration parameter in proxy connect --- Sources/WebSocketKit/WebSocket+Connect.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Sources/WebSocketKit/WebSocket+Connect.swift b/Sources/WebSocketKit/WebSocket+Connect.swift index 5fe0fed..474ac8c 100644 --- a/Sources/WebSocketKit/WebSocket+Connect.swift +++ b/Sources/WebSocketKit/WebSocket+Connect.swift @@ -193,6 +193,7 @@ extension WebSocket { proxyPort: proxyPort, proxyHeaders: proxyHeaders, proxyConnectDeadline: proxyConnectDeadline, + configuration: configuration, on: eventLoopGroup, onUpgrade: onUpgrade ) From 795c6fc454dc996b22c99da17f221c7255963f78 Mon Sep 17 00:00:00 2001 From: weixi Date: Tue, 21 Oct 2025 11:23:10 +0800 Subject: [PATCH 3/4] Use origin-form URI for wss proxy connections --- Sources/WebSocketKit/WebSocketClient.swift | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Sources/WebSocketKit/WebSocketClient.swift b/Sources/WebSocketKit/WebSocketClient.swift index 9d9302c..0e1e48c 100644 --- a/Sources/WebSocketKit/WebSocketClient.swift +++ b/Sources/WebSocketKit/WebSocketClient.swift @@ -116,11 +116,13 @@ public final class WebSocketClient: Sendable { uri = path } else { let relativePath = path.hasPrefix("/") ? path : "/" + path - let port = proxyPort.map { ":\($0)" } ?? "" - uri = "\(scheme)://\(host)\(port)\(relativePath)" - + // ws: use absolute-form for proxy; wss: use origin-form after CONNECT tunnel if scheme == "ws" { + let port = proxyPort.map { ":\($0)" } ?? "" + uri = "\(scheme)://\(host)\(port)\(relativePath)" upgradeRequestHeaders.add(contentsOf: proxyHeaders) + } else { + uri = relativePath } } From a2ce4b8458bf3e89d1a052507a915351123ed4f4 Mon Sep 17 00:00:00 2001 From: "shiwei.sun" <49645134+Weixi779@users.noreply.github.com> Date: Wed, 3 Dec 2025 17:27:16 +0800 Subject: [PATCH 4/4] Apply suggestion from code review. Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Sources/WebSocketKit/WebSocketClient.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Sources/WebSocketKit/WebSocketClient.swift b/Sources/WebSocketKit/WebSocketClient.swift index 0e1e48c..389dc9f 100644 --- a/Sources/WebSocketKit/WebSocketClient.swift +++ b/Sources/WebSocketKit/WebSocketClient.swift @@ -116,7 +116,8 @@ public final class WebSocketClient: Sendable { uri = path } else { let relativePath = path.hasPrefix("/") ? path : "/" + path - // ws: use absolute-form for proxy; wss: use origin-form after CONNECT tunnel + // ws: use absolute-form (full URI) for direct proxy connection; + // wss: use origin-form (path only) after CONNECT tunnel is established per RFC 7230 if scheme == "ws" { let port = proxyPort.map { ":\($0)" } ?? "" uri = "\(scheme)://\(host)\(port)\(relativePath)"