Cleanup codes

inja: Using a better implementation for stripping blanks for expressions.
This commit is contained in:
Tindy X
2020-08-12 02:03:00 +08:00
parent a90ceb4b8e
commit 65ac33d514
19 changed files with 103 additions and 499 deletions

View File

@@ -1460,7 +1460,9 @@ struct LexerConfig {
std::string statement_close_force_rstrip {"-%}"};
std::string line_statement {"##"};
std::string expression_open {"{{"};
std::string expression_open_force_lstrip {"{{-"};
std::string expression_close {"}}"};
std::string expression_close_force_rstrip {"-}}"};
std::string comment_open {"{#"};
std::string comment_close {"#}"};
std::string open_chars {"#{"};
@@ -1485,6 +1487,9 @@ struct LexerConfig {
if (open_chars.find(expression_open[0]) == std::string::npos) {
open_chars += expression_open[0];
}
if (open_chars.find(expression_open_force_lstrip[0]) == std::string::npos) {
open_chars += expression_open_force_lstrip[0];
}
if (open_chars.find(comment_open[0]) == std::string::npos) {
open_chars += comment_open[0];
}
@@ -1786,7 +1791,7 @@ struct Token {
Unknown,
Eof,
};
Kind kind {Kind::Unknown};
nonstd::string_view text;
@@ -1895,6 +1900,7 @@ class Lexer {
enum class State {
Text,
ExpressionStart,
ExpressionStartForceLstrip,
ExpressionBody,
LineStart,
LineBody,
@@ -1918,8 +1924,6 @@ class Lexer {
nonstd::string_view m_in;
size_t tok_start;
size_t pos;
bool temp_trim_flag = false;
Token scan_body(nonstd::string_view close, Token::Kind closeKind, nonstd::string_view close_trim = nonstd::string_view(), bool trim = false) {
again:
@@ -1942,22 +1946,13 @@ class Lexer {
return tok;
}
if (ch == '-') {
if (inja::string_view::starts_with(m_in.substr(tok_start + 1), close)) {
tok_start += 1;
temp_trim_flag = true;
} else
return make_token(Token::Kind::Unknown);
}
if (inja::string_view::starts_with(m_in.substr(tok_start), close)) {
state = State::Text;
pos = tok_start + close.size();
Token tok = make_token(closeKind);
if (trim || temp_trim_flag) {
if (trim) {
skip_whitespaces_and_first_newline();
}
temp_trim_flag = false;
return tok;
}
@@ -2192,7 +2187,12 @@ public:
nonstd::string_view open_str = m_in.substr(pos);
bool must_lstrip = false;
if (inja::string_view::starts_with(open_str, config.expression_open)) {
state = State::ExpressionStart;
if (inja::string_view::starts_with(open_str, config.expression_open_force_lstrip)) {
state = State::ExpressionStartForceLstrip;
must_lstrip = true;
} else {
state = State::ExpressionStart;
}
} else if (inja::string_view::starts_with(open_str, config.statement_open)) {
if (inja::string_view::starts_with(open_str, config.statement_open_no_lstrip)) {
state = State::StatementStartNoLstrip;
@@ -2227,11 +2227,11 @@ public:
case State::ExpressionStart: {
state = State::ExpressionBody;
pos += config.expression_open.size();
// whitespace control
if (m_in[pos] == '-') {
pos += 1;
temp_trim_flag = true;
}
return make_token(Token::Kind::ExpressionOpen);
}
case State::ExpressionStartForceLstrip: {
state = State::ExpressionBody;
pos += config.expression_open_force_lstrip.size();
return make_token(Token::Kind::ExpressionOpen);
}
case State::LineStart: {
@@ -2260,7 +2260,7 @@ public:
return make_token(Token::Kind::CommentOpen);
}
case State::ExpressionBody:
return scan_body(config.expression_close, Token::Kind::ExpressionClose);
return scan_body(config.expression_close, Token::Kind::ExpressionClose, config.expression_close_force_rstrip);
case State::LineBody:
return scan_body("\n", Token::Kind::LineStatementClose);
case State::StatementBody:
@@ -2869,7 +2869,7 @@ class Parser {
// Functions
} else if (peek_tok.kind == Token::Kind::LeftParen) {
operator_stack.emplace(std::make_shared<FunctionNode>(static_cast<std::string>(tok.text), tok.text.data() - tmpl.content.c_str()));
function_stack.emplace(operator_stack.top().get(), current_paren_level);
function_stack.emplace(operator_stack.top().get(), current_paren_level);
// Variables
} else {
@@ -3477,10 +3477,10 @@ class Renderer : public NodeVisitor {
void visit(const JsonNode& node) {
if (json_additional_data.contains(node.ptr)) {
json_eval_stack.push(&json_additional_data[node.ptr]);
} else if (json_input->contains(node.ptr)) {
json_eval_stack.push(&(*json_input)[node.ptr]);
} else {
// Try to evaluate as a no-argument callback
auto function_data = function_storage.find_function(node.name, 0);
@@ -4137,4 +4137,4 @@ inline void render_to(std::ostream &os, nonstd::string_view input, const json &d
// #include "template.hpp"
#endif // INCLUDE_INJA_INJA_HPP_
#endif // INCLUDE_INJA_INJA_HPP_

View File

@@ -1,7 +1,8 @@
FROM alpine:latest
MAINTAINER Tindy X <tindy.it@gmail.com>
FROM alpine:3.12
LABEL maintainer "tindy.it@gmail.com"
# build minimized
WORKDIR /
RUN apk add --no-cache --virtual .build-tools git g++ build-base linux-headers cmake python2 && \
apk add --no-cache --virtual .build-deps curl-dev rapidjson-dev libevent-dev pcre2-dev yaml-cpp-dev && \
git clone https://github.com/svaarala/duktape --depth=1 && \

View File

@@ -40,6 +40,6 @@ g++ -o base/subconverter $(find CMakeFiles/subconverter.dir/src/ -name "*.o") -
cd base
chmod +rx subconverter
chmod +r *
chmod +r ./*
cd ..
mv base subconverter

View File

@@ -43,7 +43,7 @@ c++ -Xlinker -unexported_symbol -Xlinker "*" -o base/subconverter -framework Cor
cd base
chmod +rx subconverter
chmod +r *
chmod +r ./*
cd ..
mv base subconverter

View File

@@ -25,7 +25,7 @@ cc -c -O3 -o duktape.o duktape.c
cc -c -O3 -o duk_module_node.o -I. ../extras/module-node/duk_module_node.c
ar cr libduktape.a duktape.o
ar cr libduktape_module.a duk_module_node.o
install -m0644 *.a /data/data/com.termux/files/usr/lib
install -m0644 ./*.a /data/data/com.termux/files/usr/lib
install -m0644 duk*.h /data/data/com.termux/files/usr/include
install -m0644 ../extras/module-node/duk_module_node.h /data/data/com.termux/files/usr/include
cd ../../..

View File

@@ -1451,10 +1451,10 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
expand.define(true);
/// read preference from argument, assign global var if not in argument
ext.tfo.read(tfo).read(tfo_flag);
ext.udp.read(udp).read(udp_flag);
ext.skip_cert_verify.read(scv).read(scv_flag);
ext.tls13.read(tls13).read(tls13_flag);
ext.tfo.parse(tfo).parse(tfo_flag);
ext.udp.parse(udp).parse(udp_flag);
ext.skip_cert_verify.parse(scv).parse(scv_flag);
ext.tls13.parse(tls13).parse(tls13_flag);
ext.sort_flag = sort_flag.get(do_sort);
use_sort_script.define(sort_script.size() != 0);
@@ -2032,11 +2032,11 @@ std::string surgeConfToClash(RESPONSE_CALLBACK_ARGS)
singlegroup["type"] = type;
for(unsigned int i = 1; i < dummy_str_array.size(); i++)
{
if(dummy_str_array[i].find("url") == 0)
if(startsWith(dummy_str_array[i], "url"))
singlegroup["url"] = trim(dummy_str_array[i].substr(dummy_str_array[i].find("=") + 1));
else if(dummy_str_array[i].find("interval") == 0)
else if(startsWith(dummy_str_array[i], "interval"))
singlegroup["interval"] = trim(dummy_str_array[i].substr(dummy_str_array[i].find("=") + 1));
else if(dummy_str_array[i].find("policy-path") == 0)
else if(startsWith(dummy_str_array[i], "policy-path"))
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]));
@@ -2114,9 +2114,7 @@ std::string surgeConfToClash(RESPONSE_CALLBACK_ARGS)
std::string::size_type lineSize;
for(std::string &x : dummy_str_array)
{
if(x.find("USER-AGENT") == 0 || x.find("URL-REGEX") == 0 || x.find("PROCESS-NAME") == 0 || x.find("AND") == 0 || x.find("OR") == 0) //remove unsupported types
continue;
else if(x.find("RULE-SET") == 0)
if(startsWith(x, "RULE-SET"))
{
strArray = split(x, ",");
if(strArray.size() != 3)
@@ -2135,7 +2133,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(strLine.find("USER-AGENT") == 0 || strLine.find("URL-REGEX") == 0 || strLine.find("PROCESS-NAME") == 0 || strLine.find("AND") == 0 || strLine.find("OR") == 0) //remove unsupported types
else if(!std::any_of(clash_rule_type.begin(), clash_rule_type.end(), [&strLine](std::string type){return startsWith(strLine, type);})) //remove unsupported types
continue;
strLine += strArray[2];
if(count_least(strLine, ',', 3))
@@ -2145,6 +2143,8 @@ std::string surgeConfToClash(RESPONSE_CALLBACK_ARGS)
ss.clear();
continue;
}
else if(!std::any_of(clash_rule_type.begin(), clash_rule_type.end(), [&strLine](std::string type){return startsWith(strLine, type);}))
continue;
rule.push_back(x);
}
clash[rule_name] = rule;
@@ -2456,12 +2456,10 @@ int simpleGenerator()
std::string proxy = parseProxy(proxy_subscription);
Request request;
Response response;
int &ret_code = response.status_code;
string_map &headers = response.headers;
for(std::string &x : sections)
{
arguments.clear();
ret_code = 200;
response.status_code = 200;
//std::cerr<<"Generating artifact '"<<x<<"'...\n";
writeLog(0, "Generating artifact '" + x + "'...", LOG_LEVEL_INFO);
ini.EnterSection(x);
@@ -2508,7 +2506,7 @@ int simpleGenerator()
request.argument = arguments;
content = subconverter(request, response);
}
if(ret_code != 200)
if(response.status_code != 200)
{
//std::cerr<<"Artifact '"<<x<<"' generate ERROR! Reason: "<<content<<"\n\n";
writeLog(0, "Artifact '" + x + "' generate ERROR! Reason: " + content + "\n", LOG_LEVEL_ERROR);
@@ -2517,12 +2515,12 @@ int simpleGenerator()
continue;
}
fileWrite(path, content, true);
auto iter = std::find_if(headers.begin(), headers.end(), [](auto y){ return y.first == "Subscription-UserInfo"; });
if(iter != headers.end())
auto iter = std::find_if(response.headers.begin(), response.headers.end(), [](auto y){ return y.first == "Subscription-UserInfo"; });
if(iter != response.headers.end())
writeLog(0, "User Info for artifact '" + x + "': " + subInfoToMessage(iter->second), LOG_LEVEL_INFO);
//std::cerr<<"Artifact '"<<x<<"' generate SUCCESS!\n\n";
writeLog(0, "Artifact '" + x + "' generate SUCCESS!\n", LOG_LEVEL_INFO);
eraseElements(headers);
eraseElements(response.headers);
}
//std::cerr<<"All artifact generated. Exiting...\n";
writeLog(0, "All artifact generated. Exiting...", LOG_LEVEL_INFO);
@@ -2537,7 +2535,7 @@ std::string renderTemplate(RESPONSE_CALLBACK_ARGS)
std::string path = UrlDecode(getUrlArg(argument, "path"));
writeLog(0, "Trying to render template '" + path + "'...", LOG_LEVEL_INFO);
if(path.find(template_path) != 0 || !fileExist(path))
if(startsWith(path, template_path) || !fileExist(path))
{
*status_code = 404;
return "Not found";

View File

@@ -135,7 +135,7 @@ int main(int argc, char *argv[])
generateBase();
std::string env_api_mode = GetEnv("API_MODE"), env_managed_prefix = GetEnv("MANAGED_PREFIX"), env_token = GetEnv("API_TOKEN");
api_mode = tribool().read(toLower(env_api_mode)).get(api_mode);
api_mode = tribool().parse(toLower(env_api_mode)).get(api_mode);
if(env_managed_prefix.size())
managed_config_prefix = env_managed_prefix;
if(env_token.size())
@@ -156,15 +156,12 @@ int main(int argc, char *argv[])
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())
{
std::string token = getUrlArg(argument, "token");
std::string token = getUrlArg(request.argument, "token");
if(token != access_token)
{
*status_code = 403;
response.status_code = 403;
return "Forbidden\n";
}
}
@@ -175,15 +172,12 @@ int main(int argc, char *argv[])
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())
{
std::string token = getUrlArg(argument, "token");
std::string token = getUrlArg(request.argument, "token");
if(token != access_token)
{
*status_code = 403;
response.status_code = 403;
return "Forbidden\n";
}
}
@@ -194,27 +188,23 @@ int main(int argc, char *argv[])
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())
{
std::string token = getUrlArg(argument, "token");
std::string token = getUrlArg(request.argument, "token");
if(token != access_token)
{
*status_code = 403;
response.status_code = 403;
return "Forbidden\n";
}
}
std::string type = getUrlArg(argument, "type");
std::string type = getUrlArg(request.argument, "type");
if(type == "form")
fileWrite(pref_path, getFormData(postdata), true);
fileWrite(pref_path, getFormData(request.postdata), true);
else if(type == "direct")
fileWrite(pref_path, postdata, true);
fileWrite(pref_path, request.postdata, true);
else
{
*status_code = 501;
response.status_code = 501;
return "Not Implemented\n";
}
@@ -247,15 +237,13 @@ int main(int argc, char *argv[])
{
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(request.argument, "url"));
return webGet(url, "");
});
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(request.argument, "path")));
});
}

View File

@@ -596,14 +596,13 @@ namespace md5 {
unsigned char* sig_p;
char* str_p;
char* max_p;
unsigned int high, low;
str_p = str_;
max_p = str_ + str_len;
for (sig_p = (unsigned char*)signature_; sig_p < (unsigned char*)signature_ + MD5_SIZE; sig_p++) {
high = *sig_p / 16;
low = *sig_p % 16;
unsigned int high = *sig_p / 16;
unsigned int low = *sig_p % 16;
/* account for 2 chars */
if (str_p + 1 >= max_p) {
break;
@@ -640,15 +639,14 @@ namespace md5 {
unsigned char *sig_p;
const char *str_p;
char* hex;
unsigned int high, low, val;
hex = (char*)md5::HEX_STRING;
sig_p = static_cast<unsigned char*>(signature_);
for (str_p = str_; str_p < str_ + MD5_SIZE * 2; str_p += 2) {
high = strchr(hex, *str_p) - hex;
low = strchr(hex, *(str_p + 1)) - hex;
val = high * 16 + low;
unsigned int high = strchr(hex, *str_p) - hex;
unsigned int low = strchr(hex, *(str_p + 1)) - hex;
unsigned int val = high * 16 + low;
*sig_p++ = val;
}
}

View File

@@ -77,10 +77,8 @@ std::string ACPToUTF8(const std::string &str_src)
memset(str, 0, len + 1);
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, len, NULL, NULL);
std::string strTemp = str;
if(wstr)
delete[] wstr;
if(str)
delete[] str;
delete[] wstr;
delete[] str;
return strTemp;
#else
return str_src;
@@ -209,7 +207,7 @@ std::string base64_encode(const std::string &string_to_encode)
unsigned int in_len = string_to_encode.size();
std::string ret;
int i = 0, j;
int i = 0;
unsigned char char_array_3[3];
unsigned char char_array_4[4];
@@ -231,6 +229,7 @@ std::string base64_encode(const std::string &string_to_encode)
if (i)
{
int j;
for(j = i; j < 3; j++)
char_array_3[j] = '\0';
@@ -445,10 +444,9 @@ std::string getSystemProxy()
return std::string();
#else
string_array proxy_env = {"all_proxy", "ALL_PROXY", "http_proxy", "HTTP_PROXY", "https_proxy", "HTTPS_PROXY"};
char* proxy;
for(std::string &x : proxy_env)
{
proxy = getenv(x.c_str());
char* proxy = getenv(x.c_str());
if(proxy != NULL)
return std::string(proxy);
}
@@ -842,7 +840,7 @@ bool isInScope(const std::string &path)
if(path.find(":\\") != path.npos || path.find("..") != path.npos)
return false;
#else
if(path.find("/") == 0 || path.find("..") != path.npos)
if(startsWith(path, "/") || path.find("..") != path.npos)
return false;
#endif // _WIN32
return true;
@@ -1036,10 +1034,9 @@ bool is_str_utf8(const std::string &data)
{
const char *str = data.c_str();
unsigned int nBytes = 0;
unsigned char chr;
for (unsigned int i = 0; str[i] != '\0'; ++i)
{
chr = *(str + i);
unsigned char chr = *(str + i);
if (nBytes == 0)
{
if (chr >= 0x80)
@@ -1122,7 +1119,7 @@ std::string getFormData(const std::string &raw_data)
{
if(i == 0)
boundary = line.substr(0, line.length() - 1); // Get boundary
else if(line.find(boundary) == 0)
else if(startsWith(line, boundary))
break; // The end
else if(line.length() == 1)
{
@@ -1134,11 +1131,10 @@ std::string getFormData(const std::string &raw_data)
while(!endfile)
{
int j = 0;
int k;
while(j < 256 && strstrm.get(c) && !endfile)
{
buffer[j] = c;
k = 0;
int k = 0;
// Verify if we are at the end
while(boundary[bl - 1 - k] == buffer[j - k])
{
@@ -1165,10 +1161,9 @@ std::string getFormData(const std::string &raw_data)
std::string UTF8ToCodePoint(const std::string &data)
{
std::stringstream ss;
int charcode;
for(std::string::size_type i = 0; i < data.size(); i++)
{
charcode = data[i] & 0xff;
int charcode = data[i] & 0xff;
if((charcode >> 7) == 0)
{
ss<<data[i];

View File

@@ -190,7 +190,7 @@ public:
return *this;
}
template <typename T> tribool read(const T &value)
template <typename T> tribool parse(const T &value)
{
define(value);
return *this;

View File

@@ -146,7 +146,7 @@ int addNodes(std::string link, std::vector<nodeInfo> &allNodes, int groupID, con
writeLog(LOG_TYPE_ERROR, "Invalid configuration file!");
return -1;
}
if(strSub.find("ssd://") == 0)
if(startsWith(strSub, "ssd://"))
{
getSubInfoFromSSD(strSub, subInfo);
}

View File

@@ -65,10 +65,9 @@ duk_ret_t cb_resolve_module(duk_context *ctx)
const char *requested_id = duk_get_string(ctx, 0);
const char *parent_id = duk_get_string(ctx, 1); /* calling module */
//const char *resolved_id;
std::string resolved_id;
if(strlen(parent_id))
std::string resolved_id, parent_path = parent_id;
if(!parent_path.empty())
{
std::string parent_path = parent_id;
string_size pos = parent_path.rfind("/");
if(pos != parent_path.npos)
resolved_id += parent_path.substr(0, pos + 1);

View File

@@ -647,7 +647,7 @@ void explodeSocks(std::string link, const std::string &custom_port, nodeInfo &no
node.proxyStr = socksConstruct(group, remarks, server, port, username, password);
}
void explodeHTTP(const std::string link, const std::string &custom_port, nodeInfo &node)
void explodeHTTP(const std::string &link, const std::string &custom_port, nodeInfo &node)
{
std::string group, remarks, server, port, username, password;
server = getUrlArg(link, "server");
@@ -1942,7 +1942,7 @@ int explodeConfContent(const std::string &content, const std::string &custom_por
return SPEEDTEST_ERROR_NONE;
}
void explode(std::string link, bool sslibev, bool ssrlibev, const std::string &custom_port, nodeInfo &node)
void explode(const std::string &link, bool sslibev, bool ssrlibev, const std::string &custom_port, nodeInfo &node)
{
// TODO: replace strFind with startsWith if appropriate
if(strFind(link, "ssr://"))

View File

@@ -21,7 +21,7 @@ void explodeQuan(const std::string &quan, const std::string &custom_port, nodeIn
void explodeShadowrocket(std::string kit, const std::string &custom_port, nodeInfo &node);
void explodeKitsunebi(std::string kit, const std::string &custom_port, nodeInfo &node);
/// Parse a link
void explode(std::string link, bool sslibev, bool ssrlibev, const std::string &custom_port, nodeInfo &node);
void explode(const std::string &link, bool sslibev, bool ssrlibev, const std::string &custom_port, nodeInfo &node);
void explodeSSD(std::string link, bool libev, const std::string &custom_port, std::vector<nodeInfo> &nodes);
void explodeSub(std::string sub, bool sslibev, bool ssrlibev, const std::string &custom_port, std::vector<nodeInfo> &nodes);
int explodeConf(std::string filepath, const std::string &custom_port, bool sslibev, bool ssrlibev, std::vector<nodeInfo> &nodes);

View File

@@ -658,10 +658,10 @@ void rulesetToClash(YAML::Node &base_rule, std::vector<ruleset_content> &ruleset
writeLog(0, "Failed to fetch ruleset or ruleset is empty: '" + x.rule_path + "'!", LOG_LEVEL_WARNING);
continue;
}
if(retrieved_rules.find("[]") == 0)
if(startsWith(retrieved_rules, "[]"))
{
strLine = retrieved_rules.substr(2);
if(strLine.find("FINAL") == 0)
if(startsWith(strLine, "FINAL"))
strLine.replace(0, 5, "MATCH");
strLine += "," + rule_group;
if(count_least(strLine, ',', 3))

View File

@@ -17,7 +17,7 @@ namespace inja
{
void convert_dot_to_json_pointer(nonstd::string_view dot, std::string& out)
{
out = std::move(JsonNode(dot, 0).ptr);
out = JsonNode::convert_dot_to_json_ptr(dot);
}
}
@@ -283,7 +283,7 @@ int renderClashScript(YAML::Node &base_rule, std::vector<ruleset_content> &rules
}
continue;
}
if(strLine.find("FINAL") == 0)
if(startsWith(strLine, "FINAL"))
strLine.replace(0, 5, "MATCH");
strLine += "," + rule_group;
if(count_least(strLine, ',', 3))

View File

@@ -96,7 +96,7 @@ static inline void curl_set_common_options(CURL *curl_handle, const char *url, c
}
//static std::string curlGet(const std::string &url, const std::string &proxy, std::string &response_headers, CURLcode &return_code, const string_map &request_headers)
static int curlGet(const FetchArgument argument, FetchResult &result)
static int curlGet(const FetchArgument &argument, FetchResult &result)
{
CURL *curl_handle;
std::string *data = result.content, new_url = argument.url;
@@ -281,7 +281,7 @@ int curlPost(const std::string &url, const std::string &data, const std::string
if(res == CURLE_OK)
{
res = curl_easy_getinfo(curl_handle, CURLINFO_HTTP_CODE, &retVal);
curl_easy_getinfo(curl_handle, CURLINFO_HTTP_CODE, &retVal);
}
curl_easy_cleanup(curl_handle);

View File

@@ -1,370 +0,0 @@
#include <iostream>
#include <fstream>
#include <map>
#include <atomic>
#include <thread>
#include <pthread.h>
#include "misc.h"
#include "socket.h"
#include "webserver.h"
typedef std::vector<std::string> string_array;
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::__cxx11::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::__cxx11::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;
sleep(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)
{
sleep(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;
}

View File

@@ -55,7 +55,7 @@ static inline int process_request(Request &request, Response &response, std::str
for(responseRoute &x : responses)
{
if(request.method == "OPTIONS" && request.postdata.find(x.method) != 0 && x.path == request.url)
if(request.method == "OPTIONS" && startsWith(request.postdata, x.method) && x.path == request.url)
{
return 1;
}
@@ -227,19 +227,23 @@ void* httpserver_dispatch(void *arg)
int httpserver_bindsocket(std::string listen_address, int listen_port, int backlog)
{
int ret;
SOCKET nfd;
nfd = socket(AF_INET, SOCK_STREAM, 0);
if (nfd <= 0)
return -1;
int one = 1;
if (setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(int)) < 0)
{
closesocket(nfd);
return -1;
}
int one = 1;
ret = setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(int));
#ifdef SO_NOSIGPIPE
ret = setsockopt(nfd, SOL_SOCKET, SO_NOSIGPIPE, (char *)&one, sizeof(int));
if (setsockopt(nfd, SOL_SOCKET, SO_NOSIGPIPE, (char *)&one, sizeof(int)) < 0)
{
closesocket(nfd);
return -1;
}
#endif
struct sockaddr_in addr;
@@ -248,14 +252,7 @@ int httpserver_bindsocket(std::string listen_address, int listen_port, int backl
addr.sin_addr.s_addr = inet_addr(listen_address.data());
addr.sin_port = htons(listen_port);
ret = ::bind(nfd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr));
if (ret < 0)
{
closesocket(nfd);
return -1;
}
ret = listen(nfd, backlog);
if (ret < 0)
if (::bind(nfd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0 || listen(nfd, backlog) < 0)
{
closesocket(nfd);
return -1;
@@ -272,7 +269,7 @@ int start_web_server_multi(void *argv)
struct listener_args *args = reinterpret_cast<listener_args*>(argv);
std::string listen_address = args->listen_address;
int port = args->port, nthreads = args->max_workers;
int i, ret;
int i;
int nfd = httpserver_bindsocket(listen_address, port, args->max_conn);
if (nfd < 0)
@@ -288,18 +285,16 @@ int start_web_server_multi(void *argv)
struct evhttp *httpd = evhttp_new(base[i]);
if (httpd == NULL)
return -1;
ret = evhttp_accept_socket(httpd, nfd);
if (ret != 0)
if (evhttp_accept_socket(httpd, nfd) != 0)
return -1;
evhttp_set_allowed_methods(httpd, EVHTTP_REQ_GET | EVHTTP_REQ_POST | EVHTTP_REQ_OPTIONS);
evhttp_set_gencb(httpd, OnReq, nullptr);
evhttp_set_timeout(httpd, 30);
ret = pthread_create(&ths[i], NULL, httpserver_dispatch, base[i]);
if (ret != 0)
if (pthread_create(&ths[i], NULL, httpserver_dispatch, base[i]) != 0)
return -1;
}
while(!SERVER_EXIT_FLAG)
while (!SERVER_EXIT_FLAG)
sleep(200); //block forever until receive stop signal
for (i = 0; i < nthreads; i++)