Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for proxying in WebsocketClient #130

Merged
merged 4 commits into from
Apr 11, 2023
Merged

Conversation

rnro
Copy link
Contributor

@rnro rnro commented Feb 27, 2023

Added support for TLS and plain text proxying of Websocket traffic.

  • In the TLS case a CONNECT header is first sent establishing the proxied traffic.

  • In the plain text case the modified URI in the initial upgrade request header indicates to the proxy server that the traffic is to be proxied.

  • Use NIOWebSocketFrameAggregator to handle aggregating frame fragments. This brings with it more protections e.g. against memory exhaustion.

  • Accompanying config has been added to support this change.

This change also includes some performance gains by reducing the allocation and copies necessary to send ByteBuffer and ByteBufferView through WebSocket.send.

  • Sending ByteBuffer or ByteBufferView doesn’t require any allocation or copy of the data. Sending a String now correctly pre allocates the ByteBuffer if multibyte characters are present in the String.

  • Remove custom random websocket mask generation which would only generate bytes between UInt8.min..<UInt8.max, therefore excluding UInt8.max i.e. 255.

Copy link
Member

@0xTim 0xTim left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this! Could you add DocC comments to all the new public APIs? Thanks!

@@ -67,4 +67,68 @@ extension WebSocket {
onUpgrade: onUpgrade
)
}

public static func connect(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add DocC comments for the new public APIs? Thanks!

Comment on lines 30 to 39
public var minNonFinalFragmentSize: Int
public var maxAccumulatedFrameCount: Int
public var maxAccumulatedFrameSize: Int

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add DocC comments describing what these are for?


let localWebsocketBin: WebsocketBin
let verifyProxyHead = { (ctx: ChannelHandlerContext, requestHead: HTTPRequestHead) in
XCTAssertEqual(requestHead.uri, "ws://apple.com/:\(ctx.localAddress!.port!)")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to confirm this is a simulated proxy and not something we're going out on the network for?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, we do a somewhat convoluted dance to insert and remove channel handlers to mimic a proxy e.g. intercepting the CONNECT request.

@rnro
Copy link
Contributor Author

rnro commented Mar 1, 2023

Thanks for the review @0xTim. I've pushed the changes you requested and also some performance improvements in a separate commit.

Copy link
Member

@0xTim 0xTim left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding these! Few more places for DocC comments and then we're good to go!

)
}

public static func connect(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing comments

}
}

public func send(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing DocC comments

self.connect(scheme: scheme, host: host, port: port, path: path, query: query, headers: headers, proxy: nil, onUpgrade: onUpgrade)
}

public func connect(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing DocC comments

@@ -2,27 +2,72 @@ import NIO
import NIOWebSocket

extension WebSocket {

public struct Configuration {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing DocC comments (and on the public functions in the type)

rnro added 4 commits March 7, 2023 14:21
Added support for TLS and plain text proxying of Websocket traffic.

In the TLS case a CONNECT header is first sent establishing the proxied
traffic.

In the plain text case the modified URI in the initial upgrade request
header indicates to the proxy server that the traffic is to be proxied.

Use `NIOWebSocketFrameAggregator` to handle aggregating frame
fragments. This brings with it more protections e.g. against memory
exhaustion.

Accompanying config has been added to support this change.
Reduce allocation and copies necessary to send `ByteBuffer` and `ByteBufferView` through `WebSocket.send`.

In fact sending `ByteBuffer` or `ByteBufferView` doesn’t require any allocation or copy of the data. Sending a `String` now correctly pre allocates the `ByteBuffer` if multibyte characters are present in the `String`.

Remove custom random websocket mask generation which would only generate bytes between `UInt8.min..<UInt8.max`, therefore excluding `UInt8.max` aka `255`.
@codecov-commenter
Copy link

codecov-commenter commented Mar 31, 2023

Codecov Report

Merging #130 (777ef32) into main (e0faccd) will decrease coverage by 3.62%.
The diff coverage is 78.80%.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #130      +/-   ##
==========================================
- Coverage   71.15%   67.54%   -3.62%     
==========================================
  Files           5        6       +1     
  Lines         475      758     +283     
==========================================
+ Hits          338      512     +174     
- Misses        137      246     +109     
Impacted Files Coverage Δ
...bSocketKit/Concurrency/WebSocket+Concurrency.swift 29.78% <ø> (ø)
Sources/WebSocketKit/WebSocket+Connect.swift 50.00% <36.84%> (-47.50%) ⬇️
Sources/WebSocketKit/WebSocket.swift 72.87% <77.41%> (+1.09%) ⬆️
...urces/WebSocketKit/HTTPUpgradeRequestHandler.swift 72.05% <77.77%> (ø)
Sources/WebSocketKit/WebSocketHandler.swift 61.97% <85.18%> (+6.65%) ⬆️
Sources/WebSocketKit/WebSocketClient.swift 86.00% <90.55%> (+18.03%) ⬆️

@rnro rnro requested a review from 0xTim March 31, 2023 05:46
@rnro
Copy link
Contributor Author

rnro commented Mar 31, 2023

Sorry about the delay. The missing DocC comments should now be there.

Copy link
Member

@0xTim 0xTim left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@0xTim 0xTim added the semver-minor Contains new APIs label Apr 11, 2023
@0xTim 0xTim changed the title WebsocketClient supports proxying Add support for proxying in WebsocketClient Apr 11, 2023
@0xTim 0xTim merged commit 2166cbe into vapor:main Apr 11, 2023
@VaporBot
Copy link

These changes are now available in 2.8.0

@rnro rnro deleted the proxy_support branch April 11, 2023 14:52
@0xTim
Copy link
Member

0xTim commented Apr 11, 2023

FYI nightly error is being tracked at swiftlang/swift#65064

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
semver-minor Contains new APIs
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants