From 1381377e917f5248e5fa8a1426fe5449783094d3 Mon Sep 17 00:00:00 2001 From: Rongrong Date: Mon, 19 Dec 2022 23:39:11 +0800 Subject: [PATCH] fix(core/utils/puppeteer): proxy-chain error (#11470) HTTPS/SOCKS proxy is not supported by proxy-chain and will cause an error unconditionally. If an HTTPS/SOCKS proxy does not need authentication, explicitly bypassing proxy-chain is a must. If it does need, making a warning and continuing without proxy seems to be the best choice. Signed-off-by: Rongrong Signed-off-by: Rongrong --- lib/utils/puppeteer.js | 13 ++++++++- test/utils/puppeteer.js | 60 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 68 insertions(+), 5 deletions(-) diff --git a/lib/utils/puppeteer.js b/lib/utils/puppeteer.js index 1f45868665..1f3ab59d70 100644 --- a/lib/utils/puppeteer.js +++ b/lib/utils/puppeteer.js @@ -1,6 +1,7 @@ const config = require('@/config').value; let puppeteer = require('puppeteer'); const proxyChain = require('proxy-chain'); +const logger = require('./logger'); const options = { args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-infobars', '--window-position=0,0', '--ignore-certificate-errors', '--ignore-certificate-errors-spki-list', `--user-agent=${config.ua}`], @@ -50,7 +51,17 @@ module.exports = async (extraOptions = {}) => { } let browser; if (proxyUri) { - options.args.push(`--proxy-server=${await proxyChain.anonymizeProxy(proxyUri)}`); + if (proxyUri.includes('@')) { + // only proxies with authentication need to be anonymized + if (proxyUri.startsWith('http:')) { + options.args.push(`--proxy-server=${await proxyChain.anonymizeProxy(proxyUri)}`); + } else { + logger.warn('SOCKS/HTTPS proxy with authentication is not supported by puppeteer, continue without proxy'); + } + } else { + // Chromium cannot recognize socks5h and socks4a, so we need to trim their postfixes + options.args.push(`--proxy-server=${proxyUri.replace('socks5h://', 'socks5://').replace('socks4a://', 'socks4://')}`); + } } if (config.puppeteerWSEndpoint) { browser = await puppeteer.connect({ diff --git a/test/utils/puppeteer.js b/test/utils/puppeteer.js index c1ad95e3b2..928036ad31 100644 --- a/test/utils/puppeteer.js +++ b/test/utils/puppeteer.js @@ -67,16 +67,35 @@ describe('puppeteer', () => { expect(chromeTest).toBe('present (passed)'); }, 15000); - it('puppeteer accept proxy uri', async () => { + it('puppeteer accept http proxy uri w/ auth', async () => { process.env.PROXY_URI = 'http://user:pass@rsshub.proxy:2333'; puppeteer = require('../../lib/utils/puppeteer'); browser = await puppeteer(); - expect(browser.process().spawnargs.some((arg) => /^--proxy-server=http:\/\/.*$/.test(arg))).toBe(true); + // trailing slash will cause net::ERR_NO_SUPPORTED_PROXIES, prohibit it + expect(browser.process().spawnargs.some((arg) => /^--proxy-server=http:\/\/.*[^/]$/.test(arg))).toBe(true); }); - it('puppeteer accept proxy', async () => { + it('puppeteer reject https proxy uri w/ auth', async () => { + process.env.PROXY_URI = 'https://user:pass@rsshub.proxy:2333'; + + puppeteer = require('../../lib/utils/puppeteer'); + browser = await puppeteer(); + + expect(browser.process().spawnargs.some((arg) => arg.includes('--proxy-server'))).toBe(false); + }); + + it('puppeteer reject socks proxy uri w/ auth', async () => { + process.env.PROXY_URI = 'socks5://user:pass@rsshub.proxy:2333'; + + puppeteer = require('../../lib/utils/puppeteer'); + browser = await puppeteer(); + + expect(browser.process().spawnargs.some((arg) => arg.includes('--proxy-server'))).toBe(false); + }); + + it('puppeteer accept http proxy', async () => { process.env.PROXY_PROTOCOL = 'http'; process.env.PROXY_HOST = 'rsshub.proxy'; process.env.PROXY_PORT = '2333'; @@ -84,6 +103,39 @@ describe('puppeteer', () => { puppeteer = require('../../lib/utils/puppeteer'); browser = await puppeteer(); - expect(browser.process().spawnargs.some((arg) => /^--proxy-server=http:\/\/.*$/.test(arg))).toBe(true); + expect(browser.process().spawnargs.some((arg) => /^--proxy-server=http:\/\/rsshub.proxy:2333$/.test(arg))).toBe(true); + }, 10000); + + it('puppeteer accept https proxy', async () => { + process.env.PROXY_PROTOCOL = 'https'; + process.env.PROXY_HOST = 'rsshub.proxy'; + process.env.PROXY_PORT = '2333'; + + puppeteer = require('../../lib/utils/puppeteer'); + browser = await puppeteer(); + + expect(browser.process().spawnargs.some((arg) => /^--proxy-server=https:\/\/rsshub.proxy:2333$/.test(arg))).toBe(true); + }, 10000); + + it('puppeteer accept socks4a proxy', async () => { + process.env.PROXY_PROTOCOL = 'socks4a'; + process.env.PROXY_HOST = 'rsshub.proxy'; + process.env.PROXY_PORT = '2333'; + + puppeteer = require('../../lib/utils/puppeteer'); + browser = await puppeteer(); + + expect(browser.process().spawnargs.some((arg) => /^--proxy-server=socks4:\/\/rsshub.proxy:2333$/.test(arg))).toBe(true); + }, 10000); + + it('puppeteer accept socks5h proxy', async () => { + process.env.PROXY_PROTOCOL = 'socks5h'; + process.env.PROXY_HOST = 'rsshub.proxy'; + process.env.PROXY_PORT = '2333'; + + puppeteer = require('../../lib/utils/puppeteer'); + browser = await puppeteer(); + + expect(browser.process().spawnargs.some((arg) => /^--proxy-server=socks5:\/\/rsshub.proxy:2333$/.test(arg))).toBe(true); }, 10000); });