From 0ef97950bebe9d1044ebe88b44b96bc180630271 Mon Sep 17 00:00:00 2001 From: Caio Ramos Casimiro Date: Sun, 17 Nov 2024 14:18:04 +0000 Subject: [PATCH 1/5] misc(*) extract fake wasm_req_ctx into its own function --- src/http/ngx_http_wasm_util.c | 35 +++++++++++++++++-- src/http/ngx_http_wasm_util.h | 4 +-- .../proxy_wasm/ngx_http_proxy_wasm_dispatch.c | 22 ++---------- 3 files changed, 37 insertions(+), 24 deletions(-) diff --git a/src/http/ngx_http_wasm_util.c b/src/http/ngx_http_wasm_util.c index fed8a36da..83940690a 100644 --- a/src/http/ngx_http_wasm_util.c +++ b/src/http/ngx_http_wasm_util.c @@ -632,7 +632,7 @@ ngx_http_wasm_init_fake_connection(ngx_connection_t *c) } -ngx_connection_t * +static ngx_connection_t * ngx_http_wasm_create_fake_connection(ngx_pool_t *pool) { #if 0 @@ -725,7 +725,7 @@ ngx_http_wasm_cleanup_nop(void *data) #endif -ngx_http_request_t * +static ngx_http_request_t * ngx_http_wasm_create_fake_request(ngx_connection_t *c) { ngx_http_request_t *r; @@ -990,3 +990,34 @@ ngx_http_wasm_free_fake_request(ngx_http_request_t *r) ngx_pfree(r->pool, r); #endif } + + +ngx_int_t +ngx_http_wasm_create_fake_rctx(ngx_proxy_wasm_exec_t *pwexec, + ngx_http_request_t **r_out, ngx_http_wasm_req_ctx_t **out) +{ + ngx_connection_t *c; + + ngx_wa_assert(pwexec->root_id == NGX_PROXY_WASM_ROOT_CTX_ID); + ngx_wa_assert(pwexec->parent->id == NGX_PROXY_WASM_ROOT_CTX_ID); + + c = ngx_http_wasm_create_fake_connection(pwexec->pool); + if (c == NULL) { + return NGX_ERROR; + } + + *r_out = ngx_http_wasm_create_fake_request(c); + if (*r_out == NULL) { + return NGX_ERROR; + } + + if (ngx_http_wasm_rctx(*r_out, out) != NGX_OK) { + return NGX_ERROR; + } + + ngx_wa_assert((*r_out)->pool == (*out)->pool); + + (*out)->data = pwexec->parent; + + return NGX_OK; +} diff --git a/src/http/ngx_http_wasm_util.h b/src/http/ngx_http_wasm_util.h index f9945bef9..83a4b90af 100644 --- a/src/http/ngx_http_wasm_util.h +++ b/src/http/ngx_http_wasm_util.h @@ -27,9 +27,9 @@ ngx_int_t ngx_http_wasm_ops_add_filter(ngx_wasm_ops_plan_t *plan, ngx_str_t *name, ngx_str_t *config, ngx_wavm_t *vm); /* fake requests */ -ngx_connection_t *ngx_http_wasm_create_fake_connection(ngx_pool_t *pool); -ngx_http_request_t *ngx_http_wasm_create_fake_request(ngx_connection_t *c); void ngx_http_wasm_finalize_fake_request(ngx_http_request_t *r, ngx_int_t rc); +ngx_int_t ngx_http_wasm_create_fake_rctx(ngx_proxy_wasm_exec_t *pwexec, + ngx_http_request_t **r_out, ngx_http_wasm_req_ctx_t **out); #endif /* _NGX_HTTP_WASM_UTIL_H_INCLUDED_ */ diff --git a/src/http/proxy_wasm/ngx_http_proxy_wasm_dispatch.c b/src/http/proxy_wasm/ngx_http_proxy_wasm_dispatch.c index b0befea6a..220aaf1ee 100644 --- a/src/http/proxy_wasm/ngx_http_proxy_wasm_dispatch.c +++ b/src/http/proxy_wasm/ngx_http_proxy_wasm_dispatch.c @@ -199,7 +199,6 @@ ngx_http_proxy_wasm_dispatch(ngx_proxy_wasm_exec_t *pwexec, #if 0 ngx_pool_cleanup_t *cln; #endif - ngx_connection_t *c; ngx_http_request_t *r; ngx_http_wasm_req_ctx_t *rctxp = NULL; ngx_http_proxy_wasm_dispatch_t *call = NULL; @@ -209,27 +208,10 @@ ngx_http_proxy_wasm_dispatch(ngx_proxy_wasm_exec_t *pwexec, /* rctx or fake request */ if (rctx == NULL) { - ngx_wa_assert(pwexec->root_id == NGX_PROXY_WASM_ROOT_CTX_ID); - ngx_wa_assert(pwexec->parent->id == NGX_PROXY_WASM_ROOT_CTX_ID); - - c = ngx_http_wasm_create_fake_connection(pwexec->pool); - if (c == NULL) { - return NULL; - } - - r = ngx_http_wasm_create_fake_request(c); - if (r == NULL) { - return NULL; - } - - if (ngx_http_wasm_rctx(r, &rctxp) != NGX_OK) { - return NULL; + if (ngx_http_wasm_create_fake_rctx(pwexec, &r, &rctxp) != NGX_OK) { + goto error; } - ngx_wa_assert(r->pool == rctxp->pool); - - rctxp->data = pwexec->parent; - } else { r = rctx->r; } From 09fece2044788a188b49221d769adb9ed07f154a Mon Sep 17 00:00:00 2001 From: Caio Ramos Casimiro Date: Mon, 25 Nov 2024 12:07:00 +0000 Subject: [PATCH 2/5] misc(proxy-wasm) rename `call` to `dispatch_call` Making struct member names explict to distinguish them from the upcoming Proxy-Wasm foreign call support. --- src/common/proxy_wasm/ngx_proxy_wasm.c | 20 +++++------ src/common/proxy_wasm/ngx_proxy_wasm.h | 32 ++++++++--------- src/common/proxy_wasm/ngx_proxy_wasm_host.c | 2 +- src/common/proxy_wasm/ngx_proxy_wasm_maps.c | 35 ++++++++++--------- src/http/proxy_wasm/ngx_http_proxy_wasm.c | 2 +- .../proxy_wasm/ngx_http_proxy_wasm_dispatch.c | 8 ++--- 6 files changed, 51 insertions(+), 48 deletions(-) diff --git a/src/common/proxy_wasm/ngx_proxy_wasm.c b/src/common/proxy_wasm/ngx_proxy_wasm.c index ce167ecba..f2eada95e 100644 --- a/src/common/proxy_wasm/ngx_proxy_wasm.c +++ b/src/common/proxy_wasm/ngx_proxy_wasm.c @@ -440,8 +440,8 @@ ngx_proxy_wasm_ctx_destroy(ngx_proxy_wasm_ctx_t *pwctx) ngx_pfree(pwctx->pool, pwctx->root_id.data); } - if (pwctx->call_status.data) { - ngx_pfree(pwctx->pool, pwctx->call_status.data); + if (pwctx->dispatch_call_status.data) { + ngx_pfree(pwctx->pool, pwctx->dispatch_call_status.data); } if (pwctx->response_status.data) { @@ -894,8 +894,8 @@ ngx_proxy_wasm_dispatch_calls_total(ngx_proxy_wasm_exec_t *pwexec) ngx_queue_t *q; ngx_uint_t n = 0; - for (q = ngx_queue_head(&pwexec->calls); - q != ngx_queue_sentinel(&pwexec->calls); + for (q = ngx_queue_head(&pwexec->dispatch_calls); + q != ngx_queue_sentinel(&pwexec->dispatch_calls); q = ngx_queue_next(q), n++) { /* void */ } dd("n: %ld", n); @@ -911,8 +911,8 @@ ngx_proxy_wasm_dispatch_calls_cancel(ngx_proxy_wasm_exec_t *pwexec) ngx_queue_t *q; ngx_http_proxy_wasm_dispatch_t *call; - while (!ngx_queue_empty(&pwexec->calls)) { - q = ngx_queue_head(&pwexec->calls); + while (!ngx_queue_empty(&pwexec->dispatch_calls)) { + q = ngx_queue_head(&pwexec->dispatch_calls); call = ngx_queue_data(q, ngx_http_proxy_wasm_dispatch_t, q); ngx_log_debug1(NGX_LOG_DEBUG_ALL, pwexec->log, 0, @@ -1145,7 +1145,7 @@ ngx_proxy_wasm_create_context(ngx_proxy_wasm_filter_t *filter, rexec->filter = filter; rexec->ictx = ictx; - ngx_queue_init(&rexec->calls); + ngx_queue_init(&rexec->dispatch_calls); log = filter->log; @@ -1262,7 +1262,7 @@ ngx_proxy_wasm_create_context(ngx_proxy_wasm_filter_t *filter, pwexec->ictx = ictx; pwexec->store = ictx->store; - ngx_queue_init(&pwexec->calls); + ngx_queue_init(&pwexec->dispatch_calls); } else { if (in->ictx != ictx) { @@ -1389,11 +1389,11 @@ ngx_proxy_wasm_on_done(ngx_proxy_wasm_exec_t *pwexec) #if 0 #ifdef NGX_WASM_HTTP - call = pwexec->call; + call = pwexec->dispatch_call; if (call) { ngx_http_proxy_wasm_dispatch_destroy(call); - pwexec->call = NULL; + pwexec->dispatch_call = NULL; } #endif #endif diff --git a/src/common/proxy_wasm/ngx_proxy_wasm.h b/src/common/proxy_wasm/ngx_proxy_wasm.h index 1d9c73981..6da1bc71f 100644 --- a/src/common/proxy_wasm/ngx_proxy_wasm.h +++ b/src/common/proxy_wasm/ngx_proxy_wasm.h @@ -188,9 +188,9 @@ struct ngx_proxy_wasm_exec_s { 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 *dispatch_call; /* swap pointer for host functions */ #endif - ngx_queue_t calls; + ngx_queue_t dispatch_calls; /* flags */ @@ -231,19 +231,19 @@ struct ngx_proxy_wasm_ctx_s { size_t req_body_len; ngx_str_t authority; ngx_str_t scheme; - ngx_str_t path; /* r->uri + r->args */ - ngx_str_t start_time; /* r->start_sec + r->start_msec */ - ngx_str_t upstream_address; /* 1st part of ngx.upstream_addr */ - ngx_str_t upstream_port; /* 2nd part of ngx.upstsream_addr */ - ngx_str_t connection_id; /* r->connection->number */ - ngx_str_t mtls; /* ngx.https && ngx.ssl_client_verify */ - ngx_str_t root_id; /* pwexec->root_id */ - ngx_str_t call_status; /* dispatch response status */ - ngx_str_t response_status; /* response status */ + ngx_str_t path; /* r->uri + r->args */ + ngx_str_t start_time; /* r->start_sec + r->start_msec */ + ngx_str_t upstream_address; /* 1st part of ngx.upstream_addr */ + ngx_str_t upstream_port; /* 2nd part of ngx.upstsream_addr */ + ngx_str_t connection_id; /* r->connection->number */ + ngx_str_t mtls; /* ngx.https && ngx.ssl_client_verify */ + ngx_str_t root_id; /* pwexec->root_id */ + ngx_str_t dispatch_call_status; /* dispatch response status */ + ngx_str_t response_status; /* response status */ #if (NGX_DEBUG) - ngx_str_t worker_id; /* ngx_worker */ + ngx_str_t worker_id; /* ngx_worker */ #endif - ngx_uint_t call_code; + ngx_uint_t dispatch_call_code; ngx_uint_t response_code; /* host properties */ @@ -258,9 +258,9 @@ struct ngx_proxy_wasm_ctx_s { /* flags */ - unsigned main:1; /* r->main */ - unsigned init:1; /* can be utilized (has no filters) */ - unsigned ready:1; /* filters chain ready */ + unsigned main:1; /* r->main */ + unsigned init:1; /* can be utilized (has no filters) */ + unsigned ready:1; /* filters chain ready */ unsigned req_headers_in_access:1; }; diff --git a/src/common/proxy_wasm/ngx_proxy_wasm_host.c b/src/common/proxy_wasm/ngx_proxy_wasm_host.c index efde7b98f..3151312d7 100644 --- a/src/common/proxy_wasm/ngx_proxy_wasm_host.c +++ b/src/common/proxy_wasm/ngx_proxy_wasm_host.c @@ -127,7 +127,7 @@ ngx_proxy_wasm_get_buffer_helper(ngx_wavm_instance_t *instance, /* get */ - call = pwexec->call; + call = pwexec->dispatch_call; if (call == NULL) { return NULL; } diff --git a/src/common/proxy_wasm/ngx_proxy_wasm_maps.c b/src/common/proxy_wasm/ngx_proxy_wasm_maps.c index 1a81aa00a..856040da8 100644 --- a/src/common/proxy_wasm/ngx_proxy_wasm_maps.c +++ b/src/common/proxy_wasm/ngx_proxy_wasm_maps.c @@ -119,7 +119,7 @@ ngx_proxy_wasm_maps_get_map(ngx_wavm_instance_t *instance, case NGX_PROXY_WASM_MAP_HTTP_CALL_RESPONSE_HEADERS: pwexec = ngx_proxy_wasm_instance2pwexec(instance); - call = pwexec->call; + call = pwexec->dispatch_call; if (call == NULL) { return NULL; } @@ -782,7 +782,7 @@ ngx_proxy_wasm_maps_get_dispatch_response_status(ngx_wavm_instance_t *instance, pwexec = ngx_proxy_wasm_instance2pwexec(instance); pwctx = pwexec->parent; - call = pwexec->call; + call = pwexec->dispatch_call; reader = &call->http_reader; /* status */ @@ -799,31 +799,34 @@ ngx_proxy_wasm_maps_get_dispatch_response_status(ngx_wavm_instance_t *instance, /* update cached value */ - if (status != pwctx->call_code) { - pwctx->call_code = status; + if (status != pwctx->dispatch_call_code) { + pwctx->dispatch_call_code = status; - if (pwctx->call_status.len) { - ngx_pfree(pwctx->pool, pwctx->call_status.data); - pwctx->call_status.len = 0; + if (pwctx->dispatch_call_status.len) { + ngx_pfree(pwctx->pool, pwctx->dispatch_call_status.data); + pwctx->dispatch_call_status.len = 0; } } /* format */ - if (!pwctx->call_status.len) { - pwctx->call_status.data = ngx_pnalloc(pwctx->pool, NGX_INT_T_LEN); - if (pwctx->call_status.data == NULL) { + if (!pwctx->dispatch_call_status.len) { + pwctx->dispatch_call_status.data = ngx_pnalloc(pwctx->pool, + NGX_INT_T_LEN); + if (pwctx->dispatch_call_status.data == NULL) { return NULL; } - pwctx->call_status.len = ngx_sprintf(pwctx->call_status.data, "%03ui", - pwctx->call_code) - - pwctx->call_status.data; + pwctx->dispatch_call_status.len = ngx_sprintf( + pwctx->dispatch_call_status.data, + "%03ui", + pwctx->dispatch_call_code) + - pwctx->dispatch_call_status.data; } - ngx_wa_assert(pwctx->call_status.len); + ngx_wa_assert(pwctx->dispatch_call_status.len); - return &pwctx->call_status; + return &pwctx->dispatch_call_status; } @@ -838,7 +841,7 @@ ngx_proxy_wasm_maps_get_dispatch_status(ngx_wavm_instance_t *instance, ngx_wa_assert(map_type == NGX_PROXY_WASM_MAP_HTTP_CALL_RESPONSE_HEADERS); pwexec = ngx_proxy_wasm_instance2pwexec(instance); - call = pwexec->call; + call = pwexec->dispatch_call; sock = &call->sock; return ngx_wasm_socket_tcp_status_strerror(sock->status); diff --git a/src/http/proxy_wasm/ngx_http_proxy_wasm.c b/src/http/proxy_wasm/ngx_http_proxy_wasm.c index 463aea2b7..d44dafc4d 100644 --- a/src/http/proxy_wasm/ngx_http_proxy_wasm.c +++ b/src/http/proxy_wasm/ngx_http_proxy_wasm.c @@ -316,7 +316,7 @@ ngx_http_proxy_wasm_on_dispatch_response(ngx_proxy_wasm_exec_t *pwexec) ngx_uint_t n_headers, body_len; ngx_list_part_t *part; ngx_proxy_wasm_filter_t *filter = pwexec->filter; - ngx_http_proxy_wasm_dispatch_t *call = pwexec->call; + ngx_http_proxy_wasm_dispatch_t *call = pwexec->dispatch_call; ngx_http_wasm_req_ctx_t *rctx = call->rctx; n_headers = 0; diff --git a/src/http/proxy_wasm/ngx_http_proxy_wasm_dispatch.c b/src/http/proxy_wasm/ngx_http_proxy_wasm_dispatch.c index 220aaf1ee..3c8a6734e 100644 --- a/src/http/proxy_wasm/ngx_http_proxy_wasm_dispatch.c +++ b/src/http/proxy_wasm/ngx_http_proxy_wasm_dispatch.c @@ -63,7 +63,7 @@ invoke_on_http_dispatch_response(ngx_proxy_wasm_exec_t *pwexec, * Set current call for subsequent call detection after the step * (no yielding). */ - pwexec->call = call; + pwexec->dispatch_call = call; /** * Save step: ngx_proxy_wasm_run_step will set pwctx->step (for host @@ -92,7 +92,7 @@ invoke_on_http_dispatch_response(ngx_proxy_wasm_exec_t *pwexec, pwexec->parent->step = step; /* remove current call now that callback was invoked */ - pwexec->call = NULL; + pwexec->dispatch_call = NULL; return NGX_OK; } @@ -161,7 +161,7 @@ ngx_http_proxy_wasm_dispatch_err(ngx_http_proxy_wasm_dispatch_t *call, ngx_http_proxy_wasm_dispatch_destroy(call); - pwexec->call = NULL; + pwexec->dispatch_call = NULL; } @@ -430,7 +430,7 @@ ngx_http_proxy_wasm_dispatch(ngx_proxy_wasm_exec_t *pwexec, call->ev = ev; - ngx_queue_insert_head(&pwexec->calls, &call->q); + ngx_queue_insert_head(&pwexec->dispatch_calls, &call->q); ngx_proxy_wasm_ctx_set_next_action(pwctx, NGX_PROXY_WASM_ACTION_PAUSE); From f10965ea2067c2735c1e2fb8d92373f85b64f723 Mon Sep 17 00:00:00 2001 From: Caio Ramos Casimiro Date: Fri, 15 Nov 2024 12:54:20 +0000 Subject: [PATCH 3/5] wip --- config | 6 +- src/common/proxy_wasm/ngx_proxy_wasm.c | 59 ++-- src/common/proxy_wasm/ngx_proxy_wasm.h | 81 +++-- .../proxy_wasm/ngx_proxy_wasm_foreign_call.c | 305 ++++++++++++++++++ .../proxy_wasm/ngx_proxy_wasm_foreign_call.h | 32 ++ src/common/proxy_wasm/ngx_proxy_wasm_host.c | 58 +++- src/common/proxy_wasm/ngx_proxy_wasm_util.c | 5 +- src/http/ngx_http_wasm_util.c | 4 +- src/http/proxy_wasm/ngx_http_proxy_wasm.c | 32 ++ .../proxy_wasm/ngx_http_proxy_wasm_dispatch.c | 50 ++- .../proxy_wasm/ngx_http_proxy_wasm_dispatch.h | 1 - .../133-proxy_dispatch_http_edge_cases.t | 2 +- .../hfuncs/140-proxy_call_foreign_function.t | 41 +++ .../140-proxy_foreign_function_resolve_lua.t | 169 ++++++++++ .../hfuncs/foreign/001-resolve_lua.t | 188 +++++++++++ t/lib/Cargo.lock | 34 +- .../context-checks/src/hostcalls.rs | 28 +- .../context-checks/src/lib.rs | 1 + t/lib/proxy-wasm-tests/hostcalls/Cargo.toml | 3 +- .../proxy-wasm-tests/hostcalls/src/filter.rs | 35 +- .../hostcalls/src/foreign_callbacks/mod.rs | 18 ++ t/lib/proxy-wasm-tests/hostcalls/src/lib.rs | 39 ++- .../hostcalls/src/tests/mod.rs | 26 ++ .../hostcalls/src/types/mod.rs | 5 + .../hostcalls/src/types/test_http.rs | 21 ++ 25 files changed, 1165 insertions(+), 78 deletions(-) create mode 100644 src/common/proxy_wasm/ngx_proxy_wasm_foreign_call.c create mode 100644 src/common/proxy_wasm/ngx_proxy_wasm_foreign_call.h create mode 100644 t/03-proxy_wasm/hfuncs/140-proxy_call_foreign_function.t create mode 100644 t/03-proxy_wasm/hfuncs/contexts/140-proxy_foreign_function_resolve_lua.t create mode 100644 t/03-proxy_wasm/hfuncs/foreign/001-resolve_lua.t create mode 100644 t/lib/proxy-wasm-tests/hostcalls/src/foreign_callbacks/mod.rs diff --git a/config b/config index 62a2f0fc9..d03e03fe5 100644 --- a/config +++ b/config @@ -144,7 +144,8 @@ NGX_WASMX_DEPS="\ $ngx_addon_dir/src/common/metrics/ngx_wa_metrics.h \ $ngx_addon_dir/src/common/proxy_wasm/ngx_proxy_wasm.h \ $ngx_addon_dir/src/common/proxy_wasm/ngx_proxy_wasm_maps.h \ - $ngx_addon_dir/src/common/proxy_wasm/ngx_proxy_wasm_properties.h" + $ngx_addon_dir/src/common/proxy_wasm/ngx_proxy_wasm_properties.h \ + $ngx_addon_dir/src/common/proxy_wasm/ngx_proxy_wasm_foreign_call.h" NGX_WASMX_SRCS="\ $ngx_addon_dir/src/ngx_wasmx.c \ @@ -160,8 +161,9 @@ NGX_WASMX_SRCS="\ $ngx_addon_dir/src/common/proxy_wasm/ngx_proxy_wasm.c \ $ngx_addon_dir/src/common/proxy_wasm/ngx_proxy_wasm_host.c \ $ngx_addon_dir/src/common/proxy_wasm/ngx_proxy_wasm_maps.c \ + $ngx_addon_dir/src/common/proxy_wasm/ngx_proxy_wasm_util.c \ $ngx_addon_dir/src/common/proxy_wasm/ngx_proxy_wasm_properties.c \ - $ngx_addon_dir/src/common/proxy_wasm/ngx_proxy_wasm_util.c" + $ngx_addon_dir/src/common/proxy_wasm/ngx_proxy_wasm_foreign_call.c" # wasm diff --git a/src/common/proxy_wasm/ngx_proxy_wasm.c b/src/common/proxy_wasm/ngx_proxy_wasm.c index f2eada95e..6ea14d517 100644 --- a/src/common/proxy_wasm/ngx_proxy_wasm.c +++ b/src/common/proxy_wasm/ngx_proxy_wasm.c @@ -5,6 +5,7 @@ #include #include +#include #ifdef NGX_WASM_HTTP #include #endif @@ -839,6 +840,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); @@ -889,13 +893,13 @@ ngx_proxy_wasm_run_step(ngx_proxy_wasm_exec_t *pwexec, ngx_uint_t -ngx_proxy_wasm_dispatch_calls_total(ngx_proxy_wasm_exec_t *pwexec) +ngx_proxy_wasm_dispatch_ops_total(ngx_proxy_wasm_exec_t *pwexec) { ngx_queue_t *q; ngx_uint_t n = 0; - for (q = ngx_queue_head(&pwexec->dispatch_calls); - q != ngx_queue_sentinel(&pwexec->dispatch_calls); + for (q = ngx_queue_head(&pwexec->dispatch_ops); + q != ngx_queue_sentinel(&pwexec->dispatch_ops); q = ngx_queue_next(q), n++) { /* void */ } dd("n: %ld", n); @@ -905,25 +909,44 @@ 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_proxy_wasm_dispatch_ops_cancel(ngx_proxy_wasm_exec_t *pwexec) { -#ifdef NGX_WASM_HTTP - ngx_queue_t *q; - ngx_http_proxy_wasm_dispatch_t *call; + ngx_queue_t *q; + ngx_proxy_wasm_dispatch_op_t *dop; - while (!ngx_queue_empty(&pwexec->dispatch_calls)) { - q = ngx_queue_head(&pwexec->dispatch_calls); - call = ngx_queue_data(q, ngx_http_proxy_wasm_dispatch_t, q); + while (!ngx_queue_empty(&pwexec->dispatch_ops)) { + q = ngx_queue_head(&pwexec->dispatch_ops); + dop = ngx_queue_data(q, ngx_proxy_wasm_dispatch_op_t, q); - ngx_log_debug1(NGX_LOG_DEBUG_ALL, pwexec->log, 0, - "proxy_wasm http dispatch cancelled (dispatch: %p)", - call); +#if (NGX_DEBUG) + /* though valid, clang complains if prev/next pointers aren't checked */ - ngx_queue_remove(&call->q); + if (!dop->q.next || !dop->q.prev) { + return; + } +#endif - ngx_http_proxy_wasm_dispatch_destroy(call); - } + ngx_queue_remove(&dop->q); + + switch (dop->type) { +#ifdef NGX_WASM_HTTP + case NGX_PROXY_WASM_DISPATCH_HTTP_CALL: + ngx_log_debug1(NGX_LOG_DEBUG_ALL, pwexec->log, 0, + "proxy_wasm http dispatch cancelled (dispatch: %p)", + dop->call); + + ngx_http_proxy_wasm_dispatch_destroy(dop->call.http); + break; #endif + default: /* NGX_PROXY_WASM_DISPATCH_FOREIGN_CALL */ + ngx_log_debug1(NGX_LOG_DEBUG_ALL, pwexec->log, 0, + "proxy_wasm foreign function callback cancelled " + "(callback: %p)", dop->call); + + ngx_proxy_wasm_foreign_call_destroy(dop->call.foreign); + break; + } + } } @@ -1145,7 +1168,7 @@ ngx_proxy_wasm_create_context(ngx_proxy_wasm_filter_t *filter, rexec->filter = filter; rexec->ictx = ictx; - ngx_queue_init(&rexec->dispatch_calls); + ngx_queue_init(&rexec->dispatch_ops); log = filter->log; @@ -1262,7 +1285,7 @@ ngx_proxy_wasm_create_context(ngx_proxy_wasm_filter_t *filter, pwexec->ictx = ictx; pwexec->store = ictx->store; - ngx_queue_init(&pwexec->dispatch_calls); + ngx_queue_init(&pwexec->dispatch_ops); } 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 6da1bc71f..16ace108d 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_LUA = 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; @@ -154,43 +160,64 @@ typedef struct ngx_proxy_wasm_instance_s ngx_proxy_wasm_instance_t; #ifdef NGX_WASM_HTTP typedef struct ngx_http_proxy_wasm_dispatch_s ngx_http_proxy_wasm_dispatch_t; #endif +typedef struct ngx_proxy_wasm_foreign_call_s ngx_proxy_wasm_foreign_call_t; 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 enum { + NGX_PROXY_WASM_DISPATCH_HTTP_CALL, + NGX_PROXY_WASM_DISPATCH_FOREIGN_CALL, +} ngx_proxy_wasm_dispatch_op_e; + + +typedef struct { + ngx_queue_t q; /* stored by caller */ + ngx_proxy_wasm_dispatch_op_e type; + + union { +#ifdef NGX_WASM_HTTP + ngx_http_proxy_wasm_dispatch_t *http; +#endif + ngx_proxy_wasm_foreign_call_t *foreign; + } call; +} ngx_proxy_wasm_dispatch_op_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; + ngx_queue_t dispatch_ops; + ngx_proxy_wasm_foreign_call_t *foreign_call; /* swap pointer for host functions */ #ifdef NGX_WASM_HTTP - ngx_http_proxy_wasm_dispatch_t *dispatch_call; /* swap pointer for host functions */ + ngx_http_proxy_wasm_dispatch_t *dispatch_call; /* swap pointer for host functions */ #endif - ngx_queue_t dispatch_calls; /* flags */ @@ -413,8 +440,10 @@ ngx_int_t ngx_proxy_wasm_resume(ngx_proxy_wasm_ctx_t *pwctx, ngx_wasm_phase_t *phase, ngx_proxy_wasm_step_e step); 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_dispatch_ops_total(ngx_proxy_wasm_exec_t *pwexec); +void ngx_proxy_wasm_dispatch_ops_cancel(ngx_proxy_wasm_exec_t *pwexec); +ngx_uint_t ngx_proxy_wasm_foreign_calls_total(ngx_proxy_wasm_exec_t *pwexec); +void ngx_proxy_wasm_foreign_calls_cancel(ngx_proxy_wasm_exec_t *pwexec); /* host handlers */ diff --git a/src/common/proxy_wasm/ngx_proxy_wasm_foreign_call.c b/src/common/proxy_wasm/ngx_proxy_wasm_foreign_call.c new file mode 100644 index 000000000..8ad2c49ae --- /dev/null +++ b/src/common/proxy_wasm/ngx_proxy_wasm_foreign_call.c @@ -0,0 +1,305 @@ +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + +#if (NGX_WASM_LUA) +#include +#endif +#include + + +void +ngx_proxy_wasm_foreign_call_destroy(ngx_proxy_wasm_foreign_call_t *call) +{ + ngx_pfree(call->pwexec->pool, call); +} + + +#if (NGX_WASM_HTTP) +#if (NGX_WASM_LUA) +static void +ngx_proxy_wasm_foreign_call(ngx_proxy_wasm_dispatch_op_t *dop) +{ + ngx_proxy_wasm_exec_t *pwexec; + ngx_proxy_wasm_step_e step; + ngx_proxy_wasm_foreign_call_t *call; + + ngx_wa_assert(dop->type == NGX_PROXY_WASM_DISPATCH_FOREIGN_CALL); + + call = dop->call.foreign; + pwexec = call->pwexec; + pwexec->foreign_call = call; + step = pwexec->parent->step; + + ngx_queue_remove(&dop->q); + + pwexec->parent->phase = ngx_wasm_phase_lookup(&ngx_http_wasm_subsystem, + NGX_WASM_BACKGROUND_PHASE); + + ngx_proxy_wasm_run_step(pwexec, NGX_PROXY_WASM_STEP_FOREIGN_CALLBACK); + + /* potential trap ignored as it's already logged and no futher handling is + * needed */ + + pwexec->parent->step = step; + pwexec->foreign_call = NULL; + + if (ngx_proxy_wasm_dispatch_ops_total(pwexec)) { + ngx_log_debug0(NGX_LOG_DEBUG_WASM, pwexec->log, 0, + "proxy_wasm more dispatch operations pending..."); + + ngx_wasm_yield(&call->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(&call->rctx->env); + ngx_proxy_wasm_ctx_set_next_action(pwexec->parent, + NGX_PROXY_WASM_ACTION_CONTINUE); + + ngx_proxy_wasm_resume(pwexec->parent, pwexec->parent->phase, step); + } + + ngx_proxy_wasm_foreign_call_destroy(call); +} + + +static void +ngx_proxy_wasm_hfuncs_resolve_lua_handler(ngx_resolver_ctx_t *rslv_ctx) +{ +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif + struct sockaddr_in *sin; + u_char *p; + u_short sa_family = AF_INET; + ngx_buf_t *b; + ngx_str_t args; + ngx_wasm_lua_ctx_t *lctx; + ngx_wasm_socket_tcp_t *sock = rslv_ctx->data; + ngx_proxy_wasm_dispatch_op_t *dop = sock->data; + ngx_proxy_wasm_foreign_call_t *call = dop->call.foreign; + u_char buf[rslv_ctx->name.len + +#if (NGX_HAVE_INET6) + sizeof(struct in6_addr) + 1]; +#else + sizeof(struct in_addr) + 1]; +#endif + + if (rslv_ctx->addr.socklen == sizeof(struct sockaddr_in6)) { + sa_family = AF_INET6; + } + + lctx = sock->lctx; + p = buf; + + ngx_memzero(buf, sizeof(buf)); + + if (rslv_ctx->state || !rslv_ctx->naddrs) { + p++; /* buffer's 1st byte is address length; 0 if address not found */ + goto not_found; + } + + ngx_wa_assert(rslv_ctx->naddrs == 1); + + switch (sa_family) { +#if (NGX_HAVE_INET6) + case AF_INET6: + 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 */ + sin = (struct sockaddr_in *) rslv_ctx->addr.sockaddr; + *(p++) = sizeof(struct in_addr); + p = ngx_cpymem(p, &sin->sin_addr, sizeof(struct in_addr)); + } + +not_found: + + p = ngx_cpymem(p, rslv_ctx->name.data, rslv_ctx->name.len); + args.data = buf; + args.len = p - buf; + + call->args_out = ngx_wasm_chain_get_free_buf(call->pwexec->pool, + &call->rctx->free_bufs, + args.len, buf_tag, 1); + + if (call->args_out == NULL) { + goto error; + } + + b = call->args_out->buf; + b->last = ngx_cpymem(b->last, args.data, args.len); + + if (lctx->yielded) { + ngx_proxy_wasm_foreign_call(dop); + + if (rslv_ctx->state == NGX_WASM_LUA_RESOLVE_ERR) { + ngx_wasm_resume(&call->rctx->env); + } + } + +error: + + ngx_free(rslv_ctx); +} +#endif /* NGX_WASM_LUA */ + + +ngx_int_t +ngx_proxy_wasm_foreign_call_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[]) +{ + ngx_proxy_wasm_exec_t *pwexec = ngx_proxy_wasm_instance2pwexec( + instance); +#if (NGX_WASM_LUA) + size_t s; + ngx_int_t rc; + ngx_buf_t *b; + ngx_resolver_ctx_t *rslv_ctx; + ngx_wasm_core_conf_t *wcf; + ngx_wasm_socket_tcp_t *sock; + ngx_http_request_t *r; + ngx_proxy_wasm_dispatch_op_t *dop; + ngx_proxy_wasm_foreign_call_t *call; + ngx_wavm_ptr_t p; + + /* check context */ + + switch (pwexec->parent->step) { + case NGX_PROXY_WASM_STEP_REQ_HEADERS: + case NGX_PROXY_WASM_STEP_REQ_BODY: + case NGX_PROXY_WASM_STEP_TICK: + case NGX_PROXY_WASM_STEP_DISPATCH_RESPONSE: + case NGX_PROXY_WASM_STEP_FOREIGN_CALLBACK: + break; + default: + return ngx_proxy_wasm_result_trap(pwexec, + "can only call resolve_lua " + "during " + "\"on_request_headers\", " + "\"on_request_body\", " + "\"on_tick\", " + "\"on_dispatch_response\", " + "\"on_foreign_function\"", + rets, NGX_WAVM_BAD_USAGE); + } + + /* check name */ + + if (!fargs->len) { + return ngx_proxy_wasm_result_trap(pwexec, + "cannot resolve, missing name", + rets, NGX_WAVM_BAD_USAGE); + } + + + call = ngx_pcalloc(pwexec->pool, sizeof(ngx_proxy_wasm_foreign_call_t)); + if (call == NULL) { + goto error; + } + + call->pwexec = pwexec; + call->fcode = NGX_PROXY_WASM_FOREIGN_RESOLVE_LUA; + + /* rctx or fake rctx */ + + if (rctx == NULL) { + if (ngx_http_wasm_create_fake_rctx(pwexec, &r, &call->rctx) != NGX_OK) { + goto error; + } + + + } else { + r = rctx->r; + call->rctx = rctx; + } + + /* dispatch */ + + dop = ngx_pcalloc(pwexec->pool, sizeof(ngx_proxy_wasm_dispatch_op_t)); + if (dop == NULL) { + goto error; + } + + dop->type = NGX_PROXY_WASM_DISPATCH_FOREIGN_CALL; + dop->call.foreign = call; + + sock = ngx_pcalloc(pwexec->pool, sizeof(ngx_wasm_socket_tcp_t)); + if (sock == NULL) { + goto error; + } + + sock->env = &call->rctx->env; + sock->log = pwexec->log; + sock->pool = pwexec->pool; + sock->data = dop; + + /* resolve */ + + wcf = ngx_wasm_core_cycle_get_conf(ngx_cycle); + if (wcf == NULL) { + goto error; + } + + rslv_ctx = ngx_resolve_start(wcf->resolver, NULL); + if (rslv_ctx == NULL || rslv_ctx == NGX_NO_RESOLVER) { + 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); + + ngx_wa_assert(rc == NGX_OK || rc == NGX_AGAIN || rc == NGX_ERROR); + + switch (rc) { + case NGX_OK: + b = call->args_out->buf; + s = *b->start; + + p = ngx_proxy_wasm_alloc(pwexec, s); + if (!p) { + goto error; + } + + 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; + + return ngx_proxy_wasm_result_ok(rets); + + case NGX_AGAIN: + ngx_queue_insert_head(&pwexec->dispatch_ops, &dop->q); + return ngx_proxy_wasm_result_ok(rets); + + default: /* NGX_ERROR */ + /* rslv_ctx is freed by ngx_wasm_lua_resolver_resolve */ + break; + } + +error: + + return ngx_proxy_wasm_result_trap(pwexec, "failed resolving name", + rets, NGX_WAVM_ERROR); +#else + + return ngx_proxy_wasm_result_trap(pwexec, + "cannot resolve, no lua support", + rets, NGX_WAVM_ERROR); +#endif +} +#endif /* NGX_WASM_HTTP */ diff --git a/src/common/proxy_wasm/ngx_proxy_wasm_foreign_call.h b/src/common/proxy_wasm/ngx_proxy_wasm_foreign_call.h new file mode 100644 index 000000000..e26fd5c59 --- /dev/null +++ b/src/common/proxy_wasm/ngx_proxy_wasm_foreign_call.h @@ -0,0 +1,32 @@ +#ifndef _NGX_PROXY_WASM_FOREIGN_CALLBACK_H_INCLUDED_ +#define _NGX_PROXY_WASM_FOREIGN_CALLBACK_H_INCLUDED_ + + +#include +#include +#include +#include +#ifdef NGX_WASM_HTTP +#include +#endif + + +struct ngx_proxy_wasm_foreign_call_s { + ngx_proxy_wasm_exec_t *pwexec; +#if (NGX_WASM_HTTP) + ngx_http_wasm_req_ctx_t *rctx; +#endif + ngx_proxy_wasm_foreign_function_e fcode; + ngx_chain_t *args_out; +}; + + +void ngx_proxy_wasm_foreign_call_destroy(ngx_proxy_wasm_foreign_call_t *call); + + +#if (NGX_WASM_HTTP) +ngx_int_t ngx_proxy_wasm_foreign_call_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[]); +#endif +#endif diff --git a/src/common/proxy_wasm/ngx_proxy_wasm_host.c b/src/common/proxy_wasm/ngx_proxy_wasm_host.c index 3151312d7..f9496b2d4 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 @@ -34,9 +35,11 @@ ngx_proxy_wasm_get_buffer_helper(ngx_wavm_instance_t *instance, ngx_http_wasm_req_ctx_t *rctx; ngx_http_request_t *r; ngx_proxy_wasm_ctx_t *pwctx; +#endif ngx_proxy_wasm_exec_t *pwexec; pwexec = ngx_proxy_wasm_instance2pwexec(instance); +#ifdef NGX_WASM_HTTP pwctx = pwexec->parent; #endif @@ -146,6 +149,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_call_t *call = pwexec->foreign_call; + + if (call == NULL) { + return NULL; + } + + ngx_wa_assert(call->args_out); + + return call->args_out; + } + default: ngx_wavm_log_error(NGX_LOG_WASM_NYI, instance->log, NULL, "NYI - get_buffer bad buf_type: %d", buf_type); @@ -1110,14 +1126,15 @@ ngx_proxy_wasm_hfuncs_send_local_response(ngx_wavm_instance_t *instance, /* pwexec->step == NGX_PROXY_WASM_STEP_DISPATCH_RESPONSE) */ - if (ngx_proxy_wasm_dispatch_calls_total(pwexec)) { + if (ngx_proxy_wasm_dispatch_ops_total(pwexec)) { ngx_proxy_wasm_log_error(NGX_LOG_NOTICE, pwexec->log, 0, "local response produced, cancelling " - "pending dispatch calls"); + "pending dispatch operations"); - ngx_proxy_wasm_dispatch_calls_cancel(pwexec); + ngx_proxy_wasm_dispatch_ops_cancel(pwexec); } + break; case NGX_ERROR: @@ -1807,7 +1824,38 @@ ngx_proxy_wasm_hfuncs_increment_metric(ngx_wavm_instance_t *instance, /* custom extension points */ -/* NYI */ + + +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_proxy_wasm_exec_t *pwexec = ngx_proxy_wasm_instance2pwexec(instance); +#ifdef NGX_WASM_HTTP + ngx_str_t fname, fargs; + int32_t *ret_size; + ngx_wavm_ptr_t *ret_data = 0; + 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_str_eq(fname.data, fname.len, "resolve_lua", -1)) { + return ngx_proxy_wasm_foreign_call_resolve_lua(instance, rctx, &fargs, + ret_data, ret_size, + rets); + } +#endif + + return ngx_proxy_wasm_result_trap(pwexec, "unknown foreign function", + rets, NGX_WAVM_ERROR); +} /* legacy */ @@ -2224,7 +2272,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_util.c b/src/common/proxy_wasm/ngx_proxy_wasm_util.c index c99f5d255..90cc392ef 100644 --- a/src/common/proxy_wasm/ngx_proxy_wasm_util.c +++ b/src/common/proxy_wasm/ngx_proxy_wasm_util.c @@ -41,7 +41,8 @@ static ngx_str_t ngx_proxy_wasm_steplist[] = { ngx_string("on_log"), ngx_string("on_done"), ngx_string("on_tick"), - ngx_string("on_dispatch_response") + ngx_string("on_dispatch_response"), + ngx_string("on_foreign_function") }; @@ -62,7 +63,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/ngx_http_wasm_util.c b/src/http/ngx_http_wasm_util.c index 83940690a..2fe8ddde8 100644 --- a/src/http/ngx_http_wasm_util.c +++ b/src/http/ngx_http_wasm_util.c @@ -632,7 +632,7 @@ ngx_http_wasm_init_fake_connection(ngx_connection_t *c) } -static ngx_connection_t * +ngx_connection_t * ngx_http_wasm_create_fake_connection(ngx_pool_t *pool) { #if 0 @@ -725,7 +725,7 @@ ngx_http_wasm_cleanup_nop(void *data) #endif -static ngx_http_request_t * +ngx_http_request_t * ngx_http_wasm_create_fake_request(ngx_connection_t *c) { ngx_http_request_t *r; diff --git a/src/http/proxy_wasm/ngx_http_proxy_wasm.c b/src/http/proxy_wasm/ngx_http_proxy_wasm.c index d44dafc4d..de5c63c3f 100644 --- a/src/http/proxy_wasm/ngx_http_proxy_wasm.c +++ b/src/http/proxy_wasm/ngx_http_proxy_wasm.c @@ -3,6 +3,7 @@ #endif #include "ddebug.h" +#include #include @@ -357,6 +358,34 @@ 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_http_wasm_req_ctx_t *rctx; + ngx_proxy_wasm_filter_t *filter = pwexec->filter; + ngx_proxy_wasm_foreign_call_t *call = pwexec->foreign_call; + + rctx = call->rctx; + + ngx_wasm_continue(&rctx->env); + + cl = call->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, call->fcode, + args_len); + + return rc; +} + + static ngx_int_t ngx_http_proxy_wasm_ecode(ngx_proxy_wasm_err_e ecode) { @@ -445,6 +474,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/src/http/proxy_wasm/ngx_http_proxy_wasm_dispatch.c b/src/http/proxy_wasm/ngx_http_proxy_wasm_dispatch.c index 3c8a6734e..bfb6925b7 100644 --- a/src/http/proxy_wasm/ngx_http_proxy_wasm_dispatch.c +++ b/src/http/proxy_wasm/ngx_http_proxy_wasm_dispatch.c @@ -203,6 +203,7 @@ ngx_http_proxy_wasm_dispatch(ngx_proxy_wasm_exec_t *pwexec, ngx_http_wasm_req_ctx_t *rctxp = NULL; ngx_http_proxy_wasm_dispatch_t *call = NULL; ngx_proxy_wasm_ctx_t *pwctx = pwexec->parent; + ngx_proxy_wasm_dispatch_op_t *dop = NULL; unsigned enable_ssl = 0; /* rctx or fake request */ @@ -417,20 +418,28 @@ ngx_http_proxy_wasm_dispatch(ngx_proxy_wasm_exec_t *pwexec, /* dispatch */ + dop = ngx_pcalloc(pwexec->pool, sizeof(ngx_proxy_wasm_dispatch_op_t)); + if (dop == NULL) { + goto error; + } + + dop->type = NGX_PROXY_WASM_DISPATCH_HTTP_CALL; + dop->call.http = call; + ev = ngx_calloc(sizeof(ngx_event_t), r->connection->log); if (ev == NULL) { goto error; } ev->handler = ngx_http_proxy_wasm_dispatch_handler; - ev->data = call; + ev->data = dop; ev->log = r->connection->log; ngx_post_event(ev, &ngx_posted_events); call->ev = ev; - ngx_queue_insert_head(&pwexec->dispatch_calls, &call->q); + ngx_queue_insert_head(&pwexec->dispatch_ops, &dop->q); ngx_proxy_wasm_ctx_set_next_action(pwctx, NGX_PROXY_WASM_ACTION_PAUSE); @@ -505,7 +514,8 @@ static void ngx_http_proxy_wasm_dispatch_handler(ngx_event_t *ev) { ngx_int_t rc; - ngx_http_proxy_wasm_dispatch_t *call = ev->data; + ngx_proxy_wasm_dispatch_op_t *dop = ev->data; + ngx_http_proxy_wasm_dispatch_t *call = dop->call.http; ngx_http_wasm_req_ctx_t *rctx = call->rctx; ngx_wasm_socket_tcp_t *sock = &call->sock; @@ -513,7 +523,7 @@ ngx_http_proxy_wasm_dispatch_handler(ngx_event_t *ev) call->ev = NULL; sock->resume_handler = ngx_http_proxy_wasm_dispatch_resume_handler; - sock->data = call; + sock->data = dop; rc = sock->resume_handler(sock); dd("sock->resume rc: %ld", rc); @@ -754,14 +764,26 @@ ngx_http_proxy_wasm_dispatch_resume_handler(ngx_wasm_socket_tcp_t *sock) ngx_int_t rc = NGX_ERROR; ngx_chain_t *nl; ngx_wavm_instance_t *instance; - ngx_http_proxy_wasm_dispatch_t *call = sock->data; - ngx_http_wasm_req_ctx_t *rctx = call->rctx; - ngx_http_request_t *r = rctx->r; - ngx_proxy_wasm_exec_t *pwexec = call->pwexec; - ngx_proxy_wasm_filter_t *filter = pwexec->filter; + ngx_proxy_wasm_dispatch_op_t *dop; + ngx_http_proxy_wasm_dispatch_t *call; + ngx_http_wasm_req_ctx_t *rctx; + ngx_http_request_t *r; + ngx_proxy_wasm_exec_t *pwexec; + ngx_proxy_wasm_filter_t *filter; dd("enter"); + dop = sock->data; + + ngx_wa_assert(dop->type == NGX_PROXY_WASM_DISPATCH_HTTP_CALL); + + call = dop->call.http; + + rctx = call->rctx; + r = rctx->r; + pwexec = call->pwexec; + filter = pwexec->filter; + ngx_wa_assert(&call->sock == sock); if (sock->err) { @@ -867,7 +889,7 @@ ngx_http_proxy_wasm_dispatch_resume_handler(ngx_wasm_socket_tcp_t *sock) } /* call has finished */ - ngx_queue_remove(&call->q); + ngx_queue_remove(&dop->q); if (invoke_on_http_dispatch_response(pwexec, call) != NGX_OK) { rc = NGX_ERROR; @@ -892,7 +914,7 @@ ngx_http_proxy_wasm_dispatch_resume_handler(ngx_wasm_socket_tcp_t *sock) error: /* call has errored */ - ngx_queue_remove(&call->q); + ngx_queue_remove(&dop->q); error2: @@ -906,9 +928,9 @@ ngx_http_proxy_wasm_dispatch_resume_handler(ngx_wasm_socket_tcp_t *sock) done: - if (ngx_proxy_wasm_dispatch_calls_total(pwexec)) { + if (ngx_proxy_wasm_dispatch_ops_total(pwexec)) { ngx_log_debug0(NGX_LOG_DEBUG_WASM, pwexec->log, 0, - "proxy_wasm more http dispatch calls pending..."); + "proxy_wasm more dispatch operations pending..."); rc = NGX_AGAIN; ngx_wasm_yield(&rctx->env); @@ -917,7 +939,7 @@ ngx_http_proxy_wasm_dispatch_resume_handler(ngx_wasm_socket_tcp_t *sock) } else { ngx_log_debug0(NGX_LOG_DEBUG_WASM, pwexec->log, 0, - "proxy_wasm last http dispatch call handled"); + "proxy_wasm last dispatch operation handled"); ngx_wasm_continue(&rctx->env); ngx_proxy_wasm_ctx_set_next_action(pwexec->parent, diff --git a/src/http/proxy_wasm/ngx_http_proxy_wasm_dispatch.h b/src/http/proxy_wasm/ngx_http_proxy_wasm_dispatch.h index 97f5b99dd..3c25a9bb8 100644 --- a/src/http/proxy_wasm/ngx_http_proxy_wasm_dispatch.h +++ b/src/http/proxy_wasm/ngx_http_proxy_wasm_dispatch.h @@ -29,7 +29,6 @@ typedef enum { struct ngx_http_proxy_wasm_dispatch_s { ngx_pool_t *pool; /* owned */ - ngx_queue_t q; /* stored by caller */ uint32_t id; ngx_msec_t timeout; ngx_wasm_socket_tcp_t sock; diff --git a/t/03-proxy_wasm/hfuncs/133-proxy_dispatch_http_edge_cases.t b/t/03-proxy_wasm/hfuncs/133-proxy_dispatch_http_edge_cases.t index 6374e5741..d0598d95f 100644 --- a/t/03-proxy_wasm/hfuncs/133-proxy_dispatch_http_edge_cases.t +++ b/t/03-proxy_wasm/hfuncs/133-proxy_dispatch_http_edge_cases.t @@ -147,7 +147,7 @@ qr/\A.*? on_request_headers.* .*? on_response_body.* .*? on_log/ --- error_log eval -qr/\[notice\] .*? local response produced, cancelling pending dispatch calls/ +qr/\[notice\] .*? local response produced, cancelling pending dispatch operations/ --- no_error_log [error] diff --git a/t/03-proxy_wasm/hfuncs/140-proxy_call_foreign_function.t b/t/03-proxy_wasm/hfuncs/140-proxy_call_foreign_function.t new file mode 100644 index 000000000..7b37f8b9d --- /dev/null +++ b/t/03-proxy_wasm/hfuncs/140-proxy_call_foreign_function.t @@ -0,0 +1,41 @@ +# vim:set ft= ts=4 sts=4 sw=4 et fdm=marker: + +use strict; +use lib '.'; +use t::TestWasmX; + +plan_tests(4); +run_tests(); + +__DATA__ + +=== TEST 1: proxy_wasm - call_foreign_function(), unknown function +--- wasm_modules: hostcalls +--- config + location /t { + proxy_wasm hostcalls 'test=/t/call_foreign_function \ + name=foo'; + } +--- error_code: 500 +--- error_log eval +qr/host trap \(internal error\): unknown foreign function/ +--- no_error_log +[crit] +[emerg] + + + +=== TEST 2: proxy_wasm - call_foreign_function(), known function +--- skip_eval: 4: $::nginxV =~ m/openresty/ +--- wasm_modules: hostcalls +--- config + location /t { + proxy_wasm hostcalls 'test=/t/call_foreign_function \ + name=resolve_lua'; + } +--- error_code: 500 +--- error_log eval +qr/host trap \(internal error\): cannot resolve, no lua support/ +--- no_error_log +[crit] +[emerg] diff --git a/t/03-proxy_wasm/hfuncs/contexts/140-proxy_foreign_function_resolve_lua.t b/t/03-proxy_wasm/hfuncs/contexts/140-proxy_foreign_function_resolve_lua.t new file mode 100644 index 000000000..39aa31ea4 --- /dev/null +++ b/t/03-proxy_wasm/hfuncs/contexts/140-proxy_foreign_function_resolve_lua.t @@ -0,0 +1,169 @@ +# vim:set ft= ts=4 sts=4 sw=4 et fdm=marker: + +use strict; +use lib '.'; +use t::TestWasmX::Lua; + +skip_hup(); +skip_no_debug(); +skip_no_openresty(); + +plan_tests(4); +run_tests(); + +__DATA__ + +=== TEST 1: proxy_wasm contexts - call_resolve_lua on_vm_start +--- main_config + wasm { + module context_checks $TEST_NGINX_CRATES_DIR/context_checks.wasm 'call_resolve_lua'; + } +--- config + location /t { + proxy_wasm context_checks; + return 200; + } +--- must_die: 0 +--- error_log +[error] +can only call resolve_lua during "on_request_headers", "on_request_body", "on_tick", "on_dispatch_response", "on_foreign_function" +--- no_error_log +[crit] + + + +=== TEST 2: proxy_wasm contexts - call_resolve_lua on_configure +--- wasm_modules: context_checks +--- config + location /t { + proxy_wasm context_checks 'on_configure=call_resolve_lua'; + return 200; + } +--- must_die: 0 +--- error_log +[error] +can only call resolve_lua during "on_request_headers", "on_request_body", "on_tick", "on_dispatch_response", "on_foreign_function" +--- no_error_log +[crit] + + + +=== TEST 3: proxy_wasm contexts - call_resolve_lua on_tick +--- wasm_modules: context_checks +--- config + location /t { + proxy_wasm context_checks 'on_tick=call_resolve_lua'; + return 200; + } +--- error_log +[error] +cannot resolve, missing name +--- no_error_log +[crit] + + + +=== TEST 4: proxy_wasm contexts - call_resolve_lua on_http_dispatch_response +--- wasm_modules: context_checks +--- config + location /t { + proxy_wasm context_checks 'on_http_dispatch_response=call_resolve_lua \ + host=127.0.0.1:$TEST_NGINX_SERVER_PORT'; + return 200; + } + + location /dispatch { + return 200; + } +--- error_log +[error] +cannot resolve, missing name +--- no_error_log +[crit] + + + +=== TEST 5: proxy_wasm contexts - call_resolve_lua on_request_headers +--- wasm_modules: context_checks +--- config + location /t { + proxy_wasm context_checks 'on_request_headers=call_resolve_lua'; + return 200; + } +--- error_code: 500 +--- ignore_response_body +--- error_log +[error] +cannot resolve, missing name +--- no_error_log +[crit] + + + +=== TEST 6: proxy_wasm contexts - call_resolve_lua on_request_body +--- load_nginx_modules: ngx_http_echo_module +--- wasm_modules: context_checks +--- config + location /t { + proxy_wasm context_checks 'on_request_body=call_resolve_lua'; + echo ok; + } +--- request +POST /t +payload +--- error_code: 500 +--- ignore_response_body +--- error_log +[error] +cannot resolve, missing name +--- no_error_log +[crit] + + + +=== TEST 7: proxy_wasm contexts - call_resolve_lua on_response_headers +--- load_nginx_modules: ngx_http_echo_module +--- wasm_modules: context_checks +--- config + location /t { + proxy_wasm context_checks 'on_response_headers=call_resolve_lua'; + echo ok; + } +--- ignore_response_body +--- error_log +[error] +can only call resolve_lua during "on_request_headers", "on_request_body", "on_tick", "on_dispatch_response", "on_foreign_function" +--- no_error_log +[crit] + + + +=== TEST 8: proxy_wasm contexts - call_resolve_lua on_response_body +--- load_nginx_modules: ngx_http_echo_module +--- wasm_modules: context_checks +--- config + location /t { + proxy_wasm context_checks 'on_response_body=call_resolve_lua'; + echo ok; + } +--- ignore_response_body +--- error_log +[error] +can only call resolve_lua during "on_request_headers", "on_request_body", "on_tick", "on_dispatch_response", "on_foreign_function" +--- no_error_log +[crit] + + + +=== TEST 9: proxy_wasm contexts - call_resolve_lua on_log +--- wasm_modules: context_checks +--- config + location /t { + proxy_wasm context_checks 'on_log=call_resolve_lua'; + return 200; + } +--- error_log +[error] +can only call resolve_lua during "on_request_headers", "on_request_body", "on_tick", "on_dispatch_response", "on_foreign_function" +--- no_error_log +[crit] diff --git a/t/03-proxy_wasm/hfuncs/foreign/001-resolve_lua.t b/t/03-proxy_wasm/hfuncs/foreign/001-resolve_lua.t new file mode 100644 index 000000000..fe811d7d5 --- /dev/null +++ b/t/03-proxy_wasm/hfuncs/foreign/001-resolve_lua.t @@ -0,0 +1,188 @@ +# vim:set ft= ts=4 sts=4 sw=4 et fdm=marker: + +use strict; +use lib '.'; +use t::TestWasmX::Lua; + +skip_no_openresty(); + +plan_tests(5); +run_tests(); + +__DATA__ + +=== TEST 1: proxy_wasm - resolve_lua, NXDOMAIN +--- wasm_modules: hostcalls +--- config + location /t { + proxy_wasm_lua_resolver on; + proxy_wasm hostcalls 'test=/t/resolve_lua \ + name=foo'; + return 200; + } +--- error_log eval +qr/could not resolve foo/ +--- no_error_log +[crit] +[emerg] +[stub] + + + +=== TEST 2: proxy_wasm - resolve_lua (no yielding) +--- wasm_modules: hostcalls +--- config + location /t { + proxy_wasm_lua_resolver on; + proxy_wasm hostcalls 'test=/t/resolve_lua \ + name=localhost'; + return 200; + } +--- error_log eval +qr/resolved \(no yielding\) localhost to \[127, 0, 0, 1\]/ +--- no_error_log +[error] +[crit] +[emerg] + + + +=== TEST 3: proxy_wasm - resolve_lua (yielding) +--- wasm_modules: hostcalls +--- config + location /t { + proxy_wasm_lua_resolver on; + proxy_wasm hostcalls 'test=/t/resolve_lua \ + name=httpbin.org'; + return 200; + } +--- error_log eval +qr/resolved \(yielding\) httpbin\.org to \[\d+, \d+, \d+, \d+\]/ +--- no_error_log +[error] +[crit] +[emerg] + + + +=== TEST 4: proxy_wasm - resolve_lua, IPv6 record +--- wasm_modules: hostcalls +--- config + location /t { + proxy_wasm_lua_resolver on; + proxy_wasm hostcalls 'test=/t/resolve_lua \ + name=ipv6.google.com'; + return 200; + } +--- error_log eval +qr/resolved \(yielding\) ipv6\.google\.com to \[\d+, \d+, \d+, \d+, \d+, \d+, \d+, \d+, \d+, \d+, \d+, \d+, \d+, \d+, \d+, \d+\]/ +--- no_error_log +[error] +[crit] +[emerg] + + + +=== TEST 5: proxy_wasm - resolve_lua, multiple calls (yielding) +--- wasm_modules: hostcalls +--- config + location /t { + proxy_wasm_lua_resolver on; + proxy_wasm hostcalls 'test=/t/resolve_lua \ + name=httpbin.org,wikipedia.org'; + return 200; + } +--- error_log eval +[ + qr/resolved \(yielding\) httpbin\.org to \[\d+, \d+, \d+, \d+\]/, + qr/resolved \(yielding\) wikipedia\.org to \[\d+, \d+, \d+, \d+\]/ +] +--- no_error_log +[error] +[crit] + + + +=== TEST 6: proxy_wasm - resolve_lua, multiple calls (mixed) +--- wasm_modules: hostcalls +--- config + location /t { + proxy_wasm_lua_resolver on; + proxy_wasm hostcalls 'test=/t/resolve_lua \ + name=localhost,httpbin.org'; + return 200; + } +--- error_log eval +[ + qr/resolved \(no yielding\) localhost to \[127, 0, 0, 1\]/, + qr/resolved \(yielding\) httpbin\.org to \[\d+, \d+, \d+, \d+\]/ +] +--- no_error_log +[error] +[crit] + + + +=== TEST 7: proxy_wasm - resolve_lua, on_tick +--- wasm_modules: hostcalls +--- config + location /t { + proxy_wasm hostcalls 'tick_period=500 \ + on_tick=resolve_lua \ + name=localhost,httpbin.org'; + return 200; + } +--- error_log eval +[ + qr/resolved \(no yielding\) localhost to \[127, 0, 0, 1\]/, + qr/resolved \(yielding\) httpbin\.org to \[\d+, \d+, \d+, \d+\]/ +] +--- no_error_log +[error] +[crit] + + + +=== TEST 8: proxy_wasm - resolve_lua, on_http_call_response +--- wasm_modules: hostcalls +--- config + location /t { + proxy_wasm hostcalls 'test=/t/dispatch_http_call \ + host=127.0.0.1:$TEST_NGINX_SERVER_PORT \ + path=/dispatch \ + on_http_call_response=resolve_lua \ + name=httpbin.org,wikipedia.org'; + return 200; + } + + location /dispatch { + return 200; + } +--- error_log eval +[ + qr/resolved \(yielding\) httpbin\.org to \[\d+, \d+, \d+, \d+\]/, + qr/resolved \(yielding\) wikipedia\.org to \[\d+, \d+, \d+, \d+\]/ +] +--- no_error_log +[error] +[crit] + + + +=== TEST 9: proxy_wasm - resolve_lua, on_foreign_function +--- wasm_modules: hostcalls +--- config + location /t { + proxy_wasm hostcalls 'test=/t/resolve_lua \ + on_foreign_function=resolve_lua \ + name=httpbin.org'; + return 200; + } +--- error_log eval +[ + qr/resolved \(yielding\) httpbin\.org to \[\d+, \d+, \d+, \d+\]/, + qr/resolved \(yielding\) httpbin\.org to \[\d+, \d+, \d+, \d+\]/ +] +--- no_error_log +[error] +[crit] diff --git a/t/lib/Cargo.lock b/t/lib/Cargo.lock index 4e418ff3c..1552a028f 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,15 @@ dependencies = [ "log", ] +[[package]] +name = "proxy-wasm" +version = "0.2.3-dev" +source = "git+https://github.com/casimiro/proxy-wasm-rust-sdk.git?branch=foreign-function-callback#501e78c45c5b3b203d51ae8bb8ebf03509fb55e1" +dependencies = [ + "hashbrown 0.15.1", + "log", +] + [[package]] name = "quote" version = "1.0.37" diff --git a/t/lib/proxy-wasm-tests/context-checks/src/hostcalls.rs b/t/lib/proxy-wasm-tests/context-checks/src/hostcalls.rs index 66a939603..bf0f3308c 100644 --- a/t/lib/proxy-wasm-tests/context-checks/src/hostcalls.rs +++ b/t/lib/proxy-wasm-tests/context-checks/src/hostcalls.rs @@ -1,7 +1,7 @@ use crate::*; use log::*; use proxy_wasm::types::*; -use std::ptr::null_mut; +use std::ptr::{null, null_mut}; #[allow(improper_ctypes)] extern "C" { @@ -455,3 +455,29 @@ pub fn increment_metric(_ctx: &TestContext) { info!("increment_metric status: {}", status as u32); } } + +#[allow(improper_ctypes)] +extern "C" { + fn proxy_call_foreign_function( + function_name_data: *const u8, + function_name_size: usize, + arguments_data: *const u8, + arguments_size: usize, + results_data: *mut *mut u8, + results_size: *mut usize, + ) -> Status; +} + +pub fn call_resolve_lua(_ctx: &TestContext) { + let name = "resolve_lua"; + + let mut ret_data: *mut u8 = null_mut(); + let mut ret_size: usize = 0; + + unsafe { + let status = proxy_call_foreign_function( + name.as_ptr(), name.len(), null(), 0, &mut ret_data, &mut ret_size); + + info!("resolve_lua status: {}", status as u32); + } +} diff --git a/t/lib/proxy-wasm-tests/context-checks/src/lib.rs b/t/lib/proxy-wasm-tests/context-checks/src/lib.rs index 1d63167e6..14be08b66 100644 --- a/t/lib/proxy-wasm-tests/context-checks/src/lib.rs +++ b/t/lib/proxy-wasm-tests/context-checks/src/lib.rs @@ -23,6 +23,7 @@ impl TestContext { "increment_metric" => increment_metric(self), "record_metric" => record_metric(self), "get_metric" => get_metric(self), + "call_resolve_lua" => call_resolve_lua(self), "set_tick_period" => set_tick_period(self), "add_request_header" => add_request_header(self, arg), "add_response_header" => add_response_header(self, arg), diff --git a/t/lib/proxy-wasm-tests/hostcalls/Cargo.toml b/t/lib/proxy-wasm-tests/hostcalls/Cargo.toml index dad9e5d85..66e168d55 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 = { git = "https://github.com/casimiro/proxy-wasm-rust-sdk.git", branch = "foreign-function-callback" } 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 f3c966c35..9de73fd6c 100644 --- a/t/lib/proxy-wasm-tests/hostcalls/src/filter.rs +++ b/t/lib/proxy-wasm-tests/hostcalls/src/filter.rs @@ -1,7 +1,8 @@ -use crate::{test_http::*, types::*}; +use crate::{test_http::*, types::*, tests::*, foreign_callbacks::*}; 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,12 +109,42 @@ impl Context for TestHttp { Some(format!("called {} times", self.n_sync_calls + 1).as_str()), ); } + "resolve_lua" => { + self.pending_callbacks = test_proxy_resolve_lua(self); + if self.pending_callbacks > 0 { + return; + } + } _ => {} } 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 => { + resolve_lua_callback(args); + } + } + + match self.get_config("on_foreign_function").unwrap_or("") { + "resolve_lua" => { test_proxy_resolve_lua(self); } + _ => (), + } + + self.pending_callbacks -= 1; + + if self.pending_callbacks == 0 { + self.send_plain_response(StatusCode::OK, Some("resolved")); + } + } + fn on_done(&mut self) -> bool { info!("[hostcalls] on_done"); diff --git a/t/lib/proxy-wasm-tests/hostcalls/src/foreign_callbacks/mod.rs b/t/lib/proxy-wasm-tests/hostcalls/src/foreign_callbacks/mod.rs new file mode 100644 index 000000000..ec362e071 --- /dev/null +++ b/t/lib/proxy-wasm-tests/hostcalls/src/foreign_callbacks/mod.rs @@ -0,0 +1,18 @@ +use log::*; + +pub fn resolve_lua_callback(args: Option>) { + match args { + Some(args) => { + let address_size = args[0] as usize; + let name = std::str::from_utf8(&args[(address_size + 1)..]).unwrap(); + + if address_size > 0 { + let address = &args[1..address_size + 1]; + info!("resolved (yielding) {} to {:?}", name, address); + } else { + info!("could not resolve {}", name) + } + } + _ => info!("empty args") + } +} diff --git a/t/lib/proxy-wasm-tests/hostcalls/src/lib.rs b/t/lib/proxy-wasm-tests/hostcalls/src/lib.rs index f5719536e..3331d3774 100644 --- a/t/lib/proxy-wasm-tests/hostcalls/src/lib.rs +++ b/t/lib/proxy-wasm-tests/hostcalls/src/lib.rs @@ -3,10 +3,11 @@ mod filter; mod tests; mod types; +mod foreign_callbacks; -use crate::{tests::*, types::test_http::*, types::test_root::*, types::*}; +use crate::{tests::*, types::test_http::*, types::test_root::*, types::*, foreign_callbacks::*}; use log::*; -use proxy_wasm::{traits::*, types::*}; +use proxy_wasm::{traits::*, types::*, hostcalls::*}; use std::{collections::BTreeMap, collections::HashMap, time::Duration}; proxy_wasm::main! {{ @@ -114,6 +115,26 @@ impl RootContext for TestRoot { self.n_sync_calls += 1; } "set_property" => test_set_property(self), + "resolve_lua" => { + let names = self + .config + .get("name") + .map(|x| x.as_str()) + .expect("expected a name argument"); + + for name in names.split(",") { + info!("attempting to resolve {}", name); + match call_foreign_function("resolve_lua", Some(name.as_bytes())) { + Ok(ret) => { + match ret { + Some(bytes) => info!("resolved (no yielding) {} to {:?}", name, bytes), + _ => () + } + } + _ => () + } + } + } "dispatch" => { let mut timeout = Duration::from_secs(0); let mut headers = Vec::new(); @@ -201,6 +222,7 @@ impl RootContext for TestRoot { on_phases: phases, metrics: self.metrics.clone(), n_sync_calls: 0, + pending_callbacks: 0, })) } } @@ -226,4 +248,17 @@ impl Context for TestRoot { None => {} } } + + 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 => { + resolve_lua_callback(args); + } + } + } } diff --git a/t/lib/proxy-wasm-tests/hostcalls/src/tests/mod.rs b/t/lib/proxy-wasm-tests/hostcalls/src/tests/mod.rs index ae4ffb612..571dd00e2 100644 --- a/t/lib/proxy-wasm-tests/hostcalls/src/tests/mod.rs +++ b/t/lib/proxy-wasm-tests/hostcalls/src/tests/mod.rs @@ -695,3 +695,29 @@ pub(crate) fn test_proxy_get_header_map_value_misaligned_return_data(_ctx: &Test ); } } + +pub(crate) fn test_proxy_resolve_lua(ctx: &TestHttp) -> u32 { + let mut pending_callbacks = 0; + let names = ctx + .config + .get("name") + .map(|x| x.as_str()) + .expect("expected a name argument"); + + for name in names.split(",") { + info!("attempting to resolve {}", name); + match call_foreign_function("resolve_lua", Some(name.as_bytes())) { + Ok(ret) => { + match ret { + Some(bytes) => info!("resolved (no yielding) {} to {:?}", name, bytes), + _ => { + pending_callbacks += 1; + } + } + } + _ => () + } + } + + return pending_callbacks; +} 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..bfa3a8c60 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 @@ -8,6 +8,7 @@ pub struct TestHttp { pub config: HashMap, pub metrics: BTreeMap, pub n_sync_calls: usize, + pub pending_callbacks: u32, } impl TestHttp { @@ -150,6 +151,26 @@ impl TestHttp { get_metric(h_id).unwrap(); } + /* foreign functions */ + "/t/call_foreign_function" => { + let name = self.config.get("name").expect("expected a name argument"); + + let ret = match self.config.get("arg") { + Some(arg) => call_foreign_function(name, Some((&arg).as_bytes())).unwrap(), + None => call_foreign_function(name, None).unwrap(), + }.unwrap(); + + info!("foreign function {} returned {:?}", name, ret); + } + "/t/resolve_lua" => { + self.pending_callbacks = test_proxy_resolve_lua(self); + + if self.pending_callbacks > 0 { + return Action::Pause + } + + } + /* errors */ "/t/trap" => panic!("custom trap"), "/t/error/get_response_body" => { From a4fd2ca6bf0407160de199785207d13e6354ac48 Mon Sep 17 00:00:00 2001 From: Caio Ramos Casimiro Date: Tue, 26 Nov 2024 22:55:33 +0000 Subject: [PATCH 4/5] chore(morestyle) ignore wrapped lines with arguments following a declaration Handles the case when the expression defining a variable being declared is a function call receiving arguments that don't fit in the same line, e.g.: ngx_proxy_wasm_exec_t *pwexec = ngx_proxy_wasm_instance2pwexec( instance); --- util/morestyle.pl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/util/morestyle.pl b/util/morestyle.pl index 16176e439..771dc1724 100755 --- a/util/morestyle.pl +++ b/util/morestyle.pl @@ -209,6 +209,10 @@ } elsif ($line =~ /^\s+[\+\-\*\/] [\s\w\(\)\+\-\*\/\.\-\>]/) { # ignoring line with a portion of a wrapped expression + } elsif ($line =~ /^\s+(\w+(, )?)+\);/) { + # ignoring line with arguments wrapped from previous line + # TODO: ensure arguments' leading spaces are correct + } elsif (!$cur_line_is_empty) { if ($n_vars > 0 && $min_var_space - $max_var_type > 3) { var_output "excessive spacing in variable alignment: needs 2 spaces from longest type to first name/pointer."; From d217d1a149275f3b62072d17c97611634a1026a5 Mon Sep 17 00:00:00 2001 From: Caio Ramos Casimiro Date: Mon, 2 Dec 2024 20:00:15 +0000 Subject: [PATCH 5/5] misc(*) increase max trap length The trap message describing the lua_resolver being called in unsupported context exceeds the current limit. --- src/wasm/vm/ngx_wavm_host.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wasm/vm/ngx_wavm_host.h b/src/wasm/vm/ngx_wavm_host.h index 9802d8333..45ba33fa8 100644 --- a/src/wasm/vm/ngx_wavm_host.h +++ b/src/wasm/vm/ngx_wavm_host.h @@ -50,7 +50,7 @@ extern const wasm_valkind_t *ngx_wavm_arity_i32x5_i64x2_i32x2[]; /* hfuncs */ -#define NGX_WAVM_HFUNCS_MAX_TRAP_LEN 128 +#define NGX_WAVM_HFUNCS_MAX_TRAP_LEN 256 #define ngx_wavm_hfunc_null { ngx_null_string, NULL, NULL, NULL }