diff --git a/src/common/proxy_wasm/ngx_proxy_wasm.c b/src/common/proxy_wasm/ngx_proxy_wasm.c index 6722b85dd..457fc2251 100644 --- a/src/common/proxy_wasm/ngx_proxy_wasm.c +++ b/src/common/proxy_wasm/ngx_proxy_wasm.c @@ -299,7 +299,7 @@ ngx_proxy_wasm_init(ngx_proxy_wasm_t *pwm) rc = ngx_wavm_instance_call_funcref(pwm->instance, pwm->proxy_on_plugin_start, &rets, - pwm->rctxid, 0); // TODO: size + pwm->rctxid, pwm->config.len); if (rc != NGX_OK || !rets->data[0].of.i32) { goto error; } @@ -320,6 +320,12 @@ ngx_proxy_wasm_init(ngx_proxy_wasm_t *pwm) void ngx_proxy_wasm_destroy(ngx_proxy_wasm_t *pwm) { + if (pwm->config.len) { + ngx_pfree(pwm->pool, pwm->config.data); + pwm->config.data = NULL; + pwm->config.len = 0; + } + ngx_wavm_ctx_destroy(&pwm->wvctx); } diff --git a/src/common/proxy_wasm/ngx_proxy_wasm.h b/src/common/proxy_wasm/ngx_proxy_wasm.h index b583dd23b..2731c931d 100644 --- a/src/common/proxy_wasm/ngx_proxy_wasm.h +++ b/src/common/proxy_wasm/ngx_proxy_wasm.h @@ -126,6 +126,7 @@ typedef ngx_uint_t (*ngx_proxy_wasm_ecode_pt)(ngx_proxy_wasm_t *pwm, ngx_uint_t struct ngx_proxy_wasm_s { + ngx_str_t config; ngx_proxy_wasm_resume_pt resume_; ngx_proxy_wasm_ctxid_pt ctxid_; ngx_proxy_wasm_ecode_pt ecode_; diff --git a/src/common/proxy_wasm/ngx_proxy_wasm_host.c b/src/common/proxy_wasm/ngx_proxy_wasm_host.c index 3417ebf52..38806b2b6 100644 --- a/src/common/proxy_wasm/ngx_proxy_wasm_host.c +++ b/src/common/proxy_wasm/ngx_proxy_wasm_host.c @@ -333,6 +333,39 @@ ngx_proxy_wasm_hfuncs_send_http_response(ngx_wavm_instance_t *instance, } +static ngx_int_t +ngx_proxy_wasm_hfuncs_get_configuration(ngx_wavm_instance_t *instance, + wasm_val_t args[], wasm_val_t rets[]) +{ + size_t *rlen; + ngx_wavm_ptr_t *rbuf, p; + ngx_proxy_wasm_t *pwm; + + pwm = ngx_proxy_wasm_get_pwm(instance); + + rbuf = ngx_wavm_memory_lift(instance->memory, args[0].of.i32); + rlen = ngx_wavm_memory_lift(instance->memory, args[1].of.i32); + + if (pwm->config.len) { + p = ngx_proxy_wasm_alloc(pwm, pwm->config.len); + if (p == 0) { + return ngx_proxy_wasm_result_err(rets); + } + + if (!ngx_wavm_memory_memcpy(instance->memory, p, + pwm->config.data, pwm->config.len)) + { + return ngx_proxy_wasm_result_invalid_mem(rets); + } + + *rbuf = p; + *rlen = pwm->config.len; + } + + return ngx_proxy_wasm_result_ok(rets); +} + + static ngx_int_t ngx_proxy_wasm_hfuncs_nop(ngx_wavm_instance_t *instance, wasm_val_t args[], wasm_val_t rets[]) @@ -744,7 +777,7 @@ static ngx_wavm_host_func_def_t ngx_proxy_wasm_hfuncs[] = { ngx_wavm_arity_i32 }, { ngx_string("proxy_get_configuration"), - &ngx_proxy_wasm_hfuncs_nop, + &ngx_proxy_wasm_hfuncs_get_configuration, ngx_wavm_arity_i32x2, ngx_wavm_arity_i32 }, diff --git a/src/http/ngx_http_wasm_module.c b/src/http/ngx_http_wasm_module.c index 8bbe66733..22932d483 100644 --- a/src/http/ngx_http_wasm_module.c +++ b/src/http/ngx_http_wasm_module.c @@ -104,7 +104,7 @@ static ngx_command_t ngx_http_wasm_module_cmds[] = { &ngx_http_wasm_op_post }, { ngx_string("proxy_wasm"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12, ngx_http_wasm_proxy_wasm_directive, NGX_HTTP_LOC_CONF_OFFSET, NGX_HTTP_MODULE, @@ -286,8 +286,8 @@ ngx_http_wasm_proxy_wasm_directive(ngx_conf_t *cf, ngx_command_t *cmd, loc->pwmodule->max_pairs = NGX_HTTP_WASM_MAX_REQ_HEADERS; - op = ngx_wasm_conf_add_op_proxy_wasm(cf, loc->ops_engine, cf->args->elts, - loc->pwmodule); + op = ngx_wasm_conf_add_op_proxy_wasm(cf, loc->ops_engine, cf->args->nelts, + cf->args->elts, loc->pwmodule); if (op == NULL) { return NGX_CONF_ERROR; } diff --git a/src/wasm/ngx_wasm_ops.c b/src/wasm/ngx_wasm_ops.c index 7af654abc..997b838a4 100644 --- a/src/wasm/ngx_wasm_ops.c +++ b/src/wasm/ngx_wasm_ops.c @@ -162,22 +162,22 @@ ngx_wasm_ops_engine_destroy(ngx_wasm_ops_engine_t *engine) static ngx_int_t ngx_wasm_op_add_helper(ngx_conf_t *cf, ngx_wasm_ops_engine_t *ops_engine, - ngx_wasm_op_t *op, ngx_str_t *mod_name) + ngx_wasm_op_t *op, ngx_str_t *arg_name) { ngx_wasm_phase_t *phase = ops_engine->subsystem->phases; ngx_wasm_ops_pipeline_t *pipeline; ngx_wasm_op_t **opp; - if (mod_name->len == 0) { + if (arg_name->len == 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid module name \"%V\"", mod_name); + "invalid module name \"%V\"", arg_name); return NGX_ERROR; } - op->module = ngx_wavm_module_lookup(ops_engine->vm, mod_name); + op->module = ngx_wavm_module_lookup(ops_engine->vm, arg_name); if (op->module == NULL) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "no \"%V\" module defined", mod_name); + "no \"%V\" module defined", arg_name); return NGX_ERROR; } @@ -222,10 +222,10 @@ ngx_wasm_conf_add_op_call(ngx_conf_t *cf, ngx_wasm_ops_engine_t *ops_engine, { ngx_wasm_op_t *op; ngx_wasm_phase_t *phase = ops_engine->subsystem->phases; - ngx_str_t *phase_name, *mod_name, *func_name; + ngx_str_t *phase_name, *arg_name, *func_name; phase_name = &value[1]; - mod_name = &value[2]; + arg_name = &value[2]; func_name = &value[3]; if (phase_name->len == 0) { @@ -272,7 +272,7 @@ ngx_wasm_conf_add_op_call(ngx_conf_t *cf, ngx_wasm_ops_engine_t *ops_engine, op->conf.call.func_name = *func_name; - if (ngx_wasm_op_add_helper(cf, ops_engine, op, mod_name) != NGX_OK) { + if (ngx_wasm_op_add_helper(cf, ops_engine, op, arg_name) != NGX_OK) { return NULL; } @@ -282,13 +282,18 @@ ngx_wasm_conf_add_op_call(ngx_conf_t *cf, ngx_wasm_ops_engine_t *ops_engine, ngx_wasm_op_t * ngx_wasm_conf_add_op_proxy_wasm(ngx_conf_t *cf, - ngx_wasm_ops_engine_t *ops_engine, ngx_str_t *value, + ngx_wasm_ops_engine_t *ops_engine, ngx_uint_t nvalues, ngx_str_t *value, ngx_proxy_wasm_t *pwmodule) { - ngx_wasm_op_t *op; - ngx_str_t *mod_name; + u_char *p; + ngx_wasm_op_t *op = NULL; + ngx_str_t *arg_name, *arg_config = NULL, *mod_config; - mod_name = &value[1]; + arg_name = &value[1]; + + if (nvalues > 2) { + arg_config = &value[2]; + } op = ngx_pcalloc(cf->pool, sizeof(ngx_wasm_op_t)); if (op == NULL) { @@ -302,14 +307,35 @@ ngx_wasm_conf_add_op_proxy_wasm(ngx_conf_t *cf, | (1 << NGX_HTTP_WASM_HEADER_FILTER_PHASE) | (1 << NGX_HTTP_LOG_PHASE); - if (ngx_wasm_op_add_helper(cf, ops_engine, op, mod_name) != NGX_OK) { - return NULL; + if (ngx_wasm_op_add_helper(cf, ops_engine, op, arg_name) != NGX_OK) { + goto error; } op->conf.proxy_wasm.pwmodule = pwmodule; op->conf.proxy_wasm.pwmodule->module = op->module; + if (arg_config) { + mod_config = &op->conf.proxy_wasm.pwmodule->config; + + mod_config->len = arg_config->len; + mod_config->data = ngx_pnalloc(pwmodule->pool, mod_config->len + 1); + if (mod_config->data == NULL) { + goto error; + } + + p = ngx_copy(mod_config->data, arg_config->data, mod_config->len); + *p = '\0'; + } + return op; + +error: + + if (op) { + ngx_pfree(cf->pool, op); + } + + return NULL; } diff --git a/src/wasm/ngx_wasm_ops.h b/src/wasm/ngx_wasm_ops.h index c385f4e34..ba5c0392d 100644 --- a/src/wasm/ngx_wasm_ops.h +++ b/src/wasm/ngx_wasm_ops.h @@ -77,7 +77,7 @@ ngx_wasm_op_t *ngx_wasm_conf_add_op_call(ngx_conf_t *cf, ngx_wasm_ops_engine_t *ops_engine, ngx_wavm_host_def_t *host, ngx_str_t *value); ngx_wasm_op_t *ngx_wasm_conf_add_op_proxy_wasm(ngx_conf_t *cf, - ngx_wasm_ops_engine_t *ops_engine, ngx_str_t *value, + ngx_wasm_ops_engine_t *ops_engine, ngx_uint_t nvalues, ngx_str_t *value, ngx_proxy_wasm_t *pwmodule); ngx_int_t ngx_wasm_ops_resume(ngx_wasm_op_ctx_t *ctx, ngx_uint_t phaseidx); diff --git a/t/03-proxy_wasm/001-proxy_wasm_directive.t b/t/03-proxy_wasm/001-proxy_wasm_directive.t index 44cdbc170..f11e1ae4d 100644 --- a/t/03-proxy_wasm/001-proxy_wasm_directive.t +++ b/t/03-proxy_wasm/001-proxy_wasm_directive.t @@ -31,7 +31,7 @@ qr/\[emerg\] .*? "proxy_wasm" directive is specified but config has no "wasm" se === TEST 2: proxy_wasm directive - invalid number of arguments --- config location /t { - proxy_wasm a foo; + proxy_wasm a foo bar; return 200; } --- error_log eval diff --git a/t/03-proxy_wasm/002-on_phases.t b/t/03-proxy_wasm/002-on_phases.t new file mode 100644 index 000000000..d2a1dc4c0 --- /dev/null +++ b/t/03-proxy_wasm/002-on_phases.t @@ -0,0 +1,78 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use strict; +use lib '.'; +use t::TestWasm; + +skip_valgrind(); + +#repeat_each(2); + +plan tests => repeat_each() * (blocks() * 7); + +run_tests(); + +__DATA__ + +=== TEST 1: proxy_wasm - on_vm_start +--- main_config + wasm { + module on_phases $TEST_NGINX_CRATES_DIR/on_phases.wasm; + } +--- config + location /t { + proxy_wasm on_phases; + return 200; + } +--- response_body +--- error_log eval +qr/\[info\] .*? \[wasm\] #0 on_vm_start, config_size: 0/ +--- no_error_log +[error] +[crit] +[emerg] +[alert] + + + +=== TEST 2: proxy_wasm - on_configure without configuration +--- main_config + wasm { + module on_phases $TEST_NGINX_CRATES_DIR/on_phases.wasm; + } +--- config + location /t { + proxy_wasm on_phases; + return 200; + } +--- response_body +--- error_log eval +qr/\[info\] .*? \[wasm\] #0 on_configure, config_size: 0/ +--- no_error_log +[error] +[crit] +[emerg] +[alert] + + + +=== TEST 3: proxy_wasm - on_configure with configuration +--- main_config + wasm { + module on_phases $TEST_NGINX_CRATES_DIR/on_phases.wasm; + } +--- config + location /t { + proxy_wasm on_phases 'key=value foo=bar'; + return 200; + } +--- response_body +--- error_log eval +[ + qr/\[info\] .*? \[wasm\] #0 on_configure, config_size: 17/, + qr/\[info\] .*? \[wasm\] #0 config: \{"foo": "bar", "key": "value"\}/ +] +--- no_error_log +[error] +[crit] +[emerg] diff --git a/t/03-proxy_wasm/002-on_tick.t b/t/03-proxy_wasm/003-on_tick.t similarity index 100% rename from t/03-proxy_wasm/002-on_tick.t rename to t/03-proxy_wasm/003-on_tick.t diff --git a/t/03-proxy_wasm/003-on_http_phases.t b/t/03-proxy_wasm/004-on_http_phases.t similarity index 82% rename from t/03-proxy_wasm/003-on_http_phases.t rename to t/03-proxy_wasm/004-on_http_phases.t index ec6ddba67..4c404f6ce 100644 --- a/t/03-proxy_wasm/003-on_http_phases.t +++ b/t/03-proxy_wasm/004-on_http_phases.t @@ -18,11 +18,11 @@ __DATA__ --- load_nginx_modules: ngx_http_echo_module --- main_config wasm { - module on_http_phases $TEST_NGINX_CRATES_DIR/on_http_phases.wasm; + module on_phases $TEST_NGINX_CRATES_DIR/on_phases.wasm; } --- config location /t { - proxy_wasm on_http_phases; + proxy_wasm on_phases; echo ok; } --- response_body @@ -42,11 +42,11 @@ should log 0 response headers (TODO: include default headers) --- load_nginx_modules: ngx_http_echo_module --- main_config wasm { - module on_http_phases $TEST_NGINX_CRATES_DIR/on_http_phases.wasm; + module on_phases $TEST_NGINX_CRATES_DIR/on_phases.wasm; } --- config location /t { - proxy_wasm on_http_phases; + proxy_wasm on_phases; echo ok; } --- response_body @@ -65,11 +65,11 @@ qr/\[info\] .*? \[wasm\] #\d+ on_response_headers, 0 headers/ --- load_nginx_modules: ngx_http_echo_module --- main_config wasm { - module on_http_phases $TEST_NGINX_CRATES_DIR/on_http_phases.wasm; + module on_phases $TEST_NGINX_CRATES_DIR/on_phases.wasm; } --- config location /t { - proxy_wasm on_http_phases; + proxy_wasm on_phases; echo ok; } --- response_body @@ -89,11 +89,11 @@ should cause HTTP 404 from static module (default content handler) --- load_nginx_modules: ngx_http_echo_module --- main_config wasm { - module on_http_phases $TEST_NGINX_CRATES_DIR/on_http_phases.wasm; + module on_phases $TEST_NGINX_CRATES_DIR/on_phases.wasm; } --- config location /t { - proxy_wasm on_http_phases; + proxy_wasm on_phases; echo_status 201; } --- error_code: 404 @@ -115,11 +115,11 @@ qr/404 Not Found/ should produce a response in and of itself, proxy_wasm wraps around --- main_config wasm { - module on_http_phases $TEST_NGINX_CRATES_DIR/on_http_phases.wasm; + module on_phases $TEST_NGINX_CRATES_DIR/on_phases.wasm; } --- config location /t { - proxy_wasm on_http_phases; + proxy_wasm on_phases; return 201; } --- error_code: 201 @@ -140,7 +140,7 @@ should produce a response in and of itself, proxy_wasm wraps around should produce a response from proxy_pass, proxy_wasm wraps around --- main_config wasm { - module on_http_phases $TEST_NGINX_CRATES_DIR/on_http_phases.wasm; + module on_phases $TEST_NGINX_CRATES_DIR/on_phases.wasm; } --- http_config eval qq{ @@ -158,7 +158,7 @@ qq{ } --- config location /t { - proxy_wasm on_http_phases; + proxy_wasm on_phases; proxy_pass http://test_upstream/; } --- error_code: 201 @@ -180,12 +180,12 @@ should not execute a log phase --- load_nginx_modules: ngx_http_echo_module --- main_config wasm { - module on_http_phases $TEST_NGINX_CRATES_DIR/on_http_phases.wasm; + module on_phases $TEST_NGINX_CRATES_DIR/on_phases.wasm; } --- config location /subrequest { internal; - proxy_wasm on_http_phases; + proxy_wasm on_phases; return 201; } diff --git a/t/TestWasm.pm b/t/TestWasm.pm index 7bf37fb84..12a39ed57 100644 --- a/t/TestWasm.pm +++ b/t/TestWasm.pm @@ -59,7 +59,7 @@ add_block_preprocessor(sub { $block->set_value("request", "GET /t"); } - # --- wasm_modules: on_http_phases + # --- wasm_modules: on_phases if (!defined $block->main_config) { my @dyn_modules; diff --git a/t/lib/rust-tests/Cargo.lock b/t/lib/rust-tests/Cargo.lock index 821b2fb84..e5ed4a292 100644 --- a/t/lib/rust-tests/Cargo.lock +++ b/t/lib/rust-tests/Cargo.lock @@ -127,7 +127,7 @@ dependencies = [ ] [[package]] -name = "on-http-phases" +name = "on-phases" version = "0.1.0" dependencies = [ "log", diff --git a/t/lib/rust-tests/Cargo.toml b/t/lib/rust-tests/Cargo.toml index f53ed3aca..917bcb423 100644 --- a/t/lib/rust-tests/Cargo.toml +++ b/t/lib/rust-tests/Cargo.toml @@ -10,6 +10,6 @@ incremental = false members = [ "ngx-rust-tests", "proxy-wasm/on-tick", - "proxy-wasm/on-http-phases", + "proxy-wasm/on-phases", "proxy-wasm/hostcalls", ] diff --git a/t/lib/rust-tests/proxy-wasm/on-http-phases/Cargo.toml b/t/lib/rust-tests/proxy-wasm/on-phases/Cargo.toml similarity index 88% rename from t/lib/rust-tests/proxy-wasm/on-http-phases/Cargo.toml rename to t/lib/rust-tests/proxy-wasm/on-phases/Cargo.toml index cad0f7baa..895fbb4df 100644 --- a/t/lib/rust-tests/proxy-wasm/on-http-phases/Cargo.toml +++ b/t/lib/rust-tests/proxy-wasm/on-phases/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "on-http-phases" +name = "on-phases" version = "0.1.0" authors = ["Thibault Charbonnier "] edition = "2018" diff --git a/t/lib/rust-tests/proxy-wasm/on-http-phases/src/lib.rs b/t/lib/rust-tests/proxy-wasm/on-phases/src/lib.rs similarity index 51% rename from t/lib/rust-tests/proxy-wasm/on-http-phases/src/lib.rs rename to t/lib/rust-tests/proxy-wasm/on-phases/src/lib.rs index 242bf4050..5d9b714bd 100644 --- a/t/lib/rust-tests/proxy-wasm/on-http-phases/src/lib.rs +++ b/t/lib/rust-tests/proxy-wasm/on-phases/src/lib.rs @@ -1,14 +1,14 @@ use log::info; use proxy_wasm::traits::*; use proxy_wasm::types::*; +use std::collections::HashMap; -#[no_mangle] -pub fn _start() { - proxy_wasm::set_log_level(LogLevel::Info); - proxy_wasm::set_root_context(|_| -> Box { Box::new(HttpHeadersRoot) }); +const ROOT_ID: u32 = 0; + +struct HttpHeadersRoot { + config: Option>, } -struct HttpHeadersRoot; impl Context for HttpHeadersRoot {} impl RootContext for HttpHeadersRoot { fn get_type(&self) -> Option { @@ -18,6 +18,29 @@ impl RootContext for HttpHeadersRoot { fn create_http_context(&self, context_id: u32) -> Option> { Some(Box::new(HttpHeaders { context_id })) } + + fn on_vm_start(&mut self, config_size: usize) -> bool { + info!("#{} on_vm_start, config_size: {}", ROOT_ID, config_size); + true + } + + fn on_configure(&mut self, config_size: usize) -> bool { + info!("#{} on_configure, config_size: {}", ROOT_ID, config_size); + + if let Some(config_bytes) = self.get_configuration() { + let config_str = String::from_utf8(config_bytes).unwrap(); + self.config = Some( + config_str + .split_whitespace() + .filter_map(|s| s.split_once('=')) + .map(|(k, v)| (k.to_string(), v.to_string())) + .collect(), + ); + info!("#{} config: {:?}", ROOT_ID, self.config.as_ref().unwrap()); + } + + true + } } struct HttpHeaders { @@ -46,3 +69,11 @@ impl HttpContext for HttpHeaders { info!("#{} on_done", self.context_id); } } + +#[no_mangle] +pub fn _start() { + proxy_wasm::set_log_level(LogLevel::Info); + proxy_wasm::set_root_context(|_| -> Box { + Box::new(HttpHeadersRoot { config: None }) + }); +} diff --git a/valgrind.suppress b/valgrind.suppress index 66ec1d8b5..50fc7eb8e 100644 --- a/valgrind.suppress +++ b/valgrind.suppress @@ -117,11 +117,7 @@ fun:malloc fun:wasm_extern_as_func fun:ngx_wavm_instance_create - fun:ngx_proxy_wasm_module_init - fun:ngx_wasm_ops_engine_init - fun:ngx_http_wasm_init_process - fun:ngx_single_process_cycle - fun:main + ... } { @@ -130,11 +126,7 @@ fun:malloc fun:wasm_func_new_with_env fun:ngx_wavm_instance_create - fun:ngx_proxy_wasm_module_init - fun:ngx_wasm_ops_engine_init - fun:ngx_http_wasm_init_process - fun:ngx_single_process_cycle - fun:main + ... } { @@ -227,10 +219,23 @@ ... } { - + + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + fun:_ZN13wasmer_engine8tunables8Tunables13create_tables17ha5e7563bb365644fE + fun:_ZN13wasmer_engine8artifact8Artifact11instantiate17h363136c5126093ffE + fun:_ZN6wasmer6module6Module11instantiate17h47071a99dba52461E + fun:_ZN6wasmer8instance8Instance3new17h857eba1234ba725bE + fun:wasm_instance_new + ... +} +{ + Memcheck:Leak match-leak-kinds: definite fun:malloc + fun:_ZN84_$LT$wasmer..tunables..BaseTunables$u20$as$u20$wasmer_engine..tunables..Tunables$GT$15create_vm_table17he2b7d0253d463835E fun:_ZN13wasmer_engine8tunables8Tunables13create_tables17ha5e7563bb365644fE fun:_ZN13wasmer_engine8artifact8Artifact11instantiate17h363136c5126093ffE fun:_ZN6wasmer6module6Module11instantiate17h47071a99dba52461E @@ -239,7 +244,7 @@ ... } { - + Memcheck:Leak match-leak-kinds: definite fun:malloc @@ -251,7 +256,7 @@ ... } { - + Memcheck:Leak match-leak-kinds: definite fun:malloc