catproxy
Version:
a node proxy or host change tools
463 lines (414 loc) • 12.7 kB
JavaScript
;
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"));