diff --git a/package.json b/package.json index c26da97b7..cd6966b38 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "testcafe-hammerhead", "description": "A powerful web-proxy used as a core for the TestCafe testing framework (https://github.com/DevExpress/testcafe).", - "version": "29.0.0", + "version": "30.0.0", "homepage": "https://github.com/DevExpress/testcafe-hammerhead", "bugs": { "url": "https://github.com/DevExpress/testcafe-hammerhead/issues" @@ -52,8 +52,8 @@ "@types/parse5": "2.2.34", "@types/semver": "^6.0.0", "@types/tough-cookie": "^4.0.1", - "@typescript-eslint/eslint-plugin": "^5.29.0", - "@typescript-eslint/parser": "^5.29.0", + "@typescript-eslint/eslint-plugin": "^5.54.1", + "@typescript-eslint/parser": "^5.54.1", "babel-eslint": "^10.1.0", "babel-plugin-add-module-exports": "^1.0.0", "basic-auth": "1.0.4", diff --git a/src/client/transport/transport-legacy.ts b/src/client/transport/transport-legacy.ts index 790c1287a..e230c965e 100644 --- a/src/client/transport/transport-legacy.ts +++ b/src/client/transport/transport-legacy.ts @@ -1,6 +1,5 @@ import TransportBase from './transport-base'; import { ServiceMessage } from '../../typings/proxy'; -import MessageSandbox from '../sandbox/event/message'; import Promise from 'pinkie'; import settings from '../settings'; import XhrSandbox from '../sandbox/xhr'; @@ -127,7 +126,7 @@ export default class TransportLegacy extends TransportBase { }); } - public start (messageSandbox: MessageSandbox): void { + public start (): void { // NOTE: There is no special logic here. } } diff --git a/src/proxy/index.ts b/src/proxy/index.ts index 8187b6b94..55ba30187 100644 --- a/src/proxy/index.ts +++ b/src/proxy/index.ts @@ -9,6 +9,7 @@ import { ServiceMessage, ServerInfo, ProxyOptions, + RouterOptions, } from '../typings/proxy'; import http, { ServerOptions } from 'http'; @@ -65,10 +66,11 @@ const DEFAULT_PROXY_OPTIONS = { export default class Proxy extends Router { private readonly openSessions: Map = new Map(); - private readonly server1Info: ServerInfo; - private readonly server2Info: ServerInfo; - private readonly server1: http.Server | https.Server; - private readonly server2: http.Server | https.Server; + private server1Info: ServerInfo | null; + private server2Info: ServerInfo | null; + private server1: http.Server | https.Server | null; + private server2: http.Server | https.Server | null; + private proxyOptions: ProxyOptions | null; private readonly sockets: Set; // Max header size for incoming HTTP requests @@ -78,43 +80,15 @@ export default class Proxy extends Router { // https://github.com/nodejs/node/commit/186035243fad247e3955fa0c202987cae99e82db#diff-1d0d420098503156cddb601e523b82e7R59 public static MAX_REQUEST_HEADER_SIZE = 80 * 1024; - constructor (hostname: string, port1: number, port2: number, options?: Partial) { - const prepareOptions = Object.assign({}, DEFAULT_PROXY_OPTIONS, options); + constructor (options: RouterOptions) { + super(options); - super(prepareOptions); - - // NOTE: to avoid https://github.com/DevExpress/testcafe/issues/7447 - if (typeof dns.setDefaultResultOrder === 'function') - // NOTE: to avoid https://github.com/nodejs/node/issues/40537 - dns.setDefaultResultOrder('ipv4first'); - - const { - ssl, - developmentMode, - cache, - } = prepareOptions; - - const protocol = ssl ? 'https:' : 'http:'; - const opts = this._getOpts(ssl); - const createServer = this._getCreateServerMethod(ssl); - - this.server1Info = createServerInfo(hostname, port1, port2, protocol, cache); - this.server2Info = createServerInfo(hostname, port2, port1, protocol, cache); - - this.server1 = createServer(opts, (req: http.IncomingMessage, res: http.ServerResponse) => this._onRequest(req, res, this.server1Info)); - this.server2 = createServer(opts, (req: http.IncomingMessage, res: http.ServerResponse) => this._onRequest(req, res, this.server2Info)); - - this.server1.on('upgrade', (req: http.IncomingMessage, socket: net.Socket, head: Buffer) => this._onUpgradeRequest(req, socket, head, this.server1Info)); - this.server2.on('upgrade', (req: http.IncomingMessage, socket: net.Socket, head: Buffer) => this._onUpgradeRequest(req, socket, head, this.server2Info)); - - this.server1.listen(port1); - this.server2.listen(port2); - - this.sockets = new Set(); - - // BUG: GH-89 - this._startSocketsCollecting(); - this._registerServiceRoutes(developmentMode); + this.server1 = null; + this.server2 = null; + this.server1Info = null; + this.server2Info = null; + this.proxyOptions = null; + this.sockets = new Set(); } _getOpts (ssl?: {}): ServerOptions { @@ -143,8 +117,8 @@ export default class Proxy extends Router { socket.on('close', () => this.sockets.delete(socket)); }; - this.server1.on('connection', handler); - this.server2.on('connection', handler); + this.server1?.on('connection', handler); // eslint-disable-line no-unused-expressions + this.server2?.on('connection', handler); // eslint-disable-line no-unused-expressions } _registerServiceRoutes (developmentMode: boolean): void { @@ -168,9 +142,7 @@ export default class Proxy extends Router { }); this.POST(SERVICE_ROUTES.messaging, (req: http.IncomingMessage, res: http.ServerResponse, serverInfo: ServerInfo) => this._onServiceMessage(req, res, serverInfo)); - - if (this.options.proxyless) - this.OPTIONS(SERVICE_ROUTES.messaging, (req: http.IncomingMessage, res: http.ServerResponse) => this._onServiceMessagePreflight(req, res)); + this.OPTIONS(SERVICE_ROUTES.messaging, (req: http.IncomingMessage, res: http.ServerResponse) => this._onServiceMessagePreflight(req, res)); this.GET(SERVICE_ROUTES.task, (req: http.IncomingMessage, res: http.ServerResponse, serverInfo: ServerInfo) => this._onTaskScriptRequest(req, res, serverInfo, false)); this.GET(SERVICE_ROUTES.iframeTask, (req: http.IncomingMessage, res: http.ServerResponse, serverInfo: ServerInfo) => this._onTaskScriptRequest(req, res, serverInfo, true)); @@ -189,7 +161,7 @@ export default class Proxy extends Router { res.setHeader(BUILTIN_HEADERS.setCookie, session.takePendingSyncCookies()); - respondWithJSON(res, result, false, this.options.proxyless); + respondWithJSON(res, result, false, this.isProxyless); } catch (err) { logger.serviceMsg.onError(msg, err); @@ -205,7 +177,7 @@ export default class Proxy extends Router { // NOTE: 'Cache-control' header set in the 'Transport' sandbox on the client side. // Request becomes non-simple (https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests) // and initiates the CORS preflight request. - res.setHeader('access-control-allow-headers', BUILTIN_HEADERS.cacheControl); + res.setHeader(BUILTIN_HEADERS.accessControlAllowHeaders, BUILTIN_HEADERS.cacheControl); acceptCrossOrigin(res); respond204(res); } @@ -241,7 +213,7 @@ export default class Proxy extends Router { _onRequest (req: http.IncomingMessage, res: http.ServerResponse | net.Socket, serverInfo: ServerInfo): void { // NOTE: Not a service request, execute the proxy pipeline. if (!this._route(req, res, serverInfo)) - runRequestPipeline(req, res, serverInfo, this.openSessions, this.options.proxyless); + runRequestPipeline(req, res, serverInfo, this.openSessions, this.isProxyless); } _onUpgradeRequest (req: http.IncomingMessage, socket: net.Socket, head: Buffer, serverInfo: ServerInfo): void { @@ -256,11 +228,52 @@ export default class Proxy extends Router { handler.content = prepareShadowUIStylesheet(handler.content as string); } + _prepareDNSRouting (): void { + // NOTE: to avoid https://github.com/DevExpress/testcafe/issues/7447 + if (typeof dns.setDefaultResultOrder === 'function') + // NOTE: to avoid https://github.com/nodejs/node/issues/40537 + dns.setDefaultResultOrder('ipv4first'); + } + // API + start (options: ProxyOptions) { + this.proxyOptions = Object.assign({}, DEFAULT_PROXY_OPTIONS, options); + + this._prepareDNSRouting(); + + const { + hostname, + port1, + port2, + ssl, + developmentMode, + cache, + } = this.proxyOptions; + + const protocol = ssl ? 'https:' : 'http:'; + const opts = this._getOpts(ssl); + const createServer = this._getCreateServerMethod(ssl); + + this.server1Info = createServerInfo(hostname, port1, port2, protocol, !!cache); + this.server2Info = createServerInfo(hostname, port2, port1, protocol, !!cache); + + this.server1 = createServer(opts, (req: http.IncomingMessage, res: http.ServerResponse) => this._onRequest(req, res, this.server1Info as ServerInfo)); + this.server2 = createServer(opts, (req: http.IncomingMessage, res: http.ServerResponse) => this._onRequest(req, res, this.server2Info as ServerInfo)); + + this.server1.on('upgrade', (req: http.IncomingMessage, socket: net.Socket, head: Buffer) => this._onUpgradeRequest(req, socket, head, this.server1Info as ServerInfo)); + this.server2.on('upgrade', (req: http.IncomingMessage, socket: net.Socket, head: Buffer) => this._onUpgradeRequest(req, socket, head, this.server2Info as ServerInfo)); + + this.server1.listen(port1); + this.server2.listen(port2); + + // BUG: GH-89 + this._startSocketsCollecting(); + this._registerServiceRoutes(!!developmentMode); + } close (): void { scriptProcessor.jsCache.reset(); - this.server1.close(); - this.server2.close(); + this.server1?.close(); // eslint-disable-line no-unused-expressions + this.server2?.close(); // eslint-disable-line no-unused-expressions this._closeSockets(); resetKeepAliveConnections(); } @@ -273,21 +286,29 @@ export default class Proxy extends Router { if (externalProxySettings) session.setExternalProxySettings(externalProxySettings); - if (this.options.disableHttp2) + const { + disableHttp2, + disableCrossDomain, + proxyless, + } = this.proxyOptions as ProxyOptions; + + if (disableHttp2) session.disableHttp2(); - if (this.options.disableCrossDomain) + if (disableCrossDomain) session.disableCrossDomain(); url = urlUtils.prepareUrl(url); - if (this.options.proxyless) + if (proxyless) return url; + const serverInfo = this.server1Info as ServerInfo; + return urlUtils.getProxyUrl(url, { - proxyHostname: this.server1Info.hostname, - proxyPort: this.server1Info.port.toString(), - proxyProtocol: this.server1Info.protocol, + proxyHostname: serverInfo.hostname, + proxyPort: serverInfo.port.toString(), + proxyProtocol: serverInfo.protocol, sessionId: session.id, windowId: session.options.windowId, }); @@ -299,7 +320,15 @@ export default class Proxy extends Router { this.openSessions.delete(session.id); } - public resolveRelativeServiceUrl (relativeServiceUrl: string, domain = this.server1Info.domain): string { + public resolveRelativeServiceUrl (relativeServiceUrl: string, domain = (this.server1Info as ServerInfo).domain): string { return new URL(relativeServiceUrl, domain).toString(); } + + public switchToProxyless (): void { + (this.proxyOptions as ProxyOptions).proxyless = true; + } + + public get isProxyless (): boolean { + return !!(this.proxyOptions as ProxyOptions).proxyless; + } } diff --git a/src/proxy/router.ts b/src/proxy/router.ts index 3acae4941..22f3eeba5 100644 --- a/src/proxy/router.ts +++ b/src/proxy/router.ts @@ -33,7 +33,7 @@ function buildRouteParamsMap (routeMatch, paramNames) { } export default abstract class Router { - public readonly options: any; + public readonly options: RouterOptions; protected readonly routes: Map = new Map(); private readonly routesWithParams: RouteWithParams[] = []; diff --git a/src/request-pipeline/builtin-header-names.ts b/src/request-pipeline/builtin-header-names.ts index 2a99a3135..59bae4ec6 100644 --- a/src/request-pipeline/builtin-header-names.ts +++ b/src/request-pipeline/builtin-header-names.ts @@ -38,6 +38,7 @@ export default { accessControlAllowOrigin: 'access-control-allow-origin', accessControlAllowCredentials: 'access-control-allow-credentials', + accessControlAllowHeaders: 'access-control-allow-headers', contentSecurityPolicy: 'content-security-policy', contentSecurityPolicyReportOnly: 'content-security-policy-report-only', xContentSecurityPolicy: 'x-content-security-policy', diff --git a/src/session/index.ts b/src/session/index.ts index ba95224dd..448aac52d 100644 --- a/src/session/index.ts +++ b/src/session/index.ts @@ -148,7 +148,7 @@ export default abstract class Session extends EventEmitter { cookie = cookie || '{{{cookie}}}'; iframeTaskScriptTemplate = iframeTaskScriptTemplate || '{{{iframeTaskScriptTemplate}}}'; - if (this.proxy?.options.proxyless) { + if (this.proxy?.isProxyless) { referer = '""'; cookie = '""'; } @@ -170,7 +170,7 @@ export default abstract class Session extends EventEmitter { isRecordMode, windowId: windowId || '', - proxyless: this.proxy?.options.proxyless || false, + proxyless: this.proxy?.isProxyless || false, disableCrossDomain: this.isCrossDomainDisabled() || false, }); diff --git a/src/typings/proxy.d.ts b/src/typings/proxy.d.ts index 37e4578e4..c21c86b97 100644 --- a/src/typings/proxy.d.ts +++ b/src/typings/proxy.d.ts @@ -31,11 +31,14 @@ interface RequestTimeout { ajax: number; } -interface ProxyOptions extends RouterOptions { - ssl: object; - developmentMode: boolean; - cache: boolean; - disableHttp2: boolean; - proxyless: boolean; - disableCrossDomain: boolean; +interface ProxyOptions { + hostname: string; + port1: number; + port2: number; + ssl?: object; + developmentMode?: boolean; + cache?: boolean; + disableHttp2?: boolean; + disableCrossDomain?: boolean; + proxyless?: boolean; } diff --git a/test/server/auth-test.js b/test/server/auth-test.js index 3094699d7..d05493958 100644 --- a/test/server/auth-test.js +++ b/test/server/auth-test.js @@ -6,7 +6,7 @@ const request = require('request-promise-native'); const headersUtils = require('../../lib/utils/headers'); const { - createProxy, + createAndStartProxy, createSession, } = require('./common/utils'); @@ -16,7 +16,7 @@ describe('Authentication', () => { // eslint-disable-line beforeEach(() => { session = createSession(); - proxy = createProxy(); + proxy = createAndStartProxy(); }); afterEach(() => { diff --git a/test/server/charset-test.js b/test/server/charset-test.js index b4847d7cf..9ef9e720f 100644 --- a/test/server/charset-test.js +++ b/test/server/charset-test.js @@ -1,19 +1,19 @@ -const fs = require('fs'); -const request = require('request-promise-native'); -const expect = require('chai').expect; -const express = require('express'); -const iconv = require('iconv-lite'); -const noop = require('lodash').noop; -const Proxy = require('../../lib/proxy'); -const Session = require('../../lib/session'); -const Charset = require('../../lib/processing/encoding/charset'); -const encodeContent = require('../../lib/processing/encoding').encodeContent; -const decodeContent = require('../../lib/processing/encoding').decodeContent; -const urlUtils = require('../../lib/utils/url'); -const processScript = require('../../lib/processing/script').processScript; -const pageProcessor = require('../../lib/processing/resources/page'); -const stylesheetProcessor = require('../../lib/processing/resources/stylesheet'); -const manifestProcessor = require('../../lib/processing/resources/manifest'); +const fs = require('fs'); +const request = require('request-promise-native'); +const { expect } = require('chai'); +const express = require('express'); +const iconv = require('iconv-lite'); +const { noop } = require('lodash'); +const Session = require('../../lib/session'); +const Charset = require('../../lib/processing/encoding/charset'); +const { encodeContent, decodeContent } = require('../../lib/processing/encoding'); +const urlUtils = require('../../lib/utils/url'); +const { processScript } = require('../../lib/processing/script'); +const pageProcessor = require('../../lib/processing/resources/page'); +const stylesheetProcessor = require('../../lib/processing/resources/stylesheet'); +const manifestProcessor = require('../../lib/processing/resources/manifest'); +const { createAndStartProxy } = require('./common/utils'); + function normalizeCode (code) { return code @@ -141,7 +141,8 @@ describe('Content charset', () => { session.handleAttachment = () => void 0; session.id = 'sessionId'; - proxy = new Proxy('127.0.0.1', 1836, 1837); + proxy = createAndStartProxy(); + proxy.openSession('http://127.0.0.1:2000/', session); }); diff --git a/test/server/common/utils.js b/test/server/common/utils.js index d9589b871..62eb105de 100644 --- a/test/server/common/utils.js +++ b/test/server/common/utils.js @@ -108,8 +108,18 @@ exports.getBasicProxyUrl = function (url, resourceType, reqOrigin, credentials, }); }; -exports.createProxy = function (options = {}) { - return new Proxy(PROXY_HOSTNAME, PROXY_PORT_1, PROXY_PORT_2, options); +exports.createAndStartProxy = function (proxyOptions = {}) { + const proxy = new Proxy(); + + const resultOptions = Object.assign({}, { + hostname: PROXY_HOSTNAME, + port1: PROXY_PORT_1, + port2: PROXY_PORT_2, + }, proxyOptions); + + proxy.start(resultOptions); + + return proxy; }; exports.normalizeNewLine = function (str) { diff --git a/test/server/external-proxy-test.js b/test/server/external-proxy-test.js index b0270d666..1785e633b 100644 --- a/test/server/external-proxy-test.js +++ b/test/server/external-proxy-test.js @@ -1,12 +1,12 @@ -const http = require('http'); -const https = require('https'); -const urlLib = require('url'); -const net = require('net'); -const request = require('request-promise-native'); -const expect = require('chai').expect; -const selfSignedCertificate = require('openssl-self-signed-certificate'); -const Proxy = require('../../lib/proxy'); -const Session = require('../../lib/session'); +const http = require('http'); +const https = require('https'); +const urlLib = require('url'); +const net = require('net'); +const request = require('request-promise-native'); +const { expect } = require('chai'); +const selfSignedCertificate = require('openssl-self-signed-certificate'); +const Session = require('../../lib/session'); +const { createAndStartProxy } = require('./common/utils'); const sockets = []; @@ -43,7 +43,7 @@ describe('External proxy', () => { session.handleFileDownload = () => void 0; session.handleAttachment = () => void 0; - proxy = new Proxy('127.0.0.1', 1836, 1837); + proxy = createAndStartProxy(); httpServer = http.createServer((req, res) => res.end(req.url)).listen(2000); httpsServer = https.createServer({ diff --git a/test/server/proxy/cache-test.js b/test/server/proxy/cache-test.js index d093ca51b..46af69940 100644 --- a/test/server/proxy/cache-test.js +++ b/test/server/proxy/cache-test.js @@ -12,7 +12,7 @@ const { const { createDestinationServer, createSession, - createProxy, + createAndStartProxy, compareCode, getBasicProxyUrl, } = require('../common/utils'); @@ -89,7 +89,7 @@ describe('Cache', () => { }); beforeEach(() => { - proxy = createProxy({ cache: true }); + proxy = createAndStartProxy({ cache: true }); }); afterEach(() => { diff --git a/test/server/proxy/file-protocol-test.js b/test/server/proxy/file-protocol-test.js index d219e6fb8..ef708a30f 100644 --- a/test/server/proxy/file-protocol-test.js +++ b/test/server/proxy/file-protocol-test.js @@ -1,6 +1,6 @@ const { createSession, - createProxy, + createAndStartProxy, getFileProtocolUrl, compareCode, } = require('../common/utils'); @@ -21,7 +21,7 @@ describe('file:// protocol', () => { beforeEach(() => { session = createSession(); - proxy = createProxy(); + proxy = createAndStartProxy(); }); afterEach(() => { diff --git a/test/server/proxy/http2-client-test.js b/test/server/proxy/http2-client-test.js index d8ab6c188..8905373f7 100644 --- a/test/server/proxy/http2-client-test.js +++ b/test/server/proxy/http2-client-test.js @@ -19,7 +19,7 @@ const { const { createSession, - createProxy, + createAndStartProxy, getBasicProxyUrl, createDestinationServer, createHttp2DestServer, @@ -143,7 +143,7 @@ describe('https proxy', () => { beforeEach(() => { session = createSession(); - proxy = createProxy(); + proxy = createAndStartProxy(); logs = []; }); diff --git a/test/server/proxy/https-test.js b/test/server/proxy/https-test.js index 7164fb122..de6673483 100644 --- a/test/server/proxy/https-test.js +++ b/test/server/proxy/https-test.js @@ -5,7 +5,7 @@ const fs = require('fs'); const { createSession, - createProxy, + createAndStartProxy, compareCode, createDestinationServer, } = require('../common/utils'); @@ -38,7 +38,7 @@ describe('https proxy', () => { beforeEach(() => { session = createSession(); - proxy = createProxy({ + proxy = createAndStartProxy({ ssl: { key: selfSignedCertificate.key, cert: selfSignedCertificate.cert, diff --git a/test/server/proxy/index-test.js b/test/server/proxy/index-test.js index 9c7d6502e..2fbe2c9d2 100644 --- a/test/server/proxy/index-test.js +++ b/test/server/proxy/index-test.js @@ -17,7 +17,7 @@ const headersUtils = require('../../../lib/utils/headers'); const { createDestinationServer, createSession, - createProxy, + createAndStartProxy, compareCode, getFileProtocolUrl, getBasicProxyUrl, @@ -339,7 +339,7 @@ describe('Proxy', () => { beforeEach(() => { session = createSession(); - proxy = createProxy(); + proxy = createAndStartProxy(); }); afterEach(() => { diff --git a/test/server/proxy/regression-test.js b/test/server/proxy/regression-test.js index 98f4211c7..00af40411 100644 --- a/test/server/proxy/regression-test.js +++ b/test/server/proxy/regression-test.js @@ -20,7 +20,7 @@ const RequestOptions = require('../../../lib/request-pipeline/request-op const { createSession, - createProxy, + createAndStartProxy, compareCode, getBasicProxyUrl, createDestinationServer, @@ -245,7 +245,7 @@ describe('Regression', () => { beforeEach(() => { session = createSession(); - proxy = createProxy(); + proxy = createAndStartProxy(); }); afterEach(() => { diff --git a/test/server/proxy/request-hooks-test.js b/test/server/proxy/request-hooks-test.js index cfbdc01d9..385f1f44e 100644 --- a/test/server/proxy/request-hooks-test.js +++ b/test/server/proxy/request-hooks-test.js @@ -15,7 +15,7 @@ const { const { createSession, - createProxy, + createAndStartProxy, compareCode, normalizeNewLine, getBasicProxyUrl, @@ -117,7 +117,7 @@ describe('Request Hooks', () => { beforeEach(() => { session = createSession(); - proxy = createProxy(); + proxy = createAndStartProxy(); }); afterEach(() => { diff --git a/test/server/proxy/web-socket-test.js b/test/server/proxy/web-socket-test.js index 249947228..ee1ed1625 100644 --- a/test/server/proxy/web-socket-test.js +++ b/test/server/proxy/web-socket-test.js @@ -7,7 +7,7 @@ const { createDestinationServer, getBasicProxyUrl, createSession, - createProxy, + createAndStartProxy, } = require('../common/utils'); const promisifyEvent = require('promisify-event'); @@ -67,7 +67,7 @@ describe('WebSocket', () => { beforeEach(() => { session = createSession(); - proxy = createProxy(); + proxy = createAndStartProxy(); }); afterEach(() => { diff --git a/ts-defs/index.d.ts b/ts-defs/index.d.ts index 4df9ed64c..b9ed19e48 100644 --- a/ts-defs/index.d.ts +++ b/ts-defs/index.d.ts @@ -211,12 +211,15 @@ declare module 'testcafe-hammerhead' { staticContentCaching?: object; } - export interface ProxyOptions extends RouterOptions { - ssl: object; - developmentMode: boolean; - cache: boolean; - disableHttp2: boolean; - proxyless: boolean; + export interface ProxyOptions { + hostname: string; + port1: number; + port2: number; + ssl?: object; + developmentMode?: boolean; + cache?: boolean; + disableHttp2?: boolean; + proxyless?: boolean; } export interface OnResponseEventData { @@ -300,16 +303,16 @@ declare module 'testcafe-hammerhead' { /** The Proxy class is used to create a web-proxy **/ export class Proxy { /** Creates a web proxy instance **/ - constructor (); - - /** Proxy options **/ - options: ProxyOptions; + constructor (options: RouterOptions); /** Information about server1 **/ server1Info: ServerInfo; /** Information about server2 **/ server2Info: ServerInfo; + /** Start the proxy instance **/ + start (options: ProxyOptions): void; + /** Close the proxy instance */ close (): void; @@ -330,6 +333,9 @@ declare module 'testcafe-hammerhead' { /** Resolve relative service url **/ resolveRelativeServiceUrl (relativeServiceUrl: string, domain?: string): string; + + /** Switch proxy to the proxyless mode **/ + switchToProxyless (): void; } /** The RequestFilterRule class is used to create URL filtering rules for request hook **/