diff --git a/src/handler/interfaces.cpp b/src/handler/interfaces.cpp index d3e32b0..3a5c3ec 100644 --- a/src/handler/interfaces.cpp +++ b/src/handler/interfaces.cpp @@ -37,8 +37,6 @@ extern WebServer webServer; string_array gRegexBlacklist = {"(.*)*"}; -void refreshRulesets(RulesetConfigs &ruleset_list, std::vector &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 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::from_ini(vArray); } /// loading custom rulesets - if(argCustomRulesets.size() && !ext.nodelist) + if(!argCustomRulesets.empty() && !ext.nodelist) { string_array vArray = split(argCustomRulesets, "@"); lCustomRulesets = INIBinding::from::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::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 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(upload, 0) + to_number(download, 0), tot = to_number(total, 0); - time_t expiry = to_number(expire, 0); + auto expiry = to_number(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: \""< writer(sb); diff --git a/src/script/script_quickjs.cpp b/src/script/script_quickjs.cpp index 438adfa..a6e6327 100644 --- a/src/script/script_quickjs.cpp +++ b/src/script/script_quickjs.cpp @@ -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"( diff --git a/src/server/webserver.cpp b/src/server/webserver.cpp deleted file mode 100644 index cbba000..0000000 --- a/src/server/webserver.cpp +++ /dev/null @@ -1,372 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "../utils/file.h" -#include "../utils/string.h" -#include "../utils/system.h" -#include "socket.h" -#include "webserver.h" - -using string_array = std::vector; -int def_timeout = 5; - -struct responseRoute -{ - std::string method; - std::string path; - std::string content_type; - response_callback rc; -}; - -std::vector 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< 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::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"<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!"< 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; -} diff --git a/src/server/webserver.h b/src/server/webserver.h index 952945e..e36b8c4 100644 --- a/src/server/webserver.h +++ b/src/server/webserver.h @@ -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().swap(redirect_map); + } + + int start_web_server(listener_args *args); + int start_web_server_multi(listener_args *args); + std::vector responses; string_map redirect_map; }; diff --git a/src/server/webserver_httplib.cpp b/src/server/webserver_httplib.cpp index ce32017..e8450d9 100644 --- a/src/server/webserver_httplib.cpp +++ b/src/server/webserver_httplib.cpp @@ -2,6 +2,7 @@ #ifdef MALLOC_TRIM #include #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); -} - diff --git a/src/server/webserver_libevent.cpp b/src/server/webserver_libevent.cpp index 8ed3315..0d74639 100644 --- a/src/server/webserver_libevent.cpp +++ b/src/server/webserver_libevent.cpp @@ -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(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(arg)); event_base_free(reinterpret_cast(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(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); -} diff --git a/src/utils/ini_reader/ini_reader.h b/src/utils/ini_reader/ini_reader.h index bb76a15..7f9b492 100644 --- a/src/utils/ini_reader/ini_reader.h +++ b/src/utils/ini_reader/ini_reader.h @@ -21,13 +21,12 @@ enum INIREADER_EXCEPTION_NONE }; -using ini_data_struct = std::map>; -using string_multimap = std::multimap; -using string_array = std::vector; -using string_size = std::string::size_type; - class INIReader { + using ini_data_struct = std::map>; + using string_multimap = std::multimap; + using string_array = std::vector; + 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. diff --git a/src/utils/string.cpp b/src/utils/string.cpp index 897edc8..667279c 100644 --- a/src/utils/string.cpp +++ b/src/utils/string.cpp @@ -7,6 +7,7 @@ #include #include "string.h" +#include "map_extra.h" std::vector 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()) diff --git a/src/utils/string.h b/src/utils/string.h index 1a42487..b376dcc 100644 --- a/src/utils/string.h +++ b/src/utils/string.h @@ -11,6 +11,7 @@ using string = std::string; using string_size = std::string::size_type; using string_array = std::vector; using string_map = std::map; +using string_multimap = std::multimap; using string_pair_array = std::vector>; std::vector 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); diff --git a/src/utils/urlencode.cpp b/src/utils/urlencode.cpp index 57c0a80..16e132e 100644 --- a/src/utils/urlencode.cpp +++ b/src/utils/urlencode.cpp @@ -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; +} diff --git a/src/utils/urlencode.h b/src/utils/urlencode.h index 771ebae..0a21c17 100644 --- a/src/utils/urlencode.h +++ b/src/utils/urlencode.h @@ -3,7 +3,10 @@ #include +#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