This commit is contained in:
root
2026-06-15 21:42:50 +00:00
parent 34a97e2577
commit 99cd92fb4a
126 changed files with 1615 additions and 1057 deletions
+4 -2
View File
@@ -10,7 +10,7 @@
namespace {
const u64 UCE_UNIT_ABI_VERSION = 6;
const u64 UCE_UNIT_ABI_VERSION = 7;
struct SharedUnitFilesystemState
{
@@ -46,7 +46,7 @@ bool compiler_jit_compile_on_request_enabled(Request* context)
{
if(!context || !context->server)
return(true);
return(config_bool("JIT_COMPILE_ON_REQUEST", true));
return(to_bool(context->server->config["JIT_COMPILE_ON_REQUEST"], true));
}
bool compiler_is_u64_string(String value)
@@ -150,6 +150,8 @@ bool compiler_failure_retry_deferred(Request* context, SharedUnit* su, const Sha
return(false);
if(state.source_time == 0)
return(false);
if(!state.metadata_exists || !state.metadata_parsed || !state.abi_compatible || !state.input_signature_matches)
return(false);
auto required_failure_inputs_time = std::max({
state.source_time,
state.setup_template_time,
+157 -17
View File
@@ -174,6 +174,74 @@ void DValue::each(std::function <void (const DValue& t, String key)> f) const
}
}
StringList DValue::keys() const
{
StringList result;
each([&](const DValue& item, String key) {
(void)item;
if(key != "")
result.push_back(key);
});
return(result);
}
DValue DValue::values() const
{
DValue result;
result.set_array();
each([&](const DValue& item, String key) {
(void)key;
result.push(item);
});
return(result);
}
DValue DValue::filter(StringList keys) const
{
DValue result;
const DValue& target = deref();
for(auto key : keys)
{
const DValue* item = target.key(key);
if(item)
result[key] = *item;
}
return(result);
}
DValue DValue::filter(std::function<bool (const DValue&, String)> f) const
{
DValue result;
bool input_is_list = is_list();
if(input_is_list)
result.set_array();
each([&](const DValue& item, String key) {
if(!f(item, key))
return;
if(key != "" && !input_is_list)
result[key] = item;
else
result.push(item);
});
return(result);
}
DValue DValue::map(std::function<DValue (const DValue&, String)> f) const
{
DValue result;
bool input_is_list = is_list();
if(input_is_list)
result.set_array();
each([&](const DValue& item, String key) {
DValue mapped = f(item, key);
if(key != "" && !input_is_list)
result[key] = mapped;
else
result.push(mapped);
});
return(result);
}
bool DValue::is_array() const
{
return(deref().type == 'M');
@@ -798,8 +866,9 @@ void DValue::clear()
namespace {
const char* UCEB_MAGIC = "UCEB";
const u8 UCEB_VERSION = 1;
const u8 UCEB_VERSION = 2;
const u8 UCEB_FLAG_LIST = 1;
const u32 UCEB_MAX_NESTING_DEPTH = 64;
thread_local String uce_dv_last_error_text;
thread_local String uce_dv_value_result;
@@ -831,6 +900,23 @@ bool ucb_read_varint(const String& src, size_t& offset, u64& value_out)
return(false);
}
char ucb_node_type(const DValue& value)
{
const DValue& target = value.deref();
switch(target.type)
{
case('M'):
case('S'):
case('F'):
case('B'):
return(target.type);
default:
// Raw pointers/references are not meaningful across the native/wasm
// membrane; preserve the historical wire behavior as an empty scalar.
return('S');
}
}
String ucb_node_scalar(const DValue& value)
{
const DValue& target = value.deref();
@@ -845,7 +931,7 @@ String ucb_node_scalar(const DValue& value)
return(out.str());
}
case('B'):
return(target._bool ? "(true)" : "(false)");
return(target._bool ? "1" : "0");
case('P'):
return("");
default:
@@ -853,11 +939,50 @@ String ucb_node_scalar(const DValue& value)
}
}
bool ucb_decode_scalar(char node_type, const String& scalar, DValue& out, String& error)
{
switch(node_type)
{
case('S'):
out = scalar;
return(true);
case('F'):
{
const char* begin = scalar.c_str();
char* end = 0;
f64 value = strtod(begin, &end);
if(end == begin || end != begin + scalar.size() || !std::isfinite(value))
{
error = "invalid UCEB2 f64 scalar";
return(false);
}
out = value;
return(true);
}
case('B'):
if(scalar == "1" || scalar == "true" || scalar == "(true)")
{
out.set_bool(true);
return(true);
}
if(scalar == "0" || scalar == "false" || scalar == "(false)")
{
out.set_bool(false);
return(true);
}
error = "invalid UCEB2 bool scalar";
return(false);
}
error = "invalid UCEB2 scalar type tag";
return(false);
}
void ucb_encode_node(String& out, const DValue& value)
{
const DValue& target = value.deref();
u8 flags = target.is_list() ? UCEB_FLAG_LIST : 0;
out.push_back((char)flags);
out.push_back(ucb_node_type(target));
String scalar = ucb_node_scalar(target);
ucb_append_varint(out, scalar.size());
out.append(scalar.data(), scalar.size());
@@ -877,26 +1002,32 @@ void ucb_encode_node(String& out, const DValue& value)
bool ucb_decode_node(const String& src, size_t& offset, DValue& out, String& error, u32 depth = 0)
{
if(depth > 1024)
if(depth >= UCEB_MAX_NESTING_DEPTH)
{
error = "UCEB1 nesting limit exceeded";
error = "UCEB2 nesting limit exceeded";
return(false);
}
if(offset >= src.size())
if(offset > src.size() || src.size() - offset < 2)
{
error = "unexpected end of UCEB1 node";
error = "unexpected end of UCEB2 node";
return(false);
}
u8 flags = (u8)src[offset++];
char node_type = src[offset++];
if(node_type != 'M' && node_type != 'S' && node_type != 'F' && node_type != 'B')
{
error = "invalid UCEB2 node type tag";
return(false);
}
u64 scalar_len = 0;
if(!ucb_read_varint(src, offset, scalar_len))
{
error = "invalid UCEB1 scalar length";
error = "invalid UCEB2 scalar length";
return(false);
}
if(scalar_len > src.size() - offset)
if(offset > src.size() || scalar_len > src.size() - offset)
{
error = "UCEB1 scalar length exceeds input";
error = "UCEB2 scalar length exceeds input";
return(false);
}
String scalar(src.data() + offset, (size_t)scalar_len);
@@ -905,15 +1036,19 @@ bool ucb_decode_node(const String& src, size_t& offset, DValue& out, String& err
u64 child_count = 0;
if(!ucb_read_varint(src, offset, child_count))
{
error = "invalid UCEB1 child count";
error = "invalid UCEB2 child count";
return(false);
}
out.clear();
if(child_count == 0 && (flags & UCEB_FLAG_LIST) == 0)
if(node_type != 'M')
{
out = scalar;
return(true);
if(child_count != 0 || (flags & UCEB_FLAG_LIST) != 0)
{
error = "UCEB2 scalar node cannot have children or list flag";
return(false);
}
return(ucb_decode_scalar(node_type, scalar, out, error));
}
if((flags & UCEB_FLAG_LIST) != 0)
out.set_array();
@@ -923,16 +1058,21 @@ bool ucb_decode_node(const String& src, size_t& offset, DValue& out, String& err
u64 key_len = 0;
if(!ucb_read_varint(src, offset, key_len))
{
error = "invalid UCEB1 child key length";
error = "invalid UCEB2 child key length";
return(false);
}
if(key_len > src.size() - offset)
if(offset > src.size() || key_len > src.size() - offset)
{
error = "UCEB1 child key length exceeds input";
error = "UCEB2 child key length exceeds input";
return(false);
}
String key(src.data() + offset, (size_t)key_len);
offset += (size_t)key_len;
if(depth + 1 >= UCEB_MAX_NESTING_DEPTH)
{
error = "UCEB2 nesting limit exceeded";
return(false);
}
DValue child;
if(!ucb_decode_node(src, offset, child, error, depth + 1))
return(false);
@@ -992,7 +1132,7 @@ bool ucb_decode(const String& encoded, DValue& out, String* error_out)
return(true);
}
if(error == "")
error = "trailing bytes after UCEB1 document";
error = "trailing bytes after UCEB2 document";
}
if(error_out)
*error_out = error;
+5
View File
@@ -23,6 +23,11 @@ struct DValue {
// conversions take an optional default that is returned when the value is
// missing (empty) or cannot be converted to the requested type.
void each(std::function <void (const DValue& t, String key)> f) const;
StringList keys() const;
DValue values() const;
DValue filter(StringList keys) const;
DValue filter(std::function<bool (const DValue&, String)> f) const;
DValue map(std::function<DValue (const DValue&, String)> f) const;
bool is_array() const;
bool is_list() const;
String to_string(String default_value = "") const;
+157 -98
View File
@@ -112,95 +112,6 @@ String list_find(StringList items, std::function<bool (String)> f, String fallba
return(fallback);
}
StringList dv_keys(DValue tree)
{
StringList result;
tree.each([&](const DValue& item, String key) {
if(key != "")
result.push_back(key);
});
return(result);
}
DValue dv_values(DValue tree)
{
DValue result;
result.set_array();
tree.each([&](const DValue& item, String key) {
result.push(item);
});
return(result);
}
DValue dv_pick(DValue tree, StringList keys)
{
DValue result;
for(auto key : keys)
{
DValue* item = tree.key(key);
if(item)
result[key] = *item;
}
return(result);
}
DValue dv_omit(DValue tree, StringList keys)
{
DValue result;
std::set<String> omitted(keys.begin(), keys.end());
tree.each([&](const DValue& item, String key) {
if(key != "" && omitted.find(key) == omitted.end())
result[key] = item;
});
return(result);
}
DValue dv_map(DValue tree, std::function<DValue (const DValue&, String)> f)
{
DValue result;
bool input_is_list = tree.is_list();
if(input_is_list)
result.set_array();
tree.each([&](const DValue& item, String key) {
DValue mapped = f(item, key);
if(key != "" && !input_is_list)
result[key] = mapped;
else
result.push(mapped);
});
return(result);
}
DValue dv_filter(DValue tree, std::function<bool (const DValue&, String)> f)
{
DValue result;
bool input_is_list = tree.is_list();
if(input_is_list)
result.set_array();
tree.each([&](const DValue& item, String key) {
if(!f(item, key))
return;
if(key != "" && !input_is_list)
result[key] = item;
else
result.push(item);
});
return(result);
}
DValue dv_group_by(DValue tree, std::function<String (const DValue&, String)> f)
{
DValue result;
tree.each([&](const DValue& item, String key) {
String group = f(item, key);
DValue* group_items = result.get_or_create(group);
if(!group_items->is_array())
group_items->set_array();
group_items->push(item);
});
return(result);
}
String substr(String s, s64 start_pos)
{
s64 len = s.length();
@@ -643,7 +554,7 @@ StringList regex_split(String pattern, String subject, String flags)
#else
// PCRE2 is not compiled into the wasm core; regex runs host-side (the host
// already links libpcre2). One UCEB1-marshalled hostcall carries the request
// already links libpcre2). One UCEB2-marshalled hostcall carries the request
// {op,pattern,subject,flags,replacement} in and the result tree out — the host
// runs the native regex_* and packs the answer. See uce_host_regex in
// src/wasm/worker.cpp.
@@ -1063,6 +974,48 @@ f64 float_val(String s)
return(strtod(s.c_str(), 0));
}
u64 to_u64(String s, u64 fallback)
{
String raw = trim(s);
if(raw == "")
return(fallback);
char* end = 0;
unsigned long long value = strtoull(raw.c_str(), &end, 10);
return(end && *end == 0 ? (u64)value : fallback);
}
s64 to_s64(String s, s64 fallback)
{
String raw = trim(s);
if(raw == "")
return(fallback);
char* end = 0;
long long value = strtoll(raw.c_str(), &end, 10);
return(end && *end == 0 ? (s64)value : fallback);
}
f64 to_f64(String s, f64 fallback)
{
String raw = trim(s);
if(raw == "")
return(fallback);
char* end = 0;
double value = strtod(raw.c_str(), &end);
return(end && *end == 0 ? (f64)value : fallback);
}
bool to_bool(String s, bool fallback)
{
String raw = trim(to_lower(s));
if(raw == "")
return(fallback);
if(raw == "1" || raw == "true" || raw == "yes" || raw == "on")
return(true);
if(raw == "0" || raw == "false" || raw == "no" || raw == "off")
return(false);
return(fallback);
}
String nibble(String& haystack, String delim)
{
auto idx = haystack.find(delim);
@@ -2255,6 +2208,58 @@ DValue yaml_decode(String s)
return(parser.parse_document());
}
static bool json_hex_to_u32(String s, u32 start, u32& value)
{
value = 0;
if(start > s.length() || s.length() - start < 4)
return(false);
for(u32 i = 0; i < 4; i += 1)
{
char c = s[start + i];
if(c >= '0' && c <= '9')
value = (value << 4) | (c - '0');
else if(c >= 'a' && c <= 'f')
value = (value << 4) | (c - 'a' + 10);
else if(c >= 'A' && c <= 'F')
value = (value << 4) | (c - 'A' + 10);
else
return(false);
}
return(true);
}
static bool json_decode_unicode_escape(String s, u32& i, String& result)
{
u32 codepoint = 0;
if(i >= s.length() || s[i] != 'u' || !json_hex_to_u32(s, i + 1, codepoint))
return(false);
u32 next_sequence_start = i + 5;
if(codepoint >= 0xd800 && codepoint <= 0xdbff)
{
u32 low = 0;
if(next_sequence_start <= s.length() && s.length() - next_sequence_start >= 6 && s[next_sequence_start] == '\\' && s[next_sequence_start + 1] == 'u' && json_hex_to_u32(s, next_sequence_start + 2, low) && low >= 0xdc00 && low <= 0xdfff)
{
codepoint = 0x10000 + (((codepoint - 0xd800) << 10) | (low - 0xdc00));
String utf8 = xml_utf8_from_codepoint(codepoint);
if(utf8 != "")
result += utf8;
i += 10;
return(true);
}
return(false);
}
if(codepoint >= 0xdc00 && codepoint <= 0xdfff)
return(false);
String utf8 = xml_utf8_from_codepoint(codepoint);
if(utf8 == "")
return(false);
result += utf8;
i += 4;
return(true);
}
// https://i.stack.imgur.com/SHLOB.gif
String json_decode_String(String s, u32& i, char termination_char)
{
@@ -2271,6 +2276,9 @@ String json_decode_String(String s, u32& i, char termination_char)
}
else if(c == '\\')
{
if(i + 1 >= s.length())
return(result);
i += 1;
c = s[i];
switch(c)
@@ -2293,9 +2301,16 @@ String json_decode_String(String s, u32& i, char termination_char)
case('f'):
result.append(1, '\f');
break;
case('u'):
// todo decode
case('"'):
result.append(1, '"');
break;
case('\''):
result.append(1, '\'');
break;
case('u'):
if(i <= s.length() && s.length() - i >= 5 && json_decode_unicode_escape(s, i, result))
break;
return(result);
default:
result.append(1, c);
break;
@@ -2342,19 +2357,58 @@ String json_decode_keyword(String s, u32& i)
String json_decode_number(String s, u32& i)
{
String result;
bool saw_dot = false;
bool saw_exponent = false;
json_consume_space(s, i);
if(i < s.length() && s[i] == '-')
{
result.append(1, '-');
i += 1;
}
if(i >= s.length() || !isdigit(s[i]))
return("");
while(i < s.length())
{
char c = s[i];
if(isdigit(c) || c == '.')
if(isdigit(c))
{
result.append(1, c);
i += 1;
continue;
}
else
if(c == '.' && !saw_dot && !saw_exponent)
{
return(result);
result.append(1, c);
saw_dot = true;
i += 1;
continue;
}
i += 1;
if((c == 'e' || c == 'E') && !saw_exponent)
{
if(i + 1 >= s.length())
break;
u32 exponent_start = i;
u32 next = i + 1;
if(s[next] == '+' || s[next] == '-')
next += 1;
if(next < s.length() && isdigit(s[next]))
{
result.append(1, s[i]);
i = i + 1;
if(i < s.length() && (s[i] == '+' || s[i] == '-'))
{
result.append(1, s[i]);
i += 1;
}
saw_exponent = true;
continue;
}
i = exponent_start;
break;
}
break;
}
return(result);
}
@@ -2364,6 +2418,9 @@ DValue json_decode_value(String s, u32& i)
DValue result;
String value = "";
json_consume_space(s, i);
if(i >= s.length())
return(result);
char c = s[i];
//print("json_decode_value " + s.substr(i) + "\n");
if(c == '"' || c == '\'') // String value
@@ -2373,7 +2430,7 @@ DValue json_decode_value(String s, u32& i)
result._String = json_decode_String(s, i, s[i-1]);
return(result);
}
else if(isdigit(c))
else if(c == '-' || isdigit(c))
{
result.type = 'S';
result._String = json_decode_number(s, i);
@@ -2426,9 +2483,11 @@ DValue json_decode_map(String s, u32& i)
else if(c == '"' || c == '\'')
{
i += 1;
if(i >= s.length())
return(result);
key = json_decode_String(s, i, s[i-1]);
json_consume_space(s, i);
if(s[i] != ':')
if(i >= s.length() || s[i] != ':')
return(result); // malformed
i += 1;
DValue v = json_decode_value(s, i);
+4 -7
View File
@@ -5,6 +5,10 @@ u8 char_to_u8(char input);
u8 hex_to_u8(String src);
u64 int_val(String s, u32 base = 10);
f64 float_val(String s);
u64 to_u64(String s, u64 fallback = 0);
s64 to_s64(String s, s64 fallback = 0);
f64 to_f64(String s, f64 fallback = 0);
bool to_bool(String s, bool fallback = false);
String to_lower(String s);
String to_upper(String s);
String substr(String s, s64 start_pos);
@@ -95,13 +99,6 @@ StringList list_sort(StringList items);
bool list_some(StringList items, std::function<bool (String)> f);
bool list_every(StringList items, std::function<bool (String)> f);
String list_find(StringList items, std::function<bool (String)> f, String fallback = "");
StringList dv_keys(DValue tree);
DValue dv_values(DValue tree);
DValue dv_pick(DValue tree, StringList keys);
DValue dv_omit(DValue tree, StringList keys);
DValue dv_map(DValue tree, std::function<DValue (const DValue&, String)> f);
DValue dv_filter(DValue tree, std::function<bool (const DValue&, String)> f);
DValue dv_group_by(DValue tree, std::function<String (const DValue&, String)> f);
template <class ...Args>
inline String first(Args... args)
+1 -61
View File
@@ -193,13 +193,6 @@ StringList ls(String dir)
return(StringList());
return(split(listing, "\n"));
}
u64 config_map_u64(StringMap& cfg, String key, u64 fallback) { String raw = first(cfg[key], std::to_string(fallback)); char* end = 0; unsigned long long v = strtoull(raw.c_str(), &end, 10); return(end && *end == 0 ? (u64)v : fallback); }
f64 config_map_f64(StringMap& cfg, String key, f64 fallback) { String raw = first(cfg[key], std::to_string(fallback)); char* end = 0; double v = strtod(raw.c_str(), &end); return(end && *end == 0 ? (f64)v : fallback); }
bool config_bool_value(String raw, bool fallback) { if(raw == "") return(fallback); return(raw != "0" && raw != "false" && raw != "no" && raw != "off"); }
bool config_map_bool(StringMap& cfg, String key, bool fallback) { return(config_bool_value(cfg[key], fallback)); }
u64 config_u64(String key, u64 fallback) { return(context ? config_map_u64(context->server->config, key, fallback) : fallback); }
f64 config_f64(String key, f64 fallback) { return(context ? config_map_f64(context->server->config, key, fallback) : fallback); }
bool config_bool(String key, bool fallback) { return(context ? config_map_bool(context->server->config, key, fallback) : fallback); }
DValue request_perf()
{
size_t required = uce_host_request_perf("", 0, 0, 0);
@@ -1412,60 +1405,6 @@ StringList ls(String dir)
return(split(trim(shell_exec("ls -1 "+shell_escape(dir))), "\n"));
}
u64 config_map_u64(StringMap& cfg, String key, u64 fallback)
{
String raw = trim(cfg[key]);
if(raw == "")
return(fallback);
return(int_val(raw));
}
f64 config_map_f64(StringMap& cfg, String key, f64 fallback)
{
String raw = trim(cfg[key]);
if(raw == "")
return(fallback);
return(float_val(raw));
}
bool config_bool_value(String raw, bool fallback)
{
raw = trim(to_lower(raw));
if(raw == "")
return(fallback);
if(raw == "1" || raw == "true" || raw == "yes" || raw == "on")
return(true);
if(raw == "0" || raw == "false" || raw == "no" || raw == "off")
return(false);
return(fallback);
}
bool config_map_bool(StringMap& cfg, String key, bool fallback)
{
return(config_bool_value(cfg[key], fallback));
}
u64 config_u64(String key, u64 fallback)
{
if(!context || !context->server)
return(fallback);
return(config_map_u64(context->server->config, key, fallback));
}
f64 config_f64(String key, f64 fallback)
{
if(!context || !context->server)
return(fallback);
return(config_map_f64(context->server->config, key, fallback));
}
bool config_bool(String key, bool fallback)
{
if(!context || !context->server)
return(fallback);
return(config_map_bool(context->server->config, key, fallback));
}
StringMap make_server_settings()
{
StringMap cfg;
@@ -1485,6 +1424,7 @@ StringMap make_server_settings()
// Command socket the WS broker listens on; workers flush ws_* dispatch
// command batches here at workspace teardown.
cfg["WS_BROKER_SOCKET_PATH"] = "/run/uce/ws-broker.sock";
cfg["WS_BROKER_OUTBOUND_TIMEOUT_SECONDS"] = "30";
cfg["TMP_UPLOAD_PATH"] = "/tmp/uce/uploads";
cfg["SESSION_PATH"] = "/tmp/uce/sessions";
cfg["COMPILER_SYS_PATH"] = ".";
-8
View File
@@ -56,14 +56,6 @@ time_t file_mtime(String file_name);
void file_unlink(String file_name);
String expand_path(String path, String relative_to_path = "");
StringList ls(String dir);
u64 config_map_u64(StringMap& cfg, String key, u64 fallback);
f64 config_map_f64(StringMap& cfg, String key, f64 fallback);
bool config_bool_value(String raw, bool fallback = true);
bool config_map_bool(StringMap& cfg, String key, bool fallback = true);
u64 config_u64(String key, u64 fallback);
f64 config_f64(String key, f64 fallback);
bool config_bool(String key, bool fallback = true);
f64 time_precise();
u64 time();
String time_format_local(String format = "", u64 timestamp = 0);
+54 -1
View File
@@ -8,6 +8,7 @@
#include <sstream>
#include <atomic>
#include <set>
#include <utility>
typedef unsigned char u8;
typedef signed char s8;
@@ -51,7 +52,58 @@ inline String operator+(String lhs, f32 rhs) {
#define DEBUG_MEMORY_OFF
typedef std::map<String, String> StringMap;
typedef std::vector<String> StringList;
struct StringList : std::vector<String> {
using std::vector<String>::vector;
using std::vector<String>::operator=;
StringList() = default;
StringList(const StringList&) = default;
StringList(StringList&&) = default;
StringList& operator=(const StringList&) = default;
StringList& operator=(StringList&&) = default;
StringList(const std::vector<String>& source) : std::vector<String>(source) {}
StringList(std::vector<String>&& source) : std::vector<String>(std::move(source)) {}
StringList& operator=(const std::vector<String>& source) { std::vector<String>::operator=(source); return(*this); }
StringList& operator=(std::vector<String>&& source) { std::vector<String>::operator=(std::move(source)); return(*this); }
template<typename F>
StringList filter(F f) const
{
StringList result;
for(const auto& item : *this)
{
if(f(item))
result.push_back(item);
}
return(result);
}
template<typename F>
StringList map(F f) const
{
StringList result;
for(const auto& item : *this)
result.push_back(f(item));
return(result);
}
StringList keys() const
{
StringList result;
for(size_t i = 0; i < size(); i++)
result.push_back(std::to_string(i));
return(result);
}
template<typename F>
void each(F f) const
{
for(const auto& item : *this)
f(item);
}
};
typedef std::ostringstream ByteStream;
struct Request;
@@ -203,6 +255,7 @@ struct Request {
String websocket_scope = "";
DValue* websocket_connection_state = 0;
StringList websocket_scope_connection_ids;
DValue websocket_connection_state_before;
DValue websocket_dispatch_commands;
bool websocket_dispatch_capture = false;
u8 websocket_opcode = 0;
+2 -2
View File
@@ -16,7 +16,7 @@ String zip_error(String api, String detail)
void archive_check_size(String api, String label, u64 size, String config_key, u64 fallback)
{
u64 limit = config_u64(config_key, fallback);
u64 limit = to_u64(context->server->config[config_key], fallback);
if(limit > 0 && size > limit)
throw std::runtime_error(zip_error(api, label + " exceeds configured limit"));
}
@@ -326,7 +326,7 @@ String gz_uncompress(String compressed)
if(!out)
throw std::runtime_error("gz_uncompress(): decompression failed");
u64 output_limit = config_u64("ARCHIVE_MAX_OUTPUT_BYTES", 64 * 1024 * 1024);
u64 output_limit = to_u64(context->server->config["ARCHIVE_MAX_OUTPUT_BYTES"], 64 * 1024 * 1024);
if(output_limit > 0 && out_len > output_limit)
{
mz_free(out);