diff --git a/.github/actions/build-wasm-test-filters/action.yml b/.github/actions/build-wasm-test-filters/action.yml index 420eb193d20..2682ae08458 100644 --- a/.github/actions/build-wasm-test-filters/action.yml +++ b/.github/actions/build-wasm-test-filters/action.yml @@ -41,7 +41,7 @@ runs: - name: Install Rust Toolchain if: steps.restore-cache.outputs.cache-hit != 'true' - uses: actions-rs/toolchain@v1 + uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af # v1 with: profile: minimal toolchain: stable @@ -51,7 +51,7 @@ runs: - name: cargo build if: steps.restore-cache.outputs.cache-hit != 'true' - uses: actions-rs/cargo@v1 + uses: actions-rs/cargo@844f36862e911db73fe0815f00a4a2602c279505 # v1 with: command: build # building in release mode yields smaller library sizes, so it's diff --git a/.github/workflows/label-schema.yml b/.github/workflows/label-schema.yml index 34a2ea6281a..cae5513ee6d 100644 --- a/.github/workflows/label-schema.yml +++ b/.github/workflows/label-schema.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Schema change label found - uses: rtCamp/action-slack-notify@c33737706dea87cd7784c687dadc9adf1be59990 # v2 + uses: Kong/action-slack-notify@bd750854aaf93c5c6f69799bf813c40e7786368a # v2_node20 continue-on-error: true env: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_SCHEMA_CHANGE }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f3674150428..ea71ad5e46d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -31,7 +31,7 @@ on: # yamllint disable-line rule:truthy env: # official release repo DOCKER_REPOSITORY: kong/kong - PRERELEASE_DOCKER_REPOSITORY: kong/kong + PRERELEASE_DOCKER_REPOSITORY: kong/kong-dev FULL_RELEASE: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' || github.actor == 'dependabot[bot]'}} # only for PR @@ -492,7 +492,7 @@ jobs: - name: Scan AMD64 Image digest id: sbom_action_amd64 if: steps.image_manifest_metadata.outputs.amd64_sha != '' - uses: Kong/public-shared-actions/security-actions/scan-docker-image@28d20a1f492927f35b00b317acd78f669c45f88b # v2.7.3 + uses: Kong/public-shared-actions/security-actions/scan-docker-image@a5b1cfac7d55d8cf9390456a1e6799425e28840d # v4.0.1 with: asset_prefix: kong-${{ needs.metadata.outputs.commit-sha }}-${{ matrix.label }}-linux-amd64 image: ${{ needs.metadata.outputs.prerelease-docker-repository }}:${{ needs.metadata.outputs.commit-sha }}-${{ matrix.label }} @@ -501,7 +501,7 @@ jobs: - name: Scan ARM64 Image digest if: steps.image_manifest_metadata.outputs.manifest_list_exists == 'true' && steps.image_manifest_metadata.outputs.arm64_sha != '' id: sbom_action_arm64 - uses: Kong/public-shared-actions/security-actions/scan-docker-image@28d20a1f492927f35b00b317acd78f669c45f88b # v2.7.3 + uses: Kong/public-shared-actions/security-actions/scan-docker-image@a5b1cfac7d55d8cf9390456a1e6799425e28840d # v4.0.1 with: asset_prefix: kong-${{ needs.metadata.outputs.commit-sha }}-${{ matrix.label }}-linux-arm64 image: ${{ needs.metadata.outputs.prerelease-docker-repository }}:${{ needs.metadata.outputs.commit-sha }}-${{ matrix.label }} diff --git a/.requirements b/.requirements index 2f3b704e370..3184bad98ba 100644 --- a/.requirements +++ b/.requirements @@ -4,14 +4,14 @@ OPENRESTY=1.25.3.2 OPENRESTY_SHA256=2d564022b06e33b45f7e5cfaf1e5dc571d38d61803af9fa2754dfff353c28d9c LUAROCKS=3.11.1 LUAROCKS_SHA256=c3fb3d960dffb2b2fe9de7e3cb004dc4d0b34bb3d342578af84f84325c669102 -OPENSSL=3.2.3 -OPENSSL_SHA256=52b5f1c6b8022bc5868c308c54fb77705e702d6c6f4594f99a0df216acf46239 +OPENSSL=3.4.0 +OPENSSL_SHA256=e15dda82fe2fe8139dc2ac21a36d4ca01d5313c75f99f46c4e8a27709b7294bf PCRE=10.44 PCRE_SHA256=86b9cb0aa3bcb7994faa88018292bc704cdbb708e785f7c74352ff6ea7d3175b ADA=2.9.2 ADA_SHA256=b2cce630590b490d79ea4f4460ba77efd5fb29c5a87a4e8cb7ebc4859bc4b564 -LIBEXPAT=2.6.2 -LIBEXPAT_SHA256=d4cf38d26e21a56654ffe4acd9cd5481164619626802328506a2869afab29ab3 +LIBEXPAT=2.6.4 +LIBEXPAT_SHA256=fd03b7172b3bd7427a3e7a812063f74754f24542429b634e0db6511b53fb2278 # Note: git repositories can be loaded from local path if path is set as value @@ -20,7 +20,7 @@ LUA_RESTY_LMDB=9da0e9f3313960d06e2d8e718b7ac494faa500f1 # 1.6.0 LUA_RESTY_EVENTS=bc85295b7c23eda2dbf2b4acec35c93f77b26787 # 0.3.1 LUA_RESTY_SIMDJSON=7e6466ce91b2bc763b45701a4f055e94b1e8143b # 1.1.0 LUA_RESTY_WEBSOCKET=966c69c39f03029b9b42ec0f8e55aaed7d6eebc0 # 0.4.0.1 -ATC_ROUTER=ffd11db657115769bf94f0c4f915f98300bc26b6 # 1.6.2 +ATC_ROUTER=4d29e10517e2c9d1dae3966f4034b38c557e2eaa # 1.7.1 SNAPPY=23b3286820105438c5dbb9bc22f1bb85c5812c8a # 1.2.0 KONG_MANAGER=nightly diff --git a/bin/busted b/bin/busted index e59760322fa..5be3493b056 100755 --- a/bin/busted +++ b/bin/busted @@ -64,6 +64,10 @@ if not os.getenv("KONG_BUSTED_RESPAWNED") then -- create shared dict resty_flags = resty_flags .. require("spec.fixtures.shared_dict") + -- create lmdb environment + local lmdb_env = os.tmpname() + resty_flags = resty_flags .. string.format(' --main-conf "lmdb_environment_path %s;" ', lmdb_env) + if resty_flags then table.insert(cmd, cmd_prefix_count+1, resty_flags) end diff --git a/build/libexpat/BUILD.libexpat.bazel b/build/libexpat/BUILD.libexpat.bazel index f8c57829460..a4cb3e61f90 100644 --- a/build/libexpat/BUILD.libexpat.bazel +++ b/build/libexpat/BUILD.libexpat.bazel @@ -39,7 +39,7 @@ configure_make( "libexpat.1.dylib", ], "//conditions:default": [ - "libexpat.so.1.9.2", + "libexpat.so.1.10.0", ], }), targets = [ diff --git a/build/luarocks/templates/luarocks_make.sh b/build/luarocks/templates/luarocks_make.sh index 96cbc9b90e6..19937cd2662 100644 --- a/build/luarocks/templates/luarocks_make.sh +++ b/build/luarocks/templates/luarocks_make.sh @@ -15,7 +15,7 @@ mkdir -p $(dirname $@) # alias LDOC command to true(1) command export LDOC=true -$luarocks_exec make --no-doc 2>&1 >$@.tmp +$luarocks_exec make --no-doc >$@.tmp 2>&1 # only generate the output when the command succeeds -mv $@.tmp $@ \ No newline at end of file +mv $@.tmp $@ diff --git a/build/luarocks/templates/luarocks_target.sh b/build/luarocks/templates/luarocks_target.sh index 5bc2b8717f4..eb5791abf13 100644 --- a/build/luarocks/templates/luarocks_target.sh +++ b/build/luarocks/templates/luarocks_target.sh @@ -33,7 +33,7 @@ EOF export LUAROCKS_CONFIG=$ROCKS_CONFIG $host_luajit $luarocks_wrap_script \ - luarocks $rocks_tree $install_destdir 2>&1 > $@.tmp + luarocks $rocks_tree $install_destdir > $@.tmp 2>&1 # write the luarocks config with host configuration mkdir -p $rocks_tree/etc/luarocks @@ -55,4 +55,4 @@ sed -i -e "s|$build_destdir|$install_destdir|g" $rocks_tree/bin/luarocks sed -i -e "s|$rocks_tree|$install_destdir|g" $rocks_tree/bin/luarocks # only generate the output when the command succeeds -mv $@.tmp $@ \ No newline at end of file +mv $@.tmp $@ diff --git a/build/openresty/patches/lua-resty-core-0.1.28_02-balancer_set_upstream_tls.patch b/build/openresty/patches/lua-resty-core-0.1.28_02-balancer_set_upstream_tls.patch new file mode 100644 index 00000000000..d8901a6de1d --- /dev/null +++ b/build/openresty/patches/lua-resty-core-0.1.28_02-balancer_set_upstream_tls.patch @@ -0,0 +1,205 @@ +diff --git a/bundle/lua-resty-core-0.1.28/lib/ngx/balancer.lua b/bundle/lua-resty-core-0.1.28/lib/ngx/balancer.lua +index 7d64d63..b0b7543 100644 +--- a/bundle/lua-resty-core-0.1.28/lib/ngx/balancer.lua ++++ b/bundle/lua-resty-core-0.1.28/lib/ngx/balancer.lua +@@ -22,6 +22,7 @@ local ngx_lua_ffi_balancer_set_current_peer + local ngx_lua_ffi_balancer_set_more_tries + local ngx_lua_ffi_balancer_get_last_failure + local ngx_lua_ffi_balancer_set_timeouts -- used by both stream and http ++local ngx_lua_ffi_balancer_set_upstream_tls + + + if subsystem == 'http' then +@@ -41,6 +42,8 @@ if subsystem == 'http' then + + int ngx_http_lua_ffi_balancer_recreate_request(ngx_http_request_t *r, + char **err); ++ int ngx_http_lua_ffi_balancer_set_upstream_tls(ngx_http_request_t *r, ++ int on, char **err); + ]] + + ngx_lua_ffi_balancer_set_current_peer = +@@ -55,6 +58,9 @@ if subsystem == 'http' then + ngx_lua_ffi_balancer_set_timeouts = + C.ngx_http_lua_ffi_balancer_set_timeouts + ++ ngx_lua_ffi_balancer_set_upstream_tls = ++ C.ngx_http_lua_ffi_balancer_set_upstream_tls ++ + elseif subsystem == 'stream' then + ffi.cdef[[ + int ngx_stream_lua_ffi_balancer_set_current_peer( +@@ -228,6 +234,29 @@ if subsystem == 'http' then + + return nil, "failed to recreate the upstream request" + end ++ ++ ++ function _M.set_upstream_tls(on) ++ local r = get_request() ++ if not r then ++ return error("no request found") ++ end ++ ++ local rc ++ ++ if on == 0 or on == false then ++ on = 0 ++ else ++ on = 1 ++ end ++ ++ rc = ngx_lua_ffi_balancer_set_upstream_tls(r, on, errmsg); ++ if rc == FFI_OK then ++ return true ++ end ++ ++ return nil, ffi_str(errmsg[0]) ++ end + end + + +diff --git a/bundle/lua-resty-core-0.1.28/lib/ngx/balancer.md b/bundle/lua-resty-core-0.1.28/lib/ngx/balancer.md +index ef2f124..3ec8cb9 100644 +--- a/bundle/lua-resty-core-0.1.28/lib/ngx/balancer.md ++++ b/bundle/lua-resty-core-0.1.28/lib/ngx/balancer.md +@@ -13,11 +13,12 @@ Table of Contents + * [stream subsystem](#stream-subsystem) + * [Description](#description) + * [Methods](#methods) ++ * [get_last_failure](#get_last_failure) ++ * [recreate_request](#recreate_request) + * [set_current_peer](#set_current_peer) + * [set_more_tries](#set_more_tries) +- * [get_last_failure](#get_last_failure) + * [set_timeouts](#set_timeouts) +- * [recreate_request](#recreate_request) ++ * [set_upstream_tls](#set_upstream_tls) + * [Community](#community) + * [English Mailing List](#english-mailing-list) + * [Chinese Mailing List](#chinese-mailing-list) +@@ -270,6 +271,21 @@ This function was first added in the `0.1.20` version of this library. + + [Back to TOC](#table-of-contents) + ++set_upstream_tls ++------------ ++**syntax:** `ok, err = balancer.set_upstream_tls(on)` ++ ++**context:** *balancer_by_lua** ++ ++Turn off the HTTPs or reenable the HTTPs for the upstream connection. ++ ++- If `on` is `true`, then the https protocol will be used to connect to the upstream server. ++- If `on` is `false`, then the http protocol will be used to connect to the upstream server. ++ ++This function was first added in the `0.1.29` version of this library. ++ ++[Back to TOC](#table-of-contents) ++ + Community + ========= + +diff --git a/bundle/lua-resty-core-0.1.28/t/balancer.t b/bundle/lua-resty-core-0.1.28/t/balancer.t +index 3e9fb2f..6201b47 100644 +--- a/bundle/lua-resty-core-0.1.28/t/balancer.t ++++ b/bundle/lua-resty-core-0.1.28/t/balancer.t +@@ -882,3 +882,98 @@ connect() failed (111: Connection refused) while connecting to upstream, client: + --- no_error_log + [warn] + [crit] ++ ++ ++ ++=== TEST 20: set_upstream_tls off ++--- skip_nginx: 5: < 1.7.5 ++--- http_config ++ lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; ++ ++ upstream backend { ++ server 0.0.0.1; ++ balancer_by_lua_block { ++ local b = require "ngx.balancer" ++ b.set_current_peer("127.0.0.1", tonumber(ngx.var.server_port)) ++ b.set_upstream_tls(false) ++ } ++ keepalive 1; ++ } ++ ++ server { ++ listen $TEST_NGINX_RAND_PORT_1 ssl; ++ ssl_certificate ../../cert/test.crt; ++ ssl_certificate_key ../../cert/test.key; ++ ++ server_tokens off; ++ location = /back { ++ return 200 "ok"; ++ } ++ } ++--- config ++ location /t { ++ proxy_pass https://backend/back; ++ proxy_http_version 1.1; ++ proxy_set_header Connection ""; ++ } ++ ++ location /back { ++ echo "Hello world!"; ++ } ++--- request ++ GET /t ++--- no_error_log ++[alert] ++[error] ++--- response_body ++Hello world! ++ ++--- no_check_leak ++ ++ ++ ++=== TEST 21: set_upstream_tls on ++--- skip_nginx: 5: < 1.7.5 ++--- http_config ++ lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; ++ ++ upstream backend { ++ server 0.0.0.1; ++ balancer_by_lua_block { ++ local b = require "ngx.balancer" ++ b.set_current_peer("127.0.0.1", $TEST_NGINX_RAND_PORT_1) ++ b.set_upstream_tls(false) ++ b.set_upstream_tls(true) ++ } ++ ++ keepalive 1; ++ } ++ ++ server { ++ listen $TEST_NGINX_RAND_PORT_1 ssl; ++ ssl_certificate ../../cert/test.crt; ++ ssl_certificate_key ../../cert/test.key; ++ ++ server_tokens off; ++ location = /back { ++ return 200 "ok"; ++ } ++ } ++--- config ++ location /t { ++ proxy_pass https://backend/back; ++ proxy_http_version 1.1; ++ proxy_set_header Connection ""; ++ } ++ ++ location /back { ++ echo "Hello world!"; ++ } ++--- request ++ GET /t ++--- no_error_log ++[alert] ++[error] ++--- response_body chomp ++ok ++--- no_check_leak diff --git a/build/openresty/patches/nginx-1.25.3_09-refresh-uri-when-proxy-pass-balancer-recreate.patch b/build/openresty/patches/nginx-1.25.3_09-refresh-uri-when-proxy-pass-balancer-recreate.patch new file mode 100644 index 00000000000..16b9da26758 --- /dev/null +++ b/build/openresty/patches/nginx-1.25.3_09-refresh-uri-when-proxy-pass-balancer-recreate.patch @@ -0,0 +1,27 @@ +diff --git a/bundle/nginx-1.25.3/src/http/modules/ngx_http_proxy_module.c b/bundle/nginx-1.25.3/src/http/modules/ngx_http_proxy_module.c +index 4eb6931..9d38e6b 100644 +--- a/bundle/nginx-1.25.3/src/http/modules/ngx_http_proxy_module.c ++++ b/bundle/nginx-1.25.3/src/http/modules/ngx_http_proxy_module.c +@@ -1277,6 +1277,22 @@ ngx_http_proxy_create_request(ngx_http_request_t *r) + + ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module); + ++ // make sure we refresh the proxy upstream uri in balancer retry scenarios ++ if (r->upstream_states && r->upstream_states->nelts > 0) { ++ if (plcf->proxy_lengths == NULL) { ++ ctx->vars = plcf->vars; ++ u->schema = plcf->vars.schema; ++ #if (NGX_HTTP_SSL) ++ u->ssl = plcf->ssl; ++ #endif ++ ++ } else { ++ if (ngx_http_proxy_eval(r, ctx, plcf) != NGX_OK) { ++ return NGX_HTTP_INTERNAL_SERVER_ERROR; ++ } ++ } ++ } ++ + if (method.len == 4 + && ngx_strncasecmp(method.data, (u_char *) "HEAD", 4) == 0) + { diff --git a/build/openresty/patches/ngx_lua-0.10.26_08-balancer_set_upstream_tls.patch b/build/openresty/patches/ngx_lua-0.10.26_08-balancer_set_upstream_tls.patch new file mode 100644 index 00000000000..24f7fcb78ee --- /dev/null +++ b/build/openresty/patches/ngx_lua-0.10.26_08-balancer_set_upstream_tls.patch @@ -0,0 +1,51 @@ +diff --git a/bundle/ngx_lua-0.10.26/src/ngx_http_lua_balancer.c b/bundle/ngx_lua-0.10.26/src/ngx_http_lua_balancer.c +index af4da73..f119948 100644 +--- a/bundle/ngx_lua-0.10.26/src/ngx_http_lua_balancer.c ++++ b/bundle/ngx_lua-0.10.26/src/ngx_http_lua_balancer.c +@@ -808,5 +808,46 @@ ngx_http_lua_ffi_balancer_recreate_request(ngx_http_request_t *r, + return u->create_request(r); + } + ++int ++ngx_http_lua_ffi_balancer_set_upstream_tls(ngx_http_request_t *r, int on, ++ char **err) ++{ ++ ngx_http_lua_ctx_t *ctx; ++ ngx_http_upstream_t *u; ++ ++ if (r == NULL) { ++ *err = "no request found"; ++ return NGX_ERROR; ++ } ++ ++ u = r->upstream; ++ ++ if (u == NULL) { ++ *err = "no upstream found"; ++ return NGX_ERROR; ++ } ++ ++ ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); ++ if (ctx == NULL) { ++ *err = "no ctx found"; ++ return NGX_ERROR; ++ } ++ ++ if ((ctx->context & NGX_HTTP_LUA_CONTEXT_BALANCER) == 0) { ++ *err = "API disabled in the current context"; ++ return NGX_ERROR; ++ } ++ ++ if (on == 0) { ++ u->ssl = 0; ++ u->schema.len = sizeof("http://") - 1; ++ ++ } else { ++ u->ssl = 1; ++ u->schema.len = sizeof("https://") - 1; ++ } ++ ++ return NGX_OK; ++} + + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/changelog/unreleased/kong/backport-resty-balancer-set-upstream.yml b/changelog/unreleased/kong/backport-resty-balancer-set-upstream.yml new file mode 100644 index 00000000000..956fb6e654c --- /dev/null +++ b/changelog/unreleased/kong/backport-resty-balancer-set-upstream.yml @@ -0,0 +1,3 @@ +message: backport balancer.set_upstream_tls feature from openresty upstream [openresty/lua-resty-core#460](https://github.com/openresty/lua-resty-core/pull/460) +type: feature +scope: Core diff --git a/changelog/unreleased/kong/bump-atc-router.yml b/changelog/unreleased/kong/bump-atc-router.yml new file mode 100644 index 00000000000..1f5d045155a --- /dev/null +++ b/changelog/unreleased/kong/bump-atc-router.yml @@ -0,0 +1,5 @@ +message: > + Bumped atc-router from v1.6.2 to v1.7.1. + This release contains dependencies upgrade and new interface for validating expressions. +type: dependency +scope: Core diff --git a/changelog/unreleased/kong/bump-libexpat-to-2_6_4.yml b/changelog/unreleased/kong/bump-libexpat-to-2_6_4.yml new file mode 100644 index 00000000000..862b1d8531b --- /dev/null +++ b/changelog/unreleased/kong/bump-libexpat-to-2_6_4.yml @@ -0,0 +1,3 @@ +message: Bumped libexpat from 2.6.2 to 2.6.4 to fix a crash in the XML_ResumeParser function caused by XML_StopParser stopping an uninitialized parser. +type: dependency +scope: Core diff --git a/changelog/unreleased/kong/bump_openssl.yml b/changelog/unreleased/kong/bump_openssl.yml new file mode 100644 index 00000000000..3c89957ca75 --- /dev/null +++ b/changelog/unreleased/kong/bump_openssl.yml @@ -0,0 +1,3 @@ +message: "Bumped OpenSSL to 3.4.0." +type: dependency +scope: Core \ No newline at end of file diff --git a/changelog/unreleased/kong/dynamic-set-tls-in-pdk-set_scheme.yml b/changelog/unreleased/kong/dynamic-set-tls-in-pdk-set_scheme.yml new file mode 100644 index 00000000000..1cc1b3edf55 --- /dev/null +++ b/changelog/unreleased/kong/dynamic-set-tls-in-pdk-set_scheme.yml @@ -0,0 +1,3 @@ +message: dynamic control upstream tls when kong.service.request.set_scheme was called +type: feature +scope: PDK diff --git a/changelog/unreleased/kong/fix-ai-analytics-key.yml b/changelog/unreleased/kong/fix-ai-analytics-key.yml new file mode 100644 index 00000000000..3ad3f607ab4 --- /dev/null +++ b/changelog/unreleased/kong/fix-ai-analytics-key.yml @@ -0,0 +1,6 @@ +message: | + **AI Plugins**: Changed the serialized log key of AI metrics from `ai.ai-proxy` to `ai.proxy`, to avoid conflicts with metrics + generated from plugins other than AI Proxy and AI Proxy Advanced. Users using logging plugins like file-log, http-log, etc. would + except to update metrics pipeline configurations to reflect this change. +type: breaking_change +scope: Plugin diff --git a/changelog/unreleased/kong/fix-ai-azure-incorrect-path-overriding.yml b/changelog/unreleased/kong/fix-ai-azure-incorrect-path-overriding.yml new file mode 100644 index 00000000000..442816185f6 --- /dev/null +++ b/changelog/unreleased/kong/fix-ai-azure-incorrect-path-overriding.yml @@ -0,0 +1,3 @@ +message: "**ai-proxy**: Fixed a bug in the Azure provider where `model.options.upstream_path` overrides would always return 404." +type: bugfix +scope: Plugin diff --git a/changelog/unreleased/kong/fix-ai-azure-streaming.yml b/changelog/unreleased/kong/fix-ai-azure-streaming.yml new file mode 100644 index 00000000000..3068b36855e --- /dev/null +++ b/changelog/unreleased/kong/fix-ai-azure-streaming.yml @@ -0,0 +1,3 @@ +message: "**ai-proxy**: Fixed a bug where Azure streaming responses would be missing individual tokens." +type: bugfix +scope: Plugin diff --git a/changelog/unreleased/kong/fix-consistent-hashing-for-hyphenated-pascal-case-headers.yml b/changelog/unreleased/kong/fix-consistent-hashing-for-hyphenated-pascal-case-headers.yml new file mode 100644 index 00000000000..e1de444b3c3 --- /dev/null +++ b/changelog/unreleased/kong/fix-consistent-hashing-for-hyphenated-pascal-case-headers.yml @@ -0,0 +1,3 @@ +message: "Fixed an issue where consistent hashing did not correctly handle hyphenated-Pascal-case headers, leading to uneven distribution of requests across upstream targets." +type: bugfix +scope: Core diff --git a/changelog/unreleased/kong/fix-declarative-config-load.yml b/changelog/unreleased/kong/fix-declarative-config-load.yml new file mode 100644 index 00000000000..0c6ddeed81e --- /dev/null +++ b/changelog/unreleased/kong/fix-declarative-config-load.yml @@ -0,0 +1,3 @@ +message: "Fixed an issue where a valid declarative config with certificate/sni entities cannot be loaded in dbless mode" +type: bugfix +scope: Core diff --git a/changelog/unreleased/kong/fix-header_cache.yml b/changelog/unreleased/kong/fix-header_cache.yml new file mode 100644 index 00000000000..a35547dd4dd --- /dev/null +++ b/changelog/unreleased/kong/fix-header_cache.yml @@ -0,0 +1,3 @@ +message: "**grpc-web** and **grpc-gateway**: Fixed a bug where the `TE` (transfer-encoding) header would not be sent to the upstream gRPC servers when `grpc-web` or `grpc-gateweay` are in use." +type: bugfix +scope: Plugin diff --git a/changelog/unreleased/kong/fix-upstream-keep-alive-pool-name.yml b/changelog/unreleased/kong/fix-upstream-keep-alive-pool-name.yml new file mode 100644 index 00000000000..6a9eb50b1cb --- /dev/null +++ b/changelog/unreleased/kong/fix-upstream-keep-alive-pool-name.yml @@ -0,0 +1,3 @@ +message: Fixed an issue where `tls_verify`, `tls_verify_depth` and `ca_certificates` of a service were not included in the upstream keepalive pool name. +type: bugfix +scope: Core diff --git a/changelog/unreleased/kong/fix_file_path_not_allowed_whitespace.yml b/changelog/unreleased/kong/fix_file_path_not_allowed_whitespace.yml new file mode 100644 index 00000000000..c00ed8dc39e --- /dev/null +++ b/changelog/unreleased/kong/fix_file_path_not_allowed_whitespace.yml @@ -0,0 +1,3 @@ +message: "**file-log**: Fixed an issue where an error would occur when there were spaces at the beginning or end of a path." +type: bugfix +scope: Plugin \ No newline at end of file diff --git a/changelog/unreleased/kong/upstream-uri-refresh-when-recreate-request.yml b/changelog/unreleased/kong/upstream-uri-refresh-when-recreate-request.yml new file mode 100644 index 00000000000..e191bed6015 --- /dev/null +++ b/changelog/unreleased/kong/upstream-uri-refresh-when-recreate-request.yml @@ -0,0 +1,3 @@ +message: refresh upstream uri variable when proxy pass balancer recreate +type: feature +scope: Core diff --git a/crate_locks/README.md b/crate_locks/README.md index e18d5c52fb3..3f4d2ecee1a 100644 --- a/crate_locks/README.md +++ b/crate_locks/README.md @@ -14,7 +14,7 @@ please check out the [rules_rust](https://github.com/bazelbuild/rules_rust). ```bash crates="atc_router_crate_index" -CARGO_BAZEL_REPIN=1 CARGO_BAZEL_REPIN_ONLY=$scrates bazel sync --only=$crates +CARGO_BAZEL_REPIN=1 CARGO_BAZEL_REPIN_ONLY=$crates bazel sync --only=$crates unset crates ``` diff --git a/crate_locks/atc_router.Cargo.lock b/crate_locks/atc_router.Cargo.lock index 364cfae6183..95f330be1f4 100644 --- a/crate_locks/atc_router.Cargo.lock +++ b/crate_locks/atc_router.Cargo.lock @@ -11,11 +11,25 @@ dependencies = [ "memchr", ] +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + [[package]] name = "atc-router" -version = "1.6.1" +version = "1.7.1" dependencies = [ + "bitflags", "cidr", + "criterion", "fnv", "lazy_static", "pest", @@ -26,6 +40,18 @@ dependencies = [ "uuid", ] +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "bitflags" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1be3f42a67d6d345ecd59f675f3f012d6974981560836e938c22b424b85ce1be" + [[package]] name = "block-buffer" version = "0.10.4" @@ -35,21 +61,85 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + [[package]] name = "cidr" -version = "0.2.3" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdf600c45bd958cf2945c445264471cca8b6c8e67bc87b71affd6d7e5682621" +checksum = "bfc95a0c21d5409adc146dbbb152b5c65aaea32bc2d2f57cf12f850bffdd7ab8" dependencies = [ "serde", ] +[[package]] +name = "clap" +version = "4.5.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8eb5e908ef3a6efbe1ed62520fb7287959888c88485abe072543190ecc66783" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.5.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b01801b5fc6a0a232407abc821660c9c6d25a1cafc0d4f85f29fb8d9afc121" +dependencies = [ + "anstyle", + "clap_lex", +] + +[[package]] +name = "clap_lex" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" + [[package]] name = "cpufeatures" version = "0.2.15" @@ -59,6 +149,73 @@ dependencies = [ "libc", ] +[[package]] +name = "criterion" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" +dependencies = [ + "anes", + "cast", + "ciborium", + "clap", + "criterion-plot", + "is-terminal", + "itertools", + "num-traits", + "once_cell", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "crypto-common" version = "0.1.6" @@ -79,6 +236,12 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + [[package]] name = "fnv" version = "1.0.7" @@ -95,6 +258,58 @@ dependencies = [ "version_check", ] +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] + +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + +[[package]] +name = "is-terminal" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" + +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -107,18 +322,39 @@ version = "0.2.164" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + [[package]] name = "once_cell" version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +[[package]] +name = "oorandom" +version = "11.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" + [[package]] name = "pest" version = "2.7.14" @@ -164,6 +400,34 @@ dependencies = [ "sha2", ] +[[package]] +name = "plotters" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" + +[[package]] +name = "plotters-svg" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" +dependencies = [ + "plotters-backend", +] + [[package]] name = "proc-macro2" version = "1.0.91" @@ -182,6 +446,26 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "regex" version = "1.11.1" @@ -211,6 +495,27 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "rustversion" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "serde" version = "1.0.215" @@ -231,6 +536,18 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.135" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + [[package]] name = "serde_regex" version = "1.1.0" @@ -283,6 +600,16 @@ dependencies = [ "syn", ] +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "typenum" version = "1.17.0" @@ -312,3 +639,172 @@ name = "version_check" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/crate_locks/atc_router.lock b/crate_locks/atc_router.lock index 9c41fe7d8f5..5fef87b3422 100644 --- a/crate_locks/atc_router.lock +++ b/crate_locks/atc_router.lock @@ -1,5 +1,5 @@ { - "checksum": "a9a20974f77d4fa9001e79b35a202afc62efc5de414664912c347ea3475fe888", + "checksum": "ff5178156a137a833a65ad66d777f2f2625ee6264ffb7651c5a4ed3c3f10215c", "crates": { "aho-corasick 1.1.3": { "name": "aho-corasick", @@ -56,9 +56,100 @@ ], "license_file": "LICENSE-MIT" }, - "atc-router 1.6.1": { + "anes 0.1.6": { + "name": "anes", + "version": "0.1.6", + "package_url": "https://github.com/zrzka/anes-rs", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/anes/0.1.6/download", + "sha256": "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + } + }, + "targets": [ + { + "Library": { + "crate_name": "anes", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "anes", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "default" + ], + "selects": {} + }, + "edition": "2018", + "version": "0.1.6" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": null + }, + "anstyle 1.0.10": { + "name": "anstyle", + "version": "1.0.10", + "package_url": "https://github.com/rust-cli/anstyle.git", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/anstyle/1.0.10/download", + "sha256": "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + } + }, + "targets": [ + { + "Library": { + "crate_name": "anstyle", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "anstyle", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "default", + "std" + ], + "selects": {} + }, + "edition": "2021", + "version": "1.0.10" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "atc-router 1.7.1": { "name": "atc-router", - "version": "1.6.1", + "version": "1.7.1", "package_url": "https://github.com/Kong/atc-router", "repository": null, "targets": [ @@ -90,7 +181,11 @@ "deps": { "common": [ { - "id": "cidr 0.2.3", + "id": "bitflags 2.7.0", + "target": "bitflags" + }, + { + "id": "cidr 0.3.0", "target": "cidr" }, { @@ -116,6 +211,15 @@ ], "selects": {} }, + "deps_dev": { + "common": [ + { + "id": "criterion 0.5.1", + "target": "criterion" + } + ], + "selects": {} + }, "edition": "2021", "proc_macro_deps": { "common": [ @@ -126,7 +230,7 @@ ], "selects": {} }, - "version": "1.6.1" + "version": "1.7.1" }, "license": "Apache-2.0", "license_ids": [ @@ -134,20 +238,20 @@ ], "license_file": null }, - "block-buffer 0.10.4": { - "name": "block-buffer", - "version": "0.10.4", - "package_url": "https://github.com/RustCrypto/utils", + "autocfg 1.4.0": { + "name": "autocfg", + "version": "1.4.0", + "package_url": "https://github.com/cuviper/autocfg", "repository": { "Http": { - "url": "https://static.crates.io/crates/block-buffer/0.10.4/download", - "sha256": "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" + "url": "https://static.crates.io/crates/autocfg/1.4.0/download", + "sha256": "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" } }, "targets": [ { "Library": { - "crate_name": "block_buffer", + "crate_name": "autocfg", "crate_root": "src/lib.rs", "srcs": { "allow_empty": false, @@ -158,44 +262,35 @@ } } ], - "library_target_name": "block_buffer", + "library_target_name": "autocfg", "common_attrs": { "compile_data_glob": [ "**" ], - "deps": { - "common": [ - { - "id": "generic-array 0.14.7", - "target": "generic_array" - } - ], - "selects": {} - }, - "edition": "2018", - "version": "0.10.4" + "edition": "2015", + "version": "1.4.0" }, - "license": "MIT OR Apache-2.0", + "license": "Apache-2.0 OR MIT", "license_ids": [ "Apache-2.0", "MIT" ], "license_file": "LICENSE-APACHE" }, - "cfg-if 1.0.0": { - "name": "cfg-if", - "version": "1.0.0", - "package_url": "https://github.com/alexcrichton/cfg-if", + "bitflags 2.7.0": { + "name": "bitflags", + "version": "2.7.0", + "package_url": "https://github.com/bitflags/bitflags", "repository": { "Http": { - "url": "https://static.crates.io/crates/cfg-if/1.0.0/download", - "sha256": "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + "url": "https://static.crates.io/crates/bitflags/2.7.0/download", + "sha256": "1be3f42a67d6d345ecd59f675f3f012d6974981560836e938c22b424b85ce1be" } }, "targets": [ { "Library": { - "crate_name": "cfg_if", + "crate_name": "bitflags", "crate_root": "src/lib.rs", "srcs": { "allow_empty": false, @@ -206,35 +301,35 @@ } } ], - "library_target_name": "cfg_if", + "library_target_name": "bitflags", "common_attrs": { "compile_data_glob": [ "**" ], - "edition": "2018", - "version": "1.0.0" + "edition": "2021", + "version": "2.7.0" }, - "license": "MIT/Apache-2.0", + "license": "MIT OR Apache-2.0", "license_ids": [ "Apache-2.0", "MIT" ], "license_file": "LICENSE-APACHE" }, - "cidr 0.2.3": { - "name": "cidr", - "version": "0.2.3", - "package_url": "https://github.com/stbuehler/rust-cidr", + "block-buffer 0.10.4": { + "name": "block-buffer", + "version": "0.10.4", + "package_url": "https://github.com/RustCrypto/utils", "repository": { "Http": { - "url": "https://static.crates.io/crates/cidr/0.2.3/download", - "sha256": "6bdf600c45bd958cf2945c445264471cca8b6c8e67bc87b71affd6d7e5682621" + "url": "https://static.crates.io/crates/block-buffer/0.10.4/download", + "sha256": "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" } }, "targets": [ { "Library": { - "crate_name": "cidr", + "crate_name": "block_buffer", "crate_root": "src/lib.rs", "srcs": { "allow_empty": false, @@ -245,41 +340,44 @@ } } ], - "library_target_name": "cidr", + "library_target_name": "block_buffer", "common_attrs": { "compile_data_glob": [ "**" ], - "crate_features": { + "deps": { "common": [ - "default", - "std" + { + "id": "generic-array 0.14.7", + "target": "generic_array" + } ], "selects": {} }, "edition": "2018", - "version": "0.2.3" + "version": "0.10.4" }, - "license": "MIT", + "license": "MIT OR Apache-2.0", "license_ids": [ + "Apache-2.0", "MIT" ], - "license_file": "LICENSE" + "license_file": "LICENSE-APACHE" }, - "cpufeatures 0.2.15": { - "name": "cpufeatures", - "version": "0.2.15", - "package_url": "https://github.com/RustCrypto/utils", + "bumpalo 3.16.0": { + "name": "bumpalo", + "version": "3.16.0", + "package_url": "https://github.com/fitzgen/bumpalo", "repository": { "Http": { - "url": "https://static.crates.io/crates/cpufeatures/0.2.15/download", - "sha256": "0ca741a962e1b0bff6d724a1a0958b686406e853bb14061f218562e1896f95e6" + "url": "https://static.crates.io/crates/bumpalo/3.16.0/download", + "sha256": "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" } }, "targets": [ { "Library": { - "crate_name": "cpufeatures", + "crate_name": "bumpalo", "crate_root": "src/lib.rs", "srcs": { "allow_empty": false, @@ -290,42 +388,19 @@ } } ], - "library_target_name": "cpufeatures", + "library_target_name": "bumpalo", "common_attrs": { "compile_data_glob": [ "**" ], - "deps": { - "common": [], - "selects": { - "aarch64-linux-android": [ - { - "id": "libc 0.2.164", - "target": "libc" - } - ], - "cfg(all(target_arch = \"aarch64\", target_os = \"linux\"))": [ - { - "id": "libc 0.2.164", - "target": "libc" - } - ], - "cfg(all(target_arch = \"aarch64\", target_vendor = \"apple\"))": [ - { - "id": "libc 0.2.164", - "target": "libc" - } - ], - "cfg(all(target_arch = \"loongarch64\", target_os = \"linux\"))": [ - { - "id": "libc 0.2.164", - "target": "libc" - } - ] - } + "crate_features": { + "common": [ + "default" + ], + "selects": {} }, - "edition": "2018", - "version": "0.2.15" + "edition": "2021", + "version": "3.16.0" }, "license": "MIT OR Apache-2.0", "license_ids": [ @@ -334,20 +409,20 @@ ], "license_file": "LICENSE-APACHE" }, - "crypto-common 0.1.6": { - "name": "crypto-common", - "version": "0.1.6", - "package_url": "https://github.com/RustCrypto/traits", + "cast 0.3.0": { + "name": "cast", + "version": "0.3.0", + "package_url": "https://github.com/japaric/cast.rs", "repository": { "Http": { - "url": "https://static.crates.io/crates/crypto-common/0.1.6/download", - "sha256": "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" + "url": "https://static.crates.io/crates/cast/0.3.0/download", + "sha256": "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" } }, "targets": [ { "Library": { - "crate_name": "crypto_common", + "crate_name": "cast", "crate_root": "src/lib.rs", "srcs": { "allow_empty": false, @@ -358,26 +433,13 @@ } } ], - "library_target_name": "crypto_common", + "library_target_name": "cast", "common_attrs": { "compile_data_glob": [ "**" ], - "deps": { - "common": [ - { - "id": "generic-array 0.14.7", - "target": "generic_array" - }, - { - "id": "typenum 1.17.0", - "target": "typenum" - } - ], - "selects": {} - }, "edition": "2018", - "version": "0.1.6" + "version": "0.3.0" }, "license": "MIT OR Apache-2.0", "license_ids": [ @@ -386,20 +448,20 @@ ], "license_file": "LICENSE-APACHE" }, - "digest 0.10.7": { - "name": "digest", - "version": "0.10.7", - "package_url": "https://github.com/RustCrypto/traits", + "cfg-if 1.0.0": { + "name": "cfg-if", + "version": "1.0.0", + "package_url": "https://github.com/alexcrichton/cfg-if", "repository": { "Http": { - "url": "https://static.crates.io/crates/digest/0.10.7/download", - "sha256": "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" + "url": "https://static.crates.io/crates/cfg-if/1.0.0/download", + "sha256": "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" } }, "targets": [ { "Library": { - "crate_name": "digest", + "crate_name": "cfg_if", "crate_root": "src/lib.rs", "srcs": { "allow_empty": false, @@ -410,57 +472,36 @@ } } ], - "library_target_name": "digest", + "library_target_name": "cfg_if", "common_attrs": { "compile_data_glob": [ "**" ], - "crate_features": { - "common": [ - "block-buffer", - "core-api", - "default" - ], - "selects": {} - }, - "deps": { - "common": [ - { - "id": "block-buffer 0.10.4", - "target": "block_buffer" - }, - { - "id": "crypto-common 0.1.6", - "target": "crypto_common" - } - ], - "selects": {} - }, "edition": "2018", - "version": "0.10.7" + "version": "1.0.0" }, - "license": "MIT OR Apache-2.0", + "license": "MIT/Apache-2.0", "license_ids": [ "Apache-2.0", "MIT" ], "license_file": "LICENSE-APACHE" }, - "fnv 1.0.7": { - "name": "fnv", - "version": "1.0.7", - "package_url": "https://github.com/servo/rust-fnv", + "ciborium 0.2.2": { + "name": "ciborium", + "version": "0.2.2", + "package_url": "https://github.com/enarx/ciborium", "repository": { "Http": { - "url": "https://static.crates.io/crates/fnv/1.0.7/download", - "sha256": "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + "url": "https://static.crates.io/crates/ciborium/0.2.2/download", + "sha256": "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" } }, "targets": [ { "Library": { - "crate_name": "fnv", - "crate_root": "lib.rs", + "crate_name": "ciborium", + "crate_root": "src/lib.rs", "srcs": { "allow_empty": false, "include": [ @@ -470,7 +511,7 @@ } } ], - "library_target_name": "fnv", + "library_target_name": "ciborium", "common_attrs": { "compile_data_glob": [ "**" @@ -482,113 +523,46 @@ ], "selects": {} }, - "edition": "2015", - "version": "1.0.7" - }, - "license": "Apache-2.0 / MIT", - "license_ids": [ - "Apache-2.0", - "MIT" - ], - "license_file": "LICENSE-APACHE" - }, - "generic-array 0.14.7": { - "name": "generic-array", - "version": "0.14.7", - "package_url": "https://github.com/fizyk20/generic-array.git", - "repository": { - "Http": { - "url": "https://static.crates.io/crates/generic-array/0.14.7/download", - "sha256": "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" - } - }, - "targets": [ - { - "Library": { - "crate_name": "generic_array", - "crate_root": "src/lib.rs", - "srcs": { - "allow_empty": false, - "include": [ - "**/*.rs" - ] - } - } - }, - { - "BuildScript": { - "crate_name": "build_script_build", - "crate_root": "build.rs", - "srcs": { - "allow_empty": false, - "include": [ - "**/*.rs" - ] - } - } - } - ], - "library_target_name": "generic_array", - "common_attrs": { - "compile_data_glob": [ - "**" - ], - "crate_features": { - "common": [ - "more_lengths" - ], - "selects": {} - }, "deps": { "common": [ { - "id": "generic-array 0.14.7", - "target": "build_script_build" + "id": "ciborium-io 0.2.2", + "target": "ciborium_io" }, { - "id": "typenum 1.17.0", - "target": "typenum" - } - ], - "selects": {} - }, - "edition": "2015", - "version": "0.14.7" - }, - "build_script_attrs": { - "data_glob": [ - "**" - ], - "deps": { - "common": [ + "id": "ciborium-ll 0.2.2", + "target": "ciborium_ll" + }, { - "id": "version_check 0.9.5", - "target": "version_check" + "id": "serde 1.0.215", + "target": "serde" } ], "selects": {} - } + }, + "edition": "2021", + "version": "0.2.2" }, - "license": "MIT", + "license": "Apache-2.0", "license_ids": [ - "MIT" + "Apache-2.0" ], "license_file": "LICENSE" }, - "lazy_static 1.5.0": { - "name": "lazy_static", - "version": "1.5.0", - "package_url": "https://github.com/rust-lang-nursery/lazy-static.rs", + "ciborium-io 0.2.2": { + "name": "ciborium-io", + "version": "0.2.2", + "package_url": "https://github.com/enarx/ciborium", "repository": { "Http": { - "url": "https://static.crates.io/crates/lazy_static/1.5.0/download", - "sha256": "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + "url": "https://static.crates.io/crates/ciborium-io/0.2.2/download", + "sha256": "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" } }, "targets": [ { "Library": { - "crate_name": "lazy_static", + "crate_name": "ciborium_io", "crate_root": "src/lib.rs", "srcs": { "allow_empty": false, @@ -599,35 +573,41 @@ } } ], - "library_target_name": "lazy_static", + "library_target_name": "ciborium_io", "common_attrs": { "compile_data_glob": [ "**" ], - "edition": "2015", - "version": "1.5.0" + "crate_features": { + "common": [ + "alloc", + "std" + ], + "selects": {} + }, + "edition": "2021", + "version": "0.2.2" }, - "license": "MIT OR Apache-2.0", + "license": "Apache-2.0", "license_ids": [ - "Apache-2.0", - "MIT" + "Apache-2.0" ], - "license_file": "LICENSE-APACHE" + "license_file": "LICENSE" }, - "libc 0.2.164": { - "name": "libc", - "version": "0.2.164", - "package_url": "https://github.com/rust-lang/libc", + "ciborium-ll 0.2.2": { + "name": "ciborium-ll", + "version": "0.2.2", + "package_url": "https://github.com/enarx/ciborium", "repository": { "Http": { - "url": "https://static.crates.io/crates/libc/0.2.164/download", - "sha256": "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" + "url": "https://static.crates.io/crates/ciborium-ll/0.2.2/download", + "sha256": "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" } }, "targets": [ { "Library": { - "crate_name": "libc", + "crate_name": "ciborium_ll", "crate_root": "src/lib.rs", "srcs": { "allow_empty": false, @@ -636,70 +616,49 @@ ] } } - }, - { - "BuildScript": { - "crate_name": "build_script_build", - "crate_root": "build.rs", - "srcs": { - "allow_empty": false, - "include": [ - "**/*.rs" - ] - } - } } ], - "library_target_name": "libc", + "library_target_name": "ciborium_ll", "common_attrs": { "compile_data_glob": [ "**" ], - "crate_features": { - "common": [ - "default", - "std" - ], - "selects": {} - }, "deps": { "common": [ { - "id": "libc 0.2.164", - "target": "build_script_build" + "id": "ciborium-io 0.2.2", + "target": "ciborium_io" + }, + { + "id": "half 2.4.1", + "target": "half" } ], "selects": {} }, - "edition": "2015", - "version": "0.2.164" - }, - "build_script_attrs": { - "data_glob": [ - "**" - ] + "edition": "2021", + "version": "0.2.2" }, - "license": "MIT OR Apache-2.0", + "license": "Apache-2.0", "license_ids": [ - "Apache-2.0", - "MIT" + "Apache-2.0" ], - "license_file": "LICENSE-APACHE" + "license_file": "LICENSE" }, - "memchr 2.7.4": { - "name": "memchr", - "version": "2.7.4", - "package_url": "https://github.com/BurntSushi/memchr", + "cidr 0.3.0": { + "name": "cidr", + "version": "0.3.0", + "package_url": "https://github.com/stbuehler/rust-cidr", "repository": { "Http": { - "url": "https://static.crates.io/crates/memchr/2.7.4/download", - "sha256": "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + "url": "https://static.crates.io/crates/cidr/0.3.0/download", + "sha256": "bfc95a0c21d5409adc146dbbb152b5c65aaea32bc2d2f57cf12f850bffdd7ab8" } }, "targets": [ { "Library": { - "crate_name": "memchr", + "crate_name": "cidr", "crate_root": "src/lib.rs", "srcs": { "allow_empty": false, @@ -710,43 +669,41 @@ } } ], - "library_target_name": "memchr", + "library_target_name": "cidr", "common_attrs": { "compile_data_glob": [ "**" ], "crate_features": { "common": [ - "alloc", "default", "std" ], "selects": {} }, "edition": "2021", - "version": "2.7.4" + "version": "0.3.0" }, - "license": "Unlicense OR MIT", + "license": "MIT", "license_ids": [ - "MIT", - "Unlicense" + "MIT" ], - "license_file": "LICENSE-MIT" + "license_file": "LICENSE" }, - "once_cell 1.20.2": { - "name": "once_cell", - "version": "1.20.2", - "package_url": "https://github.com/matklad/once_cell", + "clap 4.5.26": { + "name": "clap", + "version": "4.5.26", + "package_url": "https://github.com/clap-rs/clap", "repository": { "Http": { - "url": "https://static.crates.io/crates/once_cell/1.20.2/download", - "sha256": "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + "url": "https://static.crates.io/crates/clap/4.5.26/download", + "sha256": "a8eb5e908ef3a6efbe1ed62520fb7287959888c88485abe072543190ecc66783" } }, "targets": [ { "Library": { - "crate_name": "once_cell", + "crate_name": "clap", "crate_root": "src/lib.rs", "srcs": { "allow_empty": false, @@ -757,22 +714,28 @@ } } ], - "library_target_name": "once_cell", + "library_target_name": "clap", "common_attrs": { "compile_data_glob": [ "**" ], "crate_features": { "common": [ - "alloc", - "default", - "race", "std" ], "selects": {} }, + "deps": { + "common": [ + { + "id": "clap_builder 4.5.26", + "target": "clap_builder" + } + ], + "selects": {} + }, "edition": "2021", - "version": "1.20.2" + "version": "4.5.26" }, "license": "MIT OR Apache-2.0", "license_ids": [ @@ -781,20 +744,20 @@ ], "license_file": "LICENSE-APACHE" }, - "pest 2.7.14": { - "name": "pest", - "version": "2.7.14", - "package_url": "https://github.com/pest-parser/pest", + "clap_builder 4.5.26": { + "name": "clap_builder", + "version": "4.5.26", + "package_url": "https://github.com/clap-rs/clap", "repository": { "Http": { - "url": "https://static.crates.io/crates/pest/2.7.14/download", - "sha256": "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" + "url": "https://static.crates.io/crates/clap_builder/4.5.26/download", + "sha256": "96b01801b5fc6a0a232407abc821660c9c6d25a1cafc0d4f85f29fb8d9afc121" } }, "targets": [ { "Library": { - "crate_name": "pest", + "crate_name": "clap_builder", "crate_root": "src/lib.rs", "srcs": { "allow_empty": false, @@ -805,15 +768,13 @@ } } ], - "library_target_name": "pest", + "library_target_name": "clap_builder", "common_attrs": { "compile_data_glob": [ "**" ], "crate_features": { "common": [ - "default", - "memchr", "std" ], "selects": {} @@ -821,22 +782,18 @@ "deps": { "common": [ { - "id": "memchr 2.7.4", - "target": "memchr" - }, - { - "id": "thiserror 1.0.69", - "target": "thiserror" + "id": "anstyle 1.0.10", + "target": "anstyle" }, { - "id": "ucd-trie 0.1.7", - "target": "ucd_trie" + "id": "clap_lex 0.7.4", + "target": "clap_lex" } ], "selects": {} }, "edition": "2021", - "version": "2.7.14" + "version": "4.5.26" }, "license": "MIT OR Apache-2.0", "license_ids": [ @@ -845,20 +802,20 @@ ], "license_file": "LICENSE-APACHE" }, - "pest_derive 2.7.14": { - "name": "pest_derive", - "version": "2.7.14", - "package_url": "https://github.com/pest-parser/pest", + "clap_lex 0.7.4": { + "name": "clap_lex", + "version": "0.7.4", + "package_url": "https://github.com/clap-rs/clap", "repository": { "Http": { - "url": "https://static.crates.io/crates/pest_derive/2.7.14/download", - "sha256": "d214365f632b123a47fd913301e14c946c61d1c183ee245fa76eb752e59a02dd" + "url": "https://static.crates.io/crates/clap_lex/0.7.4/download", + "sha256": "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" } }, "targets": [ { - "ProcMacro": { - "crate_name": "pest_derive", + "Library": { + "crate_name": "clap_lex", "crate_root": "src/lib.rs", "srcs": { "allow_empty": false, @@ -869,33 +826,13 @@ } } ], - "library_target_name": "pest_derive", + "library_target_name": "clap_lex", "common_attrs": { "compile_data_glob": [ "**" ], - "crate_features": { - "common": [ - "default", - "std" - ], - "selects": {} - }, - "deps": { - "common": [ - { - "id": "pest 2.7.14", - "target": "pest" - }, - { - "id": "pest_generator 2.7.14", - "target": "pest_generator" - } - ], - "selects": {} - }, "edition": "2021", - "version": "2.7.14" + "version": "0.7.4" }, "license": "MIT OR Apache-2.0", "license_ids": [ @@ -904,20 +841,20 @@ ], "license_file": "LICENSE-APACHE" }, - "pest_generator 2.7.14": { - "name": "pest_generator", - "version": "2.7.14", - "package_url": "https://github.com/pest-parser/pest", - "repository": { - "Http": { - "url": "https://static.crates.io/crates/pest_generator/2.7.14/download", - "sha256": "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e" + "cpufeatures 0.2.15": { + "name": "cpufeatures", + "version": "0.2.15", + "package_url": "https://github.com/RustCrypto/utils", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/cpufeatures/0.2.15/download", + "sha256": "0ca741a962e1b0bff6d724a1a0958b686406e853bb14061f218562e1896f95e6" } }, "targets": [ { "Library": { - "crate_name": "pest_generator", + "crate_name": "cpufeatures", "crate_root": "src/lib.rs", "srcs": { "allow_empty": false, @@ -928,44 +865,42 @@ } } ], - "library_target_name": "pest_generator", + "library_target_name": "cpufeatures", "common_attrs": { "compile_data_glob": [ "**" ], - "crate_features": { - "common": [ - "std" - ], - "selects": {} - }, "deps": { - "common": [ - { - "id": "pest 2.7.14", - "target": "pest" - }, - { - "id": "pest_meta 2.7.14", - "target": "pest_meta" - }, - { - "id": "proc-macro2 1.0.91", - "target": "proc_macro2" - }, - { - "id": "quote 1.0.37", - "target": "quote" - }, - { - "id": "syn 2.0.89", - "target": "syn" - } - ], - "selects": {} + "common": [], + "selects": { + "aarch64-linux-android": [ + { + "id": "libc 0.2.164", + "target": "libc" + } + ], + "cfg(all(target_arch = \"aarch64\", target_os = \"linux\"))": [ + { + "id": "libc 0.2.164", + "target": "libc" + } + ], + "cfg(all(target_arch = \"aarch64\", target_vendor = \"apple\"))": [ + { + "id": "libc 0.2.164", + "target": "libc" + } + ], + "cfg(all(target_arch = \"loongarch64\", target_os = \"linux\"))": [ + { + "id": "libc 0.2.164", + "target": "libc" + } + ] + } }, - "edition": "2021", - "version": "2.7.14" + "edition": "2018", + "version": "0.2.15" }, "license": "MIT OR Apache-2.0", "license_ids": [ @@ -974,20 +909,20 @@ ], "license_file": "LICENSE-APACHE" }, - "pest_meta 2.7.14": { - "name": "pest_meta", - "version": "2.7.14", - "package_url": "https://github.com/pest-parser/pest", + "criterion 0.5.1": { + "name": "criterion", + "version": "0.5.1", + "package_url": "https://github.com/bheisler/criterion.rs", "repository": { "Http": { - "url": "https://static.crates.io/crates/pest_meta/2.7.14/download", - "sha256": "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d" + "url": "https://static.crates.io/crates/criterion/0.5.1/download", + "sha256": "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" } }, "targets": [ { "Library": { - "crate_name": "pest_meta", + "crate_name": "criterion", "crate_root": "src/lib.rs", "srcs": { "allow_empty": false, @@ -998,54 +933,126 @@ } } ], - "library_target_name": "pest_meta", + "library_target_name": "criterion", "common_attrs": { "compile_data_glob": [ "**" ], "crate_features": { "common": [ - "default" + "cargo_bench_support", + "default", + "plotters", + "rayon" ], "selects": {} }, "deps": { "common": [ + { + "id": "anes 0.1.6", + "target": "anes" + }, + { + "id": "cast 0.3.0", + "target": "cast" + }, + { + "id": "ciborium 0.2.2", + "target": "ciborium" + }, + { + "id": "clap 4.5.26", + "target": "clap" + }, + { + "id": "criterion-plot 0.5.0", + "target": "criterion_plot" + }, + { + "id": "is-terminal 0.4.13", + "target": "is_terminal" + }, + { + "id": "itertools 0.10.5", + "target": "itertools" + }, + { + "id": "num-traits 0.2.19", + "target": "num_traits" + }, { "id": "once_cell 1.20.2", "target": "once_cell" }, { - "id": "pest 2.7.14", - "target": "pest" + "id": "oorandom 11.1.4", + "target": "oorandom" + }, + { + "id": "plotters 0.3.7", + "target": "plotters" + }, + { + "id": "rayon 1.10.0", + "target": "rayon" + }, + { + "id": "regex 1.11.1", + "target": "regex" + }, + { + "id": "serde 1.0.215", + "target": "serde" + }, + { + "id": "serde_json 1.0.135", + "target": "serde_json" + }, + { + "id": "tinytemplate 1.2.1", + "target": "tinytemplate" + }, + { + "id": "walkdir 2.5.0", + "target": "walkdir" } ], "selects": {} }, - "edition": "2021", - "version": "2.7.14" + "edition": "2018", + "proc_macro_deps": { + "common": [ + { + "id": "serde_derive 1.0.215", + "target": "serde_derive" + } + ], + "selects": {} + }, + "version": "0.5.1" }, - "license": "MIT OR Apache-2.0", + "license": "Apache-2.0 OR MIT", "license_ids": [ "Apache-2.0", "MIT" ], "license_file": "LICENSE-APACHE" }, - "proc-macro2 1.0.91": { - "name": "proc-macro2", - "version": "1.0.91", - "package_url": "https://github.com/dtolnay/proc-macro2", + "criterion-plot 0.5.0": { + "name": "criterion-plot", + "version": "0.5.0", + "package_url": "https://github.com/bheisler/criterion.rs", "repository": { "Http": { - "url": "https://static.crates.io/crates/proc-macro2/1.0.91/download", - "sha256": "307e3004becf10f5a6e0d59d20f3cd28231b0e0827a96cd3e0ce6d14bc1e4bb3" + "url": "https://static.crates.io/crates/criterion-plot/0.5.0/download", + "sha256": "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" } }, "targets": [ { "Library": { - "crate_name": "proc_macro2", + "crate_name": "criterion_plot", "crate_root": "src/lib.rs", "srcs": { "allow_empty": false, @@ -1054,74 +1061,50 @@ ] } } - }, - { - "BuildScript": { - "crate_name": "build_script_build", - "crate_root": "build.rs", - "srcs": { - "allow_empty": false, - "include": [ - "**/*.rs" - ] - } - } } ], - "library_target_name": "proc_macro2", + "library_target_name": "criterion_plot", "common_attrs": { "compile_data_glob": [ "**" ], - "crate_features": { - "common": [ - "default", - "proc-macro" - ], - "selects": {} - }, "deps": { "common": [ { - "id": "proc-macro2 1.0.91", - "target": "build_script_build" + "id": "cast 0.3.0", + "target": "cast" }, { - "id": "unicode-ident 1.0.14", - "target": "unicode_ident" + "id": "itertools 0.10.5", + "target": "itertools" } ], "selects": {} }, - "edition": "2021", - "version": "1.0.91" - }, - "build_script_attrs": { - "data_glob": [ - "**" - ] + "edition": "2018", + "version": "0.5.0" }, - "license": "MIT OR Apache-2.0", + "license": "MIT/Apache-2.0", "license_ids": [ "Apache-2.0", "MIT" ], "license_file": "LICENSE-APACHE" }, - "quote 1.0.37": { - "name": "quote", - "version": "1.0.37", - "package_url": "https://github.com/dtolnay/quote", + "crossbeam-deque 0.8.6": { + "name": "crossbeam-deque", + "version": "0.8.6", + "package_url": "https://github.com/crossbeam-rs/crossbeam", "repository": { "Http": { - "url": "https://static.crates.io/crates/quote/1.0.37/download", - "sha256": "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" + "url": "https://static.crates.io/crates/crossbeam-deque/0.8.6/download", + "sha256": "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" } }, "targets": [ { "Library": { - "crate_name": "quote", + "crate_name": "crossbeam_deque", "crate_root": "src/lib.rs", "srcs": { "allow_empty": false, @@ -1132,7 +1115,7 @@ } } ], - "library_target_name": "quote", + "library_target_name": "crossbeam_deque", "common_attrs": { "compile_data_glob": [ "**" @@ -1140,21 +1123,25 @@ "crate_features": { "common": [ "default", - "proc-macro" + "std" ], "selects": {} }, "deps": { "common": [ { - "id": "proc-macro2 1.0.91", - "target": "proc_macro2" + "id": "crossbeam-epoch 0.9.18", + "target": "crossbeam_epoch" + }, + { + "id": "crossbeam-utils 0.8.21", + "target": "crossbeam_utils" } ], "selects": {} }, - "edition": "2018", - "version": "1.0.37" + "edition": "2021", + "version": "0.8.6" }, "license": "MIT OR Apache-2.0", "license_ids": [ @@ -1163,20 +1150,20 @@ ], "license_file": "LICENSE-APACHE" }, - "regex 1.11.1": { - "name": "regex", - "version": "1.11.1", - "package_url": "https://github.com/rust-lang/regex", + "crossbeam-epoch 0.9.18": { + "name": "crossbeam-epoch", + "version": "0.9.18", + "package_url": "https://github.com/crossbeam-rs/crossbeam", "repository": { "Http": { - "url": "https://static.crates.io/crates/regex/1.11.1/download", - "sha256": "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" + "url": "https://static.crates.io/crates/crossbeam-epoch/0.9.18/download", + "sha256": "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" } }, "targets": [ { "Library": { - "crate_name": "regex", + "crate_name": "crossbeam_epoch", "crate_root": "src/lib.rs", "srcs": { "allow_empty": false, @@ -1187,56 +1174,29 @@ } } ], - "library_target_name": "regex", + "library_target_name": "crossbeam_epoch", "common_attrs": { "compile_data_glob": [ "**" ], "crate_features": { "common": [ - "default", - "perf", - "perf-backtrack", - "perf-cache", - "perf-dfa", - "perf-inline", - "perf-literal", - "perf-onepass", - "std", - "unicode", - "unicode-age", - "unicode-bool", - "unicode-case", - "unicode-gencat", - "unicode-perl", - "unicode-script", - "unicode-segment" + "alloc", + "std" ], "selects": {} }, "deps": { "common": [ { - "id": "aho-corasick 1.1.3", - "target": "aho_corasick" - }, - { - "id": "memchr 2.7.4", - "target": "memchr" - }, - { - "id": "regex-automata 0.4.9", - "target": "regex_automata" - }, - { - "id": "regex-syntax 0.8.5", - "target": "regex_syntax" + "id": "crossbeam-utils 0.8.21", + "target": "crossbeam_utils" } ], "selects": {} }, "edition": "2021", - "version": "1.11.1" + "version": "0.9.18" }, "license": "MIT OR Apache-2.0", "license_ids": [ @@ -1245,20 +1205,20 @@ ], "license_file": "LICENSE-APACHE" }, - "regex-automata 0.4.9": { - "name": "regex-automata", - "version": "0.4.9", - "package_url": "https://github.com/rust-lang/regex/tree/master/regex-automata", + "crossbeam-utils 0.8.21": { + "name": "crossbeam-utils", + "version": "0.8.21", + "package_url": "https://github.com/crossbeam-rs/crossbeam", "repository": { "Http": { - "url": "https://static.crates.io/crates/regex-automata/0.4.9/download", - "sha256": "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" + "url": "https://static.crates.io/crates/crossbeam-utils/0.8.21/download", + "sha256": "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" } }, "targets": [ { "Library": { - "crate_name": "regex_automata", + "crate_name": "crossbeam_utils", "crate_root": "src/lib.rs", "srcs": { "allow_empty": false, @@ -1267,21 +1227,1865 @@ ] } } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } } ], - "library_target_name": "regex_automata", + "library_target_name": "crossbeam_utils", "common_attrs": { "compile_data_glob": [ "**" ], "crate_features": { "common": [ - "alloc", - "dfa-onepass", - "hybrid", - "meta", - "nfa-backtrack", - "nfa-pikevm", + "default", + "std" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "crossbeam-utils 0.8.21", + "target": "build_script_build" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.8.21" + }, + "build_script_attrs": { + "data_glob": [ + "**" + ] + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "crunchy 0.2.2": { + "name": "crunchy", + "version": "0.2.2", + "package_url": null, + "repository": { + "Http": { + "url": "https://static.crates.io/crates/crunchy/0.2.2/download", + "sha256": "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + } + }, + "targets": [ + { + "Library": { + "crate_name": "crunchy", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "crunchy", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "crunchy 0.2.2", + "target": "build_script_build" + } + ], + "selects": {} + }, + "edition": "2015", + "version": "0.2.2" + }, + "build_script_attrs": { + "data_glob": [ + "**" + ] + }, + "license": "MIT", + "license_ids": [ + "MIT" + ], + "license_file": null + }, + "crypto-common 0.1.6": { + "name": "crypto-common", + "version": "0.1.6", + "package_url": "https://github.com/RustCrypto/traits", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/crypto-common/0.1.6/download", + "sha256": "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" + } + }, + "targets": [ + { + "Library": { + "crate_name": "crypto_common", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "crypto_common", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "generic-array 0.14.7", + "target": "generic_array" + }, + { + "id": "typenum 1.17.0", + "target": "typenum" + } + ], + "selects": {} + }, + "edition": "2018", + "version": "0.1.6" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "digest 0.10.7": { + "name": "digest", + "version": "0.10.7", + "package_url": "https://github.com/RustCrypto/traits", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/digest/0.10.7/download", + "sha256": "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" + } + }, + "targets": [ + { + "Library": { + "crate_name": "digest", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "digest", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "block-buffer", + "core-api", + "default" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "block-buffer 0.10.4", + "target": "block_buffer" + }, + { + "id": "crypto-common 0.1.6", + "target": "crypto_common" + } + ], + "selects": {} + }, + "edition": "2018", + "version": "0.10.7" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "either 1.13.0": { + "name": "either", + "version": "1.13.0", + "package_url": "https://github.com/rayon-rs/either", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/either/1.13.0/download", + "sha256": "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + } + }, + "targets": [ + { + "Library": { + "crate_name": "either", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "either", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "use_std" + ], + "selects": {} + }, + "edition": "2018", + "version": "1.13.0" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "fnv 1.0.7": { + "name": "fnv", + "version": "1.0.7", + "package_url": "https://github.com/servo/rust-fnv", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/fnv/1.0.7/download", + "sha256": "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + } + }, + "targets": [ + { + "Library": { + "crate_name": "fnv", + "crate_root": "lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "fnv", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "default", + "std" + ], + "selects": {} + }, + "edition": "2015", + "version": "1.0.7" + }, + "license": "Apache-2.0 / MIT", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "generic-array 0.14.7": { + "name": "generic-array", + "version": "0.14.7", + "package_url": "https://github.com/fizyk20/generic-array.git", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/generic-array/0.14.7/download", + "sha256": "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" + } + }, + "targets": [ + { + "Library": { + "crate_name": "generic_array", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "generic_array", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "more_lengths" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "generic-array 0.14.7", + "target": "build_script_build" + }, + { + "id": "typenum 1.17.0", + "target": "typenum" + } + ], + "selects": {} + }, + "edition": "2015", + "version": "0.14.7" + }, + "build_script_attrs": { + "data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "version_check 0.9.5", + "target": "version_check" + } + ], + "selects": {} + } + }, + "license": "MIT", + "license_ids": [ + "MIT" + ], + "license_file": "LICENSE" + }, + "half 2.4.1": { + "name": "half", + "version": "2.4.1", + "package_url": "https://github.com/starkat99/half-rs", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/half/2.4.1/download", + "sha256": "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" + } + }, + "targets": [ + { + "Library": { + "crate_name": "half", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "half", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "cfg-if 1.0.0", + "target": "cfg_if" + } + ], + "selects": { + "cfg(target_arch = \"spirv\")": [ + { + "id": "crunchy 0.2.2", + "target": "crunchy" + } + ] + } + }, + "edition": "2021", + "version": "2.4.1" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE" + }, + "hermit-abi 0.4.0": { + "name": "hermit-abi", + "version": "0.4.0", + "package_url": "https://github.com/hermit-os/hermit-rs", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/hermit-abi/0.4.0/download", + "sha256": "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + } + }, + "targets": [ + { + "Library": { + "crate_name": "hermit_abi", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "hermit_abi", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "edition": "2021", + "version": "0.4.0" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "is-terminal 0.4.13": { + "name": "is-terminal", + "version": "0.4.13", + "package_url": "https://github.com/sunfishcode/is-terminal", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/is-terminal/0.4.13/download", + "sha256": "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" + } + }, + "targets": [ + { + "Library": { + "crate_name": "is_terminal", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "is_terminal", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [], + "selects": { + "cfg(any(unix, target_os = \"wasi\"))": [ + { + "id": "libc 0.2.164", + "target": "libc" + } + ], + "cfg(target_os = \"hermit\")": [ + { + "id": "hermit-abi 0.4.0", + "target": "hermit_abi" + } + ], + "cfg(windows)": [ + { + "id": "windows-sys 0.52.0", + "target": "windows_sys" + } + ] + } + }, + "edition": "2018", + "version": "0.4.13" + }, + "license": "MIT", + "license_ids": [ + "MIT" + ], + "license_file": "LICENSE-MIT" + }, + "itertools 0.10.5": { + "name": "itertools", + "version": "0.10.5", + "package_url": "https://github.com/rust-itertools/itertools", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/itertools/0.10.5/download", + "sha256": "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" + } + }, + "targets": [ + { + "Library": { + "crate_name": "itertools", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "itertools", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "default", + "use_alloc", + "use_std" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "either 1.13.0", + "target": "either" + } + ], + "selects": {} + }, + "edition": "2018", + "version": "0.10.5" + }, + "license": "MIT/Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "itoa 1.0.14": { + "name": "itoa", + "version": "1.0.14", + "package_url": "https://github.com/dtolnay/itoa", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/itoa/1.0.14/download", + "sha256": "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" + } + }, + "targets": [ + { + "Library": { + "crate_name": "itoa", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "itoa", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "edition": "2018", + "version": "1.0.14" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "js-sys 0.3.77": { + "name": "js-sys", + "version": "0.3.77", + "package_url": "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/js-sys", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/js-sys/0.3.77/download", + "sha256": "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" + } + }, + "targets": [ + { + "Library": { + "crate_name": "js_sys", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "js_sys", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "std" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "once_cell 1.20.2", + "target": "once_cell" + }, + { + "id": "wasm-bindgen 0.2.100", + "target": "wasm_bindgen" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.3.77" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "lazy_static 1.5.0": { + "name": "lazy_static", + "version": "1.5.0", + "package_url": "https://github.com/rust-lang-nursery/lazy-static.rs", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/lazy_static/1.5.0/download", + "sha256": "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + } + }, + "targets": [ + { + "Library": { + "crate_name": "lazy_static", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "lazy_static", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "edition": "2015", + "version": "1.5.0" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "libc 0.2.164": { + "name": "libc", + "version": "0.2.164", + "package_url": "https://github.com/rust-lang/libc", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/libc/0.2.164/download", + "sha256": "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" + } + }, + "targets": [ + { + "Library": { + "crate_name": "libc", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "libc", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "default", + "std" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "libc 0.2.164", + "target": "build_script_build" + } + ], + "selects": {} + }, + "edition": "2015", + "version": "0.2.164" + }, + "build_script_attrs": { + "data_glob": [ + "**" + ] + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "log 0.4.22": { + "name": "log", + "version": "0.4.22", + "package_url": "https://github.com/rust-lang/log", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/log/0.4.22/download", + "sha256": "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + } + }, + "targets": [ + { + "Library": { + "crate_name": "log", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "log", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "edition": "2021", + "version": "0.4.22" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "memchr 2.7.4": { + "name": "memchr", + "version": "2.7.4", + "package_url": "https://github.com/BurntSushi/memchr", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/memchr/2.7.4/download", + "sha256": "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + } + }, + "targets": [ + { + "Library": { + "crate_name": "memchr", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "memchr", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "alloc", + "default", + "std" + ], + "selects": {} + }, + "edition": "2021", + "version": "2.7.4" + }, + "license": "Unlicense OR MIT", + "license_ids": [ + "MIT", + "Unlicense" + ], + "license_file": "LICENSE-MIT" + }, + "num-traits 0.2.19": { + "name": "num-traits", + "version": "0.2.19", + "package_url": "https://github.com/rust-num/num-traits", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/num-traits/0.2.19/download", + "sha256": "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" + } + }, + "targets": [ + { + "Library": { + "crate_name": "num_traits", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "num_traits", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "default", + "std" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "num-traits 0.2.19", + "target": "build_script_build" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.2.19" + }, + "build_script_attrs": { + "data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "autocfg 1.4.0", + "target": "autocfg" + } + ], + "selects": {} + } + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "once_cell 1.20.2": { + "name": "once_cell", + "version": "1.20.2", + "package_url": "https://github.com/matklad/once_cell", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/once_cell/1.20.2/download", + "sha256": "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + } + }, + "targets": [ + { + "Library": { + "crate_name": "once_cell", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "once_cell", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "alloc", + "default", + "race", + "std" + ], + "selects": {} + }, + "edition": "2021", + "version": "1.20.2" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "oorandom 11.1.4": { + "name": "oorandom", + "version": "11.1.4", + "package_url": "https://hg.sr.ht/~icefox/oorandom", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/oorandom/11.1.4/download", + "sha256": "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" + } + }, + "targets": [ + { + "Library": { + "crate_name": "oorandom", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "oorandom", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "edition": "2018", + "version": "11.1.4" + }, + "license": "MIT", + "license_ids": [ + "MIT" + ], + "license_file": "LICENSE-MIT" + }, + "pest 2.7.14": { + "name": "pest", + "version": "2.7.14", + "package_url": "https://github.com/pest-parser/pest", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/pest/2.7.14/download", + "sha256": "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" + } + }, + "targets": [ + { + "Library": { + "crate_name": "pest", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "pest", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "default", + "memchr", + "std" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "memchr 2.7.4", + "target": "memchr" + }, + { + "id": "thiserror 1.0.69", + "target": "thiserror" + }, + { + "id": "ucd-trie 0.1.7", + "target": "ucd_trie" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "2.7.14" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "pest_derive 2.7.14": { + "name": "pest_derive", + "version": "2.7.14", + "package_url": "https://github.com/pest-parser/pest", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/pest_derive/2.7.14/download", + "sha256": "d214365f632b123a47fd913301e14c946c61d1c183ee245fa76eb752e59a02dd" + } + }, + "targets": [ + { + "ProcMacro": { + "crate_name": "pest_derive", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "pest_derive", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "default", + "std" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "pest 2.7.14", + "target": "pest" + }, + { + "id": "pest_generator 2.7.14", + "target": "pest_generator" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "2.7.14" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "pest_generator 2.7.14": { + "name": "pest_generator", + "version": "2.7.14", + "package_url": "https://github.com/pest-parser/pest", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/pest_generator/2.7.14/download", + "sha256": "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e" + } + }, + "targets": [ + { + "Library": { + "crate_name": "pest_generator", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "pest_generator", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "std" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "pest 2.7.14", + "target": "pest" + }, + { + "id": "pest_meta 2.7.14", + "target": "pest_meta" + }, + { + "id": "proc-macro2 1.0.91", + "target": "proc_macro2" + }, + { + "id": "quote 1.0.37", + "target": "quote" + }, + { + "id": "syn 2.0.89", + "target": "syn" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "2.7.14" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "pest_meta 2.7.14": { + "name": "pest_meta", + "version": "2.7.14", + "package_url": "https://github.com/pest-parser/pest", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/pest_meta/2.7.14/download", + "sha256": "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d" + } + }, + "targets": [ + { + "Library": { + "crate_name": "pest_meta", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "pest_meta", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "default" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "once_cell 1.20.2", + "target": "once_cell" + }, + { + "id": "pest 2.7.14", + "target": "pest" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "2.7.14" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "plotters 0.3.7": { + "name": "plotters", + "version": "0.3.7", + "package_url": "https://github.com/plotters-rs/plotters", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/plotters/0.3.7/download", + "sha256": "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" + } + }, + "targets": [ + { + "Library": { + "crate_name": "plotters", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "plotters", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "area_series", + "line_series", + "plotters-svg", + "svg_backend" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "num-traits 0.2.19", + "target": "num_traits" + }, + { + "id": "plotters-backend 0.3.7", + "target": "plotters_backend" + }, + { + "id": "plotters-svg 0.3.7", + "target": "plotters_svg" + } + ], + "selects": { + "cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))": [ + { + "id": "wasm-bindgen 0.2.100", + "target": "wasm_bindgen" + }, + { + "id": "web-sys 0.3.77", + "target": "web_sys" + } + ] + } + }, + "edition": "2018", + "version": "0.3.7" + }, + "license": "MIT", + "license_ids": [ + "MIT" + ], + "license_file": "LICENSE" + }, + "plotters-backend 0.3.7": { + "name": "plotters-backend", + "version": "0.3.7", + "package_url": "https://github.com/plotters-rs/plotters", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/plotters-backend/0.3.7/download", + "sha256": "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" + } + }, + "targets": [ + { + "Library": { + "crate_name": "plotters_backend", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "plotters_backend", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "edition": "2018", + "version": "0.3.7" + }, + "license": "MIT", + "license_ids": [ + "MIT" + ], + "license_file": "LICENSE" + }, + "plotters-svg 0.3.7": { + "name": "plotters-svg", + "version": "0.3.7", + "package_url": "https://github.com/plotters-rs/plotters.git", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/plotters-svg/0.3.7/download", + "sha256": "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" + } + }, + "targets": [ + { + "Library": { + "crate_name": "plotters_svg", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "plotters_svg", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "plotters-backend 0.3.7", + "target": "plotters_backend" + } + ], + "selects": {} + }, + "edition": "2018", + "version": "0.3.7" + }, + "license": "MIT", + "license_ids": [ + "MIT" + ], + "license_file": "LICENSE" + }, + "proc-macro2 1.0.91": { + "name": "proc-macro2", + "version": "1.0.91", + "package_url": "https://github.com/dtolnay/proc-macro2", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/proc-macro2/1.0.91/download", + "sha256": "307e3004becf10f5a6e0d59d20f3cd28231b0e0827a96cd3e0ce6d14bc1e4bb3" + } + }, + "targets": [ + { + "Library": { + "crate_name": "proc_macro2", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "proc_macro2", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "default", + "proc-macro" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "proc-macro2 1.0.91", + "target": "build_script_build" + }, + { + "id": "unicode-ident 1.0.14", + "target": "unicode_ident" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "1.0.91" + }, + "build_script_attrs": { + "data_glob": [ + "**" + ] + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "quote 1.0.37": { + "name": "quote", + "version": "1.0.37", + "package_url": "https://github.com/dtolnay/quote", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/quote/1.0.37/download", + "sha256": "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" + } + }, + "targets": [ + { + "Library": { + "crate_name": "quote", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "quote", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "default", + "proc-macro" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "proc-macro2 1.0.91", + "target": "proc_macro2" + } + ], + "selects": {} + }, + "edition": "2018", + "version": "1.0.37" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "rayon 1.10.0": { + "name": "rayon", + "version": "1.10.0", + "package_url": "https://github.com/rayon-rs/rayon", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/rayon/1.10.0/download", + "sha256": "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" + } + }, + "targets": [ + { + "Library": { + "crate_name": "rayon", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "rayon", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "either 1.13.0", + "target": "either" + }, + { + "id": "rayon-core 1.12.1", + "target": "rayon_core" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "1.10.0" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "rayon-core 1.12.1": { + "name": "rayon-core", + "version": "1.12.1", + "package_url": "https://github.com/rayon-rs/rayon", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/rayon-core/1.12.1/download", + "sha256": "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" + } + }, + "targets": [ + { + "Library": { + "crate_name": "rayon_core", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "rayon_core", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "crossbeam-deque 0.8.6", + "target": "crossbeam_deque" + }, + { + "id": "crossbeam-utils 0.8.21", + "target": "crossbeam_utils" + }, + { + "id": "rayon-core 1.12.1", + "target": "build_script_build" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "1.12.1" + }, + "build_script_attrs": { + "data_glob": [ + "**" + ], + "links": "rayon-core" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "regex 1.11.1": { + "name": "regex", + "version": "1.11.1", + "package_url": "https://github.com/rust-lang/regex", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/regex/1.11.1/download", + "sha256": "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" + } + }, + "targets": [ + { + "Library": { + "crate_name": "regex", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "regex", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "default", + "perf", + "perf-backtrack", + "perf-cache", + "perf-dfa", + "perf-inline", + "perf-literal", + "perf-onepass", + "std", + "unicode", + "unicode-age", + "unicode-bool", + "unicode-case", + "unicode-gencat", + "unicode-perl", + "unicode-script", + "unicode-segment" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "aho-corasick 1.1.3", + "target": "aho_corasick" + }, + { + "id": "memchr 2.7.4", + "target": "memchr" + }, + { + "id": "regex-automata 0.4.9", + "target": "regex_automata" + }, + { + "id": "regex-syntax 0.8.5", + "target": "regex_syntax" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "1.11.1" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "regex-automata 0.4.9": { + "name": "regex-automata", + "version": "0.4.9", + "package_url": "https://github.com/rust-lang/regex/tree/master/regex-automata", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/regex-automata/0.4.9/download", + "sha256": "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" + } + }, + "targets": [ + { + "Library": { + "crate_name": "regex_automata", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "regex_automata", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "alloc", + "dfa-onepass", + "hybrid", + "meta", + "nfa-backtrack", + "nfa-pikevm", "nfa-thompson", "perf-inline", "perf-literal", @@ -1304,22 +3108,1482 @@ "deps": { "common": [ { - "id": "aho-corasick 1.1.3", - "target": "aho_corasick" - }, - { - "id": "memchr 2.7.4", - "target": "memchr" + "id": "aho-corasick 1.1.3", + "target": "aho_corasick" + }, + { + "id": "memchr 2.7.4", + "target": "memchr" + }, + { + "id": "regex-syntax 0.8.5", + "target": "regex_syntax" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.4.9" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "regex-syntax 0.8.5": { + "name": "regex-syntax", + "version": "0.8.5", + "package_url": "https://github.com/rust-lang/regex/tree/master/regex-syntax", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/regex-syntax/0.8.5/download", + "sha256": "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + } + }, + "targets": [ + { + "Library": { + "crate_name": "regex_syntax", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "regex_syntax", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "default", + "std", + "unicode", + "unicode-age", + "unicode-bool", + "unicode-case", + "unicode-gencat", + "unicode-perl", + "unicode-script", + "unicode-segment" + ], + "selects": {} + }, + "edition": "2021", + "version": "0.8.5" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "rustversion 1.0.19": { + "name": "rustversion", + "version": "1.0.19", + "package_url": "https://github.com/dtolnay/rustversion", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/rustversion/1.0.19/download", + "sha256": "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" + } + }, + "targets": [ + { + "ProcMacro": { + "crate_name": "rustversion", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build/build.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "rustversion", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "rustversion 1.0.19", + "target": "build_script_build" + } + ], + "selects": {} + }, + "edition": "2018", + "version": "1.0.19" + }, + "build_script_attrs": { + "data_glob": [ + "**" + ] + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "ryu 1.0.18": { + "name": "ryu", + "version": "1.0.18", + "package_url": "https://github.com/dtolnay/ryu", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/ryu/1.0.18/download", + "sha256": "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + } + }, + "targets": [ + { + "Library": { + "crate_name": "ryu", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "ryu", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "edition": "2018", + "version": "1.0.18" + }, + "license": "Apache-2.0 OR BSL-1.0", + "license_ids": [ + "Apache-2.0", + "BSL-1.0" + ], + "license_file": "LICENSE-APACHE" + }, + "same-file 1.0.6": { + "name": "same-file", + "version": "1.0.6", + "package_url": "https://github.com/BurntSushi/same-file", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/same-file/1.0.6/download", + "sha256": "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" + } + }, + "targets": [ + { + "Library": { + "crate_name": "same_file", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "same_file", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [], + "selects": { + "cfg(windows)": [ + { + "id": "winapi-util 0.1.9", + "target": "winapi_util" + } + ] + } + }, + "edition": "2018", + "version": "1.0.6" + }, + "license": "Unlicense/MIT", + "license_ids": [ + "MIT", + "Unlicense" + ], + "license_file": "LICENSE-MIT" + }, + "serde 1.0.215": { + "name": "serde", + "version": "1.0.215", + "package_url": "https://github.com/serde-rs/serde", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/serde/1.0.215/download", + "sha256": "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" + } + }, + "targets": [ + { + "Library": { + "crate_name": "serde", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "serde", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "alloc", + "default", + "derive", + "serde_derive", + "std" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "serde 1.0.215", + "target": "build_script_build" + } + ], + "selects": {} + }, + "edition": "2018", + "proc_macro_deps": { + "common": [ + { + "id": "serde_derive 1.0.215", + "target": "serde_derive" + } + ], + "selects": {} + }, + "version": "1.0.215" + }, + "build_script_attrs": { + "data_glob": [ + "**" + ] + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "serde_derive 1.0.215": { + "name": "serde_derive", + "version": "1.0.215", + "package_url": "https://github.com/serde-rs/serde", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/serde_derive/1.0.215/download", + "sha256": "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" + } + }, + "targets": [ + { + "ProcMacro": { + "crate_name": "serde_derive", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "serde_derive", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "default" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "proc-macro2 1.0.91", + "target": "proc_macro2" + }, + { + "id": "quote 1.0.37", + "target": "quote" + }, + { + "id": "syn 2.0.89", + "target": "syn" + } + ], + "selects": {} + }, + "edition": "2015", + "version": "1.0.215" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "serde_json 1.0.135": { + "name": "serde_json", + "version": "1.0.135", + "package_url": "https://github.com/serde-rs/json", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/serde_json/1.0.135/download", + "sha256": "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9" + } + }, + "targets": [ + { + "Library": { + "crate_name": "serde_json", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "serde_json", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "default", + "std" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "itoa 1.0.14", + "target": "itoa" + }, + { + "id": "memchr 2.7.4", + "target": "memchr" + }, + { + "id": "ryu 1.0.18", + "target": "ryu" + }, + { + "id": "serde 1.0.215", + "target": "serde" + }, + { + "id": "serde_json 1.0.135", + "target": "build_script_build" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "1.0.135" + }, + "build_script_attrs": { + "data_glob": [ + "**" + ] + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "sha2 0.10.8": { + "name": "sha2", + "version": "0.10.8", + "package_url": "https://github.com/RustCrypto/hashes", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/sha2/0.10.8/download", + "sha256": "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" + } + }, + "targets": [ + { + "Library": { + "crate_name": "sha2", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "sha2", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "cfg-if 1.0.0", + "target": "cfg_if" + }, + { + "id": "digest 0.10.7", + "target": "digest" + } + ], + "selects": { + "cfg(any(target_arch = \"aarch64\", target_arch = \"x86_64\", target_arch = \"x86\"))": [ + { + "id": "cpufeatures 0.2.15", + "target": "cpufeatures" + } + ] + } + }, + "edition": "2018", + "version": "0.10.8" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "syn 2.0.89": { + "name": "syn", + "version": "2.0.89", + "package_url": "https://github.com/dtolnay/syn", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/syn/2.0.89/download", + "sha256": "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e" + } + }, + "targets": [ + { + "Library": { + "crate_name": "syn", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "syn", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "clone-impls", + "default", + "derive", + "parsing", + "printing", + "proc-macro" + ], + "selects": { + "wasm32-unknown-unknown": [ + "full", + "visit", + "visit-mut" + ] + } + }, + "deps": { + "common": [ + { + "id": "proc-macro2 1.0.91", + "target": "proc_macro2" + }, + { + "id": "quote 1.0.37", + "target": "quote" + }, + { + "id": "unicode-ident 1.0.14", + "target": "unicode_ident" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "2.0.89" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "thiserror 1.0.69": { + "name": "thiserror", + "version": "1.0.69", + "package_url": "https://github.com/dtolnay/thiserror", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/thiserror/1.0.69/download", + "sha256": "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" + } + }, + "targets": [ + { + "Library": { + "crate_name": "thiserror", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "thiserror", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "thiserror 1.0.69", + "target": "build_script_build" + } + ], + "selects": {} + }, + "edition": "2021", + "proc_macro_deps": { + "common": [ + { + "id": "thiserror-impl 1.0.69", + "target": "thiserror_impl" + } + ], + "selects": {} + }, + "version": "1.0.69" + }, + "build_script_attrs": { + "data_glob": [ + "**" + ] + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "thiserror-impl 1.0.69": { + "name": "thiserror-impl", + "version": "1.0.69", + "package_url": "https://github.com/dtolnay/thiserror", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/thiserror-impl/1.0.69/download", + "sha256": "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" + } + }, + "targets": [ + { + "ProcMacro": { + "crate_name": "thiserror_impl", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "thiserror_impl", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "proc-macro2 1.0.91", + "target": "proc_macro2" + }, + { + "id": "quote 1.0.37", + "target": "quote" + }, + { + "id": "syn 2.0.89", + "target": "syn" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "1.0.69" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "tinytemplate 1.2.1": { + "name": "tinytemplate", + "version": "1.2.1", + "package_url": "https://github.com/bheisler/TinyTemplate", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/tinytemplate/1.2.1/download", + "sha256": "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" + } + }, + "targets": [ + { + "Library": { + "crate_name": "tinytemplate", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "tinytemplate", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "serde 1.0.215", + "target": "serde" + }, + { + "id": "serde_json 1.0.135", + "target": "serde_json" + } + ], + "selects": {} + }, + "edition": "2015", + "version": "1.2.1" + }, + "license": "Apache-2.0 OR MIT", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "typenum 1.17.0": { + "name": "typenum", + "version": "1.17.0", + "package_url": "https://github.com/paholg/typenum", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/typenum/1.17.0/download", + "sha256": "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + } + }, + "targets": [ + { + "Library": { + "crate_name": "typenum", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + }, + { + "BuildScript": { + "crate_name": "build_script_main", + "crate_root": "build/main.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "typenum", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "typenum 1.17.0", + "target": "build_script_main" + } + ], + "selects": {} + }, + "edition": "2018", + "version": "1.17.0" + }, + "build_script_attrs": { + "data_glob": [ + "**" + ] + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE" + }, + "ucd-trie 0.1.7": { + "name": "ucd-trie", + "version": "0.1.7", + "package_url": "https://github.com/BurntSushi/ucd-generate", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/ucd-trie/0.1.7/download", + "sha256": "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + } + }, + "targets": [ + { + "Library": { + "crate_name": "ucd_trie", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "ucd_trie", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "std" + ], + "selects": {} + }, + "edition": "2021", + "version": "0.1.7" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "unicode-ident 1.0.14": { + "name": "unicode-ident", + "version": "1.0.14", + "package_url": "https://github.com/dtolnay/unicode-ident", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/unicode-ident/1.0.14/download", + "sha256": "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" + } + }, + "targets": [ + { + "Library": { + "crate_name": "unicode_ident", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "unicode_ident", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "edition": "2018", + "version": "1.0.14" + }, + "license": "(MIT OR Apache-2.0) AND Unicode-3.0", + "license_ids": [], + "license_file": "LICENSE-APACHE" + }, + "uuid 1.11.0": { + "name": "uuid", + "version": "1.11.0", + "package_url": "https://github.com/uuid-rs/uuid", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/uuid/1.11.0/download", + "sha256": "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" + } + }, + "targets": [ + { + "Library": { + "crate_name": "uuid", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "uuid", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "default", + "std" + ], + "selects": {} + }, + "edition": "2018", + "version": "1.11.0" + }, + "license": "Apache-2.0 OR MIT", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "version_check 0.9.5": { + "name": "version_check", + "version": "0.9.5", + "package_url": "https://github.com/SergioBenitez/version_check", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/version_check/0.9.5/download", + "sha256": "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + } + }, + "targets": [ + { + "Library": { + "crate_name": "version_check", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "version_check", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "edition": "2015", + "version": "0.9.5" + }, + "license": "MIT/Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "walkdir 2.5.0": { + "name": "walkdir", + "version": "2.5.0", + "package_url": "https://github.com/BurntSushi/walkdir", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/walkdir/2.5.0/download", + "sha256": "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" + } + }, + "targets": [ + { + "Library": { + "crate_name": "walkdir", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "walkdir", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "same-file 1.0.6", + "target": "same_file" + } + ], + "selects": { + "cfg(windows)": [ + { + "id": "winapi-util 0.1.9", + "target": "winapi_util" + } + ] + } + }, + "edition": "2018", + "version": "2.5.0" + }, + "license": "Unlicense/MIT", + "license_ids": [ + "MIT", + "Unlicense" + ], + "license_file": "LICENSE-MIT" + }, + "wasm-bindgen 0.2.100": { + "name": "wasm-bindgen", + "version": "0.2.100", + "package_url": "https://github.com/rustwasm/wasm-bindgen", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/wasm-bindgen/0.2.100/download", + "sha256": "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" + } + }, + "targets": [ + { + "Library": { + "crate_name": "wasm_bindgen", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "wasm_bindgen", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "default", + "msrv", + "rustversion", + "std" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "cfg-if 1.0.0", + "target": "cfg_if" + }, + { + "id": "once_cell 1.20.2", + "target": "once_cell" + }, + { + "id": "wasm-bindgen 0.2.100", + "target": "build_script_build" + } + ], + "selects": {} + }, + "edition": "2021", + "proc_macro_deps": { + "common": [ + { + "id": "rustversion 1.0.19", + "target": "rustversion" + }, + { + "id": "wasm-bindgen-macro 0.2.100", + "target": "wasm_bindgen_macro" + } + ], + "selects": {} + }, + "version": "0.2.100" + }, + "build_script_attrs": { + "data_glob": [ + "**" + ] + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "wasm-bindgen-backend 0.2.100": { + "name": "wasm-bindgen-backend", + "version": "0.2.100", + "package_url": "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/backend", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/wasm-bindgen-backend/0.2.100/download", + "sha256": "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" + } + }, + "targets": [ + { + "Library": { + "crate_name": "wasm_bindgen_backend", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "wasm_bindgen_backend", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "bumpalo 3.16.0", + "target": "bumpalo" + }, + { + "id": "log 0.4.22", + "target": "log" + }, + { + "id": "proc-macro2 1.0.91", + "target": "proc_macro2" + }, + { + "id": "quote 1.0.37", + "target": "quote" + }, + { + "id": "syn 2.0.89", + "target": "syn" + }, + { + "id": "wasm-bindgen-shared 0.2.100", + "target": "wasm_bindgen_shared" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.2.100" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "wasm-bindgen-macro 0.2.100": { + "name": "wasm-bindgen-macro", + "version": "0.2.100", + "package_url": "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/macro", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/wasm-bindgen-macro/0.2.100/download", + "sha256": "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" + } + }, + "targets": [ + { + "ProcMacro": { + "crate_name": "wasm_bindgen_macro", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "wasm_bindgen_macro", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "quote 1.0.37", + "target": "quote" + }, + { + "id": "wasm-bindgen-macro-support 0.2.100", + "target": "wasm_bindgen_macro_support" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.2.100" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "wasm-bindgen-macro-support 0.2.100": { + "name": "wasm-bindgen-macro-support", + "version": "0.2.100", + "package_url": "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/macro-support", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/wasm-bindgen-macro-support/0.2.100/download", + "sha256": "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" + } + }, + "targets": [ + { + "Library": { + "crate_name": "wasm_bindgen_macro_support", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "wasm_bindgen_macro_support", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "proc-macro2 1.0.91", + "target": "proc_macro2" + }, + { + "id": "quote 1.0.37", + "target": "quote" + }, + { + "id": "syn 2.0.89", + "target": "syn" + }, + { + "id": "wasm-bindgen-backend 0.2.100", + "target": "wasm_bindgen_backend" + }, + { + "id": "wasm-bindgen-shared 0.2.100", + "target": "wasm_bindgen_shared" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.2.100" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "wasm-bindgen-shared 0.2.100": { + "name": "wasm-bindgen-shared", + "version": "0.2.100", + "package_url": "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/shared", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/wasm-bindgen-shared/0.2.100/download", + "sha256": "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" + } + }, + "targets": [ + { + "Library": { + "crate_name": "wasm_bindgen_shared", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "wasm_bindgen_shared", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [ + { + "id": "unicode-ident 1.0.14", + "target": "unicode_ident" + }, + { + "id": "wasm-bindgen-shared 0.2.100", + "target": "build_script_build" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.2.100" + }, + "build_script_attrs": { + "data_glob": [ + "**" + ], + "links": "wasm_bindgen" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "LICENSE-APACHE" + }, + "web-sys 0.3.77": { + "name": "web-sys", + "version": "0.3.77", + "package_url": "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/web-sys", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/web-sys/0.3.77/download", + "sha256": "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" + } + }, + "targets": [ + { + "Library": { + "crate_name": "web_sys", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "web_sys", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "crate_features": { + "common": [ + "CanvasRenderingContext2d", + "Document", + "DomRect", + "DomRectReadOnly", + "Element", + "EventTarget", + "HtmlCanvasElement", + "HtmlElement", + "Node", + "Window", + "default", + "std" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "js-sys 0.3.77", + "target": "js_sys" }, { - "id": "regex-syntax 0.8.5", - "target": "regex_syntax" + "id": "wasm-bindgen 0.2.100", + "target": "wasm_bindgen" } ], "selects": {} }, "edition": "2021", - "version": "0.4.9" + "version": "0.3.77" }, "license": "MIT OR Apache-2.0", "license_ids": [ @@ -1328,20 +4592,20 @@ ], "license_file": "LICENSE-APACHE" }, - "regex-syntax 0.8.5": { - "name": "regex-syntax", - "version": "0.8.5", - "package_url": "https://github.com/rust-lang/regex/tree/master/regex-syntax", + "winapi-util 0.1.9": { + "name": "winapi-util", + "version": "0.1.9", + "package_url": "https://github.com/BurntSushi/winapi-util", "repository": { "Http": { - "url": "https://static.crates.io/crates/regex-syntax/0.8.5/download", - "sha256": "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + "url": "https://static.crates.io/crates/winapi-util/0.1.9/download", + "sha256": "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" } }, "targets": [ { "Library": { - "crate_name": "regex_syntax", + "crate_name": "winapi_util", "crate_root": "src/lib.rs", "srcs": { "allow_empty": false, @@ -1352,50 +4616,106 @@ } } ], - "library_target_name": "regex_syntax", + "library_target_name": "winapi_util", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [], + "selects": { + "cfg(windows)": [ + { + "id": "windows-sys 0.59.0", + "target": "windows_sys" + } + ] + } + }, + "edition": "2021", + "version": "0.1.9" + }, + "license": "Unlicense OR MIT", + "license_ids": [ + "MIT", + "Unlicense" + ], + "license_file": "LICENSE-MIT" + }, + "windows-sys 0.52.0": { + "name": "windows-sys", + "version": "0.52.0", + "package_url": "https://github.com/microsoft/windows-rs", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/windows-sys/0.52.0/download", + "sha256": "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" + } + }, + "targets": [ + { + "Library": { + "crate_name": "windows_sys", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "windows_sys", "common_attrs": { "compile_data_glob": [ "**" ], "crate_features": { "common": [ - "default", - "std", - "unicode", - "unicode-age", - "unicode-bool", - "unicode-case", - "unicode-gencat", - "unicode-perl", - "unicode-script", - "unicode-segment" + "Win32", + "Win32_Foundation", + "Win32_Storage", + "Win32_Storage_FileSystem", + "Win32_System", + "Win32_System_Console", + "default" + ], + "selects": {} + }, + "deps": { + "common": [ + { + "id": "windows-targets 0.52.6", + "target": "windows_targets" + } ], "selects": {} }, "edition": "2021", - "version": "0.8.5" + "version": "0.52.0" }, "license": "MIT OR Apache-2.0", "license_ids": [ "Apache-2.0", "MIT" ], - "license_file": "LICENSE-APACHE" + "license_file": "license-apache-2.0" }, - "sha2 0.10.8": { - "name": "sha2", - "version": "0.10.8", - "package_url": "https://github.com/RustCrypto/hashes", + "windows-sys 0.59.0": { + "name": "windows-sys", + "version": "0.59.0", + "package_url": "https://github.com/microsoft/windows-rs", "repository": { "Http": { - "url": "https://static.crates.io/crates/sha2/0.10.8/download", - "sha256": "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" + "url": "https://static.crates.io/crates/windows-sys/0.59.0/download", + "sha256": "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" } }, "targets": [ { "Library": { - "crate_name": "sha2", + "crate_name": "windows_sys", "crate_root": "src/lib.rs", "srcs": { "allow_empty": false, @@ -1406,55 +4726,149 @@ } } ], - "library_target_name": "sha2", + "library_target_name": "windows_sys", "common_attrs": { "compile_data_glob": [ "**" ], + "crate_features": { + "common": [ + "Win32", + "Win32_Foundation", + "Win32_Storage", + "Win32_Storage_FileSystem", + "Win32_System", + "Win32_System_Console", + "Win32_System_SystemInformation", + "default" + ], + "selects": {} + }, "deps": { "common": [ { - "id": "cfg-if 1.0.0", - "target": "cfg_if" - }, - { - "id": "digest 0.10.7", - "target": "digest" + "id": "windows-targets 0.52.6", + "target": "windows_targets" } ], + "selects": {} + }, + "edition": "2021", + "version": "0.59.0" + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "license-apache-2.0" + }, + "windows-targets 0.52.6": { + "name": "windows-targets", + "version": "0.52.6", + "package_url": "https://github.com/microsoft/windows-rs", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/windows-targets/0.52.6/download", + "sha256": "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" + } + }, + "targets": [ + { + "Library": { + "crate_name": "windows_targets", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "windows_targets", + "common_attrs": { + "compile_data_glob": [ + "**" + ], + "deps": { + "common": [], "selects": { - "cfg(any(target_arch = \"aarch64\", target_arch = \"x86_64\", target_arch = \"x86\"))": [ + "aarch64-pc-windows-gnullvm": [ { - "id": "cpufeatures 0.2.15", - "target": "cpufeatures" + "id": "windows_aarch64_gnullvm 0.52.6", + "target": "windows_aarch64_gnullvm" + } + ], + "cfg(all(any(target_arch = \"x86_64\", target_arch = \"arm64ec\"), target_env = \"msvc\", not(windows_raw_dylib)))": [ + { + "id": "windows_x86_64_msvc 0.52.6", + "target": "windows_x86_64_msvc" + } + ], + "cfg(all(target_arch = \"aarch64\", target_env = \"msvc\", not(windows_raw_dylib)))": [ + { + "id": "windows_aarch64_msvc 0.52.6", + "target": "windows_aarch64_msvc" + } + ], + "cfg(all(target_arch = \"x86\", target_env = \"gnu\", not(target_abi = \"llvm\"), not(windows_raw_dylib)))": [ + { + "id": "windows_i686_gnu 0.52.6", + "target": "windows_i686_gnu" + } + ], + "cfg(all(target_arch = \"x86\", target_env = \"msvc\", not(windows_raw_dylib)))": [ + { + "id": "windows_i686_msvc 0.52.6", + "target": "windows_i686_msvc" + } + ], + "cfg(all(target_arch = \"x86_64\", target_env = \"gnu\", not(target_abi = \"llvm\"), not(windows_raw_dylib)))": [ + { + "id": "windows_x86_64_gnu 0.52.6", + "target": "windows_x86_64_gnu" + } + ], + "i686-pc-windows-gnullvm": [ + { + "id": "windows_i686_gnullvm 0.52.6", + "target": "windows_i686_gnullvm" + } + ], + "x86_64-pc-windows-gnullvm": [ + { + "id": "windows_x86_64_gnullvm 0.52.6", + "target": "windows_x86_64_gnullvm" } ] } }, - "edition": "2018", - "version": "0.10.8" + "edition": "2021", + "version": "0.52.6" }, "license": "MIT OR Apache-2.0", "license_ids": [ "Apache-2.0", "MIT" ], - "license_file": "LICENSE-APACHE" + "license_file": "license-apache-2.0" }, - "syn 2.0.89": { - "name": "syn", - "version": "2.0.89", - "package_url": "https://github.com/dtolnay/syn", + "windows_aarch64_gnullvm 0.52.6": { + "name": "windows_aarch64_gnullvm", + "version": "0.52.6", + "package_url": "https://github.com/microsoft/windows-rs", "repository": { "Http": { - "url": "https://static.crates.io/crates/syn/2.0.89/download", - "sha256": "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e" + "url": "https://static.crates.io/crates/windows_aarch64_gnullvm/0.52.6/download", + "sha256": "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" } }, "targets": [ { "Library": { - "crate_name": "syn", + "crate_name": "windows_aarch64_gnullvm", "crate_root": "src/lib.rs", "srcs": { "allow_empty": false, @@ -1463,65 +4877,128 @@ ] } } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } } ], - "library_target_name": "syn", + "library_target_name": "windows_aarch64_gnullvm", "common_attrs": { "compile_data_glob": [ "**" ], - "crate_features": { + "deps": { "common": [ - "clone-impls", - "default", - "derive", - "parsing", - "printing", - "proc-macro" + { + "id": "windows_aarch64_gnullvm 0.52.6", + "target": "build_script_build" + } ], "selects": {} }, + "edition": "2021", + "version": "0.52.6" + }, + "build_script_attrs": { + "data_glob": [ + "**" + ] + }, + "license": "MIT OR Apache-2.0", + "license_ids": [ + "Apache-2.0", + "MIT" + ], + "license_file": "license-apache-2.0" + }, + "windows_aarch64_msvc 0.52.6": { + "name": "windows_aarch64_msvc", + "version": "0.52.6", + "package_url": "https://github.com/microsoft/windows-rs", + "repository": { + "Http": { + "url": "https://static.crates.io/crates/windows_aarch64_msvc/0.52.6/download", + "sha256": "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + } + }, + "targets": [ + { + "Library": { + "crate_name": "windows_aarch64_msvc", + "crate_root": "src/lib.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } + } + ], + "library_target_name": "windows_aarch64_msvc", + "common_attrs": { + "compile_data_glob": [ + "**" + ], "deps": { "common": [ { - "id": "proc-macro2 1.0.91", - "target": "proc_macro2" - }, - { - "id": "quote 1.0.37", - "target": "quote" - }, - { - "id": "unicode-ident 1.0.14", - "target": "unicode_ident" + "id": "windows_aarch64_msvc 0.52.6", + "target": "build_script_build" } ], "selects": {} }, "edition": "2021", - "version": "2.0.89" + "version": "0.52.6" + }, + "build_script_attrs": { + "data_glob": [ + "**" + ] }, "license": "MIT OR Apache-2.0", "license_ids": [ "Apache-2.0", "MIT" ], - "license_file": "LICENSE-APACHE" + "license_file": "license-apache-2.0" }, - "thiserror 1.0.69": { - "name": "thiserror", - "version": "1.0.69", - "package_url": "https://github.com/dtolnay/thiserror", + "windows_i686_gnu 0.52.6": { + "name": "windows_i686_gnu", + "version": "0.52.6", + "package_url": "https://github.com/microsoft/windows-rs", "repository": { "Http": { - "url": "https://static.crates.io/crates/thiserror/1.0.69/download", - "sha256": "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" + "url": "https://static.crates.io/crates/windows_i686_gnu/0.52.6/download", + "sha256": "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" } }, "targets": [ { "Library": { - "crate_name": "thiserror", + "crate_name": "windows_i686_gnu", "crate_root": "src/lib.rs", "srcs": { "allow_empty": false, @@ -1544,7 +5021,7 @@ } } ], - "library_target_name": "thiserror", + "library_target_name": "windows_i686_gnu", "common_attrs": { "compile_data_glob": [ "**" @@ -1552,23 +5029,14 @@ "deps": { "common": [ { - "id": "thiserror 1.0.69", + "id": "windows_i686_gnu 0.52.6", "target": "build_script_build" } ], "selects": {} }, "edition": "2021", - "proc_macro_deps": { - "common": [ - { - "id": "thiserror-impl 1.0.69", - "target": "thiserror_impl" - } - ], - "selects": {} - }, - "version": "1.0.69" + "version": "0.52.6" }, "build_script_attrs": { "data_glob": [ @@ -1580,22 +5048,22 @@ "Apache-2.0", "MIT" ], - "license_file": "LICENSE-APACHE" + "license_file": "license-apache-2.0" }, - "thiserror-impl 1.0.69": { - "name": "thiserror-impl", - "version": "1.0.69", - "package_url": "https://github.com/dtolnay/thiserror", + "windows_i686_gnullvm 0.52.6": { + "name": "windows_i686_gnullvm", + "version": "0.52.6", + "package_url": "https://github.com/microsoft/windows-rs", "repository": { "Http": { - "url": "https://static.crates.io/crates/thiserror-impl/1.0.69/download", - "sha256": "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" + "url": "https://static.crates.io/crates/windows_i686_gnullvm/0.52.6/download", + "sha256": "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" } }, "targets": [ { - "ProcMacro": { - "crate_name": "thiserror_impl", + "Library": { + "crate_name": "windows_i686_gnullvm", "crate_root": "src/lib.rs", "srcs": { "allow_empty": false, @@ -1604,9 +5072,21 @@ ] } } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } } ], - "library_target_name": "thiserror_impl", + "library_target_name": "windows_i686_gnullvm", "common_attrs": { "compile_data_glob": [ "**" @@ -1614,44 +5094,41 @@ "deps": { "common": [ { - "id": "proc-macro2 1.0.91", - "target": "proc_macro2" - }, - { - "id": "quote 1.0.37", - "target": "quote" - }, - { - "id": "syn 2.0.89", - "target": "syn" + "id": "windows_i686_gnullvm 0.52.6", + "target": "build_script_build" } ], "selects": {} }, "edition": "2021", - "version": "1.0.69" + "version": "0.52.6" + }, + "build_script_attrs": { + "data_glob": [ + "**" + ] }, "license": "MIT OR Apache-2.0", "license_ids": [ "Apache-2.0", "MIT" ], - "license_file": "LICENSE-APACHE" + "license_file": "license-apache-2.0" }, - "typenum 1.17.0": { - "name": "typenum", - "version": "1.17.0", - "package_url": "https://github.com/paholg/typenum", + "windows_i686_msvc 0.52.6": { + "name": "windows_i686_msvc", + "version": "0.52.6", + "package_url": "https://github.com/microsoft/windows-rs", "repository": { "Http": { - "url": "https://static.crates.io/crates/typenum/1.17.0/download", - "sha256": "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + "url": "https://static.crates.io/crates/windows_i686_msvc/0.52.6/download", + "sha256": "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" } }, "targets": [ { "Library": { - "crate_name": "typenum", + "crate_name": "windows_i686_msvc", "crate_root": "src/lib.rs", "srcs": { "allow_empty": false, @@ -1663,8 +5140,8 @@ }, { "BuildScript": { - "crate_name": "build_script_main", - "crate_root": "build/main.rs", + "crate_name": "build_script_build", + "crate_root": "build.rs", "srcs": { "allow_empty": false, "include": [ @@ -1674,7 +5151,7 @@ } } ], - "library_target_name": "typenum", + "library_target_name": "windows_i686_msvc", "common_attrs": { "compile_data_glob": [ "**" @@ -1682,14 +5159,14 @@ "deps": { "common": [ { - "id": "typenum 1.17.0", - "target": "build_script_main" + "id": "windows_i686_msvc 0.52.6", + "target": "build_script_build" } ], "selects": {} }, - "edition": "2018", - "version": "1.17.0" + "edition": "2021", + "version": "0.52.6" }, "build_script_attrs": { "data_glob": [ @@ -1701,22 +5178,22 @@ "Apache-2.0", "MIT" ], - "license_file": "LICENSE" + "license_file": "license-apache-2.0" }, - "ucd-trie 0.1.7": { - "name": "ucd-trie", - "version": "0.1.7", - "package_url": "https://github.com/BurntSushi/ucd-generate", + "windows_x86_64_gnu 0.52.6": { + "name": "windows_x86_64_gnu", + "version": "0.52.6", + "package_url": "https://github.com/microsoft/windows-rs", "repository": { "Http": { - "url": "https://static.crates.io/crates/ucd-trie/0.1.7/download", - "sha256": "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + "url": "https://static.crates.io/crates/windows_x86_64_gnu/0.52.6/download", + "sha256": "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" } }, "targets": [ { "Library": { - "crate_name": "ucd_trie", + "crate_name": "windows_x86_64_gnu", "crate_root": "src/lib.rs", "srcs": { "allow_empty": false, @@ -1725,43 +5202,63 @@ ] } } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } } ], - "library_target_name": "ucd_trie", + "library_target_name": "windows_x86_64_gnu", "common_attrs": { "compile_data_glob": [ "**" ], - "crate_features": { + "deps": { "common": [ - "std" + { + "id": "windows_x86_64_gnu 0.52.6", + "target": "build_script_build" + } ], "selects": {} }, "edition": "2021", - "version": "0.1.7" + "version": "0.52.6" + }, + "build_script_attrs": { + "data_glob": [ + "**" + ] }, "license": "MIT OR Apache-2.0", "license_ids": [ "Apache-2.0", "MIT" ], - "license_file": "LICENSE-APACHE" + "license_file": "license-apache-2.0" }, - "unicode-ident 1.0.14": { - "name": "unicode-ident", - "version": "1.0.14", - "package_url": "https://github.com/dtolnay/unicode-ident", + "windows_x86_64_gnullvm 0.52.6": { + "name": "windows_x86_64_gnullvm", + "version": "0.52.6", + "package_url": "https://github.com/microsoft/windows-rs", "repository": { "Http": { - "url": "https://static.crates.io/crates/unicode-ident/1.0.14/download", - "sha256": "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" + "url": "https://static.crates.io/crates/windows_x86_64_gnullvm/0.52.6/download", + "sha256": "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" } }, "targets": [ { "Library": { - "crate_name": "unicode_ident", + "crate_name": "windows_x86_64_gnullvm", "crate_root": "src/lib.rs", "srcs": { "allow_empty": false, @@ -1770,35 +5267,11 @@ ] } } - } - ], - "library_target_name": "unicode_ident", - "common_attrs": { - "compile_data_glob": [ - "**" - ], - "edition": "2018", - "version": "1.0.14" - }, - "license": "(MIT OR Apache-2.0) AND Unicode-3.0", - "license_ids": [], - "license_file": "LICENSE-APACHE" - }, - "uuid 1.11.0": { - "name": "uuid", - "version": "1.11.0", - "package_url": "https://github.com/uuid-rs/uuid", - "repository": { - "Http": { - "url": "https://static.crates.io/crates/uuid/1.11.0/download", - "sha256": "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" - } - }, - "targets": [ + }, { - "Library": { - "crate_name": "uuid", - "crate_root": "src/lib.rs", + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build.rs", "srcs": { "allow_empty": false, "include": [ @@ -1808,42 +5281,49 @@ } } ], - "library_target_name": "uuid", + "library_target_name": "windows_x86_64_gnullvm", "common_attrs": { "compile_data_glob": [ "**" ], - "crate_features": { + "deps": { "common": [ - "default", - "std" + { + "id": "windows_x86_64_gnullvm 0.52.6", + "target": "build_script_build" + } ], "selects": {} }, - "edition": "2018", - "version": "1.11.0" + "edition": "2021", + "version": "0.52.6" }, - "license": "Apache-2.0 OR MIT", + "build_script_attrs": { + "data_glob": [ + "**" + ] + }, + "license": "MIT OR Apache-2.0", "license_ids": [ "Apache-2.0", "MIT" ], - "license_file": "LICENSE-APACHE" + "license_file": "license-apache-2.0" }, - "version_check 0.9.5": { - "name": "version_check", - "version": "0.9.5", - "package_url": "https://github.com/SergioBenitez/version_check", + "windows_x86_64_msvc 0.52.6": { + "name": "windows_x86_64_msvc", + "version": "0.52.6", + "package_url": "https://github.com/microsoft/windows-rs", "repository": { "Http": { - "url": "https://static.crates.io/crates/version_check/0.9.5/download", - "sha256": "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + "url": "https://static.crates.io/crates/windows_x86_64_msvc/0.52.6/download", + "sha256": "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" } }, "targets": [ { "Library": { - "crate_name": "version_check", + "crate_name": "windows_x86_64_msvc", "crate_root": "src/lib.rs", "srcs": { "allow_empty": false, @@ -1852,27 +5332,53 @@ ] } } + }, + { + "BuildScript": { + "crate_name": "build_script_build", + "crate_root": "build.rs", + "srcs": { + "allow_empty": false, + "include": [ + "**/*.rs" + ] + } + } } ], - "library_target_name": "version_check", + "library_target_name": "windows_x86_64_msvc", "common_attrs": { "compile_data_glob": [ "**" ], - "edition": "2015", - "version": "0.9.5" + "deps": { + "common": [ + { + "id": "windows_x86_64_msvc 0.52.6", + "target": "build_script_build" + } + ], + "selects": {} + }, + "edition": "2021", + "version": "0.52.6" }, - "license": "MIT/Apache-2.0", + "build_script_attrs": { + "data_glob": [ + "**" + ] + }, + "license": "MIT OR Apache-2.0", "license_ids": [ "Apache-2.0", "MIT" ], - "license_file": "LICENSE-APACHE" + "license_file": "license-apache-2.0" } }, "binary_crates": [], "workspace_members": { - "atc-router 1.6.1": "" + "atc-router 1.7.1": "" }, "conditions": { "aarch64-apple-darwin": [ @@ -1890,6 +5396,7 @@ "aarch64-linux-android": [ "aarch64-linux-android" ], + "aarch64-pc-windows-gnullvm": [], "aarch64-pc-windows-msvc": [ "aarch64-pc-windows-msvc" ], @@ -1911,6 +5418,12 @@ "armv7-unknown-linux-gnueabi": [ "armv7-unknown-linux-gnueabi" ], + "cfg(all(any(target_arch = \"x86_64\", target_arch = \"arm64ec\"), target_env = \"msvc\", not(windows_raw_dylib)))": [ + "x86_64-pc-windows-msvc" + ], + "cfg(all(target_arch = \"aarch64\", target_env = \"msvc\", not(windows_raw_dylib)))": [ + "aarch64-pc-windows-msvc" + ], "cfg(all(target_arch = \"aarch64\", target_os = \"linux\"))": [ "aarch64-unknown-linux-gnu", "aarch64-unknown-nixos-gnu" @@ -1921,6 +5434,19 @@ "aarch64-apple-ios-sim" ], "cfg(all(target_arch = \"loongarch64\", target_os = \"linux\"))": [], + "cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\")))": [ + "wasm32-unknown-unknown" + ], + "cfg(all(target_arch = \"x86\", target_env = \"gnu\", not(target_abi = \"llvm\"), not(windows_raw_dylib)))": [ + "i686-unknown-linux-gnu" + ], + "cfg(all(target_arch = \"x86\", target_env = \"msvc\", not(windows_raw_dylib)))": [ + "i686-pc-windows-msvc" + ], + "cfg(all(target_arch = \"x86_64\", target_env = \"gnu\", not(target_abi = \"llvm\"), not(windows_raw_dylib)))": [ + "x86_64-unknown-linux-gnu", + "x86_64-unknown-nixos-gnu" + ], "cfg(any(target_arch = \"aarch64\", target_arch = \"x86_64\", target_arch = \"x86\"))": [ "aarch64-apple-darwin", "aarch64-apple-ios", @@ -1946,12 +5472,47 @@ "x86_64-unknown-nixos-gnu", "x86_64-unknown-none" ], + "cfg(any(unix, target_os = \"wasi\"))": [ + "aarch64-apple-darwin", + "aarch64-apple-ios", + "aarch64-apple-ios-sim", + "aarch64-fuchsia", + "aarch64-linux-android", + "aarch64-unknown-linux-gnu", + "aarch64-unknown-nixos-gnu", + "aarch64-unknown-nto-qnx710", + "arm-unknown-linux-gnueabi", + "armv7-linux-androideabi", + "armv7-unknown-linux-gnueabi", + "i686-apple-darwin", + "i686-linux-android", + "i686-unknown-freebsd", + "i686-unknown-linux-gnu", + "powerpc-unknown-linux-gnu", + "s390x-unknown-linux-gnu", + "wasm32-wasi", + "x86_64-apple-darwin", + "x86_64-apple-ios", + "x86_64-fuchsia", + "x86_64-linux-android", + "x86_64-unknown-freebsd", + "x86_64-unknown-linux-gnu", + "x86_64-unknown-nixos-gnu" + ], + "cfg(target_arch = \"spirv\")": [], + "cfg(target_os = \"hermit\")": [], + "cfg(windows)": [ + "aarch64-pc-windows-msvc", + "i686-pc-windows-msvc", + "x86_64-pc-windows-msvc" + ], "i686-apple-darwin": [ "i686-apple-darwin" ], "i686-linux-android": [ "i686-linux-android" ], + "i686-pc-windows-gnullvm": [], "i686-pc-windows-msvc": [ "i686-pc-windows-msvc" ], @@ -1997,6 +5558,7 @@ "x86_64-linux-android": [ "x86_64-linux-android" ], + "x86_64-pc-windows-gnullvm": [], "x86_64-pc-windows-msvc": [ "x86_64-pc-windows-msvc" ], @@ -2014,7 +5576,8 @@ ] }, "direct_deps": [ - "cidr 0.2.3", + "bitflags 2.7.0", + "cidr 0.3.0", "fnv 1.0.7", "lazy_static 1.5.0", "pest 2.7.14", @@ -2022,5 +5585,7 @@ "regex 1.11.1", "uuid 1.11.0" ], - "direct_dev_deps": [] + "direct_dev_deps": [ + "criterion 0.5.1" + ] } diff --git a/kong-3.10.0-0.rockspec b/kong-3.10.0-0.rockspec index 31f68741f8c..b189153bd6d 100644 --- a/kong-3.10.0-0.rockspec +++ b/kong-3.10.0-0.rockspec @@ -101,6 +101,7 @@ build = { ["kong.clustering.services.sync"] = "kong/clustering/services/sync/init.lua", ["kong.clustering.services.sync.rpc"] = "kong/clustering/services/sync/rpc.lua", ["kong.clustering.services.sync.hooks"] = "kong/clustering/services/sync/hooks.lua", + ["kong.clustering.services.sync.validate"] = "kong/clustering/services/sync/validate.lua", ["kong.clustering.services.sync.strategies.postgres"] = "kong/clustering/services/sync/strategies/postgres.lua", ["kong.cluster_events"] = "kong/cluster_events/init.lua", diff --git a/kong/clustering/compat/removed_fields.lua b/kong/clustering/compat/removed_fields.lua index b52e215fec1..77284a91011 100644 --- a/kong/clustering/compat/removed_fields.lua +++ b/kong/clustering/compat/removed_fields.lua @@ -228,7 +228,8 @@ return { "queue.concurrency_limit", }, }, - [30010000000] = { + -- Any dataplane older than 3.10.0 + [3010000000] = { session = { "hash_subject", "store_metadata", diff --git a/kong/clustering/control_plane.lua b/kong/clustering/control_plane.lua index 9426d38d866..057e117d259 100644 --- a/kong/clustering/control_plane.lua +++ b/kong/clustering/control_plane.lua @@ -9,6 +9,7 @@ local compat = require("kong.clustering.compat") local constants = require("kong.constants") local events = require("kong.clustering.events") local calculate_config_hash = require("kong.clustering.config_helper").calculate_config_hash +local EMPTY = require("kong.tools.table").EMPTY local string = string @@ -260,7 +261,7 @@ function _M:handle_cp_websocket(cert) labels = data.labels, cert_details = dp_cert_details, -- only update rpc_capabilities if dp_id is connected - rpc_capabilities = rpc_peers and rpc_peers[dp_id] or {}, + rpc_capabilities = rpc_peers and rpc_peers[dp_id] or EMPTY, }, { ttl = purge_delay, no_broadcast_crud_event = true, }) if not ok then ngx_log(ngx_ERR, _log_prefix, "unable to update clustering data plane status: ", err, log_suffix) diff --git a/kong/clustering/rpc/concentrator.lua b/kong/clustering/rpc/concentrator.lua index 80d19cad769..6e2ab5785c2 100644 --- a/kong/clustering/rpc/concentrator.lua +++ b/kong/clustering/rpc/concentrator.lua @@ -7,8 +7,12 @@ local queue = require("kong.clustering.rpc.queue") local cjson = require("cjson") local jsonrpc = require("kong.clustering.rpc.json_rpc_v2") local rpc_utils = require("kong.clustering.rpc.utils") +local isarray = require("table.isarray") +local isempty = require("table.isempty") +local tb_insert = table.insert +local type = type local setmetatable = setmetatable local tostring = tostring local pcall = pcall @@ -22,6 +26,7 @@ local ngx_log = ngx.log local ngx_ERR = ngx.ERR local ngx_WARN = ngx.WARN local ngx_DEBUG = ngx.DEBUG +local new_error = jsonrpc.new_error local RESP_CHANNEL_PREFIX = "rpc:resp:" -- format: rpc:resp: @@ -90,6 +95,89 @@ local function enqueue_notifications(notifications, notifications_queue) end +function _M:process_one_response(payload) + assert(payload.jsonrpc == jsonrpc.VERSION) + local payload_id = payload.id + + -- may be some error message for peer + if not payload_id then + if payload.error then + ngx_log(ngx_ERR, "[rpc] RPC failed, code: ", + payload.error.code, ", err: ", + payload.error.message) + end + return + end + + -- response + local cb = self.interest[payload_id] + self.interest[payload_id] = nil -- edge trigger only once + + if not cb then + ngx_log(ngx_WARN, "[rpc] no interest for concentrator response id: ", payload_id, ", dropping it") + return + end + + local res, err = cb(payload) + if not res then + ngx_log(ngx_WARN, "[rpc] concentrator response interest handler failed: id: ", + payload_id, ", err: ", err) + end +end + + +function _M:process_one_request(target_id, reply_to, payload, collection) + if type(payload) ~= "table" then + local res, err = self:_enqueue_rpc_response( + reply_to, + new_error(nil, jsonrpc.INVALID_REQUEST, "not an valid object"), + collection) + if not res then + ngx_log(ngx_WARN, "[rpc] unable to enqueue RPC error: ", err) + end + + return + end + + local payload_id = payload.id + + local res, err = self.manager:_local_call(target_id, payload.method, + payload.params, not payload_id) + + -- notification has no callback or id + if not payload_id then + ngx_log(ngx_DEBUG, "[rpc] notification has no response") + return + end + + if res then + -- call success + res, err = self:_enqueue_rpc_response(reply_to, { + jsonrpc = jsonrpc.VERSION, + id = payload_id, + result = res, + }, collection) + if not res then + ngx_log(ngx_WARN, "[rpc] unable to enqueue RPC call result: ", err) + end + + else + -- call failure + res, err = self:_enqueue_rpc_response(reply_to, { + jsonrpc = jsonrpc.VERSION, + id = payload_id, + error = { + code = jsonrpc.SERVER_ERROR, + message = tostring(err), + } + }, collection) + if not res then + ngx_log(ngx_WARN, "[rpc] unable to enqueue RPC error: ", err) + end + end +end + + function _M:_event_loop(lconn) local notifications_queue = queue.new(4096) local rpc_resp_channel_name = RESP_CHANNEL_PREFIX .. self.worker_id @@ -116,21 +204,16 @@ function _M:_event_loop(lconn) if n.channel == rpc_resp_channel_name then -- an response for a previous RPC call we asked for local payload = cjson_decode(n.payload) - assert(payload.jsonrpc == jsonrpc.VERSION) - - -- response - local cb = self.interest[payload.id] - self.interest[payload.id] = nil -- edge trigger only once - if cb then - local res, err = cb(payload) - if not res then - ngx_log(ngx_WARN, "[rpc] concentrator response interest handler failed: id: ", - payload.id, ", err: ", err) - end + if not isarray(payload) then + -- one rpc response + self:process_one_response(payload) else - ngx_log(ngx_WARN, "[rpc] no interest for concentrator response id: ", payload.id, ", dropping it") + -- batch rpc response + for _, v in ipairs(payload) do + self:process_one_response(v) + end end else @@ -153,45 +236,44 @@ function _M:_event_loop(lconn) local reply_to = assert(call.reply_to, "unknown requester for RPC") - local res, err = self.manager:_local_call(target_id, payload.method, - payload.params, not payload.id) + if not isarray(payload) then + -- one rpc call + self:process_one_request(target_id, reply_to, payload) - -- notification has no callback or id - if not payload.id then - ngx_log(ngx_DEBUG, "[rpc] notification has no response") goto continue end - if res then - -- call success - res, err = self:_enqueue_rpc_response(reply_to, { - jsonrpc = jsonrpc.VERSION, - id = payload.id, - result = res, - }) + -- rpc call with an empty Array + if isempty(payload) then + local res, err = self:_enqueue_rpc_response( + reply_to, + new_error(nil, jsonrpc.INVALID_REQUEST, "empty batch array")) if not res then - ngx_log(ngx_WARN, "[rpc] unable to enqueue RPC call result: ", err) + ngx_log(ngx_WARN, "[rpc] unable to enqueue RPC error: ", err) end - else - -- call failure - res, err = self:_enqueue_rpc_response(reply_to, { - jsonrpc = jsonrpc.VERSION, - id = payload.id, - error = { - code = jsonrpc.SERVER_ERROR, - message = tostring(err), - } - }) + goto continue + end + + -- batching rpc call + + local collection = {} + + for _, v in ipairs(payload) do + self:process_one_request(target_id, reply_to, v, collection) + end + + if not isempty(collection) then + local res, err = self:_enqueue_rpc_response(reply_to, collection) if not res then - ngx_log(ngx_WARN, "[rpc] unable to enqueue RPC error: ", err) + ngx_log(ngx_WARN, "[rpc] unable to enqueue RPC call result: ", err) end end ::continue:: - end - end - end + end -- for _, call + end -- if n.channel == rpc_resp_channel_name + end -- while true local res, err = lconn:wait_for_notification() if not res then @@ -217,7 +299,7 @@ function _M:_event_loop(lconn) else notifications_queue:push(res) end - end + end -- while not exiting() end @@ -270,7 +352,14 @@ end -- enqueue a RPC response from CP worker with ID worker_id -function _M:_enqueue_rpc_response(worker_id, payload) +-- collection is only for rpc batch call. +-- if collection is nil, it means the rpc is a single call. +function _M:_enqueue_rpc_response(worker_id, payload, collection) + if collection then + tb_insert(collection, payload) + return + end + local sql = string_format("SELECT pg_notify(%s, %s);", self.db.connector:escape_literal(RESP_CHANNEL_PREFIX .. worker_id), self.db.connector:escape_literal(cjson_encode(payload))) diff --git a/kong/clustering/rpc/manager.lua b/kong/clustering/rpc/manager.lua index f1918398c76..fb40ace1a6e 100644 --- a/kong/clustering/rpc/manager.lua +++ b/kong/clustering/rpc/manager.lua @@ -34,7 +34,7 @@ local parse_proxy_url = require("kong.clustering.utils").parse_proxy_url local _log_prefix = "[rpc] " -local RPC_MATA_V1 = "kong.meta.v1" +local RPC_META_V1 = "kong.meta.v1" local RPC_SNAPPY_FRAMED = "x-snappy-framed" @@ -56,6 +56,11 @@ function _M.new(conf, node_id) cluster_cert = assert(clustering_tls.get_cluster_cert(conf)), cluster_cert_key = assert(clustering_tls.get_cluster_cert_key(conf)), callbacks = callbacks.new(), + + __batch_size = 0, -- rpc batching size, 0 means disable. + -- currently, we don't have Lua interface to initiate + -- a batch call, any value `> 0` should be considered + -- as testing code. } if conf.role == "control_plane" then @@ -159,7 +164,7 @@ function _M:_handle_meta_call(c, cert) local payload = cjson_decode(data) assert(payload.jsonrpc == jsonrpc.VERSION) - if payload.method ~= RPC_MATA_V1 .. ".hello" then + if payload.method ~= RPC_META_V1 .. ".hello" then return nil, "wrong RPC meta call: " .. tostring(payload.method) end @@ -427,7 +432,7 @@ function _M:handle_websocket() -- choice a proper protocol for _, v in ipairs(protocols) do -- now we only support kong.meta.v1 - if RPC_MATA_V1 == string_tools.strip(v) then + if RPC_META_V1 == string_tools.strip(v) then meta_v1_supported = true break end @@ -447,7 +452,7 @@ function _M:handle_websocket() end -- now we only use kong.meta.v1 - ngx.header["Sec-WebSocket-Protocol"] = RPC_MATA_V1 + ngx.header["Sec-WebSocket-Protocol"] = RPC_META_V1 local wb, err = server:new(WS_OPTS) if not wb then @@ -524,7 +529,7 @@ function _M:connect(premature, node_id, host, path, cert, key) ssl_verify = true, client_cert = cert, client_priv_key = key, - protocols = RPC_MATA_V1, + protocols = RPC_META_V1, } if self.conf.cluster_mtls == "shared" then @@ -571,7 +576,7 @@ function _M:connect(premature, node_id, host, path, cert, key) -- should like "kong.meta.v1" local meta_cap = resp_headers["sec_websocket_protocol"] - if meta_cap ~= RPC_MATA_V1 then + if meta_cap ~= RPC_META_V1 then ngx_log(ngx_ERR, _log_prefix, "did not support protocol : ", meta_cap) c:send_close() -- can't do much if this fails goto err @@ -625,4 +630,12 @@ function _M:get_peer_info(node_id) end +-- Currently, this function only for testing purpose, +-- we don't have a Lua interface to initiate a batch call yet. +function _M:__set_batch(n) + assert(type(n) == "number" and n >= 0) + self.__batch_size = n +end + + return _M diff --git a/kong/clustering/rpc/socket.lua b/kong/clustering/rpc/socket.lua index 2044acf170a..1436f5edb47 100644 --- a/kong/clustering/rpc/socket.lua +++ b/kong/clustering/rpc/socket.lua @@ -11,8 +11,13 @@ local utils = require("kong.clustering.rpc.utils") local queue = require("kong.clustering.rpc.queue") local jsonrpc = require("kong.clustering.rpc.json_rpc_v2") local constants = require("kong.constants") +local isarray = require("table.isarray") +local isempty = require("table.isempty") +local tb_clear = require("table.clear") +local tb_insert = table.insert +local type = type local assert = assert local unpack = unpack local string_format = string.format @@ -59,7 +64,30 @@ function _M:_get_next_id() end -function _M._dispatch(premature, self, cb, payload) +function _M:push_request(msg) + return self.outgoing:push(msg) +end + + +-- collection is only for rpc batch call. +-- if collection is nil, it means the rpc is a single call. +function _M:push_response(msg, err_prefix, collection) + -- may be a batch + if collection then + tb_insert(collection, msg) + return true + end + + local res, err = self.outgoing:push(msg) + if not res then + return nil, err_prefix .. err + end + + return true +end + + +function _M._dispatch(premature, self, cb, payload, collection) if premature then return end @@ -73,10 +101,11 @@ function _M._dispatch(premature, self, cb, payload) return end - res, err = self.outgoing:push(new_error(payload.id, jsonrpc.SERVER_ERROR, - err)) + res, err = self:push_response(new_error(payload.id, jsonrpc.SERVER_ERROR, err), + "[rpc] unable to push RPC call error: ", + collection) if not res then - ngx_log(ngx_WARN, "[rpc] unable to push RPC call error: ", err) + ngx_log(ngx_WARN, err) end return @@ -89,14 +118,112 @@ function _M._dispatch(premature, self, cb, payload) end -- success - res, err = self.outgoing:push({ + res, err = self:push_response({ jsonrpc = jsonrpc.VERSION, id = payload.id, result = res, - }) + }, "[rpc] unable to push RPC call result: ", collection) if not res then - ngx_log(ngx_WARN, "[rpc] unable to push RPC call result: ", err) + ngx_log(ngx_WARN, err) + end +end + + +function _M:process_rpc_msg(payload, collection) + if type(payload) ~= "table" then + local res, err = self:push_response( + new_error(nil, jsonrpc.INVALID_REQUEST, "not a valid object"), + collection) + if not res then + return nil, err + end + + return true end + + assert(payload.jsonrpc == jsonrpc.VERSION) + + local payload_id = payload.id + local payload_method = payload.method + + if payload_method then + -- invoke + + ngx_log(ngx_DEBUG, "[rpc] got RPC call: ", payload_method, " (id: ", payload_id, ")") + + local dispatch_cb = self.manager.callbacks.callbacks[payload_method] + if not dispatch_cb and payload_id then + local res, err = self:push_response(new_error(payload_id, jsonrpc.METHOD_NOT_FOUND), + "unable to send \"METHOD_NOT_FOUND\" error back to client: ", + collection) + if not res then + return nil, err + end + + return true + end + + local res, err + + -- call dispatch + + if collection then + + -- TODO: async call by using a new manager of timer + -- collection is not nil, it means it is a batch call + -- we should call sync function + _M._dispatch(nil, self, dispatch_cb, payload, collection) + + else + + -- collection is nil, it means it is a single call + -- we should call async function + local name = string_format("JSON-RPC callback for node_id: %s, id: %d, method: %s", + self.node_id, payload_id or 0, payload_method) + res, err = kong.timer:named_at(name, 0, _M._dispatch, self, dispatch_cb, payload) + + if not res and payload_id then + local reso, erro = self:push_response(new_error(payload_id, jsonrpc.INTERNAL_ERROR), + "unable to send \"INTERNAL_ERROR\" error back to client: ", + collection) + if not reso then + return nil, erro + end + + return nil, "unable to dispatch JSON-RPC callback: " .. err + end + end + + else + -- may be some error message for peer + if not payload_id then + if payload.error then + ngx_log(ngx.ERR, "[rpc] RPC failed, code: ", + payload.error.code, ", err: ", + payload.error.message) + end + + return true + end + + -- response, don't care about `collection` + local interest_cb = self.interest[payload_id] + self.interest[payload_id] = nil -- edge trigger only once + + if not interest_cb then + ngx_log(ngx_WARN, "[rpc] no interest for RPC response id: ", payload_id, ", dropping it") + + return true + end + + local res, err = interest_cb(payload) + if not res then + ngx_log(ngx_WARN, "[rpc] RPC response interest handler failed: id: ", + payload_id, ", err: ", err) + end + end -- if payload.method + + return true end @@ -120,9 +247,9 @@ function _M:start() end if waited > CLUSTERING_PING_INTERVAL then - local res, err = self.outgoing:push(PING_TYPE) + local res, err = self:push_response(PING_TYPE, "unable to send ping: ") if not res then - return nil, "unable to send ping: " .. err + return nil, err end end @@ -133,9 +260,9 @@ function _M:start() last_seen = ngx_time() if typ == "ping" then - local res, err = self.outgoing:push(PONG_TYPE) + local res, err = self:push_response(PONG_TYPE, "unable to handle ping: ") if not res then - return nil, "unable to handle ping: " .. err + return nil, err end goto continue @@ -154,93 +281,144 @@ function _M:start() assert(typ == "binary") local payload = decompress_payload(data) - assert(payload.jsonrpc == jsonrpc.VERSION) - if payload.method then - -- invoke - - ngx_log(ngx_DEBUG, "[rpc] got RPC call: ", payload.method, " (id: ", payload.id, ")") + if not payload then + local res, err = self:push_response( + new_error(nil, jsonrpc.PARSE_ERROR)) + if not res then + return nil, err + end - local dispatch_cb = self.manager.callbacks.callbacks[payload.method] - if not dispatch_cb and payload.id then - local res, err = self.outgoing:push(new_error(payload.id, jsonrpc.METHOD_NOT_FOUND)) - if not res then - return nil, "unable to send \"METHOD_NOT_FOUND\" error back to client: " .. err - end + goto continue + end - goto continue + -- single rpc call + if not isarray(payload) then + local ok, err = self:process_rpc_msg(payload) + if not ok then + return nil, err end - -- call dispatch - local res, err = kong.timer:named_at(string_format("JSON-RPC callback for node_id: %s, id: %d, method: %s", - self.node_id, payload.id or 0, payload.method), - 0, _M._dispatch, self, dispatch_cb, payload) - if not res and payload.id then - local reso, erro = self.outgoing:push(new_error(payload.id, jsonrpc.INTERNAL_ERROR)) - if not reso then - return nil, "unable to send \"INTERNAL_ERROR\" error back to client: " .. erro - end + goto continue + end - return nil, "unable to dispatch JSON-RPC callback: " .. err + -- rpc call with an empty array + if isempty(payload) then + local res, err = self:push_response( + new_error(nil, jsonrpc.INVALID_REQUEST, "empty batch array")) + if not res then + return nil, err end - else - -- response - local interest_cb = self.interest[payload.id] - self.interest[payload.id] = nil -- edge trigger only once + goto continue + end - if not interest_cb then - ngx_log(ngx_WARN, "[rpc] no interest for RPC response id: ", payload.id, ", dropping it") + -- batch rpc call - goto continue - end + local collection = {} - local res, err = interest_cb(payload) - if not res then - ngx_log(ngx_WARN, "[rpc] RPC response interest handler failed: id: ", - payload.id, ", err: ", err) + ngx_log(ngx_DEBUG, "[rpc] got batch RPC call: ", #payload) + + for _, v in ipairs(payload) do + local ok, err = self:process_rpc_msg(v, collection) + if not ok then + return nil, err end end + -- may be responses or all notifications + if isempty(collection) then + goto continue + end + + assert(isarray(collection)) + + local res, err = self:push_response(collection, + "[rpc] unable to push RPC call result: ") + if not res then + return nil, err + end + ::continue:: end end) self.write_thread = ngx.thread.spawn(function() + local batch_requests = {} + while not exiting() do + -- TODO: find the more proper timeout local payload, err = self.outgoing:pop(5) if err then return nil, err end - if payload then - if payload == PING_TYPE then - local _, err = self.wb:send_ping() - if err then - return nil, "failed to send PING frame to peer: " .. err - - else - ngx_log(ngx_DEBUG, "[rpc] sent PING frame to peer") + -- timeout + if not payload then + if not isempty(batch_requests) then + local bytes, err = self.wb:send_binary(compress_payload(batch_requests)) + if not bytes then + return nil, err end - elseif payload == PONG_TYPE then - local _, err = self.wb:send_pong() - if err then - return nil, "failed to send PONG frame to peer: " .. err + ngx_log(ngx_DEBUG, "[rpc] sent batch RPC call: ", #batch_requests) - else - ngx_log(ngx_DEBUG, "[rpc] sent PONG frame to peer") - end + tb_clear(batch_requests) + end + goto continue + end + + if payload == PING_TYPE then + local _, err = self.wb:send_ping() + if err then + return nil, "failed to send PING frame to peer: " .. err + + else + ngx_log(ngx_DEBUG, "[rpc] sent PING frame to peer") + end + goto continue + end + + if payload == PONG_TYPE then + local _, err = self.wb:send_pong() + if err then + return nil, "failed to send PONG frame to peer: " .. err else - assert(type(payload) == "table") + ngx_log(ngx_DEBUG, "[rpc] sent PONG frame to peer") + end + goto continue + end + + assert(type(payload) == "table") - local bytes, err = self.wb:send_binary(compress_payload(payload)) + -- batch enabled + local batch_size = self.manager.__batch_size + + if batch_size > 0 then + tb_insert(batch_requests, payload) + + -- send batch requests + local n = #batch_requests + if n >= batch_size then + local bytes, err = self.wb:send_binary(compress_payload(batch_requests)) if not bytes then return nil, err end + + ngx_log(ngx_DEBUG, "[rpc] sent batch RPC call: ", n) + + tb_clear(batch_requests) end + goto continue end + + local bytes, err = self.wb:send_binary(compress_payload(payload)) + if not bytes then + return nil, err + end + + ::continue:: end end) end @@ -290,7 +468,7 @@ function _M:call(node_id, method, params, callback) self.interest[id] = callback end - return self.outgoing:push({ + return self:push_request({ jsonrpc = jsonrpc.VERSION, method = method, params = params, diff --git a/kong/clustering/services/sync/rpc.lua b/kong/clustering/services/sync/rpc.lua index b46f7960c08..47329a3107e 100644 --- a/kong/clustering/services/sync/rpc.lua +++ b/kong/clustering/services/sync/rpc.lua @@ -8,12 +8,15 @@ local constants = require("kong.constants") local concurrency = require("kong.concurrency") local isempty = require("table.isempty") local events = require("kong.runloop.events") +local EMPTY = require("kong.tools.table").EMPTY +local validate_deltas = require("kong.clustering.services.sync.validate").validate_deltas local insert_entity_for_txn = declarative.insert_entity_for_txn local delete_entity_for_txn = declarative.delete_entity_for_txn local DECLARATIVE_HASH_KEY = constants.DECLARATIVE_HASH_KEY local CLUSTERING_DATA_PLANES_LATEST_VERSION_KEY = constants.CLUSTERING_DATA_PLANES_LATEST_VERSION_KEY +local DECLARATIVE_EMPTY_CONFIG_HASH = constants.DECLARATIVE_EMPTY_CONFIG_HASH local DECLARATIVE_DEFAULT_WORKSPACE_KEY = constants.DECLARATIVE_DEFAULT_WORKSPACE_KEY local CLUSTERING_SYNC_STATUS = constants.CLUSTERING_SYNC_STATUS local SYNC_MUTEX_OPTS = { name = "get_delta", timeout = 0, } @@ -22,10 +25,11 @@ local MAX_RETRY = 5 local assert = assert local ipairs = ipairs -local fmt = string.format local ngx_null = ngx.null local ngx_log = ngx.log local ngx_ERR = ngx.ERR +local ngx_WARN = ngx.WARN +local ngx_INFO = ngx.INFO local ngx_DEBUG = ngx.DEBUG @@ -54,13 +58,18 @@ local function full_sync_result() end +local function get_current_version() + return declarative.get_current_hash() or DECLARATIVE_EMPTY_CONFIG_HASH +end + + function _M:init_cp(manager) local purge_delay = manager.conf.cluster_data_plane_purge_delay -- CP -- Method: kong.sync.v2.get_delta -- Params: versions: list of current versions of the database - -- example: { default = { version = 1000, }, } + -- example: { default = { version = "1000", }, } manager.callbacks:register("kong.sync.v2.get_delta", function(node_id, current_versions) ngx_log(ngx_DEBUG, "[kong.sync.v2] config push (connected client)") @@ -75,7 +84,7 @@ function _M:init_cp(manager) return nil, "default namespace does not exist inside params" end - -- { default = { version = 1000, }, } + -- { default = { version = "1000", }, } local default_namespace_version = default_namespace.version local node_info = assert(kong.rpc:get_peer_info(node_id)) @@ -88,8 +97,8 @@ function _M:init_cp(manager) labels = node_info.labels, -- get from rpc call cert_details = node_info.cert_details, -- get from rpc call sync_status = CLUSTERING_SYNC_STATUS.NORMAL, - config_hash = fmt("%032d", default_namespace_version), - rpc_capabilities = rpc_peers and rpc_peers[node_id] or {}, + config_hash = default_namespace_version, + rpc_capabilities = rpc_peers and rpc_peers[node_id] or EMPTY, }, { ttl = purge_delay, no_broadcast_crud_event = true, }) if not ok then ngx_log(ngx_ERR, "unable to update clustering data plane status: ", err) @@ -100,8 +109,9 @@ function _M:init_cp(manager) return nil, err end - if default_namespace_version == 0 or - default_namespace_version < latest_version then + -- string comparison effectively does the same as number comparison + if not self.strategy:is_valid_version(default_namespace_version) or + default_namespace_version ~= latest_version then return full_sync_result() end @@ -115,7 +125,7 @@ function _M:init_dp(manager) -- DP -- Method: kong.sync.v2.notify_new_version -- Params: new_versions: list of namespaces and their new versions, like: - -- { default = { new_version = 1000, }, } + -- { default = { new_version = "1000", }, } manager.callbacks:register("kong.sync.v2.notify_new_version", function(node_id, new_versions) -- TODO: currently only default is supported, and anything else is ignored local default_new_version = new_versions.default @@ -128,13 +138,15 @@ function _M:init_dp(manager) return nil, "'new_version' key does not exist" end - local lmdb_ver = tonumber(declarative.get_current_hash()) or 0 + local lmdb_ver = get_current_version() if lmdb_ver < version then -- set lastest version to shm kong_shm:set(CLUSTERING_DATA_PLANES_LATEST_VERSION_KEY, version) return self:sync_once() end + ngx_log(ngx_DEBUG, "no sync runs, version is ", version) + return true end) end @@ -167,16 +179,80 @@ local function is_rpc_ready() end +-- tell cp we already updated the version by rpc notification +local function update_status(ver) + local msg = { default = { version = ver, }, } + + local ok, err = kong.rpc:notify("control_plane", "kong.sync.v2.get_delta", msg) + if not ok then + ngx_log(ngx_ERR, "update status notification failed: ", err) + end +end + + +local function lmdb_update(db, t, delta, opts, is_full_sync) + local delta_type = delta.type + local delta_entity = delta.entity + + -- upsert the entity + -- delete if exists + local old_entity, err = db[delta_type]:select(delta_entity) + if err then + return nil, err + end + + if old_entity and not is_full_sync then + local res, err = delete_entity_for_txn(t, delta_type, old_entity, opts) + if not res then + return nil, err + end + end + + local res, err = insert_entity_for_txn(t, delta_type, delta_entity, opts) + if not res then + return nil, err + end + + if is_full_sync then + return nil + end + + return { delta_type, old_entity and "update" or "create", delta_entity, old_entity, } +end + + +local function lmdb_delete(db, t, delta, opts, is_full_sync) + local delta_type = delta.type + + local old_entity, err = db[delta_type]:select(delta.pk, opts) + if err then + return nil, err + end + + -- full sync requires extra torlerance for missing entities + if not old_entity then + return nil + end + + local res, err = delete_entity_for_txn(t, delta_type, old_entity, opts) + if not res then + return nil, err + end + + if is_full_sync then + return nil + end + + return { delta_type, "delete", old_entity, } +end + + local function do_sync() if not is_rpc_ready() then return nil, "rpc is not ready" end - local msg = { default = - { version = - tonumber(declarative.get_current_hash()) or 0, - }, - } + local msg = { default = { version = get_current_version(), }, } local ns_deltas, err = kong.rpc:call("control_plane", "kong.sync.v2.get_delta", msg) if not ns_deltas then @@ -192,6 +268,7 @@ local function do_sync() return nil, "default namespace does not exist inside params" end + local wipe = ns_delta.wipe local deltas = ns_delta.deltas if not deltas then @@ -217,98 +294,61 @@ local function do_sync() end assert(type(kong.default_workspace) == "string") + -- validate deltas + local ok, err = validate_deltas(deltas, wipe) + if not ok then + return nil, err + end + local t = txn.begin(512) - local wipe = ns_delta.wipe if wipe then + ngx_log(ngx_INFO, "[kong.sync.v2] full sync begins") + t:db_drop(false) end local db = kong.db - local version = 0 + local version = "" local opts = {} local crud_events = {} local crud_events_n = 0 -- delta should look like: - -- { type = ..., entity = { ... }, version = 1, ws_id = ..., } + -- { type = ..., entity = { ... }, version = "1", ws_id = ..., } for _, delta in ipairs(deltas) do local delta_version = delta.version local delta_type = delta.type local delta_entity = delta.entity - local ev -- delta should have ws_id to generate the correct lmdb key -- if entity is workspaceable -- set the correct workspace for item opts.workspace = delta.ws_id - if delta_entity ~= nil and delta_entity ~= ngx_null then - -- upsert the entity - -- does the entity already exists? - local old_entity, err = db[delta_type]:select(delta_entity) - if err then - return nil, err - end - - -- If we will wipe lmdb, we don't need to delete it from lmdb. - if old_entity and not wipe then - local res, err = delete_entity_for_txn(t, delta_type, old_entity, opts) - if not res then - return nil, err - end - end - - local res, err = insert_entity_for_txn(t, delta_type, delta_entity, opts) - if not res then - return nil, err - end - - ngx_log(ngx_DEBUG, - "[kong.sync.v2] update entity", - ", version: ", delta_version, - ", type: ", delta_type) - - -- wipe the whole lmdb, should not have events - if not wipe then - ev = { delta_type, old_entity and "update" or "create", delta_entity, old_entity, } - end - - else - -- delete the entity, opts for getting correct lmdb key - local old_entity, err = db[delta_type]:select(delta.pk, opts) -- composite key - if err then - return nil, err - end - - -- If we will wipe lmdb, we don't need to delete it from lmdb. - if old_entity and not wipe then - local res, err = delete_entity_for_txn(t, delta_type, old_entity, opts) - if not res then - return nil, err - end - end - - ngx_log(ngx_DEBUG, - "[kong.sync.v2] delete entity", - ", version: ", delta_version, - ", type: ", delta_type) - - -- wipe the whole lmdb, should not have events - if not wipe then - ev = { delta_type, "delete", old_entity, } - end - end -- if delta_entity ~= nil and delta_entity ~= ngx_null - - -- wipe the whole lmdb, should not have events - if not wipe then + local is_update = delta_entity ~= nil and delta_entity ~= ngx_null + local operation_name = is_update and "update" or "delete" + local operation = is_update and lmdb_update or lmdb_delete + + -- log the operation before executing it, so when failing we know what entity caused it + ngx_log(ngx_DEBUG, + "[kong.sync.v2] ", operation_name, " entity", + ", version: ", delta_version, + ", type: ", delta_type) + + local ev, err = operation(db, t, delta, opts, wipe) + if err then + return nil, err + end + + if ev then crud_events_n = crud_events_n + 1 crud_events[crud_events_n] = ev end -- delta.version should not be nil or ngx.null - assert(type(delta_version) == "number") + assert(type(delta_version) == "string") if delta_version ~= version then version = delta_version @@ -316,10 +356,12 @@ local function do_sync() end -- for _, delta -- store current sync version - t:set(DECLARATIVE_HASH_KEY, fmt("%032d", version)) + t:set(DECLARATIVE_HASH_KEY, version) - -- store the correct default workspace uuid - if default_ws_changed then + -- record the default workspace into LMDB for any of the following case: + -- * wipe is false, but the default workspace has been changed + -- * wipe is true (full sync) + if default_ws_changed or wipe then t:set(DECLARATIVE_DEFAULT_WORKSPACE_KEY, kong.default_workspace) end @@ -329,6 +371,8 @@ local function do_sync() end if wipe then + ngx_log(ngx_INFO, "[kong.sync.v2] full sync ends") + kong.core_cache:purge() kong.cache:purge() @@ -362,28 +406,19 @@ local function sync_handler(premature) if not res and err ~= "timeout" then ngx_log(ngx_ERR, "unable to create worker mutex and sync: ", err) end -end - - -local sync_once_impl - - -local function start_sync_once_timer(retry_count) - local ok, err = kong.timer:at(0, sync_once_impl, retry_count or 0) - if not ok then - return nil, err - end - return true + return res, err end -function sync_once_impl(premature, retry_count) +local function sync_once_impl(premature, retry_count) if premature then return end - sync_handler() + local version_before_sync = get_current_version() + + local _, err = sync_handler() -- check if "kong.sync.v2.notify_new_version" updates the latest version @@ -393,20 +428,41 @@ function sync_once_impl(premature, retry_count) return end - local current_version = tonumber(declarative.get_current_hash()) or 0 + local current_version = get_current_version() if current_version >= latest_notified_version then ngx_log(ngx_DEBUG, "version already updated") + + -- version changed, we should update status + if version_before_sync ~= current_version then + update_status(current_version) + end + return end -- retry if the version is not updated retry_count = retry_count or 0 - if retry_count > MAX_RETRY then - ngx_log(ngx_ERR, "sync_once retry count exceeded. retry_count: ", retry_count) + + if retry_count >= MAX_RETRY then + ngx_log(ngx_WARN, "sync_once retry count exceeded. retry_count: ", retry_count) return end - return start_sync_once_timer(retry_count + 1) + -- we do not count a timed out sync. just retry + if err ~= "timeout" then + retry_count = retry_count + 1 + end + + -- in some cases, the new spawned timer will be switched to immediately, + -- preventing the coroutine who possesses the mutex to run + -- to let other coroutines has a chance to run + local ok, err = kong.timer:at(0.1, sync_once_impl, retry_count) + -- this is a workaround for a timerng bug, where tail recursion causes failure + -- ok could be a string so let's convert it to boolean + if not ok then + return nil, err + end + return true end diff --git a/kong/clustering/services/sync/strategies/postgres.lua b/kong/clustering/services/sync/strategies/postgres.lua index 7bc0784c6e6..06da15cabdc 100644 --- a/kong/clustering/services/sync/strategies/postgres.lua +++ b/kong/clustering/services/sync/strategies/postgres.lua @@ -2,9 +2,17 @@ local _M = {} local _MT = { __index = _M } +local sub = string.sub +local fmt = string.format local ngx_null = ngx.null +-- version string should look like: "v02_0000" +local VER_PREFIX = "v02_" +local VER_PREFIX_LEN = #VER_PREFIX +local VERSION_FMT = VER_PREFIX .. "%028x" + + function _M.new(db) local self = { connector = db.connector, @@ -44,10 +52,15 @@ function _M:get_latest_version() local ver = res[1] and res[1].max if ver == ngx_null then - return 0 + return fmt(VERSION_FMT, 0) end - return ver + return fmt(VERSION_FMT, ver) +end + + +function _M:is_valid_version(str) + return sub(str, 1, VER_PREFIX_LEN) == VER_PREFIX end diff --git a/kong/clustering/services/sync/validate.lua b/kong/clustering/services/sync/validate.lua new file mode 100644 index 00000000000..8b5aa91ccf9 --- /dev/null +++ b/kong/clustering/services/sync/validate.lua @@ -0,0 +1,69 @@ +local declarative = require("kong.db.declarative") +local declarative_config = require("kong.db.schema.others.declarative_config") + + +local null = ngx.null +local pk_string = declarative_config.pk_string +local validate_references_sync = declarative_config.validate_references_sync +local pretty_print_error = declarative.pretty_print_error + + +local function validate_deltas(deltas, is_full_sync) + + local errs = {} + + -- generate deltas table mapping primary key string to entity item + local deltas_map = {} + + local db = kong.db + + for _, delta in ipairs(deltas) do + local delta_type = delta.type + local delta_entity = delta.entity + + if delta_entity ~= nil and delta_entity ~= null then + -- table: primary key string -> entity + local schema = db[delta_type].schema + local pk = schema:extract_pk_values(delta_entity) + local pks = pk_string(schema, pk) + + deltas_map[pks] = delta_entity + + -- validate entity + local dao = kong.db[delta_type] + if dao then + -- CP will insert ws_id into the entity, which will be validated as an + -- unknown field. + -- TODO: On the CP side, remove ws_id from the entity and set it only + -- in the delta. + local ws_id = delta_entity.ws_id + delta_entity.ws_id = nil -- clear ws_id + + local ok, err_t = dao.schema:validate(delta_entity) + + delta_entity.ws_id = ws_id -- restore ws_id + + if not ok then + errs[#errs + 1] = { [delta_type] = err_t } + end + end + end + end + + if next(errs) then + return nil, pretty_print_error(errs, "deltas") + end + + -- validate references + local ok, err_t = validate_references_sync(deltas, deltas_map, is_full_sync) + if not ok then + return nil, pretty_print_error(err_t) + end + + return true +end + + +return { + validate_deltas = validate_deltas, +} diff --git a/kong/db/declarative/init.lua b/kong/db/declarative/init.lua index 1f209657f0e..c58f40eb088 100644 --- a/kong/db/declarative/init.lua +++ b/kong/db/declarative/init.lua @@ -263,5 +263,8 @@ _M.delete_entity_for_txn = declarative_import.delete_entity_for_txn _M.workspace_id = declarative_import.workspace_id _M.GLOBAL_WORKSPACE_TAG = declarative_import.GLOBAL_WORKSPACE_TAG +-- helpful function +_M.pretty_print_error = pretty_print_error + return _M diff --git a/kong/db/schema/others/declarative_config.lua b/kong/db/schema/others/declarative_config.lua index 104fb917441..e564104beca 100644 --- a/kong/db/schema/others/declarative_config.lua +++ b/kong/db/schema/others/declarative_config.lua @@ -14,6 +14,7 @@ local null = ngx.null local type = type local next = next local pairs = pairs +local fmt = string.format local yield = require("kong.tools.yield").yield local ipairs = ipairs local insert = table.insert @@ -331,7 +332,7 @@ end local function ws_id_for(item) - if item.ws_id == nil or item.ws_id == ngx.null then + if item.ws_id == nil or item.ws_id == null then return "*" end return item.ws_id @@ -413,7 +414,7 @@ local function populate_references(input, known_entities, by_id, by_key, expecte local key = use_key and item[endpoint_key] local failed = false - if key and key ~= ngx.null then + if key and key ~= null then local ok = add_to_by_key(by_key, entity_schema, item, entity, key) if not ok then add_error(errs, parent_entity, parent_idx, entity, i, @@ -506,6 +507,71 @@ local function validate_references(self, input) end +-- TODO: Completely implement validate_references_sync without associating it +-- to declarative config. Currently, we will use the dc-generated +-- foreign_references table to accelerate iterating over entity foreign keys. +function DeclarativeConfig.validate_references_sync(deltas, deltas_map, is_full_sync) + local errs = {} + + for _, delta in ipairs(deltas) do + local item_type = delta.type + local item = delta.entity + local ws_id = delta.ws_id or kong.default_workspace + + local foreign_refs = foreign_references[item_type] + + if not item or item == null or not foreign_refs then + goto continue + end + + for k, v in pairs(item) do + + -- Try to check if item's some foreign key exists in the deltas or LMDB. + -- For example, `item[k]` could be `["service"]`, we need + -- to find the referenced foreign service entity for this router entity. + + local foreign_entity = foreign_refs[k] + + if foreign_entity and v ~= null then -- k is foreign key + + local dao = kong.db[foreign_entity] + + -- try to find it in deltas + local pks = DeclarativeConfig.pk_string(dao.schema, v) + local fvalue = deltas_map[pks] + + -- try to find it in DB (LMDB) + if not fvalue and not is_full_sync then + fvalue = dao:select(v, { workspace = ws_id }) + end + + -- record an error if not finding its foreign reference + if not fvalue then + errs[item_type] = errs[item_type] or {} + errs[item_type][foreign_entity] = errs[item_type][foreign_entity] or {} + + local msg = fmt("could not find %s's foreign refrences %s (%s)", + item_type, foreign_entity, + type(v) == "string" and v or cjson_encode(v)) + + insert(errs[item_type][foreign_entity], msg) + end + end -- if foreign_entity and v ~= null + + end -- for k, v in pairs(item) + + ::continue:: + end -- for _, delta in ipairs(deltas) + + + if next(errs) then + return nil, errs + end + + return true +end + + -- This is a best-effort generation of a cache-key-like identifier -- to feed the hash when generating deterministic UUIDs. -- We do not use the actual `cache_key` function from the DAO because @@ -626,7 +692,7 @@ local function generate_ids(input, known_entities, parent_entity) local child_key if parent_entity then local parent_schema = all_schemas[parent_entity] - if parent_schema.fields[entity] then + if parent_schema.fields[entity] and not parent_schema.fields[entity].transient then goto continue end parent_fk = parent_schema:extract_pk_values(input) @@ -663,7 +729,7 @@ local function populate_ids_for_validation(input, known_entities, parent_entity, local child_key if parent_entity then local parent_schema = all_schemas[parent_entity] - if parent_schema.fields[entity] then + if parent_schema.fields[entity] and not parent_schema.fields[entity].transient then goto continue end parent_fk = parent_schema:extract_pk_values(input) @@ -860,7 +926,7 @@ local function flatten(self, input) if field.unique then local flat_value = flat_entry[name] - if flat_value and flat_value ~= ngx.null then + if flat_value and flat_value ~= null then local unique_key = get_unique_key(schema, entry, field, flat_value) uniques[name] = uniques[name] or {} if uniques[name][unique_key] then diff --git a/kong/init.lua b/kong/init.lua index 8c4d4514221..bac5e301066 100644 --- a/kong/init.lua +++ b/kong/init.lua @@ -1383,8 +1383,14 @@ function Kong.balancer() -- upstream_host is SNI pool = pool .. "|" .. var.upstream_host - if ctx.service and ctx.service.client_certificate then - pool = pool .. "|" .. ctx.service.client_certificate.id + local ctx_service = ctx.service + if ctx_service then + pool = string.format("%s|%s|%s|%s|%s", + pool, + ctx_service.tls_verify ~= nil and tostring(ctx_service.tls_verify) or "", + ctx_service.tls_verify_depth or "", + ctx_service.ca_certificates and table.concat(ctx_service.ca_certificates, ",") or "", + ctx_service.client_certificate and ctx_service.client_certificate.id or "") end end diff --git a/kong/llm/drivers/azure.lua b/kong/llm/drivers/azure.lua index 2959cfe2c95..67f02e6001c 100644 --- a/kong/llm/drivers/azure.lua +++ b/kong/llm/drivers/azure.lua @@ -143,7 +143,6 @@ function _M.configure_request(conf) local query_table = kong.request.get_query() - -- technically min supported version query_table["api-version"] = kong.request.get_query_arg("api-version") or (conf.model.options and conf.model.options.azure_api_version) diff --git a/kong/llm/drivers/shared.lua b/kong/llm/drivers/shared.lua index 55169a29b97..4c01fb21b8d 100644 --- a/kong/llm/drivers/shared.lua +++ b/kong/llm/drivers/shared.lua @@ -82,6 +82,7 @@ _M._SUPPORTED_STREAMING_CONTENT_TYPES = { ["text/event-stream"] = true, ["application/vnd.amazon.eventstream"] = true, ["application/json"] = true, + ["application/stream+json"] = true, } _M.streaming_has_token_counts = { @@ -93,10 +94,10 @@ _M.streaming_has_token_counts = { } _M.upstream_url_format = { - openai = fmt("%s://api.openai.com:%s", (openai_override and "http") or "https", (openai_override) or "443"), + openai = fmt("%s://api.openai.com:%s", openai_override and "http" or "https", openai_override or "443"), anthropic = "https://api.anthropic.com:443", cohere = "https://api.cohere.com:443", - azure = "https://%s.openai.azure.com:443/openai/deployments/%s", + azure = fmt("%s://%%s.openai.azure.com:%s/openai/deployments/%%s", openai_override and "http" or "https", openai_override or "443"), gemini = "https://generativelanguage.googleapis.com", gemini_vertex = "https://%s", bedrock = "https://bedrock-runtime.%s.amazonaws.com", @@ -353,7 +354,7 @@ function _M.frame_to_events(frame, content_type) -- some new LLMs return the JSON object-by-object, -- because that totally makes sense to parse?! local frame_start = frame and frame:sub(1, 1) - if frame_start == "," or frame_start == "[" then + if (not kong or not kong.ctx.plugin.truncated_frame) and (frame_start == "," or frame_start == "[") then local done = false -- if this is the first frame, it will begin with array opener '[' @@ -416,7 +417,7 @@ function _M.frame_to_events(frame, content_type) if #dat > 0 and #event_lines == i then ngx.log(ngx.DEBUG, "[ai-proxy] truncated sse frame head") if kong then - kong.ctx.plugin.truncated_frame = dat + kong.ctx.plugin.truncated_frame = fmt("%s%s", (kong.ctx.plugin.truncated_frame or ""), dat) end break -- stop parsing immediately, server has done something wrong @@ -944,8 +945,12 @@ end function _M.override_upstream_url(parsed_url, conf) if conf.route_type == "preserve" then - parsed_url.path = conf.model.options and conf.model.options.upstream_path - or kong.request.get_path() + -- if `upstream_path` was set, already processes before, + -- for some provider, like azure and huggingface, the specific prefix need to prepended to the path. + if conf.model.options and conf.model.options.upstream_path then + return + end + parsed_url.path = kong.request.get_path() end end diff --git a/kong/pdk/service/request.lua b/kong/pdk/service/request.lua index f583d390fa1..d2121f4de9f 100644 --- a/kong/pdk/service/request.lua +++ b/kong/pdk/service/request.lua @@ -6,7 +6,7 @@ local cjson = require "cjson.safe" local buffer = require "string.buffer" local checks = require "kong.pdk.private.checks" local phase_checker = require "kong.pdk.private.phases" - +local balancer = require "ngx.balancer" local ngx = ngx local ngx_var = ngx.var @@ -112,6 +112,15 @@ local function new(self) error("invalid scheme: " .. scheme, 2) end + if ngx.get_phase() == "balancer" then + if scheme == "https" then + kong.service.request.enable_tls() + end + if scheme == "http" then + kong.service.request.disable_tls() + end + end + ngx_var.upstream_scheme = scheme end @@ -711,6 +720,16 @@ local function new(self) return disable_proxy_ssl() end + else + request.disable_tls = function() + check_phase(preread_and_balancer) + return balancer.set_upstream_tls(false) + end + + request.enable_tls = function() + check_phase(preread_and_balancer) + return balancer.set_upstream_tls(true) + end end return request diff --git a/kong/plugins/file-log/schema.lua b/kong/plugins/file-log/schema.lua index 67a8590d021..13694354d45 100644 --- a/kong/plugins/file-log/schema.lua +++ b/kong/plugins/file-log/schema.lua @@ -10,7 +10,7 @@ return { fields = { { path = { description = "The file path of the output log file. The plugin creates the log file if it doesn't exist yet.", type = "string", required = true, - match = [[^[^*&%%\`]+$]], + match = [[^[^%s*&%%\`][^*&%%\`]*[^%s*&%%\`]$]], err = "not a valid filename", }, }, { reopen = { description = "Determines whether the log file is closed and reopened on every request.", type = "boolean", required = true, default = false }, }, diff --git a/kong/runloop/balancer/init.lua b/kong/runloop/balancer/init.lua index 73da718a946..dc063d66801 100644 --- a/kong/runloop/balancer/init.lua +++ b/kong/runloop/balancer/init.lua @@ -12,7 +12,7 @@ local targets = require "kong.runloop.balancer.targets" -- due to startup/require order, cannot use the ones from 'kong' here local dns_client = require "kong.resty.dns.client" - +local replace_dashes_lower = require("kong.tools.string").replace_dashes_lower local toip = dns_client.toip local sub = string.sub @@ -132,7 +132,8 @@ local function get_value_to_hash(upstream, ctx) elseif hash_on == "header" then -- since nginx 1.23.0/openresty 1.25.3.1 -- ngx.var will automatically combine all header values with identical name - identifier = var["http_" .. upstream[header_field_name]] + local header_name = replace_dashes_lower(upstream[header_field_name]) + identifier = var["http_" .. header_name] elseif hash_on == "cookie" then identifier = var["cookie_" .. upstream.hash_on_cookie] diff --git a/kong/runloop/handler.lua b/kong/runloop/handler.lua index aa948b202e2..bb9de632acd 100644 --- a/kong/runloop/handler.lua +++ b/kong/runloop/handler.lua @@ -992,8 +992,30 @@ return { if strategy ~= "off" or kong.sync then local worker_state_update_frequency = kong.configuration.worker_state_update_frequency or 1 + --[[ + +-----------+ + | Start | <-------------------------------------+ + +-----------+ | + | | + | | + v | + *************************** +-------+ | + * Is reconfigure running? * ---Yes--->| Sleep | ----+ + *************************** +-------+ + | ^ + No | + | | + v | + +---------------+ | + | rebuild router|-------------------------+ + +---------------+ + + Since reconfigure will also rebuild the router, we skip this round + of rebuilding the router. + --]] local router_async_opts = { - name = "router", + name = RECONFIGURE_OPTS and RECONFIGURE_OPTS.name or "router", -- please check the above diagram for the + -- reason of using the same name as reconfigure timeout = 0, on_timeout = "return_true", } @@ -1433,8 +1455,9 @@ return { return exit(500) end + local header_cache = {} -- clear hop-by-hop request headers: - local http_connection = get_header("connection", ctx) + local http_connection = get_header("connection", header_cache) if http_connection ~= "keep-alive" and http_connection ~= "close" and http_connection ~= "upgrade" @@ -1455,7 +1478,7 @@ return { end -- add te header only when client requests trailers (proxy removes it) - local http_te = get_header("te", ctx) + local http_te = get_header("te", header_cache) if http_te then if http_te == "trailers" then var.upstream_te = "trailers" @@ -1470,11 +1493,11 @@ return { end end - if get_header("proxy", ctx) then + if get_header("proxy", header_cache) then clear_header("Proxy") end - if get_header("proxy_connection", ctx) then + if get_header("proxy_connection", header_cache) then clear_header("Proxy-Connection") end end diff --git a/scripts/explain_manifest/fixtures/amazonlinux-2-amd64.txt b/scripts/explain_manifest/fixtures/amazonlinux-2-amd64.txt index 49cfc216ee7..07cf7434c4f 100644 --- a/scripts/explain_manifest/fixtures/amazonlinux-2-amd64.txt +++ b/scripts/explain_manifest/fixtures/amazonlinux-2-amd64.txt @@ -62,7 +62,7 @@ - libc.so.6 Rpath : /usr/local/kong/lib -- Path : /usr/local/kong/lib/libexpat.so.1.9.2 +- Path : /usr/local/kong/lib/libexpat.so.1.10.0 Needed : - libm.so.6 - libstdc++.so.6 @@ -206,7 +206,7 @@ - lua-resty-lmdb - ngx_brotli - ngx_wasmx_module - OpenSSL : OpenSSL 3.2.3 3 Sep 2024 + OpenSSL : OpenSSL 3.4.0 22 Oct 2024 DWARF : True DWARF - ngx_http_request_t related DWARF DIEs: True diff --git a/scripts/explain_manifest/fixtures/amazonlinux-2023-amd64.txt b/scripts/explain_manifest/fixtures/amazonlinux-2023-amd64.txt index deae6a84933..4370dcba60f 100644 --- a/scripts/explain_manifest/fixtures/amazonlinux-2023-amd64.txt +++ b/scripts/explain_manifest/fixtures/amazonlinux-2023-amd64.txt @@ -46,7 +46,7 @@ - libc.so.6 Runpath : /usr/local/kong/lib -- Path : /usr/local/kong/lib/libexpat.so.1.9.2 +- Path : /usr/local/kong/lib/libexpat.so.1.10.0 Needed : - libstdc++.so.6 - libm.so.6 @@ -179,7 +179,7 @@ - lua-resty-lmdb - ngx_brotli - ngx_wasmx_module - OpenSSL : OpenSSL 3.2.3 3 Sep 2024 + OpenSSL : OpenSSL 3.4.0 22 Oct 2024 DWARF : True DWARF - ngx_http_request_t related DWARF DIEs: True diff --git a/scripts/explain_manifest/fixtures/amazonlinux-2023-arm64.txt b/scripts/explain_manifest/fixtures/amazonlinux-2023-arm64.txt index e4a40200bd1..891e2cb2d96 100644 --- a/scripts/explain_manifest/fixtures/amazonlinux-2023-arm64.txt +++ b/scripts/explain_manifest/fixtures/amazonlinux-2023-arm64.txt @@ -61,7 +61,7 @@ - ld-linux-aarch64.so.1 Rpath : /usr/local/kong/lib -- Path : /usr/local/kong/lib/libexpat.so.1.9.2 +- Path : /usr/local/kong/lib/libexpat.so.1.10.0 Needed : - libm.so.6 - libstdc++.so.6 @@ -203,7 +203,7 @@ - lua-resty-events - lua-resty-lmdb - ngx_wasmx_module - OpenSSL : OpenSSL 3.2.3 3 Sep 2024 + OpenSSL : OpenSSL 3.4.0 22 Oct 2024 DWARF : True DWARF - ngx_http_request_t related DWARF DIEs: True diff --git a/scripts/explain_manifest/fixtures/debian-11-amd64.txt b/scripts/explain_manifest/fixtures/debian-11-amd64.txt index fc773affedb..124d81b302d 100644 --- a/scripts/explain_manifest/fixtures/debian-11-amd64.txt +++ b/scripts/explain_manifest/fixtures/debian-11-amd64.txt @@ -51,7 +51,7 @@ - libc.so.6 Runpath : /usr/local/kong/lib -- Path : /usr/local/kong/lib/libexpat.so.1.9.2 +- Path : /usr/local/kong/lib/libexpat.so.1.10.0 Needed : - libc.so.6 @@ -180,7 +180,7 @@ - lua-resty-lmdb - ngx_brotli - ngx_wasmx_module - OpenSSL : OpenSSL 3.2.3 3 Sep 2024 + OpenSSL : OpenSSL 3.4.0 22 Oct 2024 DWARF : True DWARF - ngx_http_request_t related DWARF DIEs: True diff --git a/scripts/explain_manifest/fixtures/debian-12-amd64.txt b/scripts/explain_manifest/fixtures/debian-12-amd64.txt index 13ef4848197..674efe8ef85 100644 --- a/scripts/explain_manifest/fixtures/debian-12-amd64.txt +++ b/scripts/explain_manifest/fixtures/debian-12-amd64.txt @@ -46,7 +46,7 @@ - libc.so.6 Runpath : /usr/local/kong/lib -- Path : /usr/local/kong/lib/libexpat.so.1.9.2 +- Path : /usr/local/kong/lib/libexpat.so.1.10.0 Needed : - libc.so.6 @@ -169,7 +169,7 @@ - lua-resty-lmdb - ngx_brotli - ngx_wasmx_module - OpenSSL : OpenSSL 3.2.3 3 Sep 2024 + OpenSSL : OpenSSL 3.4.0 22 Oct 2024 DWARF : True DWARF - ngx_http_request_t related DWARF DIEs: True diff --git a/scripts/explain_manifest/fixtures/el8-amd64.txt b/scripts/explain_manifest/fixtures/el8-amd64.txt index bce086c65f0..665b21b52d0 100644 --- a/scripts/explain_manifest/fixtures/el8-amd64.txt +++ b/scripts/explain_manifest/fixtures/el8-amd64.txt @@ -51,7 +51,7 @@ - libc.so.6 Runpath : /usr/local/kong/lib -- Path : /usr/local/kong/lib/libexpat.so.1.9.2 +- Path : /usr/local/kong/lib/libexpat.so.1.10.0 Needed : - libstdc++.so.6 - libm.so.6 @@ -190,7 +190,7 @@ - lua-resty-lmdb - ngx_brotli - ngx_wasmx_module - OpenSSL : OpenSSL 3.2.3 3 Sep 2024 + OpenSSL : OpenSSL 3.4.0 22 Oct 2024 DWARF : True DWARF - ngx_http_request_t related DWARF DIEs: True diff --git a/scripts/explain_manifest/fixtures/el9-amd64.txt b/scripts/explain_manifest/fixtures/el9-amd64.txt index 15e85a6938b..f2c28124f3a 100644 --- a/scripts/explain_manifest/fixtures/el9-amd64.txt +++ b/scripts/explain_manifest/fixtures/el9-amd64.txt @@ -46,7 +46,7 @@ - libc.so.6 Runpath : /usr/local/kong/lib -- Path : /usr/local/kong/lib/libexpat.so.1.9.2 +- Path : /usr/local/kong/lib/libexpat.so.1.10.0 Needed : - libstdc++.so.6 - libm.so.6 @@ -179,7 +179,7 @@ - lua-resty-lmdb - ngx_brotli - ngx_wasmx_module - OpenSSL : OpenSSL 3.2.3 3 Sep 2024 + OpenSSL : OpenSSL 3.4.0 22 Oct 2024 DWARF : True DWARF - ngx_http_request_t related DWARF DIEs: True diff --git a/scripts/explain_manifest/fixtures/el9-arm64.txt b/scripts/explain_manifest/fixtures/el9-arm64.txt index e4a40200bd1..891e2cb2d96 100644 --- a/scripts/explain_manifest/fixtures/el9-arm64.txt +++ b/scripts/explain_manifest/fixtures/el9-arm64.txt @@ -61,7 +61,7 @@ - ld-linux-aarch64.so.1 Rpath : /usr/local/kong/lib -- Path : /usr/local/kong/lib/libexpat.so.1.9.2 +- Path : /usr/local/kong/lib/libexpat.so.1.10.0 Needed : - libm.so.6 - libstdc++.so.6 @@ -203,7 +203,7 @@ - lua-resty-events - lua-resty-lmdb - ngx_wasmx_module - OpenSSL : OpenSSL 3.2.3 3 Sep 2024 + OpenSSL : OpenSSL 3.4.0 22 Oct 2024 DWARF : True DWARF - ngx_http_request_t related DWARF DIEs: True diff --git a/scripts/explain_manifest/fixtures/ubuntu-20.04-amd64.txt b/scripts/explain_manifest/fixtures/ubuntu-20.04-amd64.txt index ced909d9fcb..55fd7bd9006 100644 --- a/scripts/explain_manifest/fixtures/ubuntu-20.04-amd64.txt +++ b/scripts/explain_manifest/fixtures/ubuntu-20.04-amd64.txt @@ -51,7 +51,7 @@ - libc.so.6 Runpath : /usr/local/kong/lib -- Path : /usr/local/kong/lib/libexpat.so.1.9.2 +- Path : /usr/local/kong/lib/libexpat.so.1.10.0 Needed : - libc.so.6 @@ -184,7 +184,7 @@ - lua-resty-lmdb - ngx_brotli - ngx_wasmx_module - OpenSSL : OpenSSL 3.2.3 3 Sep 2024 + OpenSSL : OpenSSL 3.4.0 22 Oct 2024 DWARF : True DWARF - ngx_http_request_t related DWARF DIEs: True diff --git a/scripts/explain_manifest/fixtures/ubuntu-22.04-amd64.txt b/scripts/explain_manifest/fixtures/ubuntu-22.04-amd64.txt index 019ec5337c1..50aed674cdc 100644 --- a/scripts/explain_manifest/fixtures/ubuntu-22.04-amd64.txt +++ b/scripts/explain_manifest/fixtures/ubuntu-22.04-amd64.txt @@ -46,7 +46,7 @@ - libc.so.6 Runpath : /usr/local/kong/lib -- Path : /usr/local/kong/lib/libexpat.so.1.9.2 +- Path : /usr/local/kong/lib/libexpat.so.1.10.0 Needed : - libc.so.6 @@ -173,7 +173,7 @@ - lua-resty-lmdb - ngx_brotli - ngx_wasmx_module - OpenSSL : OpenSSL 3.2.3 3 Sep 2024 + OpenSSL : OpenSSL 3.4.0 22 Oct 2024 DWARF : True DWARF - ngx_http_request_t related DWARF DIEs: True diff --git a/scripts/explain_manifest/fixtures/ubuntu-22.04-arm64.txt b/scripts/explain_manifest/fixtures/ubuntu-22.04-arm64.txt index dc470c5cdab..1acf230ab0f 100644 --- a/scripts/explain_manifest/fixtures/ubuntu-22.04-arm64.txt +++ b/scripts/explain_manifest/fixtures/ubuntu-22.04-arm64.txt @@ -44,7 +44,7 @@ - ld-linux-aarch64.so.1 Runpath : /usr/local/kong/lib -- Path : /usr/local/kong/lib/libexpat.so.1.9.2 +- Path : /usr/local/kong/lib/libexpat.so.1.10.0 Needed : - libc.so.6 - ld-linux-aarch64.so.1 @@ -190,7 +190,7 @@ - lua-resty-lmdb - ngx_brotli - ngx_wasmx_module - OpenSSL : OpenSSL 3.2.3 3 Sep 2024 + OpenSSL : OpenSSL 3.4.0 22 Oct 2024 DWARF : True DWARF - ngx_http_request_t related DWARF DIEs: True diff --git a/scripts/explain_manifest/fixtures/ubuntu-24.04-amd64.txt b/scripts/explain_manifest/fixtures/ubuntu-24.04-amd64.txt index bdffda2b0ae..6312a24e4f8 100644 --- a/scripts/explain_manifest/fixtures/ubuntu-24.04-amd64.txt +++ b/scripts/explain_manifest/fixtures/ubuntu-24.04-amd64.txt @@ -46,7 +46,7 @@ - libc.so.6 Runpath : /usr/local/kong/lib -- Path : /usr/local/kong/lib/libexpat.so.1.9.2 +- Path : /usr/local/kong/lib/libexpat.so.1.10.0 Needed : - libc.so.6 @@ -173,7 +173,7 @@ - lua-resty-lmdb - ngx_brotli - ngx_wasmx_module - OpenSSL : OpenSSL 3.2.3 3 Sep 2024 + OpenSSL : OpenSSL 3.4.0 22 Oct 2024 DWARF : True DWARF - ngx_http_request_t related DWARF DIEs: True diff --git a/scripts/explain_manifest/fixtures/ubuntu-24.04-arm64.txt b/scripts/explain_manifest/fixtures/ubuntu-24.04-arm64.txt index dc470c5cdab..1acf230ab0f 100644 --- a/scripts/explain_manifest/fixtures/ubuntu-24.04-arm64.txt +++ b/scripts/explain_manifest/fixtures/ubuntu-24.04-arm64.txt @@ -44,7 +44,7 @@ - ld-linux-aarch64.so.1 Runpath : /usr/local/kong/lib -- Path : /usr/local/kong/lib/libexpat.so.1.9.2 +- Path : /usr/local/kong/lib/libexpat.so.1.10.0 Needed : - libc.so.6 - ld-linux-aarch64.so.1 @@ -190,7 +190,7 @@ - lua-resty-lmdb - ngx_brotli - ngx_wasmx_module - OpenSSL : OpenSSL 3.2.3 3 Sep 2024 + OpenSSL : OpenSSL 3.4.0 22 Oct 2024 DWARF : True DWARF - ngx_http_request_t related DWARF DIEs: True diff --git a/scripts/explain_manifest/suites.py b/scripts/explain_manifest/suites.py index 26d5c93d30d..7923269bb6c 100644 --- a/scripts/explain_manifest/suites.py +++ b/scripts/explain_manifest/suites.py @@ -95,14 +95,14 @@ def common_suites(expect, libxcrypt_no_obsolete_api: bool = False, skip_libsimdj expect("/usr/local/openresty/nginx/sbin/nginx", "nginx should link libxcrypt.so.1") \ .needed_libraries.contain("libcrypt.so.1") - expect("/usr/local/openresty/nginx/sbin/nginx", "nginx compiled with OpenSSL 3.2.x") \ - .nginx_compiled_openssl.matches(r"OpenSSL 3.2.\d") \ - .version_requirement.key("libssl.so.3").less_than("OPENSSL_3.3.0") \ - .version_requirement.key("libcrypto.so.3").less_than("OPENSSL_3.3.0") \ - - expect("**/*.so", "dynamic libraries are compiled with OpenSSL 3.2.x") \ - .version_requirement.key("libssl.so.3").less_than("OPENSSL_3.3.0") \ - .version_requirement.key("libcrypto.so.3").less_than("OPENSSL_3.3.0") \ + expect("/usr/local/openresty/nginx/sbin/nginx", "nginx compiled with OpenSSL 3.4.x") \ + .nginx_compiled_openssl.matches(r"OpenSSL 3.4.\d") \ + .version_requirement.key("libssl.so.3").less_than("OPENSSL_3.5.0") \ + .version_requirement.key("libcrypto.so.3").less_than("OPENSSL_3.5.0") \ + + expect("**/*.so", "dynamic libraries are compiled with OpenSSL 3.4.x") \ + .version_requirement.key("libssl.so.3").less_than("OPENSSL_3.5.0") \ + .version_requirement.key("libcrypto.so.3").less_than("OPENSSL_3.5.0") \ ADA_VERSION = read_requirements()["ADA"] expect("**/*.so", "ada version is less than %s" % ADA_VERSION) \ diff --git a/spec/01-unit/01-db/10-declarative_spec.lua b/spec/01-unit/01-db/10-declarative_spec.lua index a383daaeaf3..2d27887888d 100644 --- a/spec/01-unit/01-db/10-declarative_spec.lua +++ b/spec/01-unit/01-db/10-declarative_spec.lua @@ -1,6 +1,9 @@ require("spec.helpers") -- for kong.log local declarative = require "kong.db.declarative" local conf_loader = require "kong.conf_loader" +local uuid = require "kong.tools.uuid" + +local pl_file = require "pl.file" local null = ngx.null @@ -64,4 +67,55 @@ keyauth_credentials: end) end) + it("parse nested entities correctly", function () + -- This regression test case is to make sure that when a + -- "raw" input of declarative config is given, the dc parser + -- can generate correct UUIDs for those nested entites. + -- When the declarative config parser tries to flatten the + -- config input, the input will be running agains the + -- declarative_config schema validation. But some input + -- might lacks required fieds(such as UUIDS) and their + -- relationships are declared by nesting objects. In such + -- cases the declarative config parser must generate necessary + -- fields for all the objects(known entities) inside the config. + -- This test case is to make sure that the parser can generate + -- correct UUIDs for nested entities. What's more, it also makes + -- sure that UUID generation are not influenced by the `transient` + -- field(used as a backref to foreign objects) configured inside + -- the schema. + -- + -- See https://github.com/Kong/kong/pull/14082 for more details. + local cluster_cert_content = assert(pl_file.read("spec/fixtures/kong_clustering.crt")) + local cluster_key_content = assert(pl_file.read("spec/fixtures/kong_clustering.key")) + local cert_id = uuid.uuid() + local sni_id = uuid.uuid() + local dc = declarative.new_config(conf_loader()) + local entities, err = dc:parse_table( + { + _format_version = "3.0", + certificates = { { + cert = cluster_cert_content, + id = cert_id, + key = cluster_key_content, + snis = { { + id = sni_id, + name = "alpha.example" + } } + } }, + consumers = { { + basicauth_credentials = { { + password = "qwerty", + username = "qwerty" + } }, + username = "consumerA" + } } + } + ) + + assert.is_nil(err) + assert.is_table(entities) + assert.is_not_nil(entities.snis) + assert.same('alpha.example', entities.certificates[cert_id].snis[1].name) + end) + end) diff --git a/spec/01-unit/19-hybrid/02-clustering_spec.lua b/spec/01-unit/19-hybrid/02-clustering_spec.lua index d2d54f10d83..e47b4fd3234 100644 --- a/spec/01-unit/19-hybrid/02-clustering_spec.lua +++ b/spec/01-unit/19-hybrid/02-clustering_spec.lua @@ -7,6 +7,8 @@ describe("kong.clustering.compat.version", function() assert.equal(3000001000, version.string_to_number("3.0.1")) assert.equal(3000000000, version.string_to_number("3.0.0.0")) assert.equal(3000000001, version.string_to_number("3.0.0.1")) + assert.equal(3009000000, version.string_to_number("3.9.0.0")) + assert.equal(3010000000, version.string_to_number("3.10.0.0")) assert.equal(333333333001, version.string_to_number("333.333.333.1")) assert.equal(333333333333, version.string_to_number("333.333.333.333")) end) diff --git a/spec/02-integration/05-proxy/10-balancer/03-consistent-hashing_spec.lua b/spec/02-integration/05-proxy/10-balancer/03-consistent-hashing_spec.lua index ab6bde942e6..c9297652d71 100644 --- a/spec/02-integration/05-proxy/10-balancer/03-consistent-hashing_spec.lua +++ b/spec/02-integration/05-proxy/10-balancer/03-consistent-hashing_spec.lua @@ -109,6 +109,44 @@ for _, strategy in helpers.each_strategy() do assert(count1.total + count2.total == requests) end) + it("hashing on Hyphenated-Pascal-Case headers", function() + local requests = bu.SLOTS * 2 -- go round the balancer twice + + bu.begin_testcase_setup(strategy, bp) + local upstream_name, upstream_id = bu.add_upstream(bp, { + hash_on = "header", + hash_on_header = "X-LB-Hash", + }) + local port1 = bu.add_target(bp, upstream_id, localhost) + local port2 = bu.add_target(bp, upstream_id, localhost) + local api_host = bu.add_api(bp, upstream_name) + bu.end_testcase_setup(strategy, bp) + + -- setup target servers + local server1 = https_server.new(port1, localhost) + local server2 = https_server.new(port2, localhost) + server1:start() + server2:start() + + -- Go hit them with our test requests + local oks = bu.client_requests(requests, { + ["Host"] = api_host, + ["X-LB-Hash"] = { "1st value", "2nd value", }, + }) + assert.are.equal(requests, oks) + assert.logfile().has.line("trying to get peer with value to hash: \\[1st value, 2nd value\\]") + + -- collect server results; hitcount + -- one should get all the hits, the other 0 + local count1 = server1:shutdown() + local count2 = server2:shutdown() + + -- verify + assert(count1.total == 0 or count1.total == requests, "counts should either get 0 or ALL hits") + assert(count2.total == 0 or count2.total == requests, "counts should either get 0 or ALL hits") + assert(count1.total + count2.total == requests) + end) + it("hashing on missing header", function() local requests = bu.SLOTS * 2 -- go round the balancer twice diff --git a/spec/02-integration/05-proxy/25-upstream_keepalive_spec.lua b/spec/02-integration/05-proxy/25-upstream_keepalive_spec.lua index c9421795755..84f8f5fdbc2 100644 --- a/spec/02-integration/05-proxy/25-upstream_keepalive_spec.lua +++ b/spec/02-integration/05-proxy/25-upstream_keepalive_spec.lua @@ -27,6 +27,7 @@ local fixtures = { describe("#postgres upstream keepalive", function() local proxy_client + local ca_certificate, client_cert1, client_cert2 local function start_kong(opts) local kopts = { @@ -51,8 +52,23 @@ describe("#postgres upstream keepalive", function() "routes", "services", "certificates", + "ca_certificates", }) + ca_certificate = assert(bp.ca_certificates:insert({ + cert = ssl_fixtures.cert_ca, + })) + + client_cert1 = bp.certificates:insert { + cert = ssl_fixtures.cert_client, + key = ssl_fixtures.key_client, + } + + client_cert2 = bp.certificates:insert { + cert = ssl_fixtures.cert_client2, + key = ssl_fixtures.key_client2, + } + -- upstream TLS bp.routes:insert { hosts = { "one.test" }, @@ -61,6 +77,9 @@ describe("#postgres upstream keepalive", function() protocol = helpers.mock_upstream_ssl_protocol, host = helpers.mock_upstream_hostname, port = helpers.mock_upstream_ssl_port, + tls_verify = false, + tls_verify_depth = 3, + ca_certificates = { ca_certificate.id }, }, } @@ -71,6 +90,9 @@ describe("#postgres upstream keepalive", function() protocol = helpers.mock_upstream_ssl_protocol, host = helpers.mock_upstream_hostname, port = helpers.mock_upstream_ssl_port, + tls_verify = false, + tls_verify_depth = 3, + ca_certificates = { ca_certificate.id }, }, } @@ -100,10 +122,10 @@ describe("#postgres upstream keepalive", function() hosts = { "example.test", }, service = bp.services:insert { url = "https://127.0.0.1:16798/", - client_certificate = bp.certificates:insert { - cert = ssl_fixtures.cert_client, - key = ssl_fixtures.key_client, - }, + client_certificate = client_cert1, + tls_verify = false, + tls_verify_depth = 3, + ca_certificates = { ca_certificate.id }, }, } @@ -111,10 +133,10 @@ describe("#postgres upstream keepalive", function() hosts = { "example2.test", }, service = bp.services:insert { url = "https://127.0.0.1:16798/", - client_certificate = bp.certificates:insert { - cert = ssl_fixtures.cert_client2, - key = ssl_fixtures.key_client2, - }, + client_certificate = client_cert2, + tls_verify = false, + tls_verify_depth = 3, + ca_certificates = { ca_certificate.id }, }, } end) @@ -143,12 +165,15 @@ describe("#postgres upstream keepalive", function() assert.equal("SNI=one.test", body) assert.errlog() .has - .line([[enabled connection keepalive \(pool=[A-F0-9.:]+\|\d+\|one.test]]) + .line([[enabled connection keepalive \(pool=[A-F0-9.:]+\|\d+\|one.test|false|3|]] .. + ca_certificate.id .. "|") assert.errlog() - .has.line([[keepalive get pool, name: [A-F0-9.:]+\|\d+\|one.test, cpool: 0+]]) + .has.line([[keepalive get pool, name: [A-F0-9.:]+\|\d+\|one.test|false|3|]] .. + ca_certificate.id .. [[|, cpool: 0+]]) assert.errlog() - .has.line([[keepalive create pool, name: [A-F0-9.:]+\|\d+\|one.test, size: \d+]]) + .has.line([[keepalive create pool, name: [A-F0-9.:]+\|\d+\|one.test|false|3|]] .. + ca_certificate.id .. [[|, size: \d+]]) assert.errlog() .has.line([[lua balancer: keepalive no free connection, cpool: [A-F0-9]+]]) assert.errlog() @@ -167,12 +192,15 @@ describe("#postgres upstream keepalive", function() assert.equal("SNI=two.test", body) assert.errlog() .has - .line([[enabled connection keepalive \(pool=[A-F0-9.:]+\|\d+\|two.test]]) + .line([[enabled connection keepalive \(pool=[A-F0-9.:]+\|\d+\|two.test|false|3|]] .. + ca_certificate.id .. "|") assert.errlog() - .has.line([[keepalive get pool, name: [A-F0-9.:]+\|\d+\|two.test, cpool: 0+]]) + .has.line([[keepalive get pool, name: [A-F0-9.:]+\|\d+\|two.test|false|3|]] .. + ca_certificate.id .. [[|, cpool: 0+]]) assert.errlog() - .has.line([[keepalive create pool, name: [A-F0-9.:]+\|\d+\|two.test, size: \d+]]) + .has.line([[keepalive create pool, name: [A-F0-9.:]+\|\d+\|two.test|false|3|]] .. + ca_certificate.id .. [[|, size: \d+]]) assert.errlog() .has.line([[lua balancer: keepalive no free connection, cpool: [A-F0-9]+]]) assert.errlog() @@ -225,9 +253,11 @@ describe("#postgres upstream keepalive", function() assert.not_equal(fingerprint_1, fingerprint_2) assert.errlog() - .has.line([[enabled connection keepalive \(pool=[0-9.]+|\d+|[0-9.]+:\d+|[a-f0-9-]+]]) + .has.line([[enabled connection keepalive \(pool=[0-9.]+|\d+|[0-9.]+:\d+|[a-f0-9-]+|false|3|]] .. + ca_certificate.id .. "|" .. client_cert1.id) assert.errlog() - .has.line([[keepalive get pool, name: [0-9.]+|\d+|[0-9.]+:\d+|[a-f0-9-]+, cpool: 0+]]) + .has.line([[keepalive get pool, name: [0-9.]+|\d+|[0-9.]+:\d+|[a-f0-9-]+|false|3|]] .. + ca_certificate.id .. "|" .. client_cert1.id .. [[, cpool: 0+]]) assert.errlog() .has.line([[keepalive create pool, name: [0-9.]+|\d+|[0-9.]+:\d+|[a-f0-9-]+, size: \d+]]) assert.errlog() @@ -299,12 +329,15 @@ describe("#postgres upstream keepalive", function() assert.equal("SNI=one.test", body) assert.errlog() .has - .line([[enabled connection keepalive \(pool=[A-F0-9.:]+\|\d+\|one.test]]) + .line([[enabled connection keepalive \(pool=[A-F0-9.:]+\|\d+\|one.test|false|3|]] .. + ca_certificate.id .. "|") assert.errlog() - .has.line([[keepalive get pool, name: [A-F0-9.:]+\|\d+\|one.test, cpool: 0+]]) + .has.line([[keepalive get pool, name: [A-F0-9.:]+\|\d+\|one.test|false|3|]] .. + ca_certificate.id .. [[|, cpool: 0+]]) assert.errlog() - .has.line([[keepalive create pool, name: [A-F0-9.:]+\|\d+\|one.test, size: \d+]]) + .has.line([[keepalive create pool, name: [A-F0-9.:]+\|\d+\|one.test|false|3|]] .. + ca_certificate.id .. [[|, size: \d+]]) assert.errlog() .has.line([[keepalive no free connection, cpool: [A-F0-9]+]]) assert.errlog() @@ -330,10 +363,12 @@ describe("#postgres upstream keepalive", function() assert.equal("SNI=one.test", body) assert.errlog() .has - .line([[enabled connection keepalive \(pool=[A-F0-9.:]+\|\d+\|one.test]]) + .line([[enabled connection keepalive \(pool=[A-F0-9.:]+\|\d+\|one.test|false|3|]] .. + ca_certificate.id .. "|") assert.errlog() - .has.line([[keepalive get pool, name: [A-F0-9.:]+\|\d+\|one.test, ]] .. upool_ptr) + .has.line([[keepalive get pool, name: [A-F0-9.:]+\|\d+\|one.test|false|3|]] .. + ca_certificate.id .. [[|, ]] .. upool_ptr) assert.errlog() .has.line([[keepalive reusing connection [A-F0-9]+, requests: \d+, ]] .. upool_ptr) assert.errlog() @@ -357,18 +392,22 @@ describe("#postgres upstream keepalive", function() assert.equal("SNI=one.test", body) assert.errlog() .has - .line([[enabled connection keepalive \(pool=[A-F0-9.:]+\|\d+\|one.test]]) + .line([[enabled connection keepalive \(pool=[A-F0-9.:]+\|\d+\|one.test|false|3|]] .. + ca_certificate.id .. "|") assert.errlog() - .has.line([[keepalive get pool, name: [A-F0-9.:]+\|\d+\|one.test, cpool: 0+]]) + .has.line([[keepalive get pool, name: [A-F0-9.:]+\|\d+\|one.test|false|3|]] .. + ca_certificate.id .. [[|, cpool: 0+]]) assert.errlog() - .has.line([[keepalive create pool, name: [A-F0-9.:]+\|\d+\|one.test, size: \d+]]) + .has.line([[keepalive create pool, name: [A-F0-9.:]+\|\d+\|one.test|false|3|]] .. + ca_certificate.id .. [[|, size: \d+]]) assert.errlog() .has.line([[keepalive no free connection, cpool: [A-F0-9]+]]) assert.errlog() .has.line([[keepalive not saving connection [A-F0-9]+, cpool: [A-F0-9]+]]) assert.errlog() - .has.line([[keepalive free pool, name: [A-F0-9.:]+\|\d+\|one.test, cpool: [A-F0-9]+]]) + .has.line([[keepalive free pool, name: [A-F0-9.:]+\|\d+\|one.test|false|3|]] .. + ca_certificate.id .. [[|, cpool: [A-F0-9]+]]) assert.errlog() .not_has.line([[keepalive saving connection]], true) diff --git a/spec/02-integration/09-hybrid_mode/09-node-id-persistence_spec.lua b/spec/02-integration/09-hybrid_mode/09-node-id-persistence_spec.lua index 7b358f62920..5ef1f552d8c 100644 --- a/spec/02-integration/09-hybrid_mode/09-node-id-persistence_spec.lua +++ b/spec/02-integration/09-hybrid_mode/09-node-id-persistence_spec.lua @@ -20,6 +20,7 @@ local write_node_id = [[ local function get_http_node_id() local client = helpers.proxy_client(nil, 9002) finally(function() client:close() end) + helpers.wait_until(function() local res = client:get("/request", { headers = { host = "http.node-id.test" }, @@ -87,7 +88,7 @@ for _, v in ipairs({ {"off", "off"}, {"on", "off"}, {"on", "on"}, }) do local rpc, rpc_sync = v[1], v[2] for _, strategy in helpers.each_strategy() do - describe("node id persistence " .. " rpc_sync=" .. rpc_sync, function() + describe("node id persistence rpc_sync = " .. rpc_sync, function() local control_plane_config = { role = "control_plane", diff --git a/spec/02-integration/09-hybrid_mode/11-status_spec.lua b/spec/02-integration/09-hybrid_mode/11-status_spec.lua index 7db58b87777..e2bd7150561 100644 --- a/spec/02-integration/09-hybrid_mode/11-status_spec.lua +++ b/spec/02-integration/09-hybrid_mode/11-status_spec.lua @@ -104,8 +104,7 @@ for _, strategy in helpers.each_strategy() do end) -- now dp receive config from cp, so dp should be ready - local it_rpc_sync_off= rpc_sync == "off" and it or pending - it_rpc_sync_off("should return 200 on data plane after configuring", function() + it("should return 200 on data plane after configuring", function() helpers.wait_until(function() local http_client = helpers.http_client('127.0.0.1', dp_status_port) @@ -159,57 +158,6 @@ for _, strategy in helpers.each_strategy() do end, 10) end) end) - - local describe_rpc_sync_on = rpc == "on" and rpc_sync == "on" and describe or pending - describe_rpc_sync_on("dp status ready when rpc_sync == on", function() - lazy_setup(function() - assert(start_kong_cp()) - assert(start_kong_dp()) - end) - - lazy_teardown(function() - assert(helpers.stop_kong("serve_cp")) - assert(helpers.stop_kong("serve_dp")) - end) - - it("should return 200 on data plane after configuring when rpc_sync == on", function() - -- insert one entity to make dp ready for incremental sync - - local http_client = helpers.http_client('127.0.0.1', dp_status_port) - - local res = http_client:send({ - method = "GET", - path = "/status/ready", - }) - http_client:close() - assert.equal(503, res.status) - - local admin_client = helpers.admin_client(10000) - local res = assert(admin_client:post("/services", { - body = { name = "service-001", url = "https://127.0.0.1:15556/request", }, - headers = {["Content-Type"] = "application/json"} - })) - assert.res_status(201, res) - - admin_client:close() - - helpers.wait_until(function() - local http_client = helpers.http_client('127.0.0.1', dp_status_port) - - local res = http_client:send({ - method = "GET", - path = "/status/ready", - }) - - local status = res and res.status - http_client:close() - - if status == 200 then - return true - end - end, 10) - end) - end) end) end -- for _, strategy end -- for rpc_sync diff --git a/spec/02-integration/09-hybrid_mode/12-errors_spec.lua b/spec/02-integration/09-hybrid_mode/12-errors_spec.lua index 52b3147a6ae..0912ad84dfe 100644 --- a/spec/02-integration/09-hybrid_mode/12-errors_spec.lua +++ b/spec/02-integration/09-hybrid_mode/12-errors_spec.lua @@ -69,10 +69,9 @@ local function get_error_report(client, msg) end --- XXX TODO: mock_cp does not support rpc sync rpc -for _, rpc_sync in ipairs { "off" } do +-- these tests are only for sync v1 for _, strategy in helpers.each_strategy() do - describe("CP/DP sync error-reporting with #" .. strategy .. " rpc_sync=" .. rpc_sync .. " backend", function() + describe("CP/DP sync error-reporting with #" .. strategy .. " backend", function() local client local cluster_port local cluster_ssl_port @@ -102,7 +101,7 @@ for _, strategy in helpers.each_strategy() do -- use a small map size so that it's easy for us to max it out lmdb_map_size = "1m", plugins = "bundled,cluster-error-reporting", - cluster_rpc_sync = rpc_sync, + cluster_rpc_sync = "off", }, nil, nil, fixtures)) end) @@ -260,4 +259,3 @@ for _, strategy in helpers.each_strategy() do end) end) end -- for _, strategy -end -- for rpc_sync diff --git a/spec/02-integration/18-hybrid_rpc/02-error_spec.lua b/spec/02-integration/18-hybrid_rpc/02-error_spec.lua new file mode 100644 index 00000000000..1b7a07ae6f4 --- /dev/null +++ b/spec/02-integration/18-hybrid_rpc/02-error_spec.lua @@ -0,0 +1,68 @@ +local helpers = require "spec.helpers" + + +-- register a test rpc service in custom plugin rpc-error-test +for _, strategy in helpers.each_strategy() do + describe("Hybrid Mode RPC #" .. strategy, function() + + lazy_setup(function() + helpers.get_db_utils(strategy, { + "clustering_data_planes", + }) -- runs migrations + + assert(helpers.start_kong({ + role = "control_plane", + cluster_cert = "spec/fixtures/kong_clustering.crt", + cluster_cert_key = "spec/fixtures/kong_clustering.key", + database = strategy, + cluster_listen = "127.0.0.1:9005", + nginx_conf = "spec/fixtures/custom_nginx.template", + plugins = "bundled,rpc-error-test", + nginx_worker_processes = 4, -- multiple workers + cluster_rpc = "on", -- enable rpc + cluster_rpc_sync = "off", -- disable rpc sync + })) + + assert(helpers.start_kong({ + role = "data_plane", + database = "off", + prefix = "servroot2", + cluster_cert = "spec/fixtures/kong_clustering.crt", + cluster_cert_key = "spec/fixtures/kong_clustering.key", + cluster_control_plane = "127.0.0.1:9005", + proxy_listen = "0.0.0.0:9002", + nginx_conf = "spec/fixtures/custom_nginx.template", + plugins = "bundled,rpc-error-test", + nginx_worker_processes = 4, -- multiple workers + cluster_rpc = "on", -- enable rpc + cluster_rpc_sync = "off", -- disable rpc sync + })) + end) + + lazy_teardown(function() + helpers.stop_kong("servroot2") + helpers.stop_kong() + end) + + describe("rpc errors", function() + it("in custom plugin", function() + local name = "servroot2/logs/error.log" + + -- dp logs + assert.logfile(name).has.line( + "test #1 ok", true, 10) + + -- dp logs + assert.logfile(name).has.line( + "[rpc] RPC failed, code: -32600, err: empty batch array", true, 10) + assert.logfile(name).has.line( + "[rpc] RPC failed, code: -32600, err: not a valid object", true, 10) + assert.logfile(name).has.line( + "test #2 ok", true, 10) + + assert.logfile(name).has.no.line( + "assertion failed", true, 0) + end) + end) + end) +end -- for _, strategy diff --git a/spec/02-integration/18-hybrid_rpc/05-sync-rpc_spec.lua b/spec/02-integration/18-hybrid_rpc/05-sync-rpc_spec.lua index 26aa9b4b5b1..c9559c6601d 100644 --- a/spec/02-integration/18-hybrid_rpc/05-sync-rpc_spec.lua +++ b/spec/02-integration/18-hybrid_rpc/05-sync-rpc_spec.lua @@ -6,6 +6,13 @@ local setup = require("spec.helpers.rpc_mock.setup") local get_node_id = misc.get_node_id local DP_PREFIX = "servroot_dp" + +-- now version must be a string +local function fmt(v) + return string.format("v02_%028x", v) +end + + local function change_config() -- the initial sync is flaky. let's trigger a sync by creating a service local admin_client = helpers.admin_client() @@ -74,12 +81,12 @@ describe("kong.sync.v2", function() local called = false mocked_cp:mock("kong.sync.v2.get_delta", function(node_id, payload) called = true - return { default = { version = 100, deltas = {} } } + return { default = { version = fmt(100), deltas = {} } } end) -- make a call from the mocked cp -- CP->DP: notify_new_version - assert(mocked_cp:call(node_id, "kong.sync.v2.notify_new_version", { default = { new_version = 100, } })) + assert(mocked_cp:call(node_id, "kong.sync.v2.notify_new_version", { default = { new_version = fmt(100), } })) -- DP->CP: get_delta -- the dp after receiving the notification will make a call to the cp @@ -120,7 +127,7 @@ describe("kong.sync.v2", function() -- this is a workaround to registers the data plane node -- CP does not register the DP node until it receives a call from the DP function register_dp() - local res, err = mocked_dp:call("control_plane", "kong.sync.v2.get_delta", { default = { version = 0,},}) + local res, err = mocked_dp:call("control_plane", "kong.sync.v2.get_delta", { default = { version = fmt(0),},}) assert.is_nil(err) assert.is_table(res and res.default and res.default.deltas) end @@ -132,7 +139,7 @@ describe("kong.sync.v2", function() end) it("rpc call", function() - local res, err = mocked_dp:call("control_plane", "kong.sync.v2.get_delta", { default = { version = 0,},}) + local res, err = mocked_dp:call("control_plane", "kong.sync.v2.get_delta", { default = { version = fmt(0),},}) assert.is_nil(err) assert.is_table(res and res.default and res.default.deltas) diff --git a/spec/02-integration/18-hybrid_rpc/06-batch-rpc_spec.lua b/spec/02-integration/18-hybrid_rpc/06-batch-rpc_spec.lua new file mode 100644 index 00000000000..636984386b0 --- /dev/null +++ b/spec/02-integration/18-hybrid_rpc/06-batch-rpc_spec.lua @@ -0,0 +1,77 @@ +local helpers = require "spec.helpers" + +-- register a test rpc service in custom plugin rpc-batch-test +for _, strategy in helpers.each_strategy() do + describe("Hybrid Mode RPC #" .. strategy, function() + + lazy_setup(function() + helpers.get_db_utils(strategy, { "routes", "services" }) + + assert(helpers.start_kong({ + role = "control_plane", + cluster_cert = "spec/fixtures/kong_clustering.crt", + cluster_cert_key = "spec/fixtures/kong_clustering.key", + database = strategy, + cluster_listen = "127.0.0.1:9005", + nginx_conf = "spec/fixtures/custom_nginx.template", + cluster_rpc = "on", + plugins = "bundled,rpc-batch-test", -- enable custom plugin + cluster_rpc_sync = "off", -- disable rpc sync + })) + + assert(helpers.start_kong({ + role = "data_plane", + database = "off", + prefix = "servroot2", + cluster_cert = "spec/fixtures/kong_clustering.crt", + cluster_cert_key = "spec/fixtures/kong_clustering.key", + cluster_control_plane = "127.0.0.1:9005", + proxy_listen = "0.0.0.0:9002", + nginx_conf = "spec/fixtures/custom_nginx.template", + cluster_rpc = "on", + plugins = "bundled,rpc-batch-test", -- enable custom plugin + cluster_rpc_sync = "off", -- disable rpc sync + })) + end) + + lazy_teardown(function() + helpers.stop_kong("servroot2") + helpers.stop_kong() + end) + + describe("batch works", function() + it("DP calls CP via batching", function() + local cp_logfile = nil + local dp_logfile = "servroot2/logs/error.log" + + assert.logfile(dp_logfile).has.line( + "[rpc] sent batch RPC call: 1", true, 10) + + assert.logfile(cp_logfile).has.line( + "[rpc] got batch RPC call: 1", true, 10) + assert.logfile(cp_logfile).has.line( + "kong.test.batch called: world", true, 10) + + assert.logfile(dp_logfile).has.line( + "[rpc] got batch RPC call: 1", true, 10) + assert.logfile(dp_logfile).has.line( + "kong.test.batch called: hello world", true, 10) + + assert.logfile(dp_logfile).has.line( + "[rpc] sent batch RPC call: 2", true, 10) + + assert.logfile(cp_logfile).has.line( + "[rpc] got batch RPC call: 2", true, 10) + assert.logfile(cp_logfile).has.line( + "kong.test.batch called: kong", true, 10) + assert.logfile(cp_logfile).has.line( + "kong.test.batch called: gateway", true, 10) + assert.logfile(cp_logfile).has.line( + "[rpc] notification has no response", true, 10) + + assert.logfile(dp_logfile).has.line( + "kong.test.batch ok", true, 10) + end) + end) + end) +end -- for _, strategy diff --git a/spec/02-integration/18-hybrid_rpc/06-validate_deltas_spec.lua b/spec/02-integration/18-hybrid_rpc/06-validate_deltas_spec.lua new file mode 100644 index 00000000000..9d8327692c0 --- /dev/null +++ b/spec/02-integration/18-hybrid_rpc/06-validate_deltas_spec.lua @@ -0,0 +1,228 @@ +local helpers = require "spec.helpers" +local txn = require "resty.lmdb.transaction" +local declarative = require "kong.db.declarative" + + +local insert_entity_for_txn = declarative.insert_entity_for_txn +local validate_deltas = require("kong.clustering.services.sync.validate").validate_deltas + + +local function lmdb_drop() + local t = txn.begin(512) + t:db_drop(false) + t:commit() +end + + +local function lmdb_insert(name, entity) + local t = txn.begin(512) + local res, err = insert_entity_for_txn(t, name, entity, nil) + if not res then + error("lmdb insert failed: " .. err) + end + + local ok, err = t:commit() + if not ok then + error("lmdb t:commit() failed: " .. err) + end +end + + +-- insert into LMDB +local function db_insert(bp, name, entity) + -- insert into dc blueprints + entity = bp[name]:insert(entity) + + -- insert into LMDB + lmdb_insert(name, entity) + + assert(kong.db[name]:select({id = entity.id})) + + return entity +end + + +-- Cache the declarative_config to avoid the overhead of repeatedly executing +-- the time-consuming chain: +-- declarative.new_config -> declarative_config.load -> load_plugin_subschemas +local cached_dc + +local function setup_bp() + -- reset lmdb + lmdb_drop() + + -- init bp / db ( true for expand_foreigns) + local bp, db = helpers.get_db_utils("off", nil, nil, nil, nil, true) + + -- init workspaces + local workspaces = require "kong.workspaces" + workspaces.upsert_default(db) + + -- init declarative config + if not cached_dc then + local err + cached_dc, err = declarative.new_config(kong.configuration) + assert(cached_dc, err) + end + + kong.db.declarative_config = cached_dc + + return bp, db +end + + +describe("[delta validations]",function() + + it("workspace id", function() + local bp = setup_bp() + + -- add entities + db_insert(bp, "workspaces", { name = "ws-001" }) + local service = db_insert(bp, "services", { name = "service-001", }) + db_insert(bp, "routes", { + name = "route-001", + paths = { "/mock" }, + service = { id = service.id }, + }) + + local deltas = declarative.export_config_sync() + + for _, delta in ipairs(deltas) do + local ws_id = delta.ws_id + assert(ws_id and ws_id ~= ngx.null) + end + end) + + it("route has unknown field", function() + local bp = setup_bp() + + -- add entities + db_insert(bp, "workspaces", { name = "ws-001" }) + local service = db_insert(bp, "services", { name = "service-001", }) + db_insert(bp, "routes", { + name = "route-001", + paths = { "/mock" }, + service = { id = service.id }, + }) + + local deltas = declarative.export_config_sync() + + for _, delta in ipairs(deltas) do + if delta.type == "routes" then + delta.entity.foo = "invalid_field_value" + break + end + end + + local _, err = validate_deltas(deltas) + assert.matches([[- in entry 1 of 'deltas': + in 'routes': + in 'foo': unknown field]], + err) + end) + + it("route has foreign service", function() + local bp = setup_bp() + + -- add entities + db_insert(bp, "workspaces", { name = "ws-001" }) + local service = db_insert(bp, "services", { name = "service-001", }) + db_insert(bp, "routes", { + name = "route-001", + paths = { "/mock" }, + service = { id = service.id }, + }) + + local deltas = declarative.export_config_sync() + + local ok, err = validate_deltas(deltas) + assert.is_true(ok, "validate should not fail: " .. tostring(err)) + end) + + it("route has unmatched foreign service", function() + local bp = setup_bp() + + -- add entities + db_insert(bp, "workspaces", { name = "ws-001" }) + db_insert(bp, "routes", { + name = "route-001", + paths = { "/mock" }, + -- unmatched service + service = { id = "00000000-0000-0000-0000-000000000000" }, + }) + + local deltas = declarative.export_config_sync() + local _, err = validate_deltas(deltas, false) + assert.matches( + "entry 1 of 'services': could not find routes's foreign refrences services", + err) + end) + + it("100 routes -> 1 services: matched foreign keys", function() + local bp = setup_bp() + + -- add entities + db_insert(bp, "workspaces", { name = "ws-001" }) + local service = db_insert(bp, "services", { name = "service-001", }) + + for i = 1, 100 do + db_insert(bp, "routes", { + name = "route-001", + paths = { "/mock" }, + -- unmatched service + service = { id = service.id }, + }) + end + + local deltas = declarative.export_config_sync() + local ok, err = validate_deltas(deltas, false) + assert.is_true(ok, "validate should not fail: " .. tostring(err)) + end) + + it("100 routes -> 100 services: matched foreign keys", function() + local bp = setup_bp() + + -- add entities + db_insert(bp, "workspaces", { name = "ws-001" }) + + for i = 1, 100 do + local service = db_insert(bp, "services", { name = "service-001", }) + + db_insert(bp, "routes", { + name = "route-001", + paths = { "/mock" }, + -- unmatched service + service = { id = service.id }, + }) + end + + local deltas = declarative.export_config_sync() + local ok, err = validate_deltas(deltas, false) + assert.is_true(ok, "validate should not fail: " .. tostring(err)) + end) + + it("100 routes: unmatched foreign service", function() + local bp = setup_bp() + + -- add entities + db_insert(bp, "workspaces", { name = "ws-001" }) + + for i = 1, 100 do + db_insert(bp, "routes", { + name = "route-001", + paths = { "/mock" }, + -- unmatched service + service = { id = "00000000-0000-0000-0000-000000000000" }, + }) + end + + local deltas = declarative.export_config_sync() + local _, err = validate_deltas(deltas, false) + for i = 1, 100 do + assert.matches( + "entry " .. i .. " of 'services': " .. + "could not find routes's foreign refrences services", + err) + end + end) +end) diff --git a/spec/02-integration/18-hybrid_rpc/07-notification_spec.lua b/spec/02-integration/18-hybrid_rpc/07-notification_spec.lua new file mode 100644 index 00000000000..339cd5a843b --- /dev/null +++ b/spec/02-integration/18-hybrid_rpc/07-notification_spec.lua @@ -0,0 +1,76 @@ +local helpers = require "spec.helpers" + + +-- register a test rpc service in custom plugin rpc-notification-test +for _, strategy in helpers.each_strategy() do + describe("Hybrid Mode RPC #" .. strategy, function() + + lazy_setup(function() + helpers.get_db_utils(strategy, { + "clustering_data_planes", + }) -- runs migrations + + assert(helpers.start_kong({ + role = "control_plane", + cluster_cert = "spec/fixtures/kong_clustering.crt", + cluster_cert_key = "spec/fixtures/kong_clustering.key", + database = strategy, + cluster_listen = "127.0.0.1:9005", + nginx_conf = "spec/fixtures/custom_nginx.template", + plugins = "bundled,rpc-notification-test", + nginx_worker_processes = 4, -- multiple workers + cluster_rpc = "on", -- enable rpc + cluster_rpc_sync = "off", -- disable rpc sync + })) + + assert(helpers.start_kong({ + role = "data_plane", + database = "off", + prefix = "servroot2", + cluster_cert = "spec/fixtures/kong_clustering.crt", + cluster_cert_key = "spec/fixtures/kong_clustering.key", + cluster_control_plane = "127.0.0.1:9005", + proxy_listen = "0.0.0.0:9002", + nginx_conf = "spec/fixtures/custom_nginx.template", + plugins = "bundled,rpc-notification-test", + nginx_worker_processes = 4, -- multiple workers + cluster_rpc = "on", -- enable rpc + cluster_rpc_sync = "off", -- disable rpc sync + })) + end) + + lazy_teardown(function() + helpers.stop_kong("servroot2") + helpers.stop_kong() + end) + + describe("notification works", function() + it("in custom plugin", function() + local name = nil + + -- cp logs + assert.logfile(name).has.line( + "notification is hello", true, 10) + assert.logfile(name).has.line( + "[rpc] notifying kong.test.notification(node_id:", true, 10) + assert.logfile(name).has.line( + "[rpc] notification has no response", true, 10) + assert.logfile(name).has.no.line( + "assertion failed", true, 0) + + local name = "servroot2/logs/error.log" + + -- dp logs + assert.logfile(name).has.line( + "[rpc] notifying kong.test.notification(node_id: control_plane) via local", true, 10) + assert.logfile(name).has.line( + "notification is world", true, 10) + assert.logfile(name).has.line( + "[rpc] notification has no response", true, 10) + assert.logfile(name).has.no.line( + "assertion failed", true, 0) + + end) + end) + end) +end -- for _, strategy diff --git a/spec/02-integration/18-hybrid_rpc/08-sync_v2_get_delta_spec.lua b/spec/02-integration/18-hybrid_rpc/08-sync_v2_get_delta_spec.lua new file mode 100644 index 00000000000..848bd92954c --- /dev/null +++ b/spec/02-integration/18-hybrid_rpc/08-sync_v2_get_delta_spec.lua @@ -0,0 +1,72 @@ +local helpers = require "spec.helpers" + + +-- register a rpc connected event in custom plugin rpc-get-delta-test +-- ENABLE rpc sync on cp side for testing sync.v2.get_delta +-- DISABLE rpc sync on dp side +for _, strategy in helpers.each_strategy() do + describe("Hybrid Mode RPC #" .. strategy, function() + + lazy_setup(function() + helpers.get_db_utils(strategy, { + "clustering_data_planes", + }) -- runs migrations + + assert(helpers.start_kong({ + role = "control_plane", + cluster_cert = "spec/fixtures/kong_clustering.crt", + cluster_cert_key = "spec/fixtures/kong_clustering.key", + database = strategy, + cluster_listen = "127.0.0.1:9005", + nginx_conf = "spec/fixtures/custom_nginx.template", + plugins = "bundled", + nginx_worker_processes = 4, -- multiple workers + cluster_rpc = "on", -- enable rpc + cluster_rpc_sync = "on", -- enable rpc sync + })) + + assert(helpers.start_kong({ + role = "data_plane", + database = "off", + prefix = "servroot2", + cluster_cert = "spec/fixtures/kong_clustering.crt", + cluster_cert_key = "spec/fixtures/kong_clustering.key", + cluster_control_plane = "127.0.0.1:9005", + proxy_listen = "0.0.0.0:9002", + nginx_conf = "spec/fixtures/custom_nginx.template", + plugins = "bundled,rpc-get-delta-test", + nginx_worker_processes = 4, -- multiple workers + cluster_rpc = "on", -- enable rpc + cluster_rpc_sync = "off", -- disable rpc sync + })) + end) + + lazy_teardown(function() + helpers.stop_kong("servroot2") + helpers.stop_kong() + end) + + describe("sync.v2.get_delta works", function() + it("on cp side", function() + local name = "servroot2/logs/error.log" + + -- dp logs + assert.logfile(name).has.line( + "kong.sync.v2.get_delta ok", true, 10) + assert.logfile(name).has.no.line( + "assertion failed", true, 0) + assert.logfile(name).has.no.line( + "[error]", true, 0) + + local name = nil + + -- cp logs + assert.logfile(name).has.no.line( + "assertion failed", true, 0) + assert.logfile(name).has.no.line( + "[error]", true, 0) + + end) + end) + end) +end -- for _, strategy diff --git a/spec/02-integration/18-hybrid_rpc/09-notify_new_version_spec.lua b/spec/02-integration/18-hybrid_rpc/09-notify_new_version_spec.lua new file mode 100644 index 00000000000..53c05d7f6f5 --- /dev/null +++ b/spec/02-integration/18-hybrid_rpc/09-notify_new_version_spec.lua @@ -0,0 +1,89 @@ +local rep = string.rep +local helpers = require "spec.helpers" + + +-- register a rpc connected event in custom plugin rpc-notify-new-version-test +-- DISABLE rpc sync on cp side +-- ENABLE rpc sync on dp side +for _, strategy in helpers.each_strategy() do + describe("Hybrid Mode RPC #" .. strategy, function() + + lazy_setup(function() + helpers.get_db_utils(strategy, { + "clustering_data_planes", + }) -- runs migrations + + assert(helpers.start_kong({ + role = "control_plane", + cluster_cert = "spec/fixtures/kong_clustering.crt", + cluster_cert_key = "spec/fixtures/kong_clustering.key", + database = strategy, + cluster_listen = "127.0.0.1:9005", + nginx_conf = "spec/fixtures/custom_nginx.template", + plugins = "bundled,rpc-notify-new-version-test", + nginx_worker_processes = 4, -- multiple workers + cluster_rpc = "on", -- enable rpc + cluster_rpc_sync = "off", -- disable rpc sync + })) + + assert(helpers.start_kong({ + role = "data_plane", + database = "off", + prefix = "servroot2", + cluster_cert = "spec/fixtures/kong_clustering.crt", + cluster_cert_key = "spec/fixtures/kong_clustering.key", + cluster_control_plane = "127.0.0.1:9005", + proxy_listen = "0.0.0.0:9002", + nginx_conf = "spec/fixtures/custom_nginx.template", + plugins = "bundled,rpc-notify-new-version-test", + nginx_worker_processes = 4, -- multiple workers + cluster_rpc = "on", -- enable rpc + cluster_rpc_sync = "on", -- enable rpc sync + })) + end) + + lazy_teardown(function() + helpers.stop_kong("servroot2") + helpers.stop_kong() + end) + + describe("sync.v2.notify_new_version works", function() + it("on dp side", function() + local name = "servroot2/logs/error.log" + + -- dp logs + assert.logfile(name).has.line( + "kong.test.notify_new_version ok", true, 10) + + assert.logfile(name).has.line( + "no sync runs, version is " .. rep(".", 32), true, 10) + assert.logfile(name).has.line( + "no sync runs, version is " .. rep("0", 32), true, 10) + + assert.logfile(name).has.line( + "sync_once retry count exceeded. retry_count: 5", true, 10) + assert.logfile(name).has.no.line( + "assertion failed", true, 0) + assert.logfile(name).has.no.line( + "[error]", true, 0) + + local name = nil + + -- cp logs + for i = 0, 5 do + assert.logfile(name).has.line( + "kong.sync.v2.get_delta ok: " .. i, true, 10) + end + + assert.logfile(name).has.line( + "kong.test.notify_new_version ok", true, 10) + + assert.logfile(name).has.no.line( + "assertion failed", true, 0) + assert.logfile(name).has.no.line( + "[error]", true, 0) + + end) + end) + end) +end -- for _, strategy diff --git a/spec/03-plugins/04-file-log/02-schema_spec.lua b/spec/03-plugins/04-file-log/02-schema_spec.lua index 17a815dad34..8f923f6b82b 100644 --- a/spec/03-plugins/04-file-log/02-schema_spec.lua +++ b/spec/03-plugins/04-file-log/02-schema_spec.lua @@ -17,7 +17,7 @@ describe("Plugin: file-log (schema)", function() }, ---------------------------------------- { - name = "rejects invalid filename", + name = "rejects invalid filename includes *", input = { path = "/ovo*", reopen = true @@ -30,6 +30,100 @@ describe("Plugin: file-log (schema)", function() } }, ---------------------------------------- + { + name = "rejects invalid filename includes `", + input = { + path = "/ovo`", + reopen = true + }, + output = nil, + error = { + config = { + path = "not a valid filename" + } + } + }, + ---------------------------------------- + { + name = "rejects invalid filename includes &", + input = { + path = "test&thing", + reopen = true + }, + output = nil, + error = { + config = { + path = "not a valid filename" + } + } + }, + ---------------------------------------- + { + name = "rejects invalid filename includes %", + input = { + path = "test%thing", + reopen = true + }, + output = nil, + error = { + config = { + path = "not a valid filename" + } + } + }, + ---------------------------------------- + { + name = "rejects invalid filename includes \\", + input = { + path = "test\\thing", + reopen = true + }, + output = nil, + error = { + config = { + path = "not a valid filename" + } + } + }, + ---------------------------------------- + { + name = "beginning spaces are not allowed", + input = { + path = " /ovo", + reopen = true + }, + output = nil, + error = { + config = { + path = "not a valid filename" + } + } + }, + -- ---------------------------------------- + { + name = "trailing spaces are not allowed", + input = { + path = "/ovo ", + reopen = true + }, + output = nil, + error = { + config = { + path = "not a valid filename" + } + } + }, + ---------------------------------------- + { + name = "accept valid filename that includes space", + input = { + path = "/o vo.loga", + reopen = true + }, + output = true, + error = nil, + }, + ------------------------------------ { name = "accepts valid filename", input = { diff --git a/spec/03-plugins/11-correlation-id/02-schema_spec.lua b/spec/03-plugins/11-correlation-id/02-schema_spec.lua index e5aa7c3035e..611b5b2a0f7 100644 --- a/spec/03-plugins/11-correlation-id/02-schema_spec.lua +++ b/spec/03-plugins/11-correlation-id/02-schema_spec.lua @@ -86,11 +86,33 @@ describe("Plugin: correlation-id (schema) #a [#" .. strategy .."]", function() end) end) - --- XXX FIXME: enable rpc_sync = on - for _, rpc_sync in ipairs { "off" } do + for _, v in ipairs({ {"off", "off"}, {"on", "off"}, {"on", "on"}, }) do + local rpc, rpc_sync = v[1], v[2] describe("in hybrid mode" .. " rpc_sync=" .. rpc_sync, function() local route + lazy_setup(function() + -- if the database is not cleared, the residual RPC connection information + -- between different tests will cause the test to fail. + local plugin_name = "correlation-id" + bp, db = helpers.get_db_utils(strategy, { "plugins", "workspaces", }) + ws = db.workspaces:select_by_name("default") + plugin_id = uuid.generate_v4() + local sql = render([[ + INSERT INTO plugins (id, name, config, enabled, ws_id) VALUES + ('$(ID)', '$(PLUGIN_NAME)', $(CONFIG)::jsonb, TRUE, '$(WS_ID)'); + COMMIT; + ]], { + ID = plugin_id, + PLUGIN_NAME = plugin_name, + CONFIG = pgmoon_json.encode_json(plugin_config), + WS_ID = ws.id, + }) + + local res, err = db.connector:query(sql) + assert.is_nil(err) + assert.is_not_nil(res) + route = bp.routes:insert({ hosts = {"example.com"}, }) @@ -102,9 +124,9 @@ describe("Plugin: correlation-id (schema) #a [#" .. strategy .."]", function() }, } local sql = render([[ - UPDATE plugins SET route_id='$(ROUTE_ID)', - protocols=ARRAY['grpc','grpcs','http','https'], - cache_key='$(CACHE_KEY)' + UPDATE plugins SET route_id='$(ROUTE_ID)', + protocols=ARRAY['grpc','grpcs','http','https'], + cache_key='$(CACHE_KEY)' WHERE id='$(ID)'; COMMIT; ]], { @@ -124,6 +146,7 @@ describe("Plugin: correlation-id (schema) #a [#" .. strategy .."]", function() prefix = "servroot", cluster_listen = "127.0.0.1:9005", nginx_conf = "spec/fixtures/custom_nginx.template", + cluster_rpc = rpc, cluster_rpc_sync = rpc_sync, })) @@ -136,6 +159,7 @@ describe("Plugin: correlation-id (schema) #a [#" .. strategy .."]", function() cluster_control_plane = "127.0.0.1:9005", proxy_listen = "0.0.0.0:9002", status_listen = "127.0.0.1:9100", + cluster_rpc = rpc, cluster_rpc_sync = rpc_sync, })) end) @@ -174,17 +198,20 @@ describe("Plugin: correlation-id (schema) #a [#" .. strategy .."]", function() assert.equals("uuid#counter", res.config.generator) local proxy_client = helpers.proxy_client(20000, 9002, "127.0.0.1") - res = assert(proxy_client:send { - method = "GET", - path = "/", - headers = { - ["Host"] = "example.com", - } - }) - assert.res_status(200, res) - assert.is_not_nil(res.headers["Kong-Request-ID"]) + helpers.pwait_until(function() + res = assert(proxy_client:send { + method = "GET", + path = "/", + headers = { + ["Host"] = "example.com", + } + }) + assert.res_status(200, res) + assert.is_not_nil(res.headers["Kong-Request-ID"]) + end, 10) proxy_client:close() + end) end) - end -- for rpc_sync + end -- for rpc, rpc_sync end) diff --git a/spec/03-plugins/28-grpc-gateway/01-proxy_spec.lua b/spec/03-plugins/28-grpc-gateway/01-proxy_spec.lua index 0f5d9530fd1..88741562b01 100644 --- a/spec/03-plugins/28-grpc-gateway/01-proxy_spec.lua +++ b/spec/03-plugins/28-grpc-gateway/01-proxy_spec.lua @@ -48,10 +48,50 @@ for _, strategy in helpers.each_strategy() do }, }) - assert(helpers.start_kong { + local mock_grpc_service = assert(bp.services:insert { + name = "mock_grpc_service", + url = "http://localhost:8765", + }) + + local mock_grpc_route = assert(bp.routes:insert { + protocols = { "http" }, + hosts = { "grpc_mock.example" }, + service = mock_grpc_service, + preserve_host = true, + }) + + assert(bp.plugins:insert { + route = mock_grpc_route, + name = "grpc-gateway", + config = { + proto = "./spec/fixtures/grpc/targetservice.proto", + }, + }) + + local fixtures = { + http_mock = {} + } + fixtures.http_mock.my_server_block = [[ + server { + server_name myserver; + listen 8765; + + location ~ / { + content_by_lua_block { + local headers = ngx.req.get_headers() + ngx.header.content_type = "application/grpc" + ngx.header.received_host = headers["Host"] + ngx.header.received_te = headers["te"] + } + } + } + ]] + + assert(helpers.start_kong({ database = strategy, plugins = "bundled,grpc-gateway", - }) + nginx_conf = "spec/fixtures/custom_nginx.template", + }, nil, nil, fixtures)) end) before_each(function() @@ -63,6 +103,34 @@ for _, strategy in helpers.each_strategy() do helpers.stop_grpc_target() end) + test("#new Sets 'TE: trailers'", function() + local res, err = proxy_client:post("/v1/echo", { + headers = { + ["Host"] = "grpc_mock.example", + ["Content-Type"] = "application/json", + }, + }) + + assert.equal("trailers", res.headers["received-te"]) + assert.is_nil(err) + end) + + test("#new Ignores user-agent TE", function() + -- in grpc-gateway, kong acts as a grpc client on behalf of the client + -- (which generally is a web-browser); as such, the Te header must be + -- set by kong, which will append trailers to the response body + local res, err = proxy_client:post("/v1/echo", { + headers = { + ["Host"] = "grpc_mock.example", + ["Content-Type"] = "application/json", + ["TE"] = "chunked", + }, + }) + + assert.equal("trailers", res.headers["received-te"]) + assert.is_nil(err) + end) + test("main entrypoint", function() local res, err = proxy_client:get("/v1/messages/john_doe") diff --git a/spec/03-plugins/32-grpc-web/01-proxy_spec.lua b/spec/03-plugins/32-grpc-web/01-proxy_spec.lua index 8c37776204a..03bfde82291 100644 --- a/spec/03-plugins/32-grpc-web/01-proxy_spec.lua +++ b/spec/03-plugins/32-grpc-web/01-proxy_spec.lua @@ -49,6 +49,25 @@ for _, strategy in helpers.each_strategy() do service = service1, }) + local mock_grpc_service = assert(bp.services:insert { + name = "mock_grpc_service", + url = "http://localhost:8765", + }) + + local mock_grpc_route = assert(bp.routes:insert { + protocols = { "http" }, + hosts = { "grpc_mock.example" }, + service = mock_grpc_service, + preserve_host = true, + }) + + assert(bp.plugins:insert { + route = mock_grpc_route, + name = "grpc-web", + config = { + }, + }) + assert(bp.plugins:insert { route = route1, name = "grpc-web", @@ -66,10 +85,29 @@ for _, strategy in helpers.each_strategy() do }, }) - assert(helpers.start_kong { + local fixtures = { + http_mock = {} + } + fixtures.http_mock.my_server_block = [[ + server { + server_name myserver; + listen 8765; + location ~ / { + content_by_lua_block { + local headers = ngx.req.get_headers() + ngx.header.content_type = "application/grpc" + ngx.header.received_host = headers["Host"] + ngx.header.received_te = headers["te"] + } + } + } + ]] + + assert(helpers.start_kong({ database = strategy, plugins = "bundled,grpc-web", - }) + nginx_conf = "spec/fixtures/custom_nginx.template", + }, nil, nil, fixtures)) end) before_each(function() @@ -82,6 +120,34 @@ for _, strategy in helpers.each_strategy() do end) + test("Sets 'TE: trailers'", function() + local res, err = proxy_client:post("/", { + headers = { + ["Host"] = "grpc_mock.example", + ["Content-Type"] = "application/grpc-web-text", + }, + }) + + assert.equal("trailers", res.headers["received-te"]) + assert.is_nil(err) + end) + + test("Ignores user-agent TE", function() + -- in grpc-web, kong acts as a grpc client on behalf of the client + -- (which generally is a web-browser); as such, the Te header must be + -- set by kong, which will append trailers to the response body + local res, err = proxy_client:post("/", { + headers = { + ["Host"] = "grpc_mock.example", + ["Content-Type"] = "application/grpc-web-text", + ["TE"] = "chunked", + }, + }) + + assert.equal("trailers", res.headers["received-te"]) + assert.is_nil(err) + end) + test("Call gRCP-base64 via HTTP", function() local res, err = proxy_client:post("/hello.HelloService/SayHello", { headers = { diff --git a/spec/03-plugins/38-ai-proxy/05-azure_integration_spec.lua b/spec/03-plugins/38-ai-proxy/05-azure_integration_spec.lua index 7717aa14bff..559c8f179f8 100644 --- a/spec/03-plugins/38-ai-proxy/05-azure_integration_spec.lua +++ b/spec/03-plugins/38-ai-proxy/05-azure_integration_spec.lua @@ -15,8 +15,19 @@ for _, strategy in helpers.all_strategies() do -- set up azure mock fixtures local fixtures = { http_mock = {}, + dns_mock = helpers.dns_mock.new({ + mocks_only = true, -- don't fallback to "real" DNS + }), } + fixtures.dns_mock:A { + name = "001-kong-t.openai.azure.com", + address = "127.0.0.1", + } + + -- openai llm driver will always send to this port, if var is set + helpers.setenv("OPENAI_TEST_PORT", tostring(MOCK_PORT)) + fixtures.http_mock.azure = [[ server { server_name azure; @@ -129,6 +140,56 @@ for _, strategy in helpers.all_strategies() do } } + location = "/openai/deployments/azure-other-instance/other/operation" { + content_by_lua_block { + local pl_file = require "pl.file" + local json = require("cjson.safe") + + local token = ngx.req.get_headers()["api-key"] + if token == "azure-key" then + ngx.req.read_body() + local body, err = ngx.req.get_body_data() + body, err = json.decode(body) + + if err or (body.messages == ngx.null) then + ngx.status = 400 + ngx.print(pl_file.read("spec/fixtures/ai-proxy/openai/llm-v1-chat/responses/bad_request.json")) + else + ngx.status = 200 + ngx.print(pl_file.read("spec/fixtures/ai-proxy/openai/llm-v1-chat/responses/good.json")) + end + else + ngx.status = 401 + ngx.print(pl_file.read("spec/fixtures/ai-proxy/openai/llm-v1-chat/responses/unauthorized.json")) + end + } + } + + location = "/override/path/completely" { + content_by_lua_block { + local pl_file = require "pl.file" + local json = require("cjson.safe") + + local token = ngx.req.get_headers()["api-key"] + if token == "azure-key" then + ngx.req.read_body() + local body, err = ngx.req.get_body_data() + body, err = json.decode(body) + + if err or (body.messages == ngx.null) then + ngx.status = 400 + ngx.print(pl_file.read("spec/fixtures/ai-proxy/openai/llm-v1-chat/responses/bad_request.json")) + else + ngx.status = 200 + ngx.print(pl_file.read("spec/fixtures/ai-proxy/openai/llm-v1-chat/responses/good.json")) + end + else + ngx.status = 401 + ngx.print(pl_file.read("spec/fixtures/ai-proxy/openai/llm-v1-chat/responses/unauthorized.json")) + end + } + } + } ]] @@ -387,6 +448,97 @@ for _, strategy in helpers.all_strategies() do } -- + -- Override path with unique Azure operations + local chat_override_path_from_params = assert(bp.routes:insert { + service = empty_service, + protocols = { "http" }, + strip_path = true, + paths = { "~/ai/openai/deployments/(?[^#?/]+)(?[^#?]+)$" } + }) + bp.plugins:insert { + name = PLUGIN_NAME, + route = { id = chat_override_path_from_params.id }, + config = { + route_type = "preserve", + auth = { + header_name = "api-key", + header_value = "azure-key", + }, + model = { + name = "gpt-3.5-turbo", + provider = "azure", + options = { + max_tokens = 256, + temperature = 1.0, + azure_instance = "001-kong-t", + upstream_path = "$(uri_captures.operation_path)", + azure_deployment_id = "$(uri_captures.azure_deployment)", + }, + }, + }, + } + -- + + -- Override path completely + local chat_override_path_completely = assert(bp.routes:insert { + service = empty_service, + protocols = { "http" }, + strip_path = true, + paths = { "~/override/path/completely$" } + }) + bp.plugins:insert { + name = PLUGIN_NAME, + route = { id = chat_override_path_completely.id }, + config = { + route_type = "preserve", + auth = { + header_name = "api-key", + header_value = "azure-key", + }, + model = { + name = "gpt-3.5-turbo", + provider = "azure", + options = { + max_tokens = 256, + temperature = 1.0, + azure_instance = "001-kong-t", + azure_deployment_id = "gpt-3.5-custom", + }, + }, + }, + } + -- + + -- Override path and expect 404 + local chat_override_path_incorrectly = assert(bp.routes:insert { + service = empty_service, + protocols = { "http" }, + strip_path = true, + paths = { "~/override/path/incorrectly$" } + }) + bp.plugins:insert { + name = PLUGIN_NAME, + route = { id = chat_override_path_incorrectly.id }, + config = { + route_type = "preserve", + auth = { + header_name = "api-key", + header_value = "azure-key", + }, + model = { + name = "gpt-3.5-turbo", + provider = "azure", + options = { + max_tokens = 256, + temperature = 1.0, + azure_instance = "001-kong-t", + azure_deployment_id = "gpt-3.5-custom", + }, + }, + }, + } + -- + -- start kong @@ -647,6 +799,47 @@ for _, strategy in helpers.all_strategies() do assert.equals("request body doesn't contain valid prompts", json.error.message) end) end) + + describe("azure preserve", function() + it("override path from path params", function() + local r = client:get("/ai/openai/deployments/azure-other-instance/other/operation", { + headers = { + ["content-type"] = "application/json", + ["accept"] = "application/json", + }, + body = pl_file.read("spec/fixtures/ai-proxy/openai/llm-v1-chat/requests/good.json"), + }) + + -- validate that the request succeeded, response status 200 + assert.res_status(200 , r) + end) + + it("override path completely", function() + local r = client:get("/override/path/completely", { + headers = { + ["content-type"] = "application/json", + ["accept"] = "application/json", + }, + body = pl_file.read("spec/fixtures/ai-proxy/openai/llm-v1-chat/requests/good.json"), + }) + + -- validate that the request succeeded, response status 200 + assert.res_status(200 , r) + end) + + it("override path incorrectly", function() + local r = client:get("/override/path/incorrectly", { + headers = { + ["content-type"] = "application/json", + ["accept"] = "application/json", + }, + body = pl_file.read("spec/fixtures/ai-proxy/openai/llm-v1-chat/requests/good.json"), + }) + + -- expect it to 404 from the backend + assert.res_status(404 , r) + end) + end) end) end \ No newline at end of file diff --git a/spec/fixtures/custom_plugins/kong/plugins/rpc-batch-test/handler.lua b/spec/fixtures/custom_plugins/kong/plugins/rpc-batch-test/handler.lua new file mode 100644 index 00000000000..2bb3a0b5761 --- /dev/null +++ b/spec/fixtures/custom_plugins/kong/plugins/rpc-batch-test/handler.lua @@ -0,0 +1,32 @@ +local RpcBatchTestHandler = { + VERSION = "1.0", + PRIORITY = 1000, +} + + +function RpcBatchTestHandler:init_worker() + kong.rpc.callbacks:register("kong.test.batch", function(node_id, greeting) + ngx.log(ngx.DEBUG, "kong.test.batch called: ", greeting) + return "hello ".. greeting + end) + + local worker_events = assert(kong.worker_events) + + -- if rpc is ready we will start to batch call + worker_events.register(function(capabilities_list) + kong.rpc:__set_batch(1) + + local res = assert(kong.rpc:call("control_plane", "kong.test.batch", "world")) + + ngx.log(ngx.DEBUG, "kong.test.batch called: ", res) + + kong.rpc:__set_batch(2) + assert(kong.rpc:notify("control_plane", "kong.test.batch", "kong")) + assert(kong.rpc:notify("control_plane", "kong.test.batch", "gateway")) + + ngx.log(ngx.DEBUG, "kong.test.batch ok") + end, "clustering:jsonrpc", "connected") +end + + +return RpcBatchTestHandler diff --git a/spec/fixtures/custom_plugins/kong/plugins/rpc-batch-test/schema.lua b/spec/fixtures/custom_plugins/kong/plugins/rpc-batch-test/schema.lua new file mode 100644 index 00000000000..0515df5835c --- /dev/null +++ b/spec/fixtures/custom_plugins/kong/plugins/rpc-batch-test/schema.lua @@ -0,0 +1,12 @@ +return { + name = "rpc-batch-test", + fields = { + { + config = { + type = "record", + fields = { + }, + }, + }, + }, +} diff --git a/spec/fixtures/custom_plugins/kong/plugins/rpc-error-test/handler.lua b/spec/fixtures/custom_plugins/kong/plugins/rpc-error-test/handler.lua new file mode 100644 index 00000000000..e044784c4de --- /dev/null +++ b/spec/fixtures/custom_plugins/kong/plugins/rpc-error-test/handler.lua @@ -0,0 +1,59 @@ +local cjson = require("cjson") + + +local RpcErrorTestHandler = { + VERSION = "1.0", + PRIORITY = 1000, +} + + +function RpcErrorTestHandler:init_worker() + kong.rpc.callbacks:register("kong.test.exception", function(node_id) + return nil -- no error message, default jsonrpc.SERVER_ERROR + end) + + kong.rpc.callbacks:register("kong.test.error", function(node_id) + return nil, "kong.test.error" + end) + + local worker_events = assert(kong.worker_events) + local node_id = "control_plane" + + -- if rpc is ready we will start to call + worker_events.register(function(capabilities_list) + local res, err = kong.rpc:call(node_id, "kong.test.not_exist") + assert(not res) + assert(err == "Method not found") + + local res, err = kong.rpc:call(node_id, "kong.test.exception") + assert(not res) + assert(err == "Server error") + + local res, err = kong.rpc:call(node_id, "kong.test.error") + assert(not res) + assert(err == "kong.test.error") + + ngx.log(ngx.DEBUG, "test #1 ok") + + end, "clustering:jsonrpc", "connected") + + -- if rpc is ready we will start to send raw msg + worker_events.register(function(capabilities_list) + local s = next(kong.rpc.clients[node_id]) + + -- send an empty array + local msg = setmetatable({}, cjson.array_mt) + assert(s:push_request(msg)) + + -- send an invalid msg + local msg = setmetatable({"invalid_request"}, cjson.array_mt) + assert(s:push_request(msg)) + + ngx.log(ngx.DEBUG, "test #2 ok") + + end, "clustering:jsonrpc", "connected") + +end + + +return RpcErrorTestHandler diff --git a/spec/fixtures/custom_plugins/kong/plugins/rpc-error-test/schema.lua b/spec/fixtures/custom_plugins/kong/plugins/rpc-error-test/schema.lua new file mode 100644 index 00000000000..ba3266fda13 --- /dev/null +++ b/spec/fixtures/custom_plugins/kong/plugins/rpc-error-test/schema.lua @@ -0,0 +1,12 @@ +return { + name = "rpc-error-test", + fields = { + { + config = { + type = "record", + fields = { + }, + }, + }, + }, +} diff --git a/spec/fixtures/custom_plugins/kong/plugins/rpc-get-delta-test/handler.lua b/spec/fixtures/custom_plugins/kong/plugins/rpc-get-delta-test/handler.lua new file mode 100644 index 00000000000..cbe33f92bf3 --- /dev/null +++ b/spec/fixtures/custom_plugins/kong/plugins/rpc-get-delta-test/handler.lua @@ -0,0 +1,60 @@ +local rep = string.rep +local isempty = require("table.isempty") + + +local RpcSyncV2GetDeltaTestHandler = { + VERSION = "1.0", + PRIORITY = 1000, +} + + +function RpcSyncV2GetDeltaTestHandler:init_worker() + local worker_events = assert(kong.worker_events) + + -- if rpc is ready we will send test calls + -- cp's version now is "v02_00000" + worker_events.register(function(capabilities_list) + local node_id = "control_plane" + local method = "kong.sync.v2.get_delta" + + -- no field `default` for kong.sync.v2.get_delta + local msg = {} + local res, err = kong.rpc:call(node_id, method, msg) + + assert(not res) + assert(err == "default namespace does not exist inside params") + + -- version is invalid + local msg = { default = { version = rep("A", 32), }, } + local res, err = kong.rpc:call(node_id, method, msg) + + assert(type(res) == "table") + assert(not isempty(res.default.deltas)) + assert(res.default.wipe == true) + assert(not err) + + -- dp's version is greater than cp's version + local msg = { default = { version = "v02_" .. rep("A", 28), }, } + local res, err = kong.rpc:call(node_id, method, msg) + + assert(type(res) == "table") + assert(not isempty(res.default.deltas)) + assert(res.default.wipe == true) + assert(not err) + + -- dp's version is equal to cp's version + local msg = { default = { version = "v02_" .. rep("0", 28), }, } + local res, err = kong.rpc:call(node_id, method, msg) + + assert(type(res) == "table") + assert(isempty(res.default.deltas)) + assert(res.default.wipe == false) + assert(not err) + + ngx.log(ngx.DEBUG, "kong.sync.v2.get_delta ok") + + end, "clustering:jsonrpc", "connected") +end + + +return RpcSyncV2GetDeltaTestHandler diff --git a/spec/fixtures/custom_plugins/kong/plugins/rpc-get-delta-test/schema.lua b/spec/fixtures/custom_plugins/kong/plugins/rpc-get-delta-test/schema.lua new file mode 100644 index 00000000000..8be21169f70 --- /dev/null +++ b/spec/fixtures/custom_plugins/kong/plugins/rpc-get-delta-test/schema.lua @@ -0,0 +1,12 @@ +return { + name = "rpc-get-delta-test", + fields = { + { + config = { + type = "record", + fields = { + }, + }, + }, + }, +} diff --git a/spec/fixtures/custom_plugins/kong/plugins/rpc-notification-test/handler.lua b/spec/fixtures/custom_plugins/kong/plugins/rpc-notification-test/handler.lua new file mode 100644 index 00000000000..c8877b5f6fe --- /dev/null +++ b/spec/fixtures/custom_plugins/kong/plugins/rpc-notification-test/handler.lua @@ -0,0 +1,37 @@ +local RpcNotificationTestHandler = { + VERSION = "1.0", + PRIORITY = 1000, +} + + +function RpcNotificationTestHandler:init_worker() + kong.rpc.callbacks:register("kong.test.notification", function(node_id, msg) + ngx.log(ngx.DEBUG, "notification is ", msg) + + local role = kong.configuration.role + + -- cp notify dp back + if role == "control_plane" then + local res, err = kong.rpc:notify(node_id, "kong.test.notification", "world") + assert(res == true) + assert(err == nil) + end + + -- perr should not get this by notification + return role + end) + + local worker_events = assert(kong.worker_events) + + -- if rpc is ready we will start to notify + worker_events.register(function(capabilities_list) + -- dp notify cp + local res, err = kong.rpc:notify("control_plane", "kong.test.notification", "hello") + + assert(res == true) + assert(err == nil) + end, "clustering:jsonrpc", "connected") +end + + +return RpcNotificationTestHandler diff --git a/spec/fixtures/custom_plugins/kong/plugins/rpc-notification-test/schema.lua b/spec/fixtures/custom_plugins/kong/plugins/rpc-notification-test/schema.lua new file mode 100644 index 00000000000..886dc7eb123 --- /dev/null +++ b/spec/fixtures/custom_plugins/kong/plugins/rpc-notification-test/schema.lua @@ -0,0 +1,12 @@ +return { + name = "rpc-notification-test", + fields = { + { + config = { + type = "record", + fields = { + }, + }, + }, + }, +} diff --git a/spec/fixtures/custom_plugins/kong/plugins/rpc-notify-new-version-test/handler.lua b/spec/fixtures/custom_plugins/kong/plugins/rpc-notify-new-version-test/handler.lua new file mode 100644 index 00000000000..1862de167ff --- /dev/null +++ b/spec/fixtures/custom_plugins/kong/plugins/rpc-notify-new-version-test/handler.lua @@ -0,0 +1,102 @@ +local fmt = string.format +local rep = string.rep + + +local RpcSyncV2NotifyNewVersioinTestHandler = { + VERSION = "1.0", + PRIORITY = 1000, +} + + +function RpcSyncV2NotifyNewVersioinTestHandler:init_worker() + local counter = 0 + + -- mock function on cp side + kong.rpc.callbacks:register("kong.sync.v2.get_delta", function(node_id, current_versions) + local latest_version = fmt("v02_%028x", 10) + + local fake_uuid = "00000000-0000-0000-0000-111111111111" + + -- a basic config data + local deltas = { + { + entity = { + id = fake_uuid, + name = "default", + -- It must contain feild "config" and "meta", otherwise the deltas + -- validation will fail with the error "required field missing". + config = {}, + meta = {}, + }, + type = "workspaces", + version = latest_version, + ws_id = fake_uuid, + }, + } + + ngx.log(ngx.DEBUG, "kong.sync.v2.get_delta ok: ", counter) + counter = counter + 1 + + return { default = { deltas = deltas, wipe = true, }, } + end) + + -- test dp's sync.v2.notify_new_version on cp side + kong.rpc.callbacks:register("kong.test.notify_new_version", function(node_id) + local dp_node_id = next(kong.rpc.clients) + local method = "kong.sync.v2.notify_new_version" + + -- no default + local msg = {} + local res, err = kong.rpc:call(dp_node_id, method, msg) + assert(not res) + assert(err == "default namespace does not exist inside params") + + -- no default.new_version + local msg = { default = {}, } + local res, err = kong.rpc:call(dp_node_id, method, msg) + assert(not res) + assert(err == "'new_version' key does not exist") + + -- less version string + -- "....." < "00000" < "v02_xx" + local msg = { default = { new_version = rep(".", 32), }, } + local res, err = kong.rpc:call(dp_node_id, method, msg) + assert(res) + assert(not err) + + -- less or equal version string + -- "00000" < "v02_xx" + local msg = { default = { new_version = rep("0", 32), }, } + local res, err = kong.rpc:call(dp_node_id, method, msg) + assert(res) + assert(not err) + + -- greater version string + local msg = { default = { new_version = fmt("v02_%028x", 20), }, } + local res, err = kong.rpc:call(dp_node_id, method, msg) + assert(res) + assert(not err) + + ngx.log(ngx.DEBUG, "kong.test.notify_new_version ok") + + return true + end) + + local worker_events = assert(kong.worker_events) + + -- if rpc is ready we will send test calls + worker_events.register(function(capabilities_list) + local node_id = "control_plane" + + -- trigger cp's test + local res, err = kong.rpc:call(node_id, "kong.test.notify_new_version") + assert(res == true) + assert(not err) + + ngx.log(ngx.DEBUG, "kong.test.notify_new_version ok") + + end, "clustering:jsonrpc", "connected") +end + + +return RpcSyncV2NotifyNewVersioinTestHandler diff --git a/spec/fixtures/custom_plugins/kong/plugins/rpc-notify-new-version-test/schema.lua b/spec/fixtures/custom_plugins/kong/plugins/rpc-notify-new-version-test/schema.lua new file mode 100644 index 00000000000..f920dcb599c --- /dev/null +++ b/spec/fixtures/custom_plugins/kong/plugins/rpc-notify-new-version-test/schema.lua @@ -0,0 +1,12 @@ +return { + name = "rpc-notify-new-version-test", + fields = { + { + config = { + type = "record", + fields = { + }, + }, + }, + }, +} diff --git a/spec/fixtures/dc_blueprints.lua b/spec/fixtures/dc_blueprints.lua index 139bd9c5141..26301d8c0e0 100644 --- a/spec/fixtures/dc_blueprints.lua +++ b/spec/fixtures/dc_blueprints.lua @@ -28,7 +28,9 @@ local function remove_nulls(tbl) end -local function wrap_db(db) +-- tparam boolean expand_foreigns expand the complete "foreign"-type fields, not +-- replacing it with "string"-type fields +local function wrap_db(db, expand_foreigns) local dc_as_db = {} local config = new_config() @@ -43,7 +45,7 @@ local function wrap_db(db) local schema = db.daos[name].schema tbl = schema:process_auto_fields(tbl, "insert") for fname, field in schema:each_field() do - if field.type == "foreign" then + if not expand_foreigns and field.type == "foreign" then tbl[fname] = type(tbl[fname]) == "table" and tbl[fname].id or nil @@ -110,8 +112,8 @@ local function wrap_db(db) end -function dc_blueprints.new(db) - local dc_as_db = wrap_db(db) +function dc_blueprints.new(db, expand_foreigns) + local dc_as_db = wrap_db(db, expand_foreigns) local save_dc = new_config() diff --git a/spec/internal/db.lua b/spec/internal/db.lua index 5659cdf72ef..4dff46aa8d6 100644 --- a/spec/internal/db.lua +++ b/spec/internal/db.lua @@ -261,6 +261,10 @@ end -- custom plugins as loaded. -- @param vaults (optional) vault configuration to use. -- @param skip_migrations (optional) if true, migrations will not be run. +-- @param expand_foreigns (optional) If true, it will prevent converting foreign +-- keys from primary key value pairs to strings. For example, it will keep the +-- foreign key of the router entity as `service = { id = "" }` instead of +-- converting it to `service = ""`. -- @return BluePrint, DB -- @usage -- local PLUGIN_NAME = "my_fancy_plugin" @@ -277,7 +281,7 @@ end -- route = { id = route1.id }, -- config = {}, -- } -local function get_db_utils(strategy, tables, plugins, vaults, skip_migrations) +local function get_db_utils(strategy, tables, plugins, vaults, skip_migrations, expand_foreigns) strategy = strategy or conf.database conf.database = strategy -- overwrite kong.configuration.database @@ -343,7 +347,7 @@ local function get_db_utils(strategy, tables, plugins, vaults, skip_migrations) bp = assert(Blueprints.new(db)) dcbp = nil else - bp = assert(dc_blueprints.new(db)) + bp = assert(dc_blueprints.new(db, expand_foreigns)) dcbp = bp end diff --git a/t/01-pdk/06-service-request/00-phase_checks.t b/t/01-pdk/06-service-request/00-phase_checks.t index 493e4926c0e..b2e7a992c77 100644 --- a/t/01-pdk/06-service-request/00-phase_checks.t +++ b/t/01-pdk/06-service-request/00-phase_checks.t @@ -186,6 +186,30 @@ qq{ body_filter = false, log = false, admin_api = "forced false", + },{ + method = "disable_tls", + args = { }, + init_worker = "forced false", + certificate = "pending", + rewrite = "forced false", + access = "forced false", + response = "forced false", + header_filter = "forced false", + body_filter = "forced false", + log = "forced false", + admin_api = "forced false", + },{ + method = "enable_tls", + args = { }, + init_worker = "forced false", + certificate = "pending", + rewrite = "forced false", + access = "forced false", + response = "forced false", + header_filter = "forced false", + body_filter = "forced false", + log = "forced false", + admin_api = "forced false", }, } diff --git a/t/04-patch/05-ngx-refresh-upstream-uri-when-balancer-retry.t b/t/04-patch/05-ngx-refresh-upstream-uri-when-balancer-retry.t new file mode 100644 index 00000000000..01dd35ec529 --- /dev/null +++ b/t/04-patch/05-ngx-refresh-upstream-uri-when-balancer-retry.t @@ -0,0 +1,58 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket::Lua; + +#worker_connections(1014); +#master_on(); +#workers(2); +#log_level('warn'); + +repeat_each(2); +#repeat_each(1); + +plan tests => repeat_each() * (blocks() * 2); + +#no_diff(); +#no_long_string(); +run_tests(); + +__DATA__ +=== TEST 1: recreate_request refresh upstream uri variable +--- http_config + lua_package_path "../lua-resty-core/lib/?.lua;;"; + + server { + listen 127.0.0.1:$TEST_NGINX_RAND_PORT_1; + + location / { + content_by_lua_block { + ngx.req.read_body() + local body = ngx.req.get_body_data() + ngx.say(ngx.var.uri) + } + } + } + + upstream foo { + server 127.0.0.1:$TEST_NGINX_RAND_PORT_1 max_fails=3; + + balancer_by_lua_block { + local bal = require "ngx.balancer" + ngx.req.set_body_data("hello world") + ngx.var.upstream_uri = "/ttttt" + assert(bal.recreate_request()) + } + } + +--- config + set $upstream_uri "/t"; + location = /t { + proxy_http_version 1.1; + proxy_set_header Connection ""; + proxy_pass http://foo$upstream_uri; + } +--- request +GET /t +--- error_code: 200 +--- response_body +/ttttt