Skip to content

[Foundation] Implement NSUrlSessionHandler proxy support. Fixes #14632 - #26021

Open
rolfbjarne wants to merge 19 commits into
mainfrom
dev/rolf/issue-14632-net-implement-nsurlsessionhandler-membe-1e40bf
Open

[Foundation] Implement NSUrlSessionHandler proxy support. Fixes #14632#26021
rolfbjarne wants to merge 19 commits into
mainfrom
dev/rolf/issue-14632-net-implement-nsurlsessionhandler-membe-1e40bf

Conversation

@rolfbjarne

@rolfbjarne rolfbjarne commented Jul 9, 2026

Copy link
Copy Markdown
Member

The Proxy setter previously threw PlatformNotSupportedException, and UseProxy/SupportsProxy didn't allow any custom proxy configuration.

This implements custom proxy support:

  • Proxy is now a real IWebProxy property. Since NSUrlSession applies proxy settings per-session (not per-request), the proxy returned by IWebProxy.GetProxy for the first request is translated into the session's ConnectionProxyDictionary and the session is recreated before the first request is sent (mirroring the UseCookies pattern).
  • UseProxy is now a real settable bool. Setting it to false applies an empty connection proxy dictionary, which overrides any proxy configured in the OS.
  • SupportsProxy now returns true.
  • Proxy authentication is wired up: DefaultProxyCredentials is a real property, and proxy authentication challenges (IsProxy protection spaces) use Proxy.Credentials ?? DefaultProxyCredentials.

Added an in-process HTTP forwarding proxy test server and tests covering proxy routing, proxy authentication (via Proxy.Credentials and DefaultProxyCredentials) and the proxy-related property behavior.

Fixes #14632.
Fixes #18635.

🤖 Pull request created by Copilot

The Proxy setter previously threw PlatformNotSupportedException, and
UseProxy/SupportsProxy didn't allow any custom proxy configuration.

Implement custom proxy support:

* Proxy is now a real IWebProxy property. Since NSUrlSession applies
  proxy settings per-session (not per-request), the proxy returned by
  IWebProxy.GetProxy for the first request is translated into the
  session's ConnectionProxyDictionary and the session is recreated
  before the first request is sent (mirroring the UseCookies pattern).
* UseProxy is now a real settable bool. Setting it to false applies an
  empty connection proxy dictionary, which overrides any proxy
  configured in the OS.
* SupportsProxy now returns true.
* Proxy authentication is wired up: DefaultProxyCredentials is a real
  property, and proxy authentication challenges (IsProxy protection
  spaces) use Proxy.Credentials ?? DefaultProxyCredentials.

Added an in-process HTTP forwarding proxy test server and tests
covering proxy routing, proxy authentication (via Proxy.Credentials and
DefaultProxyCredentials) and the proxy-related property behavior.

Fixes #14632

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@vs-mobiletools-engineering-service2

This comment has been minimized.

rolfbjarne and others added 2 commits July 9, 2026 21:03
…andling

Proxy authentication challenges report a proxy authentication method
(NSURLAuthenticationMethodHTTPProxy / NSURLAuthenticationMethodHTTPSProxy)
rather than a specific scheme like Basic. TryGetAuthenticationType didn't
recognize those methods and rejected the protection space, so the proxy
credentials were never applied and requests failed with a 407.

Handle proxy authentication challenges separately, using the proxy
credentials (Proxy.Credentials or DefaultProxyCredentials) directly.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…support

Implementing custom proxy support in NSUrlSessionHandler adds a small
amount of reachable code, which increases the NativeAOT (TrimmableStatic)
app size beyond the test tolerance on all platforms. Update the expected
app size files accordingly.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@vs-mobiletools-engineering-service2

This comment has been minimized.

For a plain HTTP proxy using Basic authentication, NSUrlSession doesn't
surface the proxy's 407 challenge to our session delegate, so the
delegate-based credential flow never runs. Instead, embed the proxy
credentials (kCFProxyUsernameKey/kCFProxyPasswordKey) directly in the
connection proxy dictionary; NSUrlSession/CFNetwork then sends the
Proxy-Authorization header automatically.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@vs-mobiletools-engineering-service2

This comment has been minimized.

…t diagnostics

The kCFProxyUsernameKey/kCFProxyPasswordKey keys belong to the proxy entries
returned by CFNetworkCopyProxiesForURL, not to the session's
connectionProxyDictionary (which uses the kCFNetworkProxies* SystemConfiguration
keys), so NSUrlSession ignored them. Revert that change.

