diff --git a/bin/uce_fastcgi.debug.linux.bin b/bin/uce_fastcgi.debug.linux.bin index 2d83a0e..b5dc7f0 100755 Binary files a/bin/uce_fastcgi.debug.linux.bin and b/bin/uce_fastcgi.debug.linux.bin differ diff --git a/src/lib/compiler.h b/src/lib/compiler.h index acdbb9b..bb2f44d 100644 --- a/src/lib/compiler.h +++ b/src/lib/compiler.h @@ -1,304 +1,9 @@ #define RENDER() extern "C" void render(DTree& call) -string process_html_literal(Request* context, SharedUnit* su, string content) -{ - string pc; - string HT_START = "context->print(R\"("; - string HT_END = ")\");"; - - u8 mode = 0; - char quote_char; - bool inside_quote = false; - string code_buffer = ""; - bool is_field = false; - - for(u32 i = 0; i < content.length(); i++) - { - char c = content[i]; - - switch(mode) - { - case(0): - if(c == '<' && content[i+1] == '?') - { - code_buffer = ""; - if(content[i+2] == '=') - { - is_field = true; - i += 2; - } - else - { - is_field = false; - i += 1; - } - mode = 1; // code-parsing mode - } - else - { - pc.append(1, c); - } - break; - case(1): - if(inside_quote) - { - if(quote_char == c && content[i-1] != '\\') - inside_quote = false; - code_buffer.append(1, c); - } - else - { - if(c == '\"' || c == '\'') - { - inside_quote = true; - quote_char = c; - code_buffer.append(1, c); - } - else if(c == '?' && content[i+1] == '>') - { - mode = 0; - i += 1; - if(is_field) - { - pc.append( - HT_END + - "echo(html_escape( " + - code_buffer + - " )); " + - HT_START - ); - } - else - { - pc.append(HT_END + code_buffer + HT_START); - } - } - else - { - code_buffer.append(1, c); - } - } - break; - } - - } - - return(HT_START + pc + HT_END); -} - -string preprocess_shared_unit(Request* context, SharedUnit* su) -{ - string content = file_get_contents(su->file_name); - printf("(c) compiling with root dir %s\n", context->server->config.COMPILER_SYS_PATH.c_str()); - string pc = ("#include \"")+context->server->config.COMPILER_SYS_PATH +"/src/lib/unit.h\" \n"; - string token = ""; - string html_buffer = ""; - u8 mode = 0; - bool inside_quote = false; - for(u32 i = 0; i < content.length(); i++) - { - char c = content[i]; - if(mode == 2) - { - auto end_pos = content.find(string("", i); - if(end_pos != string::npos) - { - u32 len = token.length() + 3 + end_pos - i; - html_buffer.append(content.substr(i, len - (token.length() == 0 ? 3 : 0))); - i += len - 1; - pc.append(process_html_literal(context, su, html_buffer)); - } - else - { - printf("(!) unterminated HTML literal <%s> in %s", token.c_str(), su->file_name.c_str()); - } - mode = 0; - } - else if(mode == 1) - { - if(isspace(c) || c == '>') - { - mode = 2; - if(token.length() > 0) - html_buffer.append(1, c); - } - else - { - token.append(1, c); - html_buffer.append(1, c); - } - } - else if(!inside_quote && c == '<' && (content[i+1] == '>' || isalpha(content[i+1]))) - { - mode = 1; - token = ""; - html_buffer = ""; - if(content[i+1] != '>') - html_buffer.append(1, c); - } - else if(c == '\"') - { - inside_quote = !inside_quote; - pc.append(1, c); - } - else - { - pc.append(1, c); - } - } - return(pc); -} - -void setup_unit_paths(Request* context, SharedUnit* su, string file_name) -{ - su->file_name = file_name; - - if(su->src_path.length() > 0) // we did this already - return; - - su->src_path = dirname(file_name); - su->bin_path = context->server->config.BIN_DIRECTORY + su->src_path; - su->pre_path = context->server->config.BIN_DIRECTORY + su->src_path; - - su->src_file_name = basename(file_name); - su->bin_file_name = su->src_file_name + ".so"; - su->pre_file_name = su->src_file_name + ".cpp"; - - su->so_name = su->bin_path + "/" + su->bin_file_name; -} - -void load_shared_unit(Request* context, SharedUnit* su, string file_name) -{ - setup_unit_paths(context, su, file_name); - - su->on_render = 0; - su->on_setup = 0; - su->compiler_messages = ""; - - if(!file_exists(su->so_name)) - { - printf("(i) unit file not found: %s\n", su->so_name.c_str()); - su->compiler_messages = "unit file not found"; - return; - } - - su->so_handle = dlopen(su->so_name.c_str(), RTLD_NOW); - if(su->so_handle) - { - su->last_compiled = file_mtime(su->so_name); - char *error; - su->on_setup = (request_handler)dlsym(su->so_handle, "set_current_request"); - su->on_render = (call_handler)dlsym(su->so_handle, "render"); - if ((error = dlerror()) != NULL) - printf("Error - %s in %s\n", error, su->file_name.c_str()); - else - printf("(i) loaded unit %s\n", su->file_name.c_str()); - } - else - { - printf("Error loading unit %s, could not open %s\n", su->file_name.c_str(), su->so_name.c_str()); - } -} - -void compile_shared_unit(Request* context, SharedUnit* su, string file_name) -{ - setup_unit_paths(context, su, file_name); - - if(!file_exists(su->file_name)) - { - su->compiler_messages = "source file not found (" + su->file_name + ")"; - return; - } - - shell_exec("mkdir -p " + shell_escape(su->pre_path)); - file_put_contents(su->pre_path + "/" + su->pre_file_name, preprocess_shared_unit(context, su)); - - printf("Config.COMPILE_SCRIPT %s\n", string(su->pre_path + "/" + su->pre_file_name).c_str()); - - su->compiler_messages = trim(shell_exec(context->server->config.COMPILE_SCRIPT+" "+ - shell_escape(su->src_path)+" "+ - shell_escape(su->bin_path)+" "+ - shell_escape(su->file_name)+" "+ - shell_escape(su->pre_file_name)+" "+ - shell_escape(su->bin_file_name) - )); - - if(su->compiler_messages.length() > 0) - { - printf("%s \n", su->compiler_messages.c_str()); - } - else - { - load_shared_unit(context, su, file_name); - printf("(i) compiled unit %s\n", file_name.c_str()); - } -} - -SharedUnit* get_shared_unit(Request* context, string file_name) -{ - SharedUnit* su = context->server->units[file_name]; - auto mod_time = file_mtime(file_name); - bool do_recompile = false; - if(su && (su->last_compiled < mod_time || mod_time == 0)) - { - delete su; - su = 0; - do_recompile = true; - } - if(!su) - { - su = new SharedUnit(); - - if(do_recompile) - { - compile_shared_unit(context, su, file_name); - } - else - { - load_shared_unit(context, su, file_name); - if(!su->so_handle) - compile_shared_unit(context, su, file_name); - } - - context->server->units[file_name] = su; - } - return(su); -} - -void compiler_invoke(Request* context, string file_name, DTree& call_param) -{ - if(file_name[0] != '/') - { - file_name = expand_path(file_name); - } - printf("(i) invoke %s\n", file_name.c_str()); - - //printf("(i) invoke(%s)\n", file_name.c_str()); - auto su = get_shared_unit(context, file_name); - if(!su) - { - printf("Error loading unit %s\n", file_name.c_str()); - context->print("Error loading unit: "+file_name); - } - else if(!su->on_render) - { - context->header["Content-Type"] = "text/plain"; - context->print("Compiler error: "+su->compiler_messages); - } - else - { - if(su->compiler_messages.length() > 0) - context->print(su->compiler_messages); - else - { - string prev_wd = get_cwd(); - set_cwd(su->src_path); - su->on_setup(context); - su->on_render(call_param); - set_cwd(prev_wd); - } - } -} - - - +string process_html_literal(Request* context, SharedUnit* su, string content); +string preprocess_shared_unit(Request* context, SharedUnit* su); +void setup_unit_paths(Request* context, SharedUnit* su, string file_name); +void load_shared_unit(Request* context, SharedUnit* su, string file_name); +void compile_shared_unit(Request* context, SharedUnit* su, string file_name); +SharedUnit* get_shared_unit(Request* context, string file_name); +void compiler_invoke(Request* context, string file_name, DTree& call_param); diff --git a/src/lib/dtree.h b/src/lib/dtree.h index c879ca6..a50b2f6 100644 --- a/src/lib/dtree.h +++ b/src/lib/dtree.h @@ -1,47 +1,4 @@ -struct DTree; - -string json_escape(string s) -{ - //return(string("\"")+s+"\""); - string result; - u32 i = 0; - result.append(1, '"'); - while(i < s.length()) - { - char c = s[i]; - switch(c) - { - case('\t'): - result.append("\\t"); - break; - case('\n'): - result.append("\\n"); - break; - case('"'): - result.append("\\\""); - break; - case('\r'): - result.append("\\r"); - break; - case('\\'): - result.append("\\\\"); - break; - case('\b'): - result.append("\\b"); - break; - case('\f'): - result.append("\\f"); - break; - default: - result.append(1, c); - break; - } - i += 1; - } - result.append(1, '"'); - return(result); -} - +string json_escape(string s); struct DTree { @@ -54,225 +11,31 @@ struct DTree { void* _ptr; std::map _map; - void each(std::function f) - { - switch(type) - { - case('M'): - for (auto it = _map.begin(); it != _map.end(); ++it) - { - f(it->second, it->first); - } - break; - default: - f(*this, ""); - break; - } - } - - bool is_array() - { - return(type == 'M'); - } - - string to_string() - { - switch(type) - { - case('S'): - return(_string); - break; - case('F'): - return(std::to_string(_float)); - break; - case('B'): - return(_bool ? "(true)" : "(false)"); - break; - case('M'): - return(""); - break; - case('P'): - return(std::to_string((u64)_ptr)); - break; - } - } - - string to_json() - { - switch(type) - { - case('S'): - return(json_escape(_string)); - break; - case('F'): - return(std::to_string(_float)); - break; - case('B'): - return(_bool ? "true" : "false"); - break; - case('M'): - return("\"(array)\""); - break; - case('P'): - return("\"(pointer)\""); - break; - } - } - - string get_type_name() - { - switch(type) - { - case('S'): - return("string"); - break; - case('F'): - return("f64"); - break; - case('B'): - return("bool"); - break; - case('M'): - return("array"); - break; - case('P'): - return("pointer"); - break; - } - } - - void set_type(char t) - { - if(type != t) - { - type = t; - switch(type) - { - case('M'): - _map.clear(); - _array_index = 0; - break; - } - } - } - - void set(string s) - { - set_type('S'); - _string = s; - } - - void set(void* p) - { - set_type('P'); - _ptr = p; - } - - void set(f64 f) - { - set_type('F'); - _float = f; - } - - void set_bool(bool b) - { - set_type('B'); - _bool = b; - } - - void set(DTree source) - { - set_type(source.type); - switch(type) - { - case('S'): - _string = source._string; - break; - case('F'): - _float = source._float; - break; - case('B'): - _bool = source._bool; - break; - case('M'): - _map = source._map; - break; - case('P'): - _ptr = source._ptr; - break; - } - } - - void set(StringMap source) - { - set_type('M'); - for (auto it = source.begin(); it != source.end(); ++it) - { - (*this)[it->first] = it->second; - } - } - - DTree* key(string s) - { - set_type('M'); - return(&_map[s]); - } - - DTree& operator [] (string s) { - set_type('M'); - return(_map[s]); - } - - void operator = (string v) { set(v); } - void operator = (f64 v) { set(v); } - void operator = (void* v) { set(v); } - void operator = (DTree v) { set(v); } - void operator = (StringMap v) { set(v); } - - void push(DTree& child) - { - set_type('M'); - _map[std::to_string(_array_index)] = child; - _array_index += 1; - } - - DTree pop() - { - set_type('M'); - auto last = _map.rbegin(); - DTree result = last->second; - _map.erase(last->first); - return(result); - } - - void remove(string s) - { - set_type('M'); - _map.erase(s); - } - - void clear() - { - set_type('M'); - _map.clear(); - } + void each(std::function f); + bool is_array(); + string to_string(); + string to_json(); + string get_type_name(); + void set_type(char t); + void set(string s); + void set(void* p); + void set(f64 f); + void set_bool(bool b); + void set(DTree source); + void set(StringMap source); + DTree* key(string s); + DTree& operator [] (string s); + void operator = (string v); + void operator = (f64 v); + void operator = (void* v); + void operator = (DTree v); + void operator = (StringMap v); + void push(DTree& child); + DTree pop(); + void remove(string s); + void clear(); }; -string to_string(DTree t) -{ - return(t.to_string()); -} - -string var_dump(DTree map, string prefix = "", string postfix = "\n") -{ - string result = ""; - if(!map.is_array()) - return(map.to_string()); - map.each([&] (DTree item, string key) { - result += prefix + key + ": " + item.to_string() + postfix; - if(item.is_array()) - result += var_dump(item, prefix + "\t"); - }); - return(result); -} +string to_string(DTree t); +string var_dump(DTree map, string prefix = "", string postfix = "\n"); diff --git a/src/lib/functionlib.h b/src/lib/functionlib.h index 218c3fc..d5c08bf 100644 --- a/src/lib/functionlib.h +++ b/src/lib/functionlib.h @@ -1,362 +1,20 @@ -string var_dump(StringMap map, string prefix = "", string postfix = "\n") -{ - string result = ""; - - for (auto it = map.begin(); it != map.end(); ++it) - { - result.append(prefix + it->first + ": " + it->second + postfix); - } - - return(result); -} - -string var_dump(StringList slist, string prefix = "", string postfix = "\n") -{ - string result = ""; - - for (auto& s : slist) - { - result.append(prefix + s + postfix); - } - - return(result); -} - -u8 char_to_u8(char input) -{ - if(input >= '0' && input <= '9') - return input - '0'; - if(input >= 'A' && input <= 'F') - return input - 'A' + 10; - if(input >= 'a' && input <= 'f') - return input - 'a' + 10; - return(0); -} - -u8 hex_to_u8(string src) -{ - return(char_to_u8(src[0])*16 + char_to_u8(src[1])); -} - -string trim(string raw) -{ - u32 len = raw.length(); - u32 start_pos = 0; - u32 end_pos = len - 1; - if(len == 0 || (len == 1 && isspace(raw[0]))) - return(""); - while(start_pos < len && isspace(raw[start_pos])) - start_pos++; - while(end_pos >= 0 && isspace(raw[end_pos])) - end_pos--; - if(end_pos < start_pos) - return(""); - return(raw.substr(start_pos, 1 + end_pos - start_pos)); -} - -StringList split(string str, string delim = "\n") -{ - StringList result; - int start = 0; - int end = str.find(delim); - while (end != string::npos) - { - result.push_back(str.substr(start, end - start)); - start = end + delim.size(); - end = str.find(delim, start); - } - result.push_back(str.substr(start, end - start)); - return(result); -} - -string join(StringList l, string delim = "\n") -{ - string result; - u32 i = 0; - for(auto& s : l) - { - if(i > 0) - result.append(delim); - result.append(s); - i += 1; - } - return(result); -} - -string html_escape(string s) -{ - string result; - - for(u32 i = 0; i < s.length(); i++) - { - char c = s[i]; - switch(c) - { - case('&'): - result.append("&"); - break; - case('<'): - result.append("<"); - break; - case('>'): - result.append(">"); - break; - case('"'): - result.append("""); - break; - default: - result.append(1, c); - break; - } - } - - return(result); -} - -string html_escape(u64 a) -{ - return(std::to_string(a)); -} - -string html_escape(f64 a) -{ - return(std::to_string(a)); -} - -u64 int_val(string s, u32 base = 10) -{ - return(strtoll(s.c_str(), 0, base)); -} - -string nibble(string& haystack, string delim) -{ - auto idx = haystack.find(delim); - if(idx == string::npos) - { - string result = haystack; - haystack = ""; - return(result); - } - else - { - string result = haystack.substr(0, idx); - haystack = haystack.substr(idx+delim.length()); - return(result); - } -} - -string json_encode(DTree t) -{ - string result = ""; - if(t.is_array()) - { - result += "{"; - u32 count = 0; - t.each([&] (DTree item, string key) { - if(count > 0) - result += ", "; - count += 1; - result += json_escape(key) + ": " + json_encode(item); - }); - result += "}"; - } - else - { - result = t.to_json(); - } - return(result); -} - -// https://i.stack.imgur.com/SHLOB.gif -string json_decode_string(string s, u32& i, char termination_char = '"') -{ - string result; - //echo("json_decode_string " + s.substr(i) + "\n"); - while(i < s.length()) - { - char c = s[i]; - if(c == termination_char) - { - i += 1; - //echo("json_decode_string = " + result + "\n"); - return(result); - } - else if(c == '\\') - { - i += 1; - c = s[i]; - switch(c) - { - case('t'): - result.append(1, '\t'); - break; - case('n'): - result.append(1, '\n'); - break; - case('r'): - result.append(1, '\r'); - break; - case('\\'): - result.append(1, '\\'); - break; - case('b'): - result.append(1, '\b'); - break; - case('f'): - result.append(1, '\f'); - break; - case('u'): - // todo decode - break; - default: - result.append(1, c); - break; - } - } - else - { - result.append(1, c); - } - i += 1; - } - return(result); -} - +string var_dump(StringMap map, string prefix = "", string postfix = "\n"); +string var_dump(StringList slist, string prefix = "", string postfix = "\n"); +u8 char_to_u8(char input); +u8 hex_to_u8(string src); +string trim(string raw); +StringList split(string str, string delim = "\n"); +string join(StringList l, string delim = "\n"); +string html_escape(string s); +string html_escape(u64 a); +string html_escape(f64 a); +u64 int_val(string s, u32 base = 10); +string nibble(string& haystack, string delim); +string json_encode(DTree t); +string json_decode_string(string s, u32& i, char termination_char = '"'); +void json_consume_space(string s, u32& i); +string json_decode_keyword(string s, u32& i); +string json_decode_number(string s, u32& i); +DTree json_decode_value(string s, u32& i); DTree json_decode_map(string s, u32& i); - -void json_consume_space(string s, u32& i) -{ - while(i < s.length() && isspace(s[i])) - i += 1; -} - -string json_decode_keyword(string s, u32& i) -{ - string result; - json_consume_space(s, i); - while(i < s.length()) - { - char c = s[i]; - if(isalnum(c)) - { - result.append(1, c); - } - else - { - return(result); - } - i += 1; - } - return(result); -} - -string json_decode_number(string s, u32& i) -{ - string result; - json_consume_space(s, i); - while(i < s.length()) - { - char c = s[i]; - if(isdigit(c) || c == '.') - { - result.append(1, c); - } - else - { - return(result); - } - i += 1; - } - return(result); -} - -DTree json_decode_value(string s, u32& i) -{ - DTree result; - string value = ""; - json_consume_space(s, i); - char c = s[i]; - //echo("json_decode_value " + s.substr(i) + "\n"); - if(c == '"' || c == '\'') // string value - { - result.type = 'S'; - i += 1; - result._string = json_decode_string(s, i, s[i-1]); - return(result); - } - else if(isdigit(c)) - { - result.type = 'S'; - result._string = json_decode_number(s, i); - //result._float = stod(json_decode_number(s, i)); - return(result); - } - else if(c == '{') - { - i += 1; - return(json_decode_map(s, i)); - } - else - { - value = json_decode_keyword(s, i); - if(value == "true") - result.set_bool(true); - else if(value == "false") - result.set_bool(false); - else if(value == "null") - result.set(""); - return(result); - } - return(result); -} - -DTree json_decode_map(string s, u32& i) -{ - DTree result; - result.type = 'M'; - string key = ""; - json_consume_space(s, i); - //echo("json_decode_map " + s.substr(i) + "\n"); - while(i < s.length()) - { - char c = s[i]; - if(c == '}') - { - i += 1; - return(result); - } - else if(c == ',') - { - i += 1; - } - else if(c == '"' || c == '\'') - { - i += 1; - key = json_decode_string(s, i, s[i-1]); - json_consume_space(s, i); - if(s[i] != ':') - return(result); // malformed - i += 1; - DTree v = json_decode_value(s, i); - //result._map[key] = json_decode_value(s, i); - //echo("KV " + key + " = " + to_string(v) + "\n"); - //printf("map add %s (%c) \n", key.c_str(), s[i]); - result._map[key] = v; - } - else - { - // malformed - return(result); - } - json_consume_space(s, i); - } - return(result); -} - -DTree json_decode(string s) -{ - u32 i = 0; - return(json_decode_value(s, i)); -} - - +DTree json_decode(string s); diff --git a/src/lib/mysql-connector.cpp b/src/lib/mysql-connector.cpp index 75d67dc..2f65f45 100644 --- a/src/lib/mysql-connector.cpp +++ b/src/lib/mysql-connector.cpp @@ -1,6 +1,7 @@ #include "../3rdparty/mysql/mysql.h" #include #include +#include "mysql-connector.h" bool MySQL::connect(string host, string username, string password) { diff --git a/src/lib/sys.h b/src/lib/sys.h index c93f7b2..77e127e 100644 --- a/src/lib/sys.h +++ b/src/lib/sys.h @@ -1,377 +1,36 @@ -#include -#include -#include -#include -#include -#include -#include - -string shell_exec(string cmd) -{ - printf("(i) shell_exec(%s)\n", cmd.c_str()); - string data; - FILE * stream; - const int max_buffer = 256; - char buffer[max_buffer]; - cmd.append(" 2>&1"); - - stream = popen(cmd.c_str(), "r"); - - if (stream) { - while (!feof(stream)) - if (fgets(buffer, max_buffer, stream) != NULL) data.append(buffer); - pclose(stream); - } - return data; -} - -string shell_escape(string raw) -{ - // FIXME - return("\"" + raw + "\""); - /* - ` U+0060 (Grave Accent) Backtick Command substitution -~ U+007E Tilde Tilde expansion -! U+0021 Exclamation mark History expansion -# U+0023 Number sign Hash Comments -$ U+0024 Dollar sign Parameter expansion -& U+0026 Ampersand Background commands -* U+002A Asterisk Filename expansion and globbing -( U+0028 Left Parenthesis Subshells -) U+0029 Right Parenthesis Subshells - U+0009 Tab (⇥) Word splitting (whitespace) -{ U+007B Left Curly Bracket Left brace Brace expansion -[ U+005B Left Square Bracket Filename expansion and globbing -| U+007C Vertical Line Vertical bar Pipelines -\ U+005C Reverse Solidus Backslash Escape character -; U+003B Semicolon Separating commands -' U+0027 Apostrophe Single quote String quoting -" U+0022 Quotation Mark Double quote String quoting with interpolation -↩ U+000A Line Feed Newline Line break -< U+003C Less than Input redirection -> U+003E Greater than Output redirection -? U+003F Question mark Filename expansion and globbing -   U+0020 Space Word splitting1 (whitespace) - */ -} - -string basename(string fn) -{ - string result; - while(fn.length() > 0) - result = nibble("/", fn); - //printf("basename(%s) %s\n", fn.c_str(), result.c_str()); - return(result); -} - -string dirname(string fn) -{ - string result; - auto seg = split(fn, "/"); - seg.pop_back(); - result = join(seg, "/"); - //printf("dirname(%s) %s seg#%i\n", fn.c_str(), result.c_str(), seg.size()); - return(result); -} - -bool mkdir(string path) -{ - shell_exec(string("mkdir -p ")+" "+shell_escape(path)); - return(true); -} - -bool file_exists(string path) -{ - std::filesystem::path fp{ path }; - return(std::filesystem::exists(fp)); -} - -string file_get_contents(string file_name) -{ - try - { - std::ifstream ifs(file_name); - string content( - (std::istreambuf_iterator(ifs) ), - (std::istreambuf_iterator() ) ); - return(content); - } - catch(std::exception e) - { - return(""); - } -} - -bool file_put_contents(string file_name, string content) -{ - try - { - std::ofstream out(file_name); - out << content; - out.close(); - return(true); - } - catch(std::exception e) - { - return(false); - } -} - -string get_cwd() -{ - return(std::filesystem::current_path()); -} - -void set_cwd(string path) -{ - chdir(path.c_str()); -} - -time_t file_mtime(string file_name) -{ - struct stat info; - if (stat(file_name.c_str(), &info) != 0) - { - return(0); - } - else - { - return(info.st_mtime); - } -} - -void unlink(string file_name) -{ - remove(file_name.c_str()); -} - -string expand_path(string path) -{ - string result; - - auto base_path = split(get_cwd(), "/"); - auto rel_path = split(path, "/"); - - for(auto& s : rel_path) - { - if(s == "..") - { - base_path.pop_back(); - } - else if(s == ".") - { - - } - else - { - base_path.push_back(s); - } - } - - return(join(base_path, "/")); -} - -#include #include -void on_segfault(int sig) { - void *array[10]; - size_t size; +string shell_exec(string cmd); +string shell_escape(string raw); +string basename(string fn); +string dirname(string fn); +bool mkdir(string path); +bool file_exists(string path); +string file_get_contents(string file_name); +bool file_put_contents(string file_name, string content); +string get_cwd(); +void set_cwd(string path); +time_t file_mtime(string file_name); +void unlink(string file_name); +string expand_path(string path); +void on_segfault(int sig); - // get void*'s for all entries on the stack - size = backtrace(array, 10); +f64 microtime(); +u64 time(); +string date(string format = "", u64 timestamp = 0); +string gmdate(string format = "", u64 timestamp = 0); +u64 parse_time(string time_string); - // print out all the frames to stderr - fprintf(stderr, "SEG FAULT: %d:\n", sig); - backtrace_symbols_fd(array, size, STDERR_FILENO); - exit(1); -} +u64 socket_connect(string host, short port); +void socket_close(u64 sockfd); +bool socket_write(u64 sockfd, string data); +string socket_read(u64 sockfd, u32 max_length = 1024*128, u32 timeout = 1); -f64 microtime() -{ - return ((f64)std::chrono::duration_cast( - std::chrono::high_resolution_clock::now().time_since_epoch()).count()) / 1000000; -} - -u64 time() -{ - return(std::time(0)); -} - -string date(string format = "", u64 timestamp = 0) -{ - string ts; - string fmt; - if(timestamp > 0) - ts = string("-d '@")+std::to_string(timestamp)+"'"; - if(format != "") - fmt = string("+'"+format+"'"); - return(trim(shell_exec("date "+ts+" "+fmt))); -} - -string gmdate(string format = "", u64 timestamp = 0) -{ - string ts; - string fmt; - if(timestamp > 0) - ts = string("-d '@")+std::to_string(timestamp)+"'"; - if(format == "RFC1123") - format = "%a, %d %b %Y %T GMT"; - if(format != "") - fmt = string("+'"+format+"'"); - return(trim(shell_exec("date -u "+ts+" "+fmt))); -} - -u64 parse_time(string time_string) -{ - return(int_val(trim(shell_exec("date -u -d '"+time_string+"' +'%s'")))); -} - -u64 socket_connect(string host, short port) -{ - - /*struct addrinfo { - int ai_flags; - int ai_family; - int ai_socktype; - int ai_protocol; - socklen_t ai_addrlen; - struct sockaddr *ai_addr; - char *ai_canonname; - struct addrinfo *ai_next; - };*/ - - auto sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if(sockfd < 0) - { - echo("SOCKET ERROR (could not open socket)\n"); - perror("SOCKET ERROR "); - return(0); - } - - struct sockaddr_in addr = {0}; - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = inet_addr(host.c_str()); - - if(connect(sockfd, (struct sockaddr*) &addr, sizeof(addr)) < 0) - { - echo("SOCKET ERROR (could not connect to address " + string(host) + ":" + std::to_string(port) + ")\n"); - perror("SOCKET ERROR "); - return(0); - } - context->resources.sockets.push_back(sockfd); - return(sockfd); -} - -void socket_close(u64 sockfd) -{ - close(sockfd); -} - -bool socket_write(u64 sockfd, string data) -{ - return(write(sockfd, data.c_str(), data.length()) >= 0); -} - -string socket_read(u64 sockfd, u32 max_length = 1024*128, u32 timeout = 1) -{ - struct timeval tv; - tv.tv_sec = timeout; - tv.tv_usec = 0; - setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv); - char buf[max_length+1]; - auto byte_count = recv(sockfd, buf, sizeof(buf), 0); - if(byte_count > 0) - { - buf[byte_count] = 0; - string result(buf, byte_count+1); - return(result); - } - return(""); -} - -string memcache_escape_key(string key) -{ - string result; - for(auto c : key) - { - if(isspace(c)) - c = '_'; - result.append(1, c); - } - return(result); -} - -StringList memcache_escape_keys(StringList keys) -{ - StringList result; - for(auto s : keys) - { - result.push_back(memcache_escape_key(s)); - } - return(result); -} - -u64 memcache_connect(string host = "127.0.0.1", short port = 11211) -{ - return(socket_connect(host, port)); -} - -string memcache_command(u64 connection, string command) -{ - socket_write(connection, command+"\r\n"); - return(socket_read(connection)); // FIXME: do multi-chunk until END line is received! -} - -bool memcache_set(u64 connection, string key, string value, u64 expires_in = 60*60) -{ - socket_write(connection, - // set KEY META_DATA EXPIRY_TIME LENGTH_IN_BYTES - string("set ") + memcache_escape_key(key) + " 0 " + std::to_string(expires_in) + " " + std::to_string(value.length()) + "\r\n" + - value + "\r\n"); - return("STORED" == trim(socket_read(connection))); -} - -bool memcache_delete(u64 connection, string key) -{ - socket_write(connection, - // set KEY META_DATA EXPIRY_TIME LENGTH_IN_BYTES - string("delete ") + memcache_escape_key(key) + "\r\n" - ); - return("DELETED" == trim(socket_read(connection))); -} - -string memcache_get(u64 connection, string key, string default_value = "") -{ - auto res = memcache_command(connection, string("get ")+memcache_escape_key(key)); - string t = nibble(res, " "); - if(t == "VALUE") - { - string key = nibble(res, " "); - string meta = nibble(res, " "); - u32 length = stoi(nibble(res, "\r\n")); - return(res.substr(0, length)); - } - return(default_value); -} - -StringMap memcache_get_multiple(u64 connection, StringList keys) -{ - StringMap result; - // to do: escape key string - auto res = memcache_command(connection, string("get ")+join(memcache_escape_keys(keys), " ")); - while(res.length() > 0) - { - string t = nibble(res, " "); - if(t == "VALUE") - { - string key = nibble(res, " "); - string meta = nibble(res, " "); - u32 length = stoi(nibble(res, "\r\n")); - result[key] = res.substr(0, length); - res = res.substr(length+2); - } - } - return(result); -} +string memcache_escape_key(string key); +StringList memcache_escape_keys(StringList keys); +u64 memcache_connect(string host = "127.0.0.1", short port = 11211); +string memcache_command(u64 connection, string command); +bool memcache_set(u64 connection, string key, string value, u64 expires_in = 60*60); +bool memcache_delete(u64 connection, string key); +string memcache_get(u64 connection, string key, string default_value = ""); +StringMap memcache_get_multiple(u64 connection, StringList keys); diff --git a/src/lib/types.h b/src/lib/types.h index 8a28371..b156815 100644 --- a/src/lib/types.h +++ b/src/lib/types.h @@ -1,20 +1,7 @@ -#include -#include -#include #include #include #include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include #include typedef std::string string; @@ -64,6 +51,44 @@ struct ServerSettings { }; +struct MemoryArena { + + void* data; + u64 size = 0; + u64 capacity = 0; + + MemoryArena(u64 cap) + { + capacity = cap; + printf("(i) memory arena %p created with capacity of %i bytes\n", this, capacity); + data = malloc(cap); + } + + ~MemoryArena() + { + free(data); + } + + void clear() + { + printf("(i) memory arena %p cleared after high mark of %i bytes\n", this, size); + size = 0; + } + + void* get(u64 size_needed) + { + if(size_needed + size >= capacity) + { + printf("(!) memory arena %p capacity (%i) exceeded by allocation of %i bytes\n", this, capacity, size_needed); + return(0); + } + void* result = (char *)data + size; + size += size_needed; + return(result); + } + +}; + struct SharedUnit { string file_name; @@ -84,13 +109,7 @@ struct SharedUnit { string compiler_messages; time_t last_compiled; - ~SharedUnit() - { - if(so_handle) - { - dlclose(so_handle); - } - } + ~SharedUnit(); }; struct UploadedFile { @@ -113,22 +132,7 @@ struct URI { }; -string nibble(string div, string& haystack) -{ - auto pos = haystack.find(div); - if(pos == string::npos) - { - auto result = haystack; - haystack.clear(); - return(result); - } - else - { - auto result = haystack.substr(0, pos); - haystack.erase(0, pos+div.length()); - return(result); - } -} +string nibble(string div, string& haystack); template string to_hex(ITYPE w, size_t hex_len = sizeof(ITYPE)<<1) @@ -163,6 +167,9 @@ struct Request { StringMap header; StringList set_cookies; + MemoryArena* out_arena; + MemoryArena* memory_arena; + std::string in; std::string out; std::string err; @@ -176,27 +183,10 @@ struct Request { std::vector mysql_connections; } resources; - void invoke(string file_name) - { - DTree call_param; - compiler_invoke(this, file_name, call_param); - } - - void invoke(string file_name, DTree& call_param) - { - compiler_invoke(this, file_name, call_param); - } - - void print(string s) - { - out.append(s); - } - - ~Request() - { - for(auto& sockfd : resources.sockets) - close(sockfd); - } + void invoke(string file_name); + void invoke(string file_name, DTree& call_param); + void print(string s); + ~Request(); }; diff --git a/src/lib/uce_gen.h b/src/lib/uce_gen.h deleted file mode 100644 index 09b1986..0000000 --- a/src/lib/uce_gen.h +++ /dev/null @@ -1,7 +0,0 @@ - -#include "types.h" -#include "functionlib.h" -#include "sys.h" -#include "uri.h" -#include "compiler.h" -#include "mysql-connector.h" diff --git a/src/lib/unit.h b/src/lib/unit.h index 07edc05..af4d7ce 100644 --- a/src/lib/unit.h +++ b/src/lib/unit.h @@ -1,8 +1,3 @@ -#include "uce_gen.h" +#include "uce_lib.h" -extern "C" void set_current_request(Request* _request) -{ - context = _request; - signal(SIGSEGV, on_segfault); -} diff --git a/src/lib/uri.h b/src/lib/uri.h index e19c77c..b4bad3b 100644 --- a/src/lib/uri.h +++ b/src/lib/uri.h @@ -1,316 +1,19 @@ -string var_dump(URI uri, string prefix = "", string postfix = "\n") -{ - return( - prefix + "URI Parts: " + postfix + - var_dump(uri.parts, prefix+" ", postfix)+ - prefix + " Query: " + postfix + - var_dump(uri.query, prefix+" ", postfix) - ); -} - -string uri_decode(string q) -{ - string result; - for(u32 i = 0; i < q.length(); i++) - { - char c = q[i]; - if(c == '%' && q[i+1] != '%') - { - result.append(1, hex_to_u8(q.substr(i+1, 2))); - i += 2; - } - else - { - result.append(1, c); - } - } - return(result); -} - -string uri_encode(string q) -{ - string result; - for(u32 i = 0; i < q.length(); i++) - { - char c = q[i]; - if(isalnum(c) || c == '~' || c == '.' || c == '_' || c == '-') - result.append(1, c); - else - { - result.append(1, '%'); - result.append(to_hex(c)); - } - } - return(result); -} - -StringMap parse_query(string q) -{ - StringMap result; - if(q.length() == 0) - return(result); - - bool is_key = true; - string key = ""; - string value = ""; - for (char &c: q) - { - if(c == '=') - { - is_key = !is_key; - } - else if(c == '&') - { - result[uri_decode(key)] = uri_decode(value); - key = ""; - value = ""; - is_key = true; - } - else if(is_key) - { - key.append(1, c); - } - else - { - value.append(1, c); - } - } - - result[uri_decode(key)] = uri_decode(value); - - return(result); -} - -string encode_query(StringMap map) -{ - string result; - - for (auto it = map.begin(); it != map.end(); ++it) - { - if(result.length() > 0) - result.append(1, '&'); - result.append(uri_encode(it->first) + "=" + uri_encode(it->second)); - } - - return(result); -} - -StringMap parse_multipart(string q, string boundary, std::vector& uploaded_files) -{ - StringMap result; - - auto i = boundary.length(); - while(i < q.length()) - { - auto end_pos = q.find(boundary, i); - if(end_pos != string::npos) - { - string field = q.substr(i, end_pos - i); - nibble(":", field); - string ftype = trim(nibble(";", field)); - if(ftype == "form-data") - { - nibble("=\"", field); - string field_name = nibble("\"", field); - result[field_name] = field.substr(4, field.length()-6); - } - else if(ftype == "attachment") - { - nibble("=\"", field); - UploadedFile f; - f.tmp_name = context->server->config.TMP_UPLOAD_PATH + std::to_string(rand()); - f.file_name = nibble("\"", field); - string bin = field.substr(4, field.length()-6); - f.size = bin.length(); - file_put_contents(f.tmp_name, bin); - uploaded_files.push_back(f); - } - } - else - { - // we're done - end_pos = q.length(); - } - i = end_pos + boundary.length(); - } - - return(result); -} - -URI parse_uri(string uri_string) -{ - URI result; - - u8 state = 0; - string current = ""; - char expect = 0; - - result.parts["raw"] = uri_string; - - string part_names[] = { - "scheme", - "host", - "port", - "path", - "query", - "fragment", - }; - - if(uri_string[0] == '/') - state = 3; - - for (char &c: uri_string) - { - bool append_it = true; - - if(expect && expect != c) - { - result.parts["error"] = string("\'") + c + string("\' expected"); - result.parts["error_parsing"] = current; - result.parts["error_part"] = part_names[state]; - return(result); - } - expect = 0; - - switch(state) - { - case(0): // scheme - if(c == ':') - { - result.parts[part_names[state]] = current; - append_it = false; - current = ""; - state = 1; - } - break; - case(1): // host name - if(c == '/') - { - if(current == "") - { - append_it = false; - break; - } - result.parts[part_names[state]] = current; - append_it = false; - current = ""; - state = 3; - expect = '/'; - } - else if(c == ':') - { - result.parts[part_names[state]] = current; - append_it = false; - current = ""; - state = 2; - } - break; - case(2): // port - if(c == '/') - { - result.parts[part_names[state]] = current; - append_it = false; - current = ""; - state = 3; - expect = '/'; - } - break; - case(3): // path - if(c == '/' && current == "") - { - append_it = false; - break; - } - if(c == '?') - { - result.parts[part_names[state]] = current; - append_it = false; - current = ""; - state = 4; - } - break; - case(4): // query - if(c == '#') - { - result.parts[part_names[state]] = current; - append_it = false; - current = ""; - state = 5; - } - break; - } - - if(append_it) - current.append(1, c); - } - - result.parts[part_names[state]] = current; - - result.query = parse_query(result.parts["query"]); - - return(result); -} - +string var_dump(URI uri, string prefix = "", string postfix = "\n"); +string uri_decode(string q); +string uri_encode(string q); +StringMap parse_query(string q); +string encode_query(StringMap map); +StringMap parse_multipart(string q, string boundary, std::vector& uploaded_files); +URI parse_uri(string uri_string); void set_cookie( string name, string value = "", u64 expires = 0, string path = "/", string domain = "", - bool secure = false, bool http_only = true) -{ - string cookie = "Set-Cookie: "; - cookie.append(uri_encode(name) + "=" + uri_encode(value)); - if(expires > 0) - cookie.append(string("; Expires=") + gmdate("RFC1123", expires)); - context->set_cookies.push_back(cookie); - context->cookies[name] = value; -} - -StringMap parse_cookies(string cookie_string) -{ - StringMap result; - while(cookie_string.length() > 0) - { - string key = trim(nibble("=", cookie_string)); - string value = nibble(";", cookie_string); - result[key] = value; - } - return(result); -} - -string make_session_id() -{ - return(to_hex(rand())+to_hex(rand())+to_hex(rand())+to_hex(rand())); -} - -StringMap load_session_data(string session_id) -{ - return(parse_query(file_get_contents(context->server->config.SESSION_PATH + "/" + session_id))); -} - -void save_session_data(string session_id, StringMap data) -{ - file_put_contents(context->server->config.SESSION_PATH + "/" + session_id, encode_query(data)); -} - -string session_start(string session_name = "uce-session") -{ - if(context->cookies[session_name].length() == 0) - { - set_cookie(session_name, make_session_id(), time() + context->server->config.SESSION_TIME); - } - context->session_id = context->cookies[session_name]; - context->session_name = session_name; - context->session = load_session_data(context->session_id); - return(context->session_id); -} - -void session_destroy(string session_name = "uce-session") -{ - if(context->cookies[session_name].length() > 0) - { - set_cookie(session_name, "", time() - context->server->config.SESSION_TIME); - context->session.clear(); - context->session_id = ""; - } -} + bool secure = false, bool http_only = true); +StringMap parse_cookies(string cookie_string); +string make_session_id(); +StringMap load_session_data(string session_id); +void save_session_data(string session_id, StringMap data); +string session_start(string session_name = "uce-session"); +void session_destroy(string session_name = "uce-session"); diff --git a/src/linux_fastcgi.cpp b/src/linux_fastcgi.cpp index 35ca1aa..a670345 100644 --- a/src/linux_fastcgi.cpp +++ b/src/linux_fastcgi.cpp @@ -1,5 +1,4 @@ -#include "lib/uce_gen.h" -#include "lib/mysql-connector.cpp" +#include "lib/uce_lib.cpp" #include "fastcgi/src/fcgicc.cc" @@ -34,6 +33,9 @@ int handle_data(FastCGIRequest& request) { return 0; // still OK } +MemoryArena output_buffer(1024*1024*16); +MemoryArena memory_buffer(1024*1024*16); + int handle_complete(FastCGIRequest& request) { // The event handler can also be a class member function. This // event occurs when the parameters and standard input streams are @@ -42,6 +44,10 @@ int handle_complete(FastCGIRequest& request) { context = &request; request.server = &server_state; + request.out_arena = &output_buffer; + request.out_arena->clear(); + request.memory_arena = &memory_buffer; + request.memory_arena->clear(); request.time_start = microtime(); request.header["Content-Type"] = context->server->config.CONTENT_TYPE; request.get = parse_query(request.params["QUERY_STRING"]); @@ -90,6 +96,7 @@ int handle_complete(FastCGIRequest& request) { request.time_end - request.time_start, (f32)(request.out.length()/1024) ); + return 0; } diff --git a/test/index.uce b/test/index.uce index dac5750..b136b90 100644 --- a/test/index.uce +++ b/test/index.uce @@ -2,6 +2,8 @@ RENDER() { + DTree p; + p.set(context->params); <> @@ -22,7 +24,7 @@ RENDER()
  • Memcached
  • MySQL Connector
  • -
    params) ?>
    +
    }