diff --git a/src/common/proxy_wasm/ngx_proxy_wasm.c b/src/common/proxy_wasm/ngx_proxy_wasm.c index c2359216f..66c694b48 100644 --- a/src/common/proxy_wasm/ngx_proxy_wasm.c +++ b/src/common/proxy_wasm/ngx_proxy_wasm.c @@ -839,6 +839,9 @@ ngx_proxy_wasm_run_step(ngx_proxy_wasm_exec_t *pwexec, case NGX_PROXY_WASM_STEP_DISPATCH_RESPONSE: rc = filter->subsystem->resume(pwexec, step, &action); break; + case NGX_PROXY_WASM_STEP_FOREIGN_CALLBACK: + rc = filter->subsystem->resume(pwexec, step, &action); + break; case NGX_PROXY_WASM_STEP_TICK: pwexec->in_tick = 1; rc = ngx_proxy_wasm_on_tick(pwexec); @@ -927,6 +930,45 @@ ngx_proxy_wasm_dispatch_calls_cancel(ngx_proxy_wasm_exec_t *pwexec) } +ngx_uint_t +ngx_proxy_wasm_foreign_callbacks_total(ngx_proxy_wasm_exec_t *pwexec) +{ + ngx_queue_t *q; + ngx_uint_t n = 0; + + for (q = ngx_queue_head(&pwexec->fcallbacks); + q != ngx_queue_sentinel(&pwexec->fcallbacks); + q = ngx_queue_next(q), n++) { /* void */ } + + dd("n: %ld", n); + + return n; +} + + +void +ngx_proxy_wasm_foreign_callbacks_cancel(ngx_proxy_wasm_exec_t *pwexec) +{ +#ifdef NGX_WASM_HTTP + ngx_queue_t *q; + ngx_proxy_wasm_foreign_cb_t *cb; + + while (!ngx_queue_empty(&pwexec->fcallbacks)) { + q = ngx_queue_head(&pwexec->fcallbacks); + cb = ngx_queue_data(q, ngx_proxy_wasm_foreign_cb_t, q); + + ngx_log_debug1(NGX_LOG_DEBUG_ALL, pwexec->log, 0, + "proxy_wasm foreign function callback cancelled" + " (callback: %p)", cb); + + ngx_queue_remove(&cb->q); + + ngx_proxy_wasm_foreign_callback_destroy(cb); + } +#endif +} + + /* host handlers */ @@ -1263,6 +1305,7 @@ ngx_proxy_wasm_create_context(ngx_proxy_wasm_filter_t *filter, pwexec->store = ictx->store; ngx_queue_init(&pwexec->calls); + ngx_queue_init(&pwexec->fcallbacks); } else { if (in->ictx != ictx) { diff --git a/src/common/proxy_wasm/ngx_proxy_wasm.h b/src/common/proxy_wasm/ngx_proxy_wasm.h index 1d9c73981..53420fee7 100644 --- a/src/common/proxy_wasm/ngx_proxy_wasm.h +++ b/src/common/proxy_wasm/ngx_proxy_wasm.h @@ -78,6 +78,7 @@ typedef enum { NGX_PROXY_WASM_STEP_DONE, NGX_PROXY_WASM_STEP_TICK, NGX_PROXY_WASM_STEP_DISPATCH_RESPONSE, + NGX_PROXY_WASM_STEP_FOREIGN_CALLBACK, } ngx_proxy_wasm_step_e; @@ -124,7 +125,7 @@ typedef enum { NGX_PROXY_WASM_BUFFER_GRPC_RECEIVE_BUFFER = 5, NGX_PROXY_WASM_BUFFER_VM_CONFIGURATION = 6, NGX_PROXY_WASM_BUFFER_PLUGIN_CONFIGURATION = 7, - NGX_PROXY_WASM_BUFFER_CALL_DATA = 8, + NGX_PROXY_WASM_BUFFER_FOREIGN_FUNCTION_ARGUMENTS = 8, } ngx_proxy_wasm_buffer_type_e; @@ -147,6 +148,11 @@ typedef enum { } ngx_proxy_wasm_metric_type_e; +typedef enum { + NGX_PROXY_WASM_FOREIGN_RESOLVE = 0, +} ngx_proxy_wasm_foreign_function_e; + + typedef struct ngx_proxy_wasm_ctx_s ngx_proxy_wasm_ctx_t; typedef struct ngx_proxy_wasm_filter_s ngx_proxy_wasm_filter_t; typedef struct ngx_proxy_wasm_exec_s ngx_proxy_wasm_exec_t; @@ -158,39 +164,50 @@ typedef ngx_str_t ngx_proxy_wasm_marshalled_map_t; typedef struct { - ngx_queue_t busy; - ngx_queue_t free; - ngx_queue_t sweep; - ngx_pool_t *pool; + ngx_queue_t busy; + ngx_queue_t free; + ngx_queue_t sweep; + ngx_pool_t *pool; } ngx_proxy_wasm_store_t; typedef struct { - ngx_str_t log_prefix; - ngx_log_t *orig_log; - ngx_proxy_wasm_exec_t *pwexec; + ngx_str_t log_prefix; + ngx_log_t *orig_log; + ngx_proxy_wasm_exec_t *pwexec; } ngx_proxy_wasm_log_ctx_t; +typedef struct { + ngx_queue_t q; + ngx_proxy_wasm_exec_t *pwexec; + ngx_http_wasm_req_ctx_t *rctx; + ngx_proxy_wasm_foreign_function_e fcode; + ngx_chain_t *args_out; +} ngx_proxy_wasm_foreign_cb_t; + + struct ngx_proxy_wasm_exec_s { - ngx_uint_t root_id; - ngx_uint_t id; - ngx_uint_t index; - ngx_uint_t tick_period; - ngx_rbtree_node_t node; - ngx_proxy_wasm_err_e ecode; - ngx_pool_t *pool; - ngx_log_t *log; - ngx_proxy_wasm_log_ctx_t log_ctx; - ngx_proxy_wasm_ctx_t *parent; - ngx_proxy_wasm_filter_t *filter; - ngx_proxy_wasm_instance_t *ictx; - ngx_proxy_wasm_store_t *store; - ngx_event_t *ev; + ngx_uint_t root_id; + ngx_uint_t id; + ngx_uint_t index; + ngx_uint_t tick_period; + ngx_rbtree_node_t node; + ngx_proxy_wasm_err_e ecode; + ngx_pool_t *pool; + ngx_log_t *log; + ngx_proxy_wasm_log_ctx_t log_ctx; + ngx_proxy_wasm_ctx_t *parent; + ngx_proxy_wasm_filter_t *filter; + ngx_proxy_wasm_instance_t *ictx; + ngx_proxy_wasm_store_t *store; + ngx_event_t *ev; #ifdef NGX_WASM_HTTP - ngx_http_proxy_wasm_dispatch_t *call; /* swap pointer for host functions */ + ngx_http_proxy_wasm_dispatch_t *call; /* swap pointer for host functions */ #endif - ngx_queue_t calls; + ngx_queue_t calls; + ngx_proxy_wasm_foreign_cb_t *fcallback; + ngx_queue_t fcallbacks; /* flags */ @@ -415,6 +432,9 @@ ngx_proxy_wasm_err_e ngx_proxy_wasm_run_step(ngx_proxy_wasm_exec_t *pwexec, ngx_proxy_wasm_step_e step); ngx_uint_t ngx_proxy_wasm_dispatch_calls_total(ngx_proxy_wasm_exec_t *pwexec); void ngx_proxy_wasm_dispatch_calls_cancel(ngx_proxy_wasm_exec_t *pwexec); +ngx_uint_t ngx_proxy_wasm_foreign_callbacks_total( + ngx_proxy_wasm_exec_t *pwexec); +void ngx_proxy_wasm_foreign_callbacks_cancel(ngx_proxy_wasm_exec_t *pwexec); /* host handlers */ diff --git a/src/common/proxy_wasm/ngx_proxy_wasm_host.c b/src/common/proxy_wasm/ngx_proxy_wasm_host.c index efde7b98f..85a4366cd 100644 --- a/src/common/proxy_wasm/ngx_proxy_wasm_host.c +++ b/src/common/proxy_wasm/ngx_proxy_wasm_host.c @@ -11,6 +11,7 @@ #include #include #include +#include #ifdef NGX_WASM_HTTP #include #endif @@ -29,16 +30,16 @@ static ngx_chain_t * ngx_proxy_wasm_get_buffer_helper(ngx_wavm_instance_t *instance, ngx_proxy_wasm_buffer_type_e buf_type, unsigned *none, char **trapmsg) { -#ifdef NGX_WASM_HTTP ngx_chain_t *cl; - ngx_http_wasm_req_ctx_t *rctx; - ngx_http_request_t *r; ngx_proxy_wasm_ctx_t *pwctx; ngx_proxy_wasm_exec_t *pwexec; +#ifdef NGX_WASM_HTTP + ngx_http_wasm_req_ctx_t *rctx; + ngx_http_request_t *r; +#endif pwexec = ngx_proxy_wasm_instance2pwexec(instance); pwctx = pwexec->parent; -#endif switch (buf_type) { @@ -146,6 +147,19 @@ ngx_proxy_wasm_get_buffer_helper(ngx_wavm_instance_t *instance, } #endif + case NGX_PROXY_WASM_BUFFER_FOREIGN_FUNCTION_ARGUMENTS: + { + ngx_proxy_wasm_foreign_cb_t *cb = pwexec->fcallback; + + if (cb == NULL) { + return NULL; + } + + ngx_wa_assert(cb->args_out); + + return cb->args_out; + } + default: ngx_wavm_log_error(NGX_LOG_WASM_NYI, instance->log, NULL, "NYI - get_buffer bad buf_type: %d", buf_type); @@ -1118,6 +1132,14 @@ ngx_proxy_wasm_hfuncs_send_local_response(ngx_wavm_instance_t *instance, ngx_proxy_wasm_dispatch_calls_cancel(pwexec); } + if (ngx_proxy_wasm_foreign_callbacks_total(pwexec)) { + ngx_proxy_wasm_log_error(NGX_LOG_NOTICE, pwexec->log, 0, + "local response produced, cancelling " + "pending foreign function callbacks"); + + ngx_proxy_wasm_foreign_callbacks_cancel(pwexec); + } + break; case NGX_ERROR: @@ -1807,7 +1829,309 @@ ngx_proxy_wasm_hfuncs_increment_metric(ngx_wavm_instance_t *instance, /* custom extension points */ -/* NYI */ + + +void +ngx_proxy_wasm_foreign_callback_destroy(ngx_proxy_wasm_foreign_cb_t *cb) +{ + + ngx_pfree(cb->pwexec->pool, cb); +} + + +static ngx_proxy_wasm_foreign_cb_t * +ngx_proxy_wasm_foreign_callback_alloc(ngx_proxy_wasm_exec_t *pwexec) +{ + ngx_proxy_wasm_foreign_cb_t *cb; + + cb = ngx_palloc(pwexec->pool, sizeof(ngx_proxy_wasm_foreign_cb_t)); + cb->pwexec = pwexec; + + return cb; +} + + +static void +ngx_proxy_wasm_foreign_callback(ngx_proxy_wasm_foreign_cb_t *cb) +{ + ngx_proxy_wasm_exec_t *pwexec = cb->pwexec; + ngx_proxy_wasm_err_e ecode = NGX_PROXY_WASM_ERR_NONE; + ngx_proxy_wasm_step_e step = pwexec->parent->step; + + ngx_queue_remove(&cb->q); + pwexec->fcallback = cb; + +#ifdef NGX_WASM_HTTP + pwexec->parent->phase = ngx_wasm_phase_lookup(&ngx_http_wasm_subsystem, + NGX_WASM_BACKGROUND_PHASE); +#endif + + ecode = ngx_proxy_wasm_run_step(pwexec, + NGX_PROXY_WASM_STEP_FOREIGN_CALLBACK); + if (ecode != NGX_PROXY_WASM_ERR_NONE) { + /* TODO: error handling */ + } + + pwexec->parent->step = step; + pwexec->fcallback = NULL; + + if (ngx_proxy_wasm_foreign_callbacks_total(pwexec)) { + ngx_log_debug0(NGX_LOG_DEBUG_WASM, pwexec->log, 0, + "proxy_wasm more foreign function callbacks pending..."); + + ngx_wasm_yield(&cb->rctx->env); + ngx_proxy_wasm_ctx_set_next_action(pwexec->parent, + NGX_PROXY_WASM_ACTION_PAUSE); + + } else { + ngx_log_debug0(NGX_LOG_DEBUG_WASM, pwexec->log, 0, + "proxy_wasm last foreign function callback handled"); + + ngx_wasm_continue(&cb->rctx->env); + ngx_proxy_wasm_ctx_set_next_action(pwexec->parent, + NGX_PROXY_WASM_ACTION_CONTINUE); + + /* resume current step if unfinished */ + ngx_proxy_wasm_resume(pwexec->parent, pwexec->parent->phase, step); + } + + ngx_proxy_wasm_foreign_callback_destroy(cb); +} + + +static ngx_int_t +ngx_proxy_wasm_foreign_callback_buffer_create(ngx_proxy_wasm_foreign_cb_t *cb, + size_t size) +{ + ngx_buf_t *b; + ngx_chain_t *cl; + ngx_proxy_wasm_exec_t *pwexec = cb->pwexec; + + ngx_wa_assert(pwexec); + ngx_wa_assert(size); + + cl = ngx_alloc_chain_link(pwexec->pool); + if (cl == NULL) { + return NGX_ERROR; + } + + /* TODO: if size exceeds a threshold, split allocation into N buffers */ + + b = ngx_create_temp_buf(pwexec->pool, size); + if (b == NULL) { + return NGX_ERROR; + } + + cl->buf = b; + cl->next = NULL; + + cb->args_out = cl; + + return NGX_OK; +} + + +static ngx_int_t +ngx_proxy_wasm_foreign_callback_buffer_write(ngx_proxy_wasm_foreign_cb_t *cb, + ngx_str_t *data) +{ + size_t b_size; + ngx_buf_t *b = cb->args_out->buf; + + b_size = b->end - b->start; + + ngx_wa_assert(data->len <= b_size); + + if (data->len <= b_size) { + b->last = ngx_cpymem(b->last, data->data, data->len); + return NGX_OK; + } + + /* TODO: data->len > b_size */ + + return NGX_ERROR; +} + + +static void +ngx_proxy_wasm_hfuncs_resolve_lua_handler(ngx_resolver_ctx_t *rslv_ctx) +{ + u_char *p; + ngx_str_t args; + ngx_wasm_lua_ctx_t *lctx; + ngx_wasm_socket_tcp_t *sock; + ngx_proxy_wasm_foreign_cb_t *cb; + u_short sa_family = AF_INET; + static size_t ipv6_len = 16; + u_char buf[rslv_ctx->name.len + ipv6_len + 1]; + + sock = (ngx_wasm_socket_tcp_t *) rslv_ctx->data; + lctx = sock->lctx; + cb = (ngx_proxy_wasm_foreign_cb_t *) sock->data; + p = buf; + + ngx_memzero(buf, sizeof(buf)); + + switch (sa_family) { +#if (NGX_HAVE_INET6) + case AF_INET6: + struct sockaddr_in6 *sin6 = \ + (struct sockaddr_in6 *) rslv_ctx->addr.sockaddr; + + *(p++) = sizeof(struct in6_addr); + p = ngx_cpymem(p, &sin6->sin6_addr, sizeof(struct in6_addr)); + + break; +#endif + + default: /* AF_INET */ + struct sockaddr_in *sin = \ + (struct sockaddr_in *) rslv_ctx->addr.sockaddr; + + *(p++) = sizeof(struct in_addr); + p = ngx_cpymem(p, (u_char *) &sin->sin_addr, sizeof(struct in_addr)); + } + + p = ngx_cpymem(p, rslv_ctx->name.data, rslv_ctx->name.len); + args.data = buf; + args.len = p - buf; + + if (ngx_proxy_wasm_foreign_callback_buffer_create(cb, p - buf) != NGX_OK) { + goto error; + } + + if (ngx_proxy_wasm_foreign_callback_buffer_write(cb, &args) != NGX_OK) { + goto error; + } + + if (lctx->yielded) { + ngx_proxy_wasm_foreign_callback(cb); + } + +error: + + ngx_free(rslv_ctx); + ngx_pfree(cb->pwexec->pool, sock); +} + + +static ngx_int_t +ngx_proxy_wasm_hfuncs_resolve_lua(ngx_wavm_instance_t *instance, + ngx_http_wasm_req_ctx_t *rctx, ngx_str_t *fargs, ngx_wavm_ptr_t *ret_data, + int32_t *ret_size, wasm_val_t rets[]) +{ + size_t s; + ngx_int_t rc; + ngx_buf_t *b; + ngx_http_request_t *r; + ngx_resolver_ctx_t *rslv_ctx; + ngx_wasm_socket_tcp_t *sock; + ngx_proxy_wasm_exec_t *pwexec; + ngx_proxy_wasm_foreign_cb_t *cb; + ngx_wavm_ptr_t p = 0; + + pwexec = ngx_proxy_wasm_instance2pwexec(instance); + + cb = ngx_proxy_wasm_foreign_callback_alloc(pwexec); + if (cb == NULL) { + goto error; + } + + cb->fcode = NGX_PROXY_WASM_FOREIGN_RESOLVE; + + /* rctx or fake request */ + + if (rctx == NULL) { + if (ngx_http_wasm_create_fake_req_ctx(pwexec, &r, &cb->rctx) + != NGX_OK) + { + goto error; + } + + } else { + cb->rctx = rctx; + } + + sock = ngx_palloc(pwexec->pool, sizeof(ngx_wasm_socket_tcp_t)); + if (sock == NULL) { + goto error; + } + + sock->env = &cb->rctx->env; + sock->log = pwexec->log; + sock->pool = pwexec->pool; + sock->data = cb; + + rslv_ctx = ngx_alloc(sizeof(ngx_resolver_ctx_t), pwexec->log); + if (rslv_ctx == NULL) { + goto error; + } + + rslv_ctx->name.data = fargs->data; + rslv_ctx->name.len = fargs->len; + rslv_ctx->handler = ngx_proxy_wasm_hfuncs_resolve_lua_handler; + rslv_ctx->data = sock; + + rc = ngx_wasm_lua_resolver_resolve(rslv_ctx); + + switch (rc) { + case NGX_OK: + b = cb->args_out->buf; + s = *b->start; /* first byte is the length of the resolved address */ + + p = ngx_proxy_wasm_alloc(pwexec, s); + if (!ngx_wavm_memory_memcpy(instance->memory, p, b->start + 1, s)) + { + return ngx_proxy_wasm_result_invalid_mem(rets); + } + + *ret_data = p; + *ret_size = s; + + /* fall through */ + + case NGX_AGAIN: + ngx_queue_insert_head(&pwexec->fcallbacks, &cb->q); + return ngx_proxy_wasm_result_ok(rets); + + default: + break; + } + +error: + + return ngx_proxy_wasm_result_trap(pwexec, "failed resolving name", + rets, NGX_WAVM_ERROR); +} + + +static ngx_int_t +ngx_proxy_wasm_hfuncs_call_foreign_function(ngx_wavm_instance_t *instance, + wasm_val_t args[], wasm_val_t rets[]) +{ + ngx_str_t fname, fargs; + int32_t *ret_size; + ngx_wavm_ptr_t *ret_data = 0; + ngx_proxy_wasm_exec_t *pwexec = ngx_proxy_wasm_instance2pwexec(instance); + ngx_http_wasm_req_ctx_t *rctx = ngx_http_proxy_wasm_get_rctx(instance); + + fname.len = args[1].of.i32; + fname.data = NGX_WAVM_HOST_LIFT_SLICE(instance, args[0].of.i32, fname.len); + + fargs.len = args[3].of.i32; + fargs.data = NGX_WAVM_HOST_LIFT_SLICE(instance, args[2].of.i32, fargs.len); + + ret_data = NGX_WAVM_HOST_LIFT(instance, args[4].of.i32, ngx_wavm_ptr_t); + ret_size = NGX_WAVM_HOST_LIFT(instance, args[5].of.i32, int32_t); + + if (ngx_memcmp(fname.data, "resolve_name", fname.len) == 0) { + return ngx_proxy_wasm_hfuncs_resolve_lua(instance, rctx, &fargs, + ret_data, ret_size, rets); + } + + return ngx_proxy_wasm_result_trap(pwexec, "unknown foreign function", + rets, NGX_WAVM_ERROR); +} /* legacy */ @@ -2224,7 +2548,7 @@ static ngx_wavm_host_func_def_t ngx_proxy_wasm_hfuncs[] = { ngx_wavm_arity_i32x5, ngx_wavm_arity_i32 }, { ngx_string("proxy_call_foreign_function"), /* 0.2.0 && 0.2.1 */ - &ngx_proxy_wasm_hfuncs_nop, /* NYI */ + &ngx_proxy_wasm_hfuncs_call_foreign_function, ngx_wavm_arity_i32x6, ngx_wavm_arity_i32 }, diff --git a/src/common/proxy_wasm/ngx_proxy_wasm_host_lua.c b/src/common/proxy_wasm/ngx_proxy_wasm_host_lua.c new file mode 100644 index 000000000..e69de29bb diff --git a/src/common/proxy_wasm/ngx_proxy_wasm_util.c b/src/common/proxy_wasm/ngx_proxy_wasm_util.c index c99f5d255..11d3dd290 100644 --- a/src/common/proxy_wasm/ngx_proxy_wasm_util.c +++ b/src/common/proxy_wasm/ngx_proxy_wasm_util.c @@ -62,7 +62,7 @@ ngx_proxy_wasm_step_name(ngx_proxy_wasm_step_e step) ngx_str_t *name; ngx_wa_assert(step); - ngx_wa_assert(step <= NGX_PROXY_WASM_STEP_DISPATCH_RESPONSE); + ngx_wa_assert(step <= NGX_PROXY_WASM_STEP_FOREIGN_CALLBACK); name = &ngx_proxy_wasm_steplist[step]; diff --git a/src/http/proxy_wasm/ngx_http_proxy_wasm.c b/src/http/proxy_wasm/ngx_http_proxy_wasm.c index d8f809116..9a69c31d5 100644 --- a/src/http/proxy_wasm/ngx_http_proxy_wasm.c +++ b/src/http/proxy_wasm/ngx_http_proxy_wasm.c @@ -351,6 +351,32 @@ ngx_http_proxy_wasm_on_dispatch_response(ngx_proxy_wasm_exec_t *pwexec) } +static ngx_int_t +ngx_http_proxy_wasm_on_foreign_function(ngx_proxy_wasm_exec_t *pwexec) +{ + size_t args_len = 0; + ngx_int_t rc; + ngx_chain_t *cl; + ngx_proxy_wasm_filter_t *filter = pwexec->filter; + ngx_proxy_wasm_foreign_cb_t *cb = pwexec->fcallback; + ngx_http_wasm_req_ctx_t *rctx = cb->rctx; + + ngx_wasm_continue(&rctx->env); + + cl = cb->args_out; + if (cl) { + args_len = cl->buf->last - cl->buf->start; + } + + rc = ngx_wavm_instance_call_funcref(pwexec->ictx->instance, + filter->proxy_on_custom_callback, + NULL, pwexec->id, cb->fcode, + args_len); + + return rc; +} + + static ngx_int_t ngx_http_proxy_wasm_ecode(ngx_proxy_wasm_err_e ecode) { @@ -439,6 +465,9 @@ ngx_http_proxy_wasm_resume(ngx_proxy_wasm_exec_t *pwexec, case NGX_PROXY_WASM_STEP_DISPATCH_RESPONSE: rc = ngx_http_proxy_wasm_on_dispatch_response(pwexec); break; + case NGX_PROXY_WASM_STEP_FOREIGN_CALLBACK: + rc = ngx_http_proxy_wasm_on_foreign_function(pwexec); + break; default: ngx_proxy_wasm_log_error(NGX_LOG_WASM_NYI, pwexec->log, 0, "NYI - proxy-wasm step: %d", step); diff --git a/t/03-proxy_wasm/hfuncs/130-proxy_dispatch_http.t b/t/03-proxy_wasm/hfuncs/130-proxy_dispatch_http.t index 7356cd8a7..0842109d6 100644 --- a/t/03-proxy_wasm/hfuncs/130-proxy_dispatch_http.t +++ b/t/03-proxy_wasm/hfuncs/130-proxy_dispatch_http.t @@ -261,6 +261,7 @@ qq{ === TEST 15: proxy_wasm - dispatch_http_call() sanity (default resolver) +--- ONLY --- skip_eval: 4: defined $ENV{GITHUB_ACTIONS} --- timeout eval: $::ExtTimeout --- load_nginx_modules: ngx_http_echo_module @@ -273,7 +274,8 @@ qq{ } --- config location /t { - proxy_wasm hostcalls 'test=/t/dispatch_http_call \ + proxy_wasm hostcalls 'on=request_headers \ + test=/t/dispatch_http_call \ host=httpbin.org'; echo ok; } diff --git a/t/03-proxy_wasm/hfuncs/300-foreign_resolve.t b/t/03-proxy_wasm/hfuncs/300-foreign_resolve.t new file mode 100644 index 000000000..d2582ae7d --- /dev/null +++ b/t/03-proxy_wasm/hfuncs/300-foreign_resolve.t @@ -0,0 +1,26 @@ +# vim:set ft= ts=4 sts=4 sw=4 et fdm=marker: + +use strict; +use lib '.'; +use t::TestWasmX; + +our $ExtResolver = $t::TestWasmX::extresolver; +our $ExtTimeout = $t::TestWasmX::exttimeout; + +plan_tests(4); +run_tests(); + +__DATA__ + +=== TEST 1: proxy_wasm - call_foreign_function() resolve +--- wasm_modules: hostcalls +--- config + location /t { + proxy_wasm hostcalls 'test=/t/resolve \ + name=httpbin.org'; + } +--- error_log eval +qr/\[debug\] .*? wasm lua resolved "localhost" to "127\.0\.0\.1"/ +--- no_error_log +[error] +[crit] diff --git a/t/lib/Cargo.lock b/t/lib/Cargo.lock index 4e418ff3c..235da1e30 100644 --- a/t/lib/Cargo.lock +++ b/t/lib/Cargo.lock @@ -156,6 +156,12 @@ dependencies = [ "quote", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "failure" version = "0.1.8" @@ -171,6 +177,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" + [[package]] name = "getrandom" version = "0.2.15" @@ -207,6 +219,17 @@ dependencies = [ "allocator-api2", ] +[[package]] +name = "hashbrown" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + [[package]] name = "hex" version = "0.4.3" @@ -220,7 +243,7 @@ dependencies = [ "enum-utils", "http", "log", - "proxy-wasm 0.2.2", + "proxy-wasm 0.2.3-dev", "urlencoding", ] @@ -355,6 +378,14 @@ dependencies = [ "log", ] +[[package]] +name = "proxy-wasm" +version = "0.2.3-dev" +dependencies = [ + "hashbrown 0.15.1", + "log", +] + [[package]] name = "quote" version = "1.0.37" diff --git a/t/lib/proxy-wasm-tests/hostcalls/Cargo.toml b/t/lib/proxy-wasm-tests/hostcalls/Cargo.toml index dad9e5d85..5078c907a 100644 --- a/t/lib/proxy-wasm-tests/hostcalls/Cargo.toml +++ b/t/lib/proxy-wasm-tests/hostcalls/Cargo.toml @@ -8,7 +8,8 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -proxy-wasm = "0.2" +#proxy-wasm = "0.2" +proxy-wasm = { path = "/home/casimiro/KongHQ/proxy-wasm-rust-sdk-caio" } log = "0.4" http = "0.2" enum-utils = "0.1.2" diff --git a/t/lib/proxy-wasm-tests/hostcalls/src/filter.rs b/t/lib/proxy-wasm-tests/hostcalls/src/filter.rs index 9f771c645..9d3352706 100644 --- a/t/lib/proxy-wasm-tests/hostcalls/src/filter.rs +++ b/t/lib/proxy-wasm-tests/hostcalls/src/filter.rs @@ -1,7 +1,7 @@ use crate::{test_http::*, types::*}; use http::StatusCode; use log::*; -use proxy_wasm::{traits::*, types::*}; +use proxy_wasm::{traits::*, types::*, hostcalls::*}; impl Context for TestHttp { fn on_http_call_response( @@ -108,6 +108,23 @@ impl Context for TestHttp { self.resume_http_request() } + fn on_foreign_function(&mut self, function_id: u32, args_size: usize) { + info!("[hostcalls] on_foreign_function!"); + + let f: WasmxForeignFunction = unsafe { ::std::mem::transmute(function_id) }; + let args = get_buffer(BufferType::ForeignFunctionArguments, 0, args_size).unwrap(); + + match f { + WasmxForeignFunction::ResolveLua => { + match args { + Some(bytes) => info!("recieved: {:?}", bytes), + _ => info!("empty buffer") + } + } + _ => error!("unknown function_id"), + } + } + fn on_done(&mut self) -> bool { info!("[hostcalls] on_done"); diff --git a/t/lib/proxy-wasm-tests/hostcalls/src/types/mod.rs b/t/lib/proxy-wasm-tests/hostcalls/src/types/mod.rs index 315efbf9b..6e0f23124 100644 --- a/t/lib/proxy-wasm-tests/hostcalls/src/types/mod.rs +++ b/t/lib/proxy-wasm-tests/hostcalls/src/types/mod.rs @@ -16,6 +16,11 @@ pub enum TestPhase { Log, } +#[repr(u32)] +pub enum WasmxForeignFunction { + ResolveLua = 0, +} + pub trait TestContext { fn get_config(&self, name: &str) -> Option<&str>; fn get_metrics_mapping(&self) -> &BTreeMap; diff --git a/t/lib/proxy-wasm-tests/hostcalls/src/types/test_http.rs b/t/lib/proxy-wasm-tests/hostcalls/src/types/test_http.rs index 6601ea288..f9f2554e4 100644 --- a/t/lib/proxy-wasm-tests/hostcalls/src/types/test_http.rs +++ b/t/lib/proxy-wasm-tests/hostcalls/src/types/test_http.rs @@ -150,6 +150,21 @@ impl TestHttp { get_metric(h_id).unwrap(); } + /* foreign functions */ + "/t/resolve" => { + let name = self + .config + .get("name") + .map(|x| x.as_str()) + .expect("expected a name argument"); + + if let Ok(data) = call_foreign_function("resolve", Some(name.as_bytes())) { + // let ip: Vec = data.unwrap().iter().map(|&x| x as u32).collect(); + // info!("resolved {} to {:?}", name, ip); + } + return Action::Pause; + } + /* errors */ "/t/trap" => panic!("custom trap"), "/t/error/get_response_body" => {