Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[wip] feat(proxy-wasm) host-managed property getters and setters using the Lua bridge #441

Closed
wants to merge 11 commits into from
4 changes: 4 additions & 0 deletions lib/resty/wasmx.lua
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,14 @@ ffi.cdef [[
ngx_str_t *config;
} ngx_wasm_filter_t;

typedef intptr_t ngx_int_t;
typedef unsigned char u_char;
typedef struct ngx_wavm_t ngx_wasm_vm_t;
typedef struct ngx_wasm_ops_plan_t ngx_wasm_plan_t;

typedef ngx_int_t (*ngx_wasm_host_prop_fn_t)(void *data, ngx_str_t *key,
ngx_str_t *value);

ngx_wasm_vm_t *ngx_wasm_ffi_main_vm();
]]

Expand Down
121 changes: 101 additions & 20 deletions lib/resty/wasmx/proxy_wasm.lua
Original file line number Diff line number Diff line change
Expand Up @@ -38,23 +38,25 @@ local _M = {

if subsystem == "http" then
ffi.cdef [[
int ngx_http_wasm_ffi_plan_new(ngx_wasm_vm_t *vm,
ngx_wasm_filter_t *filters,
size_t n_filters,
ngx_wasm_plan_t **out,
u_char *err, size_t *errlen);
int ngx_http_wasm_ffi_plan_free(ngx_wasm_plan_t *plan);
int ngx_http_wasm_ffi_plan_load(ngx_wasm_plan_t *plan);
int ngx_http_wasm_ffi_plan_attach(ngx_http_request_t *r,
ngx_wasm_plan_t *plan,
unsigned int isolation);
int ngx_http_wasm_ffi_start(ngx_http_request_t *r);
int ngx_http_wasm_ffi_set_property(ngx_http_request_t *r,
ngx_str_t *key,
ngx_str_t *value);
int ngx_http_wasm_ffi_get_property(ngx_http_request_t *r,
ngx_str_t *key,
ngx_str_t *out);
ngx_int_t ngx_http_wasm_ffi_plan_new(ngx_wasm_vm_t *vm,
ngx_wasm_filter_t *filters,
size_t n_filters,
ngx_wasm_plan_t **out,
u_char *err, size_t *errlen);
ngx_int_t ngx_http_wasm_ffi_plan_free(ngx_wasm_plan_t *plan);
ngx_int_t ngx_http_wasm_ffi_plan_load(ngx_wasm_plan_t *plan);
ngx_int_t ngx_http_wasm_ffi_plan_attach(ngx_http_request_t *r,
ngx_wasm_plan_t *plan,
unsigned int isolation);
ngx_int_t ngx_http_wasm_ffi_start(ngx_http_request_t *r);
ngx_int_t ngx_http_wasm_ffi_set_property(ngx_http_request_t *r,
ngx_str_t *key,
ngx_str_t *value);
ngx_int_t ngx_http_wasm_ffi_get_property(ngx_http_request_t *r,
ngx_str_t *key,
ngx_str_t *out);
ngx_int_t ngx_http_wasm_ffi_enable_property_setter(ngx_http_request_t *r);
ngx_int_t ngx_http_wasm_ffi_enable_property_getter(ngx_http_request_t *r);
]]

else
Expand Down Expand Up @@ -229,7 +231,7 @@ function _M.set_property(key, value)
error("key must be a string", 2)
end

if type(value) ~= "string" then
if value ~= nil and type(value) ~= "string" then
error("value must be a string", 2)
end

Expand All @@ -238,8 +240,14 @@ function _M.set_property(key, value)
error("no request found", 2)
end

local ckey = ffi_new("ngx_str_t", { data = key, len = #key })
local cvalue = ffi_new("ngx_str_t", { data = value, len = #value })
local ckey = ffi_new("ngx_str_t", {
data = key,
len = #key
})
local cvalue = ffi_new("ngx_str_t", {
data = value,
len = value and #value or 0
})

local rc = C.ngx_http_wasm_ffi_set_property(r, ckey, cvalue)
if rc == FFI_ERROR then
Expand Down Expand Up @@ -276,8 +284,81 @@ function _M.get_property(key)
return nil, "property \"" .. key .. "\" not found", NOT_FOUND
end

if cvalue.data == nil then
return nil
end

return ffi_str(cvalue.data, cvalue.len)
end


---
-- Define a setter function for host-managed properties.
--
-- @param setter The setter function is the handler for updating properties.
-- Its type signature is `function(string, string): boolean, string`,
-- where the inputs are the property key and value and the results are:
-- * `truthy` - success setting the property
-- * `truthy, value` - success, cache property value (useful if hosts
-- sets only a setter but not a getter)
-- * `truthy, value, truthy` - success, constant property value: further
-- requests to the same property during a request are cached by
-- ngx_wasm_module and do not invoke the Lua getter.
-- * `falsy, err` - failure, and an optional error message
-- @return true on success setting the getter, or nil and an error message.
function _M.set_property_setter(setter)
if type(setter) ~= "function" then
error("setter must be a function", 2)
end

local r = get_request()
if not r then
error("no request found", 2)
end

_M.property_setter = setter

local rc = C.ngx_http_wasm_ffi_enable_property_setter(r)
if rc ~= FFI_OK then
return nil, "could not set property setter"
end

return true
end


---
-- Define a getter function for host-managed properties.
--
-- @param getter The getter function is the handler for resolving properties.
-- Its type signature is `function(string): boolean, string, boolean`,
-- where the input is the property key and the results are:
-- * `truthy, value` - success, property value
-- * `truthy, value, truthy` - success, constant property value: further
-- requests to the same property during a request are cached by
-- ngx_wasm_module and do not invoke the Lua getter.
-- * `falsy` - property not found
-- * `falsy, err` - failure, error message
-- @return true on success setting the getter, or nil and an error message.
function _M.set_property_getter(getter)
if type(getter) ~= "function" then
error("getter must be a function", 2)
end

local r = get_request()
if not r then
error("no request found", 2)
end

_M.property_getter = getter

local rc = C.ngx_http_wasm_ffi_enable_property_getter(r)
if rc ~= FFI_OK then
return nil, "could not set property getter"
end

return true
end


return _M
104 changes: 62 additions & 42 deletions src/common/lua/ngx_wasm_lua.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#ifndef DDEBUG
#define DDEBUG 0
#define DDEBUG 1
#endif
#include "ddebug.h"

Expand Down Expand Up @@ -113,6 +113,56 @@ ngx_wasm_lua_thread_destroy(ngx_wasm_lua_ctx_t *lctx)
}


static ngx_int_t
ngx_wasm_lua_load_code(ngx_wasm_lua_ctx_t *lctx,
const char *tag, const char *src,
ngx_wasm_subsys_env_t *env)
{
ngx_int_t rc;

lctx->code = src;
lctx->code_len = ngx_strlen(src);
lctx->cache_key = ngx_wasm_lua_thread_cache_key(lctx->pool,
tag,
(u_char *) lctx->code,
lctx->code_len);
if (lctx->cache_key == NULL) {
return NGX_ERROR;
}

/* load code */

switch (env->subsys->kind) {
#if (NGX_WASM_HTTP)
case NGX_WASM_SUBSYS_HTTP:
rc = ngx_http_lua_cache_loadbuffer(lctx->log,
lctx->L,
(u_char *) lctx->code,
lctx->code_len,
&lctx->code_ref,
lctx->cache_key,
tag);
break;
#endif
#if (NGX_WASM_STREAM)
case NGX_WASM_SUBSYS_STREAM:
rc = ngx_stream_lua_cache_loadbuffer(lctx->log,
lctx->L,
(u_char *) lctx->code,
lctx->code_len,
lctx->cache_key,
tag);
break;
#endif
default:
ngx_wasm_assert(0);
return NGX_ERROR;
}

return rc;
}


ngx_wasm_lua_ctx_t *
ngx_wasm_lua_thread_new(const char *tag, const char *src,
ngx_wasm_subsys_env_t *env, ngx_log_t *log, void *data,
Expand Down Expand Up @@ -155,6 +205,9 @@ ngx_wasm_lua_thread_new(const char *tag, const char *src,

lctx->L = ngx_http_lua_get_lua_vm(r, NULL);
lctx->co = ngx_http_lua_new_thread(r, lctx->L, &lctx->co_ref);

ngx_http_lua_set_req(lctx->co, r);

break;
}
#endif
Expand All @@ -166,6 +219,9 @@ ngx_wasm_lua_thread_new(const char *tag, const char *src,

lctx->L = ngx_stream_lua_get_lua_vm(sr, NULL);
lctx->co = ngx_stream_lua_new_thread(sr, lctx->L, lctx->co_ref);

ngx_stream_lua_set_req(lctx->co, sr);

break;
}
#endif
Expand All @@ -183,47 +239,11 @@ ngx_wasm_lua_thread_new(const char *tag, const char *src,

/* code */

lctx->code = src;
lctx->code_len = ngx_strlen(src);
lctx->cache_key = ngx_wasm_lua_thread_cache_key(lctx->pool,
tag,
(u_char *) lctx->code,
lctx->code_len);
if (lctx->cache_key == NULL) {
goto error;
}

/* load code */

switch (env->subsys->kind) {
#if (NGX_WASM_HTTP)
case NGX_WASM_SUBSYS_HTTP:
rc = ngx_http_lua_cache_loadbuffer(lctx->log,
lctx->L,
(u_char *) lctx->code,
lctx->code_len,
&lctx->code_ref,
lctx->cache_key,
tag);
break;
#endif
#if (NGX_WASM_STREAM)
case NGX_WASM_SUBSYS_STREAM:
rc = ngx_stream_lua_cache_loadbuffer(lctx->log,
lctx->L,
(u_char *) lctx->code,
lctx->code_len,
lctx->cache_key,
tag);
break;
#endif
default:
ngx_wasm_assert(0);
goto error;
}

if (rc != NGX_OK) {
goto error;
if (src) {
rc = ngx_wasm_lua_load_code(lctx, tag, src, env);
if (rc != NGX_OK) {
goto error;
}
}

/* move code closure to new coroutine */
Expand Down
Loading