From 4c6deaa4494670a8615ac81df92ec5bb6f3d4621 Mon Sep 17 00:00:00 2001 From: Max Schmitt Date: Thu, 24 Jun 2021 18:50:16 +0200 Subject: [PATCH] test: added tests for WebSocket over Socks proxy (#7235) --- docs/src/assertions.md | 2 +- src/server/firefox/ffNetworkManager.ts | 4 +- tests/config/baseTest.ts | 6 +-- tests/index.d.ts | 26 ++++++++++++ tests/proxy.spec.ts | 58 ++++++++++++++++++++++++++ tests/tsconfig.json | 2 +- 6 files changed, 92 insertions(+), 6 deletions(-) create mode 100644 tests/index.d.ts diff --git a/docs/src/assertions.md b/docs/src/assertions.md index 92c70d406a78f..98ac100554068 100644 --- a/docs/src/assertions.md +++ b/docs/src/assertions.md @@ -265,7 +265,7 @@ expect(userId).toBeTruthy(); // Assert value for input element await page.waitForSelector('#search'); -const value = await page.$eval('#search', el => el.value); +const value = await page.inputValue('#search'); expect(value === 'query').toBeTruthy(); // Assert computed style diff --git a/src/server/firefox/ffNetworkManager.ts b/src/server/firefox/ffNetworkManager.ts index dca3374a7d931..ab2ad37fa9662 100644 --- a/src/server/firefox/ffNetworkManager.ts +++ b/src/server/firefox/ffNetworkManager.ts @@ -94,7 +94,9 @@ export class FFNetworkManager { ipAddress: event.remoteIPAddress, port: event.remotePort, }); - } else {response._serverAddrFinished();} + } else { + response._serverAddrFinished(); + } response._securityDetailsFinished({ protocol: event?.securityDetails?.protocol, subjectName: event?.securityDetails?.subjectName, diff --git a/tests/config/baseTest.ts b/tests/config/baseTest.ts index f1c5272a21b29..ff4667c72a036 100644 --- a/tests/config/baseTest.ts +++ b/tests/config/baseTest.ts @@ -135,7 +135,7 @@ type ServerFixtures = { asset: (p: string) => string; }; -type ServersInternal = ServerFixtures & { socksServer: any }; +type ServersInternal = ServerFixtures & { socksServer: socks.SocksServer }; const serverFixtures: Fixtures = { loopback: [ undefined, { scope: 'worker' } ], __servers: [ async ({ loopback }, run, workerInfo) => { @@ -151,8 +151,8 @@ const serverFixtures: Fixtures { - let socket; - if ((socket = accept(true))) { + const socket = accept(true); + if (socket) { // Catch and ignore ECONNRESET errors. socket.on('error', () => {}); const body = 'Served by the SOCKS proxy'; diff --git a/tests/index.d.ts b/tests/index.d.ts new file mode 100644 index 0000000000000..29a4157e21b3b --- /dev/null +++ b/tests/index.d.ts @@ -0,0 +1,26 @@ +declare module 'socksv5' { + import type net from 'net'; + + class Auth { } + + class SocksServer { + listen: net.Server['listen']; + useAuth(auth: Auth): void; + close: net.Server['close']; + } + + type Info = { + srcAddr: string; + srcPort: number; + dstAddr: string; + dstPort: number; + } + + function acceptHandler(intercept: true): net.Socket | undefined; + function acceptHandler(intercept: false): undefined; + export function createServer(cb: (info: Info, accept: typeof acceptHandler, deny: () => void) => void): SocksServer; + + export const auth: { + None: () => Auth + }; +} diff --git a/tests/proxy.spec.ts b/tests/proxy.spec.ts index 0baa67e546b99..15f2ae0a6aaa1 100644 --- a/tests/proxy.spec.ts +++ b/tests/proxy.spec.ts @@ -15,6 +15,7 @@ */ import { playwrightTest as it, expect } from './config/browserTest'; +import socks from 'socksv5'; import net from 'net'; it('should throw for bad server value', async ({browserType, browserOptions}) => { @@ -203,3 +204,60 @@ it('should use proxy', async ({ browserType, browserOptions }) => { // This connect request should have emulated user agent. expect(requestText).toContain('MyUserAgent'); }); + +async function setupSocksForwardingServer(port: number, forwardPort: number){ + const socksServer = socks.createServer((info, accept, deny) => { + if (!['127.0.0.1', 'fake-localhost-127-0-0-1.nip.io'].includes(info.dstAddr) || info.dstPort !== 1337) { + deny(); + return; + } + const socket = accept(true); + if (socket) { + const dstSock = new net.Socket(); + socket.pipe(dstSock).pipe(socket); + socket.on('close', () => dstSock.end()); + socket.on('end', () => dstSock.end()); + dstSock.setKeepAlive(false); + dstSock.connect(forwardPort, '127.0.0.1'); + } + }); + await new Promise(resolve => socksServer.listen(port, 'localhost', resolve)); + socksServer.useAuth(socks.auth.None()); + return { + closeProxyServer: () => socksServer.close(), + proxyServerAddr: `socks5://localhost:${port}`, + }; +} + +it('should use SOCKS proxy for websocket requests', async ({browserName, platform, browserType, browserOptions, server}, testInfo) => { + it.fixme(browserName === 'webkit' && platform === 'darwin'); + const {proxyServerAddr, closeProxyServer} = await setupSocksForwardingServer(testInfo.workerIndex + 2048 + 2, server.PORT); + const browser = await browserType.launch({ + ...browserOptions, + proxy: { + server: proxyServerAddr, + } + }); + server.sendOnWebSocketConnection('incoming'); + server.setRoute('/target.html', async (req, res) => { + res.end('Served by the proxy'); + }); + + const page = await browser.newPage(); + + // Hosts get resolved by the client + await page.goto('http://fake-localhost-127-0-0-1.nip.io:1337/target.html'); + expect(await page.title()).toBe('Served by the proxy'); + + const value = await page.evaluate(() => { + let cb; + const result = new Promise(f => cb = f); + const ws = new WebSocket('ws://fake-localhost-127-0-0-1.nip.io:1337/ws'); + ws.addEventListener('message', data => { ws.close(); cb(data.data); }); + return result; + }); + expect(value).toBe('incoming'); + + await browser.close(); + closeProxyServer(); +}); diff --git a/tests/tsconfig.json b/tests/tsconfig.json index dd97fb5785a62..83e5dfa89b81d 100644 --- a/tests/tsconfig.json +++ b/tests/tsconfig.json @@ -9,5 +9,5 @@ "strictBindCallApply": true, "allowSyntheticDefaultImports": true, }, - "include": ["**/*.spec.js", "**/*.ts"] + "include": ["**/*.spec.js", "**/*.ts", "index.d.ts"] }