From dff1959341a547a18f6a2feee4e11fd50e6fdc9f Mon Sep 17 00:00:00 2001 From: root Date: Tue, 16 Jun 2026 08:46:54 +0000 Subject: [PATCH] cleanup, error pages --- etc/uce/settings.cfg | 9 ++++++++ site/tests/cli_runner.uce | 5 +++++ src/lib/compiler.cpp | 47 --------------------------------------- src/lib/functionlib.cpp | 4 ++-- src/linux_fastcgi.cpp | 4 ++++ src/wasm/worker.cpp | 28 ++++++++++++----------- 6 files changed, 35 insertions(+), 62 deletions(-) diff --git a/etc/uce/settings.cfg b/etc/uce/settings.cfg index 10618d4..393c158 100644 --- a/etc/uce/settings.cfg +++ b/etc/uce/settings.cfg @@ -85,3 +85,12 @@ ARCHIVE_MAX_ZIP_ENTRIES=4096 # LIFETIME OF SESSION COOKIES IN SECONDS SESSION_TIME=2592000 + +# DEVELOPER-DEFINED ERROR PAGES (see /doc/index.uce?p=error_pages and +# /doc/index.uce?p=3_blocked_functions). The unit receives the error details in +# context.call["error"]; comment out for the plain-text fallback instead. +page_runtime_error=site/errors/runtime-error.uce + +# Comma-separated uce_host_* names to disable per server policy (empty = none). +# A unit calling a blocked hostcall fails into the error page above. +UCE_HOSTCALL_BLOCKLIST= diff --git a/site/tests/cli_runner.uce b/site/tests/cli_runner.uce index 0e5e8eb..9115cd2 100644 --- a/site/tests/cli_runner.uce +++ b/site/tests/cli_runner.uce @@ -172,6 +172,11 @@ void cli_run_http_smoke() cli_expect_http("uce_http_smoke:starter workspace ONCE assets reach head", "/examples/uce-starter/?workspace/projects", 200, "css/workspace.css"); cli_expect_http("uce_http_smoke:starter ajax section", "/examples/uce-starter/?page2-section1", 200, "UCE starter AJAX fragment response"); cli_expect_http("uce_http_smoke:starter route traversal blocked", "/examples/uce-starter/?../../../demo/index", 404, "The requested page does not exist."); + // Configurable error page (page_runtime_error): a runtime fault must render the + // developer-defined error-page unit with the real error info marshalled across + // the membrane, at the error status. Asserts HTTP 500 AND that error["request_uri"] + // reached the page (the "mode=trap" query is only shown if error_info crossed). + cli_expect_http("uce_http_smoke:configurable error page 500 + error info", "/demo/error-reporting.uce?mode=trap", 500, "mode=trap"); } void cli_run_site_suite() diff --git a/src/lib/compiler.cpp b/src/lib/compiler.cpp index 09a5f6a..a0fb5c5 100644 --- a/src/lib/compiler.cpp +++ b/src/lib/compiler.cpp @@ -497,35 +497,6 @@ void compiler_record_compile_result(SharedUnit* su, f64 duration, bool success, } } -void compiler_begin_render_result(SharedUnit* su, bool count_request) -{ - su->invoke_count += 1; - if(count_request) - su->request_count += 1; - su->last_rendered = time(); -} - -void compiler_record_render_result(SharedUnit* su, f64 duration, bool success, String error_status = "") -{ - su->last_render_duration = duration; - su->total_render_duration += duration; - if(su->best_render_duration == 0 || duration < su->best_render_duration) - su->best_render_duration = duration; - if(duration > su->worst_render_duration) - su->worst_render_duration = duration; - - if(success) - { - su->runtime_error_status = ""; - } - else - { - su->runtime_error_count += 1; - su->runtime_error_status = error_status; - su->last_error = time(); - } -} - String compiler_error_status(SharedUnit* su) { if(!su) @@ -591,24 +562,6 @@ void compiler_tree_set_bool(DValue& tree, String key, bool value) tree[key].set_bool(value); } -bool compiler_is_request_entry_unit(Request* context, SharedUnit* su) -{ - if(!context || !su) - return(false); - auto request_file = compiler_normalize_unit_path(context, context->params["SCRIPT_FILENAME"]); - return(request_file != "" && request_file == su->file_name); -} - -bool compiler_can_write_response(Request* context) -{ - return( - context && - context->params["REQUEST_METHOD"] != "" && - context->ob && - context->ob_stack.size() > 0 - ); -} - } String preprocess_shared_unit(Request* context, SharedUnit* su) diff --git a/src/lib/functionlib.cpp b/src/lib/functionlib.cpp index 6583968..3796b0c 100644 --- a/src/lib/functionlib.cpp +++ b/src/lib/functionlib.cpp @@ -625,7 +625,7 @@ String trim(String raw) s64 len = raw.length(); s64 start_pos = 0; s64 end_pos = len - 1; - if(len == 0 || (len == 1 && isspace((unsigned char)raw[0]))) + if(len == 0) return(""); while(start_pos < len && isspace((unsigned char)raw[start_pos])) start_pos++; @@ -2308,7 +2308,7 @@ String json_decode_String(String s, u32& i, char termination_char) result.append(1, '\''); break; case('u'): - if(i <= s.length() && s.length() - i >= 5 && json_decode_unicode_escape(s, i, result)) + if(s.length() - i >= 5 && json_decode_unicode_escape(s, i, result)) break; return(result); default: diff --git a/src/linux_fastcgi.cpp b/src/linux_fastcgi.cpp index eec8ffb..a1fee76 100644 --- a/src/linux_fastcgi.cpp +++ b/src/linux_fastcgi.cpp @@ -112,6 +112,10 @@ bool render_wasm_error_page(Request& request, String config_key, s32 status_code request.call.remove("error"); return(false); } + // Rendering the error-page unit set the response to its own (200) status; + // re-assert the error status + html content-type so the client sees e.g. 500. + request.set_status(status_code, status_reason); + request.header["Content-Type"] = first(request.server->config["CONTENT_TYPE"], "text/html; charset=utf-8"); print(html); return(true); } diff --git a/src/wasm/worker.cpp b/src/wasm/worker.cpp index 7a0d6c8..3f2542f 100644 --- a/src/wasm/worker.cpp +++ b/src/wasm/worker.cpp @@ -375,18 +375,25 @@ static bool uce_header_name_safe(String name) static DValue uce_http_request_value(const DValue& req) { DValue r; r["status"]=(f64)0; r["headers"].set_array(); r["body"]=""; r["error"]=""; - String method = req.key("method") ? to_upper(req.key("method")->to_string()) : String("GET"); - String url = req.key("url") ? req.key("url")->to_string() : String(""); + const DValue* method_value = req.key("method"); + const DValue* url_value = req.key("url"); + const DValue* timeout_value = req.key("timeout_ms"); + const DValue* follow_redirects_value = req.key("follow_redirects"); + const DValue* headers_value = req.key("headers"); + const DValue* body_value = req.key("body"); + String method = method_value ? to_upper(method_value->to_string()) : String("GET"); + String url = url_value ? url_value->to_string() : String(""); if(url=="" || url.find('\0')!=String::npos) { r["error"]="missing url"; return(r); } if(method=="") method="GET"; - std::vector argv = {"curl", "-sS", "--http1.0", "-X", method, "-D", "-", "-w", "\nUCE_HTTP_STATUS:%{http_code}", "--max-time", std::to_string(std::max(1, (req.key("timeout_ms") ? req.key("timeout_ms")->to_u64(5000) : 5000) / 1000))}; - if(req.key("follow_redirects") && req.key("follow_redirects")->to_bool()) argv.push_back("-L"); - if(req.key("headers")) req.key("headers")->each([&](const DValue& v, String k){ if(uce_header_name_safe(k)) { argv.push_back("-H"); argv.push_back(k + ": " + replace(replace(v.to_string(), "\r", " "), "\n", " ")); } }); - String body = req.key("body") ? req.key("body")->to_string() : String(""); - if(req.key("body")) { argv.push_back("--data-binary"); argv.push_back("@-"); } + u64 timeout_ms = timeout_value ? timeout_value->to_u64(5000) : 5000; + std::vector argv = {"curl", "-sS", "--http1.0", "-X", method, "-D", "-", "-w", "\nUCE_HTTP_STATUS:%{http_code}", "--max-time", std::to_string(std::max(1, timeout_ms / 1000))}; + if(follow_redirects_value && follow_redirects_value->to_bool()) argv.push_back("-L"); + if(headers_value) headers_value->each([&](const DValue& v, String k){ if(uce_header_name_safe(k)) { argv.push_back("-H"); argv.push_back(k + ": " + replace(replace(v.to_string(), "\r", " "), "\n", " ")); } }); + String body = body_value ? body_value->to_string() : String(""); + if(body_value) { argv.push_back("--data-binary"); argv.push_back("@-"); } argv.push_back(url); if(access("/usr/bin/curl", X_OK)!=0 && access("/bin/curl", X_OK)!=0) { r["error"]="curl binary not found in runtime PATH"; return(r); } - DValue pr = uce_exec_argv_capture(argv, body, req.key("timeout_ms") ? req.key("timeout_ms")->to_u64(5000) : 5000); + DValue pr = uce_exec_argv_capture(argv, body, timeout_ms); String out = pr["stdout"].to_string(); String marker="\nUCE_HTTP_STATUS:"; size_t mp=out.rfind(marker); if(mp!=String::npos) { r["status"]=(f64)strtoull(out.c_str()+mp+marker.size(),0,10); out=out.substr(0,mp); } @@ -989,11 +996,6 @@ public: return(""); } - String render_entry(const String& entry_source_path) - { - return(invoke_entry(entry_source_path, "render")); - } - String collect(WasmResponse& response) { String error = call_core("uce_wasm_finish_output", {}, 0);