Repository navigation
feat(settings): proxy for Filee's own downloads - #1411
Merged
Merged
Conversation
Settings -> General -> Network takes a proxy address (http, https, socks4, socks4a, socks5; socks5h is read as socks5) for engine downloads, update checks, OCR languages and links dragged from a browser. It applies to Filee alone, so a user who reaches GitHub only through a proxy doesn't have to send every program through the system proxy. Empty keeps today's behaviour: the system proxy and HTTPS_PROXY. The setting lives in settings.json, so a portable copy keeps it in data/. ProxySetting.Use wraps HttpClient.DefaultProxy once, in the app and the CLI, and reads the setting for each request, so every client that uses the default proxy follows it and a change applies without a restart. Addresses on this computer and the local network always go direct. The password in a proxy address is handed to the handler as credentials and never appears in the proxy Uri or the logs. WebDownloader's public-address guard took the handler's CONNECT tunnel to an https site through an http proxy on 127.0.0.1 for a link to this computer and refused it. A CONNECT is only ever sent by the handler to the configured proxy (downloads send GET), so it is now left alone like other proxy connections; the link's own names and numbers are still checked. Closes #879 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The refused-link test never connects, so on a fast machine DisposeAsync stops the listener before Task.Run reaches AcceptTcpClientAsync, which then throws InvalidOperationException. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
What users notice
Settings → General has a new Network card with a Proxy for Filee's downloads box (
http://127.0.0.1:7890,socks5://host:1080,user:pass@allowed). Engine downloads, update checks, OCR language downloads and links dragged from a browser go through it; other programs keep their direct connection, so there's no need to switch the whole system to a proxy just to reach GitHub (#879). An address that isn't a proxy shows a warning under the box and isn't saved; the last valid one stays in use. Empty = today's behaviour (Windows/system proxy,HTTPS_PROXY). The setting is insettings.json, so with portable mode (#1241) it lives indata/next to the app. That was the config file the reporter asked for. The CLI (filee engines install, OCR languages) reads the same setting.Accepted schemes are the ones .NET 10's
SocketsHttpHandlersupports:http,https,socks4,socks4a,socks5. curl-stylesocks5his read assocks5; .NET's socks5 already lets the proxy resolve names. I checked these by hand against a local listener:socks5hitself throwsNotSupportedException. A value with no scheme is taken ashttp://.What changed
src/Filee.Core/Web/ProxySetting.cs(new):TryParse/validation, credentials split off the address,Describefor logs (scheme://host:port only), andUse(), which wrapsHttpClient.DefaultProxyonce in aSettingsWebProxythat reads the setting on every request. Every client that uses the default proxy now follows it with no per-client change:UpdateService(HttpClientHandler),EngineInstaller.CreateHttpClient(engines, OCR languages, upscale models) andWebDownloader. A change in Settings takes effect without a restart. When a proxy is set:localhost/.local/.internalnames and single-label intranet names bypass it (Ollama, Filee Connect, a NAS). The Ollama/translation clients already useUseProxy = falseand are unchanged.Credentialsand are stripped from the proxyUri, so they never show up in .NET's error messages (whichWebDownloaderdisplays) or in Filee's logs.GetProxy/IsBypassed/Credentialsgo to the original system proxy.src/Filee.Core/Settings/AppSettings.cs:string? Proxy. It's nullable with no default, so there's no schema step (it stays at 83).src/Filee.App/App.axaml.cs:ProxySetting.Use(() => store.Settings.Proxy)right after the settings load and before anything downloads. It logs the redacted proxy, or a warning if the stored value is invalid.src/Filee.Cli/CliHost.cs: same call afterstore.Load().src/Filee.App/ViewModels/Pages/GeneralPageViewModel.cs,Views/Pages/GeneralPage.axaml: the Network card.src/Filee.App/Assets/i18n/*.json(all 22):general.network,general.proxy,general.proxy_hint,general.proxy_invalid, translated.src/Filee.Core/Web/WebDownloader.cs, SSRF guard: theConnectCallbackalready left proxy connections alone ("endpoint differs from the link"). For an https link through an http/https proxy, though, .NET first opens the connection for its ownCONNECTrequest, whoseRequestUriis the proxy. The guard took that for a direct link to127.0.0.1and refused it witherror.web_local_address. I confirmed this with a probe and with the new test, which fails without the fix. Clash's system proxy mode at 127.0.0.1:7890 already broke https link drops today. Fix: a connection opened for aCONNECTrequest is treated as a proxy connection.WebDownloaderonly ever sendsGET, so aCONNECTcan only come from the handler's proxy logic, aimed at the proxy the user configured (Filee's setting or the system's). A link can't produce one. The link's own host names and IP literals are still checked on every hop (EnsurePublic), and direct connections still go only to checked addresses. Also added an internalWebDownloader(handler, userAgent, IWebProxy)constructor so tests can pass a proxy without touching the global one.docs/ENGINES.md(one bullet under Optional engines),docs/PORTABLE.md(one sentence),docs/ARCHITECTURE.md(the CONNECT note in the WebDownloader paragraph).Tests
All local, no real network:
ProxySettingTests(Core): accepted/refused addresses (path, query, no port for socks, bad port, ftp, junk), empty = none, credentials unescaped and never in the address orDescribe, internet addresses use the set proxy, local/LAN/intranet addresses bypass it, empty/invalid setting falls back to the system proxy (including its credentials), a change applies on the next request.ProxySettingUseTests(non-parallel collection) checks thatUsewrapsDefaultProxyonce and restores it afterwards.WebDownloaderTests(Core), with a fake proxy on 127.0.0.1 and the shipped local-address guard:CONNECT files.example:443to the proxy and isn't refused as local. This one fails without the fix.ProxyPageTests(App): the box saves valid values trimmed, keeps the last valid value while the text is invalid, and saves empty as null.Results:
dotnet test tests/Filee.Core.Tests --filter ProxySetting|WebDownloader|WebDrop|Settings: 124/124 passed.dotnet test tests/Filee.App.Tests --filter ProxyPageTests|LocalizationTests|CloseActionTests|RenderTests|PortableModeUi: 730/731; the one failure isRenderTests.Engines_page_shows_versions_descriptions_and_download_speed, which trips on a Tesseract installed inC:\Program Files\Tesseract-OCRon this machine and has nothing to do with this change.dotnet test tests/Filee.Cli.Tests: 117 passed, 1 skipped, 1 failed:Zip_to_iso_converts_archive_contents_without_manual_extraction("No engine can do this conversion (zip → iso)"). That failure comes from the worktree, which has noengines/7zipfolder, and has nothing to do with this change.dotnet format --verify-no-changesis clean on Filee.Core, Filee.Cli, Filee.App, Filee.Core.Tests and Filee.App.Tests.Not covered / to decide
IWebProxyAPI. A Windows PAC script that returns several proxies (PROXY a; PROXY b; DIRECT) therefore uses only the first; .NET's internal multi-proxy failover isn't reachable from outside. Installing the wrapper only when a proxy is set would avoid that, but a proxy entered at runtime would then need a restart for clients that have already sent a request (the update checker sends one shortly after start).CONNECTto any proxy the handler picked, which includes the system/PAC proxy, not just Filee's setting. That fixes the same failure with the system proxy. Limiting it toSettingsWebProxy.Configuredis a one-line change if you'd rather keep it strict.Closes #879. The portable half shipped in #1241; this is the proxy half.
🤖 Generated with Claude Code