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 5be5f7c10..3e86c77a8 100644 --- a/.github/actions/setup-httpbin-server/action.yml +++ b/.github/actions/setup-httpbin-server/action.yml @@ -30,38 +30,46 @@ 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' 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 + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3 with: registry: ghcr.io username: ${{ inputs.ghcr_username }} password: ${{ inputs.ghcr_password }} + - 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 }} @@ -70,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: | @@ -79,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: | diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..ba6030073 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,82 @@ +# 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: + - "pr/dependabot" + groups: + production-dependencies: + dependency-type: "production" + patterns: + - "*" + development-dependencies: + dependency-type: "development" + patterns: + - "*" + commit-message: + prefix: "chore(deps) " + + - package-ecosystem: cargo + 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: + - "*" + ignore: + - dependency-name: "wasi" + versions: [">0.11"] + labels: + - "pr/dependabot" + commit-message: + prefix: "chore(tests) " + + - 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.1"] + labels: + - "pr/dependabot" + commit-message: + prefix: "chore(tests) " diff --git a/.github/workflows/ci-large.yml b/.github/workflows/ci-large.yml index 32a477aca..89eba73c0 100644 --- a/.github/workflows/ci-large.yml +++ b/.github/workflows/ci-large.yml @@ -23,11 +23,11 @@ jobs: label: [""] os: [ubuntu-latest] cc: [gcc-12] - ngx: [1.27.2] + ngx: [1.27.4] 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] @@ -52,7 +52,7 @@ jobs: wasmer: 3.1.1 os: macos-13 cc: clang - ngx: 1.27.2 + ngx: 1.27.4 ssl: ssl debug: debug hup: no_hup @@ -62,17 +62,17 @@ jobs: wasmtime: 26.0.0 os: macos-13 cc: clang - ngx: 1.27.2 + ngx: 1.27.4 ssl: ssl debug: debug hup: hup # 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.2 + ngx: 1.27.4 ssl: ssl debug: debug hup: no_hup @@ -101,11 +101,11 @@ jobs: matrix: os: [ubuntu-22.04] cc: [gcc-12] - ngx: [1.27.2] + ngx: [1.27.4] 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 @@ -168,12 +168,12 @@ jobs: matrix: label: [""] os: [ubuntu-latest] - cc: [clang-13, clang-14, gcc-10, gcc-11] - ngx: [1.27.2] + cc: [clang-14, clang-18, gcc-10, gcc-11] + ngx: [1.27.4] 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 2c9cca1b8..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.2] + ngx: [1.27.4] openresty: [""] runtime: [wasmer] wasmtime: [""] @@ -50,17 +50,17 @@ jobs: wasmtime: 26.0.0 os: ubuntu-latest cc: gcc-12 - ngx: 1.27.2 + ngx: 1.27.4 ipc: no_ipc ssl: ssl debug: debug hup: hup # V8 - runtime: v8 - v8: 12.0.267.17 + v8: 13.1.201.15 os: ubuntu-latest cc: gcc-12 - ngx: 1.27.2 + 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.2 + 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.2 + 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.2 + 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.2 + ngx: 1.27.4 runtime: wasmtime wasmtime: 26.0.0 ipc: ipc @@ -170,11 +170,11 @@ jobs: steps: - name: Coveralls Finished if: ${{ !env.ACT }} - uses: coverallsapp/github-action@v2 + uses: coverallsapp/github-action@648a8eb78e6d50909eff900e4ec85cab4524a45b # v2 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.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.2] + ngx: [1.27.4] openresty: [""] wasmtime: [""] v8: [""] @@ -200,16 +200,16 @@ jobs: wasmtime: 26.0.0 os: ubuntu-22.04 cc: gcc-12 - ngx: 1.27.2 + ngx: 1.27.4 hup: no_hup debug: debug 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.2 + ngx: 1.27.4 debug: debug hup: no_hup path: t/01-wasm @@ -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' @@ -290,14 +290,14 @@ 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: # No SSL - os: ubuntu-latest cc: clang-15 - ngx: 1.27.2 + ngx: 1.27.4 runtime: wasmer wasmer: 3.1.1 ssl: no_ssl @@ -323,11 +323,11 @@ jobs: matrix: os: [ubuntu-latest] cc: [clang-15, gcc-12] - ngx: [1.27.2] + ngx: [1.27.4] 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/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 25630cfe8..7b3ffa37b 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 @@ -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 b825bea76..85490fd88 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') }} @@ -104,7 +102,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 +116,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 @@ -151,13 +149,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 @@ -184,7 +182,7 @@ jobs: echo "name=$name" >> $GITHUB_OUTPUT - name: Coveralls Upload if: ${{ !env.ACT && inputs.coverage }} - uses: coverallsapp/github-action@v2 + uses: coverallsapp/github-action@648a8eb78e6d50909eff900e4ec85cab4524a45b # v2 with: github-token: ${{ secrets.GITHUB_TOKEN }} flag-name: ${{ steps.lcov.outputs.name }} @@ -192,11 +190,11 @@ jobs: parallel: true - name: Codecov Upload if: ${{ !env.ACT && inputs.coverage }} - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@0565863a31f2c772f9f0395002a31e3f06189574 # v4 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 bed2241a8..d44054438 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 @@ -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@648a8eb78e6d50909eff900e4ec85cab4524a45b # 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@v4 + uses: codecov/codecov-action@0565863a31f2c772f9f0395002a31e3f06189574 # 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 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2c80240f6..3b306fc4b 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" @@ -144,17 +145,17 @@ jobs: steps: - uses: actions/checkout@v3 - name: Login to GitHub Container Registry - uses: docker/login-action@v3 + uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # 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@29109295f81e9208d7d86ff1c6c12d2833863392 # v3 - name: Setup Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3 - name: ${{ matrix.name }} - uses: docker/build-push-action@v5 + uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v5 with: file: ${{ matrix.file }} tags: ${{ matrix.tags }} @@ -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@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-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@v3 - - name: Login to GitHub Container Registry - uses: docker/login-action@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@29109295f81e9208d7d86ff1c6c12d2833863392 # v3 + # - name: Login to GitHub Container Registry + # uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # 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@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-centos8: name: "Build Centos 8 binary" @@ -390,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 }} @@ -431,14 +432,13 @@ 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: - - 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 @@ -446,38 +446,46 @@ 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: marvinpinto/action-automatic-releases@latest + uses: ncipollo/release-action@440c8c1cb0ed28b9f43e4d1d670870f059653174 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: | + allowUpdates: true + removeArtifacts: true + replacesArtifacts: true + generateReleaseNotes: true + 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@440c8c1cb0ed28b9f43e4d1d670870f059653174 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: | + makeLatest: true + 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@440c8c1cb0ed28b9f43e4d1d670870f059653174 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: | + makeLatest: true + name: Release - ${{ needs.setup.outputs.release_version }} + tag: ${{ needs.setup.outputs.release_name }} + artifacts: | *.tar.gz 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 diff --git a/Makefile b/Makefile index 5ae460193..3cef2c16e 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ -NGX ?= 1.27.2 -OPENSSL ?= 3.4.0 +NGX ?= 1.27.4 +OPENSSL ?= 3.4.1 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 @@ -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/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). 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/dependabot.yml b/dependabot.yml deleted file mode 100644 index 82197f1ef..000000000 --- a/dependabot.yml +++ /dev/null @@ -1,47 +0,0 @@ -# https://docs.github.com/en/code-security/supply-chain-security/configuration-options-for-dependency-updates -version: 2 -updates: - - package-ecosystem: cargo - directory: /lib - schedule: - interval: monthly - labels: - - dependabot - groups: - production-dependencies: - dependency-type: "production" - patterns: - - "*" - commit-message: - prefix: "chore(deps) " - include: scope - - - package-ecosystem: cargo - directory: /t/lib - schedule: - interval: monthly - groups: - development-dependencies: - dependency-type: "development" - patterns: - - "*" - labels: - - dependabot - commit-message: - prefix: "chore(tests) " - include: scope - - - package-ecosystem: github-actions - directory: / - schedule: - interval: monthly - groups: - development-dependencies: - dependency-type: "development" - patterns: - - "*" - labels: - - dependabot - commit-message: - prefix: "chore(ci) " - include: scope diff --git a/docs/DIRECTIVES.md b/docs/DIRECTIVES.md index 23ce03210..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) @@ -256,10 +260,11 @@ 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 - `module` is a proxy-wasm filter. + `module` is a Proxy-Wasm filter. If successfully loaded, the module can later be referred to by `name`. @@ -285,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. @@ -304,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 @@ -340,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: @@ -358,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]. @@ -388,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) @@ -430,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 @@ -524,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) @@ -556,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 @@ -662,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 @@ -707,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 @@ -728,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/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/docs/PROXY_WASM.md b/docs/PROXY_WASM.md index 0b98595e1..734685d4a 100644 --- a/docs/PROXY_WASM.md +++ b/docs/PROXY_WASM.md @@ -10,6 +10,8 @@ - [Filters Execution in Nginx](#filters-execution-in-nginx) - [Host Properties] - [Nginx Properties] + - [HTTP Dispatches] + - [Foreign Functions] - [Supported Specifications] - [Tested SDKs](#tested-sdks) - [Supported Entrypoints](#supported-entrypoints) @@ -107,13 +109,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 +378,216 @@ 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) + +### 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 @@ -429,7 +641,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. @@ -459,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". @@ -541,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) @@ -595,6 +809,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). @@ -636,7 +851,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 +958,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 +974,16 @@ Proxy-Wasm SDK. [Filter Chains]: #filter-chains [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 [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/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/lib/resty/wasmx/shm.lua b/lib/resty/wasmx/shm.lua index 50880099c..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]) @@ -403,7 +407,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 +532,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 +558,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/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 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/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..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 @@ -440,8 +441,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) { @@ -839,10 +840,16 @@ 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; 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, @@ -852,7 +859,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 */ @@ -889,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->calls); - q != ngx_queue_sentinel(&pwexec->calls); + for (q = ngx_queue_head(&pwexec->dispatch_ops); + q != ngx_queue_sentinel(&pwexec->dispatch_ops); q = ngx_queue_next(q), n++) { /* void */ } dd("n: %ld", n); @@ -905,25 +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->calls)) { - q = ngx_queue_head(&pwexec->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; + } + } } @@ -1145,7 +1165,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_ops); log = filter->log; @@ -1213,7 +1233,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; @@ -1262,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->calls); + ngx_queue_init(&pwexec->dispatch_ops); } else { if (in->ictx != ictx) { @@ -1389,11 +1410,11 @@ ngx_proxy_wasm_on_done(ngx_proxy_wasm_exec_t *pwexec) #if 0 #ifdef NGX_WASM_HTTP - call = pwexec->call; + call = pwexec->dispatch_call; if (call) { ngx_http_proxy_wasm_dispatch_destroy(call); - pwexec->call = NULL; + pwexec->dispatch_call = NULL; } #endif #endif diff --git a/src/common/proxy_wasm/ngx_proxy_wasm.h b/src/common/proxy_wasm/ngx_proxy_wasm.h index 1d9c73981..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 *call; /* swap pointer for host functions */ + ngx_http_proxy_wasm_dispatch_t *dispatch_call; /* swap pointer for host functions */ #endif - ngx_queue_t calls; /* flags */ @@ -213,6 +240,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; @@ -231,19 +259,19 @@ struct ngx_proxy_wasm_ctx_s { size_t req_body_len; ngx_str_t authority; ngx_str_t scheme; - ngx_str_t path; /* r->uri + r->args */ - ngx_str_t start_time; /* r->start_sec + r->start_msec */ - ngx_str_t upstream_address; /* 1st part of ngx.upstream_addr */ - ngx_str_t upstream_port; /* 2nd part of ngx.upstsream_addr */ - ngx_str_t connection_id; /* r->connection->number */ - ngx_str_t mtls; /* ngx.https && ngx.ssl_client_verify */ - ngx_str_t root_id; /* pwexec->root_id */ - ngx_str_t call_status; /* dispatch response status */ - ngx_str_t response_status; /* response status */ + ngx_str_t path; /* r->uri + r->args */ + ngx_str_t start_time; /* r->start_sec + r->start_msec */ + ngx_str_t upstream_address; /* 1st part of ngx.upstream_addr */ + ngx_str_t upstream_port; /* 2nd part of ngx.upstsream_addr */ + ngx_str_t connection_id; /* r->connection->number */ + ngx_str_t mtls; /* ngx.https && ngx.ssl_client_verify */ + ngx_str_t root_id; /* pwexec->root_id */ + ngx_str_t dispatch_call_status; /* dispatch response status */ + ngx_str_t response_status; /* response status */ #if (NGX_DEBUG) - ngx_str_t worker_id; /* ngx_worker */ + ngx_str_t worker_id; /* ngx_worker */ #endif - ngx_uint_t call_code; + ngx_uint_t dispatch_call_code; ngx_uint_t response_code; /* host properties */ @@ -258,9 +286,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; }; @@ -413,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 d92ffddb7..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 @@ -127,7 +130,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; } @@ -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); } @@ -1635,7 +1654,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); @@ -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_maps.c b/src/common/proxy_wasm/ngx_proxy_wasm_maps.c index 20c175bea..856040da8 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 }, @@ -112,14 +119,21 @@ 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; } 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: @@ -507,19 +521,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) { @@ -753,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; @@ -766,14 +782,13 @@ ngx_proxy_wasm_maps_get_dispatch_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 */ - ngx_wa_assert(reader->fake_r.upstream); - if (reader->fake_r.upstream == NULL) { + /* response not received */ return NULL; } @@ -784,30 +799,51 @@ ngx_proxy_wasm_maps_get_dispatch_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->dispatch_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->dispatch_call; + sock = &call->sock; - return &pwctx->call_status; + return ngx_wasm_socket_tcp_status_strerror(sock->status); } #endif diff --git a/src/common/proxy_wasm/ngx_proxy_wasm_properties.c b/src/common/proxy_wasm/ngx_proxy_wasm_properties.c index ebe81881d..1f6bacfe9 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) { @@ -357,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; @@ -472,6 +499,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 */ @@ -774,21 +804,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 +843,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 +943,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 +1010,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 +1085,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 +1168,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 +1185,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/src/common/proxy_wasm/ngx_proxy_wasm_util.c b/src/common/proxy_wasm/ngx_proxy_wasm_util.c index c99f5d255..90cc392ef 100644 --- a/src/common/proxy_wasm/ngx_proxy_wasm_util.c +++ b/src/common/proxy_wasm/ngx_proxy_wasm_util.c @@ -41,7 +41,8 @@ static ngx_str_t ngx_proxy_wasm_steplist[] = { ngx_string("on_log"), ngx_string("on_done"), ngx_string("on_tick"), - ngx_string("on_dispatch_response") + ngx_string("on_dispatch_response"), + ngx_string("on_foreign_function") }; @@ -62,7 +63,7 @@ ngx_proxy_wasm_step_name(ngx_proxy_wasm_step_e step) ngx_str_t *name; ngx_wa_assert(step); - ngx_wa_assert(step <= NGX_PROXY_WASM_STEP_DISPATCH_RESPONSE); + ngx_wa_assert(step <= NGX_PROXY_WASM_STEP_FOREIGN_CALLBACK); name = &ngx_proxy_wasm_steplist[step]; diff --git a/src/http/ngx_http_wasm.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/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.c b/src/http/proxy_wasm/ngx_http_proxy_wasm.c index d8f809116..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 @@ -313,39 +314,73 @@ 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_proxy_wasm_dispatch_t *call = pwexec->dispatch_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; +} + + +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; } @@ -439,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 bfe15af25..b4f69b52e 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->dispatch_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->dispatch_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); } @@ -95,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 */ @@ -104,9 +155,13 @@ 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; + pwexec->dispatch_call = NULL; } @@ -144,41 +199,27 @@ 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; 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_wa_assert(pwexec->root_id == NGX_PROXY_WASM_ROOT_CTX_ID); - ngx_wa_assert(pwexec->parent->id == NGX_PROXY_WASM_ROOT_CTX_ID); - - c = ngx_http_wasm_create_fake_connection(pwexec->pool); - if (c == NULL) { - return NULL; - } - - r = ngx_http_wasm_create_fake_request(c); - if (r == NULL) { - return NULL; - } - - if (ngx_http_wasm_rctx(r, &rctxp) != NGX_OK) { - return NULL; + if (ngx_http_wasm_create_fake_rctx(pwexec, &rctxp) != NGX_OK) { + goto error; } - ngx_wa_assert(r->pool == rctxp->pool); - - rctxp->data = pwexec->parent; + r = rctxp->r; } else { r = rctx->r; } + /* alloc */ call = ngx_calloc(sizeof(ngx_http_proxy_wasm_dispatch_t), @@ -258,8 +299,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 +371,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; } @@ -374,22 +415,34 @@ 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 */ + 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->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); @@ -410,7 +463,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; @@ -464,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; @@ -472,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); @@ -577,7 +631,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 +692,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, @@ -713,16 +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_err_e ecode = NGX_PROXY_WASM_ERR_NONE; - ngx_proxy_wasm_step_e step = pwexec->parent->step; + 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) { @@ -828,44 +892,14 @@ 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 + ngx_queue_remove(&dop->q); - 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; @@ -883,25 +917,23 @@ 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: - 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: - 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); @@ -910,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, @@ -920,7 +952,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/src/http/proxy_wasm/ngx_http_proxy_wasm_dispatch.h b/src/http/proxy_wasm/ngx_http_proxy_wasm_dispatch.h index a23e9a22e..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; @@ -40,7 +39,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; 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/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/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); } 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; 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 } 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/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 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 { 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/117-proxy_properties_get.t b/t/03-proxy_wasm/hfuncs/117-proxy_properties_get.t index e07a17cca..95a8aa484 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,74 @@ 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() 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 @@ -683,3 +753,95 @@ qr/\[info\] .*? property not found: nonexistent_property,/ --- no_error_log [error] [crit] + + + +=== 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 +--- 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 20: 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 21: 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 22: 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/03-proxy_wasm/hfuncs/130-proxy_dispatch_http.t b/t/03-proxy_wasm/hfuncs/130-proxy_dispatch_http.t index 7356cd8a7..75af8db33 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] @@ -301,7 +322,7 @@ ok echo ok; } --- request -GET /t +POST /t Hello world --- response_body @@ -309,6 +330,7 @@ ok --- no_error_log [error] [crit] +[alert] @@ -329,7 +351,7 @@ ok echo failed; } --- request -GET /t +POST /t Hello world --- response_body @@ -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] @@ -384,8 +408,9 @@ 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: 4: $::osname =~ m/darwin/ +--- skip_eval: 5: $::osname =~ m/darwin/ --- valgrind --- timeout eval: $::ExtTimeout --- load_nginx_modules: ngx_http_echo_module @@ -404,20 +429,21 @@ 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] +[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 +465,7 @@ qq{ --- no_error_log [error] [crit] +[alert] @@ -476,6 +503,7 @@ qq{ --- no_error_log [error] [crit] +[alert] @@ -498,7 +526,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 +555,7 @@ ok --- no_error_log [error] [crit] +[alert] @@ -550,6 +582,7 @@ ok --- no_error_log [error] [crit] +[alert] @@ -584,6 +617,7 @@ qq{ --- no_error_log [error] [crit] +[alert] @@ -622,6 +656,7 @@ qq{ --- no_error_log [error] [crit] +[alert] @@ -660,6 +695,7 @@ K: 11.* --- no_error_log [error] [crit] +[alert] @@ -689,6 +725,7 @@ tcp socket reading done tcp socket closing --- no_error_log [error] +[crit] @@ -717,6 +754,7 @@ tcp socket reading done tcp socket closing --- no_error_log [error] +[crit] @@ -747,6 +785,7 @@ tcp socket reading done tcp socket closing --- no_error_log [error] +[crit] @@ -770,6 +809,7 @@ Hello world --- no_error_log [error] [crit] +[alert] @@ -795,6 +835,7 @@ Content-Length: 0.* --- no_error_log [error] [crit] +[alert] @@ -822,6 +863,7 @@ Content-Length: 0.* --- no_error_log [error] [crit] +[alert] @@ -851,6 +893,7 @@ Hello world tcp socket trying to receive data (max: 1) --- no_error_log [error] +[crit] @@ -879,6 +922,7 @@ Hello world --- no_error_log [error] [crit] +[alert] @@ -907,6 +951,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 +980,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 +1011,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 +1043,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 +1066,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 +1100,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 +1124,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 +1151,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 +1205,7 @@ qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - parser --- no_error_log [error] [crit] +[alert] @@ -1183,6 +1240,7 @@ qr/^\*\d+ .*? on_http_call_response \(id: \d+[^*]* --- no_error_log [error] [crit] +[alert] @@ -1208,6 +1266,7 @@ X-Callout-Header: callout-header-value --- no_error_log [error] [crit] +[alert] @@ -1251,6 +1310,7 @@ qr/^\*\d+ .*? on_http_call_response \(id: \d+, status: 200[^*]* --- no_error_log [error] [crit] +[alert] @@ -1278,6 +1338,7 @@ helloworld --- no_error_log [error] [crit] +[alert] @@ -1305,6 +1366,7 @@ helloworl --- no_error_log [error] [crit] +[alert] @@ -1329,3 +1391,54 @@ cannot override the "Host" header, skipping cannot override the "Connection" header, skipping --- no_error_log [error] +[crit] + + + +=== 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] +[alert] + + + +=== 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_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; + } +--- 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..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 @@ -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__ @@ -31,6 +31,45 @@ qq{ location /t { wasm_socket_connect_timeout 1ms; + proxy_wasm hostcalls 'test=/t/dispatch_http_call \ + host=google.com \ + on_http_call_response=echo_response_headers'; + echo ok; + } +} +--- response_body_like +:dispatch_status: timeout +--- error_log eval +[ + qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - timed out connecting to \".*?\"/, + 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; @@ -39,13 +78,89 @@ qq{ --- response_body ok --- error_log eval -qr/(\[error\]|Uncaught RuntimeError|\s+).*?dispatch failed: tcp socket - timed out connecting to \".*?\"/ +[ + 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 @@ -65,13 +180,17 @@ 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] -=== 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 @@ -92,13 +211,17 @@ 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] -=== 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 @@ -121,13 +244,17 @@ 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] -=== 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 @@ -149,10 +276,12 @@ Hello world --- no_error_log [error] [crit] +[alert] +[emerg] -=== 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 @@ -179,3 +308,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..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] @@ -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/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/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/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/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] 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] 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..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 @@ -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/, @@ -84,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; @@ -110,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; @@ -291,6 +320,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 +337,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/, @@ -610,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; @@ -636,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; @@ -687,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; @@ -713,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; @@ -764,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; @@ -796,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; 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/, 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/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 diff --git a/t/lib/Cargo.lock b/t/lib/Cargo.lock index c1fe84706..6d61c7afa 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", ] @@ -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" @@ -184,9 +196,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" @@ -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,15 +243,15 @@ dependencies = [ "enum-utils", "http", "log", - "proxy-wasm 0.2.2", + "proxy-wasm 0.2.3-dev", "urlencoding", ] [[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 +268,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 +292,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 +319,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 +345,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", ] @@ -355,11 +378,20 @@ 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.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -369,6 +401,7 @@ name = "rust-sdk-ver-zero-one" version = "0.1.0" dependencies = [ "http", + "log", "proxy-wasm 0.1.4", ] @@ -408,9 +441,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", @@ -419,9 +452,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" @@ -538,5 +571,5 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.96", ] 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 eea6eae50..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), @@ -69,13 +70,28 @@ 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; + } else if self.tester.get_config("on_foreign_function").is_some() { + self.tester + .check_host_function("call_resolve_lua|httpbin.org"); return Action::Pause; } @@ -137,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 dad9e5d85..85bc09637 100644 --- a/t/lib/proxy-wasm-tests/hostcalls/Cargo.toml +++ b/t/lib/proxy-wasm-tests/hostcalls/Cargo.toml @@ -8,8 +8,8 @@ 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 = "0.2" +http = "1.2" enum-utils = "0.1.2" urlencoding = "2.1.2" diff --git a/t/lib/proxy-wasm-tests/hostcalls/src/filter.rs b/t/lib/proxy-wasm-tests/hostcalls/src/filter.rs index 9f771c645..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( @@ -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 { @@ -38,6 +44,7 @@ impl Context for TestHttp { "request.protocol", "request.query", "request.total_size", + "request.is_subrequest", ]; for property in properties { @@ -102,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 aaf25142d..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! {{ @@ -82,6 +83,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), _ => (), } @@ -114,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(); @@ -156,14 +177,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 + ), + }, + } } _ => (), } @@ -192,6 +222,7 @@ impl RootContext for TestRoot { on_phases: phases, metrics: self.metrics.clone(), n_sync_calls: 0, + pending_callbacks: 0, })) } } @@ -205,10 +236,29 @@ 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 => {} + } + } + + 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..c293257a6 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,12 @@ pub enum TestPhase { Log, } +#[repr(u32)] +#[allow(dead_code)] // ignore erroneous dead code warning +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 5240f512e..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" => { @@ -247,13 +268,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..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,4 +10,5 @@ crate-type = ["cdylib"] [dependencies] proxy-wasm = "0.1" -http = "0.2" +http = "1.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" => { 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) + }); +} 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 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. 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 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 diff --git a/valgrind.suppress b/valgrind.suppress index 53fd9c16d..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