Repository navigation
Add local port binding to HTTPClient.Configuration - #914
VictorDebray wants to merge 3 commits into
Conversation
Adds a `localPort: Int` knob on `HTTPClient.Configuration` that pins the TCP source port the connection binds to before connecting, plus a per-request `HTTPClientRequest.localPort` override. `0` (the default) keeps the previous behaviour of letting the OS assign an ephemeral port. `localPort` is threaded through `RequestOptions` and `ConnectionPool.Key` alongside the existing `localAddress`, so connections with different `(localAddress, localPort)` pairs are pooled separately. Both the NIOTS (`requiredLocalEndpoint`) and NIOPosix (`bind(to:)`) bootstraps in the plain and TLS paths honour it.
There was a problem hiding this comment.
This looks like a solid PR. Thank you. However before merging, we will need tests, that validate that the outgoing request has actually been made from the specified port. We will need this for the old (EventLoopFuture) API as well as the new one. Overwriting the settings also needs to be tested.
Reject localPort values outside 0...65535 with a new invalidLocalPort error instead of failing silently or misbehaving at bind time.
|
I have added the needed tests. Thanks for the review! |
| /// request. Only consulted when a local address (request-level or | ||
| /// configuration-level) is also set. Values outside of `0...65535` fail the |
There was a problem hiding this comment.
Only consulted when a local address (request-level or configuration-level) is also set.
What does this mean? This is only consulted if a client-level setting is set? Is that true?
There was a problem hiding this comment.
I updated the comment, I agree I could have been more clear.
Correct what the localPort docs say about validation
Both doc comments said the port is "only consulted" when a local address is also set. That's true of binding but not of validation: the range check in `makePlainBootstrap` and `makeTLSBootstrap` runs before any address check and regardless of whether one exists, so an out of range port fails the request whether or not it would ever have been bound. The configuration comment contradicted itself, promising the value was ignored three lines above saying it fails the request. They now separate the two: the port is bound only alongside an address, and range checked either way. Also corrects the claim that bind failures surface as `HTTPClientError`. Only constructing the `SocketAddress` maps to one; `EACCES` and `EADDRINUSE` come back from the channel.
Adds a
localPort: Intknob onHTTPClient.Configurationthat pins the TCP source port the connection binds to before connecting, plus a per-requestHTTPClientRequest.localPortoverride.0(the default) keeps the previous behaviour of letting the OS assign an ephemeral port.localPortis threaded throughRequestOptionsandConnectionPool.Keyalongside the existinglocalAddress, so connections with different(localAddress, localPort)pairs are pooled separately. Both the NIOTS (requiredLocalEndpoint) and NIOPosix (bind(to:)) bootstraps in the plain and TLS paths honour it.