fix(core): stop SOCKS proxies other than socks5 from crashing startup

Since #22401 every socks* PROXY_URI is handed to undici's ProxyAgent,
which only accepts socks5: and socks:. A socks5h, socks4 or socks4a
URI fell through to its HTTP proxy path and threw "Invalid URL
protocol" while the proxy module loaded, so the server never started,
even though unify-proxy listed all of them as supported.

Pass socks5h to undici as socks5: its SOCKS5 client sends host names
to the proxy, so DNS still resolves there, as playwright.ts already
assumes. undici has no SOCKS4 support, so drop socks4 and socks4a from
the accepted protocols, which logs the supported list and disables the
proxy like any other unsupported protocol.
This commit is contained in:
pseudoyu
2026-10-15 08:29:37 +08:00
parent 8e8a1769e6
commit e0b3b98401
4 changed files with 32 additions and 2 deletions
+24
View File
@@ -80,6 +80,30 @@ describe('proxy', () => {
expect(requestTlsOf(proxy.dispatcher!).ALPNProtocols).toEqual(['h2', 'http/1.1']);
});
it('creates a socks5 dispatcher for socks5h proxies', async () => {
const proxy = await loadProxy({
PROXY_URI: 'socks5h://proxy.local:1080',
PROXY_URIS: '',
PAC_URI: '',
});
expect(proxy.agent).toBeInstanceOf(SocksProxyAgent);
expect(proxy.dispatcher).toBeInstanceOf(ProxyAgent);
expect(proxy.getCurrentProxy()?.uri).toBe('socks5h://proxy.local:1080');
});
it('disables socks4 proxies instead of failing to start', async () => {
const proxy = await loadProxy({
PROXY_URI: 'socks4://proxy.local:1080',
PROXY_URIS: '',
PAC_URI: '',
});
expect(proxy.agent).toBeNull();
expect(proxy.dispatcher).toBeNull();
expect(proxy.getCurrentProxy()).toBeNull();
});
it('prefers h2 on the http proxy dispatcher', async () => {
const proxy = await loadProxy({
PROXY_URI: 'http://proxy.local:8080',
+2 -1
View File
@@ -62,7 +62,8 @@ const createDispatcherForProxy = (uri: string, proxyObj: Config['proxy'], minVer
}
if (uri.startsWith('socks')) {
return new ProxyAgent({
uri,
// undici only accepts socks5: and socks:, and its SOCKS5 client already lets the proxy resolve host names
uri: uri.replace(/^socks5h:/, 'socks5:'),
requestTls: {
ALPNProtocols: ['h2', 'http/1.1'],
minVersion,
+4
View File
@@ -37,6 +37,10 @@ describe('unify-proxy', () => {
it('proxy-obj invalid protocol', () => {
nullExpect(unifyProxy('', { ...emptyProxyObj, protocol: 'ftp', host: 'rsshub.proxy', port: '2333' }));
});
it('proxy-uri socks4 unsupported', () => {
nullExpect(unifyProxy('socks4://rsshub.proxy:2333', emptyProxyObj));
nullExpect(unifyProxy('socks4a://rsshub.proxy:2333', emptyProxyObj));
});
const httpNoPortUri = 'http://rsshub.proxy';
const httpNoPortObj = { ...emptyProxyObj, protocol: 'http', host: 'rsshub.proxy' };
+2 -1
View File
@@ -2,7 +2,8 @@ import type { Config } from '@/config';
import logger from '@/utils/logger';
const defaultProtocol = 'http';
const possibleProtocol = ['http', 'https', 'socks', 'socks4', 'socks4a', 'socks5', 'socks5h'];
// SOCKS4 is left out because the undici dispatcher behind fetch only speaks SOCKS5
const possibleProtocol = ['http', 'https', 'socks', 'socks5', 'socks5h'];
const unifyProxy = (proxyUri: Config['proxyUri'] | string, proxyObj: Config['proxy']) => {
const [oriProxyUri, oriProxyObj] = [proxyUri, proxyObj];