Decode request maps directly into Wasm workspaces
This commit is contained in:
+95
-36
@@ -723,6 +723,46 @@ void unit_render(String file_name, Request& request)
|
||||
|
||||
void unit_render(String file_name) { unit_render(file_name, *context); }
|
||||
|
||||
struct WasmRequestEnvelopeSegment
|
||||
{
|
||||
const char* data = 0;
|
||||
size_t size = 0;
|
||||
};
|
||||
|
||||
static bool wasm_decode_request_envelope(const char* encoded, size_t encoded_size,
|
||||
WasmRequestEnvelopeSegment (&segments)[12], String& error)
|
||||
{
|
||||
if(encoded_size < 6 || memcmp(encoded, "UCER", 4) != 0)
|
||||
{
|
||||
error = "missing UCE request-envelope header";
|
||||
return(false);
|
||||
}
|
||||
if((u8)encoded[4] != 1 || (u8)encoded[5] != 12)
|
||||
{
|
||||
error = "unsupported UCE request-envelope version or segment count";
|
||||
return(false);
|
||||
}
|
||||
size_t offset = 6;
|
||||
for(u32 i = 0; i < 12; i++)
|
||||
{
|
||||
u64 segment_size = 0;
|
||||
if(!ucb_read_varint(encoded, encoded_size, offset, segment_size) || segment_size > encoded_size - offset)
|
||||
{
|
||||
error = "invalid UCE request-envelope segment " + std::to_string(i);
|
||||
return(false);
|
||||
}
|
||||
segments[i].data = encoded + offset;
|
||||
segments[i].size = (size_t)segment_size;
|
||||
offset += (size_t)segment_size;
|
||||
}
|
||||
if(offset != encoded_size)
|
||||
{
|
||||
error = "trailing bytes after UCE request envelope";
|
||||
return(false);
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
// The host has already loaded the request's entry unit and can place its
|
||||
@@ -807,46 +847,66 @@ int uce_wasm_apply_context(const char* config_buf, size_t config_len, const char
|
||||
if(context == 0)
|
||||
uce_wasm_core_init();
|
||||
StringMap decoded_config;
|
||||
DValue decoded;
|
||||
StringMap decoded_params;
|
||||
StringMap decoded_get;
|
||||
StringMap decoded_post;
|
||||
StringMap decoded_cookies;
|
||||
StringMap decoded_session;
|
||||
DValue decoded_call;
|
||||
DValue decoded_ws;
|
||||
WasmRequestEnvelopeSegment segments[12];
|
||||
String error;
|
||||
if(!ucb_decode_flat_string_map(String(config_buf, config_len), decoded_config, &error))
|
||||
if(!ucb_decode_flat_string_map(config_buf, config_len, decoded_config, &error))
|
||||
{
|
||||
uce_host_log(3, error.data(), error.size());
|
||||
return(1);
|
||||
}
|
||||
if(!ucb_decode(String(context_buf, context_len), decoded, &error))
|
||||
if(!wasm_decode_request_envelope(context_buf, context_len, segments, error))
|
||||
{
|
||||
uce_host_log(3, error.data(), error.size());
|
||||
return(2);
|
||||
}
|
||||
wasm_server.config = std::move(decoded_config);
|
||||
wasm_request.call = std::move(decoded);
|
||||
DValue& applied = wasm_request.call;
|
||||
auto apply_map = [](DValue* source, StringMap& dest) {
|
||||
dest.clear();
|
||||
if(source)
|
||||
source->each([&](const DValue& item, String key) {
|
||||
dest[key] = item.to_string();
|
||||
});
|
||||
auto decode_tree = [&](u32 index, DValue& target, const char* name) {
|
||||
if(ucb_decode(String(segments[index].data, segments[index].size), target, &error))
|
||||
return(true);
|
||||
error = String(name) + ": " + error;
|
||||
return(false);
|
||||
};
|
||||
apply_map(applied.key("params"), wasm_request.params);
|
||||
auto decode_map = [&](u32 index, StringMap& target, const char* name) {
|
||||
if(ucb_decode_flat_string_map(segments[index].data, segments[index].size, target, &error))
|
||||
return(true);
|
||||
error = String(name) + ": " + error;
|
||||
return(false);
|
||||
};
|
||||
if(!decode_tree(0, decoded_call, "request call") ||
|
||||
!decode_map(1, decoded_params, "request params") ||
|
||||
!decode_map(2, decoded_get, "request get") ||
|
||||
!decode_map(3, decoded_post, "request post") ||
|
||||
!decode_map(4, decoded_cookies, "request cookies") ||
|
||||
!decode_map(5, decoded_session, "request session"))
|
||||
{
|
||||
uce_host_log(3, error.data(), error.size());
|
||||
return(3);
|
||||
}
|
||||
if(segments[11].size && !decode_tree(11, decoded_ws, "request websocket"))
|
||||
{
|
||||
uce_host_log(3, error.data(), error.size());
|
||||
return(4);
|
||||
}
|
||||
wasm_server.config = std::move(decoded_config);
|
||||
wasm_request.call = std::move(decoded_call);
|
||||
wasm_request.params = std::move(decoded_params);
|
||||
wasm_request.get = std::move(decoded_get);
|
||||
wasm_request.post = std::move(decoded_post);
|
||||
wasm_request.cookies = std::move(decoded_cookies);
|
||||
wasm_request.session = std::move(decoded_session);
|
||||
wasm_request.response_code = wasm_request.params["GATEWAY_INTERFACE"] != "" ?
|
||||
"Status: 200 OK" : "HTTP/1.1 200 OK";
|
||||
apply_map(applied.key("get"), wasm_request.get);
|
||||
apply_map(applied.key("post"), wasm_request.post);
|
||||
apply_map(applied.key("cookies"), wasm_request.cookies);
|
||||
apply_map(applied.key("session"), wasm_request.session);
|
||||
if(DValue* session_id = applied.key("session_id"))
|
||||
wasm_request.session_id = session_id->to_string();
|
||||
if(DValue* session_name = applied.key("session_name"))
|
||||
wasm_request.session_name = session_name->to_string();
|
||||
if(DValue* session_loaded_hash = applied.key("session_loaded_hash"))
|
||||
wasm_request.session_loaded_hash = session_loaded_hash->to_string();
|
||||
DValue* entry = applied.key("entry_unit");
|
||||
if(entry)
|
||||
wasm_request.resources.current_unit_file = entry->to_string();
|
||||
DValue* raw_in = applied.key("in");
|
||||
wasm_request.in = raw_in ? raw_in->to_string() : "";
|
||||
wasm_request.session_id.assign(segments[6].data, segments[6].size);
|
||||
wasm_request.session_name.assign(segments[7].data, segments[7].size);
|
||||
wasm_request.session_loaded_hash.assign(segments[8].data, segments[8].size);
|
||||
wasm_request.resources.current_unit_file.assign(segments[9].data, segments[9].size);
|
||||
wasm_request.in.assign(segments[10].data, segments[10].size);
|
||||
// websocket event context: ws_send()/ws_close() capture into the dispatch
|
||||
// list (the workspace owns no connections), which collect() carries back to
|
||||
// the broker. Reset per invocation.
|
||||
@@ -854,20 +914,19 @@ int uce_wasm_apply_context(const char* config_buf, size_t config_len, const char
|
||||
wasm_request.resources.websocket_connection_state_before = DValue();
|
||||
wasm_request.resources.websocket_dispatch_commands = DValue();
|
||||
wasm_request.resources.websocket_dispatch_capture = false;
|
||||
DValue* ws = applied.key("ws");
|
||||
if(ws)
|
||||
if(segments[11].size)
|
||||
{
|
||||
wasm_request.resources.websocket_connection_id = (*ws)["connection_id"].to_string();
|
||||
wasm_request.resources.websocket_scope = (*ws)["scope"].to_string();
|
||||
wasm_request.resources.websocket_opcode = (u8)(*ws)["opcode"].to_u64();
|
||||
wasm_request.resources.websocket_is_binary = (*ws)["binary"].to_bool();
|
||||
wasm_request.resources.websocket_connection_id = decoded_ws["connection_id"].to_string();
|
||||
wasm_request.resources.websocket_scope = decoded_ws["scope"].to_string();
|
||||
wasm_request.resources.websocket_opcode = (u8)decoded_ws["opcode"].to_u64();
|
||||
wasm_request.resources.websocket_is_binary = decoded_ws["binary"].to_bool();
|
||||
wasm_request.resources.websocket_scope_connection_ids.clear();
|
||||
if(DValue* conns = ws->key("connections"))
|
||||
if(DValue* conns = decoded_ws.key("connections"))
|
||||
conns->each([&](const DValue& v, String) {
|
||||
wasm_request.resources.websocket_scope_connection_ids.push_back(v.to_string());
|
||||
});
|
||||
wasm_request.resources.websocket_dispatch_capture = true;
|
||||
if(DValue* cstate = ws->key("connection_state"))
|
||||
if(DValue* cstate = decoded_ws.key("connection_state"))
|
||||
wasm_request.connection = *cstate;
|
||||
wasm_request.resources.websocket_connection_state_before = wasm_request.connection;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user