From 3434919b9604103c2aaf67424a2a568f3d35c53f Mon Sep 17 00:00:00 2001 From: Caio Ramos Casimiro Date: Mon, 28 Oct 2024 16:41:20 +0000 Subject: [PATCH 01/60] feat(wasm) disallow some characters from module names We will use `:` for Proxy-Wasm metrics prefix separator. Also disallow spaces and tabs. --- docs/DIRECTIVES.md | 1 + src/wasm/ngx_wasm_directives.c | 14 +++++ t/01-wasm/directives/001-module_directive.t | 66 +++++++++++++++++---- 3 files changed, 69 insertions(+), 12 deletions(-) diff --git a/docs/DIRECTIVES.md b/docs/DIRECTIVES.md index 23ce03210..f19fb9be7 100644 --- a/docs/DIRECTIVES.md +++ b/docs/DIRECTIVES.md @@ -256,6 +256,7 @@ module Load a Wasm module from disk. - `name` is expected to be unique since it will be used to refer to this module. + It also cannot contain tabs, spaces, or colons. - `path` must point to a bytecode file whose format is `.wasm` (binary) or `.wat` (text). - `config` is an optional configuration string passed to `on_vm_start` when diff --git a/src/wasm/ngx_wasm_directives.c b/src/wasm/ngx_wasm_directives.c index 0a51e308c..6c78a94a7 100644 --- a/src/wasm/ngx_wasm_directives.c +++ b/src/wasm/ngx_wasm_directives.c @@ -257,6 +257,7 @@ ngx_wasm_core_shm_generic_directive(ngx_conf_t *cf, ngx_command_t *cmd, char * ngx_wasm_core_module_directive(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { + size_t i; ngx_int_t rc; ngx_str_t *value, *name, *path; ngx_str_t *config = NULL; @@ -272,6 +273,19 @@ ngx_wasm_core_module_directive(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } + for (i = 0; i < name->len; i++) { + if (name->data[i] == ' ' + || name->data[i] == '\t' + || name->data[i] == ':') + { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "[wasm] invalid module name \"%V\":" + " character not allowed \"%c\"", + name, name->data[i]); + return NGX_CONF_ERROR; + } + } + if (!path->len) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "[wasm] invalid module path \"%V\"", path); diff --git a/t/01-wasm/directives/001-module_directive.t b/t/01-wasm/directives/001-module_directive.t index da998b47c..8a278ea8b 100644 --- a/t/01-wasm/directives/001-module_directive.t +++ b/t/01-wasm/directives/001-module_directive.t @@ -79,7 +79,7 @@ qr/\[emerg\] .*? invalid number of arguments in "module" directive/ -=== TEST 5: module directive - bad name +=== TEST 5: module directive - empty name --- main_config wasm { module '' $TEST_NGINX_HTML_DIR/a.wat; @@ -93,7 +93,49 @@ qr/\[emerg\] .*? invalid module name ""/ -=== TEST 6: module directive - bad path +=== TEST 6: module directive - bad name, space +--- main_config + wasm { + module 'bad name' $TEST_NGINX_HTML_DIR/a.wat; + } +--- error_log eval +qr/\[emerg\] .*? invalid module name "bad name": character not allowed " "/ +--- no_error_log +[error] +[crit] +--- must_die + + + +=== TEST 7: module directive - bad name, tab +--- main_config + wasm { + module 'bad\tname' $TEST_NGINX_HTML_DIR/a.wat; + } +--- error_log eval +qr/\[emerg\] .*? invalid module name "bad\tname": character not allowed "\t"/ +--- no_error_log +[error] +[crit] +--- must_die + + + +=== TEST 8: module directive - bad name, colon +--- main_config + wasm { + module 'bad:name' $TEST_NGINX_HTML_DIR/a.wat; + } +--- error_log eval +qr/\[emerg\] .*? invalid module name "bad:name": character not allowed ":"/ +--- no_error_log +[error] +[crit] +--- must_die + + + +=== TEST 9: module directive - bad path --- main_config wasm { module a ''; @@ -107,7 +149,7 @@ qr/\[emerg\] .*? invalid module path ""/ -=== TEST 7: module directive - already defined +=== TEST 10: module directive - already defined --- main_config wasm { module a $TEST_NGINX_HTML_DIR/a.wat; @@ -125,7 +167,7 @@ qr/\[emerg\] .*? "a" module already defined/ -=== TEST 8: module directive - no such path +=== TEST 11: module directive - no such path --- main_config wasm { module a $TEST_NGINX_HTML_DIR/none.wat; @@ -139,7 +181,7 @@ qr/\[emerg\] .*? \[wasm\] open\(\) ".*?none\.wat" failed \(2: No such file or di -=== TEST 9: module directive - no .wat bytes - wasmtime, wasmer +=== TEST 12: module directive - no .wat bytes - wasmtime, wasmer --- skip_eval: 4: !( $::nginxV =~ m/wasmtime/ || $::nginxV =~ m/wasmer/ ) --- main_config wasm { @@ -158,7 +200,7 @@ qr/\[emerg\] .*? \[wasm\] open\(\) ".*?none\.wat" failed \(2: No such file or di -=== TEST 10: module directive - no .wat bytes - v8 +=== TEST 13: module directive - no .wat bytes - v8 --- skip_eval: 4: $::nginxV !~ m/v8/ --- main_config wasm { @@ -177,7 +219,7 @@ qr/\[emerg\] .*? \[wasm\] open\(\) ".*?none\.wat" failed \(2: No such file or di -=== TEST 11: module directive - no .wasm bytes +=== TEST 14: module directive - no .wasm bytes --- main_config wasm { module a $TEST_NGINX_HTML_DIR/a.wasm; @@ -195,7 +237,7 @@ qr/\[emerg\] .*? \[wasm\] open\(\) ".*?none\.wat" failed \(2: No such file or di -=== TEST 12: module directive - invalid .wat module - wasmtime, wasmer +=== TEST 15: module directive - invalid .wat module - wasmtime, wasmer --- skip_eval: 4: !( $::nginxV =~ m/wasmtime/ || $::nginxV =~ m/wasmer/ ) --- main_config wasm { @@ -217,7 +259,7 @@ qr/\[emerg\] .*? \[wasm\] open\(\) ".*?none\.wat" failed \(2: No such file or di -=== TEST 13: module directive - invalid .wat module - v8 +=== TEST 16: module directive - invalid .wat module - v8 --- skip_eval: 4: $::nginxV !~ m/v8/ --- main_config wasm { @@ -239,7 +281,7 @@ qr/\[emerg\] .*? \[wasm\] open\(\) ".*?none\.wat" failed \(2: No such file or di -=== TEST 14: module directive - invalid module (NYI import types) +=== TEST 17: module directive - invalid module (NYI import types) 'daemon off' must be set to check exit_code is 2 Valgrind mode already writes 'daemon off' HUP mode does not catch the worker exit_code @@ -264,7 +306,7 @@ qr/\[alert\] .*? \[wasm\] NYI: module import type not supported/ -=== TEST 15: module directive - invalid module (missing host function in env) +=== TEST 18: module directive - invalid module (missing host function in env) 'daemon off' must be set to check exit_code is 2 Valgrind mode already writes 'daemon off' HUP mode does not catch the worker exit_code @@ -291,7 +333,7 @@ qq{ -=== TEST 16: module directive - invalid module (missing WASI function) +=== TEST 19: module directive - invalid module (missing WASI function) 'daemon off' must be set to check exit_code is 2 Valgrind mode already writes 'daemon off' HUP mode does not catch the worker exit_code From 630a5e7de0b4cf8f8e14ad0033a4998a97d6fe6b Mon Sep 17 00:00:00 2001 From: Caio Ramos Casimiro Date: Mon, 28 Oct 2024 14:55:03 +0000 Subject: [PATCH 02/60] feat(metrics) switch metric name metadata separator to ':' Switch from `.` to `:` since module names can contain dots, making the prefix difficult to parse. --- docs/METRICS.md | 6 +++--- lib/resty/wasmx/shm.lua | 12 ++++++------ src/common/proxy_wasm/ngx_proxy_wasm_host.c | 2 +- t/04-openresty/ffi/shm/020-metrics_define.t | 8 ++++---- t/04-openresty/ffi/shm/025-metrics_get_by_name.t | 10 +++++----- t/04-openresty/ffi/shm/026-metrics_iterate_keys.t | 6 +++--- t/04-openresty/ffi/shm/027-metrics_get_keys.t | 6 +++--- 7 files changed, 25 insertions(+), 25 deletions(-) diff --git a/docs/METRICS.md b/docs/METRICS.md index ea43e77f7..a5c4981bb 100644 --- a/docs/METRICS.md +++ b/docs/METRICS.md @@ -38,9 +38,9 @@ gauge, or a histogram. ## Name Prefixing To avoid naming conflicts between Proxy-Wasm filters, the name of a metric is -always prefixed with: `pw.{filter_name}.{metric_name}`. This means that a metric -named `a_counter` inserted by `a_filter` will have its name stored as: -`pw.a_filter.a_counter`. +always prefixed with colon-separated metadata: `pw:{filter_name}:`. This means +that a metric named `a_counter` inserted by `a_filter` will have its name stored +as: `pw:a_filter:a_counter`. Thus, the maximum length of a metric name configured via [max_metric_name_length] is enforced on the prefixed name and may need to be diff --git a/lib/resty/wasmx/shm.lua b/lib/resty/wasmx/shm.lua index 50880099c..a87627294 100644 --- a/lib/resty/wasmx/shm.lua +++ b/lib/resty/wasmx/shm.lua @@ -403,7 +403,7 @@ local function metrics_define(zone, name, metric_type, opts) end end - name = "lua." .. name + name = "lua:" .. name local cname = ffi_new("ngx_str_t", { data = name, len = #name }) local m_id = ffi_new("uint32_t[1]") @@ -528,12 +528,12 @@ end --- --- ngx_wasm_module internally prefixes metric names according to --- where they have been defined, e.g. "pw.filter.*", "lua.*", or --- "wa.*". +-- ngx_wasm_module internally prefixes metric names with colon-separated +-- metadata indicating where they have been defined, e.g. "pw:a_filter:*", +-- "lua:*", or "wa:". -- -- metrics_get_by_name assumes it is retrieving a Lua-defined metric --- and will by default prefix the given name with `lua.` +-- and will by default prefix the given name with `lua:` -- -- This behavior can be disabled by passing `opts.prefix` as false. local function metrics_get_by_name(zone, name, opts) @@ -554,7 +554,7 @@ local function metrics_get_by_name(zone, name, opts) ffi_fill(_mbuf, _mbs) ffi_fill(_hbuf, _hbs) - name = (opts and opts.prefix == false) and name or "lua." .. name + name = (opts and opts.prefix == false) and name or "lua:" .. name local cname = ffi_new("ngx_str_t", { data = name, len = #name }) diff --git a/src/common/proxy_wasm/ngx_proxy_wasm_host.c b/src/common/proxy_wasm/ngx_proxy_wasm_host.c index d92ffddb7..efde7b98f 100644 --- a/src/common/proxy_wasm/ngx_proxy_wasm_host.c +++ b/src/common/proxy_wasm/ngx_proxy_wasm_host.c @@ -1635,7 +1635,7 @@ ngx_proxy_wasm_hfuncs_define_metric(ngx_wavm_instance_t *instance, } prefixed_name.data = buf; - prefixed_name.len = ngx_sprintf(buf, "pw.%V.%V", filter_name, &name) + prefixed_name.len = ngx_sprintf(buf, "pw:%V:%V", filter_name, &name) - buf; rc = ngx_wa_metrics_define(metrics, &prefixed_name, type, NULL, 0, id); diff --git a/t/04-openresty/ffi/shm/020-metrics_define.t b/t/04-openresty/ffi/shm/020-metrics_define.t index c1393cf3a..966bb06ff 100644 --- a/t/04-openresty/ffi/shm/020-metrics_define.t +++ b/t/04-openresty/ffi/shm/020-metrics_define.t @@ -40,10 +40,10 @@ __DATA__ ok --- error_log eval [ - qr/.*? \[debug\] .*? defined counter "lua.c1" with id \d+/, - qr/.*? \[debug\] .*? defined gauge "lua.g1" with id \d+/, - qr/.*? \[debug\] .*? defined histogram "lua.h1" with id \d+/, - qr/.*? \[debug\] .*? defined histogram "lua.ch1" with id \d+/, + qr/.*? \[debug\] .*? defined counter "lua:c1" with id \d+/, + qr/.*? \[debug\] .*? defined gauge "lua:g1" with id \d+/, + qr/.*? \[debug\] .*? defined histogram "lua:h1" with id \d+/, + qr/.*? \[debug\] .*? defined histogram "lua:ch1" with id \d+/, ] --- no_error_log [error] diff --git a/t/04-openresty/ffi/shm/025-metrics_get_by_name.t b/t/04-openresty/ffi/shm/025-metrics_get_by_name.t index ff1f706ba..76943ef27 100644 --- a/t/04-openresty/ffi/shm/025-metrics_get_by_name.t +++ b/t/04-openresty/ffi/shm/025-metrics_get_by_name.t @@ -12,7 +12,7 @@ run_tests(); __DATA__ === TEST 1: shm_metrics - get_by_name() sanity FFI-defined metrics -prefix: lua.* +colon-separated prefix: "lua:*" --- valgrind --- metrics: 16k --- config @@ -51,7 +51,7 @@ ch1: {sum=2,type="histogram",value={{count=0,ub=1},{count=1,ub=3},{count=0,ub=5} === TEST 2: shm_metrics - get_by_name() sanity non-FFI-defined metrics -prefix: pw.hostcalls.* +colon-separated prefix: "pw:hostcalls:*" --- wasm_modules: hostcalls --- config eval my $record_histograms; @@ -84,9 +84,9 @@ qq{ local shm = require "resty.wasmx.shm" local pretty = require "pl.pretty" - ngx.say("c1: ", pretty.write(shm.metrics:get_by_name("pw.hostcalls.c1", { prefix = false }), "")) - ngx.say("g1: ", pretty.write(shm.metrics:get_by_name("pw.hostcalls.g1", { prefix = false }), "")) - ngx.say("h1: ", pretty.write(shm.metrics:get_by_name("pw.hostcalls.h1", { prefix = false }), "")) + ngx.say("c1: ", pretty.write(shm.metrics:get_by_name("pw:hostcalls:c1", { prefix = false }), "")) + ngx.say("g1: ", pretty.write(shm.metrics:get_by_name("pw:hostcalls:g1", { prefix = false }), "")) + ngx.say("h1: ", pretty.write(shm.metrics:get_by_name("pw:hostcalls:h1", { prefix = false }), "")) } } } diff --git a/t/04-openresty/ffi/shm/026-metrics_iterate_keys.t b/t/04-openresty/ffi/shm/026-metrics_iterate_keys.t index e0cf4b3cd..6011f5393 100644 --- a/t/04-openresty/ffi/shm/026-metrics_iterate_keys.t +++ b/t/04-openresty/ffi/shm/026-metrics_iterate_keys.t @@ -32,9 +32,9 @@ __DATA__ } } --- response_body -lua.c1 -lua.g1 -lua.h1 +lua:c1 +lua:g1 +lua:h1 --- no_error_log [error] [crit] diff --git a/t/04-openresty/ffi/shm/027-metrics_get_keys.t b/t/04-openresty/ffi/shm/027-metrics_get_keys.t index 69513503f..dbb8f8cee 100644 --- a/t/04-openresty/ffi/shm/027-metrics_get_keys.t +++ b/t/04-openresty/ffi/shm/027-metrics_get_keys.t @@ -30,9 +30,9 @@ __DATA__ } } --- response_body -lua.c1 -lua.g1 -lua.h1 +lua:c1 +lua:g1 +lua:h1 --- no_error_log [error] [crit] From 741b22a9af7db531ef8125d19430d5aa0f4bdf6d Mon Sep 17 00:00:00 2001 From: Caio Ramos Casimiro Date: Wed, 30 Oct 2024 16:11:53 +0000 Subject: [PATCH 03/60] feat(ffi) produce an error on 'shm:set()' when already locked Catch the case and produce an error instead of entering a deadlock. --- lib/resty/wasmx/shm.lua | 4 ++++ src/common/lua/ngx_wasm_lua_ffi.c | 5 +++++ t/04-openresty/ffi/shm/002-kv_set.t | 12 ++++++------ 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/lib/resty/wasmx/shm.lua b/lib/resty/wasmx/shm.lua index a87627294..05a0db834 100644 --- a/lib/resty/wasmx/shm.lua +++ b/lib/resty/wasmx/shm.lua @@ -346,6 +346,10 @@ local function shm_kv_set(zone, key, value, cas) return nil, "no memory" end + if rc == FFI_ABORT then + return nil, "locked" + end + assert_debug(rc == FFI_OK) return tonumber(written[0]) diff --git a/src/common/lua/ngx_wasm_lua_ffi.c b/src/common/lua/ngx_wasm_lua_ffi.c index 12cb5b6b7..8e1984c6f 100644 --- a/src/common/lua/ngx_wasm_lua_ffi.c +++ b/src/common/lua/ngx_wasm_lua_ffi.c @@ -397,6 +397,11 @@ ngx_wa_ffi_shm_kv_set(ngx_wa_shm_t *shm, ngx_str_t *k, ngx_str_t *v, ngx_wa_assert(shm->type == NGX_WA_SHM_TYPE_KV); + if (ngx_wa_shm_locked(shm)) { + /* already locked by the current worker */ + return NGX_ABORT; + } + ngx_wa_shm_lock(shm); rc = ngx_wa_shm_kv_set_locked(shm, k, v, cas, written); diff --git a/t/04-openresty/ffi/shm/002-kv_set.t b/t/04-openresty/ffi/shm/002-kv_set.t index 68f821a90..0612c0b89 100644 --- a/t/04-openresty/ffi/shm/002-kv_set.t +++ b/t/04-openresty/ffi/shm/002-kv_set.t @@ -105,8 +105,6 @@ cas must be a number === TEST 4: shm_kv - set() on locked shm ---- timeout: 1 ---- abort --- shm_kv: kv 16k --- config location /t { @@ -115,15 +113,17 @@ cas must be a number shm.kv:lock() - shm.kv:set("kv/k1", "v1") + local written, err = shm.kv:set("kv/k1", "v1") shm.kv:unlock() - ngx.say("fail") + assert(written == nil) + + ngx.say(err) } } ---- error_code: +--- response_body +locked --- no_error_log [error] [crit] -[emerg] From d04cb7f0d72e74d55500224e11956883fe32dee3 Mon Sep 17 00:00:00 2001 From: Caio Ramos Casimiro Date: Tue, 29 Oct 2024 11:50:17 +0000 Subject: [PATCH 04/60] chore(ci) prevent dnsmasq from being auto-started on install --- .github/actions/setup-httpbin-server/action.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/actions/setup-httpbin-server/action.yml b/.github/actions/setup-httpbin-server/action.yml index 5be5f7c10..55a4e15eb 100644 --- a/.github/actions/setup-httpbin-server/action.yml +++ b/.github/actions/setup-httpbin-server/action.yml @@ -30,6 +30,10 @@ runs: if: ${{ contains(inputs.os, 'ubuntu') }} shell: bash run: | + # brute-forcing Ubuntu to not start dnsmasq on install + echo "exit 101" | sudo tee /usr/sbin/policy-rc.d + sudo chmod +x /usr/sbin/policy-rc.d + sudo apt-get update sudo apt-get install -y dnsmasq - name: 'Setup deps - macOS' From 8aadfa50aecbac434c6e93a98a1207e8f0788430 Mon Sep 17 00:00:00 2001 From: Caio Ramos Casimiro Date: Tue, 29 Oct 2024 12:14:58 +0000 Subject: [PATCH 05/60] chore(ci) cache httpbin docker image CI has been failing rather frequently due to Docker registry returning `502 Bad Gateway` when the `setup-httpbin-server` action attempts to pull httpbin's docker image. In fact, this image has been pulled by 16 jobs (Unit and Valgrind) for every GHA workflow run. This might explain why we eventually fail to pull it. Caching it should greatly reduce the number of times httpbin image is actually pulled, which should prevent us from being rate limited. --- .github/actions/load-docker-image/action.yml | 52 +++++++++++++++++++ .../actions/setup-httpbin-server/action.yml | 26 +++++++--- 2 files changed, 71 insertions(+), 7 deletions(-) create mode 100644 .github/actions/load-docker-image/action.yml diff --git a/.github/actions/load-docker-image/action.yml b/.github/actions/load-docker-image/action.yml new file mode 100644 index 000000000..9574caf02 --- /dev/null +++ b/.github/actions/load-docker-image/action.yml @@ -0,0 +1,52 @@ +name: load-docker-image +decription: | + Pull a docker image, cache and load it. + +inputs: + image: + required: true + type: string + cache_dir: + required: false + type: string + default: "$GITHUB_WORKSPACE/.docker-images-cache" + +runs: + using: 'composite' + steps: + - name: Create cache directory + shell: bash + run: mkdir -p ${{ inputs.cache_dir }} + + - name: Setup cache + uses: actions/cache@v4 + with: + path: ${{ inputs.cache_dir }} + key: pulled-docker-images + + - name: Setup cache path + id: cache_setup + shell: bash + run: | + filename="$(echo ${{ inputs.image }} | sed 's/\//_/g').tar" + cache_path="${{ inputs.cache_dir }}/$filename" + + if [ -f "$cache_path" ]; then + echo "cache_hit=true" >> $GITHUB_OUTPUT + else + echo "cache_hit=false" >> $GITHUB_OUTPUT + fi + + echo "cache_path=$cache_path" >> $GITHUB_OUTPUT + + - name: Pull Docker image + if: steps.cache_setup.outputs.cache_hit == 'false' + shell: bash + run: | + docker pull ${{ inputs.image }} + docker save -o ${{ steps.cache_setup.outputs.cache_path }} ${{ inputs.image }} + + - name: Load Docker image from cache + if: steps.cache_setup.outputs.cache-hit == 'true' + shell: bash + run: docker load -i ${{ steps.cache_setup.outputs.cache_path }} diff --git a/.github/actions/setup-httpbin-server/action.yml b/.github/actions/setup-httpbin-server/action.yml index 55a4e15eb..b480cf23b 100644 --- a/.github/actions/setup-httpbin-server/action.yml +++ b/.github/actions/setup-httpbin-server/action.yml @@ -36,24 +36,26 @@ runs: sudo apt-get update sudo apt-get install -y dnsmasq + - name: 'Setup deps - macOS' if: ${{ contains(inputs.os, 'macos') }} shell: bash run: | brew install dnsmasq docker colima colima start --network-address + - name: Setup Docker image tag id: setup shell: bash run: | - if [ -z "${{ env.ACT }}" && -n "${{ inputs.ghcr_password }}" ]; then - echo "push=true" >> $GITHUB_OUTPUT - echo "tag=ghcr.io/kong/wasmx-ci-httpbin-proxy:latest" >> $GITHUB_OUTPUT + if [ -z "${{ env.ACT }}" && -n "${{ inputs.ghcr_password }}" ]; then + echo "push=true" >> $GITHUB_OUTPUT + echo "tag=ghcr.io/kong/wasmx-ci-httpbin-proxy:latest" >> $GITHUB_OUTPUT + else + echo "push=false" >> $GITHUB_OUTPUT + echo "tag=wasmx-ci-httpbin-proxy:latest" >> $GITHUB_OUTPUT + fi - else - echo "push=false" >> $GITHUB_OUTPUT - echo "tag=wasmx-ci-httpbin-proxy:latest" >> $GITHUB_OUTPUT - fi - name: Login to GitHub Container Registry if: ${{ steps.setup.outputs.push == 'true' }} uses: docker/login-action@v3 @@ -61,9 +63,11 @@ runs: registry: ghcr.io username: ${{ inputs.ghcr_username }} password: ${{ inputs.ghcr_password }} + - name: Setup Docker Buildx if: ${{ !env.ACT }} uses: docker/setup-buildx-action@v3 + - name: Build httpbin-proxy image uses: docker/build-push-action@v5 with: @@ -74,6 +78,13 @@ runs: context: . cache-from: type=gha cache-to: type=gha,mode=max + + - name: Load httpbin image + if: ${{ !env.ACT }} + uses: ./.github/actions/load-docker-image + with: + image: 'kennethreitz/httpbin' + - name: Start dnsmasq shell: bash run: | @@ -83,6 +94,7 @@ runs: --server=${{ inputs.upstream_dns_server }} \ --address=/httpbin.org/127.0.0.1 \ --address=/example.com/127.0.0.1 + - name: Start httpbin proxy + server shell: bash run: | From 9238d4a611d9e8574f5264d977c7f7d4fa3cb2cf Mon Sep 17 00:00:00 2001 From: Thibault Charbonnier Date: Tue, 12 Nov 2024 09:54:16 -0800 Subject: [PATCH 06/60] tests(lib) catch possible 'dispatch_http_call' failures --- t/lib/Cargo.lock | 1 + .../context-checks/src/lib.rs | 14 ++++++++++++-- t/lib/proxy-wasm-tests/hostcalls/src/lib.rs | 15 ++++++++++++--- .../hostcalls/src/types/test_http.rs | 15 ++++++++++++--- .../rust-sdk-ver-zero-one/Cargo.toml | 1 + .../rust-sdk-ver-zero-one/src/filter.rs | 19 ++++++++++++++++--- 6 files changed, 54 insertions(+), 11 deletions(-) diff --git a/t/lib/Cargo.lock b/t/lib/Cargo.lock index c1fe84706..4e418ff3c 100644 --- a/t/lib/Cargo.lock +++ b/t/lib/Cargo.lock @@ -369,6 +369,7 @@ name = "rust-sdk-ver-zero-one" version = "0.1.0" dependencies = [ "http", + "log", "proxy-wasm 0.1.4", ] 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 eea6eae50..1d63167e6 100644 --- a/t/lib/proxy-wasm-tests/context-checks/src/lib.rs +++ b/t/lib/proxy-wasm-tests/context-checks/src/lib.rs @@ -69,13 +69,23 @@ impl HttpContext for TestHttp { .get_config("on_http_dispatch_response") .is_some() { - let _ = self.dispatch_http_call( + match self.dispatch_http_call( self.tester.get_config("host").unwrap_or(""), vec![(":path", "/dispatch"), (":method", "GET")], None, vec![], Duration::from_secs(0), - ); + ) { + Ok(_) => {} + Err(status) => match status { + Status::BadArgument => error!("dispatch_http_call: bad argument"), + Status::InternalFailure => error!("dispatch_http_call: internal failure"), + status => panic!( + "dispatch_http_call: unexpected status \"{}\"", + status as u32 + ), + }, + } return Action::Pause; } diff --git a/t/lib/proxy-wasm-tests/hostcalls/src/lib.rs b/t/lib/proxy-wasm-tests/hostcalls/src/lib.rs index aaf25142d..95f2a3e44 100644 --- a/t/lib/proxy-wasm-tests/hostcalls/src/lib.rs +++ b/t/lib/proxy-wasm-tests/hostcalls/src/lib.rs @@ -156,14 +156,23 @@ impl RootContext for TestRoot { info!("call {}", self.n_sync_calls); - self.dispatch_http_call( + match self.dispatch_http_call( self.get_config("host").unwrap_or(""), headers, self.get_config("body").map(|v| v.as_bytes()), vec![], timeout, - ) - .unwrap(); + ) { + Ok(_) => {} + Err(status) => match status { + Status::BadArgument => error!("dispatch_http_call: bad argument"), + Status::InternalFailure => error!("dispatch_http_call: internal failure"), + status => panic!( + "dispatch_http_call: unexpected status \"{}\"", + status as u32 + ), + }, + } } _ => (), } 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 5240f512e..6601ea288 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 @@ -247,13 +247,22 @@ impl TestHttp { None => self.get_config("host").unwrap_or(""), }; - self.dispatch_http_call( + match self.dispatch_http_call( host, headers, self.get_config("body").map(|v| v.as_bytes()), vec![], timeout, - ) - .unwrap(); + ) { + Ok(_) => {} + Err(status) => match status { + Status::BadArgument => error!("dispatch_http_call: bad argument"), + Status::InternalFailure => error!("dispatch_http_call: internal failure"), + status => panic!( + "dispatch_http_call: unexpected status \"{}\"", + status as u32 + ), + }, + } } } diff --git a/t/lib/proxy-wasm-tests/rust-sdk-ver-zero-one/Cargo.toml b/t/lib/proxy-wasm-tests/rust-sdk-ver-zero-one/Cargo.toml index 887a8b326..e9a4925a8 100644 --- a/t/lib/proxy-wasm-tests/rust-sdk-ver-zero-one/Cargo.toml +++ b/t/lib/proxy-wasm-tests/rust-sdk-ver-zero-one/Cargo.toml @@ -11,3 +11,4 @@ crate-type = ["cdylib"] [dependencies] proxy-wasm = "0.1" http = "0.2" +log = "0.4" diff --git a/t/lib/proxy-wasm-tests/rust-sdk-ver-zero-one/src/filter.rs b/t/lib/proxy-wasm-tests/rust-sdk-ver-zero-one/src/filter.rs index a8a63abd3..fcc7379f7 100644 --- a/t/lib/proxy-wasm-tests/rust-sdk-ver-zero-one/src/filter.rs +++ b/t/lib/proxy-wasm-tests/rust-sdk-ver-zero-one/src/filter.rs @@ -1,6 +1,7 @@ #![allow(clippy::single_match)] use http::StatusCode; +use log::*; use proxy_wasm::{traits::*, types::*}; use std::collections::HashMap; use std::time::Duration; @@ -88,7 +89,7 @@ impl HttpContext for TestHttpHostcalls { if let Some(test) = self.config.get("test") { match test.as_str() { "dispatch" => { - self.dispatch_http_call( + match self.dispatch_http_call( self.config.get("host").map(|v| v.as_str()).unwrap_or(""), vec![ (":method", "GET"), @@ -104,8 +105,20 @@ impl HttpContext for TestHttpHostcalls { self.config.get("body").map(|v| v.as_bytes()), vec![], Duration::from_secs(3), - ) - .unwrap(); + ) { + Ok(_) => {} + Err(status) => match status { + Status::BadArgument => error!("dispatch_http_call: bad argument"), + Status::InternalFailure => { + error!("dispatch_http_call: internal failure") + } + status => panic!( + "dispatch_http_call: unexpected status \"{}\"", + status as u32 + ), + }, + } + return Action::Pause; } "proxy_get_header_map_value" => { From 7ccae8fbe1d4813734b2308f9ad3269909d79790 Mon Sep 17 00:00:00 2001 From: Hisham Muhammad Date: Wed, 20 Nov 2024 17:44:23 -0300 Subject: [PATCH 07/60] tests(proxy-wasm) test querystring support in 'dispatch_http_call' --- .../hfuncs/130-proxy_dispatch_http.t | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) 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..6136176ac 100644 --- a/t/03-proxy_wasm/hfuncs/130-proxy_dispatch_http.t +++ b/t/03-proxy_wasm/hfuncs/130-proxy_dispatch_http.t @@ -301,7 +301,7 @@ ok echo ok; } --- request -GET /t +POST /t Hello world --- response_body @@ -329,7 +329,7 @@ ok echo failed; } --- request -GET /t +POST /t Hello world --- response_body @@ -1329,3 +1329,27 @@ cannot override the "Host" header, skipping cannot override the "Connection" header, skipping --- no_error_log [error] + + + +=== TEST 51: proxy_wasm - dispatch_http_call() can use ':path' with querystring +--- load_nginx_modules: ngx_http_echo_module +--- wasm_modules: hostcalls +--- config + location /dispatched { + return 200 "$request_uri $uri $is_args $args"; + } + + location /t { + proxy_wasm hostcalls 'on=request_headers \ + test=/t/dispatch_http_call \ + host=127.0.0.1:$TEST_NGINX_SERVER_PORT \ + path=/dispatched?foo=bar \ + on_http_call_response=echo_response_body'; + echo failed; + } +--- response_body +/dispatched?foo=bar /dispatched ? foo=bar +--- no_error_log +[error] +[crit] From d6ac8f847ccdcca2c893e3f9ae9ff49a50198ba5 Mon Sep 17 00:00:00 2001 From: Hisham Muhammad Date: Wed, 20 Nov 2024 17:45:07 -0300 Subject: [PATCH 08/60] feat(proxy-wasm) support setting querystring via ':path' --- src/common/proxy_wasm/ngx_proxy_wasm_maps.c | 14 +- .../111-proxy_set_http_request_header.t | 218 ++++++++++++++++-- .../hfuncs/130-proxy_dispatch_http.t | 28 +++ 3 files changed, 234 insertions(+), 26 deletions(-) diff --git a/src/common/proxy_wasm/ngx_proxy_wasm_maps.c b/src/common/proxy_wasm/ngx_proxy_wasm_maps.c index 20c175bea..a80c6f79e 100644 --- a/src/common/proxy_wasm/ngx_proxy_wasm_maps.c +++ b/src/common/proxy_wasm/ngx_proxy_wasm_maps.c @@ -507,19 +507,21 @@ static ngx_int_t ngx_proxy_wasm_maps_set_path(ngx_wavm_instance_t *instance, ngx_str_t *value, ngx_proxy_wasm_map_type_e map_type) { + size_t len = value->len; + u_char *query; ngx_proxy_wasm_exec_t *pwexec = ngx_proxy_wasm_instance2pwexec(instance); ngx_proxy_wasm_ctx_t *pwctx = pwexec->parent; ngx_http_wasm_req_ctx_t *rctx = ngx_http_proxy_wasm_get_rctx(instance); ngx_http_request_t *r = rctx->r; - if (ngx_strchr(value->data, '?')) { - ngx_wavm_instance_trap_printf(instance, - "NYI - cannot set request path " - "with querystring"); - return NGX_ERROR; + query = (u_char *) ngx_strchr(value->data, '?'); + if (query) { + len = query - value->data; + r->args.len = value->len - len - 1; + r->args.data = query + 1; } - r->uri.len = value->len; + r->uri.len = len; r->uri.data = value->data; if (pwctx->path.len) { diff --git a/t/03-proxy_wasm/hfuncs/111-proxy_set_http_request_header.t b/t/03-proxy_wasm/hfuncs/111-proxy_set_http_request_header.t index a9cc579f6..c28637729 100644 --- a/t/03-proxy_wasm/hfuncs/111-proxy_set_http_request_header.t +++ b/t/03-proxy_wasm/hfuncs/111-proxy_set_http_request_header.t @@ -9,7 +9,7 @@ run_tests(); __DATA__ -=== TEST 1: proxy_wasm - set_http_request_header() sets a new non-builtin header +=== TEST 1: proxy_wasm - set_http_request_header() set a new non-builtin header --- valgrind --- wasm_modules: hostcalls --- config @@ -32,7 +32,7 @@ qr/.*? on_request_headers, 2 headers.* -=== TEST 2: proxy_wasm - set_http_request_header() sets a new non-builtin header (case-sensitive) +=== TEST 2: proxy_wasm - set_http_request_header() set a new non-builtin header (case-sensitive) --- wasm_modules: hostcalls --- config location /t { @@ -54,7 +54,7 @@ qr/.*? on_request_headers, 2 headers.* -=== TEST 3: proxy_wasm - set_http_request_header() sets a non-builtin headers when many headers exist +=== TEST 3: proxy_wasm - set_http_request_header() set a non-builtin headers when many headers exist --- valgrind --- wasm_modules: hostcalls --- config @@ -97,7 +97,7 @@ Connection: close -=== TEST 5: proxy_wasm - set_http_request_header() sets the same non-builtin header multiple times +=== TEST 5: proxy_wasm - set_http_request_header() set the same non-builtin header multiple times --- wasm_modules: hostcalls --- config location /t { @@ -127,7 +127,7 @@ qr/.*? on_request_headers, 3 headers.* -=== TEST 6: proxy_wasm - set_http_request_header() sets Connection header (close) when many headers exist +=== TEST 6: proxy_wasm - set_http_request_header() set Connection header (close) when many headers exist --- wasm_modules: hostcalls --- config location /t { @@ -158,7 +158,7 @@ qr/.*? on_request_headers, 22 headers.* -=== TEST 7: proxy_wasm - set_http_request_header() sets Connection header (keep-alive) +=== TEST 7: proxy_wasm - set_http_request_header() set Connection header (keep-alive) --- timeout_expected: 5 --- abort --- wasm_modules: hostcalls @@ -186,7 +186,7 @@ qr/.*? on_request_headers, 2 headers.* -=== TEST 8: proxy_wasm - set_http_request_header() sets Connection header (closed) +=== TEST 8: proxy_wasm - set_http_request_header() set Connection header (closed) --- wasm_modules: hostcalls --- config location /t { @@ -210,7 +210,7 @@ qr/.*? on_request_headers, 2 headers.* -=== TEST 9: proxy_wasm - set_http_request_header() sets Content-Length header +=== TEST 9: proxy_wasm - set_http_request_header() set Content-Length header --- wasm_modules: hostcalls --- config location /t { @@ -263,7 +263,7 @@ qr/.*? on_request_headers, 3 headers.* -=== TEST 11: proxy_wasm - set_http_request_header() sets ':path' +=== TEST 11: proxy_wasm - set_http_request_header() set ':path' --- wasm_modules: hostcalls --- http_config eval qq{ @@ -295,26 +295,204 @@ path: /test -=== TEST 12: proxy_wasm - set_http_request_headers() cannot set ':path' with querystring (NYI) +=== TEST 12: proxy_wasm - set_http_request_headers() set ':path' with querystring --- wasm_modules: hostcalls +--- http_config eval +qq{ + upstream test_upstream { + server unix:$ENV{TEST_NGINX_UNIX_SOCKET}; + } + + server { + listen unix:$ENV{TEST_NGINX_UNIX_SOCKET}; + + location / { + return 200 '\$request_uri \$uri \$is_args \$args\n'; + } + } +} --- config location /t { proxy_wasm hostcalls 'test=/t/set_request_header name=:path value=/test?foo=bar'; - return 200; + proxy_wasm hostcalls 'test=/t/log/request_path'; + proxy_pass http://test_upstream$uri$is_args$args; } ---- error_code: 500 ---- response_body_like: 500 Internal Server Error ---- grep_error_log eval: qr/(NYI|\[.*?failed resuming).*/ ---- grep_error_log_out eval -qr/.*?NYI - cannot set request path with querystring.* -\[info\] .*? filter chain failed resuming: previous error \(instance trapped\)/ +--- response_body +/test?foo=bar /test ? foo=bar +--- error_log +path: /test?foo=bar +--- no_error_log +[error] +[crit] + + + +=== TEST 13: proxy_wasm - set_http_request_headers() set ':path' with empty querystring drops the querystring +--- wasm_modules: hostcalls +--- http_config eval +qq{ + upstream test_upstream { + server unix:$ENV{TEST_NGINX_UNIX_SOCKET}; + } + + server { + listen unix:$ENV{TEST_NGINX_UNIX_SOCKET}; + + location / { + return 200 '(\$request_uri) (\$uri) (\$is_args) (\$args)\n'; + } + } +} +--- config + location /t { + proxy_wasm hostcalls 'test=/t/set_request_header name=:path value=/test?'; + proxy_wasm hostcalls 'test=/t/log/request_path'; + proxy_pass http://test_upstream$uri$is_args$args; + } +--- request +GET /t?foo=bar +--- response_body +(/test) (/test) () () +--- error_log +path: /test +--- no_error_log +[error] +[crit] + + + +=== TEST 14: proxy_wasm - set_http_request_headers() set ':path' with empty path +--- wasm_modules: hostcalls +--- http_config eval +qq{ + upstream test_upstream { + server unix:$ENV{TEST_NGINX_UNIX_SOCKET}; + } + + server { + listen unix:$ENV{TEST_NGINX_UNIX_SOCKET}; + + location / { + return 200 '(\$request_uri) (\$uri) (\$is_args) (\$args)\n'; + } + } +} +--- config + location /t { + proxy_wasm hostcalls 'test=/t/set_request_header name=:path value='; + proxy_wasm hostcalls 'test=/t/log/request_path'; + proxy_pass http://test_upstream$uri$is_args$args; + } +--- response_body +(/t) (/t) () () +--- error_log +path: +--- no_error_log +[error] +[crit] + + + +=== TEST 15: proxy_wasm - set_http_request_headers() set ':path' with single '?' has same behavior as empty path +--- wasm_modules: hostcalls +--- http_config eval +qq{ + upstream test_upstream { + server unix:$ENV{TEST_NGINX_UNIX_SOCKET}; + } + + server { + listen unix:$ENV{TEST_NGINX_UNIX_SOCKET}; + + location / { + return 200 '(\$request_uri) (\$uri) (\$is_args) (\$args)\n'; + } + } +} +--- config + location /t { + proxy_wasm hostcalls 'test=/t/set_request_header name=:path value=?'; + proxy_wasm hostcalls 'test=/t/log/request_path'; + proxy_pass http://test_upstream$uri$is_args$args; + } +--- response_body +(/t) (/t) () () +--- error_log +path: --- no_error_log +[error] +[crit] + + + +=== TEST 16: proxy_wasm - set_http_request_headers() set ':path' with invalid characters (non percent-encoded) +Match the Nginx behavior (see following test). +--- wasm_modules: hostcalls +--- http_config eval +qq{ + upstream test_upstream { + server unix:$ENV{TEST_NGINX_UNIX_SOCKET}; + } + + server { + listen unix:$ENV{TEST_NGINX_UNIX_SOCKET}; + + location / { + return 200 '(\$request_uri) (\$uri) (\$is_args) (\$args)\n'; + } + } +} +--- config + location /set_by_proxy_wasm { + proxy_wasm hostcalls 'test=/t/set_request_header name=:path value=/test?foo=bár%20bla'; + proxy_wasm hostcalls 'test=/t/log/request_path'; + proxy_pass http://test_upstream$uri$is_args$args; + } +--- request +GET /set_by_proxy_wasm +--- response_body +(/test?foo=bár%20bla) (/test) (?) (foo=bár%20bla) +--- error_log +path: /test +--- no_error_log +[error] +[crit] + + + +=== TEST 17: Nginx - proxy a querystring with invalid characters (non percent-encoded) +This test is here just as documentation. It showcases the same behavior as +set_http_request_headers(':path'); see previous test. +--- http_config eval +qq{ + upstream test_upstream { + server unix:$ENV{TEST_NGINX_UNIX_SOCKET}; + } + + server { + listen unix:$ENV{TEST_NGINX_UNIX_SOCKET}; + + location / { + return 200 '(\$request_uri) (\$uri) (\$is_args) (\$args)\n'; + } + } +} +--- config + location /raw_nginx { + proxy_pass http://test_upstream$uri$is_args$args; + } +--- request +GET /raw_nginx?foo=bár%20bla +--- response_body +(/raw_nginx?foo=bár%20bla) (/raw_nginx) (?) (foo=bár%20bla) +--- no_error_log +[error] +[crit] [alert] -[stderr] -=== TEST 13: proxy_wasm - set_http_request_header() sets ':method' +=== TEST 18: proxy_wasm - set_http_request_header() set ':method' --- wasm_modules: hostcalls --- http_config eval qq{ @@ -344,7 +522,7 @@ POST -=== TEST 14: proxy_wasm - set_http_request_header() cannot set ':scheme' +=== TEST 19: proxy_wasm - set_http_request_header() cannot set ':scheme' --- wasm_modules: hostcalls --- http_config eval qq{ 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 6136176ac..9bbe935d0 100644 --- a/t/03-proxy_wasm/hfuncs/130-proxy_dispatch_http.t +++ b/t/03-proxy_wasm/hfuncs/130-proxy_dispatch_http.t @@ -1353,3 +1353,31 @@ cannot override the "Connection" header, skipping --- no_error_log [error] [crit] + + + +=== TEST 52: proxy_wasm - dispatch_http_call() can use ':path' with querystring, passes through invalid characters +--- load_nginx_modules: ngx_http_echo_module +--- wasm_modules: hostcalls +--- config + location /dispatched { + return 200 "Hello back $request_uri $uri $is_args $args"; + } + + location /t { + proxy_wasm hostcalls 'on=request_body \ + test=/t/dispatch_http_call \ + host=127.0.0.1:$TEST_NGINX_SERVER_PORT \ + path=/dispatched?foo=bár%20bla \ + on_http_call_response=echo_response_body'; + echo failed; + } +--- request +GET /t + +Hello world +--- response_body +Hello back /dispatched?foo=bár%20bla /dispatched ? foo=bár%20bla +--- no_error_log +[error] +[crit] From ccc56a2244665a3cc2986c03828c985c8d46db78 Mon Sep 17 00:00:00 2001 From: Hisham Muhammad Date: Wed, 20 Nov 2024 17:46:13 -0300 Subject: [PATCH 09/60] refactor(proxy-wasm) rename 'call->uri' to 'call->path' ...to clarify that it matches `":path"` (that is, path including querystring), making the field name match the pseudo-header, as is the case with the other entries in `ngx_http_proxy_wasm_dispatch_s`. --- src/http/proxy_wasm/ngx_http_proxy_wasm_dispatch.c | 10 +++++----- src/http/proxy_wasm/ngx_http_proxy_wasm_dispatch.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) 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 bfe15af25..f047819dc 100644 --- a/src/http/proxy_wasm/ngx_http_proxy_wasm_dispatch.c +++ b/src/http/proxy_wasm/ngx_http_proxy_wasm_dispatch.c @@ -258,8 +258,8 @@ ngx_http_proxy_wasm_dispatch(ngx_proxy_wasm_exec_t *pwexec, call->method.data = elt->value.data; } else if (ngx_str_eq(elt->key.data, elt->key.len, ":path", -1)) { - call->uri.len = elt->value.len; - call->uri.data = elt->value.data; + call->path.len = elt->value.len; + call->path.data = elt->value.data; } else if (ngx_str_eq(elt->key.data, elt->key.len, ":authority", -1)) @@ -330,7 +330,7 @@ ngx_http_proxy_wasm_dispatch(ngx_proxy_wasm_exec_t *pwexec, call->error = NGX_HTTP_PROXY_WASM_DISPATCH_ERR_BAD_METHOD; goto error; - } else if (!call->uri.len) { + } else if (!call->path.len) { call->error = NGX_HTTP_PROXY_WASM_DISPATCH_ERR_BAD_PATH; goto error; } @@ -577,7 +577,7 @@ ngx_http_proxy_wasm_dispatch_request(ngx_http_proxy_wasm_dispatch_t *call) * Connection: * Content-Length: */ - len += call->method.len + 1 + call->uri.len + 1 + len += call->method.len + 1 + call->path.len + 1 + sizeof(ngx_http_header_version11) - 1; len += sizeof(ngx_http_host_header) - 1 + sizeof(": ") - 1 @@ -638,7 +638,7 @@ ngx_http_proxy_wasm_dispatch_request(ngx_http_proxy_wasm_dispatch_t *call) b->last = ngx_cpymem(b->last, call->method.data, call->method.len); *b->last++ = ' '; - b->last = ngx_cpymem(b->last, call->uri.data, call->uri.len); + b->last = ngx_cpymem(b->last, call->path.data, call->path.len); *b->last++ = ' '; b->last = ngx_cpymem(b->last, ngx_http_header_version11, 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 a23e9a22e..97f5b99dd 100644 --- a/src/http/proxy_wasm/ngx_http_proxy_wasm_dispatch.h +++ b/src/http/proxy_wasm/ngx_http_proxy_wasm_dispatch.h @@ -40,7 +40,7 @@ struct ngx_http_proxy_wasm_dispatch_s { ngx_str_t host; ngx_str_t method; - ngx_str_t uri; + ngx_str_t path; /* ":path" (including query) */ ngx_str_t authority; ngx_array_t headers; ngx_array_t trailers; From 4c610b49927edbe3f82c5c43c77e7fe5e65ff03d Mon Sep 17 00:00:00 2001 From: Thibault Charbonnier Date: Fri, 15 Nov 2024 08:48:28 -0800 Subject: [PATCH 10/60] feat(proxy-wasm) invoke 'on_http_call_response' on dispatch failures Invoke `on_http_call_response` on dispatch connection failures. This allows catching failures such as: - timeout - broken connection - resolver failures - TLS handshake failures - Any other failures *after the connection has attempted to be established* Dispatch failures occurring *before* a connection has attempted to be established will not trigger `on_http_call_response` as they are already supposed to trigger a Wasm exception (i.e. trap). When a dispatch connection failure occurs, `on_http_call_response` is invoked with: `on_http_call_response(call_id, 0, 0, 0)` (i.e. no header, no body, no trailers). Calls to retrieve the response `:status` will return `None`. A user may triage the connection failure by querying the `:dispatch_status` pseudo-header: ```rust fn on_http_call_response( &mut self, token_id: u32, nheaders: usize, body_size: usize, ntrailers: usize, ) { let dispatch_status = self.get_http_call_response_header(":dispatch_status"); match dispatch_status.as_deref() { Some("timeout") => {}, Some("broken connection") => {}, Some("tls handshake failure") => {}, Some("resolver failure") => {}, Some("reader failure") => {}, Some(s) => info!("dispatch_status: {}", s), None => {} } self.resume_http_request() } ``` The socket status `"bad argument"` also exists but since the connection has not been attempted yet, it won't show up during `on_http_call_response` and is for internal use only (i.e. could be added to the socket error log for example). Fix #622. --- docs/PROXY_WASM.md | 130 +++++++++++++++- src/common/ngx_wasm_socket_tcp.c | 145 +++++++++--------- src/common/ngx_wasm_socket_tcp.h | 19 ++- src/common/ngx_wasm_socket_tcp_readers.c | 53 +++++++ src/common/ngx_wasm_socket_tcp_readers.h | 1 + src/common/proxy_wasm/ngx_proxy_wasm.c | 2 +- src/common/proxy_wasm/ngx_proxy_wasm_maps.c | 39 ++++- src/http/proxy_wasm/ngx_http_proxy_wasm.c | 40 +++-- .../proxy_wasm/ngx_http_proxy_wasm_dispatch.c | 109 +++++++------ .../hfuncs/130-proxy_dispatch_http.t | 94 ++++++++++-- .../hfuncs/131-proxy_dispatch_http_timeouts.t | 37 ++++- .../hfuncs/132-proxy_dispatch_http_ssl.t | 90 +++++++++-- .../133-proxy_dispatch_http_edge_cases.t | 12 +- .../002-go_sdk/005-dispatch_call_on_tick.t | 2 + .../proxy-wasm-tests/hostcalls/src/filter.rs | 6 + util/sdks/go.sh | 11 ++ 16 files changed, 604 insertions(+), 186 deletions(-) diff --git a/docs/PROXY_WASM.md b/docs/PROXY_WASM.md index 0b98595e1..a452138d4 100644 --- a/docs/PROXY_WASM.md +++ b/docs/PROXY_WASM.md @@ -10,6 +10,7 @@ - [Filters Execution in Nginx](#filters-execution-in-nginx) - [Host Properties] - [Nginx Properties] + - [HTTP Dispatches] - [Supported Specifications] - [Tested SDKs](#tested-sdks) - [Supported Entrypoints](#supported-entrypoints) @@ -107,13 +108,13 @@ proxy_wasm::main! {{ // the wasm instance initial entrypoint // ... proxy_wasm::set_log_level(LogLevel::Info); - // create and set the root context for this filter + // create and set the Root context for this filter proxy_wasm::set_root_context(|_| -> Box { Box::new(MyRootContext {}); }); }} -// implement root entrypoints +// implement Root entrypoints impl Context for TestRoot; impl RootContext for TestRoot { fn on_configure(&mut self, config_size: usize) -> bool { @@ -376,6 +377,122 @@ impl HttpContext for MyHttpContext { [Back to TOC](#table-of-contents) +### HTTP Dispatches + +Proxy-Wasm filters can issue requests to an external HTTP service. This feature +is called an "HTTP dispatch". + +In ngx_wasm_module, filters can issue a dispatch call with +`dispatch_http_call()` in the following steps: + +- `on_http_request_headers` +- `on_http_request_body` +- `on_tick` +- `on_http_call_response` (to issue subsequent calls) + +For example, in Rust: + +```rust +impl Context for ExampleHttpContext { + fn on_http_request_headers(&mut self, nheaders: usize, eof: bool) -> Action { + match self.dispatch_http_call( + "service.com", // host + vec![("X-Header", "Foo")], // headers + Some(b"hello world"), // body + vec![], // trailers + Duration::from_secs(3), // timeout + ) { + Ok(_) => info!("call scheduled"), + Err(status) => panic!("unexpected status \"{}\"", status as u32), + } + + Action::Pause + } +} +``` + +Several calls can be scheduled at the same time before returning +`Action::Pause`; they will be executed in parallel, their response handlers will +be invoked when each response is received, and the filter chain will resume once +all dispatch calls have finished executing. + +**Note:** in ngx_wasm_module, the `host` argument of a dispatch call must be a +valid IP address or a hostname which will be resolved using the [resolver] or +[proxy_wasm_lua_resolver] directives. This `host` argument may contain a port +component whether IP or hostname (i.e. `service.com:80`). This is unlike the +Envoy implementation in which the `host` argument receives a configured cluster +name. + +Once the call is scheduled, the `on_http_call_response` handler will be invoked +when a response is received or the connection has encountered an error. If an +error was encountered while receiving the response, `on_http_call_response` is +invoked with its response arguments set to `0`. + +For example, in Rust: + +```rust +impl Context for ExampleHttpContext { + fn on_http_call_response( + &mut self, + token_id: u32, + nheaders: usize, + body_size: usize, + ntrailers: usize, + ) { + let status = self.get_http_call_response_header(":status"); + let body_bytes = self.get_http_call_response_body(0, body_size); + + if status.is_none() { + // Dispatch had an issue + // + // nheaders == 0 + // body_size == 0 + // ntrailers == 0 + + // ngx_wasm_module extension: retrieve error via :dispatch_status pseudo-header + let dispatch_status = self.get_http_call_response_header(":dispatch_status"); + match dispatch_status.as_deref() { + Some("timeout") => {}, + Some("broken connection") => {}, + Some("tls handshake failure") => {}, + Some("resolver failure") => {}, + Some("reader failure") => {}, + Some(s) => error!("dispatch failure, status: {}", s), + None => {} + } + } + + // ... + } +} +``` + +**Note:** if the dispatch call was invoked from the `on_tick` handler, +`on_http_call_response` must be implemented on the Root filter context instead +of the HTTP context: + +```rust +proxy_wasm::main! {{ + proxy_wasm::set_root_context(|_| -> Box { + Box::new(ExampleRootContext {}) + }); +}} + +impl Context for ExampleRootContext { + fn on_http_call_response( + &mut self, + token_id: u32, + nheaders: usize, + body_size: usize, + ntrailers: usize, + ) { + // Root context handler + } +} +``` + +[Back to TOC](#table-of-contents) + ## Supported Specifications This section describes the current state of support for the Proxy-Wasm @@ -429,7 +546,7 @@ SDK ABI `0.2.1`) and their present status in ngx_wasm_module: **Name** | **Supported** | **Comment** ----------------------------------:|:-------------------:|:-------------- *Root contexts* | | -`proxy_wasm::main!` | :heavy_check_mark: | Allocate the root context. +`proxy_wasm::main!` | :heavy_check_mark: | Allocate the Root context. `on_vm_start` | :heavy_check_mark: | VM configuration handler. `on_configure` | :heavy_check_mark: | Filter configuration handler. `on_tick` | :heavy_check_mark: | Background tick handler. @@ -636,7 +753,7 @@ implementation state in ngx_wasm_module: `source.port` | :heavy_check_mark: | :x: | Maps to [ngx.remote_port](https://nginx.org/en/docs/http/ngx_http_core_module.html#remote_port). *Proxy-Wasm properties* | | `plugin_name` | :heavy_check_mark: | :x: | Returns current filter name. -`plugin_root_id` | :heavy_check_mark: | :x: | Returns filter's root context id. +`plugin_root_id` | :heavy_check_mark: | :x: | Returns filter's Root context id. `plugin_vm_id` | :x: | :x: | *NYI*. `node` | :x: | :x: | Not supported. `cluster_name` | :x: | :x: | Not supported. @@ -743,7 +860,7 @@ payloads. 3. When making a dispatch call, a valid IP address or hostname must be given to `dispatch_http_call`. This is in contrast to Envoy's implementation in which - a configured cluster name must be given. + a configured cluster name must be given. See [HTTP Dispatches]. 4. The "queue" shared memory implementation does not implement an automatic eviction mechanism when the allocated memory slab is full: @@ -759,12 +876,15 @@ Proxy-Wasm SDK. [Filter Chains]: #filter-chains [Host Properties]: #host-properties [Nginx Properties]: #nginx-properties +[HTTP Dispatches]: #http-dispatches [Supported Specifications]: #supported-specifications [Supported Properties]: #supported-properties [Examples]: #examples [Current Limitations]: #current-limitations [wasm_response_body_buffers]: DIRECTIVES.md#wasm_response_body_buffers +[resolver]: DIRECTIVES.md#resolver +[proxy_wasm_lua_resolver]: DIRECTIVES.md#proxy_wasm_lua_resolver [WebAssembly]: https://webassembly.org/ [Nginx Variables]: https://nginx.org/en/docs/varindex.html diff --git a/src/common/ngx_wasm_socket_tcp.c b/src/common/ngx_wasm_socket_tcp.c index e39d2151e..3a6de6146 100644 --- a/src/common/ngx_wasm_socket_tcp.c +++ b/src/common/ngx_wasm_socket_tcp.c @@ -14,7 +14,7 @@ static void ngx_wasm_socket_tcp_err(ngx_wasm_socket_tcp_t *sock, - const char *fmt, ...); + ngx_wasm_socket_status_e status, const char *fmt, ...); static void ngx_wasm_socket_resolve_handler(ngx_resolver_ctx_t *ctx); static ngx_int_t ngx_wasm_socket_tcp_connect_peer(ngx_wasm_socket_tcp_t *sock); static ngx_int_t ngx_wasm_socket_tcp_get_peer(ngx_peer_connection_t *pc, @@ -36,14 +36,43 @@ static ngx_int_t ngx_wasm_socket_tcp_ssl_set_server_name(ngx_connection_t *c, #endif +static ngx_str_t ngx_wasm_socket_errlist[] = { + ngx_string("ok"), + ngx_string("bad argument"), + ngx_string("timeout"), + ngx_string("broken connection"), +#if (NGX_SSL) + ngx_string("tls handshake failure"), +#endif + ngx_string("resolver failure"), + ngx_string("reader failure"), + ngx_string("internal failure") +}; + + +ngx_str_t * +ngx_wasm_socket_tcp_status_strerror(ngx_wasm_socket_status_e status) +{ + ngx_str_t *msg; + + msg = ((ngx_uint_t) status < NGX_WASM_SOCKET_STATUS_INTERNAL_FAILURE) + ? &ngx_wasm_socket_errlist[status] + : &ngx_wasm_socket_errlist[NGX_WASM_SOCKET_STATUS_INTERNAL_FAILURE]; + + return msg; +} + + static void ngx_wasm_socket_tcp_err(ngx_wasm_socket_tcp_t *sock, + ngx_wasm_socket_status_e status, const char *fmt, ...) { va_list args; u_char *p, *last; if (sock->err == NULL) { + sock->status = status; sock->err = ngx_pnalloc(sock->pool, NGX_MAX_ERROR_STR); if (sock->err == NULL) { return; @@ -193,7 +222,8 @@ ngx_wasm_socket_tcp_init(ngx_wasm_socket_tcp_t *sock, sock->url.no_resolve = 1; if (ngx_parse_url(sock->pool, &sock->url) != NGX_OK) { - ngx_wasm_socket_tcp_err(sock, "%s", sock->url.err); + ngx_wasm_socket_tcp_err(sock, NGX_WASM_SOCKET_STATUS_BAD_ARGUMENT, + "%s", sock->url.err); return NGX_ERROR; } @@ -385,7 +415,8 @@ ngx_wasm_socket_tcp_connect(ngx_wasm_socket_tcp_t *sock) } if (rslv_ctx == NULL) { - ngx_wasm_socket_tcp_err(sock, "failed starting resolver"); + ngx_wasm_socket_tcp_err(sock, NGX_WASM_SOCKET_STATUS_INTERNAL_FAILURE, + "failed starting resolver"); return NGX_ERROR; } @@ -429,7 +460,9 @@ ngx_wasm_socket_resolve_handler(ngx_resolver_ctx_t *ctx) if (ctx->state || !ctx->naddrs) { #if (NGX_WASM_LUA) if (ctx->state == NGX_WASM_LUA_RESOLVE_ERR) { - ngx_wasm_socket_tcp_err(sock, "lua resolver failed"); + ngx_wasm_socket_tcp_err(sock, + NGX_WASM_SOCKET_STATUS_RESOLVER_FAILURE, + "lua resolver failed"); goto error; } #endif @@ -440,7 +473,8 @@ ngx_wasm_socket_resolve_handler(ngx_resolver_ctx_t *ctx) } #endif - ngx_wasm_socket_tcp_err(sock, "resolver error: %s", + ngx_wasm_socket_tcp_err(sock, NGX_WASM_SOCKET_STATUS_RESOLVER_FAILURE, + "resolver error: %s", ngx_resolver_strerror(ctx->state)); goto error; } @@ -571,12 +605,14 @@ ngx_wasm_socket_tcp_connect_peer(ngx_wasm_socket_tcp_t *sock) return NGX_ERROR; } else if (rc == NGX_BUSY) { - ngx_wasm_socket_tcp_err(sock, "no live connection"); + ngx_wasm_socket_tcp_err(sock, NGX_WASM_SOCKET_STATUS_INTERNAL_FAILURE, + "no live connection"); return NGX_BUSY; } else if (rc == NGX_DECLINED) { sock->socket_errno = ngx_socket_errno; - ngx_wasm_socket_tcp_err(sock, NULL); + ngx_wasm_socket_tcp_err(sock, NGX_WASM_SOCKET_STATUS_BROKEN_CONNECTION, + NULL); return NGX_ERROR; } @@ -686,11 +722,13 @@ ngx_wasm_socket_tcp_ssl_handshake_handler(ngx_connection_t *c) } if (c->write->timedout) { - ngx_wasm_socket_tcp_err(sock, "tls handshake timed out"); + ngx_wasm_socket_tcp_err(sock, NGX_WASM_SOCKET_STATUS_TLS_FAILURE, + "tls handshake timed out"); goto resume; } - ngx_wasm_socket_tcp_err(sock, "tls handshake failed"); + ngx_wasm_socket_tcp_err(sock, NGX_WASM_SOCKET_STATUS_TLS_FAILURE, + "tls handshake failed"); resume: @@ -722,6 +760,7 @@ ngx_wasm_socket_tcp_ssl_handshake_done(ngx_connection_t *c) rc = SSL_get_verify_result(c->ssl->connection); if (rc != X509_V_OK) { ngx_wasm_socket_tcp_err(sock, + NGX_WASM_SOCKET_STATUS_TLS_FAILURE, "tls certificate verify error: (%l:%s)", rc, X509_verify_cert_error_string(rc)); return NGX_ERROR; @@ -740,6 +779,7 @@ ngx_wasm_socket_tcp_ssl_handshake_done(ngx_connection_t *c) if (ngx_ssl_check_host(c, &sock->ssl_server_name) != NGX_OK) { ngx_wasm_socket_tcp_err(sock, + NGX_WASM_SOCKET_STATUS_TLS_FAILURE, "tls certificate CN " "does not match \"%V\" sni", &sock->ssl_server_name); @@ -809,6 +849,7 @@ ngx_wasm_socket_tcp_ssl_set_server_name(ngx_connection_t *c, || ngx_inet_addr(name->data, len) != INADDR_NONE) { ngx_wasm_socket_tcp_err(sock, + NGX_WASM_SOCKET_STATUS_TLS_FAILURE, "could not derive tls sni from host (\"%V\")", &sock->host); goto error; @@ -877,7 +918,8 @@ ngx_wasm_socket_tcp_send(ngx_wasm_socket_tcp_t *sock, ngx_chain_t *cl) ngx_connection_t *c; if (!sock->connected) { - ngx_wasm_socket_tcp_err(sock, "not connected"); + ngx_wasm_socket_tcp_err(sock, NGX_WASM_SOCKET_STATUS_INTERNAL_FAILURE, + "not connected"); return NGX_ERROR; } @@ -930,7 +972,8 @@ ngx_wasm_socket_tcp_send(ngx_wasm_socket_tcp_t *sock, ngx_chain_t *cl) if (n == NGX_ERROR) { c->error = 1; sock->socket_errno = ngx_socket_errno; - ngx_wasm_socket_tcp_err(sock, NULL); + ngx_wasm_socket_tcp_err(sock, NGX_WASM_SOCKET_STATUS_BROKEN_CONNECTION, + NULL); return NGX_ERROR; } @@ -977,53 +1020,6 @@ ngx_int_t ngx_wasm_socket_read_http_response(ngx_wasm_socket_tcp_t *sock, ssize_t bytes, void *ctx) { - ngx_wasm_http_reader_ctx_t *in_ctx = ctx; - ngx_http_request_t *r; - ngx_http_wasm_req_ctx_t *rctx; - - r = &in_ctx->fake_r; - rctx = in_ctx->rctx; - - if (!r->signature) { - ngx_memzero(r, sizeof(ngx_http_request_t)); - - r->pool = in_ctx->pool; - r->signature = NGX_HTTP_MODULE; - r->connection = rctx->connection; - r->request_start = NULL; - r->header_in = NULL; - - if (ngx_list_init(&r->headers_out.headers, r->pool, 20, - sizeof(ngx_table_elt_t)) - != NGX_OK) - { - return NGX_ERROR; - } - - if (ngx_list_init(&r->headers_out.trailers, r->pool, 4, - sizeof(ngx_table_elt_t)) - != NGX_OK) - { - return NGX_ERROR; - } - - if (ngx_http_upstream_create(r) != NGX_OK) { - return NGX_ERROR; - } - - r->upstream->conf = &in_ctx->uconf; - - if (ngx_list_init(&r->upstream->headers_in.headers, r->pool, 4, - sizeof(ngx_table_elt_t)) - != NGX_OK) - { - return NGX_ERROR; - } - - r->headers_out.content_length_n = -1; - r->headers_out.last_modified_time = -1; - } - if (bytes) { ngx_log_debug1(NGX_LOG_DEBUG_WASM, sock->log, 0, "wasm tcp socket resuming http response reading " @@ -1054,7 +1050,8 @@ ngx_wasm_socket_tcp_read(ngx_wasm_socket_tcp_t *sock, ngx_connection_t *c; if (!sock->connected) { - ngx_wasm_socket_tcp_err(sock, "not connected"); + ngx_wasm_socket_tcp_err(sock, NGX_WASM_SOCKET_STATUS_INTERNAL_FAILURE, + "not connected"); return NGX_ERROR; } @@ -1091,7 +1088,9 @@ ngx_wasm_socket_tcp_read(ngx_wasm_socket_tcp_t *sock, rc = reader(sock, size, reader_ctx); if (rc == NGX_ERROR) { - ngx_wasm_socket_tcp_err(sock, "parser error"); + ngx_wasm_socket_tcp_err(sock, + NGX_WASM_SOCKET_STATUS_READER_FAILURE, + "parser error"); return NGX_ERROR; } @@ -1159,7 +1158,9 @@ ngx_wasm_socket_tcp_read(ngx_wasm_socket_tcp_t *sock, if (n == NGX_ERROR) { sock->socket_errno = ngx_socket_errno; - ngx_wasm_socket_tcp_err(sock, NULL); + ngx_wasm_socket_tcp_err(sock, + NGX_WASM_SOCKET_STATUS_BROKEN_CONNECTION, + NULL); return NGX_ERROR; } @@ -1505,11 +1506,11 @@ ngx_wasm_socket_tcp_connect_handler(ngx_wasm_socket_tcp_t *sock) "wasm tcp socket timed out connecting to \"%V:%ud\"", &c->addr_text, ngx_inet_get_port(sock->peer.sockaddr)); - ngx_wasm_socket_tcp_err(sock, "timed out connecting to \"%V:%ud\"", + ngx_wasm_socket_tcp_err(sock, + NGX_WASM_SOCKET_STATUS_TIMEOUT, + "timed out connecting to \"%V:%ud\"", &c->addr_text, ngx_inet_get_port(sock->peer.sockaddr)); - - sock->timedout = 1; return; } @@ -1520,7 +1521,9 @@ ngx_wasm_socket_tcp_connect_handler(ngx_wasm_socket_tcp_t *sock) if (rc != NGX_OK) { if (rc > 0) { sock->socket_errno = (ngx_err_t) rc; - ngx_wasm_socket_tcp_err(sock, NULL); + ngx_wasm_socket_tcp_err(sock, + NGX_WASM_SOCKET_STATUS_BROKEN_CONNECTION, + NULL); } return; @@ -1560,11 +1563,11 @@ ngx_wasm_socket_tcp_send_handler(ngx_wasm_socket_tcp_t *sock) "wasm tcp socket timed out writing to \"%V:%ud\"", &c->addr_text, ngx_inet_get_port(sock->peer.sockaddr)); - ngx_wasm_socket_tcp_err(sock, "timed out writing to \"%V:%ud\"", + ngx_wasm_socket_tcp_err(sock, + NGX_WASM_SOCKET_STATUS_TIMEOUT, + "timed out writing to \"%V:%ud\"", &c->addr_text, ngx_inet_get_port(sock->peer.sockaddr)); - - sock->timedout = 1; return; } } @@ -1584,11 +1587,11 @@ ngx_wasm_socket_tcp_receive_handler(ngx_wasm_socket_tcp_t *sock) "wasm tcp socket timed out reading from \"%V:%ud\"", &c->addr_text, ngx_inet_get_port(sock->peer.sockaddr)); - ngx_wasm_socket_tcp_err(sock, "timed out reading from \"%V:%ud\"", + ngx_wasm_socket_tcp_err(sock, + NGX_WASM_SOCKET_STATUS_TIMEOUT, + "timed out reading from \"%V:%ud\"", &c->addr_text, ngx_inet_get_port(sock->peer.sockaddr)); - - sock->timedout = 1; return; } diff --git a/src/common/ngx_wasm_socket_tcp.h b/src/common/ngx_wasm_socket_tcp.h index af762efa7..f951f0541 100644 --- a/src/common/ngx_wasm_socket_tcp.h +++ b/src/common/ngx_wasm_socket_tcp.h @@ -18,6 +18,20 @@ typedef ngx_int_t (*ngx_wasm_socket_tcp_dns_resolver_pt)( ngx_resolver_ctx_t *rslv_ctx); +typedef enum { + NGX_WASM_SOCKET_STATUS_OK = 0, + NGX_WASM_SOCKET_STATUS_BAD_ARGUMENT, + NGX_WASM_SOCKET_STATUS_TIMEOUT, + NGX_WASM_SOCKET_STATUS_BROKEN_CONNECTION, +#if (NGX_SSL) + NGX_WASM_SOCKET_STATUS_TLS_FAILURE, +#endif + NGX_WASM_SOCKET_STATUS_RESOLVER_FAILURE, + NGX_WASM_SOCKET_STATUS_READER_FAILURE, + NGX_WASM_SOCKET_STATUS_INTERNAL_FAILURE, +} ngx_wasm_socket_status_e; + + typedef struct { ngx_str_t host; in_port_t port; @@ -39,6 +53,7 @@ struct ngx_wasm_socket_tcp_s { ngx_wasm_subsys_env_t *env; ngx_wasm_socket_tcp_resume_handler_pt resume_handler; + ngx_wasm_socket_status_e status; void *data; #if (NGX_WASM_LUA) ngx_wasm_lua_ctx_t *lctx; @@ -85,19 +100,19 @@ struct ngx_wasm_socket_tcp_s { /* flags */ - unsigned timedout:1; unsigned connected:1; unsigned eof:1; unsigned closed:1; unsigned read_closed:1; unsigned write_closed:1; - #if (NGX_SSL) unsigned ssl_ready:1; #endif }; +ngx_str_t *ngx_wasm_socket_tcp_status_strerror(ngx_wasm_socket_status_e status); + ngx_int_t ngx_wasm_socket_tcp_init(ngx_wasm_socket_tcp_t *sock, ngx_str_t *host, unsigned tls, ngx_str_t *sni, ngx_wasm_subsys_env_t *env); ngx_int_t ngx_wasm_socket_tcp_connect(ngx_wasm_socket_tcp_t *sock); diff --git a/src/common/ngx_wasm_socket_tcp_readers.c b/src/common/ngx_wasm_socket_tcp_readers.c index 841ccf873..a6f242a37 100644 --- a/src/common/ngx_wasm_socket_tcp_readers.c +++ b/src/common/ngx_wasm_socket_tcp_readers.c @@ -544,4 +544,57 @@ ngx_wasm_read_http_response(ngx_buf_t *src, ngx_chain_t *buf_in, ssize_t bytes, return NGX_OK; } + + +ngx_int_t +ngx_wasm_http_reader_init(ngx_wasm_http_reader_ctx_t *in_ctx) +{ + ngx_http_wasm_req_ctx_t *rctx; + ngx_http_request_t *r; + + rctx = in_ctx->rctx; + r = &in_ctx->fake_r; + + ngx_wa_assert(!r->signature); + + ngx_memzero(r, sizeof(ngx_http_request_t)); + + r->pool = in_ctx->pool; + r->signature = NGX_HTTP_MODULE; + r->connection = rctx->connection; + r->request_start = NULL; + r->header_in = NULL; + + if (ngx_list_init(&r->headers_out.headers, r->pool, 20, + sizeof(ngx_table_elt_t)) + != NGX_OK) + { + return NGX_ERROR; + } + + if (ngx_list_init(&r->headers_out.trailers, r->pool, 4, + sizeof(ngx_table_elt_t)) + != NGX_OK) + { + return NGX_ERROR; + } + + if (ngx_http_upstream_create(r) != NGX_OK) { + return NGX_ERROR; + } + + r->upstream->conf = &in_ctx->uconf; + + if (ngx_list_init(&r->upstream->headers_in.headers, r->pool, 4, + sizeof(ngx_table_elt_t)) + != NGX_OK) + { + return NGX_ERROR; + } + + r->headers_out.content_length_n = -1; + r->headers_out.last_modified_time = -1; + + return NGX_OK; +} #endif diff --git a/src/common/ngx_wasm_socket_tcp_readers.h b/src/common/ngx_wasm_socket_tcp_readers.h index 848d7574c..bc15cec26 100644 --- a/src/common/ngx_wasm_socket_tcp_readers.h +++ b/src/common/ngx_wasm_socket_tcp_readers.h @@ -30,6 +30,7 @@ typedef struct { ngx_int_t ngx_wasm_read_http_response(ngx_buf_t *src, ngx_chain_t *buf_in, ssize_t bytes, ngx_wasm_http_reader_ctx_t *in_ctx); +ngx_int_t ngx_wasm_http_reader_init(ngx_wasm_http_reader_ctx_t *in_ctx); #endif diff --git a/src/common/proxy_wasm/ngx_proxy_wasm.c b/src/common/proxy_wasm/ngx_proxy_wasm.c index c2359216f..ce167ecba 100644 --- a/src/common/proxy_wasm/ngx_proxy_wasm.c +++ b/src/common/proxy_wasm/ngx_proxy_wasm.c @@ -852,7 +852,7 @@ ngx_proxy_wasm_run_step(ngx_proxy_wasm_exec_t *pwexec, } dd("<-- step rc: %ld, old_action: %d, ret action: %d, pwctx->action: %d, " - " ictx: %p", rc, old_action, action, pwctx->action, pwexec->ictx); + "ictx: %p", rc, old_action, action, pwctx->action, pwexec->ictx); /* pwctx->action writes in host calls overwrite action return value */ diff --git a/src/common/proxy_wasm/ngx_proxy_wasm_maps.c b/src/common/proxy_wasm/ngx_proxy_wasm_maps.c index a80c6f79e..1a81aa00a 100644 --- a/src/common/proxy_wasm/ngx_proxy_wasm_maps.c +++ b/src/common/proxy_wasm/ngx_proxy_wasm_maps.c @@ -35,6 +35,8 @@ static ngx_str_t *ngx_proxy_wasm_maps_get_response_status( static ngx_int_t ngx_proxy_wasm_maps_set_response_status( ngx_wavm_instance_t *instance, ngx_str_t *value, ngx_proxy_wasm_map_type_e map_type); +static ngx_str_t *ngx_proxy_wasm_maps_get_dispatch_response_status( + ngx_wavm_instance_t *instance, ngx_proxy_wasm_map_type_e map_type); static ngx_str_t *ngx_proxy_wasm_maps_get_dispatch_status( ngx_wavm_instance_t *instance, ngx_proxy_wasm_map_type_e map_type); #endif @@ -75,6 +77,11 @@ static ngx_proxy_wasm_maps_key_t ngx_proxy_wasm_maps_special_keys[] = { /* dispatch response */ { ngx_string(":status"), + NGX_PROXY_WASM_MAP_HTTP_CALL_RESPONSE_HEADERS, + ngx_proxy_wasm_maps_get_dispatch_response_status, + NULL }, + + { ngx_string(":dispatch_status"), NGX_PROXY_WASM_MAP_HTTP_CALL_RESPONSE_HEADERS, ngx_proxy_wasm_maps_get_dispatch_status, NULL }, @@ -118,8 +125,15 @@ ngx_proxy_wasm_maps_get_map(ngx_wavm_instance_t *instance, } reader = &call->http_reader; + r = &reader->fake_r; + + /* reader is initialized */ + ngx_wa_assert(r->signature); + + return &r->upstream->headers_in.headers; - return &reader->fake_r.upstream->headers_in.headers; + case NGX_PROXY_WASM_MAP_HTTP_CALL_RESPONSE_TRAILERS: + return NULL; #endif default: @@ -755,7 +769,7 @@ ngx_proxy_wasm_maps_set_response_status(ngx_wavm_instance_t *instance, static ngx_str_t * -ngx_proxy_wasm_maps_get_dispatch_status(ngx_wavm_instance_t *instance, +ngx_proxy_wasm_maps_get_dispatch_response_status(ngx_wavm_instance_t *instance, ngx_proxy_wasm_map_type_e map_type) { ngx_uint_t status; @@ -773,9 +787,8 @@ ngx_proxy_wasm_maps_get_dispatch_status(ngx_wavm_instance_t *instance, /* status */ - ngx_wa_assert(reader->fake_r.upstream); - if (reader->fake_r.upstream == NULL) { + /* response not received */ return NULL; } @@ -812,4 +825,22 @@ ngx_proxy_wasm_maps_get_dispatch_status(ngx_wavm_instance_t *instance, return &pwctx->call_status; } + + +static ngx_str_t * +ngx_proxy_wasm_maps_get_dispatch_status(ngx_wavm_instance_t *instance, + ngx_proxy_wasm_map_type_e map_type) +{ + ngx_proxy_wasm_exec_t *pwexec; + ngx_http_proxy_wasm_dispatch_t *call; + ngx_wasm_socket_tcp_t *sock; + + ngx_wa_assert(map_type == NGX_PROXY_WASM_MAP_HTTP_CALL_RESPONSE_HEADERS); + + pwexec = ngx_proxy_wasm_instance2pwexec(instance); + call = pwexec->call; + sock = &call->sock; + + return ngx_wasm_socket_tcp_status_strerror(sock->status); +} #endif diff --git a/src/http/proxy_wasm/ngx_http_proxy_wasm.c b/src/http/proxy_wasm/ngx_http_proxy_wasm.c index d8f809116..463aea2b7 100644 --- a/src/http/proxy_wasm/ngx_http_proxy_wasm.c +++ b/src/http/proxy_wasm/ngx_http_proxy_wasm.c @@ -313,39 +313,45 @@ ngx_http_proxy_wasm_on_dispatch_response(ngx_proxy_wasm_exec_t *pwexec) { size_t i; ngx_int_t rc; - ngx_uint_t n_headers; + 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_wasm_req_ctx_t *rctx = call->rctx; - part = &call->http_reader.fake_r.upstream->headers_in.headers.part; + n_headers = 0; + body_len = 0; - for (i = 0, n_headers = 0; /* void */; i++, n_headers++) { - if (i >= part->nelts) { - if (part->next == NULL) { - break; - } + if (call->http_reader.fake_r.signature) { + /* reader initialized */ + part = &call->http_reader.fake_r.upstream->headers_in.headers.part; + + for (i = 0, n_headers = 0; /* void */; i++, n_headers++) { + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } - part = part->next; - i = 0; + part = part->next; + i = 0; + } } - /* void */ - } + body_len = call->http_reader.body_len; - ngx_log_debug3(NGX_LOG_DEBUG_ALL, pwexec->log, 0, - "proxy_wasm http dispatch response received " - "(pwexec->id: %d, token_id: %d, n_headers: %d)", - pwexec->id, call->id, n_headers); + ngx_log_debug4(NGX_LOG_DEBUG_ALL, pwexec->log, 0, + "proxy_wasm http dispatch response received " + "(pwexec->id: %d, token_id: %d, n_headers: %d, " + "body_len: %d)", pwexec->id, call->id, n_headers, + body_len); + } ngx_wasm_continue(&rctx->env); rc = ngx_wavm_instance_call_funcref(pwexec->ictx->instance, filter->proxy_on_http_call_response, NULL, filter->id, call->id, - n_headers, - call->http_reader.body_len, 0); /* eof: 0 */ + n_headers, body_len, 0); /* eof: 0 */ return rc; } 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 f047819dc..ac5a29e50 100644 --- a/src/http/proxy_wasm/ngx_http_proxy_wasm_dispatch.c +++ b/src/http/proxy_wasm/ngx_http_proxy_wasm_dispatch.c @@ -10,7 +10,7 @@ static ngx_str_t *ngx_http_proxy_wasm_dispatch_strerror( ngx_http_proxy_wasm_dispatch_err_e err); static void ngx_http_proxy_wasm_dispatch_err( - ngx_http_proxy_wasm_dispatch_t *call); + ngx_http_proxy_wasm_dispatch_t *call, unsigned resume); static void ngx_http_proxy_wasm_dispatch_handler(ngx_event_t *ev); static ngx_chain_t *ngx_http_proxy_wasm_dispatch_request( ngx_http_proxy_wasm_dispatch_t *call); @@ -52,8 +52,55 @@ ngx_http_proxy_wasm_dispatch_strerror(ngx_http_proxy_wasm_dispatch_err_e err) } +static ngx_int_t +invoke_on_http_dispatch_response(ngx_proxy_wasm_exec_t *pwexec, + ngx_http_proxy_wasm_dispatch_t *call) +{ + ngx_proxy_wasm_step_e step; + ngx_proxy_wasm_err_e ecode; + + /** + * Set current call for subsequent call detection after the step + * (no yielding). + */ + pwexec->call = call; + + /** + * Save step: ngx_proxy_wasm_run_step will set pwctx->step (for host + * calls that need it), but we want to resume to the current step when + * all calls are finished (i.e. on_request_headers), so we'll save it + * here and set it back after run_step. + * + * This could eventually move to ngx_proxy_wasm_run_step if needed for + * other "single step invocations". + */ + step = pwexec->parent->step; + +#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_DISPATCH_RESPONSE); + if (ecode != NGX_PROXY_WASM_ERR_NONE) { + /* catch trap for tcp socket resume retval */ + return NGX_ERROR; + } + + /* reset step */ + pwexec->parent->step = step; + + /* remove current call now that callback was invoked */ + pwexec->call = NULL; + + return NGX_OK; +} + + static void -ngx_http_proxy_wasm_dispatch_err(ngx_http_proxy_wasm_dispatch_t *call) +ngx_http_proxy_wasm_dispatch_err(ngx_http_proxy_wasm_dispatch_t *call, + unsigned resume) { #if 0 const char *fmt, ...) @@ -77,6 +124,8 @@ ngx_http_proxy_wasm_dispatch_err(ngx_http_proxy_wasm_dispatch_t *call) p = ngx_slprintf(p, last, "dispatch failed"); if (sock->errlen) { + ngx_wa_assert(sock->status != NGX_WASM_SOCKET_STATUS_OK); + p = ngx_slprintf(p, last, ": %*s", (int) sock->errlen, sock->err); } @@ -104,6 +153,10 @@ ngx_http_proxy_wasm_dispatch_err(ngx_http_proxy_wasm_dispatch_t *call) p - (u_char *) &errbuf, &errbuf); } + if (resume) { + (void) invoke_on_http_dispatch_response(pwexec, call); + } + ngx_http_proxy_wasm_dispatch_destroy(call); pwexec->call = NULL; @@ -374,6 +427,10 @@ ngx_http_proxy_wasm_dispatch(ngx_proxy_wasm_exec_t *pwexec, call->http_reader.rctx = call->rctx; call->http_reader.sock = sock; + if (ngx_wasm_http_reader_init(&call->http_reader) != NGX_OK) { + goto error; + } + /* dispatch */ ev = ngx_calloc(sizeof(ngx_event_t), r->connection->log); @@ -410,7 +467,7 @@ ngx_http_proxy_wasm_dispatch(ngx_proxy_wasm_exec_t *pwexec, error: if (call) { - ngx_http_proxy_wasm_dispatch_err(call); + ngx_http_proxy_wasm_dispatch_err(call, 0); } return NULL; @@ -718,8 +775,6 @@ ngx_http_proxy_wasm_dispatch_resume_handler(ngx_wasm_socket_tcp_t *sock) 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_err_e ecode = NGX_PROXY_WASM_ERR_NONE; - ngx_proxy_wasm_step_e step = pwexec->parent->step; dd("enter"); @@ -830,42 +885,12 @@ ngx_http_proxy_wasm_dispatch_resume_handler(ngx_wasm_socket_tcp_t *sock) /* call has finished */ ngx_queue_remove(&call->q); - /** - * Set current call for subsequent call detection after the step - * (no yielding). - */ - pwexec->call = call; - - /** - * Save step: ngx_proxy_wasm_run_step will set pwctx->step (for host - * calls that need it), but we want to resume to the current step when - * all calls are finished (i.e. on_request_headers), so we'll save it - * here and set it back after run_step. - * - * This could eventually move to ngx_proxy_wasm_run_step if needed for - * other "single step invocations". - */ - step = pwexec->parent->step; - -#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_DISPATCH_RESPONSE); - if (ecode != NGX_PROXY_WASM_ERR_NONE) { - /* catch trap for tcp socket resume retval */ + if (invoke_on_http_dispatch_response(pwexec, call) != NGX_OK) { rc = NGX_ERROR; - goto error2; + ngx_http_proxy_wasm_dispatch_err(call, 0); + goto done; } - /* reset step */ - pwexec->parent->step = step; - - /* remove current call now that callback was invoked */ - pwexec->call = NULL; - ngx_http_proxy_wasm_dispatch_destroy(call); break; @@ -887,15 +912,13 @@ ngx_http_proxy_wasm_dispatch_resume_handler(ngx_wasm_socket_tcp_t *sock) error2: - if (ecode != NGX_PROXY_WASM_ERR_NONE - || rc == NGX_ABORT) - { + if (rc == NGX_ABORT) { /* catch trap for tcp socket resume retval or an instance * that trapped before the response was received */ rc = NGX_ERROR; } - ngx_http_proxy_wasm_dispatch_err(call); + ngx_http_proxy_wasm_dispatch_err(call, 1); done: @@ -920,7 +943,7 @@ ngx_http_proxy_wasm_dispatch_resume_handler(ngx_wasm_socket_tcp_t *sock) if (rc != NGX_ERROR) { rc = ngx_proxy_wasm_resume(pwexec->parent, pwexec->parent->phase, - step); + pwexec->parent->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 9bbe935d0..bb995bfdc 100644 --- a/t/03-proxy_wasm/hfuncs/130-proxy_dispatch_http.t +++ b/t/03-proxy_wasm/hfuncs/130-proxy_dispatch_http.t @@ -7,7 +7,7 @@ use t::TestWasmX; our $ExtResolver = $t::TestWasmX::extresolver; our $ExtTimeout = $t::TestWasmX::exttimeout; -plan_tests(4); +plan_tests(5); run_tests(); __DATA__ @@ -24,6 +24,7 @@ __DATA__ qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - no host/ --- no_error_log [crit] +on_http_call_response @@ -40,6 +41,7 @@ qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - no host qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - no host/ --- no_error_log [crit] +on_http_call_response @@ -56,6 +58,7 @@ qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - no host qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - invalid port/ --- no_error_log [crit] +on_http_call_response @@ -72,6 +75,7 @@ qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - invalid qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - invalid host/ --- no_error_log [crit] +on_http_call_response @@ -88,6 +92,7 @@ qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - invalid qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - invalid port/ --- no_error_log [crit] +on_http_call_response @@ -105,6 +110,7 @@ qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - invalid qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: no :method/ --- no_error_log [crit] +on_http_call_response @@ -123,6 +129,7 @@ qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: no :method/ qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: no :method/ --- no_error_log [crit] +on_http_call_response @@ -140,6 +147,7 @@ qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: no :method/ qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: no :path/ --- no_error_log [crit] +on_http_call_response @@ -155,7 +163,10 @@ qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: no :path/ --- response_body ok --- error_log eval -qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - Connection refused/ +[ + qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - Connection refused/, + "dispatch_status: broken connection" +] --- no_error_log [crit] @@ -174,7 +185,10 @@ qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - Connect --- error_code: 500 --- response_body_like: 500 Internal Server Error --- error_log eval -qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: no resolver defined to resolve "localhost"/ +[ + qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: no resolver defined to resolve "localhost"/, + "dispatch_status: resolver failure" +] --- no_error_log [crit] @@ -196,6 +210,8 @@ qq{ qr/\[error\]/, qr/dispatch failed: tcp socket - no path in the unix domain socket/ ] +--- no_error_log +on_http_call_response @@ -214,7 +230,8 @@ qq{ --- error_log eval [ qr/\[crit\] .*? connect\(\) to unix:\/tmp\/inexistent_file\.sock failed .*? No such file or directory/, - qr/\[error\] .*? dispatch failed: tcp socket - No such file or directory/ + qr/\[error\] .*? dispatch failed: tcp socket - No such file or directory/, + "dispatch_status: broken connection" ] @@ -236,7 +253,8 @@ qq{ --- error_log eval [ qr/\[(error|crit)\] .*? connect\(\) to unix:\/tmp failed .*? (Connection refused|Socket operation on non-socket)/, - qr/\[error\] .*? dispatch failed: tcp socket - (Connection refused|Socket operation on non-socket)/ + qr/\[error\] .*? dispatch failed: tcp socket - (Connection refused|Socket operation on non-socket)/, + "dispatch_status: broken connection" ] @@ -257,11 +275,13 @@ qq{ qr/\[error\]/, qr/dispatch failed: tcp socket - invalid host/ ] +--- no_error_log +on_http_call_response === TEST 15: proxy_wasm - dispatch_http_call() sanity (default resolver) ---- skip_eval: 4: defined $ENV{GITHUB_ACTIONS} +--- skip_eval: 5: defined $ENV{GITHUB_ACTIONS} --- timeout eval: $::ExtTimeout --- load_nginx_modules: ngx_http_echo_module --- main_config eval @@ -282,6 +302,7 @@ ok --- no_error_log [error] [crit] +[alert] @@ -309,6 +330,7 @@ ok --- no_error_log [error] [crit] +[alert] @@ -337,6 +359,7 @@ Hello back --- no_error_log [error] [crit] +[alert] @@ -375,6 +398,7 @@ Host: localhost\s* --- no_error_log [error] [crit] +[alert] @@ -385,7 +409,7 @@ Succeeds on: - HTTP 200 (httpbin.org/headers success) - HTTP 502 (httpbin.org Bad Gateway) - HTTP 504 (httpbin.org Gateway timeout) ---- skip_eval: 4: $::osname =~ m/darwin/ +--- skip_eval: 5: $::osname =~ m/darwin/ --- valgrind --- timeout eval: $::ExtTimeout --- load_nginx_modules: ngx_http_echo_module @@ -412,12 +436,13 @@ qq{ --- no_error_log [error] [crit] +[alert] === TEST 20: proxy_wasm - dispatch_http_call() sanity resolver + hostname (IPv6), default port Disabled on GitHub Actions due to IPv6 constraint. ---- skip_eval: 4: system("ping6 -c 1 ::1 >/dev/null 2>&1") ne 0 || defined $ENV{GITHUB_ACTIONS} +--- skip_eval: 5: system("ping6 -c 1 ::1 >/dev/null 2>&1") ne 0 || defined $ENV{GITHUB_ACTIONS} --- timeout eval: $::ExtTimeout --- load_nginx_modules: ngx_http_echo_module --- wasm_modules: hostcalls @@ -439,6 +464,7 @@ qq{ --- no_error_log [error] [crit] +[alert] @@ -476,6 +502,7 @@ qq{ --- no_error_log [error] [crit] +[alert] @@ -498,7 +525,10 @@ qq{ --- response_body ok --- error_log eval -qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - resolver error: Host not found/ +[ + qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - resolver error: Host not found/, + "dispatch_status: resolver failure" +] --- no_error_log [crit] @@ -524,6 +554,7 @@ ok --- no_error_log [error] [crit] +[alert] @@ -550,6 +581,7 @@ ok --- no_error_log [error] [crit] +[alert] @@ -584,6 +616,7 @@ qq{ --- no_error_log [error] [crit] +[alert] @@ -622,6 +655,7 @@ qq{ --- no_error_log [error] [crit] +[alert] @@ -660,6 +694,7 @@ K: 11.* --- no_error_log [error] [crit] +[alert] @@ -689,6 +724,7 @@ tcp socket reading done tcp socket closing --- no_error_log [error] +[crit] @@ -717,6 +753,7 @@ tcp socket reading done tcp socket closing --- no_error_log [error] +[crit] @@ -747,6 +784,7 @@ tcp socket reading done tcp socket closing --- no_error_log [error] +[crit] @@ -770,6 +808,7 @@ Hello world --- no_error_log [error] [crit] +[alert] @@ -795,6 +834,7 @@ Content-Length: 0.* --- no_error_log [error] [crit] +[alert] @@ -822,6 +862,7 @@ Content-Length: 0.* --- no_error_log [error] [crit] +[alert] @@ -851,6 +892,7 @@ Hello world tcp socket trying to receive data (max: 1) --- no_error_log [error] +[crit] @@ -879,6 +921,7 @@ Hello world --- no_error_log [error] [crit] +[alert] @@ -907,6 +950,7 @@ Hello world tcp socket trying to receive data (max: 1) tcp socket trying to receive data (max: 11) tcp socket - upstream response headers too large, increase wasm_socket_large_buffers size +dispatch_status: reader failure @@ -935,6 +979,7 @@ tcp socket - upstream response headers too large, increase wasm_socket_large_buf tcp socket trying to receive data (max: 24) tcp socket trying to receive data (max: 5) tcp socket - upstream response headers too large, increase wasm_socket_large_buffers size +dispatch_status: reader failure @@ -965,7 +1010,8 @@ ok --- error_log eval [ qr/tcp socket - not enough large buffers available, increase wasm_socket_large_buffers number/, - qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - parser error/ + qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - parser error/, + "dispatch_status: reader failure" ] @@ -996,6 +1042,7 @@ Hello world --- error_log tcp socket trying to receive data (max: 1) tcp socket trying to receive data (max: 1023) +on_http_call_response @@ -1018,7 +1065,10 @@ sub { --- response_body ok --- error_log eval -qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - parser error/ +[ + qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - parser error/, + "dispatch_status: reader failure" +] --- no_error_log [crit] @@ -1049,6 +1099,7 @@ Hello world --- error_log tcp socket trying to receive data (max: 24) tcp socket trying to receive data (max: 1017) +on_http_call_response @@ -1072,6 +1123,7 @@ tcp socket trying to receive data (max: 1017) ok --- error_log eval [ + "on_http_call_response", qr/\[crit\] .*? panicked at/, qr/trap!/, ] @@ -1098,7 +1150,10 @@ sub { --- response_body ok --- error_log eval -qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - parser error/ +[ + qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - parser error/, + "dispatch_status: reader failure" +] --- no_error_log [crit] @@ -1149,6 +1204,7 @@ qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - parser --- no_error_log [error] [crit] +[alert] @@ -1183,6 +1239,7 @@ qr/^\*\d+ .*? on_http_call_response \(id: \d+[^*]* --- no_error_log [error] [crit] +[alert] @@ -1208,6 +1265,7 @@ X-Callout-Header: callout-header-value --- no_error_log [error] [crit] +[alert] @@ -1251,6 +1309,7 @@ qr/^\*\d+ .*? on_http_call_response \(id: \d+, status: 200[^*]* --- no_error_log [error] [crit] +[alert] @@ -1278,6 +1337,7 @@ helloworld --- no_error_log [error] [crit] +[alert] @@ -1305,6 +1365,7 @@ helloworl --- no_error_log [error] [crit] +[alert] @@ -1329,6 +1390,7 @@ cannot override the "Host" header, skipping cannot override the "Connection" header, skipping --- no_error_log [error] +[crit] @@ -1353,6 +1415,7 @@ cannot override the "Connection" header, skipping --- no_error_log [error] [crit] +[alert] @@ -1365,19 +1428,16 @@ cannot override the "Connection" header, skipping } location /t { - proxy_wasm hostcalls 'on=request_body \ + proxy_wasm hostcalls 'on=request_headers \ test=/t/dispatch_http_call \ host=127.0.0.1:$TEST_NGINX_SERVER_PORT \ path=/dispatched?foo=bár%20bla \ on_http_call_response=echo_response_body'; echo failed; } ---- request -GET /t - -Hello world --- response_body Hello back /dispatched?foo=bár%20bla /dispatched ? foo=bár%20bla --- no_error_log [error] [crit] +[alert] diff --git a/t/03-proxy_wasm/hfuncs/131-proxy_dispatch_http_timeouts.t b/t/03-proxy_wasm/hfuncs/131-proxy_dispatch_http_timeouts.t index 8ea0def08..d557d615a 100644 --- a/t/03-proxy_wasm/hfuncs/131-proxy_dispatch_http_timeouts.t +++ b/t/03-proxy_wasm/hfuncs/131-proxy_dispatch_http_timeouts.t @@ -14,7 +14,7 @@ use t::TestWasmX; our $ExtResolver = $t::TestWasmX::extresolver; our $ExtTimeout = $t::TestWasmX::exttimeout; -plan_tests(4); +plan_tests(6); run_tests(); __DATA__ @@ -32,14 +32,19 @@ qq{ wasm_socket_connect_timeout 1ms; proxy_wasm hostcalls 'test=/t/dispatch_http_call \ - host=google.com'; + host=google.com \ + on_http_call_response=echo_response_headers'; echo ok; } } ---- response_body -ok +--- response_body_like +:dispatch_status: timeout --- error_log eval -qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - timed out connecting to \".*?\"/ +[ + qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - timed out connecting to \".*?\"/, + qr/\*\d+ .*? on_http_call_response \(id: \d+, status: , headers: 0, body_bytes: 0/, + qr/dispatch_status: timeout/ +] --- no_error_log [crit] @@ -65,7 +70,11 @@ qq{ --- response_body ok --- error_log eval -qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - resolver error: Operation timed out/ +[ + qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - resolver error: Operation timed out/, + qr/on_http_call_response \(id: \d+, status: , headers: 0, body_bytes: 0/, + "dispatch_status: resolver failure" +] --- no_error_log [crit] @@ -92,7 +101,11 @@ macOS: mockeagain NYI --- response_body ok --- error_log eval -qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - timed out reading from \"127\.0\.0\.1:\d+\"/ +[ + qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - timed out reading from \"127\.0\.0\.1:\d+\"/, + qr/on_http_call_response \(id: \d+, status: (\d+)?, headers: \d+, body_bytes: \d+/, + "dispatch_status: timeout" +] --- no_error_log [crit] @@ -121,7 +134,11 @@ macOS: mockeagain NYI --- response_body ok --- error_log eval -qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - timed out writing to \".*?\"/ +[ + qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - timed out writing to \".*?\"/, + qr/on_http_call_response \(id: \d+, status: , headers: 0, body_bytes: 0/, + "dispatch_status: timeout" +] --- no_error_log [crit] @@ -149,6 +166,8 @@ Hello world --- no_error_log [error] [crit] +[alert] +[emerg] @@ -179,3 +198,5 @@ Hello world --- no_error_log [error] [crit] +[alert] +[emerg] diff --git a/t/03-proxy_wasm/hfuncs/132-proxy_dispatch_http_ssl.t b/t/03-proxy_wasm/hfuncs/132-proxy_dispatch_http_ssl.t index 7b8ca5bdb..9228315b6 100644 --- a/t/03-proxy_wasm/hfuncs/132-proxy_dispatch_http_ssl.t +++ b/t/03-proxy_wasm/hfuncs/132-proxy_dispatch_http_ssl.t @@ -17,7 +17,7 @@ add_block_preprocessor(sub { } }); -plan_tests(4); +plan_tests(6); run_tests(); __DATA__ @@ -54,6 +54,9 @@ ok qr/\[warn\] .*? tls certificate not verified/, qr/\[warn\] .*? tls certificate host not verified/ ] +--- no_error_log +[error] +[crit] @@ -93,7 +96,9 @@ ok --- no_error_log eval [ qr/tls certificate not verified/, - qr/\[error\]/ + "[error]", + "[crit]", + "[alert]" ] @@ -138,6 +143,8 @@ Content-Length: 0.* qr/verifying tls certificate for "hostname:\d+" \(sni: "hostname"\)/ --- no_error_log [error] +[crit] +[alert] @@ -185,6 +192,8 @@ Content-Length: 0.* "verifying tls certificate for \"unix:$ENV{TEST_NGINX_UNIX_SOCKET}\" (sni: \"localhost\")" --- no_error_log [error] +[crit] +[alert] @@ -213,7 +222,11 @@ qq{ --- response_body ok --- error_log eval -qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - tls certificate verify error: \(10:certificate has expired\)/ +[ + qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - tls certificate verify error: \(10:certificate has expired\)/, + qr/\*\d+ .*? on_http_call_response \(id: \d+, status: , headers: 0, body_bytes: 0/, + qr/dispatch_status: tls handshake failure/ +] --- no_error_log [crit] @@ -260,6 +273,8 @@ Content-Length: 0.* qr/checking tls certificate CN for "hostname:\d+" \(sni: "hostname"\)/ --- no_error_log [error] +[crit] +[alert] @@ -294,7 +309,11 @@ qq{ --- response_body ok --- error_log eval -qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - tls certificate CN does not match \"localhost\" sni/ +[ + qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - tls certificate CN does not match \"localhost\" sni/, + qr/\*\d+ .*? on_http_call_response \(id: \d+, status: , headers: 0, body_bytes: 0/, + qr/dispatch_status: tls handshake failure/ +] --- no_error_log [crit] @@ -325,7 +344,11 @@ qq{ --- response_body ok --- error_log eval -qr/tls certificate verify error: \(19:self.signed certificate in certificate chain\)/ +[ + qr/tls certificate verify error: \(19:self.signed certificate in certificate chain\)/, + qr/\*\d+ .*? on_http_call_response \(id: \d+, status: , headers: 0, body_bytes: 0/, + qr/dispatch_status: tls handshake failure/ +] --- no_error_log [crit] @@ -353,7 +376,9 @@ ok --- error_log eval [ qr/\[crit\] .*? SSL_do_handshake\(\) failed/, - qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - tls handshake failed/ + qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - tls handshake failed/, + qr/\*\d+ .*? on_http_call_response \(id: \d+, status: , headers: 0, body_bytes: 0/, + qr/dispatch_status: tls handshake failure/ ] @@ -366,6 +391,8 @@ qr/\[emerg\] .*?no such file/i --- no_error_log [error] [crit] +[alert] +stub --- must_die @@ -380,6 +407,8 @@ qr/\[emerg\] .*?no certificate or crl found/i --- no_error_log [error] [crit] +[alert] +stub --- must_die --- user_files >>> ca.pem @@ -389,7 +418,7 @@ foo === TEST 12: proxy_wasm - dispatch_https_call() no trusted CA macOS: intermitent failures ---- skip_eval: 4: $::osname =~ m/darwin/ +--- skip_eval: $::osname =~ m/darwin/ --- timeout eval: $::ExtTimeout --- main_config eval qq{ @@ -411,7 +440,11 @@ qq{ } } --- error_log eval -qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - tls certificate verify error: \((18|20):(self-signed certificate|unable to get local issuer certificate)\)/ +[ + qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - tls certificate verify error: \((18|20):(self-signed certificate|unable to get local issuer certificate)\)/, + qr/\*\d+ .*? on_http_call_response \(id: \d+, status: , headers: 0, body_bytes: 0/, + qr/dispatch_status: tls handshake failure/ +] --- no_error_log [crit] [emerg] @@ -420,7 +453,7 @@ qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - tls cer === TEST 13: proxy_wasm - dispatch_https_call() empty trusted CA path macOS: intermitent failures ---- skip_eval: 4: $::osname =~ m/darwin/ +--- skip_eval: $::osname =~ m/darwin/ --- timeout eval: $::ExtTimeout --- main_config eval qq{ @@ -446,7 +479,11 @@ qq{ --- response_body ok --- error_log eval -qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - tls certificate verify error: \((18|20):(self-signed certificate|unable to get local issuer certificate)\)/ +[ + qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - tls certificate verify error: \((18|20):(self-signed certificate|unable to get local issuer certificate)\)/, + qr/\*\d+ .*? on_http_call_response \(id: \d+, status: , headers: 0, body_bytes: 0/, + qr/dispatch_status: tls handshake failure/ +] --- no_error_log [crit] @@ -490,6 +527,9 @@ ok qr/upstream tls server name: "hostname"/, qr/checking tls certificate CN for "hostname:\d+" \(sni: "hostname"\)/, ] +--- no_error_log +[error] +[crit] @@ -522,7 +562,11 @@ qq{ --- response_body ok --- error_log eval -qr/could not derive tls sni from host \("127\.0\.0\.1:\d+"\)/ +[ + qr/could not derive tls sni from host \("127\.0\.0\.1:\d+"\)/, + qr/\*\d+ .*? on_http_call_response \(id: \d+, status: , headers: 0, body_bytes: 0/, + qr/dispatch_status: tls handshake failure/ +] --- no_error_log [crit] @@ -552,7 +596,11 @@ SNI cannot be an IP address. --- response_body ok --- error_log eval -qr/could not derive tls sni from host \("\[0:0:0:0:0:0:0:1\]:\d+"\)/ +[ + qr/could not derive tls sni from host \("\[0:0:0:0:0:0:0:1\]:\d+"\)/, + qr/\*\d+ .*? on_http_call_response \(id: \d+, status: , headers: 0, body_bytes: 0/, + qr/dispatch_status: tls handshake failure/ +] --- no_error_log [crit] @@ -595,8 +643,11 @@ ok --- error_log eval [ "upstream tls server name: \"hostname\"", - qr/checking tls certificate CN for "127\.0\.0\.1:\d+" \(sni: "hostname"\)/, + qr/checking tls certificate CN for "127\.0\.0\.1:\d+" \(sni: "hostname"\)/ ] +--- no_error_log +[error] +[crit] @@ -636,6 +687,8 @@ ok --- no_error_log [error] [crit] +[alert] +[emerg] @@ -680,6 +733,9 @@ ok "upstream tls server name: \"hostname\"", "verifying tls certificate for \"unix:$ENV{TEST_NGINX_UNIX_SOCKET}\" (sni: \"hostname\")" ] +--- no_error_log +[error] +[crit] @@ -721,6 +777,8 @@ ok --- no_error_log [error] [crit] +[alert] +[emerg] @@ -762,6 +820,9 @@ qq{ qr/\[warn\] .*? tls certificate host not verified/, "on_root_http_call_response (id: 0, status: 200, headers: 5, body_bytes: 3, trailers: 0)", ] +--- no_error_log +[error] +[crit] @@ -805,3 +866,6 @@ qq{ qr/checking tls certificate CN for "hostname:\d+" \(sni: "hostname"\)/, "on_root_http_call_response (id: 0, status: 200, headers: 5, body_bytes: 3, trailers: 0)", ] +--- no_error_log +[error] +[crit] 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 3e93b9255..6374e5741 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 @@ -395,10 +395,11 @@ qr/\A.*? on_request_headers.* --- grep_error_log_out eval qr/\A\[error] .*? dispatch failed: tcp socket - Connection refused \[error] .*? dispatch failed: tcp socket - Connection refused\Z/ +--- error_log +dispatch_status: broken connection +dispatch_status: broken connection --- no_error_log [crit] -[emerg] -[alert] @@ -423,10 +424,11 @@ ok --- grep_error_log_out eval qr/\A\[error] .*? dispatch failed: tcp socket - Connection refused \[error] .*? dispatch failed: tcp socket - Connection refused\Z/ +--- error_log +dispatch_status: broken connection +dispatch_status: broken connection --- no_error_log [crit] -[emerg] -[alert] @@ -452,4 +454,4 @@ proxy_wasm http dispatch cancelled --- no_error_log [crit] [emerg] -[alert] +on_http_call_response diff --git a/t/03-proxy_wasm/sdks/002-go_sdk/005-dispatch_call_on_tick.t b/t/03-proxy_wasm/sdks/002-go_sdk/005-dispatch_call_on_tick.t index e14e17946..a1923949b 100644 --- a/t/03-proxy_wasm/sdks/002-go_sdk/005-dispatch_call_on_tick.t +++ b/t/03-proxy_wasm/sdks/002-go_sdk/005-dispatch_call_on_tick.t @@ -24,6 +24,7 @@ Missing IP for "web_service" host requested by the filter. location /t { return 200; } +--- wait: 1 --- ignore_response_body --- error_log eval qr/\[error\] .*? dispatch failed: tcp socket - resolver error: Host not found/ @@ -49,6 +50,7 @@ Connection refused on 127.0.0.1:81 requested by filter. location /t { return 200; } +--- wait: 1 --- ignore_response_body --- error_log eval qr/\[error\] .*? dispatch failed: tcp socket - Connection refused/ diff --git a/t/lib/proxy-wasm-tests/hostcalls/src/filter.rs b/t/lib/proxy-wasm-tests/hostcalls/src/filter.rs index 9f771c645..f3c966c35 100644 --- a/t/lib/proxy-wasm-tests/hostcalls/src/filter.rs +++ b/t/lib/proxy-wasm-tests/hostcalls/src/filter.rs @@ -11,6 +11,7 @@ impl Context for TestHttp { body_size: usize, ntrailers: usize, ) { + let dispatch_status = self.get_http_call_response_header(":dispatch_status"); let status = self.get_http_call_response_header(":status"); let bytes = self.get_http_call_response_body(0, body_size); let op = self @@ -23,6 +24,11 @@ impl Context for TestHttp { token_id, status.unwrap_or("".to_string()), nheaders, body_size, ntrailers, op ); + match dispatch_status.as_deref() { + Some(s) => info!("dispatch_status: {}", s), + None => {} + } + self.add_http_response_header("pwm-call-id", token_id.to_string().as_str()); match op { diff --git a/util/sdks/go.sh b/util/sdks/go.sh index 9e40031e8..d71179ad7 100755 --- a/util/sdks/go.sh +++ b/util/sdks/go.sh @@ -100,6 +100,17 @@ EOF proxywasm.LogCriticalf("dispatch httpcall failed: %v", err) } } +EOF + patch --forward --ignore-whitespace examples/dispatch_call_on_tick/main.go <<'EOF' + @@ -21,7 +21,7 @@ import ( + "github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm/types" + ) + + -const tickMilliseconds uint32 = 100 + +const tickMilliseconds uint32 = 1000 + + func main() { + proxywasm.SetVMContext(&vmContext{}) EOF set -e From 9136e463a6f1d80755ce66c88c3ddecd0eb5e25d Mon Sep 17 00:00:00 2001 From: Thibault Charbonnier Date: Tue, 19 Nov 2024 12:03:42 -0800 Subject: [PATCH 11/60] feat(proxy-wasm) implement 'proxy_wasm_log_dispatch_errors' directive --- docs/DIRECTIVES.md | 66 +++++++--- src/http/ngx_http_wasm.h | 8 +- src/http/ngx_http_wasm_module.c | 50 +++++-- .../proxy_wasm/ngx_http_proxy_wasm_dispatch.c | 6 +- src/wasm/ngx_wasm.h | 1 + src/wasm/ngx_wasm_core_module.c | 22 +++- .../hfuncs/131-proxy_dispatch_http_timeouts.t | 124 +++++++++++++++++- t/lib/proxy-wasm-tests/hostcalls/src/lib.rs | 6 + 8 files changed, 232 insertions(+), 51 deletions(-) diff --git a/docs/DIRECTIVES.md b/docs/DIRECTIVES.md index f19fb9be7..914836844 100644 --- a/docs/DIRECTIVES.md +++ b/docs/DIRECTIVES.md @@ -10,6 +10,7 @@ By alphabetical order: - [module](#module) - [proxy_wasm](#proxy_wasm) - [proxy_wasm_isolation](#proxy_wasm_isolation) +- [proxy_wasm_log_dispatch_errors](#proxy_wasm_log_dispatch_errors) - [proxy_wasm_lua_resolver](#proxy_wasm_lua_resolver) - [proxy_wasm_request_headers_in_access](#proxy_wasm_request_headers_in_access) - [resolver](#resolver) @@ -45,6 +46,8 @@ By context: - [compiler](#compiler) - [backtraces](#backtraces) - [module](#module) + - [proxy_wasm_log_dispatch_errors](#proxy_wasm_log_dispatch_errors) + - [proxy_wasm_lua_resolver](#proxy_wasm_lua_resolver) - [resolver](#resolver) - [resolver_timeout](#resolver_timeout) - [shm_kv](#shm_kv) @@ -72,6 +75,7 @@ By context: - `http{}`, `server{}`, `location{}` - [proxy_wasm](#proxy_wasm) - [proxy_wasm_isolation](#proxy_wasm_isolation) + - [proxy_wasm_log_dispatch_errors](#proxy_wasm_log_dispatch_errors) - [proxy_wasm_lua_resolver](#proxy_wasm_lua_resolver) - [proxy_wasm_request_headers_in_access](#proxy_wasm_request_headers_in_access) - [resolver_add](#resolver_add) @@ -260,7 +264,7 @@ Load a Wasm module from disk. - `path` must point to a bytecode file whose format is `.wasm` (binary) or `.wat` (text). - `config` is an optional configuration string passed to `on_vm_start` when - `module` is a proxy-wasm filter. + `module` is a Proxy-Wasm filter. If successfully loaded, the module can later be referred to by `name`. @@ -286,11 +290,11 @@ proxy_wasm **default** | **example** | `proxy_wasm my_filter_module 'foo=bar';` -Add a proxy-wasm filter to the context's execution chain (see [Execution +Add a Proxy-Wasm filter to the context's execution chain (see [Execution Chain]). - `module` must be a Wasm module name declared by a [module](#module) directive. - This module must be a valid proxy-wasm filter. + This module must be a valid Proxy-Wasm filter. - `config` is an optional configuration string passed to the filter's `on_configure` phase. @@ -305,25 +309,25 @@ start. > Notes Each instance of the `proxy_wasm` directive in the configuration will be -represented by a proxy-wasm root filter context in a Wasm instance. +represented by a Proxy-Wasm root filter context in a Wasm instance. All root filter contexts of the same module share the same instance. All root filter contexts will be initialized during nginx worker process initialization, which will invoke the filters' `on_vm_start` and `on_configure` phases. Each root context may optionally start a single background tick, as -specified by the [proxy-wasm SDK](#proxy-wasm). +specified by the [Proxy-Wasm SDK](#proxy-wasm). Note that when the master process is in use as a daemon (default Nginx configuration), the `nginx` exit code may be `0` when its worker processes fail -initialization. Since proxy-wasm filters are started on a per-process basis, +initialization. Since Proxy-Wasm filters are started on a per-process basis, filter initialization takes place (and may fail) during worker process initialization, which will be reflected in the error logs. On incoming HTTP requests traversing the context (see [Contexts]), the [Execution Chain] will resume execution for the current Nginx phase, which will -cause each configured filter to resume its corresponding proxy-wasm phase. Each -request gets associated with a proxy-wasm HTTP filter context, and a Wasm +cause each configured filter to resume its corresponding Proxy-Wasm phase. Each +request gets associated with a Proxy-Wasm HTTP filter context, and a Wasm instance to execute into. HTTP filter contexts can execute on instances with various lifecycles and @@ -341,13 +345,13 @@ proxy_wasm_isolation **default** | `none` **example** | `proxy_wasm_isolation stream;` -Select the Wasm instance isolation mode for proxy-wasm filters. +Select the Wasm instance isolation mode for Proxy-Wasm filters. - `isolation` must be one of `none`, `stream`, `filter`. > Notes -Each proxy-wasm filter within the context's [Execution Chain] will be given an +Each Proxy-Wasm filter within the context's [Execution Chain] will be given an instance to execute onto. The lifecycle and isolation of that instance depend on the chosen `isolation` mode: @@ -359,16 +363,40 @@ the chosen `isolation` mode: [Back to TOC](#directives) +proxy_wasm_log_dispatch_errors +------------------------------ + +**usage** | `proxy_wasm_log_dispatch_errors ;` +------------:|:---------------------------------------------------------------- +**contexts** | `wasm{}`, `http{}`, `server{}`, `location{}` +**default** | `on` +**example** | `proxy_wasm_log_dispatch_errors off;` + +Toggles TCP socket error logs on Proxy-Wasm dispatch calls failure. + +When enabled, an `[error]` log will be produced on failure conditions such as +timeout, broken connection, resolver failure, etc. + +When used in the `wasm{}` context, this directive has a global effect on all +`location{}` contexts (unless overridden) as well as root Proxy-Wasm dispatch +calls. + +[Back to TOC](#directives) + proxy_wasm_lua_resolver ----------------------- **usage** | `proxy_wasm_lua_resolver ;` ------------:|:---------------------------------------------------------------- -**contexts** | `http{}`, `server{}`, `location{}` +**contexts** | `wasm{}`, `http{}`, `server{}`, `location{}` **default** | `off` **example** | `proxy_wasm_lua_resolver on;` -Toggles the "Lua DNS resolver for proxy-wasm" feature within the context. +Toggles the "Lua DNS resolver for Proxy-Wasm" feature within the context. + +When used in the `wasm{}` context, this directive has a global effect on all +`location{}` contexts (unless overridden) as well as root Proxy-Wasm dispatch +calls. **Note:** this directive requires Lua support and will only have an effect if ngx_wasm_module was compiled alongside [OpenResty]. @@ -389,7 +417,7 @@ If not, a default client instance will be created pointing to `8.8.8.8` with a timeout value of `30s`. When in use, any [resolver] directive in the effective context will be ignored -for proxy-wasm HTTP dispatches. +for Proxy-Wasm HTTP dispatches. [Back to TOC](#directives) @@ -431,7 +459,7 @@ This directive's arguments are identical to Nginx's [resolver] directive. Wasm sockets usually rely on the configured Nginx [resolver] to resolve hostname. However, some contexts do not support a [resolver] yet still provide -access to Wasm sockets (e.g. proxy-wasm's `on_vm_start` or `on_tick`). In such +access to Wasm sockets (e.g. Proxy-Wasm's `on_vm_start` or `on_tick`). In such contexts, the global `wasm{}` resolver will be used. The global resolver is also used as a fallback if no resolver is configured in @@ -525,7 +553,7 @@ start. Shared memory zones are shared between all nginx worker processes, and serve as a means of storage and exchange for worker processes of a server instance. -Shared key/value memory zones can be used via the [proxy-wasm +Shared key/value memory zones can be used via the [Proxy-Wasm SDK](#proxy-wasm)'s `[get\|set]_shared_data` API. [Back to TOC](#directives) @@ -557,7 +585,7 @@ start. Shared memory zones are shared between all nginx worker processes, and serve as a means of storage and exchange for worker processes of a server instance. -Shared queue memory zones can be used via the [proxy-wasm SDK](#proxy-wasm)'s +Shared queue memory zones can be used via the [Proxy-Wasm SDK](#proxy-wasm)'s `[enqueue\|dequeue]_shared_queue` API. **Note:** shared memory queues do not presently implement an automatic eviction @@ -663,7 +691,7 @@ This directive is effective for all Wasm sockets in all contexts. > Notes -When using the [proxy-wasm SDK](#proxy-wasm) `dispatch_http_call()` method, a +When using the [Proxy-Wasm SDK](#proxy-wasm) `dispatch_http_call()` method, a `timeout` argument can be specified which will override this setting. For configuring Wasm sockets in `http{}` contexts, see @@ -708,7 +736,7 @@ Set a default timeout value for Wasm sockets read operations. > Notes -When using the [proxy-wasm SDK](#proxy-wasm) `dispatch_http_call()` method, a +When using the [Proxy-Wasm SDK](#proxy-wasm) `dispatch_http_call()` method, a `timeout` argument can be specified which will override this setting. For configuring Wasm sockets in `http{}` contexts, see @@ -729,7 +757,7 @@ Set a default timeout value for Wasm sockets send operations. > Notes -When using the [proxy-wasm SDK](#proxy-wasm) `dispatch_http_call()` method, a +When using the [Proxy-Wasm SDK](#proxy-wasm) `dispatch_http_call()` method, a `timeout` argument can be specified which will override this setting. For configuring Wasm sockets in `http{}` contexts, see diff --git a/src/http/ngx_http_wasm.h b/src/http/ngx_http_wasm.h index bd65db193..4c2f68f28 100644 --- a/src/http/ngx_http_wasm.h +++ b/src/http/ngx_http_wasm.h @@ -79,6 +79,7 @@ struct ngx_http_wasm_req_ctx_s { unsigned ffi_attached:1; unsigned pwm_lua_resolver:1; /* use Lua-land resolver in OpenResty */ + unsigned pwm_log_dispatch_errors:1; }; @@ -95,12 +96,13 @@ typedef struct { ngx_bufs_t socket_large_buffers; /* wasm_socket_large_buffer_size */ ngx_bufs_t resp_body_buffers; /* wasm_response_body_buffers */ - ngx_flag_t pwm_req_headers_in_access; - ngx_flag_t pwm_lua_resolver; - ngx_flag_t postpone_rewrite; ngx_flag_t postpone_access; + ngx_flag_t pwm_req_headers_in_access; + ngx_flag_t pwm_lua_resolver; + ngx_flag_t pwm_log_dispatch_errors; + ngx_queue_t q; /* main_conf */ } ngx_http_wasm_loc_conf_t; diff --git a/src/http/ngx_http_wasm_module.c b/src/http/ngx_http_wasm_module.c index bbaace230..53033496d 100644 --- a/src/http/ngx_http_wasm_module.c +++ b/src/http/ngx_http_wasm_module.c @@ -116,6 +116,8 @@ ngx_wasm_subsystem_t ngx_http_wasm_subsystem = { static ngx_command_t ngx_http_wasm_module_cmds[] = { + /* wasm */ + { ngx_string("wasm_call"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE3, ngx_http_wasm_call_directive, @@ -172,6 +174,22 @@ static ngx_command_t ngx_http_wasm_module_cmds[] = { offsetof(ngx_http_wasm_loc_conf_t, resp_body_buffers), NULL }, + { ngx_string("wasm_postpone_rewrite"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_wasm_loc_conf_t, postpone_rewrite), + NULL }, + + { ngx_string("wasm_postpone_access"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_wasm_loc_conf_t, postpone_access), + NULL }, + + /* proxy_wasm */ + { ngx_string("proxy_wasm"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12, ngx_http_wasm_proxy_wasm_directive, @@ -186,13 +204,6 @@ static ngx_command_t ngx_http_wasm_module_cmds[] = { NGX_HTTP_MODULE, NULL }, - { ngx_string("resolver_add"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, - ngx_http_wasm_resolver_add_directive, - NGX_HTTP_LOC_CONF_OFFSET, - NGX_HTTP_MODULE, - NULL }, - { ngx_string("proxy_wasm_request_headers_in_access"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_flag_slot, @@ -207,18 +218,20 @@ static ngx_command_t ngx_http_wasm_module_cmds[] = { offsetof(ngx_http_wasm_loc_conf_t, pwm_lua_resolver), NULL }, - { ngx_string("wasm_postpone_rewrite"), + { ngx_string("proxy_wasm_log_dispatch_errors"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_flag_slot, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_wasm_loc_conf_t, postpone_rewrite), + offsetof(ngx_http_wasm_loc_conf_t, pwm_log_dispatch_errors), NULL }, - { ngx_string("wasm_postpone_access"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_flag_slot, + /* misc */ + + { ngx_string("resolver_add"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, + ngx_http_wasm_resolver_add_directive, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_wasm_loc_conf_t, postpone_access), + NGX_HTTP_MODULE, NULL }, ngx_null_command @@ -340,6 +353,7 @@ ngx_http_wasm_create_loc_conf(ngx_conf_t *cf) loc->socket_buffer_reuse = NGX_CONF_UNSET; loc->pwm_req_headers_in_access = NGX_CONF_UNSET; loc->pwm_lua_resolver = NGX_CONF_UNSET; + loc->pwm_log_dispatch_errors = NGX_CONF_UNSET; loc->postpone_rewrite = NGX_CONF_UNSET; loc->postpone_access = NGX_CONF_UNSET; @@ -404,6 +418,9 @@ ngx_http_wasm_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_value(conf->pwm_lua_resolver, prev->pwm_lua_resolver, 0); + ngx_conf_merge_value(conf->pwm_log_dispatch_errors, + prev->pwm_log_dispatch_errors, 1); + ngx_conf_merge_value(conf->postpone_rewrite, prev->postpone_rewrite, NGX_CONF_UNSET); @@ -636,10 +653,17 @@ ngx_http_wasm_rctx(ngx_http_request_t *r, ngx_http_wasm_req_ctx_t **out) rctx->pwm_lua_resolver = loc->pwm_lua_resolver != NGX_CONF_UNSET ? loc->pwm_lua_resolver : wcf ? wcf->pwm_lua_resolver : 0; + rctx->pwm_log_dispatch_errors = loc->pwm_log_dispatch_errors + != NGX_CONF_UNSET + ? loc->pwm_log_dispatch_errors + : wcf ? wcf->pwm_log_dispatch_errors : 0; } else { /* fake request */ rctx->pwm_lua_resolver = wcf ? wcf->pwm_lua_resolver : 0; + rctx->pwm_log_dispatch_errors = wcf + ? wcf->pwm_log_dispatch_errors + : 0; } } #if (NGX_DEBUG) 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 ac5a29e50..b0befea6a 100644 --- a/src/http/proxy_wasm/ngx_http_proxy_wasm_dispatch.c +++ b/src/http/proxy_wasm/ngx_http_proxy_wasm_dispatch.c @@ -144,8 +144,10 @@ ngx_http_proxy_wasm_dispatch_err(ngx_http_proxy_wasm_dispatch_t *call, #endif if (!pwexec->ictx->instance->hostcall || rctx->fake_request) { - ngx_wasm_log_error(NGX_LOG_ERR, pwexec->log, 0, - "%*s", p - (u_char *) &errbuf, &errbuf); + if (rctx->pwm_log_dispatch_errors) { + ngx_wasm_log_error(NGX_LOG_ERR, pwexec->log, 0, "%*s", + p - (u_char *) &errbuf, &errbuf); + } } else { /* in-vm, executing a hostcall */ diff --git a/src/wasm/ngx_wasm.h b/src/wasm/ngx_wasm.h index db8d2986f..e19f703b3 100644 --- a/src/wasm/ngx_wasm.h +++ b/src/wasm/ngx_wasm.h @@ -101,6 +101,7 @@ typedef struct { ngx_resolver_t *user_resolver; ngx_flag_t pwm_lua_resolver; + ngx_flag_t pwm_log_dispatch_errors; } ngx_wasm_core_conf_t; diff --git a/src/wasm/ngx_wasm_core_module.c b/src/wasm/ngx_wasm_core_module.c index 1b6dca923..6d96aecf7 100644 --- a/src/wasm/ngx_wasm_core_module.c +++ b/src/wasm/ngx_wasm_core_module.c @@ -166,13 +166,6 @@ static ngx_command_t ngx_wasm_core_commands[] = { offsetof(ngx_wasm_core_conf_t, resolver_timeout), NULL }, - { ngx_string("proxy_wasm_lua_resolver"), - NGX_WASM_CONF|NGX_CONF_TAKE1, - ngx_wasm_core_pwm_lua_resolver_directive, - NGX_WA_WASM_CONF_OFFSET, - offsetof(ngx_wasm_core_conf_t, pwm_lua_resolver), - NULL }, - { ngx_string("socket_connect_timeout"), NGX_WASM_CONF|NGX_CONF_TAKE1, ngx_conf_set_msec_slot, @@ -215,6 +208,20 @@ static ngx_command_t ngx_wasm_core_commands[] = { offsetof(ngx_wasm_core_conf_t, socket_large_buffers), NULL }, + { ngx_string("proxy_wasm_lua_resolver"), + NGX_WASM_CONF|NGX_CONF_TAKE1, + ngx_wasm_core_pwm_lua_resolver_directive, + NGX_WA_WASM_CONF_OFFSET, + offsetof(ngx_wasm_core_conf_t, pwm_lua_resolver), + NULL }, + + { ngx_string("proxy_wasm_log_dispatch_errors"), + NGX_WASM_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_WA_WASM_CONF_OFFSET, + offsetof(ngx_wasm_core_conf_t, pwm_log_dispatch_errors), + NULL }, + ngx_null_command }; @@ -364,6 +371,7 @@ ngx_wasm_core_create_conf(ngx_conf_t *cf) wcf->recv_timeout = NGX_CONF_UNSET_MSEC; wcf->pwm_lua_resolver = NGX_CONF_UNSET; + wcf->pwm_log_dispatch_errors = NGX_CONF_UNSET; wcf->socket_buffer_size = NGX_CONF_UNSET_SIZE; wcf->socket_buffer_reuse = NGX_CONF_UNSET; diff --git a/t/03-proxy_wasm/hfuncs/131-proxy_dispatch_http_timeouts.t b/t/03-proxy_wasm/hfuncs/131-proxy_dispatch_http_timeouts.t index d557d615a..e12dce5d6 100644 --- a/t/03-proxy_wasm/hfuncs/131-proxy_dispatch_http_timeouts.t +++ b/t/03-proxy_wasm/hfuncs/131-proxy_dispatch_http_timeouts.t @@ -42,15 +42,125 @@ qq{ --- error_log eval [ qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - timed out connecting to \".*?\"/, - qr/\*\d+ .*? on_http_call_response \(id: \d+, status: , headers: 0, body_bytes: 0/, - qr/dispatch_status: timeout/ + qr/on_http_call_response \(id: \d+, status: , headers: 0, body_bytes: 0/, + "dispatch_status: timeout" +] +--- no_error_log +[crit] + + + +=== TEST 2: proxy_wasm - dispatch_http_call() 'proxy_wasm_log_dispatch_errors off;' in location{} +Note: enabled in wasm{} (and by default), but disabled in location{} takes precedence. +--- timeout eval: $::ExtTimeout +--- load_nginx_modules: ngx_http_echo_module +--- main_config eval +qq{ + wasm { + proxy_wasm_log_dispatch_errors on; + module hostcalls $t::TestWasmX::crates/hostcalls.wasm; + } +} +--- config eval +qq{ + resolver $::ExtResolver ipv6=off; + resolver_timeout $::ExtTimeout; + + location /t { + proxy_wasm_log_dispatch_errors off; + wasm_socket_connect_timeout 1ms; + + proxy_wasm hostcalls 'test=/t/dispatch_http_call \ + host=google.com'; + echo ok; + } +} +--- response_body +ok +--- error_log eval +[ + qr/on_http_call_response \(id: \d+, status: , headers: 0, body_bytes: 0/, + "dispatch_status: timeout" +] +--- no_error_log +dispatch failed: tcp socket - timed out connecting to +[crit] + + + +=== TEST 3: proxy_wasm - dispatch_http_call() 'proxy_wasm_log_dispatch_errors off;' in wasm{} +--- timeout eval: $::ExtTimeout +--- load_nginx_modules: ngx_http_echo_module +--- main_config eval +qq{ + wasm { + proxy_wasm_log_dispatch_errors off; + module hostcalls $t::TestWasmX::crates/hostcalls.wasm; + } +} +--- config eval +qq{ + resolver $::ExtResolver ipv6=off; + resolver_timeout $::ExtTimeout; + + location /t { + proxy_wasm_log_dispatch_errors off; + wasm_socket_connect_timeout 1ms; + + proxy_wasm hostcalls 'test=/t/dispatch_http_call \ + host=google.com'; + echo ok; + } +} +--- response_body +ok +--- error_log eval +[ + qr/on_http_call_response \(id: \d+, status: , headers: 0, body_bytes: 0/, + "dispatch_status: timeout" +] +--- no_error_log +dispatch failed: tcp socket - timed out connecting to +[crit] + + + +=== TEST 4: proxy_wasm - dispatch_http_call() on_tick with 'proxy_wasm_log_dispatch_errors off;' in wasm{} +Note: needs proxy_wasm_lua_resolver as ipv6=off cannot be configured in default resolver. +--- skip_eval: 6: $::nginxV !~ m/nginx version: openresty/ +--- timeout eval: $::ExtTimeout +--- load_nginx_modules: ngx_http_echo_module +--- main_config eval +qq{ + wasm { + socket_connect_timeout 1ms; + proxy_wasm_lua_resolver on; + proxy_wasm_log_dispatch_errors off; + module hostcalls $t::TestWasmX::crates/hostcalls.wasm; + } +} +--- config + location /t { + proxy_wasm hostcalls 'tick_period=200 \ + on_tick=dispatch \ + host=google.com'; + echo ok; + } +--- wait: 1 +--- response_body +ok +--- error_log eval +[ + qr/on_root_http_call_response \(id: \d+, status: , headers: 0, body_bytes: 0/, + "dispatch_status: timeout" ] --- no_error_log +dispatch failed: tcp socket - timed out connecting to [crit] -=== TEST 2: proxy_wasm - dispatch_http_call() resolver timeout +=== TEST 5: proxy_wasm - dispatch_http_call() resolver timeout Using a non-local resolver --- load_nginx_modules: ngx_http_echo_module --- wasm_modules: hostcalls @@ -80,7 +190,7 @@ ok -=== TEST 3: proxy_wasm - dispatch_http_call() read timeout +=== TEST 6: proxy_wasm - dispatch_http_call() read timeout macOS: mockeagain NYI --- skip_eval: 4: $::osname =~ m/darwin/ --- load_nginx_modules: ngx_http_echo_module @@ -111,7 +221,7 @@ ok -=== TEST 4: proxy_wasm - dispatch_http_call() write timeout +=== TEST 7: proxy_wasm - dispatch_http_call() write timeout macOS: mockeagain NYI --- skip_eval: 4: $::osname =~ m/darwin/ --- load_nginx_modules: ngx_http_echo_module @@ -144,7 +254,7 @@ ok -=== TEST 5: proxy_wasm - dispatch_http_call() on_request_headers EAGAIN +=== TEST 8: proxy_wasm - dispatch_http_call() on_request_headers EAGAIN dispatch_http_call() EAGAIN local_response() EAGAIN --- load_nginx_modules: ngx_http_echo_module @@ -171,7 +281,7 @@ Hello world -=== TEST 6: proxy_wasm - dispatch_http_call() on_request_body EAGAIN +=== TEST 9: proxy_wasm - dispatch_http_call() on_request_body EAGAIN dispatch_http_call() EAGAIN local_response() EAGAIN --- load_nginx_modules: ngx_http_echo_module diff --git a/t/lib/proxy-wasm-tests/hostcalls/src/lib.rs b/t/lib/proxy-wasm-tests/hostcalls/src/lib.rs index 95f2a3e44..f5719536e 100644 --- a/t/lib/proxy-wasm-tests/hostcalls/src/lib.rs +++ b/t/lib/proxy-wasm-tests/hostcalls/src/lib.rs @@ -214,10 +214,16 @@ impl Context for TestRoot { ntrailers: usize, ) { let status = self.get_http_call_response_header(":status"); + let dispatch_status = self.get_http_call_response_header(":dispatch_status"); info!( "[hostcalls] on_root_http_call_response (id: {}, status: {}, headers: {}, body_bytes: {}, trailers: {})", token_id, status.unwrap_or("".to_string()), nheaders, body_size, ntrailers ); + + match dispatch_status.as_deref() { + Some(s) => info!("dispatch_status: {}", s), + None => {} + } } } From d834bb04324c2884337e5ef29b5653e1f6a478c8 Mon Sep 17 00:00:00 2001 From: Thibault Charbonnier Date: Mon, 25 Nov 2024 18:24:05 -0800 Subject: [PATCH 12/60] tests(*) increase robustness of httpbin-reliant tests We sometimes get a real 503 from httpbin.org as well. The tests still succeed in case of upstream errors. --- t/03-proxy_wasm/hfuncs/130-proxy_dispatch_http.t | 5 +++-- .../lua-bridge/002-proxy_wasm_lua_resolver_sanity.t | 10 ++++++---- .../lua-bridge/003-proxy_wasm_lua_resolver_timeouts.t | 5 +++-- 3 files changed, 12 insertions(+), 8 deletions(-) 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 bb995bfdc..75af8db33 100644 --- a/t/03-proxy_wasm/hfuncs/130-proxy_dispatch_http.t +++ b/t/03-proxy_wasm/hfuncs/130-proxy_dispatch_http.t @@ -408,6 +408,7 @@ Needs IPv4 resolution + external I/O to succeed. Succeeds on: - HTTP 200 (httpbin.org/headers success) - HTTP 502 (httpbin.org Bad Gateway) +- HTTP 503 (httpbin.org Service Temporarily Unavailable) - HTTP 504 (httpbin.org Gateway timeout) --- skip_eval: 5: $::osname =~ m/darwin/ --- valgrind @@ -428,11 +429,11 @@ qq{ echo fail; } } ---- error_code_like: (200|502|504) +--- error_code_like: (200|502|503|504) --- response_body_like (\s*"Hello": "world",\s* .*? -\s*"X-Thing": "foo,bar"\s*|.*?502 Bad Gateway.*|.*?504 Gateway Time-out.*) +\s*"X-Thing": "foo,bar"\s*|.*?502 Bad Gateway.*|.*?503 Service Temporarily Unavailable.*|.*?504 Gateway Time-out.*) --- no_error_log [error] [crit] diff --git a/t/04-openresty/lua-bridge/002-proxy_wasm_lua_resolver_sanity.t b/t/04-openresty/lua-bridge/002-proxy_wasm_lua_resolver_sanity.t index 3999e3e2f..d8163e815 100644 --- a/t/04-openresty/lua-bridge/002-proxy_wasm_lua_resolver_sanity.t +++ b/t/04-openresty/lua-bridge/002-proxy_wasm_lua_resolver_sanity.t @@ -18,6 +18,7 @@ __DATA__ Succeeds on: - HTTP 200 (httpbin.org/headers success) - HTTP 502 (httpbin.org Bad Gateway) +- HTTP 503 (httpbin.org Service Temporarily Unavailable) - HTTP 504 (httpbin.org Gateway timeout) --- skip_no_debug --- timeout eval: $::ExtTimeout @@ -33,8 +34,8 @@ Succeeds on: on_http_call_response=echo_response_body'; echo failed; } ---- error_code_like: (200|502|504) ---- response_body_like: ("Host": "httpbin\.org"|.*?502 Bad Gateway.*|.*?504 Gateway Time-out.*) +--- error_code_like: (200|502|503|504) +--- response_body_like: ("Host": "httpbin\.org"|.*?502 Bad Gateway.*|.*?503 Service Temporarily Unavailable.*|.*?504 Gateway Time-out.*) --- error_log eval [ qr/\[debug\] .*? wasm lua resolver thread/, @@ -291,6 +292,7 @@ Needs IPv4 resolution + external I/O to succeed. Succeeds on: - HTTP 200 (httpbin.org/headers success) - HTTP 502 (httpbin.org Bad Gateway) +- HTTP 503 (httpbin.org Service Temporarily Unavailable) - HTTP 504 (httpbin.org Gateway timeout) --- skip_eval: 5: $t::TestWasmX::nginxV !~ m/--with-debug/ || defined $ENV{GITHUB_ACTIONS} --- skip_no_debug @@ -307,8 +309,8 @@ Succeeds on: on_http_call_response=echo_response_body'; echo failed; } ---- error_code_like: (200|502|504) ---- response_body_like: ("Host": "httpbin\.org"|.*?502 Bad Gateway.*|.*?504 Gateway Time-out.*) +--- error_code_like: (200|502|503|504) +--- response_body_like: ("Host": "httpbin\.org"|.*?502 Bad Gateway.*|.*?503 Service Temporarily Unavailable.*|.*?504 Gateway Time-out.*) --- error_log eval [ qr/\[debug\] .*? wasm lua resolver creating new dns_client/, diff --git a/t/04-openresty/lua-bridge/003-proxy_wasm_lua_resolver_timeouts.t b/t/04-openresty/lua-bridge/003-proxy_wasm_lua_resolver_timeouts.t index 1e3de2822..a2ed425ee 100644 --- a/t/04-openresty/lua-bridge/003-proxy_wasm_lua_resolver_timeouts.t +++ b/t/04-openresty/lua-bridge/003-proxy_wasm_lua_resolver_timeouts.t @@ -25,6 +25,7 @@ __DATA__ Succeeds on: - HTTP 200 (httpbin.org/headers success) - HTTP 502 (httpbin.org Bad Gateway) +- HTTP 503 (httpbin.org Service Temporarily Unavailable) - HTTP 504 (httpbin.org Gateway timeout) --- skip_no_debug --- timeout eval: $::ExtTimeout @@ -40,8 +41,8 @@ Succeeds on: on_http_call_response=echo_response_body'; echo failed; } ---- error_code_like: (200|502|504) ---- response_body_like: ("Host": "httpbin\.org"|.*?502 Bad Gateway.*|.*?504 Gateway Time-out.*) +--- error_code_like: (200|502|503|504) +--- response_body_like: ("Host": "httpbin\.org"|.*?502 Bad Gateway.*|.*?503 Service Temporarily Unavailable.*|.*?504 Gateway Time-out.*) --- error_log eval [ qr/\[debug\] .*? wasm lua resolver thread/, From fa699f27dd5c55bbdb607df3c9ca231a1f3f0d78 Mon Sep 17 00:00:00 2001 From: Hisham Muhammad Date: Tue, 3 Dec 2024 14:19:29 -0300 Subject: [PATCH 13/60] chore(v8bridge) recent V8 needs --std=c++20 --- lib/v8bridge/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/v8bridge/Makefile b/lib/v8bridge/Makefile index a0b44743b..30a1e7589 100644 --- a/lib/v8bridge/Makefile +++ b/lib/v8bridge/Makefile @@ -2,7 +2,7 @@ TARGET ?= /usr/local V8_INCDIR ?= /usr/local/include -CXXFLAGS += -I $(V8_INCDIR) -std=c++17 -O3 +CXXFLAGS += -I $(V8_INCDIR) -std=c++20 -O3 build: libv8bridge From cb7e69a746fa8448bf926acef88563adcb95b6ca Mon Sep 17 00:00:00 2001 From: Hisham Muhammad Date: Tue, 3 Dec 2024 14:20:00 -0300 Subject: [PATCH 14/60] chore(runtimes) some environments do not set CC by default --- util/runtimes/v8.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/runtimes/v8.sh b/util/runtimes/v8.sh index 295686ecf..02f6e1ee7 100755 --- a/util/runtimes/v8.sh +++ b/util/runtimes/v8.sh @@ -218,7 +218,7 @@ build_v8bridge() { make -C "$NGX_WASM_DIR/lib/v8bridge" clean fi - local v8_cxx="$CC" + local v8_cxx="${CC:-gcc}" if [[ "$v8_cxx" = "clang" ]]; then # Use the same V8 clang toolchain to build v8bridge - C++ ABI compatibility From d1250d8fcd0d77a27f145b0eecc6703cd344ec96 Mon Sep 17 00:00:00 2001 From: Thibault Charbonnier Date: Tue, 3 Dec 2024 16:23:58 -0800 Subject: [PATCH 15/60] chore(lib) new build option for OpenSSL debug builds Will produce an OpenSSL build that can be debugged via gdb. --- Makefile | 1 + util/_lib.sh | 25 +++++++++++++++++++------ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 5ae460193..b499c36a5 100644 --- a/Makefile +++ b/Makefile @@ -30,6 +30,7 @@ export NGX_BUILD_NOPOOL ?= 0 export NGX_BUILD_FSANITIZE ?= export NGX_BUILD_OPENRESTY ?= export NGX_BUILD_OPENSSL ?= +export NGX_BUILD_OPENSSL_DEBUG ?= 0 export NGX_BUILD_CLANG_ANALYZER ?= 0 export NGX_BUILD_GCOV ?= 0 export NGX_BUILD_FORCE ?= 0 diff --git a/util/_lib.sh b/util/_lib.sh index 804604739..77bb711ca 100644 --- a/util/_lib.sh +++ b/util/_lib.sh @@ -126,14 +126,27 @@ install_openssl() { local dirname="openssl-lib-$OPENSSL_VER" if [ ! -d $dirname ]; then - notice "building OpenSSL..." + notice "building OpenSSL... (debug: $NGX_BUILD_OPENSSL_DEBUG)" local prefix="$(pwd)/$dirname" + local opts="" + + if [[ "$NGX_BUILD_OPENSSL_DEBUG" == 1 ]]; then + opts+="no-asm \ + -fno-inline \ + -fno-omit-frame-pointer \ + -d \ + -g3 \ + -ggdb3 \ + -O0" + fi + pushd openssl-$OPENSSL_VER - ./config \ - --prefix=$prefix \ - --openssldir=$prefix/openssl \ - shared \ - no-threads + eval ./config \ + "--prefix=$prefix" \ + "--openssldir=$prefix/openssl" \ + "shared" \ + "no-threads" \ + "$opts" make -j$(n_jobs) make install_sw popd From 2007d2143f547cc5a6bf7a830e412d6a3d33433c Mon Sep 17 00:00:00 2001 From: Thibault Charbonnier Date: Wed, 4 Dec 2024 09:56:02 -0800 Subject: [PATCH 16/60] chore(deps) bump Nginx to 1.27.3 --- .github/workflows/ci-large.yml | 12 ++++++------ .github/workflows/ci.yml | 26 +++++++++++++------------- Makefile | 2 +- valgrind.suppress | 6 +++--- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/.github/workflows/ci-large.yml b/.github/workflows/ci-large.yml index 32a477aca..9fc7af241 100644 --- a/.github/workflows/ci-large.yml +++ b/.github/workflows/ci-large.yml @@ -23,7 +23,7 @@ jobs: label: [""] os: [ubuntu-latest] cc: [gcc-12] - ngx: [1.27.2] + ngx: [1.27.3] runtime: [wasmtime, wasmer, v8] wasmtime: [26.0.0] wasmer: [3.1.1] @@ -52,7 +52,7 @@ jobs: wasmer: 3.1.1 os: macos-13 cc: clang - ngx: 1.27.2 + ngx: 1.27.3 ssl: ssl debug: debug hup: no_hup @@ -62,7 +62,7 @@ jobs: wasmtime: 26.0.0 os: macos-13 cc: clang - ngx: 1.27.2 + ngx: 1.27.3 ssl: ssl debug: debug hup: hup @@ -72,7 +72,7 @@ jobs: v8: 12.0.267.17 os: macos-13 cc: clang - ngx: 1.27.2 + ngx: 1.27.3 ssl: ssl debug: debug hup: no_hup @@ -101,7 +101,7 @@ jobs: matrix: os: [ubuntu-22.04] cc: [gcc-12] - ngx: [1.27.2] + ngx: [1.27.3] runtime: [wasmer, wasmtime, v8] wasmtime: [26.0.0] wasmer: [3.1.1] @@ -169,7 +169,7 @@ jobs: label: [""] os: [ubuntu-latest] cc: [clang-13, clang-14, gcc-10, gcc-11] - ngx: [1.27.2] + ngx: [1.27.3] runtime: [wasmtime, wasmer, v8] wasmtime: [26.0.0] wasmer: [3.1.1] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2c9cca1b8..d889395e2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,7 +33,7 @@ jobs: label: [""] os: [ubuntu-latest] cc: [gcc-12] - ngx: [1.27.2] + ngx: [1.27.3] openresty: [""] runtime: [wasmer] wasmtime: [""] @@ -50,7 +50,7 @@ jobs: wasmtime: 26.0.0 os: ubuntu-latest cc: gcc-12 - ngx: 1.27.2 + ngx: 1.27.3 ipc: no_ipc ssl: ssl debug: debug @@ -60,7 +60,7 @@ jobs: v8: 12.0.267.17 os: ubuntu-latest cc: gcc-12 - ngx: 1.27.2 + ngx: 1.27.3 ipc: no_ipc ssl: ssl debug: debug @@ -70,7 +70,7 @@ jobs: wasmtime: 26.0.0 os: ubuntu-latest cc: gcc-12 - ngx: 1.27.2 + ngx: 1.27.3 ipc: no_ipc ssl: no_ssl debug: debug @@ -91,7 +91,7 @@ jobs: - label: dynamic_nginx os: ubuntu-latest cc: gcc-12 - ngx: 1.27.2 + ngx: 1.27.3 runtime: wasmtime wasmtime: 26.0.0 ipc: no_ipc @@ -102,7 +102,7 @@ jobs: # No SSL - os: ubuntu-latest cc: gcc-12 - ngx: 1.27.2 + ngx: 1.27.3 runtime: wasmer wasmer: 3.1.1 ipc: no_ipc @@ -136,7 +136,7 @@ jobs: - label: ipc os: ubuntu-latest cc: gcc-12 - ngx: 1.27.2 + ngx: 1.27.3 runtime: wasmtime wasmtime: 26.0.0 ipc: ipc @@ -174,7 +174,7 @@ jobs: with: github-token: ${{ secrets.GITHUB_TOKEN }} parallel-finished: true - carryforward: 'unit-ngx_1.27.2-wasmer-no_ipc-ssl-debug-no_hup-static,unit-ngx_1.27.2-wasmer-no_ipc-ssl-no_debug-no_hup-static,unit-ngx_1.27.2-wasmtime-no_ipc-ssl-debug-hup-static,unit-ngx_1.27.2-wasmtime-no_ipc-ssl-debug-hup-dynamic,unit-ngx_1.27.2-v8-no_ipc-ssl-debug-no_hup-static,unit-ngx_1.27.2-wasmtime-no_ipc-no_ssl-debug-no_hup-static-wasm32-unknown-unknown,unit-ngx_1.21.6-wasmer-no_ipc-ssl-debug-no_hup-static,unit-ngx_1.27.2-wasmer-no_ipc-no_ssl-no_debug-no_hup-static,unit-openresty_1.27.1.1-wasmtime-no_ipc-ssl-debug-no_hup-static,unit-openresty_1.27.1.1-wasmtime-no_ipc-ssl-debug-no_hup-dynamic,unit-ngx_1.27.2-wasmtime-ipc-no_ssl-debug-no_hup-static' + carryforward: 'unit-ngx_1.27.3-wasmer-no_ipc-ssl-debug-no_hup-static,unit-ngx_1.27.3-wasmer-no_ipc-ssl-no_debug-no_hup-static,unit-ngx_1.27.3-wasmtime-no_ipc-ssl-debug-hup-static,unit-ngx_1.27.3-wasmtime-no_ipc-ssl-debug-hup-dynamic,unit-ngx_1.27.3-v8-no_ipc-ssl-debug-no_hup-static,unit-ngx_1.27.3-wasmtime-no_ipc-no_ssl-debug-no_hup-static-wasm32-unknown-unknown,unit-ngx_1.21.6-wasmer-no_ipc-ssl-debug-no_hup-static,unit-ngx_1.27.3-wasmer-no_ipc-no_ssl-no_debug-no_hup-static,unit-openresty_1.27.1.1-wasmtime-no_ipc-ssl-debug-no_hup-static,unit-openresty_1.27.1.1-wasmtime-no_ipc-ssl-debug-no_hup-dynamic,unit-ngx_1.27.3-wasmtime-ipc-no_ssl-debug-no_hup-static' valgrind: name: 'Valgrind' @@ -188,7 +188,7 @@ jobs: wasmer: [3.1.1] os: [ubuntu-22.04] cc: [gcc-12] - ngx: [1.27.2] + ngx: [1.27.3] openresty: [""] wasmtime: [""] v8: [""] @@ -200,7 +200,7 @@ jobs: wasmtime: 26.0.0 os: ubuntu-22.04 cc: gcc-12 - ngx: 1.27.2 + ngx: 1.27.3 hup: no_hup debug: debug path: t/01-wasm @@ -209,7 +209,7 @@ jobs: v8: 12.0.267.17 os: ubuntu-22.04 cc: gcc-12 - ngx: 1.27.2 + ngx: 1.27.3 debug: debug hup: no_hup path: t/01-wasm @@ -297,7 +297,7 @@ jobs: # No SSL - os: ubuntu-latest cc: clang-15 - ngx: 1.27.2 + ngx: 1.27.3 runtime: wasmer wasmer: 3.1.1 ssl: no_ssl @@ -323,7 +323,7 @@ jobs: matrix: os: [ubuntu-latest] cc: [clang-15, gcc-12] - ngx: [1.27.2] + ngx: [1.27.3] runtime: [wasmtime, wasmer, v8] wasmtime: [26.0.0] wasmer: [3.1.1] diff --git a/Makefile b/Makefile index b499c36a5..e5279277e 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -NGX ?= 1.27.2 +NGX ?= 1.27.3 OPENSSL ?= 3.4.0 WASMTIME ?= 26.0.0 WASMER ?= 3.1.1 diff --git a/valgrind.suppress b/valgrind.suppress index 53fd9c16d..6c18f6a36 100644 --- a/valgrind.suppress +++ b/valgrind.suppress @@ -1,5 +1,5 @@ { - + Memcheck:Leak match-leak-kinds: definite fun:malloc @@ -7,14 +7,14 @@ fun:ngx_set_environment } { - + Memcheck:Leak fun:malloc fun:ngx_alloc fun:ngx_event_process_init } { - + Memcheck:Leak match-leak-kinds: possible fun:malloc From f872b9a7eaa71d3e8ba0fe82f65ca8d7f1cc6b6d Mon Sep 17 00:00:00 2001 From: Hisham Muhammad Date: Tue, 3 Dec 2024 14:20:21 -0300 Subject: [PATCH 17/60] chore(deps) bump V8 to 13.1.201.15 --- .github/workflows/ci-large.yml | 10 +++++----- .github/workflows/ci.yml | 8 ++++---- Makefile | 2 +- util/runtime.sh | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci-large.yml b/.github/workflows/ci-large.yml index 9fc7af241..485e497d1 100644 --- a/.github/workflows/ci-large.yml +++ b/.github/workflows/ci-large.yml @@ -27,7 +27,7 @@ jobs: runtime: [wasmtime, wasmer, v8] wasmtime: [26.0.0] wasmer: [3.1.1] - v8: [12.0.267.17] + v8: [13.1.201.15] ipc: [no_ipc] ssl: [ssl] debug: [debug, no_debug] @@ -69,7 +69,7 @@ jobs: # macOS - V8 - label: macos_v8 runtime: v8 - v8: 12.0.267.17 + v8: 13.1.201.15 os: macos-13 cc: clang ngx: 1.27.3 @@ -105,7 +105,7 @@ jobs: runtime: [wasmer, wasmtime, v8] wasmtime: [26.0.0] wasmer: [3.1.1] - v8: [12.0.267.17] + v8: [13.1.201.15] hup: [hup, no_hup] debug: [debug] include: @@ -144,7 +144,7 @@ jobs: runtime: [wasmtime, wasmer, v8] wasmtime: [26.0.0] wasmer: [3.1.1] - v8: [12.0.267.17] + v8: [13.1.201.15] ssl: [no_ssl, ssl] debug: [debug] uses: ./.github/workflows/job-clang-analyzer.yml @@ -173,7 +173,7 @@ jobs: runtime: [wasmtime, wasmer, v8] wasmtime: [26.0.0] wasmer: [3.1.1] - v8: [12.0.267.17] + v8: [13.1.201.15] include: - label: old_nginx os: ubuntu-latest diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d889395e2..5c959c885 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -57,7 +57,7 @@ jobs: hup: hup # V8 - runtime: v8 - v8: 12.0.267.17 + v8: 13.1.201.15 os: ubuntu-latest cc: gcc-12 ngx: 1.27.3 @@ -206,7 +206,7 @@ jobs: path: t/01-wasm # V8 - runtime: v8 - v8: 12.0.267.17 + v8: 13.1.201.15 os: ubuntu-22.04 cc: gcc-12 ngx: 1.27.3 @@ -290,7 +290,7 @@ jobs: runtime: [wasmtime, wasmer, v8] wasmtime: [26.0.0] wasmer: [3.1.1] - v8: [12.0.267.17] + v8: [13.1.201.15] ssl: [ssl] debug: [debug] include: @@ -327,7 +327,7 @@ jobs: runtime: [wasmtime, wasmer, v8] wasmtime: [26.0.0] wasmer: [3.1.1] - v8: [12.0.267.17] + v8: [13.1.201.15] uses: ./.github/workflows/job-build-tests.yml with: os: ${{ matrix.os }} diff --git a/Makefile b/Makefile index e5279277e..40c30ef10 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ NGX ?= 1.27.3 OPENSSL ?= 3.4.0 WASMTIME ?= 26.0.0 WASMER ?= 3.1.1 -V8 ?= 12.0.267.17 +V8 ?= 13.1.201.15 PCRE ?= 10.44 ZLIB ?= 1.3.1 LUAROCKS ?= 3.11.1 diff --git a/util/runtime.sh b/util/runtime.sh index 57883343c..780cfe2d1 100755 --- a/util/runtime.sh +++ b/util/runtime.sh @@ -45,7 +45,7 @@ Options: -A, --arch Architecture in 'uname -m' format (e.g. 'x86_64'). Defaults to the system's own. - -V, --runtime-ver Runtime version to build (e.g. '12.0.267.17') + -V, --runtime-ver Runtime version to build (e.g. '13.1.201.15') Inferred from .github/workflows/release.yml if unspecified. From 060c81ec7c904a312a0f10659b5bc0d62d0ed365 Mon Sep 17 00:00:00 2001 From: Thibault Charbonnier Date: Wed, 11 Dec 2024 09:20:12 -0800 Subject: [PATCH 18/60] chore(*) move dependabot.yml to .github/ It seems .github/ is the correct location for this file as per https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuring-dependabot-version-updates --- dependabot.yml => .github/dependabot.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename dependabot.yml => .github/dependabot.yml (100%) diff --git a/dependabot.yml b/.github/dependabot.yml similarity index 100% rename from dependabot.yml rename to .github/dependabot.yml From f85415b5c915df92027717f51d7815726f9a8593 Mon Sep 17 00:00:00 2001 From: Thibault Charbonnier Date: Wed, 11 Dec 2024 12:16:44 -0800 Subject: [PATCH 19/60] chore(*) update dependabot.yml settings - Ignore bumps in proxy-wasm-rust-sdk-ver-zero-one - Group production dependencies updates - Remove scope from message - Fix label --- .github/dependabot.yml | 52 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 82197f1ef..4c5b5f559 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,47 +1,79 @@ # https://docs.github.com/en/code-security/supply-chain-security/configuration-options-for-dependency-updates version: 2 updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: monthly + labels: + - "pr/dependabot" + commit-message: + prefix: "chore(ci) " + - package-ecosystem: cargo directory: /lib schedule: interval: monthly labels: - - dependabot + - "pr/dependabot" groups: production-dependencies: dependency-type: "production" patterns: - "*" + development-dependencies: + dependency-type: "development" + patterns: + - "*" commit-message: prefix: "chore(deps) " - include: scope - package-ecosystem: cargo - directory: /t/lib + directories: + - "/t/lib/ngx-lua-tests" + - "/t/lib/ngx-rust-tests" + - "/t/lib/wasi-host-tests" + - "/t/lib/wasi-vm-tests" + - "/t/lib/proxy-wasm-tests/benchmarks" + - "/t/lib/proxy-wasm-tests/context-checks" + - "/t/lib/proxy-wasm-tests/hostcalls" + - "/t/lib/proxy-wasm-tests/instance-lifecycle" + - "/t/lib/proxy-wasm-tests/on-phases" + - "/t/lib/proxy-wasm-tests/on-tick" schedule: interval: monthly groups: + production-dependencies: + dependency-type: "production" + patterns: + - "*" development-dependencies: dependency-type: "development" patterns: - "*" labels: - - dependabot + - "pr/dependabot" commit-message: prefix: "chore(tests) " - include: scope - - package-ecosystem: github-actions - directory: / + - package-ecosystem: cargo + directory: /t/lib/proxy-wasm-tests/rust-sdk-ver-zero-one schedule: interval: monthly groups: + production-dependencies: + dependency-type: "production" + patterns: + - "*" development-dependencies: dependency-type: "development" patterns: - "*" + ignore: + # do not update beyond proxy-wasm 0.1.x in rust-sdk-ver-zero-one + - dependency-name: "proxy-wasm" + versions: [">=0.2.0"] labels: - - dependabot + - "pr/dependabot" commit-message: - prefix: "chore(ci) " - include: scope + prefix: "chore(tests) " From 3f19cb5ab54a046f0799976891ae2aa13e84ea33 Mon Sep 17 00:00:00 2001 From: Thibault Charbonnier Date: Wed, 11 Dec 2024 19:16:51 -0800 Subject: [PATCH 20/60] chore(dependabot) ignore wasi >0.11 updates --- .github/dependabot.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 4c5b5f559..ba6030073 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -51,6 +51,9 @@ updates: dependency-type: "development" patterns: - "*" + ignore: + - dependency-name: "wasi" + versions: [">0.11"] labels: - "pr/dependabot" commit-message: @@ -72,7 +75,7 @@ updates: ignore: # do not update beyond proxy-wasm 0.1.x in rust-sdk-ver-zero-one - dependency-name: "proxy-wasm" - versions: [">=0.2.0"] + versions: [">0.1"] labels: - "pr/dependabot" commit-message: From ad506ca3c9ee7aa5606f5c8e122a8bdaf64041d5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Dec 2024 04:07:36 +0000 Subject: [PATCH 21/60] chore(tests) update http requirement Updates the requirements on [http](https://github.com/hyperium/http) to permit the latest version. Updates `http` to 1.2.0 - [Release notes](https://github.com/hyperium/http/releases) - [Changelog](https://github.com/hyperium/http/blob/master/CHANGELOG.md) - [Commits](https://github.com/hyperium/http/compare/v0.2.0...v1.2.0) --- updated-dependencies: - dependency-name: http dependency-type: direct:production dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] --- t/lib/proxy-wasm-tests/rust-sdk-ver-zero-one/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/lib/proxy-wasm-tests/rust-sdk-ver-zero-one/Cargo.toml b/t/lib/proxy-wasm-tests/rust-sdk-ver-zero-one/Cargo.toml index e9a4925a8..3dbc7b403 100644 --- a/t/lib/proxy-wasm-tests/rust-sdk-ver-zero-one/Cargo.toml +++ b/t/lib/proxy-wasm-tests/rust-sdk-ver-zero-one/Cargo.toml @@ -10,5 +10,5 @@ crate-type = ["cdylib"] [dependencies] proxy-wasm = "0.1" -http = "0.2" +http = "1.2" log = "0.4" From 883b627dd4bdcdf5d0ce622855026087eee22592 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Dec 2024 04:07:51 +0000 Subject: [PATCH 22/60] chore(tests) update http requirement Updates the requirements on [http](https://github.com/hyperium/http) to permit the latest version. Updates `http` to 1.2.0 - [Release notes](https://github.com/hyperium/http/releases) - [Changelog](https://github.com/hyperium/http/blob/master/CHANGELOG.md) - [Commits](https://github.com/hyperium/http/compare/v0.2.0...v1.2.0) --- updated-dependencies: - dependency-name: http dependency-type: direct:production dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] --- t/lib/proxy-wasm-tests/hostcalls/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/lib/proxy-wasm-tests/hostcalls/Cargo.toml b/t/lib/proxy-wasm-tests/hostcalls/Cargo.toml index dad9e5d85..a18062d83 100644 --- a/t/lib/proxy-wasm-tests/hostcalls/Cargo.toml +++ b/t/lib/proxy-wasm-tests/hostcalls/Cargo.toml @@ -10,6 +10,6 @@ crate-type = ["cdylib"] [dependencies] proxy-wasm = "0.2" log = "0.4" -http = "0.2" +http = "1.2" enum-utils = "0.1.2" urlencoding = "2.1.2" From 67a4fca0b95c56b083c6336d237801400cd42228 Mon Sep 17 00:00:00 2001 From: dev-null-undefined <50732964+dev-null-undefined@users.noreply.github.com> Date: Wed, 18 Dec 2024 17:09:23 +0100 Subject: [PATCH 23/60] misc(ngx_wavm) fix a format specifier in a debug log Use `PRIu64` for portability across architectures (#655). --- src/wasm/vm/ngx_wavm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wasm/vm/ngx_wavm.c b/src/wasm/vm/ngx_wavm.c index 8c576b701..ec0337375 100644 --- a/src/wasm/vm/ngx_wavm.c +++ b/src/wasm/vm/ngx_wavm.c @@ -1151,7 +1151,7 @@ ngx_wavm_val_vec_set(wasm_val_vec_t *out, const wasm_valtype_vec_t *valtypes, case WASM_I64: ui64 = va_arg(args, uint64_t); - dd("arg %ld i64: %llu", i, ui64); + dd("arg %ld i64: %" PRIu64, i, ui64); ngx_wasm_vec_set_i64(out, i, ui64); break; From 715589a2edb9c2d4bb8c87dc0b2d993843f0e626 Mon Sep 17 00:00:00 2001 From: Thibault Charbonnier Date: Thu, 2 Jan 2025 10:30:19 -0800 Subject: [PATCH 24/60] fix(proxy-wasm) pass VM config size to 'on_vm_start' Fix #654 Co-Authored-By: dev-null-undefined <50732964+dev-null-undefined@users.noreply.github.com> --- src/common/proxy_wasm/ngx_proxy_wasm.c | 3 ++- t/03-proxy_wasm/001-on_root_phases.t | 27 +++++++++++++++++++++++--- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/common/proxy_wasm/ngx_proxy_wasm.c b/src/common/proxy_wasm/ngx_proxy_wasm.c index ce167ecba..05b22c57a 100644 --- a/src/common/proxy_wasm/ngx_proxy_wasm.c +++ b/src/common/proxy_wasm/ngx_proxy_wasm.c @@ -1213,7 +1213,8 @@ ngx_proxy_wasm_create_context(ngx_proxy_wasm_filter_t *filter, rc = ngx_wavm_instance_call_funcref(ictx->instance, filter->proxy_on_vm_start, &rets, - rexec->id, rexec->root_id); + rexec->id, + filter->module->config.len); if (rc != NGX_OK || !rets->data[0].of.i32) { ecode = NGX_PROXY_WASM_ERR_VM_START_FAILED; goto error; diff --git a/t/03-proxy_wasm/001-on_root_phases.t b/t/03-proxy_wasm/001-on_root_phases.t index 2bcc8ac38..e99d482f0 100644 --- a/t/03-proxy_wasm/001-on_root_phases.t +++ b/t/03-proxy_wasm/001-on_root_phases.t @@ -9,7 +9,7 @@ run_tests(); __DATA__ -=== TEST 1: proxy_wasm - on_vm_start +=== TEST 1: proxy_wasm - on_vm_start without configuration --- wasm_modules: on_phases --- config location /t { @@ -25,7 +25,28 @@ qr/\[info\] .*? on_vm_start, config_size: 0/ -=== TEST 2: proxy_wasm - on_configure without configuration +=== TEST 2: proxy_wasm - on_vm_start with configuration +--- main_config eval +qq{ + wasm { + module on_phases $ENV{TEST_NGINX_CRATES_DIR}/on_phases.wasm 'foo=bar'; + } +} +--- config + location /t { + proxy_wasm on_phases; + return 200; + } +--- response_body +--- error_log eval +qr/\[info\] .*? on_vm_start, config_size: 7/ +--- no_error_log +[error] +[crit] + + + +=== TEST 3: proxy_wasm - on_configure without configuration --- wasm_modules: on_phases --- config location /t { @@ -41,7 +62,7 @@ qr/\[info\] .*? on_configure, config_size: 0/ -=== TEST 3: proxy_wasm - on_configure with configuration +=== TEST 4: proxy_wasm - on_configure with configuration --- wasm_modules: on_phases --- config location /t { From 7179e9bef75d77a167e68be438f15ff49221f2c7 Mon Sep 17 00:00:00 2001 From: Thibault Charbonnier Date: Tue, 14 Jan 2025 10:46:01 -0800 Subject: [PATCH 25/60] docs(*) add SECURITY.md --- SECURITY.md | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..b0378e225 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,51 @@ +# Security Policy + +## Reporting a Vulnerability + +At Kong, we take security issues very seriously. If you believe you have found a +security vulnerability in our project, we encourage you to disclose it +responsibly. Please report any potential security vulnerabilities to us by +sending an email to [vulnerability@konghq.com](mailto:vulnerability@konghq.com). + +## How to Report + +1. **Do not publicly disclose the vulnerability**: Please do not create a GitHub + issue or post the vulnerability on public forums. Instead, contact us + directly at [vulnerability@konghq.com](mailto:vulnerability@konghq.com). + +2. **Provide detailed information**: When reporting a vulnerability, please + include as much information as possible to help us understand and reproduce + the issue. This may include: + - Description of the vulnerability + - Steps to reproduce the issue + - Potential impact + - Any relevant logs or screenshots + +## What to Expect + +- **Acknowledgment**: We will acknowledge receipt of your vulnerability report + within 48 hours. +- **Investigation**: Our security team will investigate the report and will keep + you informed of the progress. We aim to resolve critical vulnerabilities + within 30 days of confirmation. +- **Disclosure**: We prefer coordinated disclosure and will work with you to + schedule the disclosure of the vulnerability in a way that minimizes the risk + to users. + +## Bug Bounty Program + +We encourage security researchers to participate in our bug bounty program as +outlined on the [Kong Vulnerability +Disclosure](https://konghq.com/compliance/bug-bounty) page. This program +provides rewards for discovering and reporting security vulnerabilities in +accordance with our disclosure guidelines. + +Thank you for helping to keep ngx_wasm_module secure. + +For more information on our security policies and guidelines, please visit the +[Kong Vulnerability Disclosure](https://konghq.com/compliance/bug-bounty) page. + +## Contact + +For any questions or further assistance, please contact us at +[vulnerability@konghq.com](mailto:vulnerability@konghq.com). From f29dd1cf25293fd799e922e139e6ee87f844a1ad Mon Sep 17 00:00:00 2001 From: Thibault Charbonnier Date: Tue, 14 Jan 2025 13:01:40 -0800 Subject: [PATCH 26/60] chore(ci) minor lcov fixes * Ignore unused lcov exclusions: in our non-debug builds the `src/common/debug` exclude is unused and latest lcov complains about it. * Ignore geninfo source errors: these are very tricky to get right considering the openresty bundle archive file structure makes for an inconvenient `--base-directory` argument. --- .github/workflows/job-unit-tests.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/job-unit-tests.yml b/.github/workflows/job-unit-tests.yml index b825bea76..ee9b6dadc 100644 --- a/.github/workflows/job-unit-tests.yml +++ b/.github/workflows/job-unit-tests.yml @@ -151,13 +151,13 @@ jobs: run: | case "$CC" in clang*) - lcov --gcov-tool gcov --capture --directory work/buildroot --base-directory work/nginx-patched --output-file lcov.info - lcov --gcov-tool gcov --remove lcov.info "*/ngx_wasm_module/src/common/debug/*" --output-file lcov.info + lcov --gcov-tool gcov --ignore-errors source --capture --directory work/buildroot --output-file lcov.info + lcov --ignore-errors unused --gcov-tool gcov --remove lcov.info "*/ngx_wasm_module/src/common/debug/*" --output-file lcov.info lcov --gcov-tool gcov --extract lcov.info "*/ngx_wasm_module/src/*" --output-file lcov.info ;; *) - lcov --gcov-tool gcov-${CC#*-} --capture --directory work/buildroot --output-file lcov.info - lcov --gcov-tool gcov-${CC#*-} --remove lcov.info "*/ngx_wasm_module/src/common/debug/*" --output-file lcov.info + lcov --gcov-tool gcov-${CC#*-} --ignore-errors source --capture --directory work/buildroot --output-file lcov.info + lcov --ignore-errors unused --gcov-tool gcov-${CC#*-} --remove lcov.info "*/ngx_wasm_module/src/common/debug/*" --output-file lcov.info lcov --gcov-tool gcov-${CC#*-} --extract lcov.info "*/ngx_wasm_module/src/*" --output-file lcov.info ;; esac From 63f6784e3caecf2a2b1e98167b0818d8c3797b45 Mon Sep 17 00:00:00 2001 From: Thibault Charbonnier Date: Tue, 14 Jan 2025 13:03:28 -0800 Subject: [PATCH 27/60] tests(build) fix failing tests on ubuntu 24.04 The new `ubuntu-latest` image (24.04) would cause OpenResty 1.21.4.1 to not find the Perl lib during compilation. OpenResty 1.27.1.1 can find the lib without problems. --- t/10-build/001-build_options.t | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/t/10-build/001-build_options.t b/t/10-build/001-build_options.t index ff0b44d65..93f3cb61c 100644 --- a/t/10-build/001-build_options.t +++ b/t/10-build/001-build_options.t @@ -136,16 +136,27 @@ ngx_stream_wasm_module === TEST 10: build with OpenResty ---- build: NGX_BUILD_OPENRESTY=1.21.4.1 make +--- build: NGX_BUILD_OPENRESTY=1.27.1.1 make --- grep_nginxV -openresty/1.21.4.1 (ngx_wasmx_module dev [debug +openresty/1.27.1.1 (ngx_wasmx_module dev [debug built with OpenSSL --with-debug -O0 -ggdb3 -gdwarf -=== TEST 11: build without IPC by default +=== TEST 11: build with OpenResty without debug +--- build: NGX_BUILD_OPENRESTY=1.27.1.1 NGX_BUILD_DEBUG=0 NGX_BUILD_CC_OPT= make +--- grep_nginxV +openresty/1.27.1.1 (ngx_wasmx_module dev +built with OpenSSL +--- no_grep_nginxV +--with-debug +-O0 -ggdb3 -gdwarf + + + +=== TEST 12: build without IPC by default --- build: make --- grep_nginxV ngx_wasmx_module dev [debug @@ -158,7 +169,7 @@ ngx_ipc_core_module -=== TEST 12: build with IPC (NGX_IPC=1) +=== TEST 13: build with IPC (NGX_IPC=1) --- build: make NGX_IPC=1 --- grep_nginxV ngx_wasmx_module dev [ipc @@ -170,7 +181,7 @@ ngx_ipc_core_module -=== TEST 13: build with IPC (NGX_IPC=YES) +=== TEST 14: build with IPC (NGX_IPC=YES) --- build: make NGX_IPC=YES --- grep_nginxV ngx_wasmx_module dev [ipc From 1b5f11f79bdf60707f69612ae978b462d9aaa136 Mon Sep 17 00:00:00 2001 From: Thibault Charbonnier Date: Wed, 15 Jan 2025 11:18:59 -0800 Subject: [PATCH 28/60] chore(ci) update Openresty version in CodeQL jobs (#662) Fix the Perl lib issue on Ubuntu 24.04. --- .github/workflows/codeql.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 25630cfe8..b59cee946 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -30,7 +30,7 @@ jobs: include: - language: c-cpp build-mode: manual - openresty: 1.25.3.2 + openresty: 1.27.1.1 runtime: v8 # v8bridge steps: - uses: actions/checkout@v4 From a31f6d87b593f34031ae89c5b773f3e25fb92614 Mon Sep 17 00:00:00 2001 From: Thibault Charbonnier Date: Mon, 13 Jan 2025 10:59:59 -0800 Subject: [PATCH 29/60] fix(proxy-wasm) catch get/set all scoped properties outside of requests Scoped properties (e.g. `request.*`, `response.*`, `upstream.*`, ...) can only be read/written from within the context of a request. Only non-scoped properties (e.g. `worker_id`) can be accessed from root contexts. Prior to this commit, only `ngx.*` and `wasmx.*` (host) properties were caught. Other scoped properties that did not map to either of those would cause a segfault. We now catch all scoped properties (i.e. containing a `.` character) when getting/setting properties outside of a request. --- .../proxy_wasm/ngx_proxy_wasm_properties.c | 97 +++++++++++-------- .../hfuncs/117-proxy_properties_get.t | 92 ++++++++++++++++++ .../hfuncs/119-proxy_properties_get_ngx.t | 2 +- .../hfuncs/120-proxy_properties_get_host.t | 4 +- .../hfuncs/121-proxy_properties_set.t | 92 ++++++++++++++++++ .../hfuncs/122-proxy_properties_set_ngx.t | 4 +- .../hfuncs/123-proxy_properties_set_host.t | 4 +- .../ffi/300-proxy_wasm_properties_get_ngx.t | 2 +- .../ffi/301-proxy_wasm_properties_get_host.t | 2 +- .../ffi/302-proxy_wasm_properties_set_ngx.t | 2 +- .../ffi/303-proxy_wasm_properties_set_host.t | 2 +- t/lib/proxy-wasm-tests/hostcalls/src/lib.rs | 2 + 12 files changed, 252 insertions(+), 53 deletions(-) diff --git a/src/common/proxy_wasm/ngx_proxy_wasm_properties.c b/src/common/proxy_wasm/ngx_proxy_wasm_properties.c index ebe81881d..42c1dd7fc 100644 --- a/src/common/proxy_wasm/ngx_proxy_wasm_properties.c +++ b/src/common/proxy_wasm/ngx_proxy_wasm_properties.c @@ -774,21 +774,18 @@ ngx_proxy_wasm_properties_get_ngx(ngx_proxy_wasm_ctx_t *pwctx, ngx_uint_t hash; ngx_str_t name; ngx_http_variable_value_t *vv; + ngx_http_request_t *r; ngx_http_wasm_req_ctx_t *rctx; + rctx = (ngx_http_wasm_req_ctx_t *) pwctx->data; + ngx_wa_assert(rctx && !rctx->fake_request); + r = rctx->r; + name.data = (u_char *) (path->data + ngx_prefix_len); name.len = path->len - ngx_prefix_len; - hash = hash_str(name.data, name.len); - rctx = (ngx_http_wasm_req_ctx_t *) pwctx->data; - if (rctx == NULL || rctx->fake_request) { - ngx_wavm_log_error(NGX_LOG_ERR, pwctx->log, NULL, - "cannot get ngx properties outside of a request"); - return NGX_ERROR; - } - - vv = ngx_http_get_variable(rctx->r, &name, hash); + vv = ngx_http_get_variable(r, &name, hash); if (vv && !vv->not_found) { value->data = vv->data; value->len = vv->len; @@ -816,12 +813,7 @@ ngx_proxy_wasm_properties_set_ngx(ngx_proxy_wasm_ctx_t *pwctx, ngx_http_core_main_conf_t *cmcf; rctx = (ngx_http_wasm_req_ctx_t *) pwctx->data; - if (rctx == NULL || rctx->fake_request) { - ngx_wavm_log_error(NGX_LOG_ERR, pwctx->log, NULL, - "cannot set ngx properties outside of a request"); - return NGX_ERROR; - } - + ngx_wa_assert(rctx && !rctx->fake_request); r = rctx->r; cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); @@ -921,17 +913,8 @@ static ngx_int_t ngx_proxy_wasm_properties_get_host(ngx_proxy_wasm_ctx_t *pwctx, ngx_str_t *path, ngx_str_t *value) { - uint32_t hash; - host_props_node_t *hpn; -#ifdef NGX_WASM_HTTP - ngx_http_wasm_req_ctx_t *rctx = pwctx->data; - - if (rctx == NULL || rctx->fake_request) { - ngx_wavm_log_error(NGX_LOG_ERR, pwctx->log, NULL, - "cannot get host properties outside of a request"); - return NGX_ERROR; - } -#endif + uint32_t hash; + host_props_node_t *hpn; dd("get \"%.*s\"", (int) path->len, path->data); @@ -997,14 +980,10 @@ ngx_proxy_wasm_properties_set_host(ngx_proxy_wasm_ctx_t *pwctx, { uint32_t hash; host_props_node_t *hpn; -#ifdef NGX_WASM_HTTP +#if (NGX_WASM_HTTP && NGX_DEBUG) ngx_http_wasm_req_ctx_t *rctx = pwctx->data; - if (rctx == NULL || rctx->fake_request) { - ngx_wavm_log_error(NGX_LOG_ERR, pwctx->log, NULL, - "cannot set host properties outside of a request"); - return NGX_ERROR; - } + ngx_wa_assert(rctx && !rctx->fake_request); #endif dd("set \"%.*s\"=\"%.*s\"", @@ -1076,18 +1055,35 @@ ngx_int_t ngx_proxy_wasm_properties_get(ngx_proxy_wasm_ctx_t *pwctx, ngx_str_t *path, ngx_str_t *value, ngx_str_t *err) { - u_char dotted_path_buf[path->len]; - ngx_int_t rc; - ngx_uint_t key; - ngx_str_t p = { path->len, NULL }; - pwm2ngx_mapping_t *m; + u_char dotted_path_buf[path->len]; + ngx_int_t rc; + ngx_uint_t key; + ngx_str_t p = { path->len, NULL }; + pwm2ngx_mapping_t *m; +#ifdef NGX_WASM_HTTP + ngx_http_wasm_req_ctx_t *rctx = pwctx->data; +#endif + + /* ensure this buffer is initialized for ngx_strchr below */ + ngx_memzero(&dotted_path_buf, path->len); p.data = replace_nulls_by_dots(path, dotted_path_buf); - key = ngx_hash_key(p.data, p.len); ngx_log_debug1(NGX_LOG_DEBUG_WASM, pwctx->log, 0, "wasm properties get \"%V\"", &p); +#ifdef NGX_WASM_HTTP + if ((rctx == NULL || rctx->fake_request) + && ngx_strchr(p.data, '.')) + { + ngx_wavm_log_error(NGX_LOG_ERR, pwctx->log, NULL, + "cannot get scoped properties " + "outside of a request"); + return NGX_ERROR; + } +#endif + + key = ngx_hash_key(p.data, p.len); m = ngx_hash_find_combined(&pwm2ngx_hash, key, p.data, p.len); if (m) { if (!m->getter) { @@ -1142,10 +1138,16 @@ ngx_int_t ngx_proxy_wasm_properties_set(ngx_proxy_wasm_ctx_t *pwctx, ngx_str_t *path, ngx_str_t *value, ngx_str_t *err) { - u_char dotted_path_buf[path->len]; - ngx_str_t p = { path->len, NULL }; - ngx_uint_t key; - pwm2ngx_mapping_t *m; + u_char dotted_path_buf[path->len]; + ngx_str_t p = { path->len, NULL }; + ngx_uint_t key; + pwm2ngx_mapping_t *m; +#ifdef NGX_WASM_HTTP + ngx_http_wasm_req_ctx_t *rctx = pwctx->data; +#endif + + /* ensure this buffer is initialized for ngx_strchr below */ + ngx_memzero(&dotted_path_buf, path->len); p.data = replace_nulls_by_dots(path, dotted_path_buf); @@ -1153,6 +1155,17 @@ ngx_proxy_wasm_properties_set(ngx_proxy_wasm_ctx_t *pwctx, "wasm properties set \"%V\" to \"%V\"", &p, value); +#ifdef NGX_WASM_HTTP + if ((rctx == NULL || rctx->fake_request) + && ngx_strchr(p.data, '.')) + { + ngx_wavm_log_error(NGX_LOG_ERR, pwctx->log, NULL, + "cannot set scoped properties " + "outside of a request"); + return NGX_ERROR; + } +#endif + if (p.len > ngx_prefix_len && ngx_memcmp(p.data, ngx_prefix, ngx_prefix_len) == 0) { diff --git a/t/03-proxy_wasm/hfuncs/117-proxy_properties_get.t b/t/03-proxy_wasm/hfuncs/117-proxy_properties_get.t index e07a17cca..edfc6cbcb 100644 --- a/t/03-proxy_wasm/hfuncs/117-proxy_properties_get.t +++ b/t/03-proxy_wasm/hfuncs/117-proxy_properties_get.t @@ -683,3 +683,95 @@ qr/\[info\] .*? property not found: nonexistent_property,/ --- no_error_log [error] [crit] + + + +=== TEST 16: proxy_wasm - get_property() request.* - not available on: tick (isolation: global) +--- skip_hup +--- wasm_modules: hostcalls +--- load_nginx_modules: ngx_http_echo_module +--- config + location /t { + proxy_wasm hostcalls 'tick_period=200 \ + on_tick=log_property \ + name=request.id'; + echo_sleep 0.5; + echo ok; + } +--- ignore_response_body +--- error_log eval +[ + qr/\[info\] .*? \[hostcalls\] on_tick/, + qr/\[error\] .*? cannot get scoped properties outside of a request/, + qr/\[crit\] .*? panicked at/, + qr/value: InternalFailure/, +] + + + +=== TEST 17: proxy_wasm - get_property() response.* - not available on: tick (isolation: global) +--- skip_hup +--- wasm_modules: hostcalls +--- load_nginx_modules: ngx_http_echo_module +--- config + location /t { + proxy_wasm hostcalls 'tick_period=200 \ + on_tick=log_property \ + name=response.grpc_status'; + echo_sleep 0.5; + echo ok; + } +--- ignore_response_body +--- error_log eval +[ + qr/\[info\] .*? \[hostcalls\] on_tick/, + qr/\[error\] .*? cannot get scoped properties outside of a request/, + qr/\[crit\] .*? panicked at/, + qr/value: InternalFailure/, +] + + + +=== TEST 18: proxy_wasm - get_property() upstream.* - not available on: tick (isolation: global) +--- skip_hup +--- wasm_modules: hostcalls +--- load_nginx_modules: ngx_http_echo_module +--- config + location /t { + proxy_wasm hostcalls 'tick_period=200 \ + on_tick=log_property \ + name=upstream.address'; + echo_sleep 0.5; + echo ok; + } +--- ignore_response_body +--- error_log eval +[ + qr/\[info\] .*? \[hostcalls\] on_tick/, + qr/\[error\] .*? cannot get scoped properties outside of a request/, + qr/\[crit\] .*? panicked at/, + qr/value: InternalFailure/, +] + + + +=== TEST 19: proxy_wasm - get_property() upstream.* - not available on: configure (isolation: global) +--- skip_hup +--- wasm_modules: hostcalls +--- load_nginx_modules: ngx_http_echo_module +--- config + location /t { + proxy_wasm hostcalls 'on_configure=log_property \ + name=upstream.address'; + echo_sleep 0.5; + echo ok; + } +--- must_die: 0 +--- ignore_response_body +--- error_log eval +[ + qr/\[error\] .*? cannot get scoped properties outside of a request/, + qr/\[crit\] .*? panicked at/, + qr/value: InternalFailure/, + qr/\[emerg\] .*? failed initializing "hostcalls"/, +] diff --git a/t/03-proxy_wasm/hfuncs/119-proxy_properties_get_ngx.t b/t/03-proxy_wasm/hfuncs/119-proxy_properties_get_ngx.t index 11d1e3fce..99f3a17ab 100644 --- a/t/03-proxy_wasm/hfuncs/119-proxy_properties_get_ngx.t +++ b/t/03-proxy_wasm/hfuncs/119-proxy_properties_get_ngx.t @@ -147,7 +147,7 @@ ngx_http_* calls. --- error_log eval [ qr/\[info\] .*? \[hostcalls\] on_tick/, - qr/\[error\] .*? cannot get ngx properties outside of a request/, + qr/\[error\] .*? cannot get scoped properties outside of a request/, qr/\[crit\] .*? panicked at/, qr/value: InternalFailure/, ] diff --git a/t/03-proxy_wasm/hfuncs/120-proxy_properties_get_host.t b/t/03-proxy_wasm/hfuncs/120-proxy_properties_get_host.t index 816063fbf..6f6bb3da0 100644 --- a/t/03-proxy_wasm/hfuncs/120-proxy_properties_get_host.t +++ b/t/03-proxy_wasm/hfuncs/120-proxy_properties_get_host.t @@ -142,7 +142,7 @@ qr/\[info\] .*? property not found: was,/ --- error_log eval [ qr/\[info\] .*? \[hostcalls\] on_tick/, - qr/\[error\] .*? cannot get host properties outside of a request/, + qr/\[error\] .*? cannot get scoped properties outside of a request/, qr/\[crit\] .*? panicked at/, qr/value: InternalFailure/, ] @@ -166,7 +166,7 @@ qr/\[info\] .*? property not found: was,/ --- error_log eval [ qr/\[info\] .*? \[hostcalls\] on_tick/, - qr/\[error\] .*? cannot get host properties outside of a request/, + qr/\[error\] .*? cannot get scoped properties outside of a request/, qr/\[crit\] .*? panicked at/, qr/value: InternalFailure/, ] diff --git a/t/03-proxy_wasm/hfuncs/121-proxy_properties_set.t b/t/03-proxy_wasm/hfuncs/121-proxy_properties_set.t index ce631bc60..d85b8f2f3 100644 --- a/t/03-proxy_wasm/hfuncs/121-proxy_properties_set.t +++ b/t/03-proxy_wasm/hfuncs/121-proxy_properties_set.t @@ -59,3 +59,95 @@ forward the NotFound status back to the caller. ] --- no_error_log [emerg] + + + +=== TEST 3: proxy_wasm - set_property() request.* - not available on: tick (isolation: global) +--- wasm_modules: hostcalls +--- load_nginx_modules: ngx_http_echo_module +--- config + location /t { + proxy_wasm hostcalls 'tick_period=200 \ + on_tick=set_property \ + name=request.id \ + show_old=false'; + echo_sleep 0.5; + echo ok; + } +--- ignore_response_body +--- error_log eval +[ + qr/\[info\] .*? \[hostcalls\] on_tick/, + qr/\[error\] .*? cannot set scoped properties outside of a request/, + qr/\[crit\] .*? panicked at/, + qr/unexpected status: 10/, +] + + + +=== TEST 4: proxy_wasm - set_property() response.* - not available on: tick (isolation: global) +--- wasm_modules: hostcalls +--- load_nginx_modules: ngx_http_echo_module +--- config + location /t { + proxy_wasm hostcalls 'tick_period=200 \ + on_tick=set_property \ + name=response.grpc_status \ + show_old=false'; + echo_sleep 0.5; + echo ok; + } +--- ignore_response_body +--- error_log eval +[ + qr/\[info\] .*? \[hostcalls\] on_tick/, + qr/\[error\] .*? cannot set scoped properties outside of a request/, + qr/\[crit\] .*? panicked at/, + qr/unexpected status: 10/, +] + + + +=== TEST 5: proxy_wasm - set_property() upstream.* - not available on: tick (isolation: global) +--- wasm_modules: hostcalls +--- load_nginx_modules: ngx_http_echo_module +--- config + location /t { + proxy_wasm hostcalls 'tick_period=200 \ + on_tick=set_property \ + name=upstream.address \ + show_old=false'; + echo_sleep 0.5; + echo ok; + } +--- ignore_response_body +--- error_log eval +[ + qr/\[info\] .*? \[hostcalls\] on_tick/, + qr/\[error\] .*? cannot set scoped properties outside of a request/, + qr/\[crit\] .*? panicked at/, + qr/unexpected status: 10/, +] + + + +=== TEST 6: proxy_wasm - set_property() upstream.* - not available on: configure (isolation: global) +--- wasm_modules: hostcalls +--- load_nginx_modules: ngx_http_echo_module +--- config + location /t { + proxy_wasm hostcalls 'on_configure=set_property \ + name=upstream.address \ + show_old=false'; + echo_sleep 0.5; + echo ok; + } +--- must_die: 0 +--- ignore_response_body +--- error_log eval +[ + qr/\[error\] .*? cannot set scoped properties outside of a request/, + qr/\[crit\] .*? panicked at/, + qr/unexpected status: 10/, + qr/\[emerg\] .*? failed initializing "hostcalls"/, +] diff --git a/t/03-proxy_wasm/hfuncs/122-proxy_properties_set_ngx.t b/t/03-proxy_wasm/hfuncs/122-proxy_properties_set_ngx.t index 84429308b..8595ddcad 100644 --- a/t/03-proxy_wasm/hfuncs/122-proxy_properties_set_ngx.t +++ b/t/03-proxy_wasm/hfuncs/122-proxy_properties_set_ngx.t @@ -212,7 +212,7 @@ ngx_http_* calls. --- error_log eval [ qr/\[info\] .*? \[hostcalls\] on_tick/, - qr/\[error\] .*? cannot set ngx properties outside of a request/, + qr/\[error\] .*? cannot set scoped properties outside of a request/, qr/\[crit\] .*? panicked at/, qr/unexpected status: 10/, ] @@ -247,7 +247,7 @@ HTTP 200 since the root and request instances are different. --- error_log eval [ qr/\[info\] .*? \[hostcalls\] on_tick/, - qr/\[error\] .*? cannot set ngx properties outside of a request/, + qr/\[error\] .*? cannot set scoped properties outside of a request/, qr/\[crit\] .*? panicked at/, qr/unexpected status: 10/, ] diff --git a/t/03-proxy_wasm/hfuncs/123-proxy_properties_set_host.t b/t/03-proxy_wasm/hfuncs/123-proxy_properties_set_host.t index d66325a57..505f906df 100644 --- a/t/03-proxy_wasm/hfuncs/123-proxy_properties_set_host.t +++ b/t/03-proxy_wasm/hfuncs/123-proxy_properties_set_host.t @@ -159,7 +159,7 @@ ngx_http_* calls. --- error_log eval [ qr/\[info\] .*? \[hostcalls\] on_tick/, - qr/\[error\] .*? cannot set host properties outside of a request/, + qr/\[error\] .*? cannot set scoped properties outside of a request/, qr/\[crit\] .*? panicked at/, qr/unexpected status: 10/, ] @@ -191,7 +191,7 @@ ngx_http_* calls. --- error_log eval [ qr/\[info\] .*? \[hostcalls\] on_tick/, - qr/\[error\] .*? cannot set host properties outside of a request/, + qr/\[error\] .*? cannot set scoped properties outside of a request/, qr/\[crit\] .*? panicked at/, qr/unexpected status: 10/, ] diff --git a/t/04-openresty/ffi/300-proxy_wasm_properties_get_ngx.t b/t/04-openresty/ffi/300-proxy_wasm_properties_get_ngx.t index bc19aa79e..83999947b 100644 --- a/t/04-openresty/ffi/300-proxy_wasm_properties_get_ngx.t +++ b/t/04-openresty/ffi/300-proxy_wasm_properties_get_ngx.t @@ -39,7 +39,7 @@ __DATA__ ok --- error_log eval [ - qr/\[error\] .*? cannot get ngx properties outside of a request/, + qr/\[error\] .*? cannot get scoped properties outside of a request/, qr/\[error\] .*? init_worker_by_lua(\(nginx\.conf:\d+\))?:\d+: unknown error/, ] --- no_error_log diff --git a/t/04-openresty/ffi/301-proxy_wasm_properties_get_host.t b/t/04-openresty/ffi/301-proxy_wasm_properties_get_host.t index 2fd92a0b8..5ca9f2feb 100644 --- a/t/04-openresty/ffi/301-proxy_wasm_properties_get_host.t +++ b/t/04-openresty/ffi/301-proxy_wasm_properties_get_host.t @@ -39,7 +39,7 @@ __DATA__ ok --- error_log eval [ - qr/\[error\] .*? cannot get host properties outside of a request/, + qr/\[error\] .*? cannot get scoped properties outside of a request/, qr/\[error\] .*? init_worker_by_lua(\(nginx\.conf:\d+\))?:\d+: unknown error/, ] diff --git a/t/04-openresty/ffi/302-proxy_wasm_properties_set_ngx.t b/t/04-openresty/ffi/302-proxy_wasm_properties_set_ngx.t index f1cf75ea6..664e81cd3 100644 --- a/t/04-openresty/ffi/302-proxy_wasm_properties_set_ngx.t +++ b/t/04-openresty/ffi/302-proxy_wasm_properties_set_ngx.t @@ -41,7 +41,7 @@ __DATA__ ok --- error_log eval [ - qr/\[error\] .*? cannot set ngx properties outside of a request/, + qr/\[error\] .*? cannot set scoped properties outside of a request/, qr/\[error\] .*? init_worker_by_lua(\(nginx\.conf:\d+\))?:\d+: unknown error/, ] --- no_error_log diff --git a/t/04-openresty/ffi/303-proxy_wasm_properties_set_host.t b/t/04-openresty/ffi/303-proxy_wasm_properties_set_host.t index 74bda3026..2bb0de1c2 100644 --- a/t/04-openresty/ffi/303-proxy_wasm_properties_set_host.t +++ b/t/04-openresty/ffi/303-proxy_wasm_properties_set_host.t @@ -39,7 +39,7 @@ __DATA__ ok --- error_log eval [ - qr/\[error\] .*? cannot set host properties outside of a request/, + qr/\[error\] .*? cannot set scoped properties outside of a request/, qr/\[error\] .*? init_worker_by_lua(\(nginx\.conf:\d+\))?:\d+: unknown error/, ] --- no_error_log diff --git a/t/lib/proxy-wasm-tests/hostcalls/src/lib.rs b/t/lib/proxy-wasm-tests/hostcalls/src/lib.rs index f5719536e..89e39aa63 100644 --- a/t/lib/proxy-wasm-tests/hostcalls/src/lib.rs +++ b/t/lib/proxy-wasm-tests/hostcalls/src/lib.rs @@ -82,6 +82,8 @@ impl RootContext for TestRoot { test_define_metrics(self); test_record_metric(self, TestPhase::Configure); } + "log_property" => test_log_property(self), + "set_property" => test_set_property(self), _ => (), } From 3b009cd2a8cd6503ee1a9249866a8cd8ed9dcec9 Mon Sep 17 00:00:00 2001 From: Thibault Charbonnier Date: Wed, 15 Jan 2025 17:39:57 -0800 Subject: [PATCH 30/60] tests(lua-bridge) ensure CI uses the dnsmasq resolver Some tests resolving to external services were unreliable as they were using a real resolver instead of the local dnsmasq mock resolver that we use on CI. --- .../002-proxy_wasm_lua_resolver_sanity.t | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/t/04-openresty/lua-bridge/002-proxy_wasm_lua_resolver_sanity.t b/t/04-openresty/lua-bridge/002-proxy_wasm_lua_resolver_sanity.t index d8163e815..a8ba970bc 100644 --- a/t/04-openresty/lua-bridge/002-proxy_wasm_lua_resolver_sanity.t +++ b/t/04-openresty/lua-bridge/002-proxy_wasm_lua_resolver_sanity.t @@ -85,6 +85,20 @@ ok --- timeout eval: $::ExtTimeout --- load_nginx_modules: ngx_http_echo_module --- wasm_modules: hostcalls +--- http_config eval +qq{ + init_worker_by_lua_block { + dns_client = require 'resty.dns.client' + assert(dns_client.init({ + noSynchronisation = false, -- default + order = { 'A' }, + resolvConf = { + 'nameserver $::ExtResolver', + 'options timeout:$::ExtTimeout', + } + })) + } +} --- config location /t { proxy_wasm_lua_resolver on; @@ -111,6 +125,20 @@ called 3 times --- timeout eval: $::ExtTimeout --- load_nginx_modules: ngx_http_echo_module --- wasm_modules: hostcalls +--- http_config eval +qq{ + init_worker_by_lua_block { + dns_client = require 'resty.dns.client' + assert(dns_client.init({ + noSynchronisation = false, -- default + order = { 'A' }, + resolvConf = { + 'nameserver $::ExtResolver', + 'options timeout:$::ExtTimeout', + } + })) + } +} --- config location /t { proxy_wasm_lua_resolver on; @@ -612,6 +640,20 @@ ok --- timeout eval: $::ExtTimeout --- load_nginx_modules: ngx_http_echo_module --- wasm_modules: hostcalls +--- http_config eval +qq{ + init_worker_by_lua_block { + dns_client = require 'resty.dns.client' + assert(dns_client.init({ + noSynchronisation = false, -- default + order = { 'A' }, + resolvConf = { + 'nameserver $::ExtResolver', + 'options timeout:$::ExtTimeout', + } + })) + } +} --- config location /t { proxy_wasm_lua_resolver on; @@ -638,6 +680,20 @@ TODO: also test with no_postpone --- timeout eval: $::ExtTimeout --- load_nginx_modules: ngx_http_echo_module --- wasm_modules: hostcalls +--- http_config eval +qq{ + init_worker_by_lua_block { + dns_client = require 'resty.dns.client' + assert(dns_client.init({ + noSynchronisation = false, -- default + order = { 'A' }, + resolvConf = { + 'nameserver $::ExtResolver', + 'options timeout:$::ExtTimeout', + } + })) + } +} --- config location /t { proxy_wasm_lua_resolver on; @@ -689,6 +745,20 @@ ok --- timeout eval: $::ExtTimeout --- load_nginx_modules: ngx_http_echo_module --- wasm_modules: hostcalls +--- http_config eval +qq{ + init_worker_by_lua_block { + dns_client = require 'resty.dns.client' + assert(dns_client.init({ + noSynchronisation = false, -- default + order = { 'A' }, + resolvConf = { + 'nameserver $::ExtResolver', + 'options timeout:$::ExtTimeout', + } + })) + } +} --- config location /t { proxy_wasm_lua_resolver on; @@ -715,6 +785,20 @@ TODO: also test with no_postpone --- timeout eval: $::ExtTimeout --- load_nginx_modules: ngx_http_echo_module --- wasm_modules: hostcalls +--- http_config eval +qq{ + init_worker_by_lua_block { + dns_client = require 'resty.dns.client' + assert(dns_client.init({ + noSynchronisation = false, -- default + order = { 'A' }, + resolvConf = { + 'nameserver $::ExtResolver', + 'options timeout:$::ExtTimeout', + } + })) + } +} --- config location /t { proxy_wasm_lua_resolver on; @@ -766,6 +850,20 @@ ok --- timeout eval: $::ExtTimeout --- load_nginx_modules: ngx_http_echo_module --- wasm_modules: hostcalls +--- http_config eval +qq{ + init_worker_by_lua_block { + dns_client = require 'resty.dns.client' + assert(dns_client.init({ + noSynchronisation = false, -- default + order = { 'A' }, + resolvConf = { + 'nameserver $::ExtResolver', + 'options timeout:$::ExtTimeout', + } + })) + } +} --- config location /t { proxy_wasm_lua_resolver on; @@ -798,6 +896,20 @@ ok --- timeout eval: $::ExtTimeout --- load_nginx_modules: ngx_http_echo_module --- wasm_modules: hostcalls +--- http_config eval +qq{ + init_worker_by_lua_block { + dns_client = require 'resty.dns.client' + assert(dns_client.init({ + noSynchronisation = false, -- default + order = { 'A' }, + resolvConf = { + 'nameserver $::ExtResolver', + 'options timeout:$::ExtTimeout', + } + })) + } +} --- config location /t { proxy_wasm_lua_resolver on; From 0c9eeed055841068dd4f3287cde301c513b1e8f4 Mon Sep 17 00:00:00 2001 From: Niklaus Schen <8458369+Water-Melon@users.noreply.github.com> Date: Fri, 17 Jan 2025 02:51:23 +0800 Subject: [PATCH 31/60] chore(ci) pin 3rd-party actions to commit hashes --- .github/actions/setup-httpbin-server/action.yml | 6 +++--- .github/workflows/ci.yml | 4 ++-- .github/workflows/codeql.yml | 2 +- .github/workflows/job-unit-tests.yml | 8 ++++---- .github/workflows/job-valgrind-tests.yml | 6 +++--- .github/workflows/release.yml | 14 +++++++------- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/.github/actions/setup-httpbin-server/action.yml b/.github/actions/setup-httpbin-server/action.yml index b480cf23b..3e86c77a8 100644 --- a/.github/actions/setup-httpbin-server/action.yml +++ b/.github/actions/setup-httpbin-server/action.yml @@ -58,7 +58,7 @@ runs: - name: Login to GitHub Container Registry if: ${{ steps.setup.outputs.push == 'true' }} - uses: docker/login-action@v3 + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3 with: registry: ghcr.io username: ${{ inputs.ghcr_username }} @@ -66,10 +66,10 @@ runs: - name: Setup Docker Buildx if: ${{ !env.ACT }} - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3 - name: Build httpbin-proxy image - uses: docker/build-push-action@v5 + uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5 with: file: './assets/ci/Dockerfile.nginx' tags: ${{ steps.setup.outputs.tag }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5c959c885..512dabdae 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -170,7 +170,7 @@ jobs: steps: - name: Coveralls Finished if: ${{ !env.ACT }} - uses: coverallsapp/github-action@v2 + uses: coverallsapp/github-action@cfd0633edbd2411b532b808ba7a8b5e04f76d2c8 # v2 with: github-token: ${{ secrets.GITHUB_TOKEN }} parallel-finished: true @@ -255,7 +255,7 @@ jobs: ~/.rustup/toolchains/* ~/.rustup/update-hashes/* key: rust-toolchain-${{ runner.os }}-${{ hashFiles('.github/**/*.yml', '.github/**/*.sh', 'rust-toolchain') }} - - uses: dtolnay/rust-toolchain@stable + - uses: dtolnay/rust-toolchain@1ff72ee08e3cb84d84adba594e0a297990fc1ed3 # stable with: components: clippy - name: 'Setup cache - work/ dir' diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index b59cee946..7b3ffa37b 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -70,7 +70,7 @@ jobs: echo "name=${{ matrix.language }}" >> $GITHUB_OUTPUT fi - name: Filter SARIF - uses: advanced-security/filter-sarif@v1 + uses: advanced-security/filter-sarif@f3b8118a9349d88f7b1c0c488476411145b6270d # v1 with: patterns: | -**/* # exclusion: DENY ALL diff --git a/.github/workflows/job-unit-tests.yml b/.github/workflows/job-unit-tests.yml index ee9b6dadc..e929c869c 100644 --- a/.github/workflows/job-unit-tests.yml +++ b/.github/workflows/job-unit-tests.yml @@ -104,7 +104,7 @@ jobs: key: work-${{ inputs.os }}-${{ inputs.cc }}-${{ inputs.ngx }}-${{ inputs.openresty }}-${{ inputs.runtime }}-${{ hashFiles('util/**/*.sh', 'util/**/*.pl', 'util/**/*.awk', '.github/**/*.yml', '.github/**/*.sh', '.github/**/*.js', 'rust-toolchain', 'Makefile') }} - name: Setup Rust if: ${{ !env.ACT }} - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@1ff72ee08e3cb84d84adba594e0a297990fc1ed3 # stable with: target: wasm32-wasip1 - name: Add wasm32-unknown-unknown target @@ -118,7 +118,7 @@ jobs: go-version: 1.22.x - name: Setup TinyGo if: ${{ !env.ACT }} - uses: acifani/setup-tinygo@v2 + uses: acifani/setup-tinygo@b2ba42b249c7d3efdfe94166ec0f48b3191404f7 # v2 with: tinygo-version: 0.31.1 - name: Setup Node.js @@ -184,7 +184,7 @@ jobs: echo "name=$name" >> $GITHUB_OUTPUT - name: Coveralls Upload if: ${{ !env.ACT && inputs.coverage }} - uses: coverallsapp/github-action@v2 + uses: coverallsapp/github-action@cfd0633edbd2411b532b808ba7a8b5e04f76d2c8 # v2 with: github-token: ${{ secrets.GITHUB_TOKEN }} flag-name: ${{ steps.lcov.outputs.name }} @@ -192,7 +192,7 @@ jobs: parallel: true - name: Codecov Upload if: ${{ !env.ACT && inputs.coverage }} - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4 with: token: ${{ secrets.CODECOV_TOKEN }} files: './lcov.info' diff --git a/.github/workflows/job-valgrind-tests.yml b/.github/workflows/job-valgrind-tests.yml index bed2241a8..33b78dcd1 100644 --- a/.github/workflows/job-valgrind-tests.yml +++ b/.github/workflows/job-valgrind-tests.yml @@ -93,7 +93,7 @@ jobs: key: work-${{ inputs.os }}-${{ inputs.cc }}-${{ inputs.ngx }}-${{ inputs.openresty }}-${{ inputs.runtime }}-${{ hashFiles('util/**/*.sh', 'util/**/*.pl', 'util/**/*.awk', '.github/**/*.yml', '.github/**/*.sh', '.github/**/*.js', 'rust-toolchain', 'Makefile') }} - name: Setup Rust if: ${{ !env.ACT }} - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@1ff72ee08e3cb84d84adba594e0a297990fc1ed3 # stable with: target: wasm32-wasip1 - name: Setup Go @@ -103,7 +103,7 @@ jobs: go-version: 1.22.x - name: Setup TinyGo if: ${{ !env.ACT }} - uses: acifani/setup-tinygo@v2 + uses: acifani/setup-tinygo@b2ba42b249c7d3efdfe94166ec0f48b3191404f7 # v2 with: tinygo-version: 0.31.1 - name: Setup Node.js @@ -139,7 +139,7 @@ jobs: lcov --gcov-tool gcov-${CC#*-} --extract lcov.info "*/ngx_wasm_module/src/*" --output-file lcov.info - name: Codecov Upload if: ${{ !env.ACT && inputs.coverage }} - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4 with: token: ${{ secrets.CODECOV_TOKEN }} files: './lcov.info' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2c80240f6..d38e58f0f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -144,17 +144,17 @@ jobs: steps: - uses: actions/checkout@v3 - name: Login to GitHub Container Registry - uses: docker/login-action@v3 + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.TOKEN_GITHUB }} - name: Setup QEMU - uses: docker/setup-qemu-action@v3 + uses: docker/setup-qemu-action@53851d14592bedcffcf25ea515637cff71ef929a # v3 - name: Setup Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3 - name: ${{ matrix.name }} - uses: docker/build-push-action@v5 + uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5 with: file: ${{ matrix.file }} tags: ${{ matrix.tags }} @@ -267,9 +267,9 @@ jobs: steps: - uses: actions/checkout@v3 - name: Setup QEMU - uses: docker/setup-qemu-action@v3 + uses: docker/setup-qemu-action@53851d14592bedcffcf25ea515637cff71ef929a # v3 - name: Login to GitHub Container Registry - uses: docker/login-action@v3 + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3 with: registry: ghcr.io username: ${{ github.repository_owner }} @@ -448,7 +448,7 @@ jobs: run: find . -name '*.tar.gz' # Channel: nightly - name: Nightly release - uses: marvinpinto/action-automatic-releases@latest + uses: marvinpinto/action-automatic-releases@d68defdd11f9dcc7f52f35c1b7c236ee7513bcc1 if: ${{ needs.setup.outputs.create_release == 'true' && needs.setup.outputs.release_channel == 'nightly' }} with: prerelease: true From 1ec8c84980e8638c5e6e0cbb739ddaa2b211c195 Mon Sep 17 00:00:00 2001 From: Thibault Charbonnier Date: Thu, 16 Jan 2025 11:53:45 -0800 Subject: [PATCH 32/60] chore(ci) bump clang builds to clang-14+clang-18 (#665) Ubuntu 24.04 does not have clang-13 anymore. --- .github/workflows/ci-large.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-large.yml b/.github/workflows/ci-large.yml index 485e497d1..301783872 100644 --- a/.github/workflows/ci-large.yml +++ b/.github/workflows/ci-large.yml @@ -168,7 +168,7 @@ jobs: matrix: label: [""] os: [ubuntu-latest] - cc: [clang-13, clang-14, gcc-10, gcc-11] + cc: [clang-14, clang-18, gcc-10, gcc-11] ngx: [1.27.3] runtime: [wasmtime, wasmer, v8] wasmtime: [26.0.0] From 6138510f14cb767e5403554403b44c1580017d3b Mon Sep 17 00:00:00 2001 From: Martin Kos Date: Wed, 15 Jan 2025 18:18:02 +0100 Subject: [PATCH 33/60] feat(proxy-wasm) new 'request.is_subrequest' property Introduce a new request property `request.is_subrequest` to indicate whether the current request is a subrequest of an existing request (e.g. in slicing scenarios). Note: although the property uses the `request.*` prefix, this is not an Envoy-supported attribute. See #658. Co-Authored-By: Thibault Charbonnier --- docs/PROXY_WASM.md | 1 + .../proxy_wasm/ngx_proxy_wasm_properties.c | 68 +++++++++++++------ .../hfuncs/117-proxy_properties_get.t | 42 ++++++++++-- .../proxy-wasm-tests/hostcalls/src/filter.rs | 1 + 4 files changed, 83 insertions(+), 29 deletions(-) diff --git a/docs/PROXY_WASM.md b/docs/PROXY_WASM.md index a452138d4..020aadac4 100644 --- a/docs/PROXY_WASM.md +++ b/docs/PROXY_WASM.md @@ -712,6 +712,7 @@ implementation state in ngx_wasm_module: `request.size` | :heavy_check_mark: | :x: | Maps to [ngx.content_length](https://nginx.org/en/docs/http/ngx_http_core_module.html#content_length). `request.total_size` | :heavy_check_mark: | :x: | Maps to [ngx.request_length](https://nginx.org/en/docs/http/ngx_http_core_module.html#request_length). `request.headers.*` | :heavy_check_mark: | :x: | Returns the value of any request header, e.g. `request.headers.date`. +`request.is_subrequest` | :heavy_check_mark: | :x: | An ngx_wasm_module extension indicating whether the current request is a subrequest as a `"true"/"false"` string. *Response properties* | | `response.code` | :heavy_check_mark: | :x: | Maps to [ngx.status](https://nginx.org/en/docs/http/ngx_http_core_module.html#status). `response.size` | :heavy_check_mark: | :x: | Maps to [ngx.body_bytes_sent](https://nginx.org/en/docs/http/ngx_http_core_module.html#body_bytes_sent). diff --git a/src/common/proxy_wasm/ngx_proxy_wasm_properties.c b/src/common/proxy_wasm/ngx_proxy_wasm_properties.c index 42c1dd7fc..81183938b 100644 --- a/src/common/proxy_wasm/ngx_proxy_wasm_properties.c +++ b/src/common/proxy_wasm/ngx_proxy_wasm_properties.c @@ -41,15 +41,22 @@ static const char *ngx_prefix = "ngx."; static const size_t ngx_prefix_len = 4; +static const char *host_prefix = + NGX_WASM_HOST_PROPERTY_NAMESPACE_STR "."; +static size_t host_prefix_len; + + +#ifdef NGX_WASM_HTTP +static ngx_str_t str_on = ngx_string("true"); +static ngx_str_t str_off = ngx_string("false"); +#endif + + static ngx_hash_init_t pwm2ngx_init; static ngx_hash_combined_t pwm2ngx_hash; static ngx_hash_keys_arrays_t pwm2ngx_keys; -static const char *host_prefix = NGX_WASM_HOST_PROPERTY_NAMESPACE_STR "."; -static size_t host_prefix_len; - - typedef struct { ngx_str_node_t sn; ngx_str_t value; @@ -171,6 +178,37 @@ get_request_time(ngx_proxy_wasm_ctx_t *pwctx, ngx_str_t *path, } +static ngx_int_t +get_request_header(ngx_proxy_wasm_ctx_t *pwctx, ngx_str_t *path, + ngx_str_t *value) +{ + ngx_str_t name; + + name.data = (u_char *) (path->data + request_headers_prefix_len); + name.len = path->len - request_headers_prefix_len; + + return get_map_value(pwctx, &name, value, + NGX_PROXY_WASM_MAP_HTTP_REQUEST_HEADERS); +} + + +static ngx_int_t +is_subrequest(ngx_proxy_wasm_ctx_t *pwctx, ngx_str_t *path, + ngx_str_t *value) +{ + ngx_str_t *result; + ngx_http_wasm_req_ctx_t *rctx = pwctx->data; + ngx_http_request_t *r = rctx->r; + + result = r != r->main ? &str_on : &str_off; + + value->data = result->data; + value->len = result->len; + + return NGX_OK; +} + + static ngx_int_t get_upstream_address(ngx_proxy_wasm_ctx_t *pwctx, ngx_str_t *path, ngx_str_t *value) @@ -243,20 +281,6 @@ get_upstream_port(ngx_proxy_wasm_ctx_t *pwctx, ngx_str_t *path, } -static ngx_int_t -get_request_header(ngx_proxy_wasm_ctx_t *pwctx, ngx_str_t *path, - ngx_str_t *value) -{ - ngx_str_t name; - - name.data = (u_char *) (path->data + request_headers_prefix_len); - name.len = path->len - request_headers_prefix_len; - - return get_map_value(pwctx, &name, value, - NGX_PROXY_WASM_MAP_HTTP_REQUEST_HEADERS); -} - - static ngx_int_t get_response_header(ngx_proxy_wasm_ctx_t *pwctx, ngx_str_t *path, ngx_str_t *value) @@ -313,9 +337,6 @@ get_connection_mtls(ngx_proxy_wasm_ctx_t *pwctx, ngx_str_t *path, static ngx_str_t verify_p = ngx_string("ngx.ssl_client_verify"); static ngx_str_t verify_e = ngx_string("SUCCESS"); - static ngx_str_t mtls_on = ngx_string("true"); - static ngx_str_t mtls_off = ngx_string("false"); - if (!pwctx->mtls.len) { rc = ngx_proxy_wasm_properties_get_ngx(pwctx, &https_p, &https_v); if (rc != NGX_OK) { @@ -331,7 +352,7 @@ get_connection_mtls(ngx_proxy_wasm_ctx_t *pwctx, ngx_str_t *path, && ngx_str_eq(verify_v.data, verify_v.len, verify_e.data, verify_e.len); - result = on ? &mtls_on : &mtls_off; + result = on ? &str_on : &str_off; pwctx->mtls.data = ngx_pnalloc(pwctx->pool, result->len); if (pwctx->mtls.data == NULL) { @@ -472,6 +493,9 @@ static pwm2ngx_mapping_t pw2ngx[] = { { ngx_string("request.headers.*"), ngx_null_string, &get_request_header, NULL }, + { ngx_string("request.is_subrequest"), + ngx_null_string, + &is_subrequest, NULL }, /* Response properties */ diff --git a/t/03-proxy_wasm/hfuncs/117-proxy_properties_get.t b/t/03-proxy_wasm/hfuncs/117-proxy_properties_get.t index edfc6cbcb..d6d4da1d8 100644 --- a/t/03-proxy_wasm/hfuncs/117-proxy_properties_get.t +++ b/t/03-proxy_wasm/hfuncs/117-proxy_properties_get.t @@ -19,6 +19,7 @@ our $request_properties = join(',', qw( request.duration request.size request.total_size + request.is_subrequest )); plan_tests(5); @@ -63,7 +64,8 @@ request\.protocol: HTTP\/1\.1 at RequestHeaders request\.query: special_arg\=true\&special_arg2\=false at RequestHeaders request\.duration: \d+\.\d+ at RequestHeaders request\.size: 5 at RequestHeaders -request\.total_size: 187 at RequestHeaders/ +request\.total_size: 187 at RequestHeaders +request\.is_subrequest: false at RequestHeaders/ --- no_error_log [error] [crit] @@ -151,7 +153,8 @@ request.method: GET at OnHttpCallResponse request.time: \d+\.\d+ at OnHttpCallResponse request.protocol: HTTP\/1\.1 at OnHttpCallResponse request.query: hello\=world at OnHttpCallResponse -request.total_size: [1-9]+[0-9]+ at OnHttpCallResponse/ +request.total_size: [1-9]+[0-9]+ at OnHttpCallResponse +request.is_subrequest: false at OnHttpCallResponse/ --- no_error_log [error] [crit] @@ -667,7 +670,32 @@ qr/"response.code_details" property not supported -=== TEST 15: proxy_wasm - get_property() - unknown property on: request_headers +=== TEST 15: proxy_wasm - get_property() - request.is_subrequest on: request_headers +--- load_nginx_modules: ngx_http_echo_module +--- wasm_modules: hostcalls +--- config + location /t { + echo_subrequest GET '/sub'; + } + + location /sub { + proxy_wasm hostcalls 'on=request_headers \ + test=/t/log/properties \ + name=request.is_subrequest'; + echo ok; + } +--- response_body +ok +--- grep_error_log eval: qr/request\.is_subrequest: (true|false) at \w+/ +--- grep_error_log_out eval +qr/request\.is_subrequest: true at RequestHeaders/ +--- no_error_log +[error] +[crit] + + + +=== TEST 16: proxy_wasm - get_property() - unknown property on: request_headers --- wasm_modules: hostcalls --- load_nginx_modules: ngx_http_echo_module --- config @@ -686,7 +714,7 @@ qr/\[info\] .*? property not found: nonexistent_property,/ -=== TEST 16: proxy_wasm - get_property() request.* - not available on: tick (isolation: global) +=== TEST 17: proxy_wasm - get_property() request.* - not available on: tick (isolation: global) --- skip_hup --- wasm_modules: hostcalls --- load_nginx_modules: ngx_http_echo_module @@ -709,7 +737,7 @@ qr/\[info\] .*? property not found: nonexistent_property,/ -=== TEST 17: proxy_wasm - get_property() response.* - not available on: tick (isolation: global) +=== TEST 18: proxy_wasm - get_property() response.* - not available on: tick (isolation: global) --- skip_hup --- wasm_modules: hostcalls --- load_nginx_modules: ngx_http_echo_module @@ -732,7 +760,7 @@ qr/\[info\] .*? property not found: nonexistent_property,/ -=== TEST 18: proxy_wasm - get_property() upstream.* - not available on: tick (isolation: global) +=== TEST 19: proxy_wasm - get_property() upstream.* - not available on: tick (isolation: global) --- skip_hup --- wasm_modules: hostcalls --- load_nginx_modules: ngx_http_echo_module @@ -755,7 +783,7 @@ qr/\[info\] .*? property not found: nonexistent_property,/ -=== TEST 19: proxy_wasm - get_property() upstream.* - not available on: configure (isolation: global) +=== TEST 20: proxy_wasm - get_property() upstream.* - not available on: configure (isolation: global) --- skip_hup --- wasm_modules: hostcalls --- load_nginx_modules: ngx_http_echo_module diff --git a/t/lib/proxy-wasm-tests/hostcalls/src/filter.rs b/t/lib/proxy-wasm-tests/hostcalls/src/filter.rs index f3c966c35..4b39adaf0 100644 --- a/t/lib/proxy-wasm-tests/hostcalls/src/filter.rs +++ b/t/lib/proxy-wasm-tests/hostcalls/src/filter.rs @@ -44,6 +44,7 @@ impl Context for TestHttp { "request.protocol", "request.query", "request.total_size", + "request.is_subrequest", ]; for property in properties { From fa0cd87cd0fd9de859b49bf8d297b5cd7b557250 Mon Sep 17 00:00:00 2001 From: Thibault Charbonnier Date: Fri, 17 Jan 2025 10:42:37 -0800 Subject: [PATCH 34/60] fix(proxy-wasm) support get 'plugin_name' in tick context No filter chain initialized on tick contexts means the root context must be stored in the empty filter chain context for later retrieval. --- src/common/proxy_wasm/ngx_proxy_wasm.c | 3 ++ src/common/proxy_wasm/ngx_proxy_wasm.h | 1 + .../proxy_wasm/ngx_proxy_wasm_properties.c | 12 +++-- .../hfuncs/117-proxy_properties_get.t | 52 +++++++++++++++++-- 4 files changed, 60 insertions(+), 8 deletions(-) diff --git a/src/common/proxy_wasm/ngx_proxy_wasm.c b/src/common/proxy_wasm/ngx_proxy_wasm.c index 05b22c57a..6333c996f 100644 --- a/src/common/proxy_wasm/ngx_proxy_wasm.c +++ b/src/common/proxy_wasm/ngx_proxy_wasm.c @@ -840,9 +840,12 @@ ngx_proxy_wasm_run_step(ngx_proxy_wasm_exec_t *pwexec, rc = filter->subsystem->resume(pwexec, step, &action); break; case NGX_PROXY_WASM_STEP_TICK: + ngx_wa_assert(pwexec->root_id == NGX_PROXY_WASM_ROOT_CTX_ID); + pwctx->rexec = pwexec; pwexec->in_tick = 1; rc = ngx_proxy_wasm_on_tick(pwexec); pwexec->in_tick = 0; + pwctx->rexec = NULL; break; default: ngx_proxy_wasm_log_error(NGX_LOG_WASM_NYI, pwctx->log, 0, diff --git a/src/common/proxy_wasm/ngx_proxy_wasm.h b/src/common/proxy_wasm/ngx_proxy_wasm.h index 1d9c73981..e3490f838 100644 --- a/src/common/proxy_wasm/ngx_proxy_wasm.h +++ b/src/common/proxy_wasm/ngx_proxy_wasm.h @@ -213,6 +213,7 @@ struct ngx_proxy_wasm_ctx_s { ngx_uint_t isolation; ngx_proxy_wasm_store_t store; ngx_proxy_wasm_context_type_e type; + ngx_proxy_wasm_exec_t *rexec; /* root exec ctx */ ngx_log_t *log; ngx_pool_t *pool; ngx_pool_t *parent_pool; diff --git a/src/common/proxy_wasm/ngx_proxy_wasm_properties.c b/src/common/proxy_wasm/ngx_proxy_wasm_properties.c index 81183938b..1f6bacfe9 100644 --- a/src/common/proxy_wasm/ngx_proxy_wasm_properties.c +++ b/src/common/proxy_wasm/ngx_proxy_wasm_properties.c @@ -378,9 +378,15 @@ get_filter_name(ngx_proxy_wasm_ctx_t *pwctx, ngx_str_t *path, ngx_proxy_wasm_exec_t *pwexec, *pwexecs; ngx_proxy_wasm_filter_t *filter; - pwexecs = (ngx_proxy_wasm_exec_t *) pwctx->pwexecs.elts; - pwexec = &pwexecs[pwctx->exec_index]; - filter = pwexec->filter; + if (pwctx->step == NGX_PROXY_WASM_STEP_TICK) { + /* no filter chain initialized */ + filter = pwctx->rexec->filter; + + } else { + pwexecs = (ngx_proxy_wasm_exec_t *) pwctx->pwexecs.elts; + pwexec = &pwexecs[pwctx->exec_index]; + filter = pwexec->filter; + } value->len = filter->name->len; value->data = filter->name->data; diff --git a/t/03-proxy_wasm/hfuncs/117-proxy_properties_get.t b/t/03-proxy_wasm/hfuncs/117-proxy_properties_get.t index d6d4da1d8..95a8aa484 100644 --- a/t/03-proxy_wasm/hfuncs/117-proxy_properties_get.t +++ b/t/03-proxy_wasm/hfuncs/117-proxy_properties_get.t @@ -695,7 +695,49 @@ qr/request\.is_subrequest: true at RequestHeaders/ -=== TEST 16: proxy_wasm - get_property() - unknown property on: request_headers +=== TEST 16: proxy_wasm - get_property() plugin_name on: tick +--- wasm_modules: hostcalls +--- load_nginx_modules: ngx_http_echo_module +--- config + location /t { + proxy_wasm hostcalls 'tick_period=200 \ + on_tick=log_property \ + name=plugin_name'; + echo_sleep 0.5; + echo ok; + } +--- response_body +ok +--- error_log +plugin_name: hostcalls +--- no_error_log +[error] +[crit] + + + +=== TEST 17: proxy_wasm - get_property() plugin_root_id on: tick +--- wasm_modules: hostcalls +--- load_nginx_modules: ngx_http_echo_module +--- config + location /t { + proxy_wasm hostcalls 'tick_period=200 \ + on_tick=log_property \ + name=plugin_root_id'; + echo_sleep 0.5; + echo ok; + } +--- response_body +ok +--- error_log +plugin_root_id: 0 +--- no_error_log +[error] +[crit] + + + +=== TEST 18: proxy_wasm - get_property() - unknown property on: request_headers --- wasm_modules: hostcalls --- load_nginx_modules: ngx_http_echo_module --- config @@ -714,7 +756,7 @@ qr/\[info\] .*? property not found: nonexistent_property,/ -=== TEST 17: proxy_wasm - get_property() request.* - not available on: tick (isolation: global) +=== TEST 19: proxy_wasm - get_property() request.* - not available on: tick (isolation: global) --- skip_hup --- wasm_modules: hostcalls --- load_nginx_modules: ngx_http_echo_module @@ -737,7 +779,7 @@ qr/\[info\] .*? property not found: nonexistent_property,/ -=== TEST 18: proxy_wasm - get_property() response.* - not available on: tick (isolation: global) +=== TEST 20: proxy_wasm - get_property() response.* - not available on: tick (isolation: global) --- skip_hup --- wasm_modules: hostcalls --- load_nginx_modules: ngx_http_echo_module @@ -760,7 +802,7 @@ qr/\[info\] .*? property not found: nonexistent_property,/ -=== TEST 19: proxy_wasm - get_property() upstream.* - not available on: tick (isolation: global) +=== TEST 21: proxy_wasm - get_property() upstream.* - not available on: tick (isolation: global) --- skip_hup --- wasm_modules: hostcalls --- load_nginx_modules: ngx_http_echo_module @@ -783,7 +825,7 @@ qr/\[info\] .*? property not found: nonexistent_property,/ -=== TEST 20: proxy_wasm - get_property() upstream.* - not available on: configure (isolation: global) +=== TEST 22: proxy_wasm - get_property() upstream.* - not available on: configure (isolation: global) --- skip_hup --- wasm_modules: hostcalls --- load_nginx_modules: ngx_http_echo_module From 004ae21032297f241c635b79d6f9c1399bcea228 Mon Sep 17 00:00:00 2001 From: Thibault Charbonnier Date: Tue, 21 Jan 2025 12:57:32 -0800 Subject: [PATCH 35/60] chore(deps) cargo update --- lib/Cargo.lock | 358 +++++++++++++++++++++++++++++++++++++++-------- t/lib/Cargo.lock | 70 ++++----- 2 files changed, 334 insertions(+), 94 deletions(-) diff --git a/lib/Cargo.lock b/lib/Cargo.lock index 3833b5de3..b2b7fc576 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "aho-corasick" @@ -13,28 +13,39 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "cc" -version = "1.1.21" +version = "1.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0" +checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229" dependencies = [ "shlex", ] [[package]] name = "cmake" -version = "0.1.51" +version = "0.1.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb1e43aa7fd152b1f968787f7dbcdeb306d1867ff373c69955211876c053f91a" +checksum = "c682c223677e0e5b6b7f63a64b9351844c3f1b1678a68b7ee617e30fb082620e" dependencies = [ "cc", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -56,14 +67,143 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "idna" -version = "0.5.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", ] [[package]] @@ -78,9 +218,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "lazy_static" @@ -90,9 +230,15 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.158" +version = "0.2.169" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" + +[[package]] +name = "litemap" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" [[package]] name = "memchr" @@ -145,27 +291,27 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] [[package]] name = "regex" -version = "1.10.6" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -175,9 +321,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -186,9 +332,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rustc-demangle" @@ -204,18 +350,18 @@ checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "serde" -version = "1.0.210" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", @@ -224,9 +370,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b" dependencies = [ "itoa", "memchr", @@ -240,11 +386,23 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "syn" -version = "2.0.77" +version = "2.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" dependencies = [ "proc-macro2", "quote", @@ -252,19 +410,25 @@ dependencies = [ ] [[package]] -name = "tinyvec" -version = "1.8.0" +name = "synstructure" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ - "tinyvec_macros", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "tinyvec_macros" -version = "0.1.1" +name = "tinystr" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] [[package]] name = "unescape" @@ -272,38 +436,35 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccb97dac3243214f8d8507998906ca3e2e0b900bf9bf4870477f125b82e68f6e" -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - [[package]] name = "unicode-ident" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" - -[[package]] -name = "unicode-normalization" -version = "0.1.24" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" -dependencies = [ - "tinyvec", -] +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "url" -version = "2.5.2" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna", "percent-encoding", ] +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "wabt" version = "0.10.0" @@ -336,3 +497,82 @@ dependencies = [ "indexmap", "url", ] + +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerofrom" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/t/lib/Cargo.lock b/t/lib/Cargo.lock index 4e418ff3c..1762eb67a 100644 --- a/t/lib/Cargo.lock +++ b/t/lib/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.24.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] @@ -42,9 +42,9 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.18" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "arrayref" @@ -86,9 +86,9 @@ dependencies = [ [[package]] name = "blake3" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" +checksum = "b8ee0c1824c4dea5b5f81736aff91bae041d2c07ee1192bec91054e10e3e601e" dependencies = [ "arrayref", "arrayvec", @@ -99,15 +99,15 @@ dependencies = [ [[package]] name = "bytes" -version = "1.7.2" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" [[package]] name = "cc" -version = "1.1.21" +version = "1.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0" +checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229" dependencies = [ "shlex", ] @@ -184,9 +184,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.31.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "hashbrown" @@ -226,9 +226,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.12" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" dependencies = [ "bytes", "fnv", @@ -245,21 +245,21 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "libc" -version = "0.2.158" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "log" -version = "0.4.22" +version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" [[package]] name = "memchr" @@ -269,9 +269,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "miniz_oxide" -version = "0.8.0" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" dependencies = [ "adler2", ] @@ -296,9 +296,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.4" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] @@ -322,15 +322,15 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] @@ -357,9 +357,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -409,9 +409,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.77" +version = "2.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" dependencies = [ "proc-macro2", "quote", @@ -420,9 +420,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "urlencoding" @@ -539,5 +539,5 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] From 61b821495c4226302cf1f79fdc7ab3021e2d9e5f Mon Sep 17 00:00:00 2001 From: Thibault Charbonnier Date: Tue, 21 Jan 2025 13:44:56 -0800 Subject: [PATCH 36/60] chore(release) disable releases for EOL platforms - Disable Centos7 - Disable Ubuntu 18.04 - Temporarily disable ARM releases until V8 ARM build --- .github/workflows/release.yml | 220 +++++++++++++++++----------------- 1 file changed, 111 insertions(+), 109 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d38e58f0f..e6d49e2a7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -122,19 +122,20 @@ jobs: strategy: matrix: include: - - name: "Ubuntu 18.04 build image" - file: "./assets/release/Dockerfiles/Dockerfile.amd64.ubuntu-18.04" - tags: "ghcr.io/kong/wasmx-build-ubuntu:18.04" + #- name: "Ubuntu 18.04 build image" + # file: "./assets/release/Dockerfiles/Dockerfile.amd64.ubuntu-18.04" + # tags: "ghcr.io/kong/wasmx-build-ubuntu:18.04" - name: "Ubuntu 20.04 build image" file: "./assets/release/Dockerfiles/Dockerfile.ubuntu-20.04" tags: "ghcr.io/kong/wasmx-build-ubuntu:20.04" - name: "Ubuntu 22.04 build image" file: "./assets/release/Dockerfiles/Dockerfile.ubuntu-22.04" tags: "ghcr.io/kong/wasmx-build-ubuntu:22.04" - platforms: "linux/arm64,linux/amd64" - - name: "Centos 7 build image" - file: "./assets/release/Dockerfiles/Dockerfile.amd64.centos7" - tags: "ghcr.io/kong/wasmx-build-centos:7" + #platforms: "linux/arm64,linux/amd64" + platforms: "linux/amd64" + #- name: "Centos 7 build image" + # file: "./assets/release/Dockerfiles/Dockerfile.amd64.centos7" + # tags: "ghcr.io/kong/wasmx-build-centos:7" - name: "Centos 8 build image" file: "./assets/release/Dockerfiles/Dockerfile.amd64.centos8" tags: "ghcr.io/kong/wasmx-build-centos:8" @@ -163,37 +164,37 @@ jobs: cache-from: type=gha cache-to: type=gha,mode=max - binary-ubuntu-bionic: - name: "Build Ubuntu 18.04 (bionic) binary" - needs: [setup, build-images] - runs-on: ubuntu-latest - timeout-minutes: 120 - env: - WASMTIME_VER: ${{ needs.setup.outputs.wasmtime_ver }} - WASMER_VER: ${{ needs.setup.outputs.wasmer_ver }} - V8_VER: ${{ needs.setup.outputs.v8_ver }} - container: - image: ghcr.io/kong/wasmx-build-ubuntu:18.04 - credentials: - username: ${{ github.repository_owner }} - password: ${{ secrets.TOKEN_GITHUB }} - steps: - - uses: actions/checkout@v3 - - name: Build binary - run: ./util/release.sh ${{ needs.setup.outputs.release_name }} --bin - env: - GITHUB_OAUTH_TOKEN: ${{ secrets.GH_BOT_TOKEN }} - - name: Upload binary - uses: actions/upload-artifact@v3 - with: - name: release-artifacts-${{ github.job }} - path: dist - retention-days: ${{ env.RETENTION_DAYS }} - - uses: actions/upload-artifact@v3 - if: failure() - with: - name: ${{ github.workflow }}-${{ github.job }}-sha-${{ github.sha }}-run-${{ github.run_number }} - path: work/dist/build/* + #binary-ubuntu-bionic: + # name: "Build Ubuntu 18.04 (bionic) binary" + # needs: [setup, build-images] + # runs-on: ubuntu-latest + # timeout-minutes: 120 + # env: + # WASMTIME_VER: ${{ needs.setup.outputs.wasmtime_ver }} + # WASMER_VER: ${{ needs.setup.outputs.wasmer_ver }} + # V8_VER: ${{ needs.setup.outputs.v8_ver }} + # container: + # image: ghcr.io/kong/wasmx-build-ubuntu:18.04 + # credentials: + # username: ${{ github.repository_owner }} + # password: ${{ secrets.TOKEN_GITHUB }} + # steps: + # - uses: actions/checkout@v3 + # - name: Build binary + # run: ./util/release.sh ${{ needs.setup.outputs.release_name }} --bin + # env: + # GITHUB_OAUTH_TOKEN: ${{ secrets.GH_BOT_TOKEN }} + # - name: Upload binary + # uses: actions/upload-artifact@v3 + # with: + # name: release-artifacts-${{ github.job }} + # path: dist + # retention-days: ${{ env.RETENTION_DAYS }} + # - uses: actions/upload-artifact@v3 + # if: failure() + # with: + # name: ${{ github.workflow }}-${{ github.job }}-sha-${{ github.sha }}-run-${{ github.run_number }} + # path: work/dist/build/* binary-ubuntu-focal: name: "Build Ubuntu 20.04 (focal) binary" @@ -259,77 +260,77 @@ jobs: name: ${{ github.workflow }}-${{ github.job }}-sha-${{ github.sha }}-run-${{ github.run_number }} path: work/dist/build/* - binary-ubuntu-jammy-arm: - name: "Build ARM Ubuntu 22.04 (jammy) binary" - needs: [setup, build-images] - runs-on: ubuntu-latest - timeout-minutes: 150 - steps: - - uses: actions/checkout@v3 - - name: Setup QEMU - uses: docker/setup-qemu-action@53851d14592bedcffcf25ea515637cff71ef929a # v3 - - name: Login to GitHub Container Registry - uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3 - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.TOKEN_GITHUB }} - - run: | - docker run \ - --platform=linux/arm64 \ - --volume $PWD:/wasmx \ - --volume $GITHUB_ENV:$GITHUB_ENV \ - -e CI \ - -e GITHUB_ENV \ - --env CARGO_NET_GIT_FETCH_WITH_CLI=true \ - --env WASMTIME_VER='${{ needs.setup.outputs.wasmtime_ver }}' \ - --env WASMER_VER='${{ needs.setup.outputs.wasmer_ver }}' \ - --env V8_VER='${{ needs.setup.outputs.v8_ver }}' \ - ghcr.io/kong/wasmx-build-ubuntu:22.04 \ - /wasmx/util/release.sh ${{ needs.setup.outputs.release_name }} --bin - - name: Upload binary - uses: actions/upload-artifact@v4 - with: - name: release-artifacts-${{ github.job }} - path: dist - retention-days: ${{ env.RETENTION_DAYS }} - - uses: actions/upload-artifact@v4 - if: failure() - with: - name: ${{ github.workflow }}-${{ github.job }}-sha-${{ github.sha }}-run-${{ github.run_number }} - path: work/dist/build/* + #binary-ubuntu-jammy-arm: + # name: "Build ARM Ubuntu 22.04 (jammy) binary" + # needs: [setup, build-images] + # runs-on: ubuntu-latest + # timeout-minutes: 150 + # steps: + # - uses: actions/checkout@v3 + # - name: Setup QEMU + # uses: docker/setup-qemu-action@53851d14592bedcffcf25ea515637cff71ef929a # v3 + # - name: Login to GitHub Container Registry + # uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3 + # with: + # registry: ghcr.io + # username: ${{ github.repository_owner }} + # password: ${{ secrets.TOKEN_GITHUB }} + # - run: | + # docker run \ + # --platform=linux/arm64 \ + # --volume $PWD:/wasmx \ + # --volume $GITHUB_ENV:$GITHUB_ENV \ + # -e CI \ + # -e GITHUB_ENV \ + # --env CARGO_NET_GIT_FETCH_WITH_CLI=true \ + # --env WASMTIME_VER='${{ needs.setup.outputs.wasmtime_ver }}' \ + # --env WASMER_VER='${{ needs.setup.outputs.wasmer_ver }}' \ + # --env V8_VER='${{ needs.setup.outputs.v8_ver }}' \ + # ghcr.io/kong/wasmx-build-ubuntu:22.04 \ + # /wasmx/util/release.sh ${{ needs.setup.outputs.release_name }} --bin + # - name: Upload binary + # uses: actions/upload-artifact@v4 + # with: + # name: release-artifacts-${{ github.job }} + # path: dist + # retention-days: ${{ env.RETENTION_DAYS }} + # - uses: actions/upload-artifact@v4 + # if: failure() + # with: + # name: ${{ github.workflow }}-${{ github.job }}-sha-${{ github.sha }}-run-${{ github.run_number }} + # path: work/dist/build/* - binary-centos7: - name: "Build Centos 7 binary" - needs: [setup, build-images] - runs-on: ubuntu-latest - timeout-minutes: 120 - env: - WASMTIME_VER: ${{ needs.setup.outputs.wasmtime_ver }} - WASMER_VER: ${{ needs.setup.outputs.wasmer_ver }} - V8_VER: ${{ needs.setup.outputs.v8_ver }} - container: - image: ghcr.io/kong/wasmx-build-centos:7 - credentials: - username: ${{ github.repository_owner }} - password: ${{ secrets.TOKEN_GITHUB }} - steps: - - uses: actions/checkout@v3 - - name: Build binary - run: ./util/release.sh ${{ needs.setup.outputs.release_name }} --bin - env: - GITHUB_OAUTH_TOKEN: ${{ secrets.GH_BOT_TOKEN }} - - name: Upload binary - uses: actions/upload-artifact@v3 - with: - name: release-artifacts-${{ github.job }} - path: dist - retention-days: ${{ env.RETENTION_DAYS }} - - uses: actions/upload-artifact@v3 - if: failure() - with: - name: ${{ github.workflow }}-${{ github.job }}-sha-${{ github.sha }}-run-${{ github.run_number }} - path: work/dist/build/* + #binary-centos7: + # name: "Build Centos 7 binary" + # needs: [setup, build-images] + # runs-on: ubuntu-latest + # timeout-minutes: 120 + # env: + # WASMTIME_VER: ${{ needs.setup.outputs.wasmtime_ver }} + # WASMER_VER: ${{ needs.setup.outputs.wasmer_ver }} + # V8_VER: ${{ needs.setup.outputs.v8_ver }} + # container: + # image: ghcr.io/kong/wasmx-build-centos:7 + # credentials: + # username: ${{ github.repository_owner }} + # password: ${{ secrets.TOKEN_GITHUB }} + # steps: + # - uses: actions/checkout@v3 + # - name: Build binary + # run: ./util/release.sh ${{ needs.setup.outputs.release_name }} --bin + # env: + # GITHUB_OAUTH_TOKEN: ${{ secrets.GH_BOT_TOKEN }} + # - name: Upload binary + # uses: actions/upload-artifact@v3 + # with: + # name: release-artifacts-${{ github.job }} + # path: dist + # retention-days: ${{ env.RETENTION_DAYS }} + # - uses: actions/upload-artifact@v3 + # if: failure() + # with: + # name: ${{ github.workflow }}-${{ github.job }}-sha-${{ github.sha }}-run-${{ github.run_number }} + # path: work/dist/build/* binary-centos8: name: "Build Centos 8 binary" @@ -431,7 +432,8 @@ jobs: upload-artifacts: name: "Upload release artifacts" - needs: [setup, source-release, binary-ubuntu-bionic, binary-ubuntu-focal, binary-ubuntu-jammy, binary-ubuntu-jammy-arm, binary-centos7, binary-centos8, binary-arch, binary-macos] + #needs: [setup, source-release, binary-ubuntu-bionic, binary-ubuntu-focal, binary-ubuntu-jammy, binary-ubuntu-jammy-arm, binary-centos7, binary-centos8, binary-arch, binary-macos] + needs: [setup, source-release, binary-ubuntu-focal, binary-ubuntu-jammy, binary-centos8, binary-arch, binary-macos] runs-on: ubuntu-latest timeout-minutes: ${{ fromJSON(vars.GHA_DEFAULT_TIMEOUT) }} steps: From 7042e29b059ae9831dc2d8cec6043e0da18b3a4a Mon Sep 17 00:00:00 2001 From: Thibault Charbonnier Date: Thu, 23 Jan 2025 10:17:38 -0800 Subject: [PATCH 37/60] chore(release) bump upload/download artifacts GHA to '@v4' As per recent EOL warnings of `@v3`. --- .github/workflows/release.yml | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e6d49e2a7..1cb6da9d2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -185,12 +185,12 @@ jobs: # env: # GITHUB_OAUTH_TOKEN: ${{ secrets.GH_BOT_TOKEN }} # - name: Upload binary - # uses: actions/upload-artifact@v3 + # uses: actions/upload-artifact@v4 # with: # name: release-artifacts-${{ github.job }} # path: dist # retention-days: ${{ env.RETENTION_DAYS }} - # - uses: actions/upload-artifact@v3 + # - uses: actions/upload-artifact@v4 # if: failure() # with: # name: ${{ github.workflow }}-${{ github.job }}-sha-${{ github.sha }}-run-${{ github.run_number }} @@ -321,12 +321,12 @@ jobs: # env: # GITHUB_OAUTH_TOKEN: ${{ secrets.GH_BOT_TOKEN }} # - name: Upload binary - # uses: actions/upload-artifact@v3 + # uses: actions/upload-artifact@v4 # with: # name: release-artifacts-${{ github.job }} # path: dist # retention-days: ${{ env.RETENTION_DAYS }} - # - uses: actions/upload-artifact@v3 + # - uses: actions/upload-artifact@v4 # if: failure() # with: # name: ${{ github.workflow }}-${{ github.job }}-sha-${{ github.sha }}-run-${{ github.run_number }} @@ -391,7 +391,7 @@ jobs: name: release-artifacts-${{ github.job }} path: dist retention-days: ${{ env.RETENTION_DAYS }} - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 if: failure() with: name: ${{ github.workflow }}-${{ github.job }}-sha-${{ github.sha }}-run-${{ github.run_number }} @@ -437,10 +437,8 @@ jobs: runs-on: ubuntu-latest timeout-minutes: ${{ fromJSON(vars.GHA_DEFAULT_TIMEOUT) }} steps: - - name: Retrieve sibling release artifacts (legacy upload-artifact) - uses: actions/download-artifact@v4.1.7 - name: Retrieve sibling release artifacts - uses: actions/download-artifact@v4.1.7 + uses: actions/download-artifact@v4 with: pattern: release-artifacts-* merge-multiple: true From 19a43da6dc0e46b43832ef428cf873451d0b544c Mon Sep 17 00:00:00 2001 From: Caio Ramos Casimiro Date: Sun, 17 Nov 2024 14:18:04 +0000 Subject: [PATCH 38/60] refactor(*) extract 'create_fake_rctx' into its own function --- src/http/ngx_http_wasm_util.c | 32 +++++++++++++++++++ src/http/ngx_http_wasm_util.h | 2 ++ .../proxy_wasm/ngx_http_proxy_wasm_dispatch.c | 31 ++++-------------- 3 files changed, 40 insertions(+), 25 deletions(-) diff --git a/src/http/ngx_http_wasm_util.c b/src/http/ngx_http_wasm_util.c index fed8a36da..0623f4f98 100644 --- a/src/http/ngx_http_wasm_util.c +++ b/src/http/ngx_http_wasm_util.c @@ -990,3 +990,35 @@ 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_wasm_req_ctx_t **out) +{ + ngx_connection_t *c; + ngx_http_request_t *r; + + 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 = ngx_http_wasm_create_fake_request(c); + if (r == NULL) { + return NGX_ERROR; + } + + if (ngx_http_wasm_rctx(r, out) != NGX_OK) { + return NGX_ERROR; + } + + ngx_wa_assert(r->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..85c316042 100644 --- a/src/http/ngx_http_wasm_util.h +++ b/src/http/ngx_http_wasm_util.h @@ -30,6 +30,8 @@ ngx_int_t ngx_http_wasm_ops_add_filter(ngx_wasm_ops_plan_t *plan, 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_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..196098d41 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; @@ -208,32 +207,14 @@ 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; - } - - ngx_wa_assert(r->pool == rctxp->pool); - - rctxp->data = pwexec->parent; - - } else { - r = rctx->r; + if (rctx == NULL + && ngx_http_wasm_create_fake_rctx(pwexec, &rctxp) != NGX_OK) + { + goto error; } + r = rctx->r; + /* alloc */ call = ngx_calloc(sizeof(ngx_http_proxy_wasm_dispatch_t), From f5295af9dc8aaa1f48aa3075f7e719a9b0924786 Mon Sep 17 00:00:00 2001 From: Caio Ramos Casimiro Date: Mon, 2 Dec 2024 20:00:15 +0000 Subject: [PATCH 39/60] misc(ngx_wavm) 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 } From fabd5e753b1bb0e1155a5c06cf7a456a75a2330e Mon Sep 17 00:00:00 2001 From: Caio Ramos Casimiro Date: Mon, 25 Nov 2024 12:07:00 +0000 Subject: [PATCH 40/60] 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 6333c996f..1d09eaed7 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) { @@ -897,8 +897,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); @@ -914,8 +914,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, @@ -1148,7 +1148,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; @@ -1266,7 +1266,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) { @@ -1393,11 +1393,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 e3490f838..d3e41269f 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 */ @@ -232,19 +232,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 */ @@ -259,9 +259,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 196098d41..9ba78a69a 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; } @@ -429,7 +429,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 78750cedab048e1f1b1ca76646f41c289968a629 Mon Sep 17 00:00:00 2001 From: Caio Ramos Casimiro Date: Fri, 15 Nov 2024 12:54:20 +0000 Subject: [PATCH 41/60] feat(proxy-wasm) foreign function support Also adds `resolve_lua` foreign function, which allows filter developers to resolve names using the Lua DNS resolver. --- config | 6 +- docs/PROXY_WASM.md | 100 +++++- src/common/proxy_wasm/ngx_proxy_wasm.c | 53 ++- src/common/proxy_wasm/ngx_proxy_wasm.h | 81 +++-- .../proxy_wasm/ngx_proxy_wasm_foreign_call.c | 308 ++++++++++++++++++ .../proxy_wasm/ngx_proxy_wasm_foreign_call.h | 34 ++ src/common/proxy_wasm/ngx_proxy_wasm_host.c | 62 +++- src/common/proxy_wasm/ngx_proxy_wasm_util.c | 5 +- src/http/proxy_wasm/ngx_http_proxy_wasm.c | 32 ++ .../proxy_wasm/ngx_http_proxy_wasm_dispatch.c | 64 ++-- .../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 +++ .../hfuncs/contexts/002-set_tick_period.t | 17 + .../hfuncs/contexts/100-proxy_log.t | 17 + .../107-proxy_add_http_request_header.t | 17 + .../108-proxy_add_http_response_header.t | 17 + .../109-proxy_set_http_request_headers.t | 17 + .../110-proxy_set_http_response_headers.t | 17 + .../111-proxy_set_http_request_header.t | 17 + .../112-proxy_set_http_response_header.t | 17 + .../113-proxy_get_http_request_body.t | 17 + .../114-proxy_set_http_request_body.t | 17 + .../115-proxy_get_http_response_body.t | 17 + .../116-proxy_set_http_response_body.t | 17 + .../hfuncs/contexts/130-proxy_dispatch_http.t | 27 +- .../140-proxy_foreign_function_resolve_lua.t | 185 +++++++++++ .../metrics/001-proxy_define_metric.t | 20 ++ .../metrics/010-proxy_increment_metric.t | 20 ++ .../metrics/020-proxy_record_metric.t | 20 ++ .../contexts/metrics/030-proxy_get_metric.t | 20 ++ .../hfuncs/foreign/001-resolve_lua.t | 209 ++++++++++++ t/lib/Cargo.lock | 36 +- .../context-checks/Cargo.toml | 2 +- .../context-checks/src/hostcalls.rs | 32 ++ .../context-checks/src/lib.rs | 17 + t/lib/proxy-wasm-tests/hostcalls/Cargo.toml | 2 +- .../proxy-wasm-tests/hostcalls/src/filter.rs | 36 +- .../hostcalls/src/foreign_callbacks/mod.rs | 18 + t/lib/proxy-wasm-tests/hostcalls/src/lib.rs | 37 ++- .../hostcalls/src/tests/mod.rs | 24 ++ .../hostcalls/src/types/mod.rs | 5 + .../hostcalls/src/types/test_http.rs | 21 ++ 43 files changed, 1635 insertions(+), 89 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/docs/PROXY_WASM.md b/docs/PROXY_WASM.md index 020aadac4..734685d4a 100644 --- a/docs/PROXY_WASM.md +++ b/docs/PROXY_WASM.md @@ -11,6 +11,7 @@ - [Host Properties] - [Nginx Properties] - [HTTP Dispatches] + - [Foreign Functions] - [Supported Specifications] - [Tested SDKs](#tested-sdks) - [Supported Entrypoints](#supported-entrypoints) @@ -493,6 +494,100 @@ impl Context for ExampleRootContext { [Back to TOC](#table-of-contents) +### Foreign Functions + +Proxy-Wasm filters can invoke so-called "foreign functions" which are +host-specific *host functions* (i.e. only available in one host embedding) that +can extend filters capabilities in that host. + +To call a foreign function, a filter may invoke `call_foreign_function` with the +name of the foreign function and its arguments. + +`call_foreign_function` may return: + +- A vector of bytes containing the foreign function's return value. +- A value representing a failure (e.g. "function not found"). +- Or an empty vector of bytes indicating that the invoked function will return + asynchronously later. + +When the function returns asynchronously, the `on_foreign_function` callback is +invoked upon completion with the foreign function's `id` and the size in bytes +of its returned value. This return value can then be retrieved by calling +`get_buffer` accordingly. + +ngx_wasm_module supports the following foreign functions: + +#### `resolve_lua` + +Resolve an IPv4/IPv6 hostname using the Lua DNS resolver (see +[proxy_wasm_lua_resolver]). + +This function's sole argument is the name to be resolved. + +This function either returns 4 bytes representing an IPv4 address or 16 bytes +representing an IPv6 address. Note that this return value may be immediate or +asynchronous as determined by the initial return value (see example below). + +**Supported Contexts** + +- `on_request_headers` +- `on_request_body` +- `on_tick` +- `on_dispatch_response` +- `on_foreign_function` + +> Notes + +This function requires the directive `proxy_wasm_lua_resolver` to be enabled, +see [proxy_wasm_lua_resolver]. + +Example: + +```rust +enum WasmxForeignFunctions { + ResolveLua = 0, // match the function id assigned to this function by ngx_wasm_module +} + +let hostname = "example.com"; + +match call_foreign_function("resolve_lua", Some(hostname.as_bytes())) { + Ok(ret) => match ret { + Some(bytes) => info!("resolved {} to {:?} without yielding", hostname, bytes), + None => info!("yielded while resolving {}", hostname), + }, + Err(_) => info!("failed calling resolve_lua"), +} + +fn on_foreign_function(&mut self, function_id: u32, args_size: usize) { + let fid: WasmxForeignFunctions = unsafe { ::std::mem::transmute(function_id) }; + let args = get_buffer(BufferType::CallData, 0, args_size).unwrap(); + + match fid { + WasmxForeignFunctions::ResolveLua => { + // this callback originates from a call to `resolve_lua`, retrieve + // the address from args + 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 {} to {:?} after yielding", name, address); + } else { + info!("could not resolve {}", name) + } + }, + _ => {} + } + }, + _ => {} + } +} +``` + +[Back to TOC](#table-of-contents) + ## Supported Specifications This section describes the current state of support for the Proxy-Wasm @@ -576,6 +671,8 @@ SDK ABI `0.2.1`) and their present status in ngx_wasm_module: `on_done` | :heavy_check_mark: | HTTP context done handler. *Shared memory queues* | | `on_queue_ready` | :x: | *NYI* +*Custom extension points* | | +`on_foreign_function` | :heavy_check_mark: | Foreign functions resume handler. "*NYI*" stands for "Not Yet Implemented". @@ -658,7 +755,7 @@ SDK ABI `0.2.1`) and their present status in ngx_wasm_module: `proxy_record_metric` | :heavy_check_mark: | `proxy_increment_metric` | :heavy_check_mark: | *Custom extension points* | | -`proxy_call_foreign_function` | :x: | +`proxy_call_foreign_function` | :heavy_check_mark: | [Back to TOC](#table-of-contents) @@ -878,6 +975,7 @@ Proxy-Wasm SDK. [Host Properties]: #host-properties [Nginx Properties]: #nginx-properties [HTTP Dispatches]: #http-dispatches +[Foreign Functions]: #foreign-functions [Supported Specifications]: #supported-specifications [Supported Properties]: #supported-properties [Examples]: #examples diff --git a/src/common/proxy_wasm/ngx_proxy_wasm.c b/src/common/proxy_wasm/ngx_proxy_wasm.c index 1d09eaed7..fbf0c1b91 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: ngx_wa_assert(pwexec->root_id == NGX_PROXY_WASM_ROOT_CTX_ID); pwctx->rexec = pwexec; @@ -892,13 +896,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); @@ -908,25 +912,38 @@ 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); + ngx_wa_assert(dop->q.next && dop->q.prev); + ngx_queue_remove(&dop->q); - ngx_queue_remove(&call->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(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; + } + } } @@ -1148,7 +1165,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; @@ -1266,7 +1283,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 d3e41269f..f37bb3e02 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 */ @@ -414,8 +441,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..69890ebb2 --- /dev/null +++ b/src/common/proxy_wasm/ngx_proxy_wasm_foreign_call.c @@ -0,0 +1,308 @@ +#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_callback(ngx_proxy_wasm_dispatch_op_t *dop) +{ + ngx_proxy_wasm_step_e step; + ngx_proxy_wasm_exec_t *pwexec; + 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; + + /* set current call for host functions */ + pwexec->foreign_call = call; + + /* save step */ + step = pwexec->parent->step; + + ngx_queue_remove(&dop->q); + + pwexec->parent->phase = ngx_wasm_phase_lookup(&ngx_http_wasm_subsystem, + NGX_WASM_BACKGROUND_PHASE); + + /** + * Potential trap ignored as it is already logged and no futher handling is + * needed. + */ + (void) ngx_proxy_wasm_run_step(pwexec, + NGX_PROXY_WASM_STEP_FOREIGN_CALLBACK); + + + /* reset step */ + pwexec->parent->step = step; + + /* remove current call now that callback was invoked */ + 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_str_t args; + ngx_buf_t *b; + ngx_wasm_socket_tcp_t *sock = rslv_ctx->data; + ngx_wasm_lua_ctx_t *lctx = sock->lctx; + 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 + + ngx_memzero(buf, sizeof(buf)); + p = buf; + + if (rslv_ctx->addr.socklen == sizeof(struct sockaddr_in6)) { + sa_family = AF_INET6; + } + + 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_callback(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; + + pwexec = ngx_proxy_wasm_instance2pwexec(instance); + +#if (!NGX_WASM_LUA) + return ngx_proxy_wasm_result_trap(pwexec, + "cannot resolve, no lua support", + rets, NGX_WAVM_ERROR); + +#else + 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_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 + && ngx_http_wasm_create_fake_rctx(pwexec, &rctx) != NGX_OK) + { + goto error; + } + + 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); + + switch (rc) { + case NGX_OK: + b = call->args_out->buf; + s = *b->start; + + p = ngx_proxy_wasm_alloc(pwexec, s); + if (p == 0) { + 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_wa_assert(rc == 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); +#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..23fc605a2 --- /dev/null +++ b/src/common/proxy_wasm/ngx_proxy_wasm_foreign_call.h @@ -0,0 +1,34 @@ +#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 /* _NGX_PROXY_WASM_FOREIGN_CALLBACK_H_INCLUDED_ */ diff --git a/src/common/proxy_wasm/ngx_proxy_wasm_host.c b/src/common/proxy_wasm/ngx_proxy_wasm_host.c index 3151312d7..55929dda4 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: @@ -1173,6 +1190,7 @@ ngx_proxy_wasm_hfuncs_dispatch_http_call(ngx_wavm_instance_t *instance, 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, @@ -1180,8 +1198,9 @@ ngx_proxy_wasm_hfuncs_dispatch_http_call(ngx_wavm_instance_t *instance, "during " "\"on_request_headers\", " "\"on_request_body\", " + "\"on_tick\", " "\"on_dispatch_response\", " - "\"on_tick\"", + "\"on_foreign_function\"", rets, NGX_WAVM_BAD_USAGE); } @@ -1807,7 +1826,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 +2274,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/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 9ba78a69a..b4f69b52e 100644 --- a/src/http/proxy_wasm/ngx_http_proxy_wasm_dispatch.c +++ b/src/http/proxy_wasm/ngx_http_proxy_wasm_dispatch.c @@ -203,17 +203,22 @@ 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 */ - if (rctx == NULL - && ngx_http_wasm_create_fake_rctx(pwexec, &rctxp) != NGX_OK) - { - goto error; + if (rctx == NULL) { + if (ngx_http_wasm_create_fake_rctx(pwexec, &rctxp) != NGX_OK) { + goto error; + } + + r = rctxp->r; + + } else { + r = rctx->r; } - r = rctx->r; /* alloc */ @@ -416,20 +421,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); @@ -504,7 +517,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; @@ -512,7 +526,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); @@ -753,14 +767,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) { @@ -866,7 +892,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; @@ -891,7 +917,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: @@ -905,9 +931,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); @@ -916,7 +942,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..c308c198c --- /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/002-set_tick_period.t b/t/03-proxy_wasm/hfuncs/contexts/002-set_tick_period.t index 0a96d188a..bae039b73 100644 --- a/t/03-proxy_wasm/hfuncs/contexts/002-set_tick_period.t +++ b/t/03-proxy_wasm/hfuncs/contexts/002-set_tick_period.t @@ -180,3 +180,20 @@ can only set tick_period in root context --- no_error_log [crit] [alert] + + + +=== TEST 10: proxy_wasm contexts - set_tick_period on_foreign_function +--- skip_eval: 4: $::nginxV !~ m/openresty/ +--- wasm_modules: context_checks +--- config + location /t { + proxy_wasm context_checks 'on_foreign_function=set_tick_period'; + return 200; + } +--- ignore_response_body +--- error_log +can only set tick_period in root context +--- no_error_log +[crit] +[alert] diff --git a/t/03-proxy_wasm/hfuncs/contexts/100-proxy_log.t b/t/03-proxy_wasm/hfuncs/contexts/100-proxy_log.t index f37a7c4d0..d844d186f 100644 --- a/t/03-proxy_wasm/hfuncs/contexts/100-proxy_log.t +++ b/t/03-proxy_wasm/hfuncs/contexts/100-proxy_log.t @@ -187,3 +187,20 @@ proxy_log msg --- no_error_log [error] [crit] + + + +=== TEST 10: proxy_wasm contexts - proxy_log on_foreign_function +--- skip_eval: 4: $::nginxV !~ m/openresty/ +--- wasm_modules: context_checks +--- config + location /t { + proxy_wasm context_checks 'on_foreign_function=proxy_log'; + return 200; + } +--- ignore_response_body +--- error_log +proxy_log msg +--- no_error_log +[error] +[crit] diff --git a/t/03-proxy_wasm/hfuncs/contexts/107-proxy_add_http_request_header.t b/t/03-proxy_wasm/hfuncs/contexts/107-proxy_add_http_request_header.t index b4ec060f5..5c3f0ea23 100644 --- a/t/03-proxy_wasm/hfuncs/contexts/107-proxy_add_http_request_header.t +++ b/t/03-proxy_wasm/hfuncs/contexts/107-proxy_add_http_request_header.t @@ -183,3 +183,20 @@ should not be retrievable after on_response_body since buffers are consumed can only set request headers before response is produced --- no_error_log [crit] + + + +=== TEST 10: proxy_wasm contexts - add_http_request_header on_foreign_function +--- skip_eval: 4: $::nginxV !~ m/openresty/ +--- wasm_modules: context_checks +--- config + location /t { + proxy_wasm context_checks 'on_foreign_function=add_request_header|foo=bar'; + return 200; + } +--- ignore_response_body +--- error_log +[error] +can only set request headers before response is produced +--- no_error_log +[crit] diff --git a/t/03-proxy_wasm/hfuncs/contexts/108-proxy_add_http_response_header.t b/t/03-proxy_wasm/hfuncs/contexts/108-proxy_add_http_response_header.t index 75b4114d0..d1ee8c6d2 100644 --- a/t/03-proxy_wasm/hfuncs/contexts/108-proxy_add_http_response_header.t +++ b/t/03-proxy_wasm/hfuncs/contexts/108-proxy_add_http_response_header.t @@ -267,3 +267,20 @@ add_response_header status: 0 --- no_error_log [error] [crit] + + + +=== TEST 14: proxy_wasm contexts - add_http_response_header on_foreign_function +--- skip_eval: 4: $::nginxV !~ m/openresty/ +--- wasm_modules: context_checks +--- config + location /t { + proxy_wasm context_checks 'on_foreign_function=add_response_header|:foo=bar'; + return 200; + } +--- ignore_response_body +--- error_log +[error] +can only set response headers before "on_response_body" +--- no_error_log +[crit] diff --git a/t/03-proxy_wasm/hfuncs/contexts/109-proxy_set_http_request_headers.t b/t/03-proxy_wasm/hfuncs/contexts/109-proxy_set_http_request_headers.t index 78f588162..4708bc5b8 100644 --- a/t/03-proxy_wasm/hfuncs/contexts/109-proxy_set_http_request_headers.t +++ b/t/03-proxy_wasm/hfuncs/contexts/109-proxy_set_http_request_headers.t @@ -183,3 +183,20 @@ should not be retrievable after on_response_body since buffers are consumed can only set request headers before response is produced --- no_error_log [crit] + + + +=== TEST 10: proxy_wasm contexts - set_http_request_headers on_foreign_function +--- skip_eval: 4: $::nginxV !~ m/openresty/ +--- wasm_modules: context_checks +--- config + location /t { + proxy_wasm context_checks 'on_foreign_function=set_request_headers|foo=bar'; + return 200; + } +--- ignore_response_body +--- error_log +[error] +can only set request headers before response is produced +--- no_error_log +[crit] diff --git a/t/03-proxy_wasm/hfuncs/contexts/110-proxy_set_http_response_headers.t b/t/03-proxy_wasm/hfuncs/contexts/110-proxy_set_http_response_headers.t index a580d470e..0e3e184a8 100644 --- a/t/03-proxy_wasm/hfuncs/contexts/110-proxy_set_http_response_headers.t +++ b/t/03-proxy_wasm/hfuncs/contexts/110-proxy_set_http_response_headers.t @@ -267,3 +267,20 @@ set_response_headers status: 0 --- no_error_log [error] [crit] + + + +=== TEST 14: proxy_wasm contexts - set_http_response_headers on_foreign_function +--- skip_eval: 4: $::nginxV !~ m/openresty/ +--- wasm_modules: context_checks +--- config + location /t { + proxy_wasm context_checks 'on_foreign_function=set_response_headers|:foo=bar'; + return 200; + } +--- ignore_response_body +--- error_log +[error] +can only set response headers before "on_response_body" +--- no_error_log +[crit] diff --git a/t/03-proxy_wasm/hfuncs/contexts/111-proxy_set_http_request_header.t b/t/03-proxy_wasm/hfuncs/contexts/111-proxy_set_http_request_header.t index 5812628df..4d36fb34a 100644 --- a/t/03-proxy_wasm/hfuncs/contexts/111-proxy_set_http_request_header.t +++ b/t/03-proxy_wasm/hfuncs/contexts/111-proxy_set_http_request_header.t @@ -184,3 +184,20 @@ should not be retrievable after on_response_body since buffers are consumed can only set request headers before response is produced --- no_error_log [crit] + + + +=== TEST 10: proxy_wasm contexts - set_http_request_header on_foreign_function +--- skip_eval: 4: $::nginxV !~ m/openresty/ +--- wasm_modules: context_checks +--- config + location /t { + proxy_wasm context_checks 'on_foreign_function=set_request_header|:foo=bar'; + return 200; + } +--- ignore_response_body +--- error_log +[error] +can only set request headers before response is produced +--- no_error_log +[crit] diff --git a/t/03-proxy_wasm/hfuncs/contexts/112-proxy_set_http_response_header.t b/t/03-proxy_wasm/hfuncs/contexts/112-proxy_set_http_response_header.t index 6d33be217..0dea537a2 100644 --- a/t/03-proxy_wasm/hfuncs/contexts/112-proxy_set_http_response_header.t +++ b/t/03-proxy_wasm/hfuncs/contexts/112-proxy_set_http_response_header.t @@ -267,3 +267,20 @@ set_response_header status: 0 --- no_error_log [error] [crit] + + + +=== TEST 14: proxy_wasm contexts - set_http_response_header on_foreign_function +--- skip_eval: 4: $::nginxV !~ m/openresty/ +--- wasm_modules: context_checks +--- config + location /t { + proxy_wasm context_checks 'on_foreign_function=set_response_header|:foo=bar'; + return 200; + } +--- ignore_response_body +--- error_log +[error] +can only set response headers before "on_response_body" +--- no_error_log +[crit] diff --git a/t/03-proxy_wasm/hfuncs/contexts/113-proxy_get_http_request_body.t b/t/03-proxy_wasm/hfuncs/contexts/113-proxy_get_http_request_body.t index d6ffc78cf..b59d5177d 100644 --- a/t/03-proxy_wasm/hfuncs/contexts/113-proxy_get_http_request_body.t +++ b/t/03-proxy_wasm/hfuncs/contexts/113-proxy_get_http_request_body.t @@ -186,3 +186,20 @@ get_request_body_buffer status: 0 --- no_error_log [error] [crit] + + + +=== TEST 10: proxy_wasm contexts - get_http_request_body on_foreign_function +--- skip_eval: 4: $::nginxV !~ m/openresty/ +--- wasm_modules: context_checks +--- config + location /t { + proxy_wasm context_checks 'on_foreign_function=get_request_body_buffer'; + return 200; + } +--- ignore_response_body +--- error_log +[error] +can only get request body during "on_request_body" +--- no_error_log +[crit] diff --git a/t/03-proxy_wasm/hfuncs/contexts/114-proxy_set_http_request_body.t b/t/03-proxy_wasm/hfuncs/contexts/114-proxy_set_http_request_body.t index d95bea022..3adf9435c 100644 --- a/t/03-proxy_wasm/hfuncs/contexts/114-proxy_set_http_request_body.t +++ b/t/03-proxy_wasm/hfuncs/contexts/114-proxy_set_http_request_body.t @@ -182,3 +182,20 @@ can only set request body during "on_request_body" can only set request body during "on_request_body" --- no_error_log [crit] + + + +=== TEST 10: proxy_wasm contexts - set_http_request_body on_foreign_function +--- skip_eval: 4: $::nginxV !~ m/openresty/ +--- wasm_modules: context_checks +--- config + location /t { + proxy_wasm context_checks 'on_foreign_function=set_request_body_buffer'; + return 200; + } +--- ignore_response_body +--- error_log +[error] +can only set request body during "on_request_body" +--- no_error_log +[crit] diff --git a/t/03-proxy_wasm/hfuncs/contexts/115-proxy_get_http_response_body.t b/t/03-proxy_wasm/hfuncs/contexts/115-proxy_get_http_response_body.t index d2128c5aa..a3eafc122 100644 --- a/t/03-proxy_wasm/hfuncs/contexts/115-proxy_get_http_response_body.t +++ b/t/03-proxy_wasm/hfuncs/contexts/115-proxy_get_http_response_body.t @@ -185,3 +185,20 @@ get_response_body_buffer status: 0 can only get response body during "on_response_body" --- no_error_log [crit] + + + +=== TEST 10: proxy_wasm contexts - set_http_response_body on_foreign_function +--- skip_eval: 4: $::nginxV !~ m/openresty/ +--- wasm_modules: context_checks +--- config + location /t { + proxy_wasm context_checks 'on_foreign_function=get_response_body_buffer'; + return 200; + } +--- ignore_response_body +--- error_log +[error] +can only get response body during "on_response_body" +--- no_error_log +[crit] diff --git a/t/03-proxy_wasm/hfuncs/contexts/116-proxy_set_http_response_body.t b/t/03-proxy_wasm/hfuncs/contexts/116-proxy_set_http_response_body.t index ee26e4757..ac08f9aeb 100644 --- a/t/03-proxy_wasm/hfuncs/contexts/116-proxy_set_http_response_body.t +++ b/t/03-proxy_wasm/hfuncs/contexts/116-proxy_set_http_response_body.t @@ -185,3 +185,20 @@ should not be retrievable after on_response_body since buffers are consumed can only set response body during "on_response_body" --- no_error_log [crit] + + + +=== TEST 10: proxy_wasm contexts - set_http_response_body on_foreign_function +--- skip_eval: 4: $::nginxV !~ m/openresty/ +--- wasm_modules: context_checks +--- config + location /t { + proxy_wasm context_checks 'on_foreign_function=set_response_body_buffer'; + return 200; + } +--- ignore_response_body +--- error_log +[error] +can only set response body during "on_response_body" +--- no_error_log +[crit] diff --git a/t/03-proxy_wasm/hfuncs/contexts/130-proxy_dispatch_http.t b/t/03-proxy_wasm/hfuncs/contexts/130-proxy_dispatch_http.t index 98677d5df..d2092ce1e 100644 --- a/t/03-proxy_wasm/hfuncs/contexts/130-proxy_dispatch_http.t +++ b/t/03-proxy_wasm/hfuncs/contexts/130-proxy_dispatch_http.t @@ -25,7 +25,7 @@ __DATA__ --- must_die: 0 --- error_log [error] -can only send HTTP dispatch during "on_request_headers", "on_request_body", "on_dispatch_response", "on_tick" +can only send HTTP dispatch during "on_request_headers", "on_request_body", "on_tick", "on_dispatch_response", "on_foreign_function" --- no_error_log [crit] @@ -41,7 +41,7 @@ can only send HTTP dispatch during "on_request_headers", "on_request_body", "on_ --- must_die: 0 --- error_log [error] -can only send HTTP dispatch during "on_request_headers", "on_request_body", "on_dispatch_response", "on_tick" +can only send HTTP dispatch during "on_request_headers", "on_request_body", "on_tick", "on_dispatch_response", "on_foreign_function" --- no_error_log [crit] @@ -132,7 +132,7 @@ dispatch failed: no :method --- ignore_response_body --- error_log [error] -can only send HTTP dispatch during "on_request_headers", "on_request_body", "on_dispatch_response", "on_tick" +can only send HTTP dispatch during "on_request_headers", "on_request_body", "on_tick", "on_dispatch_response", "on_foreign_function" --- no_error_log [crit] @@ -149,7 +149,7 @@ can only send HTTP dispatch during "on_request_headers", "on_request_body", "on_ --- ignore_response_body --- error_log [error] -can only send HTTP dispatch during "on_request_headers", "on_request_body", "on_dispatch_response", "on_tick" +can only send HTTP dispatch during "on_request_headers", "on_request_body", "on_tick", "on_dispatch_response", "on_foreign_function" --- no_error_log [crit] @@ -164,6 +164,23 @@ can only send HTTP dispatch during "on_request_headers", "on_request_body", "on_ } --- error_log [error] -can only send HTTP dispatch during "on_request_headers", "on_request_body", "on_dispatch_response", "on_tick" +can only send HTTP dispatch during "on_request_headers", "on_request_body", "on_tick", "on_dispatch_response", "on_foreign_function" +--- no_error_log +[crit] + + + +=== TEST 10: proxy_wasm contexts - dispatch_http_call on_foreign_function +--- skip_eval: 4: $::nginxV !~ m/openresty/ +--- wasm_modules: context_checks +--- config + location /t { + proxy_wasm context_checks 'on_foreign_function=dispatch_http_call'; + return 200; + } +--- ignore_response_body +--- error_log +[error] +dispatch failed: no :method --- no_error_log [crit] 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..6c021a4f5 --- /dev/null +++ b/t/03-proxy_wasm/hfuncs/contexts/140-proxy_foreign_function_resolve_lua.t @@ -0,0 +1,185 @@ +# 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] + + + +=== TEST 10: proxy_wasm contexts - call_resolve_lua on_foreign_function +--- wasm_modules: context_checks +--- config + location /t { + proxy_wasm context_checks 'on_foreign_function=call_resolve_lua'; + return 200; + } +--- ignore_response_body +--- error_log +[error] +cannot resolve, missing name +--- no_error_log +[crit] diff --git a/t/03-proxy_wasm/hfuncs/contexts/metrics/001-proxy_define_metric.t b/t/03-proxy_wasm/hfuncs/contexts/metrics/001-proxy_define_metric.t index fe69d804c..485bb1222 100644 --- a/t/03-proxy_wasm/hfuncs/contexts/metrics/001-proxy_define_metric.t +++ b/t/03-proxy_wasm/hfuncs/contexts/metrics/001-proxy_define_metric.t @@ -185,3 +185,23 @@ define_metric status: 0 --- no_error_log [error] [crit] + + + +=== TEST 10: proxy_wasm contexts - define_metric on_foreign_function +--- skip_eval: 4: $::nginxV !~ m/openresty/ +--- main_config + wasm { + module context_checks $TEST_NGINX_CRATES_DIR/context_checks.wasm; + } +--- config + location /t { + proxy_wasm context_checks 'on_foreign_function=define_metric'; + return 200; + } +--- ignore_response_body +--- error_log +define_metric status: 0 +--- no_error_log +[error] +[crit] diff --git a/t/03-proxy_wasm/hfuncs/contexts/metrics/010-proxy_increment_metric.t b/t/03-proxy_wasm/hfuncs/contexts/metrics/010-proxy_increment_metric.t index ecd2b3b5b..daf32b468 100644 --- a/t/03-proxy_wasm/hfuncs/contexts/metrics/010-proxy_increment_metric.t +++ b/t/03-proxy_wasm/hfuncs/contexts/metrics/010-proxy_increment_metric.t @@ -183,3 +183,23 @@ increment_metric status: 0 --- no_error_log [error] [crit] + + + +=== TEST 10: proxy_wasm contexts - increment_metric on_foreign_function +--- skip_eval: 4: $::nginxV !~ m/openresty/ +--- main_config + wasm { + module context_checks $TEST_NGINX_CRATES_DIR/context_checks.wasm; + } +--- config + location /t { + proxy_wasm context_checks 'on_foreign_function=increment_metric'; + return 200; + } +--- ignore_response_body +--- error_log +increment_metric status: 0 +--- no_error_log +[error] +[crit] diff --git a/t/03-proxy_wasm/hfuncs/contexts/metrics/020-proxy_record_metric.t b/t/03-proxy_wasm/hfuncs/contexts/metrics/020-proxy_record_metric.t index 3ce178c37..d8505b558 100644 --- a/t/03-proxy_wasm/hfuncs/contexts/metrics/020-proxy_record_metric.t +++ b/t/03-proxy_wasm/hfuncs/contexts/metrics/020-proxy_record_metric.t @@ -183,3 +183,23 @@ record_metric status: 0 --- no_error_log [error] [crit] + + + +=== TEST 10: proxy_wasm contexts - record_metric on_foreign_function +--- skip_eval: 4: $::nginxV !~ m/openresty/ +--- main_config + wasm { + module context_checks $TEST_NGINX_CRATES_DIR/context_checks.wasm; + } +--- config + location /t { + proxy_wasm context_checks 'on_foreign_function=record_metric'; + return 200; + } +--- ignore_response_body +--- error_log +record_metric status: 0 +--- no_error_log +[error] +[crit] diff --git a/t/03-proxy_wasm/hfuncs/contexts/metrics/030-proxy_get_metric.t b/t/03-proxy_wasm/hfuncs/contexts/metrics/030-proxy_get_metric.t index 61e80e4f8..ca6676f0e 100644 --- a/t/03-proxy_wasm/hfuncs/contexts/metrics/030-proxy_get_metric.t +++ b/t/03-proxy_wasm/hfuncs/contexts/metrics/030-proxy_get_metric.t @@ -183,3 +183,23 @@ get_metric status: 0 --- no_error_log [error] [crit] + + + +=== TEST 10: proxy_wasm contexts - get_metric on_foreign_function +--- skip_eval: 4: $::nginxV !~ m/openresty/ +--- main_config + wasm { + module context_checks $TEST_NGINX_CRATES_DIR/context_checks.wasm; + } +--- config + location /t { + proxy_wasm context_checks 'on_foreign_function=get_metric'; + return 200; + } +--- ignore_response_body +--- error_log +get_metric status: 0 +--- no_error_log +[error] +[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..661c04677 --- /dev/null +++ b/t/03-proxy_wasm/hfuncs/foreign/001-resolve_lua.t @@ -0,0 +1,209 @@ +# 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/\[error\] .*? lua user thread aborted: .*? wasm lua failed resolving "foo": dns client error: 101 empty record received.*?/, + qr/\[info\] .*? could not resolve foo/ +] +--- no_error_log +[crit] +[emerg] + + + +=== TEST 2: proxy_wasm - resolve_lua, bad name +--- wasm_modules: hostcalls +--- config + location /t { + proxy_wasm_lua_resolver on; + proxy_wasm hostcalls 'test=/t/resolve_lua \ + name='; + return 200; + } +--- error_code: 500 +--- error_log eval +qr/host trap \(bad usage\): cannot resolve, missing name/, +--- no_error_log +[crit] +[emerg] +[alert] + + + +=== TEST 3: 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 4: 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 5: 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 6: 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,example.com'; + return 200; + } +--- error_log eval +[ + qr/resolved \(yielding\) httpbin\.org to \[\d+, \d+, \d+, \d+\]/, + qr/resolved \(yielding\) example\.com to \[\d+, \d+, \d+, \d+\]/ +] +--- no_error_log +[error] +[crit] + + + +=== TEST 7: 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 8: 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 9: 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,example.com'; + return 200; + } + + location /dispatch { + return 200; + } +--- error_log eval +[ + qr/resolved \(yielding\) httpbin\.org to \[\d+, \d+, \d+, \d+\]/, + qr/resolved \(yielding\) example\.com to \[\d+, \d+, \d+, \d+\]/ +] +--- no_error_log +[error] +[crit] + + + +=== TEST 10: 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 1762eb67a..6d61c7afa 100644 --- a/t/lib/Cargo.lock +++ b/t/lib/Cargo.lock @@ -129,7 +129,7 @@ name = "context-checks" version = "0.1.0" dependencies = [ "log", - "proxy-wasm 0.2.2", + "proxy-wasm 0.2.3-dev", ] [[package]] @@ -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/kong/proxy-wasm-rust-sdk.git?branch=main#e58dd9395904f611c8a71d75517a882c92e65979" +dependencies = [ + "hashbrown 0.15.1", + "log", +] + [[package]] name = "quote" version = "1.0.38" diff --git a/t/lib/proxy-wasm-tests/context-checks/Cargo.toml b/t/lib/proxy-wasm-tests/context-checks/Cargo.toml index 65f7feee9..6e090141a 100644 --- a/t/lib/proxy-wasm-tests/context-checks/Cargo.toml +++ b/t/lib/proxy-wasm-tests/context-checks/Cargo.toml @@ -8,5 +8,5 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -proxy-wasm = "0.2" +proxy-wasm = { git = "https://github.com/kong/proxy-wasm-rust-sdk.git", branch = "main" } log = "0.4" 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..0e42226a8 100644 --- a/t/lib/proxy-wasm-tests/context-checks/src/hostcalls.rs +++ b/t/lib/proxy-wasm-tests/context-checks/src/hostcalls.rs @@ -455,3 +455,35 @@ 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, name: &str) { + let f_name = "resolve_lua"; + + let mut ret_data: *mut u8 = null_mut(); + let mut ret_size: usize = 0; + + unsafe { + let status = proxy_call_foreign_function( + f_name.as_ptr(), + f_name.len(), + name.as_ptr(), + name.len(), + &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..b6b31b74b 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, arg), "set_tick_period" => set_tick_period(self), "add_request_header" => add_request_header(self, arg), "add_response_header" => add_response_header(self, arg), @@ -87,6 +88,11 @@ impl HttpContext for TestHttp { }, } + return Action::Pause; + } else if self.tester.get_config("on_foreign_function").is_some() { + self.tester + .check_host_function("call_resolve_lua|httpbin.org"); + return Action::Pause; } @@ -147,6 +153,17 @@ impl Context for TestHttp { self.tester.check_host_function(name); } } + + fn on_foreign_function(&mut self, function_id: u32, args_size: usize) { + info!( + "on_foreign_function (id: {}, args_size: {})", + function_id, args_size + ); + + if let Some(name) = self.tester.get_config("on_foreign_function") { + self.tester.check_host_function(name); + } + } } impl RootContext for TestRoot { diff --git a/t/lib/proxy-wasm-tests/hostcalls/Cargo.toml b/t/lib/proxy-wasm-tests/hostcalls/Cargo.toml index a18062d83..85bc09637 100644 --- a/t/lib/proxy-wasm-tests/hostcalls/Cargo.toml +++ b/t/lib/proxy-wasm-tests/hostcalls/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -proxy-wasm = "0.2" +proxy-wasm = { git = "https://github.com/kong/proxy-wasm-rust-sdk.git", branch = "main" } log = "0.4" http = "1.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 4b39adaf0..64ee771ad 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 crate::{foreign_callbacks::*, test_http::*, tests::*, types::*}; use http::StatusCode; use log::*; -use proxy_wasm::{traits::*, types::*}; +use proxy_wasm::{hostcalls::*, traits::*, types::*}; impl Context for TestHttp { fn on_http_call_response( @@ -109,12 +109,44 @@ 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::CallData, 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..687df1efa --- /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 89e39aa63..8767856d2 100644 --- a/t/lib/proxy-wasm-tests/hostcalls/src/lib.rs +++ b/t/lib/proxy-wasm-tests/hostcalls/src/lib.rs @@ -1,12 +1,13 @@ #![allow(clippy::single_match)] mod filter; +mod foreign_callbacks; mod tests; mod types; -use crate::{tests::*, types::test_http::*, types::test_root::*, types::*}; +use crate::{foreign_callbacks::*, tests::*, types::test_http::*, types::test_root::*, types::*}; use log::*; -use proxy_wasm::{traits::*, types::*}; +use proxy_wasm::{hostcalls::*, traits::*, types::*}; use std::{collections::BTreeMap, collections::HashMap, time::Duration}; proxy_wasm::main! {{ @@ -116,6 +117,24 @@ 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(); @@ -203,6 +222,7 @@ impl RootContext for TestRoot { on_phases: phases, metrics: self.metrics.clone(), n_sync_calls: 0, + pending_callbacks: 0, })) } } @@ -228,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::CallData, 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..e89a3cb9d 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,27 @@ 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..4a7b98417 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 ea1ec76ebb1727dba76922b1284070d0eaaa623f Mon Sep 17 00:00:00 2001 From: Thibault Charbonnier Date: Wed, 29 Jan 2025 10:56:12 -0800 Subject: [PATCH 42/60] chore(ci) add valgrind coverage results to coveralls --- .github/workflows/job-unit-tests.yml | 4 +- .github/workflows/job-valgrind-tests.yml | 47 ++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/.github/workflows/job-unit-tests.yml b/.github/workflows/job-unit-tests.yml index e929c869c..370e166e3 100644 --- a/.github/workflows/job-unit-tests.yml +++ b/.github/workflows/job-unit-tests.yml @@ -74,8 +74,6 @@ jobs: name: 'Unit tests' runs-on: ${{ inputs.os }} timeout-minutes: 90 - outputs: - coveralls_name: ${{ steps.lcov.outputs.name }} steps: - name: 'Setup deps - apt-get' if: ${{ contains(inputs.os, 'ubuntu') }} @@ -196,7 +194,7 @@ jobs: with: token: ${{ secrets.CODECOV_TOKEN }} files: './lcov.info' - flags: unit + flags: ${{ steps.lcov.outputs.name }} - run: rm -f t/servroot/html/nginx.sock if: ${{ failure() && !env.ACT }} - name: Artifacts Upload diff --git a/.github/workflows/job-valgrind-tests.yml b/.github/workflows/job-valgrind-tests.yml index 33b78dcd1..fcd7a2803 100644 --- a/.github/workflows/job-valgrind-tests.yml +++ b/.github/workflows/job-valgrind-tests.yml @@ -132,18 +132,57 @@ jobs: exit 1 fi - name: Run lcov + id: lcov if: ${{ !env.ACT && inputs.coverage }} run: | - lcov --gcov-tool gcov-${CC#*-} --capture --directory work/buildroot --output-file lcov.info - lcov --gcov-tool gcov-${CC#*-} --remove lcov.info "*/ngx_wasm_module/src/common/debug/*" --output-file lcov.info - lcov --gcov-tool gcov-${CC#*-} --extract lcov.info "*/ngx_wasm_module/src/*" --output-file lcov.info + case "$CC" in + clang*) + lcov --gcov-tool gcov --ignore-errors source --capture --directory work/buildroot --output-file lcov.info + lcov --ignore-errors unused --gcov-tool gcov --remove lcov.info "*/ngx_wasm_module/src/common/debug/*" --output-file lcov.info + lcov --gcov-tool gcov --extract lcov.info "*/ngx_wasm_module/src/*" --output-file lcov.info + ;; + *) + lcov --gcov-tool gcov-${CC#*-} --ignore-errors source --capture --directory work/buildroot --output-file lcov.info + lcov --ignore-errors unused --gcov-tool gcov-${CC#*-} --remove lcov.info "*/ngx_wasm_module/src/common/debug/*" --output-file lcov.info + lcov --gcov-tool gcov-${CC#*-} --extract lcov.info "*/ngx_wasm_module/src/*" --output-file lcov.info + ;; + esac + + name="valgrind" + if [ -n "${{ inputs.openresty }}" ]; then + name="$name-openresty_${{ inputs.openresty }}" + else + name="$name-ngx_${{ inputs.ngx }}" + fi + name="$name-${{ inputs.runtime }}" + name="$name-${{ inputs.ipc }}" + name="$name-${{ inputs.ssl }}" + name="$name-${{ inputs.debug }}" + name="$name-${{ inputs.hup }}" + if [ "${{ inputs.module_type }}" = dynamic ]; then + name="$name-dynamic" + else + name="$name-static" + fi + if [ -n "${{ inputs.wasm_target }}" ]; then + name="$name-${{ inputs.wasm_target }}" + fi + echo "name=$name" >> $GITHUB_OUTPUT + - name: Coveralls Upload + if: ${{ !env.ACT && inputs.coverage }} + uses: coverallsapp/github-action@cfd0633edbd2411b532b808ba7a8b5e04f76d2c8 # v2 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + flag-name: ${{ steps.lcov.outputs.name }} + path-to-lcov: './lcov.info' + parallel: true - name: Codecov Upload if: ${{ !env.ACT && inputs.coverage }} uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4 with: token: ${{ secrets.CODECOV_TOKEN }} files: './lcov.info' - flags: valgrind + flags: ${{ steps.lcov.outputs.name }} - run: rm -f t/servroot/html/nginx.sock if: ${{ failure() && !env.ACT }} - uses: actions/upload-artifact@v4 From 49a25bc337d9051f3a80757277c5c05cf3b4bebb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Feb 2025 12:01:48 +0000 Subject: [PATCH 43/60] chore(ci) bump codecov/codecov-action from 4.6.0 to 5.3.1 Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 4.6.0 to 5.3.1. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238...13ce06bfc6bbe3ecf90edbbf1bc32fe5978ca1d3) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/job-unit-tests.yml | 2 +- .github/workflows/job-valgrind-tests.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/job-unit-tests.yml b/.github/workflows/job-unit-tests.yml index 370e166e3..ffd4ba8cf 100644 --- a/.github/workflows/job-unit-tests.yml +++ b/.github/workflows/job-unit-tests.yml @@ -190,7 +190,7 @@ jobs: parallel: true - name: Codecov Upload if: ${{ !env.ACT && inputs.coverage }} - uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4 + uses: codecov/codecov-action@13ce06bfc6bbe3ecf90edbbf1bc32fe5978ca1d3 # v4 with: token: ${{ secrets.CODECOV_TOKEN }} files: './lcov.info' diff --git a/.github/workflows/job-valgrind-tests.yml b/.github/workflows/job-valgrind-tests.yml index fcd7a2803..279e45366 100644 --- a/.github/workflows/job-valgrind-tests.yml +++ b/.github/workflows/job-valgrind-tests.yml @@ -178,7 +178,7 @@ jobs: parallel: true - name: Codecov Upload if: ${{ !env.ACT && inputs.coverage }} - uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4 + uses: codecov/codecov-action@13ce06bfc6bbe3ecf90edbbf1bc32fe5978ca1d3 # v4 with: token: ${{ secrets.CODECOV_TOKEN }} files: './lcov.info' From c2b0fb13ff85393ff54c8a98e97c3298f47a3aa0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Feb 2025 12:01:53 +0000 Subject: [PATCH 44/60] chore(ci) bump coverallsapp/github-action from 2.3.4 to 2.3.6 Bumps [coverallsapp/github-action](https://github.com/coverallsapp/github-action) from 2.3.4 to 2.3.6. - [Release notes](https://github.com/coverallsapp/github-action/releases) - [Commits](https://github.com/coverallsapp/github-action/compare/cfd0633edbd2411b532b808ba7a8b5e04f76d2c8...648a8eb78e6d50909eff900e4ec85cab4524a45b) --- updated-dependencies: - dependency-name: coverallsapp/github-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/ci.yml | 2 +- .github/workflows/job-unit-tests.yml | 2 +- .github/workflows/job-valgrind-tests.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 512dabdae..c023b08fa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -170,7 +170,7 @@ jobs: steps: - name: Coveralls Finished if: ${{ !env.ACT }} - uses: coverallsapp/github-action@cfd0633edbd2411b532b808ba7a8b5e04f76d2c8 # v2 + uses: coverallsapp/github-action@648a8eb78e6d50909eff900e4ec85cab4524a45b # v2 with: github-token: ${{ secrets.GITHUB_TOKEN }} parallel-finished: true diff --git a/.github/workflows/job-unit-tests.yml b/.github/workflows/job-unit-tests.yml index ffd4ba8cf..0399f3275 100644 --- a/.github/workflows/job-unit-tests.yml +++ b/.github/workflows/job-unit-tests.yml @@ -182,7 +182,7 @@ jobs: echo "name=$name" >> $GITHUB_OUTPUT - name: Coveralls Upload if: ${{ !env.ACT && inputs.coverage }} - uses: coverallsapp/github-action@cfd0633edbd2411b532b808ba7a8b5e04f76d2c8 # v2 + uses: coverallsapp/github-action@648a8eb78e6d50909eff900e4ec85cab4524a45b # v2 with: github-token: ${{ secrets.GITHUB_TOKEN }} flag-name: ${{ steps.lcov.outputs.name }} diff --git a/.github/workflows/job-valgrind-tests.yml b/.github/workflows/job-valgrind-tests.yml index 279e45366..5cd0f6584 100644 --- a/.github/workflows/job-valgrind-tests.yml +++ b/.github/workflows/job-valgrind-tests.yml @@ -170,7 +170,7 @@ jobs: echo "name=$name" >> $GITHUB_OUTPUT - name: Coveralls Upload if: ${{ !env.ACT && inputs.coverage }} - uses: coverallsapp/github-action@cfd0633edbd2411b532b808ba7a8b5e04f76d2c8 # v2 + uses: coverallsapp/github-action@648a8eb78e6d50909eff900e4ec85cab4524a45b # v2 with: github-token: ${{ secrets.GITHUB_TOKEN }} flag-name: ${{ steps.lcov.outputs.name }} From e952cecf99d79219e1aa2340c09c831d826bbd5f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Feb 2025 12:01:56 +0000 Subject: [PATCH 45/60] chore(ci) bump docker/build-push-action from 5.4.0 to 6.13.0 Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 5.4.0 to 6.13.0. - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](https://github.com/docker/build-push-action/compare/ca052bb54ab0790a636c9b5f226502c73d547a25...ca877d9245402d1537745e0e356eab47c3520991) --- updated-dependencies: - dependency-name: docker/build-push-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1cb6da9d2..d7dbeac14 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -155,7 +155,7 @@ jobs: - name: Setup Docker Buildx uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3 - name: ${{ matrix.name }} - uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5 + uses: docker/build-push-action@ca877d9245402d1537745e0e356eab47c3520991 # v5 with: file: ${{ matrix.file }} tags: ${{ matrix.tags }} From b798fc2d7ee64ea030f47d507c4af2e6937c0154 Mon Sep 17 00:00:00 2001 From: Thibault Charbonnier Date: Mon, 3 Feb 2025 18:33:08 -0800 Subject: [PATCH 46/60] chore(release) replace release action with a maintained alternative Fix #676 --- .github/workflows/release.yml | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d7dbeac14..891f970f2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -448,36 +448,33 @@ jobs: run: find . -name '*.tar.gz' # Channel: nightly - name: Nightly release - uses: marvinpinto/action-automatic-releases@d68defdd11f9dcc7f52f35c1b7c236ee7513bcc1 + uses: ncipollo/release-action@cdcc88a9acf3ca41c16c37bb7d21b9ad48560d87 if: ${{ needs.setup.outputs.create_release == 'true' && needs.setup.outputs.release_channel == 'nightly' }} with: prerelease: true - title: ${{ needs.setup.outputs.release_name }} - automatic_release_tag: nightly - repo_token: ${{ secrets.GITHUB_TOKEN }} - files: | + name: ${{ needs.setup.outputs.release_name }} + tag: nightly + artifacts: | *.tar.gz # Channel: prerelease - name: Prerelease - uses: marvinpinto/action-automatic-releases@latest + uses: ncipollo/release-action@cdcc88a9acf3ca41c16c37bb7d21b9ad48560d87 if: ${{ needs.setup.outputs.create_release == 'true' && needs.setup.outputs.release_channel == 'prerelease' }} with: draft: true prerelease: true - title: Prerelease - ${{ needs.setup.outputs.release_version }} - automatic_release_tag: ${{ needs.setup.outputs.release_name }} - repo_token: ${{ secrets.GITHUB_TOKEN }} - files: | + name: Prerelease - ${{ needs.setup.outputs.release_version }} + tag: ${{ needs.setup.outputs.release_name }} + artifacts: | *.tar.gz # Channel: release - name: Release - uses: marvinpinto/action-automatic-releases@latest + uses: ncipollo/release-action@cdcc88a9acf3ca41c16c37bb7d21b9ad48560d87 if: ${{ needs.setup.outputs.create_release == 'true' && needs.setup.outputs.release_channel == 'release' }} with: draft: true prerelease: false - title: Release - ${{ needs.setup.outputs.release_version }} - automatic_release_tag: ${{ needs.setup.outputs.release_name }} - repo_token: ${{ secrets.GITHUB_TOKEN }} - files: | + name: Release - ${{ needs.setup.outputs.release_version }} + tag: ${{ needs.setup.outputs.release_name }} + artifacts: | *.tar.gz From 2bbd747c9a74f873a73f296f69732787ed922a19 Mon Sep 17 00:00:00 2001 From: Thibault Charbonnier Date: Tue, 4 Feb 2025 10:29:06 -0800 Subject: [PATCH 47/60] fix(ops) free plan struct on ngx_wasm_ops_plan_destroy Also free pipeline ops arrays. Fix #675 --- src/wasm/ngx_wasm_ops.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/wasm/ngx_wasm_ops.c b/src/wasm/ngx_wasm_ops.c index 8c02e7b01..b8b7e3fb5 100644 --- a/src/wasm/ngx_wasm_ops.c +++ b/src/wasm/ngx_wasm_ops.c @@ -213,10 +213,20 @@ ngx_wasm_ops_plan_load(ngx_wasm_ops_plan_t *plan, ngx_log_t *log) void ngx_wasm_ops_plan_destroy(ngx_wasm_ops_plan_t *plan) { + size_t i; + ngx_wasm_ops_pipeline_t *pipeline; + ngx_log_debug1(NGX_LOG_DEBUG_WASM, ngx_cycle->log, 0, "wasm freeing plan: %p", plan); + for (i = plan->subsystem->nphases - 1; i-- > 0; /* void */) { + pipeline = &plan->pipelines[i]; + + ngx_array_destroy(&pipeline->ops); + } + ngx_pfree(plan->pool, plan->pipelines); + ngx_pfree(plan->pool, plan); } From b507f3f6f71fe6c26b8523b4ffc7df51ae6b7096 Mon Sep 17 00:00:00 2001 From: Thibault Charbonnier Date: Tue, 4 Feb 2025 13:55:51 -0800 Subject: [PATCH 48/60] chore(tests) suppress an erroneous dead-code Rust warning --- t/lib/proxy-wasm-tests/hostcalls/src/types/mod.rs | 1 + 1 file changed, 1 insertion(+) 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 6e0f23124..c293257a6 100644 --- a/t/lib/proxy-wasm-tests/hostcalls/src/types/mod.rs +++ b/t/lib/proxy-wasm-tests/hostcalls/src/types/mod.rs @@ -17,6 +17,7 @@ pub enum TestPhase { } #[repr(u32)] +#[allow(dead_code)] // ignore erroneous dead code warning pub enum WasmxForeignFunction { ResolveLua = 0, } From 8e8b5154c8c45669cea205a9599e4a135f8ebafe Mon Sep 17 00:00:00 2001 From: Thibault Charbonnier Date: Thu, 6 Feb 2025 09:23:11 -0800 Subject: [PATCH 49/60] chore(deps) bump Nginx to 1.27.4 --- .github/workflows/ci-large.yml | 12 ++++++------ .github/workflows/ci.yml | 26 +++++++++++++------------- Makefile | 2 +- valgrind.suppress | 6 +++--- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/.github/workflows/ci-large.yml b/.github/workflows/ci-large.yml index 301783872..89eba73c0 100644 --- a/.github/workflows/ci-large.yml +++ b/.github/workflows/ci-large.yml @@ -23,7 +23,7 @@ jobs: label: [""] os: [ubuntu-latest] cc: [gcc-12] - ngx: [1.27.3] + ngx: [1.27.4] runtime: [wasmtime, wasmer, v8] wasmtime: [26.0.0] wasmer: [3.1.1] @@ -52,7 +52,7 @@ jobs: wasmer: 3.1.1 os: macos-13 cc: clang - ngx: 1.27.3 + ngx: 1.27.4 ssl: ssl debug: debug hup: no_hup @@ -62,7 +62,7 @@ jobs: wasmtime: 26.0.0 os: macos-13 cc: clang - ngx: 1.27.3 + ngx: 1.27.4 ssl: ssl debug: debug hup: hup @@ -72,7 +72,7 @@ jobs: v8: 13.1.201.15 os: macos-13 cc: clang - ngx: 1.27.3 + ngx: 1.27.4 ssl: ssl debug: debug hup: no_hup @@ -101,7 +101,7 @@ jobs: matrix: os: [ubuntu-22.04] cc: [gcc-12] - ngx: [1.27.3] + ngx: [1.27.4] runtime: [wasmer, wasmtime, v8] wasmtime: [26.0.0] wasmer: [3.1.1] @@ -169,7 +169,7 @@ jobs: label: [""] os: [ubuntu-latest] cc: [clang-14, clang-18, gcc-10, gcc-11] - ngx: [1.27.3] + ngx: [1.27.4] runtime: [wasmtime, wasmer, v8] wasmtime: [26.0.0] wasmer: [3.1.1] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c023b08fa..a8858b20b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,7 +33,7 @@ jobs: label: [""] os: [ubuntu-latest] cc: [gcc-12] - ngx: [1.27.3] + ngx: [1.27.4] openresty: [""] runtime: [wasmer] wasmtime: [""] @@ -50,7 +50,7 @@ jobs: wasmtime: 26.0.0 os: ubuntu-latest cc: gcc-12 - ngx: 1.27.3 + ngx: 1.27.4 ipc: no_ipc ssl: ssl debug: debug @@ -60,7 +60,7 @@ jobs: v8: 13.1.201.15 os: ubuntu-latest cc: gcc-12 - ngx: 1.27.3 + ngx: 1.27.4 ipc: no_ipc ssl: ssl debug: debug @@ -70,7 +70,7 @@ jobs: wasmtime: 26.0.0 os: ubuntu-latest cc: gcc-12 - ngx: 1.27.3 + ngx: 1.27.4 ipc: no_ipc ssl: no_ssl debug: debug @@ -91,7 +91,7 @@ jobs: - label: dynamic_nginx os: ubuntu-latest cc: gcc-12 - ngx: 1.27.3 + ngx: 1.27.4 runtime: wasmtime wasmtime: 26.0.0 ipc: no_ipc @@ -102,7 +102,7 @@ jobs: # No SSL - os: ubuntu-latest cc: gcc-12 - ngx: 1.27.3 + ngx: 1.27.4 runtime: wasmer wasmer: 3.1.1 ipc: no_ipc @@ -136,7 +136,7 @@ jobs: - label: ipc os: ubuntu-latest cc: gcc-12 - ngx: 1.27.3 + ngx: 1.27.4 runtime: wasmtime wasmtime: 26.0.0 ipc: ipc @@ -174,7 +174,7 @@ jobs: with: github-token: ${{ secrets.GITHUB_TOKEN }} parallel-finished: true - carryforward: 'unit-ngx_1.27.3-wasmer-no_ipc-ssl-debug-no_hup-static,unit-ngx_1.27.3-wasmer-no_ipc-ssl-no_debug-no_hup-static,unit-ngx_1.27.3-wasmtime-no_ipc-ssl-debug-hup-static,unit-ngx_1.27.3-wasmtime-no_ipc-ssl-debug-hup-dynamic,unit-ngx_1.27.3-v8-no_ipc-ssl-debug-no_hup-static,unit-ngx_1.27.3-wasmtime-no_ipc-no_ssl-debug-no_hup-static-wasm32-unknown-unknown,unit-ngx_1.21.6-wasmer-no_ipc-ssl-debug-no_hup-static,unit-ngx_1.27.3-wasmer-no_ipc-no_ssl-no_debug-no_hup-static,unit-openresty_1.27.1.1-wasmtime-no_ipc-ssl-debug-no_hup-static,unit-openresty_1.27.1.1-wasmtime-no_ipc-ssl-debug-no_hup-dynamic,unit-ngx_1.27.3-wasmtime-ipc-no_ssl-debug-no_hup-static' + carryforward: 'unit-ngx_1.27.4-wasmer-no_ipc-ssl-debug-no_hup-static,unit-ngx_1.27.4-wasmer-no_ipc-ssl-no_debug-no_hup-static,unit-ngx_1.27.4-wasmtime-no_ipc-ssl-debug-hup-static,unit-ngx_1.27.4-wasmtime-no_ipc-ssl-debug-hup-dynamic,unit-ngx_1.27.4-v8-no_ipc-ssl-debug-no_hup-static,unit-ngx_1.27.4-wasmtime-no_ipc-no_ssl-debug-no_hup-static-wasm32-unknown-unknown,unit-ngx_1.21.6-wasmer-no_ipc-ssl-debug-no_hup-static,unit-ngx_1.27.4-wasmer-no_ipc-no_ssl-no_debug-no_hup-static,unit-openresty_1.27.1.1-wasmtime-no_ipc-ssl-debug-no_hup-static,unit-openresty_1.27.1.1-wasmtime-no_ipc-ssl-debug-no_hup-dynamic,unit-ngx_1.27.4-wasmtime-ipc-no_ssl-debug-no_hup-static' valgrind: name: 'Valgrind' @@ -188,7 +188,7 @@ jobs: wasmer: [3.1.1] os: [ubuntu-22.04] cc: [gcc-12] - ngx: [1.27.3] + ngx: [1.27.4] openresty: [""] wasmtime: [""] v8: [""] @@ -200,7 +200,7 @@ jobs: wasmtime: 26.0.0 os: ubuntu-22.04 cc: gcc-12 - ngx: 1.27.3 + ngx: 1.27.4 hup: no_hup debug: debug path: t/01-wasm @@ -209,7 +209,7 @@ jobs: v8: 13.1.201.15 os: ubuntu-22.04 cc: gcc-12 - ngx: 1.27.3 + ngx: 1.27.4 debug: debug hup: no_hup path: t/01-wasm @@ -297,7 +297,7 @@ jobs: # No SSL - os: ubuntu-latest cc: clang-15 - ngx: 1.27.3 + ngx: 1.27.4 runtime: wasmer wasmer: 3.1.1 ssl: no_ssl @@ -323,7 +323,7 @@ jobs: matrix: os: [ubuntu-latest] cc: [clang-15, gcc-12] - ngx: [1.27.3] + ngx: [1.27.4] runtime: [wasmtime, wasmer, v8] wasmtime: [26.0.0] wasmer: [3.1.1] diff --git a/Makefile b/Makefile index 40c30ef10..bc77778d7 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -NGX ?= 1.27.3 +NGX ?= 1.27.4 OPENSSL ?= 3.4.0 WASMTIME ?= 26.0.0 WASMER ?= 3.1.1 diff --git a/valgrind.suppress b/valgrind.suppress index 6c18f6a36..53c357c9d 100644 --- a/valgrind.suppress +++ b/valgrind.suppress @@ -1,5 +1,5 @@ { - + Memcheck:Leak match-leak-kinds: definite fun:malloc @@ -7,14 +7,14 @@ fun:ngx_set_environment } { - + Memcheck:Leak fun:malloc fun:ngx_alloc fun:ngx_event_process_init } { - + Memcheck:Leak match-leak-kinds: possible fun:malloc From a376e67ce02c916304cc9b9ef25a540865ee6740 Mon Sep 17 00:00:00 2001 From: Thibault Charbonnier Date: Tue, 11 Feb 2025 09:25:45 -0800 Subject: [PATCH 50/60] chore(deps) bump OpenSSL to 3.4.1 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index bc77778d7..3cef2c16e 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ NGX ?= 1.27.4 -OPENSSL ?= 3.4.0 +OPENSSL ?= 3.4.1 WASMTIME ?= 26.0.0 WASMER ?= 3.1.1 V8 ?= 13.1.201.15 From f77105e1f242039ddb428461e47d642bd1743624 Mon Sep 17 00:00:00 2001 From: Thibault Charbonnier Date: Fri, 21 Feb 2025 09:57:24 -0800 Subject: [PATCH 51/60] chore(release) allow replacing existing nightly releases --- .github/workflows/release.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 891f970f2..88859fba2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -452,6 +452,8 @@ jobs: if: ${{ needs.setup.outputs.create_release == 'true' && needs.setup.outputs.release_channel == 'nightly' }} with: prerelease: true + allowUpdates: true + replacesArtifacts: true name: ${{ needs.setup.outputs.release_name }} tag: nightly artifacts: | @@ -463,6 +465,7 @@ jobs: with: draft: true prerelease: true + makeLatest: true name: Prerelease - ${{ needs.setup.outputs.release_version }} tag: ${{ needs.setup.outputs.release_name }} artifacts: | @@ -474,6 +477,7 @@ jobs: with: draft: true prerelease: false + makeLatest: true name: Release - ${{ needs.setup.outputs.release_version }} tag: ${{ needs.setup.outputs.release_name }} artifacts: | From 8450ea4dd53f50506c9cbb5971dae6f3d954b935 Mon Sep 17 00:00:00 2001 From: Thibault Charbonnier Date: Mon, 24 Feb 2025 10:54:00 -0800 Subject: [PATCH 52/60] chore(release) nightly release fixes - Override `nightly` tag - Remove previous nightly release artifacts - Generate nightly release notes --- .github/workflows/release.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 88859fba2..9ef5e8fa8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -446,6 +446,11 @@ jobs: run: find . -name '*wasmer*' | xargs rm -f - name: List all collected assets run: find . -name '*.tar.gz' + - name: Update Nightly tag + uses: actions-ecosystem/action-push-tag@v1 + if: ${{ needs.setup.outputs.create_release == 'true' && needs.setup.outputs.release_channel == 'nightly' }} + with: + tag: nightly # Channel: nightly - name: Nightly release uses: ncipollo/release-action@cdcc88a9acf3ca41c16c37bb7d21b9ad48560d87 @@ -453,7 +458,9 @@ jobs: with: prerelease: true allowUpdates: true + removeArtifacts: true replacesArtifacts: true + generateReleaseNotes: true name: ${{ needs.setup.outputs.release_name }} tag: nightly artifacts: | From 49735f5929b02ec480c39736af5bb37a6073a873 Mon Sep 17 00:00:00 2001 From: Thibault Charbonnier Date: Mon, 24 Feb 2025 09:54:18 -0800 Subject: [PATCH 53/60] feat(wasi) add stubs for missing wasip1 host functions Fix #682 --- src/wasm/wasi/ngx_wasi_preview1_host.c | 15 +++++++++++++++ t/05-wasi/wasi-p1/fd_fdstat_set_flags.t | 23 +++++++++++++++++++++++ t/05-wasi/wasi-p1/poll_oneoff.t | 23 +++++++++++++++++++++++ t/05-wasi/wasi-p1/sched_yield.t | 23 +++++++++++++++++++++++ t/lib/wasi-host-tests/src/lib.rs | 20 ++++++++++++++++++++ 5 files changed, 104 insertions(+) create mode 100644 t/05-wasi/wasi-p1/fd_fdstat_set_flags.t create mode 100644 t/05-wasi/wasi-p1/poll_oneoff.t create mode 100644 t/05-wasi/wasi-p1/sched_yield.t diff --git a/src/wasm/wasi/ngx_wasi_preview1_host.c b/src/wasm/wasi/ngx_wasi_preview1_host.c index ad0d799a2..545a24b2d 100644 --- a/src/wasm/wasi/ngx_wasi_preview1_host.c +++ b/src/wasm/wasi/ngx_wasi_preview1_host.c @@ -356,6 +356,11 @@ static ngx_wavm_host_func_def_t ngx_wasi_hfuncs[] = { ngx_wavm_arity_i32x2, ngx_wavm_arity_i32 }, + { ngx_string("fd_fdstat_set_flags"), + &ngx_wasi_hfuncs_errno_badf, + ngx_wavm_arity_i32x2, + ngx_wavm_arity_i32 }, + { ngx_string("fd_prestat_get"), &ngx_wasi_hfuncs_errno_badf, ngx_wavm_arity_i32x2, @@ -396,6 +401,16 @@ static ngx_wavm_host_func_def_t ngx_wasi_hfuncs[] = { ngx_wavm_arity_i32x2, ngx_wavm_arity_i32 }, + { ngx_string("sched_yield"), + &ngx_wasi_hfuncs_errno_notsup, + NULL, + ngx_wavm_arity_i32 }, + + { ngx_string("poll_oneoff"), + &ngx_wasi_hfuncs_errno_notsup, + ngx_wavm_arity_i32x4, + ngx_wavm_arity_i32 }, + ngx_wavm_hfunc_null }; diff --git a/t/05-wasi/wasi-p1/fd_fdstat_set_flags.t b/t/05-wasi/wasi-p1/fd_fdstat_set_flags.t new file mode 100644 index 000000000..5bb9582cc --- /dev/null +++ b/t/05-wasi/wasi-p1/fd_fdstat_set_flags.t @@ -0,0 +1,23 @@ +# vim:set ft= ts=4 sts=4 sw=4 et fdm=marker: + +use strict; +use lib '.'; +use t::TestWasmX; + +skip_no_wasi(); + +plan_tests(3); +run_tests(); + +__DATA__ + +=== TEST 1: fd_fdstat_set_flags stub +--- wasm_modules: wasi_host_tests +--- config + location /t { + wasm_call rewrite wasi_host_tests test_wasi_fd_fdstat_set_flags; + } +--- response_body +test passed +--- no_error_log +[error] diff --git a/t/05-wasi/wasi-p1/poll_oneoff.t b/t/05-wasi/wasi-p1/poll_oneoff.t new file mode 100644 index 000000000..0608d9411 --- /dev/null +++ b/t/05-wasi/wasi-p1/poll_oneoff.t @@ -0,0 +1,23 @@ +# vim:set ft= ts=4 sts=4 sw=4 et fdm=marker: + +use strict; +use lib '.'; +use t::TestWasmX; + +skip_no_wasi(); + +plan_tests(3); +run_tests(); + +__DATA__ + +=== TEST 1: fd_fdstat_set_flags stub +--- wasm_modules: wasi_host_tests +--- config + location /t { + wasm_call rewrite wasi_host_tests test_wasi_poll_oneoff; + } +--- response_body +test passed +--- no_error_log +[error] diff --git a/t/05-wasi/wasi-p1/sched_yield.t b/t/05-wasi/wasi-p1/sched_yield.t new file mode 100644 index 000000000..e8fe1893e --- /dev/null +++ b/t/05-wasi/wasi-p1/sched_yield.t @@ -0,0 +1,23 @@ +# vim:set ft= ts=4 sts=4 sw=4 et fdm=marker: + +use strict; +use lib '.'; +use t::TestWasmX; + +skip_no_wasi(); + +plan_tests(3); +run_tests(); + +__DATA__ + +=== TEST 1: fd_fdstat_set_flags stub +--- wasm_modules: wasi_host_tests +--- config + location /t { + wasm_call rewrite wasi_host_tests test_wasi_sched_yield; + } +--- response_body +test passed +--- no_error_log +[error] diff --git a/t/lib/wasi-host-tests/src/lib.rs b/t/lib/wasi-host-tests/src/lib.rs index e27c32f49..c9b0883af 100644 --- a/t/lib/wasi-host-tests/src/lib.rs +++ b/t/lib/wasi-host-tests/src/lib.rs @@ -254,6 +254,12 @@ pub fn test_wasi_fd_fdstat_get() { expect_errno(wasi::ERRNO_BADF, unsafe { wasi::fd_fdstat_get(1) }); } +#[no_mangle] +pub fn test_wasi_fd_fdstat_set_flags() { + // current stub implementation always returns BADF + expect_errno(wasi::ERRNO_BADF, unsafe { wasi::fd_fdstat_set_flags(1, 0) }); +} + #[no_mangle] pub fn test_wasi_fd_prestat_get() { // current stub implementation always returns BADF @@ -293,3 +299,17 @@ pub fn test_wasi_path_open() { wasi::path_open(1, 0, "/tmp", 0, 0, 0, 0) }); } + +#[no_mangle] +pub fn test_wasi_sched_yield() { + // current stub implementation always returns NOTSUP + expect_errno(wasi::ERRNO_NOTSUP, unsafe { wasi::sched_yield() }); +} + +#[no_mangle] +pub fn test_wasi_poll_oneoff() { + // current stub implementation always returns NOTSUP + expect_errno(wasi::ERRNO_NOTSUP, unsafe { + wasi::poll_oneoff(std::ptr::null(), std::ptr::null_mut(), 0) + }); +} From c62213bae4dd913328edc981769d66155b0948ae Mon Sep 17 00:00:00 2001 From: Thibault Charbonnier Date: Mon, 24 Feb 2025 17:20:30 -0800 Subject: [PATCH 54/60] docs(changelog) prerelease-0.6.0 --- CHANGELOG.md | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index eefc43152..3d0e9dda0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # Table of Contents +- [0.6.0] - [0.5.0] - [0.4.0] - [0.3.0] @@ -34,6 +35,71 @@ As for Nginx developers, the module can also be used to write other modules; the best resource for that sort of information would be [DEVELOPER.md](https://github.com/Kong/ngx_wasm_module/tree/main/docs/DEVELOPER.md). +## 0.6.0 + +> 2025/02/24 - Prerelease +> +> [Documentation](https://github.com/Kong/ngx_wasm_module/tree/prerelease-0.6.0/docs) +> | [Release assets](https://github.com/Kong/ngx_wasm_module/releases/tag/prerelease-0.6.0) + +This prerelease includes a number of features and improvements mostly targeted +at improving the Proxy-Wasm embedding. + +#### Changes + +> [0.5.0...0.6.0](https://github.com/Kong/ngx_wasm_module/compare/prerelease-0.5.0...prerelease-0.6.0) + +- Proxy-Wasm + - Feature: support for the foreign function interface allowing for custom + host extensions. + - Feature: always invoke the `on_http_call_response()` handler during HTTP + dispatch failures (e.g. timeout, broken connection, resolver failures, + ...). + - Feature: support for setting the proxied request querystring via the + `:path` property. + - Feature: new property `request.is_subrequest` allowing filters to + determine whether the current request is a subrequest. + - Feature: add a new directive: `proxy_wasm_log_dispatch_errors` which + toggles whether TCP socket errors produce an `[error]` log or not. + - Bugfix: resolve a segfault when filters would access request-only + properties in root contexts (e.g. `request.*`, `upstream.*`, ...). + - Bugfix: allow filters to access root properties in the background tick + context (e.g. `plugin_name`, `plugin_root_id`, ...). + - Bugfix: pass the VM config size argument to the `on_vm_start()` handler. +- LuaJIT FFI + - Feature: produce an error when `shm:set()` is invoked while the shm lock + is already being held. +- WASI + - Feature: add some missing wasi-preview1 host functions (as stubs only). +- Misc + - Feature: disallow spaces, tabs and colons in the name of defined Wasm + modules. + - Bugfix: ensure filter chain plans are freed on worker shutdown as well as + during FFI reconfiguration. + +#### Dependencies + +This release is tested with the following Nginx/OpenResty versions and dependencies: + +Name | Version | Notes +---------:|:---------------:|:-------------------------------------------------- +Nginx | [1.27.4](https://nginx.org/en/download.html) | +OpenSSL | [3.4.1](https://www.openssl.org/source/) | +Wasmtime | [26.0.0](https://github.com/bytecodealliance/wasmtime/releases) | +Wasmer | [3.1.1](https://github.com/wasmerio/wasmer/releases/) | +V8 | [13.1.201.15](https://github.com/Kong/ngx_wasm_runtimes/releases/) | Built by [Kong/ngx_wasm_runtimes] for convenience. +OpenResty | [1.27.1.1](https://openresty.org/en/download.html) | No binary, tested only. + +#### Components + +Same as [0.1.0]. + +#### Known Issues + +N/A + +[Back to TOC](#table-of-contents) + ## 0.5.0 > 2024/10/23 - Prerelease @@ -390,6 +456,7 @@ lua-resty-wasmx | A LuaJIT FFI binding exposing some of ngx_wasm_module's featur [Back to TOC](#table-of-contents) +[0.6.0]: #060 [0.5.0]: #050 [0.4.0]: #040 [0.3.0]: #030 From bde7e1443d49c2aa5342bb8c1426057302a49f78 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Mar 2025 11:46:06 +0000 Subject: [PATCH 55/60] chore(ci) bump docker/build-push-action from 6.13.0 to 6.15.0 Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6.13.0 to 6.15.0. - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](https://github.com/docker/build-push-action/compare/ca877d9245402d1537745e0e356eab47c3520991...471d1dc4e07e5cdedd4c2171150001c434f0b7a4) --- updated-dependencies: - dependency-name: docker/build-push-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9ef5e8fa8..33916a30a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -155,7 +155,7 @@ jobs: - name: Setup Docker Buildx uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3 - name: ${{ matrix.name }} - uses: docker/build-push-action@ca877d9245402d1537745e0e356eab47c3520991 # v5 + uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v5 with: file: ${{ matrix.file }} tags: ${{ matrix.tags }} From 6812ec25225b72c6d38ecf563f1849415d257616 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Mar 2025 11:46:08 +0000 Subject: [PATCH 56/60] chore(ci) bump ncipollo/release-action from 1.15.0 to 1.16.0 Bumps [ncipollo/release-action](https://github.com/ncipollo/release-action) from 1.15.0 to 1.16.0. - [Release notes](https://github.com/ncipollo/release-action/releases) - [Commits](https://github.com/ncipollo/release-action/compare/cdcc88a9acf3ca41c16c37bb7d21b9ad48560d87...440c8c1cb0ed28b9f43e4d1d670870f059653174) --- updated-dependencies: - dependency-name: ncipollo/release-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/release.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 33916a30a..8fef36b36 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -453,7 +453,7 @@ jobs: tag: nightly # Channel: nightly - name: Nightly release - uses: ncipollo/release-action@cdcc88a9acf3ca41c16c37bb7d21b9ad48560d87 + uses: ncipollo/release-action@440c8c1cb0ed28b9f43e4d1d670870f059653174 if: ${{ needs.setup.outputs.create_release == 'true' && needs.setup.outputs.release_channel == 'nightly' }} with: prerelease: true @@ -467,7 +467,7 @@ jobs: *.tar.gz # Channel: prerelease - name: Prerelease - uses: ncipollo/release-action@cdcc88a9acf3ca41c16c37bb7d21b9ad48560d87 + uses: ncipollo/release-action@440c8c1cb0ed28b9f43e4d1d670870f059653174 if: ${{ needs.setup.outputs.create_release == 'true' && needs.setup.outputs.release_channel == 'prerelease' }} with: draft: true @@ -479,7 +479,7 @@ jobs: *.tar.gz # Channel: release - name: Release - uses: ncipollo/release-action@cdcc88a9acf3ca41c16c37bb7d21b9ad48560d87 + uses: ncipollo/release-action@440c8c1cb0ed28b9f43e4d1d670870f059653174 if: ${{ needs.setup.outputs.create_release == 'true' && needs.setup.outputs.release_channel == 'release' }} with: draft: true From 54895d10367d7e634f89553884c156d66cf56cbb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Mar 2025 11:46:10 +0000 Subject: [PATCH 57/60] chore(ci) bump docker/setup-qemu-action from 3.3.0 to 3.6.0 Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 3.3.0 to 3.6.0. - [Release notes](https://github.com/docker/setup-qemu-action/releases) - [Commits](https://github.com/docker/setup-qemu-action/compare/53851d14592bedcffcf25ea515637cff71ef929a...29109295f81e9208d7d86ff1c6c12d2833863392) --- updated-dependencies: - dependency-name: docker/setup-qemu-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8fef36b36..f25a734ed 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -151,7 +151,7 @@ jobs: username: ${{ github.repository_owner }} password: ${{ secrets.TOKEN_GITHUB }} - name: Setup QEMU - uses: docker/setup-qemu-action@53851d14592bedcffcf25ea515637cff71ef929a # v3 + uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3 - name: Setup Docker Buildx uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3 - name: ${{ matrix.name }} @@ -268,7 +268,7 @@ jobs: # steps: # - uses: actions/checkout@v3 # - name: Setup QEMU - # uses: docker/setup-qemu-action@53851d14592bedcffcf25ea515637cff71ef929a # v3 + # uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3 # - name: Login to GitHub Container Registry # uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3 # with: From e3d38f60a167f79ff01bdf9169b1ef88a84e7720 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Mar 2025 11:46:13 +0000 Subject: [PATCH 58/60] chore(ci) bump docker/setup-buildx-action from 3.8.0 to 3.10.0 Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 3.8.0 to 3.10.0. - [Release notes](https://github.com/docker/setup-buildx-action/releases) - [Commits](https://github.com/docker/setup-buildx-action/compare/6524bf65af31da8d45b59e8c27de4bd072b392f5...b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2) --- updated-dependencies: - dependency-name: docker/setup-buildx-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f25a734ed..93436956e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -153,7 +153,7 @@ jobs: - name: Setup QEMU uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3 - name: Setup Docker Buildx - uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3 + uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3 - name: ${{ matrix.name }} uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v5 with: From 5c629c8b76860b3a2e9beb2ffc8ab553018af616 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Mar 2025 11:46:15 +0000 Subject: [PATCH 59/60] chore(ci) bump codecov/codecov-action from 5.3.1 to 5.4.0 Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 5.3.1 to 5.4.0. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/13ce06bfc6bbe3ecf90edbbf1bc32fe5978ca1d3...0565863a31f2c772f9f0395002a31e3f06189574) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/job-unit-tests.yml | 2 +- .github/workflows/job-valgrind-tests.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/job-unit-tests.yml b/.github/workflows/job-unit-tests.yml index 0399f3275..85490fd88 100644 --- a/.github/workflows/job-unit-tests.yml +++ b/.github/workflows/job-unit-tests.yml @@ -190,7 +190,7 @@ jobs: parallel: true - name: Codecov Upload if: ${{ !env.ACT && inputs.coverage }} - uses: codecov/codecov-action@13ce06bfc6bbe3ecf90edbbf1bc32fe5978ca1d3 # v4 + uses: codecov/codecov-action@0565863a31f2c772f9f0395002a31e3f06189574 # v4 with: token: ${{ secrets.CODECOV_TOKEN }} files: './lcov.info' diff --git a/.github/workflows/job-valgrind-tests.yml b/.github/workflows/job-valgrind-tests.yml index 5cd0f6584..d44054438 100644 --- a/.github/workflows/job-valgrind-tests.yml +++ b/.github/workflows/job-valgrind-tests.yml @@ -178,7 +178,7 @@ jobs: parallel: true - name: Codecov Upload if: ${{ !env.ACT && inputs.coverage }} - uses: codecov/codecov-action@13ce06bfc6bbe3ecf90edbbf1bc32fe5978ca1d3 # v4 + uses: codecov/codecov-action@0565863a31f2c772f9f0395002a31e3f06189574 # v4 with: token: ${{ secrets.CODECOV_TOKEN }} files: './lcov.info' From 3bed27836bb402143c6cbde17994b1d11a1084bc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Apr 2025 11:32:41 +0000 Subject: [PATCH 60/60] chore(ci) bump docker/login-action from 3.3.0 to 3.4.0 Bumps [docker/login-action](https://github.com/docker/login-action) from 3.3.0 to 3.4.0. - [Release notes](https://github.com/docker/login-action/releases) - [Commits](https://github.com/docker/login-action/compare/9780b0c442fbb1117ed29e0efdff1e18412f7567...74a5d142397b4f367a81961eba4e8cd7edddf772) --- updated-dependencies: - dependency-name: docker/login-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 93436956e..3b306fc4b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -145,7 +145,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Login to GitHub Container Registry - uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3 + uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3 with: registry: ghcr.io username: ${{ github.repository_owner }} @@ -270,7 +270,7 @@ jobs: # - name: Setup QEMU # uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3 # - name: Login to GitHub Container Registry - # uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3 + # uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3 # with: # registry: ghcr.io # username: ${{ github.repository_owner }}