diff --git a/bin/uce_fastcgi.debug.linux.bin b/bin/uce_fastcgi.debug.linux.bin index 5264f78..2cf63bd 100755 Binary files a/bin/uce_fastcgi.debug.linux.bin and b/bin/uce_fastcgi.debug.linux.bin differ diff --git a/build_linux.sh b/build_linux.sh index a27f576..7a87972 100755 --- a/build_linux.sh +++ b/build_linux.sh @@ -16,14 +16,13 @@ mkdir bin/assets > /dev/null 2>&1 mkdir work > /dev/null 2>&1 COMPILER="clang++" -FLAGS="-w -Wall -$OPT_FLAG -std=c++17 -fpermissive -ffast-math" +FLAGS="-g -w -Wall -$OPT_FLAG -std=c++17 -fpermissive -ffast-math" LIBS="-ldl -lm -lpthread " SRCFLAGS="-D EXEC_NAME=\"$GF\" -D PLATFORM_NAME=\"linux\"" echo "Compliling executable..." -#time -p -$COMPILER src/linux_fastcgi.cpp $SRCFLAGS $FLAGS $LIBS -o bin/$GF.$BUILDMODE.linux.bin 2>&1 +time -p $COMPILER src/linux_fastcgi.cpp $SRCFLAGS $FLAGS $LIBS -o bin/$GF.$BUILDMODE.linux.bin 2>&1 if [ $? -eq 0 ] then diff --git a/src/lib/compiler.h b/src/lib/compiler.h index 43b8496..698f131 100644 --- a/src/lib/compiler.h +++ b/src/lib/compiler.h @@ -1,31 +1,6 @@ -#include - #define RENDER() extern "C" void render() -typedef void (*call_handler)(); -typedef void (*request_handler)(Request* request); - -struct SharedUnit { - string file_name; - string so_name; - void* so_handle; - request_handler on_setup; - call_handler on_render; - string compiler_messages; - time_t last_compiled; - - ~SharedUnit() - { - if(so_handle) - { - dlclose(so_handle); - } - } -}; - -std::map units; - -string process_html_literal(string content, string file_name) +string process_html_literal(SharedUnit* su, string content) { string pc; string HT_START = "context->print(R\"("; @@ -99,9 +74,10 @@ string process_html_literal(string content, string file_name) return(HT_START + pc + HT_END); } -string preprocess(string content, string file_name) +string preprocess_shared_unit(SharedUnit* su) { - string pc = "#include \""+get_cwd()+"/src/lib/uce_gen.h\" \n"; + string content = file_get_contents(su->file_name); + string pc = "#include \""+context->server_state->config.COMPILER_SYS_PATH +"/src/lib/uce_gen.h\" \n"; string token = ""; string html_buffer = ""; u8 mode = 0; @@ -117,11 +93,11 @@ string preprocess(string content, string file_name) 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(html_buffer, file_name)); + pc.append(process_html_literal(su, html_buffer)); } else { - printf("(!) unterminated HTML literal <%s> in %s", token.c_str(), file_name.c_str()); + printf("(!) unterminated HTML literal <%s> in %s", token.c_str(), su->file_name.c_str()); } mode = 0; } @@ -160,9 +136,39 @@ string preprocess(string content, string file_name) return(pc); } -void load_shared_unit(SharedUnit* su) +void setup_unit_paths(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_state->config.BIN_DIRECTORY + su->src_path; + su->pre_path = context->server_state->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(SharedUnit* su, string file_name) +{ + setup_unit_paths(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) { @@ -181,79 +187,95 @@ void load_shared_unit(SharedUnit* su) } } -SharedUnit* compile_shared_unit(string file_name) +void compile_shared_unit(SharedUnit* su, string file_name) { - SharedUnit* su = new SharedUnit(); + setup_unit_paths(su, file_name); - string src_path = dirname(file_name); - string src_fn = basename(file_name); - string dest_path = Config.BIN_DIRECTORY + src_path; - string pp_fn = src_fn + ".cpp"; - string so_fn = src_fn + ".so"; + if(!file_exists(su->file_name)) + { + su->compiler_messages = "source file not found"; + return; + } - su->file_name = file_name; - su->so_name = dest_path + "/" + so_fn; + shell_exec("mkdir -p " + shell_escape(su->pre_path)); + file_put_contents(su->pre_path + "/" + su->pre_file_name, preprocess_shared_unit(su)); - string pc = preprocess(file_get_contents(file_name), file_name); - file_put_contents(dest_path + "/" + pp_fn, pc); + printf("Config.COMPILE_SCRIPT %s\n", string(su->pre_path + "/" + su->pre_file_name).c_str()); - su->compiler_messages = trim(shell_exec(Config.COMPILE_SCRIPT+" "+ - shell_escape(src_path)+" "+ - shell_escape(dest_path)+" "+ - shell_escape(src_fn)+" "+ - shell_escape(pp_fn)+" "+ - shell_escape(so_fn) + su->compiler_messages = trim(shell_exec(context->server_state->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()); - - printf("(i) compiled unit %s\n", file_name.c_str()); - - load_shared_unit(su); - - return(su); + } + else + { + load_shared_unit(su, file_name); + printf("(i) compiled unit %s\n", file_name.c_str()); + } } SharedUnit* get_shared_unit(string file_name) { - SharedUnit* su = units[file_name]; - if(su && su->last_compiled < file_mtime(file_name)) + SharedUnit* su = context->server_state->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 = units[file_name] = compile_shared_unit(file_name); + su = new SharedUnit(); + + if(do_recompile) + { + compile_shared_unit(su, file_name); + } + else + { + load_shared_unit(su, file_name); + if(!su->so_handle) + compile_shared_unit(su, file_name); + } + + context->server_state->units[file_name] = su; } return(su); } -void invoke(Request* req, string file_name) +void invoke(string file_name) { + printf("(i) invoke(%s)\n", file_name.c_str()); auto su = get_shared_unit(file_name); if(!su) { - printf("Error loading unit %s\n", su->file_name.c_str()); + printf("Error loading unit %s\n", file_name.c_str()); + context->print("Error loading unit: "+file_name); } else if(!su->on_render) { - req->print("Compiler error: "+su->compiler_messages); + context->print("Compiler error: "+su->compiler_messages); } else { if(su->compiler_messages.length() > 0) - req->print(su->compiler_messages); + context->print(su->compiler_messages); else { - su->on_setup(req); + string prev_wd = get_cwd(); + set_cwd(su->src_path); + su->on_setup(context); su->on_render(); + set_cwd(prev_wd); } } } - -void invoke(string file_name) -{ - return(invoke(context, file_name)); -} diff --git a/src/lib/settings.h b/src/lib/settings.h index b36f532..c1419a7 100644 --- a/src/lib/settings.h +++ b/src/lib/settings.h @@ -1,4 +1,4 @@ -struct Settings { +struct ServerSettings { string BIN_DIRECTORY = "work"; string COMPILE_SCRIPT = "scripts/compile"; @@ -6,6 +6,7 @@ struct Settings { string CONTENT_TYPE = "text/html; charset=utf-8"; string SOCKET_PATH = "/run/uce.sock"; string TMP_UPLOAD = "/tmp"; + string COMPILER_SYS_PATH = ""; u32 LISTEN_PORT = 9993; -} Config; +}; diff --git a/src/lib/sys.h b/src/lib/sys.h index 39eeb00..935c2f4 100644 --- a/src/lib/sys.h +++ b/src/lib/sys.h @@ -1,5 +1,6 @@ string shell_exec(string cmd) { + printf("(i) shell_exec(%s)\n", cmd.c_str()); string data; FILE * stream; const int max_buffer = 256; @@ -98,6 +99,11 @@ 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; diff --git a/src/lib/types.h b/src/lib/types.h index 15e378b..ac28403 100644 --- a/src/lib/types.h +++ b/src/lib/types.h @@ -10,6 +10,7 @@ #include #include #include +#include typedef std::string string; @@ -33,11 +34,47 @@ typedef long long s64; typedef std::map StringMap; typedef std::vector StringList; +typedef void (*invoke_handler)(string file_name); + struct UploadedFile { string file_name; string tmp_name; u32 size; }; +struct Request; + +typedef void (*call_handler)(); +typedef void (*request_handler)(Request* request); + +struct SharedUnit { + + string file_name; + string so_name; + + string src_path; + string bin_path; + string pre_path; + string src_file_name; + string bin_file_name; + string pre_file_name; + + void* so_handle; + + request_handler on_setup; + call_handler on_render; + + string compiler_messages; + time_t last_compiled; + + ~SharedUnit() + { + if(so_handle) + { + dlclose(so_handle); + } + } +}; + #include "dtree.h" diff --git a/src/lib/uce_gen.h b/src/lib/uce_gen.h index b338c4a..8f7035b 100644 --- a/src/lib/uce_gen.h +++ b/src/lib/uce_gen.h @@ -3,9 +3,17 @@ #include "datastructures.h" #include "sys.h" #include "time.h" -#include "uri.h" -struct FastCGIRequest { +struct ServerState { + + std::map units; + ServerSettings config; + +} server_state; + +struct Request { + + ServerState* server_state; StringMap params; StringMap get; @@ -29,13 +37,15 @@ struct FastCGIRequest { }; -typedef FastCGIRequest Request; +typedef Request FastCGIRequest; Request* context; +#include "uri.h" +#include "compiler.h" + extern "C" void set_current_request(Request* _request) { context = _request; } -#include "compiler.h" diff --git a/src/lib/uri.h b/src/lib/uri.h index 8e78e45..f3bd3a3 100644 --- a/src/lib/uri.h +++ b/src/lib/uri.h @@ -177,7 +177,7 @@ struct URI { { nibble("=\"", field); UploadedFile f; - f.tmp_name = Config.TMP_UPLOAD + to_string(rand()); + f.tmp_name = context->server_state->config.TMP_UPLOAD + to_string(rand()); f.file_name = nibble("\"", field); string bin = field.substr(4, field.length()-6); f.size = bin.length(); diff --git a/src/linux_fastcgi.cpp b/src/linux_fastcgi.cpp index 2ebd64f..64a57be 100644 --- a/src/linux_fastcgi.cpp +++ b/src/linux_fastcgi.cpp @@ -38,9 +38,11 @@ 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 // both closed, and thus the request is complete. + context = &request; + request.server_state = &server_state; request.time_start = microtime(); - request.header["Content-Type"] = Config.CONTENT_TYPE; + request.header["Content-Type"] = context->server_state->config.CONTENT_TYPE; request.get = URI::parse_query(request.params["QUERY_STRING"]); string ct_info = request.params["CONTENT_TYPE"]; @@ -59,7 +61,7 @@ int handle_complete(FastCGIRequest& request) { } } - invoke(&request, request.params["SCRIPT_FILENAME"]); + invoke(request.params["SCRIPT_FILENAME"]); string headers = var_dump(request.header, "", "\r\n") + "\r\n"; request.out = headers + request.out; @@ -87,11 +89,17 @@ int main(int argc, char** argv) server.data_handler(&handle_data); server.complete_handler(&handle_complete); - if(Config.LISTEN_PORT) - server.listen(Config.LISTEN_PORT); - if(Config.SOCKET_PATH != "") - server.listen(Config.SOCKET_PATH); - chmod(Config.SOCKET_PATH.c_str(), S_IRWXU | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + if(server_state.config.COMPILER_SYS_PATH == "") + server_state.config.COMPILER_SYS_PATH = get_cwd(); + server_state.config.BIN_DIRECTORY = + server_state.config.COMPILER_SYS_PATH + "/" + server_state.config.BIN_DIRECTORY; + server_state.config.COMPILE_SCRIPT = + server_state.config.COMPILER_SYS_PATH + "/" + server_state.config.COMPILE_SCRIPT; + if(server_state.config.LISTEN_PORT) + server.listen(server_state.config.LISTEN_PORT); + if(server_state.config.SOCKET_PATH != "") + server.listen(server_state.config.SOCKET_PATH); + chmod(server_state.config.SOCKET_PATH.c_str(), S_IRWXU | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); //server.process(100); //server.process(); diff --git a/test/index.uce b/test/index.uce index a7ae0db..b7f5db6 100644 --- a/test/index.uce +++ b/test/index.uce @@ -4,7 +4,7 @@ RENDER() { - +