Add diagnostics (status code + proxy request counts) to the proxy authentication
test assertion messages so the CI TestSummary reveals the actual runtime behavior
(whether the proxy 407 triggers a delegate challenge/retry at all).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

rolfbjarne and others added 2 commits July 10, 2026 12:04
NSUrlSession only delivers a proxy authentication challenge to the delegate
for CONNECT tunnels (HTTPS destinations); for a plain HTTP forward proxy it
returns the 407 directly to the caller without a delegate challenge. So the
proxy-auth tests must exercise an HTTPS destination through the proxy's CONNECT
support.

- Add CONNECT tunneling to ProxyTestServer (validate Proxy-Authorization, then
  200 Connection Established + raw byte pipe to the target).
- Extract the reusable in-proc TLS server (NWListener + self-signed cert) from
  MessageHandlers into a shared TlsTestServer helper.
- Convert the two proxy-auth tests to GET an https:// TLS destination through
  the authenticating proxy.
- Enable HTTPS proxying on non-macOS platforms via the literal "HTTPSEnable"
  key (the strongly-typed HttpsEnable property is macOS-only), required for
  CONNECT tunneling to work there.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

The CONNECT tunnel method was missing its closing brace, causing a CS1513
build failure in monotouch-test (and the autoformatter then over-indented the
rest of the file). Restore the correct structure and indentation.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@vs-mobiletools-engineering-service2

This comment has been minimized.

CFNetwork bypasses the configured proxy for HTTPS (CONNECT) requests to
localhost destinations, so the proxy never saw the request and
AuthenticatedRequestCount stayed 0 on macOS and Mac Catalyst.

Request a non-local hostname instead (so CFNetwork routes the CONNECT
through the proxy) and have the test proxy tunnel every CONNECT to the
local TLS test server via a new forceTunnelPort option.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Implements end-to-end custom proxy support for NSUrlSessionHandler (previously throwing/limited), including proxy routing and proxy authentication, and adds in-process test infrastructure to validate behavior across Apple platforms.

Changes:

  • Implement Proxy, UseProxy, SupportsProxy, and DefaultProxyCredentials in NSUrlSessionHandler, including per-session proxy configuration and proxy auth challenge handling.
  • Add in-process TLS server + HTTP forwarding proxy test server, and new tests validating proxy routing and authentication.
  • Update app-size test baselines to account for the new code.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/monotouch-test/System.Net.Http/TlsTestServer.cs Adds a reusable in-process TLS listener for HTTPS/proxy-tunneling tests.
tests/monotouch-test/System.Net.Http/ProxyTestServer.cs Adds an in-process forwarding proxy with CONNECT support for proxy/auth tests.
tests/monotouch-test/System.Net.Http/NSUrlSessionHandlerTest.cs Adds new tests for proxy routing, proxy auth, and property behavior.
tests/monotouch-test/System.Net.Http/MessageHandlers.cs Refactors existing TLS listener helper usage to the new shared TlsTestServer.
tests/dotnet/UnitTests/expected/TVOS-NativeAOT-TrimmableStatic-size.txt Updates size baseline after Foundation handler changes.
tests/dotnet/UnitTests/expected/MacOSX-NativeAOT-TrimmableStatic-size.txt Updates size baseline after Foundation handler changes.
tests/dotnet/UnitTests/expected/MacCatalyst-NativeAOT-TrimmableStatic-size.txt Updates size baseline after Foundation handler changes.
tests/dotnet/UnitTests/expected/iOS-NativeAOT-TrimmableStatic-size.txt Updates size baseline after Foundation handler changes.
src/Foundation/NSUrlSessionHandler.cs Implements proxy configuration/auth support and enables SupportsProxy.

Comment thread src/Foundation/NSUrlSessionHandler.cs
Comment thread tests/monotouch-test/System.Net.Http/ProxyTestServer.cs
- NSUrlSessionHandler.SendAsync: mark the handler non-modifiable (set
  sentRequest) before configuring the session proxy, so handler
  properties can't be mutated once the first request has started.
- ProxyTestServer.ReadBodyAsync: if the client disconnects early, return
  only the bytes actually read instead of a buffer padded with trailing
  zero bytes.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@rolfbjarne
rolfbjarne requested a review from Copilot July 14, 2026 14:20
@rolfbjarne

Copy link
Copy Markdown
Member Author

/review

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

dalexsoto
dalexsoto previously approved these changes Jul 17, 2026
@vs-mobiletools-engineering-service2

This comment has been minimized.

…net-implement-nsurlsessionhandler-membe-1e40bf

@Redth Redth left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Mostly looks good, one small area to look at more closely.

