Add network path/interface restriction fields to HTTPClient.Configuration - #915
Closed
o-nnerb wants to merge 1 commit into
Closed
Add network path/interface restriction fields to HTTPClient.Configuration#915o-nnerb wants to merge 1 commit into
o-nnerb wants to merge 1 commit into
Conversation
…tion
Motivation:
URLSessionConfiguration exposes allowsCellularAccess, allowsExpensiveNetworkAccess,
and allowsConstrainedNetworkAccess. Clients migrating from URLSession, or apps that
need to respect a user's Low Data Mode / cellular preferences, expect parity.
HTTPClient.Configuration has no equivalent today, and no library built on top of
AsyncHTTPClient can add this either: the only place these NWParameters constraints
can be applied is at connection-establishment time, inside
HTTPConnectionPool+Factory.swift, which is internal to AsyncHTTPClient. There is no
generic escape hatch for NWParameters customization from outside the package.
Modifications:
- Add HTTPClient.Configuration.NetworkInterfaceType, a public struct mirroring
NWInterface.InterfaceType's cases (.other, .wifi, .cellular, .wiredEthernet,
.loopback) without requiring Network to be imported at the declaration site,
following the same Backing-enum pattern already used by DNSResolver/HTTPVersion.
- Add five new Configuration fields: prohibitedInterfaceTypes (mirrors
NWParameters.prohibitedInterfaceTypes), requiredInterfaceType (mirrors
NWParameters.requiredInterfaceType, exposed as Optional instead of that
property's non-optional .other-as-sentinel default), allowsExpensiveNetworkAccess
and allowsConstrainedNetworkAccess (inverted mirrors of
NWParameters.prohibitExpensivePaths / .prohibitConstrainedPaths), and
allowsUltraConstrainedPaths (direct mirror of the macOS/iOS/tvOS/watchOS/visionOS
26.0+ NWParameters.allowUltraConstrainedPaths). All default to NWParameters' own
defaults, verified empirically against a live NWParameters instance.
- Wire all five into both makePlainBootstrap and makeTLSBootstrap in
HTTPConnectionPool+Factory.swift via a single new configureNWParameters(_:localAddress:)
helper. NIOTSConnectionBootstrap.configureNWParameters(_:) only keeps the most
recently passed closure rather than composing across calls, so the existing
requiredLocalEndpoint-binding closure and the new field wiring had to be folded
into one closure instead of two separate configureNWParameters { } calls, which
would have silently dropped local-address binding.
- Add two tests in HTTPClientNIOTSTests.swift: one exercising all five fields
together with localAddress (regression coverage for the closure-composition
issue above), one confirming .other as an explicit requiredInterfaceType behaves
like the nil/unrestricted default.
Result:
HTTPClient.Configuration can now restrict connections by interface category and
by expensive/constrained/ultra-constrained network path, matching what
URLSessionConfiguration already offers, on Darwin platforms using Network.framework
as the transport. This is a no-op everywhere else (non-Darwin platforms, and for
allowsUltraConstrainedPaths, older OS versions), same as the existing
networkFrameworkWaitForConnectivity field.
Member
|
We highly recommend using
For libraries that want to abstract over the underlying HTTP transport, we recommend looking at the new abstract HTTPClient protocol: https://forums.swift.org/t/designing-an-http-client-api-for-swift/85254 If you have a specific use-case in mind, please open up this PR and state your use-case. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
URLSessionConfigurationexposesallowsCellularAccess,allowsExpensiveNetworkAccess, andallowsConstrainedNetworkAccess. Clients migrating fromURLSession, or apps that need to respect a user's Low Data Mode / cellular preferences, expect parity.HTTPClient.Configurationhas no equivalent today — and critically, no library built on top ofAsyncHTTPClientcan add this either, since the only place theseNWParametersconstraints can be applied is at connection-establishment time, insideHTTPConnectionPool+Factory.swift, which is internal to this package. There is no generic escape hatch forNWParameterscustomization from the outside.networkFrameworkWaitForConnectivityis the existing precedent for exactly this kind of field: declared unconditionally (no#if canImport(Network)on the declaration, it's simply inert elsewhere), and consumed only inside the two#if canImport(Network)-guarded bootstrap factories.Modifications
Adds
HTTPClient.Configuration.NetworkInterfaceType, a public struct mirroringNWInterface.InterfaceType's cases (.other,.wifi,.cellular,.wiredEthernet,.loopback) without requiringNetworkto be imported at the declaration site — following the sameBacking-enum patternDNSResolver/HTTPVersionalready use in this file, so the public type stays frozen/ABI-stable while the backing can evolve.Adds five new
Configurationfields:prohibitedInterfaceTypes: Set<NetworkInterfaceType>— mirrorsNWParameters.prohibitedInterfaceTypes.requiredInterfaceType: NetworkInterfaceType?— mirrorsNWParameters.requiredInterfaceType, exposed asOptionalinstead of that property's non-optional.other-as-"unrestricted"-sentinel default, since.otheris otherwise both a real interface category and the "don't care" default, which is easy to misread.allowsExpensiveNetworkAccess/allowsConstrainedNetworkAccess: Bool— inverted mirrors ofNWParameters.prohibitExpensivePaths/.prohibitConstrainedPaths.allowsUltraConstrainedPaths: Bool— direct mirror ofNWParameters.allowUltraConstrainedPaths(available macOS/iOS/watchOS/tvOS/visionOS 26.0+; a no-op on older OS versions, not just non-Darwin platforms).All defaults match
NWParameters' own defaults, confirmed both against theNetwork.swiftinterfaceshipped in Xcode 26.5 and empirically against a liveNWParametersinstance.Wires all five into both
makePlainBootstrapandmakeTLSBootstrapvia one newconfigureNWParameters(_:localAddress:)helper.NIOTSConnectionBootstrap.configureNWParameters(_:)only retains the most recently passed closure rather than composing across calls, so the existingrequiredLocalEndpointlocal-address-binding closure and the new field wiring are folded into a single closure — two separateconfigureNWParameters { }calls would have silently dropped the local-address binding.Adds two tests to
HTTPClientNIOTSTests.swift: one exercising all five fields together withlocalAddressset (regression coverage for the closure-composition issue above), one confirming.otheras an explicitrequiredInterfaceTypebehaves the same as thenil/unrestricted default.Result
HTTPClient.Configurationcan restrict connections by interface category and by expensive/constrained/ultra-constrained network path, matching whatURLSessionConfigurationalready offers, on Darwin platforms using Network.framework as the transport. No-op everywhere else (non-Darwin platforms, and forallowsUltraConstrainedPaths, older OS versions), same as the existingnetworkFrameworkWaitForConnectivityfield.🤖 Generated with Claude Code