UCE Test: Index @@ -13,6 +13,7 @@ RENDER()
  • Hello
  • Form Post
  • Form Multipart Post
  • +
  • Working Directory
  • params) ?>
    diff --git a/test/style.css b/test/style.css index 461e468..28a4d56 100644 --- a/test/style.css +++ b/test/style.css @@ -65,7 +65,8 @@ textarea { pre { height: 20%; overflow: auto; - padding. 8px; + padding: 8px; border: 2px solid rgba(0,0,0,0.2); background: rgba(100,100,100,0.15); + font-family: monospace; } diff --git a/test/test2/working-dir-test.uce b/test/test2/working-dir-test.uce new file mode 100644 index 0000000..f201afc --- /dev/null +++ b/test/test2/working-dir-test.uce @@ -0,0 +1,6 @@ + + +RENDER() +{ + echo("Sub-Invoke Working dir: " + get_cwd() + "\n"); +} diff --git a/test/working-dir.uce b/test/working-dir.uce new file mode 100644 index 0000000..566a5b0 --- /dev/null +++ b/test/working-dir.uce @@ -0,0 +1,19 @@ + + +RENDER() +{ + + <> + +

    + UCE Test: + Working Directory +

    +
    +
    params) ?>
    + + +} diff --git a/todo.txt b/todo.txt index 15c9ab8..7665b60 100644 --- a/todo.txt +++ b/todo.txt @@ -16,7 +16,6 @@ Bugs ================================= - shell_escape() - include path -- current request working directory - preprocessor - nested tags