Enhancements

Change section and key names in configuration files.
Add support for using Quantumult X rulesets/Clash rule-providers as rule sources.
Optimize codes.
This commit is contained in:
Tindy X 2020-06-19 23:57:10 +08:00
parent ee6de60223
commit 605e273d69
No known key found for this signature in database
GPG Key ID: C6AD413169968D58
18 changed files with 475 additions and 201 deletions

View File

@ -22,19 +22,19 @@ custom_proxy_group=!!import:snippets/groups_forcerule.txt
;Options for custom rulesets ;Options for custom rulesets
enable_rule_generator=false enable_rule_generator=false
overwrite_original_rules=false overwrite_original_rules=false
;surge_ruleset=DIRECT,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Unbreak.list ;ruleset=DIRECT,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Unbreak.list
;surge_ruleset=⛔️ 广告拦截,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Advertising.list ;ruleset=⛔️ 广告拦截,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Advertising.list
;surge_ruleset=🚫 运营劫持,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Hijacking.list ;ruleset=🚫 运营劫持,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Hijacking.list
;surge_ruleset=🌌 YouTube,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Media/YouTube.list ;ruleset=🌌 YouTube,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Media/YouTube.list
;surge_ruleset=🎥 NETFLIX,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Media/Netflix.list ;ruleset=🎥 NETFLIX,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Media/Netflix.list
;surge_ruleset=HBO,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Media/HBO.list ;ruleset=HBO,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Media/HBO.list
;surge_ruleset=Fox,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Media/Fox.list ;ruleset=Fox,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Media/Fox.list
;surge_ruleset=🌍 国外媒体,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/GlobalMedia.list ;ruleset=🌍 国外媒体,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/GlobalMedia.list
;surge_ruleset=🌏 港台媒体,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/HKMTMedia.list ;ruleset=🌏 港台媒体,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/HKMTMedia.list
;surge_ruleset=📲 电报信息,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Telegram.list ;ruleset=📲 电报信息,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Telegram.list
;surge_ruleset=🔰 节点选择,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Global.list ;ruleset=🔰 节点选择,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Global.list
;surge_ruleset=🍎 苹果服务,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Apple.list ;ruleset=🍎 苹果服务,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Apple.list
;surge_ruleset=DIRECT,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/China.list ;ruleset=DIRECT,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/China.list
;Options for custom base configuration file ;Options for custom base configuration file
clash_rule_base=base/forcerule.yml clash_rule_base=base/forcerule.yml

View File

@ -67,16 +67,21 @@ emojis:
# - {match: "(流量|时间|应急)", emoji: "🏳️‍🌈"} # - {match: "(流量|时间|应急)", emoji: "🏳️‍🌈"}
- {import: snippets/emoji.txt} - {import: snippets/emoji.txt}
ruleset: rulesets:
enabled: true enabled: true
overwrite_original_rules: false overwrite_original_rules: false
update_ruleset_on_request: false update_ruleset_on_request: false
surge_ruleset: rulesets:
# - {rule: "GEOIP,CN", group: "DIRECT"} # - {rule: "GEOIP,CN", group: "DIRECT"}
# - {ruleset: "rules/LocalAreaNetwork.list", group: "DIRECT"} # - {ruleset: "rules/LocalAreaNetwork.list", group: "DIRECT"}
# - {ruleset: "surge:rules/LocalAreaNetwork.list", group: "DIRECT"}
# - {ruleset: "quanx:https://raw.githubusercontent.com/ConnersHua/Profiles/master/Quantumult/X/Filter/Advertising.list", group: "Advertising"}
# - {ruleset: "clash-domain:https://ruleset.dev/clash_domestic_services_domains", group: "Domestic Services"}
# - {ruleset: "clash-ipcidr:https://ruleset.dev/clash_domestic_services_ips", group: "Domestic Services"}
# - {ruleset: "clash-classic:https://raw.githubusercontent.com/DivineEngine/Profiles/master/Clash/RuleSet/China.yaml", group: "DIRECT"}
- {import: snippets/rulesets.txt} - {import: snippets/rulesets.txt}
proxy_group: proxy_groups:
custom_proxy_group: custom_proxy_group:
# - {name: UrlTest, type: url-test, rule: [".*"], url: http://www.gstatic.com/generate_204, interval: 300, tolerance: 100, timeout: 5} # - {name: UrlTest, type: url-test, rule: [".*"], url: http://www.gstatic.com/generate_204, interval: 300, tolerance: 100, timeout: 5}
# - {name: Proxy, type: select, rule: [".*"]} # - {name: Proxy, type: select, rule: [".*"]}

View File

@ -142,7 +142,7 @@ remove_old_emoji=true
rule=!!import:snippets/emoji.txt rule=!!import:snippets/emoji.txt
[ruleset] [rulesets]
;Enable generating rules with rulesets ;Enable generating rules with rulesets
enabled=true enabled=true
@ -153,17 +153,24 @@ overwrite_original_rules=false
update_ruleset_on_request=false update_ruleset_on_request=false
;Ruleset addresses, supports local files/URL ;Ruleset addresses, supports local files/URL
;Format: Group name,URL ;Format: Group name,[type:]URL
; Group name,[]Rule ; Group name,[]Rule
;where "type" supports the following value: surge, quanx, clash-domain, clash-ipcidr, clash-classic
;type defaults to surge if omitted
;surge_ruleset=DIRECT,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Unbreak.list ;ruleset=DIRECT,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Unbreak.list
;surge_ruleset=🎯 全球直连,rules/LocalAreaNetwork.list ;ruleset=🎯 全球直连,rules/LocalAreaNetwork.list
;surge_ruleset=🎯 全球直连,[]GEOIP,CN ;ruleset=DIRECT,surge:rules/LocalAreaNetwork.list
;surge_ruleset=🐟 漏网之鱼,[]FINAL ;ruleset=Advertising,quanx:https://raw.githubusercontent.com/ConnersHua/Profiles/master/Quantumult/X/Filter/Advertising.list
;ruleset=Domestic Services,clash-domain:https://ruleset.dev/clash_domestic_services_domains
;ruleset=Domestic Services,clash-ipcidr:https://ruleset.dev/clash_domestic_services_ips
;ruleset=DIRECT,clash-classic:https://raw.githubusercontent.com/DivineEngine/Profiles/master/Clash/RuleSet/China.yaml
;ruleset=🎯 全球直连,[]GEOIP,CN
;ruleset=🐟 漏网之鱼,[]FINAL
surge_ruleset=!!import:snippets/rulesets.txt ruleset=!!import:snippets/rulesets.txt
[clash_proxy_group] [proxy_groups]
;Generate Clash Proxy Group with the following patterns. Node filtering rule supports regular expression. ;Generate Clash Proxy Group with the following patterns. Node filtering rule supports regular expression.
;Format: Group_Name`select`Rule_1`Rule_2`... ;Format: Group_Name`select`Rule_1`Rule_2`...
; Group_Name`url-test|fallback|load-balance`Rule_1`Rule_2`...`test_url`interval[,timeout][,tolerance] ; Group_Name`url-test|fallback|load-balance`Rule_1`Rule_2`...`test_url`interval[,timeout][,tolerance]

View File

@ -217,7 +217,7 @@ public:
string_multimap itemGroup, existItemGroup; string_multimap itemGroup, existItemGroup;
std::stringstream strStrm; std::stringstream strStrm;
unsigned int lineSize = 0; unsigned int lineSize = 0;
char delimiter = count(content.begin(), content.end(), '\n') < 1 ? '\r' : '\n'; char delimiter = getLineBreak(content);
EraseAll(); //first erase all data EraseAll(); //first erase all data
if(do_utf8_to_gbk && is_str_utf8(content)) if(do_utf8_to_gbk && is_str_utf8(content))

View File

