mirror of
https://github.com/asdlokj1qpi233/subconverter.git
synced 2026-11-03 18:24:58 +00:00
Fix request arguments not properly handled (#661)
This commit is contained in:
12 files changed
+177
-543
No files matched your search
+88
-91
@@ -37,8 +37,6 @@ extern WebServer webServer;
|
||||
|
||||
string_array gRegexBlacklist = {"(.*)*"};
|
||||
|
||||
void refreshRulesets(RulesetConfigs &ruleset_list, std::vector<RulesetContent> &ruleset_content_array);
|
||||
|
||||
std::string parseProxy(const std::string &source)
|
||||
{
|
||||
std::string proxy = source;
|
||||
@@ -136,19 +134,18 @@ void matchUserAgent(const std::string &user_agent, std::string &target, tribool
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
std::string getRuleset(RESPONSE_CALLBACK_ARGS)
|
||||
{
|
||||
std::string &argument = request.argument;
|
||||
auto &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
|
||||
std::string url = urlSafeBase64Decode(getUrlArg(argument, "url")), type = getUrlArg(argument, "type"), group = urlSafeBase64Decode(getUrlArg(argument, "group"));
|
||||
std::string output_content, dummy;
|
||||
int type_int = to_int(type, 0);
|
||||
|
||||
if(!url.size() || !type.size() || (type_int == 2 && !group.size()) || (type_int < 1 || type_int > 6))
|
||||
if(url.empty() || type.empty() || (type_int == 2 && group.empty()) || (type_int < 1 || type_int > 6))
|
||||
{
|
||||
*status_code = 400;
|
||||
return "Invalid request!";
|
||||
@@ -167,7 +164,7 @@ std::string getRuleset(RESPONSE_CALLBACK_ARGS)
|
||||
output_content += convertRuleset(content, x.rule_type);
|
||||
}
|
||||
|
||||
if(!output_content.size())
|
||||
if(output_content.empty())
|
||||
{
|
||||
*status_code = 400;
|
||||
return "Invalid request!";
|
||||
@@ -184,11 +181,11 @@ std::string getRuleset(RESPONSE_CALLBACK_ARGS)
|
||||
{
|
||||
posb = 0;
|
||||
pose = strLine.find(',');
|
||||
if(pose == strLine.npos)
|
||||
if(pose == std::string::npos)
|
||||
return 1;
|
||||
posb = pose + 1;
|
||||
pose = strLine.find(',', posb);
|
||||
if(pose == strLine.npos)
|
||||
if(pose == std::string::npos)
|
||||
{
|
||||
pose = strLine.size();
|
||||
if(strLine[pose - 1] == '\r')
|
||||
@@ -215,11 +212,11 @@ std::string getRuleset(RESPONSE_CALLBACK_ARGS)
|
||||
switch(type_int)
|
||||
{
|
||||
case 2:
|
||||
if(!std::any_of(QuanXRuleTypes.begin(), QuanXRuleTypes.end(), [&strLine](std::string type){return startsWith(strLine, type);}))
|
||||
if(!std::any_of(QuanXRuleTypes.begin(), QuanXRuleTypes.end(), [&strLine](const std::string& type){return startsWith(strLine, type);}))
|
||||
continue;
|
||||
break;
|
||||
case 1:
|
||||
if(!std::any_of(SurgeRuleTypes.begin(), SurgeRuleTypes.end(), [&strLine](std::string type){return startsWith(strLine, type);}))
|
||||
if(!std::any_of(SurgeRuleTypes.begin(), SurgeRuleTypes.end(), [&strLine](const std::string& type){return startsWith(strLine, type);}))
|
||||
continue;
|
||||
break;
|
||||
case 3:
|
||||
@@ -251,7 +248,7 @@ std::string getRuleset(RESPONSE_CALLBACK_ARGS)
|
||||
output_content += '\n';
|
||||
continue;
|
||||
case 6:
|
||||
if(!std::any_of(ClashRuleTypes.begin(), ClashRuleTypes.end(), [&strLine](std::string type){return startsWith(strLine, type);}))
|
||||
if(!std::any_of(ClashRuleTypes.begin(), ClashRuleTypes.end(), [&strLine](const std::string& type){return startsWith(strLine, type);}))
|
||||
continue;
|
||||
output_content += " - ";
|
||||
}
|
||||
@@ -303,12 +300,12 @@ void checkExternalBase(const std::string &path, std::string &dest)
|
||||
|
||||
std::string subconverter(RESPONSE_CALLBACK_ARGS)
|
||||
{
|
||||
std::string &argument = request.argument;
|
||||
auto &argument = request.argument;
|
||||
int *status_code = &response.status_code;
|
||||
|
||||
std::string argTarget = getUrlArg(argument, "target"), argSurgeVer = getUrlArg(argument, "ver");
|
||||
tribool argClashNewField = getUrlArg(argument, "new_name");
|
||||
int intSurgeVer = argSurgeVer.size() ? to_int(argSurgeVer, 3) : 3;
|
||||
int intSurgeVer = !argSurgeVer.empty() ? to_int(argSurgeVer, 3) : 3;
|
||||
if(argTarget == "auto")
|
||||
matchUserAgent(request.headers["User-Agent"], argTarget, argClashNewField, intSurgeVer);
|
||||
|
||||
@@ -352,8 +349,8 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
|
||||
std::vector<RulesetContent> lRulesetContent;
|
||||
extra_settings ext;
|
||||
std::string subInfo, dummy;
|
||||
int interval = argUpdateInterval.size() ? to_int(argUpdateInterval, global.updateInterval) : global.updateInterval;
|
||||
bool authorized = !global.APIMode || getUrlArg(argument, "token") == global.accessToken, strict = argUpdateStrict.size() ? argUpdateStrict == "true" : global.updateStrict;
|
||||
int interval = !argUpdateInterval.empty() ? to_int(argUpdateInterval, global.updateInterval) : global.updateInterval;
|
||||
bool authorized = !global.APIMode || getUrlArg(argument, "token") == global.accessToken, strict = !argUpdateStrict.empty() ? argUpdateStrict == "true" : global.updateStrict;
|
||||
|
||||
if(std::find(gRegexBlacklist.cbegin(), gRegexBlacklist.cend(), argIncludeRemark) != gRegexBlacklist.cend() || std::find(gRegexBlacklist.cbegin(), gRegexBlacklist.cend(), argExcludeRemark) != gRegexBlacklist.cend())
|
||||
return "Invalid request!";
|
||||
@@ -365,28 +362,35 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
|
||||
|
||||
/// validate urls
|
||||
argEnableInsert.define(global.enableInsert);
|
||||
if(!argUrl.size() && (!global.APIMode || authorized))
|
||||
if(argUrl.empty() && (!global.APIMode || authorized))
|
||||
argUrl = global.defaultUrls;
|
||||
if((!argUrl.size() && !(global.insertUrls.size() && argEnableInsert)) || !argTarget.size())
|
||||
if((argUrl.empty() && !(!global.insertUrls.empty() && argEnableInsert)) || argTarget.empty())
|
||||
{
|
||||
*status_code = 400;
|
||||
return "Invalid request!";
|
||||
}
|
||||
|
||||
/// load request arguments as template variables
|
||||
string_array req_args = split(argument, "&");
|
||||
// string_array req_args = split(argument, "&");
|
||||
// string_map req_arg_map;
|
||||
// for(std::string &x : req_args)
|
||||
// {
|
||||
// string_size pos = x.find("=");
|
||||
// if(pos == x.npos)
|
||||
// {
|
||||
// req_arg_map[x] = "";
|
||||
// continue;
|
||||
// }
|
||||
// if(x.substr(0, pos) == "token")
|
||||
// continue;
|
||||
// req_arg_map[x.substr(0, pos)] = x.substr(pos + 1);
|
||||
// }
|
||||
string_map req_arg_map;
|
||||
for(std::string &x : req_args)
|
||||
for (auto &x : argument)
|
||||
{
|
||||
string_size pos = x.find("=");
|
||||
if(pos == x.npos)
|
||||
{
|
||||
req_arg_map[x] = "";
|
||||
if(x.first == "token")
|
||||
continue;
|
||||
}
|
||||
if(x.substr(0, pos) == "token")
|
||||
continue;
|
||||
req_arg_map[x.substr(0, pos)] = x.substr(pos + 1);
|
||||
req_arg_map[x.first] = x.second;
|
||||
}
|
||||
req_arg_map["target"] = argTarget;
|
||||
req_arg_map["ver"] = std::to_string(intSurgeVer);
|
||||
@@ -414,7 +418,7 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
|
||||
ext.tls13.define(argTLS13).define(global.TLS13Flag);
|
||||
|
||||
ext.sort_flag = argSort.get(global.enableSort);
|
||||
argUseSortScript.define(global.sortScript.size() != 0);
|
||||
argUseSortScript.define(!global.sortScript.empty());
|
||||
if(ext.sort_flag && argUseSortScript)
|
||||
ext.sort_script = global.sortScript;
|
||||
ext.filter_deprecated = argFilterDeprecated.get(global.filterDeprecated);
|
||||
@@ -428,7 +432,7 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
|
||||
|
||||
ext.nodelist = argGenNodeList;
|
||||
ext.surge_ssr_path = global.surgeSSRPath;
|
||||
ext.quanx_dev_id = argDeviceID.size() ? argDeviceID : global.quanXDevID;
|
||||
ext.quanx_dev_id = !argDeviceID.empty() ? argDeviceID : global.quanXDevID;
|
||||
ext.enable_rule_generator = global.enableRuleGen;
|
||||
ext.overwrite_original_rules = global.overwriteOriginalRules;
|
||||
if(!argExpandRulesets)
|
||||
@@ -437,7 +441,7 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
|
||||
/// load external configuration
|
||||
if(argExternalConfig.empty())
|
||||
argExternalConfig = global.defaultExtConfig;
|
||||
if(argExternalConfig.size())
|
||||
if(!argExternalConfig.empty())
|
||||
{
|
||||
//std::cerr<<"External configuration file provided. Loading...\n";
|
||||
writeLog(0, "External configuration file provided. Loading...", LOG_LEVEL_INFO);
|
||||
@@ -459,21 +463,21 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
|
||||
checkExternalBase(extconf.loon_rule_base, lLoonBase);
|
||||
checkExternalBase(extconf.singbox_rule_base, lSingBoxBase);
|
||||
|
||||
if(extconf.surge_ruleset.size())
|
||||
if(!extconf.surge_ruleset.empty())
|
||||
lCustomRulesets = extconf.surge_ruleset;
|
||||
if(extconf.custom_proxy_group.size())
|
||||
if(!extconf.custom_proxy_group.empty())
|
||||
lCustomProxyGroups = extconf.custom_proxy_group;
|
||||
ext.enable_rule_generator = extconf.enable_rule_generator;
|
||||
ext.overwrite_original_rules = extconf.overwrite_original_rules;
|
||||
}
|
||||
}
|
||||
if(extconf.rename.size())
|
||||
if(!extconf.rename.empty())
|
||||
ext.rename_array = extconf.rename;
|
||||
if(extconf.emoji.size())
|
||||
if(!extconf.emoji.empty())
|
||||
ext.emoji_array = extconf.emoji;
|
||||
if(extconf.include.size())
|
||||
if(!extconf.include.empty())
|
||||
lIncludeRemarks = extconf.include;
|
||||
if(extconf.exclude.size())
|
||||
if(!extconf.exclude.empty())
|
||||
lExcludeRemarks = extconf.exclude;
|
||||
argAddEmoji.define(extconf.add_emoji);
|
||||
argRemoveEmoji.define(extconf.remove_old_emoji);
|
||||
@@ -484,14 +488,14 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
|
||||
if(!lSimpleSubscription)
|
||||
{
|
||||
/// loading custom groups
|
||||
if(argCustomGroups.size() && !ext.nodelist)
|
||||
if(!argCustomGroups.empty() && !ext.nodelist)
|
||||
{
|
||||
string_array vArray = split(argCustomGroups, "@");
|
||||
lCustomProxyGroups = INIBinding::from<ProxyGroupConfig>::from_ini(vArray);
|
||||
}
|
||||
|
||||
/// loading custom rulesets
|
||||
if(argCustomRulesets.size() && !ext.nodelist)
|
||||
if(!argCustomRulesets.empty() && !ext.nodelist)
|
||||
{
|
||||
string_array vArray = split(argCustomRulesets, "@");
|
||||
lCustomRulesets = INIBinding::from<RulesetConfig>::from_ini(vArray);
|
||||
@@ -519,15 +523,15 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
|
||||
ext.remove_emoji = argRemoveEmoji.get(global.removeEmoji);
|
||||
if(ext.add_emoji && ext.emoji_array.empty())
|
||||
ext.emoji_array = safe_get_emojis();
|
||||
if(argRenames.size())
|
||||
if(!argRenames.empty())
|
||||
ext.rename_array = INIBinding::from<RegexMatchConfig>::from_ini(split(argRenames, "`"), "@");
|
||||
else if(ext.rename_array.empty())
|
||||
ext.rename_array = safe_get_renames();
|
||||
|
||||
/// check custom include/exclude settings
|
||||
if(argIncludeRemark.size() && regValid(argIncludeRemark))
|
||||
if(!argIncludeRemark.empty() && regValid(argIncludeRemark))
|
||||
lIncludeRemarks = string_array{argIncludeRemark};
|
||||
if(argExcludeRemark.size() && regValid(argExcludeRemark))
|
||||
if(!argExcludeRemark.empty() && regValid(argExcludeRemark))
|
||||
lExcludeRemarks = string_array{argExcludeRemark};
|
||||
|
||||
/// initialize script runtime
|
||||
@@ -559,7 +563,7 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
|
||||
parse_set.js_runtime = ext.js_runtime;
|
||||
parse_set.js_context = ext.js_context;
|
||||
|
||||
if(global.insertUrls.size() && argEnableInsert)
|
||||
if(!global.insertUrls.empty() && argEnableInsert)
|
||||
{
|
||||
groupID = -1;
|
||||
urls = split(global.insertUrls, "|");
|
||||
@@ -602,12 +606,12 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
|
||||
groupID++;
|
||||
}
|
||||
//exit if found nothing
|
||||
if(!nodes.size() && !insert_nodes.size())
|
||||
if(nodes.empty() && insert_nodes.empty())
|
||||
{
|
||||
*status_code = 400;
|
||||
return "No nodes were found!";
|
||||
}
|
||||
if(subInfo.size() && argAppendUserinfo.get(global.appendUserinfo))
|
||||
if(!subInfo.empty() && argAppendUserinfo.get(global.appendUserinfo))
|
||||
response.headers.emplace("Subscription-UserInfo", subInfo);
|
||||
|
||||
if(request.method == "HEAD")
|
||||
@@ -627,7 +631,7 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
|
||||
std::string filterScript = global.filterScript;
|
||||
if(authorized && !argFilterScript.empty())
|
||||
filterScript = argFilterScript;
|
||||
if(filterScript.size())
|
||||
if(!filterScript.empty())
|
||||
{
|
||||
if(startsWith(filterScript, "path:"))
|
||||
filterScript = fileGet(filterScript.substr(5), false);
|
||||
@@ -670,7 +674,7 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
|
||||
}
|
||||
|
||||
//check custom group name
|
||||
if(argGroupName.size())
|
||||
if(!argGroupName.empty())
|
||||
for(Proxy &x : nodes)
|
||||
x.Group = argGroupName;
|
||||
|
||||
@@ -695,7 +699,7 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
|
||||
std::vector<RulesetContent> dummy_ruleset;
|
||||
std::string managed_url = base64Decode(urlDecode(getUrlArg(argument, "profile_data")));
|
||||
if(managed_url.empty())
|
||||
managed_url = global.managedConfigPrefix + "/sub?" + argument;
|
||||
managed_url = global.managedConfigPrefix + "/sub?" + joinArguments(argument);
|
||||
|
||||
//std::cerr<<"Generate target: ";
|
||||
proxy = parseProxy(global.proxyConfig);
|
||||
@@ -747,7 +751,7 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
|
||||
if(argUpload)
|
||||
uploadGist("surge" + argSurgeVer, argUploadPath, output_content, true);
|
||||
|
||||
if(global.writeManagedConfig && global.managedConfigPrefix.size())
|
||||
if(global.writeManagedConfig && !global.managedConfigPrefix.empty())
|
||||
output_content = "#!MANAGED-CONFIG " + managed_url + (interval ? " interval=" + std::to_string(interval) : "") \
|
||||
+ " strict=" + std::string(strict ? "true" : "false") + "\n\n" + output_content;
|
||||
}
|
||||
@@ -764,7 +768,7 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
|
||||
if(argUpload)
|
||||
uploadGist("surfboard", argUploadPath, output_content, true);
|
||||
|
||||
if(global.writeManagedConfig && global.managedConfigPrefix.size())
|
||||
if(global.writeManagedConfig && !global.managedConfigPrefix.empty())
|
||||
output_content = "#!MANAGED-CONFIG " + managed_url + (interval ? " interval=" + std::to_string(interval) : "") \
|
||||
+ " strict=" + std::string(strict ? "true" : "false") + "\n\n" + output_content;
|
||||
break;
|
||||
@@ -899,18 +903,18 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
|
||||
return "Unrecognized target";
|
||||
}
|
||||
writeLog(0, "Generate completed.", LOG_LEVEL_INFO);
|
||||
if(argFilename.size())
|
||||
if(!argFilename.empty())
|
||||
response.headers.emplace("Content-Disposition", "attachment; filename=\"" + argFilename + "\"; filename*=utf-8''" + urlEncode(argFilename));
|
||||
return output_content;
|
||||
}
|
||||
|
||||
std::string simpleToClashR(RESPONSE_CALLBACK_ARGS)
|
||||
{
|
||||
std::string &argument = request.argument;
|
||||
auto argument = joinArguments(request.argument);
|
||||
int *status_code = &response.status_code;
|
||||
|
||||
std::string url = argument.size() <= 8 ? "" : argument.substr(8);
|
||||
if(!url.size() || argument.substr(0, 8) != "sublink=")
|
||||
if(url.empty() || argument.substr(0, 8) != "sublink=")
|
||||
{
|
||||
*status_code = 400;
|
||||
return "Invalid request!";
|
||||
@@ -920,13 +924,14 @@ std::string simpleToClashR(RESPONSE_CALLBACK_ARGS)
|
||||
*status_code = 400;
|
||||
return "Please insert your subscription link instead of clicking the default link.";
|
||||
}
|
||||
request.argument = "target=clashr&url=" + urlEncode(url);
|
||||
request.argument.emplace("target", "clashr");
|
||||
request.argument.emplace("url", urlEncode(url));
|
||||
return subconverter(request, response);
|
||||
}
|
||||
|
||||
std::string surgeConfToClash(RESPONSE_CALLBACK_ARGS)
|
||||
{
|
||||
std::string &argument = request.argument;
|
||||
auto argument = joinArguments(request.argument);
|
||||
int *status_code = &response.status_code;
|
||||
|
||||
INIReader ini;
|
||||
@@ -937,9 +942,9 @@ std::string surgeConfToClash(RESPONSE_CALLBACK_ARGS)
|
||||
|
||||
ini.store_any_line = true;
|
||||
|
||||
if(!url.size())
|
||||
if(url.empty())
|
||||
url = global.defaultUrls;
|
||||
if(!url.size() || argument.substr(0, 5) != "link=")
|
||||
if(url.empty() || argument.substr(0, 5) != "link=")
|
||||
{
|
||||
*status_code = 400;
|
||||
return "Invalid request!";
|
||||
@@ -1008,11 +1013,11 @@ std::string surgeConfToClash(RESPONSE_CALLBACK_ARGS)
|
||||
for(unsigned int i = 1; i < dummy_str_array.size(); i++)
|
||||
{
|
||||
if(startsWith(dummy_str_array[i], "url"))
|
||||
singlegroup["url"] = trim(dummy_str_array[i].substr(dummy_str_array[i].find("=") + 1));
|
||||
singlegroup["url"] = trim(dummy_str_array[i].substr(dummy_str_array[i].find('=') + 1));
|
||||
else if(startsWith(dummy_str_array[i], "interval"))
|
||||
singlegroup["interval"] = trim(dummy_str_array[i].substr(dummy_str_array[i].find("=") + 1));
|
||||
singlegroup["interval"] = trim(dummy_str_array[i].substr(dummy_str_array[i].find('=') + 1));
|
||||
else if(startsWith(dummy_str_array[i], "policy-path"))
|
||||
links.emplace_back(trim(dummy_str_array[i].substr(dummy_str_array[i].find("=") + 1)));
|
||||
links.emplace_back(trim(dummy_str_array[i].substr(dummy_str_array[i].find('=') + 1)));
|
||||
else
|
||||
singlegroup["proxies"].push_back(trim(dummy_str_array[i]));
|
||||
}
|
||||
@@ -1048,7 +1053,7 @@ std::string surgeConfToClash(RESPONSE_CALLBACK_ARGS)
|
||||
}
|
||||
|
||||
//exit if found nothing
|
||||
if(!nodes.size())
|
||||
if(nodes.empty())
|
||||
{
|
||||
*status_code = 400;
|
||||
return "No nodes were found!";
|
||||
@@ -1075,7 +1080,7 @@ std::string surgeConfToClash(RESPONSE_CALLBACK_ARGS)
|
||||
name = x.first;
|
||||
content = x.second;
|
||||
dummy_str_array = split(content, ",");
|
||||
if(!dummy_str_array.size())
|
||||
if(dummy_str_array.empty())
|
||||
continue;
|
||||
content = trim(dummy_str_array[0]);
|
||||
switch(hash_(content))
|
||||
@@ -1112,7 +1117,7 @@ std::string surgeConfToClash(RESPONSE_CALLBACK_ARGS)
|
||||
if(strArray.size() != 3)
|
||||
continue;
|
||||
content = webGet(strArray[1], proxy, global.cacheRuleset);
|
||||
if(!content.size())
|
||||
if(content.empty())
|
||||
continue;
|
||||
|
||||
ss << content;
|
||||
@@ -1125,7 +1130,7 @@ std::string surgeConfToClash(RESPONSE_CALLBACK_ARGS)
|
||||
strLine.erase(--lineSize);
|
||||
if(!lineSize || strLine[0] == ';' || strLine[0] == '#' || (lineSize >= 2 && strLine[0] == '/' && strLine[1] == '/')) //empty lines and comments are ignored
|
||||
continue;
|
||||
else if(!std::any_of(ClashRuleTypes.begin(), ClashRuleTypes.end(), [&strLine](std::string type){return startsWith(strLine, type);})) //remove unsupported types
|
||||
else if(!std::any_of(ClashRuleTypes.begin(), ClashRuleTypes.end(), [&strLine](const std::string& type){return startsWith(strLine, type);})) //remove unsupported types
|
||||
continue;
|
||||
strLine += strArray[2];
|
||||
if(count_least(strLine, ',', 3))
|
||||
@@ -1135,7 +1140,7 @@ std::string surgeConfToClash(RESPONSE_CALLBACK_ARGS)
|
||||
ss.clear();
|
||||
continue;
|
||||
}
|
||||
else if(!std::any_of(ClashRuleTypes.begin(), ClashRuleTypes.end(), [&strLine](std::string type){return startsWith(strLine, type);}))
|
||||
else if(!std::any_of(ClashRuleTypes.begin(), ClashRuleTypes.end(), [&strLine](const std::string& type){return startsWith(strLine, type);}))
|
||||
continue;
|
||||
rule.push_back(x);
|
||||
}
|
||||
@@ -1148,7 +1153,7 @@ std::string surgeConfToClash(RESPONSE_CALLBACK_ARGS)
|
||||
|
||||
std::string getProfile(RESPONSE_CALLBACK_ARGS)
|
||||
{
|
||||
std::string &argument = request.argument;
|
||||
auto &argument = request.argument;
|
||||
int *status_code = &response.status_code;
|
||||
|
||||
std::string name = urlDecode(getUrlArg(argument, "name")), token = urlDecode(getUrlArg(argument, "token"));
|
||||
@@ -1164,7 +1169,8 @@ std::string getProfile(RESPONSE_CALLBACK_ARGS)
|
||||
{
|
||||
profile_content = vfs::vfs_get(name);
|
||||
}
|
||||
else */if(fileExist(name))
|
||||
else */
|
||||
if(fileExist(name))
|
||||
{
|
||||
profile_content = fileGet(name, true);
|
||||
}
|
||||
@@ -1187,7 +1193,7 @@ std::string getProfile(RESPONSE_CALLBACK_ARGS)
|
||||
writeLog(0, "Trying to parse profile '" + name + "'.", LOG_LEVEL_INFO);
|
||||
string_multimap contents;
|
||||
ini.get_items("Profile", contents);
|
||||
if(!contents.size())
|
||||
if(contents.empty())
|
||||
{
|
||||
//std::cerr<<"Load profile failed! Reason: Empty Profile section\n";
|
||||
writeLog(0, "Load profile failed! Reason: Empty Profile section", LOG_LEVEL_ERROR);
|
||||
@@ -1234,7 +1240,7 @@ std::string getProfile(RESPONSE_CALLBACK_ARGS)
|
||||
continue;
|
||||
}
|
||||
url = ini.get("Profile", "url");
|
||||
if(url.size())
|
||||
if(!url.empty())
|
||||
{
|
||||
all_urls += "|" + url;
|
||||
writeLog(0, "Profile url from '" + name + "' added.", LOG_LEVEL_INFO);
|
||||
@@ -1248,10 +1254,8 @@ std::string getProfile(RESPONSE_CALLBACK_ARGS)
|
||||
}
|
||||
|
||||
contents.emplace("token", token);
|
||||
contents.emplace("profile_data", base64Encode(global.managedConfigPrefix + "/getprofile?" + argument));
|
||||
std::string query = std::accumulate(contents.begin(), contents.end(), std::string(), [](const std::string &x, auto y){ return x + y.first + "=" + urlEncode(y.second) + "&"; });
|
||||
query += argument;
|
||||
request.argument = query;
|
||||
contents.emplace("profile_data", base64Encode(global.managedConfigPrefix + "/getprofile?" + joinArguments(argument)));
|
||||
request.argument = argument;
|
||||
return subconverter(request, response);
|
||||
}
|
||||
|
||||
@@ -1276,7 +1280,7 @@ inline std::string intToStream(unsigned long long stream)
|
||||
streamval /= 1024.0;
|
||||
}
|
||||
snprintf(chrs, 15, "%.2f %cB", streamval, units[level]);
|
||||
return std::string(chrs);
|
||||
return {chrs};
|
||||
}
|
||||
|
||||
std::string subInfoToMessage(std::string subinfo)
|
||||
@@ -1286,7 +1290,7 @@ std::string subInfoToMessage(std::string subinfo)
|
||||
std::string retdata, useddata = "N/A", totaldata = "N/A", expirydata = "N/A";
|
||||
std::string upload = getUrlArg(subinfo, "upload"), download = getUrlArg(subinfo, "download"), total = getUrlArg(subinfo, "total"), expire = getUrlArg(subinfo, "expire");
|
||||
ull used = to_number<ull>(upload, 0) + to_number<ull>(download, 0), tot = to_number<ull>(total, 0);
|
||||
time_t expiry = to_number<time_t>(expire, 0);
|
||||
auto expiry = to_number<time_t>(expire, 0);
|
||||
if(used != 0)
|
||||
useddata = intToStream(used);
|
||||
if(tot != 0)
|
||||
@@ -1309,7 +1313,7 @@ int simpleGenerator()
|
||||
{
|
||||
//std::cerr<<"\nReading generator configuration...\n";
|
||||
writeLog(0, "Reading generator configuration...", LOG_LEVEL_INFO);
|
||||
std::string config = fileGet("generate.ini"), path, profile, arguments, content;
|
||||
std::string config = fileGet("generate.ini"), path, profile, content;
|
||||
if(config.empty())
|
||||
{
|
||||
//std::cerr<<"Generator configuration not found or empty!\n";
|
||||
@@ -1328,7 +1332,7 @@ int simpleGenerator()
|
||||
writeLog(0, "Read generator configuration completed.\n", LOG_LEVEL_INFO);
|
||||
|
||||
string_array sections = ini.get_section_names();
|
||||
if(global.generateProfiles.size())
|
||||
if(!global.generateProfiles.empty())
|
||||
{
|
||||
//std::cerr<<"Generating with specific artifacts: \""<<gen_profile<<"\"...\n";
|
||||
writeLog(0, "Generating with specific artifacts: \"" + global.generateProfiles + "\"...", LOG_LEVEL_INFO);
|
||||
@@ -1358,7 +1362,6 @@ int simpleGenerator()
|
||||
Response response;
|
||||
for(std::string &x : sections)
|
||||
{
|
||||
arguments.clear();
|
||||
response.status_code = 200;
|
||||
//std::cerr<<"Generating artifact '"<<x<<"'...\n";
|
||||
writeLog(0, "Generating artifact '" + x + "'...", LOG_LEVEL_INFO);
|
||||
@@ -1374,12 +1377,14 @@ int simpleGenerator()
|
||||
if(ini.item_exist("profile"))
|
||||
{
|
||||
profile = ini.get("profile");
|
||||
request.argument = "name=" + urlEncode(profile) + "&token=" + global.accessToken + "&expand=true";
|
||||
request.argument.emplace("name", urlEncode(profile));
|
||||
request.argument.emplace("token", global.accessToken);
|
||||
request.argument.emplace("expand", "true");
|
||||
content = getProfile(request, response);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(ini.get_bool("direct") == true)
|
||||
if(ini.get_bool("direct"))
|
||||
{
|
||||
std::string url = ini.get("url");
|
||||
content = fetchFile(url, proxy, global.cacheSubscription);
|
||||
@@ -1400,10 +1405,8 @@ int simpleGenerator()
|
||||
{
|
||||
if(y.first == "path")
|
||||
continue;
|
||||
arguments += y.first + "=" + urlEncode(y.second) + "&";
|
||||
request.argument.emplace(y.first, y.second);
|
||||
}
|
||||
arguments.erase(arguments.size() - 1);
|
||||
request.argument = arguments;
|
||||
content = subconverter(request, response);
|
||||
}
|
||||
if(response.status_code != 200)
|
||||
@@ -1429,7 +1432,7 @@ int simpleGenerator()
|
||||
|
||||
std::string renderTemplate(RESPONSE_CALLBACK_ARGS)
|
||||
{
|
||||
std::string &argument = request.argument;
|
||||
auto &argument = request.argument;
|
||||
int *status_code = &response.status_code;
|
||||
|
||||
std::string path = urlDecode(getUrlArg(argument, "path"));
|
||||
@@ -1450,16 +1453,10 @@ std::string renderTemplate(RESPONSE_CALLBACK_ARGS)
|
||||
tpl_args.global_vars = global.templateVars;
|
||||
|
||||
//load request arguments as template variables
|
||||
string_array req_args = split(argument, "&");
|
||||
string_size pos;
|
||||
string_map req_arg_map;
|
||||
for(std::string &x : req_args)
|
||||
for (auto &x : argument)
|
||||
{
|
||||
pos = x.find("=");
|
||||
if(pos == x.npos)
|
||||
req_arg_map[x] = "";
|
||||
else
|
||||
req_arg_map[x.substr(0, pos)] = x.substr(pos + 1);
|
||||
req_arg_map[x.first] = x.second;
|
||||
}
|
||||
tpl_args.request_params = req_arg_map;
|
||||
|
||||
|
||||
+1
-1
@@ -73,7 +73,7 @@ void refresh_schedule()
|
||||
|
||||
std::string list_cron_schedule(RESPONSE_CALLBACK_ARGS)
|
||||
{
|
||||
std::string &argument = request.argument;
|
||||
auto &argument = request.argument;
|
||||
std::string token = getUrlArg(argument, "token");
|
||||
rapidjson::StringBuffer sb;
|
||||
rapidjson::Writer<rapidjson::StringBuffer> writer(sb);
|
||||
|
||||
@@ -377,6 +377,11 @@ static qjs_fetch_Response qjs_fetch(qjs_fetch_Request request)
|
||||
return response;
|
||||
}
|
||||
|
||||
static std::string qjs_getUrlArg(const std::string &url, const std::string &request)
|
||||
{
|
||||
return getUrlArg(url, request);
|
||||
}
|
||||
|
||||
std::string getGeoIP(const std::string &address, const std::string &proxy)
|
||||
{
|
||||
return fetchFile("https://api.ip.sb/geoip/" + address, parseProxy(proxy), global.cacheConfig);
|
||||
@@ -506,7 +511,7 @@ int script_context_init(qjs::Context &context)
|
||||
.add<¤tTime>("time")
|
||||
.add<&sleepMs>("sleep")
|
||||
.add<&ShowMsgbox>("msgbox")
|
||||
.add<&getUrlArg>("getUrlArg")
|
||||
.add<&qjs_getUrlArg>("getUrlArg")
|
||||
.add<&fileGet>("fileGet")
|
||||
.add<&fileWrite>("fileWrite");
|
||||
context.eval(R"(
|
||||
|
||||
@@ -1,372 +0,0 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "../utils/file.h"
|
||||
#include "../utils/string.h"
|
||||
#include "../utils/system.h"
|
||||
#include "socket.h"
|
||||
#include "webserver.h"
|
||||
|
||||
using string_array = std::vector<std::string>;
|
||||
int def_timeout = 5;
|
||||
|
||||
struct responseRoute
|
||||
{
|
||||
std::string method;
|
||||
std::string path;
|
||||
std::string content_type;
|
||||
response_callback rc;
|
||||
};
|
||||
|
||||
std::vector<responseRoute> responses;
|
||||
|
||||
//for use of multi-thread
|
||||
int max_send_failure = 10;
|
||||
std::atomic_bool SERVER_EXIT_FLAG(false);
|
||||
std::atomic_int working_thread(0);
|
||||
|
||||
int sendall(SOCKET sock, std::string data)
|
||||
{
|
||||
unsigned int total = 0, bytesleft = data.size();
|
||||
int sent = 0;
|
||||
const char* datastr = data.data();
|
||||
while(total < bytesleft)
|
||||
{
|
||||
sent = send(sock, datastr + total, bytesleft, 0);
|
||||
if(sent < 0)
|
||||
{
|
||||
std::cerr<<strerror(errno)<<std::endl;
|
||||
if(errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
total += sent;
|
||||
bytesleft -= sent;
|
||||
}
|
||||
return sent == -1 ? -1 : 0;
|
||||
}
|
||||
|
||||
void wrong_req(SOCKET sock)
|
||||
{
|
||||
std::string response = "HTTP/1.1 501 Not Implemented\r\n"
|
||||
"Access-Control-Allow-Origin: *\r\nAccess-Control-Allow-Headers: *\r\n"
|
||||
"Content-Type: text/plain\r\n\r\n"
|
||||
"The command is not yet completed\r\n";
|
||||
|
||||
if (sendall(sock, response) == -1)
|
||||
{
|
||||
std::cerr << "Sending failed!" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void file_not_found(std::string arguments, int sock)
|
||||
{
|
||||
std::string prompt_info = "Not found: " + arguments;
|
||||
std::string response = "HTTP/1.1 404 Not Found\r\n"
|
||||
"Content-Type: text/plain\r\nConnection: close\r\n"
|
||||
"Access-Control-Allow-Origin: *\r\nAccess-Control-Allow-Headers: *\r\n"
|
||||
"Content-Length: " + std::to_string(prompt_info.size()) + "\r\n\r\n" + prompt_info + "\r\n";
|
||||
|
||||
if (sendall(sock, response) == -1)
|
||||
{
|
||||
printf("Sending error!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void send_header(SOCKET send_to, std::string content_type)
|
||||
{
|
||||
std::string header = "HTTP/1.1 200 OK\r\nConnection: close\r\nCache-Control: no-cache, no-store, must-revalidate\r\nAccess-Control-Allow-Origin: *\r\n";
|
||||
if(content_type.size())
|
||||
header += "Content-Type: " + content_type + "\r\n";
|
||||
if(sendall(send_to, header) == -1)
|
||||
{
|
||||
printf("Sending error!");
|
||||
}
|
||||
}
|
||||
|
||||
void send_options_header(SOCKET send_to)
|
||||
{
|
||||
std::string header = "HTTP/1.1 200 OK\r\nAccess-Control-Allow-Origin: *\r\nAccess-Control-Allow-Headers: *\r\n";
|
||||
if(sendall(send_to, header) == -1)
|
||||
{
|
||||
printf("Sending error!");
|
||||
}
|
||||
}
|
||||
|
||||
char* file_type(const char* arg)
|
||||
{
|
||||
char * temp;
|
||||
if ((temp=strrchr(arg,'.')) != NULL)
|
||||
{
|
||||
return temp+1;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void serve_options(SOCKET sock)
|
||||
{
|
||||
send_options_header(sock);
|
||||
std::string extra_header = "Content-Length: 0\r\n\r\n";
|
||||
sendall(sock, extra_header);
|
||||
sendall(sock, "\r\n\r\n");
|
||||
}
|
||||
|
||||
void serve_content(SOCKET sock, std::string type, std::string content)
|
||||
{
|
||||
send_header(sock, type.data());
|
||||
std::string extra_header = "Content-Length: " + std::to_string(content.size()) + "\r\n";
|
||||
sendall(sock, extra_header);
|
||||
send(sock, "\r\n", 2, 0);
|
||||
if (sendall(sock, content) == -1)
|
||||
{
|
||||
printf("Sending error!");
|
||||
}
|
||||
sendall(sock, "\r\n\r\n");
|
||||
}
|
||||
|
||||
void send_file(std::string arguments, int sock)
|
||||
{
|
||||
char* extension = file_type(arguments.data());
|
||||
std::string content_type = "text/plain", data;
|
||||
char sizestr[16] = {};
|
||||
int len;
|
||||
|
||||
if (strcmp(extension, "html") == 0)
|
||||
{
|
||||
content_type = "text/html";
|
||||
}
|
||||
if (strcmp(extension, "gif") == 0)
|
||||
{
|
||||
content_type = "image/gif";
|
||||
}
|
||||
if (strcmp(extension, "jpg") == 0)
|
||||
{
|
||||
content_type = "image/jpg";
|
||||
}
|
||||
|
||||
send_header(sock, content_type);
|
||||
sendall(sock, "Transfer-Encoding: chunked\r\n\r\n");
|
||||
data = fileGet(arguments);
|
||||
len = data.size();
|
||||
sprintf(sizestr, "%x\r\n", len);
|
||||
if (sendall(sock, sizestr) == -1)
|
||||
{
|
||||
printf("Sending error!");
|
||||
}
|
||||
if (sendall(sock, data) == -1)
|
||||
{
|
||||
printf("Sending error!");
|
||||
}
|
||||
len = 2;
|
||||
sendall(sock, "\r\n");
|
||||
|
||||
len = 7;
|
||||
sendall(sock, "0\r\n\r\n");
|
||||
}
|
||||
|
||||
int setTimeout(SOCKET s, int timeout)
|
||||
{
|
||||
int ret = -1;
|
||||
#ifdef _WIN32
|
||||
ret = setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(int));
|
||||
ret = setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(int));
|
||||
#else
|
||||
struct timeval timeo = {timeout / 1000, (timeout % 1000) * 1000};
|
||||
ret = setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (const char*)&timeo, sizeof(timeo));
|
||||
ret = setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeo, sizeof(timeo));
|
||||
#endif
|
||||
def_timeout = timeout;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void handle_req(std::string request, int client_sock)
|
||||
{
|
||||
working_thread++;
|
||||
std::cerr<<"worker startup"<<std::endl;
|
||||
string_array vArray;
|
||||
char command[16] = {};
|
||||
char arguments[BUFSIZ] = {};
|
||||
std::string uri, args, target, postdata;
|
||||
|
||||
if (sscanf(request.data(), "%s%s", command, arguments) != 2)
|
||||
{
|
||||
goto end;
|
||||
}
|
||||
|
||||
std::cerr<<"handle_cmd: "<<command<<"\n"<<"handle_path: "<<arguments<<"\n";
|
||||
|
||||
vArray = split(arguments, "?");
|
||||
|
||||
if(vArray.size() > 2)
|
||||
{
|
||||
wrong_req(client_sock);
|
||||
goto end;
|
||||
}
|
||||
else if(vArray.size() > 1)
|
||||
{
|
||||
uri = vArray[0];
|
||||
args = vArray[1];
|
||||
}
|
||||
else
|
||||
uri = arguments;
|
||||
|
||||
if(strcmp(command, "POST") == 0)
|
||||
{
|
||||
if(request.find("\r\n\r\n") != request.npos)
|
||||
postdata = request.substr(request.find("\r\n\r\n") + 4);
|
||||
}
|
||||
else if(strcmp(command, "OPTIONS") == 0)
|
||||
{
|
||||
serve_options(client_sock);
|
||||
goto end;
|
||||
}
|
||||
|
||||
for(std::vector<responseRoute>::iterator iter = responses.begin(); iter != responses.end(); ++iter)
|
||||
{
|
||||
if(iter->method.compare(command) == 0 && iter->path == uri)
|
||||
{
|
||||
response_callback &rc = iter->rc;
|
||||
serve_content(client_sock, iter->content_type, rc(args, postdata));
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
file_not_found(uri, client_sock);
|
||||
|
||||
end:
|
||||
std::cerr<<"worker stop"<<std::endl;
|
||||
sleepMs(1);
|
||||
closesocket(client_sock);
|
||||
working_thread--;
|
||||
}
|
||||
|
||||
void append_response(const std::string &type, const std::string &request, const std::string &content_type, response_callback response)
|
||||
{
|
||||
responseRoute rr;
|
||||
rr.method = type;
|
||||
rr.path = request;
|
||||
rr.content_type = content_type;
|
||||
rr.rc = response;
|
||||
responses.push_back(std::move(rr));
|
||||
}
|
||||
|
||||
void stop_web_server()
|
||||
{
|
||||
SERVER_EXIT_FLAG = true;
|
||||
}
|
||||
|
||||
int start_web_server(void *argv)
|
||||
{
|
||||
struct listener_args *args = (listener_args*)argv;
|
||||
args->max_workers = 1;
|
||||
return start_web_server_multi(args);
|
||||
}
|
||||
|
||||
int start_web_server_multi(void *argv)
|
||||
{
|
||||
//log startup
|
||||
struct listener_args *args = (listener_args*)argv;
|
||||
std::string listen_address = args->listen_address, request;
|
||||
int port = args->port, max_conn = args->max_conn, max_workers = args->max_workers, numbytes, worker_index = 0;
|
||||
socklen_t sock_size = sizeof(struct sockaddr_in);
|
||||
char buf[BUFSIZ];
|
||||
struct sockaddr_in user_socket, server_addr;
|
||||
SOCKET acc_socket;
|
||||
int server_socket, fail_counter = 0;
|
||||
server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
|
||||
std::thread workers[max_workers];
|
||||
|
||||
if (server_socket == -1)
|
||||
{
|
||||
//log socket error
|
||||
std::cerr<<"socket build error!"<<std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ZeroMemory(&server_addr, sizeof(server_addr));
|
||||
server_addr.sin_family = AF_INET;
|
||||
server_addr.sin_port = htons((short)port);
|
||||
server_addr.sin_addr.s_addr = inet_addr(listen_address.data());
|
||||
if (::bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1)
|
||||
{
|
||||
//log bind error
|
||||
std::cerr<<"socket bind error!"<<std::endl;
|
||||
closesocket(server_socket);
|
||||
return 0;
|
||||
}
|
||||
if (listen(server_socket, max_conn) == -1 )
|
||||
{
|
||||
//log listen error
|
||||
std::cerr<<"socket listen error!"<<std::endl;
|
||||
closesocket(server_socket);
|
||||
return 0;
|
||||
}
|
||||
setTimeout(server_socket, 500);
|
||||
|
||||
while(true)
|
||||
{
|
||||
acc_socket = accept(server_socket, (struct sockaddr *)&user_socket, &sock_size); //wait for connection
|
||||
if(acc_socket < 0)
|
||||
{
|
||||
if(errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)
|
||||
{
|
||||
fail_counter++;
|
||||
if(fail_counter > max_send_failure)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
request = "";
|
||||
while(true) //receive the complete request
|
||||
{
|
||||
numbytes = recv(acc_socket, buf, BUFSIZ - 1, 0);
|
||||
if(numbytes > 0) //received
|
||||
request.append(buf);
|
||||
if(numbytes < 0)
|
||||
{
|
||||
if(errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(numbytes == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
//handle_req(buf, acc_socket);
|
||||
|
||||
while(working_thread >= max_workers)
|
||||
{
|
||||
sleepMs(10);
|
||||
if(SERVER_EXIT_FLAG)
|
||||
break;
|
||||
}
|
||||
while(workers[worker_index].get_id() != std::thread::id())
|
||||
{
|
||||
worker_index++;
|
||||
}
|
||||
workers[worker_index] = std::thread(handle_req, request, acc_socket);
|
||||
workers[worker_index].detach();
|
||||
worker_index++;
|
||||
if(worker_index > max_workers)
|
||||
worker_index = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
+25
-7
@@ -14,7 +14,7 @@ struct Request
|
||||
{
|
||||
std::string method;
|
||||
std::string url;
|
||||
std::string argument;
|
||||
string_multimap argument;
|
||||
string_icase_map headers;
|
||||
std::string postdata;
|
||||
};
|
||||
@@ -45,7 +45,7 @@ struct responseRoute
|
||||
std::string method;
|
||||
std::string path;
|
||||
std::string content_type;
|
||||
response_callback rc;
|
||||
response_callback rc {};
|
||||
};
|
||||
|
||||
class WebServer
|
||||
@@ -62,13 +62,31 @@ public:
|
||||
bool require_auth = false;
|
||||
std::string auth_user, auth_password, auth_realm = "Please enter username and password:";
|
||||
|
||||
void append_response(const std::string &method, const std::string &uri, const std::string &content_type, response_callback response);
|
||||
void append_redirect(const std::string &uri, const std::string &target);
|
||||
void reset_redirect();
|
||||
int start_web_server(void *argv);
|
||||
int start_web_server_multi(void *argv);
|
||||
void stop_web_server();
|
||||
|
||||
void append_response(const std::string &method, const std::string &uri, const std::string &content_type, response_callback response)
|
||||
{
|
||||
responseRoute rr;
|
||||
rr.method = method;
|
||||
rr.path = uri;
|
||||
rr.content_type = content_type;
|
||||
rr.rc = response;
|
||||
responses.emplace_back(std::move(rr));
|
||||
}
|
||||
|
||||
void append_redirect(const std::string &uri, const std::string &target)
|
||||
{
|
||||
redirect_map[uri] = target;
|
||||
}
|
||||
|
||||
void reset_redirect()
|
||||
{
|
||||
std::map<std::string, std::string>().swap(redirect_map);
|
||||
}
|
||||
|
||||
int start_web_server(listener_args *args);
|
||||
int start_web_server_multi(listener_args *args);
|
||||
|
||||
std::vector<responseRoute> responses;
|
||||
string_map redirect_map;
|
||||
};
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#ifdef MALLOC_TRIM
|
||||
#include <malloc.h>
|
||||
#endif // MALLOC_TRIM
|
||||
#define CPPHTTPLIB_REQUEST_URI_MAX_LENGTH 16384
|
||||
#include "httplib.h"
|
||||
|
||||
#include "../utils/base64/base64.h"
|
||||
@@ -11,11 +12,6 @@
|
||||
#include "../utils/urlencode.h"
|
||||
#include "webserver.h"
|
||||
|
||||
int WebServer::start_web_server(void *argv)
|
||||
{
|
||||
return start_web_server_multi(argv);
|
||||
}
|
||||
|
||||
void WebServer::stop_web_server()
|
||||
{
|
||||
SERVER_EXIT_FLAG = true;
|
||||
@@ -33,11 +29,7 @@ static httplib::Server::Handler makeHandler(const responseRoute &rr)
|
||||
{
|
||||
req.headers[h.first] = h.second;
|
||||
}
|
||||
for (auto &p: request.params)
|
||||
{
|
||||
req.argument += p.first + "=" + p.second + "&";
|
||||
}
|
||||
req.argument.pop_back();
|
||||
req.argument = request.params;
|
||||
req.postdata = request.body;
|
||||
if (request.get_header_value("Content-Type") == "application/x-www-form-urlencoded")
|
||||
{
|
||||
@@ -57,10 +49,9 @@ static httplib::Server::Handler makeHandler(const responseRoute &rr)
|
||||
};
|
||||
}
|
||||
|
||||
int WebServer::start_web_server_multi(void *argv)
|
||||
int WebServer::start_web_server_multi(listener_args *args)
|
||||
{
|
||||
httplib::Server server;
|
||||
auto *args = (listener_args *)argv;
|
||||
for (auto &x : responses)
|
||||
{
|
||||
switch (hash_(x.method))
|
||||
@@ -104,7 +95,7 @@ int WebServer::start_web_server_multi(void *argv)
|
||||
std::string params;
|
||||
for (auto &p: req.params)
|
||||
{
|
||||
params += p.first + "=" + p.second + "&";
|
||||
params += p.first + "=" + urlEncode(p.second) + "&";
|
||||
}
|
||||
if (!params.empty())
|
||||
{
|
||||
@@ -201,23 +192,7 @@ int WebServer::start_web_server_multi(void *argv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void WebServer::append_response(const std::string &method, const std::string &uri, const std::string &content_type, response_callback response)
|
||||
int WebServer::start_web_server(listener_args *args)
|
||||
{
|
||||
responseRoute rr;
|
||||
rr.method = method;
|
||||
rr.path = uri;
|
||||
rr.content_type = content_type;
|
||||
rr.rc = response;
|
||||
responses.emplace_back(std::move(rr));
|
||||
return start_web_server_multi(args);
|
||||
}
|
||||
|
||||
void WebServer::append_redirect(const std::string &uri, const std::string &target)
|
||||
{
|
||||
redirect_map[uri] = target;
|
||||
}
|
||||
|
||||
void WebServer::reset_redirect()
|
||||
{
|
||||
eraseElements(redirect_map);
|
||||
}
|
||||
|
||||
@@ -112,14 +112,22 @@ static inline void buffer_cleanup(struct evbuffer *eb)
|
||||
#endif // MALLOC_TRIM
|
||||
}
|
||||
|
||||
inline int process_request(WebServer *server, Request &request, Response &response, std::string &return_data)
|
||||
static int process_request(WebServer *server, Request &request, Response &response, std::string &return_data)
|
||||
{
|
||||
writeLog(0, "handle_cmd: " + request.method + " handle_uri: " + request.url, LOG_LEVEL_VERBOSE);
|
||||
|
||||
string_size pos = request.url.find('?');
|
||||
if(pos != std::string::npos)
|
||||
{
|
||||
request.argument = request.url.substr(pos + 1);
|
||||
auto argument = split(request.url.substr(pos + 1), "&");
|
||||
for(auto &x : argument)
|
||||
{
|
||||
string_size pos2 = x.find('=');
|
||||
if(pos2 != std::string::npos)
|
||||
request.argument.emplace(x.substr(0, pos2), x.substr(pos2 + 1));
|
||||
else
|
||||
request.argument.emplace(x, "");
|
||||
}
|
||||
request.url.erase(pos);
|
||||
}
|
||||
|
||||
@@ -143,7 +151,7 @@ inline int process_request(WebServer *server, Request &request, Response &respon
|
||||
}
|
||||
catch(std::exception &e)
|
||||
{
|
||||
return_data = "Internal server error while processing request path '" + request.url + "' with arguments '" + request.argument + "'!";
|
||||
return_data = "Internal server error while processing request path '" + request.url + "' with arguments '" + joinArguments(request.argument) + "'!";
|
||||
return_data += "\n exception: ";
|
||||
return_data += type(e);
|
||||
return_data += "\n what(): ";
|
||||
@@ -163,9 +171,9 @@ inline int process_request(WebServer *server, Request &request, Response &respon
|
||||
if(!request.argument.empty())
|
||||
{
|
||||
if(return_data.find('?') != std::string::npos)
|
||||
return_data += "&" + request.argument;
|
||||
return_data += "&" + joinArguments(request.argument);
|
||||
else
|
||||
return_data += "?" + request.argument;
|
||||
return_data += "?" + joinArguments(request.argument);
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
@@ -179,7 +187,7 @@ inline int process_request(WebServer *server, Request &request, Response &respon
|
||||
return -1;
|
||||
}
|
||||
|
||||
void on_request(evhttp_request *req, void *args)
|
||||
static void on_request(evhttp_request *req, void *args)
|
||||
{
|
||||
auto server = (WebServer*) args;
|
||||
static std::string auth_token = "Basic " + base64Encode(server->auth_user + ":" + server->auth_password);
|
||||
@@ -293,9 +301,8 @@ void on_request(evhttp_request *req, void *args)
|
||||
buffer_cleanup(output_buffer);
|
||||
}
|
||||
|
||||
int WebServer::start_web_server(void *argv)
|
||||
int WebServer::start_web_server(listener_args *args)
|
||||
{
|
||||
auto *args = reinterpret_cast<listener_args*>(argv);
|
||||
std::string listen_address = args->listen_address;
|
||||
int port = args->port;
|
||||
if (!event_init())
|
||||
@@ -314,10 +321,8 @@ int WebServer::start_web_server(void *argv)
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto call_on_request = [&](evhttp_request *req, void *args) { on_request(req, args); };
|
||||
|
||||
evhttp_set_allowed_methods(server.get(), EVHTTP_REQ_GET | EVHTTP_REQ_POST | EVHTTP_REQ_OPTIONS | EVHTTP_REQ_PUT | EVHTTP_REQ_PATCH | EVHTTP_REQ_DELETE | EVHTTP_REQ_HEAD);
|
||||
evhttp_set_gencb(server.get(), wrap(call_on_request), this);
|
||||
evhttp_set_gencb(server.get(), on_request, this);
|
||||
evhttp_set_timeout(server.get(), 30);
|
||||
if (event_dispatch() == -1)
|
||||
{
|
||||
@@ -329,14 +334,14 @@ int WebServer::start_web_server(void *argv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* httpserver_dispatch(void *arg)
|
||||
static void* httpserver_dispatch(void *arg)
|
||||
{
|
||||
event_base_dispatch(reinterpret_cast<event_base*>(arg));
|
||||
event_base_free(reinterpret_cast<event_base*>(arg)); //free resources
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int httpserver_bindsocket(std::string listen_address, int listen_port, int backlog)
|
||||
static int httpserver_bindsocket(std::string listen_address, int listen_port, int backlog)
|
||||
{
|
||||
SOCKET nfd;
|
||||
nfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
@@ -375,9 +380,8 @@ int httpserver_bindsocket(std::string listen_address, int listen_port, int backl
|
||||
return nfd;
|
||||
}
|
||||
|
||||
int WebServer::start_web_server_multi(void *argv)
|
||||
int WebServer::start_web_server_multi(listener_args *args)
|
||||
{
|
||||
auto *args = reinterpret_cast<listener_args*>(argv);
|
||||
std::string listen_address = args->listen_address;
|
||||
int port = args->port, nthreads = args->max_workers, max_conn = args->max_conn;
|
||||
|
||||
@@ -426,23 +430,3 @@ void WebServer::stop_web_server()
|
||||
{
|
||||
SERVER_EXIT_FLAG = true;
|
||||
}
|
||||
|
||||
void WebServer::append_response(const std::string &method, const std::string &uri, const std::string &content_type, response_callback response)
|
||||
{
|
||||
responseRoute rr;
|
||||
rr.method = method;
|
||||
rr.path = uri;
|
||||
rr.content_type = content_type;
|
||||
rr.rc = response;
|
||||
responses.emplace_back(std::move(rr));
|
||||
}
|
||||
|
||||
void WebServer::append_redirect(const std::string &uri, const std::string &target)
|
||||
{
|
||||
redirect_map[uri] = target;
|
||||
}
|
||||
|
||||
void WebServer::reset_redirect()
|
||||
{
|
||||
eraseElements(redirect_map);
|
||||
}
|
||||
@@ -21,13 +21,12 @@ enum
|
||||
INIREADER_EXCEPTION_NONE
|
||||
};
|
||||
|
||||
using ini_data_struct = std::map<std::string, std::multimap<std::string, std::string>>;
|
||||
using string_multimap = std::multimap<std::string, std::string>;
|
||||
using string_array = std::vector<std::string>;
|
||||
using string_size = std::string::size_type;
|
||||
|
||||
class INIReader
|
||||
{
|
||||
using ini_data_struct = std::map<std::string, std::multimap<std::string, std::string>>;
|
||||
using string_multimap = std::multimap<std::string, std::string>;
|
||||
using string_array = std::vector<std::string>;
|
||||
using string_size = std::string::size_type;
|
||||
/**
|
||||
* @brief A simple INI reader which utilize map and vector
|
||||
* to store sections and items, allowing access in logarithmic time.
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <time.h>
|
||||
|
||||
#include "string.h"
|
||||
#include "map_extra.h"
|
||||
|
||||
std::vector<std::string> split(const std::string &s, const std::string &seperator)
|
||||
{
|
||||
@@ -298,6 +299,14 @@ std::string getUrlArg(const std::string &url, const std::string &request)
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string getUrlArg(const string_multimap &url, const std::string &request)
|
||||
{
|
||||
auto it = url.find(request);
|
||||
if(it != url.end())
|
||||
return it->second;
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string replaceAllDistinct(std::string str, const std::string &old_value, const std::string &new_value)
|
||||
{
|
||||
for(std::string::size_type pos(0); pos != std::string::npos; pos += new_value.length())
|
||||
|
||||
@@ -11,6 +11,7 @@ using string = std::string;
|
||||
using string_size = std::string::size_type;
|
||||
using string_array = std::vector<std::string>;
|
||||
using string_map = std::map<std::string, std::string>;
|
||||
using string_multimap = std::multimap<std::string, std::string>;
|
||||
using string_pair_array = std::vector<std::pair<std::string, std::string>>;
|
||||
|
||||
std::vector<std::string> split(const std::string &s, const std::string &seperator);
|
||||
@@ -27,6 +28,7 @@ std::string join(InputIt first, InputIt last, const std::string &delimiter)
|
||||
}
|
||||
|
||||
std::string getUrlArg(const std::string &url, const std::string &request);
|
||||
std::string getUrlArg(const string_multimap &url, const std::string &request);
|
||||
std::string replaceAllDistinct(std::string str, const std::string &old_value, const std::string &new_value);
|
||||
std::string trimOf(const std::string& str, char target, bool before = true, bool after = true);
|
||||
std::string trim(const std::string& str, bool before = true, bool after = true);
|
||||
|
||||
@@ -69,3 +69,17 @@ std::string urlDecode(const std::string& str)
|
||||
}
|
||||
return strTemp;
|
||||
}
|
||||
|
||||
std::string joinArguments(const string_multimap &args)
|
||||
{
|
||||
std::string strTemp;
|
||||
for (auto &p: args)
|
||||
{
|
||||
strTemp += p.first + "=" + urlEncode(p.second) + "&";
|
||||
}
|
||||
if (!strTemp.empty())
|
||||
{
|
||||
strTemp.pop_back();
|
||||
}
|
||||
return strTemp;
|
||||
}
|
||||
@@ -3,7 +3,10 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "utils/string.h"
|
||||
|
||||
std::string urlEncode(const std::string& str);
|
||||
std::string urlDecode(const std::string& str);
|
||||
std::string joinArguments(const string_multimap &args);
|
||||
|
||||
#endif // URLENCODE_H_INCLUDED
|
||||
Reference in new issue
Block a user