Comment thread src/Foundation/NSUrlSessionHandler.cs
…downgrading

NSUrlSession's connection proxy dictionary can only describe a plain-HTTP
connection to the proxy: the HTTP/HTTPS proxy keys select which destination
scheme is proxied, not the protocol used to reach the proxy, and there's no
key to connect to the proxy over TLS or via SOCKS.

Previously the proxy uri's scheme was ignored (only host and port were used),
so a secure ('https') or SOCKS proxy would be silently connected to over plain
HTTP -- doing the wrong thing. Throw a NotSupportedException for any proxy
scheme other than 'http' so the misconfiguration fails loudly, and add a test.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

dalexsoto
dalexsoto previously approved these changes Jul 20, 2026
@rolfbjarne rolfbjarne added the ready-to-review This PR is ready to review/merge. label Jul 27, 2026
dalexsoto
dalexsoto previously approved these changes Aug 3, 2026
@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@rolfbjarne
rolfbjarne enabled auto-merge (squash) August 3, 2026 19:58
…net-implement-nsurlsessionhandler-membe-1e40bf

# Conflicts:
#	tests/monotouch-test/System.Net.Http/MessageHandlers.cs
@vs-mobiletools-engineering-service2

Copy link
Copy Markdown
Collaborator

✅ API diff for current PR / commit

NET (empty diffs)

✅ API diff vs stable

NET (empty diffs)

ℹ️ Generator diff

Generator Diff: vsdrops (html) vsdrops (raw diff) gist (raw diff) - Please review changes)

Pipeline on Agent
Hash: 6bffe0d57815e124b7b045aef2bd3ffa081223e5 [PR build]

@vs-mobiletools-engineering-service2

Copy link
Copy Markdown
Collaborator

🚀 [CI Build #6bffe0d] Test results 🚀

Test results

✅ All tests passed on VSTS: test results.

🎉 All 203 tests passed 🎉

Tests counts

✅ assembly-processing: All 1 tests passed. Html Report (VSDrops) Download
✅ cecil: All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (iOS): All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (MacCatalyst): All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (macOS): All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (Multiple platforms): All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (tvOS): All 1 tests passed. Html Report (VSDrops) Download
✅ framework: All 2 tests passed. Html Report (VSDrops) Download
✅ fsharp: All 4 tests passed. Html Report (VSDrops) Download
✅ generator: All 5 tests passed. Html Report (VSDrops) Download
✅ interdependent-binding-projects: All 4 tests passed. Html Report (VSDrops) Download
✅ introspection: All 4 tests passed. Html Report (VSDrops) Download
✅ linker (iOS): All 15 tests passed. Html Report (VSDrops) Download
✅ linker (MacCatalyst): All 15 tests passed. Html Report (VSDrops) Download
✅ linker (macOS): All 21 tests passed. Html Report (VSDrops) Download
✅ linker (tvOS): All 15 tests passed. Html Report (VSDrops) Download
✅ monotouch (iOS): All 19 tests passed. Html Report (VSDrops) Download
✅ monotouch (MacCatalyst): All 18 tests passed. Html Report (VSDrops) Download
✅ monotouch (macOS): All 19 tests passed. Html Report (VSDrops) Download
✅ monotouch (tvOS): All 19 tests passed. Html Report (VSDrops) Download
✅ msbuild: All 2 tests passed. Html Report (VSDrops) Download
✅ sharpie: All 1 tests passed. Html Report (VSDrops) Download
✅ windows: All 3 tests passed. Html Report (VSDrops) Download
✅ xcframework: All 4 tests passed. Html Report (VSDrops) Download
✅ xtro: All 1 tests passed. Html Report (VSDrops) Download

macOS tests

✅ Tests on macOS Monterey (12): All 5 tests passed. Html Report (VSDrops) Download
✅ Tests on macOS Ventura (13): All 5 tests passed. Html Report (VSDrops) Download
✅ Tests on macOS Sonoma (14): All 5 tests passed. Html Report (VSDrops) Download
✅ Tests on macOS Sequoia (15): All 5 tests passed. Html Report (VSDrops) Download
✅ Tests on macOS Tahoe (26): All 5 tests passed. Html Report (VSDrops) Download

Linux Build Verification

Linux build succeeded

Pipeline on Agent
Hash: 6bffe0d57815e124b7b045aef2bd3ffa081223e5 [PR build]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

copilot ready-to-review This PR is ready to review/merge.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support for Proxy in HttpClient in iOS [.NET] Implement NSUrlSessionHandler members that throw PlatformNotSupportedException

5 participants