143 lines
2.7 KiB
C++
143 lines
2.7 KiB
C++
// WASM-PROPOSAL Phase 2 — native UCE core subset compiled to WASM.
|
|
//
|
|
// This scaffold validates the Phase 2 membrane without the Phase 3 dynamic
|
|
// loader: the core owns memory/libc++/DValue/UCEB1, imports a tiny hostcall
|
|
// surface, decodes a host-provided UCEB1 request context, and invokes one
|
|
// statically linked real .uce page.
|
|
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
|
|
#include "../../src/lib/types.h"
|
|
#include "../../src/lib/dvalue.cpp"
|
|
|
|
extern "C" {
|
|
size_t uce_host_ctx_read(char* buf, size_t cap);
|
|
void uce_host_log(int level, const char* buf, size_t len);
|
|
}
|
|
|
|
#define RENDER(X) extern "C" void __uce_render(X)
|
|
#include "page.uce"
|
|
|
|
static Request g_request;
|
|
static ByteStream g_ob;
|
|
static String g_output;
|
|
|
|
SharedUnit::~SharedUnit() {}
|
|
|
|
String nibble(String div, String& haystack)
|
|
{
|
|
auto pos = haystack.find(div);
|
|
if(pos == String::npos)
|
|
{
|
|
auto result = haystack;
|
|
haystack.clear();
|
|
return(result);
|
|
}
|
|
auto result = haystack.substr(0, pos);
|
|
haystack.erase(0, pos + div.length());
|
|
return(result);
|
|
}
|
|
|
|
void Request::ob_start()
|
|
{
|
|
ob_stack.push_back(new ByteStream());
|
|
ob = ob_stack.back();
|
|
}
|
|
|
|
void Request::set_status(s32 code, String reason)
|
|
{
|
|
if(reason == "")
|
|
reason = code == 200 ? "OK" : "Status";
|
|
response_code = "HTTP/1.1 " + std::to_string(code) + " " + reason;
|
|
}
|
|
|
|
Request::~Request()
|
|
{
|
|
for(auto* stream : ob_stack)
|
|
delete stream;
|
|
ob_stack.clear();
|
|
}
|
|
|
|
static void phase2_clear_ob_stack()
|
|
{
|
|
for(auto* stream : g_request.ob_stack)
|
|
delete stream;
|
|
g_request.ob_stack.clear();
|
|
}
|
|
|
|
static void phase2_apply_context(DValue& root)
|
|
{
|
|
g_request.call = root;
|
|
g_request.params.clear();
|
|
DValue* params = root.key("params");
|
|
if(params)
|
|
{
|
|
params->each([&](const DValue& item, String key) {
|
|
g_request.params[key] = item.to_string();
|
|
});
|
|
}
|
|
}
|
|
|
|
extern "C" {
|
|
|
|
void* uce_alloc(size_t len)
|
|
{
|
|
return(malloc(len));
|
|
}
|
|
|
|
void uce_free(void* ptr)
|
|
{
|
|
free(ptr);
|
|
}
|
|
|
|
int uce_phase2_render()
|
|
{
|
|
context = &g_request;
|
|
phase2_clear_ob_stack();
|
|
g_ob.str("");
|
|
g_ob.clear();
|
|
g_request.ob = &g_ob;
|
|
g_request.out = "";
|
|
g_output = "";
|
|
|
|
size_t ctx_required = uce_host_ctx_read(0, 0);
|
|
if(ctx_required == 0)
|
|
return(10);
|
|
char* ctx_buf = (char*)malloc(ctx_required);
|
|
if(ctx_buf == 0)
|
|
return(11);
|
|
size_t ctx_len = uce_host_ctx_read(ctx_buf, ctx_required);
|
|
if(ctx_len != ctx_required)
|
|
{
|
|
free(ctx_buf);
|
|
return(12);
|
|
}
|
|
DValue decoded;
|
|
String error;
|
|
bool ok = ucb_decode(String(ctx_buf, ctx_len), decoded, &error);
|
|
free(ctx_buf);
|
|
if(!ok)
|
|
{
|
|
uce_host_log(3, error.data(), error.size());
|
|
return(20);
|
|
}
|
|
|
|
phase2_apply_context(decoded);
|
|
__uce_render(g_request);
|
|
g_output = g_ob.str();
|
|
return(0);
|
|
}
|
|
|
|
const char* uce_phase2_output_data()
|
|
{
|
|
return(g_output.data());
|
|
}
|
|
|
|
size_t uce_phase2_output_size()
|
|
{
|
|
return(g_output.size());
|
|
}
|
|
|
|
}
|