From 28108d4c785b24cc8171e818f9bbdb371ce6148d Mon Sep 17 00:00:00 2001 From: Otto Mao <ottomao@gmail.com> Date: Tue, 21 Jan 2020 10:59:14 +0800 Subject: [PATCH] introduce jest and travis-ci (#541) introduce jest and travis-ci --- .babelrc | 6 - .eslintrc | 2 +- .travis.yml | 5 + README.md | 1 + babel.config.js | 11 + bin/anyproxy-ca | 8 +- jest.config.js | 188 ++++++++ lib/httpsServerMgr.js | 93 ++-- lib/requestHandler.js | 5 +- lib/wsServer.js | 6 +- package.json | 13 +- proxy.js | 23 +- test.js | 16 - test/__snapshots__/basic.spec.js.snap | 57 +++ test/basic.spec.js | 247 ++++++++++ test/data/headers.js | 29 -- test/data/test.css | 3 - test/data/test.eot | Bin 5320 -> 0 bytes test/data/test.js | 4 - test/data/test.json | 3 - test/data/test.png | Bin 105758 -> 0 bytes test/data/test.svg | 14 - test/data/test.ttf | Bin 5152 -> 0 bytes test/data/test.webp | Bin 45982 -> 0 bytes test/data/test.woff | Bin 2960 -> 0 bytes test/data/test.woff2 | Bin 2400 -> 0 bytes test/fixtures/image.png | Bin 0 -> 7181 bytes test/fixtures/someRule.js | 3 + test/jasmine.json | 14 - test/large_post.js | 35 -- test/lib/httpsServerMgr.spec.js | 17 + .../ruleLoader.js => lib/ruleLoader.spec.js} | 29 +- test/{spec_lib/util.js => lib/util.spec.js} | 12 +- test/report/README | 1 - test/rule/beforeDealHttpsRequest.spec.js | 50 ++ test/rule/beforeSendRequest.spec.js | 93 ++++ test/rule/beforeSendResponse.js | 45 ++ test/rule/onError.spec.js | 60 +++ test/server/server.js | 385 ---------------- test/server/startServer.js | 3 - test/spec_lib/proxyServerModule.js | 123 ----- test/spec_lib/webInterface.js | 30 -- test/spec_outweb/test_realweb_spec.js | 147 ------ test/spec_rule/no_rule_big_response_spec.js | 42 -- test/spec_rule/no_rule_spec.js | 427 ------------------ test/spec_rule/no_rule_websocket_spec.js | 134 ------ .../rule/rule_replace_request_data.js | 22 - .../rule/rule_replace_request_option.js | 13 - .../rule/rule_replace_request_protocol.js | 15 - .../rule/rule_replace_response_data.js | 17 - .../rule/rule_replace_response_header.js | 30 -- .../rule/rule_replace_response_status_code.js | 20 - .../rule/rule_should_intercept_https_req.js | 19 - .../rule/rule_should_use_local_response.js | 21 - test/spec_rule/rule_deal_error_spec.js | 155 ------- .../rule_replace_request_data_spec.js | 120 ----- .../rule_replace_request_option_spec.js | 89 ---- .../rule_replace_request_protocol_spec.js | 112 ----- .../rule_replace_response_data_spec.js | 87 ---- .../rule_replace_response_header_spec.js | 91 ---- .../rule_replace_response_status_code_spec.js | 87 ---- .../rule_should_intercept_https_req_spec.js | 87 ---- .../rule_should_use_local_response_spec.js | 55 --- test/util.js | 80 ++++ test/util/CommonUtil.js | 291 ------------ test/util/HttpUtil.js | 373 --------------- test/util/ProxyServerUtil.js | 86 ---- test/util/SimHash.js | 0 .../curlUtil.js => web/curlUtil.spec.js} | 0 test/web/webInterface.spec.js | 27 ++ web/src/common/ApiUtil.js | 6 +- web/src/common/Constant.js | 4 +- web/src/common/WsUtil.js | 1 + web/src/common/apiUtil.js | 62 +++ web/src/common/constant.js | 9 + web/src/common/curlUtil.js | 48 +- web/src/common/wsUtil.js | 42 ++ web/src/component/download-root-ca.jsx | 4 +- web/src/component/header-menu.jsx | 6 +- web/src/component/left-menu.jsx | 4 +- web/src/component/map-local.jsx | 6 +- web/src/component/record-filter.jsx | 2 +- web/src/component/record-request-detail.jsx | 2 +- web/src/component/record-row.jsx | 2 +- .../component/record-ws-message-detail.jsx | 4 +- web/src/component/table-panel.jsx | 2 +- web/src/component/title-bar.jsx | 2 +- web/src/component/ws-listener.jsx | 4 +- web/src/index.jsx | 4 +- web/src/reducer/globalStatusReducer.js | 2 +- web/src/saga/rootSaga.js | 2 +- 91 files changed, 1112 insertions(+), 3387 deletions(-) delete mode 100644 .babelrc create mode 100644 .travis.yml create mode 100644 babel.config.js create mode 100644 jest.config.js delete mode 100644 test.js create mode 100644 test/__snapshots__/basic.spec.js.snap create mode 100644 test/basic.spec.js delete mode 100644 test/data/headers.js delete mode 100644 test/data/test.css delete mode 100755 test/data/test.eot delete mode 100644 test/data/test.js delete mode 100644 test/data/test.json delete mode 100755 test/data/test.png delete mode 100755 test/data/test.svg delete mode 100755 test/data/test.ttf delete mode 100644 test/data/test.webp delete mode 100755 test/data/test.woff delete mode 100755 test/data/test.woff2 create mode 100644 test/fixtures/image.png create mode 100644 test/fixtures/someRule.js delete mode 100644 test/jasmine.json delete mode 100644 test/large_post.js create mode 100644 test/lib/httpsServerMgr.spec.js rename test/{spec_lib/ruleLoader.js => lib/ruleLoader.spec.js} (56%) rename test/{spec_lib/util.js => lib/util.spec.js} (73%) delete mode 100644 test/report/README create mode 100644 test/rule/beforeDealHttpsRequest.spec.js create mode 100644 test/rule/beforeSendRequest.spec.js create mode 100644 test/rule/beforeSendResponse.js create mode 100644 test/rule/onError.spec.js delete mode 100644 test/server/server.js delete mode 100644 test/server/startServer.js delete mode 100644 test/spec_lib/proxyServerModule.js delete mode 100644 test/spec_lib/webInterface.js delete mode 100644 test/spec_outweb/test_realweb_spec.js delete mode 100644 test/spec_rule/no_rule_big_response_spec.js delete mode 100644 test/spec_rule/no_rule_spec.js delete mode 100644 test/spec_rule/no_rule_websocket_spec.js delete mode 100644 test/spec_rule/rule/rule_replace_request_data.js delete mode 100644 test/spec_rule/rule/rule_replace_request_option.js delete mode 100644 test/spec_rule/rule/rule_replace_request_protocol.js delete mode 100644 test/spec_rule/rule/rule_replace_response_data.js delete mode 100644 test/spec_rule/rule/rule_replace_response_header.js delete mode 100644 test/spec_rule/rule/rule_replace_response_status_code.js delete mode 100644 test/spec_rule/rule/rule_should_intercept_https_req.js delete mode 100644 test/spec_rule/rule/rule_should_use_local_response.js delete mode 100644 test/spec_rule/rule_deal_error_spec.js delete mode 100644 test/spec_rule/rule_replace_request_data_spec.js delete mode 100644 test/spec_rule/rule_replace_request_option_spec.js delete mode 100644 test/spec_rule/rule_replace_request_protocol_spec.js delete mode 100644 test/spec_rule/rule_replace_response_data_spec.js delete mode 100644 test/spec_rule/rule_replace_response_header_spec.js delete mode 100644 test/spec_rule/rule_replace_response_status_code_spec.js delete mode 100644 test/spec_rule/rule_should_intercept_https_req_spec.js delete mode 100644 test/spec_rule/rule_should_use_local_response_spec.js create mode 100644 test/util.js delete mode 100644 test/util/CommonUtil.js delete mode 100644 test/util/HttpUtil.js delete mode 100644 test/util/ProxyServerUtil.js delete mode 100644 test/util/SimHash.js rename test/{spec_web/curlUtil.js => web/curlUtil.spec.js} (100%) create mode 100644 test/web/webInterface.spec.js create mode 100644 web/src/common/apiUtil.js create mode 100644 web/src/common/constant.js create mode 100644 web/src/common/wsUtil.js diff --git a/.babelrc b/.babelrc deleted file mode 100644 index 3aa0747..0000000 --- a/.babelrc +++ /dev/null @@ -1,6 +0,0 @@ -{ - "presets": [ - "es2015", - "stage-0" - ] -} \ No newline at end of file diff --git a/.eslintrc b/.eslintrc index 1b7b3f1..e17b451 100644 --- a/.eslintrc +++ b/.eslintrc @@ -5,7 +5,7 @@ "browser": true, "node": true, "es6": true, - "jasmine": true + "jest": true }, "globals": { "React": true, diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..0466163 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,5 @@ +language: node_js +node_js: + - 12 +before_script: + - node ./bin/anyproxy-ca -g \ No newline at end of file diff --git a/README.md b/README.md index 3612f28..b845c9d 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ AnyProxy [![NPM version][npm-image]][npm-url] [![node version][node-image]][node-url] [![npm download][download-image]][download-url] +[](https://travis-ci.org/alibaba/anyproxy) [npm-image]: https://img.shields.io/npm/v/anyproxy.svg?style=flat-square [npm-url]: https://npmjs.org/package/anyproxy diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 0000000..edbb252 --- /dev/null +++ b/babel.config.js @@ -0,0 +1,11 @@ +if (process.env.NODE_ENV === 'test') { + module.exports = {}; +} else { + module.exports = { + presets: [ + 'es2015', + 'stage-0' + ] + }; +} + diff --git a/bin/anyproxy-ca b/bin/anyproxy-ca index f03a60f..85a71f7 100755 --- a/bin/anyproxy-ca +++ b/bin/anyproxy-ca @@ -20,10 +20,10 @@ program .parse(process.argv); function openFolderOfFile(filePath) { - const isWin = /^win/.test(process.platform); - if (isWin) { + const platform = process.platform; + if (/^win/.test(platform)) { exec('start .', { cwd: path.dirname(filePath) }); - } else { + } else if (/darwin/.test(platform)) { exec(`open -R ${filePath}`); } } @@ -33,7 +33,6 @@ function guideToGenrateCA() { if (!error) { const certDir = path.dirname(keyPath); console.log(`The cert is generated at ${certDir}. Please trust the ${color.bold('rootCA.crt')}.`); - // TODO: console.log('guide to install'); openFolderOfFile(crtPath); } else { console.error('failed to generate rootCA', error); @@ -44,7 +43,6 @@ function guideToGenrateCA() { function guideToTrustCA() { const certPath = AnyProxy.utils.certMgr.getRootCAFilePath(); if (certPath) { - // TODO: console.log('guide to install'); openFolderOfFile(certPath); } else { console.error('failed to get cert path'); diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 0000000..5081a7f --- /dev/null +++ b/jest.config.js @@ -0,0 +1,188 @@ +// For a detailed explanation regarding each configuration property, visit: +// https://jestjs.io/docs/en/configuration.html + +module.exports = { + // All imported modules in your tests should be mocked automatically + // automock: false, + + // Stop running tests after `n` failures + // bail: 0, + + // Respect "browser" field in package.json when resolving modules + // browser: false, + + // The directory where Jest should store its cached dependency information + // cacheDirectory: "/private/var/folders/dn/t1cpcmtx6ng82d7qf8b02w7r0000gn/T/jest_dx", + + // Automatically clear mock calls and instances between every test + clearMocks: true, + + // Indicates whether the coverage information should be collected while executing the test + // collectCoverage: false, + + // An array of glob patterns indicating a set of files for which coverage information should be collected + // collectCoverageFrom: null, + + // The directory where Jest should output its coverage files + coverageDirectory: 'coverage', + + // An array of regexp pattern strings used to skip coverage collection + // coveragePathIgnorePatterns: [ + // "/node_modules/" + // ], + + // A list of reporter names that Jest uses when writing coverage reports + // coverageReporters: [ + // "json", + // "text", + // "lcov", + // "clover" + // ], + + // An object that configures minimum threshold enforcement for coverage results + // coverageThreshold: null, + + // A path to a custom dependency extractor + // dependencyExtractor: null, + + // Make calling deprecated APIs throw helpful error messages + // errorOnDeprecated: false, + + // Force coverage collection from ignored files using an array of glob patterns + // forceCoverageMatch: [], + + // A path to a module which exports an async function that is triggered once before all test suites + // globalSetup: null, + + // A path to a module which exports an async function that is triggered once after all test suites + // globalTeardown: null, + + // A set of global variables that need to be available in all test environments + // globals: {}, + + // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. + // maxWorkers: "50%", + + // An array of directory names to be searched recursively up from the requiring module's location + // moduleDirectories: [ + // "node_modules" + // ], + + // An array of file extensions your modules use + // moduleFileExtensions: [ + // "js", + // "json", + // "jsx", + // "ts", + // "tsx", + // "node" + // ], + + // A map from regular expressions to module names that allow to stub out resources with a single module + // moduleNameMapper: {}, + + // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader + // modulePathIgnorePatterns: [], + + // Activates notifications for test results + // notify: false, + + // An enum that specifies notification mode. Requires { notify: true } + // notifyMode: "failure-change", + + // A preset that is used as a base for Jest's configuration + // preset: null, + + // Run tests from one or more projects + // projects: null, + + // Use this configuration option to add custom reporters to Jest + // reporters: undefined, + + // Automatically reset mock state between every test + // resetMocks: false, + + // Reset the module registry before running each individual test + // resetModules: false, + + // A path to a custom resolver + // resolver: null, + + // Automatically restore mock state between every test + // restoreMocks: false, + + // The root directory that Jest should scan for tests and modules within + // rootDir: null, + + // A list of paths to directories that Jest should use to search for files in + // roots: [ + // "<rootDir>" + // ], + + // Allows you to use a custom runner instead of Jest's default test runner + // runner: "jest-runner", + + // The paths to modules that run some code to configure or set up the testing environment before each test + // setupFiles: [], + + // A list of paths to modules that run some code to configure or set up the testing framework before each test + // setupFilesAfterEnv: [], + + // A list of paths to snapshot serializer modules Jest should use for snapshot testing + // snapshotSerializers: [], + + // The test environment that will be used for testing + testEnvironment: 'node', + + // Options that will be passed to the testEnvironment + // testEnvironmentOptions: {}, + + // Adds a location field to test results + // testLocationInResults: false, + + // The glob patterns Jest uses to detect test files + // testMatch: [ + // "**/__tests__/**/*.[jt]s?(x)", + // "**/?(*.)+(spec|test).[tj]s?(x)" + // ], + + // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped + // testPathIgnorePatterns: [ + // "/node_modules/" + // ], + + // The regexp pattern or array of patterns that Jest uses to detect test files + // testRegex: [], + + // This option allows the use of a custom results processor + // testResultsProcessor: null, + + // This option allows use of a custom test runner + // testRunner: "jasmine2", + + // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href + // testURL: "http://localhost", + + // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout" + // timers: "real", + + // A map from regular expressions to paths to transformers + // transform: null, + + // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation + // transformIgnorePatterns: [ + // "/node_modules/" + // ], + + // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them + // unmockedModulePathPatterns: undefined, + + // Indicates whether each individual test should be reported during the run + // verbose: null, + + // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode + // watchPathIgnorePatterns: [], + + // Whether to use watchman for file crawling + // watchman: true, +}; diff --git a/lib/httpsServerMgr.js b/lib/httpsServerMgr.js index e66c840..2b39db0 100644 --- a/lib/httpsServerMgr.js +++ b/lib/httpsServerMgr.js @@ -11,11 +11,11 @@ const async = require('async'), util = require('./util'), wsServerMgr = require('./wsServerMgr'), co = require('co'), + assert = require('assert'), constants = require('constants'), asyncTask = require('async-task-mgr'); const createSecureContext = tls.createSecureContext || crypto.createSecureContext; -//using sni to avoid multiple ports function SNIPrepareCert(serverName, SNICallback) { let keyContent, crtContent, @@ -59,7 +59,6 @@ function SNIPrepareCert(serverName, SNICallback) { //config.port - port to start https server //config.handler - request handler - /** * Create an https server * @@ -73,44 +72,11 @@ function createHttpsServer(config) { } return new Promise((resolve) => { - certMgr.getCertificate('anyproxy_internal_https_server', (err, keyContent, crtContent) => { - const server = https.createServer({ - secureOptions: constants.SSL_OP_NO_SSLv3 || constants.SSL_OP_NO_TLSv1, - SNICallback: SNIPrepareCert, - key: keyContent, - cert: crtContent - }, config.handler).listen(config.port); - resolve(server); - }); - }); -} - -/** -* create an https server that serving on IP address -* @param @required {object} config -* @param @required {string} config.ip the IP address of the server -* @param @required {number} config.port the port to listen on -* @param @required {function} handler the handler of each connect -*/ -function createIPHttpsServer(config) { - if (!config || !config.port || !config.handler) { - throw (new Error('please assign a port')); - } - - if (!config.ip) { - throw (new Error('please assign an IP to create the https server')); - } - - return new Promise((resolve) => { - certMgr.getCertificate(config.ip, (err, keyContent, crtContent) => { - const server = https.createServer({ - secureOptions: constants.SSL_OP_NO_SSLv3 || constants.SSL_OP_NO_TLSv1, - key: keyContent, - cert: crtContent - }, config.handler).listen(config.port); - - resolve(server); - }); + const server = https.createServer({ + secureOptions: constants.SSL_OP_NO_SSLv3 || constants.SSL_OP_NO_TLSv1, + SNICallback: SNIPrepareCert, + }, config.handler).listen(config.port); + resolve(server); }); } @@ -124,20 +90,20 @@ function createIPHttpsServer(config) { */ class httpsServerMgr { constructor(config) { - if (!config || !config.handler) { - throw new Error('handler is required'); - } - this.instanceDefaultHost = '127.0.0.1'; - this.httpsAsyncTask = new asyncTask(); + assert(config, 'config is required'); + assert(config.handler && config.wsHandler, 'handler and wsHandler are required'); + assert(config.hostname, 'hostname is required'); + this.hostname = config.hostname; this.handler = config.handler; - this.wsHandler = config.wsHandler + this.wsHandler = config.wsHandler; + this.httpsAsyncTask = new asyncTask(); + this.asyncTaskName = `https_${Math.random()}`; + this.httpsServer = null; } - getSharedHttpsServer(hostname) { - // ip address will have a unique name - const finalHost = util.isIpDomain(hostname) ? hostname : this.instanceDefaultHost; - + getSharedHttpsServer() { const self = this; + const finalHost = self.hostname; function prepareServer(callback) { let instancePort; co(util.getFreePort) @@ -145,19 +111,10 @@ class httpsServerMgr { instancePort = port; let httpsServer = null; - // if ip address passed in, will create an IP http server - if (util.isIpDomain(hostname)) { - httpsServer = yield createIPHttpsServer({ - ip: hostname, - port, - handler: self.handler - }); - } else { - httpsServer = yield createHttpsServer({ - port, - handler: self.handler - }); - } + httpsServer = yield createHttpsServer({ + port, + handler: self.handler + }); wsServerMgr.getWsServer({ server: httpsServer, @@ -168,6 +125,8 @@ class httpsServerMgr { logUtil.debug('will let WebSocket server to handle the upgrade event'); }); + self.httpsServer = httpsServer; + const result = { host: finalHost, port: instancePort, @@ -181,9 +140,7 @@ class httpsServerMgr { } return new Promise((resolve, reject) => { - // each ip address will gain a unit task name, - // while the domain address will share a common task name - self.httpsAsyncTask.addTask(`createHttpsServer-${finalHost}`, prepareServer, (error, serverInfo) => { + self.httpsAsyncTask.addTask(self.asyncTaskName, prepareServer, (error, serverInfo) => { if (error) { reject(error); } else { @@ -192,6 +149,10 @@ class httpsServerMgr { }); }); } + + close() { + return this.httpsServer && this.httpsServer.close(); + } } module.exports = httpsServerMgr; diff --git a/lib/requestHandler.js b/lib/requestHandler.js index 6ed1e41..6a6c6c0 100644 --- a/lib/requestHandler.js +++ b/lib/requestHandler.js @@ -129,7 +129,7 @@ function fetchRemoteResponse(protocol, options, reqData, config) { }); } else if (isServerDeflated && originContentLen) { refactContentEncoding(); - zlib.inflateRaw(serverResData, (err, buff) => { + zlib.inflate(serverResData, (err, buff) => { if (err) { rejectParsing(err); } else { @@ -893,7 +893,8 @@ class RequestHandler { reqHandlerCtx.httpsServerMgr = new HttpsServerMgr({ handler: reqHandlerCtx.userRequestHandler, - wsHandler: reqHandlerCtx.wsHandler // websocket + wsHandler: reqHandlerCtx.wsHandler, // websocket + hostname: '127.0.0.1', }); this.connectReqHandler = getConnectReqHandler.apply(reqHandlerCtx, [userRule, recorder, reqHandlerCtx.httpsServerMgr]); diff --git a/lib/wsServer.js b/lib/wsServer.js index beb28b2..ec40c99 100644 --- a/lib/wsServer.js +++ b/lib/wsServer.js @@ -59,6 +59,7 @@ class wsServer { const self = this; self.config = config; self.recorder = recorder; + self.checkBroadcastFlagTimer = null; } start() { @@ -78,7 +79,7 @@ class wsServer { // the flat to indicate wheter to broadcast the record let broadcastFlag = true; - setInterval(() => { + self.checkBroadcastFlagTimer = setInterval(() => { broadcastFlag = true; sendMultipleMessage(); }, 50); @@ -161,6 +162,9 @@ class wsServer { closeAll() { const self = this; + if (self.checkBroadcastFlagTimer) { + clearInterval(self.checkBroadcastFlagTimer); + } return new Promise((resolve, reject) => { self.wss.close((e) => { if (e) { diff --git a/package.json b/package.json index ce16669..694fff9 100644 --- a/package.json +++ b/package.json @@ -40,10 +40,13 @@ "ws": "^5.1.0" }, "devDependencies": { + "@babel/core": "^7.8.3", + "@babel/preset-env": "^7.8.3", "antd": "^2.5.0", "autoprefixer": "^6.4.1", "babel-core": "^6.14.0", "babel-eslint": "^7.0.0", + "babel-jest": "^24.9.0", "babel-loader": "^6.2.5", "babel-plugin-import": "^1.0.0", "babel-plugin-transform-runtime": "^6.15.0", @@ -61,11 +64,7 @@ "eslint-plugin-react": "^7.4.0", "extract-text-webpack-plugin": "^3.0.2", "file-loader": "^0.9.0", - "jasmine": "^2.5.3", - "koa": "^1.2.1", - "koa-body": "^1.4.0", - "koa-router": "^5.4.0", - "koa-send": "^3.2.0", + "jest": "^24.9.0", "less": "^2.7.1", "less-loader": "^2.2.3", "node-simhash": "^0.1.0", @@ -86,15 +85,15 @@ "svg-inline-loader": "^0.7.1", "tunnel": "^0.0.6", "url-loader": "^0.5.7", + "urllib": "^2.34.2", "webpack": "^3.10.0", "worker-loader": "^0.7.1" }, "scripts": { "prepublish": "npm run buildweb", - "test": "node test.js", + "test": "npx jest", "lint": "eslint .", "testserver": "node test/server/startServer.js", - "testOutWeb": "jasmine test/spec_outweb/test_realweb_spec.js", "buildweb": "NODE_ENV=production webpack --config web/webpack.config.js --colors", "webserver": "NODE_ENV=test webpack --config web/webpack.config.js --colors --watch", "doc:serve": "node build_scripts/prebuild-doc.js && gitbook serve ./docs-src ./docs --log debug", diff --git a/proxy.js b/proxy.js index 1230a07..76ce576 100644 --- a/proxy.js +++ b/proxy.js @@ -14,25 +14,6 @@ const http = require('http'), wsServerMgr = require('./lib/wsServerMgr'), ThrottleGroup = require('stream-throttle').ThrottleGroup; -// const memwatch = require('memwatch-next'); - -// setInterval(() => { -// console.log(process.memoryUsage()); -// const rss = Math.ceil(process.memoryUsage().rss / 1000 / 1000); -// console.log('Program is using ' + rss + ' mb of Heap.'); -// }, 1000); - -// memwatch.on('stats', (info) => { -// console.log('gc !!'); -// console.log(process.memoryUsage()); -// const rss = Math.ceil(process.memoryUsage().rss / 1000 / 1000); -// console.log('GC !! Program is using ' + rss + ' mb of Heap.'); - -// // var heapUsed = Math.ceil(process.memoryUsage().heapUsed / 1000); -// // console.log("Program is using " + heapUsed + " kb of Heap."); -// // console.log(info); -// }); - const T_TYPE_HTTP = 'http', T_TYPE_HTTPS = 'https', DEFAULT_TYPE = T_TYPE_HTTP; @@ -273,6 +254,10 @@ class ProxyCore extends events.EventEmitter { cltSocket.end(); } + if (this.requestHandler.httpsServerMgr) { + this.requestHandler.httpsServerMgr.close(); + } + if (this.socketPool) { for (const key in this.socketPool) { this.socketPool[key].destroy(); diff --git a/test.js b/test.js deleted file mode 100644 index abd6d8c..0000000 --- a/test.js +++ /dev/null @@ -1,16 +0,0 @@ -const Jasmine = require('jasmine'); - -const jasmine = new Jasmine(); -const util = require('./lib/util'); -const path = require('path'); - -const testTmpPath = path.join(__dirname, './test/temp'); -const configFilePath = path.join(__dirname, './test/jasmine.json'); -// rm - rf./test / temp / -util.deleteFolderContentsRecursive(testTmpPath); - -jasmine.loadConfigFile(configFilePath); -jasmine.configureDefaultReporter({ - showColors: false -}); -jasmine.execute(); diff --git a/test/__snapshots__/basic.spec.js.snap b/test/__snapshots__/basic.spec.js.snap new file mode 100644 index 0000000..c7dc7ef --- /dev/null +++ b/test/__snapshots__/basic.spec.js.snap @@ -0,0 +1,57 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`http - HTTP verbs DELETE: args 1`] = ` +Object { + "foo": "bar", +} +`; + +exports[`http - HTTP verbs DELETE: data 1`] = `""`; + +exports[`http - HTTP verbs GET: args 1`] = ` +Object { + "param": "param_value", +} +`; + +exports[`http - HTTP verbs GET: data 1`] = `undefined`; + +exports[`http - HTTP verbs PATCH: args 1`] = `Object {}`; + +exports[`http - HTTP verbs PATCH: data 1`] = `""`; + +exports[`http - HTTP verbs POST body and header: args 1`] = `Object {}`; + +exports[`http - HTTP verbs POST body and header: data 1`] = `"data:application/octet-stream;base64,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"`; + +exports[`http - HTTP verbs PUT: args 1`] = `Object {}`; + +exports[`http - HTTP verbs PUT: data 1`] = `"data:application/octet-stream;base64,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"`; + +exports[`https - HTTP verbs DELETE: args 1`] = ` +Object { + "foo": "bar", +} +`; + +exports[`https - HTTP verbs DELETE: data 1`] = `""`; + +exports[`https - HTTP verbs GET: args 1`] = ` +Object { + "param": "param_value", +} +`; + +exports[`https - HTTP verbs GET: data 1`] = `undefined`; + +exports[`https - HTTP verbs PATCH: args 1`] = `Object {}`; + +exports[`https - HTTP verbs PATCH: data 1`] = `""`; + +exports[`https - HTTP verbs POST body and header: args 1`] = `Object {}`; + +exports[`https - HTTP verbs POST body and header: data 1`] = `"data:application/octet-stream;base64,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"`; + +exports[`https - HTTP verbs PUT: args 1`] = `Object {}`; + +exports[`https - HTTP verbs PUT: data 1`] = `"data:application/octet-stream;base64,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"`; diff --git a/test/basic.spec.js b/test/basic.spec.js new file mode 100644 index 0000000..f5cadfd --- /dev/null +++ b/test/basic.spec.js @@ -0,0 +1,247 @@ + +process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; +const path = require('path'); +const fs = require('fs'); +const urllib = require('urllib'); +const request = require('request'); +const { basicProxyRequest, proxyServerWithRule, } = require('./util.js'); +const http = require('http'); +const WebSocket = require('ws'); +const tunnel = require('tunnel'); + +let proxyServer; +let proxyPort; +let proxyHost; +let proxyWebInterfaceHost; +beforeAll(async () => { + jest.DEFAULT_TIMEOUT_INTERVAL = 20 * 1000; + proxyServer = await proxyServerWithRule({}, {}); + proxyPort = proxyServer.proxyPort; + proxyHost = `http://localhost:${proxyPort}`; + const proxyWebInterfacePort = proxyServer.webServerInstance.webPort; + proxyWebInterfaceHost = `http://localhost:${proxyWebInterfacePort}`; +}); + +afterAll(() => { + return proxyServer && proxyServer.close(); +}); + +function doProxyWebSocket(url, headers = {}) { + let agent = new tunnel.httpOverHttp({ + proxy: { + hostname: 'localhost', + port: proxyPort, + } + }) + + if (url.indexOf('wss') === 0) { + agent = new tunnel.httpsOverHttp({ + rejectUnauthorized: false, + proxy: { + hostname: 'localhost', + port: proxyPort, + } + }) + } + + const ws = new WebSocket(url, { + agent, + rejectUnauthorized: false, + headers + }); + + return ws; +} + +['http', 'https'].forEach(protocol => { + describe(`${protocol} - HTTP verbs`, () => { + const assertProxyRes = (result) => { + const proxyRes = result.response; + const body = JSON.parse(result.body); + expect(proxyRes.statusCode).toBe(200); + expect(body.args).toMatchSnapshot('args'); + expect(body.data).toMatchSnapshot('data'); + return body; + }; + + it('GET', async () => { + const url = `${protocol}://httpbin.org/get`; + const getParam = { + param: 'param_value' + }; + await basicProxyRequest(proxyHost, 'GET', url, {}, getParam).then(assertProxyRes); + }); + + it('POST body and header', async () => { + const url = `${protocol}://httpbin.org/post`; + const payloadStream = fs.createReadStream(path.resolve(__dirname, './fixtures/image.png')); + + const postHeaders = { + anyproxy_header: 'header_value', + }; + + const body = await basicProxyRequest(proxyHost, 'POST', url, postHeaders, {}, payloadStream).then(assertProxyRes); + expect(body.headers['Anyproxy-Header']).toBe(postHeaders.anyproxy_header); + }); + + it('PUT', async () => { + const url = `${protocol}://httpbin.org/put`; + const payloadStream = fs.createReadStream(path.resolve(__dirname, './fixtures/image.png')); + await basicProxyRequest(proxyHost, 'PUT', url, {}, undefined, payloadStream).then(assertProxyRes); + }); + + it('DELETE', async () => { + const url = `${protocol}://httpbin.org/delete`; + const param = { + foo: 'bar', + }; + await basicProxyRequest(proxyHost, 'DELETE', url, {}, param).then(assertProxyRes); + }); + + it('PATCH', async () => { + const url = `${protocol}://httpbin.org/patch`; + await basicProxyRequest(proxyHost, 'PATCH', url).then(assertProxyRes); + }); + + it('Websocket', async () => { + const expectEcho = (ws) => { + return new Promise((resolve, reject) => { + const wsMsg = Buffer.alloc(100 * 1024, 'a').toString(); // 100kb + + ws.on('open', () => { + ws.send(wsMsg); + }); + + ws.on('message', (msg) => { + expect(msg).toBe(wsMsg); + ws.close(); + resolve(); + }); + }); + }; + + const wsUrl = `${protocol === 'https' ? 'wss' : 'ws'}://echo.websocket.org`; + const ws = doProxyWebSocket(wsUrl, {}); + await expectEcho(ws); + }); + }); +}); + +describe('status code and headers', () => { + [302, 404, 500].forEach(statusCode => { + it(`GET ${statusCode}`, async () => { + const status = statusCode; + const url = `http://httpbin.org/status/${status}`; + const result = await basicProxyRequest(proxyHost, 'GET', url, {}, {}); + const proxyRes = result.response; + expect(proxyRes.statusCode).toBe(statusCode); + }); + + it(`PUT ${statusCode}`, async () => { + const status = statusCode; + const url = `http://httpbin.org/status/${status}`; + const result = await basicProxyRequest(proxyHost, 'PUT', url, {}, {}); + const proxyRes = result.response; + expect(proxyRes.statusCode).toBe(statusCode); + }); + }); +}); + +describe('response data formats', () => { + ['brotli', 'deflate', 'gzip'].forEach(encoding => { + it(`GET ${encoding}`, async () => { + const url = `http://httpbin.org/${encoding}`; + const result = await basicProxyRequest(proxyHost, 'GET', url); + const headers = result.response.headers; + const body = JSON.parse(result.body); + expect(headers['content-encoding']).toBeUndefined(); // should be removed by anyproxy + expect(body.brotli || body.deflated || body.gzipped).toBeTruthy(); + }); + }); +}); + +describe('big files', () => { + const BIG_FILE_SIZE = 100 * 1024 * 1024 - 1; // 100 mb + const BUFFER_FILL = 'a'; + + let server; + beforeAll(() => { + server = http.createServer({}, (req, res) => { + if (/download/.test(req.url)) { + const bufferContent = Buffer.alloc(BIG_FILE_SIZE, BUFFER_FILL); + res.write(bufferContent); + res.end(); + } else if (/upload/.test(req.url)) { + let reqPayloadSize = 0; + req.on('data', (data) => { + const bufferLength = data.length; + reqPayloadSize += bufferLength; + const expectBufferContent = Buffer.alloc(bufferLength, BUFFER_FILL); + if (!expectBufferContent.equals(data)) { + res.statusCode = 500; + res.write('content not match'); + } + }).on('end', () => { + if (res.statusCode === 500 || reqPayloadSize !== BIG_FILE_SIZE) { + res.statusCode = 500; + } else { + res.statusCode = 200; + } + res.end(); + }); + } + }); + + server.listen(3000); + }); + + afterAll((done) => { + server && server.close(done); + }); + + it('download big file', (done) => { + let responseSizeCount = 0; + request({ + url: 'http://127.0.0.1:3000/download', + proxy: proxyHost, + }).on('data', (data) => { + const bufferLength = data.length; + responseSizeCount += bufferLength; + const expectBufferContent = Buffer.alloc(bufferLength, BUFFER_FILL); + if (!expectBufferContent.equals(data)) { + return done(new Error('download content not match')); + } + }).on('end', () => { + if (responseSizeCount !== BIG_FILE_SIZE) { + return done(new Error('file size not match')); + } + done(); + }); + }, 120 * 1000); + + it('upload big file', (done) => { + const bufferContent = Buffer.alloc(BIG_FILE_SIZE, BUFFER_FILL); + const req = request({ + url: 'http://127.0.0.1:3000/upload', + method: 'POST', + proxy: proxyHost, + }, (err, response, body) => { + if (err) { + return done(err); + } else if (response.statusCode !== 200) { + return done(new Error('upload failed ' + body)); + } + done(); + }); + req.write(bufferContent); + req.end(); + }, 120 * 1000); +}); + +describe('web interface', () => { + it('should be available', async () => { + await urllib.request(proxyWebInterfaceHost).then((result) => { + expect(result.status).toBe(200); + }); + }); +}); diff --git a/test/data/headers.js b/test/data/headers.js deleted file mode 100644 index 8062bf0..0000000 --- a/test/data/headers.js +++ /dev/null @@ -1,29 +0,0 @@ -/* -* 用于放置所有header信息的测试数据 -* -*/ - -// Get 和 Post共有的header信息 -/*eslint max-len: ["off"]*/ -const CommonRequestHeader = { - Accept: 'application/json;charset=utf-8,text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', - 'Accept-Charset': 'utf-8', - 'Accept-Encoding': 'gzip, deflate', - 'Accept-Language': 'zh-CN', - 'Accept-Datetime': 'Thu, 31 May 2007 20:35:00 GMT', - Authorization: 'Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==', - 'Cache-Control': 'no-cache', - Connection: 'keep-alive', - Cookie: 'testCookie1=cookie1; testCookie2=cookie2', - 'Content-Type': 'application/x-www-form-urlencoded', - Date: 'Tue, 15 Nov 1994 08:12:31 GMT', - Origin: 'http://localhost', - Pragma: 'no-cache', - some_thing: 'only_to_test_letter_case', - 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36' -}; - -module.exports = { - CommonRequestHeader -}; - diff --git a/test/data/test.css b/test/data/test.css deleted file mode 100644 index 7345751..0000000 --- a/test/data/test.css +++ /dev/null @@ -1,3 +0,0 @@ -.test { - display: block; -} \ No newline at end of file diff --git a/test/data/test.eot b/test/data/test.eot deleted file mode 100755 index c4c74f965eb55d1c1b527f12af37d3047521be65..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5320 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 diff --git a/test/data/test.js b/test/data/test.js deleted file mode 100644 index 8021481..0000000 --- a/test/data/test.js +++ /dev/null @@ -1,4 +0,0 @@ -function test() { - console.info('This is nothing but a js file, to test the js download'); -} -test(); diff --git a/test/data/test.json b/test/data/test.json deleted file mode 100644 index 107be9b..0000000 --- a/test/data/test.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - 'testkey': 'this is just a normal json file' -} \ No newline at end of file diff --git a/test/data/test.png b/test/data/test.png deleted file mode 100755 index 55a2aa302a5bbc31c885566fa4225dcbb5cd1221..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 105758 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	PRNOG$s6)_PwsSvN`2e~Xms@L<v`xJg+yZe} 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 diff --git a/test/data/test.svg b/test/data/test.svg deleted file mode 100755 index b3c6de3..0000000 --- a/test/data/test.svg +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" standalone="no"?> -<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> -<svg xmlns="http://www.w3.org/2000/svg"> -<metadata>Copyright (C) 2016 by original authors @ fontello.com</metadata> -<defs> -<font id="fontello" horiz-adv-x="1000" > -<font-face font-family="fontello" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" /> -<missing-glyph horiz-adv-x="1000" /> -<glyph glyph-name="glass" unicode="" d="M948 746q0-19-24-43l-353-353v-429h179q15 0 25-10t11-25-11-25-25-11h-500q-14 0-25 11t-11 25 11 25 25 10h179v429l-353 353q-24 24-24 43 0 13 10 21t21 9 24 3h786q13 0 24-3t21-9 10-21z" horiz-adv-x="1000" /> - -<glyph glyph-name="music" unicode="" d="M857 725v-625q0-28-19-50t-48-33-58-18-53-6-54 6-58 18-48 33-19 50 19 50 48 33 58 18 54 6q58 0 107-22v300l-429-132v-396q0-28-19-50t-48-33-58-18-53-6-54 6-58 18-48 33-19 50 19 50 48 34 58 17 54 6q58 0 107-21v539q0 17 10 32t28 20l464 142q7 3 16 3 22 0 38-16t15-38z" horiz-adv-x="857.1" /> -</font> -</defs> -</svg> \ No newline at end of file diff --git a/test/data/test.ttf b/test/data/test.ttf deleted file mode 100755 index c3616fe23945564cafbca9856b0fe8f2e84ab93f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5152 zcmd^CO>7&-6@IfzQWB~EA6hXTXXup_SzJ;-wq-@36@?VVI8GW`l3lLTHe6BEk1L5R zMF(~dMGkFY5J{T$(q4)b1q!5x0z)YQ+@OaXS|BYNAV3kI=%L7^fKarz7U-e1`n~0k zY*}f5T)WineDA$)X5PGc^L9moh&t#s(y5SKycUzM58i?1-?*1vS{$9230{7VNTeWN z&u-a;yYavM9P&H3zm<KpBt4%TXhhA;u*=oL+E)4dZ&{FsiF}1Md#3<>CuB6#yta8~ z_09MGG(@DsE@szr_KNqX=HH22>#$F*L(vq~uR;C^<bn0A(rw?_g9FIFhTOWD&)PIc zu(>{l+`MJqF3@j$_aOffvfQ?}a=-uasnd}EMWlUH$nTWS(Mz8aHGK&C#X>Px_{+1Q zUlH~E2=aG{*Y2e;njvk|E^Sl$-24kmbdp@q^TqZDvDn;Lvz^7TMZm^Z0gWI}jW6_j z;w^Gx{%>lSiC(X^;!_$Ih?GWd9ol2A)M{ddX7_1d=nDro>4v^QKLm|us$LiqyF_H- z#=PQs&6a|eSteSqqj%AO!*Q{GUvLEXiJy?G9>WvC9{;~ztxf=tjn0Lr>;v#!jT}c0 z7<!fuZtCyqK6;$a%s$brYov=LLaygE*hHFyXcL!*dj|$w?*5SIZ4zDQCQb`aQ}E2t z`N<RKy2Q|h^E2XN5K8^s{`+t5b@XceZTDN-{r>j7`)~L6`rGvGHh-`7*B)5!FZQ19 z75-CxA$}q3{+_l@P4mEA?B>CSegl4lXkvD>yGs+UPN9o4f^<DeF5$|vuka}Yg_b5w zYtt@2+28+UpWFRdNObkKYY}}$zc_KC%Uu(+X9T44lNSdk&rSGsYiN3UEIKu;4Me9- zPLJPTJd{sOPLKC?i;tUH{8IbmKi@lL`r9?{$>HemNw4q=^V|1JhpJP$r%wxXop!&e zOZJKHckX&JuXIHJNj}{P^B+F?$M0YvZk?6wV`W@0IOcqzk8>VK--rDGy?CStFP%qn zZp+DWa%u##bexGQTf@mXNjuQReO#0H>ZU(8#<~Ex%H-30q0y^}F4eFO{ag*ZfM2L# zH~DC(hCR@~Qo~;C&sq)psE2;Qr_|Mgd2Z6rYFJRG=%`_h+Qkz!tV18JVHfbF8g`Rk zyja5?=(9EKrR!p+hJ7?7ejCph?i4rH)=P3YepXJ5jZezuJ2DT|#<smF?OUbwd~rw4 z%GLaKDYv<qk7V;(b-a*UyR~T->temVo-6Kb<hSK`WUQ`A=C*T1yOdku(RW^5n<$l5 z<!Uj%CFg77%0e-JGnXwz)=Q<r^yp~4C(lQ5%2R>vP?0tes&y)nq+w{!qMbll9;Zp5 zWiTX|Rn`V=lTDk@*mMg$)*Z_Z<XPOSkhY=Cfw2i3p)8(TkLVY`SVR9!j8c5WdUTZQ zU>A`*8_wtwensHjQC1SHZHH+)9<0Ehs_#4WDrTF2wuD~nWzq3U(!4X`p}!LGVB1ZM zlLb5CM5P4nG>zhSbk6$vkX7~bf;Ygimo79^2^YE7Htn4q_tveQjVu!dR}_2!9KHI< z`Qhws@U6&{ims&-mXufSQTx>^%CmSQt<DG3u$5Vr<!foB4cfnK#u3P7jpaZvsK`<j zH|BORM?4b?D`6^`Sq&@Alq*twkW#Lp8@t288&6~t3ooaGMleuLOO;BcgKE|aNHxW1 z%CcmoO0rkfFjO^3sxh{YG4q2|TEdC4EtNNw&OjsC=4CX=XfhMXSe6w~B4k;HqEtF( zSz)D{G9i^~(1t_qcq*;jMof8(7~Hp%$b^;4G~kz9skoP8k}cKA`3ZX>tMri|^l@31 zWsF@Ja}Q!!SJRnPz+SM@h6U^FVj89ZFRC_kSh-Er6c6oU+nmsNAQ~|PAvR*R(w0}1 z$YOlu9to=^Q?ir3c=n!)mO+7=vl)vinK{SFW^=d6NAW~#B-jXci}`Tyz12}f2rk62 z;*3m`4VyQ@i4+Amno0)XWZg@p4;uDdbqe2SbXNoDh0cwoJ=m$0bH<46`n-A~9Sj&j zYa|#}ZDvK&5^BYs3#)b$3y@N^#-HbP0T?k$wXw7SsSQ$CbzqoICnORP$ii*a9?!^f zMyhrMEv!1tD@*B$Yh}(FP;EKmc35?pSFWb7ELN3)AoM+szT2!&NBmm4($Rtavtz0w z#7T<Oja6Ft(T0Z-e(Z!km`YbTa}lgq8QaU#jsy*KtK&e`&RvlEY_+hGB>Yciu!#?C z)n{yA1s|gZLL65#vnzyfvZ2SM3TcU@wCXToGNF7(N-rkP#AF83zt`C*sGVZ5a;DPl z38`Wza0X%O#oBs8Vby0=1h;;~ncEX)Md!BPthl&+%&fS%J!w`v+y=}_6St?#N;9{Q zo0S%BPn)FLLSMj<C*a6w3?ShMw?R0<?HM@2tpP{49e^X;4#E*`hu{dePr?yyhv5jf zXH6M(@_fX^`a3f+&avQ4v(c)voKzuGjfB()j*E#*O(La^JuikmWpJ(fpA6(nScMyV zApFW4QKE0miE`w@s61>MHRT1z&oOXB;?d)ZDsZe@tSA4wP6?iyF{Ub`q7N$>$GYL@ zv0XCAT6-$2Cd|l*Xjq;5JSs9Q3;KC%1^EYML?-!UB7~RA<)o2BB}k)Yqvqkbo)e<4 z7xQ003GpNQ@#j!fOFWb-M+_;WWsEg>XqJ)c7|Mk)!ICP&hk5pDdQX$O4D4w``bjIs z1+E#T67yk3V;)BfyZG=q!J!tRY9-g=nH59naeD<dMvL14;EaWXd9;rWmr!+$d3!2g zV1{|D3ym`i#ye&bIKq|Ch0~4LyOBt!+ebXXh&DP8I!@q;*9e!e!?}<p7dZwJv%80C zF)*SC&6J~7%{aYM&KpUdjCboPCuF>UT106n9g$JI_}Jr`5`!Iv+%pL2GE9wEYjvX@ zO|Fbl+Zp&6R?{^P;`Ob`@Vocu66;&}v}wo)M{OQeH)=&H`2Ph5FWOLJHxJd98fu4K z@A?pD##9$Vb<0D8K4YrMP#HPI$x_B~d}Ly5OGJe*|Ev=(PQZF}Ik^m+iU<x#)yHR1 zEKr~unOa}(=ci)wxWxD(*~f9?x)L>}0>KCNJ80E>jBzmPL5=hJgB*Ewv9^xJlIO7G zzUtw`s~qRBC!)r2789SLpGU0~y*+9IoTRDFqj`>_mOxzPJl<LLI9)b59o2IP>+|L= z(X#+o00e^<%w6GVUIcJ7Ut&%Srk9w*AjKR8SDC|LfjKh(i_BrL#2g0Kn8V;Yb7ld) z%p3-3<}k3B!{7#U;s7r*hrw5v!{DpTVemEPJOl6wa~Ncp!@y<^gJn})Y=k+>f_fV2 z6$eFua!x)$eF?&<siqq2H5MH9x`UX#;UK2oG}TiL>epFtsGAOA>Xw6;x^1fI1~t!u zLoGOnso!uAQ;X(ai%YA28O1`XIj8i2)NOv%gb5$nA1>enM7)WjT>Y#rRLC8}>S=_* zo>vpiRn$%n^2FZPK7hFe+NRk1G+V_w%~b}(-K+R&yqm7*D|3}0mfmlE4gZkN-p%6E a2^4%BTYIgVXdSsH4!)yYZ{S5SNAzD0tecPk diff --git a/test/data/test.webp b/test/data/test.webp deleted file mode 100644 index 565200ab489d6037e98e9f5de5eab505dc7c5875..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 45982 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�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 diff --git a/test/data/test.woff b/test/data/test.woff deleted file mode 100755 index 6324ce3cb91be4b06497774b7dfb5f8929a84724..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2960 zcmY+Gc|4SB8^<4pvCLSq4kp=`V;hFbZYWFkELn;f%tVcSvUKKHjwM^RvM&jRB1<I- z8B1YC*+~wv(}+T(@IE^4`^S5KKEKcX{Jzh1-Piqjo<FWD)Y{k>U;w}cO9!})cRsOy z{qghvFB3ZlLjYiK0;x7Ad$APhaBDjiHIUr}y%8u!J#jNrPhVUB$R<E<1MU$CM)WGr z5Rw=GFv@|97nB%u^oWrVaMc%NIsm|&4%QDy%1C#<iVFsFS!iGk>wm?4l^9L{*$8-+ zASi>>=aVwtc$^m)LI-2epiZ-wDz1Bj5CGW3Kz|aH6pIeT!P}P<1~LQC!;b}%KRP1% zdmhJGfd1ba=YSGlTo_oF%^qZ8zts(E^27P!K}G^=hJyF(rxhVZ1N?(Q&wgB22Gkie zU_BcUga>nBe4xJxDt-~8&=OYYiS@!_XFX8ZI!|n$nPRW!Y;fQf8!p`gi;Du%b<_$} zWzo7B(U3QgzWOL1PBB7E0wW;r%xnt$&Yh;5jgHQWj;>1b;etSnxMB(9c5F`%6CWOn zC$zIO4qdiGAl*<cSTD}~d)?gK$S%}LIT~vw1lV7LErVyQr`K~tq2NsK6Ym?OU@#Pv zJ>9+G{I^D-n4B-=k<Ds#z?I7#6w#EPn$e&QVzai%bQrz%wm7fjF6oZrA$@i0y3(Qj z$TIsR6Rin$<@inp5FYLx<hDL<ECUY#@)4|2<LDDQY|M8u+^jHGQ5vRn4cFD>Q)etg zq(re{8a&0W6xL*wB=c#nwtY>UnRVatnhah!6XCKUq9T?4Y&jtRPFd)3|0wMvp2sC~ z0`@uMZh=bo$e7G+x(?fFyd~9^ET{daI6kR&hS`?8CVTS5$y?{nN!UDpQg@E~r>Jwj z7kS0jnA%u=$+AyLcU9SS9@FYD6CteCSFe4)oPZ{I>o!O`ARJ0fAL?EldWf&wS1?m( zdEG&~)Nj*~U?t(xBJ^g!bXw%<vp#Q)#(B9UV#Ac&MXCHx7{2hkqddzCNo?>wmj3i_ zeHAAbJAWlqPm~op)|odB|7ueSuL#xDuXp#iZCo%o)ssq}rIV!HV_jWwQ_t?K%h{g@ z84ooiexTbQ5z@Zp8$(_wsI?BHV5`V++zR^lX@}y@N`=-xGEK@{8Zvk>pYc|7bG_)X z`2_jEeuVSDKZ9&1Mh-I3@b9^LqQAaQ%V)!Q8N-m&n<mnQti1BLV0E)eR1j7gpZrJF z&Xe4;i#J@lTstDxCkJ!hdC%K~dg!=vopjZ-?fvR~u_Di+Xws~|OrE3kE=eYgRtu5S zFEw-X_0&krG8sNgcoTb0f>CM8+zz9tU0*KG)L$ml+AQ+0IYh~&yce=FRkpjm<k-|a zY&Xfd{nR+pvBE=Z0yezrv!L?TXL3>E{ObOyP=v)CW{goSL+Nzq-53`C1I{7pcs4R_ z96Ir3eM_P8ud#ER<qSVX21Kn#<=HIaavc&J4LoYDJ7@QfRtr@1jD#BHJGNC1GbIHf z1>d%%1Rl7f(b>5?Z8M3(PbHOggV)Vjhmquh8@l=9Roy`hfrN0Y3g_&N&+2c#L5h}~ zi^o@4&0Q<X6!k}Zq8ClHPI`u8VELpON_sMCfsr#E75e~U<mC3ZxFSCs*UW0<B!FY3 zN+UYHc_KQ3gyQR3s_~;Ec4qUFc}`HGA=V>Rw3&8(@!B8F_J*&#?XMXX^Y~@i^Syr* zi7#=}`4+EPCt#Y>lkcwjE-TG=ac_)Y$zNFeQhWWH|EbjPnqM!DCCBMAAB~RLOSgLT zciwrtDH2~ylznu%DvV^A^WH)C<)OR1y%TI(#5B%HuCIX@a8)8UO{*yWT1l1>jY!jZ z_W1@i|6b?88C638n}fYGe8RA)7%OKp=k?j@(eaNBQ`#{>XL%LPRL^YfJMKwHJ{^k4 zaPBKkBZ~$wr(D2KT!Yl`w|tOQ<;t6ude0Q-YJ1vra^f9RA_sCSDtxPmNd~v}h-1O( zQ#{8WGtQ3^E_=E3W|`uxFX!o7a^=5VE9TC9uk=o7fBHcLSG!@@=N|}{QvdNF0&dTL zzY3wjKcIfmuM+D1=EF;0!#AAUl7EDBHdN1bz7^Qb%JdbAC6_0RmX+Nbb1SuaG!;SM z%h@PuW2T5{s7C%dLkdjqd*#xrX5tI6dm)@<H=b`a?{I5v$#$o8p3bXzJ>T!8tmsYm z;YS}S-Io>XzWZ_xU6c_V*}=telv2AN*sS5z%{H1?5CVvS4V$FfN00X>$i)f{af5+U zGgc!n2A8q$UtANBCOeRUUC)&u4(0c|`Mmf1wm%W`o|FoHu2?yPx?a=l{1Q4fK!VJP zo7AK>^>L6Zpn*5bn~|&Hv!4I(&oQ*iM0L;d{_{L#$qp#{k)o;BzD&ancyY!kEukg| z?}XbqgAsJKTNKe?1esEJBT6N&Qw)5Ypb0NV$pT@0NT|E&Ey_3zx5*Lw1wy7Gp{l_M zDH^V>c6AIzQ*s-)QqqWVD1q2nJ56=Y+1TNG4pRl=4_Yy_LyFkL!^+j~>HEAY@SUqM zx%<f&ivx$@BJrIwZiuxFsOk<E2rXVCsCek>6mkwb%iSwPz2%L>U9OMa2F+mKW;i+m zxWWq0r@pr8ut6F}M!F=JDk$YppO3MZ8}cSxpcv*uKd_=<TC0_?<h0r9w07RJl$fSH zp0=2pP!vvQS)>iZYSXe=oc0N+wFS#zLkPCFiwuc8VHoVdOLYvO98R4VDzZgltERq? z-kJq3V0S}wI?Y_oryrAFX`d*sZn<Xev+=ElXUJnb^Y4hYoBfw0xaIyz+)K26<Tsjd z!Qn4^zHYSsN~&Jh*7b35^=my77_3`V^cyHC&F|*O-(v<|gAEn-wYdC>zeur`mvrXM zrbx8N673OnE18^Lxoq-`<!}K}*f!U)m6Th{Nta!<Y1(tp%T(GwJlJFzdYB}L&$xt1 zjCt{Er-ZDmu|i{`h58*Z6iTa!{o7ZuSYVES{kmh<)<-gamJq?fhif8#r^+J^j*gBj zmIP^22FffDUQ<4xHHzEde>q@}WtMXP#lpBG2sb#v*A537i&(P3W)E5Uubjazf4sn1 z0{jmk1QdVo;NSqT1HwQs$c$j%oB)7l-bklfbr|r)A7v!7Ckk6mX(>Qdv&|)7JUl#b zBFPBuYIniM{K72@79O|G&`lhf?Oyl25ERs-V3oXFfWB(Q(yq}ap000=)PxnP_WfY0 zSaDV!(05hNbXUx==`L7QJ9xFoF3RonWDa_&S}bWfMPTolVt}-=(!E*3spC)=<;*{` z&71gZv#Hy~i|jHI&o6hk?g>|pI+|d-y?kwQ)(MX#D_pB8OS^7Acy;>zP!*lpd?Dr3 z+rF<OLGL~Fo!&l~zV$PF?z8&EM51PYtMHG++AH(#Lq>-!2Tl`|mtB+=2M9e`j<6ZD zl{f9tNAF*{ToAeHx;W#m$Lu&U+p?Nqzp_LDt#Wy^6nd+gmF;quy7Ji634((Byx!YF zTf@(2Ng3_Uy(^+WROM$6a~-w^*Kj)G>+cfOR6gW%e&Kv-TrNc=p|yXm>vqRiJon)U zU4J>^e2J$sMmTe~-qm#=Y}+bCA-*vgIum)g!7}d?YyJCQdPD)rP<m8eMq)-@MqIRp zu55i%uEvXJXVH1l41n}YCU7zYXPwPyN`Qo%hoq#Z`vUY$5fYAs_cDtJITf8&MX7m5 zBMO>x5t?F(dQenyzmMQBLy5X<djFSa$rOeT0wLf-Wyiz`L_Oucq=#g164h9P+h5QG p0+CEMG6^zeGBuOpCNAMT76vCNd#`Um%r}f>pn?EAL~<Jd{sWiB5qkgt diff --git a/test/data/test.woff2 b/test/data/test.woff2 deleted file mode 100755 index c40c369c6dd4d092be4a9908fbd5ea90c3537beb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2400 zcmV-m37__NPew8T0RR910103K4*&oF02Ckq00{>G0RR9100000000000000000000 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 SO2V~oOY#)vQdW!v0000Cg?`rn diff --git a/test/fixtures/image.png b/test/fixtures/image.png new file mode 100644 index 0000000000000000000000000000000000000000..f5416aa969379d941d1e022b0dded6e4c2fe8b31 GIT binary patch literal 7181 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 literal 0 HcmV?d00001 diff --git a/test/fixtures/someRule.js b/test/fixtures/someRule.js new file mode 100644 index 0000000..5b4c8fd --- /dev/null +++ b/test/fixtures/someRule.js @@ -0,0 +1,3 @@ +module.exports = { + foo: 'bar', +}; diff --git a/test/jasmine.json b/test/jasmine.json deleted file mode 100644 index f455f85..0000000 --- a/test/jasmine.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "spec_dir": "test", - "spec_files": [ - "spec_lib/*.js", - "spec_rule/*.js", - "spec_web/*.js" - ], - "helpers": [ - "../node_modules/babel-register/lib/node.js", - "../node_modules/babel-polyfill/dist/polyfill.js" - ], - "stopSpecOnExpectationFailure": false, - "random": false -} diff --git a/test/large_post.js b/test/large_post.js deleted file mode 100644 index 45c5865..0000000 --- a/test/large_post.js +++ /dev/null @@ -1,35 +0,0 @@ -const proxyTester = require('proxy-eval'), - Buffer = require('buffer').Buffer, - express = require('express'); - -const app = express(); - -app.post('/', (req, res) => { - const bigBody = new Buffer(1024 * 1024 * 10); - res.send(bigBody); //10 mb -}); -app.listen(3000); - -function test() { - //test the basic availibility of proxy server - setTimeout(() => { - const testParam = { - proxy: 'http://127.0.0.1:8001/', - reqTimeout: 4500, - httpGetUrl: '', - httpPostUrl: 'http://127.0.0.1:3000/', - httpPostBody: '123', - httpsGetUrl: '', - httpsPostUrl: '', - httpsPostBody: '' - }; - proxyTester.test(testParam, (results) => { - process.exit(); - }); - }, 1000); -} - -setTimeout(() => { - test(); -}, 3000); - diff --git a/test/lib/httpsServerMgr.spec.js b/test/lib/httpsServerMgr.spec.js new file mode 100644 index 0000000..c169250 --- /dev/null +++ b/test/lib/httpsServerMgr.spec.js @@ -0,0 +1,17 @@ +const httpsServerMgr = require('../../lib/httpsServerMgr'); + +describe('httpsServerMgr', () => { + it('get https server', async () => { + const serverMgr = new httpsServerMgr({ + hostname: '127.0.0.1', + handler: () => { + console.log('this is handler'); + }, + wsHandler: () => { + console.log('this is handler'); + }, + }); + await serverMgr.getSharedHttpsServer(); + serverMgr.close(); + }); +}); diff --git a/test/spec_lib/ruleLoader.js b/test/lib/ruleLoader.spec.js similarity index 56% rename from test/spec_lib/ruleLoader.js rename to test/lib/ruleLoader.spec.js index 3bf4560..5674b13 100644 --- a/test/spec_lib/ruleLoader.js +++ b/test/lib/ruleLoader.spec.js @@ -1,34 +1,25 @@ -/* -* test for rule replaceOption rule -* -*/ - const ruleLoader = require('../../lib/ruleLoader'); const fs = require('fs'); const path = require('path'); -const localModulePath = path.join(__dirname, '../util/CommonUtil.js'); -describe('rule loader', () => { - it('should successfully cache a remote file', done => { - ruleLoader.cacheRemoteFile('https://cdn.bootcss.com/lodash.js/4.16.4/lodash.min.js') +const localModulePath = path.join(__dirname, '../fixtures/someRule.js'); +describe('ruleLoader', () => { + it('should successfully cache a remote file', async () => { + await ruleLoader.cacheRemoteFile('https://cdn.bootcss.com/lodash.js/4.16.4/lodash.min.js') .then(filePath => { let content; if (filePath) { content = fs.readFileSync(filePath, { encoding: 'utf8' }); } expect(content && content.length > 100).toBe(true); - done(); - }) - .catch(done.fail); + }); }); - it('should load a local module ../util/CommonUtil', done => { - ruleLoader.loadLocalPath(localModulePath) + it('should load a local module ../util/CommonUtil', async () => { + await ruleLoader.loadLocalPath(localModulePath) .then(module => { - expect(module.printLog).not.toBeUndefined(); - done(); - }) - .catch(done.fail); + expect(module.foo).not.toBeUndefined(); + }); }); it('should smart load a remote module', done => { @@ -43,7 +34,7 @@ describe('rule loader', () => { it('should smart load a local module', done => { ruleLoader.requireModule(localModulePath) .then(module => { - expect(module.printLog).not.toBeUndefined(); + expect(module.foo).not.toBeUndefined(); done(); }) .catch(done.fail); diff --git a/test/spec_lib/util.js b/test/lib/util.spec.js similarity index 73% rename from test/spec_lib/util.js rename to test/lib/util.spec.js index 8881df3..d01afcb 100644 --- a/test/spec_lib/util.js +++ b/test/lib/util.spec.js @@ -1,17 +1,13 @@ -/* -* test for rule replaceOption rule -* -*/ const util = require('../../lib/util'); describe('utils', () => { - it('should get some free ports', done => { + it('getFreePort', async () => { const count = 100; const tasks = []; for (let i = 1; i <= count; i++) { tasks.push(util.getFreePort()); } - Promise.all(tasks) + await Promise.all(tasks) .then((results) => { // ensure ports are unique const portMap = {}; @@ -19,8 +15,6 @@ describe('utils', () => { portMap[portNumber] = true; }); expect(Object.keys(portMap).length).toEqual(count); - done(); - }) - .catch(done.fail); + }); }); }); diff --git a/test/report/README b/test/report/README deleted file mode 100644 index bb7c511..0000000 --- a/test/report/README +++ /dev/null @@ -1 +0,0 @@ -* this is a folder to save test reports * \ No newline at end of file diff --git a/test/rule/beforeDealHttpsRequest.spec.js b/test/rule/beforeDealHttpsRequest.spec.js new file mode 100644 index 0000000..d8d04e4 --- /dev/null +++ b/test/rule/beforeDealHttpsRequest.spec.js @@ -0,0 +1,50 @@ +const fs = require('fs'); +const path = require('path'); +const { basicProxyRequest, proxyServerWithRule, } = require('../util.js'); + +const RULE_PAYLOAD = 'this is something in rule'; + +const rule = { + *beforeSendRequest(requestDetail) { + const requestOptions = requestDetail.requestOptions; + return { + requestOptions, + requestData: RULE_PAYLOAD, + }; + }, + + *beforeDealHttpsRequest(requestDetail) { + return requestDetail.host.indexOf('httpbin.org') >= 0; + } +}; + +describe('Rule beforeDealHttpsRequest', () => { + let proxyServer; + let proxyPort; + let proxyHost; + + beforeAll(async () => { + proxyServer = await proxyServerWithRule(rule); + proxyPort = proxyServer.proxyPort; + proxyHost = `http://localhost:${proxyPort}`; + }); + + afterAll(() => { + return proxyServer && proxyServer.close(); + }); + it('Should replace the https request body', async () => { + const url = 'https://httpbin.org/put'; + const payloadStream = fs.createReadStream(path.resolve(__dirname, '../fixtures/image.png')); + const postHeaders = { + anyproxy_header: 'header_value', + }; + + await basicProxyRequest(proxyHost, 'PUT', url, postHeaders, {}, payloadStream).then((result) => { + const proxyRes = result.response; + const body = JSON.parse(result.body); + expect(proxyRes.statusCode).toBe(200); + expect(body.data).toEqual(RULE_PAYLOAD); + expect(body.url.indexOf('/put')).toBeGreaterThan(0); + }); + }); +}); diff --git a/test/rule/beforeSendRequest.spec.js b/test/rule/beforeSendRequest.spec.js new file mode 100644 index 0000000..965808a --- /dev/null +++ b/test/rule/beforeSendRequest.spec.js @@ -0,0 +1,93 @@ +const fs = require('fs'); +const path = require('path'); +const { basicProxyRequest, proxyServerWithRule, } = require('../util.js'); + +const RULE_PAYLOAD = 'this is something in rule'; +const RULE_REPLACE_HEADER_KEY = 'rule_replace_header_key'; +const RULE_REPLACE_HEADER_VALUE = 'rule_replace_header_value'; + +const rule = { + *beforeSendRequest(requestDetail) { + const reqUrl = requestDetail.url; + if (reqUrl.indexOf('/post') >= 0) { + const requestOptions = requestDetail.requestOptions; + requestOptions.path = '/put'; + requestOptions.method = 'PUT'; + return { + requestOptions, + requestData: RULE_PAYLOAD, + }; + } else if (reqUrl.indexOf('/status/302') >= 0) { + return { + response: { + statusCode: 404, + header: { + [RULE_REPLACE_HEADER_KEY]: RULE_REPLACE_HEADER_VALUE, + 'content-type': 'plain/text', + }, + body: RULE_PAYLOAD + } + }; + } else if (reqUrl.indexOf('/should_be_replaced') >= 0) { + const requestOptions = requestDetail.requestOptions; + requestOptions.hostname = 'httpbin.org'; + requestOptions.path = '/status/302'; + requestOptions.port = '443'; + return { + protocol: 'https', + requestOptions, + }; + } + } +}; + +describe('Rule replaceRequestData', () => { + let proxyServer; + let proxyPort; + let proxyHost; + + beforeAll(async () => { + proxyServer = await proxyServerWithRule(rule); + proxyPort = proxyServer.proxyPort; + proxyHost = `http://localhost:${proxyPort}`; + }); + + afterAll(() => { + return proxyServer && proxyServer.close(); + }); + + it('should replace the request data in proxy if the assertion is true', async () => { + const url = 'http://httpbin.org/post'; + const payloadStream = fs.createReadStream(path.resolve(__dirname, '../fixtures/image.png')); + const postHeaders = { + anyproxy_header: 'header_value', + }; + + await basicProxyRequest(proxyHost, 'POST', url, postHeaders, {}, payloadStream).then((result) => { + const proxyRes = result.response; + const body = JSON.parse(result.body); + expect(proxyRes.statusCode).toBe(200); + expect(body.data).toEqual(RULE_PAYLOAD); + expect(body.url.indexOf('/put')).toBeGreaterThan(0); + }); + }); + + it('should respond content specified in rule', async () => { + const url = 'http://httpbin.org/status/302'; + await basicProxyRequest(proxyHost, 'GET', url).then((result) => { + const proxyRes = result.response; + const body = result.body; + expect(body).toBe(RULE_PAYLOAD); + expect(proxyRes.statusCode).toBe(404); + expect(proxyRes.headers[RULE_REPLACE_HEADER_KEY]).toBe(RULE_REPLACE_HEADER_VALUE); + }); + }); + + it('should replace protocol and url', async () => { + const url = 'http://domain_not_exists.anyproxy.io/should_be_replaced'; + await basicProxyRequest(proxyHost, 'GET', url).then((result) => { + const proxyRes = result.response; + expect(proxyRes.statusCode).toBe(302); + }); + }); +}); diff --git a/test/rule/beforeSendResponse.js b/test/rule/beforeSendResponse.js new file mode 100644 index 0000000..dd4169d --- /dev/null +++ b/test/rule/beforeSendResponse.js @@ -0,0 +1,45 @@ +const { basicProxyRequest, proxyServerWithRule, } = require('../util.js'); + +const RULE_REPLACE_HEADER_KEY = 'rule_replace_header_key'; +const RULE_REPLACE_HEADER_VALUE = 'rule_replace_header_value'; +const RULE_REPLACE_BODY = 'RULE_REPLACE_BODY'; +const rule = { + *beforeSendResponse(requestDetail, responseDetail) { + if (requestDetail.url.indexOf('/uuid') >= 0) { + const newResponse = responseDetail.response; + newResponse.header[RULE_REPLACE_HEADER_KEY] = RULE_REPLACE_HEADER_VALUE; + newResponse.body = RULE_REPLACE_BODY; + newResponse.statusCode = 502; + return { + response: newResponse, + }; + } + }, +}; + +describe('Rule replaceResponseData', () => { + let proxyServer; + let proxyPort; + let proxyHost; + + beforeAll(async () => { + proxyServer = await proxyServerWithRule(rule); + proxyPort = proxyServer.proxyPort; + proxyHost = `http://localhost:${proxyPort}`; + }); + + afterAll(() => { + return proxyServer && proxyServer.close(); + }); + + it('Should replace the header and body', async () => { + const url = 'http://httpbin.org/uuid'; + await basicProxyRequest(proxyHost, 'GET', url).then((result) => { + const proxyRes = result.response; + const body = result.body; + expect(proxyRes.statusCode).toBe(502); + expect(proxyRes.headers[RULE_REPLACE_HEADER_KEY]).toBe(RULE_REPLACE_HEADER_VALUE); + expect(body).toBe(RULE_REPLACE_BODY); + }); + }); +}); diff --git a/test/rule/onError.spec.js b/test/rule/onError.spec.js new file mode 100644 index 0000000..b03c9e0 --- /dev/null +++ b/test/rule/onError.spec.js @@ -0,0 +1,60 @@ +const { basicProxyRequest, proxyServerWithRule, } = require('../util.js'); + +const jestMockErrorFn = jest.fn(); +const jestMockConnectErrorFn = jest.fn(); + +const ERROR_PAGE_IN_RULE = 'this is my error page'; +const rule = { + onConnectError: jestMockConnectErrorFn, + *onError(requestDetail, error) { + jestMockErrorFn(requestDetail, error); + return { + response: { + statusCode: '200', + header: {}, + body: ERROR_PAGE_IN_RULE, + } + }; + }, + *beforeDealHttpsRequest(requestDetail) { + return requestDetail.host.indexOf('intercept') === 0; + }, +}; + +describe('Rule replaceResponseData', () => { + let proxyServer; + let proxyPort; + let proxyHost; + + beforeAll(async () => { + proxyServer = await proxyServerWithRule(rule); + proxyPort = proxyServer.proxyPort; + proxyHost = `http://localhost:${proxyPort}`; + }); + + afterAll(() => { + return proxyServer && proxyServer.close(); + }); + + it('should get error', async () => { + const url = 'https://intercept.anyproxy_not_exists.io/some_path'; + const result = await basicProxyRequest(proxyHost, 'GET', url); + const proxyRes = result.response; + const body = result.body; + expect(proxyRes.statusCode).toBe(200); + expect(body).toBe(ERROR_PAGE_IN_RULE); + expect(jestMockErrorFn.mock.calls.length).toBe(1); + }); + + it('should get connec error', async () => { + const url = 'https://anyproxy_not_exists.io/do_not_intercept'; + let e; + try { + await basicProxyRequest(proxyHost, 'GET', url); + } catch (err) { + e = err; + } + expect(e).not.toBeUndefined(); + expect(jestMockConnectErrorFn.mock.calls.length).toBe(1); + }); +}); diff --git a/test/server/server.js b/test/server/server.js deleted file mode 100644 index 1dff4e0..0000000 --- a/test/server/server.js +++ /dev/null @@ -1,385 +0,0 @@ -const Koa = require('koa'); -const KoaRouter = require('koa-router'); -const koaBody = require('koa-body'); -const send = require('koa-send'); -const path = require('path'); -const https = require('https'); -const certMgr = require('../../lib/certMgr'); -const fs = require('fs'); -const nurl = require('url'); -const color = require('colorful'); -const WebSocketServer = require('ws').Server; -const tls = require('tls'); -const crypto = require('crypto'); -const stream = require('stream'); -const brotli = require('brotli'); -const zlib = require('zlib'); - -const createSecureContext = tls.createSecureContext || crypto.createSecureContext; - -const DEFAULT_PORT = 3000; -const HTTPS_PORT = 3001; -const HTTPS_PORT2 = 3002; // start multiple https server -const UPLOAD_DIR = path.resolve(__dirname, '../temp'); -const PROXY_KEY_PREFIX = 'proxy-'; - -function SNICertCallback(serverName, SNICallback) { - certMgr.getCertificate(serverName, (err, key, crt) => { - if (err) { - console.error('error happend in sni callback', err); - return; - } - const ctx = createSecureContext({ - key, - cert: crt - }); - - SNICallback(null, ctx); - }); -} - -function KoaServer() { - this.httpServer = null; - this.httpsServer = null; - this.requestRecordMap = {}; // store all request data to the map - const self = this; - - /** - * log the request info, write as - */ - this.logRequest = function *(next) { - const headers = this.request.headers; - let key = this.request.protocol + '://' + this.request.host + nurl.parse(this.request.url).pathname; // remove param to get clean key - - // take proxy data with 'proxy-' + url - if (headers['via-proxy'] === 'true') { - key = PROXY_KEY_PREFIX + key; - } - - printLog('log request with key :' + key); - let body = this.request.body; - body = typeof body === 'object' ? JSON.stringify(body) : body; - - self.requestRecordMap[key] = { - headers, - body - }; - yield next; - }; - - this.logWsRequest = function (wsReq) { - const headers = wsReq.headers; - const host = headers.host; - const isEncript = wsReq.connection && wsReq.connection.encrypted; - const protocol = isEncript ? 'wss' : 'ws'; - let key = `${protocol}://${host}${wsReq.url}`; - // take proxy data with 'proxy-' + url - if (headers['via-proxy'] === 'true') { - key = PROXY_KEY_PREFIX + key; - } - - self.requestRecordMap[key] = { - headers: wsReq.headers, - body: '' - } - }; - - this.start(); -} - -KoaServer.prototype.constructRouter = function () { - const router = KoaRouter(); - router.post('/test/getuser', koaBody(), this.logRequest, function *(next) { - printLog('requesting post /test/getuser'); - this.response.set('reqbody', JSON.stringify(this.request.body)); - this.response.body = 'body_post_getuser'; - }); - - router.get('/test', this.logRequest, function *(next) { - printLog('request in get: ' + JSON.stringify(this.request)); - this.cookies.set('a1', 'a1value'); - this.cookies.set('a2', 'a2value'); - this.cookies.set('a3', 'a3value'); - this.response.set('header1', 'cookie2=headervalue2'); - - this.response.body = 'something'; - this.response.__req = this.request; - printLog('response in get:' + JSON.stringify(this.response)); - }); - - router.get('/test/uselocal', this.logRequest, function *(next) { - printLog('request in get local:' + JSON.stringify(this.request)); - this.response.body = 'something should be in local'; - // this.response.__req = this.request; - printLog('response in get:' + JSON.stringify(this.response)); - }); - - ['png', 'webp', 'json', 'js', 'css', 'ttf', 'eot', 'svg', 'woff', 'woff2'].forEach(item => { - router.get(`/test/download/${item}`, this.logRequest, function *(next) { - yield send(this, `./data/test.${item}`, { - root: path.resolve(__dirname, '../') - }); - }); - }); - - router.get('/test/response/304', this.logRequest, function *(next) { - this.response.set('Content-Encoding', 'gzip'); - this.status = 304; - }); - - router.get('/test/response/303', function *(next) { - printLog('now to redirect 303'); - this.redirect('/test'); - this.status = 303; - }); - - router.get('/test/response/302', function *(next) { - printLog('now to redirect 302'); - this.redirect('/test'); - }); - - router.get('/test/response/301', function *(next) { - printLog('now to redirect permanently'); - this.redirect('/test'); - this.status = 301; - }); - - const onFileBegin = function (name, file) { - if (!fs.existsSync(UPLOAD_DIR)) { - try { - fs.mkdirSync(UPLOAD_DIR, '0777'); - } catch (e) { - console.log(e); - return null; - } - } - - file.name = 'test_upload_' + Date.now() + '.png'; - const folder = path.dirname(file.path); - file.path = path.join(folder, file.name); - }; - - router.post('/test/upload/png', - this.logRequest, - koaBody({ - multipart: true, - formidable: { - uploadDir: UPLOAD_DIR, - onFileBegin - } - }), - function *(next) { - const file = this.request.body.files.file; - this.response.set('reqbody', JSON.stringify(this.request.body.fields)); - this.response.body = file.path; - } - ); - - router.put('/test/upload/putpng', - this.logRequest, - koaBody({ - multipart: true, - formidable: { - uploadDir: UPLOAD_DIR, - onFileBegin - } - }), - function *(next) { - const file = this.request.body.files.file; - this.response.body = file.path; - } - ); - - router.put('/test/put', koaBody(), this.logRequest, function *(next) { - printLog('requesting put /test/put' + JSON.stringify(this.request)); - this.response.body = 'something in put'; - }); - - router.delete('/test/delete/:id', this.logRequest, function *(next) { - printLog('requesting delete /test/delete/:id' + JSON.stringify(this.params)); - this.response.body = 'something in delete'; - }); - - router.head('/test/head', this.logRequest, function *(next) { - printLog('requesting head /test/head'); - this.response.body = ''; // the body will not be passed to response, in HEAD request - this.response.set('reqBody', 'head_request_contains_no_resbody'); - }); - - router.options('/test/options', this.logRequest, function *(next) { - printLog('requesting options /test/options'); - this.response.body = 'could_be_empty'; - this.response.set('Allow', 'GET, HEAD, POST, OPTIONS'); - }); - - router.get('/test/should_not_replace_option', this.logRequest, function *(next) { - this.response.body = 'the_option_that_not_be_replaced'; - }); - - router.get('/test/should_replace_option', this.logRequest, function *(next) { - this.response.body = 'the_request_that_has_not_be_replaced'; - }); - - router.get('/test/new_replace_option', this.logRequest, function *(next) { - this.response.body = 'the_new_replaced_option_page_content'; - }); - - router.get('/test/normal_request1', this.logRequest, koaBody(), function *(next) { - printLog('requesting get /test/normal_request1'); - this.response.body = 'body_normal_request1'; - }); - - router.get('/test/normal_request2', this.logRequest, koaBody(), function *(next) { - printLog('requesting get /test/normal_request2'); - this.response.body = 'body_normal_request2'; - }); - - router.post('/test/normal_post_request1', koaBody(), this.logRequest, function *(next) { - printLog('requesting post /test/normal_post_request1'); - this.response.body = 'body_normal_post_request1'; - }); - - router.get('/big_response', this.logRequest, function *(next) { - const buf = new Buffer(1 * 1024 * 1024 * 1024); // 1GB - buf.fill(1); - printLog('request in get big response of 1GB'); - this.response.type = 'application/octet-stream'; - this.response.body = buf; - }); - - router.get('/test/brotli', this.logRequest, function *(next) { - this.status = 200; - this.response.set('Content-Encoding', 'br'); - this.response.set('Content-Type', 'application/json'); - const buf = new Buffer('{"type":"brotli","message":"This is a brotli encoding response, but it need to be a long string or the brotli module\'s compress result will be null"}'); - this.response.body = Buffer.from(brotli.compress(buf)); - }); - - router.get('/test/gzip', this.logRequest, function *(next) { - this.status = 200; - this.response.set('Content-Encoding', 'gzip'); - this.response.set('Content-Type', 'application/json'); - const bufStream = new stream.PassThrough(); - bufStream.end(new Buffer('{"type":"gzip","message":"This is a gzip encoding response"}')); - this.response.body = bufStream.pipe(zlib.createGzip()); - }); - - router.get('/test/deflate', this.logRequest, function *(next) { - this.status = 200; - this.response.set('Content-Encoding', 'deflate'); - this.response.set('Content-Type', 'application/json'); - this.response.body = zlib.deflateRawSync('{"type":"deflate","message":"This is a deflate encoding response"}'); - }); - - return router; -}; - -KoaServer.prototype.createWsServer = function (httpServer) { - const wsServer = new WebSocketServer({ - server: httpServer, - path: '/test/socket' - }); - wsServer.on('connection', (ws, wsReq) => { - const self = this; - self.logWsRequest(wsReq); - const messageObj = { - type: 'initial', - content: 'default message' - }; - - ws.send(JSON.stringify(messageObj)); - ws.on('message', message => { - printLog('message from request socket: ' + message); - self.handleRecievedMessage(ws, message); - }); - }) -}; - -KoaServer.prototype.getRequestRecord = function (key) { - return this.requestRecordMap[key] || null; -}; - -KoaServer.prototype.getProxyRequestRecord = function (key) { - key = PROXY_KEY_PREFIX + key; - return this.requestRecordMap[key] || null; -}; - -KoaServer.prototype.handleRecievedMessage = function (ws, message) { - const newMessage = { - type: 'onMessage', - content: message - }; - ws.send(JSON.stringify(newMessage)); -}; - -KoaServer.prototype.start = function () { - printLog('Starting the server...'); - const router = this.constructRouter(); - const self = this; - const app = Koa(); - - app.use(router.routes()); - this.httpServer = app.listen(DEFAULT_PORT); - this.createWsServer(this.httpServer); - - - printLog('HTTP is now listening on port :' + DEFAULT_PORT); - - certMgr.getCertificate('localhost', (error, keyContent, crtContent) => { - if (error) { - console.error('failed to create https server:', error); - } else { - self.httpsServer = https.createServer({ - SNICallback: SNICertCallback, - key: keyContent, - cert: crtContent - }, app.callback()); - - // create wss server - const wss = new WebSocketServer({ - server: self.httpsServer - }); - - wss.on('connection', (ws, wsReq) => { - self.logWsRequest(wsReq); - ws.on('message', (message) => { - printLog('received in wss: ' + message); - self.handleRecievedMessage(ws, message); - }); - }); - - wss.on('error', e => console.error('error happened in wss:%s', e)); - - self.httpsServer.listen(HTTPS_PORT); - - self.httpsServer2 = https.createServer({ - key: keyContent, - cert: crtContent - }, app.callback()); - - self.httpsServer2.listen(HTTPS_PORT2); - - printLog('HTTPS is now listening on port :' + HTTPS_PORT); - - printLog('Server started successfully'); - } - }); - - return this; -}; - -KoaServer.prototype.close = function () { - printLog('Closing server now...'); - this.httpServer && this.httpServer.close(); - this.httpsServer && this.httpsServer.close(); - this.httpsServer2 && this.httpsServer2.close(); - this.requestRecordMap = {}; - printLog('Server closed successfully'); -}; - - -function printLog(content) { - console.log(color.cyan('[SERVER LOG]: ' + content)); -} - -module.exports = KoaServer; diff --git a/test/server/startServer.js b/test/server/startServer.js deleted file mode 100644 index 7b861e3..0000000 --- a/test/server/startServer.js +++ /dev/null @@ -1,3 +0,0 @@ -const Server = require('./server.js'); - -new Server(); diff --git a/test/spec_lib/proxyServerModule.js b/test/spec_lib/proxyServerModule.js deleted file mode 100644 index 3a52ef2..0000000 --- a/test/spec_lib/proxyServerModule.js +++ /dev/null @@ -1,123 +0,0 @@ -/* -* test for rule replaceOption rule -* -*/ -const AnyProxy = require('../../proxy'); -const { - proxyGet, - directGet, - generateUrl, -} = require('../util/HttpUtil.js'); -const Server = require('../server/server.js'); - -describe('AnyProxy.proxyServer basic test', () => { - it('should successfully start a proxy server', done => { - const options = { - port: 8001, - rule: null, - webInterface: { - enable: true, - webPort: 8002 - }, - throttle: 10000, - forceProxyHttps: false, - silent: false - }; - const proxyServer = new AnyProxy.ProxyServer(options); - proxyServer.on('ready', () => { - proxyServer.close(); - done(); - }); - proxyServer.on('error', done.fail); - proxyServer.start(); - }); -}); - -describe('AnyProxy.proxyServer high order test', () => { - let proxyServer; - let serverInstance; - beforeAll(done => { - // jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000; - serverInstance = new Server(); - - const options = { - port: 8001, - rule: null, - webInterface: { - enable: true, - webPort: 8002, - }, - throttle: 10000, - forceProxyHttps: false, - silent: false - }; - proxyServer = new AnyProxy.ProxyServer(options); - proxyServer.on('ready', done); - proxyServer.start(); - }); - - afterAll(() => { - proxyServer && proxyServer.close(); - serverInstance && serverInstance.close(); - }); - - it('should work as expected for domain host', done => { - // test if proxy server works - proxyGet('https://www.tmall.com', {}, {}) - .then(res => { - expect(res && res.statusCode && res.statusCode === 200 && res.body.length > 300).toBe(true); - done(); - }) - .catch(done); - }); - - it('should work as expected for ip host', done => { - // test if proxy server works - proxyGet(generateUrl('https', '/test'), {}, {}) - .then(res => { - expect(res && res.statusCode && res.statusCode === 200).toBe(true); - done(); - }) - .catch(done); - }); - - it('should start webinterface correctly', done => { - // test web interface - directGet('http://127.0.0.1:8002', {}, {}) - .then(res => { - expect(res && res.statusCode && res.statusCode === 200 && res.body.length > 300).toBe(true); - done(); - }) - .catch(done); - }); - - it('should deal well with the gzip encoding response', done => { - proxyGet(generateUrl('https', '/test/gzip'), {}, {}) - .then(res => { - expect(res && res.statusCode === 200).toBe(true); - expect(JSON.parse(res.body).type).toBe('gzip'); - done(); - }) - .catch(done); - }); - - it('should deal well with the deflate encoding response', done => { - proxyGet(generateUrl('https', '/test/deflate'), {}, {}) - .then(res => { - expect(res && res.statusCode === 200).toBe(true); - expect(JSON.parse(res.body).type).toBe('deflate'); - done(); - }) - .catch(done); - }); - - it('should deal well with the brotli encoding response', done => { - proxyGet(generateUrl('https', '/test/brotli'), {}, {}) - .then(res => { - expect(res && res.statusCode === 200).toBe(true); - expect(JSON.parse(res.body).type).toBe('brotli'); - done(); - }) - .catch(done); - }); -}); diff --git a/test/spec_lib/webInterface.js b/test/spec_lib/webInterface.js deleted file mode 100644 index f3f8570..0000000 --- a/test/spec_lib/webInterface.js +++ /dev/null @@ -1,30 +0,0 @@ -const WebInterface = require('../../lib/webInterface.js'); -const Recorder = require('../../lib/recorder'); -const { directGet } = require('../util/HttpUtil.js'); - -describe('WebInterface server', () => { - let webServer = null; - const webHost = 'http://127.0.0.1:8002' - - beforeAll(() => { - const recorder = new Recorder(); - webServer = new WebInterface({ - webPort: 8002, - }, recorder); - }); - - afterAll(() => { - webServer.close(); - }); - - it('should response qrcode string in /getQrCode', done => { - directGet(`${webHost}/api/getQrCode`) - .then(res => { - const body = JSON.parse(res.body); - expect(body.qrImgDom).toMatch('<img src="data:image/'); - expect(body.url).toBe(`${webHost}/downloadCrt`); - done(); - }) - .catch(done); - }); -}); diff --git a/test/spec_outweb/test_realweb_spec.js b/test/spec_outweb/test_realweb_spec.js deleted file mode 100644 index 50cc76f..0000000 --- a/test/spec_outweb/test_realweb_spec.js +++ /dev/null @@ -1,147 +0,0 @@ - -/** - * use phantomjs to capture requests in real websites, then compare the directly-connected response with those through AnyProxy - */ -const fs = require('fs'); -const ProxyServerUtil = require('../util/ProxyServerUtil.js'); -const HttpUtil = require('../util/HttpUtil.js'); -const path = require('path'); -const { printLog, printError, printHilite, stringSimilarity } = require('../util/CommonUtil.js'); - -const reportPath = path.join(__dirname, '../report/'); - -const testUrls = ['https://www.taobao.com', 'https://www.baidu.com', 'https://www.tmall.com']; - -let direcrtResponseSampleA = []; -let direcrtResponseSampleB = []; -let proxyResponse = []; - -function test(url, requestHeaders = {}) { - describe('Test requests in real broswer', () => { - let proxyServer; - - beforeAll((done) => { - jasmine.DEFAULT_TIMEOUT_INTERVAL = 200000; - printLog('Start server for ' + url); - - proxyServer = ProxyServerUtil.defaultProxyServer(); - setTimeout(() => { - done(); - }, 2000); - }); - - afterAll(() => { - proxyServer && proxyServer.close(); - printLog('Closed server for ' + url); - }); - - it(`Request towards ${url}`, (done) => { - HttpUtil.getRequestListFromPage(url).then((arr) => { - const directPromisesA = []; - const directPromisesB = []; - const proxyPromises = []; - arr.forEach((data, i) => { - const requestPath = data.url; - const headers = data.headers; - const method = data.method; - const params = data.method === 'POST' ? JSON.parse(data.postData) : {}; - if (HttpUtil.isSupportedProtocol(requestPath)) { - directPromisesA.push(HttpUtil.directRequest(method, requestPath, params, headers)); - directPromisesB.push(HttpUtil.directRequest(method, requestPath, params, headers)); - proxyPromises.push(HttpUtil.proxyRequest(method, requestPath, params, headers)); - } - }); - Promise.all(directPromisesA).then(responseArr => { direcrtResponseSampleA = responseArr }).then(() => { - Promise.all(directPromisesB).then(responseArr => { direcrtResponseSampleB = responseArr }).then(() => { - Promise.all(proxyPromises).then(responseArr => { proxyResponse = responseArr }).then(() => { - showResponseResult(); - const { compareResult: TESTRESULT, errRecord } = compareResponses(url); - const reportFile = dealLogFile(errRecord, url, () => { - printHilite('====== COMPARE RESULT: ' + TESTRESULT.toString().toUpperCase() + ' ======'); - !TESTRESULT && printHilite(`Check more details in ${reportFile}`); - // expect(TESTRESULT).toBe(true); - done(); - }); - }) - .catch((err) => { - printError(err); - done(); - }); - }) - .catch((err) => { - printError(err); - done(); - }); - }) - .catch((err) => { - printError(err); - done(); - }); - }); - }) - }) -} - -function compareResponses(curUrl) { - const errRecord = []; - if (direcrtResponseSampleA.length !== direcrtResponseSampleB.length || direcrtResponseSampleA.length !== proxyResponse.length) { - printError('compare fail: length not match'); - return { - compareResult: false, - errRecord - } - } - for (let i = 0; i < proxyResponse.length; i++) { - const direcrtResponseInfoA = direcrtResponseSampleA[i]; - const direcrtResponseInfoB = direcrtResponseSampleB[i]; - const proxyResponseInfo = proxyResponse[i]; - const { similarity: similarity_direct } = stringSimilarity(stringify(direcrtResponseInfoA.body), stringify(direcrtResponseInfoB.body)); - const { similarity: similarity_proxy } = stringSimilarity(stringify(direcrtResponseInfoA.body), stringify(proxyResponseInfo.body)); - if (similarity_direct !== similarity_proxy) { - let LogText = `Similarity from ${proxyResponseInfo.request.href} between direct samples and proxy is not equal : ${similarity_direct} | ${similarity_proxy}\n`; - printError(LogText); - LogText += `\n${stringify(direcrtResponseInfoA.body)}`; - LogText += '\n=============================================\n'; - LogText += `${stringify(direcrtResponseInfoB.body)}`; - LogText += '\n=============================================\n'; - LogText += `${stringify(proxyResponseInfo.body)}\n\n`; - errRecord.push(LogText); - } - } - return { - compareResult: errRecord.length === 0, - errRecord - }; -} - -function stringify(data) { - return data ? data.replace(/\s+/g, '') : ''; -} - -function showResponseResult() { - if (direcrtResponseSampleA.length !== direcrtResponseSampleB.length || direcrtResponseSampleA.length !== proxyResponse.length) { - printError('compare fail: length not match'); - } - proxyResponse.forEach((dataObj, i) => { - const direcrtResponseInfoA = direcrtResponseSampleA[i]; - const direcrtResponseInfoB = direcrtResponseSampleB[i]; - printLog(`Direct Sample A ${direcrtResponseInfoA.request.method}: ${direcrtResponseInfoA.request.href} ${direcrtResponseInfoA.statusCode}${direcrtResponseInfoA.statusMessage}`); - printLog(`Direct Sample B ${direcrtResponseInfoB.request.method}: ${direcrtResponseInfoB.request.href} ${direcrtResponseInfoB.statusCode}${direcrtResponseInfoB.statusMessage}`); - printLog(`PROXY ${dataObj.request.method}: ${dataObj.request.href} ${dataObj.statusCode}${dataObj.statusMessage}`); - }) - console.log('\n'); -} - -function dealLogFile(dataObj = 'Log', url, cb) { - const filePath = reportPath + url.replace(/[^\u4E00-\u9FA5A-Za-z\s()()\d•·]/g, '_') + '.txt'; - fs.writeFile(filePath, dataObj, (err) => { - if (err) throw err; - console.log('Log is saved!'); - cb && cb(); - }); - return filePath; -} - -testUrls.forEach((link) => { - test(link); -}); diff --git a/test/spec_rule/no_rule_big_response_spec.js b/test/spec_rule/no_rule_big_response_spec.js deleted file mode 100644 index a215ab8..0000000 --- a/test/spec_rule/no_rule_big_response_spec.js +++ /dev/null @@ -1,42 +0,0 @@ -process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; -const { printLog } = require('../util/CommonUtil.js'); -const spawn = require('child_process').spawn; -const Server = require('../server/server.js'); - -const ProxyServerUtil = require('../util/ProxyServerUtil.js'); - -describe('Test request with big body', () => { - let proxyServer; - let serverInstance; - - beforeAll((done) => { - jasmine.DEFAULT_TIMEOUT_INTERVAL = 200000; - printLog('Start server for no_rule_big_response'); - - serverInstance = new Server(); - proxyServer = ProxyServerUtil.defaultProxyServer(); - - setTimeout(() => { - done(); - }, 2000); - }); - - afterAll(() => { - serverInstance && serverInstance.close(); - proxyServer && proxyServer.close(); - printLog('Closed server for no_rule_spec'); - }); - - it('should successfully get file', (done) => { - const isWin = /^win/.test(process.platform); - if (isWin) { - done(); - } else { - const curl = spawn('curl', ['http://localhost:3000/big_response', '--proxy', 'http://127.0.0.1:8001', '-o', '/dev/null']); - curl.on('close', (code) => { - expect(code).toEqual(0); - done(); - }); - } - }); -}); diff --git a/test/spec_rule/no_rule_spec.js b/test/spec_rule/no_rule_spec.js deleted file mode 100644 index 32373ef..0000000 --- a/test/spec_rule/no_rule_spec.js +++ /dev/null @@ -1,427 +0,0 @@ - -process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; -const path = require('path'); -const fs = require('fs'); -const Server = require('../server/server.js'); -const - { - proxyGet, - proxyPost, - directGet, - directPost, - directUpload, - proxyUpload, - generateUrl, - proxyPut, - directPut, - proxyDelete, - directDelete, - directHead, - proxyHead, - directOptions, - proxyOptions, - proxyPutUpload, - directPutUpload - } = require('../util/HttpUtil.js'); -const { CommonRequestHeader } = require('../data/headers.js'); -const { isCommonResHeaderEqual, isCommonReqEqual, printLog } = require('../util/CommonUtil.js'); -const streamEqual = require('stream-equal'); - -const ProxyServerUtil = require('../util/ProxyServerUtil.js'); - -testRequest('http'); -testRequest('https'); -testRequest('http', false); -testRequest('https', false); - -// Test suites for http and https request -function testRequest(protocol = 'http', needWeb = true) { - function constructUrl(urlPath) { - return generateUrl(protocol, urlPath); - } - - describe('Test request without proxy rules in protocol ' + protocol, () => { - let proxyServer; - let serverInstance; - - beforeAll((done) => { - jasmine.DEFAULT_TIMEOUT_INTERVAL = 200000; - printLog('Start server for no_rule_spec'); - - serverInstance = new Server(); - proxyServer = ProxyServerUtil.defaultProxyServer(needWeb); - setTimeout(() => { - done(); - }, 2000); - }); - - afterAll(() => { - serverInstance && serverInstance.close(); - proxyServer && proxyServer.close(); - printLog('Closed server for no_rule_spec'); - }); - - - it('Get should work as direct without proxy rules', (done) => { - const url = constructUrl('/test'); - const getParam = { - param: 'nothing' - }; - - proxyGet(url, getParam, CommonRequestHeader).then((proxyRes) => { - directGet(url, getParam, CommonRequestHeader).then(directRes => { - expect(proxyRes.statusCode).toEqual(200); - expect(isCommonResHeaderEqual(directRes.headers, proxyRes.headers, url)).toBe(true); - expect(isCommonReqEqual(url, serverInstance)).toBe(true); - expect(proxyRes.statusCode).toEqual(directRes.statusCode); - expect(directRes.body).toEqual(proxyRes.body); - - done(); - }, error => { - console.error('error happend in direct get:', error); - done.fail('error happend in direct get'); - }); - }, error => { - console.log('error happened in proxy get:', error); - done.fail('error happend in proxy get'); - }); - }); - - it('Post should work as direct without proxy rules', (done) => { - const url = constructUrl('/test/getuser'); - const param = { - param: 'postnothing' - }; - - proxyPost(url, param, CommonRequestHeader).then(proxyRes => { - directPost(url, param, CommonRequestHeader).then(directRes => { - expect(proxyRes.statusCode).toEqual(200); - - expect(isCommonResHeaderEqual(directRes.headers, proxyRes.headers, url)).toBe(true); - expect(proxyRes.statusCode).toEqual(directRes.statusCode); - expect(directRes.body).toEqual(proxyRes.body); - - expect(isCommonReqEqual(url, serverInstance)).toBe(true); - - done(); - }, error => { - console.error('error in direct post:', error); - done.fail('error happend in direct post'); - }); - }, error => { - console.log('error happened in proxy post,', error); - done.fail('error happend in proxy post'); - }); - }); - - it('PUT should work as direct without proxy rules', done => { - const url = constructUrl('/test/put'); - const param = { - param: 'putsomething' - }; - proxyPut(url, param, CommonRequestHeader).then(proxyRes => { - directPut(url, param, CommonRequestHeader).then(directRes => { - expect(directRes.statusCode).toEqual(200); - - expect(isCommonResHeaderEqual(directRes.headers, proxyRes.headers, url)).toBe(true); - expect(directRes.statusCode).toEqual(proxyRes.statusCode); - expect(directRes.body).toEqual(proxyRes.body); - expect(isCommonReqEqual(url, serverInstance)).toBe(true); - - done(); - }, error => { - console.error('error happened in direct put', error); - done.fail('error happened in direct put'); - }); - }, error => { - console.error('error happened in proxy put', error); - done.fail('error happened in proxy put'); - }); - }); - - it('DELETE rquest should work as direct without proxy rules', (done) => { - const url = constructUrl('/test/delete/123456'); - - proxyDelete(url, {}, CommonRequestHeader).then(proxyRes => { - directDelete(url, {}, CommonRequestHeader).then(directRes => { - expect(directRes.statusCode).toEqual(200); - - expect(directRes.statusCode).toEqual(proxyRes.statusCode); - expect(isCommonResHeaderEqual(directRes.headers, proxyRes.headers, url)).toBe(true); - expect(directRes.body).toEqual(proxyRes.body); - expect(isCommonReqEqual(url, serverInstance)).toBe(true); - - done(); - }, error => { - console.error('error happened in direct delete :', error); - done.fail('error happened in direct delete'); - }); - }, error => { - console.error('error happened in proxy delete :', error); - done.fail('error happened in proxy delete'); - }); - }); - - it('HEAD request should work as direct without proxy rules', (done) => { - const url = constructUrl('/test/head'); - - proxyHead(url, CommonRequestHeader) - .then(proxyRes => { - directHead(url, CommonRequestHeader) - .then(directRes => { - expect(directRes.statusCode).toEqual(200); - expect(directRes.body).toEqual(''); - - expect(directRes.statusCode).toEqual(proxyRes.statusCode); - expect(isCommonResHeaderEqual(directRes.headers, proxyRes.headers, url)).toBe(true); - expect(directRes.body).toEqual(proxyRes.body); - expect(isCommonReqEqual(url, serverInstance)).toBe(true); - - done(); - }, error => { - console.error('error happened in direct head request:', error); - done.fail('error happened in direct head request'); - }); - }, error => { - console.error('error happened in proxy head request:', error); - done.fail('error happened in proxy head request'); - }); - }); - - it('OPTIONS request should work as direct without proxy rules', (done) => { - const url = constructUrl('/test/options'); - - proxyOptions(url, CommonRequestHeader) - .then(proxyRes => { - directOptions(url, CommonRequestHeader) - .then(directRes => { - expect(directRes.statusCode).toEqual(200); - expect(directRes.body).toEqual('could_be_empty'); - - expect(directRes.statusCode).toEqual(proxyRes.statusCode); - expect(isCommonResHeaderEqual(directRes.headers, proxyRes.headers, url)).toBe(true); - expect(directRes.body).toEqual(proxyRes.body); - expect(isCommonReqEqual(url, serverInstance)).toBe(true); - - done(); - }, error => { - console.error('error happened in direct options request:', error); - done.fail('error happened in direct options request'); - }); - }, error => { - console.error('error happened in proxy options request:', error); - done.fail('error happened in proxy options request'); - }); - }); - - it('304 should work as direct without proxy rules', (done) => { - const url = constructUrl('/test/response/304'); - - proxyGet(url, CommonRequestHeader) - .then(proxyRes => { - directGet(url, CommonRequestHeader) - .then(directRes => { - expect(directRes.statusCode).toEqual(304); - expect(directRes.body).toEqual(''); - - expect(directRes.statusCode).toEqual(proxyRes.statusCode); - expect(isCommonResHeaderEqual(directRes.headers, proxyRes.headers, url)).toBe(true); - expect(directRes.body).toEqual(proxyRes.body); - expect(isCommonReqEqual(url, serverInstance)).toBe(true); - done(); - }, error => { - console.error('error happened in direct 304 request:', error); - done.fail('error happened in direct 304 request'); - }); - }, error => { - console.error('error happened in proxy 304 request:', error); - done.fail('error happened in proxy 304 request'); - }); - }) - - describe('Response code should be honored as direct without proxy rules', () => { - [301, 302, 303].forEach(code => { - testRedirect(code); - }); - - function testRedirect(redirectCode) { - it(`${redirectCode} response should work as direct without proxy rules`, (done) => { - const url = constructUrl(`/test/response/${redirectCode}`); - - proxyGet(url) - .then(proxyRes => { - directGet(url) - .then(directRes => { - expect(directRes.statusCode).toEqual(redirectCode); - expect(directRes.headers.location).toEqual(proxyRes.headers.location); - expect(directRes.statusCode).toEqual(proxyRes.statusCode); - expect(directRes.headers.location).toEqual('/test'); - done(); - }).catch(error => { - console.log(`error happened in direct ${redirectCode}:`, error); - done.fail(`error happened in direct ${redirectCode}`); - }); - }).catch(error => { - console.log(`error happened in proxy ${redirectCode}:`, error); - done.fail(`error happened in proxy ${redirectCode}`); - }); - }); - } - }); - - describe('Test file download ', () => { - const testArray = [ - { - url: constructUrl('/test/download/png'), - type: 'png', - contentType: 'image/png' - }, - { - url: constructUrl('/test/download/webp'), - type: 'WEBP', - contentType: 'image/webp' - }, - { - url: constructUrl('/test/download/json'), - type: 'JSON', - contentType: 'application/json; charset=utf-8' - }, - { - url: constructUrl('/test/download/css'), - type: 'CSS', - contentType: 'text/css; charset=utf-8' - }, - { - url: constructUrl('/test/download/ttf'), - type: 'TTF', - contentType: 'application/x-font-ttf' - }, - { - url: constructUrl('/test/download/eot'), - type: 'EOT', - contentType: 'application/vnd.ms-fontobject' - }, - { - url: constructUrl('/test/download/svg'), - type: 'SVG', - contentType: 'image/svg+xml' - }, - { - url: constructUrl('/test/download/woff'), - type: 'WOFF', - contentType: 'application/font-woff' - }, - { - url: constructUrl('/test/download/woff2'), - type: 'WOFF2', - contentType: 'application/font-woff2' - } - ]; - - testArray.forEach(item => { - testFileDownload(item.url, item.type, item.contentType); - }); - - // 封装测试文件下载的测试工具类 - function testFileDownload(url, filetype, contentType) { - const describe = `${filetype} file download without rules should be work as direct download`; - const param = {}; - - it(describe, (done) => { - proxyGet(url, param).then(proxyRes => { - directGet(url, param).then(directRes => { - expect(proxyRes.statusCode).toEqual(200); - - expect(isCommonResHeaderEqual(directRes.headers, proxyRes.headers, url)).toBe(true); - expect(proxyRes.statusCode).toEqual(directRes.statusCode); - expect(proxyRes.body).toEqual(directRes.body); - expect(isCommonReqEqual(url, serverInstance)).toBe(true); - done(); - }, error => { - console.error('error in direct get :', filetype, error); - done.fail(`error happend in direct get ${filetype}`); - }); - }, error => { - console.error('error in proxy get :', filetype, error); - done.fail(`error happend in proxy get ${filetype}`); - }); - }); - } - }); - - describe('Test file upload', () => { - const formParams = { - param1: 'param_1', - param2: 'param2' - }; - it('POST upload should be working', (done) => { - const url = constructUrl('/test/upload/png'); - const filePath = path.resolve(__dirname, '../data/test.png'); - - proxyUpload(url, filePath, formParams) - .then(proxyRes => { - directUpload(url, filePath, formParams) - .then((directRes) => { - expect(isCommonResHeaderEqual(directRes.headers, proxyRes.headers, url)).toBe(true); - expect(isCommonReqEqual(url, serverInstance)).toBe(true); - assertReponse(proxyRes, directRes, filePath, done); - }, error => { - console.error('error in direct upload:', error); - done.fail('error in direct upload'); - }); - }, error => { - console.error('error in proxy upload:', error); - done.fail('error in proxy upload:'); - }); - }); - - it('PUT upload should be working', (done) => { - const url = constructUrl('/test/upload/putpng'); - const filePath = path.resolve(__dirname, '../data/test.png'); - proxyPutUpload(url, filePath, formParams) - .then(proxyRes => { - directPutUpload(url, filePath, formParams) - .then((directRes) => { - expect(isCommonResHeaderEqual(directRes.headers, proxyRes.headers, url)).toBe(true); - - assertReponse(proxyRes, directRes, filePath, done); - }, error => { - console.error('error in direct upload:', error); - done.fail('error in direct upload'); - }); - }, error => { - console.error('error in proxy upload:', error); - done.fail('error in proxy upload:'); - }); - }); - - function assertReponse(proxyRes, directRes, originFilePath, done) { - expect(proxyRes.statusCode).toEqual(200); - - expect(proxyRes.statusCode).toEqual(directRes.statusCode); - // expect(proxyRes.headers.reqbody).toEqual(directRes.headers.reqbody); - - // the body will be the file path - const directUploadedStream = fs.createReadStream(directRes.body); - const proxyUploadedStream = fs.createReadStream(proxyRes.body); - const localFileStream = fs.createReadStream(originFilePath); - streamEqual(directUploadedStream, localFileStream) - .then(isLocalEqual => { - expect(isLocalEqual).toBe(true); - streamEqual(directUploadedStream, proxyUploadedStream) - .then(isUploadedEqual => { - expect(isUploadedEqual).toBe(true); - done(); - }, error => { - console.error('error in comparing directUpload with proxy:\n', error); - done.fail('error in comparing directUpload with proxy'); - }); - done(); - }, error => { - console.error('error in comparing directUpload with local:\n', error); - done.fail('error in comparing directUpload with local'); - }); - } - }); - }); -} diff --git a/test/spec_rule/no_rule_websocket_spec.js b/test/spec_rule/no_rule_websocket_spec.js deleted file mode 100644 index 9f197fb..0000000 --- a/test/spec_rule/no_rule_websocket_spec.js +++ /dev/null @@ -1,134 +0,0 @@ -/* -* Test suites for WebSocket. -* ONLY TO ENSURE THE REQUEST WILL BE BYPASSED SUCCESSFULLY, WE HAVEN'T SUPPORTTED WEBSOCKET YET. -* -*/ -const ProxyServerUtil = require('../util/ProxyServerUtil.js'); -const { generateWsUrl, directWs, proxyWs } = require('../util/HttpUtil.js'); -const Server = require('../server/server.js'); -const { printLog, isArrayEqual, isCommonReqEqual } = require('../util/CommonUtil.js'); - -testWebsocket('ws'); -testWebsocket('wss'); -testWebsocket('ws', true); -testWebsocket('wss', true); - -function testWebsocket(protocol, masked = false) { - describe('Test WebSocket in protocol : ' + protocol, () => { - const url = generateWsUrl(protocol, '/test/socket'); - let serverInstance; - let proxyServer; - // the message to - const testMessageArray = [ - 'Send the message with default option1', - 'Send the message with default option2', - 'Send the message with default option3', - 'Send the message with default option4' - ]; - - const websocketHeaders = { - referer: 'https://www.anyproxy.io/websocket/test', - origin: 'www.anyproxy.io' - } - - beforeAll((done) => { - jasmine.DEFAULT_TIMEOUT_INTERVAL = 200000; - printLog('Start server for no_rule_websocket_spec'); - serverInstance = new Server(); - - proxyServer = ProxyServerUtil.defaultProxyServer(); - - setTimeout(() => { - done(); - }, 2000); - }); - - afterAll(() => { - serverInstance && serverInstance.close(); - proxyServer && proxyServer.close(); - printLog('Closed server for no_rule_websocket_spec'); - }); - - it('Default websocket option', done => { - const directMessages = []; // set the flag for direct message, compare when both direct and proxy got message - const proxyMessages = []; - let directResHeaders; - let proxyResHeaders; - - const ws = directWs(url, websocketHeaders); - const proxyWsRef = proxyWs(url, websocketHeaders); - ws.on('open', () => { - ws.send(testMessageArray[0], masked); - for (let i = 1; i < testMessageArray.length; i++) { - setTimeout(() => { - ws.send(testMessageArray[i], masked); - }, 1000); - } - }); - - proxyWsRef.on('open', () => { - try { - proxyWsRef.send(testMessageArray[0], masked); - for (let i = 1; i < testMessageArray.length; i++) { - setTimeout(() => { - proxyWsRef.send(testMessageArray[i], masked); - }, 1000); - } - } catch (e) { - console.error(e); - } - }); - - ws.on('upgrade', (res) => { - directResHeaders = res.headers; - compareMessageIfReady(); - }); - - proxyWsRef.on('upgrade', (res) => { - proxyResHeaders = res.headers; - compareMessageIfReady(); - }); - - ws.on('message', (data, flag) => { - const message = JSON.parse(data); - if (message.type === 'onMessage') { - directMessages.push(message.content); - compareMessageIfReady(); - } - }); - - proxyWsRef.on('message', (data, flag) => { - const message = JSON.parse(data); - if (message.type === 'onMessage') { - proxyMessages.push(message.content); - compareMessageIfReady(); - } - }); - - ws.on('error', error => { - console.error('error happened in direct websocket:', error); - done.fail('Error happened in direct websocket'); - }); - - proxyWsRef.on('error', error => { - console.error('error happened in proxy websocket:', error); - done.fail('Error happened in proxy websocket'); - }); - - function compareMessageIfReady() { - const targetLen = testMessageArray.length; - if (directMessages.length === targetLen - && proxyMessages.length === targetLen - && directResHeaders && proxyResHeaders - ) { - expect(isArrayEqual(directMessages, testMessageArray)).toBe(true); - expect(isArrayEqual(directMessages, proxyMessages)).toBe(true); - expect(directResHeaders['x-anyproxy-websocket']).toBeUndefined(); - expect(proxyResHeaders['x-anyproxy-websocket']).toBe('true'); - expect(isCommonReqEqual(url, serverInstance)).toBe(true); - done(); - } - } - }); - }); -} diff --git a/test/spec_rule/rule/rule_replace_request_data.js b/test/spec_rule/rule/rule_replace_request_data.js deleted file mode 100644 index 1f3bb3b..0000000 --- a/test/spec_rule/rule/rule_replace_request_data.js +++ /dev/null @@ -1,22 +0,0 @@ -/* -* add authToken parameter to the request data -* -*/ -module.exports = { - *beforeSendRequest(requestDetail) { - if (requestDetail.url.indexOf('/getuser') >= 0) { - let requestStr = requestDetail.requestData.toString(); - try { - requestStr = JSON.stringify(Object.assign(JSON.parse(requestStr), { - authToken: 'auth_token_inrule' - })) - } catch (e) { - requestStr += '&authToken=auth_token_inrule'; - } - return { - requestOptions: requestDetail.requestOptions, - requestData: requestStr - }; - } - } -}; diff --git a/test/spec_rule/rule/rule_replace_request_option.js b/test/spec_rule/rule/rule_replace_request_option.js deleted file mode 100644 index 915d910..0000000 --- a/test/spec_rule/rule/rule_replace_request_option.js +++ /dev/null @@ -1,13 +0,0 @@ -//rule scheme : -module.exports = { - - *beforeSendRequest(requestDetail) { - const newOption = requestDetail.requestOptions; - if (newOption.hostname === 'localhost' && newOption.path === '/test/should_replace_option') { - newOption.path = '/test/new_replace_option'; - return { - requestOptions: newOption - } - } - } -}; diff --git a/test/spec_rule/rule/rule_replace_request_protocol.js b/test/spec_rule/rule/rule_replace_request_protocol.js deleted file mode 100644 index bd5942c..0000000 --- a/test/spec_rule/rule/rule_replace_request_protocol.js +++ /dev/null @@ -1,15 +0,0 @@ -//rule scheme : -module.exports = { - *summary() { - return 'The rule to replace request protocol'; - }, - - *beforeSendRequest(requestDetail) { - const newConfig = { - protocol: 'http', - requestOptions: requestDetail.requestOptions - }; - newConfig.requestOptions.port = 3000; - return newConfig; - } -}; diff --git a/test/spec_rule/rule/rule_replace_response_data.js b/test/spec_rule/rule/rule_replace_response_data.js deleted file mode 100644 index fc79191..0000000 --- a/test/spec_rule/rule/rule_replace_response_data.js +++ /dev/null @@ -1,17 +0,0 @@ -//rule scheme : replace the reponse data - -module.exports = { - - *beforeSendResponse(requestDetail, responseDetail) { - if (requestDetail.url.indexOf('/test/normal_request1') > -1) { - const newResponse = responseDetail.response; - - const newDataStr = newResponse.body.toString() + '_hello_world!'; - newResponse.body = newDataStr; - - return { - response: newResponse - }; - } - } -}; diff --git a/test/spec_rule/rule/rule_replace_response_header.js b/test/spec_rule/rule/rule_replace_response_header.js deleted file mode 100644 index 5a39c87..0000000 --- a/test/spec_rule/rule/rule_replace_response_header.js +++ /dev/null @@ -1,30 +0,0 @@ -//rule scheme : remove the cache headers in response headers -module.exports = { - *summary() { - return 'The rule to remove the cache headers in response'; - }, - - *beforeSendResponse(requestDetail, responseDetail) { - if (requestDetail.url.indexOf('/test/normal_request1') >= 0) { - const newResponse = responseDetail.response; - newResponse.header.replacedheaderkey = 'replacedHeader_value_in_rule'; - - return { - response: newResponse - }; - } - } - - // replaceResponseHeader(req, res, header) { - // const d = Q.defer(); - - // header = Object.assign({}, header); - // if (req.url.indexOf('test/normal_request1') > -1) { - // header.replacedheaderkey = 'replacedHeader_value_in_rule'; - // } - - // d.resolve(header); - - // return d.promise; - // } -}; diff --git a/test/spec_rule/rule/rule_replace_response_status_code.js b/test/spec_rule/rule/rule_replace_response_status_code.js deleted file mode 100644 index 31eac12..0000000 --- a/test/spec_rule/rule/rule_replace_response_status_code.js +++ /dev/null @@ -1,20 +0,0 @@ -//replace all the images with local one -module.exports = { - - *summary() { - return 'replace the response status code.'; - }, - - *beforeSendResponse(requestDetail, responseDetail) { - if (requestDetail.url.indexOf('/test/normal_request1') >= 0) { - const newResponse = responseDetail.response; - newResponse.statusCode = 302; - newResponse.header.location = 'www.taobao.com'; - - return { - response: newResponse - }; - } - }, -}; - diff --git a/test/spec_rule/rule/rule_should_intercept_https_req.js b/test/spec_rule/rule/rule_should_intercept_https_req.js deleted file mode 100644 index a73ccda..0000000 --- a/test/spec_rule/rule/rule_should_intercept_https_req.js +++ /dev/null @@ -1,19 +0,0 @@ -//rule scheme : - -module.exports = { - *summary() { - return 'Rule to intercept https request'; - }, - - *beforeSendResponse(requestDetail, responseDetail) { - const newResponse = responseDetail.response; - newResponse.body = newResponse.body.toString() + '_hello_world'; - return { - response: newResponse - }; - }, - - *beforeDealHttpsRequest(requestDetail) { - return requestDetail.host.indexOf('localhost:3001') > -1; - } -}; diff --git a/test/spec_rule/rule/rule_should_use_local_response.js b/test/spec_rule/rule/rule_should_use_local_response.js deleted file mode 100644 index 9056a69..0000000 --- a/test/spec_rule/rule/rule_should_use_local_response.js +++ /dev/null @@ -1,21 +0,0 @@ -/* -* Rule defination for shouldUseLocalResponse -* -*/ -const localData = 'handled_in_local_response'; - -module.exports = { - *beforeSendRequest(requestDetail) { - if (requestDetail.url.indexOf('uselocal') > -1) { - return { - response: { - statusCode: 200, - header: { - 'Via-Proxy-Local': 'true' - }, - body: localData - } - }; - } - } -}; diff --git a/test/spec_rule/rule_deal_error_spec.js b/test/spec_rule/rule_deal_error_spec.js deleted file mode 100644 index e1794b3..0000000 --- a/test/spec_rule/rule_deal_error_spec.js +++ /dev/null @@ -1,155 +0,0 @@ -/* -* test for rule replaceResponseStatus rule -* -*/ -const ProxyServerUtil = require('../util/ProxyServerUtil.js'); -const { proxyGet } = require('../util/HttpUtil.js'); -const { printLog } = require('../util/CommonUtil.js'); - -const domain_not_exists = 'not_exist.not_exist_anyproxy_io_domain.com'; - -let errorInRule = null; -const ruleNotDealError = { - *onError(requestDetail, error) { - errorInRule = error; - } -}; - -let errorInConnect = null; -const ruleDealConnectError = { - *onConnectError(requestDetail, error) { - errorInConnect = error; - } -}; - -const ERROR_PAGE_IN_RULE = 'this is my error page'; -const ruleReturnAnErrorPage = { - *onError(requestDetail, error) { - return { - response: { - statusCode: '200', - header: {}, - body: ERROR_PAGE_IN_RULE, - } - }; - } -}; - -testWrapper('http'); -testWrapper('https'); -testHttpsConnect(); - -function testWrapper(protocol) { - describe('Rule should get an error in :' + protocol, () => { - let proxyServer; - // let serverInstance; - - beforeAll((done) => { - jasmine.DEFAULT_TIMEOUT_INTERVAL = 50000; - printLog('Start server for rule_deal_error_spec'); - errorInRule = null; - - proxyServer = ProxyServerUtil.proxyServerWithRule(ruleNotDealError); - - setTimeout(() => { - done(); - }, 2000); - }); - - afterAll(() => { - // serverInstance && serverInstance.close(); - proxyServer && proxyServer.close(); - printLog('Close server for rule_deal_error_spec'); - }); - - it('Should get a request error', done => { - const url = protocol + `://${domain_not_exists}`; - proxyGet(url) - .then(proxyRes => { - expect(proxyRes.statusCode).toEqual(500); - expect(proxyRes.headers['proxy-error']).toEqual('true'); - expect(errorInRule).not.toBe(null); - done(); - }) - .catch(error => { - console.error('error happened in proxy get: ', error); - done.fail('error happened in proxy get'); - }); - }); - }); - - describe('Rule should return a custom error page in :' + protocol, () => { - let proxyServer; - // let serverInstance; - - beforeAll((done) => { - jasmine.DEFAULT_TIMEOUT_INTERVAL = 50000; - printLog('Start server for rule_deal_error_custom_error_page'); - - proxyServer = ProxyServerUtil.proxyServerWithRule(ruleReturnAnErrorPage); - - setTimeout(() => { - done(); - }, 2000); - }); - - afterAll(() => { - // serverInstance && serverInstance.close(); - proxyServer && proxyServer.close(); - printLog('Close server for rule_deal_error_custom_error_page'); - }); - - it('Should get a request error', done => { - const url = protocol + `://${domain_not_exists}`; - proxyGet(url) - .then(proxyRes => { - expect(proxyRes.statusCode).toEqual(200); - expect(proxyRes.headers['proxy-error']).toBe(undefined); - expect(proxyRes.body).toEqual(ERROR_PAGE_IN_RULE); - done(); - }) - .catch(error => { - console.error('error happened in proxy get: ', error); - done.fail('error happened in proxy get'); - }); - }); - }); -} - -function testHttpsConnect() { - describe('Rule should get a connect error', () => { - let proxyServer; - // let serverInstance; - - beforeAll((done) => { - errorInConnect = null; - jasmine.DEFAULT_TIMEOUT_INTERVAL = 50000; - printLog('Start server for rule_deal_error_custom_error_page'); - - proxyServer = ProxyServerUtil.proxyServerWithRule(ruleDealConnectError, { - forceProxyHttps: false - }); - - setTimeout(() => { - done(); - }, 2000); - }); - - afterAll(() => { - proxyServer && proxyServer.close(); - printLog('Close server for rule_deal_error_custom_error_page'); - }); - - it('Should get a request error', done => { - const url = `https://${domain_not_exists}`; - proxyGet(url) - .then(proxyRes => { - done.fail('should throw an error when requesting'); - }) - .catch(error => { - expect(errorInConnect).not.toBe(null); - done(); - }); - }); - }); -} diff --git a/test/spec_rule/rule_replace_request_data_spec.js b/test/spec_rule/rule_replace_request_data_spec.js deleted file mode 100644 index 5edc2e6..0000000 --- a/test/spec_rule/rule_replace_request_data_spec.js +++ /dev/null @@ -1,120 +0,0 @@ -/* -* test for rule replaceRequestData rule -* -*/ -const ProxyServerUtil = require('../util/ProxyServerUtil.js'); -const { proxyPost, generateUrl, directPost, isViaProxy } = require('../util/HttpUtil.js'); -const Server = require('../server/server.js'); -const { printLog, isObjectEqual } = require('../util/CommonUtil.js'); - -const rule = require('./rule/rule_replace_request_data.js'); - -testWrapper('http'); -testWrapper('https'); - -function testWrapper(protocol) { - describe('Rule replaceRequestData should be working in :' + protocol, () => { - let proxyServer; - let serverInstance; - - beforeAll((done) => { - jasmine.DEFAULT_TIMEOUT_INTERVAL = 50000; - printLog('Start server for rule_replace_request_data_spec'); - - serverInstance = new Server(); - proxyServer = ProxyServerUtil.proxyServerWithRule(rule); - - setTimeout(() => { - done(); - }, 2000); - }); - - afterAll(() => { - serverInstance && serverInstance.close(); - proxyServer && proxyServer.close(); - printLog('Close server for rule_replace_request_data_spec'); - }); - - it('Should replace the request data in proxy if the assertion is true', done => { - const url = generateUrl(protocol, '/test/getuser'); - const userName = 'username_test'; - const param = { - username: userName - }; - - proxyPost(url, param) - .then(proxyRes => { - expect(proxyRes.statusCode).toEqual(200); - expect(proxyRes.body).toEqual('body_post_getuser'); - const proxyRequest = serverInstance.getProxyRequestRecord(url); - const proxyReqBodyObj = JSON.parse(proxyRequest.body.toString()); - - expect(isViaProxy(proxyRequest)).toBe(true); - - expect(proxyReqBodyObj.username).toEqual(userName); - expect(proxyReqBodyObj.authToken).toEqual('auth_token_inrule'); - - directPost(url, param) - .then(directRes => { - expect(directRes.statusCode).toEqual(200); - expect(directRes.body).toEqual(proxyRes.body); - - - const directRequest = serverInstance.getRequestRecord(url); - const directReqBodyObj = JSON.parse(directRequest.body.toString()); - expect(isViaProxy(directRequest)).toBe(false); - - expect(directReqBodyObj.username).toEqual(userName); - expect(directReqBodyObj.authToken).toBeUndefined(); - done(); - }) - .catch(error => { - console.error('error happened in direct post: ', error); - done.fail('error happened in direct post'); - }); - }) - .catch(error => { - console.error('error happened in proxy post: ', error); - console.error(error); - console.error(error.stack); - done.fail('error happened in proxy post'); - }); - }); - - it('Should not replace the request data in proxy if the assertion is false', done => { - const url = generateUrl(protocol, '/test/normal_post_request1'); - const userName = 'normal_username_test'; - - const param = { - username: userName - }; - - proxyPost(url, param) - .then(proxyRes => { - expect(proxyRes.statusCode).toEqual(200); - expect(proxyRes.body).toEqual('body_normal_post_request1'); - const proxyReqRecord = serverInstance.getProxyRequestRecord(url); - const proxyReqBody = JSON.parse(proxyReqRecord.body); - expect(isObjectEqual(proxyReqBody, param, url)).toBe(true); - - directPost(url, param) - .then(directRes => { - expect(directRes.statusCode).toEqual(proxyRes.statusCode); - expect(directRes.body).toEqual(proxyRes.body); - const directReqRecord = serverInstance.getRequestRecord(url); - const directReqBody = JSON.parse(directReqRecord.body); - expect(isObjectEqual(directReqBody, proxyReqBody, url)).toBe(true); - done(); - }) - .catch(error => { - console.error('error happened in direct post:', error); - done.fail('error happened in direct post'); - }); - }) - .catch(error => { - console.error('error happened in proxy post:', error); - done.fail('error happened in proxy post'); - }); - }); - }); -} diff --git a/test/spec_rule/rule_replace_request_option_spec.js b/test/spec_rule/rule_replace_request_option_spec.js deleted file mode 100644 index dbcaae0..0000000 --- a/test/spec_rule/rule_replace_request_option_spec.js +++ /dev/null @@ -1,89 +0,0 @@ -/* -* test for rule replaceOption rule -* -*/ - -const ProxyServerUtil = require('../util/ProxyServerUtil.js'); -const { proxyGet, generateUrl, directGet } = require('../util/HttpUtil.js'); -const Server = require('../server/server.js'); -const { printLog } = require('../util/CommonUtil.js'); - -const rule = require('./rule/rule_replace_request_option.js'); - -testWrapper('http'); -testWrapper('https'); - -function testWrapper(protocol) { - describe('Rule replaceRequestOption should be working in :' + protocol, () => { - let proxyServer; - let serverInstance; - - beforeAll(done => { - jasmine.DEFAULT_TIMEOUT_INTERVAL = 50000; - printLog('Start server for rule_replace_request_option_spec'); - - serverInstance = new Server(); - - proxyServer = ProxyServerUtil.proxyServerWithRule(rule); - - setTimeout(() => { - done(); - }, 2000); - }); - - afterAll(() => { - serverInstance && serverInstance.close(); - proxyServer && proxyServer.close(); - printLog('Close server for rule_replace_request_option_spec'); - }); - - it('Should replace request option if the assertion is true', done => { - const url = generateUrl(protocol, '/test/should_replace_option'); - const replacedUrl = generateUrl(protocol, '/test/new_replace_option'); - - const token = 'replacedOption' + Date.now(); - const directToken = 'notRepacedOption' + Date.now(); - proxyGet(url, {}, { token }) - .then(proxyRes => { - directGet(url, {}, { token: directToken }) - .then(directRes => { - expect(proxyRes.statusCode).toEqual(200); - expect(proxyRes.body).toEqual('the_new_replaced_option_page_content'); - - const proxyRequestObj = serverInstance.getProxyRequestRecord(replacedUrl); - expect(proxyRequestObj.headers.token).toEqual(token); - expect(proxyRequestObj.headers['via-proxy']).toEqual('true'); - - expect(directRes.statusCode).toEqual(200); - expect(directRes.body).toEqual('the_request_that_has_not_be_replaced'); - - const directRequestObj = serverInstance.getRequestRecord(url); - expect(directRequestObj.headers.token).toEqual(directToken); - - done(); - }).catch(error => { - console.error('error happened in direct get for replaceOption rule: ', error); - done.fail('error happened when direct test replaceOption rule '); - }); - }).catch(error => { - console.error('error happened in proxy get for replaceOption rule: ', error); - done.fail('error happened when proxy test replaceOption rule '); - }); - }); - - it('Should not replace request option if the assertion is false', done => { - const url = generateUrl(protocol, '/test/should_not_replace_option'); - - proxyGet(url) - .then(proxyRes => { - done(); - }, error => { - console.error('error happened in proxy get:', error); - done.fail('error happened in proxy get'); - }).catch(error => { - console.error('error happend in syntax:', error); - done.fail('error happend in syntax'); - }); - }); - }); -} diff --git a/test/spec_rule/rule_replace_request_protocol_spec.js b/test/spec_rule/rule_replace_request_protocol_spec.js deleted file mode 100644 index 9a41fec..0000000 --- a/test/spec_rule/rule_replace_request_protocol_spec.js +++ /dev/null @@ -1,112 +0,0 @@ -/* -* test for rule replaceOption rule -* -*/ - -const ProxyServerUtil = require('../util/ProxyServerUtil.js'); -const { proxyGet, generateUrl, directGet } = require('../util/HttpUtil.js'); -const Server = require('../server/server.js'); -const { printLog } = require('../util/CommonUtil.js'); - -const rule = require('./rule/rule_replace_request_protocol.js'); - -testWrapper(); - -function testWrapper() { - describe('Rule replaceRequestProtocol should be working', () => { - let proxyServer; - let serverInstance; - - beforeAll((done) => { - jasmine.DEFAULT_TIMEOUT_INTERVAL = 50000; - printLog('Start server for rule_replace_request_protocol'); - - serverInstance = new Server(); - - proxyServer = ProxyServerUtil.proxyServerWithRule(rule); - - setTimeout(() => { - done(); - }, 2000); - }); - - afterAll(() => { - serverInstance && serverInstance.close(); - proxyServer && proxyServer.close(); - printLog('Close server for rule_replace_request_protocol'); - }); - - it('Should replace request protocol in PROXY https request', done => { - const url = generateUrl('https', '/test/normal_request1'); - const httpUrl = url.replace('https', 'http'); - const token = 'proxy_request1_token_' + Date.now(); - proxyGet(url, {}, { token }) - .then(proxyRes => { - expect(proxyRes.body).toEqual('body_normal_request1'); - - // there should be no https url be requested in proxy, it should be http request - expect(serverInstance.getProxyRequestRecord(url)).toBe(null); - const httpRecord = serverInstance.getProxyRequestRecord(httpUrl); - expect(httpRecord.headers.token).toEqual(token); - expect(httpRecord.headers['via-proxy']).toEqual('true'); - done(); - }) - .catch(error => { - console.error('Error happened in proxy the https request: ', error); - done.fail('error happened in proxy the https request'); - }); - }); - - it('Should not replace protocol in PROXY http request', done => { - const url = generateUrl('http', '/test/normal_request2'); - const token = 'proxy_request2_token_' + Date.now(); - proxyGet(url, {}, { token }) - .then(proxyRes => { - expect(proxyRes.body).toEqual('body_normal_request2'); - const requestRecord = serverInstance.getProxyRequestRecord(url); - expect(requestRecord).not.toBe(null); - expect(requestRecord.headers.token).toEqual(token); - expect(requestRecord.headers['via-proxy']).toEqual('true'); - done(); - }) - .catch(error => { - console.error('error happened in proxy the http request: ', error); - done.fail('error happend in proxy the http request'); - }); - }); - - it('Should the direct request still be working with https', done => { - const url = generateUrl('https', '/test/normal_request1'); - const token = 'direct_request1_token_' + Date.now(); - directGet(url, {}, { token }) - .then(directRes => { - expect(directRes.body).toEqual('body_normal_request1'); - const requestRecord = serverInstance.getRequestRecord(url); - expect(requestRecord.headers.token).toEqual(token); - expect(requestRecord.headers['via-proxy']).toBeUndefined(); - done(); - }) - .catch(error => { - console.error('error happened in direct https get:', error); - done.fail('error happened in direct https get'); - }); - }); - - it('Should the direct request still be working with http', done => { - const url = generateUrl('http', '/test/normal_request2'); - const token = 'direct_request1_token_' + Date.now(); - directGet(url, {}, { token }) - .then(directRes => { - expect(directRes.body).toEqual('body_normal_request2'); - const requestRecord = serverInstance.getRequestRecord(url); - expect(requestRecord.headers.token).toEqual(token); - expect(requestRecord.headers['via-proxy']).toBeUndefined(); - done(); - }) - .catch(error => { - console.error('error happened in direct http get:', error); - done.fail('error happened in direct http get'); - }); - }); - }); -} diff --git a/test/spec_rule/rule_replace_response_data_spec.js b/test/spec_rule/rule_replace_response_data_spec.js deleted file mode 100644 index d3c507c..0000000 --- a/test/spec_rule/rule_replace_response_data_spec.js +++ /dev/null @@ -1,87 +0,0 @@ -/* -* test for rule replaceResponseData rule -* -*/ -const ProxyServerUtil = require('../util/ProxyServerUtil.js'); -const { proxyGet, generateUrl, directGet } = require('../util/HttpUtil.js'); -const Server = require('../server/server.js'); -const { printLog } = require('../util/CommonUtil.js'); - -const rule = require('./rule/rule_replace_response_data.js'); - -testWrapper('http'); -testWrapper('https'); - -function testWrapper(protocol) { - describe('Rule replaceResponseData should be working in :' + protocol, () => { - let proxyServer; - let serverInstance; - - beforeAll((done) => { - jasmine.DEFAULT_TIMEOUT_INTERVAL = 50000; - printLog('Start server for rule_replace_response_data'); - - serverInstance = new Server(); - - proxyServer = ProxyServerUtil.proxyServerWithRule(rule); - - setTimeout(() => { - done(); - }, 2000); - }); - - afterAll(() => { - serverInstance && serverInstance.close(); - proxyServer && proxyServer.close(); - printLog('Close server for rule_replace_response_data'); - }); - - it('Should replace the header in proxy if assertion is true', done => { - const url = generateUrl(protocol, '/test/normal_request1'); - proxyGet(url) - .then(proxyRes => { - expect(proxyRes.statusCode).toEqual(200); - expect(proxyRes.body).toEqual('body_normal_request1_hello_world!'); - - directGet(url) - .then(directRes => { - expect(directRes.statusCode).toEqual(200); - expect(directRes.body).toEqual('body_normal_request1'); - done(); - }) - .catch(error => { - console.error('error happened in direct get: ', error); - done.fail('error happened in direct get'); - }); - }) - .catch(error => { - console.error('error happened in proxy get: ', error); - done.fail('error happened in proxy get'); - }); - }); - - it('Should not replace the header in proxy if assertion is false', done => { - const url = generateUrl(protocol, '/test/normal_request2'); - proxyGet(url) - .then(proxyRes => { - expect(proxyRes.statusCode).toEqual(200); - expect(proxyRes.body).toEqual('body_normal_request2'); - - directGet(url) - .then(directRes => { - expect(directRes.statusCode).toEqual(200); - expect(directRes.body).toEqual(proxyRes.body); - done(); - }) - .catch(error => { - console.error('error happened in direct get: ', error); - done.fail('error happened in direct get'); - }); - }) - .catch(error => { - console.error('error happened in proxy get: ', error); - done.fail('error happened in proxy get'); - }); - }); - }); -} diff --git a/test/spec_rule/rule_replace_response_header_spec.js b/test/spec_rule/rule_replace_response_header_spec.js deleted file mode 100644 index 6a21599..0000000 --- a/test/spec_rule/rule_replace_response_header_spec.js +++ /dev/null @@ -1,91 +0,0 @@ -/* -* test for rule replaceResponseHeader rule -* -*/ -const ProxyServerUtil = require('../util/ProxyServerUtil.js'); -const { proxyGet, generateUrl, directGet } = require('../util/HttpUtil.js'); -const Server = require('../server/server.js'); -const { printLog } = require('../util/CommonUtil.js'); - -const rule = require('./rule/rule_replace_response_header.js'); - -testWrapper('http'); -testWrapper('https'); - -function testWrapper(protocol) { - describe('Rule replaceResponseHeader should be working in :' + protocol, () => { - let proxyServer; - let serverInstance; - - beforeAll((done) => { - jasmine.DEFAULT_TIMEOUT_INTERVAL = 50000; - printLog('Start server for rule_replace_response_header_spec'); - - serverInstance = new Server(); - - proxyServer = ProxyServerUtil.proxyServerWithRule(rule); - - setTimeout(() => { - done(); - }, 2000); - }); - - afterAll(() => { - serverInstance && serverInstance.close(); - proxyServer && proxyServer.close(); - printLog('Close server for rule_replace_response_header_spec'); - }); - - it('Should replace the header in proxy if assertion is true', done => { - const url = generateUrl(protocol, '/test/normal_request1'); - proxyGet(url) - .then(proxyRes => { - expect(proxyRes.statusCode).toEqual(200); - expect(proxyRes.headers.replacedheaderkey).toEqual('replacedHeader_value_in_rule'); - expect(proxyRes.body).toEqual('body_normal_request1'); - - directGet(url) - .then(directRes => { - expect(directRes.statusCode).toEqual(200); - expect(directRes.headers.replacedheaderkey).toBeUndefined(); - expect(directRes.body).toEqual(proxyRes.body); - done(); - }) - .catch(error => { - console.error('error happened in direct get: ', error); - done.fail('error happened in direct get'); - }); - }) - .catch(error => { - console.error('error happened in proxy get: ', error); - done.fail('error happened in proxy get'); - }); - }); - - it('Should not replace the header in proxy if the assertion is false', done => { - const url = generateUrl(protocol, '/test/normal_request2'); - proxyGet(url) - .then(proxyRes => { - expect(proxyRes.statusCode).toEqual(200); - expect(proxyRes.headers.replacedheaderkey).toBeUndefined(); - expect(proxyRes.body).toEqual('body_normal_request2'); - - directGet(url) - .then(directRes => { - expect(directRes.statusCode).toEqual(200); - expect(directRes.headers.replacedheaderkey).toBeUndefined(); - expect(directRes.body).toEqual(proxyRes.body); - done(); - }) - .catch(error => { - console.error('error happened in direct get: ', error); - done.fail('error happened in direct get'); - }); - }) - .catch(error => { - console.error('error happened in proxy get: ', error); - done.fail('error happened in proxy get'); - }); - }); - }); -} diff --git a/test/spec_rule/rule_replace_response_status_code_spec.js b/test/spec_rule/rule_replace_response_status_code_spec.js deleted file mode 100644 index 3e7448d..0000000 --- a/test/spec_rule/rule_replace_response_status_code_spec.js +++ /dev/null @@ -1,87 +0,0 @@ -/* -* test for rule replaceResponseStatus rule -* -*/ -const ProxyServerUtil = require('../util/ProxyServerUtil.js'); -const { proxyGet, generateUrl, directGet } = require('../util/HttpUtil.js'); -const Server = require('../server/server.js'); -const { printLog } = require('../util/CommonUtil.js'); - -const rule = require('./rule/rule_replace_response_status_code.js'); - -testWrapper('http'); -testWrapper('https'); - -function testWrapper(protocol) { - describe('Rule replaceResponseStatus should be working in :' + protocol, () => { - let proxyServer; - let serverInstance; - - beforeAll((done) => { - jasmine.DEFAULT_TIMEOUT_INTERVAL = 50000; - printLog('Start server for rule_replace_response_status_code'); - - serverInstance = new Server(); - - proxyServer = ProxyServerUtil.proxyServerWithRule(rule); - - setTimeout(() => { - done(); - }, 2000); - }); - - afterAll(() => { - serverInstance && serverInstance.close(); - proxyServer && proxyServer.close(); - printLog('Close server for rule_replace_response_status_code'); - }); - - it('Should replace the status code in proxy if assertion is true', done => { - const url = generateUrl(protocol, '/test/normal_request1'); - proxyGet(url) - .then(proxyRes => { - expect(proxyRes.statusCode).toEqual(302); - expect(proxyRes.headers.location).toEqual('www.taobao.com'); - - directGet(url) - .then(directRes => { - expect(directRes.statusCode).toEqual(200); - expect(directRes.body).toEqual('body_normal_request1'); - done(); - }) - .catch(error => { - console.error('error happened in direct get: ', error); - done.fail('error happened in direct get'); - }); - }) - .catch(error => { - console.error('error happened in proxy get: ', error); - done.fail('error happened in proxy get'); - }); - }); - - it('Should not replace the status code in proxy if assertion is false', done => { - const url = generateUrl(protocol, '/test/normal_request2'); - proxyGet(url) - .then(proxyRes => { - expect(proxyRes.statusCode).toEqual(200); - expect(proxyRes.body).toEqual('body_normal_request2'); - - directGet(url) - .then(directRes => { - expect(directRes.statusCode).toEqual(200); - expect(directRes.body).toEqual('body_normal_request2'); - done(); - }) - .catch(error => { - console.error('error happened in direct get: ', error); - done.fail('error happened in direct get'); - }); - }) - .catch(error => { - console.error('error happened in proxy get: ', error); - done.fail('error happened in proxy get'); - }); - }); - }); -} diff --git a/test/spec_rule/rule_should_intercept_https_req_spec.js b/test/spec_rule/rule_should_intercept_https_req_spec.js deleted file mode 100644 index 0f256c0..0000000 --- a/test/spec_rule/rule_should_intercept_https_req_spec.js +++ /dev/null @@ -1,87 +0,0 @@ -/* -* test for rule shouldInterceptHttpsReq rule -* -*/ -const ProxyServerUtil = require('../util/ProxyServerUtil.js'); -const { proxyGet, directGet } = require('../util/HttpUtil.js'); -const Server = require('../server/server.js'); -const { printLog } = require('../util/CommonUtil.js'); - -const rule = require('./rule/rule_should_intercept_https_req.js'); - -testWrapper(); - -function testWrapper() { - describe('Rule shouldInterceptHttpsReq should be working', () => { - let proxyServer; - let serverInstance; - - beforeAll(done => { - jasmine.DEFAULT_TIMEOUT_INTERVAL = 50000; - printLog('Start server for test_rule_should_intercept_https_req_spec'); - - serverInstance = new Server(); - - proxyServer = ProxyServerUtil.proxyServerWithRule(rule, { - forceProxyHttps: false - }); - - setTimeout(() => { - done(); - }, 2000); - }); - - afterAll(() => { - serverInstance && serverInstance.close(); - proxyServer && proxyServer.close(); - printLog('Close server for test_rule_should_intercept_https_req_spec'); - }); - - it('Should replace the header in proxy if assertion is true', done => { - const url = 'https://localhost:3001/test'; - - proxyGet(url) - .then(proxyRes => { - directGet(url) - .then(directRes => { - expect(proxyRes.statusCode).toEqual(200); - - expect(directRes.statusCode).toEqual(200); - expect(directRes.body + '_hello_world').toEqual(proxyRes.body); - done(); - }) - .catch(error => { - console.error('error happened in direct get: ', error); - done.fail('error happened in direct get'); - }); - }) - .catch(error => { - console.error('error happened in proxy get: ', error); - done.fail('error happened in proxy get'); - }); - }); - - it('Should not replace the header in proxy if assertion is false', done => { - const url = 'https://localhost:3002/test'; - proxyGet(url) - .then(proxyRes => { - expect(proxyRes.statusCode).toEqual(200); - - directGet(url) - .then(directRes => { - expect(directRes.statusCode).toEqual(200); - expect(directRes.body.replace(/\s/g, '')).toEqual(proxyRes.body.replace(/\s/g, '')); - done(); - }) - .catch(error => { - console.error('error happened in direct get: ', error); - done.fail('error happened in direct get'); - }); - }) - .catch(error => { - console.error('error happened in proxy get: ', error); - done.fail('error happened in proxy get'); - }); - }); - }); -} diff --git a/test/spec_rule/rule_should_use_local_response_spec.js b/test/spec_rule/rule_should_use_local_response_spec.js deleted file mode 100644 index 74f4bc4..0000000 --- a/test/spec_rule/rule_should_use_local_response_spec.js +++ /dev/null @@ -1,55 +0,0 @@ -/* -* test for rule shouldUseLocal -* -*/ - -const ProxyServerUtil = require('../util/ProxyServerUtil.js'); -const { proxyGet, generateUrl } = require('../util/HttpUtil.js'); -const Server = require('../server/server.js'); -const { printLog } = require('../util/CommonUtil.js'); - -const rule = require('./rule/rule_should_use_local_response.js'); - -const expectedLocalBody = 'handled_in_local_response'; - -testWrapper('http'); -testWrapper('https'); - -function testWrapper(protocol) { - describe('Rule shouldUseLocalResponse should be working in :' + protocol, () => { - let proxyServer; - let serverInstance; - - beforeAll((done) => { - jasmine.DEFAULT_TIMEOUT_INTERVAL = 50000; - printLog('Start server for rule_shouldUseLocalResponse_spec'); - - serverInstance = new Server(); - - proxyServer = ProxyServerUtil.proxyServerWithRule(rule); - - setTimeout(() => { - done(); - }, 2000); - }); - - afterAll(() => { - serverInstance && serverInstance.close(); - proxyServer && proxyServer.close(); - printLog('Close server for rule_shouldUseLocalResponse_spec'); - }); - - it('Should use local response if the assertion is true', done => { - const url = generateUrl(protocol, '/test/uselocal'); - proxyGet(url, {}) - .then(res => { - expect(res.body).toEqual(expectedLocalBody); - expect(res.headers['via-proxy-local']).toEqual('true'); - done(); - }).catch((error) => { - console.log('error happened in proxy get for shouldUseLocal: ', error); - done.fail('error happened when test shouldUseLocal rule'); - }); - }); - }); -} diff --git a/test/util.js b/test/util.js new file mode 100644 index 0000000..9de4d41 --- /dev/null +++ b/test/util.js @@ -0,0 +1,80 @@ +const request = require('request'); +const assert = require('assert'); +// TODO +const { freshRequire, getFreePort } = require('../lib/util.js'); + +function basicProxyRequest(proxyHost, method, url, headers, qs, payload) { + assert(method && url, 'method and url are required'); + assert(proxyHost, 'proxyHost is required'); + headers = Object.assign({ + 'via-anyproxy': 'true', + }, headers || {}); + + const requestOpt = { + method, + url, + headers, + followRedirect: false, + rejectUnauthorized: false, + qs, + proxy: proxyHost, + }; + + return new Promise((resolve, reject) => { + const callback = (error, response, body) => { + if (error) { + reject(error); + } else { + resolve({ + response, + body, + }); + } + }; + if (payload) { + payload.pipe(request(requestOpt, callback)); + } else { + request(requestOpt, callback); + } + }); +} + +const DEFAULT_OPTIONS = { + type: 'http', + port: 8001, + webInterface: false, + wsIntercept: true, + // throttle: 10000, // optional, speed limit in kb/s + forceProxyHttps: true, // intercept https as well + dangerouslyIgnoreUnauthorized: true, + silent: false //optional, do not print anything into terminal. do not set it when you are still debugging. +}; + +async function proxyServerWithRule(rule, overrideConfig) { + const AnyProxy = freshRequire('../proxy.js'); + const freeportA = await getFreePort(); + const freeportB = await getFreePort(); + const options = Object.assign(DEFAULT_OPTIONS, { + port: freeportA, + webInterface: { + enable: true, + webPort: freeportB, + } + }, overrideConfig || {}); + options.rule = rule; + + + return new Promise((resolve, reject) => { + const instance = new AnyProxy.ProxyServer(options); + instance.on('error', reject); + instance.on('ready', () => { + resolve(instance); + }); + instance.start(); + }); +} + +module.exports = { + basicProxyRequest, + proxyServerWithRule, +}; diff --git a/test/util/CommonUtil.js b/test/util/CommonUtil.js deleted file mode 100644 index 1c4b7cf..0000000 --- a/test/util/CommonUtil.js +++ /dev/null @@ -1,291 +0,0 @@ -/** -* -* The utility class for test -*/ -const color = require('colorful'); - -function _isDeepEqual(source, target) { - // if the objects are Array - if (source.constructor === Array && target.constructor === Array) { - if (source.length !== target.length) { - return false; - } - - let _isEqual = true; - for (let i = 0; i < source.length; i++) { - if (!_isDeepEqual(source[i], target[i])) { - _isEqual = false; - break; - } - } - - return _isEqual; - } - - // if the source and target are just object - if (typeof source === 'object' && typeof target === 'object') { - let _isEqual = true; - for (const key in source) { - if (!_isDeepEqual(source[key], target[key])) { - _isEqual = false; - break; - } - } - - return _isEqual; - } - - return source === target; -} -/* -* Compare whether tow object are equal -*/ -function isObjectEqual(source = {}, target = {}, url = '') { - source = Object.assign({}, source); - target = Object.assign({}, target); - let isEqual = true; - - for (const key in source) { - isEqual = isEqual && _isDeepEqual(source[key], target[key]); - - if (!isEqual) { - console.info('source object :', source); - console.info('target object :', target); - printError(`different key in isObjectEqual is: "${key}", source is "${source[key]}", - target is "${target[key]}" the url is ${url}`); - break; - } - - delete source[key]; - delete target[key]; - } - - for (const key in target) { - isEqual = isEqual && source[key] === target[key]; - - if (!isEqual) { - console.info('source object :', source); - console.info('target object :', target); - printError(`different key in isObjectEqual is: "${key}", source is "${source[key]}", - target is "${target[key]}" the url is ${url}`); - break; - } - - delete source[key]; - delete target[key]; - } - - return isEqual; -} - -/* -* Compare the header between direct with proxy -* Will exclude the header(s) which modified by proxy -*/ -function isCommonResHeaderEqual(directHeaders, proxyHeaders, requestUrl) { - directHeaders = Object.assign({}, directHeaders); - proxyHeaders = Object.assign({}, proxyHeaders); - let isEqual = true; - const mustEqualFileds = []; // the fileds that have to be equal, or the assert will be failed - - if (!/gzip/i.test(directHeaders['content-encoding'])) { - // if the content is gzipped, proxy will unzip and remove the header - mustEqualFileds.push('content-encoding'); - } - mustEqualFileds.push('content-type'); - mustEqualFileds.push('cache-control'); - mustEqualFileds.push('allow'); - - // ensure the required fileds are same - mustEqualFileds.forEach(filedName => { - isEqual = directHeaders[filedName] === proxyHeaders[filedName]; - delete directHeaders[filedName]; - delete proxyHeaders[filedName]; - }); - - // remained filed are good to be same, but are allowed to be different - // will warn out those different fileds - for (const key in directHeaders) { - if (!_isDeepEqual(directHeaders[key], proxyHeaders[key])) { - printWarn(`key "${key}" of two response headers are different in request "${requestUrl}" : - direct is: "${directHeaders[key]}", proxy is: "${proxyHeaders[key]}"`); - } - } - - return isEqual; -} - -/* -* Compare the request between direct with proxy -* -*/ -function isCommonReqEqual(url, serverInstance) { - console.info('==> trying to get the url ', url); - try { - let isEqual = true; - - const directReqObj = serverInstance.getRequestRecord(url); - const proxyReqObj = serverInstance.getProxyRequestRecord(url); - - // ensure the proxy header is correct - isEqual = isEqual && proxyReqObj.headers['via-proxy'] === 'true'; - delete proxyReqObj.headers['via-proxy']; - - directReqObj.headers['content-type'] = trimFormContentType(directReqObj.headers['content-type']); - proxyReqObj.headers['content-type'] = trimFormContentType(proxyReqObj.headers['content-type']); - - // avoid compare content-length header via proxy - delete directReqObj.headers['content-length']; - delete proxyReqObj.headers['content-length']; - delete directReqObj.headers['transfer-encoding']; - delete proxyReqObj.headers['transfer-encoding']; - - // delete the headers that should not be passed by AnyProxy - delete directReqObj.headers.connection; - delete proxyReqObj.headers.connection; - - // delete the headers related to websocket establishment - const directHeaderKeys = Object.keys(directReqObj.headers); - directHeaderKeys.forEach((key) => { - // if the key matchs 'sec-websocket', delete it - if (/sec-websocket/ig.test(key)) { - delete directReqObj.headers[key]; - } - }); - - const proxyHeaderKeys = Object.keys(proxyReqObj.headers); - proxyHeaderKeys.forEach((key) => { - // if the key matchs 'sec-websocaket', delete it - if (/sec-websocket/ig.test(key)) { - delete proxyReqObj.headers[key]; - } - }); - - isEqual = isEqual && directReqObj.url === proxyReqObj.url; - isEqual = isEqual && isObjectEqual(directReqObj.headers, proxyReqObj.headers, url); - isEqual = isEqual && directReqObj.body === proxyReqObj.body; - return isEqual; - } catch (e) { - console.error(e); - } -} - -/* -* for multipart-form, the boundary will be different with each update, we trim it here -*/ -function trimFormContentType(contentType = '') { - return contentType.replace(/boundary.*/, ''); -} - - -function printLog(content) { - console.log(color.blue('==LOG==: ' + content)); -} - -function printWarn(content) { - console.log(color.magenta('==WARN==: ' + content)); -} - -function printError(content) { - console.log(color.red('==ERROR==: ' + content)); -} - -function printHilite(content) { - console.log(color.yellow('==LOG==: ' + content)); -} - -function parseUrlQuery(string = '') { - const parameterArray = string.split('&'); - const parsedObj = {}; - parameterArray.forEach((parameter) => { - // 获取等号的位置 - const indexOfEqual = parameter.indexOf('='); - const name = parameter.substr(0, indexOfEqual); - const value = parameter.substr(indexOfEqual + 1); - parsedObj[name] = value; - }); - return parsedObj; -} - -function stringSimilarity(a, b, precision = 2) { - let similarity = '0%'; - let isCongruent = false; - if (a && b) { - const targetLen = Math.max(a.length, b.length); - targetLen > 1000 ? - similarity = simHasH(a, b) : - similarity = LevenshteinSimilarity(a, b); - isCongruent = similarity === 100; - similarity = similarity.toFixed(precision) + '%'; - } - return { - isCongruent, - similarity - } -} - -/** -* simhash similarity -*/ -function simHasH(a, b) { - const simhash = require('node-simhash'); - return (simhash.compare(a, b) * 100); -} - -/** -* Levenshtein Distance -*/ -function LevenshteinSimilarity(a, b) { - let cost; - const maxLen = Math.max(a.length, b.length); - const minOfThree = (numa, numb, numc) => { - if (numa > numb) { - return numb > numc ? numc : numb; - } else { - return numa > numc ? numc : numa; - } - } - if (a.length === 0) cost = b.length; - if (b.length === 0) cost = a.length; - - if (a.length > b.length) { - const tmp = a; - a = b; - b = tmp; - } - - const row = []; - for (let i = 0; i <= a.length; i++) { - row[i] = i; - } - - for (let i = 1; i <= b.length; i++) { - let prev = i; - for (let j = 1; j <= a.length; j++) { - let val; - if (b.charAt(i - 1) === a.charAt(j - 1)) { - val = row[j - 1]; - } else { - val = minOfThree(row[j - 1] + 1, prev + 1, row[j] + 1); - } - row[j - 1] = prev; - prev = val; - } - row[a.length] = prev; - } - cost = row[a.length]; - return ((maxLen - cost) / maxLen * 100); -} - -module.exports = { - isObjectEqual, - isCommonResHeaderEqual, - printLog, - printWarn, - printError, - printHilite, - isCommonReqEqual, - parseUrlQuery, - stringSimilarity, - isArrayEqual: _isDeepEqual -}; diff --git a/test/util/HttpUtil.js b/test/util/HttpUtil.js deleted file mode 100644 index 76281d1..0000000 --- a/test/util/HttpUtil.js +++ /dev/null @@ -1,373 +0,0 @@ -/* eslint prefer-arrow-callback: 0 */ -/** - * An util to make the request out - * - */ -const request = require('request'); -const fs = require('fs'); -const WebSocket = require('ws'); -const tunnel = require('tunnel'); -const stream = require('stream'); -const nodeUrl = require('url'); - -const PROXY_HOST = 'http://localhost:8001'; -const SOCKET_PROXY_HOST = 'http://localhost:8001'; - -const HTTP_SERVER_BASE = 'http://localhost:3000'; -const HTTPS_SERVER_BASE = 'https://localhost:3001'; -const WS_SERVER_BASE = 'ws://localhost:3000'; -const WSS_SERVER_BASE = 'wss://localhost:3001'; -const DEFAULT_CHUNK_COLLECT_THRESHOLD = 20 * 1024 * 1024; // about 20 mb - -const SOCKE_PROXY_URL_OBJ = nodeUrl.parse(SOCKET_PROXY_HOST); - -class commonStream extends stream.Readable { - constructor(config) { - super({ - highWaterMark: DEFAULT_CHUNK_COLLECT_THRESHOLD * 5 - }); - } - _read(size) {} -} - -function getHostFromUrl(url = '') { - const hostReg = /^(https{0,1}:\/\/)(\w+)/; - const match = url.match(hostReg); - - return match && match[2] ? match[2] : ''; -} - -function getPortFromUrl(url = '') { - const portReg = /^https{0,1}:\/\/\w+(:(\d+)){0,1}/; - const match = url.match(portReg); - let port = match && match[2] ? match[2] : ''; - - if (!port) { - port = url.indexOf('https://') === 0 ? 443 : 80; - } - return port; -} - -/** - * 获取url中的path - */ -function getPathFromUrl(url = '') { - const pathReg = /^https{0,1}:\/\/\w+(:\d+){0,1}(.+)/; - const match = url.match(pathReg); - const path = match && match[3] ? match[2] : url; - return path; -} - -function proxyRequest(method = 'GET', url, params, headers = {}) { - return doRequest(method, url, params, headers, true); -} - -/* - * 直接请求到真实服务器,不经过代理服务器 - * - */ -function directRequest(method = 'GET', url, params, headers = {}) { - return doRequest(method, url, params, headers); -} - -function directUpload(url, filepath, formParams = {}, headers = {}) { - return doUpload(url, 'POST', filepath, formParams, headers); -} - -function proxyUpload(url, filepath, formParams = {}, headers = {}) { - return doUpload(url, 'POST', filepath, formParams, headers, true); -} - -function directPutUpload(url, filepath, formParams = {}, headers = {}) { - return doUpload(url, 'PUT', filepath, formParams, headers); -} - -function proxyPutUpload(url, filepath, headers = {}) { - return doUpload(url, 'PUT', filepath, headers, true); -} - -/** - * @param params {String} json类型或file路径 - * {Object} key-value形式 - */ -function doRequest(method = 'GET', url, params, headers = {}, isProxy) { - headers = Object.assign({}, headers); - - let reqStream = new commonStream(); - const requestData = { - headers, - followRedirect: false, - rejectUnauthorized: false - }; - - if (isProxy) { - requestData.proxy = PROXY_HOST; - requestData.headers['via-proxy'] = 'true'; - } - - const streamReq = (resolve, reject) => { - requestData.headers['content-type'] = 'text/plain'; //otherwise, koa-body could not recognize - if (typeof params === 'string') { - fs.existsSync(params) ? - reqStream = fs.createReadStream(params) : - reqStream.push(params); - } else if (typeof params === 'object') { - reqStream.push(JSON.stringify(params)); - } - reqStream.push(null); - reqStream.pipe(request[method.toLowerCase()]( - url, - requestData, - (error, response, body) => { - if (error) { - reject(error); - } else { - resolve(response); - } - } - )) - } - const commonReq = (resolve, reject) => { - requestData.url = url; - requestData.method = method; - requestData.qs = params; - request( - requestData, - (error, response, body) => { - if (error) { - reject(error); - } else { - resolve(response); - } - } - ); - } - const requestTask = new Promise((resolve, reject) => { - if (method === 'POST' || method === 'PUT') { - streamReq(resolve, reject); - } else { - commonReq(resolve, reject); - } - }); - return requestTask; -} - - -function doUpload(url, method, filepath, formParams, headers = {}, isProxy) { - let formData = { - file: fs.createReadStream(filepath) - }; - - formData = Object.assign({}, formData, formParams); - headers = Object.assign({}, headers); - - const requestData = { - formData, - url, - method, - headers, - json: true, - rejectUnauthorized: false - }; - - if (isProxy) { - requestData.proxy = PROXY_HOST; - requestData.headers['via-proxy'] = 'true'; - } - const requestTask = new Promise((resolve, reject) => { - request( - requestData, - (error, response, body) => { - if (error) { - reject(error); - return; - } - resolve(response); - } - ); - }); - return requestTask; -} - -function doWebSocket(url, headers = {}, isProxy) { - let ws; - if (isProxy) { - headers['via-proxy'] = 'true'; - let agent = new tunnel.httpOverHttp({ - proxy: { - hostname: SOCKE_PROXY_URL_OBJ.hostname, - port: SOCKE_PROXY_URL_OBJ.port - } - }) - - if (url.indexOf('wss') === 0) { - agent = new tunnel.httpsOverHttp({ - rejectUnauthorized: false, - proxy: { - hostname: SOCKE_PROXY_URL_OBJ.hostname, - port: SOCKE_PROXY_URL_OBJ.port - } - }) - } - - ws = new WebSocket(url, { - agent, - rejectUnauthorized: false, - headers - }); - } else { - ws = new WebSocket(url, { - rejectUnauthorized: false, - headers - }); - } - - return ws; -} - -function proxyGet(url, params, headers = {}) { - return proxyRequest('GET', url, params, headers); -} - -function proxyPost(url, params, headers = {}) { - return proxyRequest('POST', url, params, headers); -} - -function proxyPut(url, params, headers = {}) { - return proxyRequest('PUT', url, params, headers); -} - -function proxyDelete(url, params, headers = {}) { - return proxyRequest('DELETE', url, params, headers); -} - -function proxyHead(url, headers = {}) { - return proxyRequest('HEAD', url, {}, headers); -} - -function proxyOptions(url, headers = {}) { - return proxyRequest('OPTIONS', url, {}, headers); -} - -function directGet(url, params, headers = {}) { - return directRequest('GET', url, params, headers); -} - -function directPost(url, params, headers = {}) { - return directRequest('POST', url, params, headers); -} - -function directPut(url, params, headers = {}) { - return directRequest('PUT', url, params, headers); -} - -function directDelete(url, params, headers = {}) { - return directRequest('DELETE', url, params, headers); -} - -function directHead(url, headers = {}) { - return directRequest('HEAD', url, {}, headers); -} - -function directOptions(url, headers = {}) { - return directRequest('OPTIONS', url, {}, headers); -} - -function proxyWs(url, headers) { - return doWebSocket(url, headers, true); -} - -function directWs(url, headers) { - return doWebSocket(url, headers); -} - -/** -* generate the final url based on protocol and path -* -*/ -function generateUrl(protocol, urlPath) { - return protocol === 'http' ? HTTP_SERVER_BASE + urlPath : HTTPS_SERVER_BASE + urlPath; -} - -function generateWsUrl(protocol, urlPath) { - return protocol === 'wss' ? WSS_SERVER_BASE + urlPath : WS_SERVER_BASE + urlPath; -} - -/* -* verify if the request data is a valid proxy request, by checking specified header -*/ -function isViaProxy(req) { - return req.headers['via-proxy'] === 'true'; -} - -/* -* check if url is supported by request moudle -*/ -function isSupportedProtocol(requestPath) { - return requestPath.indexOf('http://') === 0 || requestPath.indexOf('https://') === 0; -} - -/* -* collect all request data in one url -*/ -function getRequestListFromPage(pageUrl, cb) { - let _ph; - let _page; - let _outObj; - const phantom = require('phantom'); - console.log(`collecting requests from ${pageUrl}...`); - return phantom.create().then(ph => { - _ph = ph; - return _ph.createPage(); - }).then(page => { - _page = page; - _outObj = _ph.createOutObject(); - _outObj.urls = []; - page.property('onResourceRequested', function (requestData, networkRequest, out) { - out.urls.push(requestData); - }, _outObj); - return _page.open(pageUrl); - }) - .then(status => _outObj.property('urls')) - .then(urls => { - _page.close(); - _ph.exit(); - return urls; - }) - .catch((err) => { - console.log(`failed to collecting requests from ${pageUrl}`); - console.log(err); - }); -} - - -module.exports = { - getHostFromUrl, - getPathFromUrl, - getPortFromUrl, - proxyGet, - proxyPost, - directGet, - directPost, - directUpload, - proxyUpload, - generateUrl, - proxyWs, - directWs, - generateWsUrl, - directPut, - proxyPut, - directDelete, - proxyDelete, - directHead, - proxyHead, - directOptions, - proxyOptions, - directPutUpload, - proxyPutUpload, - isViaProxy, - getRequestListFromPage, - directRequest, - proxyRequest, - isSupportedProtocol -}; diff --git a/test/util/ProxyServerUtil.js b/test/util/ProxyServerUtil.js deleted file mode 100644 index abd9449..0000000 --- a/test/util/ProxyServerUtil.js +++ /dev/null @@ -1,86 +0,0 @@ -/* -* Utility class for creating proxy server, used to create specfied proxy server -* -*/ - -const util = require('../../lib/util.js'); - -const DEFAULT_OPTIONS = { - type: 'http', - port: 8001, - webInterface: { - enable: true, - webPort: 8002, // optional, port for web interface - }, - wsIntercept: true, - throttle: 10000, // optional, speed limit in kb/s - forceProxyHttps: true, // intercept https as well - dangerouslyIgnoreUnauthorized: true, - silent: false //optional, do not print anything into terminal. do not set it when you are still debugging. -}; - -/** -* -* @return An instance of proxy, could be closed by calling `instance.close()` -*/ -function defaultProxyServer(webinterfaceEnable = true) { - const AnyProxy = util.freshRequire('../proxy.js'); - - const options = util.merge({}, DEFAULT_OPTIONS); - util.merge(options, { - webInterface: { - enable: webinterfaceEnable, - webPort: 8002 - } - }) - const instance = new AnyProxy.ProxyServer(options); - instance.on('error', e => { - console.log('server instance error', e); - }); - instance.start(); - return instance; -} - -/* -* Create proxy server with rule -* @param rules - Object, the rule object which contains required intercept method - @return An instance of proxy, could be closed by calling `instance.close()` -*/ -function proxyServerWithRule(rule, overrideConfig) { - const AnyProxy = util.freshRequire('../proxy.js'); - - const options = Object.assign({}, DEFAULT_OPTIONS, overrideConfig); - options.rule = rule; - - const instance = new AnyProxy.ProxyServer(options); - instance.on('error', e => { - console.log('server instance error', e); - }); - instance.start(); - - return instance; -} - -function proxyServerWithoutHttpsIntercept(rule) { - const AnyProxy = util.freshRequire('../proxy.js'); - - const options = util.merge({}, DEFAULT_OPTIONS); - if (rule) { - options.rule = rule; - } - options.forceProxyHttps = false; - - const instance = new AnyProxy.ProxyServer(options); - instance.on('error', e => { - console.log('server instance error', e); - }); - instance.start(); - return instance; -} - -module.exports = { - defaultProxyServer, - proxyServerWithoutHttpsIntercept, - proxyServerWithRule -}; diff --git a/test/util/SimHash.js b/test/util/SimHash.js deleted file mode 100644 index e69de29..0000000 diff --git a/test/spec_web/curlUtil.js b/test/web/curlUtil.spec.js similarity index 100% rename from test/spec_web/curlUtil.js rename to test/web/curlUtil.spec.js diff --git a/test/web/webInterface.spec.js b/test/web/webInterface.spec.js new file mode 100644 index 0000000..3b4297e --- /dev/null +++ b/test/web/webInterface.spec.js @@ -0,0 +1,27 @@ +const WebInterface = require('../../lib/webInterface.js'); +const Recorder = require('../../lib/recorder'); +const urllib = require('urllib'); + +describe('WebInterface server', () => { + let webServer = null; + const webHost = 'http://127.0.0.1:8002' + + beforeAll(async () => { + const recorder = new Recorder(); + webServer = new WebInterface({ + webPort: 8002, + }, recorder); + await webServer.start(); + }); + + afterAll(async () => { + await webServer.close(); + }); + + it('should response qrcode string in /getQrCode', async () => { + const response = await urllib.request(`${webHost}/api/getQrCode`); + const body = JSON.parse(response.res.data); + expect(body.qrImgDom).toMatch('<img src="data:image/'); + expect(body.url).toBe(`${webHost}/downloadCrt`); + }); +}); diff --git a/web/src/common/ApiUtil.js b/web/src/common/ApiUtil.js index 7405e23..4962dab 100644 --- a/web/src/common/ApiUtil.js +++ b/web/src/common/ApiUtil.js @@ -1,7 +1,7 @@ /** * AJAX操作工具类 */ -import PromiseUtil from './PromiseUtil'; +import PromiseUtil from './promiseUtil'; export function getJSON(url, data) { const d = PromiseUtil.defer(); fetch(url + serializeQuery(data)) @@ -53,10 +53,10 @@ export function isApiSuccess (response) { return response.status === 'success'; } -const ApiUtil = { +const apiUtil = { getJSON, postJSON, isApiSuccess }; -export default ApiUtil; +export default apiUtil; diff --git a/web/src/common/Constant.js b/web/src/common/Constant.js index 07fee10..c0ec500 100644 --- a/web/src/common/Constant.js +++ b/web/src/common/Constant.js @@ -1,9 +1,9 @@ /** -* define all Constant variables here +* define all constant variables here */ module.exports.MenuKeyMap = { RECORD_FILTER: 'RECORD_FILTER', MAP_LOCAL: 'MAP_LOCAL', ROOT_CA: 'ROOT_CA' -}; \ No newline at end of file +}; diff --git a/web/src/common/WsUtil.js b/web/src/common/WsUtil.js index 833d8e8..eb94b59 100644 --- a/web/src/common/WsUtil.js +++ b/web/src/common/WsUtil.js @@ -39,3 +39,4 @@ export function initWs(wsPort = location.port, path = 'do-not-proxy') { export default { initWs: initWs }; + diff --git a/web/src/common/apiUtil.js b/web/src/common/apiUtil.js new file mode 100644 index 0000000..4962dab --- /dev/null +++ b/web/src/common/apiUtil.js @@ -0,0 +1,62 @@ +/** +* AJAX操作工具类 +*/ +import PromiseUtil from './promiseUtil'; +export function getJSON(url, data) { + const d = PromiseUtil.defer(); + fetch(url + serializeQuery(data)) + .then((data) => { + d.resolve(data.json()); + }) + .catch((error) => { + console.error(error); + d.reject(error); + }); + return d.promise; +} + +export function postJSON(url, data) { + const d = PromiseUtil.defer(); + fetch(url, { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify(data) + }) + .then((data) => { + + d.resolve(data.json()); + }) + .catch((error) => { + console.error(error); + d.reject(error); + }); + return d.promise; +} + +function serializeQuery (data = {}) { + data['__t'] = Date.now();// disable the cache + const queryArray = []; + + for (let key in data) { + queryArray.push(`${key}=${data[key]}`); + } + + const queryStr = queryArray.join('&'); + + return queryStr ? '?' + queryStr : ''; +} + +export function isApiSuccess (response) { + return response.status === 'success'; +} + +const apiUtil = { + getJSON, + postJSON, + isApiSuccess +}; + +export default apiUtil; diff --git a/web/src/common/constant.js b/web/src/common/constant.js new file mode 100644 index 0000000..c0ec500 --- /dev/null +++ b/web/src/common/constant.js @@ -0,0 +1,9 @@ +/** +* define all constant variables here +*/ + +module.exports.MenuKeyMap = { + RECORD_FILTER: 'RECORD_FILTER', + MAP_LOCAL: 'MAP_LOCAL', + ROOT_CA: 'ROOT_CA' +}; diff --git a/web/src/common/curlUtil.js b/web/src/common/curlUtil.js index 86540a4..707f757 100644 --- a/web/src/common/curlUtil.js +++ b/web/src/common/curlUtil.js @@ -1,25 +1,27 @@ -export function curlify(recordDetail) { - const headers = { ...recordDetail.reqHeader }; - const acceptEncoding = headers['Accept-Encoding'] || headers['accept-encoding']; - // escape reserve character in url - const url = recordDetail.url.replace(/([\[\]])/g, '\\$1'); - const curlified = ['curl', `'${url}'`]; +module.exports = { + curlify(recordDetail) { + const headers = { ...recordDetail.reqHeader }; + const acceptEncoding = headers['Accept-Encoding'] || headers['accept-encoding']; + // escape reserve character in url + const url = recordDetail.url.replace(/([\[\]])/g, '\\$1'); + const curlified = ['curl', `'${url}'`]; - if (recordDetail.method.toUpperCase() !== 'GET') { - curlified.push('-X', recordDetail.method); + if (recordDetail.method.toUpperCase() !== 'GET') { + curlified.push('-X', recordDetail.method); + } + + Object.keys(headers).forEach((key) => { + curlified.push('-H', `'${key}: ${headers[key]}'`); + }); + + if (recordDetail.reqBody) { + curlified.push('-d', `'${recordDetail.reqBody}'`); + } + + if (/deflate|gzip/.test(acceptEncoding)) { + curlified.push('--compressed'); + } + + return curlified.join(' '); } - - Object.keys(headers).forEach((key) => { - curlified.push('-H', `'${key}: ${headers[key]}'`); - }); - - if (recordDetail.reqBody) { - curlified.push('-d', `'${recordDetail.reqBody}'`); - } - - if (/deflate|gzip/.test(acceptEncoding)) { - curlified.push('--compressed'); - } - - return curlified.join(' '); -} +}; diff --git a/web/src/common/wsUtil.js b/web/src/common/wsUtil.js new file mode 100644 index 0000000..eb94b59 --- /dev/null +++ b/web/src/common/wsUtil.js @@ -0,0 +1,42 @@ +/* +* Utility for websocket +* +*/ +import { message } from 'antd'; + +/** +* Initiate a ws connection. +* The default path `do-not-proxy` means the ws do not need to be proxied. +* This is very important for AnyProxy‘s own server, such as WEB UI, +* and the websocket detail panel in it, to prevent a recursive proxy. +* @param {wsPort} wsPort the port of websocket +* @param {key} path the path of the ws url +* +*/ +export function initWs(wsPort = location.port, path = 'do-not-proxy') { + if(!WebSocket){ + throw (new Error('WebSocket is not supported on this browser')); + } + + const wsClient = new WebSocket(`ws://${location.hostname}:${wsPort}/${path}`); + + wsClient.onerror = (error) => { + console.error(error); + message.error('error happened when setup websocket'); + }; + + wsClient.onopen = (e) => { + console.info('websocket opened: ', e); + }; + + wsClient.onclose = (e) => { + console.info('websocket closed: ', e); + }; + + return wsClient; +} + +export default { + initWs: initWs +}; + diff --git a/web/src/component/download-root-ca.jsx b/web/src/component/download-root-ca.jsx index 40c1913..f530432 100644 --- a/web/src/component/download-root-ca.jsx +++ b/web/src/component/download-root-ca.jsx @@ -10,8 +10,8 @@ import { connect } from 'react-redux'; import { message, Button, Spin } from 'antd'; import ResizablePanel from 'component/resizable-panel'; import { hideRootCA, updateIsRootCAExists } from 'action/globalStatusAction'; -import { MenuKeyMap } from 'common/Constant'; -import { getJSON, ajaxGet, postJSON } from 'common/ApiUtil'; +import { MenuKeyMap } from 'common/constant'; +import { getJSON, ajaxGet, postJSON } from 'common/apiUtil'; import Style from './download-root-ca.less'; import CommonStyle from '../style/common.less'; diff --git a/web/src/component/header-menu.jsx b/web/src/component/header-menu.jsx index ad41b59..7b58f29 100644 --- a/web/src/component/header-menu.jsx +++ b/web/src/component/header-menu.jsx @@ -7,8 +7,8 @@ import ClassBind from 'classnames/bind'; import { connect } from 'react-redux'; import InlineSVG from 'svg-inline-react'; import { message, Modal, Popover, Button } from 'antd'; -import { getQueryParameter } from 'common/CommonUtil'; -import { MenuKeyMap } from 'common/Constant'; +import { getQueryParameter } from 'common/commonUtil'; +import { MenuKeyMap } from 'common/constant'; import { resumeRecording, @@ -27,7 +27,7 @@ const { RECORD_FILTER: RECORD_FILTER_MENU_KEY } = MenuKeyMap; -import { getJSON } from 'common/ApiUtil'; +import { getJSON } from 'common/apiUtil'; import Style from './header-menu.less'; diff --git a/web/src/component/left-menu.jsx b/web/src/component/left-menu.jsx index 14edc6d..52f1459 100644 --- a/web/src/component/left-menu.jsx +++ b/web/src/component/left-menu.jsx @@ -5,7 +5,7 @@ import React, { PropTypes } from 'react'; import { connect } from 'react-redux'; import InlineSVG from 'svg-inline-react'; -import { getQueryParameter } from 'common/CommonUtil'; +import { getQueryParameter } from 'common/commonUtil'; import Style from './left-menu.less'; import ClassBind from 'classnames/bind'; @@ -15,7 +15,7 @@ import { showRootCA } from 'action/globalStatusAction'; -import { MenuKeyMap } from 'common/Constant'; +import { MenuKeyMap } from 'common/constant'; const StyleBind = ClassBind.bind(Style); const { diff --git a/web/src/component/map-local.jsx b/web/src/component/map-local.jsx index bf1c356..31cd1a2 100644 --- a/web/src/component/map-local.jsx +++ b/web/src/component/map-local.jsx @@ -4,14 +4,12 @@ */ import React, { PropTypes } from 'react'; -import ReactDOM from 'react-dom'; -import ClassBind from 'classnames/bind'; import { connect } from 'react-redux'; import { Tree, Form, Input, Button } from 'antd'; import ResizablePanel from 'component/resizable-panel'; -import PromiseUtil from 'common/PromiseUtil'; +import PromiseUtil from 'common/promiseUtil'; import { fetchDirectory, hideMapLocal, fetchMappedConfig, updateRemoteMappedConfig } from 'action/globalStatusAction'; -import { MenuKeyMap } from 'common/Constant'; +import { MenuKeyMap } from 'common/constant'; import Style from './map-local.less'; import CommonStyle from '../style/common.less'; diff --git a/web/src/component/record-filter.jsx b/web/src/component/record-filter.jsx index 84cb7c3..2d33150 100644 --- a/web/src/component/record-filter.jsx +++ b/web/src/component/record-filter.jsx @@ -10,7 +10,7 @@ import { connect } from 'react-redux'; import { Input, Alert } from 'antd'; import ResizablePanel from 'component/resizable-panel'; import { hideFilter, updateFilter } from 'action/globalStatusAction'; -import { MenuKeyMap } from 'common/Constant'; +import { MenuKeyMap } from 'common/constant'; import Style from './record-filter.less'; import CommonStyle from '../style/common.less'; diff --git a/web/src/component/record-request-detail.jsx b/web/src/component/record-request-detail.jsx index f700c29..b12377a 100644 --- a/web/src/component/record-request-detail.jsx +++ b/web/src/component/record-request-detail.jsx @@ -10,7 +10,7 @@ import clipboard from 'clipboard-js' import JsonViewer from 'component/json-viewer'; import ModalPanel from 'component/modal-panel'; import { hideRecordDetail } from 'action/recordAction'; -import { selectText } from 'common/CommonUtil'; +import { selectText } from 'common/commonUtil'; import { curlify } from 'common/curlUtil'; import Style from './record-detail.less'; diff --git a/web/src/component/record-row.jsx b/web/src/component/record-row.jsx index 8f3e657..cbc508f 100644 --- a/web/src/component/record-row.jsx +++ b/web/src/component/record-row.jsx @@ -3,7 +3,7 @@ */ import React, { PropTypes } from 'react'; -import { formatDate } from 'common/CommonUtil'; +import { formatDate } from 'common/commonUtil'; import Style from './record-row.less'; import CommonStyle from '../style/common.less'; diff --git a/web/src/component/record-ws-message-detail.jsx b/web/src/component/record-ws-message-detail.jsx index f816e52..1113df3 100644 --- a/web/src/component/record-ws-message-detail.jsx +++ b/web/src/component/record-ws-message-detail.jsx @@ -5,8 +5,8 @@ import React, { PropTypes } from 'react'; import { message, Button, Icon } from 'antd'; -import { formatDate } from 'common/CommonUtil'; -import { initWs } from 'common/WsUtil'; +import { formatDate } from 'common/commonUtil'; +import { initWs } from 'common/wsUtil'; import ClassBind from 'classnames/bind'; import Style from './record-ws-message-detail.less'; diff --git a/web/src/component/table-panel.jsx b/web/src/component/table-panel.jsx index b592822..96c83ec 100644 --- a/web/src/component/table-panel.jsx +++ b/web/src/component/table-panel.jsx @@ -5,7 +5,7 @@ import React, { PropTypes } from 'react'; import ReactDOM from 'react-dom'; import { Table } from 'antd'; -import { formatDate } from 'common/CommonUtil'; +import { formatDate } from 'common/commonUtil'; import Style from './table-panel.less'; import ClassBind from 'classnames/bind'; diff --git a/web/src/component/title-bar.jsx b/web/src/component/title-bar.jsx index 125d1ca..6bc6c30 100644 --- a/web/src/component/title-bar.jsx +++ b/web/src/component/title-bar.jsx @@ -5,7 +5,7 @@ import React, { PropTypes } from 'react'; import { Icon } from 'antd'; -import { getQueryParameter } from 'common/CommonUtil'; +import { getQueryParameter } from 'common/commonUtil'; import Style from './title-bar.less'; diff --git a/web/src/component/ws-listener.jsx b/web/src/component/ws-listener.jsx index d5da6a4..cd87056 100644 --- a/web/src/component/ws-listener.jsx +++ b/web/src/component/ws-listener.jsx @@ -5,14 +5,14 @@ import React, { PropTypes } from 'react'; import { message } from 'antd'; -import { initWs } from 'common/WsUtil'; +import { initWs } from 'common/wsUtil'; import { updateWholeRequest } from 'action/recordAction'; import { updateShouldClearRecord, updateShowNewRecordTip } from 'action/globalStatusAction'; const RecordWorker = require('worker-loader?inline!./record-worker.jsx'); -import { getJSON } from 'common/ApiUtil'; +import { getJSON } from 'common/apiUtil'; const myRecordWorker = new RecordWorker(window.URL.createObjectURL(new Blob([RecordWorker.toString()]))); const fetchLatestLog = function () { diff --git a/web/src/index.jsx b/web/src/index.jsx index 85903ca..599d2b0 100644 --- a/web/src/index.jsx +++ b/web/src/index.jsx @@ -6,8 +6,8 @@ import { LocaleProvider } from 'antd'; import enUS from 'antd/lib/locale-provider/en_US'; import createSagaMiddleware from 'redux-saga'; import rootSaga from 'saga/rootSaga'; -import { MenuKeyMap } from 'common/Constant'; -import { getQueryParameter } from 'common/CommonUtil'; +import { MenuKeyMap } from 'common/constant'; +import { getQueryParameter } from 'common/commonUtil'; import reducer from 'reducer/rootReducer'; import HeaderMenu from 'component/header-menu'; diff --git a/web/src/reducer/globalStatusReducer.js b/web/src/reducer/globalStatusReducer.js index 3f59496..11122da 100644 --- a/web/src/reducer/globalStatusReducer.js +++ b/web/src/reducer/globalStatusReducer.js @@ -21,7 +21,7 @@ const defaultStatus = { mappedConfig:[] // configured map config }; -import { MenuKeyMap } from 'common/Constant'; +import { MenuKeyMap } from 'common/constant'; import { STOP_RECORDING, diff --git a/web/src/saga/rootSaga.js b/web/src/saga/rootSaga.js index a334e19..5e9525f 100644 --- a/web/src/saga/rootSaga.js +++ b/web/src/saga/rootSaga.js @@ -29,7 +29,7 @@ import { updateLocalGlobalProxyFlag } from 'action/globalStatusAction'; -import { getJSON, postJSON, isApiSuccess } from 'common/ApiUtil'; +import { getJSON, postJSON, isApiSuccess } from 'common/apiUtil'; function* doFetchRequestList() { const data = yield call(getJSON, '/latestLog');