@ -75,6 +75,8 @@ size_t max_allowed_rulesets = 64, max_allowed_rules = 32768;
string_array regex_blacklist = {"(.*)*"}; string_array regex_blacklist = {"(.*)*"};
void refreshRulesets(string_array &ruleset_list, std::vector<ruleset_content> &rca);
std::string parseProxy(const std::string &source) std::string parseProxy(const std::string &source)
{ {
std::string proxy = source; std::string proxy = source;
@ -90,8 +92,80 @@ const string_array clash_rule_type = {basic_types, "IP-CIDR6", "SRC-PORT", "DST-
const string_array surge_rule_type = {basic_types, "IP-CIDR6", "USER-AGENT", "URL-REGEX", "AND", "OR", "NOT", "PROCESS-NAME", "IN-PORT", "DEST-PORT", "SRC-IP"}; const string_array surge_rule_type = {basic_types, "IP-CIDR6", "USER-AGENT", "URL-REGEX", "AND", "OR", "NOT", "PROCESS-NAME", "IN-PORT", "DEST-PORT", "SRC-IP"};
const string_array quanx_rule_type = {basic_types, "USER-AGENT", "HOST", "HOST-SUFFIX", "HOST-KEYWORD"}; const string_array quanx_rule_type = {basic_types, "USER-AGENT", "HOST", "HOST-SUFFIX", "HOST-KEYWORD"};
std::string convertRuleset(const std::string &content, int type)
{
/// Target: Surge type,pattern[,flag]
/// Source: QuanX type,pattern[,group]
/// Clash payload:\n - 'ipcidr/domain/classic(Surge-like)'
std::string output, strLine, strTemp;
if(type == RULESET_SURGE)
return content;
if(startsWith(content, "payload:")) /// Clash
{
output = regReplace(regReplace(content, "payload:\\r?\\n", "", true), "\\s?^\\s*-\\s+('?)(.*)\\1$", "\n$2", true);
if(type == RULESET_CLASH_CLASSICAL) /// classical type
return output;
std::stringstream ss;
ss << output;
char delimiter = getLineBreak(output);
output.clear();
string_size pos, lineSize;
while(getline(ss, strLine, delimiter))
{
lineSize = strLine.size();
if(lineSize && strLine[lineSize - 1] == '\r') //remove line break
{
strLine.erase(lineSize - 1);
lineSize--;
}
if(!strLine.empty() && (strLine[0] != ';' && strLine[0] != '#' && !(lineSize >= 2 && strLine[0] == '/' && strLine[1] == '/')))
{
pos = strLine.find("/");
if(pos != strLine.npos) /// ipcidr
{
if(isIPv4(strLine.substr(0, pos)))
output += "IP-CIDR,";
else
output += "IP-CIDR6,";
}
else
{
if(strLine[0] == '.' || (lineSize >= 2 && strLine[0] == '+' && strLine[1] == '.')) /// suffix
{
output += "DOMAIN-SUFFIX,";
strLine.erase(0, 2 - (strLine[0] == '.'));
}
else
output += "DOMAIN,";
}
}
output += strLine;
output += '\n';
}
return output;
}
else /// QuanX
{
output = regReplace(regReplace(content, "(?i:host)", "DOMAIN", true), "(?i:ip6-cidr)", "IP-CIDR6", true); //translate type
output = regReplace(output, "^((?i:DOMAIN(?:-(?:SUFFIX|KEYWORD))?|IP-CIDR6?),.*?)(?:,(?!no-resolve).*?)(,no-resolve)?$", "$1$2", true); //remove group
return output;
}
}
std::string getConvertedRuleset(RESPONSE_CALLBACK_ARGS)
{
std::string url = UrlDecode(getUrlArg(request.argument, "url")), type = getUrlArg(request.argument, "type");
return convertRuleset(fetchFile(url, parseProxy(proxy_ruleset), cache_ruleset), to_int(type));
}
std::string getRuleset(RESPONSE_CALLBACK_ARGS) std::string getRuleset(RESPONSE_CALLBACK_ARGS)
{ {
std::string &argument = request.argument;
int *status_code = &response.status_code;
/// type: 1 for Surge, 2 for Quantumult X, 3 for Clash domain rule-provider, 4 for Clash ipcidr rule-provider, 5 for Surge DOMAIN-SET, 6 for Clash classical ruleset /// type: 1 for Surge, 2 for Quantumult X, 3 for Clash domain rule-provider, 4 for Clash ipcidr rule-provider, 5 for Surge DOMAIN-SET, 6 for Clash classical ruleset
std::string url = urlsafe_base64_decode(getUrlArg(argument, "url")), type = getUrlArg(argument, "type"), group = urlsafe_base64_decode(getUrlArg(argument, "group")); std::string url = urlsafe_base64_decode(getUrlArg(argument, "url")), type = getUrlArg(argument, "type"), group = urlsafe_base64_decode(getUrlArg(argument, "group"));
std::string output_content, dummy; std::string output_content, dummy;
@ -106,7 +180,14 @@ std::string getRuleset(RESPONSE_CALLBACK_ARGS)
std::string proxy = parseProxy(proxy_ruleset); std::string proxy = parseProxy(proxy_ruleset);
string_array vArray = split(url, "|"); string_array vArray = split(url, "|");
for(std::string &x : vArray) for(std::string &x : vArray)
output_content += fetchFile(x, proxy, cache_ruleset) + "\n"; x.insert(0, "ruleset,");
std::vector<ruleset_content> rca;
refreshRulesets(vArray, rca);
for(ruleset_content &x : rca)
{
std::string content = x.rule_content.get();
output_content += convertRuleset(content, x.rule_type);
}
if(!output_content.size()) if(!output_content.size())
{ {
@ -119,7 +200,7 @@ std::string getRuleset(RESPONSE_CALLBACK_ARGS)
const std::string rule_match_regex = "^(.*?,.*?)(,.*)(,.*)$"; const std::string rule_match_regex = "^(.*?,.*?)(,.*)(,.*)$";
ss << output_content; ss << output_content;
char delimiter = count(output_content.begin(), output_content.end(), '\n') < 1 ? '\r' : '\n'; char delimiter = getLineBreak(output_content);
std::string::size_type lineSize, posb, pose; std::string::size_type lineSize, posb, pose;
auto filterLine = [&]() auto filterLine = [&]()
{ {
@ -136,7 +217,7 @@ std::string getRuleset(RESPONSE_CALLBACK_ARGS)
pose--; pose--;
} }
else else
pose -= posb + 1; pose -= posb;
return 0; return 0;
}; };
@ -255,7 +336,7 @@ int importItems(string_array &target, bool scope_limit = true)
if(fileExist(path)) if(fileExist(path))
content = fileGet(path, scope_limit); content = fileGet(path, scope_limit);
else if(startsWith(path, "http://") || startsWith(path, "https://") || startsWith(path, "data:")) else if(isLink(path))
content = webGet(path, proxy, dummy, cache_config); content = webGet(path, proxy, dummy, cache_config);
else else
writeLog(0, "File not found or not a valid URL: " + path, LOG_LEVEL_ERROR); writeLog(0, "File not found or not a valid URL: " + path, LOG_LEVEL_ERROR);
@ -263,7 +344,7 @@ int importItems(string_array &target, bool scope_limit = true)
return -1; return -1;
ss << content; ss << content;
char delimiter = count(content.begin(), content.end(), '\n') < 1 ? '\r' : '\n'; char delimiter = getLineBreak(content);
std::string::size_type lineSize; std::string::size_type lineSize;
while(getline(ss, strLine, delimiter)) while(getline(ss, strLine, delimiter))
{ {
@ -427,7 +508,7 @@ void readRuleset(YAML::Node node, string_array &dest, bool scope_limit = true)
void refreshRulesets(string_array &ruleset_list, std::vector<ruleset_content> &rca) void refreshRulesets(string_array &ruleset_list, std::vector<ruleset_content> &rca)
{ {
eraseElements(rca); eraseElements(rca);
std::string rule_group, rule_url, dummy; std::string rule_group, rule_url, rule_url_typed, dummy;
ruleset_content rc; ruleset_content rc;
std::string proxy = parseProxy(proxy_ruleset); std::string proxy = parseProxy(proxy_ruleset);
@ -450,12 +531,25 @@ void refreshRulesets(string_array &ruleset_list, std::vector<ruleset_content> &r
{ {
writeLog(0, "Adding rule '" + rule_url.substr(2) + "," + rule_group + "'.", LOG_LEVEL_INFO); writeLog(0, "Adding rule '" + rule_url.substr(2) + "," + rule_group + "'.", LOG_LEVEL_INFO);
//std::cerr<<"Adding rule '"<<rule_url.substr(2)<<","<<rule_group<<"'."<<std::endl; //std::cerr<<"Adding rule '"<<rule_url.substr(2)<<","<<rule_group<<"'."<<std::endl;
rc = {rule_group, "", std::async(std::launch::async, [rule_url](){return rule_url;})}; rc = {rule_group, "", "", RULESET_SURGE, std::async(std::launch::async, [rule_url](){return rule_url;})};
rca.emplace_back(rc); rca.emplace_back(rc);
continue; continue;
} }
else else
{ {
ruleset_type type = RULESET_SURGE;
const std::map<std::string, ruleset_type> types = {{"clash-domain:", RULESET_CLASH_DOMAIN}, {"clash-ipcidr:", RULESET_CLASH_IPCIDR}, {"clash-classic:", RULESET_CLASH_CLASSICAL}, \
{"quanx:", RULESET_QUANX}, {"surge:", RULESET_SURGE}};
rule_url_typed = rule_url;
for(auto &y : types)
{
if(startsWith(rule_url, y.first))
{
rule_url.erase(0, y.first.size());
type = y.second;
break;
}
}
//std::cerr<<"Updating ruleset url '"<<rule_url<<"' with group '"<<rule_group<<"'."<<std::endl; //std::cerr<<"Updating ruleset url '"<<rule_url<<"' with group '"<<rule_group<<"'."<<std::endl;
writeLog(0, "Updating ruleset url '" + rule_url + "' with group '" + rule_group + "'.", LOG_LEVEL_INFO); writeLog(0, "Updating ruleset url '" + rule_url + "' with group '" + rule_group + "'.", LOG_LEVEL_INFO);
/* /*
@ -470,7 +564,7 @@ void refreshRulesets(string_array &ruleset_list, std::vector<ruleset_content> &r
else else
continue; continue;
*/ */
rc = {rule_group, rule_url, fetchFileAsync(rule_url, proxy, cache_ruleset, async_fetch_ruleset)}; rc = {rule_group, rule_url, rule_url_typed, type, fetchFileAsync(rule_url, proxy, cache_ruleset, async_fetch_ruleset)};
} }
rca.emplace_back(rc); rca.emplace_back(rc);
/* /*
@ -610,9 +704,10 @@ void readYAMLConf(YAML::Node &node)
} }
} }
if(node["ruleset"].IsDefined()) const char *rulesets_title = node["rulesets"].IsDefined() ? "rulesets" : "ruleset";
if(node[rulesets_title].IsDefined())
{ {
section = node["ruleset"]; section = node[rulesets_title];
section["enabled"] >> enable_rule_generator; section["enabled"] >> enable_rule_generator;
if(!enable_rule_generator) if(!enable_rule_generator)
{ {
@ -624,12 +719,14 @@ void readYAMLConf(YAML::Node &node)
section["overwrite_original_rules"] >> overwrite_original_rules; section["overwrite_original_rules"] >> overwrite_original_rules;
section["update_ruleset_on_request"] >> update_ruleset_on_request; section["update_ruleset_on_request"] >> update_ruleset_on_request;
} }
if(section["surge_ruleset"].IsSequence()) const char *ruleset_title = section["rulesets"].IsDefined() ? "rulesets" : "surge_ruleset";
readRuleset(section["surge_ruleset"], rulesets, false); if(section[ruleset_title].IsSequence())
readRuleset(section[ruleset_title], rulesets, false);
} }
if(node["proxy_group"].IsDefined() && node["proxy_group"]["custom_proxy_group"].IsDefined()) const char *groups_title = node["proxy_groups"].IsDefined() ? "proxy_groups" : "proxy_group";
readGroup(node["proxy_group"]["custom_proxy_group"], clash_extra_group, false); if(node[groups_title].IsDefined() && node[groups_title]["custom_proxy_group"].IsDefined())
readGroup(node[groups_title]["custom_proxy_group"], clash_extra_group, false);
if(node["template"].IsDefined()) if(node["template"].IsDefined())
{ {
@ -851,13 +948,21 @@ void readConf()
eraseElements(tempArray); eraseElements(tempArray);
} }
ini.EnterSection("ruleset"); if(ini.SectionExist("rulesets"))
ini.EnterSection("rulesets");
else
ini.EnterSection("ruleset");
enable_rule_generator = ini.GetBool("enabled"); enable_rule_generator = ini.GetBool("enabled");
if(enable_rule_generator) if(enable_rule_generator)
{ {
ini.GetBoolIfExist("overwrite_original_rules", overwrite_original_rules); ini.GetBoolIfExist("overwrite_original_rules", overwrite_original_rules);
ini.GetBoolIfExist("update_ruleset_on_request", update_ruleset_on_request); ini.GetBoolIfExist("update_ruleset_on_request", update_ruleset_on_request);
if(ini.ItemPrefixExist("surge_ruleset")) if(ini.ItemPrefixExist("ruleset"))
{
ini.GetAll("ruleset", rulesets);
importItems(rulesets, true);
}
else if(ini.ItemPrefixExist("surge_ruleset"))
{ {
ini.GetAll("surge_ruleset", rulesets); ini.GetAll("surge_ruleset", rulesets);
importItems(rulesets, false); importItems(rulesets, false);
@ -869,7 +974,10 @@ void readConf()
update_ruleset_on_request = false; update_ruleset_on_request = false;
} }
ini.EnterSection("clash_proxy_group"); if(ini.SectionExist("proxy_groups"))
ini.EnterSection("proxy_groups");
else
ini.EnterSection("clash_proxy_group");
if(ini.ItemPrefixExist("custom_proxy_group")) if(ini.ItemPrefixExist("custom_proxy_group"))
{ {
ini.GetAll("custom_proxy_group", clash_extra_group); ini.GetAll("custom_proxy_group", clash_extra_group);
@ -1000,9 +1108,10 @@ int loadExternalYAML(YAML::Node &node, ExternalConfig &ext)
if(section["custom_proxy_group"].size()) if(section["custom_proxy_group"].size())
readGroup(section["custom_proxy_group"], ext.custom_proxy_group, api_mode); readGroup(section["custom_proxy_group"], ext.custom_proxy_group, api_mode);
if(section["surge_ruleset"].size()) const char *ruleset_name = section["rulesets"].IsDefined() ? "rulesets" : "surge_ruleset";
if(section[ruleset_name].size())
{ {
readRuleset(section["surge_ruleset"], ext.surge_ruleset, api_mode); readRuleset(section[ruleset_name], ext.surge_ruleset, api_mode);
if(max_allowed_rulesets && ext.surge_ruleset.size() > max_allowed_rulesets) if(max_allowed_rulesets && ext.surge_ruleset.size() > max_allowed_rulesets)
{ {
writeLog(0, "Ruleset count in external config has exceeded limit.", LOG_LEVEL_WARNING); writeLog(0, "Ruleset count in external config has exceeded limit.", LOG_LEVEL_WARNING);
@ -1014,8 +1123,9 @@ int loadExternalYAML(YAML::Node &node, ExternalConfig &ext)
if(section["rename_node"].size()) if(section["rename_node"].size())
readRegexMatch(section["rename_node"], "@", ext.rename, api_mode); readRegexMatch(section["rename_node"], "@", ext.rename, api_mode);
if(section["emoji"].size()) const char *emoji_name = section["emojis"].IsDefined() ? "emojis" : "emoji";
readEmoji(section["emoji"], ext.emoji, api_mode); if(section[emoji_name].size())
readEmoji(section[emoji_name], ext.emoji, api_mode);
section["include_remarks"] >> ext.include; section["include_remarks"] >> ext.include;
section["exclude_remarks"] >> ext.exclude; section["exclude_remarks"] >> ext.exclude;
@ -1067,9 +1177,10 @@ int loadExternalConfig(std::string &path, ExternalConfig &ext)
ini.GetAll("custom_proxy_group", ext.custom_proxy_group); ini.GetAll("custom_proxy_group", ext.custom_proxy_group);
importItems(ext.custom_proxy_group, api_mode); importItems(ext.custom_proxy_group, api_mode);
} }
if(ini.ItemPrefixExist("surge_ruleset")) std::string ruleset_name = ini.ItemPrefixExist("ruleset") ? "ruleset" : "surge_ruleset";
if(ini.ItemPrefixExist(ruleset_name))
{ {
ini.GetAll("surge_ruleset", ext.surge_ruleset); ini.GetAll(ruleset_name, ext.surge_ruleset);
importItems(ext.surge_ruleset, api_mode); importItems(ext.surge_ruleset, api_mode);
if(max_allowed_rulesets && ext.surge_ruleset.size() > max_allowed_rulesets) if(max_allowed_rulesets && ext.surge_ruleset.size() > max_allowed_rulesets)
{ {
@ -1120,7 +1231,7 @@ int loadExternalConfig(std::string &path, ExternalConfig &ext)
void checkExternalBase(const std::string &path, std::string &dest) void checkExternalBase(const std::string &path, std::string &dest)
{ {
if(startsWith(path, "https://") || startsWith(path, "http://") || startsWith(path, "data:") || (startsWith(path, base_path) && fileExist(path))) if(isLink(path) || (startsWith(path, base_path) && fileExist(path)))
dest = path; dest = path;
} }
@ -1158,6 +1269,9 @@ void generateBase()
std::string subconverter(RESPONSE_CALLBACK_ARGS) std::string subconverter(RESPONSE_CALLBACK_ARGS)
{ {
std::string &argument = request.argument;
int *status_code = &response.status_code;
std::string target = getUrlArg(argument, "target"); std::string target = getUrlArg(argument, "target");
switch(hash_(target)) switch(hash_(target))
{ {
@ -1469,7 +1583,7 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
x.group = group; x.group = group;
if(subInfo.size() && append_sub_userinfo.get(append_userinfo)) if(subInfo.size() && append_sub_userinfo.get(append_userinfo))
extra_headers.emplace("Subscription-UserInfo", subInfo); response.headers.emplace("Subscription-UserInfo", subInfo);
//do pre-process now //do pre-process now
preprocessNodes(nodes, ext); preprocessNodes(nodes, ext);
@ -1702,12 +1816,15 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
} }
writeLog(0, "Generate completed.", LOG_LEVEL_INFO); writeLog(0, "Generate completed.", LOG_LEVEL_INFO);
if(filename.size()) if(filename.size())
extra_headers.emplace("Content-Disposition", "attachment; filename=\"" + filename + "\""); response.headers.emplace("Content-Disposition", "attachment; filename=\"" + filename + "\"");
return output_content; return output_content;
} }
std::string simpleToClashR(RESPONSE_CALLBACK_ARGS) std::string simpleToClashR(RESPONSE_CALLBACK_ARGS)
{ {
std::string &argument = request.argument;
int *status_code = &response.status_code;
std::string url = argument.size() <= 8 ? "" : argument.substr(8); std::string url = argument.size() <= 8 ? "" : argument.substr(8);
if(!url.size() || argument.substr(0, 8) != "sublink=") if(!url.size() || argument.substr(0, 8) != "sublink=")
{ {
@ -1719,11 +1836,15 @@ std::string simpleToClashR(RESPONSE_CALLBACK_ARGS)
*status_code = 400; *status_code = 400;
return "Please insert your subscription link instead of clicking the default link."; return "Please insert your subscription link instead of clicking the default link.";
} }
return subconverter("target=clashr&url=" + UrlEncode(url), postdata, status_code, extra_headers); request.argument = "target=clashr&url=" + UrlEncode(url);
return subconverter(request, response);
} }
std::string surgeConfToClash(RESPONSE_CALLBACK_ARGS) std::string surgeConfToClash(RESPONSE_CALLBACK_ARGS)
{ {
std::string &argument = request.argument;
int *status_code = &response.status_code;
INIReader ini; INIReader ini;
string_array dummy_str_array; string_array dummy_str_array;
std::vector<nodeInfo> nodes; std::vector<nodeInfo> nodes;
@ -1899,7 +2020,7 @@ std::string surgeConfToClash(RESPONSE_CALLBACK_ARGS)
continue; continue;
ss << content; ss << content;
char delimiter = count(content.begin(), content.end(), '\n') < 1 ? '\r' : '\n'; char delimiter = getLineBreak(content);
while(getline(ss, strLine, delimiter)) while(getline(ss, strLine, delimiter))
{ {
@ -1931,6 +2052,9 @@ std::string surgeConfToClash(RESPONSE_CALLBACK_ARGS)
std::string getProfile(RESPONSE_CALLBACK_ARGS) std::string getProfile(RESPONSE_CALLBACK_ARGS)
{ {
std::string &argument = request.argument;
int *status_code = &response.status_code;
std::string name = UrlDecode(getUrlArg(argument, "name")), token = UrlDecode(getUrlArg(argument, "token")); std::string name = UrlDecode(getUrlArg(argument, "name")), token = UrlDecode(getUrlArg(argument, "token"));
string_array profiles = split(name, "|"); string_array profiles = split(name, "|");
name = profiles[0]; name = profiles[0];
@ -2026,11 +2150,14 @@ std::string getProfile(RESPONSE_CALLBACK_ARGS)
query += x.first + "=" + UrlEncode(x.second) + "&"; query += x.first + "=" + UrlEncode(x.second) + "&";
} }
query += argument; query += argument;
return subconverter(query, postdata, status_code, extra_headers); request.argument = query;
return subconverter(request, response);
} }
std::string getScript(RESPONSE_CALLBACK_ARGS) std::string getScript(RESPONSE_CALLBACK_ARGS)
{ {
std::string &argument = request.argument;
std::string url = urlsafe_base64_decode(getUrlArg(argument, "url")), dev_id = getUrlArg(argument, "id"); std::string url = urlsafe_base64_decode(getUrlArg(argument, "url")), dev_id = getUrlArg(argument, "id");
std::string output_content, dummy; std::string output_content, dummy;
@ -2054,6 +2181,8 @@ std::string getScript(RESPONSE_CALLBACK_ARGS)
std::string getRewriteRemote(RESPONSE_CALLBACK_ARGS) std::string getRewriteRemote(RESPONSE_CALLBACK_ARGS)
{ {
std::string &argument = request.argument;
std::string url = urlsafe_base64_decode(getUrlArg(argument, "url")), dev_id = getUrlArg(argument, "id"); std::string url = urlsafe_base64_decode(getUrlArg(argument, "url")), dev_id = getUrlArg(argument, "id");
std::string output_content, dummy; std::string output_content, dummy;
@ -2070,7 +2199,7 @@ std::string getRewriteRemote(RESPONSE_CALLBACK_ARGS)
std::string strLine; std::string strLine;
const std::string pattern = "^(.*? url script-.*? )(.*?)$"; const std::string pattern = "^(.*? url script-.*? )(.*?)$";
string_size lineSize; string_size lineSize;
char delimiter = count(output_content.begin(), output_content.end(), '\n') < 1 ? '\r' : '\n'; char delimiter = getLineBreak(output_content);
ss << output_content; ss << output_content;
output_content.clear(); output_content.clear();
@ -2228,10 +2357,11 @@ int simpleGenerator()
writeLog(0, "Generating all artifacts...", LOG_LEVEL_INFO); writeLog(0, "Generating all artifacts...", LOG_LEVEL_INFO);
string_multimap allItems; string_multimap allItems;
std::string dummy_str;
std::string proxy = parseProxy(proxy_subscription); std::string proxy = parseProxy(proxy_subscription);
string_map headers; Request request;
int ret_code = 200; Response response;
int &ret_code = response.status_code;
string_map &headers = response.headers;
for(std::string &x : sections) for(std::string &x : sections)
{ {
arguments.clear(); arguments.clear();
@ -2250,7 +2380,8 @@ int simpleGenerator()
if(ini.ItemExist("profile")) if(ini.ItemExist("profile"))
{ {
profile = ini.Get("profile"); profile = ini.Get("profile");
content = getProfile("name=" + UrlEncode(profile) + "&token=" + access_token + "&expand=true", dummy_str, &ret_code, headers); request.argument = "name=" + UrlEncode(profile) + "&token=" + access_token + "&expand=true";
content = getProfile(request, response);
} }
else else
{ {
@ -2278,7 +2409,8 @@ int simpleGenerator()
arguments += y.first + "=" + UrlEncode(y.second) + "&"; arguments += y.first + "=" + UrlEncode(y.second) + "&";
} }
arguments.erase(arguments.size() - 1); arguments.erase(arguments.size() - 1);
content = subconverter(arguments, dummy_str, &ret_code, headers); request.argument = arguments;
content = subconverter(request, response);
} }
if(ret_code != 200) if(ret_code != 200)
{ {
@ -2308,6 +2440,9 @@ int simpleGenerator()
std::string renderTemplate(RESPONSE_CALLBACK_ARGS) std::string renderTemplate(RESPONSE_CALLBACK_ARGS)
{ {
std::string &argument = request.argument;
int *status_code = &response.status_code;
std::string path = UrlDecode(getUrlArg(argument, "path")); std::string path = UrlDecode(getUrlArg(argument, "path"));
writeLog(0, "Trying to render template '" + path + "'...", LOG_LEVEL_INFO); writeLog(0, "Trying to render template '" + path + "'...", LOG_LEVEL_INFO);

View File

@ -12,7 +12,9 @@ void refreshRulesets(string_array &ruleset_list, std::vector<ruleset_content> &r
void readConf(); void readConf();
void generateBase(); void generateBase();
int simpleGenerator(); int simpleGenerator();
std::string convertRuleset(const std::string &content, int type);
std::string getConvertedRuleset(RESPONSE_CALLBACK_ARGS);
std::string getScript(RESPONSE_CALLBACK_ARGS); std::string getScript(RESPONSE_CALLBACK_ARGS);
std::string getProfile(RESPONSE_CALLBACK_ARGS); std::string getProfile(RESPONSE_CALLBACK_ARGS);
std::string getRuleset(RESPONSE_CALLBACK_ARGS); std::string getRuleset(RESPONSE_CALLBACK_ARGS);

View File

@ -156,6 +156,9 @@ int main(int argc, char *argv[])
append_response("GET", "/refreshrules", "text/plain", [](RESPONSE_CALLBACK_ARGS) -> std::string append_response("GET", "/refreshrules", "text/plain", [](RESPONSE_CALLBACK_ARGS) -> std::string
{ {
std::string &argument = request.argument;
int *status_code = &response.status_code;
if(access_token.size()) if(access_token.size())
{ {
std::string token = getUrlArg(argument, "token"); std::string token = getUrlArg(argument, "token");
@ -172,6 +175,9 @@ int main(int argc, char *argv[])
append_response("GET", "/readconf", "text/plain", [](RESPONSE_CALLBACK_ARGS) -> std::string append_response("GET", "/readconf", "text/plain", [](RESPONSE_CALLBACK_ARGS) -> std::string
{ {
std::string &argument = request.argument;
int *status_code = &response.status_code;
if(access_token.size()) if(access_token.size())
{ {
std::string token = getUrlArg(argument, "token"); std::string token = getUrlArg(argument, "token");
@ -188,6 +194,10 @@ int main(int argc, char *argv[])
append_response("POST", "/updateconf", "text/plain", [](RESPONSE_CALLBACK_ARGS) -> std::string append_response("POST", "/updateconf", "text/plain", [](RESPONSE_CALLBACK_ARGS) -> std::string
{ {
std::string &argument = request.argument;
std::string postdata = request.postdata;
int *status_code = &response.status_code;
if(access_token.size()) if(access_token.size())
{ {
std::string token = getUrlArg(argument, "token"); std::string token = getUrlArg(argument, "token");
@ -231,16 +241,20 @@ int main(int argc, char *argv[])
append_response("GET", "/render", "text/plain;charset=utf-8", renderTemplate); append_response("GET", "/render", "text/plain;charset=utf-8", renderTemplate);
append_response("GET", "/convert", "text/plain;charset=utf-8", getConvertedRuleset);
if(!api_mode) if(!api_mode)
{ {
append_response("GET", "/get", "text/plain;charset=utf-8", [](RESPONSE_CALLBACK_ARGS) -> std::string append_response("GET", "/get", "text/plain;charset=utf-8", [](RESPONSE_CALLBACK_ARGS) -> std::string
{ {
std::string &argument = request.argument;
std::string url = UrlDecode(getUrlArg(argument, "url")); std::string url = UrlDecode(getUrlArg(argument, "url"));
return webGet(url, ""); return webGet(url, "");
}); });
append_response("GET", "/getlocal", "text/plain;charset=utf-8", [](RESPONSE_CALLBACK_ARGS) -> std::string append_response("GET", "/getlocal", "text/plain;charset=utf-8", [](RESPONSE_CALLBACK_ARGS) -> std::string
{ {
std::string &argument = request.argument;
return fileGet(UrlDecode(getUrlArg(argument, "path"))); return fileGet(UrlDecode(getUrlArg(argument, "path")));
}); });
} }

View File

@ -723,7 +723,7 @@ int regGetMatch(const std::string &src, const std::string &match, size_t group_c
std::string regTrim(const std::string &src) std::string regTrim(const std::string &src)
{ {
return regReplace(src, "^\\s*?(.*?)\\s*$", "$1"); return regReplace(src, "^\\s*?([\\s\\S]*)\\s*$", "$1", false);
} }
std::string speedCalc(double speed) std::string speedCalc(double speed)

View File

@ -4,6 +4,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <sstream> #include <sstream>
#include <algorithm>
#include <yaml-cpp/yaml.h> #include <yaml-cpp/yaml.h>
@ -34,83 +35,6 @@ static const std::string base64_chars =
"abcdefghijklmnopqrstuvwxyz" "abcdefghijklmnopqrstuvwxyz"
"0123456789+/"; "0123456789+/";
class tribool
{
private:
int _M_VALUE = -1;
public:
tribool() { clear(); }
template <typename T> tribool(const T &value) { set(value); }
tribool(const tribool &value) { *this = value; }
~tribool() = default;
tribool& operator=(const tribool &src)
{
_M_VALUE = src._M_VALUE;
return *this;
}
template <typename T> tribool& operator=(const T &value)
{
set(value);
return *this;
}
operator bool() const { return _M_VALUE == 1; }
bool is_undef() { return _M_VALUE == -1; }
template <typename T> void define(const T &value)
{
if(_M_VALUE == -1)
*this = value;
}
template <typename T> tribool read(const T &value)
{
define(value);
return *this;
}
bool get(const bool &def_value = false)
{
if(_M_VALUE == -1)
return def_value;
return _M_VALUE;
}
template <typename T> bool set(const T &value)
{
_M_VALUE = value;
return _M_VALUE;
}
bool set(const std::string &str)
{
switch(hash_(str))
{
case "true"_hash:
_M_VALUE = 1;
break;
case "false"_hash:
_M_VALUE = 0;
break;
default:
_M_VALUE = -1;
break;
}
return _M_VALUE;
}
void clear() { _M_VALUE = -1; }
};
std::string UrlEncode(const std::string& str); std::string UrlEncode(const std::string& str);
std::string UrlDecode(const std::string& str); std::string UrlDecode(const std::string& str);
std::string base64_decode(const std::string &encoded_string, bool accept_urlsafe = false); std::string base64_decode(const std::string &encoded_string, bool accept_urlsafe = false);
@ -203,6 +127,93 @@ template <typename T, typename U> static inline T to_number(const U &value, T de
int to_int(const std::string &str, int def_value = 0); int to_int(const std::string &str, int def_value = 0);
static inline char getLineBreak(const std::string &str)
{
return count(str.begin(), str.end(), '\n') < 1 ? '\r' : '\n';
}
class tribool
{
private:
int _M_VALUE = -1;
public:
tribool() { clear(); }
template <typename T> tribool(const T &value) { set(value); }
tribool(const tribool &value) { *this = value; }
~tribool() = default;
tribool& operator=(const tribool &src)
{
_M_VALUE = src._M_VALUE;
return *this;
}
template <typename T> tribool& operator=(const T &value)
{
set(value);
return *this;
}
operator bool() const { return _M_VALUE == 1; }
bool is_undef() { return _M_VALUE == -1; }
template <typename T> void define(const T &value)
{
if(_M_VALUE == -1)
*this = value;
}
template <typename T> tribool read(const T &value)
{
define(value);
return *this;
}
bool get(const bool &def_value = false)
{
if(_M_VALUE == -1)
return def_value;
return _M_VALUE;
}
template <typename T> bool set(const T &value)
{
_M_VALUE = value;
return _M_VALUE;
}
bool set(const std::string &str)
{
switch(hash_(str))
{
case "true"_hash:
case "1"_hash:
_M_VALUE = 1;
break;
case "false"_hash:
case "0"_hash:
_M_VALUE = 0;
break;
default:
if(to_int(str, 0) > 1)
_M_VALUE = 1;
else
_M_VALUE = -1;
break;
}
return _M_VALUE;
}
void clear() { _M_VALUE = -1; }
};
#ifndef HAVE_TO_STRING #ifndef HAVE_TO_STRING
namespace std namespace std
{ {

View File

@ -76,7 +76,7 @@ std::shared_future<std::string> fetchFileAsync(const std::string &path, const st
std::shared_future<std::string> retVal; std::shared_future<std::string> retVal;
if(fileExist(path)) if(fileExist(path))
retVal = std::async(std::launch::async, [path](){return fileGet(path, true);}); retVal = std::async(std::launch::async, [path](){return fileGet(path, true);});
else if(startsWith(path, "https://") || startsWith(path, "http://") || startsWith(path, "data:")) else if(isLink(path))
retVal = std::async(std::launch::async, [path, proxy, cache_ttl](){return webGet(path, proxy, cache_ttl);}); retVal = std::async(std::launch::async, [path, proxy, cache_ttl](){return webGet(path, proxy, cache_ttl);});
else else
return std::async(std::launch::async, [](){return std::string();}); return std::async(std::launch::async, [](){return std::string();});

View File

@ -72,7 +72,7 @@ int addNodes(std::string link, std::vector<nodeInfo> &allNodes, int groupID, std
linkType = SPEEDTEST_MESSAGE_FOUNDSOCKS; linkType = SPEEDTEST_MESSAGE_FOUNDSOCKS;
else if(startsWith(link, "https://t.me/http") || startsWith(link, "tg://http")) else if(startsWith(link, "https://t.me/http") || startsWith(link, "tg://http"))
linkType = SPEEDTEST_MESSAGE_FOUNDHTTP; linkType = SPEEDTEST_MESSAGE_FOUNDHTTP;
else if(startsWith(link, "http://") || startsWith(link, "https://") || startsWith(link, "data:") || startsWith(link, "surge:///install-config")) else if(isLink(link) || startsWith(link, "surge:///install-config"))
linkType = SPEEDTEST_MESSAGE_FOUNDSUB; linkType = SPEEDTEST_MESSAGE_FOUNDSUB;
else if(startsWith(link, "Netch://")) else if(startsWith(link, "Netch://"))
linkType = SPEEDTEST_MESSAGE_FOUNDNETCH; linkType = SPEEDTEST_MESSAGE_FOUNDNETCH;

View File

@ -1974,7 +1974,7 @@ void explode(std::string link, bool sslibev, bool ssrlibev, const std::string &c
explodeNetch(link, sslibev, ssrlibev, custom_port, node); explodeNetch(link, sslibev, ssrlibev, custom_port, node);
else if(strFind(link, "trojan://")) else if(strFind(link, "trojan://"))
explodeTrojan(link, custom_port, node); explodeTrojan(link, custom_port, node);
else if(strFind(link, "http://") || strFind(link, "https://")) else if(isLink(link))
explodeHTTPSub(link, custom_port, node); explodeHTTPSub(link, custom_port, node);
} }

View File

@ -22,6 +22,7 @@
#include "templates.h" #include "templates.h"
#include "script_duktape.h" #include "script_duktape.h"
#include "yamlcpp_extra.h" #include "yamlcpp_extra.h"
#include "interfaces.h"
extern bool api_mode; extern bool api_mode;
extern string_array ss_ciphers, ssr_ciphers; extern string_array ss_ciphers, ssr_ciphers;
@ -559,7 +560,7 @@ void processRemark(std::string &oldremark, std::string &newremark, string_array
void rulesetToClash(YAML::Node &base_rule, std::vector<ruleset_content> &ruleset_content_array, bool overwrite_original_rules, bool new_field_name) void rulesetToClash(YAML::Node &base_rule, std::vector<ruleset_content> &ruleset_content_array, bool overwrite_original_rules, bool new_field_name)
{ {
string_array allRules, vArray; string_array allRules, vArray;
std::string rule_group, retrived_rules, strLine; std::string rule_group, retrieved_rules, strLine;
std::stringstream strStrm; std::stringstream strStrm;
const std::string field_name = new_field_name ? "rules" : "Rule"; const std::string field_name = new_field_name ? "rules" : "Rule";
YAML::Node Rules; YAML::Node Rules;
@ -573,15 +574,15 @@ void rulesetToClash(YAML::Node &base_rule, std::vector<ruleset_content> &ruleset
if(max_allowed_rules && total_rules > max_allowed_rules) if(max_allowed_rules && total_rules > max_allowed_rules)
break; break;
rule_group = x.rule_group; rule_group = x.rule_group;
retrived_rules = x.rule_content.get(); retrieved_rules = x.rule_content.get();
if(retrived_rules.empty()) if(retrieved_rules.empty())
{ {
writeLog(0, "Failed to fetch ruleset or ruleset is empty: '" + x.rule_path + "'!", LOG_LEVEL_WARNING); writeLog(0, "Failed to fetch ruleset or ruleset is empty: '" + x.rule_path + "'!", LOG_LEVEL_WARNING);
continue; continue;
} }
if(retrived_rules.find("[]") == 0) if(retrieved_rules.find("[]") == 0)
{ {
strLine = retrived_rules.substr(2); strLine = retrieved_rules.substr(2);
if(strLine.find("FINAL") == 0) if(strLine.find("FINAL") == 0)
strLine.replace(0, 5, "MATCH"); strLine.replace(0, 5, "MATCH");
strLine += "," + rule_group; strLine += "," + rule_group;
@ -591,10 +592,11 @@ void rulesetToClash(YAML::Node &base_rule, std::vector<ruleset_content> &ruleset
total_rules++; total_rules++;
continue; continue;
} }
char delimiter = count(retrived_rules.begin(), retrived_rules.end(), '\n') < 1 ? '\r' : '\n'; convertRuleset(retrieved_rules, x.rule_type);
char delimiter = getLineBreak(retrieved_rules);
strStrm.clear(); strStrm.clear();
strStrm<<retrived_rules; strStrm<<retrieved_rules;
std::string::size_type lineSize; std::string::size_type lineSize;
while(getline(strStrm, strLine, delimiter)) while(getline(strStrm, strLine, delimiter))
{ {
@ -646,7 +648,7 @@ void rulesetToClash(YAML::Node &base_rule, std::vector<ruleset_content> &ruleset
std::string rulesetToClashStr(YAML::Node &base_rule, std::vector<ruleset_content> &ruleset_content_array, bool overwrite_original_rules, bool new_field_name) std::string rulesetToClashStr(YAML::Node &base_rule, std::vector<ruleset_content> &ruleset_content_array, bool overwrite_original_rules, bool new_field_name)
{ {
string_array allRules, vArray; string_array allRules, vArray;
std::string rule_group, retrived_rules, strLine; std::string rule_group, retrieved_rules, strLine;
std::stringstream strStrm; std::stringstream strStrm;
const std::string field_name = new_field_name ? "rules" : "Rule"; const std::string field_name = new_field_name ? "rules" : "Rule";
std::string output_content = "\n" + field_name + ":\n"; std::string output_content = "\n" + field_name + ":\n";
@ -664,15 +666,15 @@ std::string rulesetToClashStr(YAML::Node &base_rule, std::vector<ruleset_content
if(max_allowed_rules && total_rules > max_allowed_rules) if(max_allowed_rules && total_rules > max_allowed_rules)
break; break;
rule_group = x.rule_group; rule_group = x.rule_group;
retrived_rules = x.rule_content.get(); retrieved_rules = x.rule_content.get();
if(retrived_rules.empty()) if(retrieved_rules.empty())
{ {
writeLog(0, "Failed to fetch ruleset or ruleset is empty: '" + x.rule_path + "'!", LOG_LEVEL_WARNING); writeLog(0, "Failed to fetch ruleset or ruleset is empty: '" + x.rule_path + "'!", LOG_LEVEL_WARNING);
continue; continue;
} }
if(retrived_rules.find("[]") == 0) if(retrieved_rules.find("[]") == 0)
{ {
strLine = retrived_rules.substr(2); strLine = retrieved_rules.substr(2);
if(strLine.find("FINAL") == 0) if(strLine.find("FINAL") == 0)
strLine.replace(0, 5, "MATCH"); strLine.replace(0, 5, "MATCH");
strLine += "," + rule_group; strLine += "," + rule_group;
@ -682,10 +684,11 @@ std::string rulesetToClashStr(YAML::Node &base_rule, std::vector<ruleset_content
total_rules++; total_rules++;
continue; continue;
} }
char delimiter = count(retrived_rules.begin(), retrived_rules.end(), '\n') < 1 ? '\r' : '\n'; convertRuleset(retrieved_rules, x.rule_type);
char delimiter = getLineBreak(retrieved_rules);
strStrm.clear(); strStrm.clear();
strStrm<<retrived_rules; strStrm<<retrieved_rules;
std::string::size_type lineSize; std::string::size_type lineSize;
while(getline(strStrm, strLine, delimiter)) while(getline(strStrm, strLine, delimiter))
{ {
@ -714,7 +717,7 @@ std::string rulesetToClashStr(YAML::Node &base_rule, std::vector<ruleset_content
void rulesetToSurge(INIReader &base_rule, std::vector<ruleset_content> &ruleset_content_array, int surge_ver, bool overwrite_original_rules, std::string remote_path_prefix) void rulesetToSurge(INIReader &base_rule, std::vector<ruleset_content> &ruleset_content_array, int surge_ver, bool overwrite_original_rules, std::string remote_path_prefix)
{ {
string_array allRules; string_array allRules;
std::string rule_group, rule_path, retrieved_rules, strLine; std::string rule_group, rule_path, rule_path_typed, retrieved_rules, strLine;
std::stringstream strStrm; std::stringstream strStrm;
size_t total_rules = 0; size_t total_rules = 0;
@ -755,6 +758,7 @@ void rulesetToSurge(INIReader &base_rule, std::vector<ruleset_content> &ruleset_
break; break;
rule_group = x.rule_group; rule_group = x.rule_group;
rule_path = x.rule_path; rule_path = x.rule_path;
rule_path_typed = x.rule_path_typed;
if(rule_path.empty()) if(rule_path.empty())
{ {
strLine = x.rule_content.get().substr(2); strLine = x.rule_content.get().substr(2);
@ -780,39 +784,54 @@ void rulesetToSurge(INIReader &base_rule, std::vector<ruleset_content> &ruleset_
} }
else else
{ {
if(surge_ver == -1 && x.rule_type == RULESET_QUANX && isLink(rule_path))
{
strLine = rule_path + ", tag=" + rule_group + ", force-policy=" + rule_group + ", enabled=true";
base_rule.Set("filter_remote", "{NONAME}", strLine);
continue;
}
if(fileExist(rule_path)) if(fileExist(rule_path))
{ {
if(surge_ver > 2 && remote_path_prefix.size()) if(surge_ver > 2 && remote_path_prefix.size())
{ {
strLine = "RULE-SET," + remote_path_prefix + "/getruleset?type=1&url=" + urlsafe_base64_encode(rule_path) + "," + rule_group; strLine = "RULE-SET," + remote_path_prefix + "/getruleset?type=1&url=" + urlsafe_base64_encode(rule_path_typed) + "," + rule_group;
allRules.emplace_back(strLine); allRules.emplace_back(strLine);
continue; continue;
} }
else if(surge_ver == -1 && remote_path_prefix.size()) else if(surge_ver == -1 && remote_path_prefix.size())
{ {
strLine = remote_path_prefix + "/getruleset?type=2&url=" + urlsafe_base64_encode(rule_path) + "&group=" + urlsafe_base64_encode(rule_group); strLine = remote_path_prefix + "/getruleset?type=2&url=" + urlsafe_base64_encode(rule_path_typed) + "&group=" + urlsafe_base64_encode(rule_group);
strLine += ", tag=" + rule_group + ", enabled=true"; strLine += ", tag=" + rule_group + ", enabled=true";
base_rule.Set("filter_remote", "{NONAME}", strLine); base_rule.Set("filter_remote", "{NONAME}", strLine);
continue; continue;
} }
else if(surge_ver == -4 && remote_path_prefix.size()) else if(surge_ver == -4 && remote_path_prefix.size())
{ {
strLine = remote_path_prefix + "/getruleset?type=1&url=" + urlsafe_base64_encode(rule_path) + "," + rule_group; strLine = remote_path_prefix + "/getruleset?type=1&url=" + urlsafe_base64_encode(rule_path_typed) + "," + rule_group;
base_rule.Set("Remote Rule", "{NONAME}", strLine); base_rule.Set("Remote Rule", "{NONAME}", strLine);
continue; continue;
} }
} }
else if(startsWith(rule_path, "https://") || startsWith(rule_path, "http://") || startsWith(rule_path, "data:")) else if(isLink(rule_path))
{ {
if(surge_ver > 2) if(surge_ver > 2)
{ {
strLine = "RULE-SET," + rule_path + "," + rule_group; if(x.rule_type != RULESET_SURGE)
{
if(remote_path_prefix.size())
strLine = "RULE-SET," + remote_path_prefix + "/getruleset?type=1&url=" + urlsafe_base64_encode(rule_path_typed) + "," + rule_group;
else
continue;
}
else
strLine = "RULE-SET," + rule_path + "," + rule_group;
allRules.emplace_back(strLine); allRules.emplace_back(strLine);
continue; continue;
} }
else if(surge_ver == -1 && remote_path_prefix.size()) else if(surge_ver == -1 && remote_path_prefix.size())
{ {
strLine = remote_path_prefix + "/getruleset?type=2&url=" + urlsafe_base64_encode(rule_path) + "&group=" + urlsafe_base64_encode(rule_group); strLine = remote_path_prefix + "/getruleset?type=2&url=" + urlsafe_base64_encode(rule_path_typed) + "&group=" + urlsafe_base64_encode(rule_group);
strLine += ", tag=" + rule_group + ", enabled=true"; strLine += ", tag=" + rule_group + ", enabled=true";
base_rule.Set("filter_remote", "{NONAME}", strLine); base_rule.Set("filter_remote", "{NONAME}", strLine);
continue; continue;
@ -833,7 +852,8 @@ void rulesetToSurge(INIReader &base_rule, std::vector<ruleset_content> &ruleset_
continue; continue;
} }
char delimiter = count(retrieved_rules.begin(), retrieved_rules.end(), '\n') < 1 ? '\r' : '\n'; convertRuleset(retrieved_rules, x.rule_type);
char delimiter = getLineBreak(retrieved_rules);
strStrm.clear(); strStrm.clear();
strStrm<<retrieved_rules; strStrm<<retrieved_rules;
@ -2427,7 +2447,7 @@ void netchToQuanX(std::vector<nodeInfo> &nodes, INIReader &ini, std::vector<rule
if(regMatch(content, pattern)) if(regMatch(content, pattern))
{ {
url = regReplace(content, pattern, "$2"); url = regReplace(content, pattern, "$2");
if(startsWith(url, "https://") || startsWith(url, "http://")) if(isLink(url))
{ {
url = ext.managed_config_prefix + "/qx-script?id=" + ext.quanx_dev_id + "&url=" + urlsafe_base64_encode(url); url = ext.managed_config_prefix + "/qx-script?id=" + ext.quanx_dev_id + "&url=" + urlsafe_base64_encode(url);
content = regReplace(content, pattern, "$1") + url; content = regReplace(content, pattern, "$1") + url;
@ -2451,7 +2471,7 @@ void netchToQuanX(std::vector<nodeInfo> &nodes, INIReader &ini, std::vector<rule
else else
content = x.second; content = x.second;
if(startsWith(content, "https://") || startsWith(content, "http://")) if(isLink(content))
{ {
pos = content.find(","); pos = content.find(",");
url = ext.managed_config_prefix + "/qx-rewrite?id=" + ext.quanx_dev_id + "&url=" + urlsafe_base64_encode(content.substr(0, pos)); url = ext.managed_config_prefix + "/qx-rewrite?id=" + ext.quanx_dev_id + "&url=" + urlsafe_base64_encode(content.substr(0, pos));

View File

@ -9,10 +9,21 @@
#include "ini_reader.h" #include "ini_reader.h"
#include "nodeinfo.h" #include "nodeinfo.h"
enum ruleset_type
{
RULESET_SURGE,
RULESET_QUANX,
RULESET_CLASH_DOMAIN,
RULESET_CLASH_IPCIDR,
RULESET_CLASH_CLASSICAL
};
struct ruleset_content struct ruleset_content
{ {
std::string rule_group; std::string rule_group;
std::string rule_path; std::string rule_path;
std::string rule_path_typed;
int rule_type = RULESET_SURGE;
std::shared_future<std::string> rule_content; std::shared_future<std::string> rule_content;
}; };

View File

@ -9,6 +9,7 @@
#include "templates.h" #include "templates.h"
#include "logger.h" #include "logger.h"
#include "misc.h" #include "misc.h"
#include "webget.h"
extern std::string managed_config_prefix; extern std::string managed_config_prefix;
@ -220,12 +221,13 @@ int renderClashScript(YAML::Node &base_rule, std::vector<ruleset_content> &rules
{ {
nlohmann::json data; nlohmann::json data;
std::string match_group, geoips, retrieved_rules; std::string match_group, geoips, retrieved_rules;
std::string strLine, rule_group, rule_path, rule_name; std::string strLine, rule_group, rule_path, rule_path_typed, rule_name;
std::stringstream strStrm; std::stringstream strStrm;
string_array vArray, groups; string_array vArray, groups;
string_map keywords, urls, names; string_map keywords, urls, names;
std::map<std::string, bool> has_domain, has_ipcidr; std::map<std::string, bool> has_domain, has_ipcidr;
string_array rules; string_array rules;
int index = 0;
if(!overwrite_original_rules && base_rule["rules"].IsDefined()) if(!overwrite_original_rules && base_rule["rules"].IsDefined())
rules = safe_as<string_array>(base_rule["rules"]); rules = safe_as<string_array>(base_rule["rules"]);
@ -234,6 +236,7 @@ int renderClashScript(YAML::Node &base_rule, std::vector<ruleset_content> &rules
{ {
rule_group = x.rule_group; rule_group = x.rule_group;
rule_path = x.rule_path; rule_path = x.rule_path;
rule_path_typed = x.rule_path_typed;
if(rule_path.empty()) if(rule_path.empty())
{ {
strLine = x.rule_content.get().substr(2); strLine = x.rule_content.get().substr(2);
@ -260,13 +263,38 @@ int renderClashScript(YAML::Node &base_rule, std::vector<ruleset_content> &rules
} }
else else
{ {
if(x.rule_type == RULESET_CLASH_IPCIDR || x.rule_type == RULESET_CLASH_DOMAIN || x.rule_type == RULESET_CLASH_CLASSICAL)
{
rule_name = std::to_string(hash_(rule_group + rule_path));
names[rule_name] = rule_group;
urls[rule_name] = "*" + rule_path;
switch(x.rule_type)
{
case RULESET_CLASH_IPCIDR:
has_ipcidr[rule_name] = true;
if(!script)
rules.emplace_back("RULE-SET," + rule_group + "_" + rule_name + "_ipcidr," + rule_group);
break;
case RULESET_CLASH_DOMAIN:
has_domain[rule_name] = true;
if(!script)
rules.emplace_back("RULE-SET," + rule_group + "_" + rule_name + "_domain," + rule_group);
break;
case RULESET_CLASH_CLASSICAL:
if(!script)
rules.emplace_back("RULE-SET," + rule_group + "_" + rule_name + "_classical," + rule_group);
break;
}
groups.emplace_back(rule_name);
continue;
}
if(remote_path_prefix.size()) if(remote_path_prefix.size())
{ {
if(fileExist(rule_path) || startsWith(rule_path, "https://") || startsWith(rule_path, "http://") || startsWith(rule_path, "data:")) if(isLink(rule_path) || startsWith(rule_path, "data:"))
{ {
rule_name = std::to_string(hash_(rule_path)); rule_name = std::to_string(hash_(rule_group + rule_path));
names[rule_name] = rule_group; names[rule_name] = rule_group;
urls[rule_name] = rule_path; urls[rule_name] = rule_path_typed;
if(clash_classical_ruleset) if(clash_classical_ruleset)
{ {
groups.emplace_back(rule_name); groups.emplace_back(rule_name);
@ -286,7 +314,7 @@ int renderClashScript(YAML::Node &base_rule, std::vector<ruleset_content> &rules
continue; continue;
} }
char delimiter = std::count(retrieved_rules.begin(), retrieved_rules.end(), '\n') < 1 ? '\r' : '\n'; char delimiter = getLineBreak(retrieved_rules);
strStrm.clear(); strStrm.clear();
strStrm<<retrieved_rules; strStrm<<retrieved_rules;
@ -335,7 +363,6 @@ int renderClashScript(YAML::Node &base_rule, std::vector<ruleset_content> &rules
groups.emplace_back(rule_name); groups.emplace_back(rule_name);
} }
} }
int index = 0;
for(std::string &x : groups) for(std::string &x : groups)
{ {
std::string json_path = "rules." + std::to_string(index) + "."; std::string json_path = "rules." + std::to_string(index) + ".";
@ -345,7 +372,10 @@ int renderClashScript(YAML::Node &base_rule, std::vector<ruleset_content> &rules
{ {
base_rule["rule-providers"][name + "_" + x + "_classical"]["type"] = "http"; base_rule["rule-providers"][name + "_" + x + "_classical"]["type"] = "http";
base_rule["rule-providers"][name + "_" + x + "_classical"]["behavior"] = "classical"; base_rule["rule-providers"][name + "_" + x + "_classical"]["behavior"] = "classical";
base_rule["rule-providers"][name + "_" + x + "_classical"]["url"] = remote_path_prefix + "/getruleset?type=6&url=" + urlsafe_base64_encode(url); if(url[0] == '*')
base_rule["rule-providers"][name + "_" + x + "_classical"]["url"] = url.substr(1);
else
base_rule["rule-providers"][name + "_" + x + "_classical"]["url"] = remote_path_prefix + "/getruleset?type=6&url=" + urlsafe_base64_encode(url);
base_rule["rule-providers"][name + "_" + x + "_classical"]["path"] = "./providers/rule-provider_" + x + "_classical.yaml"; base_rule["rule-providers"][name + "_" + x + "_classical"]["path"] = "./providers/rule-provider_" + x + "_classical.yaml";
} }
else else
@ -354,14 +384,20 @@ int renderClashScript(YAML::Node &base_rule, std::vector<ruleset_content> &rules
{ {
base_rule["rule-providers"][name + "_" + x + "_domain"]["type"] = "http"; base_rule["rule-providers"][name + "_" + x + "_domain"]["type"] = "http";
base_rule["rule-providers"][name + "_" + x + "_domain"]["behavior"] = "domain"; base_rule["rule-providers"][name + "_" + x + "_domain"]["behavior"] = "domain";
base_rule["rule-providers"][name + "_" + x + "_domain"]["url"] = remote_path_prefix + "/getruleset?type=3&url=" + urlsafe_base64_encode(url); if(url[0] == '*')
base_rule["rule-providers"][name + "_" + x + "_domain"]["url"] = url.substr(1);
else
base_rule["rule-providers"][name + "_" + x + "_domain"]["url"] = remote_path_prefix + "/getruleset?type=3&url=" + urlsafe_base64_encode(url);
base_rule["rule-providers"][name + "_" + x + "_domain"]["path"] = "./providers/rule-provider_" + x + "_domain.yaml"; base_rule["rule-providers"][name + "_" + x + "_domain"]["path"] = "./providers/rule-provider_" + x + "_domain.yaml";
} }
if(group_has_ipcidr) if(group_has_ipcidr)
{ {
base_rule["rule-providers"][name + "_" + x + "_ipcidr"]["type"] = "http"; base_rule["rule-providers"][name + "_" + x + "_ipcidr"]["type"] = "http";
base_rule["rule-providers"][name + "_" + x + "_ipcidr"]["behavior"] = "ipcidr"; base_rule["rule-providers"][name + "_" + x + "_ipcidr"]["behavior"] = "ipcidr";
base_rule["rule-providers"][name + "_" + x + "_ipcidr"]["url"] = remote_path_prefix + "/getruleset?type=4&url=" + urlsafe_base64_encode(url); if(url[0] == '*')
base_rule["rule-providers"][name + "_" + x + "_ipcidr"]["url"] = url.substr(1);
else
base_rule["rule-providers"][name + "_" + x + "_ipcidr"]["url"] = remote_path_prefix + "/getruleset?type=4&url=" + urlsafe_base64_encode(url);
base_rule["rule-providers"][name + "_" + x + "_ipcidr"]["path"] = "./providers/rule-provider_" + x + "_ipcidr.yaml"; base_rule["rule-providers"][name + "_" + x + "_ipcidr"]["path"] = "./providers/rule-provider_" + x + "_ipcidr.yaml";
} }
} }
@ -391,8 +427,9 @@ int renderClashScript(YAML::Node &base_rule, std::vector<ruleset_content> &rules
std::string output_content = env.render(tmpl, data); std::string output_content = env.render(tmpl, data);
base_rule["script"]["code"] = output_content; base_rule["script"]["code"] = output_content;
} }
catch (std::exception&) catch (std::exception &e)
{ {
writeLog(0, "Error when rendering: " + std::string(e.what()), LOG_TYPE_ERROR);
return -1; return -1;
} }
} }

View File

@ -16,4 +16,9 @@ std::string buildSocks5ProxyString(const std::string &addr, int port, const std:
std::string httpGet(const std::string &host, const std::string &addr, const std::string &uri); std::string httpGet(const std::string &host, const std::string &addr, const std::string &uri);
std::string httpsGet(const std::string &host, const std::string &addr, const std::string &uri); std::string httpsGet(const std::string &host, const std::string &addr, const std::string &uri);
static inline bool isLink(const std::string &url)
{
return startsWith(url, "https://") || startsWith(url, "http://") || startsWith(url, "data:");
}
#endif // WEBGET_H_INCLUDED #endif // WEBGET_H_INCLUDED

View File

@ -1,9 +1,28 @@
#ifndef WEBSERVER_H_INCLUDED #ifndef WEBSERVER_H_INCLUDED
#define WEBSERVER_H_INCLUDED #define WEBSERVER_H_INCLUDED
typedef std::string (*response_callback)(std::string, std::string, int*, std::map<std::string, std::string>&); //process arguments and POST data and return served-content #include <string>
#include <map>
#define RESPONSE_CALLBACK_ARGS std::string argument, std::string postdata, int *status_code, std::map<std::string, std::string> &extra_headers struct Request
{
std::string method;
std::string url;
std::string argument;
std::map<std::string, std::string> headers;
std::string postdata;
};
struct Response
{
int status_code = 200;
std::string content_type;
std::map<std::string, std::string> headers;
};
typedef std::string (*response_callback)(Request&, Response&); //process arguments and POST data and return served-content
#define RESPONSE_CALLBACK_ARGS Request &request, Response &response
struct listener_args struct listener_args
{ {

View File

@ -40,47 +40,45 @@ static inline void buffer_cleanup(struct evbuffer *eb)
#endif // MALLOC_TRIM #endif // MALLOC_TRIM
} }
static inline int process_request(const char *method_str, std::string uri, std::string &postdata, std::string &content_type, std::string &return_data, int *status_code, std::map<std::string, std::string> &extra_headers) //static inline int process_request(const char *method_str, std::string uri, std::string &postdata, std::string &content_type, std::string &return_data, int *status_code, std::map<std::string, std::string> &extra_headers)
static inline int process_request(Request &request, Response &response, std::string &return_data)
{ {
std::string path, arguments; writeLog(0, "handle_cmd: " + request.method + " handle_uri: " + request.url, LOG_LEVEL_VERBOSE);
//std::cerr << "handle_cmd: " << method_str << std::endl << "handle_uri: " << uri << std::endl;
writeLog(0, "handle_cmd: " + std::string(method_str) + " handle_uri: " + uri, LOG_LEVEL_VERBOSE);
if(strFind(uri, "?")) string_size pos = request.url.find("?");
if(pos != request.url.npos)
{ {
path = uri.substr(0, uri.find("?")); request.argument = request.url.substr(pos + 1);
arguments = uri.substr(uri.find("?") + 1); request.url.erase(pos);
} }
else
path = uri;
for(responseRoute &x : responses) for(responseRoute &x : responses)
{ {
if(strcmp(method_str, "OPTIONS") == 0 && postdata.find(x.method) != 0 && x.path == path) if(request.method == "OPTIONS" && request.postdata.find(x.method) != 0 && x.path == request.url)
{ {
return 1; return 1;
} }
else if(x.method.compare(method_str) == 0 && x.path == path) else if(x.method == request.method && x.path == request.url)
{ {
response_callback &rc = x.rc; response_callback &rc = x.rc;
return_data = rc(arguments, postdata, status_code, extra_headers); return_data = rc(request, response);
content_type = x.content_type; response.content_type = x.content_type;
return 0; return 0;
} }
} }
auto iter = redirect_map.find(path); auto iter = redirect_map.find(request.url);
if(iter != redirect_map.end()) if(iter != redirect_map.end())
{ {
return_data = iter->second; return_data = iter->second;
if(arguments.size()) if(request.argument.size())
{ {
if(return_data.find("?") != return_data.npos) if(return_data.find("?") != return_data.npos)
return_data += "&" + arguments; return_data += "&" + request.argument;
else else
return_data += "?" + arguments; return_data += "?" + request.argument;
} }
content_type = "REDIRECT"; response.content_type = "REDIRECT";
return 0; return 0;
} }
@ -117,16 +115,26 @@ void OnReq(evhttp_request *req, void *args)
postdata.assign(req_ac_method); postdata.assign(req_ac_method);
} }
int status_code = 200; Request request;
std::map<std::string, std::string> extra_headers; Response response;
retVal = process_request(req_method, uri, postdata, content_type, return_data, &status_code, extra_headers); request.method = req_method;
request.url = uri;
struct evkeyval* kv = req->input_headers->tqh_first;
while (kv)
{
request.headers.emplace(kv->key, kv->value);
kv = kv->next.tqe_next;
}
retVal = process_request(request, response, return_data);
content_type = response.content_type;
auto *OutBuf = evhttp_request_get_output_buffer(req); auto *OutBuf = evhttp_request_get_output_buffer(req);
//struct evbuffer *OutBuf = evbuffer_new(); //struct evbuffer *OutBuf = evbuffer_new();
if (!OutBuf) if (!OutBuf)
return; return;
for(auto &x : extra_headers) for(auto &x : response.headers)
evhttp_add_header(req->output_headers, x.first.data(), x.second.data()); evhttp_add_header(req->output_headers, x.first.data(), x.second.data());
switch(retVal) switch(retVal)
@ -134,7 +142,7 @@ void OnReq(evhttp_request *req, void *args)
case 1: //found OPTIONS case 1: //found OPTIONS
evhttp_add_header(req->output_headers, "Access-Control-Allow-Origin", "*"); evhttp_add_header(req->output_headers, "Access-Control-Allow-Origin", "*");
evhttp_add_header(req->output_headers, "Access-Control-Allow-Headers", "*"); evhttp_add_header(req->output_headers, "Access-Control-Allow-Headers", "*");
evhttp_send_reply(req, status_code, "", NULL); evhttp_send_reply(req, response.status_code, "", NULL);
break; break;
case 0: //found normal case 0: //found normal
if(content_type.size()) if(content_type.size())
@ -152,7 +160,7 @@ void OnReq(evhttp_request *req, void *args)
evhttp_add_header(req->output_headers, "Access-Control-Allow-Origin", "*"); evhttp_add_header(req->output_headers, "Access-Control-Allow-Origin", "*");
evhttp_add_header(req->output_headers, "Connection", "close"); evhttp_add_header(req->output_headers, "Connection", "close");
evbuffer_add(OutBuf, return_data.data(), return_data.size()); evbuffer_add(OutBuf, return_data.data(), return_data.size());
evhttp_send_reply(req, status_code, "", OutBuf); evhttp_send_reply(req, response.status_code, "", OutBuf);
break; break;
case -1: //not found case -1: //not found
return_data = "File not found."; return_data = "File not found.";