UNPKG

catproxy

Version:

a node proxy or host change tools

463 lines (414 loc) 12.7 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.parseRule = exports.getRules = exports.saveRules = exports.checkHosts = undefined; var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; }; /** * 规则管理入口 */ var _config = require('./config'); var config = _interopRequireWildcard(_config); var _log = require('../log'); var _log2 = _interopRequireDefault(_log); var _path = require('path'); var _path2 = _interopRequireDefault(_path); var _promise = require('promise'); var _promise2 = _interopRequireDefault(_promise); var _url = require('url'); var _url2 = _interopRequireDefault(_url); var _dns = require('dns'); var _dns2 = _interopRequireDefault(_dns); var _tools = require('../tools'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } var parseOneRule = void 0, parseBranch = void 0, parseOneBranch = void 0, _execParse = void 0, standardUrl = void 0; var isStringReg = /^\/.+\/$/; var isStartHttp = /^http(s)?:\/\//; var isStartSlash = /^\//; var ruleType = { host: 'host', localFile: 'localFile', localDir: 'localDir', remoteFile: 'remoteFile', redirect: 'redirect' }; var checkRules = function checkRules(branch) { var rules = branch.rules; if (rules && rules.length >= 0 && (typeof rules === 'undefined' ? 'undefined' : _typeof(rules)) === 'object') { // 空数组是合法的 if (rules.length === 0) { return true; } var newRule = []; var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = rules[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var rule = _step.value; if (rule.type && ruleType[rule.type] && rule.test) { rule.type = rule.type.trim(); rule.exec = rule.exec.trim(); rule.test = rule.test.trim(); newRule.push(rule); } } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } branch.rules = newRule; return true; } }; var checkBranch = function checkBranch(branchs) { if (branchs && branchs.length >= 0 && (typeof branchs === 'undefined' ? 'undefined' : _typeof(branchs)) === 'object') { // 空数组是合法的 if (branchs.length === 0) { return true; } var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = branchs[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var branch = _step2.value; // 名字是必须得字段 if (branch && branch.name !== undefined) { // 没定义这个字段 if (branch.rules === undefined || branch.rules === null) { // 定义一个空得 branch.rules = []; } if (!checkRules(branch)) { return false; } } else { return false; } } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2.return) { _iterator2.return(); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } return true; } }; /** * 检测传进来的规则是否是是符合规范的规则 * @param {[type]} rules 规则 *[{ * name: "caipiao", * isOpen: true, * branch: [{ * name: "test1", * rules: [{ * type: "host", * test: "test", * exec: "192.168.199.100" * }] * }], * }, { * name: "guobao", * disable: true, * branch: [], *}] * @return {[type]} 如果是就返回true,其他都不是 */ var checkHosts = exports.checkHosts = function checkHosts(hosts) { if (hosts && hosts.length >= 0 && (typeof hosts === 'undefined' ? 'undefined' : _typeof(hosts)) === 'object') { // 空数组是合法的 if (hosts.length === 0) { return true; } var _iteratorNormalCompletion3 = true; var _didIteratorError3 = false; var _iteratorError3 = undefined; try { for (var _iterator3 = hosts[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { var host = _step3.value; if (host && host.name !== undefined) { // 没定义这个字段 if (host.branch === undefined || host.branch === null) { // 定义一个空得 host.branch = []; } if (!checkBranch(host.branch)) { return false; } } else { return false; } } } catch (err) { _didIteratorError3 = true; _iteratorError3 = err; } finally { try { if (!_iteratorNormalCompletion3 && _iterator3.return) { _iterator3.return(); } } finally { if (_didIteratorError3) { throw _iteratorError3; } } } return true; } }; /** * 保存规则 * @param {[type]} rules 规则数据 */ var saveRules = exports.saveRules = function saveRules(rules) { if (checkHosts(rules)) { // 覆盖旧的rule config.set('hosts', rules); // 存入文件中 config.save('hosts'); } else { throw '存入规则文件出现错误,规则文件非法'; } }; /** * 获取规则 * @return {[Array]} 获取到得规则对象 */ var getRules = exports.getRules = function getRules() { return config.get('hosts') || []; }; /** * reqInfo 包含的信息 * { * headers: "请求头" * host: "请求地址" * method: "请求方法" * protocol: "请求协议" * originalFullUrl: "原始请求地址,包括参数" * req: "请求对象,请勿删除" * port: "请求端口" * startTime: "请求开始时间" * path: "请求路径,包括参数" * originalUrl: "原始的请求地址,不包括参数,请不要修改", * bodyData: "buffer 数据,body参数,可以修改" * 原始地址仅供查看,无法修改 * } */ var parseRule = exports.parseRule = function parseRule(reqInfo) { var rules = getRules(); if (!rules || !rules.length) { return _promise2.default.resolve(reqInfo); } return _execParse(rules.map(function (current) { return { fun: parseOneRule, param: [current, reqInfo] }; })).then(function (result) { return result ? result : reqInfo; }); }; parseOneRule = function parseOneRule(group, reqInfo) { var branches = void 0; branches = group.branch; // 如果禁用这个分组直接跳出,不存在分支 if (group.disable || !branches || !branches.length) { return; } return _execParse(branches.map(function (current) { return { fun: parseBranch, param: [current, reqInfo] }; })); }; parseBranch = function parseBranch(branch, reqInfo) { var rules = branch.rules; if (branch.disable || !rules || !rules.length) { return; } return _execParse(rules.map(function (current) { return { fun: parseOneBranch, param: [current, reqInfo] }; })); }; parseOneBranch = function parseOneBranch(rule, reqInfo) { var test = rule.test; var exec = rule.exec; var type = rule.type; var _rule$virtualPath = rule.virtualPath; var virtualPath = _rule$virtualPath === undefined ? '' : _rule$virtualPath; if (isStringReg.test(test)) { test = test.slice(1, test.length - 1); } else { test = isStartHttp.test(test) ? test : reqInfo.protocol === 'https' ? "https://" + test : "http://" + test; test = '^' + test; } // 将test转换成正则 test = new RegExp(test); var currentUrl = (0, _tools.getUrl)(reqInfo); // 测试没有通过 if (!test.test(currentUrl) || rule.disable) { return; } _log2.default.info('解析规则,当前url:' + currentUrl + ', 规则类型:' + type + ',规则正则' + test + ',规则执行' + exec); switch (type) { // host模式下只能修改 host protocol port case 'host': // 远程文件替换整个url路径包括参数 case 'remoteFile': if (exec) { // 转换成一个url的对象 var execObj = standardUrl(exec, reqInfo.protocol); reqInfo.host = execObj.host; reqInfo.protocol = execObj.protocol.split(':')[0]; reqInfo.port = execObj.port ? execObj.port : reqInfo.protocol === 'https' ? 443 : 80; reqInfo.path = type === 'host' ? reqInfo.path : execObj.path; // log.debug('', reqInfo.protocol, reqInfo.port, exec); } else { // 没有配置exec如果是 host就访问线上,如果是 remoteFile就跳过 if (type === 'host') { return new _promise2.default(function (resolve, reject) { _dns2.default.resolve(reqInfo.host.split(':')[0], function (err, addresses) { if (err || !addresses || !addresses.length) { _log2.default.error('规则解析中, dns解析出现错误,规则类型:' + type + ',规则正则' + test); reject(reqInfo); } else { reqInfo.host = addresses[0]; resolve(reqInfo); } }); }); } } break; case 'redirect': if (exec) { reqInfo.redirect = isStartHttp.test(exec) ? exec : 'http://' + exec; } break; case 'localFile': if (exec) { reqInfo.sendToFile = exec; } break; case 'localDir': if (exec) { // 去掉hash和param var p = reqInfo.path.split('?')[0]; p = reqInfo.path.split('#')[0]; if (!isStartSlash.test(virtualPath)) { virtualPath = '/' + virtualPath; } p = p.replace(new RegExp('^' + virtualPath), ''); reqInfo.sendToFile = _path2.default.join(exec, p); } break; default: } return reqInfo; }; // 转换url为一个标准对象 standardUrl = function standardUrl(originalUrl, protocol) { originalUrl = isStartHttp.test(originalUrl) ? originalUrl : protocol + '://' + originalUrl; return _url2.default.parse(originalUrl); }; /** * 按tasks的顺序执行promise * * @param {[array]} tasks [任务列表] * [{ * fun: fun, * param: [param] * }] * @return {[promise]} [promise] */ _execParse = function execParse(tasks, index) { if (!tasks || !tasks.length) { return _promise2.default.resolve(); } if (!index) { index = 0; } var current = tasks[index]; var next = tasks[index + 1]; var result = null; if (typeof current === 'function') { result = current(); } else { result = current.fun.apply(null, current.param); } // 如果当前任务有返回结果,并且结果不是一个promise if (result !== null && result !== undefined && !result.then) { return _promise2.default.resolve(result); } if (result === undefined || result === null) { result = _promise2.default.resolve(result); } return result.then(function (res) { return res !== null && res !== undefined ? res : next ? _execParse(tasks, index + 1) : undefined; }); }; // test=========== // let reqInfo = { // headers: {}, // host: "g.caipiao.163.com", // protocol: "http", // port: 80, // path: "/caipiao/test/mm/bb.html", // originalFullUrl: "http://g.caipiao.163.com/caipiao/test/mm/bb.html" // }; // parseRule(reqInfo) // .then((result) => { // log.debug(result); // }); // parseOneBranch({ // type: "host", // test: '/zhuhu.com/test/', // exec: "http://192.168.199.100/test?aaa" // }, reqInfo); // parseOneBranch({ // type: "remoteFile", // test: '/zhuhu.com/test/', // exec: "http://192.168.199.100/test?aaa" // }, reqInfo); // // parseOneBranch({ // type: "localFile", // test: '/zhuhu.com/test/', // exec: "D:/test/1111/1222" // }, reqInfo); // parseOneBranch({ // type: "localDir", // test: '/zhuhu.com/test/', // exec: "D:/test/1111/cjx", // virtualPath: "/test/" // }, reqInfo); // console.log(standardUrl("test:8080?a=1"));